Repo init with mostly unchanged import of LW code
This commit is contained in:
commit
221f0c8ef8
161 changed files with 61414 additions and 0 deletions
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
.vim.local/signature
|
||||
.vim.local/data
|
||||
output/*
|
1
.vim.local/bundles-init/YouCompleteMe.cfg.vim
Normal file
1
.vim.local/bundles-init/YouCompleteMe.cfg.vim
Normal file
|
@ -0,0 +1 @@
|
|||
let g:ycm_global_ycm_extra_conf = g:vim_local_path . "/ycm_extra_conf.py"
|
1
.vim.local/bundles-init/YouCompleteMe.load.vim
Normal file
1
.vim.local/bundles-init/YouCompleteMe.load.vim
Normal file
|
@ -0,0 +1 @@
|
|||
NeoBundle "Valloric/YouCompleteMe"
|
2
.vim.local/bundles-init/vim-uncrustify.cfg.vim
Normal file
2
.vim.local/bundles-init/vim-uncrustify.cfg.vim
Normal file
|
@ -0,0 +1,2 @@
|
|||
let g:uncrustify_cfg_file_path = g:vim_local_path . "/../coding-style-uncrustify.cfg"
|
||||
|
1
.vim.local/bundles-init/vim-uncrustify.load.vim
Normal file
1
.vim.local/bundles-init/vim-uncrustify.load.vim
Normal file
|
@ -0,0 +1 @@
|
|||
NeoBundle "cofyc/vim-uncrustify"
|
42
.vim.local/bundles-init/vimmake.cfg.vim
Normal file
42
.vim.local/bundles-init/vimmake.cfg.vim
Normal file
|
@ -0,0 +1,42 @@
|
|||
let g:vimmake_path = g:vim_local_path . 'scripts'
|
||||
|
||||
let g:vimmake_mode = {}
|
||||
let g:vimmake_mode['clean'] = 'async'
|
||||
let g:vimmake_mode['build'] = 'async'
|
||||
let g:vimmake_mode['rebuild'] = 'async'
|
||||
let g:vimmake_mode['test'] = 'async'
|
||||
|
||||
function! DoBuild(full)
|
||||
silent call vimmake#toggle_quickfix(12,1)
|
||||
if a:full == 0
|
||||
VimTool build
|
||||
else
|
||||
VimTool rebuild
|
||||
endif
|
||||
endfunc
|
||||
|
||||
function! KillBuild()
|
||||
silent call vimmake#toggle_quickfix(0)
|
||||
VimStop
|
||||
endfunc
|
||||
|
||||
function! RunTest()
|
||||
silent call vimmake#toggle_quickfix(12,1)
|
||||
VimTool test
|
||||
endfunc
|
||||
|
||||
augroup QuickfixStatus
|
||||
au! BufWinEnter quickfix setlocal
|
||||
\ statusline=%t\ [%{g:vimmake_build_status}]\ %{exists('w:quickfix_title')?\ '\ '.w:quickfix_title\ :\ ''}\ %=%-15(%l,%c%V%)\ %P
|
||||
augroup END
|
||||
|
||||
noremap <F12> :silent call vimmake#toggle_quickfix(12)<cr>
|
||||
inoremap <F12> <esc>:silent call vimmake#toggle_quickfix(12)<cr>li
|
||||
noremap <F10> :silent call DoBuild(0)<cr>
|
||||
inoremap <F10> <esc>:silent call DoBuild(0)<cr>li
|
||||
noremap <S-F10> :silent call DoBuild(1)<cr>
|
||||
inoremap <S-F10> <esc>:silent call DoBuild(1)<cr>li
|
||||
noremap <C-F10> :silent call KillBuild()<cr>
|
||||
inoremap <C-F10> <esc>:silent call KillBuild()<cr>li
|
||||
noremap <F11> :silent call RunTest()<cr>
|
||||
inoremap <F11> <esc>:silent call RunTest()<cr>li
|
1
.vim.local/bundles-init/vimmake.load.vim
Normal file
1
.vim.local/bundles-init/vimmake.load.vim
Normal file
|
@ -0,0 +1 @@
|
|||
NeoBundle 'skywind3000/vimmake'
|
3
.vim.local/ftplugin/cpp.vim
Normal file
3
.vim.local/ftplugin/cpp.vim
Normal file
|
@ -0,0 +1,3 @@
|
|||
setlocal colorcolumn=121
|
||||
noremap <buffer> <C-f> :call Uncrustify('cpp')<CR>
|
||||
vnoremap <buffer> <C-f> :call RangeUncrustify('cpp')<CR>
|
1
.vim.local/ftplugin/srd.vim
Symbolic link
1
.vim.local/ftplugin/srd.vim
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../data/srd-ftplugin.vim
|
2
.vim.local/scripts/vimmake.build
Executable file
2
.vim.local/scripts/vimmake.build
Executable file
|
@ -0,0 +1,2 @@
|
|||
#!/bin/sh
|
||||
make -j 8 all
|
2
.vim.local/scripts/vimmake.clean
Executable file
2
.vim.local/scripts/vimmake.clean
Executable file
|
@ -0,0 +1,2 @@
|
|||
#!/bin/sh
|
||||
make clean-extra
|
3
.vim.local/scripts/vimmake.rebuild
Executable file
3
.vim.local/scripts/vimmake.rebuild
Executable file
|
@ -0,0 +1,3 @@
|
|||
#!/bin/sh
|
||||
make clean-extra
|
||||
make -j 8 all
|
14
.vim.local/scripts/vimmake.test
Executable file
14
.vim.local/scripts/vimmake.test
Executable file
|
@ -0,0 +1,14 @@
|
|||
#!/bin/bash
|
||||
if [ "$VIM_RELDIR" = "tests" ] && [ "$VIM_FILEEXT" = ".cc" ]; then
|
||||
if make -j 8 all; then
|
||||
if [ -f "output/fast/test-$VIM_FILENOEXT" ]; then
|
||||
LD_LIBRARY_PATH=./output/fast \
|
||||
./output/fast/test-$VIM_FILENOEXT 2>&1 \
|
||||
| sed -e s/"$VIM_FILENAME"/'tests\/'"$VIM_FILENAME"/g
|
||||
else
|
||||
LD_LIBRARY_PATH=./output/fast \
|
||||
./output/fast/run-all-tests 2>&1 \
|
||||
| sed -e 's/^\([a-z\-]\+\.cc\)/tests\/\1/g'
|
||||
fi
|
||||
fi
|
||||
fi
|
1
.vim.local/syntax/srd.vim
Symbolic link
1
.vim.local/syntax/srd.vim
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../data/srd-syntax.vim
|
7
.vim.local/vimrc
Normal file
7
.vim.local/vimrc
Normal file
|
@ -0,0 +1,7 @@
|
|||
let g:vim_local = {
|
||||
\ "vardata" : g:vim_local_path . "/data"
|
||||
\ }
|
||||
|
||||
au BufNewFile,BufRead *.srd setf srd
|
||||
|
||||
"let &wildignore=&wildignore . ',glef.c,glef.h'
|
143
.vim.local/ycm_extra_conf.py
Normal file
143
.vim.local/ycm_extra_conf.py
Normal file
|
@ -0,0 +1,143 @@
|
|||
# This file is NOT licensed under the GPLv3, which is the license for the rest
|
||||
# of YouCompleteMe.
|
||||
#
|
||||
# Here's the license text for this file:
|
||||
#
|
||||
# This is free and unencumbered software released into the public domain.
|
||||
#
|
||||
# Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
# distribute this software, either in source code form or as a compiled
|
||||
# binary, for any purpose, commercial or non-commercial, and by any
|
||||
# means.
|
||||
#
|
||||
# In jurisdictions that recognize copyright laws, the author or authors
|
||||
# of this software dedicate any and all copyright interest in the
|
||||
# software to the public domain. We make this dedication for the benefit
|
||||
# of the public at large and to the detriment of our heirs and
|
||||
# successors. We intend this dedication to be an overt act of
|
||||
# relinquishment in perpetuity of all present and future rights to this
|
||||
# software under copyright law.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
# IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
# OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
# For more information, please refer to <http://unlicense.org/>
|
||||
|
||||
import os
|
||||
import ycm_core
|
||||
|
||||
# These are the compilation flags that will be used in case there's no
|
||||
# compilation database set (by default, one is not set).
|
||||
# CHANGE THIS LIST OF FLAGS. YES, THIS IS THE DROID YOU HAVE BEEN LOOKING FOR.
|
||||
flags = [
|
||||
'-Wall',
|
||||
'-Wextra',
|
||||
'-Werror',
|
||||
'-Wno-long-long',
|
||||
'-Wno-variadic-macros',
|
||||
'-fexceptions',
|
||||
'-std=c++14',
|
||||
'-x',
|
||||
'c++',
|
||||
'-I' ,
|
||||
'./include'
|
||||
]
|
||||
|
||||
|
||||
# Set this to the absolute path to the folder (NOT the file!) containing the
|
||||
# compile_commands.json file to use that instead of 'flags'. See here for
|
||||
# more details: http://clang.llvm.org/docs/JSONCompilationDatabase.html
|
||||
#
|
||||
# You can get CMake to generate this file for you by adding:
|
||||
# set( CMAKE_EXPORT_COMPILE_COMMANDS 1 )
|
||||
# to your CMakeLists.txt file.
|
||||
#
|
||||
# Most projects will NOT need to set this to anything; you can just change the
|
||||
# 'flags' list of compilation flags. Notice that YCM itself uses that approach.
|
||||
compilation_database_folder = ''
|
||||
|
||||
if os.path.exists( compilation_database_folder ):
|
||||
database = ycm_core.CompilationDatabase( compilation_database_folder )
|
||||
else:
|
||||
database = None
|
||||
|
||||
SOURCE_EXTENSIONS = [ '.cpp', '.cxx', '.cc', '.c', '.m', '.mm' ]
|
||||
|
||||
def DirectoryOfThisScript():
|
||||
return os.path.dirname( os.path.dirname( os.path.abspath( __file__ ) ) )
|
||||
|
||||
|
||||
def MakeRelativePathsInFlagsAbsolute( flags, working_directory ):
|
||||
if not working_directory:
|
||||
return list( flags )
|
||||
new_flags = []
|
||||
make_next_absolute = False
|
||||
path_flags = [ '-isystem', '-I', '-iquote', '--sysroot=' ]
|
||||
for flag in flags:
|
||||
new_flag = flag
|
||||
|
||||
if make_next_absolute:
|
||||
make_next_absolute = False
|
||||
if not flag.startswith( '/' ):
|
||||
new_flag = os.path.join( working_directory, flag )
|
||||
|
||||
for path_flag in path_flags:
|
||||
if flag == path_flag:
|
||||
make_next_absolute = True
|
||||
break
|
||||
|
||||
if flag.startswith( path_flag ):
|
||||
path = flag[ len( path_flag ): ]
|
||||
new_flag = path_flag + os.path.join( working_directory, path )
|
||||
break
|
||||
|
||||
if new_flag:
|
||||
new_flags.append( new_flag )
|
||||
return new_flags
|
||||
|
||||
|
||||
def IsHeaderFile( filename ):
|
||||
extension = os.path.splitext( filename )[ 1 ]
|
||||
return extension in [ '.h', '.hxx', '.hpp', '.hh' ]
|
||||
|
||||
|
||||
def GetCompilationInfoForFile( filename ):
|
||||
# The compilation_commands.json file generated by CMake does not have entries
|
||||
# for header files. So we do our best by asking the db for flags for a
|
||||
# corresponding source file, if any. If one exists, the flags for that file
|
||||
# should be good enough.
|
||||
if IsHeaderFile( filename ):
|
||||
basename = os.path.splitext( filename )[ 0 ]
|
||||
for extension in SOURCE_EXTENSIONS:
|
||||
replacement_file = basename + extension
|
||||
if os.path.exists( replacement_file ):
|
||||
compilation_info = database.GetCompilationInfoForFile(
|
||||
replacement_file )
|
||||
if compilation_info.compiler_flags_:
|
||||
return compilation_info
|
||||
return None
|
||||
return database.GetCompilationInfoForFile( filename )
|
||||
|
||||
|
||||
def FlagsForFile( filename, **kwargs ):
|
||||
if database:
|
||||
# Bear in mind that compilation_info.compiler_flags_ does NOT return a
|
||||
# python list, but a "list-like" StringVec object
|
||||
compilation_info = GetCompilationInfoForFile( filename )
|
||||
if not compilation_info:
|
||||
return None
|
||||
|
||||
final_flags = MakeRelativePathsInFlagsAbsolute(
|
||||
compilation_info.compiler_flags_,
|
||||
compilation_info.compiler_working_dir_ )
|
||||
|
||||
else:
|
||||
relative_to = DirectoryOfThisScript()
|
||||
final_flags = MakeRelativePathsInFlagsAbsolute( flags, relative_to )
|
||||
|
||||
return { 'flags': final_flags }
|
240
include/ebcl/Alloc.hh
Normal file
240
include/ebcl/Alloc.hh
Normal file
|
@ -0,0 +1,240 @@
|
|||
/******************************************************************************/
|
||||
/* ALLOCATORS *****************************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
#ifndef _H_EBCL_ALLOC
|
||||
#define _H_EBCL_ALLOC
|
||||
#include <lw/lib/Config.hh>
|
||||
#include <lw/lib/Utilities.hh>
|
||||
#include <atomic>
|
||||
namespace lw {
|
||||
|
||||
|
||||
/* Helpers for pool allocators. */
|
||||
struct T_PoolHelper
|
||||
{
|
||||
/* Storage type for an object */
|
||||
template<
|
||||
size_t ObjectSize ,
|
||||
size_t ObjectAlign
|
||||
> using T_Object = std::aligned_storage_t< ObjectSize , ObjectAlign >;
|
||||
|
||||
/* List of object storage items. The storage type is assumed to
|
||||
* have a void* field called list.
|
||||
*/
|
||||
template<
|
||||
typename T_Storage ,
|
||||
size_t ListSize
|
||||
> struct T_List final
|
||||
{
|
||||
static constexpr size_t BitmapSize
|
||||
= ( ListSize / 8 ) + ( ListSize % 8 ? 1 : 0 );
|
||||
|
||||
using T_Self = T_List< T_Storage , ListSize >;
|
||||
|
||||
T_Storage storage[ ListSize ]; // Stored data
|
||||
T_Self* next; // Next list in chain
|
||||
size_t free; // Free objects
|
||||
uint8_t bitmap[ BitmapSize ]; // Allocation map
|
||||
|
||||
T_List( ) = delete;
|
||||
T_List( T_Self const& ) = delete;
|
||||
T_List( T_Self&& ) = delete;
|
||||
|
||||
// Create a new list, replacing the chain's head
|
||||
explicit T_List( T_Self*& head ) noexcept;
|
||||
|
||||
// Find an unused item in the list. The list must have free
|
||||
// items.
|
||||
T_Storage* findUnused( ) noexcept;
|
||||
// Find the index of an item. The item must be part of the list.
|
||||
size_t indexOf( T_Storage const* item ) noexcept;
|
||||
|
||||
// Destroy a complete chain of lists
|
||||
static void destroy( T_Self*& head ) noexcept;
|
||||
};
|
||||
|
||||
/* The core of a pool allocator */
|
||||
template<
|
||||
typename T_Storage ,
|
||||
size_t PerList ,
|
||||
size_t MaxFreeLists
|
||||
> struct T_Allocator final
|
||||
{
|
||||
static_assert( PerList > 1 , "allocator lists must contain at least 2 items" );
|
||||
static_assert( MaxFreeLists > 0 , "allocator must have at least 1 free list" );
|
||||
|
||||
using T_List_ = T_List< T_Storage , PerList >;
|
||||
using T_Self = T_Allocator< T_Storage , PerList , MaxFreeLists >;
|
||||
|
||||
// The chains
|
||||
T_List_* free_;
|
||||
T_List_* partial_;
|
||||
T_List_* full_;
|
||||
size_t nFree_;
|
||||
|
||||
T_Allocator( ) noexcept;
|
||||
~T_Allocator( );
|
||||
|
||||
T_Allocator( T_Self const& ) = delete;
|
||||
T_Allocator( T_Self&& ) = delete;
|
||||
|
||||
/* Allocate an object. */
|
||||
T_Storage* allocate( ) noexcept;
|
||||
/* Free an object */
|
||||
void free( T_Storage* item ) noexcept;
|
||||
|
||||
/* Get the amount of lists. Mostly used for testing. */
|
||||
size_t countFreeLists( ) const noexcept;
|
||||
size_t countPartialLists( ) const noexcept;
|
||||
size_t countFullLists( ) const noexcept;
|
||||
|
||||
/* Get the amount of total, free and used objects */
|
||||
void getUsage( size_t& total ,
|
||||
size_t& free ,
|
||||
size_t& used ) const noexcept;
|
||||
|
||||
private:
|
||||
/* Move a list of objects from one of the allocation lists to another. */
|
||||
static void moveList(
|
||||
T_List_* list ,
|
||||
T_List_*& from ,
|
||||
T_List_*& to ) noexcept;
|
||||
|
||||
/* Count the amount of lists in an allocation list */
|
||||
static size_t countLists(
|
||||
T_List_ const* head ) noexcept;
|
||||
};
|
||||
};
|
||||
|
||||
/*============================================================================*/
|
||||
|
||||
/* The pool allocator implements a thread-unsafe pool of objects, similar to a
|
||||
* slab allocator.
|
||||
*/
|
||||
template<
|
||||
size_t ObjectSize , size_t ObjectAlign ,
|
||||
size_t PerList = std::max( size_t( 8 ) , 4096u / ObjectSize ) ,
|
||||
size_t MaxFreeLists = 4
|
||||
>
|
||||
class T_PoolAllocator
|
||||
{
|
||||
public:
|
||||
using T_Self = T_PoolAllocator< ObjectSize , ObjectAlign , PerList , MaxFreeLists >;
|
||||
|
||||
private:
|
||||
// Structure that stores a single allocated item
|
||||
struct T_Storage_ final
|
||||
{
|
||||
T_PoolHelper::T_Object< ObjectSize , ObjectAlign > data;
|
||||
void* list;
|
||||
};
|
||||
|
||||
using T_Alloc_ = T_PoolHelper::T_Allocator< T_Storage_ , PerList , MaxFreeLists >;
|
||||
T_Alloc_ alloc_;
|
||||
|
||||
public:
|
||||
T_PoolAllocator( ) noexcept = default;
|
||||
T_PoolAllocator( T_Self const& ) = delete;
|
||||
T_PoolAllocator( T_Self&& ) = delete;
|
||||
|
||||
/* Allocate an object. */
|
||||
void* allocate( size_t requested ) noexcept;
|
||||
/* Free an object */
|
||||
void free( void* item ) noexcept;
|
||||
|
||||
/* Get the amount of lists. Mostly used for testing. */
|
||||
size_t countFreeLists( ) const noexcept;
|
||||
size_t countPartialLists( ) const noexcept;
|
||||
size_t countFullLists( ) const noexcept;
|
||||
|
||||
/* Get the amount of total, free and used objects */
|
||||
void getUsage( size_t& total ,
|
||||
size_t& free ,
|
||||
size_t& used ) const noexcept;
|
||||
};
|
||||
|
||||
/*============================================================================*/
|
||||
|
||||
/* Pool allocator with multithreading support. Allocation is performed from
|
||||
* a thread-specific pool allocator; when the memory is freed, the memory is
|
||||
* either returned directly to the pool if the freeing thread is the same as
|
||||
* the allocating thread, or queued for the original thread to free later.
|
||||
*/
|
||||
template<
|
||||
size_t ObjectSize , size_t ObjectAlign ,
|
||||
size_t PerList = std::max( size_t( 8 ) , 4096u / ObjectSize ) ,
|
||||
size_t MaxFreeLists = 4
|
||||
>
|
||||
class T_ThreadedPoolAllocator
|
||||
{
|
||||
public:
|
||||
using T_Self = T_ThreadedPoolAllocator<
|
||||
ObjectSize , ObjectAlign , PerList , MaxFreeLists >;
|
||||
|
||||
private:
|
||||
// Pointer to either the owning pool or the next object in the
|
||||
// pending list
|
||||
struct T_Storage_;
|
||||
union T_ExtraPointer_
|
||||
{
|
||||
T_Storage_* next;
|
||||
T_Self* pool;
|
||||
};
|
||||
|
||||
// Structure that stores a single allocated item
|
||||
struct T_Storage_ final
|
||||
{
|
||||
T_PoolHelper::T_Object< ObjectSize , ObjectAlign > data;
|
||||
void* list;
|
||||
T_ExtraPointer_ extra;
|
||||
};
|
||||
|
||||
// The head for the "remote" freeing stack
|
||||
struct T_FreeHead_ final
|
||||
{
|
||||
uintptr_t aba{ 0 };
|
||||
T_Storage_* head{ nullptr };
|
||||
};
|
||||
|
||||
// Atomic stack head, plus padding to prevent false sharing between
|
||||
// the stack head and the actual allocator.
|
||||
char padding_0_[ 64 ];
|
||||
std::atomic< T_FreeHead_ > freeHead_;
|
||||
char padding_1_[ 64 - sizeof( std::atomic< T_FreeHead_ > ) ];
|
||||
|
||||
using T_Alloc_ = T_PoolHelper::T_Allocator<
|
||||
T_Storage_ , PerList , MaxFreeLists >;
|
||||
T_Alloc_ alloc_;
|
||||
|
||||
public:
|
||||
T_ThreadedPoolAllocator( ) noexcept = default;
|
||||
T_ThreadedPoolAllocator( T_Self const& ) = delete;
|
||||
T_ThreadedPoolAllocator( T_Self&& ) = delete;
|
||||
|
||||
/* Allocate an object. */
|
||||
void* allocate( size_t requested ) noexcept;
|
||||
/* Free an object */
|
||||
void free( void* item ) noexcept;
|
||||
|
||||
/* Get the amount of lists. Mostly used for testing. */
|
||||
size_t countFreeLists( ) const noexcept;
|
||||
size_t countPartialLists( ) const noexcept;
|
||||
size_t countFullLists( ) const noexcept;
|
||||
|
||||
/* Get the amount of total, free and used objects */
|
||||
void getUsage( size_t& total ,
|
||||
size_t& free ,
|
||||
size_t& used ) const noexcept;
|
||||
|
||||
private:
|
||||
// Try to take an item from the stack.
|
||||
T_Storage_* takeFromStack( ) noexcept;
|
||||
// Add an item to the stack
|
||||
void addToStack( T_Storage_* item ) noexcept;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
#endif //_H_EBCL_ALLOC
|
||||
#include <lw/lib/inline/Alloc.hh>
|
446
include/ebcl/Arrays.hh
Normal file
446
include/ebcl/Arrays.hh
Normal file
|
@ -0,0 +1,446 @@
|
|||
/******************************************************************************/
|
||||
/* ARRAYS *********************************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
#ifndef _H_EBCL_ARRAYS
|
||||
#define _H_EBCL_ARRAYS
|
||||
#include <lw/lib/Externals.hh>
|
||||
#include <lw/lib/Pointers.hh>
|
||||
#include <lw/lib/Utilities.hh>
|
||||
#include <lw/lib/Types.hh>
|
||||
namespace lw {
|
||||
|
||||
|
||||
/*= DYNAMIC ARRAYS ===========================================================*/
|
||||
|
||||
template< class T >
|
||||
class T_Array final
|
||||
{
|
||||
public:
|
||||
static constexpr uint32_t DEFAULT_GROWTH( )
|
||||
{
|
||||
return std::max< uint32_t >( 1 , 4096 / sizeof( T ) );
|
||||
}
|
||||
|
||||
private:
|
||||
typedef T_Array< T > MyType_;
|
||||
|
||||
T* data_;
|
||||
uint32_t capacity_;
|
||||
uint32_t size_;
|
||||
uint32_t growth_;
|
||||
|
||||
public:
|
||||
M_TEMPLATE_POINTERS( MyType_ );
|
||||
|
||||
T_Array( ) noexcept;
|
||||
explicit T_Array( uint32_t growth ) noexcept;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
T_Array( MyType_ const& source ) noexcept;
|
||||
MyType_& operator= ( MyType_ const& other ) noexcept;
|
||||
|
||||
T_Array( MyType_&& source ) noexcept;
|
||||
MyType_& operator= ( MyType_&& other ) noexcept;
|
||||
|
||||
template< typename TP >
|
||||
friend void swap( T_Array< TP >& lhs ,
|
||||
T_Array< TP >& rhs ) noexcept;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
~T_Array( );
|
||||
|
||||
MyType_& clear( ) noexcept;
|
||||
MyType_& free( ) noexcept;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
uint32_t capacity( ) const noexcept;
|
||||
uint32_t size( ) const noexcept;
|
||||
uint32_t growth( ) const noexcept;
|
||||
|
||||
MyType_& ensureCapacity( uint32_t capacity ) noexcept;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
T& operator[] ( uint32_t index ) noexcept;
|
||||
T const& operator[] ( uint32_t index ) const noexcept;
|
||||
|
||||
int32_t indexOf( T const& item ) const noexcept;
|
||||
bool contains( T const& item ) const noexcept;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
uint32_t add( T const& item ) noexcept;
|
||||
uint32_t add( T&& item ) noexcept;
|
||||
|
||||
template< typename... Args >
|
||||
T& addNew( Args&& ... args );
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
MyType_& addAll( MyType_ const& other ) noexcept;
|
||||
MyType_& addAll( MyType_&& other ) noexcept;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
MyType_& operator<< ( T const& item ) noexcept;
|
||||
MyType_& operator<< ( T&& item ) noexcept;
|
||||
MyType_& operator<< ( MyType_ const& other ) noexcept;
|
||||
MyType_& operator<< ( MyType_&& other ) noexcept;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
void insert( uint32_t index ,
|
||||
T const& item ) noexcept;
|
||||
void insert( uint32_t index ,
|
||||
T&& item ) noexcept;
|
||||
|
||||
template< typename... Args >
|
||||
T& insertNew( uint32_t index ,
|
||||
Args&& ... args );
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
void remove( uint32_t index ) noexcept;
|
||||
void removeSwap( uint32_t index ) noexcept;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
void sort( F_Comparator< T > cmp = T_Comparator< T >::compare ) noexcept;
|
||||
void sort( uint32_t first ,
|
||||
uint32_t items ,
|
||||
F_Comparator< T > cmp = T_Comparator< T >::compare ) noexcept;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
MyType_ copyRange( uint32_t first ,
|
||||
uint32_t last = UINT32_MAX ) const noexcept;
|
||||
|
||||
MyType_ moveRange( uint32_t first ,
|
||||
uint32_t last = UINT32_MAX ) noexcept;
|
||||
};
|
||||
|
||||
// Instantiate some common types directly
|
||||
extern template class T_Array< uint32_t >;
|
||||
|
||||
|
||||
/*= STATICALLY ALLOCATED ARRAYS ==============================================*/
|
||||
/* These arrays offer the same interface as dynamic arrays, but are in fact
|
||||
* implemented as in-place storage.
|
||||
*/
|
||||
|
||||
template< typename Type , uint32_t Size >
|
||||
class T_StaticArray final
|
||||
{
|
||||
static_assert( Size > 0 , "Size must be greater than 0" );
|
||||
|
||||
public:
|
||||
using T_Self = T_StaticArray< Type , Size >;
|
||||
|
||||
private:
|
||||
// Actual storage type
|
||||
using T_Storage_ = std::aligned_storage_t<
|
||||
sizeof( Type ) , alignof( Type )
|
||||
>;
|
||||
|
||||
T_Storage_ storage_[ Size ];
|
||||
uint32_t size_;
|
||||
|
||||
public:
|
||||
M_TEMPLATE_POINTERS( T_Self );
|
||||
|
||||
T_StaticArray( ) noexcept;
|
||||
|
||||
// Copy
|
||||
T_StaticArray( T_Self const& source ) noexcept;
|
||||
T_Self& operator= ( T_Self const& other ) noexcept;
|
||||
|
||||
// Move
|
||||
T_StaticArray( T_Self&& source ) noexcept;
|
||||
T_Self& operator= ( T_Self&& other ) noexcept;
|
||||
|
||||
~T_StaticArray( ) noexcept;
|
||||
T_Self& clear( ) noexcept;
|
||||
|
||||
template< typename T , uint32_t S >
|
||||
friend void swap(
|
||||
T_StaticArray< T , S >& lhs ,
|
||||
T_StaticArray< T , S >& rhs ) noexcept;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
constexpr uint32_t capacity( ) const noexcept;
|
||||
uint32_t size( ) const noexcept;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
Type& operator[] ( uint32_t index ) noexcept;
|
||||
Type const& operator[] ( uint32_t index ) const noexcept;
|
||||
|
||||
int32_t indexOf( Type const& item ) const noexcept;
|
||||
bool contains( Type const& item ) const noexcept;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
uint32_t add( Type&& item ) noexcept;
|
||||
uint32_t add( Type const& item ) noexcept;
|
||||
template< typename... Args >
|
||||
Type& addNew( Args&& ... args );
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
T_Self& addAll( T_Self const& other ) noexcept;
|
||||
T_Self& addAll( T_Self&& other ) noexcept;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
T_Self& operator<< ( Type const& item ) noexcept;
|
||||
T_Self& operator<< ( Type&& item ) noexcept;
|
||||
T_Self& operator<< ( T_Self const& other ) noexcept;
|
||||
T_Self& operator<< ( T_Self&& other ) noexcept;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
void insert( uint32_t index ,
|
||||
Type&& item ) noexcept;
|
||||
void insert( uint32_t index ,
|
||||
Type const& item ) noexcept;
|
||||
template< typename... Args >
|
||||
Type& insertNew( uint32_t index ,
|
||||
Args&& ... args );
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
void remove( uint32_t index ) noexcept;
|
||||
void removeSwap( uint32_t index ) noexcept;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
void sort( F_Comparator< Type > cmp = T_Comparator< Type >::compare ) noexcept;
|
||||
void sort( uint32_t first ,
|
||||
uint32_t items ,
|
||||
F_Comparator< Type > cmp = T_Comparator< Type >::compare ) noexcept;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
T_Self copyRange( uint32_t first ,
|
||||
uint32_t last = UINT32_MAX ) const noexcept;
|
||||
T_Self moveRange( uint32_t first ,
|
||||
uint32_t last = UINT32_MAX ) noexcept;
|
||||
};
|
||||
|
||||
|
||||
/*= MULTI-ARRAYS ============================================================-*/
|
||||
/*
|
||||
* Arrays that allow storing multiple values for one entry. Values must be
|
||||
* added in order.
|
||||
*/
|
||||
|
||||
template< typename T >
|
||||
class T_MultiArray
|
||||
{
|
||||
public:
|
||||
using T_Data = T_Array< T >;
|
||||
|
||||
private:
|
||||
typedef T_MultiArray< T > MyType_;
|
||||
|
||||
T_Array< uint32_t > meta_;
|
||||
T_Data values_;
|
||||
|
||||
public:
|
||||
M_TEMPLATE_POINTERS( T_MultiArray );
|
||||
|
||||
template< typename TP >
|
||||
friend void swap( T_MultiArray< TP >& lhs , T_MultiArray< TP >& rhs );
|
||||
|
||||
// Start the next entry
|
||||
void next( );
|
||||
// Add a value to the current entry
|
||||
void add( T value );
|
||||
// Add a value, calling its constructor
|
||||
template<
|
||||
typename Q = T ,
|
||||
typename... Args ,
|
||||
typename = std::enable_if_t< std::is_class< Q >::value >
|
||||
>
|
||||
Q& addNew( Args&& ... args );
|
||||
// Copy an array's contents into the current entry
|
||||
void copyFrom( T_Data const& source );
|
||||
|
||||
// Returns the amount of entries
|
||||
uint32_t size( ) const;
|
||||
// Returns the index of the first value for an entry
|
||||
uint32_t firstOf( uint32_t item ) const;
|
||||
// Returns the amount of values for an entry
|
||||
uint32_t sizeOf( uint32_t item ) const;
|
||||
|
||||
// Access a value in an entry
|
||||
T const& get( uint32_t item , uint32_t sub ) const;
|
||||
T& get( uint32_t item , uint32_t sub );
|
||||
|
||||
// Access a value using its index
|
||||
T const& operator[] ( uint32_t index ) const;
|
||||
T& operator[] ( uint32_t index );
|
||||
|
||||
// Is a value present in an entry?
|
||||
bool contains( uint32_t index , T const& value ) const;
|
||||
|
||||
// Reset storage, don't free memory
|
||||
void clear( );
|
||||
// Reset storage and free memory
|
||||
void free( );
|
||||
|
||||
// Copy values from an entry into the current entry
|
||||
void copyFrom( uint32_t index );
|
||||
// Copy another multi-array's entry into the current entry
|
||||
void copyFrom( MyType_ const& other , uint32_t index );
|
||||
|
||||
// Copy values from another entry into the current entry if
|
||||
// they are not already present. Duplicate entries in the
|
||||
// source array are still copied, though.
|
||||
void copyUnique( uint32_t index );
|
||||
// Copy another multi-array's entry into the current entry,
|
||||
// ignoring values that are already present. Duplicates in
|
||||
// the source array are still copied.
|
||||
void copyUnique( MyType_ const& other , uint32_t index );
|
||||
|
||||
// Sort an entry's values
|
||||
void sort( uint32_t index , F_Comparator< T > cmp = T_Comparator< T >::compare );
|
||||
};
|
||||
|
||||
|
||||
// Instantiate some common types directly
|
||||
extern template class T_MultiArray< uint32_t >;
|
||||
|
||||
|
||||
/*= AUTOMATIC ARRAYS =========================================================*/
|
||||
/* Arrays that are stored in-place up to some limit, then transform into
|
||||
* dynamic arrays if necessary.
|
||||
*/
|
||||
|
||||
template<
|
||||
typename T , uint32_t StaticSize ,
|
||||
uint32_t DynamicGrowth = StaticSize * 4
|
||||
> class T_AutoArray
|
||||
{
|
||||
public:
|
||||
using T_Self = T_AutoArray< T , StaticSize , DynamicGrowth >;
|
||||
|
||||
private:
|
||||
using T_Static_ = T_StaticArray< T , StaticSize >;
|
||||
using T_Dynamic_ = T_Array< T >;
|
||||
|
||||
T_Union< T_Static_ , T_Dynamic_ > array_;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
public:
|
||||
M_TEMPLATE_POINTERS( T_Self );
|
||||
|
||||
T_AutoArray( ) noexcept;
|
||||
|
||||
T_AutoArray( T_Self const& source ) noexcept;
|
||||
T_Self& operator =( T_Self const& source ) noexcept;
|
||||
|
||||
T_AutoArray( T_Self&& source ) noexcept;
|
||||
T_Self& operator =( T_Self&& source ) noexcept;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
template< typename TP , uint32_t S , uint32_t G >
|
||||
friend void swap(
|
||||
T_AutoArray< TP , S , G >& lhs ,
|
||||
T_AutoArray< TP , S , G >& rhs ) noexcept;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
T_Self& clear( ) noexcept;
|
||||
T_Self& free( ) noexcept;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
uint32_t capacity( ) const noexcept;
|
||||
uint32_t size( ) const noexcept;
|
||||
constexpr uint32_t growth( ) const noexcept;
|
||||
bool isStatic( ) const noexcept;
|
||||
|
||||
T_Self& ensureCapacity( uint32_t capacity ) noexcept;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
T& operator[] ( uint32_t index ) noexcept;
|
||||
T const& operator[] ( uint32_t index ) const noexcept;
|
||||
|
||||
int32_t indexOf( T const& item ) const noexcept;
|
||||
bool contains( T const& item ) const noexcept;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
uint32_t add( T const& item ) noexcept;
|
||||
uint32_t add( T&& item ) noexcept;
|
||||
|
||||
template< typename... Args >
|
||||
T& addNew( Args&& ... args );
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
T_Self& addAll( T_Self const& other ) noexcept;
|
||||
T_Self& addAll( T_Self&& other ) noexcept;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
T_Self& operator<< ( T const& item ) noexcept;
|
||||
T_Self& operator<< ( T&& item ) noexcept;
|
||||
T_Self& operator<< ( T_Self const& other ) noexcept;
|
||||
T_Self& operator<< ( T_Self&& other ) noexcept;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
void insert( uint32_t index ,
|
||||
T const& item ) noexcept;
|
||||
void insert( uint32_t index ,
|
||||
T&& item ) noexcept;
|
||||
|
||||
template< typename... Args >
|
||||
T& insertNew( uint32_t index ,
|
||||
Args&& ... args );
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
void remove( uint32_t index ) noexcept;
|
||||
void removeSwap( uint32_t index ) noexcept;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
void sort( F_Comparator< T > cmp = T_Comparator< T >::compare ) noexcept;
|
||||
void sort( uint32_t first ,
|
||||
uint32_t items ,
|
||||
F_Comparator< T > cmp = T_Comparator< T >::compare ) noexcept;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
T_Self copyRange( uint32_t first ,
|
||||
uint32_t last = UINT32_MAX ) const noexcept;
|
||||
|
||||
T_Self moveRange( uint32_t first ,
|
||||
uint32_t last = UINT32_MAX ) noexcept;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
private:
|
||||
void convertToDynamic_( uint32_t capacity ) noexcept;
|
||||
|
||||
T_Static_& static_( ) noexcept;
|
||||
T_Static_ const& static_( ) const noexcept;
|
||||
T_Dynamic_& dynamic_( ) noexcept;
|
||||
T_Dynamic_ const& dynamic_( ) const noexcept;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
#endif // _H_EBCL_ARRAYS
|
||||
#include <lw/lib/inline/Arrays.hh>
|
169
include/ebcl/BinaryStreams.hh
Normal file
169
include/ebcl/BinaryStreams.hh
Normal file
|
@ -0,0 +1,169 @@
|
|||
/******************************************************************************/
|
||||
/* BINARY READER/WRITER FOR STREAMS *******************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
#include <lw/lib/Streams.hh>
|
||||
namespace lw {
|
||||
|
||||
|
||||
/*= OBJECT READER/WRITER TEMPLATES ===========================================*/
|
||||
/*
|
||||
* This pair of templates must be specialized to handle specific types.
|
||||
*/
|
||||
|
||||
struct T_BinaryReader;
|
||||
struct T_BinaryWriter;
|
||||
|
||||
template< typename T >
|
||||
struct T_ObjectReader
|
||||
{
|
||||
static T read( T_BinaryReader const& reader );
|
||||
};
|
||||
|
||||
|
||||
template< typename T >
|
||||
struct T_ObjectWriter
|
||||
{
|
||||
static void write( T_BinaryWriter const& writer , T const& string );
|
||||
};
|
||||
|
||||
|
||||
// Helper macros to declare and define readers and writers
|
||||
#define M_DECLARE_OBJECT_READER( Type ) \
|
||||
template< > \
|
||||
struct T_ObjectReader< Type > \
|
||||
{ \
|
||||
static Type read( T_BinaryReader const& ); \
|
||||
}
|
||||
|
||||
|
||||
#define M_DEFINE_OBJECT_READER( Type ) \
|
||||
Type T_ObjectReader< Type >::read( T_BinaryReader const & reader )
|
||||
|
||||
#define M_DECLARE_OBJECT_WRITER( Type ) \
|
||||
template< > \
|
||||
struct T_ObjectWriter< Type > \
|
||||
{ \
|
||||
static void write( T_BinaryWriter const& , \
|
||||
Type const& ); \
|
||||
}
|
||||
|
||||
|
||||
#define M_DEFINE_OBJECT_WRITER( Type ) \
|
||||
void T_ObjectWriter< Type >::write( T_BinaryWriter const & writer , \
|
||||
Type const & item )
|
||||
|
||||
|
||||
/*= READER ===================================================================*/
|
||||
|
||||
struct T_BinaryReader
|
||||
{
|
||||
private:
|
||||
A_InputStream& stream_;
|
||||
const E_Endian endian_;
|
||||
|
||||
public:
|
||||
T_BinaryReader( ) = delete;
|
||||
|
||||
explicit T_BinaryReader( A_InputStream& stream , E_Endian endian = E_Endian::NATIVE ) noexcept;
|
||||
|
||||
T_BinaryReader( T_BinaryReader const& other ) noexcept = delete;
|
||||
T_BinaryReader( T_BinaryReader&& other ) noexcept = delete;
|
||||
|
||||
A_InputStream& stream( ) const;
|
||||
E_Endian endian( ) const;
|
||||
|
||||
template< typename T >
|
||||
T readNumericNative( ) const;
|
||||
template< typename T >
|
||||
T readNumericLittleEndian( ) const;
|
||||
template< typename T >
|
||||
T readNumericBigEndian( ) const;
|
||||
|
||||
template< typename T >
|
||||
T read( ) const;
|
||||
|
||||
private:
|
||||
template<
|
||||
typename T ,
|
||||
bool IsNum = std::is_integral< T >::value
|
||||
|| std::is_floating_point< T >::value
|
||||
>
|
||||
struct T_Reader_ { };
|
||||
|
||||
|
||||
template< typename T >
|
||||
struct T_Reader_< T , true >
|
||||
{
|
||||
static T read( T_BinaryReader const& reader );
|
||||
};
|
||||
|
||||
|
||||
template< typename T >
|
||||
struct T_Reader_< T , false >
|
||||
{
|
||||
static T read( T_BinaryReader const& reader );
|
||||
};
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
/*= WRITER ===================================================================*/
|
||||
|
||||
struct T_BinaryWriter
|
||||
{
|
||||
private:
|
||||
A_OutputStream& stream_;
|
||||
const E_Endian endian_;
|
||||
|
||||
public:
|
||||
T_BinaryWriter( ) noexcept = delete;
|
||||
|
||||
explicit T_BinaryWriter( A_OutputStream& stream , E_Endian endian = E_Endian::NATIVE ) noexcept;
|
||||
|
||||
T_BinaryWriter( T_BinaryWriter const& other ) noexcept = delete;
|
||||
T_BinaryWriter( T_BinaryWriter&& other ) noexcept = delete;
|
||||
|
||||
A_OutputStream& stream( ) const;
|
||||
E_Endian endian( ) const;
|
||||
|
||||
template< typename T >
|
||||
void writeNumericNative( T value ) const;
|
||||
template< typename T >
|
||||
void writeNumericLittleEndian( T const& value ) const;
|
||||
template< typename T >
|
||||
void writeNumericBigEndian( T const& value ) const;
|
||||
|
||||
template< typename T >
|
||||
void write( T const& value ) const;
|
||||
|
||||
private:
|
||||
template<
|
||||
typename T ,
|
||||
bool IsNum = std::is_integral< T >::value
|
||||
|| std::is_floating_point< T >::value
|
||||
>
|
||||
struct T_Writer_ { };
|
||||
|
||||
|
||||
template< typename T >
|
||||
struct T_Writer_< T , true >
|
||||
{
|
||||
static void write( T_BinaryWriter const& writer , T value );
|
||||
};
|
||||
|
||||
|
||||
template< typename T >
|
||||
struct T_Writer_< T , false >
|
||||
{
|
||||
static void write( T_BinaryWriter const& writer , T const& value );
|
||||
};
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
#include <lw/lib/inline/BinaryStreams.hh>
|
104
include/ebcl/Buffers.hh
Normal file
104
include/ebcl/Buffers.hh
Normal file
|
@ -0,0 +1,104 @@
|
|||
/******************************************************************************/
|
||||
/* BUFFERS ********************************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
/* Buffers can be used to manipulate raw data. No constructors or destructors
|
||||
* will ever be called.
|
||||
*
|
||||
* Buffers are available in two flavors: fixed size (where the size of the
|
||||
* buffer is a template argument) and dynamic (where the size can be changed).
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <lw/lib/Externals.hh>
|
||||
namespace lw {
|
||||
|
||||
|
||||
/*============================================================================*/
|
||||
|
||||
class T_BufferBase
|
||||
{
|
||||
protected:
|
||||
uint8_t* data_;
|
||||
|
||||
T_BufferBase( ) = delete;
|
||||
explicit T_BufferBase( uint8_t* buffer ) noexcept;
|
||||
explicit T_BufferBase( size_t size );
|
||||
T_BufferBase( T_BufferBase&& source ) noexcept;
|
||||
|
||||
public:
|
||||
~T_BufferBase( );
|
||||
|
||||
friend void swap( T_BufferBase& lhs , T_BufferBase& rhs );
|
||||
|
||||
uint8_t * data( ) const;
|
||||
};
|
||||
|
||||
|
||||
/*============================================================================*/
|
||||
|
||||
template< size_t SIZE , class T >
|
||||
class T_FixedBuffer : public T_BufferBase
|
||||
{
|
||||
private:
|
||||
typedef T_FixedBuffer< SIZE , T > MyType_;
|
||||
static constexpr size_t BYTES_ = SIZE * sizeof( T );
|
||||
|
||||
public:
|
||||
T_FixedBuffer( );
|
||||
T_FixedBuffer( MyType_&& source ) noexcept;
|
||||
T_FixedBuffer( MyType_ const& source );
|
||||
|
||||
template< size_t SZ , typename TP >
|
||||
friend void swap( T_FixedBuffer< SZ , TP >& lhs , T_FixedBuffer< SZ , TP >& rhs ) noexcept;
|
||||
|
||||
MyType_& operator= ( MyType_ const& other );
|
||||
MyType_& operator= ( MyType_&& other ) noexcept;
|
||||
|
||||
size_t bytes( ) const;
|
||||
T& operator[] ( size_t index );
|
||||
T const& operator[] ( size_t index ) const;
|
||||
|
||||
MyType_& setAll( T const& value );
|
||||
};
|
||||
|
||||
|
||||
/*============================================================================*/
|
||||
|
||||
template< class T >
|
||||
class T_Buffer : public T_BufferBase
|
||||
{
|
||||
private:
|
||||
typedef T_Buffer< T > MyType_;
|
||||
|
||||
protected:
|
||||
size_t size_;
|
||||
|
||||
public:
|
||||
T_Buffer( ) noexcept;
|
||||
T_Buffer( size_t size );
|
||||
T_Buffer( T const* data , size_t size );
|
||||
|
||||
T_Buffer( MyType_ const& other );
|
||||
T_Buffer( MyType_&& other ) noexcept;
|
||||
|
||||
MyType_& operator= ( MyType_ const& other );
|
||||
MyType_& operator= ( MyType_&& other );
|
||||
|
||||
template< typename TP >
|
||||
friend void swap( T_Buffer< TP >& lhs , T_Buffer< TP >& rhs ) noexcept;
|
||||
|
||||
size_t size( ) const;
|
||||
size_t bytes( ) const;
|
||||
|
||||
T& operator[] ( size_t index );
|
||||
T const& operator[] ( size_t index ) const;
|
||||
|
||||
MyType_& resize( size_t newSize );
|
||||
MyType_& setAll( T const& value );
|
||||
MyType_& copyAll( T const* data );
|
||||
};
|
||||
|
||||
|
||||
} // namespace
|
||||
#include <lw/lib/inline/Buffers.hh>
|
25
include/ebcl/Config.hh
Normal file
25
include/ebcl/Config.hh
Normal file
|
@ -0,0 +1,25 @@
|
|||
/******************************************************************************/
|
||||
/* CONFIGURATION FOR THE BUILD ************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
#ifndef _H_EBCL_CONFIG
|
||||
#define _H_EBCL_CONFIG
|
||||
|
||||
|
||||
/*= DEBUGGING OPTIONS ========================================================*/
|
||||
|
||||
/* Disable memory allocators */
|
||||
//#define EBCL_CFG_NO_ALLOCATORS
|
||||
|
||||
|
||||
/*= TUNING ===================================================================*/
|
||||
|
||||
/* Pool allocator parameters for shared pointer references */
|
||||
#define EBCL_CFG_SHAREDPTR_REFPOOL_SIZE 512
|
||||
#define EBCL_CFG_SHAREDPTR_REFPOOL_MAXFREE 2
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
|
||||
#endif // _H_EBCL_CONFIG
|
48
include/ebcl/DynLib.hh
Normal file
48
include/ebcl/DynLib.hh
Normal file
|
@ -0,0 +1,48 @@
|
|||
/******************************************************************************/
|
||||
/* DYNAMIC LIBRARIES **********************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
#ifndef _H_EBCL_DYNLIB
|
||||
#define _H_EBCL_DYNLIB
|
||||
|
||||
#include <lw/lib/Strings.hh>
|
||||
#include <lw/lib/Utilities.hh>
|
||||
namespace lw {
|
||||
|
||||
|
||||
/*= DYNAMIC LIBRARY SUPPORT ==================================================*/
|
||||
|
||||
class T_DynLib : public A_PrivateImplementation
|
||||
{
|
||||
public:
|
||||
T_DynLib( ) = delete;
|
||||
T_DynLib( T_DynLib const& ) = delete;
|
||||
T_DynLib& operator =( T_DynLib const& ) = delete;
|
||||
|
||||
/* Initialise and set the name of the library to load */
|
||||
explicit T_DynLib( T_String const& name );
|
||||
explicit T_DynLib( char const* const name );
|
||||
|
||||
/* Load/unload the library */
|
||||
bool load( );
|
||||
void unload( );
|
||||
|
||||
/* Check whether the library has been loaded */
|
||||
bool isLoaded( ) const noexcept;
|
||||
/* Obtain the last error that was encoutered */
|
||||
T_String lastError( ) const noexcept;
|
||||
|
||||
/* Symbol access. The library MUST be loaded. */
|
||||
void* getRawSymbol( char const* name ) const noexcept;
|
||||
template< typename T >
|
||||
T* getPointer( char const* name ) const noexcept;
|
||||
template< typename T >
|
||||
std::function< T > getFunction(
|
||||
char const* name ) const noexcept;
|
||||
};
|
||||
M_CLASS_POINTERS( DynLib );
|
||||
|
||||
|
||||
} // namespace lw
|
||||
#endif // _H_EBCL_DYNLIB
|
||||
#include <lw/lib/inline/DynLib.hh>
|
19
include/ebcl/Externals.hh
Normal file
19
include/ebcl/Externals.hh
Normal file
|
@ -0,0 +1,19 @@
|
|||
/******************************************************************************/
|
||||
/* EXTERNAL HEADER FILES ******************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <cassert>
|
||||
#include <condition_variable>
|
||||
#include <functional>
|
||||
#include <malloc.h>
|
||||
#include <mutex>
|
||||
#include <new>
|
||||
#include <shared_mutex>
|
||||
#include <thread>
|
||||
#include <utility>
|
187
include/ebcl/Files.hh
Normal file
187
include/ebcl/Files.hh
Normal file
|
@ -0,0 +1,187 @@
|
|||
/******************************************************************************/
|
||||
/* FILES **********************************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
#ifndef _H_LW_LIB_FILES
|
||||
#define _H_LW_LIB_FILES
|
||||
#include <lw/lib/Streams.hh>
|
||||
#include <lw/lib/Strings.hh>
|
||||
namespace lw {
|
||||
|
||||
|
||||
/*= FILE ACCESS ==============================================================*/
|
||||
|
||||
enum class E_FileMode {
|
||||
READ_ONLY ,
|
||||
READ_WRITE ,
|
||||
OVERWRITE
|
||||
};
|
||||
|
||||
|
||||
class T_File final
|
||||
{
|
||||
private:
|
||||
T_String path_;
|
||||
E_FileMode mode_;
|
||||
FILE* file_;
|
||||
size_t size_ , pos_;
|
||||
|
||||
T_File( );
|
||||
|
||||
public:
|
||||
// Construct from a file path. Does not open the file.
|
||||
T_File( T_String const& path , E_FileMode mode );
|
||||
|
||||
// Move constructor and assignment
|
||||
T_File( T_File&& other ) noexcept;
|
||||
T_File& operator= ( T_File&& other ) noexcept;
|
||||
|
||||
// Disabled copy constructor / assignment operator
|
||||
T_File( T_File const& ) = delete;
|
||||
T_File& operator= ( T_File const& ) = delete;
|
||||
|
||||
// Destructor - must close the file if it is open
|
||||
~T_File( );
|
||||
|
||||
// Swapping
|
||||
friend void swap( T_File& lhs , T_File& rhs ) noexcept;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
// Get the path
|
||||
T_String const& path( ) const noexcept;
|
||||
// Get the mode
|
||||
E_FileMode mode( ) const noexcept;
|
||||
|
||||
// Open the file. Throws an exception if that fails. Will be called
|
||||
// automatically by most methods.
|
||||
virtual void open( );
|
||||
|
||||
// Close the file. Never throws, even if the file's already closed or
|
||||
// if closing fails.
|
||||
void close( ) noexcept;
|
||||
|
||||
// Check if the file is open
|
||||
bool isOpen( ) const noexcept;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
// Get the file's size
|
||||
size_t size( ) const noexcept;
|
||||
// Get the current file position
|
||||
size_t position( ) const noexcept;
|
||||
|
||||
// Set the position relative to the start or the end of the file
|
||||
void position( size_t position , bool fromEnd = false );
|
||||
// Set the position relative to the current position
|
||||
void move( ssize_t offset );
|
||||
|
||||
// Read/write methods
|
||||
size_t read( void* data , size_t size );
|
||||
size_t write( void const* data , size_t size );
|
||||
|
||||
// Flushing
|
||||
void flush( );
|
||||
};
|
||||
|
||||
|
||||
M_CLASS_POINTERS( File );
|
||||
|
||||
|
||||
/*= FILE STREAMS =============================================================*/
|
||||
|
||||
class T_FileInputStream final : public A_InputStream
|
||||
{
|
||||
protected:
|
||||
RP_File fileRaw_;
|
||||
OP_File fileOwned_;
|
||||
size_t start_;
|
||||
|
||||
public:
|
||||
T_FileInputStream( ) = delete;
|
||||
|
||||
// Construct from a file instance
|
||||
explicit T_FileInputStream( T_File& file , ssize_t offset = 0 ,
|
||||
size_t limit = SIZE_MAX );
|
||||
// Construct from a file owning pointer
|
||||
explicit T_FileInputStream( OP_File&& file , ssize_t offset = 0 ,
|
||||
size_t limit = SIZE_MAX );
|
||||
|
||||
// Copy constructor and assignment
|
||||
T_FileInputStream( T_FileInputStream const& );
|
||||
T_FileInputStream& operator= ( T_FileInputStream const& );
|
||||
|
||||
// Move constructor and assignment
|
||||
T_FileInputStream( T_FileInputStream&& other ) noexcept;
|
||||
T_FileInputStream& operator= ( T_FileInputStream&& other ) noexcept;
|
||||
|
||||
// Swapping
|
||||
void swap( T_FileInputStream& rhs ) noexcept;
|
||||
|
||||
// Get the file
|
||||
T_File& file( ) const noexcept;
|
||||
// Get the start offset
|
||||
size_t offset( ) const noexcept;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
size_t read( void* data , size_t size ) override;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
private:
|
||||
void init( ssize_t offset , size_t limit );
|
||||
};
|
||||
|
||||
|
||||
M_CLASS_POINTERS( FileInputStream );
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
class T_FileOutputStream final : public A_OutputStream
|
||||
{
|
||||
protected:
|
||||
RP_File fileRaw_;
|
||||
OP_File fileOwned_;
|
||||
size_t start_;
|
||||
|
||||
public:
|
||||
T_FileOutputStream( ) = delete;
|
||||
|
||||
// Construct from a file.
|
||||
explicit T_FileOutputStream( T_File& file , ssize_t offset = 0 );
|
||||
// Construct from a file owning pointer
|
||||
explicit T_FileOutputStream( OP_File&& file , ssize_t offset = 0 );
|
||||
|
||||
// Copy constructor and assignment
|
||||
T_FileOutputStream( T_FileOutputStream const& );
|
||||
T_FileOutputStream& operator= ( T_FileOutputStream const& );
|
||||
|
||||
// Move constructor and assignment
|
||||
T_FileOutputStream( T_FileOutputStream&& other ) noexcept;
|
||||
T_FileOutputStream& operator= ( T_FileOutputStream&& other ) noexcept;
|
||||
|
||||
// Swapping
|
||||
void swap( T_FileOutputStream& rhs ) noexcept;
|
||||
|
||||
// Get the file
|
||||
T_File& file( ) const noexcept;
|
||||
// Get the start offset
|
||||
size_t offset( ) const noexcept;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
size_t write( void const* data , size_t size ) override;
|
||||
void flush( ) override;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
private:
|
||||
void init( ssize_t offset );
|
||||
};
|
||||
|
||||
|
||||
M_CLASS_POINTERS( FileOutputStream );
|
||||
|
||||
|
||||
}
|
||||
#endif // _H_LW_LIB_FILES
|
||||
#include <lw/lib/inline/Files.hh>
|
30
include/ebcl/GameLoop.hh
Normal file
30
include/ebcl/GameLoop.hh
Normal file
|
@ -0,0 +1,30 @@
|
|||
/******************************************************************************/
|
||||
/* GAME'S MAIN LOOP ***********************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
#ifndef _H_LW_LIB_GAMELOOP
|
||||
#define _H_LW_LIB_GAMELOOP
|
||||
#include <lw/lib/Messages.hh>
|
||||
namespace lw {
|
||||
|
||||
|
||||
/*= GAME LOOP ================================================================*/
|
||||
|
||||
class T_GameLoop : public A_PrivateImplementation
|
||||
{
|
||||
public:
|
||||
T_GameLoop( ) noexcept;
|
||||
T_GameLoop( T_GameLoop const& ) = delete;
|
||||
T_GameLoop( T_GameLoop&& ) = delete;
|
||||
|
||||
bool active( ) const noexcept;
|
||||
void start( ) noexcept;
|
||||
void shutdown( ) noexcept;
|
||||
|
||||
void putMessage( T_UIMessage&& message ) noexcept;
|
||||
};
|
||||
M_CLASS_POINTERS( GameLoop );
|
||||
|
||||
|
||||
}
|
||||
#endif // _H_LW_LIB_GAMELOOP
|
79
include/ebcl/HashIndex.hh
Normal file
79
include/ebcl/HashIndex.hh
Normal file
|
@ -0,0 +1,79 @@
|
|||
/******************************************************************************/
|
||||
/* HASH INDEX *****************************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
#include <lw/lib/Externals.hh>
|
||||
#include <lw/lib/Pointers.hh>
|
||||
namespace lw {
|
||||
|
||||
|
||||
/*
|
||||
* This is based on http://glampert.com/2016/05-04/dissecting-idhashindex,
|
||||
* which explains how the hash tables in idTech4 work. Not looking at the code
|
||||
* to avoid GPL-related issues, so my implementation will probably suck.
|
||||
*
|
||||
* Unlike the original thing, this version considers that:
|
||||
* - all additions are made at the end of the array (and therefore at the
|
||||
* end of the index),
|
||||
* - erasing is done by swapping the element being erased and the last
|
||||
* element of the index.
|
||||
*
|
||||
* It also keeps track of the hash key for a given index in order to make
|
||||
* erasing easier.
|
||||
*/
|
||||
|
||||
class T_HashIndex
|
||||
{
|
||||
public:
|
||||
static constexpr uint32_t INVALID_INDEX = 0xffffffff;
|
||||
static constexpr uint32_t DEFAULT_SIZE = 1024;
|
||||
static constexpr uint32_t DEFAULT_GROWTH = 1024;
|
||||
|
||||
private:
|
||||
static uint32_t invalidIndex_;
|
||||
|
||||
uint32_t hashSize_;
|
||||
uint32_t* hash_;
|
||||
|
||||
uint32_t indexSize_;
|
||||
uint32_t indexGrowth_;
|
||||
uint32_t indexUsed_;
|
||||
uint32_t* index_;
|
||||
uint32_t* indexReverse_;
|
||||
|
||||
uint32_t hashMask_;
|
||||
uint32_t lookupMask_;
|
||||
|
||||
void enlargeIndex( uint32_t needed );
|
||||
void allocateIfNecessary( );
|
||||
|
||||
public:
|
||||
T_HashIndex( ) noexcept;
|
||||
T_HashIndex( uint32_t hashSize , uint32_t indexSize , uint32_t growth = DEFAULT_GROWTH ) noexcept;
|
||||
|
||||
T_HashIndex( T_HashIndex const& source );
|
||||
T_HashIndex( T_HashIndex&& source ) noexcept;
|
||||
|
||||
~T_HashIndex( );
|
||||
|
||||
T_HashIndex& operator =( T_HashIndex const& other );
|
||||
T_HashIndex& operator =( T_HashIndex&& other ) noexcept;
|
||||
|
||||
friend void swap( T_HashIndex& lhs , T_HashIndex& rhs ) noexcept;
|
||||
|
||||
void free( );
|
||||
void clear( );
|
||||
|
||||
void add( uint32_t key );
|
||||
void remove( uint32_t index );
|
||||
|
||||
uint32_t first( uint32_t key ) const;
|
||||
uint32_t next( uint32_t index ) const;
|
||||
};
|
||||
M_CLASS_POINTERS( HashIndex );
|
||||
void swap( T_HashIndex& lhs , T_HashIndex& rhs ) noexcept;
|
||||
|
||||
|
||||
} // namespace
|
||||
#include <lw/lib/inline/HashIndex.hh>
|
203
include/ebcl/HashTables.hh
Normal file
203
include/ebcl/HashTables.hh
Normal file
|
@ -0,0 +1,203 @@
|
|||
/******************************************************************************/
|
||||
/* HASH TABLES ****************************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
#ifndef _H_LW_LIB_HASHTABLES
|
||||
#define _H_LW_LIB_HASHTABLES
|
||||
#include <lw/lib/Arrays.hh>
|
||||
#include <lw/lib/HashIndex.hh>
|
||||
namespace lw {
|
||||
|
||||
|
||||
// F_KeyMatch< K > - Equality check function for keys
|
||||
template< typename K >
|
||||
using F_KeyMatch = std::function< bool( K const& , K const& ) >;
|
||||
|
||||
|
||||
// T_DefaultKeyMatch< K > - Default equality check for keys
|
||||
template< typename K >
|
||||
struct T_DefaultKeyMatch
|
||||
{
|
||||
static bool keysMatch( K const& , K const& );
|
||||
};
|
||||
|
||||
|
||||
/*= KEY / VALUE TABLE ========================================================*/
|
||||
|
||||
/*
|
||||
* T_KeyValueTable - Hash table with separate key and value storage.
|
||||
* This class is meant to be used when data with unrelated types need to be
|
||||
* associated with each other, e.g. string -> int mapping.
|
||||
*/
|
||||
|
||||
template<
|
||||
typename KeyType ,
|
||||
typename ValueType
|
||||
>
|
||||
class T_KeyValueTable
|
||||
{
|
||||
public:
|
||||
typedef F_KeyMatch< KeyType > F_Match;
|
||||
|
||||
private:
|
||||
typedef T_KeyValueTable< KeyType , ValueType > MyType_;
|
||||
|
||||
F_Match match_;
|
||||
T_HashIndex index_;
|
||||
T_Array< KeyType > keys_;
|
||||
T_Array< ValueType > values_;
|
||||
|
||||
public:
|
||||
M_TEMPLATE_POINTERS( MyType_ );
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
T_KeyValueTable( uint32_t initialSize = T_HashIndex::DEFAULT_SIZE ,
|
||||
uint32_t hashSize = T_HashIndex::DEFAULT_SIZE ,
|
||||
uint32_t growth = T_HashIndex::DEFAULT_GROWTH ,
|
||||
F_Match match = T_DefaultKeyMatch< KeyType >::keysMatch );
|
||||
|
||||
template< typename K , typename T >
|
||||
friend void swap( T_KeyValueTable< K , T >& lhs , T_KeyValueTable< K , T >& rhs );
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
// Add a new value (fails if key already present)
|
||||
template<
|
||||
typename A , typename B ,
|
||||
T_EnableIfTypesMatch< KeyType , A > = true ,
|
||||
T_EnableIfTypesMatch< ValueType , B > = true
|
||||
> bool add( A&& k , B&& v );
|
||||
|
||||
// Update an existing value (fails if key not present)
|
||||
template<
|
||||
typename A ,
|
||||
T_EnableIfTypesMatch< ValueType , A > = true
|
||||
> bool update( KeyType const& k , A&& v );
|
||||
|
||||
// Add or modify a key/value pair
|
||||
template<
|
||||
typename A , typename B ,
|
||||
T_EnableIfTypesMatch< KeyType , A > = true ,
|
||||
T_EnableIfTypesMatch< ValueType , B > = true
|
||||
> void set( A&& k , B&& v );
|
||||
|
||||
// Remove a key/value pair
|
||||
bool remove( KeyType const& k );
|
||||
|
||||
void clear( );
|
||||
void free( );
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
uint32_t size( ) const;
|
||||
T_Array< KeyType > const& keys( ) const;
|
||||
T_Array< ValueType > const& values( ) const;
|
||||
uint32_t indexOf( KeyType const& k ) const;
|
||||
bool contains( KeyType const& k ) const;
|
||||
|
||||
ValueType const * get( KeyType const& k ) const;
|
||||
ValueType * get( KeyType const& k );
|
||||
|
||||
ValueType& operator[] ( uint32_t index );
|
||||
ValueType const& operator[] ( uint32_t index ) const;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
private:
|
||||
uint32_t find( KeyType const& k , uint32_t hash ) const;
|
||||
};
|
||||
|
||||
template< typename K , typename T >
|
||||
void swap( T_KeyValueTable< K , T >& lhs , T_KeyValueTable< K , T >& rhs );
|
||||
|
||||
|
||||
/*= OBJECT TABLE =============================================================*/
|
||||
|
||||
/*
|
||||
* This class is meant to be used to store objects that somehow contain their
|
||||
* own keys. Of course, modifying one of these objects' key after it's been
|
||||
* inserted will cause major SNAFU's.
|
||||
*/
|
||||
|
||||
template<
|
||||
typename KeyType ,
|
||||
typename ValueType
|
||||
>
|
||||
class T_ObjectTable
|
||||
{
|
||||
public:
|
||||
typedef F_KeyMatch< KeyType > F_Match;
|
||||
typedef std::function< KeyType( ValueType const& ) > F_GetKey;
|
||||
|
||||
private:
|
||||
typedef T_ObjectTable< KeyType , ValueType > MyType_;
|
||||
|
||||
F_Match match_;
|
||||
F_GetKey keyGetter_;
|
||||
T_HashIndex index_;
|
||||
T_Array< ValueType > values_;
|
||||
|
||||
public:
|
||||
M_TEMPLATE_POINTERS( MyType_ );
|
||||
T_ObjectTable( ) = delete;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
T_ObjectTable( F_GetKey keyGetter , uint32_t initialSize = T_HashIndex::DEFAULT_SIZE ,
|
||||
uint32_t hashSize = T_HashIndex::DEFAULT_SIZE ,
|
||||
uint32_t growth = T_HashIndex::DEFAULT_GROWTH ,
|
||||
F_Match match = T_DefaultKeyMatch< KeyType >::keysMatch );
|
||||
|
||||
template< typename K , typename T >
|
||||
friend void swap( T_ObjectTable< K , T >& lhs , T_ObjectTable< K , T >& rhs );
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
template<
|
||||
typename A ,
|
||||
T_EnableIfTypesMatch< ValueType , A > = true
|
||||
> bool add( A&& v );
|
||||
|
||||
template<
|
||||
typename A ,
|
||||
T_EnableIfTypesMatch< ValueType , A > = true
|
||||
> bool update( A&& v );
|
||||
|
||||
template<
|
||||
typename A ,
|
||||
T_EnableIfTypesMatch< ValueType , A > = true
|
||||
> void set( A&& v );
|
||||
|
||||
bool remove( KeyType const& k );
|
||||
|
||||
void clear( );
|
||||
void free( );
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
uint32_t size( ) const;
|
||||
uint32_t indexOf( KeyType const& k ) const;
|
||||
bool contains( KeyType const& k ) const;
|
||||
T_Array< KeyType > keys( ) const;
|
||||
T_Array< ValueType > const& values( ) const;
|
||||
|
||||
ValueType const * get( KeyType const& k ) const;
|
||||
ValueType * get( KeyType const& k );
|
||||
|
||||
ValueType& operator[] ( uint32_t index );
|
||||
ValueType const& operator[] ( uint32_t index ) const;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
private:
|
||||
uint32_t find( KeyType const& k , uint32_t hash ) const;
|
||||
};
|
||||
|
||||
template< typename K , typename T >
|
||||
void swap( T_ObjectTable< K , T >& lhs , T_ObjectTable< K , T >& rhs );
|
||||
|
||||
|
||||
}
|
||||
#endif // _H_LW_LIB_HASHTABLES
|
||||
#include <lw/lib/inline/HashTables.hh>
|
62
include/ebcl/MemoryStreams.hh
Normal file
62
include/ebcl/MemoryStreams.hh
Normal file
|
@ -0,0 +1,62 @@
|
|||
/******************************************************************************/
|
||||
/* MEMORY STREAMS *************************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
#include <lw/lib/Streams.hh>
|
||||
namespace lw {
|
||||
|
||||
|
||||
class T_MemoryInputStream final : public A_InputStream
|
||||
{
|
||||
private:
|
||||
uint8_t const* buffer_;
|
||||
|
||||
public:
|
||||
T_MemoryInputStream( ) = delete;
|
||||
T_MemoryInputStream( void const* buffer , size_t size );
|
||||
|
||||
T_MemoryInputStream( T_MemoryInputStream const& other ) noexcept;
|
||||
friend void swap( T_MemoryInputStream& lhs , T_MemoryInputStream& rhs ) noexcept;
|
||||
|
||||
T_MemoryInputStream& operator= ( T_MemoryInputStream const& other ) noexcept;
|
||||
|
||||
template< int S , typename T >
|
||||
explicit T_MemoryInputStream( T_FixedBuffer< S , T > const& buffer );
|
||||
|
||||
template< typename T >
|
||||
explicit T_MemoryInputStream( T_Buffer< T > const& buffer );
|
||||
|
||||
size_t read( void* data , size_t size ) override;
|
||||
};
|
||||
M_CLASS_POINTERS( MemoryInputStream );
|
||||
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
class T_MemoryOutputStream final : public A_OutputStream
|
||||
{
|
||||
typedef std::function< uint8_t*( uint8_t* , size_t ) > F_Resizer;
|
||||
|
||||
private:
|
||||
uint8_t* buffer_;
|
||||
F_Resizer resizer_;
|
||||
|
||||
public:
|
||||
T_MemoryOutputStream( ) = delete;
|
||||
|
||||
T_MemoryOutputStream( void* buffer , size_t size , F_Resizer resizer = nullptr );
|
||||
|
||||
template< int S , typename T >
|
||||
explicit T_MemoryOutputStream( T_FixedBuffer< S , T >& buffer );
|
||||
|
||||
template< typename T >
|
||||
explicit T_MemoryOutputStream( T_Buffer< T >& buffer );
|
||||
|
||||
size_t write( void const* data , size_t size ) override;
|
||||
};
|
||||
M_CLASS_POINTERS( MemoryOutputStream );
|
||||
|
||||
|
||||
} // namespace
|
||||
#include <lw/lib/inline/MemoryStreams.hh>
|
282
include/ebcl/Messages.hh
Normal file
282
include/ebcl/Messages.hh
Normal file
|
@ -0,0 +1,282 @@
|
|||
/******************************************************************************/
|
||||
/* UI<=>GAME MESSAGES *********************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
#ifndef _H_LW_LIB_MESSAGES
|
||||
#define _H_LW_LIB_MESSAGES
|
||||
#include <lw/lib/Strings.hh>
|
||||
#include <lw/lib/Types.hh>
|
||||
namespace lw {
|
||||
|
||||
|
||||
/*= VIEWS ====================================================================*/
|
||||
|
||||
/* Empty abstract class that serves as a base for game views */
|
||||
class A_GameView
|
||||
{
|
||||
public:
|
||||
virtual ~A_GameView( ) = 0;
|
||||
};
|
||||
M_ABSTRACT_POINTERS( GameView );
|
||||
|
||||
|
||||
/* Abstract class for a view builder
|
||||
*
|
||||
* User interfaces need to access the game's data in order to display it. View
|
||||
* builders provide a way to do that; they are passed to the game's main loop
|
||||
* by the UI. Once set, they will be used to create and update view data.
|
||||
*/
|
||||
class A_ViewBuilder
|
||||
{
|
||||
public:
|
||||
virtual ~A_ViewBuilder( ) = 0;
|
||||
|
||||
/* This method creates a view instance. It is called twice when the
|
||||
* builder is installed, in order to create a "double buffer" - one
|
||||
* view can be sent to the UI while the other is being updated.
|
||||
*/
|
||||
virtual OP_GameView createView( ) = 0;
|
||||
|
||||
/* This method is responsible for updating a view instance. */
|
||||
virtual void updateView( OP_GameView view ) = 0;
|
||||
};
|
||||
M_ABSTRACT_POINTERS( ViewBuilder );
|
||||
|
||||
|
||||
/*= GAME STATE ===============================================================*/
|
||||
|
||||
/* State of the main loop */
|
||||
enum class E_GameState {
|
||||
NO_GAME , // No game loaded
|
||||
GAME_PAUSED , // Game is loaded but not running
|
||||
GAME_SLOW , // Game is running at slow speed
|
||||
GAME_NORMAL , // Game is running at normal speed
|
||||
GAME_FAST // Game is running at high speed
|
||||
};
|
||||
M_LSHIFT_OP( T_StringBuilder , E_GameState );
|
||||
|
||||
|
||||
/*= PROGRESS INFORMATION =====================================================*/
|
||||
|
||||
/* Progress information for long operations - part (main or sub) */
|
||||
class T_ProgressInfoPart
|
||||
{
|
||||
private:
|
||||
T_String text_;
|
||||
uint32_t progress_;
|
||||
uint32_t total_;
|
||||
|
||||
public:
|
||||
T_ProgressInfoPart( ) = delete;
|
||||
T_ProgressInfoPart( T_String text , uint32_t progress , uint32_t total ) noexcept;
|
||||
T_ProgressInfoPart( T_ProgressInfoPart&& other ) noexcept;
|
||||
T_ProgressInfoPart( T_ProgressInfoPart const& other );
|
||||
|
||||
T_String const& text( ) const noexcept;
|
||||
uint32_t progress( ) const noexcept;
|
||||
uint32_t total( ) const noexcept;
|
||||
};
|
||||
|
||||
/* Progress information for long operations - main */
|
||||
class T_ProgressInfo
|
||||
{
|
||||
private:
|
||||
T_ProgressInfoPart main_;
|
||||
T_Optional< T_ProgressInfoPart > sub_;
|
||||
|
||||
public:
|
||||
T_ProgressInfo( ) = delete;
|
||||
T_ProgressInfo( T_String text , uint32_t progress , uint32_t total ) noexcept;
|
||||
explicit T_ProgressInfo( T_ProgressInfoPart main ) noexcept;
|
||||
T_ProgressInfo( T_ProgressInfoPart main , T_ProgressInfoPart sub ) noexcept;
|
||||
T_ProgressInfo( T_ProgressInfoPart main ,
|
||||
T_String sText , uint32_t sProgress , uint32_t sTotal ) noexcept;
|
||||
T_ProgressInfo( T_String text , uint32_t progress , uint32_t total ,
|
||||
T_String sText , uint32_t sProgress , uint32_t sTotal ) noexcept;
|
||||
T_ProgressInfo( T_ProgressInfo&& other ) noexcept;
|
||||
T_ProgressInfo( T_ProgressInfo const& other ) = delete;
|
||||
|
||||
T_ProgressInfoPart const& main( ) const noexcept;
|
||||
bool hasSub( ) const noexcept;
|
||||
T_ProgressInfoPart const& sub( ) const;
|
||||
};
|
||||
M_CLASS_POINTERS( ProgressInfo );
|
||||
|
||||
|
||||
/*= MESSAGES =================================================================*/
|
||||
|
||||
/* Types of messages sent by the UI to the game */
|
||||
enum class E_GameUIMessage {
|
||||
/* Create a new game
|
||||
* Data: XXX
|
||||
*/
|
||||
NEW ,
|
||||
/* Load an existing game
|
||||
* Data: uint32_t - game identifier
|
||||
*/
|
||||
LOAD ,
|
||||
/* Save the current game
|
||||
* Data: none
|
||||
*/
|
||||
SAVE ,
|
||||
/* Quit the current game
|
||||
* Data: none
|
||||
*/
|
||||
STOP ,
|
||||
/* Quit current game (if any) the exit the main loop
|
||||
* Data: none
|
||||
*/
|
||||
QUIT ,
|
||||
|
||||
/* Abort the current operation
|
||||
* Data: none
|
||||
*/
|
||||
ABORT ,
|
||||
|
||||
/* Delete a saved game
|
||||
* Data: uint32_t - game identifier
|
||||
*/
|
||||
DELETE ,
|
||||
/* Copy or rename a saved game
|
||||
* Data: XXX
|
||||
*/
|
||||
COPY_OR_RENAME ,
|
||||
|
||||
/* Set the current game's speed
|
||||
* Data: E_GameState (but NO_GAME will be ignored)
|
||||
*/
|
||||
SET_SPEED ,
|
||||
/* Execute computation steps
|
||||
* Data: XXX
|
||||
*/
|
||||
STEPS ,
|
||||
/* Set a view builder
|
||||
* Data: XXX
|
||||
*/
|
||||
SET_VIEW ,
|
||||
/* Indicate that a view has been displayed
|
||||
* Data: T_String - identifier of the view
|
||||
*/
|
||||
VIEW_DISPLAYED ,
|
||||
/* Send a query to the game
|
||||
* Data: XXX
|
||||
*/
|
||||
QUERY ,
|
||||
/* Send a command to the game
|
||||
* Data: XXX
|
||||
*/
|
||||
COMMAND
|
||||
};
|
||||
M_LSHIFT_OP( T_StringBuilder , E_GameUIMessage );
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
/* Types of messages sent by the main loop to the UI */
|
||||
enum class E_GameLoopMessage {
|
||||
/* Main loop exiting
|
||||
* Data: none
|
||||
*/
|
||||
TERMINATED ,
|
||||
/* Progress information
|
||||
* Data: T_ProgressInfo
|
||||
*/
|
||||
PROGRESS ,
|
||||
/* Operation completed
|
||||
* Data: none
|
||||
*/
|
||||
DONE ,
|
||||
/* State changed
|
||||
* Data: E_GameState
|
||||
*/
|
||||
STATE_CHANGED ,
|
||||
/* Indicate that a view is available
|
||||
* Data: XXX
|
||||
*/
|
||||
VIEW_AVAILABLE ,
|
||||
/* Query response
|
||||
* Data: XXX
|
||||
*/
|
||||
QUERY_RESPONSE ,
|
||||
/* Command execution - success
|
||||
* Data: none
|
||||
*/
|
||||
COMMAND_OK ,
|
||||
/* Command execution - syntax error
|
||||
* Data: XXX
|
||||
*/
|
||||
COMMAND_SYNTAX ,
|
||||
/* Command execution - error
|
||||
* Data: XXX
|
||||
*/
|
||||
COMMAND_ERROR ,
|
||||
};
|
||||
M_LSHIFT_OP( T_StringBuilder , E_GameLoopMessage );
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
/* Types for message data */
|
||||
using T_GameUIMessageData = T_Union<
|
||||
uint32_t ,
|
||||
T_String ,
|
||||
E_GameState
|
||||
>;
|
||||
using T_GameLoopMessageData = T_Union<
|
||||
T_ProgressInfo ,
|
||||
E_GameState
|
||||
>;
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
/* Message direction */
|
||||
enum class E_MessageDirection {
|
||||
FROM_UI_TO_GAME ,
|
||||
FROM_GAME_TO_UI
|
||||
};
|
||||
|
||||
/* Message class template, can be used for both directions */
|
||||
template<
|
||||
E_MessageDirection Direction ,
|
||||
typename EType = std::conditional_t<
|
||||
Direction == E_MessageDirection::FROM_UI_TO_GAME ,
|
||||
E_GameUIMessage , E_GameLoopMessage > ,
|
||||
typename DType = std::conditional_t<
|
||||
Direction == E_MessageDirection::FROM_UI_TO_GAME ,
|
||||
T_GameUIMessageData , T_GameLoopMessageData >
|
||||
>
|
||||
class T_GameMessage
|
||||
{
|
||||
public:
|
||||
using T_Type = EType;
|
||||
using T_Data = DType;
|
||||
|
||||
private:
|
||||
using T_Self_ = T_GameMessage< Direction >;
|
||||
T_Optional< T_Type > type_;
|
||||
T_Optional< T_Data > data_;
|
||||
|
||||
public:
|
||||
constexpr T_GameMessage( ) noexcept;
|
||||
constexpr T_GameMessage( T_Type type ) noexcept;
|
||||
T_GameMessage( T_Type type , T_Data data ) noexcept;
|
||||
T_GameMessage( T_Self_ const& ) = delete;
|
||||
T_GameMessage( T_Self_&& other ) noexcept;
|
||||
|
||||
T_Self_& operator =( T_Self_ const& ) = delete;
|
||||
T_Self_& operator =( T_Self_&& other ) noexcept;
|
||||
|
||||
constexpr bool hasMessage( ) const noexcept;
|
||||
constexpr T_Type type( ) const noexcept;
|
||||
|
||||
template< typename T >
|
||||
constexpr T const& data( ) const;
|
||||
};
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
using T_UIMessage = T_GameMessage< E_MessageDirection::FROM_UI_TO_GAME >;
|
||||
using T_LoopMessage = T_GameMessage< E_MessageDirection::FROM_GAME_TO_UI >;
|
||||
|
||||
|
||||
} // namespace lw
|
||||
#endif // _H_LW_LIB_MESSAGES
|
||||
#include <lw/lib/inline/Messages.hh>
|
247
include/ebcl/Mods.hh
Normal file
247
include/ebcl/Mods.hh
Normal file
|
@ -0,0 +1,247 @@
|
|||
/******************************************************************************/
|
||||
/* MODDING SYSTEM *************************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
#ifndef _H_LW_LIB_MODS
|
||||
#define _H_LW_LIB_MODS
|
||||
#include <lw/lib/Log.hh>
|
||||
#include <lw/lib/ModInterface.hh>
|
||||
namespace lw {
|
||||
|
||||
|
||||
/*= MOD INFORMATION ==========================================================*/
|
||||
|
||||
/* Mod identifier (name + version) */
|
||||
struct T_ModIdentifier {
|
||||
T_String name;
|
||||
uint32_t version; // Main version number used for dependencies
|
||||
|
||||
bool operator ==( T_ModIdentifier const& other ) const noexcept;
|
||||
bool operator !=( T_ModIdentifier const& other ) const noexcept;
|
||||
|
||||
int compare( T_ModIdentifier const& other ) const noexcept;
|
||||
};
|
||||
M_CLASS_POINTERS( ModIdentifier );
|
||||
M_DECLARE_HASH( T_ModIdentifier );
|
||||
M_DECLARE_COMPARATOR( T_ModIdentifier );
|
||||
M_LSHIFT_OP( T_StringBuilder , T_ModIdentifier const& );
|
||||
|
||||
/* Types of mods */
|
||||
enum class E_ModType {
|
||||
DATA , // This mod consists of data only
|
||||
NATIVE , // This mod consists of native code
|
||||
UI , // This mod is an user interface
|
||||
};
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
/* Mod information record */
|
||||
struct T_ModInfo
|
||||
{
|
||||
T_String path;
|
||||
E_ModType type;
|
||||
|
||||
/* Mod name, version and revision (the latter is for changes that don't
|
||||
* affect the interface).
|
||||
*/
|
||||
T_ModIdentifier identifier;
|
||||
uint32_t revision;
|
||||
|
||||
/* Required library version number */
|
||||
uint32_t libVersion;
|
||||
|
||||
/* List of dependencies */
|
||||
T_Array< T_ModIdentifier > modDeps;
|
||||
|
||||
/* Is this mod an user interface mod? */
|
||||
bool isUserInterface( ) const noexcept;
|
||||
};
|
||||
M_CLASS_POINTERS( ModInfo );
|
||||
M_LSHIFT_OP( T_StringBuilder , T_ModInfo const& );
|
||||
|
||||
|
||||
/*= MODS MANAGER CONFIGURATION ===============================================*/
|
||||
|
||||
/* Loading mode for a mod */
|
||||
enum class E_ModMode {
|
||||
EXCLUDE , // Never load this mod
|
||||
AUTO , // Load the most appropriate version of the mod
|
||||
VERSION , // Load a specific version of the mod, fails
|
||||
// if the mod in the specified version is not
|
||||
// present
|
||||
REQUIRE // Require that the specified mod be present
|
||||
|
||||
// Note that both VERSION and REQUIRE can apply to an UI-specific mod;
|
||||
// while the mod will not be loaded if the corresponding UI isn't,
|
||||
// its presence will still be required.
|
||||
};
|
||||
|
||||
/* Mods manager configuration */
|
||||
class T_ModsManagerConfiguration : public A_PrivateImplementation
|
||||
{
|
||||
public:
|
||||
T_ModsManagerConfiguration( ) noexcept;
|
||||
|
||||
T_ModsManagerConfiguration(
|
||||
T_ModsManagerConfiguration const& ) = delete;
|
||||
T_ModsManagerConfiguration& operator =(
|
||||
T_ModsManagerConfiguration const& ) = delete;
|
||||
|
||||
T_ModsManagerConfiguration(
|
||||
T_ModsManagerConfiguration&& ) noexcept;
|
||||
T_ModsManagerConfiguration& operator =(
|
||||
T_ModsManagerConfiguration&& other ) noexcept;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
/* Set a mod configuration entry */
|
||||
void setAuto( T_String const& name ) noexcept;
|
||||
void setRequired( T_String const& name ) noexcept;
|
||||
void setExcluded( T_String const& name ) noexcept;
|
||||
void setVersion( T_String const& name ,
|
||||
uint32_t version ) noexcept;
|
||||
void setVersion( T_String const& name ,
|
||||
uint32_t version ,
|
||||
uint32_t revision ) noexcept;
|
||||
|
||||
/* Query mod configuration */
|
||||
T_Array< T_String > configured( ) const noexcept;
|
||||
E_ModMode modeFor( T_String const& name ) const noexcept;
|
||||
uint32_t requiredVersion( T_String const& name ) const noexcept;
|
||||
T_Optional< uint32_t > requiredRevision(
|
||||
T_String const& name ) const noexcept;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
/* Set or clear an UI preference */
|
||||
void setUIPreference(
|
||||
T_String const& name ,
|
||||
int32_t weight ) noexcept;
|
||||
void clearUIPreference(
|
||||
T_String const& name ) noexcept;
|
||||
|
||||
/* List UI preferences */
|
||||
T_Array< T_String > uiPreferences( ) const noexcept;
|
||||
/* Get the preference for an UI */
|
||||
int32_t uiPreference(
|
||||
T_String const& name ) const noexcept;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
/* Filter a list of mods using the configuration's exclusions and
|
||||
* version limits.
|
||||
*/
|
||||
T_Array< RPC_ModInfo > filterMods(
|
||||
T_Array< RPC_ModInfo > const& mods ) const noexcept;
|
||||
/* Generate the list of required mods. This includes all mods that
|
||||
* have been set as required, and all mods that have a version
|
||||
* requirement.
|
||||
*/
|
||||
T_Array< T_String > requiredMods( ) const noexcept;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
/* Get a default configuration */
|
||||
static T_ModsManagerConfiguration DefaultConfiguration( ) noexcept;
|
||||
|
||||
/* Get the parser's configuration used to load mods manager configuration */
|
||||
static T_SRDParserConfig GetParserConfig( );
|
||||
};
|
||||
M_CLASS_POINTERS( ModsManagerConfiguration );
|
||||
|
||||
|
||||
/*= MODS DEPENDENCY GRAPH ====================================================*/
|
||||
|
||||
class T_ModsDependencies : public A_PrivateImplementation
|
||||
{
|
||||
public:
|
||||
T_ModsDependencies( ) noexcept;
|
||||
T_ModsDependencies(
|
||||
T_Logger& logger ,
|
||||
T_Array< RPC_ModInfo > const& mods ,
|
||||
T_ModsManagerConfiguration const& config ) noexcept;
|
||||
|
||||
T_ModsDependencies(
|
||||
T_ModsDependencies const& other ) noexcept;
|
||||
T_ModsDependencies& operator =(
|
||||
T_ModsDependencies const& other ) noexcept;
|
||||
|
||||
T_ModsDependencies(
|
||||
T_ModsDependencies&& other ) noexcept;
|
||||
T_ModsDependencies& operator =(
|
||||
T_ModsDependencies&& other ) noexcept;
|
||||
|
||||
friend M_DECLARE_SWAP( T_ModsDependencies );
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
bool resolved( ) const;
|
||||
bool ambiguous( ) const;
|
||||
T_Array< T_String > userInterfaces( ) const;
|
||||
T_Array< RPC_ModInfo > const& commonMods( ) const;
|
||||
T_Array< RPC_ModInfo >::RPC forUserInterface(
|
||||
T_String const& name ) const;
|
||||
};
|
||||
M_CLASS_POINTERS( ModsDependencies );
|
||||
M_DECLARE_SWAP( T_ModsDependencies );
|
||||
|
||||
|
||||
/*= MODS MANAGER =============================================================*/
|
||||
|
||||
/* Function type for a function that generates a feedback function used to
|
||||
* update the initialisation progress when the mods are being initialised.
|
||||
*/
|
||||
using F_CreateInitUpdater = std::function< F_UpdateInitProgress( RPC_ModInfo ) >;
|
||||
|
||||
class T_ModsManager : public A_PrivateImplementation
|
||||
{
|
||||
public:
|
||||
T_ModsManager( ) = delete;
|
||||
T_ModsManager( T_ModsManager const& ) = delete;
|
||||
T_ModsManager( T_ModsManager&& ) noexcept = delete;
|
||||
|
||||
T_ModsManager( T_ModsManagerConfiguration&& config ) noexcept;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
/* Find available mods, load their descriptions */
|
||||
bool scanForMods( );
|
||||
/* Get the list of available mods */
|
||||
T_Array< RPC_ModInfo > availableMods( ) const noexcept;
|
||||
|
||||
/* Resolve dependencies between mods using the configuration;
|
||||
* returns true if there is a valid set of mods.
|
||||
*/
|
||||
bool resolveDependencies( ) noexcept;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
/* Pre-initialise common mods */
|
||||
bool preinitCommon( ) noexcept;
|
||||
/* Pre-initialise UI mods and try to start the user interface. */
|
||||
OP_UserInterface preinitUIMods(
|
||||
T_String const& ui ) noexcept;
|
||||
/* Try to pre-initialise an UI mod. */
|
||||
OP_UserInterface preinitUIMods( ) noexcept;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
/* Get the amount of loaded mods */
|
||||
uint32_t modsCount( ) const noexcept;
|
||||
/* Initialise the mods, sending progress updates along the way */
|
||||
bool initialise(
|
||||
F_CreateInitUpdater const& fciu ) noexcept;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
/* Shutdown all initialised mods. */
|
||||
void shutdown( ) noexcept;
|
||||
/* Unload all mods, calling post-shutdown routines if available */
|
||||
void unload( ) noexcept;
|
||||
};
|
||||
M_CLASS_POINTERS( ModsManager );
|
||||
|
||||
|
||||
} // namespace lw
|
||||
#endif // _H_LW_LIB_MODS
|
||||
#include <lw/lib/inline/Mods.hh>
|
423
include/ebcl/Pointers.hh
Normal file
423
include/ebcl/Pointers.hh
Normal file
|
@ -0,0 +1,423 @@
|
|||
/******************************************************************************/
|
||||
/* POINTERS *******************************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
#ifndef _H_LW_LIB_POINTERS
|
||||
#define _H_LW_LIB_POINTERS
|
||||
#include <lw/lib/Utilities.hh>
|
||||
namespace lw {
|
||||
|
||||
template< typename T > class T_OwnPtr;
|
||||
template< typename T > class T_SharedPtr;
|
||||
template< typename T > class T_WeakPtr;
|
||||
|
||||
/*= OWNING POINTERS ==========================================================*/
|
||||
|
||||
template< typename T >
|
||||
class T_OwnPtr
|
||||
{
|
||||
template< typename RT , typename... AT >
|
||||
friend T_OwnPtr< RT > NewOwned( AT&& ... arguments );
|
||||
|
||||
template<
|
||||
typename RT
|
||||
> friend T_OwnPtr< RT > OwnRawPointer( RT*& ) noexcept;
|
||||
|
||||
template<
|
||||
typename RT , typename OT ,
|
||||
T_EnableForChild< RT , OT >
|
||||
> friend T_OwnPtr< RT > OwnRawPointer( OT*& ) noexcept;
|
||||
|
||||
template<
|
||||
typename RT , typename OT ,
|
||||
T_EnableForParent< RT , OT >
|
||||
> friend T_OwnPtr< RT > OwnRawPointer( OT*& );
|
||||
|
||||
template< typename >
|
||||
friend class T_OwnPtr;
|
||||
|
||||
friend T_SharedPtr< T >;
|
||||
|
||||
private:
|
||||
typedef T_OwnPtr< T > MyType_;
|
||||
|
||||
T* p_;
|
||||
|
||||
T_OwnPtr( T* p ) noexcept;
|
||||
|
||||
public:
|
||||
T_OwnPtr( );
|
||||
~T_OwnPtr( );
|
||||
|
||||
T_OwnPtr( MyType_ const& ) = delete;
|
||||
MyType_& operator= ( MyType_ const& ) = delete;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
template< typename Q , T_EnableForChild< T , Q > = true >
|
||||
T_OwnPtr( T_OwnPtr< Q >&& source ) noexcept;
|
||||
|
||||
template< typename Q , T_EnableForParent< T , Q > = false >
|
||||
explicit T_OwnPtr( T_OwnPtr< Q >&& source );
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
template< typename Q , T_EnableForChild< T , Q > = true >
|
||||
MyType_& operator= ( T_OwnPtr< Q >&& source ) noexcept;
|
||||
|
||||
template< typename Q , T_EnableForParent< T , Q > = false >
|
||||
MyType_& operator= ( T_OwnPtr< Q >&& source );
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
template< typename TP >
|
||||
friend void swap( T_OwnPtr< TP >& lhs , T_OwnPtr< TP >& rhs ) noexcept;
|
||||
|
||||
void clear( );
|
||||
|
||||
bool operator== ( const T* p ) const;
|
||||
bool operator!= ( const T* p ) const;
|
||||
operator bool ( ) const;
|
||||
bool operator! ( ) const;
|
||||
|
||||
T * get( ) const;
|
||||
T* operator-> ( ) const;
|
||||
T& operator* ( ) const;
|
||||
|
||||
T_SharedPtr< T > makeShared( );
|
||||
};
|
||||
|
||||
|
||||
// NewOwned< T >( ... ) - New T as an owned pointer
|
||||
template<
|
||||
typename Type ,
|
||||
typename... ArgTypes
|
||||
>
|
||||
T_OwnPtr< Type > NewOwned( ArgTypes&& ... arguments );
|
||||
|
||||
// OwnRawPointer< T >( pointer ) - Transfer a raw pointer to an owned pointer.
|
||||
// The raw pointer will be set to nullptr.
|
||||
template< typename Type >
|
||||
T_OwnPtr< Type > OwnRawPointer( Type*& pointer ) noexcept;
|
||||
|
||||
template<
|
||||
typename Type , typename Other ,
|
||||
T_EnableForChild< Type , Other > = true ,
|
||||
std::enable_if_t< !std::is_same< Type , Other >::value , bool > = true
|
||||
> T_OwnPtr< Type > OwnRawPointer( Other*& pointer ) noexcept;
|
||||
|
||||
template<
|
||||
typename Type , typename Other ,
|
||||
T_EnableForParent< Type , Other > = false
|
||||
> T_OwnPtr< Type > OwnRawPointer( Other*& pointer );
|
||||
|
||||
|
||||
/*= SHARED POINTERS ==========================================================*/
|
||||
/* WARNING: these pointers are NOT thread-safe! */
|
||||
|
||||
class T_Reference_;
|
||||
|
||||
// Weak pointer chaining
|
||||
struct T_WeakChain_
|
||||
{
|
||||
T_Reference_* * const ref;
|
||||
T_WeakChain_* prev;
|
||||
T_WeakChain_* next;
|
||||
|
||||
explicit T_WeakChain_( T_Reference_*& ref );
|
||||
void unchain( );
|
||||
void init( );
|
||||
};
|
||||
|
||||
|
||||
// Base class for shared and weak pointers
|
||||
template< typename T >
|
||||
class T_BasePtr_
|
||||
{
|
||||
protected:
|
||||
typedef T_BasePtr_< T > T_Base_;
|
||||
|
||||
T_Reference_* ref_;
|
||||
|
||||
explicit T_BasePtr_( T_Reference_* ref ) noexcept;
|
||||
|
||||
T_BasePtr_( ) = delete;
|
||||
T_BasePtr_( T_Base_ const& ) = delete;
|
||||
T_BasePtr_( T_Base_&& ) = delete;
|
||||
|
||||
public:
|
||||
operator bool ( ) const;
|
||||
bool operator! ( ) const;
|
||||
|
||||
T* operator-> ( ) const;
|
||||
explicit operator T* ( ) const;
|
||||
T& operator* ( ) const;
|
||||
};
|
||||
|
||||
|
||||
// Exception thrown when makeOwned( ) is called on a shared pointers that has
|
||||
// more than one reference.
|
||||
class X_TooManyReferences : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
X_TooManyReferences( );
|
||||
};
|
||||
|
||||
|
||||
// T_SharedPtr< T > - Shared pointer implementation
|
||||
template< typename T >
|
||||
class T_SharedPtr : public T_BasePtr_< T >
|
||||
{
|
||||
private:
|
||||
typedef T_BasePtr_< T > T_Base_;
|
||||
typedef T_SharedPtr< T > T_Self_;
|
||||
typedef T_WeakPtr< T > T_Weak_;
|
||||
|
||||
template< typename >
|
||||
friend class T_SharedPtr;
|
||||
|
||||
template< typename >
|
||||
friend class T_WeakPtr;
|
||||
|
||||
template<
|
||||
typename RT
|
||||
> friend T_SharedPtr< RT > ShareRawPointer( RT*& ) noexcept;
|
||||
|
||||
template<
|
||||
typename RT , typename OT ,
|
||||
T_EnableForChild< RT , OT >
|
||||
> friend T_SharedPtr< RT > ShareRawPointer( OT*& ) noexcept;
|
||||
|
||||
template<
|
||||
typename RT , typename OT ,
|
||||
T_EnableForParent< RT , OT >
|
||||
> friend T_SharedPtr< RT > ShareRawPointer( OT*& );
|
||||
|
||||
template< typename OT , typename... AT >
|
||||
friend T_SharedPtr< OT > NewShared( AT&& ... arguments );
|
||||
friend T_OwnPtr< T >;
|
||||
|
||||
using T_Base_::ref_;
|
||||
|
||||
T_Reference_ * setRef( T_Reference_* from );
|
||||
void clearRef( );
|
||||
|
||||
explicit T_SharedPtr( T* ptr );
|
||||
|
||||
public:
|
||||
T_SharedPtr( ) noexcept;
|
||||
~T_SharedPtr( );
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Copy constructors
|
||||
|
||||
T_SharedPtr( T_Self_ const& source );
|
||||
|
||||
template< typename Q , T_EnableForChild< T , Q > = true >
|
||||
T_SharedPtr( T_SharedPtr< Q > const& source );
|
||||
|
||||
template< typename Q , T_EnableForParent< T , Q > = false >
|
||||
explicit T_SharedPtr( T_SharedPtr< Q > const& source );
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Move constructors
|
||||
|
||||
template< typename Q , T_EnableForChild< T , Q > = true >
|
||||
T_SharedPtr( T_SharedPtr< Q >&& source ) noexcept;
|
||||
|
||||
template< typename Q , T_EnableForParent< T , Q > = false >
|
||||
explicit T_SharedPtr( T_SharedPtr< Q >&& source );
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Copy assignment operators
|
||||
|
||||
T_Self_& operator= ( T_Self_ const& other );
|
||||
|
||||
template< typename Q , T_EnableForChild< T , Q > = true >
|
||||
T_Self_& operator= ( T_SharedPtr< Q > const& other );
|
||||
|
||||
template< typename Q , T_EnableForParent< T , Q > = false >
|
||||
T_Self_& operator= ( T_SharedPtr< Q > const& other );
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Move assignment operators
|
||||
|
||||
template< typename Q , T_EnableForChild< T , Q > = true >
|
||||
T_Self_& operator= ( T_SharedPtr< Q >&& other ) noexcept;
|
||||
|
||||
template< typename Q , T_EnableForParent< T , Q > = false >
|
||||
T_Self_& operator= ( T_SharedPtr< Q >&& other );
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
template< typename TP >
|
||||
friend void swap( T_SharedPtr< TP >& lhs , T_SharedPtr< TP >& rhs ) noexcept;
|
||||
|
||||
bool operator== ( T_Self_ const& other ) const;
|
||||
bool operator!= ( T_Self_ const& other ) const;
|
||||
bool operator== ( T_Weak_ const& other ) const;
|
||||
bool operator!= ( T_Weak_ const& other ) const;
|
||||
|
||||
void clear( );
|
||||
|
||||
T_OwnPtr< T > makeOwned( );
|
||||
};
|
||||
|
||||
|
||||
// T_WeakPtr< T > - Weak pointer implementation
|
||||
template< typename T >
|
||||
class T_WeakPtr : public T_BasePtr_< T >
|
||||
{
|
||||
private:
|
||||
typedef T_BasePtr_< T > T_Base_;
|
||||
typedef T_SharedPtr< T > T_Shared_;
|
||||
typedef T_WeakPtr< T > T_Self_;
|
||||
|
||||
template< typename > friend class T_SharedPtr;
|
||||
template< typename > friend class T_WeakPtr;
|
||||
friend T_Reference_;
|
||||
|
||||
using T_Base_::ref_;
|
||||
|
||||
T_WeakChain_ chain_;
|
||||
|
||||
T_WeakPtr( T_Reference_* ref );
|
||||
|
||||
public:
|
||||
|
||||
T_WeakPtr( );
|
||||
~T_WeakPtr( );
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Copy constructors
|
||||
|
||||
T_WeakPtr( T_Self_ const& other );
|
||||
|
||||
template< typename Q , T_EnableForChild< T , Q > = true >
|
||||
T_WeakPtr( T_WeakPtr< Q > const& other );
|
||||
|
||||
template< typename Q , T_EnableForParent< T , Q > = false >
|
||||
explicit T_WeakPtr( T_WeakPtr< Q > const& other );
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Move constructors
|
||||
|
||||
template< typename Q , T_EnableForChild< T , Q > = true >
|
||||
T_WeakPtr( T_WeakPtr< Q >&& other ) noexcept;
|
||||
|
||||
template< typename Q , T_EnableForParent< T , Q > = false >
|
||||
explicit T_WeakPtr( T_WeakPtr< Q >&& other );
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Construct from shared pointer
|
||||
|
||||
explicit T_WeakPtr( T_Shared_ const& shared );
|
||||
|
||||
template< typename Q , T_EnableForChild< T , Q > = true >
|
||||
explicit T_WeakPtr( T_SharedPtr< Q > const& shared );
|
||||
|
||||
template< typename Q , T_EnableForParent< T , Q > = false >
|
||||
explicit T_WeakPtr( T_SharedPtr< Q > const& shared );
|
||||
|
||||
explicit T_WeakPtr( T_Shared_&& shared ) = delete;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Copy assignment operators
|
||||
|
||||
T_Self_& operator= ( T_Self_ const& other );
|
||||
|
||||
template< typename Q , T_EnableForChild< T , Q > = true >
|
||||
T_Self_& operator =( T_WeakPtr< Q > const& other );
|
||||
|
||||
template< typename Q , T_EnableForParent< T , Q > = false >
|
||||
T_Self_& operator =( T_WeakPtr< Q > const& other );
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Move assignment operators
|
||||
|
||||
template< typename Q , T_EnableForChild< T , Q > = true >
|
||||
T_Self_& operator =( T_WeakPtr< Q >&& other );
|
||||
|
||||
template< typename Q , T_EnableForParent< T , Q > = false >
|
||||
T_Self_& operator =( T_WeakPtr< Q >&& other );
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Assign from shared pointer
|
||||
|
||||
T_Self_& operator= ( T_Shared_ const& shared );
|
||||
|
||||
template< typename Q , T_EnableForChild< T , Q > = true >
|
||||
T_Self_& operator= ( T_SharedPtr< Q > const& shared );
|
||||
|
||||
template< typename Q , T_EnableForParent< T , Q > = false >
|
||||
T_Self_& operator= ( T_SharedPtr< Q > const& shared );
|
||||
|
||||
T_Self_& operator= ( T_Shared_&& ) = delete;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
template< typename TP >
|
||||
friend void swap( T_WeakPtr< TP >& lhs , T_WeakPtr< TP >& rhs );
|
||||
|
||||
bool operator== ( T_Self_ const& other ) const;
|
||||
bool operator!= ( T_Self_ const& other ) const;
|
||||
bool operator== ( T_Shared_ const& other ) const;
|
||||
bool operator!= ( T_Shared_ const& other ) const;
|
||||
|
||||
void clear( );
|
||||
};
|
||||
|
||||
|
||||
// NewShared< T >( ... ) - New T as shared pointer
|
||||
template<
|
||||
typename Type ,
|
||||
typename... ArgTypes
|
||||
>
|
||||
T_SharedPtr< Type > NewShared( ArgTypes&& ... arguments );
|
||||
|
||||
// ShareRawPointer< T >( pointer ) - Transfer a raw pointer to a shared pointer.
|
||||
// The raw pointer will be set to nullptr.
|
||||
template< typename Type >
|
||||
T_SharedPtr< Type > ShareRawPointer(
|
||||
Type*& pointer ) noexcept;
|
||||
|
||||
template<
|
||||
typename Type , typename Other ,
|
||||
T_EnableForChild< Type , Other > = true ,
|
||||
std::enable_if_t< !std::is_same< Type , Other >::value , bool > = true
|
||||
> T_SharedPtr< Type > ShareRawPointer(
|
||||
Other*& pointer ) noexcept;
|
||||
|
||||
template<
|
||||
typename Type , typename Other ,
|
||||
T_EnableForParent< Type , Other > = false
|
||||
> T_SharedPtr< Type > ShareRawPointer( Other*& pointer );
|
||||
|
||||
|
||||
/*= HELPER MACROS ============================================================*/
|
||||
|
||||
#define M_CLASS_POINTERS( NAME ) \
|
||||
typedef T_ ## NAME* RP_ ## NAME; \
|
||||
typedef T_ ## NAME const* RPC_ ## NAME; \
|
||||
typedef T_OwnPtr< T_ ## NAME > OP_ ## NAME; \
|
||||
typedef T_SharedPtr< T_ ## NAME > SP_ ## NAME; \
|
||||
typedef T_WeakPtr< T_ ## NAME > WP_ ## NAME
|
||||
|
||||
#define M_ABSTRACT_POINTERS( NAME ) \
|
||||
typedef A_ ## NAME* RP_ ## NAME; \
|
||||
typedef A_ ## NAME const* RPC_ ## NAME; \
|
||||
typedef T_OwnPtr< A_ ## NAME > OP_ ## NAME; \
|
||||
typedef T_SharedPtr< A_ ## NAME > SP_ ## NAME; \
|
||||
typedef T_WeakPtr< A_ ## NAME > WP_ ## NAME
|
||||
|
||||
#define M_TEMPLATE_POINTERS( NAME ) \
|
||||
typedef NAME* RP; \
|
||||
typedef NAME const* RPC; \
|
||||
typedef T_OwnPtr< NAME > OP; \
|
||||
typedef T_SharedPtr< NAME > SP; \
|
||||
typedef T_WeakPtr< NAME > WP
|
||||
|
||||
|
||||
} // namespace
|
||||
#endif // _H_LW_LIB_POINTERS
|
||||
#include <lw/lib/inline/Pointers.hh>
|
85
include/ebcl/Registration.hh
Normal file
85
include/ebcl/Registration.hh
Normal file
|
@ -0,0 +1,85 @@
|
|||
/******************************************************************************/
|
||||
/* REGISTRATION SUPPORT *******************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
#ifndef _H_LW_LIB_REGISTRATION
|
||||
#define _H_LW_LIB_REGISTRATION
|
||||
#include <lw/lib/Utilities.hh>
|
||||
#include <lw/lib/Pointers.hh>
|
||||
namespace lw {
|
||||
|
||||
|
||||
/*= REGISTRATION SUPPORT =====================================================*/
|
||||
|
||||
/* This class is meant to be used with any class that supports registration of
|
||||
* items (for example the VFS to which VFS drivers are added).
|
||||
*
|
||||
* It must be returned from registration methods, and will serve as a way to
|
||||
* unregister an item, either directly using the unregister() method, or
|
||||
* automatically when the instance is destroyed (if automatic unregistration
|
||||
* is active, which is the default).
|
||||
*/
|
||||
class T_RegisteredItem
|
||||
{
|
||||
public:
|
||||
using F_Unregister = std::function< void( void* ) >;
|
||||
using SP_Unregister = T_SharedPtr< F_Unregister >;
|
||||
|
||||
private:
|
||||
using F_Destructor_ = std::function< void( void* ) >;
|
||||
using WP_Unregister_ = T_WeakPtr< F_Unregister >;
|
||||
|
||||
bool automatic_;
|
||||
WP_Unregister_ unregisterFunction_;
|
||||
void* data_;
|
||||
F_Destructor_ dataDestructor_;
|
||||
|
||||
public:
|
||||
/* Initialise an empty item (indicates registration failure) */
|
||||
T_RegisteredItem( ) noexcept;
|
||||
|
||||
/* Initialise a registered item */
|
||||
T_RegisteredItem( SP_Unregister& unregisterFunction ,
|
||||
void* data ,
|
||||
F_Destructor_ destructor ) noexcept;
|
||||
template< typename T >
|
||||
T_RegisteredItem( SP_Unregister& unregisterFunction ,
|
||||
T* data ) noexcept;
|
||||
|
||||
/* Destructor. Will unregister the item if automatic mode is
|
||||
* enabled */
|
||||
~T_RegisteredItem( );
|
||||
|
||||
/* Copy is disabled */
|
||||
T_RegisteredItem( T_RegisteredItem const& ) = delete;
|
||||
T_RegisteredItem& operator =( T_RegisteredItem const& ) = delete;
|
||||
|
||||
/* Move and swap */
|
||||
T_RegisteredItem( T_RegisteredItem&& other ) noexcept;
|
||||
T_RegisteredItem& operator =( T_RegisteredItem&& other ) noexcept;
|
||||
friend M_DECLARE_SWAP( T_RegisteredItem );
|
||||
|
||||
/* Set whether this registrable will unregister automatically when
|
||||
* it is deleted. */
|
||||
void automatic( bool v ) noexcept;
|
||||
bool automatic( ) const noexcept;
|
||||
|
||||
/* Unregister this item. May be called multiple times; the first
|
||||
* call will unregister the item, other calls will be ignored.
|
||||
*/
|
||||
void unregister( ) noexcept;
|
||||
|
||||
/* Registration check */
|
||||
operator bool( ) const noexcept;
|
||||
|
||||
private:
|
||||
void clear( ) noexcept;
|
||||
void deleteData( ) noexcept;
|
||||
};
|
||||
M_CLASS_POINTERS( RegisteredItem );
|
||||
M_DECLARE_SWAP( T_RegisteredItem );
|
||||
|
||||
|
||||
} // namespace
|
||||
#endif // _H_LW_LIB_REGISTRATION
|
||||
#include <lw/lib/inline/Registration.hh>
|
78
include/ebcl/SRDBinary.hh
Normal file
78
include/ebcl/SRDBinary.hh
Normal file
|
@ -0,0 +1,78 @@
|
|||
/******************************************************************************/
|
||||
/* SRD - BINARY STORAGE *******************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
#ifndef _H_LW_LIB_SRDBINARY
|
||||
#define _H_LW_LIB_SRDBINARY
|
||||
#include <lw/lib/SRDIO.hh>
|
||||
#include <lw/lib/HashIndex.hh>
|
||||
namespace lw {
|
||||
|
||||
|
||||
/*= WRITER ===================================================================*/
|
||||
|
||||
class T_SRDBinaryWriter : public A_SRDWriter
|
||||
{
|
||||
private:
|
||||
T_BinaryWriter writer_;
|
||||
T_HashIndex wordsIndex_;
|
||||
T_Array< T_String > words_;
|
||||
T_StringBuilder comment_;
|
||||
uint32_t depth_;
|
||||
|
||||
void flushComment( );
|
||||
void writeWord( T_String const& word );
|
||||
|
||||
public:
|
||||
T_SRDBinaryWriter( ) = delete;
|
||||
T_SRDBinaryWriter( T_SRDBinaryWriter const& ) = delete;
|
||||
T_SRDBinaryWriter( T_SRDBinaryWriter&& ) = delete;
|
||||
|
||||
explicit T_SRDBinaryWriter( A_OutputStream& output );
|
||||
|
||||
T_SRDBinaryWriter& start( ) override;
|
||||
|
||||
T_SRDBinaryWriter& startList( ) override;
|
||||
T_SRDBinaryWriter& endList( ) override;
|
||||
|
||||
T_SRDBinaryWriter& putText( T_String const& text ) override;
|
||||
T_SRDBinaryWriter& putWord( T_String const& word ) override;
|
||||
T_SRDBinaryWriter& putString( T_String const& string ) override;
|
||||
|
||||
T_SRDBinaryWriter& putComment( T_String const& comment ) override;
|
||||
|
||||
T_SRDBinaryWriter& putVariable( T_String const& variable ) override;
|
||||
|
||||
T_SRDBinaryWriter& putBinary( T_Buffer< uint8_t > const& binary ) override;
|
||||
|
||||
T_SRDBinaryWriter& putInteger( int64_t value ) override;
|
||||
T_SRDBinaryWriter& putInt32( int32_t value ) override;
|
||||
T_SRDBinaryWriter& putInt64( int64_t value ) override;
|
||||
|
||||
T_SRDBinaryWriter& putFloat( double value ) override;
|
||||
|
||||
T_SRDBinaryWriter& end( ) override;
|
||||
};
|
||||
|
||||
void SRDBinaryWriteTo( A_OutputStream& output , T_SRDList const& data );
|
||||
|
||||
|
||||
/*= READER ===================================================================*/
|
||||
|
||||
class T_SRDBinaryReader : public A_SRDReader
|
||||
{
|
||||
public:
|
||||
T_SRDBinaryReader( ) = delete;
|
||||
T_SRDBinaryReader( T_SRDBinaryReader const& ) = delete;
|
||||
T_SRDBinaryReader( T_SRDBinaryReader&& ) = delete;
|
||||
|
||||
T_SRDBinaryReader( A_SRDReaderTarget& target );
|
||||
void read( T_String const& name , A_InputStream& input ) override;
|
||||
};
|
||||
|
||||
T_SRDList SRDBinaryReadFrom( T_String const& name , A_InputStream& input , bool structured = true );
|
||||
|
||||
|
||||
} // namespace
|
||||
#include <lw/lib/inline/SRDBinary.hh>
|
||||
#endif // _H_LW_LIB_SRDBINARY
|
361
include/ebcl/SRDData.hh
Normal file
361
include/ebcl/SRDData.hh
Normal file
|
@ -0,0 +1,361 @@
|
|||
/******************************************************************************/
|
||||
/* SRD - DATA *****************************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
#ifndef _H_LW_LIB_SRDDATA
|
||||
#define _H_LW_LIB_SRDDATA
|
||||
#include <lw/lib/Externals.hh>
|
||||
#include <lw/lib/Strings.hh>
|
||||
#include <lw/lib/Types.hh>
|
||||
namespace lw {
|
||||
|
||||
class T_Logger;
|
||||
|
||||
// Forward declarations
|
||||
struct T_SRDLocationChaining;
|
||||
M_CLASS_POINTERS( SRDLocationChaining );
|
||||
class T_SRDLocation;
|
||||
M_CLASS_POINTERS( SRDLocation );
|
||||
class T_SRDToken;
|
||||
M_CLASS_POINTERS( SRDToken );
|
||||
|
||||
|
||||
/*= SOURCE LOCATIONS =========================================================*/
|
||||
|
||||
// E_SRDLocationChaining - Token location chaining circumstances
|
||||
enum class E_SRDLocationChaining {
|
||||
INCLUDED ,
|
||||
LOADED ,
|
||||
CALLED ,
|
||||
GENERATED ,
|
||||
SUBSTITUTED ,
|
||||
EVALUATED ,
|
||||
EXPANDED
|
||||
};
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
// T_SRDLocationChaining - Token location chaining structure
|
||||
struct T_SRDLocationChaining
|
||||
{
|
||||
E_SRDLocationChaining circumstances;
|
||||
uint32_t depth;
|
||||
SP_SRDLocation location;
|
||||
|
||||
T_SRDLocationChaining(
|
||||
E_SRDLocationChaining how ,
|
||||
uint32_t depth ,
|
||||
SP_SRDLocation const& to ) noexcept;
|
||||
|
||||
bool isGenerated( ) const noexcept;
|
||||
};
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
// T_SRDLocation - Token source location information
|
||||
class T_SRDLocation
|
||||
{
|
||||
private:
|
||||
T_String source_;
|
||||
uint32_t line_;
|
||||
size_t character_;
|
||||
T_Optional< T_SRDLocationChaining > chaining_;
|
||||
|
||||
public:
|
||||
// SRD locations are pooled
|
||||
void* operator new( size_t count ) noexcept;
|
||||
void operator delete( void* object ) noexcept;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
// Unknown location
|
||||
T_SRDLocation( ) noexcept;
|
||||
// Text input location
|
||||
T_SRDLocation( T_String const& source ,
|
||||
uint32_t line ,
|
||||
size_t character ) noexcept;
|
||||
// Binary input location
|
||||
T_SRDLocation( T_String const& source ,
|
||||
size_t byte ) noexcept;
|
||||
// Location of a token
|
||||
explicit T_SRDLocation(
|
||||
T_SRDToken const& token ) noexcept;
|
||||
|
||||
T_SRDLocation( T_SRDLocation const& other ) noexcept;
|
||||
T_SRDLocation& operator= ( T_SRDLocation const& other ) noexcept;
|
||||
|
||||
T_SRDLocation( T_SRDLocation&& other ) noexcept;
|
||||
T_SRDLocation& operator= ( T_SRDLocation&& other ) noexcept;
|
||||
|
||||
friend M_DECLARE_SWAP( T_SRDLocation );
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
void chain( E_SRDLocationChaining how ,
|
||||
SP_SRDLocation const& to ) noexcept;
|
||||
void chain( E_SRDLocationChaining how ,
|
||||
uint32_t depth ,
|
||||
SP_SRDLocation const& to ) noexcept;
|
||||
void clearChain( ) noexcept;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
bool unknown( ) const noexcept;
|
||||
T_String const& source( ) const noexcept;
|
||||
bool binary( ) const noexcept;
|
||||
uint32_t line( ) const noexcept;
|
||||
size_t character( ) const noexcept;
|
||||
size_t byte( ) const noexcept;
|
||||
|
||||
bool isChained( ) const noexcept;
|
||||
T_SRDLocationChaining const& chaining( ) const noexcept;
|
||||
};
|
||||
M_DECLARE_SWAP( T_SRDLocation );
|
||||
M_LSHIFT_OP( T_StringBuilder , T_SRDLocation ) noexcept;
|
||||
|
||||
|
||||
/*= ERRORS ===================================================================*/
|
||||
|
||||
// An error that occurred during SRD processing
|
||||
class T_SRDError
|
||||
{
|
||||
private:
|
||||
T_String error_;
|
||||
T_SRDLocation location_;
|
||||
bool isDetails_;
|
||||
|
||||
public:
|
||||
T_SRDError( ) = delete;
|
||||
|
||||
T_SRDError( T_String error ,
|
||||
T_SRDLocation location ,
|
||||
bool details = false ) noexcept;
|
||||
|
||||
T_SRDError( T_SRDError const& other ) noexcept;
|
||||
T_SRDError& operator= ( T_SRDError const& other ) noexcept;
|
||||
|
||||
T_SRDError( T_SRDError&& other ) noexcept;
|
||||
T_SRDError& operator= ( T_SRDError&& other ) noexcept;
|
||||
|
||||
friend M_DECLARE_SWAP( T_SRDError );
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
T_String const& error( ) const noexcept;
|
||||
T_SRDLocation const& location( ) const noexcept;
|
||||
bool isDetails( ) const noexcept;
|
||||
};
|
||||
M_DECLARE_SWAP( T_SRDError );
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
// List of errors
|
||||
class T_SRDErrors
|
||||
{
|
||||
public:
|
||||
enum : uint32_t { MAX_ERRORS = 40 };
|
||||
|
||||
private:
|
||||
T_AutoArray< T_SRDError , MAX_ERRORS / 2 > errors_;
|
||||
uint32_t errCount_ = 0;
|
||||
|
||||
public:
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
template< typename ... ArgTypes >
|
||||
void add( char const* error ,
|
||||
ArgTypes&&... locationArgs );
|
||||
template< typename ... ArgTypes >
|
||||
void add( T_String const& error ,
|
||||
ArgTypes&&... locationArgs );
|
||||
|
||||
template< typename ... ArgTypes >
|
||||
void details( char const* message ,
|
||||
ArgTypes&&... locationArgs );
|
||||
template< typename ... ArgTypes >
|
||||
void details( T_String const& message ,
|
||||
ArgTypes&&... locationArgs );
|
||||
|
||||
template< typename ... ArgTypes >
|
||||
void add( InPlace , ArgTypes&&... args );
|
||||
void add( T_SRDError const& error );
|
||||
void add( T_SRDError&& error );
|
||||
|
||||
void addAll( T_SRDErrors const& errors );
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
uint32_t size( ) const noexcept;
|
||||
T_SRDError const& operator[] ( uint32_t index ) const noexcept;
|
||||
|
||||
void clear( ) noexcept;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
private:
|
||||
void checkAdded( T_SRDError const& last );
|
||||
};
|
||||
M_CLASS_POINTERS( SRDErrors );
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
// SRD processing exception
|
||||
class X_SRDErrors : public std::exception
|
||||
{
|
||||
public:
|
||||
const T_SRDErrors errors;
|
||||
X_SRDErrors( T_SRDErrors const& errors );
|
||||
char const * what( ) const noexcept override;
|
||||
#ifndef LW_MINLIB
|
||||
void log( T_Logger& logger ) const;
|
||||
#endif // LW_MINLIB
|
||||
};
|
||||
|
||||
|
||||
/*= TOKENS ===================================================================*/
|
||||
|
||||
// E_SRDTokenType - Token types
|
||||
enum class E_SRDTokenType {
|
||||
LIST , // Complete list
|
||||
START , // List start
|
||||
END , // List end
|
||||
WORD , // Word
|
||||
VAR , // Variable
|
||||
STRING , // Quoted string
|
||||
BINARY , // Binary data
|
||||
INT , // Integer (32 bits)
|
||||
LONG , // Integer (64 bits)
|
||||
FLOAT , // Floating point value
|
||||
COMMENT , // Commented text
|
||||
FLUSH , // Special token that causes a parser to flush
|
||||
};
|
||||
T_StringBuilder& operator<< ( T_StringBuilder& sb , E_SRDTokenType tt );
|
||||
|
||||
// T_SRDList - Token lists
|
||||
using T_SRDList = T_Array< T_SRDToken >;
|
||||
M_CLASS_POINTERS( SRDList );
|
||||
|
||||
// T_SRDToken - Token data
|
||||
class T_SRDToken
|
||||
{
|
||||
private:
|
||||
using T_BinData_ = T_SharedPtr< T_Buffer< uint8_t > >;
|
||||
|
||||
E_SRDTokenType type_; // Token type
|
||||
T_String text_; // Token's full string
|
||||
OP_SRDList list_; // List of tokens (type == LIST)
|
||||
int64_t longValue_; // 64-bit integer value
|
||||
double floatValue_; // 64-bit floating point value
|
||||
T_String stringValue_; // String value
|
||||
T_BinData_ binary_; // Binary data
|
||||
|
||||
SP_SRDLocation location_;
|
||||
|
||||
T_SRDToken( ) = default;
|
||||
T_SRDToken( const E_SRDTokenType type ) noexcept;
|
||||
|
||||
public:
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
static bool IsWord( T_String const& string );
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
static T_SRDToken ListStart( );
|
||||
static T_SRDToken ListEnd( );
|
||||
|
||||
static T_SRDToken List( );
|
||||
static T_SRDToken List( T_SRDList const& list );
|
||||
static T_SRDToken List( T_SRDList&& list );
|
||||
|
||||
// Either a Word or a String, depending on the contents
|
||||
static T_SRDToken AutoText( T_String text );
|
||||
static T_SRDToken Word( T_String word );
|
||||
static T_SRDToken String( T_String string );
|
||||
|
||||
static T_SRDToken Variable( T_String variable );
|
||||
static T_SRDToken Comment( T_String text );
|
||||
|
||||
// Binary data
|
||||
static T_SRDToken Binary(
|
||||
T_BinData_ const& data ) noexcept;
|
||||
template< typename T >
|
||||
static T_SRDToken Binary(
|
||||
T const* data ,
|
||||
uint32_t count ) noexcept;
|
||||
template< typename T >
|
||||
static T_SRDToken Binary(
|
||||
T_Buffer< T > const& data ) noexcept;
|
||||
|
||||
// A Long or an Int, depending on the value
|
||||
static T_SRDToken AutoInteger( int64_t value );
|
||||
static T_SRDToken Integer( int32_t value );
|
||||
static T_SRDToken Long( int64_t value );
|
||||
static T_SRDToken Float( double value );
|
||||
|
||||
// A special "flush" token
|
||||
static T_SRDToken Flush( ) noexcept;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
T_SRDToken( T_SRDToken const& other );
|
||||
T_SRDToken( T_SRDToken&& other ) noexcept;
|
||||
T_SRDToken& operator= ( T_SRDToken const& other );
|
||||
T_SRDToken& operator= ( T_SRDToken&& other ) noexcept;
|
||||
|
||||
friend void swap( T_SRDToken& lhs , T_SRDToken& rhs ) noexcept;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
E_SRDTokenType type( ) const;
|
||||
bool isText( ) const;
|
||||
bool isNumeric( ) const;
|
||||
bool isInteger( ) const;
|
||||
|
||||
T_String const& text( ) const;
|
||||
T_SRDList const& list( ) const;
|
||||
T_SRDList& list( );
|
||||
int64_t longValue( ) const;
|
||||
double floatValue( ) const;
|
||||
T_String const& stringValue( ) const;
|
||||
T_Buffer< uint8_t > const& binary( ) const;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
int compare( T_SRDToken const& other ) const;
|
||||
bool operator ==( T_SRDToken const& other ) const;
|
||||
bool operator !=( T_SRDToken const& other ) const;
|
||||
bool operator >( T_SRDToken const& other ) const;
|
||||
bool operator <( T_SRDToken const& other ) const;
|
||||
bool operator >=( T_SRDToken const& other ) const;
|
||||
bool operator <=( T_SRDToken const& other ) const;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
bool hasFullText( ) const;
|
||||
T_String fullText( ) const;
|
||||
T_SRDToken& setFullText( T_String text );
|
||||
T_SRDToken& generateFullText( );
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
bool hasLocation( ) const noexcept;
|
||||
T_SRDLocation const& location( ) const noexcept;
|
||||
T_SRDLocation& location( ) noexcept;
|
||||
|
||||
T_SRDToken& location( T_String const& source , size_t byte );
|
||||
T_SRDToken& location( T_String const& source , uint32_t line , size_t character );
|
||||
T_SRDToken& location( T_SRDLocation const& other );
|
||||
T_SRDToken& location( T_SRDLocation&& other );
|
||||
T_SRDToken& copyLocationOf( T_SRDToken const& other );
|
||||
};
|
||||
void swap( T_SRDToken& lhs , T_SRDToken& rhs ) noexcept;
|
||||
M_DECLARE_COMPARATOR( T_SRDToken );
|
||||
|
||||
|
||||
extern template class T_Array< T_SRDToken >;
|
||||
|
||||
|
||||
} // namespace
|
||||
#include <lw/lib/inline/SRDData.hh>
|
||||
#endif // _H_LW_LIB_SRDDATA
|
321
include/ebcl/SRDDefinitions.hh
Normal file
321
include/ebcl/SRDDefinitions.hh
Normal file
|
@ -0,0 +1,321 @@
|
|||
/******************************************************************************/
|
||||
/* SRD - PARSER DEFINITIONS ***************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
#ifndef _H_LW_LIB_SRDDEFINITIONS
|
||||
#define _H_LW_LIB_SRDDEFINITIONS
|
||||
#include <lw/lib/SRDData.hh>
|
||||
#include <lw/lib/HashTables.hh>
|
||||
namespace lw {
|
||||
|
||||
|
||||
/*= DEFINITION DATA ==========================================================*/
|
||||
|
||||
// Full definition -> {contexts}, default context, {enums}
|
||||
// Context -> name, {rules}
|
||||
// Rule -> Accepted input, [context, [init], [exit]], [executor]
|
||||
// Input def -> Word
|
||||
// | Enum
|
||||
// | Token type
|
||||
// | Alternatives
|
||||
// | Repetition
|
||||
// Alternatives -> {input def}
|
||||
// Repetition -> Input sequence, min count, max count
|
||||
|
||||
// Forward declarations
|
||||
struct T_SRDParserData;
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
// F_SRDHandler - Parser callbacks
|
||||
using F_SRDHandler = std::function< bool( T_SRDParserData const& ) >;
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
// T_SRDEnum - an enumeration
|
||||
// i.e. set of words with associated sequence of integers, that can be
|
||||
// recognized as a single input token.
|
||||
class T_SRDEnum
|
||||
{
|
||||
private:
|
||||
T_String name_;
|
||||
T_HashIndex index_;
|
||||
T_Array< T_String > words_;
|
||||
|
||||
public:
|
||||
T_SRDEnum( ) = delete;
|
||||
|
||||
T_SRDEnum( T_String name );
|
||||
T_SRDEnum( T_SRDEnum const& ) = default;
|
||||
T_SRDEnum( T_SRDEnum && ) = default;
|
||||
|
||||
T_SRDEnum & operator <<( T_String && word );
|
||||
T_SRDEnum & operator <<( char const* word );
|
||||
|
||||
T_String const& name( ) const;
|
||||
auto size( ) const;
|
||||
|
||||
T_String const& operator[]( int index ) const;
|
||||
T_String const& operator[]( uint32_t index ) const;
|
||||
|
||||
uint32_t operator[]( T_String const& word ) const;
|
||||
uint32_t operator[]( char const* word ) const;
|
||||
|
||||
bool contains( T_String const& word ) const;
|
||||
bool contains( char const* word ) const;
|
||||
};
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
// E_SRDInputItem - Possible types for input definition elements
|
||||
enum class E_SRDInputItem
|
||||
{
|
||||
WORD , // A specific word
|
||||
ENUM , // A word from an enumeration
|
||||
TOKEN , // An arbitrary token
|
||||
ALTERNATIVE , // A set of alternative rules
|
||||
REPETITION , // Repetition of a sequence
|
||||
};
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
// T_SRDInputItem - An element from an input definition
|
||||
class T_SRDInputItem
|
||||
{
|
||||
public:
|
||||
struct T_ListHelper {
|
||||
T_Array< T_SRDInputItem > items;
|
||||
T_ListHelper( );
|
||||
T_ListHelper& operator <<( T_SRDInputItem item );
|
||||
};
|
||||
|
||||
private:
|
||||
E_SRDInputItem type_;
|
||||
T_String word_;
|
||||
E_SRDTokenType token_;
|
||||
T_Array< T_SRDInputItem > items_;
|
||||
uint32_t min_ , max_;
|
||||
|
||||
public:
|
||||
// Construct an ALTERNATIVE input element
|
||||
T_SRDInputItem( );
|
||||
// Construct either a WORD or an ENUM input element
|
||||
T_SRDInputItem( T_String wordOrName , bool isWord );
|
||||
// Construct a WORD from a C string
|
||||
T_SRDInputItem( char const* cString );
|
||||
// Construct a TOKEN input element
|
||||
T_SRDInputItem( E_SRDTokenType type );
|
||||
// Construct a REPETITION input element
|
||||
T_SRDInputItem( uint32_t min , uint32_t max );
|
||||
|
||||
friend void swap( T_SRDInputItem & lhs , T_SRDInputItem & rhs ) noexcept;
|
||||
|
||||
T_SRDInputItem( T_SRDInputItem const& ) = default;
|
||||
T_SRDInputItem( T_SRDInputItem && ) noexcept = default;
|
||||
T_SRDInputItem & operator=( T_SRDInputItem const& ) = default;
|
||||
T_SRDInputItem & operator=( T_SRDInputItem && ) = default;
|
||||
|
||||
E_SRDInputItem type( ) const;
|
||||
T_String const& word( ) const;
|
||||
E_SRDTokenType token( ) const;
|
||||
T_Array< T_SRDInputItem > items( ) const;
|
||||
uint32_t min( ) const;
|
||||
uint32_t max( ) const;
|
||||
|
||||
T_SRDInputItem & operator <<( T_SRDInputItem item );
|
||||
T_SRDInputItem& operator <<( T_ListHelper list );
|
||||
|
||||
// This operator is not actually used. It's only here to make the template
|
||||
// instantiation happy. It actually returns false.
|
||||
bool operator ==( T_SRDInputItem const& other ) const;
|
||||
};
|
||||
void swap( T_SRDInputItem & lhs , T_SRDInputItem & rhs ) noexcept;
|
||||
T_StringBuilder & operator <<( T_StringBuilder & sb , T_SRDInputItem const& item );
|
||||
|
||||
T_Array< T_SRDInputItem >& operator <<( T_Array< T_SRDInputItem > & items ,
|
||||
T_SRDInputItem::T_ListHelper& list );
|
||||
|
||||
extern template class T_Array< T_SRDInputItem >;
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
// T_SRDInputRule - A full rule from a context
|
||||
class T_SRDInputRule
|
||||
{
|
||||
public:
|
||||
struct T_SetContextExecutor {
|
||||
const bool exit;
|
||||
const F_SRDHandler executor;
|
||||
T_SetContextExecutor( bool exit , F_SRDHandler executor );
|
||||
};
|
||||
struct T_SetContext {
|
||||
const T_String name;
|
||||
T_SetContext( T_String string );
|
||||
};
|
||||
|
||||
private:
|
||||
F_SRDHandler executor_;
|
||||
T_Array< T_SRDInputItem > items_;
|
||||
|
||||
T_String context_;
|
||||
F_SRDHandler contextEnter_;
|
||||
F_SRDHandler contextExit_;
|
||||
|
||||
public:
|
||||
T_SRDInputRule & operator <<( T_SRDInputItem item );
|
||||
T_SRDInputRule & operator <<( F_SRDHandler executor );
|
||||
T_SRDInputRule & operator <<( T_SetContextExecutor sce );
|
||||
T_SRDInputRule & operator <<( T_SetContext sc );
|
||||
T_SRDInputRule & operator <<( T_SRDInputItem::T_ListHelper sc );
|
||||
|
||||
F_SRDHandler const& handler( ) const;
|
||||
T_Array< T_SRDInputItem > const& rule( ) const;
|
||||
T_String const& context( ) const;
|
||||
F_SRDHandler const& onEnter( ) const;
|
||||
F_SRDHandler const& onExit( ) const;
|
||||
};
|
||||
T_StringBuilder & operator <<( T_StringBuilder & sb , T_SRDInputRule const& item );
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
// T_SRDContext - A set of rules that will share common data
|
||||
class T_SRDContext
|
||||
{
|
||||
private:
|
||||
T_String name_;
|
||||
T_String parent_;
|
||||
T_Array< T_SRDInputRule > rules_;
|
||||
|
||||
public:
|
||||
T_SRDContext( ) = delete;
|
||||
|
||||
explicit T_SRDContext( T_String name , T_String parent = T_String( ) );
|
||||
|
||||
T_SRDContext & operator <<( T_SRDInputRule rule );
|
||||
|
||||
T_String const& name( ) const;
|
||||
T_String const& parent( ) const;
|
||||
T_Array< T_SRDInputRule > const& rules( ) const;
|
||||
|
||||
T_StringBuilder & dump( T_StringBuilder & sb , T_String const& separator );
|
||||
};
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
// T_SRDParserDefs - All definitions for a parser
|
||||
class T_SRDParserDefs
|
||||
{
|
||||
public:
|
||||
// SetHandler - Used to set start/end handlers
|
||||
struct SetHandler
|
||||
{
|
||||
const F_SRDHandler handler;
|
||||
const bool start;
|
||||
SetHandler( F_SRDHandler const& handler , bool start );
|
||||
};
|
||||
|
||||
private:
|
||||
T_String dfCtx_;
|
||||
T_ObjectTable< T_String , T_SRDContext > ctx_;
|
||||
T_ObjectTable< T_String , T_SRDEnum > enums_;
|
||||
|
||||
F_SRDHandler onStart_;
|
||||
F_SRDHandler onFinish_;
|
||||
|
||||
public:
|
||||
T_SRDParserDefs( ) = delete;
|
||||
|
||||
explicit T_SRDParserDefs( T_String defaultContext );
|
||||
explicit T_SRDParserDefs( char const* defaultContext );
|
||||
|
||||
T_String const& defaultContext( ) const;
|
||||
void defaultContext( T_String const& name );
|
||||
void defaultContext( char const* name );
|
||||
|
||||
T_SRDParserDefs & operator <<( SetHandler sh );
|
||||
F_SRDHandler const& onStart( ) const;
|
||||
F_SRDHandler const& onFinish( ) const;
|
||||
|
||||
uint32_t contexts( ) const;
|
||||
T_SRDContext & operator[]( uint32_t idx );
|
||||
T_SRDContext const& operator[]( uint32_t idx ) const;
|
||||
|
||||
uint32_t contextId( T_String const& name ) const;
|
||||
|
||||
T_SRDContext & context( T_String const& name );
|
||||
T_SRDContext & context( char const* name );
|
||||
T_SRDContext & context( T_String const& name , T_String const& parent );
|
||||
T_SRDContext & context( char const* name , char const* parent );
|
||||
|
||||
uint32_t enums( ) const;
|
||||
bool hasEnum( T_String const& name ) const;
|
||||
T_SRDEnum & enumeration( char const* name );
|
||||
T_SRDEnum & enumeration( T_String const& name );
|
||||
T_SRDEnum const& enumeration( T_String const& name ) const;
|
||||
};
|
||||
M_CLASS_POINTERS( SRDParserDefs );
|
||||
|
||||
|
||||
/*= PARSER DEFINITIONS HELPERS ===============================================*/
|
||||
|
||||
namespace SRD {
|
||||
|
||||
T_SRDParserDefs::SetHandler OnStart( F_SRDHandler const& handler );
|
||||
T_SRDParserDefs::SetHandler OnFinish( F_SRDHandler const& handler );
|
||||
|
||||
T_SRDContext Context( T_String name );
|
||||
T_SRDContext Context( char const* name );
|
||||
|
||||
T_SRDContext Context( char const* name , char const* parent );
|
||||
T_SRDContext Context( T_String name , T_String parent );
|
||||
|
||||
T_SRDInputRule Rule( );
|
||||
|
||||
T_SRDEnum CreateEnum( T_String name );
|
||||
T_SRDEnum CreateEnum( char const* name );
|
||||
|
||||
T_SRDInputItem Word( T_String const& word );
|
||||
T_SRDInputItem Word( char const* word );
|
||||
|
||||
T_SRDInputItem Word( );
|
||||
T_SRDInputItem String( );
|
||||
T_SRDInputItem Binary( );
|
||||
T_SRDInputItem LStart( );
|
||||
T_SRDInputItem LEnd( );
|
||||
T_SRDInputItem Int32( );
|
||||
T_SRDInputItem Int64( );
|
||||
T_SRDInputItem Float( );
|
||||
|
||||
T_SRDInputItem Enum( T_String name );
|
||||
T_SRDInputItem Enum( char const* name );
|
||||
|
||||
T_SRDInputItem::T_ListHelper List( );
|
||||
|
||||
T_SRDInputItem Alt( );
|
||||
|
||||
T_SRDInputItem Sub( );
|
||||
|
||||
T_SRDInputItem Opt( );
|
||||
T_SRDInputItem Opt( T_SRDInputItem item );
|
||||
|
||||
T_SRDInputItem AtLeast( uint32_t n );
|
||||
T_SRDInputItem AtMost( uint32_t n );
|
||||
T_SRDInputItem Times( uint32_t n );
|
||||
T_SRDInputItem Between( uint32_t a , uint32_t b );
|
||||
|
||||
T_SRDInputItem Integer( );
|
||||
T_SRDInputItem Numeric( );
|
||||
T_SRDInputItem Text( );
|
||||
|
||||
T_SRDInputRule::T_SetContext EnterContext( T_String name );
|
||||
T_SRDInputRule::T_SetContext EnterContext( char const* name );
|
||||
|
||||
T_SRDInputRule::T_SetContextExecutor OnEnter( F_SRDHandler f );
|
||||
T_SRDInputRule::T_SetContextExecutor OnExit( F_SRDHandler f );
|
||||
|
||||
} // namespace SRD
|
||||
|
||||
|
||||
} // namespace
|
||||
#include <lw/lib/inline/SRDDefinitions.hh>
|
||||
#endif // _H_LW_LIB_SRDDEFINITIONS
|
187
include/ebcl/SRDIO.hh
Normal file
187
include/ebcl/SRDIO.hh
Normal file
|
@ -0,0 +1,187 @@
|
|||
/******************************************************************************/
|
||||
/* SRD - INPUT AND OUTPUT *****************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
#ifndef _H_LW_LIB_SRDIO
|
||||
#define _H_LW_LIB_SRDIO
|
||||
#include <lw/lib/SRDData.hh>
|
||||
namespace lw {
|
||||
|
||||
|
||||
/*= INPUT / OUTPUT ABSTRACTIONS ==============================================*/
|
||||
|
||||
// A_SRDWriter - Abstract SRD writer
|
||||
class A_SRDWriter
|
||||
{
|
||||
protected:
|
||||
A_SRDWriter( ) = default;
|
||||
|
||||
public:
|
||||
A_SRDWriter( A_SRDWriter const& ) = delete;
|
||||
A_SRDWriter( A_SRDWriter&& ) = delete;
|
||||
|
||||
virtual ~A_SRDWriter( ) = 0;
|
||||
|
||||
virtual A_SRDWriter& start( ) = 0;
|
||||
|
||||
virtual A_SRDWriter& startList( ) = 0;
|
||||
virtual A_SRDWriter& endList( ) = 0;
|
||||
|
||||
A_SRDWriter& putList( T_SRDList const& list );
|
||||
A_SRDWriter& putToken( T_SRDToken const& token );
|
||||
|
||||
virtual A_SRDWriter& putText( T_String const& text ) = 0;
|
||||
virtual A_SRDWriter& putWord( T_String const& word ) = 0;
|
||||
virtual A_SRDWriter& putString( T_String const& string ) = 0;
|
||||
|
||||
virtual A_SRDWriter& putComment( T_String const& comment ) = 0;
|
||||
|
||||
virtual A_SRDWriter& putVariable( T_String const& var ) = 0;
|
||||
|
||||
virtual A_SRDWriter& putBinary( T_Buffer< uint8_t > const& binary ) = 0;
|
||||
|
||||
virtual A_SRDWriter& putInteger( int64_t value ) = 0;
|
||||
virtual A_SRDWriter& putInt32( int32_t value ) = 0;
|
||||
virtual A_SRDWriter& putInt64( int64_t value ) = 0;
|
||||
|
||||
virtual A_SRDWriter& putFloat( double value ) = 0;
|
||||
|
||||
virtual A_SRDWriter& end( ) = 0;
|
||||
};
|
||||
M_ABSTRACT_POINTERS( SRDWriter );
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
// A_SRDReaderTarget - Abstract token receiver for SRD readers
|
||||
class A_SRDReaderTarget
|
||||
{
|
||||
public:
|
||||
virtual ~A_SRDReaderTarget( ) = 0;
|
||||
virtual void start( T_SRDErrors& errors ) = 0;
|
||||
virtual void push( T_SRDErrors& errors , T_SRDToken&& token ) = 0;
|
||||
virtual void end( T_SRDErrors& errors ) = 0;
|
||||
};
|
||||
M_ABSTRACT_POINTERS( SRDReaderTarget );
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
// A_SRDReader - Abstract token reader
|
||||
class A_SRDReader
|
||||
{
|
||||
protected:
|
||||
A_SRDReaderTarget& target_;
|
||||
|
||||
public:
|
||||
A_SRDReader( A_SRDReaderTarget& target );
|
||||
|
||||
virtual ~A_SRDReader( ) = 0;
|
||||
virtual void read( T_String const& name , A_InputStream& input ) = 0;
|
||||
};
|
||||
M_ABSTRACT_POINTERS( SRDReader );
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
// X_SRDWriterError - SRD writer exception
|
||||
class X_SRDWriterError : public std::exception
|
||||
{
|
||||
private:
|
||||
char const* msg_;
|
||||
|
||||
public:
|
||||
X_SRDWriterError( char const* msg ) noexcept;
|
||||
|
||||
X_SRDWriterError( ) = delete;
|
||||
X_SRDWriterError( X_SRDWriterError const& ) = default;
|
||||
X_SRDWriterError( X_SRDWriterError&& ) = default;
|
||||
|
||||
char const * what( ) const noexcept override;
|
||||
};
|
||||
|
||||
|
||||
/*= HELPERS ==================================================================*/
|
||||
|
||||
// T_SRDReaderTargetHelper - Calls start() and end() using RAII
|
||||
class T_SRDReaderTargetHelper
|
||||
{
|
||||
private:
|
||||
A_SRDReaderTarget& target_;
|
||||
T_SRDErrors& errors_;
|
||||
|
||||
public:
|
||||
T_SRDReaderTargetHelper( A_SRDReaderTarget& target , T_SRDErrors& errors );
|
||||
~T_SRDReaderTargetHelper( );
|
||||
};
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
// T_SRDListFixer - A stage that adds missing EOL's and discards extraneous
|
||||
// EOL's, emitting errors as it does so.
|
||||
class T_SRDListFixer final : public A_SRDReaderTarget
|
||||
{
|
||||
private:
|
||||
A_SRDReaderTarget& output_;
|
||||
T_AutoArray< T_SRDLocation , 32 > listStarts_;
|
||||
|
||||
public:
|
||||
explicit T_SRDListFixer( A_SRDReaderTarget& output ) noexcept;
|
||||
|
||||
void start( T_SRDErrors& errors ) override;
|
||||
void push( T_SRDErrors& errors ,
|
||||
T_SRDToken&& token ) override;
|
||||
void end( T_SRDErrors& errors ) override;
|
||||
};
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
// T_SRDMemoryTarget - Stores the reader's output as a T_SRDList
|
||||
class T_SRDMemoryTarget : public A_SRDReaderTarget
|
||||
{
|
||||
private:
|
||||
const bool structured_;
|
||||
bool clearFlushToken_;
|
||||
T_SRDToken list_;
|
||||
RP_SRDToken current_;
|
||||
T_Array< RP_SRDToken > stack_;
|
||||
|
||||
public:
|
||||
// If structured is set, the generated token list will include sub-lists
|
||||
// as E_SRDTokenType::LIST tokens; if it isn't, the list will feature
|
||||
// only start and end of list tokens.
|
||||
explicit T_SRDMemoryTarget( bool structured = true );
|
||||
|
||||
// Set/get flush token handling
|
||||
void clearFlushToken( bool clearIt ) noexcept;
|
||||
bool clearFlushToken( ) const noexcept;
|
||||
|
||||
void start( T_SRDErrors& errors ) override;
|
||||
void push( T_SRDErrors& errors , T_SRDToken&& token ) override;
|
||||
void end( T_SRDErrors& errors ) override;
|
||||
|
||||
// Get the list
|
||||
T_SRDList const& list( ) const;
|
||||
// Does the list only contains complete items?
|
||||
bool complete( ) const;
|
||||
};
|
||||
M_CLASS_POINTERS( SRDMemoryTarget );
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
// T_SRDWriterTarget - Forwards token that are read to a writer
|
||||
class T_SRDWriterTarget : public A_SRDReaderTarget
|
||||
{
|
||||
private:
|
||||
A_SRDWriter& writer_;
|
||||
|
||||
public:
|
||||
explicit T_SRDWriterTarget( A_SRDWriter& writer );
|
||||
|
||||
void start( T_SRDErrors& errors ) override;
|
||||
void push( T_SRDErrors& errors , T_SRDToken&& token ) override;
|
||||
void end( T_SRDErrors& errors ) override;
|
||||
};
|
||||
M_CLASS_POINTERS( SRDWriterTarget );
|
||||
|
||||
|
||||
} // namespace
|
||||
#include <lw/lib/inline/SRDIO.hh>
|
||||
#endif // _H_LW_LIB_SRDIO
|
101
include/ebcl/SRDPPCommands.hh
Normal file
101
include/ebcl/SRDPPCommands.hh
Normal file
|
@ -0,0 +1,101 @@
|
|||
/******************************************************************************/
|
||||
/* SRD - PREPROCESSOR COMMANDS ************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
#ifndef _H_LW_LIB_SRDPPCOMMANDS
|
||||
#define _H_LW_LIB_SRDPPCOMMANDS
|
||||
#include <lw/lib/SRDPreproc.hh>
|
||||
namespace lw {
|
||||
|
||||
|
||||
M_SRDPP_COMMAND_DECL( Add ); M_SRDPP_COMMAND_INIT( Add , "add" );
|
||||
M_SRDPP_COMMAND_DECL( And ); M_SRDPP_COMMAND_INIT( And , "and" );
|
||||
|
||||
M_SRDPP_COMMAND_DECL( Bless ); M_SRDPP_COMMAND_INIT( Bless , "bless" );
|
||||
M_SRDPP_COMMAND_DECL( Break ); M_SRDPP_COMMAND_INIT( Break , "break" );
|
||||
M_SRDPP_COMMAND_DECL( BwAnd ); M_SRDPP_COMMAND_INIT( BwAnd , "bw-and" );
|
||||
M_SRDPP_COMMAND_DECL( BwNot ); M_SRDPP_COMMAND_INIT( BwNot , "bw-not" );
|
||||
M_SRDPP_COMMAND_DECL( BwOr ); M_SRDPP_COMMAND_INIT( BwOr , "bw-or" );
|
||||
M_SRDPP_COMMAND_DECL( BwXor ); M_SRDPP_COMMAND_INIT( BwXor , "bw-xor" );
|
||||
|
||||
M_SRDPP_COMMAND_DECL( Call ); M_SRDPP_COMMAND_INIT( Call , "call" );
|
||||
M_SRDPP_COMMAND_DECL( CastString ); M_SRDPP_COMMAND_INIT( CastString , "to-string" );
|
||||
M_SRDPP_COMMAND_DECL( CastWord ); M_SRDPP_COMMAND_INIT( CastWord , "to-word" );
|
||||
M_SRDPP_COMMAND_DECL( CastInt ); M_SRDPP_COMMAND_INIT( CastInt , "to-integer" );
|
||||
M_SRDPP_COMMAND_DECL( CastLong ); M_SRDPP_COMMAND_INIT( CastLong , "to-long" );
|
||||
M_SRDPP_COMMAND_DECL( CastBestInt ); M_SRDPP_COMMAND_INIT( CastBestInt , "to-best-integer" );
|
||||
M_SRDPP_COMMAND_DECL( CastReal ); M_SRDPP_COMMAND_INIT( CastReal , "to-real" );
|
||||
M_SRDPP_COMMAND_DECL( CastVar ); M_SRDPP_COMMAND_INIT( CastVar , "to-variable" );
|
||||
M_SRDPP_COMMAND_DECL( CastList ); M_SRDPP_COMMAND_INIT( CastList , "to-list" );
|
||||
M_SRDPP_COMMAND_DECL( ClearScope ); M_SRDPP_COMMAND_INIT_N( ClearScope , "clear-scope" , 0 );
|
||||
M_SRDPP_COMMAND_DECL( Cmp ); M_SRDPP_COMMAND_INIT( Cmp , "cmp" );
|
||||
M_SRDPP_COMMAND_DECL( CmpEq ); M_SRDPP_COMMAND_INIT( CmpEq , "eq" );
|
||||
M_SRDPP_COMMAND_DECL( CmpNe ); M_SRDPP_COMMAND_INIT( CmpNe , "ne" );
|
||||
M_SRDPP_COMMAND_DECL( CmpLt ); M_SRDPP_COMMAND_INIT( CmpLt , "lt" );
|
||||
M_SRDPP_COMMAND_DECL( CmpGt ); M_SRDPP_COMMAND_INIT( CmpGt , "gt" );
|
||||
M_SRDPP_COMMAND_DECL( CmpLe ); M_SRDPP_COMMAND_INIT( CmpLe , "le" );
|
||||
M_SRDPP_COMMAND_DECL( CmpGe ); M_SRDPP_COMMAND_INIT( CmpGe , "ge" );
|
||||
M_SRDPP_COMMAND_DECL( Concat ); M_SRDPP_COMMAND_INIT( Concat , "concat" );
|
||||
|
||||
M_SRDPP_COMMAND_DECL( Div ); M_SRDPP_COMMAND_INIT( Div , "div" );
|
||||
|
||||
M_SRDPP_COMMAND_DECL( EndsWith ); M_SRDPP_COMMAND_INIT( EndsWith , "ends-with" );
|
||||
M_SRDPP_COMMAND_DECL( Eval ); M_SRDPP_COMMAND_INIT( Eval , "eval" );
|
||||
M_SRDPP_COMMAND_DECL( Error ); M_SRDPP_COMMAND_INIT( Error , "error" );
|
||||
|
||||
M_SRDPP_COMMAND_DECL( FromSource ); M_SRDPP_COMMAND_INIT( FromSource , "from-source" );
|
||||
M_SRDPP_COMMAND_DECL( FromSRB ); M_SRDPP_COMMAND_INIT( FromSRB , "from-srb" );
|
||||
|
||||
M_SRDPP_COMMAND_DECL( Get ); M_SRDPP_COMMAND_INIT( Get , "get" );
|
||||
|
||||
M_SRDPP_COMMAND_DECL( If ); M_SRDPP_COMMAND_INIT_N( If , "if" , 1 );
|
||||
M_SRDPP_COMMAND_DECL( Ignore ); M_SRDPP_COMMAND_INIT_N( Ignore , "ignore" , 0 );
|
||||
M_SRDPP_COMMAND_DECL( IsBlessed ); M_SRDPP_COMMAND_INIT( IsBlessed , "is-blessed" );
|
||||
M_SRDPP_COMMAND_DECL( IsMacro ); M_SRDPP_COMMAND_INIT( IsMacro , "is-macro" );
|
||||
M_SRDPP_COMMAND_DECL( IsSet ); M_SRDPP_COMMAND_INIT( IsSet , "is-set" );
|
||||
|
||||
M_SRDPP_COMMAND_DECL( Length ); M_SRDPP_COMMAND_INIT( Length , "length" );
|
||||
M_SRDPP_COMMAND_DECL( ListMacros ); M_SRDPP_COMMAND_INIT_N( ListMacros , "ls-macros" , 0 );
|
||||
M_SRDPP_COMMAND_DECL( ListVariables ); M_SRDPP_COMMAND_INIT_N( ListVariables , "ls-variables" , 0 );
|
||||
|
||||
M_SRDPP_COMMAND_DECL( Mod ); M_SRDPP_COMMAND_INIT( Mod , "mod" );
|
||||
M_SRDPP_COMMAND_DECL( Mul ); M_SRDPP_COMMAND_INIT( Mul , "mul" );
|
||||
|
||||
M_SRDPP_COMMAND_DECL( Neg ); M_SRDPP_COMMAND_INIT( Neg , "neg" );
|
||||
M_SRDPP_COMMAND_DECL( Not ); M_SRDPP_COMMAND_INIT( Not , "not" );
|
||||
|
||||
M_SRDPP_COMMAND_DECL( Or ); M_SRDPP_COMMAND_INIT( Or , "or" );
|
||||
M_SRDPP_COMMAND_DECL( Output ); M_SRDPP_COMMAND_INIT( Output , "output" );
|
||||
|
||||
M_SRDPP_COMMAND_DECL( Raw ); M_SRDPP_COMMAND_INIT_N( Raw , "raw" , 0 );
|
||||
M_SRDPP_COMMAND_DECL( Rethrow ); M_SRDPP_COMMAND_INIT( Rethrow , "rethrow" );
|
||||
|
||||
M_SRDPP_COMMAND_DECL( Scope ); M_SRDPP_COMMAND_INIT_N( Scope , "scope" , 0 );
|
||||
M_SRDPP_COMMAND_DECL( Set ); M_SRDPP_COMMAND_INIT( Set , "set" );
|
||||
M_SRDPP_COMMAND_DECL( SetMacro ); M_SRDPP_COMMAND_INIT( SetMacro , "set-macro" );
|
||||
M_SRDPP_COMMAND_DECL( StartsWith ); M_SRDPP_COMMAND_INIT( StartsWith , "starts-with" );
|
||||
M_SRDPP_COMMAND_DECL( StrFind ); M_SRDPP_COMMAND_INIT( StrFind , "str-find" );
|
||||
M_SRDPP_COMMAND_DECL( StrSplit ); M_SRDPP_COMMAND_INIT( StrSplit , "str-split" );
|
||||
M_SRDPP_COMMAND_DECL( Sub ); M_SRDPP_COMMAND_INIT( Sub , "sub" );
|
||||
M_SRDPP_COMMAND_DECL( Substr ); M_SRDPP_COMMAND_INIT( Substr , "substr" );
|
||||
|
||||
M_SRDPP_COMMAND_DECL( ToSource ); M_SRDPP_COMMAND_INIT( ToSource , "to-source" );
|
||||
M_SRDPP_COMMAND_DECL( Try ); M_SRDPP_COMMAND_INIT_N( Try , "try" , 0 );
|
||||
M_SRDPP_COMMAND_DECL( TypeOf ); M_SRDPP_COMMAND_INIT( TypeOf , "type-of" );
|
||||
|
||||
M_SRDPP_COMMAND_DECL( Unset ); M_SRDPP_COMMAND_INIT( Unset , "unset" );
|
||||
M_SRDPP_COMMAND_DECL( UnsetMacro ); M_SRDPP_COMMAND_INIT( UnsetMacro , "unset-macro" );
|
||||
M_SRDPP_COMMAND_DECL( Unwrap ); M_SRDPP_COMMAND_INIT( Unwrap , "unwrap" );
|
||||
|
||||
M_SRDPP_COMMAND_DECL_OBJ( VFSList , T_VFS& , vfs_ );
|
||||
M_SRDPP_COMMAND_INIT_OBJ( VFSList , "vfs-list" , T_VFS& , vfs_ );
|
||||
M_SRDPP_COMMAND_DECL_OBJ( VFSLoad , T_VFS& , vfs_ );
|
||||
M_SRDPP_COMMAND_INIT_OBJ( VFSLoad , "vfs-load" , T_VFS& , vfs_ );
|
||||
M_SRDPP_COMMAND_DECL_OBJ( VFSType , T_VFS& , vfs_ );
|
||||
M_SRDPP_COMMAND_INIT_OBJ( VFSType , "vfs-type" , T_VFS& , vfs_ );
|
||||
|
||||
M_SRDPP_COMMAND_DECL( Xor ); M_SRDPP_COMMAND_INIT( Xor , "xor" );
|
||||
|
||||
|
||||
} // namespace lw
|
||||
#endif // _H_LW_LIB_SRDPPCOMMANDS
|
90
include/ebcl/SRDParser.hh
Normal file
90
include/ebcl/SRDParser.hh
Normal file
|
@ -0,0 +1,90 @@
|
|||
/******************************************************************************/
|
||||
/* SRD PARSER AND PREPROCESSOR ************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
#include <lw/lib/SRDIO.hh>
|
||||
#include <lw/lib/SRDParserConfig.hh>
|
||||
namespace lw {
|
||||
|
||||
|
||||
// T_SRDParserData - Run-time data passed to the handlers when parsing
|
||||
struct T_SRDParserData
|
||||
{
|
||||
// Parser configuration
|
||||
T_SRDParserConfig const& config;
|
||||
// Error output
|
||||
T_SRDErrors & errors;
|
||||
|
||||
// Input list (if any) for the current rule
|
||||
RPC_SRDList input;
|
||||
|
||||
// Name of the current context
|
||||
T_String currentContext;
|
||||
// Current context's data
|
||||
RP_Variant currentData;
|
||||
|
||||
// Target context when entering or exiting
|
||||
T_String targetContext;
|
||||
// Data for the target context; must be initialised at entrance
|
||||
RP_Variant targetData;
|
||||
|
||||
explicit T_SRDParserData(
|
||||
T_SRDParserConfig const& parser ,
|
||||
T_SRDErrors & errors );
|
||||
};
|
||||
M_CLASS_POINTERS( SRDParserData );
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
// E_SRDFlushMode - How the parser flushes its command list
|
||||
enum class E_SRDFlushMode {
|
||||
MANUAL , // The parser never flushes the command list, it
|
||||
// must be done manually by calling flush()
|
||||
END , // Flush the command list after parsing has been
|
||||
// completed. This is the default.
|
||||
SENTENCE // Flush after each sentence (start() and end()
|
||||
// will also cause flushes)
|
||||
};
|
||||
|
||||
|
||||
// T_SRDParser - The parser's main class
|
||||
class T_SRDParser : public A_SRDReaderTarget , public A_PrivateImplementation
|
||||
{
|
||||
public:
|
||||
T_SRDParser( ) = delete;
|
||||
|
||||
T_SRDParser( T_SRDParserConfig const& cfg );
|
||||
|
||||
void start( T_SRDErrors & errors ) override;
|
||||
void push( T_SRDErrors & errors , T_SRDToken && token ) override;
|
||||
void end( T_SRDErrors & errors ) override;
|
||||
|
||||
// Execute all currently queued commands
|
||||
void flush( );
|
||||
|
||||
// Set/get the flush mode
|
||||
void flushMode( E_SRDFlushMode mode ) noexcept;
|
||||
E_SRDFlushMode flushMode( ) const noexcept;
|
||||
|
||||
// Set/get flush token handling
|
||||
void handleFlushToken( bool handleIt ) noexcept;
|
||||
bool handleFlushToken( ) const noexcept;
|
||||
|
||||
template< typename T >
|
||||
T const& getData( ) const;
|
||||
|
||||
private:
|
||||
T_Variant const& getExecStackTop( ) const;
|
||||
|
||||
};
|
||||
M_CLASS_POINTERS( SRDParser );
|
||||
|
||||
template< typename T >
|
||||
inline T const& T_SRDParser::getData( ) const
|
||||
{
|
||||
return getExecStackTop( ).value< T >( );
|
||||
}
|
||||
|
||||
|
||||
} // namespace
|
99
include/ebcl/SRDParserConfig.hh
Normal file
99
include/ebcl/SRDParserConfig.hh
Normal file
|
@ -0,0 +1,99 @@
|
|||
/******************************************************************************/
|
||||
/* SRD - PARSER CONFIGURATION *************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
#ifndef _H_LW_LIB_SRDPARSERCONFIG
|
||||
#define _H_LW_LIB_SRDPARSERCONFIG
|
||||
#include <lw/lib/SRDDefinitions.hh>
|
||||
#include <lw/lib/Types.hh>
|
||||
namespace lw {
|
||||
|
||||
|
||||
/*= PROCESSED PARSER CONFIGURATION ===========================================*/
|
||||
|
||||
// E_SRDTransitionType - Type of a parser state transition
|
||||
enum class E_SRDTransitionType {
|
||||
WORD ,
|
||||
ENUM ,
|
||||
TOKEN
|
||||
};
|
||||
|
||||
// T_SRDTransition - A parser transition (condition + next state)
|
||||
struct T_SRDTransition
|
||||
{
|
||||
// Match type
|
||||
E_SRDTransitionType type;
|
||||
|
||||
// Match value: word or enum index, or token type.
|
||||
union {
|
||||
uint32_t index;
|
||||
E_SRDTokenType tokenType;
|
||||
};
|
||||
|
||||
// Next state
|
||||
uint32_t next;
|
||||
|
||||
T_SRDTransition( E_SRDTokenType tokenType , uint32_t next );
|
||||
T_SRDTransition( E_SRDTransitionType type , uint32_t index , uint32_t next );
|
||||
};
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
// T_SRDParserConfig - Parser configuration
|
||||
struct T_SRDParserConfig
|
||||
{
|
||||
enum : uint32_t { INVALID_END = 0xffffffff };
|
||||
|
||||
F_SRDHandler onStart;
|
||||
F_SRDHandler onFinish;
|
||||
|
||||
T_Array< T_SRDContext > contexts;
|
||||
T_ObjectTable< T_String , T_SRDEnum > enums;
|
||||
|
||||
// Index of words used in the rules
|
||||
T_HashIndex wordsIndex;
|
||||
T_Array< T_String > words;
|
||||
|
||||
// Start indices for the contexts' automatons
|
||||
T_Array< uint32_t > startStates;
|
||||
|
||||
// End states. Either 0xffffffff for states that are not end states,
|
||||
// or the rule ID for valid end states.
|
||||
T_Array< uint32_t > endStates;
|
||||
|
||||
// State transitions
|
||||
T_MultiArray< T_SRDTransition > transitions;
|
||||
|
||||
// Rule contexts
|
||||
T_MultiArray< uint32_t > ruleContexts;
|
||||
|
||||
T_SRDParserConfig( ) = delete;
|
||||
T_SRDParserConfig( T_SRDParserDefs const& defs );
|
||||
|
||||
// Try to find a transition matching the token
|
||||
bool transition( uint32_t& state , T_SRDToken const& token ) const;
|
||||
|
||||
// Find the value of an enumeration member
|
||||
T_Optional< uint32_t > enumValue( char const* name , T_String const& member ) const noexcept;
|
||||
T_Optional< uint32_t > enumValue( T_String const& name , T_String const& member ) const noexcept;
|
||||
};
|
||||
M_CLASS_POINTERS( SRDParserConfig );
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
// X_SRDParserConfig - Exception indicating that definitions were incorrect
|
||||
class X_SRDParserConfig : public std::exception
|
||||
{
|
||||
private:
|
||||
T_Buffer< char > errorString_;
|
||||
|
||||
public:
|
||||
explicit X_SRDParserConfig( T_StringBuilder const& error );
|
||||
explicit X_SRDParserConfig( T_String const& error );
|
||||
char const * what( ) const noexcept override;
|
||||
};
|
||||
|
||||
|
||||
} // namespace
|
||||
#include <lw/lib/inline/SRDParserConfig.hh>
|
||||
#endif // _H_LW_LIB_SRDPARSERCONFIG
|
93
include/ebcl/SRDText.hh
Normal file
93
include/ebcl/SRDText.hh
Normal file
|
@ -0,0 +1,93 @@
|
|||
/******************************************************************************/
|
||||
/* SRD - TEXT STORAGE *********************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
#ifndef _H_LW_LIB_SRDTEXT
|
||||
#define _H_LW_LIB_SRDTEXT
|
||||
#include <lw/lib/SRDIO.hh>
|
||||
namespace lw {
|
||||
|
||||
|
||||
/*= READER ===================================================================*/
|
||||
|
||||
// Streaming lexer for SRD text
|
||||
class T_SRDLexer : public A_PrivateImplementation
|
||||
{
|
||||
public:
|
||||
T_SRDLexer( ) = delete;
|
||||
T_SRDLexer( T_SRDLexer const& ) = delete;
|
||||
T_SRDLexer( T_SRDLexer&& ) = delete;
|
||||
|
||||
T_SRDLexer( T_String const& name , T_SRDErrors& errors , A_SRDReaderTarget& target );
|
||||
|
||||
void processCharacter( T_Character c );
|
||||
void processEnd( );
|
||||
};
|
||||
M_CLASS_POINTERS( SRDLexer );
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
// Text reader - wraps the lexer inside a SRD reader
|
||||
class T_SRDTextReader : public A_SRDReader
|
||||
{
|
||||
public:
|
||||
T_SRDTextReader( ) = delete;
|
||||
T_SRDTextReader( T_SRDTextReader const& ) = delete;
|
||||
T_SRDTextReader( T_SRDTextReader&& ) = delete;
|
||||
|
||||
T_SRDTextReader( A_SRDReaderTarget& target );
|
||||
void read( T_String const& name , A_InputStream& input ) override;
|
||||
};
|
||||
M_CLASS_POINTERS( SRDTextReader );
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
T_SRDList SRDFromText( T_String const& name , T_String const& string , bool structured = true );
|
||||
T_SRDList SRDFromText( T_String const& name , char const* string , bool structured = true );
|
||||
|
||||
|
||||
/*= WRITER ===================================================================*/
|
||||
|
||||
// T_SRDTextWriter - Writer for the text form of SRD
|
||||
class T_SRDTextWriter : public A_SRDWriter , public A_PrivateImplementation
|
||||
{
|
||||
public:
|
||||
T_SRDTextWriter( ) = delete;
|
||||
T_SRDTextWriter( T_SRDTextWriter const& ) = delete;
|
||||
T_SRDTextWriter( T_SRDTextWriter&& ) = delete;
|
||||
|
||||
explicit T_SRDTextWriter( A_OutputStream& output );
|
||||
|
||||
T_SRDTextWriter& start( ) override;
|
||||
|
||||
T_SRDTextWriter& startList( ) override;
|
||||
T_SRDTextWriter& endList( ) override;
|
||||
|
||||
T_SRDTextWriter& putText( T_String const& text ) override;
|
||||
T_SRDTextWriter& putWord( T_String const& word ) override;
|
||||
T_SRDTextWriter& putString( T_String const& string ) override;
|
||||
|
||||
T_SRDTextWriter& putComment( T_String const& comment ) override;
|
||||
|
||||
T_SRDTextWriter& putVariable( T_String const& variable ) override;
|
||||
|
||||
T_SRDTextWriter& putBinary( T_Buffer< uint8_t > const& binary ) override;
|
||||
|
||||
T_SRDTextWriter& putInteger( int64_t value ) override;
|
||||
T_SRDTextWriter& putInt32( int32_t value ) override;
|
||||
T_SRDTextWriter& putInt64( int64_t value ) override;
|
||||
|
||||
T_SRDTextWriter& putFloat( double value ) override;
|
||||
|
||||
T_SRDTextWriter& end( ) override;
|
||||
};
|
||||
M_CLASS_POINTERS( SRDTextWriter );
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
void SRDWriteAsText( A_OutputStream& output , T_SRDList const& data );
|
||||
|
||||
|
||||
} // namespace
|
||||
#include <lw/lib/inline/SRDText.hh>
|
||||
#endif // _H_LW_LIB_SRDTEXT
|
110
include/ebcl/Streams.hh
Normal file
110
include/ebcl/Streams.hh
Normal file
|
@ -0,0 +1,110 @@
|
|||
/******************************************************************************/
|
||||
/* STREAMS ********************************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
#include <lw/lib/Externals.hh>
|
||||
#include <lw/lib/Utilities.hh>
|
||||
#include <lw/lib/Pointers.hh>
|
||||
#include <lw/lib/Buffers.hh>
|
||||
namespace lw {
|
||||
|
||||
|
||||
/*= STREAM ERRORS ============================================================*/
|
||||
|
||||
enum class E_StreamError {
|
||||
NOT_SUPPORTED , // Operation not supported
|
||||
INVALID_POSITION ,
|
||||
END , // End of stream
|
||||
BAD_DATA , // Invalid data read from the stream
|
||||
SYSTEM_ERROR ,
|
||||
UNAVAILABLE , // Stream is no longer available
|
||||
};
|
||||
|
||||
|
||||
class X_StreamError : public std::exception
|
||||
{
|
||||
private:
|
||||
E_StreamError error_;
|
||||
int sysError_;
|
||||
|
||||
public:
|
||||
explicit X_StreamError( E_StreamError e );
|
||||
explicit X_StreamError( int error );
|
||||
|
||||
X_StreamError( ) = delete;
|
||||
X_StreamError( X_StreamError const& ) = default;
|
||||
X_StreamError( X_StreamError&& ) noexcept = default;
|
||||
virtual X_StreamError& operator= ( X_StreamError const& ) = default;
|
||||
virtual X_StreamError& operator= ( X_StreamError&& ) = default;
|
||||
|
||||
E_StreamError code( ) const;
|
||||
int systemError( ) const;
|
||||
|
||||
char const * what( ) const noexcept;
|
||||
};
|
||||
|
||||
|
||||
/*= BASE ABSTRACT CLASSES FOR STREAMS ========================================*/
|
||||
|
||||
class A_Stream
|
||||
{
|
||||
private:
|
||||
const bool isInput_;
|
||||
const bool knownSize_;
|
||||
|
||||
protected:
|
||||
size_t size_;
|
||||
size_t position_;
|
||||
|
||||
A_Stream( bool isInput , size_t position ) noexcept;
|
||||
A_Stream( bool isInput , size_t position , size_t size ) noexcept;
|
||||
|
||||
public:
|
||||
A_Stream( ) = delete;
|
||||
A_Stream( A_Stream const& ) = delete;
|
||||
A_Stream( A_Stream&& ) = delete;
|
||||
virtual ~A_Stream( ) = 0;
|
||||
|
||||
bool isInput( ) const;
|
||||
bool isSizeKnown( ) const;
|
||||
size_t position( ) const;
|
||||
size_t size( ) const;
|
||||
};
|
||||
|
||||
|
||||
M_ABSTRACT_POINTERS( Stream );
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
class A_InputStream : public A_Stream
|
||||
{
|
||||
protected:
|
||||
explicit A_InputStream( size_t position ) noexcept;
|
||||
A_InputStream( size_t position , size_t size ) noexcept;
|
||||
|
||||
public:
|
||||
virtual size_t read( void* data , size_t size ) = 0;
|
||||
};
|
||||
|
||||
|
||||
M_ABSTRACT_POINTERS( InputStream );
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
class A_OutputStream : public A_Stream
|
||||
{
|
||||
protected:
|
||||
A_OutputStream( size_t position ) noexcept;
|
||||
A_OutputStream( size_t position , size_t size ) noexcept;
|
||||
|
||||
public:
|
||||
virtual size_t write( void const* data , size_t size ) = 0;
|
||||
virtual void flush( );
|
||||
};
|
||||
|
||||
|
||||
M_ABSTRACT_POINTERS( OutputStream );
|
||||
|
||||
} // namespace
|
||||
#include <lw/lib/inline/Streams.hh>
|
457
include/ebcl/Strings.hh
Normal file
457
include/ebcl/Strings.hh
Normal file
|
@ -0,0 +1,457 @@
|
|||
/******************************************************************************/
|
||||
/* STRINGS AND RELATED UTILITIES **********************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
#ifndef _H_LW_LIB_STRINGS
|
||||
#define _H_LW_LIB_STRINGS
|
||||
#include <lw/lib/Externals.hh>
|
||||
#include <lw/lib/Pointers.hh>
|
||||
#include <lw/lib/Arrays.hh>
|
||||
#include <lw/lib/BinaryStreams.hh>
|
||||
namespace lw {
|
||||
|
||||
|
||||
/*= UTF-8 UTILITY FUNCTIONS ==================================================*/
|
||||
|
||||
// Is the specified C string valid UTF-8 ?
|
||||
bool UTF8IsValid( char const* string );
|
||||
|
||||
// Get the length (in characters) of the specified UTF-8 0-terminated string
|
||||
uint32_t UTF8Length( char const* string );
|
||||
|
||||
// Get the size (in bytes) of the specified UTF-8 0-terminated string
|
||||
uint32_t UTF8Size( char const* string );
|
||||
|
||||
// Combined function that does all the above
|
||||
bool UTF8Info( char const* string , uint32_t& size , uint32_t& length );
|
||||
|
||||
// Check if the specified data is a valid UTF-8 string, and compute its length
|
||||
// (in characters).
|
||||
bool UTF8BufferInfo( char const* data , uint32_t size , uint32_t& length );
|
||||
|
||||
// Get the codepoint from a sequence of UTF-8 bytes. Sets "bytes" to the amount
|
||||
// of bytes read from the input.
|
||||
uint32_t UTF8GetCodepoint( char const* data , uint32_t& bytes );
|
||||
|
||||
// Similar to the above, without the amount of bytes output.
|
||||
uint32_t UTF8GetCodepoint( char const* data );
|
||||
|
||||
// Write an UTF-8 encoded codepoint to a string, returns the amount of bytes
|
||||
// that were written, or 0 if there wasn't enough space.
|
||||
uint32_t UTF8PutCodepoint( char* output , uint32_t available , uint32_t codepoint );
|
||||
|
||||
// Get the memory offset of a codepoint in an UTF-8 sequence based on its index.
|
||||
uint32_t UTF8GetMemoryOffset( char const* input , uint32_t index );
|
||||
|
||||
// Convert an UTF-8 sequence into an unsigned integer.
|
||||
uint64_t UTF8ToUnsignedInteger( char const* input , uint32_t size ,
|
||||
bool * ok = nullptr , int base = 10 , bool useSep = false ,
|
||||
uint32_t separator = ' ' );
|
||||
|
||||
// Convert an UTF-8 sequence into a signed integer.
|
||||
int64_t UTF8ToInteger( char const* input , uint32_t size ,
|
||||
bool * ok = nullptr , int base = 10 , bool useSep = false ,
|
||||
uint32_t separator = ' ' );
|
||||
|
||||
// Convert an UTF-8 sequence into a double precision floating point number. The
|
||||
// sequence will be checked, converted into a C string and passed to strtod()
|
||||
// for actual conversion.
|
||||
double UTF8ToDouble( char const* input , uint32_t size ,
|
||||
bool * ok = nullptr , uint32_t decimalPoint = '.' ,
|
||||
bool useSep = false , uint32_t separator = ' ' );
|
||||
|
||||
|
||||
/*= UNICODE CHARACTERS =======================================================*/
|
||||
|
||||
struct T_Character
|
||||
{
|
||||
const uint32_t codepoint;
|
||||
|
||||
T_Character( ) noexcept;
|
||||
T_Character( T_Character const& other ) noexcept;
|
||||
M_WITH_INT( T ) T_Character( T codepoint ) noexcept;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
bool isValid( ) const;
|
||||
bool isAscii( ) const;
|
||||
bool isControl( ) const;
|
||||
bool isUppercase( ) const;
|
||||
bool isLowercase( ) const;
|
||||
bool isAlpha( ) const;
|
||||
bool isNumeric( ) const;
|
||||
bool isAlphanumeric( ) const;
|
||||
bool isWhitespace( ) const;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
bool operator== ( T_Character const& other ) const;
|
||||
bool operator!= ( T_Character const& other ) const;
|
||||
bool operator< ( T_Character const& other ) const;
|
||||
bool operator> ( T_Character const& other ) const;
|
||||
bool operator<= ( T_Character const& other ) const;
|
||||
bool operator>= ( T_Character const& other ) const;
|
||||
|
||||
M_WITH_INT( T ) bool operator== ( T other ) const;
|
||||
M_WITH_INT( T ) bool operator!= ( T other ) const;
|
||||
M_WITH_INT( T ) bool operator< ( T other ) const;
|
||||
M_WITH_INT( T ) bool operator<= ( T other ) const;
|
||||
M_WITH_INT( T ) bool operator> ( T other ) const;
|
||||
M_WITH_INT( T ) bool operator>= ( T other ) const;
|
||||
|
||||
operator uint32_t ( ) const;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
uint32_t writeTo( char* output , uint32_t avail ) const;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
T_Character toUpper( ) const;
|
||||
T_Character toLower( ) const;
|
||||
};
|
||||
|
||||
|
||||
M_CLASS_POINTERS( Character );
|
||||
M_DECLARE_OBJECT_READER( T_Character );
|
||||
M_DECLARE_OBJECT_WRITER( T_Character );
|
||||
|
||||
|
||||
/*= IMMUTABLE UTF8 STRINGS ===================================================*/
|
||||
|
||||
/*
|
||||
* NOTE: the *objects* are NOT immutable. The strings they contain, however,
|
||||
* are.
|
||||
*/
|
||||
|
||||
class T_StringBuilder;
|
||||
class T_StringIterator;
|
||||
|
||||
// T_StringData - Abstract base for the various types of string storage.
|
||||
class A_StringData
|
||||
{
|
||||
protected:
|
||||
char* data_;
|
||||
uint32_t size_;
|
||||
bool valid_;
|
||||
uint32_t length_;
|
||||
|
||||
A_StringData( ) = default;
|
||||
A_StringData( A_StringData const& ) = delete;
|
||||
A_StringData( A_StringData&& ) = delete;
|
||||
|
||||
public:
|
||||
virtual ~A_StringData( ) = 0;
|
||||
|
||||
// Is valid UTF-8?
|
||||
bool valid( ) const;
|
||||
// Get a pointer to the data
|
||||
char const * data( ) const;
|
||||
// Length in characters
|
||||
uint32_t length( ) const;
|
||||
// Size in bytes
|
||||
uint32_t size( ) const;
|
||||
};
|
||||
M_ABSTRACT_POINTERS( StringData );
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
// T_String - Main UTF-8 string class
|
||||
class T_String
|
||||
{
|
||||
private:
|
||||
RP_StringData data_;
|
||||
|
||||
public:
|
||||
// Construct an empty string. No overhead whatsoever, just an assignment
|
||||
T_String( ) noexcept;
|
||||
|
||||
// This constructor will try to:
|
||||
// - use the empty string if initial is null or ""
|
||||
// - use a pooled string if one matches initial
|
||||
// - create a dynamic string otherwise.
|
||||
// Because of this, it is relatively slow and should be avoided in
|
||||
// general.
|
||||
explicit T_String( char const* initial );
|
||||
|
||||
T_String( T_StringBuilder&& sb );
|
||||
T_String( T_StringBuilder const& sb );
|
||||
|
||||
// Construct a dynamic string, either using the provided memory
|
||||
// or duplicating it. Doesn't use the pools at all.
|
||||
T_String( char const* data , uint32_t size , bool nodup = false );
|
||||
|
||||
T_String( T_String const& source );
|
||||
T_String( T_String&& source ) noexcept;
|
||||
|
||||
~T_String( );
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
// Get a pooled string. Faster than constructing then calling
|
||||
// addToPool( ) if the string is already pooled. If it isn't, it will
|
||||
// be added as a dynamic string.
|
||||
static T_String Pooled( char const* string );
|
||||
static T_String Pooled( char const* data , uint32_t size );
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
T_String& operator= ( T_String&& string ) noexcept;
|
||||
T_String& operator= ( T_String const& string );
|
||||
|
||||
T_String& operator= ( T_StringBuilder&& sb );
|
||||
T_String& operator= ( T_StringBuilder const& sb );
|
||||
|
||||
friend void swap( T_String& lhs , T_String& rhs ) noexcept;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
// Adds the string to the pool if it isn't pooled already. If the pool
|
||||
// already contains a pooled version of this string, use it instead.
|
||||
T_String& addToPool( );
|
||||
|
||||
// Attempts to use the pooled version of a string if it exists. If it
|
||||
// doesn't, keep using the current version.
|
||||
T_String& usePool( );
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
bool valid( ) const;
|
||||
uint32_t size( ) const;
|
||||
uint32_t length( ) const;
|
||||
char const * data( ) const;
|
||||
operator bool ( ) const;
|
||||
bool operator! ( ) const;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
// Return the character at the specified index
|
||||
T_Character operator[] ( uint32_t index ) const;
|
||||
|
||||
// Return a substring from the left side of the string
|
||||
T_String left( uint32_t count ) const;
|
||||
// Return a substring from the right side of the string
|
||||
T_String right( uint32_t count ) const;
|
||||
// Return a substring from the specified offset
|
||||
T_String substr( uint32_t offset , uint32_t count = UINT32_MAX ) const;
|
||||
// Return the substring between the two specified offsets
|
||||
T_String range( uint32_t start , uint32_t end ) const;
|
||||
|
||||
// Remove whitespace from the start and end of the string
|
||||
T_String trim( ) const noexcept;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
bool equals( T_String const& other ) const;
|
||||
bool equals( char const* string ) const;
|
||||
|
||||
int32_t compare( T_String const& other ) const;
|
||||
int32_t compareIgnoreCase( T_String const& other ) const;
|
||||
|
||||
bool startsWith( T_String const& other ) const;
|
||||
bool endsWith( T_String const& other ) const;
|
||||
|
||||
// Finds a sub-string. Returns -1 if it isn't found.
|
||||
int32_t find( T_String const& other , uint32_t from = 0 ) const;
|
||||
// Finds a character. Returns -1 if it isn't found.
|
||||
int32_t find( T_Character character , uint32_t from = 0 ) const;
|
||||
|
||||
bool operator== ( T_String const& other ) const;
|
||||
bool operator!= ( T_String const& other ) const;
|
||||
bool operator< ( T_String const& other ) const;
|
||||
bool operator> ( T_String const& other ) const;
|
||||
bool operator>= ( T_String const& other ) const;
|
||||
bool operator<= ( T_String const& other ) const;
|
||||
|
||||
bool operator== ( char const* string ) const;
|
||||
bool operator!= ( char const* string ) const;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
T_String replace( T_Character initial , T_Character replacement ) const;
|
||||
T_String replace( T_String const& initial , T_String const& replacement ) const;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
uint64_t toUnsignedInteger( bool * ok = nullptr , int base = 10 ,
|
||||
bool useSep = false , T_Character separator = ' ' ) const;
|
||||
int64_t toInteger( bool * ok = nullptr , int base = 10 , bool useSep = false ,
|
||||
T_Character separator = ' ' ) const;
|
||||
double toDouble( bool * ok = nullptr , T_Character decimalPoint = '.' ,
|
||||
bool useSep = false , T_Character separator = ' ' ) const;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
T_StringIterator getIterator( uint32_t offset ) const;
|
||||
operator T_StringIterator( ) const;
|
||||
|
||||
// Converts the string to an array of bytes suitable for use with the
|
||||
// operating system's functions (e.g. UTF-8 C string on Linux, or
|
||||
// UTF-16 strings on Windows)
|
||||
T_Buffer< char > toOSString( ) const;
|
||||
};
|
||||
M_CLASS_POINTERS( String );
|
||||
M_DECLARE_HASH( T_String );
|
||||
M_DECLARE_COMPARATOR( T_String );
|
||||
M_DECLARE_OBJECT_READER( T_String );
|
||||
M_DECLARE_OBJECT_WRITER( T_String );
|
||||
|
||||
void swap( T_String& lhs , T_String& rhs ) noexcept;
|
||||
|
||||
extern template class T_Array< T_String >;
|
||||
extern template class T_MultiArray< T_String >;
|
||||
|
||||
|
||||
/*= STRING ITERATORS =========================================================*/
|
||||
|
||||
class T_StringIterator final
|
||||
{
|
||||
friend class T_String;
|
||||
|
||||
private:
|
||||
RP_StringData data_;
|
||||
uint32_t pos_;
|
||||
uint32_t index_;
|
||||
uint32_t codepoint_;
|
||||
uint32_t bytes_;
|
||||
|
||||
T_StringIterator( RP_StringData data , uint32_t index );
|
||||
|
||||
public:
|
||||
T_StringIterator( ) = delete;
|
||||
T_StringIterator( T_StringIterator const& other );
|
||||
T_StringIterator( T_StringIterator&& other ) noexcept;
|
||||
|
||||
~T_StringIterator( );
|
||||
|
||||
T_StringIterator& operator= ( T_StringIterator const& other );
|
||||
T_StringIterator& operator= ( T_StringIterator&& other ) noexcept;
|
||||
|
||||
friend void swap( T_StringIterator& lhs , T_StringIterator& rhs ) noexcept;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
bool next( );
|
||||
|
||||
uint32_t index( ) const;
|
||||
bool atEnd( ) const;
|
||||
|
||||
T_Character character( ) const;
|
||||
operator T_Character ( ) const;
|
||||
};
|
||||
|
||||
|
||||
M_CLASS_POINTERS( StringIterator );
|
||||
void swap( T_StringIterator& lhs , T_StringIterator& rhs ) noexcept;
|
||||
|
||||
|
||||
/*= STRING BUILDERS ==========================================================*/
|
||||
|
||||
class T_StringBuilder
|
||||
{
|
||||
public:
|
||||
enum : uint32_t { C_GROWTH = 32 };
|
||||
|
||||
private:
|
||||
char* data_;
|
||||
uint32_t capacity_;
|
||||
uint32_t size_;
|
||||
uint32_t length_;
|
||||
|
||||
friend class T_String;
|
||||
|
||||
public:
|
||||
T_StringBuilder( ) noexcept;
|
||||
|
||||
T_StringBuilder( T_StringBuilder const& other );
|
||||
T_StringBuilder( T_StringBuilder&& other ) noexcept;
|
||||
|
||||
T_StringBuilder( char const* data , uint32_t size );
|
||||
explicit T_StringBuilder( T_String const& string );
|
||||
explicit T_StringBuilder( char const* string );
|
||||
|
||||
~T_StringBuilder( );
|
||||
|
||||
T_StringBuilder& operator =( T_StringBuilder const& other );
|
||||
T_StringBuilder& operator =( T_StringBuilder&& other ) noexcept;
|
||||
|
||||
friend void swap( T_StringBuilder& lhs , T_StringBuilder& rhs );
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
char const * data( ) const;
|
||||
uint32_t capacity( ) const;
|
||||
uint32_t size( ) const;
|
||||
uint32_t length( ) const;
|
||||
operator bool ( ) const;
|
||||
bool operator! ( ) const;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
T_StringBuilder& ensureCapacity( uint32_t minCap );
|
||||
T_StringBuilder& clear( );
|
||||
T_StringBuilder& free( );
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
T_StringBuilder& append( T_StringBuilder const& other );
|
||||
T_StringBuilder& append( T_StringBuilder&& other );
|
||||
T_StringBuilder& append( T_String const& string );
|
||||
T_StringBuilder& append( char const* string , uint32_t size );
|
||||
T_StringBuilder& append( char character );
|
||||
T_StringBuilder& append( T_Character character );
|
||||
|
||||
T_StringBuilder& appendNumeric( int64_t value , int base = 10 , bool useSep = false ,
|
||||
T_Character sep = ' ' , int sepEvery = 3 );
|
||||
|
||||
T_StringBuilder& appendNumeric( uint64_t value , int base = 10 , bool useSep = false ,
|
||||
T_Character sep = ' ' , int sepEvery = 3 );
|
||||
|
||||
T_StringBuilder& appendDouble( double value , uint32_t precision = 6 , bool trailingZeros = false );
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
bool operator== ( T_StringBuilder const& other ) const;
|
||||
bool operator!= ( T_StringBuilder const& other ) const;
|
||||
|
||||
bool operator== ( T_String const& string ) const;
|
||||
bool operator!= ( T_String const& string ) const;
|
||||
|
||||
bool operator== ( char const* string ) const;
|
||||
bool operator!= ( char const* string ) const;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
uint64_t toUnsignedInteger( bool * ok = nullptr , int base = 10 ,
|
||||
bool useSep = false , T_Character separator = ' ' ) const;
|
||||
int64_t toInteger( bool * ok = nullptr , int base = 10 , bool useSep = false ,
|
||||
T_Character separator = ' ' ) const;
|
||||
double toDouble( bool * ok = nullptr , T_Character decimalPoint = '.' ,
|
||||
bool useSep = false , T_Character separator = ' ' ) const;
|
||||
};
|
||||
|
||||
|
||||
M_CLASS_POINTERS( StringBuilder );
|
||||
M_DECLARE_OBJECT_WRITER( T_StringBuilder );
|
||||
void swap( T_StringBuilder& lhs , T_StringBuilder& rhs );
|
||||
|
||||
// Operator <<
|
||||
M_LSHIFT_OP( T_StringBuilder , T_StringBuilder const& );
|
||||
M_LSHIFT_OP( T_StringBuilder , T_StringBuilder && );
|
||||
M_LSHIFT_OP( T_StringBuilder , T_String const& );
|
||||
M_LSHIFT_OP( T_StringBuilder , char const* );
|
||||
M_LSHIFT_OP( T_StringBuilder , char );
|
||||
M_LSHIFT_OP( T_StringBuilder , T_Character );
|
||||
M_LSHIFT_OP( T_StringBuilder , int16_t );
|
||||
M_LSHIFT_OP( T_StringBuilder , int32_t );
|
||||
M_LSHIFT_OP( T_StringBuilder , int64_t );
|
||||
M_LSHIFT_OP( T_StringBuilder , uint16_t );
|
||||
M_LSHIFT_OP( T_StringBuilder , uint32_t );
|
||||
M_LSHIFT_OP( T_StringBuilder , uint64_t );
|
||||
M_LSHIFT_OP( T_StringBuilder , float );
|
||||
M_LSHIFT_OP( T_StringBuilder , double );
|
||||
|
||||
|
||||
} // namespace
|
||||
#endif // _H_LW_LIB_STRINGS
|
||||
#include <lw/lib/inline/Strings.hh>
|
150
include/ebcl/Threading.hh
Normal file
150
include/ebcl/Threading.hh
Normal file
|
@ -0,0 +1,150 @@
|
|||
/******************************************************************************/
|
||||
/* THREADING ******************************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
#ifndef _H_LW_LIB_THREADING
|
||||
#define _H_LW_LIB_THREADING
|
||||
|
||||
#include <lw/lib/Pointers.hh>
|
||||
#include <lw/lib/Arrays.hh>
|
||||
namespace lw {
|
||||
|
||||
|
||||
/*= ALIASES ==================================================================*/
|
||||
|
||||
using T_Mutex = std::mutex;
|
||||
using T_ScopeLock = std::lock_guard< std::mutex >;
|
||||
using T_ExclusiveLock = std::unique_lock< std::mutex >;
|
||||
using T_Condition = std::condition_variable;
|
||||
using T_Thread = std::thread;
|
||||
|
||||
M_CLASS_POINTERS( Mutex );
|
||||
M_CLASS_POINTERS( ExclusiveLock );
|
||||
M_CLASS_POINTERS( Condition );
|
||||
M_CLASS_POINTERS( Thread );
|
||||
|
||||
|
||||
/*= READ/WRITE LOCKING =======================================================*/
|
||||
|
||||
// A mutex that supports multiple readers and one writer. Based on the
|
||||
// implementation from G++ 6's standard library.
|
||||
class T_ReadWriteMutex
|
||||
{
|
||||
private:
|
||||
static constexpr uint32_t C_WLOCKED_ = 1 << 31;
|
||||
static constexpr uint32_t C_READERS_ = ~C_WLOCKED_;
|
||||
|
||||
T_Mutex mutex_;
|
||||
T_Condition readerBlock_;
|
||||
T_Condition writerBlock_;
|
||||
uint32_t state_;
|
||||
|
||||
public:
|
||||
T_ReadWriteMutex( );
|
||||
T_ReadWriteMutex( T_ReadWriteMutex const& ) = delete;
|
||||
T_ReadWriteMutex( T_ReadWriteMutex&& ) = default;
|
||||
~T_ReadWriteMutex( );
|
||||
|
||||
T_ReadWriteMutex& operator=( T_ReadWriteMutex const& ) = delete;
|
||||
T_ReadWriteMutex& operator=( T_ReadWriteMutex&& ) = default;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
// Write lock
|
||||
void lock( );
|
||||
bool try_lock( );
|
||||
void unlock( );
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
// Read lock
|
||||
void lock_shared( );
|
||||
bool try_lock_shared( );
|
||||
void unlock_shared( );
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
void upgradeLock( );
|
||||
};
|
||||
M_CLASS_POINTERS( ReadWriteMutex );
|
||||
|
||||
|
||||
// Write lock / scoped write lock aliases
|
||||
using T_WriteLock = std::unique_lock< T_ReadWriteMutex >;
|
||||
using T_ScopeWriteLock = std::lock_guard< T_ReadWriteMutex >;
|
||||
M_CLASS_POINTERS( WriteLock );
|
||||
|
||||
|
||||
// Read lock based on std::shared_lock, but that can be
|
||||
// upgraded to a write lock without releasing
|
||||
class T_ReadLock : public std::shared_lock< T_ReadWriteMutex >
|
||||
{
|
||||
public:
|
||||
T_ReadLock( ) noexcept;
|
||||
T_ReadLock( T_ReadLock&& other );
|
||||
explicit T_ReadLock( T_ReadWriteMutex& m );
|
||||
T_ReadLock( T_ReadWriteMutex& m , std::defer_lock_t t );
|
||||
T_ReadLock( T_ReadWriteMutex& m , std::try_to_lock_t t );
|
||||
T_ReadLock( T_ReadWriteMutex& m , std::adopt_lock_t t );
|
||||
|
||||
T_WriteLock upgrade( );
|
||||
};
|
||||
M_CLASS_POINTERS( ReadLock );
|
||||
|
||||
|
||||
/*= RING BUFFER ==============================================================*/
|
||||
|
||||
template< typename ElementType >
|
||||
class T_RingBuffer
|
||||
{
|
||||
private:
|
||||
typedef T_RingBuffer< ElementType > T_Self;
|
||||
|
||||
uint32_t expand_;
|
||||
ElementType * data_;
|
||||
uint32_t allocated_;
|
||||
uint32_t used_;
|
||||
uint32_t readPos_;
|
||||
|
||||
public:
|
||||
M_TEMPLATE_POINTERS( T_Self );
|
||||
|
||||
explicit T_RingBuffer( uint32_t expand = 64 );
|
||||
|
||||
T_RingBuffer( T_Self const& other );
|
||||
T_RingBuffer( T_Self&& other ) noexcept;
|
||||
|
||||
~T_RingBuffer( );
|
||||
|
||||
T_Self& operator=( T_Self const& other );
|
||||
T_Self& operator=( T_Self&& other ) noexcept;
|
||||
|
||||
template< typename T >
|
||||
friend void swap( T_RingBuffer< T >& lhs , T_RingBuffer< T >& rhs ) noexcept;
|
||||
|
||||
void free( );
|
||||
|
||||
uint32_t size( ) const;
|
||||
uint32_t capacity( ) const;
|
||||
uint32_t growth( ) const;
|
||||
|
||||
bool readNext( ElementType& output );
|
||||
bool readAll( T_Array< ElementType >& output );
|
||||
|
||||
void put( ElementType const& input );
|
||||
void put( ElementType&& input );
|
||||
|
||||
template< typename... ArgTypes >
|
||||
void putNew( ArgTypes&&... arguments );
|
||||
|
||||
private:
|
||||
void expand( );
|
||||
};
|
||||
|
||||
template< typename T >
|
||||
void swap( T_RingBuffer< T >& lhs , T_RingBuffer< T >& rhs ) noexcept;
|
||||
|
||||
|
||||
}
|
||||
#endif // _H_LW_LIB_THREADING
|
||||
#include <lw/lib/inline/Threading.hh>
|
498
include/ebcl/Types.hh
Normal file
498
include/ebcl/Types.hh
Normal file
|
@ -0,0 +1,498 @@
|
|||
/******************************************************************************/
|
||||
/* CONTAINER TYPES ************************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
#ifndef _H_LW_LIB_TYPES
|
||||
#define _H_LW_LIB_TYPES
|
||||
#include <lw/lib/Utilities.hh>
|
||||
#include <lw/lib/Pointers.hh>
|
||||
namespace lw {
|
||||
|
||||
|
||||
/*= VARIANT TYPE =============================================================*/
|
||||
|
||||
// Forward declaration of the main variant type
|
||||
template< size_t InPlaceSize = sizeof( void* ) >
|
||||
class T_VariantExt;
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
/* Helper class for the variant type. Contains the handlers for both in-place
|
||||
* and heap-allocated storage.
|
||||
*/
|
||||
struct T_VariantHelper
|
||||
{
|
||||
// Copy handler - Can be used to copy objects, will abort if the
|
||||
// type doesn't support copy construction.
|
||||
template<
|
||||
typename Type ,
|
||||
bool CanCopy = std::is_copy_constructible< Type >::value
|
||||
> struct T_CopyHandler;
|
||||
|
||||
template< typename Type > struct T_CopyHandler< Type , true >
|
||||
{ static void copy( void* , Type const& ); };
|
||||
template< typename Type > struct T_CopyHandler< Type , false >
|
||||
{ static void copy( void* , Type const& ); };
|
||||
|
||||
// Move handler - Can be used to move objects, will abort if the
|
||||
// type doesn't support move construction.
|
||||
template<
|
||||
typename Type ,
|
||||
bool CanMove = std::is_move_constructible< Type >::value
|
||||
> struct T_MoveHandler;
|
||||
|
||||
template< typename Type > struct T_MoveHandler< Type , true >
|
||||
{ static void move( void* , Type& ); };
|
||||
template< typename Type > struct T_MoveHandler< Type , false >
|
||||
{ static void move( void* , Type& ); };
|
||||
|
||||
// E_HandlerMode - Whether a handler uses in-place storage or
|
||||
// heap allocation
|
||||
enum class E_HandlerMode {
|
||||
IN_PLACE ,
|
||||
HEAP_ALLOC
|
||||
};
|
||||
|
||||
// T_HandlerInfo - Information about the handler, used when assigning
|
||||
// between variants with different in-place sizes.
|
||||
struct T_HandlerInfo
|
||||
{
|
||||
size_t size , align;
|
||||
E_HandlerMode mode;
|
||||
};
|
||||
|
||||
// E_HandlerOp - An operation that can be executed by the data handler
|
||||
enum class E_HandlerOp {
|
||||
ALLOC , // Allocate item storage
|
||||
// Arg0: N/A
|
||||
// Arg1: data storage
|
||||
ACCESS , // Access the item
|
||||
// Arg0: data storage
|
||||
// Arg1: pointer to the item
|
||||
DESTRUCT , // Call the item's destructor
|
||||
// Arg0: N/A
|
||||
// Arg1: data storage
|
||||
TYPEID , // Return type information
|
||||
// Arg0: N/A
|
||||
// Arg1: type info
|
||||
COPY , // Create a copy of the item
|
||||
// Arg0: source pointer
|
||||
// Arg1: destination pointer
|
||||
MOVE , // Move the item
|
||||
// Arg0: source pointer
|
||||
// Arg1: destination pointer
|
||||
HINFO , // Return information about the handler
|
||||
// Arg0: N/A
|
||||
// Arg1: handler info
|
||||
MKHDL , // Initialise another handler for the same type
|
||||
// Input: E_HandlerMode
|
||||
// Output: handler pointer
|
||||
};
|
||||
|
||||
// F_Handler - Handler function pointer
|
||||
typedef void (*F_Handler)(
|
||||
E_HandlerOp op ,
|
||||
void const* source ,
|
||||
void* argument );
|
||||
|
||||
// T_InPlaceHandler - Handler for items that can be stored in-place
|
||||
template< typename Type >
|
||||
struct T_InPlaceHandler
|
||||
{
|
||||
template< typename Raw >
|
||||
static void init( void* storage ,
|
||||
F_Handler& handler ,
|
||||
Raw const& value );
|
||||
template< typename Raw >
|
||||
static void init( void* storage ,
|
||||
F_Handler& handler ,
|
||||
Raw&& value );
|
||||
template< typename... Arguments >
|
||||
static void init( Construct< Type > ,
|
||||
void* storage ,
|
||||
F_Handler& handler ,
|
||||
Arguments&&... arguments );
|
||||
|
||||
static void action( E_HandlerOp op ,
|
||||
void const* source ,
|
||||
void* target );
|
||||
};
|
||||
|
||||
// T_HeapHandler - Handler for items that require memory allocation
|
||||
template< typename Type >
|
||||
struct T_HeapHandler
|
||||
{
|
||||
template< typename Raw >
|
||||
static void init( void* storage ,
|
||||
F_Handler& handler ,
|
||||
Raw const& value );
|
||||
template< typename Raw >
|
||||
static void init( void* storage ,
|
||||
F_Handler& handler ,
|
||||
Raw&& value );
|
||||
template< typename... Arguments >
|
||||
static void init( Construct< Type > ,
|
||||
void* storage ,
|
||||
F_Handler& handler ,
|
||||
Arguments&&... arguments );
|
||||
|
||||
static void action( E_HandlerOp op ,
|
||||
void const* source ,
|
||||
void* target );
|
||||
};
|
||||
|
||||
// T_BestHandlerFor - Handler for some item type, based on whether it
|
||||
// requires heap allocation or not.
|
||||
template< typename Type , size_t Size >
|
||||
using T_BestHandlerFor = std::conditional_t<
|
||||
std::is_move_constructible< Type >::value
|
||||
&& sizeof( Type ) <= Size
|
||||
&& alignof( Type ) <= alignof( void* ) ,
|
||||
T_InPlaceHandler< Type > ,
|
||||
T_HeapHandler< Type > >;
|
||||
|
||||
// T_IsVariant - Templated horror to check whether something is a
|
||||
// variant of arbitrary size.
|
||||
template< typename T >
|
||||
struct T_IsVariant
|
||||
{
|
||||
static constexpr bool value = false;
|
||||
};
|
||||
template< size_t S >
|
||||
struct T_IsVariant< T_VariantExt< S > >
|
||||
{
|
||||
static constexpr bool value = true;
|
||||
};
|
||||
|
||||
// T_CanFit - Templated horror that compares two variant's storage sizes.
|
||||
template<
|
||||
size_t A , size_t B
|
||||
> struct T_CanFit
|
||||
{
|
||||
using T_A = T_VariantExt< A >;
|
||||
using T_B = T_VariantExt< B >;
|
||||
static constexpr bool value = T_A::StorageSize <= T_B::StorageSize;
|
||||
};
|
||||
};
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
template< size_t InPlaceSize >
|
||||
class T_VariantExt
|
||||
{
|
||||
template< size_t >
|
||||
friend class T_VariantExt;
|
||||
|
||||
public:
|
||||
using T_Self = T_VariantExt< InPlaceSize >;
|
||||
static constexpr size_t StorageSize
|
||||
= std::max( sizeof( void* ) , InPlaceSize );
|
||||
|
||||
M_TEMPLATE_POINTERS( T_VariantExt );
|
||||
|
||||
private:
|
||||
// T_RawOther_ - Raw type, provided it's not a T_VariantExt
|
||||
template<
|
||||
typename T ,
|
||||
typename Raw = std::decay_t< T >
|
||||
> using T_RawOther_ = std::enable_if_t<
|
||||
!T_VariantHelper::T_IsVariant< Raw >::value , Raw
|
||||
>;
|
||||
|
||||
// T_DataStorage_ - Contains the data or pointer to the data
|
||||
union T_DataStorage_
|
||||
{
|
||||
void* pointer;
|
||||
std::aligned_storage_t< StorageSize , alignof( void* ) > inPlace;
|
||||
|
||||
T_DataStorage_( ) = default;
|
||||
T_DataStorage_( T_DataStorage_ const& ) = delete;
|
||||
T_DataStorage_& operator =( T_DataStorage_ const& ) = delete;
|
||||
};
|
||||
|
||||
// Handler function and storage area
|
||||
T_VariantHelper::F_Handler handler_;
|
||||
T_DataStorage_ storage_;
|
||||
|
||||
public:
|
||||
T_VariantExt( ) noexcept;
|
||||
~T_VariantExt( );
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
// Constructors from other T_VariantExt instances
|
||||
T_VariantExt( T_Self const& other );
|
||||
T_VariantExt( T_Self&& other );
|
||||
template< size_t S >
|
||||
T_VariantExt( T_VariantExt< S > const& other );
|
||||
template< size_t S >
|
||||
T_VariantExt( T_VariantExt< S >&& other );
|
||||
|
||||
// Assignment from other T_VariantExt instances
|
||||
T_Self& operator=( T_Self const& source );
|
||||
T_Self& operator=( T_Self&& source );
|
||||
template< size_t S >
|
||||
T_Self& operator=( T_VariantExt< S > const& source );
|
||||
template< size_t S >
|
||||
T_Self& operator=( T_VariantExt< S >&& source );
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
// Constructors from other types
|
||||
template<
|
||||
typename T ,
|
||||
typename Raw = T_RawOther_< T > ,
|
||||
typename std::enable_if_t< std::is_constructible< Raw , T&& >::value , bool > = true
|
||||
> T_VariantExt( T&& value );
|
||||
template<
|
||||
typename T ,
|
||||
typename Raw = T_RawOther_< T > ,
|
||||
typename std::enable_if_t< !std::is_constructible< Raw , T&& >::value , bool > = false
|
||||
> T_VariantExt( T&& value );
|
||||
|
||||
// Assignment from other types
|
||||
template<
|
||||
typename T ,
|
||||
typename Raw = T_RawOther_< T > ,
|
||||
typename std::enable_if_t< std::is_constructible< Raw , T&& >::value , bool > = true
|
||||
> T_Self& operator= ( T&& value );
|
||||
template<
|
||||
typename T ,
|
||||
typename Raw = T_RawOther_< T > ,
|
||||
typename std::enable_if_t< !std::is_constructible< Raw , T&& >::value , bool > = false
|
||||
> T_Self& operator= ( T&& value );
|
||||
|
||||
// In-place construction for another type
|
||||
template< typename Type , typename... Arguments >
|
||||
void setNew( Arguments&&... arguments );
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
template< size_t A , size_t B >
|
||||
friend void swap(
|
||||
T_VariantExt< A >& lhs ,
|
||||
T_VariantExt< B >& rhs ) noexcept;
|
||||
|
||||
void clear( ) noexcept;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
std::type_info const& typeInfo( ) const;
|
||||
template< typename T >
|
||||
T const& value( ) const;
|
||||
template< typename T >
|
||||
T& value( );
|
||||
|
||||
operator bool( ) const noexcept;
|
||||
bool operator !( ) const noexcept;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
private:
|
||||
// Copy implementation
|
||||
template< size_t S >
|
||||
void copyFrom_( T_VariantExt< S > const& other );
|
||||
|
||||
// Different move implementations based on source size
|
||||
template<
|
||||
size_t S ,
|
||||
std::enable_if_t< T_VariantHelper::T_CanFit< S , InPlaceSize >::value , bool > = true
|
||||
> void moveFrom_( T_VariantExt< S >&& source );
|
||||
template<
|
||||
size_t S ,
|
||||
std::enable_if_t< !T_VariantHelper::T_CanFit< S , InPlaceSize >::value , bool > = false
|
||||
> void moveFrom_( T_VariantExt< S >&& source );
|
||||
};
|
||||
|
||||
using T_Variant = T_VariantExt< >;
|
||||
M_CLASS_POINTERS( Variant );
|
||||
|
||||
|
||||
/*= OPTIONAL TYPE ============================================================*/
|
||||
|
||||
template< typename Type >
|
||||
class T_Optional
|
||||
{
|
||||
private:
|
||||
using T_Self_ = T_Optional< Type >;
|
||||
|
||||
bool present_;
|
||||
std::aligned_storage_t< sizeof( Type ) , alignof( Type ) > storage_;
|
||||
|
||||
public:
|
||||
M_TEMPLATE_POINTERS( T_Optional );
|
||||
|
||||
// Construct as empty
|
||||
constexpr T_Optional( ) noexcept;
|
||||
// Copy/move constructors
|
||||
T_Optional( T_Self_ const& other );
|
||||
T_Optional( T_Self_&& other ) noexcept;
|
||||
// Delete the value if necessary
|
||||
~T_Optional( ) noexcept;
|
||||
|
||||
// Copy/move assignment
|
||||
T_Self_& operator =( T_Self_ const& other );
|
||||
T_Self_& operator =( T_Self_ && other ) noexcept;
|
||||
|
||||
template< typename T >
|
||||
friend M_DECLARE_SWAP( T_Optional< T > );
|
||||
|
||||
// Initialise or assign from values
|
||||
T_Optional( Type const& value );
|
||||
T_Optional( Type&& value ) noexcept;
|
||||
T_Self_& operator =( Type const& value );
|
||||
T_Self_& operator =( Type&& value ) noexcept;
|
||||
|
||||
// Initialise or set to new value
|
||||
template< typename... Arguments >
|
||||
T_Optional( Construct< Type > , Arguments&&... arguments );
|
||||
template< typename... Arguments >
|
||||
void setNew( Arguments&&... arguments );
|
||||
// Clear current value
|
||||
void clear( ) noexcept;
|
||||
|
||||
// Is there a value?
|
||||
constexpr bool present( ) const noexcept;
|
||||
// Pointer to value or nullptr if no value
|
||||
constexpr Type const* target( ) const noexcept;
|
||||
constexpr Type* target( ) noexcept;
|
||||
// Reference to value or std::bad_cast if no value
|
||||
operator Type const&( ) const;
|
||||
operator Type& ( );
|
||||
};
|
||||
|
||||
template< typename Type >
|
||||
M_DECLARE_SWAP( T_Optional< Type > );
|
||||
|
||||
|
||||
/*= UNION TYPE ===============================================================*/
|
||||
|
||||
template< typename... Types >
|
||||
class T_Union
|
||||
{
|
||||
private:
|
||||
static_assert( MetaAnd< CanCopyOrMove< Types >... >::value ,
|
||||
"types must be either copiable or movable" );
|
||||
static_assert( MetaLength< Types... >::value > 0 ,
|
||||
"empty unions are not allowed" );
|
||||
|
||||
using T_Self_ = T_Union< Types... >;
|
||||
using T_Storage_ = std::aligned_union_t< 0 , Types... >;
|
||||
|
||||
// Supported_< T > - Checks whether the type is in the union's type list
|
||||
template< typename T >
|
||||
using Supported_ = MetaContains< T , std::decay_t< Types >... >;
|
||||
// IndexOf_< T > - Finds the type's index in the union's list
|
||||
template< typename T >
|
||||
using IndexOf_ = MetaIndexOf< T , std::decay_t< Types >... >;
|
||||
// GetType_< I > - Finds the type at the specified index in the union's list
|
||||
template< unsigned I >
|
||||
using GetType_ = T_MetaGet< I , std::decay_t< Types >... >;
|
||||
// RawType_< T > - Raw type of one of the union's supported types
|
||||
template< typename T , typename R = std::decay_t< T > >
|
||||
using RawType_ = std::enable_if_t< Supported_< R >::value , R >;
|
||||
|
||||
uint32_t type_;
|
||||
T_Storage_ storage_;
|
||||
|
||||
public:
|
||||
M_TEMPLATE_POINTERS( T_Union );
|
||||
|
||||
// Default constructor - only available if the first type in the union's
|
||||
// type list is default constructible.
|
||||
template<
|
||||
typename T0 = GetType_< 0 > ,
|
||||
typename std::enable_if_t< std::is_default_constructible< T0 >::value , bool > = true
|
||||
> T_Union( );
|
||||
|
||||
// Copy and move constructors - only available if all the types in the
|
||||
// union are copy- or move-constructible, respectively.
|
||||
T_Union( T_Self_ const& other );
|
||||
T_Union( T_Self_&& other ) noexcept;
|
||||
|
||||
~T_Union( );
|
||||
|
||||
// Swap - only available if all the types in the union are
|
||||
// move-constructible
|
||||
template< typename... TL >
|
||||
friend M_DECLARE_SWAP( T_Union< TL... > );
|
||||
|
||||
// Copy and move assignment - only available if all the types in the
|
||||
// union are copy- or move-constructible, respectively.
|
||||
T_Self_& operator =( T_Self_ const& );
|
||||
T_Self_& operator =( T_Self_ && ) noexcept;
|
||||
|
||||
template< typename T , typename... ArgTypes >
|
||||
T_Union( Construct< T > , ArgTypes&&... arguments );
|
||||
|
||||
// Construct from an instance of one of the union's types. Move and copy
|
||||
// are both supported.
|
||||
template<
|
||||
typename T ,
|
||||
typename Raw = RawType_< T > ,
|
||||
typename std::enable_if_t< std::is_constructible< Raw , T&& >::value , bool > = true
|
||||
> T_Union( T&& );
|
||||
template<
|
||||
typename T ,
|
||||
typename Raw = RawType_< T > ,
|
||||
typename std::enable_if_t< !std::is_constructible< Raw , T&& >::value , bool > = false
|
||||
> T_Union( T&& );
|
||||
|
||||
// Assign from an instance of one of the union's types. Move and copy
|
||||
// are both supported.
|
||||
template<
|
||||
typename T ,
|
||||
typename Raw = RawType_< T > ,
|
||||
typename std::enable_if_t< std::is_constructible< Raw , T&& >::value , bool > = true
|
||||
> T_Self_& operator =( T&& );
|
||||
template<
|
||||
typename T ,
|
||||
typename Raw = RawType_< T > ,
|
||||
typename std::enable_if_t< !std::is_constructible< Raw , T&& >::value , bool > = false
|
||||
> T_Self_& operator =( T&& );
|
||||
|
||||
// Checks whether the instance contains an instance of the specified
|
||||
// type
|
||||
template< typename T >
|
||||
constexpr bool hasType( ) const noexcept;
|
||||
// Returns the type information for the instance's current contents
|
||||
std::type_info const& typeInfo( ) const noexcept;
|
||||
|
||||
// Obtains a pointer to the contents; may be nullptr if the union
|
||||
// does not contain an instance of that type at the time
|
||||
template< typename T >
|
||||
constexpr T const* target( ) const noexcept;
|
||||
template< typename T >
|
||||
constexpr T* target( ) noexcept;
|
||||
|
||||
// Obtains a reference to the contents. Will throw std::bad_cast
|
||||
// if the contents' type doesn't match.
|
||||
template< typename T >
|
||||
T const& value( ) const;
|
||||
template< typename T >
|
||||
T& value( );
|
||||
|
||||
private:
|
||||
// Destroying contents
|
||||
void destroy( );
|
||||
template< typename T >
|
||||
static void destroyImpl( T_Storage_* storage );
|
||||
|
||||
// Copying contents
|
||||
void copy( T_Storage_* to ) const;
|
||||
template< typename T >
|
||||
static void copyImpl( T_Storage_ const* from , T_Storage_* to );
|
||||
|
||||
// Moving contents
|
||||
void move( T_Storage_* to );
|
||||
template< typename T >
|
||||
static void moveImpl( T_Storage_* from , T_Storage_* to );
|
||||
};
|
||||
|
||||
template< typename... Types >
|
||||
M_DECLARE_SWAP( T_Union< Types... > );
|
||||
|
||||
|
||||
} // namespace
|
||||
#endif // _H_LW_LIB_TYPES
|
||||
#include <lw/lib/inline/Types.hh>
|
393
include/ebcl/Utilities.hh
Normal file
393
include/ebcl/Utilities.hh
Normal file
|
@ -0,0 +1,393 @@
|
|||
/******************************************************************************/
|
||||
/* VARIOUS UTILITIES **********************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
#ifndef _H_LW_LIB_UTILITIES
|
||||
#define _H_LW_LIB_UTILITIES
|
||||
#include <lw/lib/Externals.hh>
|
||||
namespace lw {
|
||||
|
||||
|
||||
// IsPowerOf2( v ) - Is some integer a power of 2 ?
|
||||
template< typename T >
|
||||
static constexpr bool IsPowerOf2( T value );
|
||||
|
||||
|
||||
/*= TEMPLATED HORRORS ========================================================*/
|
||||
|
||||
// MetaOr< ... > - Logical OR for templates
|
||||
template< typename... >
|
||||
struct MetaOr : std::false_type
|
||||
{ };
|
||||
template< typename T >
|
||||
struct MetaOr< T > : T
|
||||
{ };
|
||||
template< typename T , typename... Rest >
|
||||
struct MetaOr< T , Rest... >
|
||||
: std::conditional_t< bool( T::value ) , T , MetaOr< Rest... > >
|
||||
{ };
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
// MetaAnd< ... > - Logical AND for templates
|
||||
template< typename... >
|
||||
struct MetaAnd : std::true_type
|
||||
{ };
|
||||
template< typename T >
|
||||
struct MetaAnd< T > : T
|
||||
{ };
|
||||
template< typename T , typename... Rest >
|
||||
struct MetaAnd< T , Rest... >
|
||||
: std::conditional_t< bool( T::value ) , MetaAnd< Rest... > , T >
|
||||
{ };
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
// MetaNot< ... > - Logical NOT
|
||||
template< typename T >
|
||||
struct MetaNot : std::integral_constant< bool , !bool( T::value ) >
|
||||
{ };
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
// MetaGet< N , List... > - Get the Nth element in a list
|
||||
template< unsigned , typename... >
|
||||
struct MetaGet { };
|
||||
template< typename T , typename... Rest >
|
||||
struct MetaGet< 0 , T , Rest... >
|
||||
{ using type = T; };
|
||||
template< unsigned N , typename First , typename... Rest >
|
||||
struct MetaGet< N , First , Rest... >
|
||||
: MetaGet< N - 1 , Rest... >
|
||||
{ };
|
||||
template< unsigned N , typename... List >
|
||||
using T_MetaGet = typename MetaGet< N , List... >::type;
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
// MetaLength< List... > - Get the length of a list
|
||||
template< typename... >
|
||||
struct MetaLength
|
||||
: std::integral_constant< unsigned , 0 >
|
||||
{ };
|
||||
template< typename T >
|
||||
struct MetaLength< T >
|
||||
: std::integral_constant< unsigned , 1 >
|
||||
{ };
|
||||
template< typename First , typename... Rest >
|
||||
struct MetaLength< First , Rest... >
|
||||
: std::integral_constant< unsigned , MetaLength< Rest... >::value + 1 >
|
||||
{ };
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
// MetaContains< Type , List... > - Checks whether Type is in List
|
||||
template< typename Type , typename... List >
|
||||
using MetaContains = MetaOr< std::is_same< Type , List >... >;
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
// MetaIndexOf< Type , List... > - Gets the index of Type in List. If Type is
|
||||
// not in the list, the length of the list is returned.
|
||||
template< typename Type , typename... List >
|
||||
struct MetaIndexOf { };
|
||||
template< typename Type >
|
||||
struct MetaIndexOf< Type >
|
||||
: std::integral_constant< unsigned , 0 >
|
||||
{ };
|
||||
template< typename Type , typename First , typename... Rest >
|
||||
struct MetaIndexOf< Type , First , Rest... >
|
||||
: std::conditional_t< std::is_same< Type , First >::value ,
|
||||
std::integral_constant< unsigned , 0 > ,
|
||||
std::integral_constant< unsigned ,
|
||||
MetaIndexOf< Type , Rest... >::value + 1 > >
|
||||
{ };
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
// CanCopyOrMove< Type > - Check whether a type can be copy- or move-constructed.
|
||||
template< typename T >
|
||||
using CanCopyOrMove = MetaOr<
|
||||
std::is_copy_constructible< T > ,
|
||||
std::is_move_constructible< T > >;
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
// CanCopyConsAll< List... > - Checks that all listed types are copy-constructible
|
||||
template< typename... List >
|
||||
using CanCopyConsAll = MetaOr< std::is_copy_constructible< List >... >;
|
||||
|
||||
// CanMoveConsAll< List... > - Checks that all listed types are move-constructible
|
||||
template< typename... List >
|
||||
using CanMoveConsAll = MetaOr< std::is_move_constructible< List >... >;
|
||||
|
||||
// CanCopyAssAll< List... > - Checks that all listed types are copy-constructible
|
||||
template< typename... List >
|
||||
using CanCopyAssAll = MetaOr< std::is_copy_assignable< List >... >;
|
||||
|
||||
// CanMoveAssAll< List... > - Checks that all listed types are move-constructible
|
||||
template< typename... List >
|
||||
using CanMoveAssAll = MetaOr< std::is_move_assignable< List >... >;
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
// EnableForChild< P , C > - Enable if P is a parent class of C, or if P and C
|
||||
// are the same.
|
||||
template<
|
||||
typename Parent ,
|
||||
typename Child
|
||||
>
|
||||
using EnableForChild =
|
||||
std::enable_if<
|
||||
std::is_base_of< Parent , Child >::value ,
|
||||
bool
|
||||
>;
|
||||
|
||||
template< typename C , typename P >
|
||||
using T_EnableForChild = typename EnableForChild<C, P>::type;
|
||||
|
||||
// EnableForParent< C , P > - Enable if P is a parent class of C, and if P and
|
||||
// C are distinct.
|
||||
template<
|
||||
typename Child ,
|
||||
typename Parent
|
||||
>
|
||||
using EnableForParent =
|
||||
std::enable_if<
|
||||
std::is_base_of< Parent , Child >::value
|
||||
&& !std::is_same< Parent , Child >::value ,
|
||||
bool
|
||||
>;
|
||||
|
||||
template< typename C , typename P >
|
||||
using T_EnableForParent = typename EnableForParent<C, P>::type;
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
// Remove const and topmost reference
|
||||
template< typename T >
|
||||
using RemoveConstRef = std::remove_const< std::remove_reference_t< T > >;
|
||||
|
||||
template< typename T >
|
||||
using T_RemoveConstRef = typename RemoveConstRef< T >::type;
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
// T_EnableIfTypesMatch - Make sure that the A type actually matches the V type.
|
||||
template<
|
||||
typename V , typename A ,
|
||||
typename RA = T_RemoveConstRef< A >
|
||||
> using EnableIfTypesMatch =
|
||||
std::enable_if< std::is_same< RA , V >::value , bool >;
|
||||
|
||||
template<
|
||||
typename V , typename A
|
||||
> using T_EnableIfTypesMatch = typename EnableIfTypesMatch< V , A >::type;
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
/* In-place construction tag */
|
||||
template< typename Type >
|
||||
struct Construct
|
||||
{
|
||||
explicit constexpr Construct( ) = default;
|
||||
static constexpr Construct< Type > v = Construct< Type >( );
|
||||
};
|
||||
|
||||
using InPlace = Construct< void >;
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
template< typename T >
|
||||
struct T_CFunc { };
|
||||
|
||||
template< typename RT , typename... AT >
|
||||
struct T_CFunc< RT( AT... ) >
|
||||
{
|
||||
typedef RT (* type )( AT... );
|
||||
};
|
||||
|
||||
template< typename T >
|
||||
using F_CFunc = typename T_CFunc< T >::type;
|
||||
|
||||
|
||||
/*= MACRO HORRORS ============================================================*/
|
||||
|
||||
// M_LSHIFT_OP( Type , Target ) - Declare a left-shift operator using the
|
||||
// specified types
|
||||
#define M_LSHIFT_OP( Type , Target ) \
|
||||
Type & operator<< ( Type& obj , Target value )
|
||||
|
||||
// M_WITH_INT( Name ) - Declare a template with a type that needs to be some
|
||||
// sort of integer.
|
||||
#define M_WITH_INT( Name ) \
|
||||
template< \
|
||||
typename Name , \
|
||||
typename = std::enable_if_t< std::is_integral< Name >::value > \
|
||||
>
|
||||
|
||||
// M_DECLARE_SWAP( Type ) - Declare the swap function for a given type
|
||||
#define M_DECLARE_SWAP( Type ) \
|
||||
void swap( Type& lhs , Type& rhs ) noexcept
|
||||
|
||||
// M_DEFINE_SWAP( Type ) - Define the swap function for a given type
|
||||
#define M_DEFINE_SWAP( Type ) \
|
||||
void lw::swap( Type& lhs , Type& rhs ) noexcept
|
||||
|
||||
|
||||
/*= ENDIAN DETECTION =========================================================*/
|
||||
/*
|
||||
* Unfortunately there's no standard way to do this so we depend on some
|
||||
* GCC-specific stuff.
|
||||
*/
|
||||
|
||||
#ifndef __BYTE_ORDER__
|
||||
# error "We need the __BYTE_ORDER__ macro to exist :("
|
||||
#endif
|
||||
|
||||
enum class E_Endian {
|
||||
LITTLE = __ORDER_LITTLE_ENDIAN__ ,
|
||||
BIG = __ORDER_BIG_ENDIAN__ ,
|
||||
NATIVE = __BYTE_ORDER__
|
||||
};
|
||||
|
||||
|
||||
static constexpr bool IsBigEndian( );
|
||||
static constexpr bool IsLittleEndian( );
|
||||
|
||||
|
||||
/*= ENDIAN CONVERSION ========================================================*/
|
||||
|
||||
template<
|
||||
typename T ,
|
||||
E_Endian E = E_Endian::NATIVE ,
|
||||
typename = std::enable_if_t<
|
||||
std::is_integral< T >::value
|
||||
|| std::is_floating_point< T >::value
|
||||
>
|
||||
>
|
||||
struct T_LittleEndian
|
||||
{
|
||||
static T convert( T value );
|
||||
};
|
||||
|
||||
|
||||
template<
|
||||
typename T ,
|
||||
E_Endian E = E_Endian::NATIVE ,
|
||||
typename = std::enable_if_t<
|
||||
std::is_integral< T >::value
|
||||
|| std::is_floating_point< T >::value
|
||||
>
|
||||
>
|
||||
struct T_BigEndian
|
||||
{
|
||||
static T convert( T value );
|
||||
};
|
||||
|
||||
|
||||
/*= COMPARATORS AND SORTING ==================================================*/
|
||||
|
||||
// F_Comparator< T > - T_Comparator function type
|
||||
template< typename T >
|
||||
using F_Comparator = std::function< int( T const& a , T const& b ) >;
|
||||
|
||||
// T_Comparator< T > - Default comparison function implementation
|
||||
template< typename T >
|
||||
struct T_Comparator
|
||||
{
|
||||
static int compare( T const& a , T const& b );
|
||||
};
|
||||
|
||||
|
||||
// Helper macros to declare and define specialised hash functions.
|
||||
#define M_DECLARE_COMPARATOR( Type ) \
|
||||
template< > \
|
||||
struct T_Comparator< Type > \
|
||||
{ \
|
||||
static int compare( Type const& , Type const& ); \
|
||||
}
|
||||
|
||||
|
||||
#define M_DEFINE_COMPARATOR( Type ) \
|
||||
int T_Comparator< Type >::compare( Type const & a , Type const & b )
|
||||
|
||||
// Instantiate some commonly used comparators
|
||||
extern template struct T_Comparator< uint32_t >;
|
||||
|
||||
// Sort - Sort an array
|
||||
template< typename T >
|
||||
void Sort( T* array , uint32_t items , F_Comparator< T > comparator = T_Comparator< T >::compare );
|
||||
|
||||
|
||||
/*= HASHING ==================================================================*/
|
||||
|
||||
// HashData( data , size ) - General hash function (Jenkin's one-at-a-time)
|
||||
uint32_t HashData( uint8_t const* data , uint32_t size );
|
||||
|
||||
// Hash function template struct. Meant to be specialized. By default it uses
|
||||
// the function above.
|
||||
template< typename T , int S = sizeof( T ) >
|
||||
struct T_HashFunction
|
||||
{
|
||||
static uint32_t hash( T const& item );
|
||||
};
|
||||
|
||||
|
||||
// ComputeHash( T ) - The actual hash function.
|
||||
template< typename T >
|
||||
uint32_t ComputeHash( T const& item );
|
||||
|
||||
// Helper macros to declare and define specialised hash functions.
|
||||
#define M_DECLARE_HASH( Type ) \
|
||||
template< > \
|
||||
struct T_HashFunction< Type > \
|
||||
{ \
|
||||
static uint32_t hash( Type const& ); \
|
||||
}
|
||||
|
||||
|
||||
#define M_DEFINE_HASH( Type ) \
|
||||
uint32_t T_HashFunction< Type >::hash( Type const & item )
|
||||
|
||||
|
||||
/*= PRIVATE IMPLEMENTATION BASE ==============================================*/
|
||||
|
||||
/* This class should be used as a base class for any non-performance-critical
|
||||
* class that contains a lot of private stuff. The idea is to limit the amount
|
||||
* of stuff exposed through the API, which in turns makes binary compatibility
|
||||
* somewhat easier.
|
||||
*/
|
||||
class A_PrivateImplementation
|
||||
{
|
||||
private:
|
||||
using T_Destructor_ = std::function< void( void* ) >;
|
||||
void* p_;
|
||||
T_Destructor_ piDestructor_;
|
||||
|
||||
protected:
|
||||
A_PrivateImplementation( ) = delete;
|
||||
A_PrivateImplementation( A_PrivateImplementation const& ) = delete;
|
||||
A_PrivateImplementation& operator=( A_PrivateImplementation const& ) = delete;
|
||||
|
||||
A_PrivateImplementation( void* p , T_Destructor_ destructor );
|
||||
template< typename T >
|
||||
explicit A_PrivateImplementation( T* p );
|
||||
A_PrivateImplementation( A_PrivateImplementation&& ) noexcept;
|
||||
A_PrivateImplementation& operator=( A_PrivateImplementation&& ) noexcept;
|
||||
|
||||
public:
|
||||
virtual ~A_PrivateImplementation( );
|
||||
|
||||
protected:
|
||||
template< typename T >
|
||||
T& p( ) const;
|
||||
|
||||
private:
|
||||
void callPrivateDestructor( ) noexcept;
|
||||
};
|
||||
|
||||
|
||||
} // namespace
|
||||
#endif // _H_LW_LIB_UTILITIES
|
||||
#include <lw/lib/inline/Utilities.hh>
|
19
include/ebcl/Version.hh
Normal file
19
include/ebcl/Version.hh
Normal file
|
@ -0,0 +1,19 @@
|
|||
/******************************************************************************/
|
||||
/* VERSION NUMBERS ************************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
#ifndef _H_LW_LIB_VERSION
|
||||
#define _H_LW_LIB_VERSION
|
||||
#include <lw/lib/Externals.hh>
|
||||
namespace lw {
|
||||
|
||||
|
||||
static constexpr inline uint32_t LibVersion( )
|
||||
{ return 0; }
|
||||
|
||||
static constexpr inline uint32_t LibRevision( )
|
||||
{ return 0; }
|
||||
|
||||
|
||||
}
|
||||
#endif // _H_LW_LIB_VERSION
|
19
include/ebcl/Version.hh.in
Normal file
19
include/ebcl/Version.hh.in
Normal file
|
@ -0,0 +1,19 @@
|
|||
/******************************************************************************/
|
||||
/* VERSION NUMBERS ************************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
#ifndef _H_LW_LIB_VERSION
|
||||
#define _H_LW_LIB_VERSION
|
||||
#include <lw/lib/Externals.hh>
|
||||
namespace lw {
|
||||
|
||||
|
||||
static constexpr inline uint32_t LibVersion( )
|
||||
{ return __VERSION__; }
|
||||
|
||||
static constexpr inline uint32_t LibRevision( )
|
||||
{ return __REVISION__; }
|
||||
|
||||
|
||||
}
|
||||
#endif // _H_LW_LIB_VERSION
|
376
include/ebcl/inline/Alloc.hh
Normal file
376
include/ebcl/inline/Alloc.hh
Normal file
|
@ -0,0 +1,376 @@
|
|||
/******************************************************************************/
|
||||
/* ALLOCATORS - INLINE CODE ***************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
#ifndef _H_LW_LIB_INLINE_ALLOC
|
||||
#define _H_LW_LIB_INLINE_ALLOC
|
||||
#include <lw/lib/Alloc.hh>
|
||||
namespace lw {
|
||||
|
||||
|
||||
/*= T_PoolHelper::T_List =====================================================*/
|
||||
|
||||
template< typename T , size_t P >
|
||||
inline T_PoolHelper::T_List< T , P >::T_List(
|
||||
T_List< T , P >*& n ) noexcept
|
||||
: next( n ) , free( P )
|
||||
{
|
||||
for ( size_t i = 0 ; i < P ; i ++ ) {
|
||||
storage[ i ].list = this;
|
||||
}
|
||||
for ( size_t i = 0 ; i < BitmapSize ; i ++ ) {
|
||||
bitmap[ i ] = 0;
|
||||
}
|
||||
n = this;
|
||||
}
|
||||
|
||||
template< typename T , size_t P >
|
||||
inline T* T_PoolHelper::T_List< T , P >::findUnused( ) noexcept
|
||||
{
|
||||
size_t i = 0;
|
||||
while ( bitmap[ i ] == 255 ) {
|
||||
assert( i < BitmapSize );
|
||||
i ++;
|
||||
}
|
||||
|
||||
size_t j = 0;
|
||||
while ( ( bitmap[ i ] & ( 1 << j ) ) != 0 ) {
|
||||
j ++;
|
||||
}
|
||||
assert( i * 8 + j < P );
|
||||
|
||||
bitmap[ i ] = bitmap[ i ] | ( 1 << j );
|
||||
free --;
|
||||
return &storage[ i * 8 + j ];
|
||||
}
|
||||
|
||||
template< typename T , size_t P >
|
||||
inline size_t T_PoolHelper::T_List< T , P >::indexOf(
|
||||
T const* const item ) noexcept
|
||||
{
|
||||
assert( item >= &storage[ 0 ] );
|
||||
const size_t offset( ( (char*) item ) - ( (char*) &storage[ 0 ] ) );
|
||||
assert( offset % sizeof( T ) == 0 );
|
||||
const size_t index( offset / sizeof( T ) );
|
||||
assert( index < P );
|
||||
return index;
|
||||
}
|
||||
|
||||
template< typename T , size_t P >
|
||||
inline void T_PoolHelper::T_List< T , P >::destroy(
|
||||
T_List< T , P >*& head ) noexcept
|
||||
{
|
||||
while ( head != nullptr ) {
|
||||
T_Self* const n( head->next );
|
||||
delete head;
|
||||
head = n;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*= T_PoolHelper::T_Allocator ================================================*/
|
||||
|
||||
template< typename T , size_t P , size_t M >
|
||||
inline T_PoolHelper::T_Allocator< T , P , M >::T_Allocator( ) noexcept
|
||||
: free_( nullptr ) , partial_( nullptr ) , full_( nullptr ) ,
|
||||
nFree_( 1 )
|
||||
{
|
||||
new T_List_( free_ );
|
||||
}
|
||||
|
||||
template< typename T , size_t P , size_t M >
|
||||
inline T_PoolHelper::T_Allocator< T , P , M >::~T_Allocator( )
|
||||
{
|
||||
T_List_::destroy( free_ );
|
||||
T_List_::destroy( partial_ );
|
||||
T_List_::destroy( full_ );
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
template< typename T , size_t P , size_t M >
|
||||
inline T* T_PoolHelper::T_Allocator< T , P , M >::allocate( ) noexcept
|
||||
{
|
||||
if ( partial_ == nullptr ) {
|
||||
if ( free_ == nullptr ) {
|
||||
new T_List_( partial_ );
|
||||
} else {
|
||||
assert( nFree_ > 0 );
|
||||
partial_ = free_;
|
||||
free_ = free_->next;
|
||||
partial_->next = nullptr;
|
||||
nFree_ --;
|
||||
}
|
||||
}
|
||||
|
||||
T* const data( partial_->findUnused( ) );
|
||||
if ( partial_->free == 0 ) {
|
||||
T_List_* const nf( partial_ );
|
||||
partial_ = nf->next;
|
||||
nf->next = full_;
|
||||
full_ = nf;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
template< typename T , size_t P , size_t M >
|
||||
void T_PoolHelper::T_Allocator< T , P , M >::free(
|
||||
T* const item ) noexcept
|
||||
{
|
||||
T_List_* const list( reinterpret_cast< T_List_* >( item->list ) );
|
||||
const size_t index( list->indexOf( item ) );
|
||||
|
||||
list->bitmap[ index / 8 ] = list->bitmap[ index / 8 ] & ~( 1 << ( index & 7 ) );
|
||||
list->free ++;
|
||||
|
||||
if ( list->free == 1 ) {
|
||||
// Full list is now partial
|
||||
moveList( list , full_ , partial_ );
|
||||
} else if ( list->free == P ) {
|
||||
// Partial list is now free
|
||||
if ( nFree_ == M ) {
|
||||
T_List_* p( nullptr );
|
||||
moveList( list , partial_ , p );
|
||||
delete list;
|
||||
} else {
|
||||
moveList( list , partial_ , free_ );
|
||||
nFree_ ++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
template< typename T , size_t P , size_t M >
|
||||
size_t T_PoolHelper::T_Allocator< T , P , M >::countFreeLists( ) const noexcept
|
||||
{
|
||||
return nFree_;
|
||||
}
|
||||
|
||||
template< typename T , size_t P , size_t M >
|
||||
size_t T_PoolHelper::T_Allocator< T , P , M >::countPartialLists( ) const noexcept
|
||||
{
|
||||
return countLists( partial_ );
|
||||
}
|
||||
|
||||
template< typename T , size_t P , size_t M >
|
||||
size_t T_PoolHelper::T_Allocator< T , P , M >::countFullLists( ) const noexcept
|
||||
{
|
||||
return countLists( full_ );
|
||||
}
|
||||
|
||||
template< typename T , size_t P , size_t M >
|
||||
void T_PoolHelper::T_Allocator< T , P , M >::getUsage(
|
||||
size_t& total ,
|
||||
size_t& free ,
|
||||
size_t& used ) const noexcept
|
||||
{
|
||||
free = countFreeLists( ) * P;
|
||||
used = countFullLists( ) * P;
|
||||
total = free + used;
|
||||
|
||||
T_List_ const* p( partial_ );
|
||||
while ( p != nullptr ) {
|
||||
free += p->free;
|
||||
used += P - p->free;
|
||||
total += P;
|
||||
p = p->next;
|
||||
}
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
template< typename T , size_t P , size_t M >
|
||||
void T_PoolHelper::T_Allocator< T , P , M >::moveList(
|
||||
T_List_* const list ,
|
||||
T_List_*& from ,
|
||||
T_List_*& to ) noexcept
|
||||
{
|
||||
T_List_** ptr( &from );
|
||||
while ( *ptr != list ) {
|
||||
ptr = &( (*ptr)->next );
|
||||
assert( *ptr != nullptr );
|
||||
}
|
||||
*ptr = list->next;
|
||||
list->next = to;
|
||||
to = list;
|
||||
}
|
||||
|
||||
template< typename T , size_t P , size_t M >
|
||||
size_t T_PoolHelper::T_Allocator< T , P , M >::countLists(
|
||||
T_List_ const* head ) noexcept
|
||||
{
|
||||
size_t nLists( 0 );
|
||||
while ( head != nullptr ) {
|
||||
nLists ++;
|
||||
head = head->next;
|
||||
}
|
||||
return nLists;
|
||||
}
|
||||
|
||||
|
||||
/*= T_PoolAllocator ==========================================================*/
|
||||
|
||||
template< size_t OS , size_t OA , size_t P , size_t M >
|
||||
inline void* T_PoolAllocator< OS , OA , P , M >::allocate(
|
||||
const size_t requested ) noexcept
|
||||
{
|
||||
#ifdef LW_CFG_NO_ALLOCATORS
|
||||
return ::operator new( requested );
|
||||
#else
|
||||
assert( requested <= OS );
|
||||
return reinterpret_cast< char* >( alloc_.allocate( ) );
|
||||
#endif
|
||||
}
|
||||
|
||||
template< size_t OS , size_t OA , size_t P , size_t M >
|
||||
void T_PoolAllocator< OS , OA , P , M >::free(
|
||||
void* const item ) noexcept
|
||||
{
|
||||
#ifdef LW_CFG_NO_ALLOCATORS
|
||||
::operator delete( item );
|
||||
#else
|
||||
alloc_.free( reinterpret_cast< T_Storage_* >( item ) );
|
||||
#endif
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
template< size_t OS , size_t OA , size_t P , size_t M >
|
||||
size_t T_PoolAllocator< OS , OA , P , M >::countFreeLists( ) const noexcept
|
||||
{
|
||||
return alloc_.countFreeLists( );
|
||||
}
|
||||
|
||||
template< size_t OS , size_t OA , size_t P , size_t M >
|
||||
size_t T_PoolAllocator< OS , OA , P , M >::countPartialLists( ) const noexcept
|
||||
{
|
||||
return alloc_.countPartialLists( );
|
||||
}
|
||||
|
||||
template< size_t OS , size_t OA , size_t P , size_t M >
|
||||
size_t T_PoolAllocator< OS , OA , P , M >::countFullLists( ) const noexcept
|
||||
{
|
||||
return alloc_.countFullLists( );
|
||||
}
|
||||
|
||||
template< size_t OS , size_t OA , size_t P , size_t M >
|
||||
void T_PoolAllocator< OS , OA , P , M >::getUsage(
|
||||
size_t& total ,
|
||||
size_t& free ,
|
||||
size_t& used ) const noexcept
|
||||
{
|
||||
return alloc_.getUsage( total , free , used );
|
||||
}
|
||||
|
||||
|
||||
/*= T_ThreadedPoolAllocator ==================================================*/
|
||||
|
||||
template< size_t OS , size_t OA , size_t P , size_t M >
|
||||
inline void* T_ThreadedPoolAllocator< OS , OA , P , M >::allocate(
|
||||
const size_t requested ) noexcept
|
||||
{
|
||||
#ifdef LW_CFG_NO_ALLOCATORS
|
||||
return ::operator new( requested );
|
||||
#else
|
||||
assert( requested <= OS );
|
||||
|
||||
T_Storage_* const alloc( ([this](){
|
||||
T_Storage_* const fs( takeFromStack( ) );
|
||||
return fs ? fs : alloc_.allocate( );
|
||||
})() );
|
||||
alloc->extra.pool = this;
|
||||
return reinterpret_cast< char* >( alloc );
|
||||
#endif
|
||||
}
|
||||
|
||||
template< size_t OS , size_t OA , size_t P , size_t M >
|
||||
void T_ThreadedPoolAllocator< OS , OA , P , M >::free(
|
||||
void* const item ) noexcept
|
||||
{
|
||||
#ifdef LW_CFG_NO_ALLOCATORS
|
||||
::operator delete( item );
|
||||
#else
|
||||
T_Storage_* const storage( reinterpret_cast< T_Storage_* >( item ) );
|
||||
if ( storage->extra.pool == this ) {
|
||||
alloc_.free( storage );
|
||||
} else {
|
||||
storage->extra.pool->addToStack( storage );
|
||||
}
|
||||
|
||||
T_Storage_* const fs( takeFromStack( ) );
|
||||
if ( fs ) {
|
||||
alloc_.free( fs );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
template< size_t OS , size_t OA , size_t P , size_t M >
|
||||
size_t T_ThreadedPoolAllocator< OS , OA , P , M >::countFreeLists( ) const noexcept
|
||||
{
|
||||
return alloc_.countFreeLists( );
|
||||
}
|
||||
|
||||
template< size_t OS , size_t OA , size_t P , size_t M >
|
||||
size_t T_ThreadedPoolAllocator< OS , OA , P , M >::countPartialLists( ) const noexcept
|
||||
{
|
||||
return alloc_.countPartialLists( );
|
||||
}
|
||||
|
||||
template< size_t OS , size_t OA , size_t P , size_t M >
|
||||
size_t T_ThreadedPoolAllocator< OS , OA , P , M >::countFullLists( ) const noexcept
|
||||
{
|
||||
return alloc_.countFullLists( );
|
||||
}
|
||||
|
||||
template< size_t OS , size_t OA , size_t P , size_t M >
|
||||
void T_ThreadedPoolAllocator< OS , OA , P , M >::getUsage(
|
||||
size_t& total ,
|
||||
size_t& free ,
|
||||
size_t& used ) const noexcept
|
||||
{
|
||||
return alloc_.getUsage( total , free , used );
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
template< size_t OS , size_t OA , size_t P , size_t M >
|
||||
typename T_ThreadedPoolAllocator< OS , OA , P , M >::T_Storage_*
|
||||
T_ThreadedPoolAllocator< OS , OA , P , M >::takeFromStack( ) noexcept
|
||||
{
|
||||
T_FreeHead_ o( freeHead_.load( std::memory_order_relaxed ) );
|
||||
if ( o.head == nullptr ) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
T_FreeHead_ next;
|
||||
do {
|
||||
next.aba = o.aba + 1;
|
||||
next.head = o.head->extra.next;
|
||||
} while ( !freeHead_.compare_exchange_weak( o , next ,
|
||||
std::memory_order_acq_rel ,
|
||||
std::memory_order_acquire ) );
|
||||
return o.head;
|
||||
}
|
||||
|
||||
template< size_t OS , size_t OA , size_t P , size_t M >
|
||||
void T_ThreadedPoolAllocator< OS , OA , P , M >::addToStack(
|
||||
T_Storage_* storage ) noexcept
|
||||
{
|
||||
assert( storage->extra.pool == this );
|
||||
T_FreeHead_ o( freeHead_.load( std::memory_order_relaxed ) );
|
||||
T_FreeHead_ r;
|
||||
do {
|
||||
storage->extra.next = o.head;
|
||||
r.aba = o.aba + 1;
|
||||
r.head = storage;
|
||||
} while ( !freeHead_.compare_exchange_weak( o , r ,
|
||||
std::memory_order_acq_rel ,
|
||||
std::memory_order_acquire ) );
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
#endif //_H_LW_LIB_INLINE_ALLOC
|
1594
include/ebcl/inline/Arrays.hh
Normal file
1594
include/ebcl/inline/Arrays.hh
Normal file
File diff suppressed because it is too large
Load diff
145
include/ebcl/inline/BinaryStreams.hh
Normal file
145
include/ebcl/inline/BinaryStreams.hh
Normal file
|
@ -0,0 +1,145 @@
|
|||
/******************************************************************************/
|
||||
/* BINARY READER/WRITER FOR STREAMS - INLINE CODE *****************************/
|
||||
/******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
#include <lw/lib/BinaryStreams.hh>
|
||||
namespace lw {
|
||||
|
||||
|
||||
/*= T_BinaryReader ===========================================================*/
|
||||
|
||||
inline T_BinaryReader::T_BinaryReader( A_InputStream& stream , E_Endian endian ) noexcept
|
||||
: stream_( stream ) , endian_( endian )
|
||||
{ }
|
||||
|
||||
inline A_InputStream& T_BinaryReader::stream( ) const
|
||||
{
|
||||
return stream_;
|
||||
}
|
||||
|
||||
inline E_Endian T_BinaryReader::endian( ) const
|
||||
{
|
||||
return endian_;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
template< typename T >
|
||||
inline T T_BinaryReader::readNumericNative( ) const
|
||||
{
|
||||
static_assert( std::is_integral< T >( ) || std::is_floating_point< T >( ) ,
|
||||
"numeric type expected" );
|
||||
T value = 0;
|
||||
auto r = stream_.read( &value , sizeof( T ) );
|
||||
if ( r != sizeof( T ) ) {
|
||||
throw X_StreamError( E_StreamError::BAD_DATA );
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
inline T T_BinaryReader::readNumericLittleEndian( ) const
|
||||
{
|
||||
return T_LittleEndian< T >::convert( readNumericNative< T >( ) );
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
inline T T_BinaryReader::readNumericBigEndian( ) const
|
||||
{
|
||||
return T_BigEndian< T >::convert( readNumericNative< T >( ) );
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
inline T T_BinaryReader::read( ) const
|
||||
{
|
||||
return T_Reader_< T >::read( *this );
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
template< typename T >
|
||||
inline T T_BinaryReader::T_Reader_< T , true >::read( T_BinaryReader const& reader )
|
||||
{
|
||||
if ( reader.endian_ == E_Endian::BIG ) {
|
||||
return reader.readNumericBigEndian< T >( );
|
||||
} else {
|
||||
return reader.readNumericLittleEndian< T >( );
|
||||
}
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
inline T T_BinaryReader::T_Reader_< T , false >::read( T_BinaryReader const& reader )
|
||||
{
|
||||
typedef T_ObjectReader< T > Reader;
|
||||
return Reader::read( reader );
|
||||
}
|
||||
|
||||
|
||||
/*= T_BinaryWriter ===========================================================*/
|
||||
|
||||
inline T_BinaryWriter::T_BinaryWriter( A_OutputStream& stream , E_Endian endian ) noexcept
|
||||
: stream_( stream ) , endian_( endian )
|
||||
{ }
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
inline A_OutputStream& T_BinaryWriter::stream( ) const
|
||||
{
|
||||
return stream_;
|
||||
}
|
||||
|
||||
inline E_Endian T_BinaryWriter::endian( ) const
|
||||
{
|
||||
return endian_;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
template< typename T >
|
||||
inline void T_BinaryWriter::writeNumericNative( T value ) const
|
||||
{
|
||||
static_assert( std::is_integral< T >( ) || std::is_floating_point< T >( ) ,
|
||||
"numeric type expected" );
|
||||
stream_.write( &value , sizeof( T ) );
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
inline void T_BinaryWriter::writeNumericLittleEndian( T const& value ) const
|
||||
{
|
||||
writeNumericNative( T_LittleEndian< T >::convert( value ) );
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
inline void T_BinaryWriter::writeNumericBigEndian( T const& value ) const
|
||||
{
|
||||
writeNumericNative( T_BigEndian< T >::convert( value ) );
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
inline void T_BinaryWriter::write( T const& value ) const
|
||||
{
|
||||
T_Writer_< T >::write( *this , value );
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
template< typename T >
|
||||
inline void T_BinaryWriter::T_Writer_< T , true >::write( T_BinaryWriter const& writer , T value )
|
||||
{
|
||||
if ( writer.endian_ == E_Endian::BIG ) {
|
||||
writer.writeNumericBigEndian( value );
|
||||
} else {
|
||||
writer.writeNumericLittleEndian( value );
|
||||
}
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
inline void T_BinaryWriter::T_Writer_< T , false >::write( T_BinaryWriter const& writer , T const& value )
|
||||
{
|
||||
typedef T_ObjectWriter< T > Writer;
|
||||
Writer::write( writer , value );
|
||||
}
|
||||
|
||||
|
||||
} // namespace
|
263
include/ebcl/inline/Buffers.hh
Normal file
263
include/ebcl/inline/Buffers.hh
Normal file
|
@ -0,0 +1,263 @@
|
|||
/******************************************************************************/
|
||||
/* BUFFERS - INLINE CODE ******************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
#include <lw/lib/Buffers.hh>
|
||||
namespace lw {
|
||||
|
||||
|
||||
/*= T_BufferBase =============================================================*/
|
||||
|
||||
inline T_BufferBase::T_BufferBase( uint8_t* buffer ) noexcept
|
||||
: data_( buffer )
|
||||
{ }
|
||||
|
||||
inline T_BufferBase::T_BufferBase( size_t size )
|
||||
: data_( ( uint8_t* ) malloc( size ) )
|
||||
{
|
||||
if ( size != 0 && data_ == nullptr ) {
|
||||
throw std::bad_alloc( );
|
||||
}
|
||||
}
|
||||
|
||||
inline T_BufferBase::T_BufferBase( T_BufferBase&& source ) noexcept
|
||||
: T_BufferBase( nullptr )
|
||||
{
|
||||
swap( *this , source );
|
||||
}
|
||||
|
||||
inline T_BufferBase::~T_BufferBase( )
|
||||
{
|
||||
free( data_ );
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
inline void swap( T_BufferBase& lhs , T_BufferBase& rhs )
|
||||
{
|
||||
using std::swap;
|
||||
swap( lhs.data_ , rhs.data_ );
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
inline uint8_t* T_BufferBase::data( ) const
|
||||
{
|
||||
return data_;
|
||||
}
|
||||
|
||||
|
||||
/*= T_FixedBuffer ============================================================*/
|
||||
|
||||
template< size_t S , typename T >
|
||||
inline T_FixedBuffer< S , T >::T_FixedBuffer( )
|
||||
: T_BufferBase( BYTES_ )
|
||||
{ }
|
||||
|
||||
template< size_t S , typename T >
|
||||
inline T_FixedBuffer< S , T >::T_FixedBuffer(
|
||||
T_FixedBuffer< S , T >&& source ) noexcept
|
||||
: T_BufferBase( std::move( source ) )
|
||||
{ }
|
||||
|
||||
template< size_t S , typename T >
|
||||
inline T_FixedBuffer< S , T >::T_FixedBuffer(
|
||||
T_FixedBuffer< S , T > const& source )
|
||||
: T_BufferBase( BYTES_ )
|
||||
{
|
||||
*this = source;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
template< size_t S , typename T >
|
||||
inline T_FixedBuffer< S , T >& T_FixedBuffer< S , T >::operator= ( T_FixedBuffer< S , T > const& other )
|
||||
{
|
||||
memcpy( data_ , other.data_ , BYTES_ );
|
||||
return *this;
|
||||
}
|
||||
|
||||
template< size_t S , typename T >
|
||||
inline T_FixedBuffer< S , T >& T_FixedBuffer< S , T >::operator= ( T_FixedBuffer< S , T >&& other ) noexcept
|
||||
{
|
||||
swap( *this , other );
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
template< size_t S , typename T >
|
||||
inline void swap( T_FixedBuffer< S , T >& lhs , T_FixedBuffer< S , T >& rhs ) noexcept
|
||||
{
|
||||
swap( ( T_BufferBase& ) lhs , ( T_BufferBase& ) rhs );
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
template< size_t S , typename T >
|
||||
inline size_t T_FixedBuffer< S , T >::bytes( ) const
|
||||
{
|
||||
return BYTES_;
|
||||
}
|
||||
|
||||
template< size_t S , typename T >
|
||||
inline T& T_FixedBuffer< S , T >::operator[] ( size_t index )
|
||||
{
|
||||
assert( index < S );
|
||||
return *reinterpret_cast< T* >( data_ + index * sizeof( T ) );
|
||||
}
|
||||
|
||||
template< size_t S , typename T >
|
||||
inline T const& T_FixedBuffer< S , T >::operator[] ( size_t index ) const
|
||||
{
|
||||
assert( index < S );
|
||||
return *reinterpret_cast< T* >( data_ + index * sizeof( T ) );
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
template< size_t S , typename T >
|
||||
inline T_FixedBuffer< S , T >& T_FixedBuffer< S , T >::setAll( T const& value )
|
||||
{
|
||||
for ( size_t i = 0 ; i < S ; i ++ ) {
|
||||
memcpy( &(*this)[ i ] , &value , sizeof( T ) );
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
/*= T_Buffer =================================================================*/
|
||||
|
||||
template< typename T >
|
||||
inline T_Buffer< T >::T_Buffer( ) noexcept
|
||||
: T_BufferBase( nullptr ) , size_( 0 )
|
||||
{ }
|
||||
|
||||
template< typename T >
|
||||
inline T_Buffer< T >::T_Buffer( size_t size )
|
||||
: T_BufferBase( size * sizeof( T ) ) , size_( size )
|
||||
{ }
|
||||
|
||||
template< typename T >
|
||||
inline T_Buffer< T >::T_Buffer( T const* data , size_t size )
|
||||
: T_BufferBase( size * sizeof( T ) ) , size_( size )
|
||||
{
|
||||
memcpy( data_ , data , bytes( ) );
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
template< typename T >
|
||||
inline T_Buffer< T >::T_Buffer( T_Buffer< T > const& other )
|
||||
: T_Buffer( reinterpret_cast< T const* >( other.data_ ) , other.size( ) )
|
||||
{ }
|
||||
|
||||
template< typename T >
|
||||
inline T_Buffer< T >::T_Buffer( T_Buffer< T >&& other ) noexcept
|
||||
: T_Buffer( )
|
||||
{
|
||||
swap( *this , other );
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
template< typename T >
|
||||
inline T_Buffer< T >& T_Buffer< T >::operator= ( T_Buffer< T > const& other )
|
||||
{
|
||||
if ( size_ != other.size_ ) {
|
||||
free( data_ );
|
||||
size_ = other.size_;
|
||||
if ( size_ == 0 ) {
|
||||
data_ = nullptr;
|
||||
} else {
|
||||
data_ = ( uint8_t* ) malloc( bytes( ) );
|
||||
if ( data_ == nullptr ) {
|
||||
throw std::bad_alloc( );
|
||||
}
|
||||
}
|
||||
}
|
||||
memcpy( data_ , other.data_ , bytes( ) );
|
||||
return *this;
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
inline T_Buffer< T >& T_Buffer< T >::operator= ( T_Buffer< T >&& other )
|
||||
{
|
||||
swap( *this , other );
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
template< typename T >
|
||||
inline void swap( T_Buffer< T >& lhs , T_Buffer< T >& rhs ) noexcept
|
||||
{
|
||||
using std::swap;
|
||||
swap( ( T_BufferBase& ) lhs , ( T_BufferBase& ) rhs );
|
||||
swap( lhs.size_ , rhs.size_ );
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
template< typename T >
|
||||
inline size_t T_Buffer< T >::size( ) const
|
||||
{
|
||||
return size_;
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
inline size_t T_Buffer< T >::bytes( ) const
|
||||
{
|
||||
return size_ * sizeof( T );
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
template< typename T >
|
||||
inline T& T_Buffer< T >::operator[] ( size_t index )
|
||||
{
|
||||
assert( index < size_ );
|
||||
return *reinterpret_cast< T* >( data_ + index * sizeof( T ) );
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
inline T const& T_Buffer< T >::operator[] ( size_t index ) const
|
||||
{
|
||||
assert( index < size_ );
|
||||
return *reinterpret_cast< T* >( data_ + index * sizeof( T ) );
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
template< typename T >
|
||||
inline T_Buffer< T >& T_Buffer< T >::resize( size_t newSize )
|
||||
{
|
||||
if ( newSize != size_ ) {
|
||||
size_ = newSize;
|
||||
data_ = ( uint8_t* ) realloc( data_ , bytes( ) );
|
||||
if ( bytes( ) != 0 && data_ == nullptr ) {
|
||||
throw std::bad_alloc( );
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
inline T_Buffer< T >& T_Buffer< T >::setAll( T const& value )
|
||||
{
|
||||
for ( size_t i = 0 ; i < size_ ; i ++ ) {
|
||||
memcpy( &(*this)[ i ] , &value , sizeof( T ) );
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
inline T_Buffer< T >& T_Buffer< T >::copyAll( T const* data )
|
||||
{
|
||||
memcpy( data_ , data , bytes( ) );
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
} // namespace
|
30
include/ebcl/inline/DynLib.hh
Normal file
30
include/ebcl/inline/DynLib.hh
Normal file
|
@ -0,0 +1,30 @@
|
|||
/******************************************************************************/
|
||||
/* DYNAMIC LIBRARIES - INLINE CODE ********************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
#ifndef _H_LW_LIB_INLINE_DYNLIB
|
||||
#define _H_LW_LIB_INLINE_DYNLIB
|
||||
|
||||
#include <lw/lib/DynLib.hh>
|
||||
namespace lw {
|
||||
|
||||
|
||||
/*= T_DynLib =================================================================*/
|
||||
|
||||
template< typename T >
|
||||
inline T* T_DynLib::getPointer(
|
||||
char const* const name ) const noexcept
|
||||
{
|
||||
return reinterpret_cast< T* >( getRawSymbol( name ) );
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
inline std::function< T > T_DynLib::getFunction(
|
||||
char const* const name ) const noexcept
|
||||
{
|
||||
return std::function< T >{ (F_CFunc< T >) getRawSymbol( name ) };
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
#endif // _H_LW_LIB_INLINE_DYNLIB
|
99
include/ebcl/inline/Files.hh
Normal file
99
include/ebcl/inline/Files.hh
Normal file
|
@ -0,0 +1,99 @@
|
|||
/******************************************************************************/
|
||||
/* FILES - INLINE CODE ********************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
#ifndef _H_LW_LIB_INLINE_FILES
|
||||
#define _H_LW_LIB_INLINE_FILES
|
||||
#include <lw/lib/Files.hh>
|
||||
namespace lw {
|
||||
|
||||
|
||||
/*= T_File ===================================================================*/
|
||||
|
||||
inline T_File::~T_File( )
|
||||
{
|
||||
close( );
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
inline void swap( T_File& lhs , T_File& rhs ) noexcept
|
||||
{
|
||||
using std::swap;
|
||||
swap( lhs.path_ , rhs.path_ );
|
||||
swap( lhs.mode_ , rhs.mode_ );
|
||||
swap( lhs.file_ , rhs.file_ );
|
||||
swap( lhs.size_ , rhs.size_ );
|
||||
swap( lhs.pos_ , rhs.pos_ );
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
inline T_String const& T_File::path( ) const noexcept
|
||||
{
|
||||
return path_;
|
||||
}
|
||||
|
||||
inline E_FileMode T_File::mode( ) const noexcept
|
||||
{
|
||||
return mode_;
|
||||
}
|
||||
|
||||
inline bool T_File::isOpen( ) const noexcept
|
||||
{
|
||||
return file_ != nullptr;
|
||||
}
|
||||
|
||||
inline size_t T_File::size( ) const noexcept
|
||||
{
|
||||
return isOpen( ) ? size_ : 0;
|
||||
}
|
||||
|
||||
inline size_t T_File::position( ) const noexcept
|
||||
{
|
||||
return isOpen( ) ? pos_ : 0;
|
||||
}
|
||||
|
||||
|
||||
/*= T_FileInputStream ========================================================*/
|
||||
|
||||
inline void swap( T_FileInputStream& lhs , T_FileInputStream& rhs ) noexcept
|
||||
{
|
||||
lhs.swap( rhs );
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
inline T_File& T_FileInputStream::file( ) const noexcept
|
||||
{
|
||||
return fileRaw_ ? *fileRaw_ : *fileOwned_;
|
||||
}
|
||||
|
||||
inline size_t T_FileInputStream::offset( ) const noexcept
|
||||
{
|
||||
return start_;
|
||||
}
|
||||
|
||||
|
||||
/*= T_FileOutputStream =======================================================*/
|
||||
|
||||
inline void swap( T_FileOutputStream& lhs , T_FileOutputStream& rhs ) noexcept
|
||||
{
|
||||
lhs.swap( rhs );
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
inline T_File& T_FileOutputStream::file( ) const noexcept
|
||||
{
|
||||
return fileRaw_ ? *fileRaw_ : *fileOwned_;
|
||||
}
|
||||
|
||||
inline size_t T_FileOutputStream::offset( ) const noexcept
|
||||
{
|
||||
return start_;
|
||||
}
|
||||
|
||||
|
||||
} // namespace
|
||||
#endif // _H_LW_LIB_INLINE_FILES
|
29
include/ebcl/inline/HashIndex.hh
Normal file
29
include/ebcl/inline/HashIndex.hh
Normal file
|
@ -0,0 +1,29 @@
|
|||
/******************************************************************************/
|
||||
/* HASH INDEX - INLINE CODE ***************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
#include <lw/lib/HashIndex.hh>
|
||||
namespace lw {
|
||||
|
||||
|
||||
/*= T_HashIndex ==============================================================*/
|
||||
|
||||
inline T_HashIndex::~T_HashIndex( )
|
||||
{
|
||||
free( );
|
||||
}
|
||||
|
||||
inline uint32_t T_HashIndex::first( uint32_t key ) const
|
||||
{
|
||||
return hash_[ key & hashMask_ & lookupMask_ ];
|
||||
}
|
||||
|
||||
inline uint32_t T_HashIndex::next( uint32_t index ) const
|
||||
{
|
||||
assert( index < indexSize_ );
|
||||
return index_[ index & lookupMask_ ];
|
||||
}
|
||||
|
||||
|
||||
}
|
421
include/ebcl/inline/HashTables.hh
Normal file
421
include/ebcl/inline/HashTables.hh
Normal file
|
@ -0,0 +1,421 @@
|
|||
/******************************************************************************/
|
||||
/* HASH TABLES - INLINE CODE **************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
#ifndef _H_LW_LIB_INLINE_HASHTABLES
|
||||
#define _H_LW_LIB_INLINE_HASHTABLES
|
||||
#include <lw/lib/HashTables.hh>
|
||||
namespace lw {
|
||||
|
||||
|
||||
/*= T_DefaultKeyMatch ========================================================*/
|
||||
|
||||
template< typename K >
|
||||
inline bool T_DefaultKeyMatch< K >::keysMatch( K const& a , K const& b )
|
||||
{
|
||||
return a == b;
|
||||
}
|
||||
|
||||
|
||||
/*= T_KeyValueTable ==========================================================*/
|
||||
|
||||
template< typename K , typename V >
|
||||
inline T_KeyValueTable< K , V >::T_KeyValueTable(
|
||||
uint32_t initialSize , uint32_t hashSize , uint32_t growth ,
|
||||
F_KeyMatch< K > match )
|
||||
: match_( match ) , index_( hashSize , initialSize , growth ) ,
|
||||
keys_( growth ) , values_( growth )
|
||||
{ }
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
template< typename K , typename T >
|
||||
void swap( T_KeyValueTable< K , T >& lhs , T_KeyValueTable< K , T >& rhs )
|
||||
{
|
||||
using std::swap;
|
||||
swap( lhs.match_ , rhs.match_ );
|
||||
swap( lhs.index_ , rhs.index_ );
|
||||
swap( lhs.keys_ , rhs.keys_ );
|
||||
swap( lhs.values_ , rhs.values_ );
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
template< typename K , typename V >
|
||||
template<
|
||||
typename A , typename B ,
|
||||
T_EnableIfTypesMatch< K , A > ,
|
||||
T_EnableIfTypesMatch< V , B >
|
||||
> inline bool T_KeyValueTable< K , V >::add(
|
||||
A&& k ,
|
||||
B&& v )
|
||||
{
|
||||
const uint32_t hash = ComputeHash( k );
|
||||
uint32_t idx = find( k , hash );
|
||||
if ( idx != T_HashIndex::INVALID_INDEX ) {
|
||||
return false;
|
||||
}
|
||||
keys_.add( std::forward< A >( k ) );
|
||||
values_.add( std::forward< B >( v ) );
|
||||
index_.add( hash );
|
||||
return true;
|
||||
}
|
||||
|
||||
template< typename K , typename V >
|
||||
template< typename B , T_EnableIfTypesMatch< V , B > >
|
||||
inline bool T_KeyValueTable< K , V >::update(
|
||||
K const& k ,
|
||||
B&& v )
|
||||
{
|
||||
const uint32_t hash = ComputeHash( k );
|
||||
uint32_t idx = find( k , hash );
|
||||
if ( idx == T_HashIndex::INVALID_INDEX ) {
|
||||
return false;
|
||||
}
|
||||
values_[ idx ] = std::forward< B >( v );
|
||||
return true;
|
||||
}
|
||||
|
||||
template< typename K , typename V >
|
||||
template<
|
||||
typename A , typename B ,
|
||||
T_EnableIfTypesMatch< K , A > ,
|
||||
T_EnableIfTypesMatch< V , B >
|
||||
> inline void T_KeyValueTable< K , V >::set(
|
||||
A&& k ,
|
||||
B&& v )
|
||||
{
|
||||
const uint32_t hash = ComputeHash( k );
|
||||
uint32_t idx = find( k , hash );
|
||||
if ( idx == T_HashIndex::INVALID_INDEX ) {
|
||||
keys_.add( std::forward< A >( k ) );
|
||||
values_.add( std::forward< B >( v ) );
|
||||
index_.add( hash );
|
||||
} else {
|
||||
values_[ idx ] = std::forward< B >( v );
|
||||
}
|
||||
}
|
||||
|
||||
template< typename K , typename V >
|
||||
inline bool T_KeyValueTable< K , V >::remove( K const& k )
|
||||
{
|
||||
const uint32_t hash = ComputeHash( k );
|
||||
uint32_t idx = find( k , hash );
|
||||
if ( idx == T_HashIndex::INVALID_INDEX ) {
|
||||
return false;
|
||||
}
|
||||
keys_.removeSwap( idx );
|
||||
values_.removeSwap( idx );
|
||||
index_.remove( idx );
|
||||
return true;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
template< typename K , typename V >
|
||||
inline void T_KeyValueTable< K , V >::clear( )
|
||||
{
|
||||
values_.clear( );
|
||||
keys_.clear( );
|
||||
index_.clear( );
|
||||
}
|
||||
|
||||
template< typename K , typename V >
|
||||
inline void T_KeyValueTable< K , V >::free( )
|
||||
{
|
||||
values_.free( );
|
||||
keys_.free( );
|
||||
index_.free( );
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
template< typename K , typename V >
|
||||
inline uint32_t T_KeyValueTable< K , V >::size( ) const
|
||||
{
|
||||
return keys_.size( );
|
||||
}
|
||||
|
||||
template< typename K , typename V >
|
||||
T_Array< K > const& T_KeyValueTable< K , V >::keys( ) const
|
||||
{
|
||||
return keys_;
|
||||
}
|
||||
|
||||
template< typename K , typename V >
|
||||
T_Array< V > const& T_KeyValueTable< K , V >::values( ) const
|
||||
{
|
||||
return values_;
|
||||
}
|
||||
|
||||
template< typename K , typename V >
|
||||
inline uint32_t T_KeyValueTable< K , V >::indexOf( K const& k ) const
|
||||
{
|
||||
return find( k , ComputeHash( k ) );
|
||||
}
|
||||
|
||||
template< typename K , typename V >
|
||||
inline bool T_KeyValueTable< K , V >::contains( K const& k ) const
|
||||
{
|
||||
const uint32_t hash = ComputeHash( k );
|
||||
return find( k , hash ) != T_HashIndex::INVALID_INDEX;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
template< typename K , typename V >
|
||||
inline V const* T_KeyValueTable< K , V >::get( K const& k ) const
|
||||
{
|
||||
const uint32_t hash = ComputeHash( k );
|
||||
uint32_t idx = find( k , hash );
|
||||
if ( idx == T_HashIndex::INVALID_INDEX ) {
|
||||
return nullptr;
|
||||
}
|
||||
return &values_[ idx ];
|
||||
}
|
||||
|
||||
template< typename K , typename V >
|
||||
inline V* T_KeyValueTable< K , V >::get( K const& k )
|
||||
{
|
||||
const uint32_t hash = ComputeHash( k );
|
||||
uint32_t idx = find( k , hash );
|
||||
if ( idx == T_HashIndex::INVALID_INDEX ) {
|
||||
return nullptr;
|
||||
}
|
||||
return &values_[ idx ];
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
template< typename K , typename V >
|
||||
inline V& T_KeyValueTable< K , V >::operator[] ( uint32_t index )
|
||||
{
|
||||
return values_[ index ];
|
||||
}
|
||||
|
||||
template< typename K , typename V >
|
||||
inline V const& T_KeyValueTable< K , V >::operator[] ( uint32_t index ) const
|
||||
{
|
||||
return values_[ index ];
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
template< typename K , typename V >
|
||||
inline uint32_t T_KeyValueTable< K , V >::find( K const& k , uint32_t hash ) const
|
||||
{
|
||||
uint32_t idx = index_.first( hash );
|
||||
while ( idx != T_HashIndex::INVALID_INDEX ) {
|
||||
if ( match_( keys_[ idx ] , k ) ) {
|
||||
break;
|
||||
}
|
||||
idx = index_.next( idx );
|
||||
}
|
||||
return idx;
|
||||
}
|
||||
|
||||
|
||||
/*= T_ObjectTable ============================================================*/
|
||||
|
||||
template< typename K , typename V >
|
||||
inline T_ObjectTable< K , V >::T_ObjectTable(
|
||||
T_ObjectTable< K , V >::F_GetKey keyGetter ,
|
||||
uint32_t initialSize , uint32_t hashSize , uint32_t growth ,
|
||||
T_ObjectTable< K , V >::F_Match match )
|
||||
: match_( match ) , keyGetter_( keyGetter ) ,
|
||||
index_( hashSize , initialSize , growth ) ,
|
||||
values_( growth )
|
||||
{ }
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
template< typename K , typename T >
|
||||
void swap( T_ObjectTable< K , T >& lhs , T_ObjectTable< K , T >& rhs )
|
||||
{
|
||||
using std::swap;
|
||||
swap( lhs.keyGetter_ , rhs.keyGetter_ );
|
||||
swap( lhs.match_ , rhs.match_ );
|
||||
swap( lhs.index_ , rhs.index_ );
|
||||
swap( lhs.values_ , rhs.values_ );
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
template< typename K , typename V >
|
||||
template< typename A , T_EnableIfTypesMatch< V , A > >
|
||||
inline bool T_ObjectTable< K , V >::add(
|
||||
A&& v )
|
||||
{
|
||||
K k = keyGetter_( v );
|
||||
const uint32_t hash = ComputeHash( k );
|
||||
uint32_t idx = find( k , hash );
|
||||
if ( idx != T_HashIndex::INVALID_INDEX ) {
|
||||
return false;
|
||||
}
|
||||
values_.add( std::forward< A >( v ) );
|
||||
index_.add( hash );
|
||||
return true;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
template< typename K , typename V >
|
||||
template< typename A , T_EnableIfTypesMatch< V , A > >
|
||||
inline bool T_ObjectTable< K , V >::update(
|
||||
A&& v )
|
||||
{
|
||||
K k = keyGetter_( v );
|
||||
const uint32_t hash = ComputeHash( k );
|
||||
uint32_t idx = find( k , hash );
|
||||
if ( idx == T_HashIndex::INVALID_INDEX ) {
|
||||
return false;
|
||||
}
|
||||
values_[ idx ] = std::forward< A >( v );
|
||||
return true;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
template< typename K , typename V >
|
||||
template< typename A , T_EnableIfTypesMatch< V , A > >
|
||||
inline void T_ObjectTable< K , V >::set(
|
||||
A&& v )
|
||||
{
|
||||
K k = keyGetter_( v );
|
||||
const uint32_t hash = ComputeHash( k );
|
||||
uint32_t idx = find( k , hash );
|
||||
if ( idx == T_HashIndex::INVALID_INDEX ) {
|
||||
values_.add( std::forward< A >( v ) );
|
||||
index_.add( hash );
|
||||
} else {
|
||||
values_[ idx ] = std::forward< A >( v );
|
||||
}
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
template< typename K , typename V >
|
||||
inline bool T_ObjectTable< K , V >::remove( K const& k )
|
||||
{
|
||||
const uint32_t hash = ComputeHash( k );
|
||||
uint32_t idx = find( k , hash );
|
||||
if ( idx == T_HashIndex::INVALID_INDEX ) {
|
||||
return false;
|
||||
}
|
||||
values_.removeSwap( idx );
|
||||
index_.remove( idx );
|
||||
return true;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
template< typename K , typename V >
|
||||
inline void T_ObjectTable< K , V >::clear( )
|
||||
{
|
||||
values_.clear( );
|
||||
index_.clear( );
|
||||
}
|
||||
|
||||
template< typename K , typename V >
|
||||
inline void T_ObjectTable< K , V >::free( )
|
||||
{
|
||||
values_.free( );
|
||||
index_.free( );
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
template< typename K , typename V >
|
||||
inline uint32_t T_ObjectTable< K , V >::size( ) const
|
||||
{
|
||||
return values_.size( );
|
||||
}
|
||||
|
||||
template< typename K , typename V >
|
||||
inline uint32_t T_ObjectTable< K , V >::indexOf( K const& k ) const
|
||||
{
|
||||
return find( k , ComputeHash( k ) );
|
||||
}
|
||||
|
||||
template< typename K , typename V >
|
||||
inline bool T_ObjectTable< K , V >::contains( K const& k ) const
|
||||
{
|
||||
const uint32_t hash = ComputeHash( k );
|
||||
return find( k , hash ) != T_HashIndex::INVALID_INDEX;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
template< typename K , typename V >
|
||||
inline T_Array< K > T_ObjectTable< K , V >::keys( ) const
|
||||
{
|
||||
const auto sz( size( ) );
|
||||
T_Array< K > k( sz ? sz : 1 );
|
||||
for ( uint32_t i = 0 ; i < sz ; i ++ ) {
|
||||
k.add( keyGetter_( values_[ i ] ) );
|
||||
}
|
||||
return k;
|
||||
}
|
||||
|
||||
template< typename K , typename V >
|
||||
inline T_Array< V > const& T_ObjectTable< K , V >::values( ) const
|
||||
{
|
||||
return values_;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
template< typename K , typename V >
|
||||
inline V const* T_ObjectTable< K , V >::get( K const& k ) const
|
||||
{
|
||||
const uint32_t hash = ComputeHash( k );
|
||||
uint32_t idx = find( k , hash );
|
||||
if ( idx == T_HashIndex::INVALID_INDEX ) {
|
||||
return nullptr;
|
||||
}
|
||||
return &values_[ idx ];
|
||||
}
|
||||
|
||||
template< typename K , typename V >
|
||||
inline V* T_ObjectTable< K , V >::get( K const& k )
|
||||
{
|
||||
const uint32_t hash = ComputeHash( k );
|
||||
uint32_t idx = find( k , hash );
|
||||
if ( idx == T_HashIndex::INVALID_INDEX ) {
|
||||
return nullptr;
|
||||
}
|
||||
return &values_[ idx ];
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
template< typename K , typename V >
|
||||
inline V& T_ObjectTable< K , V >::operator[] ( uint32_t index )
|
||||
{
|
||||
return values_[ index ];
|
||||
}
|
||||
|
||||
template< typename K , typename V >
|
||||
inline V const& T_ObjectTable< K , V >::operator[] ( uint32_t index ) const
|
||||
{
|
||||
return values_[ index ];
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
template< typename K , typename V >
|
||||
inline uint32_t T_ObjectTable< K , V >::find( K const& k , uint32_t hash ) const
|
||||
{
|
||||
uint32_t idx = index_.first( hash );
|
||||
while ( idx != T_HashIndex::INVALID_INDEX ) {
|
||||
if ( match_( keyGetter_( values_[ idx ] ) , k ) ) {
|
||||
break;
|
||||
}
|
||||
idx = index_.next( idx );
|
||||
}
|
||||
return idx;
|
||||
}
|
||||
|
||||
|
||||
} // namespace
|
||||
#endif // _H_LW_LIB_INLINE_HASHTABLES
|
43
include/ebcl/inline/MemoryStreams.hh
Normal file
43
include/ebcl/inline/MemoryStreams.hh
Normal file
|
@ -0,0 +1,43 @@
|
|||
/******************************************************************************/
|
||||
/* MEMORY STREAMS - INLINE CODE ***********************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
#include <lw/lib/MemoryStreams.hh>
|
||||
namespace lw {
|
||||
|
||||
|
||||
/*= T_MemoryInputStream ======================================================*/
|
||||
|
||||
template< int S , typename T >
|
||||
inline T_MemoryInputStream::T_MemoryInputStream( T_FixedBuffer< S , T > const& buffer )
|
||||
: T_MemoryInputStream( buffer.data( ) , buffer.bytes( ) )
|
||||
{ }
|
||||
|
||||
template< typename T >
|
||||
inline T_MemoryInputStream::T_MemoryInputStream( T_Buffer< T > const& buffer )
|
||||
: T_MemoryInputStream( buffer.data( ) , buffer.bytes( ) )
|
||||
{ }
|
||||
|
||||
|
||||
/*= T_MemoryOutputStream =====================================================*/
|
||||
|
||||
template< int S , typename T >
|
||||
inline T_MemoryOutputStream::T_MemoryOutputStream( T_FixedBuffer< S , T >& buffer )
|
||||
: T_MemoryOutputStream( buffer.data( ) , buffer.bytes( ) )
|
||||
{ }
|
||||
|
||||
template< typename T >
|
||||
inline T_MemoryOutputStream::T_MemoryOutputStream( T_Buffer< T >& buffer )
|
||||
: T_MemoryOutputStream( buffer.data( ) , buffer.bytes( ) ,
|
||||
[&buffer] ( uint8_t* , size_t reqSize ) -> uint8_t*
|
||||
{
|
||||
const size_t mod( reqSize % sizeof( T ) );
|
||||
const size_t nItems( reqSize / sizeof( T ) + ( mod ? 1 : 0 ) );
|
||||
buffer.resize( nItems );
|
||||
return buffer.data( );
|
||||
} )
|
||||
{ }
|
||||
|
||||
|
||||
} // namespace
|
154
include/ebcl/inline/Messages.hh
Normal file
154
include/ebcl/inline/Messages.hh
Normal file
|
@ -0,0 +1,154 @@
|
|||
/******************************************************************************/
|
||||
/* UI<=>GAME MESSAGES - INLINE CODE *******************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
#ifndef _H_LW_LIB_INLINE_MESSAGES
|
||||
#define _H_LW_LIB_INLINE_MESSAGES
|
||||
#include <lw/lib/GameLoop.hh>
|
||||
namespace lw {
|
||||
|
||||
|
||||
/*= T_ProgressInfoPart =======================================================*/
|
||||
|
||||
inline T_ProgressInfoPart::T_ProgressInfoPart( T_String text ,
|
||||
uint32_t progress , uint32_t total ) noexcept
|
||||
: text_( std::move( text ) ) , progress_( progress ) , total_( total )
|
||||
{ }
|
||||
|
||||
inline T_ProgressInfoPart::T_ProgressInfoPart( T_ProgressInfoPart&& other ) noexcept
|
||||
: text_( std::move( other.text_ ) ) , progress_( other.progress_ ) ,
|
||||
total_( other.total_ )
|
||||
{ }
|
||||
|
||||
inline T_ProgressInfoPart::T_ProgressInfoPart( T_ProgressInfoPart const& other )
|
||||
: text_( other.text_ ) , progress_( other.progress_ ) , total_( other.total_ )
|
||||
{ }
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
inline T_String const& T_ProgressInfoPart::text( ) const noexcept
|
||||
{
|
||||
return text_;
|
||||
}
|
||||
|
||||
inline uint32_t T_ProgressInfoPart::progress( ) const noexcept
|
||||
{
|
||||
return progress_;
|
||||
}
|
||||
|
||||
inline uint32_t T_ProgressInfoPart::total( ) const noexcept
|
||||
{
|
||||
return total_;
|
||||
}
|
||||
|
||||
|
||||
/*= T_ProgressInfo ===========================================================*/
|
||||
|
||||
inline T_ProgressInfo::T_ProgressInfo( T_String text , uint32_t progress , uint32_t total ) noexcept
|
||||
: main_( std::move( text ) , progress , total ) , sub_( )
|
||||
{ }
|
||||
|
||||
inline T_ProgressInfo::T_ProgressInfo( T_ProgressInfoPart main ) noexcept
|
||||
: main_( std::move( main ) )
|
||||
{ }
|
||||
|
||||
inline T_ProgressInfo::T_ProgressInfo(
|
||||
T_ProgressInfoPart main ,
|
||||
T_ProgressInfoPart sub ) noexcept
|
||||
: main_( std::move( main ) ) ,
|
||||
sub_( std::move( sub ) )
|
||||
{ }
|
||||
|
||||
inline T_ProgressInfo::T_ProgressInfo( T_ProgressInfoPart main ,
|
||||
T_String sText , uint32_t sProgress , uint32_t sTotal ) noexcept
|
||||
: main_( std::move( main ) ) ,
|
||||
sub_( T_ProgressInfoPart{ std::move( sText ) , sProgress , sTotal } )
|
||||
{ }
|
||||
|
||||
inline T_ProgressInfo::T_ProgressInfo( T_String text , uint32_t progress , uint32_t total ,
|
||||
T_String sText , uint32_t sProgress , uint32_t sTotal ) noexcept
|
||||
: main_( std::move( text ) , progress , total ) ,
|
||||
sub_( T_ProgressInfoPart{ std::move( sText ) , sProgress , sTotal } )
|
||||
{ }
|
||||
|
||||
inline T_ProgressInfo::T_ProgressInfo( T_ProgressInfo&& other ) noexcept
|
||||
: main_( std::move( other.main_ ) ) , sub_( std::move( other.sub_ ) )
|
||||
{ }
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
inline T_ProgressInfoPart const& T_ProgressInfo::main( ) const noexcept
|
||||
{
|
||||
return main_;
|
||||
}
|
||||
|
||||
inline bool T_ProgressInfo::hasSub( ) const noexcept
|
||||
{
|
||||
return sub_.present( );
|
||||
}
|
||||
|
||||
inline T_ProgressInfoPart const& T_ProgressInfo::sub( ) const
|
||||
{
|
||||
return (T_ProgressInfoPart const&) sub_;
|
||||
}
|
||||
|
||||
|
||||
/*= T_GameMessage ============================================================*/
|
||||
|
||||
template< E_MessageDirection D , typename MT , typename MD >
|
||||
inline constexpr T_GameMessage< D , MT , MD >::T_GameMessage( ) noexcept
|
||||
: type_( ) , data_( )
|
||||
{ }
|
||||
|
||||
template< E_MessageDirection D , typename MT , typename MD >
|
||||
inline constexpr T_GameMessage< D , MT , MD >::T_GameMessage(
|
||||
T_Type type ) noexcept
|
||||
: type_( type ) , data_( )
|
||||
{ }
|
||||
|
||||
template< E_MessageDirection D , typename MT , typename MD >
|
||||
inline T_GameMessage< D , MT , MD >::T_GameMessage(
|
||||
T_Type type ,
|
||||
T_Data data ) noexcept
|
||||
: type_( type ) , data_( data )
|
||||
{ }
|
||||
|
||||
template< E_MessageDirection D , typename MT , typename MD >
|
||||
inline T_GameMessage< D , MT , MD >::T_GameMessage(
|
||||
T_Self_&& other ) noexcept
|
||||
: type_( other.type_ ) , data_( std::move( other.data_ ) )
|
||||
{ }
|
||||
|
||||
template< E_MessageDirection D , typename MT , typename MD >
|
||||
inline T_GameMessage< D >& T_GameMessage< D , MT , MD >::operator =(
|
||||
T_Self_&& other ) noexcept
|
||||
{
|
||||
type_ = other.type_;
|
||||
data_ = std::move( other.data_ );
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
template< E_MessageDirection D , typename MT , typename MD >
|
||||
inline constexpr bool T_GameMessage< D , MT , MD >::hasMessage( ) const noexcept
|
||||
{
|
||||
return type_.present( );
|
||||
}
|
||||
|
||||
template< E_MessageDirection D , typename MT , typename MD >
|
||||
inline constexpr MT T_GameMessage< D , MT , MD >::type( ) const noexcept
|
||||
{
|
||||
return type_;
|
||||
}
|
||||
|
||||
template< E_MessageDirection D , typename MT , typename MD >
|
||||
template< typename T >
|
||||
constexpr T const& T_GameMessage< D , MT , MD >::data( ) const
|
||||
{
|
||||
return (T const&)( (MD const&) data_ );
|
||||
}
|
||||
|
||||
|
||||
} // namespace lw
|
||||
#endif // _H_LW_LIB_INLINE_MESSAGES
|
59
include/ebcl/inline/Mods.hh
Normal file
59
include/ebcl/inline/Mods.hh
Normal file
|
@ -0,0 +1,59 @@
|
|||
/******************************************************************************/
|
||||
/* MODDING SYSTEM - INLINE CODE ***********************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
#ifndef _H_LW_LIB_INLINE_MODS
|
||||
#define _H_LW_LIB_INLINE_MODS
|
||||
#include <lw/lib/Mods.hh>
|
||||
namespace lw {
|
||||
|
||||
|
||||
/*= T_ModIdentifier ==========================================================*/
|
||||
|
||||
inline bool T_ModIdentifier::operator ==(
|
||||
T_ModIdentifier const& other ) const noexcept
|
||||
{
|
||||
return &other == this || ( name == other.name
|
||||
&& version == other.version );
|
||||
}
|
||||
|
||||
inline bool T_ModIdentifier::operator !=(
|
||||
T_ModIdentifier const& other ) const noexcept
|
||||
{
|
||||
return &other != this && ( name != other.name
|
||||
|| version != other.version );
|
||||
}
|
||||
|
||||
inline M_DEFINE_HASH( T_ModIdentifier )
|
||||
{
|
||||
return ComputeHash( item.name ) * 47 + item.version;
|
||||
}
|
||||
|
||||
inline M_DEFINE_COMPARATOR( T_ModIdentifier )
|
||||
{
|
||||
return a.compare( b );
|
||||
}
|
||||
|
||||
inline M_LSHIFT_OP( T_StringBuilder , T_ModIdentifier const& )
|
||||
{
|
||||
obj << value.name << ':' << value.version;
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
||||
/*= T_ModInfo ================================================================*/
|
||||
|
||||
inline bool T_ModInfo::isUserInterface( ) const noexcept
|
||||
{
|
||||
return type == E_ModType::UI;
|
||||
}
|
||||
|
||||
inline M_LSHIFT_OP( T_StringBuilder , T_ModInfo const& )
|
||||
{
|
||||
obj << value.identifier << '.' << value.revision;
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
#endif // _H_LW_LIB_INLINE_MODS
|
854
include/ebcl/inline/Pointers.hh
Normal file
854
include/ebcl/inline/Pointers.hh
Normal file
|
@ -0,0 +1,854 @@
|
|||
/******************************************************************************/
|
||||
/* POINTERS - INLINE CODE *****************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
#ifndef _H_LW_LIB_INLINE_POINTERS
|
||||
#define _H_LW_LIB_INLINE_POINTERS
|
||||
#include <lw/lib/Pointers.hh>
|
||||
namespace lw {
|
||||
|
||||
|
||||
/*= T_OwnPtr =================================================================*/
|
||||
|
||||
template< typename T >
|
||||
inline T_OwnPtr< T >::T_OwnPtr( T* p ) noexcept
|
||||
: p_( p )
|
||||
{ }
|
||||
|
||||
template< typename T >
|
||||
inline T_OwnPtr< T >::T_OwnPtr( )
|
||||
: T_OwnPtr( nullptr )
|
||||
{ }
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
template< typename T >
|
||||
template<
|
||||
typename Q ,
|
||||
T_EnableForChild< T , Q >
|
||||
> inline T_OwnPtr< T >::T_OwnPtr( T_OwnPtr< Q >&& source ) noexcept
|
||||
: p_( nullptr )
|
||||
{
|
||||
T* temp( source.p_ );
|
||||
source.p_ = nullptr;
|
||||
p_ = temp;
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
template<
|
||||
typename Q ,
|
||||
T_EnableForParent< T , Q >
|
||||
> inline T_OwnPtr< T >::T_OwnPtr( T_OwnPtr< Q >&& source )
|
||||
: p_( nullptr )
|
||||
{
|
||||
T* temp( dynamic_cast< T* >( source.p_ ) );
|
||||
if ( source.p_ && !temp ) {
|
||||
throw std::bad_cast( );
|
||||
}
|
||||
source.p_ = nullptr;
|
||||
p_ = temp;
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
template<
|
||||
typename Q ,
|
||||
T_EnableForChild< T , Q >
|
||||
> inline T_OwnPtr< T >& T_OwnPtr< T >::operator= ( T_OwnPtr< Q >&& source ) noexcept
|
||||
{
|
||||
T* temp( source.p_ );
|
||||
clear( );
|
||||
source.p_ = nullptr;
|
||||
p_ = temp;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
template<
|
||||
typename Q ,
|
||||
T_EnableForParent< T , Q >
|
||||
> inline T_OwnPtr< T >& T_OwnPtr< T >::operator= (
|
||||
T_OwnPtr< Q >&& source )
|
||||
{
|
||||
T* temp( dynamic_cast< T* >( source.p_ ) );
|
||||
if ( source.p_ && !temp ) {
|
||||
throw std::bad_cast( );
|
||||
}
|
||||
clear( );
|
||||
source.p_ = nullptr;
|
||||
p_ = temp;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
template< typename T >
|
||||
inline T_OwnPtr< T >::~T_OwnPtr( )
|
||||
{
|
||||
clear( );
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
template< typename T >
|
||||
inline void swap( T_OwnPtr< T >& lhs , T_OwnPtr< T >& rhs ) noexcept
|
||||
{
|
||||
std::swap( lhs.p_ , rhs.p_ );
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
template< typename T >
|
||||
inline void T_OwnPtr< T >::clear( )
|
||||
{
|
||||
T* ptr( nullptr );
|
||||
std::swap( p_ , ptr );
|
||||
delete ptr;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
template< typename T >
|
||||
inline bool T_OwnPtr< T >::operator== ( const T* p ) const
|
||||
{
|
||||
return p == p_;
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
inline bool T_OwnPtr< T >::operator!= ( const T* p ) const
|
||||
{
|
||||
return p != p_;
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
inline T_OwnPtr< T >::operator bool ( ) const
|
||||
{
|
||||
return p_ != nullptr;
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
inline bool T_OwnPtr< T >::operator! ( ) const
|
||||
{
|
||||
return p_ == nullptr;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
template< typename T >
|
||||
inline T* T_OwnPtr< T >::get( ) const
|
||||
{
|
||||
return p_;
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
inline T* T_OwnPtr< T >::operator-> ( ) const
|
||||
{
|
||||
assert( p_ != nullptr );
|
||||
return p_;
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
inline T& T_OwnPtr< T >::operator* ( ) const
|
||||
{
|
||||
assert( p_ != nullptr );
|
||||
return *p_;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
template< typename T >
|
||||
inline T_SharedPtr< T > T_OwnPtr< T >::makeShared( )
|
||||
{
|
||||
T* temp( nullptr );
|
||||
std::swap( p_ , temp );
|
||||
return T_SharedPtr< T >( temp );
|
||||
}
|
||||
|
||||
|
||||
/*= NewOwned / OwnRawPointer =================================================*/
|
||||
|
||||
template<
|
||||
typename Type ,
|
||||
typename... ArgTypes
|
||||
>
|
||||
inline T_OwnPtr< Type > NewOwned( ArgTypes&& ... arguments )
|
||||
{
|
||||
return T_OwnPtr< Type >( new Type( std::forward< ArgTypes >( arguments ) ... ) );
|
||||
}
|
||||
|
||||
template< typename Type >
|
||||
inline T_OwnPtr< Type > OwnRawPointer( Type*& pointer ) noexcept
|
||||
{
|
||||
assert( pointer != nullptr );
|
||||
T_OwnPtr< Type > p( pointer );
|
||||
pointer = nullptr;
|
||||
return p;
|
||||
}
|
||||
|
||||
template<
|
||||
typename Type , typename Other ,
|
||||
T_EnableForChild< Type , Other >
|
||||
> inline T_OwnPtr< Type > OwnRawPointer( Other*& pointer ) noexcept
|
||||
{
|
||||
assert( pointer != nullptr );
|
||||
T_OwnPtr< Type > p( pointer );
|
||||
pointer = nullptr;
|
||||
return p;
|
||||
}
|
||||
|
||||
template<
|
||||
typename Type , typename Other ,
|
||||
T_EnableForParent< Type , Other >
|
||||
> inline T_OwnPtr< Type > OwnRawPointer( Other*& pointer )
|
||||
{
|
||||
assert( pointer != nullptr );
|
||||
Type* temp( dynamic_cast< Type* >( pointer ) );
|
||||
if ( temp == nullptr ) {
|
||||
throw std::bad_cast( );
|
||||
}
|
||||
T_OwnPtr< Type > p( temp );
|
||||
pointer = nullptr;
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
/*= T_Reference_ =============================================================*/
|
||||
|
||||
// Reference counter for shared pointers
|
||||
class T_Reference_
|
||||
{
|
||||
private:
|
||||
typedef std::function< void ( void* ) > F_Destr_;
|
||||
|
||||
friend struct T_WeakChain_;
|
||||
|
||||
void* pointer_;
|
||||
F_Destr_ destr_;
|
||||
uint32_t count_;
|
||||
T_WeakChain_* weaks_;
|
||||
|
||||
public:
|
||||
/* References are pooled */
|
||||
void* operator new( size_t count ) noexcept;
|
||||
void operator delete( void* object ) noexcept;
|
||||
|
||||
T_Reference_( ) = delete;
|
||||
T_Reference_( T_Reference_ const& ) = delete;
|
||||
T_Reference_( T_Reference_&& ) = delete;
|
||||
|
||||
T_Reference_( void* ptr , F_Destr_ destructor );
|
||||
|
||||
~T_Reference_( );
|
||||
|
||||
void* pointer( ) const;
|
||||
T_Reference_ * increase( );
|
||||
void decrease( );
|
||||
void* extract( );
|
||||
};
|
||||
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
inline void* T_Reference_::pointer( ) const
|
||||
{
|
||||
return pointer_;
|
||||
}
|
||||
|
||||
inline T_Reference_* T_Reference_::increase( )
|
||||
{
|
||||
assert( count_ > 0 );
|
||||
count_ ++;
|
||||
return this;
|
||||
}
|
||||
|
||||
inline void T_Reference_::decrease( )
|
||||
{
|
||||
assert( count_ > 0 );
|
||||
count_ --;
|
||||
if ( count_ == 0 ) {
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*= T_BasePtr_ ===============================================================*/
|
||||
|
||||
template< typename T >
|
||||
inline T_BasePtr_< T >::T_BasePtr_( T_Reference_* ref ) noexcept
|
||||
: ref_( ref )
|
||||
{ }
|
||||
|
||||
template< typename T >
|
||||
inline T_BasePtr_< T >::operator bool ( ) const
|
||||
{
|
||||
return ref_ != nullptr;
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
inline bool T_BasePtr_< T >::operator! ( ) const
|
||||
{
|
||||
return ref_ == nullptr;
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
inline T* T_BasePtr_< T >::operator-> ( ) const
|
||||
{
|
||||
assert( ref_ != nullptr );
|
||||
return reinterpret_cast< T* >( ref_->pointer( ) );
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
inline T_BasePtr_< T >::operator T* ( ) const
|
||||
{
|
||||
return ref_ == nullptr
|
||||
? nullptr
|
||||
: reinterpret_cast< T* >( ref_->pointer( ) );
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
inline T& T_BasePtr_< T >::operator* ( ) const
|
||||
{
|
||||
assert( ref_ != nullptr );
|
||||
return *reinterpret_cast< T* >( ref_->pointer( ) );
|
||||
}
|
||||
|
||||
|
||||
/*= X_TooManyReferences ======================================================*/
|
||||
|
||||
inline X_TooManyReferences::X_TooManyReferences( )
|
||||
: std::runtime_error( "too many references" )
|
||||
{ }
|
||||
|
||||
/*= T_SharedPtr ==============================================================*/
|
||||
|
||||
template< typename T >
|
||||
inline T_Reference_* T_SharedPtr< T >::setRef( T_Reference_* from )
|
||||
{
|
||||
if ( from == nullptr ) {
|
||||
return nullptr;
|
||||
}
|
||||
return from->increase( );
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
inline void T_SharedPtr< T >::clearRef( )
|
||||
{
|
||||
if ( ref_ != nullptr ) {
|
||||
ref_->decrease( );
|
||||
}
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
template< typename T >
|
||||
inline T_SharedPtr< T >::T_SharedPtr( T* ptr )
|
||||
: T_Base_( new T_Reference_( ptr ,
|
||||
[]( void* p ) {
|
||||
delete reinterpret_cast< T* >( p );
|
||||
} ) )
|
||||
{ }
|
||||
|
||||
template< typename T >
|
||||
inline T_SharedPtr< T >::T_SharedPtr( ) noexcept
|
||||
: T_Base_( nullptr )
|
||||
{ }
|
||||
|
||||
template< typename T >
|
||||
inline T_SharedPtr< T >::~T_SharedPtr( )
|
||||
{
|
||||
clearRef( );
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
template< typename T >
|
||||
inline T_SharedPtr< T >::T_SharedPtr( T_Self_ const& source )
|
||||
: T_Base_( setRef( source.ref_ ) )
|
||||
{ }
|
||||
|
||||
template< typename T >
|
||||
template<
|
||||
typename Q ,
|
||||
T_EnableForChild< T , Q >
|
||||
> inline T_SharedPtr< T >::T_SharedPtr( T_SharedPtr< Q > const& other )
|
||||
: T_Base_( setRef( other.ref_ ) )
|
||||
{ }
|
||||
|
||||
template< typename T >
|
||||
template<
|
||||
typename Q ,
|
||||
T_EnableForParent< T , Q >
|
||||
> inline T_SharedPtr< T >::T_SharedPtr( T_SharedPtr< Q > const& other )
|
||||
: T_Base_( nullptr )
|
||||
{
|
||||
Q* const p( other );
|
||||
if ( p != nullptr && dynamic_cast< T* >( p ) == nullptr ) {
|
||||
throw std::bad_cast( );
|
||||
}
|
||||
ref_ = setRef( other.ref_ );
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
template< typename T >
|
||||
template<
|
||||
typename Q ,
|
||||
T_EnableForChild< T , Q >
|
||||
> inline T_SharedPtr< T >::T_SharedPtr( T_SharedPtr< Q >&& other ) noexcept
|
||||
: T_Base_( other.ref_ )
|
||||
{
|
||||
other.ref_ = nullptr;
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
template<
|
||||
typename Q ,
|
||||
T_EnableForParent< T , Q >
|
||||
> inline T_SharedPtr< T >::T_SharedPtr( T_SharedPtr< Q >&& other )
|
||||
: T_Base_( nullptr )
|
||||
{
|
||||
Q* const p( other );
|
||||
if ( p != nullptr && dynamic_cast< T* >( p ) == nullptr ) {
|
||||
throw std::bad_cast( );
|
||||
}
|
||||
using std::swap;
|
||||
swap( ref_ , other.ref_ );
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
template< typename T >
|
||||
inline T_SharedPtr< T >& T_SharedPtr< T >::operator= ( T_SharedPtr< T > const& other )
|
||||
{
|
||||
if ( &other != this && other.ref_ != ref_ ) {
|
||||
clearRef( );
|
||||
ref_ = setRef( other.ref_ );
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
template<
|
||||
typename Q ,
|
||||
T_EnableForChild< T , Q >
|
||||
> inline T_SharedPtr< T >& T_SharedPtr< T >::operator= ( T_SharedPtr< Q > const& other )
|
||||
{
|
||||
if ( other.ref_ != ref_ ) {
|
||||
clearRef( );
|
||||
ref_ = setRef( other.ref_ );
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
template<
|
||||
typename Q ,
|
||||
T_EnableForParent< T , Q >
|
||||
> inline T_SharedPtr< T >& T_SharedPtr< T >::operator= ( T_SharedPtr< Q > const& other )
|
||||
{
|
||||
if ( other.ref_ != ref_ ) {
|
||||
Q* const p( other );
|
||||
if ( p != nullptr && dynamic_cast< T* >( p ) == nullptr ) {
|
||||
throw std::bad_cast( );
|
||||
}
|
||||
clearRef( );
|
||||
ref_ = setRef( other.ref_ );
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
template< typename T >
|
||||
template<
|
||||
typename Q ,
|
||||
T_EnableForChild< T , Q >
|
||||
> inline T_SharedPtr< T >& T_SharedPtr< T >::operator= ( T_SharedPtr< Q >&& other ) noexcept
|
||||
{
|
||||
if ( other.ref_ != ref_ ) {
|
||||
clearRef( );
|
||||
ref_ = nullptr;
|
||||
std::swap( ref_ , other.ref_ );
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
template<
|
||||
typename Q ,
|
||||
T_EnableForParent< T , Q >
|
||||
> inline T_SharedPtr< T >& T_SharedPtr< T >::operator= ( T_SharedPtr< Q >&& other )
|
||||
{
|
||||
if ( other.ref_ != ref_ ) {
|
||||
Q* const p( other );
|
||||
if ( p != nullptr && dynamic_cast< T* >( p ) == nullptr ) {
|
||||
throw std::bad_cast( );
|
||||
}
|
||||
clearRef( );
|
||||
ref_ = nullptr;
|
||||
std::swap( ref_ , other.ref_ );
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
template< typename T >
|
||||
inline void swap( T_SharedPtr< T >& lhs , T_SharedPtr< T >& rhs ) noexcept
|
||||
{
|
||||
std::swap( lhs.ref_ , rhs.ref_ );
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
template< typename T >
|
||||
inline bool T_SharedPtr< T >::operator== ( T_SharedPtr< T > const& other ) const
|
||||
{
|
||||
return other.ref_ == ref_;
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
inline bool T_SharedPtr< T >::operator!= ( T_SharedPtr< T > const& other ) const
|
||||
{
|
||||
return other.ref_ != ref_;
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
inline bool T_SharedPtr< T >::operator== ( T_WeakPtr< T > const& other ) const
|
||||
{
|
||||
return other.ref_ == ref_;
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
inline bool T_SharedPtr< T >::operator!= ( T_WeakPtr< T > const& other ) const
|
||||
{
|
||||
return other.ref_ != ref_;
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
inline void T_SharedPtr< T >::clear( )
|
||||
{
|
||||
clearRef( );
|
||||
ref_ = nullptr;
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
T_OwnPtr< T > T_SharedPtr< T >::makeOwned( )
|
||||
{
|
||||
if ( ref_ == nullptr ) {
|
||||
return T_OwnPtr< T >( );
|
||||
}
|
||||
void* const p( ref_->extract( ) );
|
||||
ref_ = nullptr;
|
||||
return T_OwnPtr< T >( reinterpret_cast< T* >( p ) );
|
||||
}
|
||||
|
||||
|
||||
/*= T_WeakPtr ================================================================*/
|
||||
|
||||
template< typename T >
|
||||
inline T_WeakPtr< T >::T_WeakPtr( T_Reference_* ref )
|
||||
: T_BasePtr_< T >( ref ) , chain_( ref_ )
|
||||
{
|
||||
chain_.init( );
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
inline T_WeakPtr< T >::T_WeakPtr( )
|
||||
: T_WeakPtr( nullptr )
|
||||
{ }
|
||||
|
||||
template< typename T >
|
||||
inline T_WeakPtr< T >::~T_WeakPtr( )
|
||||
{
|
||||
chain_.unchain( );
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
template< typename T >
|
||||
inline T_WeakPtr< T >::T_WeakPtr( T_WeakPtr< T > const& other )
|
||||
: T_WeakPtr( other.ref_ )
|
||||
{ }
|
||||
|
||||
template< typename T >
|
||||
template< typename Q , T_EnableForChild< T , Q > >
|
||||
inline T_WeakPtr< T >::T_WeakPtr( T_WeakPtr< Q > const& other )
|
||||
: T_WeakPtr( other.ref_ )
|
||||
{ }
|
||||
|
||||
template< typename T >
|
||||
template< typename Q , T_EnableForParent< T , Q > >
|
||||
inline T_WeakPtr< T >::T_WeakPtr( T_WeakPtr< Q > const& other )
|
||||
: T_WeakPtr( )
|
||||
{
|
||||
Q* const p( other );
|
||||
if ( p != nullptr && dynamic_cast< T* >( p ) == nullptr ) {
|
||||
throw std::bad_cast( );
|
||||
}
|
||||
ref_ = other.ref_;
|
||||
chain_.init( );
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
template< typename T >
|
||||
template< typename Q , T_EnableForChild< T , Q > >
|
||||
inline T_WeakPtr< T >::T_WeakPtr( T_WeakPtr< Q >&& other ) noexcept
|
||||
: T_WeakPtr( nullptr )
|
||||
{
|
||||
other.chain_.unchain( );
|
||||
ref_ = other.ref_;
|
||||
other.ref_ = nullptr;
|
||||
chain_.init( );
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
template< typename Q , T_EnableForParent< T , Q > >
|
||||
inline T_WeakPtr< T >::T_WeakPtr( T_WeakPtr< Q >&& other )
|
||||
: T_WeakPtr( nullptr )
|
||||
{
|
||||
Q* const p( other );
|
||||
if ( p != nullptr && dynamic_cast< T* >( p ) == nullptr ) {
|
||||
throw std::bad_cast( );
|
||||
}
|
||||
other.chain_.unchain( );
|
||||
ref_ = other.ref_;
|
||||
other.ref_ = nullptr;
|
||||
chain_.init( );
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
template< typename T >
|
||||
inline T_WeakPtr< T >::T_WeakPtr( T_SharedPtr< T > const& shared )
|
||||
: T_WeakPtr( shared.ref_ )
|
||||
{ }
|
||||
|
||||
template< typename T >
|
||||
template< typename Q , T_EnableForChild< T , Q > >
|
||||
inline T_WeakPtr< T >::T_WeakPtr( T_SharedPtr< Q > const& shared )
|
||||
: T_WeakPtr( shared.ref_ )
|
||||
{ }
|
||||
|
||||
template< typename T >
|
||||
template< typename Q , T_EnableForParent< T , Q > >
|
||||
inline T_WeakPtr< T >::T_WeakPtr( T_SharedPtr< Q > const& shared )
|
||||
: T_WeakPtr( nullptr )
|
||||
{
|
||||
Q* const p( shared );
|
||||
if ( p != nullptr && dynamic_cast< T* >( p ) == nullptr ) {
|
||||
throw std::bad_cast( );
|
||||
}
|
||||
ref_ = shared.ref_;
|
||||
chain_.init( );
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
template< typename T >
|
||||
inline void swap( T_WeakPtr< T >& lhs , T_WeakPtr< T >& rhs )
|
||||
{
|
||||
if ( lhs.ref_ != rhs.ref_ ) {
|
||||
lhs.chain_.unchain( );
|
||||
rhs.chain_.unchain( );
|
||||
std::swap( lhs.ref_ , rhs.ref_ );
|
||||
lhs.chain_.init( );
|
||||
rhs.chain_.init( );
|
||||
}
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
template< typename T >
|
||||
inline T_WeakPtr< T >& T_WeakPtr< T >::operator= ( T_WeakPtr< T > const& other )
|
||||
{
|
||||
chain_.unchain( );
|
||||
ref_ = other.ref_;
|
||||
chain_.init( );
|
||||
return *this;
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
template< typename Q , T_EnableForChild< T , Q > >
|
||||
inline T_WeakPtr< T >& T_WeakPtr< T >::operator= ( T_WeakPtr< Q > const& other )
|
||||
{
|
||||
chain_.unchain( );
|
||||
ref_ = other.ref_;
|
||||
chain_.init( );
|
||||
return *this;
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
template< typename Q , T_EnableForParent< T , Q > >
|
||||
inline T_WeakPtr< T >& T_WeakPtr< T >::operator= ( T_WeakPtr< Q > const& other )
|
||||
{
|
||||
Q* const p( other );
|
||||
if ( p != nullptr && dynamic_cast< T* >( p ) == nullptr ) {
|
||||
throw std::bad_cast( );
|
||||
}
|
||||
chain_.unchain( );
|
||||
ref_ = other.ref_;
|
||||
chain_.init( );
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
template< typename T >
|
||||
template< typename Q , T_EnableForChild< T , Q > >
|
||||
inline T_WeakPtr< T >& T_WeakPtr< T >::operator= ( T_WeakPtr< Q >&& other )
|
||||
{
|
||||
ref_ = nullptr;
|
||||
chain_.unchain( );
|
||||
if ( other.ref_ ) {
|
||||
other.chain_.unchain( );
|
||||
ref_ = other.ref_;
|
||||
other.ref_ = nullptr;
|
||||
chain_.init( );
|
||||
other.chain_.init( );
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
template< typename Q , T_EnableForParent< T , Q > >
|
||||
inline T_WeakPtr< T >& T_WeakPtr< T >::operator= ( T_WeakPtr< Q >&& other )
|
||||
{
|
||||
Q* const p( other );
|
||||
if ( p != nullptr && dynamic_cast< T* >( p ) == nullptr ) {
|
||||
throw std::bad_cast( );
|
||||
}
|
||||
ref_ = nullptr;
|
||||
chain_.unchain( );
|
||||
if ( other.ref_ ) {
|
||||
other.chain_.unchain( );
|
||||
ref_ = other.ref_;
|
||||
other.ref_ = nullptr;
|
||||
chain_.init( );
|
||||
other.chain_.init( );
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
template< typename T >
|
||||
inline T_WeakPtr< T >& T_WeakPtr< T >::operator= ( T_SharedPtr< T > const& shared )
|
||||
{
|
||||
chain_.unchain( );
|
||||
ref_ = shared.ref_;
|
||||
chain_.init( );
|
||||
return *this;
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
template< typename Q , T_EnableForChild< T , Q > >
|
||||
inline T_WeakPtr< T >& T_WeakPtr< T >::operator= ( T_SharedPtr< Q > const& shared )
|
||||
{
|
||||
chain_.unchain( );
|
||||
ref_ = shared.ref_;
|
||||
chain_.init( );
|
||||
return *this;
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
template< typename Q , T_EnableForParent< T , Q > >
|
||||
inline T_WeakPtr< T >& T_WeakPtr< T >::operator= ( T_SharedPtr< Q > const& shared )
|
||||
{
|
||||
Q* const p( shared );
|
||||
if ( p != nullptr && dynamic_cast< T* >( p ) == nullptr ) {
|
||||
throw std::bad_cast( );
|
||||
}
|
||||
chain_.unchain( );
|
||||
ref_ = shared.ref_;
|
||||
chain_.init( );
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
template< typename T >
|
||||
inline bool T_WeakPtr< T >::operator== ( T_WeakPtr< T > const& other ) const
|
||||
{
|
||||
return other.ref_ == ref_;
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
inline bool T_WeakPtr< T >::operator!= ( T_WeakPtr< T > const& other ) const
|
||||
{
|
||||
return other.ref_ != ref_;
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
inline bool T_WeakPtr< T >::operator== ( T_SharedPtr< T > const& other ) const
|
||||
{
|
||||
return other.ref_ == ref_;
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
inline bool T_WeakPtr< T >::operator!= ( T_SharedPtr< T > const& other ) const
|
||||
{
|
||||
return other.ref_ != ref_;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
template< typename T >
|
||||
inline void T_WeakPtr< T >::clear( )
|
||||
{
|
||||
chain_.unchain( );
|
||||
ref_ = nullptr;
|
||||
}
|
||||
|
||||
|
||||
/*= NewShared ================================================================*/
|
||||
|
||||
template<
|
||||
typename Type ,
|
||||
typename... ArgTypes
|
||||
> inline T_SharedPtr< Type > NewShared( ArgTypes&& ... arguments )
|
||||
{
|
||||
return T_SharedPtr< Type >( new Type( std::forward< ArgTypes >( arguments ) ... ) );
|
||||
}
|
||||
|
||||
template< typename Type >
|
||||
T_SharedPtr< Type > ShareRawPointer(
|
||||
Type*& pointer ) noexcept
|
||||
{
|
||||
assert( pointer != nullptr );
|
||||
T_SharedPtr< Type > p( pointer );
|
||||
pointer = nullptr;
|
||||
return p;
|
||||
}
|
||||
|
||||
template<
|
||||
typename Type , typename Other ,
|
||||
T_EnableForChild< Type , Other >
|
||||
> inline T_SharedPtr< Type > ShareRawPointer(
|
||||
Other*& pointer ) noexcept
|
||||
{
|
||||
assert( pointer != nullptr );
|
||||
T_SharedPtr< Type > p( pointer );
|
||||
pointer = nullptr;
|
||||
return p;
|
||||
}
|
||||
|
||||
template<
|
||||
typename Type , typename Other ,
|
||||
T_EnableForParent< Type , Other >
|
||||
> inline T_SharedPtr< Type > ShareRawPointer(
|
||||
Other*& pointer )
|
||||
{
|
||||
assert( pointer != nullptr );
|
||||
Type* temp( dynamic_cast< Type* >( pointer ) );
|
||||
if ( temp == nullptr ) {
|
||||
throw std::bad_cast( );
|
||||
}
|
||||
T_SharedPtr< Type > p( temp );
|
||||
pointer = nullptr;
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
} // namespace
|
||||
#endif // _H_LW_LIB_INLINE_POINTERS
|
124
include/ebcl/inline/Registration.hh
Normal file
124
include/ebcl/inline/Registration.hh
Normal file
|
@ -0,0 +1,124 @@
|
|||
/******************************************************************************/
|
||||
/* REGISTRATION SUPPORT - INLINE CODE *****************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
#ifndef _H_LW_LIB_INLINE_REGISTRATION
|
||||
#define _H_LW_LIB_INLINE_REGISTRATION
|
||||
#include <lw/lib/Registration.hh>
|
||||
namespace lw {
|
||||
|
||||
|
||||
/*= T_RegisteredItem ============================================================*/
|
||||
|
||||
inline T_RegisteredItem::T_RegisteredItem( ) noexcept
|
||||
: automatic_( false ) , unregisterFunction_( ) ,
|
||||
data_( nullptr ) , dataDestructor_( )
|
||||
{ }
|
||||
|
||||
inline T_RegisteredItem::T_RegisteredItem(
|
||||
SP_Unregister& unregisterFunction ,
|
||||
void* data ,
|
||||
F_Destructor_ destructor ) noexcept
|
||||
: automatic_( true ) , unregisterFunction_( unregisterFunction ) ,
|
||||
data_( data ) , dataDestructor_( destructor )
|
||||
{ }
|
||||
|
||||
template< typename T >
|
||||
inline T_RegisteredItem::T_RegisteredItem(
|
||||
SP_Unregister& unregisterFunction ,
|
||||
T* data ) noexcept
|
||||
: T_RegisteredItem( unregisterFunction , data ,
|
||||
[]( void* d ) {
|
||||
reinterpret_cast< T* >( d )->~T( );
|
||||
::operator delete( d );
|
||||
} )
|
||||
{ }
|
||||
|
||||
template< >
|
||||
inline T_RegisteredItem::T_RegisteredItem(
|
||||
SP_Unregister& unregisterFunction ,
|
||||
void* data ) noexcept
|
||||
: T_RegisteredItem( unregisterFunction , data , [](void*){} )
|
||||
{ }
|
||||
|
||||
inline T_RegisteredItem::~T_RegisteredItem( )
|
||||
{
|
||||
clear( );
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
inline T_RegisteredItem::T_RegisteredItem(
|
||||
T_RegisteredItem&& other ) noexcept
|
||||
: T_RegisteredItem( )
|
||||
{
|
||||
swap( *this , other );
|
||||
}
|
||||
|
||||
inline T_RegisteredItem& T_RegisteredItem::operator =(
|
||||
T_RegisteredItem&& other ) noexcept
|
||||
{
|
||||
clear( );
|
||||
swap( *this , other );
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline M_DECLARE_SWAP( T_RegisteredItem )
|
||||
{
|
||||
using std::swap;
|
||||
swap( lhs.automatic_ , rhs.automatic_ );
|
||||
swap( lhs.unregisterFunction_ , rhs.unregisterFunction_ );
|
||||
swap( lhs.data_ , rhs.data_ );
|
||||
swap( lhs.dataDestructor_ , rhs.dataDestructor_ );
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
inline void T_RegisteredItem::automatic(
|
||||
const bool v ) noexcept
|
||||
{
|
||||
automatic_ = v;
|
||||
}
|
||||
|
||||
inline bool T_RegisteredItem::automatic( ) const noexcept
|
||||
{
|
||||
return automatic_;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
inline void T_RegisteredItem::unregister( ) noexcept
|
||||
{
|
||||
if ( data_ && unregisterFunction_ ) {
|
||||
(*unregisterFunction_)( data_ );
|
||||
deleteData( );
|
||||
}
|
||||
}
|
||||
|
||||
inline T_RegisteredItem::operator bool( ) const noexcept
|
||||
{
|
||||
return bool( data_ );
|
||||
}
|
||||
|
||||
inline void T_RegisteredItem::clear( ) noexcept
|
||||
{
|
||||
if ( automatic_ ) {
|
||||
unregister( );
|
||||
} else {
|
||||
deleteData( );
|
||||
}
|
||||
}
|
||||
|
||||
inline void T_RegisteredItem::deleteData( ) noexcept
|
||||
{
|
||||
if ( data_ != nullptr ) {
|
||||
if ( dataDestructor_ ) {
|
||||
dataDestructor_( data_ );
|
||||
}
|
||||
data_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // namespace lw
|
||||
#endif // _H_LW_LIB_INLINE_REGISTRATION
|
33
include/ebcl/inline/SRDBinary.hh
Normal file
33
include/ebcl/inline/SRDBinary.hh
Normal file
|
@ -0,0 +1,33 @@
|
|||
/******************************************************************************/
|
||||
/* SRD - BINARY STORAGE - INLINE CODE *****************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
#ifndef _H_LW_LIB_INLINE_SRDBINARY
|
||||
#define _H_LW_LIB_INLINE_SRDBINARY
|
||||
#include <lw/lib/SRDBinary.hh>
|
||||
namespace lw {
|
||||
|
||||
|
||||
inline void SRDBinaryWriteTo( A_OutputStream& output , T_SRDList const& data )
|
||||
{
|
||||
T_SRDBinaryWriter( output ).start( ).putList( data ).end( );
|
||||
}
|
||||
|
||||
|
||||
/*= T_SRDBinaryReader ========================================================*/
|
||||
|
||||
inline T_SRDBinaryReader::T_SRDBinaryReader( A_SRDReaderTarget& target )
|
||||
: A_SRDReader( target )
|
||||
{ }
|
||||
|
||||
inline T_SRDList SRDBinaryReadFrom( T_String const& name , A_InputStream& input , bool structured )
|
||||
{
|
||||
T_SRDErrors errors;
|
||||
T_SRDMemoryTarget mt( structured );
|
||||
T_SRDBinaryReader( mt ).read( name , input );
|
||||
return mt.list( );
|
||||
}
|
||||
|
||||
|
||||
} // namespace
|
||||
#endif // _H_LW_LIB_INLINE_SRDBINARY
|
438
include/ebcl/inline/SRDData.hh
Normal file
438
include/ebcl/inline/SRDData.hh
Normal file
|
@ -0,0 +1,438 @@
|
|||
/******************************************************************************/
|
||||
/* SRD - DATA - INLINE CODE ***************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
#ifndef _H_LW_LIB_INLINE_SRDDATA
|
||||
#define _H_LW_LIB_INLINE_SRDDATA
|
||||
#include <lw/lib/SRDData.hh>
|
||||
namespace lw {
|
||||
|
||||
|
||||
/*= T_SRDLocationChaining ====================================================*/
|
||||
|
||||
inline T_SRDLocationChaining::T_SRDLocationChaining(
|
||||
const E_SRDLocationChaining how ,
|
||||
const uint32_t depth ,
|
||||
SP_SRDLocation const& to ) noexcept
|
||||
: circumstances( how ) , depth( depth ) , location( to )
|
||||
{ }
|
||||
|
||||
inline bool T_SRDLocationChaining::isGenerated( ) const noexcept
|
||||
{
|
||||
return circumstances == E_SRDLocationChaining::GENERATED
|
||||
|| circumstances == E_SRDLocationChaining::SUBSTITUTED;
|
||||
}
|
||||
|
||||
|
||||
/*= T_SRDLocation ============================================================*/
|
||||
|
||||
inline T_SRDLocation::T_SRDLocation( ) noexcept
|
||||
: source_( ) , line_( 0 ) , character_( 0 )
|
||||
{ }
|
||||
|
||||
inline T_SRDLocation& T_SRDLocation::operator= (
|
||||
T_SRDLocation&& other ) noexcept
|
||||
{
|
||||
swap( *this , other );
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline T_SRDLocation::T_SRDLocation(
|
||||
T_SRDToken const& token ) noexcept
|
||||
: T_SRDLocation( )
|
||||
{
|
||||
if ( token.hasLocation( ) ) {
|
||||
*this = token.location( );
|
||||
}
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
inline void T_SRDLocation::chain(
|
||||
const E_SRDLocationChaining how ,
|
||||
SP_SRDLocation const& to ) noexcept
|
||||
{
|
||||
chain( how , 0 , to );
|
||||
}
|
||||
|
||||
inline void T_SRDLocation::chain(
|
||||
const E_SRDLocationChaining how ,
|
||||
const uint32_t depth ,
|
||||
SP_SRDLocation const& to ) noexcept
|
||||
{
|
||||
assert( bool( to ) );
|
||||
chaining_.setNew( how , depth , to );
|
||||
}
|
||||
|
||||
inline void T_SRDLocation::clearChain( ) noexcept
|
||||
{
|
||||
chaining_.clear( );
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
inline bool T_SRDLocation::unknown( ) const noexcept
|
||||
{
|
||||
return source_.size( ) == 0;
|
||||
}
|
||||
|
||||
inline T_String const& T_SRDLocation::source( ) const noexcept
|
||||
{
|
||||
return source_;
|
||||
}
|
||||
|
||||
inline bool T_SRDLocation::binary( ) const noexcept
|
||||
{
|
||||
return line_ == 0;
|
||||
}
|
||||
|
||||
inline uint32_t T_SRDLocation::line( ) const noexcept
|
||||
{
|
||||
return line_;
|
||||
}
|
||||
|
||||
inline size_t T_SRDLocation::character( ) const noexcept
|
||||
{
|
||||
return character_;
|
||||
}
|
||||
|
||||
inline size_t T_SRDLocation::byte( ) const noexcept
|
||||
{
|
||||
return character_;
|
||||
}
|
||||
|
||||
inline bool T_SRDLocation::isChained( ) const noexcept
|
||||
{
|
||||
return chaining_.present( );
|
||||
}
|
||||
|
||||
inline T_SRDLocationChaining const& T_SRDLocation::chaining( ) const noexcept
|
||||
{
|
||||
return chaining_;
|
||||
}
|
||||
|
||||
|
||||
/*= T_SRDError ===============================================================*/
|
||||
|
||||
inline T_SRDError::T_SRDError(
|
||||
T_String error ,
|
||||
T_SRDLocation location ,
|
||||
const bool details ) noexcept
|
||||
: error_( std::move( error ) ) ,
|
||||
location_( std::move( location ) ) ,
|
||||
isDetails_( details )
|
||||
{ }
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
inline T_SRDError::T_SRDError(
|
||||
T_SRDError const& other ) noexcept
|
||||
: error_( other.error_ ) ,
|
||||
location_( other.location_ ) ,
|
||||
isDetails_( other.isDetails_ )
|
||||
{ }
|
||||
|
||||
inline T_SRDError& T_SRDError::operator= (
|
||||
T_SRDError const& other ) noexcept
|
||||
{
|
||||
error_ = other.error_;
|
||||
location_ = other.location_;
|
||||
isDetails_ = other.isDetails_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
inline T_SRDError::T_SRDError(
|
||||
T_SRDError&& other ) noexcept
|
||||
: error_( ) , location_( )
|
||||
{
|
||||
swap( *this , other );
|
||||
}
|
||||
|
||||
inline T_SRDError& T_SRDError::operator=(
|
||||
T_SRDError&& other ) noexcept
|
||||
{
|
||||
swap( *this , other );
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
inline M_DECLARE_SWAP( T_SRDError )
|
||||
{
|
||||
using std::swap;
|
||||
swap( lhs.error_ , rhs.error_ );
|
||||
swap( lhs.location_ , rhs.location_ );
|
||||
swap( lhs.isDetails_ , rhs.isDetails_ );
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
inline T_String const& T_SRDError::error( ) const noexcept
|
||||
{
|
||||
return error_;
|
||||
}
|
||||
|
||||
inline T_SRDLocation const& T_SRDError::location( ) const noexcept
|
||||
{
|
||||
return location_;
|
||||
}
|
||||
|
||||
inline bool T_SRDError::isDetails( ) const noexcept
|
||||
{
|
||||
return isDetails_;
|
||||
}
|
||||
|
||||
|
||||
/*= T_SRDErrors ==============================================================*/
|
||||
|
||||
template< typename ... ArgTypes >
|
||||
inline void T_SRDErrors::add(
|
||||
char const* error ,
|
||||
ArgTypes&&... locationArgs )
|
||||
{
|
||||
add( InPlace::v , T_String::Pooled( error ) ,
|
||||
T_SRDLocation( std::forward< ArgTypes >( locationArgs ) ... ) );
|
||||
}
|
||||
|
||||
template< typename ... ArgTypes >
|
||||
inline void T_SRDErrors::add(
|
||||
T_String const& error ,
|
||||
ArgTypes&&... locationArgs )
|
||||
{
|
||||
add( InPlace::v , error ,
|
||||
T_SRDLocation( std::forward< ArgTypes >( locationArgs ) ... ) );
|
||||
}
|
||||
|
||||
template< typename ... ArgTypes >
|
||||
inline void T_SRDErrors::details(
|
||||
char const* error ,
|
||||
ArgTypes&&... locationArgs )
|
||||
{
|
||||
add( InPlace::v , T_String::Pooled( error ) ,
|
||||
T_SRDLocation( std::forward< ArgTypes >( locationArgs ) ... ) ,
|
||||
true );
|
||||
}
|
||||
|
||||
template< typename ... ArgTypes >
|
||||
inline void T_SRDErrors::details(
|
||||
T_String const& error ,
|
||||
ArgTypes&&... locationArgs )
|
||||
{
|
||||
add( InPlace::v , error ,
|
||||
T_SRDLocation( std::forward< ArgTypes >( locationArgs ) ... ) ,
|
||||
true );
|
||||
}
|
||||
|
||||
template< typename ... ArgTypes >
|
||||
inline void T_SRDErrors::add(
|
||||
InPlace ,
|
||||
ArgTypes&&... args )
|
||||
{
|
||||
checkAdded( errors_.addNew( std::forward< ArgTypes >( args ) ... ) );
|
||||
}
|
||||
|
||||
inline void T_SRDErrors::add(
|
||||
T_SRDError const& error )
|
||||
{
|
||||
checkAdded( errors_.addNew( error ) );
|
||||
}
|
||||
|
||||
inline void T_SRDErrors::add(
|
||||
T_SRDError&& error )
|
||||
{
|
||||
checkAdded( errors_.addNew( std::move( error ) ) );
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
inline uint32_t T_SRDErrors::size( ) const noexcept
|
||||
{
|
||||
return errors_.size( );
|
||||
}
|
||||
|
||||
inline T_SRDError const& T_SRDErrors::operator[] (
|
||||
uint32_t index ) const noexcept
|
||||
{
|
||||
return errors_[ index ];
|
||||
}
|
||||
|
||||
inline void T_SRDErrors::clear( ) noexcept
|
||||
{
|
||||
errors_.clear( );
|
||||
errCount_ = 0;
|
||||
}
|
||||
|
||||
|
||||
/*= X_SRDErrors ==============================================================*/
|
||||
|
||||
inline X_SRDErrors::X_SRDErrors( T_SRDErrors const& errors )
|
||||
: errors( errors )
|
||||
{ }
|
||||
|
||||
|
||||
/*= T_SRDToken ===============================================================*/
|
||||
|
||||
inline T_SRDToken::T_SRDToken(
|
||||
const E_SRDTokenType type ) noexcept
|
||||
: type_( type )
|
||||
{ }
|
||||
|
||||
inline T_SRDToken::T_SRDToken( T_SRDToken&& other ) noexcept
|
||||
{
|
||||
swap( *this , other );
|
||||
}
|
||||
|
||||
inline T_SRDToken& T_SRDToken::operator= ( T_SRDToken&& other ) noexcept
|
||||
{
|
||||
swap( *this , other );
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
template< typename T >
|
||||
inline T_SRDToken T_SRDToken::Binary(
|
||||
T const* const data ,
|
||||
const uint32_t count ) noexcept
|
||||
{
|
||||
return Binary( (uint8_t const*) data , count );
|
||||
}
|
||||
|
||||
template< >
|
||||
inline T_SRDToken T_SRDToken::Binary< uint8_t >(
|
||||
uint8_t const* const data ,
|
||||
const uint32_t count ) noexcept
|
||||
{
|
||||
return Binary( NewShared< T_Buffer< uint8_t > >( data , count ) );
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
inline T_SRDToken T_SRDToken::Binary(
|
||||
T_Buffer< T > const& data ) noexcept
|
||||
{
|
||||
if ( data.size( ) == 0 ) {
|
||||
return Binary( NewShared< T_Buffer< uint8_t > >( ) );
|
||||
} else {
|
||||
return Binary( (uint8_t const*) &data[ 0 ] , data.bytes( ) );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
inline E_SRDTokenType T_SRDToken::type( ) const
|
||||
{
|
||||
return type_;
|
||||
}
|
||||
|
||||
inline bool T_SRDToken::isText( ) const
|
||||
{
|
||||
return type_ == E_SRDTokenType::WORD || type_ == E_SRDTokenType::STRING;
|
||||
}
|
||||
|
||||
inline bool T_SRDToken::isNumeric( ) const
|
||||
{
|
||||
return isInteger( ) || type_ == E_SRDTokenType::FLOAT;
|
||||
}
|
||||
|
||||
inline bool T_SRDToken::isInteger( ) const
|
||||
{
|
||||
return type_ == E_SRDTokenType::INT || type_ == E_SRDTokenType::LONG;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
inline T_String const& T_SRDToken::text( ) const
|
||||
{
|
||||
return text_;
|
||||
}
|
||||
|
||||
inline T_SRDList const& T_SRDToken::list( ) const
|
||||
{
|
||||
return *list_;
|
||||
}
|
||||
|
||||
inline T_SRDList& T_SRDToken::list( )
|
||||
{
|
||||
return *list_;
|
||||
}
|
||||
|
||||
inline int64_t T_SRDToken::longValue( ) const
|
||||
{
|
||||
return longValue_;
|
||||
}
|
||||
|
||||
inline double T_SRDToken::floatValue( ) const
|
||||
{
|
||||
return floatValue_;
|
||||
}
|
||||
|
||||
inline T_String const& T_SRDToken::stringValue( ) const
|
||||
{
|
||||
return stringValue_;
|
||||
}
|
||||
|
||||
inline T_Buffer< uint8_t > const& T_SRDToken::binary( ) const
|
||||
{
|
||||
return *binary_;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
inline bool T_SRDToken::operator ==( T_SRDToken const& other ) const
|
||||
{
|
||||
return compare( other ) == 0;
|
||||
}
|
||||
|
||||
inline bool T_SRDToken::operator !=( T_SRDToken const& other ) const
|
||||
{
|
||||
return compare( other ) != 0;
|
||||
}
|
||||
|
||||
inline bool T_SRDToken::operator >( T_SRDToken const& other ) const
|
||||
{
|
||||
return compare( other ) > 0;
|
||||
}
|
||||
|
||||
inline bool T_SRDToken::operator <( T_SRDToken const& other ) const
|
||||
{
|
||||
return compare( other ) < 0;
|
||||
}
|
||||
|
||||
inline bool T_SRDToken::operator >=( T_SRDToken const& other ) const
|
||||
{
|
||||
return compare( other ) >= 0;
|
||||
}
|
||||
|
||||
inline bool T_SRDToken::operator <=( T_SRDToken const& other ) const
|
||||
{
|
||||
return compare( other ) <= 0;
|
||||
}
|
||||
|
||||
inline M_DEFINE_COMPARATOR( T_SRDToken )
|
||||
{
|
||||
return a.compare( b );
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
inline bool T_SRDToken::hasLocation( ) const noexcept
|
||||
{
|
||||
return bool( location_ );
|
||||
}
|
||||
|
||||
inline T_SRDLocation& T_SRDToken::location( ) noexcept
|
||||
{
|
||||
return *location_;
|
||||
}
|
||||
|
||||
inline T_SRDLocation const& T_SRDToken::location( ) const noexcept
|
||||
{
|
||||
return *location_;
|
||||
}
|
||||
|
||||
|
||||
} // namespace
|
||||
#endif // _H_LW_LIB_INLINE_SRDDATA
|
525
include/ebcl/inline/SRDDefinitions.hh
Normal file
525
include/ebcl/inline/SRDDefinitions.hh
Normal file
|
@ -0,0 +1,525 @@
|
|||
/******************************************************************************/
|
||||
/* SRD - PARSER DEFINITIONS - INLINE CODE *************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
#ifndef _H_LW_LIB_INLINE_SRDDEFINITIONS
|
||||
#define _H_LW_LIB_INLINE_SRDDEFINITIONS
|
||||
#include <lw/lib/SRDDefinitions.hh>
|
||||
namespace lw {
|
||||
|
||||
|
||||
/*= T_SRDEnum ================================================================*/
|
||||
|
||||
inline T_SRDEnum::T_SRDEnum( T_String name )
|
||||
: name_( std::move( name ) ) , index_( 32 , 32 , 32 ) , words_( 32 )
|
||||
{ }
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
inline T_SRDEnum& T_SRDEnum::operator<< ( char const* word )
|
||||
{
|
||||
return operator<< ( T_String::Pooled( word ) );
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
inline T_String const& T_SRDEnum::name( ) const
|
||||
{
|
||||
return name_;
|
||||
}
|
||||
|
||||
inline auto T_SRDEnum::size( ) const
|
||||
{
|
||||
return words_.size( );
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
inline T_String const& T_SRDEnum::operator[] ( int index ) const
|
||||
{
|
||||
return words_[ index ];
|
||||
}
|
||||
|
||||
inline T_String const& T_SRDEnum::operator[] ( uint32_t index ) const
|
||||
{
|
||||
return words_[ index ];
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
inline bool T_SRDEnum::contains( T_String const& word ) const
|
||||
{
|
||||
return (*this)[ word ] != T_HashIndex::INVALID_INDEX;
|
||||
}
|
||||
|
||||
inline bool T_SRDEnum::contains( char const* word ) const
|
||||
{
|
||||
return (*this)[ word ] != T_HashIndex::INVALID_INDEX;
|
||||
}
|
||||
|
||||
|
||||
/*= T_SRDInputItem ===========================================================*/
|
||||
|
||||
inline T_SRDInputItem::T_ListHelper::T_ListHelper( )
|
||||
: items( 16 )
|
||||
{ }
|
||||
|
||||
inline T_SRDInputItem::T_ListHelper& T_SRDInputItem::T_ListHelper::operator <<( T_SRDInputItem item )
|
||||
{
|
||||
items.add( std::move( item ) );
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
inline T_SRDInputItem::T_SRDInputItem( )
|
||||
: type_( E_SRDInputItem::ALTERNATIVE ) , items_( 32 )
|
||||
{ }
|
||||
|
||||
inline T_SRDInputItem::T_SRDInputItem( T_String wordOrName , bool isWord )
|
||||
: type_( isWord ? E_SRDInputItem::WORD : E_SRDInputItem::ENUM ) , word_( std::move( wordOrName ) )
|
||||
{ }
|
||||
|
||||
inline T_SRDInputItem::T_SRDInputItem( char const* cString )
|
||||
: T_SRDInputItem( T_String::Pooled( cString ) , true )
|
||||
{ }
|
||||
|
||||
inline T_SRDInputItem::T_SRDInputItem( E_SRDTokenType type )
|
||||
: type_( E_SRDInputItem::TOKEN ) , token_( type )
|
||||
{ }
|
||||
|
||||
inline T_SRDInputItem::T_SRDInputItem( uint32_t min , uint32_t max )
|
||||
: type_( E_SRDInputItem::REPETITION ) , items_( 32 ) , min_( min ) , max_( max )
|
||||
{
|
||||
if ( min > max ) {
|
||||
throw std::invalid_argument( "min > max" );
|
||||
} else if ( min == 0 && max == 0 ) {
|
||||
throw std::invalid_argument( "min = max = 0" );
|
||||
}
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
inline E_SRDInputItem T_SRDInputItem::type( ) const
|
||||
{
|
||||
return type_;
|
||||
}
|
||||
|
||||
inline T_String const& T_SRDInputItem::word( ) const
|
||||
{
|
||||
return word_;
|
||||
}
|
||||
|
||||
inline E_SRDTokenType T_SRDInputItem::token( ) const
|
||||
{
|
||||
return token_;
|
||||
}
|
||||
|
||||
inline T_Array< T_SRDInputItem > T_SRDInputItem::items( ) const
|
||||
{
|
||||
return items_;
|
||||
}
|
||||
|
||||
inline uint32_t T_SRDInputItem::min( ) const
|
||||
{
|
||||
return min_;
|
||||
}
|
||||
|
||||
inline uint32_t T_SRDInputItem::max( ) const
|
||||
{
|
||||
return max_;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
inline bool T_SRDInputItem::operator ==( T_SRDInputItem const& ) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
inline T_Array< T_SRDInputItem >& operator <<(
|
||||
T_Array< T_SRDInputItem >& items ,
|
||||
T_SRDInputItem::T_ListHelper& list )
|
||||
{
|
||||
items << T_SRDInputItem( E_SRDTokenType::START );
|
||||
items.addAll( list.items );
|
||||
items << T_SRDInputItem( E_SRDTokenType::END );
|
||||
return items;
|
||||
}
|
||||
|
||||
inline T_SRDInputItem& T_SRDInputItem::operator <<( T_ListHelper list )
|
||||
{
|
||||
items_ << list;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
/*= T_SRDInputRule ===========================================================*/
|
||||
|
||||
inline T_SRDInputRule::T_SetContextExecutor::T_SetContextExecutor( bool exit , F_SRDHandler executor )
|
||||
: exit( exit ) , executor( executor )
|
||||
{ }
|
||||
|
||||
inline T_SRDInputRule::T_SetContext::T_SetContext( T_String string )
|
||||
: name( std::move( string ) )
|
||||
{ }
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
inline T_SRDInputRule& T_SRDInputRule::operator<< ( F_SRDHandler executor )
|
||||
{
|
||||
executor_ = executor;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline T_SRDInputRule& T_SRDInputRule::operator<< ( T_SetContextExecutor sce )
|
||||
{
|
||||
if ( sce.exit ) {
|
||||
contextExit_ = sce.executor;
|
||||
} else {
|
||||
contextEnter_ = sce.executor;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline T_SRDInputRule& T_SRDInputRule::operator<< ( T_SetContext sc )
|
||||
{
|
||||
context_ = sc.name;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline T_SRDInputRule& T_SRDInputRule::operator <<( T_SRDInputItem::T_ListHelper lh )
|
||||
{
|
||||
items_ << lh;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
inline F_SRDHandler const& T_SRDInputRule::handler( ) const
|
||||
{
|
||||
return executor_;
|
||||
}
|
||||
|
||||
inline T_Array< T_SRDInputItem > const& T_SRDInputRule::rule( ) const
|
||||
{
|
||||
return items_;
|
||||
}
|
||||
|
||||
inline T_String const& T_SRDInputRule::context( ) const
|
||||
{
|
||||
return context_;
|
||||
}
|
||||
|
||||
inline F_SRDHandler const& T_SRDInputRule::onEnter( ) const
|
||||
{
|
||||
return contextEnter_;
|
||||
}
|
||||
|
||||
inline F_SRDHandler const& T_SRDInputRule::onExit( ) const
|
||||
{
|
||||
return contextExit_;
|
||||
}
|
||||
|
||||
/*= T_SRDContext =============================================================*/
|
||||
|
||||
inline T_String const& T_SRDContext::name( ) const
|
||||
{
|
||||
return name_;
|
||||
}
|
||||
|
||||
inline T_String const& T_SRDContext::parent( ) const
|
||||
{
|
||||
return parent_;
|
||||
}
|
||||
|
||||
inline T_Array< T_SRDInputRule > const& T_SRDContext::rules( ) const
|
||||
{
|
||||
return rules_;
|
||||
}
|
||||
|
||||
|
||||
/*= T_SRDParserDefs ==========================================================*/
|
||||
|
||||
inline T_SRDParserDefs::SetHandler::SetHandler( F_SRDHandler const& handler , bool start )
|
||||
: handler( handler ) , start( start )
|
||||
{ }
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
inline T_SRDParserDefs::T_SRDParserDefs( char const* name )
|
||||
: T_SRDParserDefs( T_String::Pooled( name ) )
|
||||
{ }
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
inline T_String const& T_SRDParserDefs::defaultContext( ) const
|
||||
{
|
||||
return dfCtx_;
|
||||
}
|
||||
|
||||
inline void T_SRDParserDefs::defaultContext( char const* name )
|
||||
{
|
||||
defaultContext( T_String::Pooled( name ) );
|
||||
}
|
||||
|
||||
inline F_SRDHandler const& T_SRDParserDefs::onStart( ) const
|
||||
{
|
||||
return onStart_;
|
||||
}
|
||||
|
||||
inline F_SRDHandler const& T_SRDParserDefs::onFinish( ) const
|
||||
{
|
||||
return onFinish_;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
inline uint32_t T_SRDParserDefs::contexts( ) const
|
||||
{
|
||||
return ctx_.size( );
|
||||
}
|
||||
|
||||
inline T_SRDContext& T_SRDParserDefs::operator[] ( uint32_t idx )
|
||||
{
|
||||
return ctx_[ idx ];
|
||||
}
|
||||
|
||||
inline T_SRDContext const& T_SRDParserDefs::operator[] ( uint32_t idx ) const
|
||||
{
|
||||
return ctx_[ idx ];
|
||||
}
|
||||
|
||||
inline T_SRDContext& T_SRDParserDefs::context( char const* name )
|
||||
{
|
||||
return context( T_String::Pooled( name ) );
|
||||
}
|
||||
|
||||
inline T_SRDContext& T_SRDParserDefs::context( char const* name , char const* parent )
|
||||
{
|
||||
return context( T_String::Pooled( name ) , T_String::Pooled( parent ) );
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
inline uint32_t T_SRDParserDefs::enums( ) const
|
||||
{
|
||||
return enums_.size( );
|
||||
}
|
||||
|
||||
inline T_SRDEnum & T_SRDParserDefs::enumeration( char const* name )
|
||||
{
|
||||
return enumeration( T_String::Pooled( name ) );
|
||||
}
|
||||
|
||||
|
||||
/*= SRD::* ===================================================================*/
|
||||
|
||||
namespace SRD {
|
||||
|
||||
inline T_SRDParserDefs::SetHandler OnStart( F_SRDHandler const& handler )
|
||||
{
|
||||
return T_SRDParserDefs::SetHandler( handler , true );
|
||||
}
|
||||
|
||||
inline T_SRDParserDefs::SetHandler OnFinish( F_SRDHandler const& handler )
|
||||
{
|
||||
return T_SRDParserDefs::SetHandler( handler , false );
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
inline T_SRDContext Context( T_String name )
|
||||
{
|
||||
return T_SRDContext( std::move( name ) );
|
||||
}
|
||||
|
||||
inline T_SRDContext Context( char const* name )
|
||||
{
|
||||
return T_SRDContext( T_String::Pooled( name ) );
|
||||
}
|
||||
|
||||
inline T_SRDContext Context( char const* name , char const* parent )
|
||||
{
|
||||
return T_SRDContext( T_String::Pooled( name ) , T_String::Pooled( parent ) );
|
||||
}
|
||||
|
||||
inline T_SRDContext Context( T_String name , T_String parent )
|
||||
{
|
||||
return T_SRDContext( std::move( name ) , std::move( parent ) );
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
inline T_SRDInputRule Rule( )
|
||||
{
|
||||
return T_SRDInputRule( );
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
inline T_SRDEnum CreateEnum( T_String name )
|
||||
{
|
||||
return T_SRDEnum( std::move( name ) );
|
||||
}
|
||||
|
||||
inline T_SRDEnum CreateEnum( char const* name )
|
||||
{
|
||||
return T_SRDEnum( T_String::Pooled( name ) );
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
inline T_SRDInputItem Word( T_String const& word )
|
||||
{
|
||||
return T_SRDInputItem( word , true );
|
||||
}
|
||||
|
||||
inline T_SRDInputItem Word( char const* word )
|
||||
{
|
||||
return T_SRDInputItem( T_String::Pooled( word ) , true );
|
||||
}
|
||||
|
||||
inline T_SRDInputItem Word( )
|
||||
{
|
||||
return T_SRDInputItem( E_SRDTokenType::WORD );
|
||||
}
|
||||
|
||||
inline T_SRDInputItem String( )
|
||||
{
|
||||
return T_SRDInputItem( E_SRDTokenType::STRING );
|
||||
}
|
||||
|
||||
inline T_SRDInputItem Binary( )
|
||||
{
|
||||
return T_SRDInputItem( E_SRDTokenType::BINARY );
|
||||
}
|
||||
|
||||
inline T_SRDInputItem LStart( )
|
||||
{
|
||||
return T_SRDInputItem( E_SRDTokenType::START );
|
||||
}
|
||||
|
||||
inline T_SRDInputItem LEnd( )
|
||||
{
|
||||
return T_SRDInputItem( E_SRDTokenType::END );
|
||||
}
|
||||
|
||||
inline T_SRDInputItem Int32( )
|
||||
{
|
||||
return T_SRDInputItem( E_SRDTokenType::INT );
|
||||
}
|
||||
|
||||
inline T_SRDInputItem Int64( )
|
||||
{
|
||||
return T_SRDInputItem( E_SRDTokenType::LONG );
|
||||
}
|
||||
|
||||
inline T_SRDInputItem Float( )
|
||||
{
|
||||
return T_SRDInputItem( E_SRDTokenType::FLOAT );
|
||||
}
|
||||
|
||||
inline T_SRDInputItem Enum( T_String name )
|
||||
{
|
||||
return T_SRDInputItem( std::move( name ) , false );
|
||||
}
|
||||
|
||||
inline T_SRDInputItem Enum( char const* name )
|
||||
{
|
||||
return T_SRDInputItem( T_String::Pooled( name ) , false );
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
inline T_SRDInputItem::T_ListHelper List( )
|
||||
{
|
||||
return T_SRDInputItem::T_ListHelper( );
|
||||
}
|
||||
|
||||
inline T_SRDInputItem Alt( )
|
||||
{
|
||||
return T_SRDInputItem( );
|
||||
}
|
||||
|
||||
inline T_SRDInputItem Sub( )
|
||||
{
|
||||
return T_SRDInputItem( 1 , 1 );
|
||||
}
|
||||
|
||||
inline T_SRDInputItem Opt( )
|
||||
{
|
||||
return T_SRDInputItem( 0 , 1 );
|
||||
}
|
||||
|
||||
inline T_SRDInputItem Opt( T_SRDInputItem item )
|
||||
{
|
||||
return Opt( ) << std::move( item );
|
||||
}
|
||||
|
||||
inline T_SRDInputItem AtLeast( uint32_t n )
|
||||
{
|
||||
return T_SRDInputItem( n , UINT32_MAX );
|
||||
}
|
||||
|
||||
inline T_SRDInputItem AtMost( uint32_t n )
|
||||
{
|
||||
return T_SRDInputItem( 0 , n );
|
||||
}
|
||||
|
||||
inline T_SRDInputItem Times( uint32_t n )
|
||||
{
|
||||
return T_SRDInputItem( n , n );
|
||||
}
|
||||
|
||||
inline T_SRDInputItem Between( uint32_t a , uint32_t b )
|
||||
{
|
||||
return T_SRDInputItem( a > b ? b : a , a > b ? a : b );
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
inline T_SRDInputItem Integer( )
|
||||
{
|
||||
return Alt( ) << Int32( ) << Int64( );
|
||||
}
|
||||
inline T_SRDInputItem Numeric( )
|
||||
{
|
||||
return Alt( ) << Integer( ) << Float( );
|
||||
}
|
||||
inline T_SRDInputItem Text( )
|
||||
{
|
||||
return Alt( ) << String( ) << Word( );
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
inline T_SRDInputRule::T_SetContext EnterContext( T_String name )
|
||||
{
|
||||
return T_SRDInputRule::T_SetContext( std::move( name ) );
|
||||
}
|
||||
|
||||
inline T_SRDInputRule::T_SetContext EnterContext( char const* name )
|
||||
{
|
||||
return EnterContext( T_String::Pooled( name ) );
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
inline T_SRDInputRule::T_SetContextExecutor OnEnter( F_SRDHandler f )
|
||||
{
|
||||
return T_SRDInputRule::T_SetContextExecutor( false , f );
|
||||
}
|
||||
|
||||
inline T_SRDInputRule::T_SetContextExecutor OnExit( F_SRDHandler f )
|
||||
{
|
||||
return T_SRDInputRule::T_SetContextExecutor( true , f );
|
||||
}
|
||||
|
||||
} // namespace SRD
|
||||
|
||||
|
||||
} // namespace
|
||||
#endif // _H_LW_LIB_INLINE_SRDDEFINITIONS
|
80
include/ebcl/inline/SRDIO.hh
Normal file
80
include/ebcl/inline/SRDIO.hh
Normal file
|
@ -0,0 +1,80 @@
|
|||
/******************************************************************************/
|
||||
/* SRD - INPUT AND OUTPUT - INLINE CODE ***************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
#ifndef _H_LW_LIB_INLINE_SRDIO
|
||||
#define _H_LW_LIB_INLINE_SRDIO
|
||||
#include <lw/lib/SRDIO.hh>
|
||||
namespace lw {
|
||||
|
||||
/*= A_SRDWriter ==============================================================*/
|
||||
|
||||
inline A_SRDWriter::~A_SRDWriter( )
|
||||
{ }
|
||||
|
||||
|
||||
/*= A_SRDReaderTarget ========================================================*/
|
||||
|
||||
inline A_SRDReaderTarget::~A_SRDReaderTarget( )
|
||||
{ }
|
||||
|
||||
|
||||
/*= A_SRDReader ==============================================================*/
|
||||
|
||||
inline A_SRDReader::A_SRDReader( A_SRDReaderTarget& target )
|
||||
: target_( target )
|
||||
{ }
|
||||
|
||||
inline A_SRDReader::~A_SRDReader( )
|
||||
{ }
|
||||
|
||||
|
||||
/*= X_SRDWriterError =========================================================*/
|
||||
|
||||
inline X_SRDWriterError::X_SRDWriterError( char const* msg ) noexcept
|
||||
: std::exception( ) , msg_( msg )
|
||||
{ }
|
||||
|
||||
|
||||
/*= T_SRDReaderTargetHelper ==================================================*/
|
||||
|
||||
inline T_SRDReaderTargetHelper::T_SRDReaderTargetHelper( A_SRDReaderTarget& target , T_SRDErrors& errors )
|
||||
: target_( target ) , errors_( errors )
|
||||
{
|
||||
target_.start( errors_ );
|
||||
}
|
||||
|
||||
inline T_SRDReaderTargetHelper::~T_SRDReaderTargetHelper( )
|
||||
{
|
||||
target_.end( errors_ );
|
||||
}
|
||||
|
||||
|
||||
/*= T_SRDMemoryTarget ========================================================*/
|
||||
|
||||
inline void T_SRDMemoryTarget::clearFlushToken(
|
||||
bool clearIt ) noexcept
|
||||
{
|
||||
clearFlushToken_ = clearIt;
|
||||
}
|
||||
|
||||
inline bool T_SRDMemoryTarget::clearFlushToken( ) const noexcept
|
||||
{
|
||||
return clearFlushToken_;
|
||||
}
|
||||
|
||||
inline T_SRDList const& T_SRDMemoryTarget::list( ) const
|
||||
{
|
||||
return list_.list( );
|
||||
}
|
||||
|
||||
inline bool T_SRDMemoryTarget::complete( ) const
|
||||
{
|
||||
return current_ != nullptr && stack_.size( ) == 0 && list_.list( ).size( ) != 0;
|
||||
}
|
||||
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
#endif // _H_LW_LIB_INLINE_SRDIO
|
33
include/ebcl/inline/SRDParserConfig.hh
Normal file
33
include/ebcl/inline/SRDParserConfig.hh
Normal file
|
@ -0,0 +1,33 @@
|
|||
/******************************************************************************/
|
||||
/* SRD - PARSER CONFIGURATION - INLINE CODE ***********************************/
|
||||
/******************************************************************************/
|
||||
|
||||
#ifndef _H_LW_LIB_INLINE_SRDPARSERCONFIG
|
||||
#define _H_LW_LIB_INLINE_SRDPARSERCONFIG
|
||||
#include <lw/lib/SRDParserConfig.hh>
|
||||
namespace lw {
|
||||
|
||||
|
||||
/*= T_SRDTransition ==========================================================*/
|
||||
|
||||
inline T_SRDTransition::T_SRDTransition( E_SRDTokenType tokenType , uint32_t next )
|
||||
: type( E_SRDTransitionType::TOKEN ) , tokenType( tokenType ) ,
|
||||
next( next )
|
||||
{ }
|
||||
|
||||
inline T_SRDTransition::T_SRDTransition( E_SRDTransitionType type , uint32_t index , uint32_t next )
|
||||
: type( type ) , index( index ) , next( next )
|
||||
{ }
|
||||
|
||||
|
||||
/*= T_SRDParserConfig ========================================================*/
|
||||
|
||||
inline T_Optional< uint32_t > T_SRDParserConfig::enumValue(
|
||||
char const* name , T_String const& member ) const noexcept
|
||||
{
|
||||
return enumValue( T_String::Pooled( name ) , member );
|
||||
}
|
||||
|
||||
|
||||
} // namespace
|
||||
#endif // _H_LW_LIB_INLINE_SRDPARSERCONFIG
|
25
include/ebcl/inline/SRDText.hh
Normal file
25
include/ebcl/inline/SRDText.hh
Normal file
|
@ -0,0 +1,25 @@
|
|||
/******************************************************************************/
|
||||
/* SRD - TEXT STORAGE - INLINE CODE *******************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
#ifndef _H_LW_LIB_INLINE_SRDTEXT
|
||||
#define _H_LW_LIB_INLINE_SRDTEXT
|
||||
#include <lw/lib/SRDText.hh>
|
||||
namespace lw {
|
||||
|
||||
|
||||
inline void SRDWriteAsText( A_OutputStream& output , T_SRDList const& data )
|
||||
{
|
||||
T_SRDTextWriter( output ).start( ).putList( data ).end( );
|
||||
}
|
||||
|
||||
|
||||
/*= T_SRDTextReader ==========================================================*/
|
||||
|
||||
inline T_SRDTextReader::T_SRDTextReader( A_SRDReaderTarget& target )
|
||||
: A_SRDReader( target )
|
||||
{ }
|
||||
|
||||
|
||||
} // namespace
|
||||
#endif // _H_LW_LIB_INLINE_SRDTEXT
|
98
include/ebcl/inline/Streams.hh
Normal file
98
include/ebcl/inline/Streams.hh
Normal file
|
@ -0,0 +1,98 @@
|
|||
/******************************************************************************/
|
||||
/* STREAMS - INLINE CODE ******************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
#include <lw/lib/Streams.hh>
|
||||
namespace lw {
|
||||
|
||||
|
||||
/*= X_StreamError ============================================================*/
|
||||
|
||||
inline X_StreamError::X_StreamError( E_StreamError e )
|
||||
: std::exception( ) , error_( e ) , sysError_( -1 )
|
||||
{ }
|
||||
|
||||
inline X_StreamError::X_StreamError( int error )
|
||||
: std::exception( ) , error_( E_StreamError::SYSTEM_ERROR ) , sysError_( error )
|
||||
{ }
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
inline E_StreamError X_StreamError::code( ) const
|
||||
{
|
||||
return error_;
|
||||
}
|
||||
|
||||
inline int X_StreamError::systemError( ) const
|
||||
{
|
||||
return sysError_;
|
||||
}
|
||||
|
||||
|
||||
/*= A_Stream =================================================================*/
|
||||
|
||||
inline A_Stream::A_Stream( bool isInput , size_t position ) noexcept
|
||||
: isInput_( isInput ) , knownSize_( false ) , position_( position )
|
||||
{ }
|
||||
|
||||
inline A_Stream::A_Stream( bool isInput , size_t position , size_t size ) noexcept
|
||||
: isInput_( isInput ) , knownSize_( true ) , size_( size ) ,
|
||||
position_( position )
|
||||
{ }
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
inline A_Stream::~A_Stream( )
|
||||
{ }
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
inline bool A_Stream::isInput( ) const
|
||||
{
|
||||
return isInput_;
|
||||
}
|
||||
|
||||
inline bool A_Stream::isSizeKnown( ) const
|
||||
{
|
||||
return knownSize_;
|
||||
}
|
||||
|
||||
inline size_t A_Stream::position( ) const
|
||||
{
|
||||
return position_;
|
||||
}
|
||||
|
||||
inline size_t A_Stream::size( ) const
|
||||
{
|
||||
if ( knownSize_ ) {
|
||||
return size_;
|
||||
} else {
|
||||
throw X_StreamError( E_StreamError::NOT_SUPPORTED );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*= A_InputStream ============================================================*/
|
||||
|
||||
inline A_InputStream::A_InputStream( size_t position ) noexcept
|
||||
: A_Stream( true , position )
|
||||
{ }
|
||||
|
||||
inline A_InputStream::A_InputStream( size_t position , size_t size ) noexcept
|
||||
: A_Stream( true , position , size )
|
||||
{ }
|
||||
|
||||
|
||||
/*= A_OutputStream ===========================================================*/
|
||||
|
||||
inline A_OutputStream::A_OutputStream( size_t position ) noexcept
|
||||
: A_Stream( false , position )
|
||||
{ }
|
||||
|
||||
inline A_OutputStream::A_OutputStream( size_t position , size_t size ) noexcept
|
||||
: A_Stream( false , position , size )
|
||||
{ }
|
||||
|
||||
|
||||
} // namespace
|
591
include/ebcl/inline/Strings.hh
Normal file
591
include/ebcl/inline/Strings.hh
Normal file
|
@ -0,0 +1,591 @@
|
|||
/******************************************************************************/
|
||||
/* STRINGS AND RELATED UTILITIES - INLINE CODE ********************************/
|
||||
/******************************************************************************/
|
||||
|
||||
#ifndef _H_LW_LIB_INLINE_STRINGS
|
||||
#define _H_LW_LIB_INLINE_STRINGS
|
||||
#include <lw/lib/Strings.hh>
|
||||
namespace lw {
|
||||
|
||||
|
||||
/*= T_Character ==============================================================*/
|
||||
|
||||
inline T_Character::T_Character( ) noexcept
|
||||
: codepoint( 0 )
|
||||
{ }
|
||||
|
||||
inline T_Character::T_Character( const T_Character& other ) noexcept
|
||||
: codepoint( other.codepoint )
|
||||
{ }
|
||||
|
||||
template< typename T , typename >
|
||||
inline T_Character::T_Character( T codepoint ) noexcept
|
||||
: codepoint( uint32_t( codepoint ) )
|
||||
{
|
||||
assert( codepoint >= 0 );
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
inline bool T_Character::isValid( ) const
|
||||
{
|
||||
return codepoint < 0x110000;
|
||||
}
|
||||
|
||||
inline bool T_Character::isAscii( ) const
|
||||
{
|
||||
return codepoint < 128;
|
||||
}
|
||||
|
||||
inline bool T_Character::isControl( ) const
|
||||
{
|
||||
return codepoint < 32;
|
||||
}
|
||||
|
||||
inline bool T_Character::isUppercase( ) const
|
||||
{
|
||||
return codepoint >= 'A' && codepoint <= 'Z';
|
||||
}
|
||||
|
||||
inline bool T_Character::isLowercase( ) const
|
||||
{
|
||||
return codepoint >= 'a' && codepoint <= 'z';
|
||||
}
|
||||
|
||||
inline bool T_Character::isAlpha( ) const
|
||||
{
|
||||
return isUppercase( ) || isLowercase( );
|
||||
}
|
||||
|
||||
inline bool T_Character::isNumeric( ) const
|
||||
{
|
||||
return codepoint >= '0' && codepoint <= '9';
|
||||
}
|
||||
|
||||
inline bool T_Character::isAlphanumeric( ) const
|
||||
{
|
||||
return isAlpha( ) || isNumeric( );
|
||||
}
|
||||
|
||||
inline bool T_Character::isWhitespace( ) const
|
||||
{
|
||||
return codepoint == 32 || codepoint == '\t'
|
||||
|| codepoint == '\n' || codepoint == '\r';
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
inline bool T_Character::operator== ( T_Character const& other ) const
|
||||
{
|
||||
return codepoint == other.codepoint;
|
||||
}
|
||||
|
||||
inline bool T_Character::operator!= ( T_Character const& other ) const
|
||||
{
|
||||
return codepoint != other.codepoint;
|
||||
}
|
||||
|
||||
inline bool T_Character::operator< ( T_Character const& other ) const
|
||||
{
|
||||
return codepoint < other.codepoint;
|
||||
}
|
||||
|
||||
inline bool T_Character::operator> ( T_Character const& other ) const
|
||||
{
|
||||
return codepoint > other.codepoint;
|
||||
}
|
||||
|
||||
inline bool T_Character::operator<= ( T_Character const& other ) const
|
||||
{
|
||||
return codepoint <= other.codepoint;
|
||||
}
|
||||
|
||||
inline bool T_Character::operator>= ( T_Character const& other ) const
|
||||
{
|
||||
return codepoint >= other.codepoint;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
template< typename T , typename >
|
||||
inline bool T_Character::operator== ( T other ) const
|
||||
{
|
||||
return codepoint == uint32_t( other );
|
||||
}
|
||||
|
||||
template< typename T , typename >
|
||||
inline bool T_Character::operator!= ( T other ) const
|
||||
{
|
||||
return codepoint != uint32_t( other );
|
||||
}
|
||||
|
||||
template< typename T , typename >
|
||||
inline bool T_Character::operator< ( T other ) const
|
||||
{
|
||||
return codepoint < uint32_t( other );
|
||||
}
|
||||
|
||||
template< typename T , typename >
|
||||
inline bool T_Character::operator<= ( T other ) const
|
||||
{
|
||||
return codepoint <= uint32_t( other );
|
||||
}
|
||||
|
||||
template< typename T , typename >
|
||||
inline bool T_Character::operator> ( T other ) const
|
||||
{
|
||||
return codepoint > uint32_t( other );
|
||||
}
|
||||
|
||||
template< typename T , typename >
|
||||
inline bool T_Character::operator>= ( T other ) const
|
||||
{
|
||||
return codepoint >= uint32_t( other );
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
inline T_Character::operator uint32_t ( ) const
|
||||
{
|
||||
return codepoint;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
inline uint32_t T_Character::writeTo( char* output , uint32_t avail ) const
|
||||
{
|
||||
return UTF8PutCodepoint( output , avail , codepoint );
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
inline T_Character T_Character::toUpper( ) const
|
||||
{
|
||||
if ( isLowercase( ) ) {
|
||||
return *this & (~0x20);
|
||||
} else {
|
||||
return *this;
|
||||
}
|
||||
}
|
||||
|
||||
inline T_Character T_Character::toLower( ) const
|
||||
{
|
||||
if ( isUppercase( ) ) {
|
||||
return *this | 0x20;
|
||||
} else {
|
||||
return *this;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*= A_StringData =============================================================*/
|
||||
|
||||
inline bool A_StringData::valid( ) const
|
||||
{
|
||||
return valid_;
|
||||
}
|
||||
|
||||
inline char const* A_StringData::data( ) const
|
||||
{
|
||||
return data_;
|
||||
}
|
||||
|
||||
inline uint32_t A_StringData::length( ) const
|
||||
{
|
||||
return length_;
|
||||
}
|
||||
|
||||
inline uint32_t A_StringData::size( ) const
|
||||
{
|
||||
return size_;
|
||||
}
|
||||
|
||||
|
||||
/*= T_String =================================================================*/
|
||||
|
||||
inline T_String T_String::Pooled( char const* string )
|
||||
{
|
||||
return Pooled( string , strlen( string ) );
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
inline bool T_String::valid( ) const
|
||||
{
|
||||
return data_->valid( );
|
||||
}
|
||||
|
||||
inline uint32_t T_String::size( ) const
|
||||
{
|
||||
return data_->size( );
|
||||
}
|
||||
|
||||
inline uint32_t T_String::length( ) const
|
||||
{
|
||||
return data_->length( );
|
||||
}
|
||||
|
||||
inline char const* T_String::data( ) const
|
||||
{
|
||||
return data_->data( );
|
||||
}
|
||||
|
||||
inline T_String::operator bool ( ) const
|
||||
{
|
||||
return size( ) != 0;
|
||||
}
|
||||
|
||||
inline bool T_String::operator! ( ) const
|
||||
{
|
||||
return size( ) == 0;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
inline T_Character T_String::operator[] ( uint32_t index ) const
|
||||
{
|
||||
assert( index < length( ) );
|
||||
char const* const d( data( ) );
|
||||
return UTF8GetCodepoint( d + UTF8GetMemoryOffset( d , index ) );
|
||||
}
|
||||
|
||||
inline T_String T_String::range( uint32_t start , uint32_t end ) const
|
||||
{
|
||||
if ( start > end ) {
|
||||
return T_String( );
|
||||
}
|
||||
return substr( start , end == UINT32_MAX ? UINT32_MAX : ( end - start + 1 ) );
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
inline bool T_String::equals( T_String const& other ) const
|
||||
{
|
||||
return data_ == other.data_ || ( other.size( ) == size( )
|
||||
&& ( size( ) == 0 || !memcmp( other.data( ) , data( ) , size( ) ) ) );
|
||||
}
|
||||
|
||||
inline bool T_String::equals( char const* string ) const
|
||||
{
|
||||
const auto l( strlen( string ) );
|
||||
return size( ) == l && ( l == 0 || !memcmp( string , data( ) , l ) );
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
inline bool T_String::operator== ( T_String const& other ) const
|
||||
{
|
||||
return equals( other );
|
||||
}
|
||||
|
||||
inline bool T_String::operator!= ( T_String const& other ) const
|
||||
{
|
||||
return !equals( other );
|
||||
}
|
||||
|
||||
inline bool T_String::operator< ( T_String const& other ) const
|
||||
{
|
||||
return compare( other ) < 0;
|
||||
}
|
||||
|
||||
inline bool T_String::operator> ( T_String const& other ) const
|
||||
{
|
||||
return compare( other ) > 0;
|
||||
}
|
||||
|
||||
inline bool T_String::operator>= ( T_String const& other ) const
|
||||
{
|
||||
return compare( other ) >= 0;
|
||||
}
|
||||
|
||||
inline bool T_String::operator<= ( T_String const& other ) const
|
||||
{
|
||||
return compare( other ) <= 0;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
inline bool T_String::operator== ( char const* string ) const
|
||||
{
|
||||
return equals( string );
|
||||
}
|
||||
|
||||
inline bool T_String::operator!= ( char const* string ) const
|
||||
{
|
||||
return !equals( string );
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
inline int64_t T_String::toInteger( bool * ok , int base , bool useSep ,
|
||||
T_Character separator ) const
|
||||
{
|
||||
return UTF8ToInteger( data( ) , size( ) , ok , base , useSep , separator );
|
||||
}
|
||||
|
||||
inline uint64_t T_String::toUnsignedInteger( bool * ok , int base , bool useSep ,
|
||||
T_Character separator ) const
|
||||
{
|
||||
return UTF8ToUnsignedInteger( data( ) , size( ) , ok , base , useSep , separator );
|
||||
}
|
||||
|
||||
inline double T_String::toDouble( bool * ok , T_Character decimalPoint ,
|
||||
bool useSep , T_Character separator ) const
|
||||
{
|
||||
return UTF8ToDouble( data( ) , size( ) , ok , decimalPoint , useSep , separator );
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
inline T_StringIterator T_String::getIterator( uint32_t offset ) const
|
||||
{
|
||||
if ( offset >= data_->size( ) ) {
|
||||
return T_StringIterator( nullptr , 0 );
|
||||
}
|
||||
return T_StringIterator( data_ , offset );
|
||||
}
|
||||
|
||||
inline T_String::operator T_StringIterator( ) const
|
||||
{
|
||||
return getIterator( 0 );
|
||||
}
|
||||
|
||||
|
||||
/*= T_String helpers =========================================================*/
|
||||
|
||||
inline M_DEFINE_HASH( T_String )
|
||||
{
|
||||
return HashData(
|
||||
reinterpret_cast< uint8_t const* >( item.data( ) ) ,
|
||||
item.size( ) );
|
||||
}
|
||||
|
||||
inline M_DEFINE_COMPARATOR( T_String )
|
||||
{
|
||||
return a.compare( b );
|
||||
}
|
||||
|
||||
|
||||
/*= T_StringIterator =========================================================*/
|
||||
|
||||
inline T_StringIterator::T_StringIterator( T_StringIterator&& other ) noexcept
|
||||
: data_( other.data_ ) , pos_( other.pos_ ) ,
|
||||
index_( other.index_ ) ,
|
||||
codepoint_( other.codepoint_ ) ,
|
||||
bytes_( other.bytes_ )
|
||||
{
|
||||
other.data_ = nullptr;
|
||||
}
|
||||
|
||||
inline T_StringIterator& T_StringIterator::operator= ( T_StringIterator&& other ) noexcept
|
||||
{
|
||||
swap( *this , other );
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
inline uint32_t T_StringIterator::index( ) const
|
||||
{
|
||||
return index_;
|
||||
}
|
||||
|
||||
inline bool T_StringIterator::atEnd( ) const
|
||||
{
|
||||
return data_ == nullptr || pos_ == data_->size( );
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
inline T_Character T_StringIterator::character( ) const
|
||||
{
|
||||
return codepoint_;
|
||||
}
|
||||
|
||||
inline T_StringIterator::operator T_Character ( ) const
|
||||
{
|
||||
return codepoint_;
|
||||
}
|
||||
|
||||
|
||||
/*= T_StringBuilder ==========================================================*/
|
||||
|
||||
inline T_StringBuilder::T_StringBuilder( ) noexcept
|
||||
: data_( nullptr ) , capacity_( 0 ) , size_( 0 ) , length_( 0 )
|
||||
{ }
|
||||
|
||||
inline T_StringBuilder::T_StringBuilder( char const* string )
|
||||
: T_StringBuilder( string , strlen( string ) )
|
||||
{ }
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
inline char const* T_StringBuilder::data( ) const
|
||||
{
|
||||
return data_;
|
||||
}
|
||||
|
||||
inline uint32_t T_StringBuilder::capacity( ) const
|
||||
{
|
||||
return capacity_;
|
||||
}
|
||||
|
||||
inline uint32_t T_StringBuilder::size( ) const
|
||||
{
|
||||
return size_;
|
||||
}
|
||||
|
||||
inline uint32_t T_StringBuilder::length( ) const
|
||||
{
|
||||
return length_;
|
||||
}
|
||||
|
||||
inline T_StringBuilder::operator bool ( ) const
|
||||
{
|
||||
return size_ != 0;
|
||||
}
|
||||
|
||||
inline bool T_StringBuilder::operator! ( ) const
|
||||
{
|
||||
return size_ == 0;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
inline T_StringBuilder& T_StringBuilder::clear( )
|
||||
{
|
||||
size_ = length_ = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
inline bool T_StringBuilder::operator== ( T_StringBuilder const& other ) const
|
||||
{
|
||||
return other.size_ == size_ && ( size_ == 0 || !memcmp( other.data_ , data_ , size_ ) );
|
||||
}
|
||||
|
||||
inline bool T_StringBuilder::operator!= ( T_StringBuilder const& other ) const
|
||||
{
|
||||
return other.size_ != size_ || ( size_ != 0 && memcmp( other.data_ , data_ , size_ ) );
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
inline bool T_StringBuilder::operator== ( T_String const& string ) const
|
||||
{
|
||||
return string.size( ) == size_ && ( size_ == 0 || !memcmp( string.data( ) , data_ , size_ ) );
|
||||
}
|
||||
|
||||
inline bool T_StringBuilder::operator!= ( T_String const& string ) const
|
||||
{
|
||||
return string.size( ) != size_ || ( size_ != 0 && memcmp( string.data( ) , data_ , size_ ) );
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
inline bool T_StringBuilder::operator== ( char const* string ) const
|
||||
{
|
||||
return strlen( string ) == size_ && ( size_ == 0 || !memcmp( string , data_ , size_ ) );
|
||||
}
|
||||
|
||||
inline bool T_StringBuilder::operator!= ( char const* string ) const
|
||||
{
|
||||
return strlen( string ) != size_ || ( size_ != 0 && memcmp( string , data_ , size_ ) );
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
inline int64_t T_StringBuilder::toInteger( bool * ok , int base , bool useSep ,
|
||||
T_Character separator ) const
|
||||
{
|
||||
return UTF8ToInteger( data_ , size_ , ok , base , useSep , separator );
|
||||
}
|
||||
|
||||
inline uint64_t T_StringBuilder::toUnsignedInteger( bool * ok , int base , bool useSep ,
|
||||
T_Character separator ) const
|
||||
{
|
||||
return UTF8ToUnsignedInteger( data_ , size_ , ok , base , useSep , separator );
|
||||
}
|
||||
|
||||
inline double T_StringBuilder::toDouble( bool * ok , T_Character decimalPoint ,
|
||||
bool useSep , T_Character separator ) const
|
||||
{
|
||||
return UTF8ToDouble( data( ) , size( ) , ok , decimalPoint , useSep , separator );
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
inline T_StringBuilder& operator<< ( T_StringBuilder& sb , T_StringBuilder const& value )
|
||||
{
|
||||
return sb.append( value );
|
||||
}
|
||||
|
||||
inline T_StringBuilder& operator<< ( T_StringBuilder& sb , T_StringBuilder&& value )
|
||||
{
|
||||
return sb.append( std::move( value ) );
|
||||
}
|
||||
|
||||
inline T_StringBuilder& operator<< ( T_StringBuilder& sb , T_String const& value )
|
||||
{
|
||||
return sb.append( value );
|
||||
}
|
||||
|
||||
inline T_StringBuilder& operator<< ( T_StringBuilder& sb , char const* value )
|
||||
{
|
||||
return sb.append( value , strlen( value ) );
|
||||
}
|
||||
|
||||
inline T_StringBuilder& operator<< ( T_StringBuilder& sb , char value )
|
||||
{
|
||||
return sb.append( value );
|
||||
}
|
||||
|
||||
inline T_StringBuilder& operator<< ( T_StringBuilder& sb , T_Character value )
|
||||
{
|
||||
return sb.append( value );
|
||||
}
|
||||
|
||||
inline T_StringBuilder& operator<< ( T_StringBuilder& sb , int16_t value )
|
||||
{
|
||||
return sb.appendNumeric( int64_t( value ) );
|
||||
}
|
||||
|
||||
inline T_StringBuilder& operator<< ( T_StringBuilder& sb , int32_t value )
|
||||
{
|
||||
return sb.appendNumeric( int64_t( value ) );
|
||||
}
|
||||
|
||||
inline T_StringBuilder& operator<< ( T_StringBuilder& sb , int64_t value )
|
||||
{
|
||||
return sb.appendNumeric( value );
|
||||
}
|
||||
|
||||
inline T_StringBuilder& operator<< ( T_StringBuilder& sb , uint16_t value )
|
||||
{
|
||||
return sb.appendNumeric( uint64_t( value ) );
|
||||
}
|
||||
|
||||
inline T_StringBuilder& operator<< ( T_StringBuilder& sb , uint32_t value )
|
||||
{
|
||||
return sb.appendNumeric( uint64_t( value ) );
|
||||
}
|
||||
|
||||
inline T_StringBuilder& operator<< ( T_StringBuilder& sb , uint64_t value )
|
||||
{
|
||||
return sb.appendNumeric( value );
|
||||
}
|
||||
|
||||
inline T_StringBuilder& operator<< ( T_StringBuilder& sb , float value )
|
||||
{
|
||||
return sb.appendDouble( double( value ) );
|
||||
}
|
||||
|
||||
inline T_StringBuilder& operator<< ( T_StringBuilder& sb , double value )
|
||||
{
|
||||
return sb.appendDouble( value );
|
||||
}
|
||||
|
||||
|
||||
} // namespace
|
||||
#endif // _H_LW_LIB_INLINE_STRINGS
|
352
include/ebcl/inline/Threading.hh
Normal file
352
include/ebcl/inline/Threading.hh
Normal file
|
@ -0,0 +1,352 @@
|
|||
/******************************************************************************/
|
||||
/* THREADING - INLINE CODE ****************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
#ifndef _H_LW_LIB_INLINE_THREADING
|
||||
#define _H_LW_LIB_INLINE_THREADING
|
||||
#include <lw/lib/Threading.hh>
|
||||
namespace lw {
|
||||
|
||||
|
||||
/*= T_ReadWriteMutex =========================================================*/
|
||||
|
||||
inline T_ReadWriteMutex::T_ReadWriteMutex( )
|
||||
: state_( 0 )
|
||||
{ }
|
||||
|
||||
inline T_ReadWriteMutex::~T_ReadWriteMutex( )
|
||||
{
|
||||
assert( state_ == 0 );
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
inline void T_ReadWriteMutex::lock( )
|
||||
{
|
||||
T_ExclusiveLock lock( mutex_ );
|
||||
writerBlock_.wait( lock , [this]( ) {
|
||||
return ( state_ & C_WLOCKED_ ) == 0;
|
||||
} );
|
||||
state_ |= C_WLOCKED_;
|
||||
readerBlock_.wait( lock , [this]( ) {
|
||||
return ( state_ & C_READERS_ ) == 0;
|
||||
} );
|
||||
}
|
||||
|
||||
inline bool T_ReadWriteMutex::try_lock( )
|
||||
{
|
||||
T_ExclusiveLock lock( mutex_ , std::try_to_lock );
|
||||
if ( lock.owns_lock( ) && state_ == 0 ) {
|
||||
state_ = C_WLOCKED_;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline void T_ReadWriteMutex::unlock( )
|
||||
{
|
||||
T_ScopeLock lock( mutex_ );
|
||||
assert( ( state_ & C_WLOCKED_ ) != 0 );
|
||||
state_ = 0;
|
||||
writerBlock_.notify_all( );
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
inline void T_ReadWriteMutex::lock_shared( )
|
||||
{
|
||||
T_ExclusiveLock lock( mutex_ );
|
||||
writerBlock_.wait( lock , [this]( ) {
|
||||
return state_ < C_READERS_;
|
||||
} );
|
||||
state_ ++;
|
||||
}
|
||||
|
||||
inline bool T_ReadWriteMutex::try_lock_shared( )
|
||||
{
|
||||
T_ExclusiveLock lock( mutex_ , std::try_to_lock );
|
||||
if ( !lock.owns_lock( ) && state_ < C_READERS_ ) {
|
||||
state_ ++;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline void T_ReadWriteMutex::unlock_shared( )
|
||||
{
|
||||
T_ScopeLock lock( mutex_ );
|
||||
assert( ( state_ & C_READERS_ ) != 0 );
|
||||
auto previous( state_ -- );
|
||||
if ( previous == ( C_WLOCKED_ & 1 ) ) {
|
||||
readerBlock_.notify_one( );
|
||||
} else if ( previous == C_READERS_ ) {
|
||||
writerBlock_.notify_one( );
|
||||
}
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
inline void T_ReadWriteMutex::upgradeLock( )
|
||||
{
|
||||
T_ExclusiveLock lock( mutex_ );
|
||||
assert( ( state_ & C_READERS_ ) != 0 );
|
||||
state_ --;
|
||||
writerBlock_.wait( lock , [this]( ) {
|
||||
return ( state_ & C_WLOCKED_ ) == 0;
|
||||
} );
|
||||
state_ |= C_WLOCKED_;
|
||||
readerBlock_.wait( lock , [this]( ) {
|
||||
return ( state_ & C_READERS_ ) == 0;
|
||||
} );
|
||||
}
|
||||
|
||||
|
||||
/*= T_ReadLock ===============================================================*/
|
||||
|
||||
inline T_ReadLock::T_ReadLock( ) noexcept
|
||||
: std::shared_lock< T_ReadWriteMutex >( )
|
||||
{ }
|
||||
|
||||
inline T_ReadLock::T_ReadLock( T_ReadLock&& other )
|
||||
: std::shared_lock< T_ReadWriteMutex >( std::move( other ) )
|
||||
{ }
|
||||
|
||||
inline T_ReadLock::T_ReadLock( T_ReadWriteMutex& m )
|
||||
: std::shared_lock< T_ReadWriteMutex >( m )
|
||||
{ }
|
||||
|
||||
inline T_ReadLock::T_ReadLock( T_ReadWriteMutex& m , std::defer_lock_t t )
|
||||
: std::shared_lock< T_ReadWriteMutex >( m , t )
|
||||
{ }
|
||||
|
||||
inline T_ReadLock::T_ReadLock( T_ReadWriteMutex& m , std::try_to_lock_t t )
|
||||
: std::shared_lock< T_ReadWriteMutex >( m , t )
|
||||
{ }
|
||||
|
||||
inline T_ReadLock::T_ReadLock( T_ReadWriteMutex& m , std::adopt_lock_t t )
|
||||
: std::shared_lock< T_ReadWriteMutex >( m , t )
|
||||
{ }
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
inline T_WriteLock T_ReadLock::upgrade( )
|
||||
{
|
||||
assert( owns_lock( ) );
|
||||
RP_ReadWriteMutex mutex( release( ) );
|
||||
mutex->upgradeLock( );
|
||||
return T_WriteLock( *mutex , std::adopt_lock );
|
||||
}
|
||||
|
||||
|
||||
/*= T_RingBuffer =============================================================*/
|
||||
|
||||
template< typename T >
|
||||
inline T_RingBuffer< T >::T_RingBuffer( uint32_t expand )
|
||||
: expand_( expand ) , data_( nullptr ) , allocated_( 0 ) ,
|
||||
used_( 0 ) , readPos_( 0 )
|
||||
{
|
||||
assert( expand );
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
inline T_RingBuffer< T >::T_RingBuffer( T_RingBuffer< T > const& other )
|
||||
: expand_( other.expand_ ) , allocated_( other.allocated_ ) ,
|
||||
used_( other.used_ ) , readPos_( 0 )
|
||||
{
|
||||
if ( allocated_ ) {
|
||||
data_ = reinterpret_cast< T* >( ::operator new( sizeof( T ) * allocated_ ) );
|
||||
for ( uint32_t i = 0 ; i < other.used_ ; i ++ ) {
|
||||
const auto sidx( ( i + other.readPos_ ) % allocated_ );
|
||||
new ( reinterpret_cast< char* >( &data_[ i ] ) ) T( other.data_[ sidx ] );
|
||||
}
|
||||
} else {
|
||||
data_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
inline T_RingBuffer< T >::T_RingBuffer( T_RingBuffer< T >&& other ) noexcept
|
||||
: T_RingBuffer( other.growth( ) )
|
||||
{
|
||||
swap( *this , other );
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
template< typename T >
|
||||
inline T_RingBuffer< T >::~T_RingBuffer( )
|
||||
{
|
||||
free( );
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
template< typename T >
|
||||
inline T_RingBuffer< T >& T_RingBuffer< T >::operator =( T_RingBuffer< T > const& other )
|
||||
{
|
||||
free( );
|
||||
|
||||
expand_ = other.expand_;
|
||||
allocated_ = other.allocated_;
|
||||
used_ = other.used_;
|
||||
readPos_ = 0;
|
||||
if ( allocated_ ) {
|
||||
data_ = reinterpret_cast< T* >( ::operator new( sizeof( T ) * allocated_ ) );
|
||||
for ( uint32_t i = 0 ; i < other.used_ ; i ++ ) {
|
||||
const auto sidx( ( i + other.readPos_ ) % allocated_ );
|
||||
new ( reinterpret_cast< char* >( &data_[ i ] ) ) T( other.data_[ sidx ] );
|
||||
}
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
inline T_RingBuffer< T >& T_RingBuffer< T >::operator =( T_RingBuffer< T >&& other ) noexcept
|
||||
{
|
||||
free( );
|
||||
expand_ = other.expand_;
|
||||
swap( *this , other );
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
template< typename T >
|
||||
inline void swap( T_RingBuffer< T >& lhs , T_RingBuffer< T >& rhs ) noexcept
|
||||
{
|
||||
using std::swap;
|
||||
swap( lhs.expand_ , rhs.expand_ );
|
||||
swap( lhs.data_ , rhs.data_ );
|
||||
swap( lhs.allocated_ , rhs.allocated_ );
|
||||
swap( lhs.used_ , rhs.used_ );
|
||||
swap( lhs.readPos_ , rhs.readPos_ );
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
template< typename T >
|
||||
inline void T_RingBuffer< T >::free( )
|
||||
{
|
||||
for ( uint32_t i = 0 ; i < used_ ; i ++ ) {
|
||||
const auto idx( ( readPos_ + i ) % allocated_ );
|
||||
data_[ idx ].~T( );
|
||||
}
|
||||
::operator delete( (void*) data_ );
|
||||
data_ = nullptr;
|
||||
allocated_ = 0;
|
||||
used_ = 0;
|
||||
readPos_ = 0;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
template< typename T >
|
||||
inline uint32_t T_RingBuffer< T >::size( ) const
|
||||
{
|
||||
return used_;
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
inline uint32_t T_RingBuffer< T >::capacity( ) const
|
||||
{
|
||||
return allocated_;
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
inline uint32_t T_RingBuffer< T >::growth( ) const
|
||||
{
|
||||
return expand_;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
template< typename T >
|
||||
inline bool T_RingBuffer< T >::readNext( T& output )
|
||||
{
|
||||
if ( used_ == 0 ) {
|
||||
return false;
|
||||
}
|
||||
output = std::move( data_[ readPos_ ] );
|
||||
data_[ readPos_ ].~T( );
|
||||
readPos_ = ( readPos_ + 1 ) % allocated_;
|
||||
used_ --;
|
||||
return true;
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
inline bool T_RingBuffer< T >::readAll( T_Array< T >& output )
|
||||
{
|
||||
if ( used_ == 0 ) {
|
||||
return false;
|
||||
}
|
||||
for ( uint32_t i = 0 ; i < used_ ; i ++ ) {
|
||||
output.add( std::move( data_[ ( readPos_ + i ) % allocated_ ] ) );
|
||||
}
|
||||
for ( uint32_t i = 0 ; i < used_ ; i ++ ) {
|
||||
data_[ ( readPos_ + i ) % allocated_ ].~T( );
|
||||
}
|
||||
used_ = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
template< typename T >
|
||||
inline void T_RingBuffer< T >::put( T const& input )
|
||||
{
|
||||
if ( used_ == allocated_ ) {
|
||||
expand( );
|
||||
}
|
||||
const auto idx( ( readPos_ + used_ ) % allocated_ );
|
||||
new ( reinterpret_cast< char* >( &data_[ idx ] ) ) T( input );
|
||||
used_ ++;
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
inline void T_RingBuffer< T >::put( T&& input )
|
||||
{
|
||||
if ( used_ == allocated_ ) {
|
||||
expand( );
|
||||
}
|
||||
const auto idx( ( readPos_ + used_ ) % allocated_ );
|
||||
new ( reinterpret_cast< char* >( &data_[ idx ] ) ) T( std::move( input ) );
|
||||
used_ ++;
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
template< typename... ArgTypes >
|
||||
inline void T_RingBuffer< T >::putNew( ArgTypes&&... arguments )
|
||||
{
|
||||
if ( used_ == allocated_ ) {
|
||||
expand( );
|
||||
}
|
||||
const auto idx( ( readPos_ + used_ ) % allocated_ );
|
||||
new ( reinterpret_cast< char* >( &data_[ idx ] ) ) T( std::forward< ArgTypes >( arguments ) ... );
|
||||
used_ ++;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
template< typename T >
|
||||
inline void T_RingBuffer< T >::expand( )
|
||||
{
|
||||
const auto nsz( allocated_ + expand_ );
|
||||
T* nData( reinterpret_cast< T* >( ::operator new( sizeof( T ) * nsz ) ) );
|
||||
for ( uint32_t i = 0 ; i < used_ ; i ++ ) {
|
||||
const auto idx( ( readPos_ + i ) % allocated_ );
|
||||
new( reinterpret_cast< char* >( &nData[ i ] ) ) T( std::move( data_[ idx ] ) );
|
||||
data_[ idx ].~T( );
|
||||
}
|
||||
|
||||
using std::swap;
|
||||
swap( data_ , nData );
|
||||
allocated_ = nsz;
|
||||
readPos_ = 0;
|
||||
::operator delete( (void*) nData );
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
#endif // _H_LW_LIB_INLINE_THREADING
|
1000
include/ebcl/inline/Types.hh
Normal file
1000
include/ebcl/inline/Types.hh
Normal file
File diff suppressed because it is too large
Load diff
303
include/ebcl/inline/Utilities.hh
Normal file
303
include/ebcl/inline/Utilities.hh
Normal file
|
@ -0,0 +1,303 @@
|
|||
/******************************************************************************/
|
||||
/* VARIOUS UTILITIES - INLINE CODE ********************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
#ifndef _H_LW_LIB_INLINE_UTILITIES
|
||||
#define _H_LW_LIB_INLINE_UTILITIES
|
||||
#include <lw/lib/Utilities.hh>
|
||||
namespace lw {
|
||||
|
||||
|
||||
template< typename T >
|
||||
inline constexpr bool IsPowerOf2( T value )
|
||||
{
|
||||
static_assert( std::is_integral< T >( ) , "integer type only" );
|
||||
return value > 0 && ( value & ( value - 1 ) ) == 0;
|
||||
}
|
||||
|
||||
|
||||
/*= ENDIAN DETECTION =========================================================*/
|
||||
|
||||
inline static constexpr bool IsBigEndian( )
|
||||
{
|
||||
return E_Endian::NATIVE == E_Endian::BIG;
|
||||
}
|
||||
|
||||
inline static constexpr bool IsLittleEndian( )
|
||||
{
|
||||
return E_Endian::NATIVE == E_Endian::LITTLE;
|
||||
}
|
||||
|
||||
static_assert( IsBigEndian( ) || IsLittleEndian( ) ,
|
||||
"unsupported endianness" );
|
||||
|
||||
|
||||
/*= ENDIAN CONVERSION ========================================================*/
|
||||
|
||||
template<
|
||||
typename T ,
|
||||
uint32_t S = sizeof( T ) ,
|
||||
typename = std::enable_if_t<
|
||||
std::is_integral< T >::value
|
||||
|| std::is_floating_point< T >::value
|
||||
>
|
||||
>
|
||||
struct T_ByteSwapper_ { };
|
||||
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
template< typename T >
|
||||
struct T_ByteSwapper_< T , 1 >
|
||||
{
|
||||
static constexpr T swap( T value )
|
||||
{
|
||||
return value;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
template< typename T >
|
||||
struct T_ByteSwapper_< T , 2 >
|
||||
{
|
||||
static T swap( T value )
|
||||
{
|
||||
union { T v;
|
||||
uint16_t i;
|
||||
} u = { value };
|
||||
u.i = __builtin_bswap16( u.i );
|
||||
return u.v;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
template< typename T >
|
||||
struct T_ByteSwapper_< T , 4 >
|
||||
{
|
||||
static T swap( T value )
|
||||
{
|
||||
union { T v;
|
||||
uint32_t i;
|
||||
} u = { value };
|
||||
u.i = __builtin_bswap32( u.i );
|
||||
return u.v;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
template< typename T >
|
||||
struct T_ByteSwapper_< T , 8 >
|
||||
{
|
||||
static T swap( T value );
|
||||
};
|
||||
|
||||
|
||||
template< typename T >
|
||||
inline T T_ByteSwapper_< T , 8 >::swap( T value )
|
||||
{
|
||||
union { T v;
|
||||
uint64_t i;
|
||||
} u = { value };
|
||||
u.i = __builtin_bswap64( u.i );
|
||||
return u.v;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
template< typename T >
|
||||
struct T_LittleEndian< T , E_Endian::LITTLE >
|
||||
{
|
||||
static T convert( T value )
|
||||
{
|
||||
return value;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template< typename T >
|
||||
struct T_LittleEndian< T , E_Endian::BIG >
|
||||
{
|
||||
static T convert( T value )
|
||||
{
|
||||
return T_ByteSwapper_< T >::swap( value );
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
template< typename T >
|
||||
struct T_BigEndian< T , E_Endian::LITTLE >
|
||||
{
|
||||
static T convert( T value )
|
||||
{
|
||||
return T_ByteSwapper_< T >::swap( value );
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template< typename T >
|
||||
struct T_BigEndian< T , E_Endian::BIG >
|
||||
{
|
||||
static T convert( T value )
|
||||
{
|
||||
return value;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/*= COMPARATORS AND SORTING ==================================================*/
|
||||
|
||||
template< typename T >
|
||||
inline int T_Comparator< T >::compare( T const& a , T const& b )
|
||||
{
|
||||
if ( a < b ) return -1;
|
||||
if ( a > b ) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
// T_Sorter_ - "Plumbing" for Sort
|
||||
struct T_Sorter_
|
||||
{
|
||||
typedef std::function< void ( uint8_t* a , uint8_t* b ) > F_Swap;
|
||||
typedef std::function< int ( uint8_t const* a , uint8_t const* b ) > F_Cmp;
|
||||
static void sort( uint8_t* data , uint32_t itemSize , uint32_t items , F_Swap swap , F_Cmp cmp );
|
||||
};
|
||||
|
||||
|
||||
template< typename T >
|
||||
void Sort( T* array , uint32_t items , F_Comparator< T > comparator )
|
||||
{
|
||||
T_Sorter_::sort( reinterpret_cast< uint8_t* >( array ) ,
|
||||
sizeof( T ) , items ,
|
||||
[]( uint8_t* a , uint8_t* b ) {
|
||||
using std::swap;
|
||||
swap( *reinterpret_cast< T* >( a ) ,
|
||||
*reinterpret_cast< T* >( b ) );
|
||||
} ,
|
||||
[comparator]( uint8_t const* a , uint8_t const* b ) {
|
||||
return comparator(
|
||||
*reinterpret_cast< T const* >( a ) ,
|
||||
*reinterpret_cast< T const* >( b ) );
|
||||
} );
|
||||
}
|
||||
|
||||
|
||||
/*= HASHING ==================================================================*/
|
||||
|
||||
template< typename T , int S >
|
||||
inline uint32_t T_HashFunction< T , S >::hash( T const& item )
|
||||
{
|
||||
return HashData( reinterpret_cast< uint8_t const* >( &item ) , sizeof( T ) );
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
template< typename T >
|
||||
inline uint32_t ComputeHash( T const& item )
|
||||
{
|
||||
return T_HashFunction< T >::hash( item );
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
// Hash function specializations for data sizes 1, 2, 4 and 8.
|
||||
|
||||
template< typename T >
|
||||
struct T_HashFunction< T , 1 >
|
||||
{
|
||||
static uint32_t hash( T const& item )
|
||||
{
|
||||
return *reinterpret_cast< uint8_t const* >( &item );
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template< typename T >
|
||||
struct T_HashFunction< T , 2 >
|
||||
{
|
||||
static uint32_t hash( T const& item )
|
||||
{
|
||||
return *reinterpret_cast< uint16_t const* >( &item );
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template< typename T >
|
||||
struct T_HashFunction< T , 4 >
|
||||
{
|
||||
static uint32_t hash( T const& item )
|
||||
{
|
||||
return *reinterpret_cast< uint32_t const* >( &item );
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template< typename T >
|
||||
struct T_HashFunction< T , 8 >
|
||||
{
|
||||
static uint32_t hash( T const& item )
|
||||
{
|
||||
uint64_t v = *reinterpret_cast< uint64_t const* >( &item );
|
||||
return ( v >> 32 ) ^ v;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/*= PRIVATE IMPLEMENTATION BASE ==============================================*/
|
||||
|
||||
inline A_PrivateImplementation::A_PrivateImplementation( void* p , T_Destructor_ destructor )
|
||||
: p_( p ) , piDestructor_( destructor )
|
||||
{ }
|
||||
|
||||
template< typename T >
|
||||
inline A_PrivateImplementation::A_PrivateImplementation( T* p )
|
||||
: A_PrivateImplementation( p , []( void* ptr ) {
|
||||
reinterpret_cast< T* >( ptr )->~T( );
|
||||
} )
|
||||
{ }
|
||||
|
||||
inline A_PrivateImplementation::A_PrivateImplementation( A_PrivateImplementation&& other ) noexcept
|
||||
: p_( other.p_ ) , piDestructor_( other.piDestructor_ )
|
||||
{
|
||||
other.p_ = nullptr;
|
||||
}
|
||||
|
||||
inline A_PrivateImplementation& A_PrivateImplementation::operator=( A_PrivateImplementation&& other ) noexcept
|
||||
{
|
||||
callPrivateDestructor( );
|
||||
p_ = other.p_;
|
||||
piDestructor_ = other.piDestructor_;
|
||||
other.p_ = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline A_PrivateImplementation::~A_PrivateImplementation( )
|
||||
{
|
||||
callPrivateDestructor( );
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
inline T& A_PrivateImplementation::p( ) const
|
||||
{
|
||||
return *reinterpret_cast< T* >( p_ );
|
||||
}
|
||||
|
||||
inline void A_PrivateImplementation::callPrivateDestructor( ) noexcept
|
||||
{
|
||||
if ( p_ && piDestructor_ ) {
|
||||
piDestructor_( p_ );
|
||||
::operator delete( p_ );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
#endif // _H_LW_LIB_INLINE_UTILITIES
|
667
src/Console-Unix.hh
Normal file
667
src/Console-Unix.hh
Normal file
|
@ -0,0 +1,667 @@
|
|||
/******************************************************************************/
|
||||
/* CONSOLE SUPPORT - UNIX IMPLEMENTATION **************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
#include <lw/lib/Console.hh>
|
||||
#include <unistd.h>
|
||||
#include <termios.h>
|
||||
#include <pty.h>
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
// List of unsupported terminals
|
||||
char const* const BadTerminals_[] = {
|
||||
"dumb" , "cons25" , "emacs" ,
|
||||
nullptr
|
||||
};
|
||||
|
||||
// Extended input sequences
|
||||
char const* const InputSequences_[] = {
|
||||
"A" , // Up
|
||||
"B" , // Down
|
||||
"C" , // Right
|
||||
"D" , // Left
|
||||
"H" , // Home
|
||||
"F" , // End
|
||||
"3~" , // Delete
|
||||
"1;5C" , // C-Right
|
||||
"1;5D" , // C-Left
|
||||
"15~" , // F5
|
||||
"17~" , // F6
|
||||
"18~" , // F7
|
||||
"19~" , // F8
|
||||
"20~" , // F9
|
||||
"21~" , // F10
|
||||
"23~" , // F11
|
||||
"24~" , // F12
|
||||
"1;2P" , // S-F1
|
||||
"1;2Q" , // S-F2
|
||||
"1;2R" , // S-F3
|
||||
"1;2S" , // S-F4
|
||||
"15;2~" , // S-F5
|
||||
"17;2~" , // S-F6
|
||||
"18;2~" , // S-F7
|
||||
"19;2~" , // S-F8
|
||||
"20;2~" , // S-F9
|
||||
"21;2~" , // S-F10
|
||||
"23;2~" , // S-F11
|
||||
"24;2~" , // S-F12
|
||||
"1;5P" , // C-F1
|
||||
"1;5Q" , // C-F2
|
||||
"1;5R" , // C-F3
|
||||
"1;5S" , // C-F4
|
||||
"15;5~" , // C-F5
|
||||
"17;5~" , // C-F6
|
||||
"18;5~" , // C-F7
|
||||
"19;5~" , // C-F8
|
||||
"20;5~" , // C-F9
|
||||
"21;5~" , // C-F10
|
||||
"23;5~" , // C-F11
|
||||
"24;5~" , // C-F12
|
||||
"1;6P" , // C-S-F1
|
||||
"1;6Q" , // C-S-F2
|
||||
"1;6R" , // C-S-F3
|
||||
"1;6S" , // C-S-F4
|
||||
"15;6~" , // C-S-F5
|
||||
"17;6~" , // C-S-F6
|
||||
"18;6~" , // C-S-F7
|
||||
"19;6~" , // C-S-F8
|
||||
"20;6~" , // C-S-F9
|
||||
"21;6~" , // C-S-F10
|
||||
"23;6~" , // C-S-F11
|
||||
"24;6~" , // C-S-F12
|
||||
nullptr
|
||||
};
|
||||
const lw::E_ConsoleKey InputKeys_[] = {
|
||||
lw::E_ConsoleKey::UP ,
|
||||
lw::E_ConsoleKey::DOWN ,
|
||||
lw::E_ConsoleKey::RIGHT ,
|
||||
lw::E_ConsoleKey::LEFT ,
|
||||
lw::E_ConsoleKey::HOME ,
|
||||
lw::E_ConsoleKey::END ,
|
||||
lw::E_ConsoleKey::DELETE ,
|
||||
lw::E_ConsoleKey::WNEXT ,
|
||||
lw::E_ConsoleKey::WPREV ,
|
||||
lw::E_ConsoleKey::F5 ,
|
||||
lw::E_ConsoleKey::F6 ,
|
||||
lw::E_ConsoleKey::F7 ,
|
||||
lw::E_ConsoleKey::F8 ,
|
||||
lw::E_ConsoleKey::F9 ,
|
||||
lw::E_ConsoleKey::F10 ,
|
||||
lw::E_ConsoleKey::F11 ,
|
||||
lw::E_ConsoleKey::F12 ,
|
||||
lw::E_ConsoleKey::S_F1 ,
|
||||
lw::E_ConsoleKey::S_F2 ,
|
||||
lw::E_ConsoleKey::S_F3 ,
|
||||
lw::E_ConsoleKey::S_F4 ,
|
||||
lw::E_ConsoleKey::S_F5 ,
|
||||
lw::E_ConsoleKey::S_F6 ,
|
||||
lw::E_ConsoleKey::S_F7 ,
|
||||
lw::E_ConsoleKey::S_F8 ,
|
||||
lw::E_ConsoleKey::S_F9 ,
|
||||
lw::E_ConsoleKey::S_F10 ,
|
||||
lw::E_ConsoleKey::S_F11 ,
|
||||
lw::E_ConsoleKey::S_F12 ,
|
||||
lw::E_ConsoleKey::C_F1 ,
|
||||
lw::E_ConsoleKey::C_F2 ,
|
||||
lw::E_ConsoleKey::C_F3 ,
|
||||
lw::E_ConsoleKey::C_F4 ,
|
||||
lw::E_ConsoleKey::C_F5 ,
|
||||
lw::E_ConsoleKey::C_F6 ,
|
||||
lw::E_ConsoleKey::C_F7 ,
|
||||
lw::E_ConsoleKey::C_F8 ,
|
||||
lw::E_ConsoleKey::C_F9 ,
|
||||
lw::E_ConsoleKey::C_F10 ,
|
||||
lw::E_ConsoleKey::C_F11 ,
|
||||
lw::E_ConsoleKey::C_F12 ,
|
||||
lw::E_ConsoleKey::CS_F1 ,
|
||||
lw::E_ConsoleKey::CS_F2 ,
|
||||
lw::E_ConsoleKey::CS_F3 ,
|
||||
lw::E_ConsoleKey::CS_F4 ,
|
||||
lw::E_ConsoleKey::CS_F5 ,
|
||||
lw::E_ConsoleKey::CS_F6 ,
|
||||
lw::E_ConsoleKey::CS_F7 ,
|
||||
lw::E_ConsoleKey::CS_F8 ,
|
||||
lw::E_ConsoleKey::CS_F9 ,
|
||||
lw::E_ConsoleKey::CS_F10 ,
|
||||
lw::E_ConsoleKey::CS_F11 ,
|
||||
lw::E_ConsoleKey::CS_F12 ,
|
||||
};
|
||||
|
||||
// Various control codes
|
||||
const char CCGetTermSizeStart_[] = "\033[s\033[99999C\033[99999A";
|
||||
const char CCGetTermSizeEnd_[] = "\033[u";
|
||||
const char CCGetCursorPos_[] = "\033[6n";
|
||||
const char CCClearScreen_[] = "\033[H\033[2J";
|
||||
const char CCNextLine_[] = "\n\033[99999D\033[K";
|
||||
const char CCClearLine_[] = "\033[99999D\033[K";
|
||||
const char CCClearLineUp_[] = "\033[99999D\033[K\033[A";
|
||||
|
||||
// Are we running in an unsupported terminal?
|
||||
inline bool IsBadTerminal_( )
|
||||
{
|
||||
char const* const t( getenv( "TERM" ) );
|
||||
if ( t == nullptr ) {
|
||||
return true;
|
||||
}
|
||||
for ( auto i = 0 ; BadTerminals_[ i ] ; i ++ ) {
|
||||
if ( !strcasecmp( t , BadTerminals_[ i ] ) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
class T_ConsoleImpl_
|
||||
{
|
||||
private:
|
||||
bool ok_;
|
||||
termios initialTerm_;
|
||||
lw::E_ConsoleInteractionMode mode_;
|
||||
bool failed_;
|
||||
bool interrupted_;
|
||||
|
||||
int sizePolling_;
|
||||
uint32_t rows_ , cols_;
|
||||
|
||||
lw::T_StringBuilder styleSeq_;
|
||||
uint8_t keyBuf_[ 16 ];
|
||||
uint32_t kbPos_;
|
||||
|
||||
public:
|
||||
T_ConsoleImpl_( );
|
||||
~T_ConsoleImpl_( );
|
||||
|
||||
bool initConsole( );
|
||||
void shutdownConsole( );
|
||||
bool failed( ) const;
|
||||
|
||||
bool resized( uint32_t& rows , uint32_t& cols ) const;
|
||||
bool getTerminalSize( uint32_t& rows , uint32_t& cols );
|
||||
bool getCursorPosition( uint32_t& column , uint32_t& row );
|
||||
|
||||
bool readKey( lw::E_ConsoleKey& key , uint32_t& character );
|
||||
|
||||
bool clearScreen( );
|
||||
void setTextStyle( uint8_t style , lw::T_TextColor color );
|
||||
void printCharacter( lw::T_Character c );
|
||||
void nextLine( );
|
||||
void clearLine( );
|
||||
void clearLines( uint32_t count );
|
||||
void moveCursor( int32_t x , int32_t y );
|
||||
|
||||
private:
|
||||
bool initTTY( );
|
||||
bool checkInput( lw::E_ConsoleKey& key , uint32_t& character );
|
||||
|
||||
bool getTerminalSize( );
|
||||
bool writeSequence( char const* sequence );
|
||||
bool writeSequence( char const* sequence , uint32_t size );
|
||||
};
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
T_ConsoleImpl_::T_ConsoleImpl_( )
|
||||
{
|
||||
// Buffer size:
|
||||
// * "ESC[0m" always => 4
|
||||
// * 2 per enabled style => 6
|
||||
// * color: "38;2;" + 3 unsigned 8-bit numbers + 2 ";" separators => 16
|
||||
// That would be 26, but let's go for 32 instead
|
||||
styleSeq_.ensureCapacity( 32 );
|
||||
}
|
||||
|
||||
T_ConsoleImpl_::~T_ConsoleImpl_( )
|
||||
{
|
||||
shutdownConsole( );
|
||||
}
|
||||
|
||||
bool T_ConsoleImpl_::initConsole( )
|
||||
{
|
||||
failed_ = false;
|
||||
kbPos_ = 0;
|
||||
ok_ = isatty( STDIN_FILENO ) && !IsBadTerminal_( ) && initTTY( );
|
||||
if ( ok_ && getTerminalSize( ) ) {
|
||||
sizePolling_ = 0;
|
||||
}
|
||||
return ok_ && !failed_;
|
||||
}
|
||||
|
||||
void T_ConsoleImpl_::shutdownConsole( )
|
||||
{
|
||||
if ( ok_ ) {
|
||||
setTextStyle( 0 , lw::E_TextColor::WHITE );
|
||||
tcsetattr( STDIN_FILENO , TCSAFLUSH , &initialTerm_ );
|
||||
}
|
||||
}
|
||||
|
||||
inline bool T_ConsoleImpl_::failed( ) const
|
||||
{
|
||||
return failed_;
|
||||
}
|
||||
|
||||
bool T_ConsoleImpl_::resized( uint32_t& rows , uint32_t& cols ) const
|
||||
{
|
||||
if ( cols_ != cols || rows_ != rows ) {
|
||||
cols = cols_;
|
||||
rows = rows_;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool T_ConsoleImpl_::getTerminalSize( uint32_t& rows , uint32_t& cols )
|
||||
{
|
||||
if ( !getTerminalSize( ) ) {
|
||||
return false;
|
||||
}
|
||||
rows = rows_;
|
||||
cols = cols_;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
bool T_ConsoleImpl_::readKey( lw::E_ConsoleKey& key , uint32_t& character )
|
||||
{
|
||||
if ( failed_ ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
do {
|
||||
assert( kbPos_ < sizeof( keyBuf_ ) );
|
||||
const auto n( read( STDIN_FILENO , &keyBuf_[ kbPos_ ] , 1 ) );
|
||||
if ( n != 1 ) {
|
||||
failed_ = failed_ || ( n == -1 );
|
||||
if ( n == 0 && kbPos_ == 0 ) {
|
||||
sizePolling_ = ( sizePolling_ + 1 ) % 20;
|
||||
if ( sizePolling_ == 0 ) {
|
||||
getTerminalSize( );
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
kbPos_ ++;
|
||||
} while ( !checkInput( key , character ) );
|
||||
kbPos_ = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool T_ConsoleImpl_::checkInput( lw::E_ConsoleKey& key , uint32_t& character )
|
||||
{
|
||||
assert( kbPos_ > 0 );
|
||||
|
||||
const uint8_t first( keyBuf_[ 0 ] );
|
||||
if ( kbPos_ == 1 ) {
|
||||
// Escape or UTF-8 input
|
||||
if ( first == 0x1b || first > 0x7f ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch ( first ) {
|
||||
case 0x01: // Ctrl+A
|
||||
key = lw::E_ConsoleKey::HOME;
|
||||
return true;
|
||||
|
||||
case 0x02: // Ctrl+B
|
||||
key = lw::E_ConsoleKey::LEFT;
|
||||
return true;
|
||||
|
||||
case 0x03: // Ctrl+C
|
||||
key = lw::E_ConsoleKey::INTERRUPT;
|
||||
return true;
|
||||
|
||||
case 0x04: // Ctrl+D
|
||||
key = lw::E_ConsoleKey::EXIT;
|
||||
return true;
|
||||
|
||||
case 0x05: // Ctrl+E
|
||||
key = lw::E_ConsoleKey::END;
|
||||
return true;
|
||||
|
||||
case 0x06: // Ctrl+F
|
||||
key = lw::E_ConsoleKey::RIGHT;
|
||||
return true;
|
||||
|
||||
case 0x08: // Ctrl+H
|
||||
case 0x7f:
|
||||
key = lw::E_ConsoleKey::BACKSPACE;
|
||||
return true;
|
||||
|
||||
case 0x09: // Ctrl+I/Tab
|
||||
key = lw::E_ConsoleKey::CHARACTER;
|
||||
character = ' ';
|
||||
return true;
|
||||
|
||||
case 0x0b: // Ctrl+K
|
||||
key = lw::E_ConsoleKey::KILL_REST;
|
||||
return true;
|
||||
|
||||
case 0x0c: // Ctrl+L
|
||||
key = lw::E_ConsoleKey::CLEAR;
|
||||
return true;
|
||||
|
||||
case 0x0d: // Ctrl+M/Enter
|
||||
key = lw::E_ConsoleKey::ENTER;
|
||||
return true;
|
||||
|
||||
case 0x0e: // Ctrl+N
|
||||
key = lw::E_ConsoleKey::DOWN;
|
||||
return true;
|
||||
|
||||
case 0x10: // Ctrl+P
|
||||
key = lw::E_ConsoleKey::UP;
|
||||
return true;
|
||||
|
||||
case 0x15: // Ctrl+U
|
||||
key = lw::E_ConsoleKey::KILL_LINE;
|
||||
return true;
|
||||
|
||||
case 0x17: // Ctrl+W
|
||||
key = lw::E_ConsoleKey::KILL_WORD;
|
||||
return true;
|
||||
|
||||
case 0x19: // Ctrl+Y
|
||||
key = lw::E_ConsoleKey::PASTE;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Skip other control characters
|
||||
if ( first < 32 ) {
|
||||
kbPos_ = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
key = lw::E_ConsoleKey::CHARACTER;
|
||||
character = first;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check for UTF-8 input
|
||||
if ( first != 0x1b ) {
|
||||
uint32_t l( 0 );
|
||||
if ( !lw::UTF8BufferInfo( (char const*) keyBuf_ , kbPos_ , l ) ) {
|
||||
if ( kbPos_ > 4 ) {
|
||||
kbPos_ = 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if ( l != 1 ) {
|
||||
kbPos_ = 0;
|
||||
return false;
|
||||
} else {
|
||||
key = lw::E_ConsoleKey::CHARACTER;
|
||||
character = lw::UTF8GetCodepoint( (char const*) keyBuf_ );
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Escape sequences
|
||||
const uint8_t second( keyBuf_[ 1 ] );
|
||||
if ( kbPos_ == 2 ) {
|
||||
switch ( second ) {
|
||||
case 0x7f:
|
||||
key = lw::E_ConsoleKey::KILL_WORD;
|
||||
return true;
|
||||
|
||||
case 'f':
|
||||
case 'F':
|
||||
key = lw::E_ConsoleKey::WNEXT;
|
||||
return true;
|
||||
|
||||
case 'b':
|
||||
case 'B':
|
||||
key = lw::E_ConsoleKey::WPREV;
|
||||
return true;
|
||||
|
||||
default:
|
||||
kbPos_ = 0;
|
||||
case 'O':
|
||||
case '[':
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// ESC-O-x sequences
|
||||
if ( second == 'O' ) {
|
||||
switch ( keyBuf_[ 2 ] ) {
|
||||
case 'F':
|
||||
key = lw::E_ConsoleKey::END;
|
||||
return true;
|
||||
case 'H':
|
||||
key = lw::E_ConsoleKey::HOME;
|
||||
return true;
|
||||
case 'P':
|
||||
key = lw::E_ConsoleKey::F1;
|
||||
return true;
|
||||
case 'Q':
|
||||
key = lw::E_ConsoleKey::F2;
|
||||
return true;
|
||||
case 'R':
|
||||
key = lw::E_ConsoleKey::F3;
|
||||
return true;
|
||||
case 'S':
|
||||
key = lw::E_ConsoleKey::F4;
|
||||
return true;
|
||||
}
|
||||
kbPos_ = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Extended sequences - ESC-[, ends with ~ or uppercase letter
|
||||
const uint8_t last( keyBuf_[ kbPos_ - 1 ] );
|
||||
if ( last != '~' && ( last < 'A' || last > 'Z' ) ) {
|
||||
if ( kbPos_ == sizeof( keyBuf_ ) - 1 ) {
|
||||
kbPos_ = 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check the list
|
||||
uint32_t idx( 0 );
|
||||
keyBuf_[ kbPos_ ] = 0;
|
||||
while ( InputSequences_[ idx ] != nullptr ) {
|
||||
if ( !strcmp( (char const*) keyBuf_ + 2 , InputSequences_[ idx ] ) ) {
|
||||
key = InputKeys_[ idx ];
|
||||
return true;
|
||||
}
|
||||
idx ++;
|
||||
}
|
||||
kbPos_ = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
bool T_ConsoleImpl_::clearScreen( )
|
||||
{
|
||||
return writeSequence( CCClearScreen_ , sizeof( CCClearScreen_ ) - 1 );
|
||||
}
|
||||
|
||||
void T_ConsoleImpl_::setTextStyle( uint8_t style , lw::T_TextColor color )
|
||||
{
|
||||
styleSeq_.clear( );
|
||||
styleSeq_ << "\033[0";
|
||||
if ( ( style & uint8_t( lw::E_TextStyle::BOLD ) ) != 0 ) {
|
||||
styleSeq_ << ";1";
|
||||
}
|
||||
if ( ( style & uint8_t( lw::E_TextStyle::ITALIC ) ) != 0 ) {
|
||||
styleSeq_ << ";3";
|
||||
}
|
||||
if ( ( style & uint8_t( lw::E_TextStyle::UNDERLINE ) ) != 0 ) {
|
||||
styleSeq_ << ";4";
|
||||
}
|
||||
if ( color.type == lw::E_TextColor::CUSTOM ) {
|
||||
styleSeq_ << ";38;2;" << color.r
|
||||
<< ';' << color.g
|
||||
<< ';' << color.b;
|
||||
} else {
|
||||
styleSeq_ << ';' << ( 30 + uint8_t( color.type ) );
|
||||
}
|
||||
styleSeq_ << 'm';
|
||||
writeSequence( styleSeq_.data( ) , styleSeq_.size( ) );
|
||||
}
|
||||
|
||||
void T_ConsoleImpl_::printCharacter( lw::T_Character c )
|
||||
{
|
||||
char buf[ 8 ];
|
||||
uint32_t l( UTF8PutCodepoint( buf , 7 , c ) );
|
||||
if ( l == 0 ) {
|
||||
return;
|
||||
}
|
||||
writeSequence( buf , l );
|
||||
}
|
||||
|
||||
void T_ConsoleImpl_::nextLine( )
|
||||
{
|
||||
writeSequence( CCNextLine_ , sizeof( CCNextLine_ ) - 1 );
|
||||
}
|
||||
|
||||
void T_ConsoleImpl_::clearLine( )
|
||||
{
|
||||
writeSequence( CCClearLine_ , sizeof( CCClearLine_ ) - 1 );
|
||||
}
|
||||
|
||||
void T_ConsoleImpl_::clearLines( uint32_t count )
|
||||
{
|
||||
assert( count > 0 );
|
||||
while ( --count ) {
|
||||
writeSequence( CCClearLineUp_ , sizeof( CCClearLineUp_ ) - 1 );
|
||||
}
|
||||
clearLine( );
|
||||
}
|
||||
|
||||
void T_ConsoleImpl_::moveCursor( int32_t x , int32_t y )
|
||||
{
|
||||
styleSeq_.clear( );
|
||||
if ( x ) {
|
||||
styleSeq_ << "\033["
|
||||
<< ( x > 0 ? x : -x )
|
||||
<< ( x > 0 ? 'C' : 'D' );
|
||||
}
|
||||
if ( y ) {
|
||||
styleSeq_ << "\033["
|
||||
<< ( y > 0 ? y : -y )
|
||||
<< ( y > 0 ? 'B' : 'A' );
|
||||
}
|
||||
if ( styleSeq_.size( ) ) {
|
||||
writeSequence( styleSeq_.data( ) , styleSeq_.size( ) );
|
||||
}
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
bool T_ConsoleImpl_::initTTY( )
|
||||
{
|
||||
if ( tcgetattr( STDIN_FILENO , &initialTerm_ ) == -1 ) {
|
||||
failed_ = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
termios rawTerm( initialTerm_ );
|
||||
rawTerm.c_iflag &= ~( BRKINT | ICRNL | INPCK | ISTRIP | IXON );
|
||||
rawTerm.c_oflag &= ~OPOST;
|
||||
rawTerm.c_cflag |= CS8;
|
||||
rawTerm.c_lflag &= ~( ECHO | ICANON | IEXTEN | ISIG );
|
||||
rawTerm.c_cc[ VMIN ] = 0;
|
||||
rawTerm.c_cc[ VTIME ] = 0;
|
||||
|
||||
if ( tcsetattr( STDIN_FILENO , TCSAFLUSH , &rawTerm ) >= 0 ) {
|
||||
return getTerminalSize( );
|
||||
} else {
|
||||
failed_ = true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
bool T_ConsoleImpl_::getTerminalSize( )
|
||||
{
|
||||
// Try obtaining the size using ioctl
|
||||
winsize ws;
|
||||
if ( ioctl( STDIN_FILENO , TIOCGWINSZ , &ws ) != -1 && ws.ws_col != 0 ) {
|
||||
rows_ = ws.ws_row;
|
||||
cols_ = ws.ws_col;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Otherwise, we need to move the cursor to the bottom/right corner, then
|
||||
// get its position.
|
||||
return writeSequence( CCGetTermSizeStart_ , sizeof( CCGetTermSizeStart_ ) - 1 )
|
||||
&& getCursorPosition( cols_ , rows_ )
|
||||
&& writeSequence( CCGetTermSizeEnd_ , sizeof( CCGetTermSizeEnd_ ) - 1 );
|
||||
}
|
||||
|
||||
bool T_ConsoleImpl_::getCursorPosition( uint32_t& column , uint32_t& row )
|
||||
{
|
||||
if ( failed_ || tcflush( STDIN_FILENO , TCIFLUSH ) != 0 ) {
|
||||
failed_ = true;
|
||||
return false;
|
||||
}
|
||||
if ( !writeSequence( CCGetCursorPos_ , sizeof( CCGetCursorPos_ ) - 1 ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
char buf[ 32 ];
|
||||
size_t i( 0 );
|
||||
while ( i < sizeof( buf ) ) {
|
||||
if ( read( STDIN_FILENO , buf + i , 1 ) != 1 ) {
|
||||
i = sizeof( buf );
|
||||
break;
|
||||
}
|
||||
if ( buf[ i ] == 'R' ) {
|
||||
break;
|
||||
}
|
||||
i ++;
|
||||
}
|
||||
|
||||
if ( i == sizeof( buf ) || i < 6 || buf[ 0 ] != 27 || buf[ 1 ] != '[' ) {
|
||||
failed_ = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
buf[ i ] = 0;
|
||||
if ( sscanf( buf + 2 , "%d;%d" , &row , &column ) != 2 ) {
|
||||
failed_ = true;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#if 0
|
||||
bool T_ConsoleImpl_::writeSequence( char const* sequence )
|
||||
{
|
||||
if ( failed_ ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const int n( strlen( sequence ) );
|
||||
if ( write( STDOUT_FILENO , sequence , n ) != n ) {
|
||||
failed_ = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool T_ConsoleImpl_::writeSequence( char const* sequence , uint32_t size )
|
||||
{
|
||||
if ( failed_ ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( write( STDOUT_FILENO , sequence , size ) != size ) {
|
||||
failed_ = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
}
|
1346
src/Console.cc
Normal file
1346
src/Console.cc
Normal file
File diff suppressed because it is too large
Load diff
83
src/ConsoleLogWriter.cc
Normal file
83
src/ConsoleLogWriter.cc
Normal file
|
@ -0,0 +1,83 @@
|
|||
#include <lw/lib/BuiltinLoggers.hh>
|
||||
using namespace lw;
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
char const* const V_Name_ = "console";
|
||||
inline T_String Name_( ) { return T_String::Pooled( V_Name_ ); }
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*= T_ConsoleLogWriterFactory ================================================*/
|
||||
|
||||
T_ConsoleLogWriterFactory::T_ConsoleLogWriterFactory( T_Console& console )
|
||||
: A_LogWriterFactory( Name_( ) ) , console_( console )
|
||||
{ }
|
||||
|
||||
RP_LogWriterConfiguration T_ConsoleLogWriterFactory::createConfiguration( T_String const& name ) const
|
||||
{
|
||||
RP_LogWriterConfiguration p( new T_LogWriterConfiguration( Name_( ) ) );
|
||||
p->setName( name );
|
||||
return p;
|
||||
}
|
||||
|
||||
OP_LogWriter T_ConsoleLogWriterFactory::createLogWriter( OP_LogWriterConfiguration&& configuration ) const
|
||||
{
|
||||
T_ConsoleLogWriter* p( new T_ConsoleLogWriter( std::move( configuration ) , console_ ) );
|
||||
return OwnRawPointer( p );
|
||||
}
|
||||
|
||||
|
||||
/*= T_ConsoleLogWriter =======================================================*/
|
||||
|
||||
T_ConsoleLogWriter::T_ConsoleLogWriter( OP_LogWriterConfiguration&& configuration , T_Console& console )
|
||||
: A_LogWriter( std::move( configuration ) ) , console_( console )
|
||||
{ }
|
||||
|
||||
void T_ConsoleLogWriter::log( T_LogTimestamp const& timestamp ,
|
||||
E_LogLevel level , T_LogPath const& path ,
|
||||
T_LogStringData const& data , uint32_t size )
|
||||
{
|
||||
using namespace std::chrono;
|
||||
|
||||
char timeBuffer[ 128 ];
|
||||
std::time_t tst( T_LogTimestamp::clock::to_time_t( timestamp ) );
|
||||
std::strftime( timeBuffer , 128 , "%Y-%m-%d %H:%M:%S" , std::gmtime( &tst ) );
|
||||
const auto ms( ( duration_cast< milliseconds >( timestamp - T_LogTimestamp( ) ) ).count( ) % 1000 );
|
||||
|
||||
T_TextBuilder sb;
|
||||
|
||||
sb << timeBuffer << '.';
|
||||
if ( ms < 100 ) {
|
||||
sb << '0';
|
||||
if ( ms < 10 ) {
|
||||
sb << '0';
|
||||
}
|
||||
}
|
||||
sb << ms << ' ' << path.toString( ) << " - "
|
||||
<< E_TextStyle::UNDERLINE;
|
||||
switch ( level ) {
|
||||
case E_LogLevel::TRACE:
|
||||
case E_LogLevel::DEBUG:
|
||||
case E_LogLevel::INFO:
|
||||
sb << E_TextColor::CYAN;
|
||||
break;
|
||||
case E_LogLevel::NOTICE:
|
||||
break;
|
||||
case E_LogLevel::WARNING:
|
||||
sb << E_TextColor::YELLOW;
|
||||
break;
|
||||
case E_LogLevel::CRITICAL:
|
||||
sb << E_TextStyle::BOLD;
|
||||
case E_LogLevel::ERROR:
|
||||
sb << E_TextColor::RED;
|
||||
break;
|
||||
}
|
||||
sb << level;
|
||||
sb.reset( );
|
||||
sb << " - " << T_String( &( (*data) [ 0 ] ) , size );
|
||||
|
||||
console_.putLine( std::move( sb ) );
|
||||
}
|
153
src/CwdFileLogger.cc
Normal file
153
src/CwdFileLogger.cc
Normal file
|
@ -0,0 +1,153 @@
|
|||
/******************************************************************************/
|
||||
/* LOGGING SYSTEM - BUILT-IN LOGGERS - NON-VFS FILE LOG WRITER ****************/
|
||||
/******************************************************************************/
|
||||
|
||||
#include <lw/lib/BuiltinLoggers.hh>
|
||||
#include <lw/lib/SRDParser.hh>
|
||||
using namespace lw;
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
|
||||
char const* const V_Name_ = "preinit-file";
|
||||
inline T_String Name_( ) { return T_String::Pooled( V_Name_ ); }
|
||||
|
||||
bool CFLCPath_( T_SRDParserData const& data )
|
||||
{
|
||||
auto const& ptok( (*data.input)[ 1 ] );
|
||||
auto lconf( data.targetData->value< RP_LogWriterConfiguration >( ) );
|
||||
( dynamic_cast< T_CWDFileLogWriterCfg* >( lconf ) )->setPath( ptok.stringValue( ) );
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CFLCAppend_( T_SRDParserData const& data )
|
||||
{
|
||||
auto lconf( data.targetData->value< RP_LogWriterConfiguration >( ) );
|
||||
( dynamic_cast< T_CWDFileLogWriterCfg* >( lconf ) )->setAppend( true );
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CFLCTruncate_( T_SRDParserData const& data )
|
||||
{
|
||||
auto lconf( data.targetData->value< RP_LogWriterConfiguration >( ) );
|
||||
( dynamic_cast< T_CWDFileLogWriterCfg* >( lconf ) )->setAppend( false );
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*= T_CWDFileLogWriterFactory ==================================================*/
|
||||
|
||||
T_CWDFileLogWriterFactory::T_CWDFileLogWriterFactory( )
|
||||
: A_LogWriterFactory( Name_( ) )
|
||||
{ }
|
||||
|
||||
RP_LogWriterConfiguration T_CWDFileLogWriterFactory::createConfiguration( T_String const& name ) const
|
||||
{
|
||||
RP_LogWriterConfiguration p( new T_CWDFileLogWriterCfg( ) );
|
||||
p->setName( name );
|
||||
return p;
|
||||
}
|
||||
|
||||
OP_LogWriter T_CWDFileLogWriterFactory::createLogWriter( OP_LogWriterConfiguration&& configuration ) const
|
||||
{
|
||||
T_CWDFileLogWriter* p( new T_CWDFileLogWriter( std::move( configuration ) ) );
|
||||
return OwnRawPointer( p );
|
||||
}
|
||||
|
||||
void T_CWDFileLogWriterFactory::initializeSyntax( T_SRDParserDefs& , T_SRDContext& main ) const
|
||||
{
|
||||
using namespace lw::SRD;
|
||||
main << ( Rule( ) << "file" << Text( ) << CFLCPath_ );
|
||||
main << ( Rule( ) << "append" << CFLCAppend_ );
|
||||
main << ( Rule( ) << "truncate" << CFLCTruncate_ );
|
||||
}
|
||||
|
||||
|
||||
/*= T_CWDFileLogWriterCfg ======================================================*/
|
||||
|
||||
T_CWDFileLogWriterCfg::T_CWDFileLogWriterCfg( )
|
||||
: T_LogWriterConfiguration( Name_( ) )
|
||||
{ }
|
||||
|
||||
T_CWDFileLogWriterCfg::T_CWDFileLogWriterCfg( T_CWDFileLogWriterCfg const& source )
|
||||
: T_LogWriterConfiguration( source ) , path_( source.path_ ) ,
|
||||
append_( source.append_ )
|
||||
{ }
|
||||
|
||||
OP_LogWriterConfiguration T_CWDFileLogWriterCfg::clone( )
|
||||
{
|
||||
T_CWDFileLogWriterCfg* ptr( new T_CWDFileLogWriterCfg( *this ) );
|
||||
return OwnRawPointer( ptr );
|
||||
}
|
||||
|
||||
void T_CWDFileLogWriterCfg::check( T_SRDErrors& errors , T_SRDList const& input )
|
||||
{
|
||||
T_LogWriterConfiguration::check( errors , input );
|
||||
if ( !path_ ) {
|
||||
errors.add( "no file selected" , input[ 0 ] );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*= T_CWDFileLogWriter =========================================================*/
|
||||
|
||||
T_CWDFileLogWriter::T_CWDFileLogWriter( OP_LogWriterConfiguration&& configuration )
|
||||
: A_LogWriter( std::move( configuration ) )
|
||||
{ }
|
||||
|
||||
void T_CWDFileLogWriter::log( T_LogTimestamp const& timestamp ,
|
||||
E_LogLevel level , T_LogPath const& path ,
|
||||
T_LogStringData const& data , uint32_t size )
|
||||
{
|
||||
using namespace std::chrono;
|
||||
|
||||
char timeBuffer[ 128 ];
|
||||
std::time_t tst( T_LogTimestamp::clock::to_time_t( timestamp ) );
|
||||
std::strftime( timeBuffer , 128 , "%Y-%m-%d %H:%M:%S" , std::gmtime( &tst ) );
|
||||
const auto ms( ( duration_cast< milliseconds >( timestamp - T_LogTimestamp( ) ) ).count( ) % 1000 );
|
||||
|
||||
T_StringBuilder sb;
|
||||
|
||||
sb << timeBuffer << '.';
|
||||
if ( ms < 100 ) {
|
||||
sb << '0';
|
||||
if ( ms < 10 ) {
|
||||
sb << '0';
|
||||
}
|
||||
}
|
||||
sb << ms << ' ' << path.toString( ) << " - " << level << ": ";
|
||||
sb.append( &( (*data) [ 0 ] ) , size );
|
||||
sb << '\n';
|
||||
|
||||
auto const& cfg( configuration< T_CWDFileLogWriterCfg >( ) );
|
||||
auto const& p( cfg.path( ) );
|
||||
if ( !file_ ) {
|
||||
file_ = NewOwned< T_File >( p , cfg.append( ) ? E_FileMode::READ_WRITE : E_FileMode::OVERWRITE );
|
||||
if ( !file_ ) {
|
||||
disable( );
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
file_->open( );
|
||||
} catch ( X_StreamError const& ) {
|
||||
disable( );
|
||||
file_.clear( );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
file_->position( 0 , true );
|
||||
file_->write( sb.data( ) , sb.size( ) );
|
||||
file_->flush( );
|
||||
} catch ( X_StreamError ) {
|
||||
disable( );
|
||||
file_.clear( );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
135
src/DynLib.cc
Normal file
135
src/DynLib.cc
Normal file
|
@ -0,0 +1,135 @@
|
|||
/******************************************************************************/
|
||||
/* DYNAMIC LIBRARIES **********************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
#include <lw/lib/DynLib.hh>
|
||||
#include <lw/lib/Threading.hh>
|
||||
using namespace lw;
|
||||
|
||||
#ifdef _WIN32
|
||||
# error "Not implemented"
|
||||
#endif
|
||||
|
||||
|
||||
/*= T_DynLibLinux_ ===========================================================*/
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <atomic>
|
||||
|
||||
namespace {
|
||||
struct T_DynLibLinux_
|
||||
{
|
||||
T_Buffer< char > path;
|
||||
T_String error;
|
||||
void* lib;
|
||||
|
||||
explicit T_DynLibLinux_( T_String const& path ) noexcept;
|
||||
explicit T_DynLibLinux_( char const* const path ) noexcept;
|
||||
~T_DynLibLinux_( ) noexcept;
|
||||
|
||||
bool load( ) noexcept;
|
||||
void unload( ) noexcept;
|
||||
|
||||
bool isLoaded( ) const noexcept;
|
||||
|
||||
void* getSymbol( char const* const symbol ) noexcept;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
inline T_DynLibLinux_::T_DynLibLinux_(
|
||||
T_String const& path ) noexcept
|
||||
: path( path.toOSString( ) ) , lib( nullptr )
|
||||
{ }
|
||||
|
||||
inline T_DynLibLinux_::T_DynLibLinux_(
|
||||
char const* const path ) noexcept
|
||||
: path( path , strlen( path ) ) , lib( nullptr )
|
||||
{ }
|
||||
|
||||
inline T_DynLibLinux_::~T_DynLibLinux_( ) noexcept
|
||||
{
|
||||
unload( );
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
inline bool T_DynLibLinux_::load( ) noexcept
|
||||
{
|
||||
if ( lib != nullptr ) {
|
||||
return true;
|
||||
}
|
||||
lib = dlopen( &path[ 0 ] , RTLD_LOCAL | RTLD_NOW );
|
||||
error = lib ? T_String{} : T_String{ dlerror( ) };
|
||||
return lib != nullptr;
|
||||
}
|
||||
|
||||
inline void T_DynLibLinux_::unload( ) noexcept
|
||||
{
|
||||
if ( lib != nullptr ) {
|
||||
dlclose( lib );
|
||||
lib = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool T_DynLibLinux_::isLoaded( ) const noexcept
|
||||
{
|
||||
return lib != nullptr;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
inline void* T_DynLibLinux_::getSymbol(
|
||||
char const* const symbol ) noexcept
|
||||
{
|
||||
assert( lib != nullptr );
|
||||
void* const ptr( dlsym( lib , symbol ) );
|
||||
error = ( ptr == nullptr ) ? T_String{ dlerror( ) } : T_String{};
|
||||
return ptr;
|
||||
}
|
||||
|
||||
|
||||
/*= T_DynLib =================================================================*/
|
||||
|
||||
using T_DynLibImpl_ = T_DynLibLinux_; // FIXME
|
||||
|
||||
T_DynLib::T_DynLib(
|
||||
T_String const& name )
|
||||
: A_PrivateImplementation( new T_DynLibImpl_( name ) )
|
||||
{ }
|
||||
|
||||
T_DynLib::T_DynLib(
|
||||
char const* const name )
|
||||
: A_PrivateImplementation( new T_DynLibImpl_( name ) )
|
||||
{ }
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
bool T_DynLib::load( )
|
||||
{
|
||||
return p< T_DynLibImpl_ >( ).load( );
|
||||
}
|
||||
|
||||
void T_DynLib::unload( )
|
||||
{
|
||||
p< T_DynLibImpl_ >( ).unload( );
|
||||
}
|
||||
|
||||
bool T_DynLib::isLoaded( ) const noexcept
|
||||
{
|
||||
return p< T_DynLibImpl_ >( ).isLoaded( );
|
||||
}
|
||||
|
||||
T_String T_DynLib::lastError( ) const noexcept
|
||||
{
|
||||
return p< T_DynLibImpl_ >( ).error;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
void* T_DynLib::getRawSymbol(
|
||||
char const* const name ) const noexcept
|
||||
{
|
||||
return p< T_DynLibImpl_ >( ).getSymbol( name );
|
||||
}
|
326
src/Files.cc
Normal file
326
src/Files.cc
Normal file
|
@ -0,0 +1,326 @@
|
|||
/******************************************************************************/
|
||||
/* FILES **********************************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
|
||||
#include <lw/lib/Files.hh>
|
||||
using namespace lw;
|
||||
|
||||
|
||||
/*= T_File ==================================================================*/
|
||||
|
||||
T_File::T_File( )
|
||||
: path_( ) , file_( nullptr )
|
||||
{ }
|
||||
|
||||
T_File::T_File( T_String const& path , E_FileMode mode )
|
||||
: path_( path ) , mode_( mode ) , file_( nullptr )
|
||||
{ }
|
||||
|
||||
T_File::T_File( T_File&& other ) noexcept
|
||||
: T_File( )
|
||||
{
|
||||
swap( *this , other );
|
||||
}
|
||||
|
||||
T_File& T_File::operator= ( T_File&& other ) noexcept
|
||||
{
|
||||
swap( *this , other );
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
void T_File::open( )
|
||||
{
|
||||
if ( file_ != nullptr ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Copy file path to C string
|
||||
const T_Buffer< char > path( path_.toOSString( ) );
|
||||
|
||||
// Select the right mode
|
||||
char const* mode;
|
||||
switch ( mode_ ) {
|
||||
case E_FileMode::READ_ONLY:
|
||||
mode = "rb";
|
||||
break;
|
||||
|
||||
case E_FileMode::READ_WRITE:
|
||||
mode = "rb+";
|
||||
break;
|
||||
|
||||
case E_FileMode::OVERWRITE:
|
||||
mode = "wb+";
|
||||
break;
|
||||
}
|
||||
|
||||
// Open the file
|
||||
#ifdef WIN32_
|
||||
file_ = _wfopen( ( wchar_t const* ) &path[ 0 ] , mode );
|
||||
#else
|
||||
file_ = fopen( &path[ 0 ] , mode );
|
||||
#endif
|
||||
if ( file_ == nullptr ) {
|
||||
throw X_StreamError( errno );
|
||||
}
|
||||
|
||||
// Get initial size
|
||||
if ( fseek( file_ , 0 , SEEK_END ) != 0 ) {
|
||||
auto err( errno );
|
||||
close( );
|
||||
throw X_StreamError( err );
|
||||
}
|
||||
off_t sz( ftell( file_ ) );
|
||||
if ( sz < 0 || fseek( file_ , 0 , SEEK_SET ) != 0 ) {
|
||||
auto err( errno );
|
||||
close( );
|
||||
throw X_StreamError( err );
|
||||
}
|
||||
pos_ = 0;
|
||||
size_ = sz;
|
||||
}
|
||||
|
||||
void T_File::close( ) noexcept
|
||||
{
|
||||
if ( file_ != nullptr ) {
|
||||
fclose( file_ );
|
||||
file_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
void T_File::position( size_t position , bool fromEnd )
|
||||
{
|
||||
open( );
|
||||
const auto rv( fromEnd
|
||||
? fseek( file_ , -position , SEEK_END )
|
||||
: fseek( file_ , +position , SEEK_SET ) );
|
||||
if ( rv < 0 ) {
|
||||
throw X_StreamError( errno );
|
||||
}
|
||||
pos_ = rv;
|
||||
}
|
||||
|
||||
void T_File::move( ssize_t offset )
|
||||
{
|
||||
open( );
|
||||
const auto rv( fseek( file_ , offset , SEEK_CUR ) );
|
||||
if ( rv < 0 ) {
|
||||
throw X_StreamError( errno );
|
||||
}
|
||||
pos_ = rv;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
size_t T_File::read( void* data , size_t size )
|
||||
{
|
||||
open( );
|
||||
if ( pos_ >= size_ ) {
|
||||
throw X_StreamError( E_StreamError::END );
|
||||
}
|
||||
|
||||
const auto rv( fread( data , 1 , size , file_ ) );
|
||||
if ( ferror( file_ ) ) {
|
||||
throw X_StreamError( errno );
|
||||
} else {
|
||||
pos_ += rv;
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
size_t T_File::write( void const* data , size_t size )
|
||||
{
|
||||
if ( mode_ == E_FileMode::READ_ONLY ) {
|
||||
throw X_StreamError( E_StreamError::NOT_SUPPORTED );
|
||||
}
|
||||
|
||||
open( );
|
||||
auto rv( fwrite( data , 1 , size , file_ ) );
|
||||
if ( ferror( file_ ) ) {
|
||||
throw X_StreamError( errno );
|
||||
} else {
|
||||
pos_ += rv;
|
||||
if ( pos_ > size_ ) {
|
||||
size_ = pos_;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
void T_File::flush( )
|
||||
{
|
||||
if ( !isOpen( ) || mode_ == E_FileMode::READ_ONLY ) {
|
||||
return;
|
||||
}
|
||||
fflush( file_ );
|
||||
}
|
||||
|
||||
|
||||
/*= T_FileInputStream =======================================================*/
|
||||
|
||||
|
||||
T_FileInputStream::T_FileInputStream( T_File& file , ssize_t offset , size_t limit )
|
||||
: A_InputStream( 0 , 0 ) , fileRaw_( &file ) , fileOwned_( )
|
||||
{
|
||||
init( offset , limit );
|
||||
}
|
||||
|
||||
T_FileInputStream::T_FileInputStream( OP_File&& file , ssize_t offset , size_t limit )
|
||||
: A_InputStream( 0 , 0 ) , fileRaw_( nullptr ) , fileOwned_( std::move( file ) )
|
||||
{
|
||||
file.clear( );
|
||||
init( offset , limit );
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
T_FileInputStream::T_FileInputStream( T_FileInputStream const& other )
|
||||
: A_InputStream( other.position( ) , other.size( ) ) ,
|
||||
fileRaw_( &( other.file( ) ) ) , fileOwned_( ) ,
|
||||
start_( other.start_ )
|
||||
{ }
|
||||
|
||||
T_FileInputStream& T_FileInputStream::operator= ( T_FileInputStream const& other )
|
||||
{
|
||||
position_ = other.position_;
|
||||
size_ = other.size_;
|
||||
fileRaw_ = &( other.file( ) );
|
||||
fileOwned_ = OP_File( );
|
||||
start_ = other.start_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
void T_FileInputStream::swap( T_FileInputStream& rhs ) noexcept
|
||||
{
|
||||
using std::swap;
|
||||
swap( size_ , rhs.size_ );
|
||||
swap( position_ , rhs.position_ );
|
||||
swap( fileRaw_ , rhs.fileRaw_ );
|
||||
swap( fileOwned_ , rhs.fileOwned_ );
|
||||
swap( start_ , rhs.start_ );
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
size_t T_FileInputStream::read( void* data , size_t size )
|
||||
{
|
||||
if ( position_ >= size_ ) {
|
||||
throw X_StreamError( E_StreamError::END );
|
||||
}
|
||||
|
||||
auto& f( file( ) );
|
||||
f.open( );
|
||||
if ( f.position( ) != start_ + position_ ) {
|
||||
f.position( start_ + position_ );
|
||||
}
|
||||
|
||||
const size_t rSize( std::min( size , size_ - position_ ) );
|
||||
const auto r( f.read( data , rSize ) );
|
||||
position_ += r;
|
||||
return r;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
void T_FileInputStream::init( ssize_t offset , size_t limit )
|
||||
{
|
||||
auto& f( file( ) );
|
||||
f.open( );
|
||||
const ssize_t start( f.position( ) + offset );
|
||||
if ( start < 0 || start > ssize_t( f.size( ) ) ) {
|
||||
throw X_StreamError( E_StreamError::INVALID_POSITION );
|
||||
}
|
||||
start_ = start;
|
||||
size_ = std::min( f.size( ) - start , limit );
|
||||
}
|
||||
|
||||
|
||||
/*= T_FileOutputStream =======================================================*/
|
||||
|
||||
|
||||
T_FileOutputStream::T_FileOutputStream( T_File& file , ssize_t offset )
|
||||
: A_OutputStream( 0 ) , fileRaw_( &file ) , fileOwned_( )
|
||||
{
|
||||
init( offset );
|
||||
}
|
||||
|
||||
T_FileOutputStream::T_FileOutputStream( OP_File&& file , ssize_t offset )
|
||||
: A_OutputStream( 0 ) , fileRaw_( nullptr ) , fileOwned_( std::move( file ) )
|
||||
{
|
||||
init( offset );
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
T_FileOutputStream::T_FileOutputStream( T_FileOutputStream const& other )
|
||||
: A_OutputStream( other.position( ) ) , fileRaw_( &other.file( ) ) ,
|
||||
fileOwned_( ) , start_( other.start_ )
|
||||
{ }
|
||||
|
||||
T_FileOutputStream& T_FileOutputStream::operator= ( T_FileOutputStream const& other )
|
||||
{
|
||||
position_ = other.position_;
|
||||
fileRaw_ = &other.file( );
|
||||
fileOwned_ = OP_File( );
|
||||
start_ = other.start_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
inline void T_FileOutputStream::swap( T_FileOutputStream& rhs ) noexcept
|
||||
{
|
||||
using std::swap;
|
||||
swap( position_ , rhs.position_ );
|
||||
swap( fileRaw_ , rhs.fileRaw_ );
|
||||
swap( fileOwned_ , rhs.fileOwned_ );
|
||||
swap( start_ , rhs.start_ );
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
size_t T_FileOutputStream::write( void const* data , size_t size )
|
||||
{
|
||||
auto& f( file( ) );
|
||||
f.open( );
|
||||
if ( f.position( ) != start_ + position_ ) {
|
||||
f.position( start_ + position_ );
|
||||
}
|
||||
|
||||
const auto w( f.write( data , size ) );
|
||||
position_ += w;
|
||||
return w;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
void T_FileOutputStream::flush( )
|
||||
{
|
||||
file( ).flush( );
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
void T_FileOutputStream::init( ssize_t offset )
|
||||
{
|
||||
auto& f( file( ) );
|
||||
if ( f.mode( ) == E_FileMode::READ_ONLY ) {
|
||||
throw X_StreamError( E_StreamError::NOT_SUPPORTED );
|
||||
}
|
||||
const ssize_t start( f.position( ) + offset );
|
||||
if ( start < 0 || start > ssize_t( f.size( ) ) ) {
|
||||
throw X_StreamError( E_StreamError::INVALID_POSITION );
|
||||
}
|
||||
start_ = start;
|
||||
}
|
140
src/GameLoop.cc
Normal file
140
src/GameLoop.cc
Normal file
|
@ -0,0 +1,140 @@
|
|||
/******************************************************************************/
|
||||
/* GAME'S MAIN LOOP ***********************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
#include <lw/lib/GameLoop.hh>
|
||||
#include <lw/lib/Threading.hh>
|
||||
#include <lw/lib/Log.hh>
|
||||
#include <lw/lib/LW.hh>
|
||||
using namespace lw;
|
||||
|
||||
|
||||
/*= T_GameLoopPrivate_ =======================================================*/
|
||||
|
||||
namespace {
|
||||
struct T_GameLoopPrivate_
|
||||
{
|
||||
T_Logger logger{ "/core/loop" };
|
||||
|
||||
OP_Thread thread;
|
||||
bool active = false;
|
||||
bool forceShutdown = false;
|
||||
|
||||
T_Mutex mutex;
|
||||
T_Condition cond;
|
||||
T_RingBuffer< T_UIMessage > messages{ 64 };
|
||||
|
||||
/* Game loop */
|
||||
void run( ) noexcept;
|
||||
|
||||
/* Wait for the next message, no timeout */
|
||||
bool nextMessage(
|
||||
T_UIMessage& message ) noexcept;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
inline void T_GameLoopPrivate_::run( ) noexcept
|
||||
{
|
||||
const bool trace( logger.hasLevel( E_LogLevel::TRACE ) );
|
||||
logger.debug( ) << "Game loop thread starting";
|
||||
|
||||
while ( !forceShutdown ) {
|
||||
T_UIMessage message;
|
||||
if ( !nextMessage( message ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto mt( message.type( ) );
|
||||
if ( trace ) {
|
||||
logger.trace( ) << "Got message " << mt;
|
||||
}
|
||||
|
||||
switch ( mt ) {
|
||||
|
||||
case lw::E_GameUIMessage::QUIT:
|
||||
// FIXME quit properly
|
||||
LW::ui( ).putMessage( E_GameLoopMessage::TERMINATED );
|
||||
forceShutdown = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
logger.debug( ) << "Unhandled message " << mt;
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
active = false;
|
||||
logger.debug( ) << "Game loop thread exiting";
|
||||
}
|
||||
|
||||
inline bool T_GameLoopPrivate_::nextMessage(
|
||||
T_UIMessage& message ) noexcept
|
||||
{
|
||||
T_ExclusiveLock lock( mutex );
|
||||
cond.wait( lock , [this]() {
|
||||
return messages.size( ) != 0 || forceShutdown;
|
||||
} );
|
||||
return messages.readNext( message )
|
||||
&& message.hasMessage( );
|
||||
}
|
||||
|
||||
|
||||
/*= T_GameLoop ===============================================================*/
|
||||
|
||||
#define M_PRIVATE_ \
|
||||
auto& pi( p< T_GameLoopPrivate_ >( ) );
|
||||
|
||||
T_GameLoop::T_GameLoop( ) noexcept
|
||||
: A_PrivateImplementation( new T_GameLoopPrivate_( ) )
|
||||
{ }
|
||||
|
||||
bool T_GameLoop::active( ) const noexcept
|
||||
{
|
||||
M_PRIVATE_;
|
||||
return bool( pi.thread ) && !pi.active;
|
||||
}
|
||||
|
||||
void T_GameLoop::start( ) noexcept
|
||||
{
|
||||
M_PRIVATE_;
|
||||
pi.logger.trace( ) << "Starting main loop thread";
|
||||
if ( pi.thread ) {
|
||||
pi.logger.warning( )
|
||||
<< "The main loop thread is already active?!";
|
||||
}
|
||||
pi.active = true;
|
||||
pi.thread = NewOwned< T_Thread >( [&]{
|
||||
pi.run( );
|
||||
} );
|
||||
}
|
||||
|
||||
void T_GameLoop::shutdown( ) noexcept
|
||||
{
|
||||
M_PRIVATE_;
|
||||
if ( !pi.thread ) {
|
||||
pi.logger.trace( )
|
||||
<< "The main loop thread is not present";
|
||||
return;
|
||||
}
|
||||
|
||||
if ( pi.active ) {
|
||||
pi.logger.notice( ) << "Main loop is still active at shutdown!";
|
||||
pi.forceShutdown = true;
|
||||
|
||||
T_ExclusiveLock lock( pi.mutex );
|
||||
pi.cond.notify_one( );
|
||||
}
|
||||
pi.thread->join( );
|
||||
pi.thread.clear( );
|
||||
}
|
||||
|
||||
void T_GameLoop::putMessage( T_UIMessage&& message ) noexcept
|
||||
{
|
||||
M_PRIVATE_;
|
||||
T_ExclusiveLock lock( pi.mutex );
|
||||
pi.messages.put( std::move( message ) );
|
||||
pi.cond.notify_one( );
|
||||
}
|
231
src/HashIndex.cc
Normal file
231
src/HashIndex.cc
Normal file
|
@ -0,0 +1,231 @@
|
|||
/******************************************************************************/
|
||||
/* HASH INDEX *****************************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
|
||||
#include <lw/lib/HashIndex.hh>
|
||||
#include <lw/lib/Utilities.hh>
|
||||
using namespace lw;
|
||||
|
||||
|
||||
/*= T_HashIndex =============================================================*/
|
||||
|
||||
constexpr uint32_t T_HashIndex::INVALID_INDEX;
|
||||
uint32_t T_HashIndex::invalidIndex_ = T_HashIndex::INVALID_INDEX;
|
||||
|
||||
T_HashIndex::T_HashIndex( ) noexcept
|
||||
: T_HashIndex( DEFAULT_SIZE , DEFAULT_SIZE )
|
||||
{ }
|
||||
|
||||
T_HashIndex::T_HashIndex( uint32_t hashSize , uint32_t indexSize , uint32_t growth ) noexcept
|
||||
: hashSize_( hashSize ) , hash_( &invalidIndex_ ) ,
|
||||
indexSize_( indexSize ) , indexGrowth_( growth ) ,
|
||||
indexUsed_( 0 ) , index_( &invalidIndex_ ) ,
|
||||
hashMask_( hashSize - 1 ) , lookupMask_( 0 )
|
||||
{
|
||||
assert( IsPowerOf2( hashSize ) && "size must be a power of 2" );
|
||||
assert( growth > 0 && "growth must be greater than 0" );
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
T_HashIndex::T_HashIndex( T_HashIndex const& other )
|
||||
: hashSize_( other.hashSize_ ) , indexSize_( other.indexSize_ ) ,
|
||||
indexGrowth_( other.indexGrowth_ ) , indexUsed_( other.indexUsed_ ) ,
|
||||
hashMask_( other.hashMask_ ) , lookupMask_( other.lookupMask_ )
|
||||
{
|
||||
if ( indexUsed_ == 0 ) {
|
||||
hash_ = &invalidIndex_;
|
||||
index_ = &invalidIndex_;
|
||||
} else {
|
||||
hash_ = ( uint32_t* ) malloc( hashSize_ * sizeof( uint32_t ) );
|
||||
index_ = ( uint32_t* ) malloc( indexSize_ * sizeof( uint32_t ) );
|
||||
indexReverse_ = ( uint32_t* ) malloc( indexSize_ * sizeof( uint32_t ) );
|
||||
memcpy( hash_ , other.hash_ , hashSize_ * sizeof( uint32_t ) );
|
||||
memcpy( index_ , other.index_ , indexSize_ * sizeof( uint32_t ) );
|
||||
memcpy( indexReverse_ , other.indexReverse_ , indexSize_ * sizeof( uint32_t ) );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
T_HashIndex::T_HashIndex( T_HashIndex&& other ) noexcept
|
||||
: T_HashIndex( )
|
||||
{
|
||||
swap( *this , other );
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
T_HashIndex& T_HashIndex::operator =( T_HashIndex const& other )
|
||||
{
|
||||
if ( hash_ != &invalidIndex_ ) {
|
||||
::free( hash_ );
|
||||
::free( index_ );
|
||||
::free( indexReverse_ );
|
||||
}
|
||||
hashSize_ = other.hashSize_;
|
||||
indexSize_ = other.indexSize_;
|
||||
indexGrowth_ = other.indexGrowth_;
|
||||
indexUsed_ = other.indexUsed_;
|
||||
hashMask_ = other.hashMask_;
|
||||
lookupMask_ = other.lookupMask_;
|
||||
|
||||
if ( indexUsed_ == 0 ) {
|
||||
hash_ = &invalidIndex_;
|
||||
index_ = &invalidIndex_;
|
||||
} else {
|
||||
hash_ = ( uint32_t* ) malloc( hashSize_ * sizeof( uint32_t ) );
|
||||
index_ = ( uint32_t* ) malloc( indexSize_ * sizeof( uint32_t ) );
|
||||
indexReverse_ = ( uint32_t* ) malloc( indexSize_ * sizeof( uint32_t ) );
|
||||
memcpy( hash_ , other.hash_ , hashSize_ * sizeof( uint32_t ) );
|
||||
memcpy( index_ , other.index_ , indexSize_ * sizeof( uint32_t ) );
|
||||
memcpy( indexReverse_ , other.indexReverse_ , indexSize_ * sizeof( uint32_t ) );
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
T_HashIndex& T_HashIndex::operator =( T_HashIndex&& other ) noexcept
|
||||
{
|
||||
swap( *this , other );
|
||||
other.clear( );
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
void lw::swap( T_HashIndex& lhs , T_HashIndex& rhs ) noexcept
|
||||
{
|
||||
using std::swap;
|
||||
|
||||
swap( lhs.hashSize_ , rhs.hashSize_ );
|
||||
swap( lhs.hash_ , rhs.hash_ );
|
||||
|
||||
swap( lhs.indexSize_ , rhs.indexSize_ );
|
||||
swap( lhs.indexGrowth_ , rhs.indexGrowth_ );
|
||||
swap( lhs.indexUsed_ , rhs.indexUsed_ );
|
||||
swap( lhs.index_ , rhs.index_ );
|
||||
swap( lhs.indexReverse_ , rhs.indexReverse_ );
|
||||
|
||||
swap( lhs.hashMask_ , rhs.hashMask_ );
|
||||
swap( lhs.lookupMask_ , rhs.lookupMask_ );
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
void T_HashIndex::free( )
|
||||
{
|
||||
if ( hash_ != &invalidIndex_ ) {
|
||||
::free( hash_ );
|
||||
::free( index_ );
|
||||
::free( indexReverse_ );
|
||||
hash_ = &invalidIndex_;
|
||||
index_ = &invalidIndex_;
|
||||
}
|
||||
lookupMask_ = 0;
|
||||
indexUsed_ = 0;
|
||||
}
|
||||
|
||||
void T_HashIndex::clear( )
|
||||
{
|
||||
if ( hash_ != &invalidIndex_ ) {
|
||||
memset( hash_ , 0xff , hashSize_ * sizeof( uint32_t ) );
|
||||
memset( index_ , 0xff , indexSize_ * sizeof( uint32_t ) );
|
||||
indexUsed_ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
void T_HashIndex::enlargeIndex( uint32_t needed )
|
||||
{
|
||||
const uint32_t mod = needed % indexGrowth_;
|
||||
const uint32_t newSize = ( mod == 0 )
|
||||
? needed
|
||||
: ( needed + indexGrowth_ - mod );
|
||||
if ( index_ != &invalidIndex_ ) {
|
||||
index_ = ( uint32_t* ) realloc( index_ ,
|
||||
newSize * sizeof( uint32_t ) );
|
||||
indexReverse_ = ( uint32_t* ) realloc( indexReverse_ ,
|
||||
newSize * sizeof( uint32_t ) );
|
||||
memset( index_ + indexSize_ , 0xff ,
|
||||
( newSize - indexSize_ ) * sizeof( uint32_t ) );
|
||||
memset( indexReverse_ + indexSize_ , 0xff ,
|
||||
( newSize - indexSize_ ) * sizeof( uint32_t ) );
|
||||
}
|
||||
indexSize_ = newSize;
|
||||
}
|
||||
|
||||
void T_HashIndex::allocateIfNecessary( )
|
||||
{
|
||||
if ( hash_ == &invalidIndex_ ) {
|
||||
hash_ = ( uint32_t* ) malloc( hashSize_ * sizeof( uint32_t ) );
|
||||
index_ = ( uint32_t* ) malloc( indexSize_ * sizeof( uint32_t ) );
|
||||
indexReverse_ = ( uint32_t* ) malloc( indexSize_ * sizeof( uint32_t ) );
|
||||
memset( hash_ , 0xff , hashSize_ * sizeof( uint32_t ) );
|
||||
memset( index_ , 0xff , indexSize_ * sizeof( uint32_t ) );
|
||||
memset( indexReverse_ , 0xff , indexSize_ * sizeof( uint32_t ) );
|
||||
lookupMask_ = INVALID_INDEX;
|
||||
}
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
void T_HashIndex::add( uint32_t key )
|
||||
{
|
||||
const uint32_t index = indexUsed_;
|
||||
if ( index >= indexSize_ ) {
|
||||
enlargeIndex( index + indexGrowth_ );
|
||||
}
|
||||
allocateIfNecessary( );
|
||||
|
||||
assert( index_[ index ] == INVALID_INDEX );
|
||||
|
||||
const uint32_t hti = key & hashMask_;
|
||||
const uint32_t oldIndex = hash_[ hti ];
|
||||
hash_[ hti ] = index;
|
||||
index_[ index ] = oldIndex;
|
||||
indexReverse_[ index ] = hti;
|
||||
indexUsed_ ++;
|
||||
}
|
||||
|
||||
void T_HashIndex::remove( uint32_t index )
|
||||
{
|
||||
assert( hash_ != &invalidIndex_ );
|
||||
assert( index < indexUsed_ );
|
||||
|
||||
// Follow the chain until we find the reference to the index.
|
||||
const auto key( indexReverse_[ index ] );
|
||||
uint32_t* ptr = &hash_[ key & hashMask_ ];
|
||||
assert( *ptr != INVALID_INDEX );
|
||||
while ( *ptr != index ) {
|
||||
ptr = &index_[ *ptr ];
|
||||
assert( *ptr != INVALID_INDEX );
|
||||
}
|
||||
|
||||
// Update the reference so it points to the next item in the chain
|
||||
*ptr = index_[ index ];
|
||||
|
||||
// If the index wasn't the last used index, swap it with the last used
|
||||
// value
|
||||
const uint32_t last = indexUsed_ - 1;
|
||||
if ( index != last ) {
|
||||
const uint32_t reverse = indexReverse_[ last ];
|
||||
assert( reverse != INVALID_INDEX );
|
||||
|
||||
index_[ index ] = index_[ last ];
|
||||
indexReverse_[ index ] = reverse;
|
||||
|
||||
// Change the reference to the item we moved in its chain
|
||||
uint32_t* ptr = &hash_[ reverse ];
|
||||
assert( *ptr != INVALID_INDEX );
|
||||
while ( *ptr != last ) {
|
||||
ptr = &index_[ *ptr ];
|
||||
assert( *ptr != INVALID_INDEX );
|
||||
}
|
||||
*ptr = index;
|
||||
}
|
||||
index_[ last ] = INVALID_INDEX;
|
||||
indexReverse_[ last ] = INVALID_INDEX;
|
||||
indexUsed_ = last;
|
||||
}
|
||||
|
603
src/LW.cc
Normal file
603
src/LW.cc
Normal file
|
@ -0,0 +1,603 @@
|
|||
/******************************************************************************/
|
||||
/* MAIN CLASS *****************************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
#include <lw/lib/LW.hh>
|
||||
#include <lw/lib/BuiltinLoggers.hh>
|
||||
#include <lw/lib/SRDBinary.hh>
|
||||
#include <lw/lib/SRDParser.hh>
|
||||
#include <lw/lib/SRDText.hh>
|
||||
#include <lw/lib/MemoryStreams.hh>
|
||||
#include <lw/lib/VFSDrivers.hh>
|
||||
using namespace lw;
|
||||
|
||||
|
||||
/*= LIBRARY DATA =============================================================*/
|
||||
|
||||
namespace {
|
||||
#ifdef LW_BUILD
|
||||
# include "lib-rom.hh"
|
||||
#else
|
||||
const uint8_t lw_library_rom[] = { 0 };
|
||||
#endif
|
||||
} // namespace
|
||||
|
||||
|
||||
/*= INTERNALS ================================================================*/
|
||||
|
||||
namespace {
|
||||
|
||||
/* Command line arguments */
|
||||
struct T_CommandLine_
|
||||
{
|
||||
T_String homePath;
|
||||
T_Array< T_String > extraPaths;
|
||||
T_String ui;
|
||||
};
|
||||
|
||||
struct T_LWInternals_
|
||||
{
|
||||
T_LWComponents& components;
|
||||
|
||||
const T_String executablePath_;
|
||||
T_CommandLine_ arguments_;
|
||||
|
||||
OP_LoggingSystem loggingSystem;
|
||||
T_Logger lPreinit;
|
||||
T_Logger logger;
|
||||
T_Logger lShutdown;
|
||||
|
||||
bool uiInitialised;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
T_LWInternals_( T_String const& executablePath ,
|
||||
T_LWComponents& components ) noexcept;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
[[noreturn]] void fatalError( T_Logger& logger , char const* text );
|
||||
|
||||
/* Load a logging configuration file */
|
||||
OP_LoggingConfiguration loadLoggingConfigFile(
|
||||
T_Logger& logger ,
|
||||
char const* path ) noexcept;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
/* Pre-initialisation - console, logging, VFS, mods manager */
|
||||
void preInit( T_String const& commandLine );
|
||||
|
||||
OP_LoggingConfiguration getInitialLoggingConfig( );
|
||||
void parseCommandLine(
|
||||
T_String const& commandLine );
|
||||
OP_LoggingConfiguration loadPreinitLoggingConfig( );
|
||||
OP_LoggingConfiguration getDefaultPreinitLoggingConfig( );
|
||||
T_ModsManagerConfiguration getModsManagerConfiguration( );
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
void init( );
|
||||
void run( );
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
void shutdown( );
|
||||
OP_LoggingConfiguration loadShutdownLoggingConfig( );
|
||||
OP_LoggingConfiguration getDefaultShutdownLoggingConfig( );
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
inline T_LWInternals_::T_LWInternals_(
|
||||
T_String const& executablePath ,
|
||||
T_LWComponents& components ) noexcept
|
||||
: components( components ) ,
|
||||
executablePath_( executablePath ) ,
|
||||
lPreinit( "/core/preinit" ) ,
|
||||
logger( "/core/init" ) ,
|
||||
lShutdown( "/core/shutdown" )
|
||||
{ }
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
void T_LWInternals_::fatalError( T_Logger& logger , char const* message )
|
||||
{
|
||||
logger.critical( ) << message;
|
||||
// XXX UI-specific error display if possible
|
||||
throw X_FatalError( );
|
||||
}
|
||||
|
||||
OP_LoggingConfiguration T_LWInternals_::loadLoggingConfigFile(
|
||||
T_Logger& logger ,
|
||||
char const* const path ) noexcept
|
||||
{
|
||||
T_StringBuilder sb;
|
||||
sb << path << ".srd";
|
||||
const T_String srd( std::move( sb ) );
|
||||
sb << path << ".srb";
|
||||
const T_String srb( std::move( sb ) );
|
||||
|
||||
auto& vfs( LW::vfs( ) );
|
||||
const bool useSRD( vfs.typeOf( srd ) == E_VFSEntryType::FILE );
|
||||
if ( !useSRD && vfs.typeOf( srb ) != E_VFSEntryType::FILE ) {
|
||||
return {};
|
||||
}
|
||||
T_String const& pstr( useSRD ? srd : srb );
|
||||
|
||||
auto cfg( LW::logWriters( ).getParserConfiguration( ) );
|
||||
T_SRDParser parser( cfg );
|
||||
OP_SRDReader reader( ([&]() -> OP_SRDReader {
|
||||
if ( useSRD ) {
|
||||
return NewOwned< T_SRDTextReader >( parser );
|
||||
} else {
|
||||
return NewOwned< T_SRDBinaryReader >( parser );
|
||||
}
|
||||
})( ) );
|
||||
try {
|
||||
OP_InputStream input( vfs.read( pstr ) );
|
||||
if ( !input ) {
|
||||
throw X_StreamError( E_StreamError::UNAVAILABLE );
|
||||
}
|
||||
reader->read( pstr , *input );
|
||||
return NewOwned< T_LoggingConfiguration >(
|
||||
std::move( *parser.getData< SP_LoggingConfiguration >( ) ) );
|
||||
|
||||
} catch ( X_StreamError const& e ) {
|
||||
logger.warning( ) << "could not load '"
|
||||
<< pstr << "': " << e.what( );
|
||||
} catch ( X_SRDErrors const& errors ) {
|
||||
errors.log( lPreinit );
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
|
||||
/*= PRE-INITIALISATION =======================================================*/
|
||||
|
||||
void T_LWInternals_::preInit(
|
||||
T_String const& commandLine )
|
||||
{
|
||||
// Initialise the console, if we can
|
||||
components.console = NewOwned< T_Console >( );
|
||||
components.console->mode( E_ConsoleMode::OPTIONAL );
|
||||
|
||||
// Register basic log writers
|
||||
components.logWriters = NewOwned< T_LogWriterRegistry >( );
|
||||
LW::logWriters( ).add< T_CWDFileLogWriterFactory >( ).automatic( false );
|
||||
LW::logWriters( ).add< T_ConsoleLogWriterFactory >( LW::console( ) ).automatic( false );
|
||||
|
||||
// Initialise the logging system with a temporary configuration
|
||||
loggingSystem = NewOwned< T_LoggingSystem >(
|
||||
LW::logWriters( ) ,
|
||||
getInitialLoggingConfig( ) );
|
||||
|
||||
// Parse command line arguments
|
||||
if ( commandLine ) {
|
||||
parseCommandLine( commandLine );
|
||||
}
|
||||
|
||||
// Initialise the VFS
|
||||
try {
|
||||
if ( arguments_.homePath ) {
|
||||
components.vfs = NewOwned< T_VFS >( arguments_.homePath );
|
||||
} else {
|
||||
components.vfs = NewOwned< T_VFS >( );
|
||||
}
|
||||
} catch ( X_VFSInitialisationFailure const& ) {
|
||||
fatalError( lPreinit , "Could not initialise the VFS." );
|
||||
}
|
||||
|
||||
// Add the VFS-based log writer, then try reconfiguring
|
||||
LW::logWriters( ).add< T_TextFileLogWriterFactory >( LW::vfs( ) ).automatic( false );
|
||||
loggingSystem->reconfigure( loadPreinitLoggingConfig( ) );
|
||||
|
||||
// Finish configuring the VFS
|
||||
lPreinit.debug( ) << "Adding install path '" << executablePath_
|
||||
<< "' to the VFS";
|
||||
{
|
||||
auto ipvfsd( LW::vfs( ).addDriver< T_VFSFilesystemDriver >(
|
||||
executablePath_ ) );
|
||||
if ( !ipvfsd ) {
|
||||
fatalError( lPreinit , "Could not initialise the VFS." );
|
||||
} else {
|
||||
ipvfsd.automatic( false );
|
||||
}
|
||||
}
|
||||
const uint32_t nExtraPaths( arguments_.extraPaths.size( ) );
|
||||
for ( uint32_t i = 0 ; i < nExtraPaths ; i ++ ) {
|
||||
auto const& path( arguments_.extraPaths[ i ] );
|
||||
lPreinit.trace( ) << "Adding extra path '" << path << "' to the VFS";
|
||||
auto vfsd( LW::vfs( ).addDriver< T_VFSFilesystemDriver >( path ) );
|
||||
if ( vfsd ) {
|
||||
vfsd.automatic( false );
|
||||
} else {
|
||||
lPreinit.warning( ) << "unable to add directory '"
|
||||
<< path << "' to the VFS";
|
||||
}
|
||||
}
|
||||
lPreinit.debug( ) << "Adding library data to the VFS";
|
||||
LW::vfs( ).addDriver( LW::getLibData( ) ).automatic( false );
|
||||
|
||||
// Create the global preprocessor configuration
|
||||
lPreinit.trace( ) << "Creating SRD preprocessor configuration";
|
||||
components.ppConfig = NewOwned< T_SRDPreprocessorConfig >( );
|
||||
components.ppConfig->addBuiltinCommands( );
|
||||
components.ppConfig->addVFSCommands( *components.vfs );
|
||||
|
||||
// Initialise the mods manager
|
||||
lPreinit.trace( ) << "Initialising mods manager";
|
||||
components.mods = NewOwned< T_ModsManager >(
|
||||
getModsManagerConfiguration( ) );
|
||||
auto& mods( LW::mods( ) );
|
||||
if ( !mods.scanForMods( ) ) {
|
||||
// TODO later - switch to installer
|
||||
fatalError( lPreinit , "No mods found" );
|
||||
}
|
||||
if ( !mods.resolveDependencies( ) ) {
|
||||
// TODO later - switch to installer
|
||||
fatalError( lPreinit ,
|
||||
"Could not find a valid set of mods "
|
||||
"matching the current configuration" );
|
||||
}
|
||||
|
||||
// Pre-initialise mods
|
||||
mods.preinitCommon( );
|
||||
components.ui = arguments_.ui
|
||||
? mods.preinitUIMods( arguments_.ui )
|
||||
: mods.preinitUIMods( );
|
||||
if ( !components.ui ) {
|
||||
fatalError( lPreinit , "Unable to start the user interface." );
|
||||
}
|
||||
uiInitialised = false;
|
||||
|
||||
// Create the main loop object
|
||||
components.gameLoop = NewOwned< T_GameLoop >( );
|
||||
lPreinit.trace( ) << "UI & game loop created";
|
||||
|
||||
// Load main logging configuration
|
||||
auto lc( loadLoggingConfigFile( lPreinit , "/logging" ) );
|
||||
if ( lc ) {
|
||||
loggingSystem->reconfigure( std::move( lc ) );
|
||||
}
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
OP_LoggingConfiguration T_LWInternals_::getInitialLoggingConfig( )
|
||||
{
|
||||
auto logCfg( NewOwned< T_LoggingConfiguration >( ) );
|
||||
logCfg->setMinLevelFor( T_LogPath( ) , E_LogLevel::NOTICE );
|
||||
{
|
||||
const T_String console( T_String::Pooled( "console" ) );
|
||||
logCfg->addLogWriter( T_LogPath( ) , console );
|
||||
auto writerConfig( LW::logWriters( )
|
||||
.get( console )
|
||||
->createConfiguration( console ) );
|
||||
logCfg->putLogWriter( OwnRawPointer( writerConfig ) );
|
||||
}
|
||||
{
|
||||
const T_String tfw( "preinit-file" );
|
||||
T_CWDFileLogWriterCfg* writerConfig(
|
||||
dynamic_cast< T_CWDFileLogWriterCfg *>(
|
||||
LW::logWriters( )
|
||||
.get( tfw )
|
||||
->createConfiguration( tfw ) ) );
|
||||
writerConfig->setPath( T_String::Pooled( "legacyworlds-preinit.log" ) );
|
||||
writerConfig->setAppend( false );
|
||||
logCfg->putLogWriter( OwnRawPointer( writerConfig ) );
|
||||
logCfg->addLogWriter( T_LogPath( ) , tfw );
|
||||
}
|
||||
return logCfg;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
void T_LWInternals_::parseCommandLine(
|
||||
T_String const& commandLine )
|
||||
{
|
||||
const T_SRDParserConfig clpConfig( ([]( T_CommandLine_* cl ) {
|
||||
using namespace lw::SRD;
|
||||
T_SRDParserDefs defs( "default" );
|
||||
|
||||
defs << OnStart( [cl]( T_SRDParserData const& d ) -> bool {
|
||||
*( d.currentData ) = cl;
|
||||
return true;
|
||||
} );
|
||||
|
||||
defs.context( "default" )
|
||||
<< ( Rule( ) << "ui" << Text( )
|
||||
<< []( T_SRDParserData const& d ) -> bool {
|
||||
auto cl( d.currentData->value< T_CommandLine_* >( ) );
|
||||
if ( cl->ui ) {
|
||||
d.errors.add( "duplicate UI identifier" , (*d.input)[ 0 ] );
|
||||
} else {
|
||||
cl->ui = (*d.input)[ 1 ].stringValue( );
|
||||
}
|
||||
return true;
|
||||
} )
|
||||
<< ( Rule( ) << "home" << Text( )
|
||||
<< []( T_SRDParserData const& d ) -> bool {
|
||||
auto cl( d.currentData->value< T_CommandLine_* >( ) );
|
||||
if ( cl->homePath ) {
|
||||
d.errors.add( "duplicate home directory" , (*d.input)[ 0 ] );
|
||||
} else {
|
||||
cl->homePath = (*d.input)[ 1 ].stringValue( );
|
||||
}
|
||||
return true;
|
||||
} )
|
||||
<< ( Rule( ) << "extra-paths" << ( AtLeast( 1 ) << Text( ) )
|
||||
<< []( T_SRDParserData const& d ) -> bool {
|
||||
auto cl( d.currentData->value< T_CommandLine_* >( ) );
|
||||
auto const& input( *d.input );
|
||||
const auto nPaths( input.size( ) );
|
||||
for ( uint32_t i = 1 ; i < nPaths ; i ++ ) {
|
||||
auto const& tok( input[ i ] );
|
||||
if ( cl->extraPaths.contains( tok.stringValue( ) ) ) {
|
||||
d.errors.add( "duplicate data path" , tok );
|
||||
} else {
|
||||
cl->extraPaths.add( tok.stringValue( ) );
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} );
|
||||
|
||||
return T_SRDParserConfig( defs );
|
||||
})( &arguments_ ) );
|
||||
|
||||
T_SRDParser parser( clpConfig );
|
||||
T_SRDTextReader reader( parser );
|
||||
T_MemoryInputStream input( commandLine.data( ) , commandLine.size( ) );
|
||||
try {
|
||||
reader.read( T_String( "command line" ) , input );
|
||||
} catch ( X_SRDErrors const& errors ) {
|
||||
errors.log( lPreinit );
|
||||
fatalError( lPreinit , "Invalid command line arguments" );
|
||||
}
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
OP_LoggingConfiguration T_LWInternals_::loadPreinitLoggingConfig( )
|
||||
{
|
||||
auto rv( loadLoggingConfigFile( lPreinit , "/logging-pre" ) );
|
||||
if ( !rv ) {
|
||||
return getDefaultPreinitLoggingConfig( );
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
OP_LoggingConfiguration T_LWInternals_::getDefaultPreinitLoggingConfig( )
|
||||
{
|
||||
auto logCfg( NewOwned< T_LoggingConfiguration >( ) );
|
||||
{
|
||||
const T_String console( T_String::Pooled( "console" ) );
|
||||
auto writerConfig( LW::logWriters( )
|
||||
.get( console )
|
||||
->createConfiguration( console ) );
|
||||
writerConfig->setMinLevel( E_LogLevel::NOTICE );
|
||||
logCfg->putLogWriter( OwnRawPointer( writerConfig ) );
|
||||
logCfg->addLogWriter( T_LogPath( ) , console );
|
||||
}
|
||||
{
|
||||
const T_String tfw( "text-file" );
|
||||
T_TextFileLogWriterCfg* writerConfig(
|
||||
dynamic_cast< T_TextFileLogWriterCfg *>(
|
||||
LW::logWriters( )
|
||||
.get( tfw )
|
||||
->createConfiguration( tfw ) ) );
|
||||
writerConfig->setMinLevel( E_LogLevel::INFO );
|
||||
writerConfig->setPath( "/preinit.log" );
|
||||
writerConfig->setAppend( false );
|
||||
logCfg->putLogWriter( OwnRawPointer( writerConfig ) );
|
||||
logCfg->addLogWriter( T_LogPath( ) , tfw );
|
||||
}
|
||||
return logCfg;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
T_ModsManagerConfiguration T_LWInternals_::getModsManagerConfiguration( )
|
||||
{
|
||||
using T_MMC = T_ModsManagerConfiguration;
|
||||
using SP_MMC = SP_ModsManagerConfiguration;
|
||||
|
||||
const T_String mmcfgf( "/mods.srd" );
|
||||
auto& vfs( LW::vfs( ) );
|
||||
if ( vfs.typeOf( mmcfgf ) == E_VFSEntryType::FILE ) {
|
||||
auto pconf( T_MMC::GetParserConfig( ) );
|
||||
T_SRDParser parser( pconf );
|
||||
T_SRDTextReader reader( parser );
|
||||
try {
|
||||
OP_InputStream input( vfs.read( mmcfgf ) );
|
||||
if ( !input ) {
|
||||
throw X_StreamError( E_StreamError::UNAVAILABLE );
|
||||
}
|
||||
reader.read( mmcfgf , *input );
|
||||
return std::move( *parser.getData< SP_MMC >( ) );
|
||||
|
||||
} catch ( X_StreamError const& e ) {
|
||||
lPreinit.warning( ) << "could not load '" << mmcfgf << "': "
|
||||
<< e.what( );
|
||||
} catch ( X_SRDErrors const& errors ) {
|
||||
errors.log( lPreinit );
|
||||
}
|
||||
}
|
||||
lPreinit.debug( ) << "Using default mods configuration";
|
||||
return T_MMC::DefaultConfiguration( );
|
||||
}
|
||||
|
||||
|
||||
/*= INITIALISATION ===========================================================*/
|
||||
|
||||
void T_LWInternals_::init( )
|
||||
{
|
||||
// Initialise all the mods
|
||||
const uint32_t nLoaded( components.mods->modsCount( ) );
|
||||
uint32_t initialised = 0;
|
||||
components.mods->initialise(
|
||||
[&]( RPC_ModInfo mi ) -> F_UpdateInitProgress {
|
||||
const T_ProgressInfoPart main{
|
||||
([&](){
|
||||
T_StringBuilder sb( "Initializing mod " );
|
||||
sb << mi->identifier.name;
|
||||
return T_String{ std::move( sb ) };
|
||||
})( ) , initialised + 1 , nLoaded + 2
|
||||
};
|
||||
initialised ++;
|
||||
components.ui->setInitProgress(
|
||||
T_ProgressInfo{ main } );
|
||||
|
||||
return [&]( T_ProgressInfoPart part ) {
|
||||
components.ui->setInitProgress(
|
||||
T_ProgressInfo{ main , part } );
|
||||
};
|
||||
} );
|
||||
|
||||
// Initialise UI
|
||||
const T_ProgressInfoPart uiInitMain{
|
||||
T_String( "Initializing user interface" ) ,
|
||||
initialised + 1 , nLoaded + 2
|
||||
};
|
||||
components.ui->setInitProgress( T_ProgressInfo{ uiInitMain } );
|
||||
if ( ! components.ui->init( [&]( T_ProgressInfoPart part ) {
|
||||
components.ui->setInitProgress(
|
||||
T_ProgressInfo{ uiInitMain , part } );
|
||||
}) ) {
|
||||
fatalError( logger , "Failed to initialize user interface" );
|
||||
}
|
||||
uiInitialised = true;
|
||||
|
||||
// Start game loop
|
||||
components.gameLoop->start( );
|
||||
}
|
||||
|
||||
/*FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME*/
|
||||
|
||||
void T_LWInternals_::run( )
|
||||
{
|
||||
components.ui->run( );
|
||||
}
|
||||
|
||||
|
||||
/*= SHUTDOWN =================================================================*/
|
||||
|
||||
void T_LWInternals_::shutdown( )
|
||||
{
|
||||
lShutdown.trace( ) << "Starting shutdown";
|
||||
|
||||
// Shutdown game loop if it's still active
|
||||
if ( components.gameLoop ) {
|
||||
components.gameLoop->shutdown( );
|
||||
}
|
||||
|
||||
// If the UI is present and initialised, shut it down
|
||||
if ( components.ui && uiInitialised ) {
|
||||
components.ui->shutdown( );
|
||||
uiInitialised = false;
|
||||
}
|
||||
|
||||
// Shut down mods
|
||||
if ( components.mods ) {
|
||||
components.mods->shutdown( );
|
||||
}
|
||||
|
||||
// Reset logging configuration
|
||||
lShutdown.trace( ) << "Resetting logger configuration";
|
||||
loggingSystem->reconfigure( loadShutdownLoggingConfig( ) );
|
||||
|
||||
// Terminate the UI
|
||||
if ( components.ui ) {
|
||||
components.ui->postshutdown( );
|
||||
components.ui.clear( );
|
||||
components.gameLoop.clear( );
|
||||
lShutdown.trace( ) << "UI and game loop terminated";
|
||||
}
|
||||
|
||||
// Clear mods
|
||||
if ( components.mods ) {
|
||||
components.mods->unload( );
|
||||
components.mods.clear( );
|
||||
lShutdown.trace( ) << "Mods unloaded";
|
||||
}
|
||||
|
||||
// Clear remaining components
|
||||
lShutdown.trace( ) << "Terminating core components";
|
||||
components.ppConfig.clear( );
|
||||
loggingSystem.clear( );
|
||||
components.logWriters.clear( );
|
||||
components.console.clear( );
|
||||
components.vfs.clear( );
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
OP_LoggingConfiguration T_LWInternals_::loadShutdownLoggingConfig( )
|
||||
{
|
||||
auto rv( loadLoggingConfigFile( lShutdown , "/logging-post" ) );
|
||||
if ( !rv ) {
|
||||
return getDefaultShutdownLoggingConfig( );
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
OP_LoggingConfiguration T_LWInternals_::getDefaultShutdownLoggingConfig( )
|
||||
{
|
||||
auto logCfg( NewOwned< T_LoggingConfiguration >( ) );
|
||||
{
|
||||
const T_String console( T_String::Pooled( "console" ) );
|
||||
auto writerConfig( LW::logWriters( )
|
||||
.get( console )
|
||||
->createConfiguration( console ) );
|
||||
writerConfig->setMinLevel( E_LogLevel::NOTICE );
|
||||
logCfg->putLogWriter( OwnRawPointer( writerConfig ) );
|
||||
logCfg->addLogWriter( T_LogPath( ) , console );
|
||||
}
|
||||
{
|
||||
const T_String tfw( "text-file" );
|
||||
T_TextFileLogWriterCfg* writerConfig(
|
||||
dynamic_cast< T_TextFileLogWriterCfg *>(
|
||||
LW::logWriters( )
|
||||
.get( tfw )
|
||||
->createConfiguration( tfw ) ) );
|
||||
writerConfig->setMinLevel( E_LogLevel::INFO );
|
||||
writerConfig->setPath( "/shutdown.log" );
|
||||
writerConfig->setAppend( false );
|
||||
logCfg->putLogWriter( OwnRawPointer( writerConfig ) );
|
||||
logCfg->addLogWriter( T_LogPath( ) , tfw );
|
||||
}
|
||||
return logCfg;
|
||||
}
|
||||
|
||||
|
||||
/*= MAIN CLASS ===============================================================*/
|
||||
|
||||
LW* LW::instance_ = nullptr;
|
||||
|
||||
LW::LW( T_String const& commandLine , T_String const& executablePath )
|
||||
{
|
||||
assert( instance_ == nullptr );
|
||||
instance_ = this;
|
||||
T_LWInternals_ pi( executablePath , components );
|
||||
try {
|
||||
pi.preInit( commandLine );
|
||||
pi.init( );
|
||||
pi.run( );
|
||||
} catch ( X_FatalError const& ) {
|
||||
pi.shutdown( );
|
||||
components.~T_LWComponents( );
|
||||
instance_ = nullptr;
|
||||
throw;
|
||||
}
|
||||
pi.shutdown( );
|
||||
instance_ = nullptr;
|
||||
}
|
||||
|
||||
OP_VFSDriver LW::getLibData( ) noexcept
|
||||
{
|
||||
return NewOwned< T_VFSRomDriver >(
|
||||
lw_library_rom , sizeof( lw_library_rom ) );
|
||||
}
|
1041
src/Log.cc
Normal file
1041
src/Log.cc
Normal file
File diff suppressed because it is too large
Load diff
60
src/MemoryStreams.cc
Normal file
60
src/MemoryStreams.cc
Normal file
|
@ -0,0 +1,60 @@
|
|||
/******************************************************************************/
|
||||
/* MEMORY STREAMS *************************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
#include <lw/lib/MemoryStreams.hh>
|
||||
using namespace lw;
|
||||
|
||||
|
||||
/*= T_MemoryInputStream ======================================================*/
|
||||
|
||||
|
||||
T_MemoryInputStream::T_MemoryInputStream( void const* buffer , size_t size )
|
||||
: A_InputStream( 0 , size ) ,
|
||||
buffer_( reinterpret_cast< uint8_t const* >( buffer ) )
|
||||
{ }
|
||||
|
||||
|
||||
size_t T_MemoryInputStream::read( void* data , size_t size )
|
||||
{
|
||||
if ( position_ == size_ ) {
|
||||
throw X_StreamError( E_StreamError::END );
|
||||
}
|
||||
|
||||
const size_t readCount( position_ + size <= size_ ? size
|
||||
: ( size_ - position_ ) );
|
||||
memcpy( data , buffer_ + position_ , readCount );
|
||||
position_ += readCount;
|
||||
return readCount;
|
||||
}
|
||||
|
||||
|
||||
/*= T_MemoryOutputStream =====================================================*/
|
||||
|
||||
|
||||
T_MemoryOutputStream::T_MemoryOutputStream( void* buffer , size_t size , F_Resizer resizer )
|
||||
: A_OutputStream( 0 , size ) ,
|
||||
buffer_( reinterpret_cast< uint8_t* >( buffer ) ) ,
|
||||
resizer_( resizer )
|
||||
{ }
|
||||
|
||||
|
||||
size_t T_MemoryOutputStream::write( void const* data , size_t size )
|
||||
{
|
||||
if ( position_ == size_ && !resizer_ ) {
|
||||
throw X_StreamError( E_StreamError::END );
|
||||
}
|
||||
|
||||
size_t ok( size_ - position_ );
|
||||
if ( resizer_ && ok < size ) {
|
||||
size_ = size_ + size - ok;
|
||||
buffer_ = resizer_( buffer_ , size_ );
|
||||
ok = size;
|
||||
}
|
||||
|
||||
const size_t count( ok > size ? size : ok );
|
||||
memcpy( buffer_ + position_ , data , count );
|
||||
position_ += count;
|
||||
return count;
|
||||
}
|
||||
|
86
src/Messages.cc
Normal file
86
src/Messages.cc
Normal file
|
@ -0,0 +1,86 @@
|
|||
/******************************************************************************/
|
||||
/* UI<=>GAME MESSAGES *********************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
#include <lw/lib/Messages.hh>
|
||||
|
||||
using namespace lw;
|
||||
|
||||
#define M_ENUM_OUT_( Type , Value ) \
|
||||
case Type::Value: obj << #Value; break
|
||||
|
||||
|
||||
/*= A_GameView ===============================================================*/
|
||||
|
||||
A_GameView::~A_GameView( )
|
||||
{ }
|
||||
|
||||
|
||||
/*= A_ViewBuilder ============================================================*/
|
||||
|
||||
A_ViewBuilder::~A_ViewBuilder( )
|
||||
{ }
|
||||
|
||||
|
||||
/*= E_GameState ==============================================================*/
|
||||
|
||||
namespace lw {
|
||||
M_LSHIFT_OP( T_StringBuilder , E_GameState )
|
||||
{
|
||||
switch ( value ) {
|
||||
M_ENUM_OUT_( E_GameState , NO_GAME );
|
||||
M_ENUM_OUT_( E_GameState , GAME_PAUSED );
|
||||
M_ENUM_OUT_( E_GameState , GAME_SLOW );
|
||||
M_ENUM_OUT_( E_GameState , GAME_NORMAL );
|
||||
M_ENUM_OUT_( E_GameState , GAME_FAST );
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
} // namespace lw
|
||||
|
||||
|
||||
/*= E_GameUIMessage ==========================================================*/
|
||||
|
||||
namespace lw {
|
||||
M_LSHIFT_OP( T_StringBuilder , E_GameUIMessage )
|
||||
{
|
||||
switch ( value ) {
|
||||
M_ENUM_OUT_( E_GameUIMessage , NEW );
|
||||
M_ENUM_OUT_( E_GameUIMessage , LOAD );
|
||||
M_ENUM_OUT_( E_GameUIMessage , SAVE );
|
||||
M_ENUM_OUT_( E_GameUIMessage , STOP );
|
||||
M_ENUM_OUT_( E_GameUIMessage , QUIT );
|
||||
M_ENUM_OUT_( E_GameUIMessage , ABORT );
|
||||
M_ENUM_OUT_( E_GameUIMessage , DELETE );
|
||||
M_ENUM_OUT_( E_GameUIMessage , COPY_OR_RENAME );
|
||||
M_ENUM_OUT_( E_GameUIMessage , SET_SPEED );
|
||||
M_ENUM_OUT_( E_GameUIMessage , STEPS );
|
||||
M_ENUM_OUT_( E_GameUIMessage , SET_VIEW );
|
||||
M_ENUM_OUT_( E_GameUIMessage , VIEW_DISPLAYED );
|
||||
M_ENUM_OUT_( E_GameUIMessage , QUERY );
|
||||
M_ENUM_OUT_( E_GameUIMessage , COMMAND );
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
} // namespace lw
|
||||
|
||||
|
||||
/*= E_GameLoopMessage ========================================================*/
|
||||
|
||||
namespace lw {
|
||||
M_LSHIFT_OP( T_StringBuilder , E_GameLoopMessage )
|
||||
{
|
||||
switch ( value ) {
|
||||
M_ENUM_OUT_( E_GameLoopMessage , TERMINATED );
|
||||
M_ENUM_OUT_( E_GameLoopMessage , PROGRESS );
|
||||
M_ENUM_OUT_( E_GameLoopMessage , DONE );
|
||||
M_ENUM_OUT_( E_GameLoopMessage , STATE_CHANGED );
|
||||
M_ENUM_OUT_( E_GameLoopMessage , VIEW_AVAILABLE );
|
||||
M_ENUM_OUT_( E_GameLoopMessage , QUERY_RESPONSE );
|
||||
M_ENUM_OUT_( E_GameLoopMessage , COMMAND_OK );
|
||||
M_ENUM_OUT_( E_GameLoopMessage , COMMAND_SYNTAX );
|
||||
M_ENUM_OUT_( E_GameLoopMessage , COMMAND_ERROR );
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
} // namespace lw
|
20
src/ModInterface.cc
Normal file
20
src/ModInterface.cc
Normal file
|
@ -0,0 +1,20 @@
|
|||
/******************************************************************************/
|
||||
/* MODDING SYSTEM INTERFACES **************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
#include <lw/lib/ModInterface.hh>
|
||||
using namespace lw;
|
||||
|
||||
|
||||
/*= A_ModBase ===============================================================*/
|
||||
|
||||
A_ModBase::~A_ModBase( ) noexcept
|
||||
{ }
|
||||
|
||||
|
||||
/*= A_NativeMod ==============================================================*/
|
||||
|
||||
OP_UserInterface A_NativeMod::getUserInterface( ) const noexcept
|
||||
{
|
||||
return {};
|
||||
}
|
2646
src/Mods.cc
Normal file
2646
src/Mods.cc
Normal file
File diff suppressed because it is too large
Load diff
103
src/Pointers.cc
Normal file
103
src/Pointers.cc
Normal file
|
@ -0,0 +1,103 @@
|
|||
/******************************************************************************/
|
||||
/* POINTERS *******************************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
#include <lw/lib/Alloc.hh>
|
||||
#include <lw/lib/Config.hh>
|
||||
#include <lw/lib/Pointers.hh>
|
||||
using namespace lw;
|
||||
|
||||
|
||||
/*= T_WeakChain_ =============================================================*/
|
||||
|
||||
T_WeakChain_::T_WeakChain_( T_Reference_*& ref )
|
||||
: ref( &ref ) , prev( nullptr ) , next( nullptr )
|
||||
{ }
|
||||
|
||||
void T_WeakChain_::unchain( )
|
||||
{
|
||||
if ( prev != nullptr ) {
|
||||
prev->next = next;
|
||||
prev = nullptr;
|
||||
} else if ( (*ref) != nullptr ) {
|
||||
assert( this == (*ref)->weaks_ );
|
||||
(*ref)->weaks_ = next;
|
||||
}
|
||||
if ( next != nullptr ) {
|
||||
next->prev = prev;
|
||||
next = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void T_WeakChain_::init( )
|
||||
{
|
||||
if ( (*ref) == nullptr ) {
|
||||
return;
|
||||
}
|
||||
next = (*ref)->weaks_;
|
||||
if ( next != nullptr ) {
|
||||
next->prev = this;
|
||||
}
|
||||
(*ref)->weaks_ = this;
|
||||
}
|
||||
|
||||
|
||||
/*= T_Reference_ =============================================================*/
|
||||
|
||||
namespace {
|
||||
|
||||
static T_ThreadedPoolAllocator<
|
||||
sizeof( T_Reference_ ) , alignof( T_Reference_ ) ,
|
||||
LW_CFG_SHAREDPTR_REFPOOL_SIZE ,
|
||||
LW_CFG_SHAREDPTR_REFPOOL_MAXFREE
|
||||
> ReferenceAllocator_;
|
||||
|
||||
}
|
||||
|
||||
void* T_Reference_::operator new(
|
||||
const size_t count ) noexcept
|
||||
{
|
||||
return ReferenceAllocator_.allocate( count );
|
||||
}
|
||||
|
||||
void T_Reference_::operator delete(
|
||||
void* const object ) noexcept
|
||||
{
|
||||
return ReferenceAllocator_.free( object );
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
T_Reference_::T_Reference_(
|
||||
void* const ptr ,
|
||||
F_Destr_ destructor )
|
||||
: pointer_( ptr ) , destr_( std::move( destructor ) ) ,
|
||||
count_( 1 ) , weaks_( nullptr )
|
||||
{
|
||||
assert( pointer_ != nullptr );
|
||||
}
|
||||
|
||||
T_Reference_::~T_Reference_( )
|
||||
{
|
||||
assert( count_ == 0 );
|
||||
T_WeakChain_* wr = weaks_;
|
||||
while ( wr != nullptr ) {
|
||||
T_WeakChain_* const next = wr->next;
|
||||
wr->unchain( );
|
||||
*( wr->ref ) = nullptr;
|
||||
wr = next;
|
||||
}
|
||||
destr_( pointer_ );
|
||||
}
|
||||
|
||||
void* T_Reference_::extract( )
|
||||
{
|
||||
if ( count_ > 1 ) {
|
||||
throw X_TooManyReferences( );
|
||||
}
|
||||
void* p( pointer_ );
|
||||
count_ = 0;
|
||||
pointer_ = nullptr;
|
||||
delete this;
|
||||
return p;
|
||||
}
|
567
src/SRDBinary.cc
Normal file
567
src/SRDBinary.cc
Normal file
|
@ -0,0 +1,567 @@
|
|||
/******************************************************************************/
|
||||
/* SRD PARSER AND PREPROCESSOR - BINARY FORM **********************************/
|
||||
/******************************************************************************/
|
||||
|
||||
#include <lw/lib/SRDBinary.hh>
|
||||
using namespace lw;
|
||||
|
||||
|
||||
/*= MAGIC NUMBERS, VERSIONS AND TAGS =========================================*/
|
||||
|
||||
namespace {
|
||||
|
||||
// Magic number for binary SRD
|
||||
static constexpr uint32_t C_MAGIC_ = 0xea7ca1ce;
|
||||
|
||||
// E_Versions_ - Binary SRD version numbers
|
||||
enum class E_Version_ : uint32_t {
|
||||
V1 = 0xc0ffee00 ,
|
||||
};
|
||||
|
||||
// E_V1Tag_ - Version 1 SRD tags
|
||||
enum class E_V1Tag_ : uint8_t {
|
||||
END = 0x00 ,
|
||||
LIST = 0x01 ,
|
||||
WORD_NEW = 0x02 ,
|
||||
WORD_KNOWN = 0x03 ,
|
||||
VAR_WORD = 0x04 ,
|
||||
STRING = 0x05 ,
|
||||
INT = 0x06 ,
|
||||
LONG = 0x07 ,
|
||||
FLOAT = 0x08 ,
|
||||
COMMENT = 0x09 ,
|
||||
BINARY = 0x0a ,
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
namespace lw {
|
||||
|
||||
// Writer for version numbers
|
||||
template< >
|
||||
struct T_ObjectWriter< E_Version_ >
|
||||
{
|
||||
static void write( T_BinaryWriter const& writer , E_Version_ const& v )
|
||||
{
|
||||
writer.write( ( uint32_t ) v );
|
||||
}
|
||||
};
|
||||
|
||||
// Writer for version 1 tags
|
||||
template< >
|
||||
struct T_ObjectWriter< E_V1Tag_ >
|
||||
{
|
||||
static void write( T_BinaryWriter const& writer , E_V1Tag_ const& v )
|
||||
{
|
||||
writer.write( ( uint8_t ) v );
|
||||
}
|
||||
};
|
||||
|
||||
// Reader for version 1 tags
|
||||
template< >
|
||||
struct T_ObjectReader< E_V1Tag_ >
|
||||
{
|
||||
static E_V1Tag_ read( T_BinaryReader const& reader )
|
||||
{
|
||||
return ( E_V1Tag_ ) reader.read< uint8_t >( );
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
/*= VERSION 1 BINARY READER ==================================================*/
|
||||
|
||||
namespace {
|
||||
|
||||
class T_SRDBRVersion1_
|
||||
{
|
||||
private:
|
||||
T_BinaryReader& reader_;
|
||||
T_String const& name_;
|
||||
T_SRDErrors& errors_;
|
||||
A_SRDReaderTarget& target_;
|
||||
|
||||
T_HashIndex wordsIndex_;
|
||||
T_Array< T_String > words_;
|
||||
uint32_t lastTagPos_;
|
||||
|
||||
typedef std::function< T_SRDToken( T_String const& ) > F_StringTok;
|
||||
|
||||
size_t curPos( ) const
|
||||
{
|
||||
return reader_.stream( ).position( );
|
||||
}
|
||||
|
||||
void push( T_SRDToken&& token )
|
||||
{
|
||||
token.location( name_ , lastTagPos_ );
|
||||
target_.push( errors_ , std::move( token ) );
|
||||
}
|
||||
|
||||
void readNewWord( F_StringTok mt );
|
||||
void readKnownWord( F_StringTok mt );
|
||||
void readString( F_StringTok mt );
|
||||
|
||||
void readLoop( );
|
||||
|
||||
public:
|
||||
T_SRDBRVersion1_( T_BinaryReader& reader , T_String const& name , T_SRDErrors& errors ,
|
||||
A_SRDReaderTarget& target )
|
||||
: reader_( reader ) , name_( name ) , errors_( errors ) ,
|
||||
target_( target )
|
||||
{ }
|
||||
|
||||
void read( );
|
||||
};
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
void T_SRDBRVersion1_::readNewWord( F_StringTok mt )
|
||||
{
|
||||
const auto wordPos( curPos( ) );
|
||||
const T_String word( reader_.read< T_String >( ).usePool( ) );
|
||||
if ( word.size( ) == 0 ) {
|
||||
errors_.add( "empty word" , name_ , uint32_t( wordPos ) );
|
||||
return;
|
||||
}
|
||||
|
||||
const bool valid = T_SRDToken::IsWord( word );
|
||||
if ( !valid ) {
|
||||
errors_.add( "invalid word" , name_ , wordPos );
|
||||
}
|
||||
|
||||
const auto hash( ComputeHash( word ) );
|
||||
uint32_t index( wordsIndex_.first( hash ) );
|
||||
while ( index != T_HashIndex::INVALID_INDEX ) {
|
||||
if ( words_[ index ] == word ) {
|
||||
errors_.add( "duplicate word" , name_ , wordPos );
|
||||
return;
|
||||
}
|
||||
index = wordsIndex_.next( index );
|
||||
}
|
||||
|
||||
wordsIndex_.add( hash );
|
||||
words_.add( word );
|
||||
if ( valid ) {
|
||||
push( mt( word ) );
|
||||
}
|
||||
}
|
||||
|
||||
void T_SRDBRVersion1_::readKnownWord( F_StringTok mt )
|
||||
{
|
||||
const auto pos( curPos( ) );
|
||||
const auto widx( reader_.read< uint32_t >( ) );
|
||||
|
||||
if ( widx >= words_.size( ) ) {
|
||||
errors_.add( "unregistered word" , name_ , pos );
|
||||
return;
|
||||
}
|
||||
|
||||
T_String const& word( words_[ widx ] );
|
||||
if ( T_SRDToken::IsWord( word ) ) {
|
||||
push( mt( word ) );
|
||||
}
|
||||
}
|
||||
|
||||
void T_SRDBRVersion1_::readString( F_StringTok mt )
|
||||
{
|
||||
const auto str( reader_.read< T_String >( ).usePool( ) );
|
||||
push( mt( str ) );
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
void T_SRDBRVersion1_::readLoop( )
|
||||
{
|
||||
bool pendingVariable = false;
|
||||
uint32_t depth = 1;
|
||||
while ( depth > 0 ) {
|
||||
lastTagPos_ = reader_.stream( ).position( );
|
||||
const auto tag( reader_.read< E_V1Tag_ >( ) );
|
||||
|
||||
if ( pendingVariable && tag != E_V1Tag_::WORD_NEW && tag != E_V1Tag_::WORD_KNOWN ) {
|
||||
pendingVariable = false;
|
||||
errors_.add( "spurious variable tag" , name_ , lastTagPos_ - 1 );
|
||||
}
|
||||
|
||||
switch ( tag ) {
|
||||
|
||||
case E_V1Tag_::LIST:
|
||||
depth ++;
|
||||
push( T_SRDToken::ListStart( ) );
|
||||
break;
|
||||
|
||||
case E_V1Tag_::END:
|
||||
depth --;
|
||||
if ( depth > 0 ) {
|
||||
push( T_SRDToken::ListEnd( ) );
|
||||
}
|
||||
break;
|
||||
|
||||
case E_V1Tag_::WORD_NEW:
|
||||
if ( pendingVariable ) {
|
||||
lastTagPos_ --;
|
||||
readNewWord( T_SRDToken::Variable );
|
||||
pendingVariable = false;
|
||||
} else {
|
||||
readNewWord( T_SRDToken::Word );
|
||||
}
|
||||
break;
|
||||
|
||||
case E_V1Tag_::WORD_KNOWN:
|
||||
if ( pendingVariable ) {
|
||||
lastTagPos_ --;
|
||||
readKnownWord( T_SRDToken::Variable );
|
||||
pendingVariable = false;
|
||||
} else {
|
||||
readKnownWord( T_SRDToken::Word );
|
||||
}
|
||||
break;
|
||||
|
||||
case E_V1Tag_::VAR_WORD:
|
||||
pendingVariable = true;
|
||||
break;
|
||||
|
||||
case E_V1Tag_::STRING:
|
||||
readString( T_SRDToken::String );
|
||||
break;
|
||||
|
||||
case E_V1Tag_::COMMENT:
|
||||
readString( T_SRDToken::Comment );
|
||||
break;
|
||||
|
||||
case E_V1Tag_::INT:
|
||||
push( T_SRDToken::Integer( reader_.read< int32_t >( ) ) );
|
||||
break;
|
||||
|
||||
case E_V1Tag_::LONG:
|
||||
push( T_SRDToken::Long( reader_.read< int64_t >( ) ) );
|
||||
break;
|
||||
|
||||
case E_V1Tag_::FLOAT:
|
||||
push( T_SRDToken::Float( reader_.read< double >( ) ) );
|
||||
break;
|
||||
|
||||
case E_V1Tag_::BINARY:
|
||||
{
|
||||
const uint32_t size( reader_.read< uint32_t >( ) );
|
||||
T_SharedPtr< T_Buffer< uint8_t > > buffer(
|
||||
NewShared< T_Buffer< uint8_t > >( size ) );
|
||||
if ( size ) {
|
||||
reader_.stream( ).read( buffer->data( ) , size );
|
||||
}
|
||||
push( T_SRDToken::Binary( buffer ) );
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void T_SRDBRVersion1_::read( )
|
||||
{
|
||||
T_SRDReaderTargetHelper rth( target_ , errors_ );
|
||||
try {
|
||||
readLoop( );
|
||||
} catch ( X_StreamError const& e ) {
|
||||
switch ( e.code( ) ) {
|
||||
|
||||
case E_StreamError::BAD_DATA:
|
||||
errors_.add( "invalid data" , name_ , reader_.stream( ).position( ) );
|
||||
break;
|
||||
|
||||
case E_StreamError::END:
|
||||
errors_.add( "unexpected end of file" , name_ , reader_.stream( ).position( ) );
|
||||
break;
|
||||
|
||||
default:
|
||||
errors_.add( "read error" , name_ , reader_.stream( ).position( ) );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
/*= T_SRDBinaryWriter ========================================================*/
|
||||
|
||||
T_SRDBinaryWriter::T_SRDBinaryWriter( A_OutputStream& output )
|
||||
: writer_( output , E_Endian::LITTLE ) , depth_( 0 )
|
||||
{ }
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
void T_SRDBinaryWriter::flushComment( )
|
||||
{
|
||||
if ( comment_.size( ) != 0 ) {
|
||||
writer_.write( E_V1Tag_::COMMENT );
|
||||
writer_.write( comment_ );
|
||||
comment_.clear( );
|
||||
}
|
||||
}
|
||||
|
||||
void T_SRDBinaryWriter::writeWord( T_String const& word )
|
||||
{
|
||||
// Try to find the word in the index
|
||||
const uint32_t hash = ComputeHash( word );
|
||||
uint32_t index = wordsIndex_.first( hash );
|
||||
while ( index != T_HashIndex::INVALID_INDEX ) {
|
||||
if ( word == words_[ index ] ) {
|
||||
break;
|
||||
}
|
||||
index = wordsIndex_.next( index );
|
||||
}
|
||||
|
||||
if ( index == T_HashIndex::INVALID_INDEX ) {
|
||||
// New word
|
||||
wordsIndex_.add( hash );
|
||||
words_.add( word );
|
||||
writer_.write( E_V1Tag_::WORD_NEW );
|
||||
writer_.write( word );
|
||||
} else {
|
||||
// Known word, use the index
|
||||
writer_.write( E_V1Tag_::WORD_KNOWN );
|
||||
writer_.write( index );
|
||||
}
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
T_SRDBinaryWriter& T_SRDBinaryWriter::start( )
|
||||
{
|
||||
if ( depth_ != 0 ) {
|
||||
throw X_SRDWriterError( "already started" );
|
||||
}
|
||||
writer_.write( C_MAGIC_ );
|
||||
writer_.write( E_Version_::V1 );
|
||||
depth_ = 1;
|
||||
return *this;
|
||||
}
|
||||
|
||||
T_SRDBinaryWriter& T_SRDBinaryWriter::end( )
|
||||
{
|
||||
if ( depth_ != 1 ) {
|
||||
throw X_SRDWriterError( depth_ == 0 ? "already ended" : "unterminated lists" );
|
||||
}
|
||||
|
||||
flushComment( );
|
||||
writer_.write( E_V1Tag_::END );
|
||||
depth_ = 0;
|
||||
|
||||
comment_.free( );
|
||||
wordsIndex_.free( );
|
||||
words_.free( );
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
T_SRDBinaryWriter& T_SRDBinaryWriter::startList( )
|
||||
{
|
||||
if ( depth_ == 0 ) {
|
||||
throw X_SRDWriterError( "not started" );
|
||||
}
|
||||
flushComment( );
|
||||
writer_.write( E_V1Tag_::LIST );
|
||||
depth_ ++;
|
||||
return *this;
|
||||
}
|
||||
|
||||
T_SRDBinaryWriter& T_SRDBinaryWriter::endList( )
|
||||
{
|
||||
if ( depth_ == 0 ) {
|
||||
throw X_SRDWriterError( "not started" );
|
||||
}
|
||||
flushComment( );
|
||||
writer_.write( E_V1Tag_::END );
|
||||
depth_ --;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
T_SRDBinaryWriter& T_SRDBinaryWriter::putText( T_String const& text )
|
||||
{
|
||||
if ( T_SRDToken::IsWord( text ) ) {
|
||||
return putWord( text );
|
||||
} else {
|
||||
return putString( text );
|
||||
}
|
||||
}
|
||||
|
||||
T_SRDBinaryWriter& T_SRDBinaryWriter::putWord( T_String const& word )
|
||||
{
|
||||
if ( depth_ == 0 ) {
|
||||
throw X_SRDWriterError( "not started" );
|
||||
}
|
||||
flushComment( );
|
||||
writeWord( word );
|
||||
return *this;
|
||||
}
|
||||
|
||||
T_SRDBinaryWriter& T_SRDBinaryWriter::putString( T_String const& string )
|
||||
{
|
||||
if ( depth_ == 0 ) {
|
||||
throw X_SRDWriterError( "not started" );
|
||||
}
|
||||
flushComment( );
|
||||
writer_.write( E_V1Tag_::STRING );
|
||||
writer_.write( string );
|
||||
return *this;
|
||||
}
|
||||
|
||||
T_SRDBinaryWriter& T_SRDBinaryWriter::putComment( T_String const& comment )
|
||||
{
|
||||
if ( depth_ == 0 ) {
|
||||
throw X_SRDWriterError( "not started" );
|
||||
}
|
||||
comment_ << comment;
|
||||
return *this;
|
||||
}
|
||||
|
||||
T_SRDBinaryWriter& T_SRDBinaryWriter::putVariable( T_String const& variable )
|
||||
{
|
||||
if ( depth_ == 0 ) {
|
||||
throw X_SRDWriterError( "not started" );
|
||||
}
|
||||
flushComment( );
|
||||
writer_.write( E_V1Tag_::VAR_WORD );
|
||||
writeWord( variable );
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
T_SRDBinaryWriter& T_SRDBinaryWriter::putBinary(
|
||||
T_Buffer< uint8_t > const& binary )
|
||||
{
|
||||
if ( depth_ == 0 ) {
|
||||
throw X_SRDWriterError( "not started" );
|
||||
}
|
||||
flushComment( );
|
||||
writer_.write( E_V1Tag_::BINARY );
|
||||
writer_.write( uint32_t( binary.bytes( ) ) );
|
||||
if ( binary.size( ) != 0 ) {
|
||||
writer_.stream( ).write( binary.data( ) , binary.bytes( ) );
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
T_SRDBinaryWriter& T_SRDBinaryWriter::putInteger( int64_t value )
|
||||
{
|
||||
if ( value >= INT32_MIN && value <= INT32_MAX ) {
|
||||
return putInt32( int32_t( value ) );
|
||||
} else {
|
||||
return putInt64( int64_t( value ) );
|
||||
}
|
||||
}
|
||||
|
||||
T_SRDBinaryWriter& T_SRDBinaryWriter::putInt32( int32_t value )
|
||||
{
|
||||
if ( depth_ == 0 ) {
|
||||
throw X_SRDWriterError( "not started" );
|
||||
}
|
||||
flushComment( );
|
||||
writer_.write( E_V1Tag_::INT );
|
||||
writer_.write( value );
|
||||
return *this;
|
||||
}
|
||||
|
||||
T_SRDBinaryWriter& T_SRDBinaryWriter::putInt64( int64_t value )
|
||||
{
|
||||
if ( depth_ == 0 ) {
|
||||
throw X_SRDWriterError( "not started" );
|
||||
}
|
||||
flushComment( );
|
||||
writer_.write( E_V1Tag_::LONG );
|
||||
writer_.write( value );
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
T_SRDBinaryWriter& T_SRDBinaryWriter::putFloat( double value )
|
||||
{
|
||||
if ( depth_ == 0 ) {
|
||||
throw X_SRDWriterError( "not started" );
|
||||
}
|
||||
flushComment( );
|
||||
writer_.write( E_V1Tag_::FLOAT );
|
||||
writer_.write( value );
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
/*= T_SRDBinaryReader ========================================================*/
|
||||
|
||||
void T_SRDBinaryReader::read( T_String const& name , A_InputStream& input )
|
||||
{
|
||||
T_BinaryReader rd( input , E_Endian::LITTLE );
|
||||
T_SRDErrors errors;
|
||||
|
||||
// Read/check magic number
|
||||
const auto magicPos( input.position( ) );
|
||||
const uint32_t magic( ([&]( ) {
|
||||
try {
|
||||
return rd.read< uint32_t >( );
|
||||
} catch ( X_StreamError& e ) {
|
||||
switch ( e.code( ) ) {
|
||||
|
||||
case E_StreamError::BAD_DATA:
|
||||
case E_StreamError::END:
|
||||
errors.add( "missing magic" , name , input.position( ) );
|
||||
break;
|
||||
|
||||
default:
|
||||
errors.add( "read error" , name , input.position( ) );
|
||||
break;
|
||||
}
|
||||
throw X_SRDErrors( errors );
|
||||
}
|
||||
})( ) );
|
||||
if ( magic != C_MAGIC_ ) {
|
||||
errors.add( "invalid magic number" , name , magicPos );
|
||||
throw X_SRDErrors( errors );
|
||||
}
|
||||
|
||||
// Read version number
|
||||
const uint32_t versionPos( input.position( ) );
|
||||
const uint32_t version( ([&]( ) {
|
||||
try {
|
||||
return rd.read< uint32_t >( );
|
||||
} catch ( X_StreamError& e ) {
|
||||
switch ( e.code( ) ) {
|
||||
|
||||
case E_StreamError::BAD_DATA:
|
||||
case E_StreamError::END:
|
||||
errors.add( "missing version ID" , name , input.position( ) );
|
||||
break;
|
||||
|
||||
default:
|
||||
errors.add( "read error" , name , input.position( ) );
|
||||
break;
|
||||
}
|
||||
throw X_SRDErrors( errors );
|
||||
}
|
||||
})( ) );
|
||||
switch ( version ) {
|
||||
|
||||
case uint32_t( E_Version_::V1 ):
|
||||
T_SRDBRVersion1_( rd , name , errors , target_ ).read( );
|
||||
break;
|
||||
|
||||
default:
|
||||
errors.add( "invalid version ID" , name , versionPos );
|
||||
break;
|
||||
}
|
||||
|
||||
if ( errors.size( ) != 0 ) {
|
||||
throw X_SRDErrors( errors );
|
||||
}
|
||||
}
|
657
src/SRDData.cc
Normal file
657
src/SRDData.cc
Normal file
|
@ -0,0 +1,657 @@
|
|||
/******************************************************************************/
|
||||
/* SRD PARSER AND PREPROCESSOR - DATA REPRESENTATION **************************/
|
||||
/******************************************************************************/
|
||||
|
||||
#include <lw/lib/SRDData.hh>
|
||||
#include <lw/lib/Alloc.hh>
|
||||
#include <lw/lib/Log.hh>
|
||||
using namespace lw;
|
||||
|
||||
|
||||
/*= T_SRDLocation ============================================================*/
|
||||
|
||||
static thread_local T_ThreadedPoolAllocator<
|
||||
sizeof( T_SRDLocation ) , alignof( T_SRDLocation ) ,
|
||||
128 , 2
|
||||
> LocationPool_;
|
||||
|
||||
void* T_SRDLocation::operator new(
|
||||
const size_t count ) noexcept
|
||||
{
|
||||
return LocationPool_.allocate( count );
|
||||
}
|
||||
|
||||
void T_SRDLocation::operator delete(
|
||||
void* const object ) noexcept
|
||||
{
|
||||
LocationPool_.free( object );
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
T_SRDLocation::T_SRDLocation(
|
||||
T_String const& source ,
|
||||
const uint32_t line ,
|
||||
const size_t character ) noexcept
|
||||
: source_( source ) , line_( line ) , character_( character )
|
||||
{
|
||||
assert( line > 0 );
|
||||
}
|
||||
|
||||
T_SRDLocation::T_SRDLocation(
|
||||
T_String const& source ,
|
||||
const size_t byte ) noexcept
|
||||
: source_( source ) , line_( 0 ) , character_( byte )
|
||||
{ }
|
||||
|
||||
T_SRDLocation::T_SRDLocation(
|
||||
T_SRDLocation const& other ) noexcept
|
||||
: source_( other.source_ ) , line_( other.line_ ) ,
|
||||
character_( other.character_ ) ,
|
||||
chaining_( other.chaining_ )
|
||||
{ }
|
||||
|
||||
T_SRDLocation::T_SRDLocation(
|
||||
T_SRDLocation&& other ) noexcept
|
||||
: T_SRDLocation( )
|
||||
{
|
||||
swap( *this , other );
|
||||
}
|
||||
|
||||
namespace lw {
|
||||
M_DECLARE_SWAP( T_SRDLocation )
|
||||
{
|
||||
using std::swap;
|
||||
swap( lhs.source_ , rhs.source_ );
|
||||
swap( lhs.line_ , rhs.line_ );
|
||||
swap( lhs.character_ , rhs.character_ );
|
||||
swap( lhs.chaining_ , rhs.chaining_ );
|
||||
}
|
||||
}
|
||||
|
||||
T_SRDLocation& T_SRDLocation::operator= (
|
||||
T_SRDLocation const& other ) noexcept
|
||||
{
|
||||
source_ = other.source_;
|
||||
line_ = other.line_;
|
||||
character_ = other.character_;
|
||||
chaining_ = other.chaining_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
T_StringBuilder& operator<< (
|
||||
T_StringBuilder& sb ,
|
||||
T_SRDLocation const& location ) noexcept
|
||||
{
|
||||
if ( location.unknown( ) ) {
|
||||
sb << "unknown location";
|
||||
} else {
|
||||
sb << location.source( ) << ' ';
|
||||
if ( location.binary( ) ) {
|
||||
sb << 'b' << location.character( );
|
||||
} else {
|
||||
sb << 'l' << location.line( )
|
||||
<< ' ' << 'c' << location.character( );
|
||||
}
|
||||
}
|
||||
return sb;
|
||||
}
|
||||
|
||||
|
||||
/*= T_SRDErrors ============================================================*/
|
||||
|
||||
void T_SRDErrors::checkAdded(
|
||||
T_SRDError const& last )
|
||||
{
|
||||
if ( last.isDetails( ) || errCount_ >= MAX_ERRORS ) {
|
||||
return;
|
||||
}
|
||||
errCount_ ++;
|
||||
if ( errCount_ == T_SRDErrors::MAX_ERRORS ) {
|
||||
errors_.addNew( T_String::Pooled( "too many errors" ) ,
|
||||
last.location( ) );
|
||||
throw X_SRDErrors( *this );
|
||||
}
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
void T_SRDErrors::addAll(
|
||||
T_SRDErrors const& source )
|
||||
{
|
||||
if ( errCount_ >= MAX_ERRORS ) {
|
||||
return;
|
||||
}
|
||||
|
||||
const uint32_t nErrors( source.size( ) );
|
||||
RPC_SRDLocation lastLocation = nullptr;
|
||||
for ( uint32_t i = 0 ; i < nErrors ; i ++ ) {
|
||||
errors_.add( source[ i ] );
|
||||
if ( !source[ i ].isDetails( ) ) {
|
||||
lastLocation = &source[ i ].location( );
|
||||
}
|
||||
}
|
||||
errCount_ += source.errCount_;
|
||||
if ( errCount_ >= MAX_ERRORS ) {
|
||||
errors_.addNew( T_String::Pooled( "too many errors" ) ,
|
||||
lastLocation ? *lastLocation : T_SRDLocation( ) );
|
||||
throw X_SRDErrors( *this );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*= X_SRDErrors ============================================================*/
|
||||
|
||||
char const* X_SRDErrors::what( ) const noexcept
|
||||
{
|
||||
return "SRD read/parse errors";
|
||||
}
|
||||
|
||||
#ifndef LW_MINLIB
|
||||
void X_SRDErrors::log( T_Logger& logger ) const
|
||||
{
|
||||
const auto nErrors( errors.size( ) );
|
||||
for ( size_t i = 0 ; i < nErrors ; i ++ ) {
|
||||
auto sb( logger.error( ) );
|
||||
auto const& e( errors[ i ] );
|
||||
auto const& l( e.location( ) );
|
||||
|
||||
if ( l.unknown( ) ) {
|
||||
sb << "unknown location";
|
||||
} else {
|
||||
sb << l.source( );
|
||||
if ( l.binary( ) ) {
|
||||
sb << ", b" << l.byte( );
|
||||
} else {
|
||||
sb << ", l" << l.line( ) << ", c" << l.character( );
|
||||
}
|
||||
}
|
||||
sb << ": " << e.error( );
|
||||
}
|
||||
}
|
||||
#endif // LW_MINLIB
|
||||
|
||||
|
||||
/*= T_SRDToken =============================================================*/
|
||||
|
||||
T_StringBuilder& lw::operator<< ( T_StringBuilder& sb , E_SRDTokenType tt )
|
||||
{
|
||||
static char const* const C_TOKEN_TYPES_[] = {
|
||||
"(...)" ,
|
||||
"(" , ")" ,
|
||||
"WORD" ,
|
||||
"$WORD" ,
|
||||
"STRING" ,
|
||||
"BINARY" ,
|
||||
"INT" ,
|
||||
"LONG" ,
|
||||
"FLOAT" ,
|
||||
"COMMENT"
|
||||
};
|
||||
return sb << C_TOKEN_TYPES_[ int( tt ) ];
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
bool T_SRDToken::IsWord( T_String const& text )
|
||||
{
|
||||
enum {
|
||||
INIT_ ,
|
||||
AFTER_DASH_ ,
|
||||
IN_WORD_
|
||||
} state = INIT_;
|
||||
|
||||
T_StringIterator it( text );
|
||||
while ( !it.atEnd( ) ) {
|
||||
T_Character c( it );
|
||||
it.next( );
|
||||
|
||||
if ( state == INIT_ ) {
|
||||
if ( c == '-' ) {
|
||||
state = AFTER_DASH_;
|
||||
} else if ( c.isAlpha( ) ) {
|
||||
state = IN_WORD_;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
} else if ( state == AFTER_DASH_ ) {
|
||||
if ( c.isAlpha( ) ) {
|
||||
state = IN_WORD_;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else if ( !c.isAlphanumeric( ) ) {
|
||||
if ( c == '-' ) {
|
||||
state = AFTER_DASH_;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return state == IN_WORD_;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
T_SRDToken T_SRDToken::ListStart( )
|
||||
{
|
||||
return T_SRDToken( E_SRDTokenType::START );
|
||||
}
|
||||
|
||||
T_SRDToken T_SRDToken::ListEnd( )
|
||||
{
|
||||
return T_SRDToken( E_SRDTokenType::END );
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
T_SRDToken T_SRDToken::List( )
|
||||
{
|
||||
T_SRDToken token( E_SRDTokenType::LIST );
|
||||
token.list_ = NewOwned< T_SRDList >( 16 );
|
||||
return token;
|
||||
}
|
||||
|
||||
T_SRDToken T_SRDToken::List( T_SRDList const& list )
|
||||
{
|
||||
T_SRDToken token( E_SRDTokenType::LIST );
|
||||
token.list_ = NewOwned< T_SRDList >( list );
|
||||
return token;
|
||||
}
|
||||
|
||||
T_SRDToken T_SRDToken::List( T_SRDList&& list )
|
||||
{
|
||||
T_SRDToken token( E_SRDTokenType::LIST );
|
||||
token.list_ = NewOwned< T_SRDList >( std::move( list ) );
|
||||
return token;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
T_SRDToken T_SRDToken::AutoText( T_String text )
|
||||
{
|
||||
const bool w = IsWord( text );
|
||||
T_SRDToken token( w ? E_SRDTokenType::WORD : E_SRDTokenType::STRING );
|
||||
token.stringValue_ = std::move( text );
|
||||
return token;
|
||||
}
|
||||
|
||||
T_SRDToken T_SRDToken::Word( T_String word )
|
||||
{
|
||||
assert( IsWord( word ) );
|
||||
T_SRDToken token( E_SRDTokenType::WORD );
|
||||
token.stringValue_ = std::move( word );
|
||||
return token;
|
||||
}
|
||||
|
||||
T_SRDToken T_SRDToken::String( T_String string )
|
||||
{
|
||||
T_SRDToken token( E_SRDTokenType::STRING );
|
||||
token.stringValue_ = std::move( string );
|
||||
return token;
|
||||
}
|
||||
|
||||
T_SRDToken T_SRDToken::Variable( T_String variable )
|
||||
{
|
||||
assert( IsWord( variable ) );
|
||||
T_SRDToken token( E_SRDTokenType::VAR );
|
||||
token.stringValue_ = std::move( variable );
|
||||
return token;
|
||||
}
|
||||
|
||||
T_SRDToken T_SRDToken::Comment( T_String text )
|
||||
{
|
||||
T_SRDToken token( E_SRDTokenType::COMMENT );
|
||||
token.stringValue_ = std::move( text );
|
||||
return token;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
T_SRDToken T_SRDToken::Binary(
|
||||
T_SharedPtr< T_Buffer< uint8_t > > const& data ) noexcept
|
||||
{
|
||||
T_SRDToken token( E_SRDTokenType::BINARY );
|
||||
assert( bool( data ) );
|
||||
token.binary_ = data;
|
||||
return token;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
T_SRDToken T_SRDToken::Flush( ) noexcept
|
||||
{
|
||||
return T_SRDToken( E_SRDTokenType::FLUSH );
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
T_SRDToken T_SRDToken::AutoInteger( int64_t value )
|
||||
{
|
||||
const bool isInt = ( value >= INT32_MIN && value <= INT32_MAX );
|
||||
const E_SRDTokenType type = ([ = ]( ) {
|
||||
if ( isInt ) {
|
||||
return E_SRDTokenType::INT;
|
||||
} else {
|
||||
return E_SRDTokenType::LONG;
|
||||
}
|
||||
} )( );
|
||||
|
||||
T_SRDToken token( type );
|
||||
token.longValue_ = value;
|
||||
token.floatValue_ = value;
|
||||
|
||||
T_StringBuilder sb;
|
||||
sb << value;
|
||||
token.stringValue_ = std::move( sb );
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
T_SRDToken T_SRDToken::Integer( int32_t value )
|
||||
{
|
||||
T_SRDToken token( E_SRDTokenType::INT );
|
||||
token.longValue_ = value;
|
||||
token.floatValue_ = value;
|
||||
|
||||
T_StringBuilder sb;
|
||||
sb << value;
|
||||
token.stringValue_ = std::move( sb );
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
T_SRDToken T_SRDToken::Long( int64_t value )
|
||||
{
|
||||
T_SRDToken token( E_SRDTokenType::LONG );
|
||||
token.longValue_ = value;
|
||||
token.floatValue_ = value;
|
||||
|
||||
T_StringBuilder sb;
|
||||
sb << value;
|
||||
token.stringValue_ = std::move( sb );
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
T_SRDToken T_SRDToken::Float( double value )
|
||||
{
|
||||
T_SRDToken token( E_SRDTokenType::FLOAT );
|
||||
token.longValue_ = value;
|
||||
token.floatValue_ = value;
|
||||
|
||||
T_StringBuilder sb;
|
||||
sb << value;
|
||||
token.stringValue_ = std::move( sb );
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
T_SRDToken::T_SRDToken( T_SRDToken const& other )
|
||||
: type_( other.type_ ) , text_( other.text_ ) ,
|
||||
longValue_( other.longValue_ ) ,
|
||||
floatValue_( other.floatValue_ ) ,
|
||||
stringValue_( other.stringValue_ ) ,
|
||||
binary_( other.binary_ ) ,
|
||||
location_( other.location_ )
|
||||
{
|
||||
if ( other.list_ ) {
|
||||
list_ = NewOwned< T_SRDList >( *other.list_ );
|
||||
}
|
||||
}
|
||||
|
||||
T_SRDToken& T_SRDToken::operator= ( T_SRDToken const& other )
|
||||
{
|
||||
type_ = other.type_;
|
||||
text_ = other.text_;
|
||||
if ( other.list_ ) {
|
||||
list_ = NewOwned< T_SRDList >( *other.list_ );
|
||||
} else {
|
||||
list_.clear( );
|
||||
}
|
||||
longValue_ = other.longValue_;
|
||||
floatValue_ = other.floatValue_;
|
||||
stringValue_ = other.stringValue_;
|
||||
location_ = other.location_;
|
||||
binary_ = other.binary_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
void lw::swap( T_SRDToken& lhs , T_SRDToken& rhs ) noexcept
|
||||
{
|
||||
using std::swap;
|
||||
swap( lhs.type_ , rhs.type_ );
|
||||
swap( lhs.text_ , rhs.text_ );
|
||||
swap( lhs.list_ , rhs.list_ );
|
||||
swap( lhs.longValue_ , rhs.longValue_ );
|
||||
swap( lhs.floatValue_ , rhs.floatValue_ );
|
||||
swap( lhs.stringValue_ , rhs.stringValue_ );
|
||||
swap( lhs.binary_ , rhs.binary_ );
|
||||
swap( lhs.location_ , rhs.location_ );
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
int T_SRDToken::compare( T_SRDToken const& other ) const
|
||||
{
|
||||
// Numeric values can be compared even if they don't have the exact same type
|
||||
if ( isInteger( ) && other.isInteger( ) ) {
|
||||
return T_Comparator< int64_t >::compare( longValue_ , other.longValue_ );
|
||||
}
|
||||
if ( isNumeric( ) && other.isNumeric( ) ) {
|
||||
return T_Comparator< double >::compare( floatValue_ , other.floatValue_ );
|
||||
}
|
||||
|
||||
// We need to have the same type to keep going
|
||||
if ( type_ != other.type_ ) {
|
||||
return T_Comparator< int >::compare( int( type_ ) , int( other.type_ ) );
|
||||
}
|
||||
|
||||
// List start/end -> nothing else to do
|
||||
if ( type_ == E_SRDTokenType::START || type_ == E_SRDTokenType::END ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// List -> compare all tokens
|
||||
if ( type_ == E_SRDTokenType::LIST ) {
|
||||
auto const& l0( *list_ );
|
||||
auto const& l1( *( other.list_ ) );
|
||||
const auto lim( std::min( l0.size( ) , l1.size( ) ) );
|
||||
for ( size_t i = 0 ; i < lim ; i ++ ) {
|
||||
const auto tcmp( l0[ i ].compare( l1[ i ] ) );
|
||||
if ( tcmp != 0 ) {
|
||||
return tcmp;
|
||||
}
|
||||
}
|
||||
return T_Comparator< size_t >::compare( l0.size( ) , l1.size( ) );
|
||||
}
|
||||
|
||||
|
||||
// Everything else: text compare
|
||||
return T_Comparator< T_String >::compare( stringValue_ , other.stringValue_ );
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
bool T_SRDToken::hasFullText( ) const
|
||||
{
|
||||
return text_
|
||||
|| type_ == E_SRDTokenType::WORD
|
||||
|| type_ == E_SRDTokenType::START
|
||||
|| type_ == E_SRDTokenType::END;
|
||||
}
|
||||
|
||||
T_String T_SRDToken::fullText( ) const
|
||||
{
|
||||
switch ( type_ ) {
|
||||
|
||||
case E_SRDTokenType::WORD:
|
||||
return stringValue_;
|
||||
|
||||
case E_SRDTokenType::START:
|
||||
return T_String::Pooled( "(" );
|
||||
|
||||
case E_SRDTokenType::END:
|
||||
return T_String::Pooled( ")" );
|
||||
|
||||
default:
|
||||
return text_;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
T_SRDToken& T_SRDToken::setFullText( T_String text )
|
||||
{
|
||||
if ( type_ != E_SRDTokenType::WORD && type_ != E_SRDTokenType::START
|
||||
&& type_ != E_SRDTokenType::END ) {
|
||||
text_ = std::move( text );
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
T_SRDToken& T_SRDToken::generateFullText( )
|
||||
{
|
||||
if ( hasFullText( ) ) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
T_StringBuilder sb;
|
||||
switch ( type_ ) {
|
||||
|
||||
case E_SRDTokenType::LIST:
|
||||
sb << '(';
|
||||
if ( list_->size( ) != 0 ) {
|
||||
sb << ' ';
|
||||
}
|
||||
for ( size_t i = 0 ; i < list_->size( ) ; i ++ ) {
|
||||
sb << (*list_)[ i ].generateFullText( )
|
||||
.fullText( )
|
||||
<< ' ';
|
||||
}
|
||||
sb << ')';
|
||||
break;
|
||||
|
||||
case E_SRDTokenType::VAR:
|
||||
sb << '$' << stringValue_;
|
||||
break;
|
||||
|
||||
case E_SRDTokenType::STRING:
|
||||
{
|
||||
T_StringIterator it( stringValue_ );
|
||||
sb << '"';
|
||||
while ( !it.atEnd( ) ) {
|
||||
T_Character c( it );
|
||||
if ( c.isControl( ) ) {
|
||||
if ( c == '\n' ) {
|
||||
sb << "\\n";
|
||||
} else if ( c == '\t' ) {
|
||||
sb << "\\t";
|
||||
} else {
|
||||
sb << "\\x";
|
||||
if ( c < 16 ) {
|
||||
sb << '0';
|
||||
}
|
||||
sb << c.codepoint;
|
||||
}
|
||||
} else if ( c == '\\' ) {
|
||||
sb << "\\\\";
|
||||
} else if ( c == '"' ) {
|
||||
sb << "\\\"";
|
||||
} else {
|
||||
sb << c;
|
||||
}
|
||||
it.next( );
|
||||
}
|
||||
sb << '"';
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case E_SRDTokenType::COMMENT:
|
||||
{
|
||||
T_StringIterator it( stringValue_ );
|
||||
bool atStart = true;
|
||||
while ( !it.atEnd( ) ) {
|
||||
T_Character c( it );
|
||||
if ( atStart ) {
|
||||
sb << '#';
|
||||
atStart = false;
|
||||
}
|
||||
sb << c;
|
||||
if ( c == '\n' ) {
|
||||
atStart = true;
|
||||
}
|
||||
it.next( );
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case E_SRDTokenType::INT:
|
||||
case E_SRDTokenType::LONG:
|
||||
sb << longValue_;
|
||||
break;
|
||||
|
||||
case E_SRDTokenType::FLOAT:
|
||||
sb << floatValue_;
|
||||
break;
|
||||
|
||||
case E_SRDTokenType::BINARY:
|
||||
{
|
||||
sb << '[';
|
||||
const uint32_t sz( binary_->size( ) );
|
||||
for ( uint32_t i = 0 ; i < sz ; i ++ ) {
|
||||
sb << ' ';
|
||||
sb.appendNumeric( uint64_t( binary_->operator[]( i ) ) , 16 );
|
||||
}
|
||||
sb << " ]";
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
default:
|
||||
assert( 0 && "This shouldn't be happening" );
|
||||
}
|
||||
text_ = std::move( sb );
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
T_SRDToken& T_SRDToken::location( T_String const& source , size_t byte )
|
||||
{
|
||||
location_ = NewShared< T_SRDLocation >( source , byte );
|
||||
return *this;
|
||||
}
|
||||
|
||||
T_SRDToken& T_SRDToken::location( T_String const& source , uint32_t line , size_t character )
|
||||
{
|
||||
location_ = NewShared< T_SRDLocation >( source , line , character );
|
||||
return *this;
|
||||
}
|
||||
|
||||
T_SRDToken& T_SRDToken::location( T_SRDLocation const& other )
|
||||
{
|
||||
location_ = NewShared< T_SRDLocation >( other );
|
||||
return *this;
|
||||
}
|
||||
|
||||
T_SRDToken& T_SRDToken::location( T_SRDLocation && other )
|
||||
{
|
||||
location_ = NewShared< T_SRDLocation >( std::move( other ) );
|
||||
return *this;
|
||||
}
|
||||
|
||||
T_SRDToken& T_SRDToken::copyLocationOf( T_SRDToken const& other )
|
||||
{
|
||||
location_ = other.location_;
|
||||
return *this;
|
||||
}
|
||||
|
297
src/SRDDefinitions.cc
Normal file
297
src/SRDDefinitions.cc
Normal file
|
@ -0,0 +1,297 @@
|
|||
/******************************************************************************/
|
||||
/* SRD - PARSER DEFINITIONS ***************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
|
||||
#include <lw/lib/SRDDefinitions.hh>
|
||||
using namespace lw;
|
||||
|
||||
|
||||
/*= T_SRDEnum ================================================================*/
|
||||
|
||||
T_SRDEnum& T_SRDEnum::operator<< ( T_String&& word )
|
||||
{
|
||||
if ( (*this)[ word ] != T_HashIndex::INVALID_INDEX ) {
|
||||
throw std::invalid_argument( "duplicate enum item" );
|
||||
}
|
||||
|
||||
const uint32_t hash( ComputeHash( word ) );
|
||||
index_.add( hash );
|
||||
words_.add( std::move( word ) );
|
||||
return *this;
|
||||
}
|
||||
|
||||
uint32_t T_SRDEnum::operator[] ( T_String const& word ) const
|
||||
{
|
||||
const uint32_t hash( ComputeHash( word ) );
|
||||
uint32_t idx = index_.first( hash );
|
||||
while ( idx != T_HashIndex::INVALID_INDEX ) {
|
||||
if ( words_[ idx ] == word ) {
|
||||
break;
|
||||
}
|
||||
idx = index_.next( idx );
|
||||
}
|
||||
return idx;
|
||||
}
|
||||
|
||||
uint32_t T_SRDEnum::operator[] ( char const* word ) const
|
||||
{
|
||||
const auto len = strlen( word );
|
||||
const uint32_t hash( HashData( (uint8_t const*)word , len ) );
|
||||
uint32_t idx = index_.first( hash );
|
||||
while ( idx != T_HashIndex::INVALID_INDEX ) {
|
||||
auto const& w( words_[ idx ] );
|
||||
if ( w.size( ) == len && !memcmp( w.data( ) , word , len ) ) {
|
||||
break;
|
||||
}
|
||||
idx = index_.next( idx );
|
||||
}
|
||||
return idx;
|
||||
}
|
||||
|
||||
|
||||
/*= T_SRDInputItem ===========================================================*/
|
||||
|
||||
void lw::swap( T_SRDInputItem& lhs , T_SRDInputItem& rhs ) noexcept
|
||||
{
|
||||
using std::swap;
|
||||
swap( lhs.type_ , rhs.type_ );
|
||||
swap( lhs.word_ , rhs.word_ );
|
||||
swap( lhs.token_ , rhs.token_ );
|
||||
swap( lhs.items_ , rhs.items_ );
|
||||
swap( lhs.min_ , rhs.min_ );
|
||||
swap( lhs.max_ , rhs.max_ );
|
||||
}
|
||||
|
||||
T_SRDInputItem& T_SRDInputItem::operator<< ( T_SRDInputItem item )
|
||||
{
|
||||
if ( type_ != E_SRDInputItem::ALTERNATIVE
|
||||
&& type_ != E_SRDInputItem::REPETITION ) {
|
||||
throw std::invalid_argument(
|
||||
"not an ALTERNATIVE or REPETITION" );
|
||||
}
|
||||
if ( item.type( ) == type_ ) {
|
||||
items_.addAll( item.items( ) );
|
||||
} else {
|
||||
items_.add( std::move( item ) );
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
T_StringBuilder& lw::operator<< ( T_StringBuilder& sb , T_SRDInputItem const& item )
|
||||
{
|
||||
switch ( item.type( ) ) {
|
||||
|
||||
case E_SRDInputItem::WORD:
|
||||
sb << item.word( );
|
||||
break;
|
||||
|
||||
case E_SRDInputItem::ENUM:
|
||||
sb << '[' << item.word( ) << "::*]";
|
||||
break;
|
||||
|
||||
case E_SRDInputItem::TOKEN:
|
||||
sb << item.token( );
|
||||
break;
|
||||
|
||||
case E_SRDInputItem::ALTERNATIVE:
|
||||
{
|
||||
auto const& alts( item.items( ) );
|
||||
sb << "[ ";
|
||||
for ( uint32_t i = 0 ; i < alts.size( ) ; i ++ ) {
|
||||
if ( i != 0 ) {
|
||||
sb << " | ";
|
||||
}
|
||||
sb << alts[ i ];
|
||||
}
|
||||
sb << " ]";
|
||||
break;
|
||||
}
|
||||
|
||||
case E_SRDInputItem::REPETITION:
|
||||
{
|
||||
auto const& seq( item.items( ) );
|
||||
const bool listBits( seq.size( ) != 1 && ( item.min( ) != 1 || item.max( ) != 1 ) );
|
||||
|
||||
if ( listBits ) {
|
||||
sb << "[ ";
|
||||
}
|
||||
for ( uint32_t i = 0 ; i < seq.size( ) ; i ++ ) {
|
||||
if ( i != 0 ) {
|
||||
sb << ' ';
|
||||
}
|
||||
sb << seq[ i ];
|
||||
}
|
||||
if ( listBits ) {
|
||||
if ( seq.size( ) ) {
|
||||
sb << ' ';
|
||||
}
|
||||
sb << ']';
|
||||
}
|
||||
if ( item.min( ) == 0 && item.max( ) == 1 ) {
|
||||
sb << '?';
|
||||
} else if ( item.max( ) == UINT32_MAX ) {
|
||||
if ( item.min( ) == 0 ) {
|
||||
sb << '*';
|
||||
} else {
|
||||
if ( item.min( ) != 1 ) {
|
||||
sb << '{' << item.min( );
|
||||
}
|
||||
sb << '+';
|
||||
if ( item.min( ) != 1 ) {
|
||||
sb << '}';
|
||||
}
|
||||
}
|
||||
} else if ( item.min( ) == item.max( ) && item.min( ) != 1 ) {
|
||||
sb << '{' << item.min( ) << '}';
|
||||
} else if ( item.min( ) != item.max( ) ) {
|
||||
sb << '{' << item.min( ) << ','
|
||||
<< item.max( ) << '}';
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return sb;
|
||||
}
|
||||
|
||||
|
||||
/*= T_SRDInputRule ===========================================================*/
|
||||
|
||||
T_SRDInputRule& T_SRDInputRule::operator<< ( T_SRDInputItem item )
|
||||
{
|
||||
items_.add( std::move( item ) );
|
||||
return *this;
|
||||
}
|
||||
|
||||
T_StringBuilder& lw::operator<< ( T_StringBuilder& sb , T_SRDInputRule const& item )
|
||||
{
|
||||
auto const& seq( item.rule( ) );
|
||||
sb << '(';
|
||||
for ( uint32_t i = 0 ; i < seq.size( ) ; i ++ ) {
|
||||
sb << ' ' << seq[ i ];
|
||||
}
|
||||
if ( item.context( ) ) {
|
||||
sb << " ..." << item.context( ) << "...";
|
||||
}
|
||||
sb << " )";
|
||||
return sb;
|
||||
}
|
||||
|
||||
|
||||
/*= T_SRDContext =============================================================*/
|
||||
|
||||
T_SRDContext::T_SRDContext( T_String name , T_String parent )
|
||||
: name_( std::move( name ) ) , parent_( std::move( parent ) ) ,
|
||||
rules_( 16 )
|
||||
{ }
|
||||
|
||||
|
||||
T_SRDContext& T_SRDContext::operator<< ( T_SRDInputRule rule )
|
||||
{
|
||||
rules_.add( std::move( rule ) );
|
||||
return *this;
|
||||
}
|
||||
|
||||
T_StringBuilder& T_SRDContext::dump( T_StringBuilder& sb , T_String const& separator )
|
||||
{
|
||||
const auto nr( rules_.size( ) );
|
||||
for ( uint32_t i = 0 ; i < nr ; i ++ ) {
|
||||
if ( i > 0 ) {
|
||||
sb << separator;
|
||||
}
|
||||
sb << rules_[ i ];
|
||||
}
|
||||
return sb;
|
||||
}
|
||||
|
||||
|
||||
/*= T_SRDParserDefs ==========================================================*/
|
||||
|
||||
T_SRDParserDefs::T_SRDParserDefs( T_String defaultContext )
|
||||
: dfCtx_( std::move( defaultContext ) ) ,
|
||||
ctx_( []( T_SRDContext const& c ) -> T_String const& {
|
||||
return c.name( );
|
||||
} , 64 , 64 , 64 ) ,
|
||||
enums_( []( T_SRDEnum const& e ) -> T_String const& {
|
||||
return e.name( );
|
||||
} , 64 , 64 , 64 )
|
||||
{
|
||||
ctx_.add( T_SRDContext( dfCtx_ ) );
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
void T_SRDParserDefs::defaultContext( T_String const& name )
|
||||
{
|
||||
if ( name == dfCtx_ ) {
|
||||
return;
|
||||
}
|
||||
if ( !ctx_.contains( name ) ) {
|
||||
throw std::invalid_argument( "default context must exist" );
|
||||
}
|
||||
dfCtx_ = name;
|
||||
}
|
||||
|
||||
uint32_t T_SRDParserDefs::contextId( T_String const& name ) const
|
||||
{
|
||||
return ctx_.indexOf( name );
|
||||
}
|
||||
|
||||
T_SRDParserDefs& T_SRDParserDefs::operator<< ( SetHandler sh )
|
||||
{
|
||||
if ( sh.start ) {
|
||||
onStart_ = sh.handler;
|
||||
} else {
|
||||
onFinish_ = sh.handler;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
T_SRDContext& T_SRDParserDefs::context( T_String const& name )
|
||||
{
|
||||
if ( !ctx_.contains( name ) ) {
|
||||
ctx_.add( T_SRDContext( name ) );
|
||||
}
|
||||
return *( ctx_.get( name ) );
|
||||
}
|
||||
|
||||
T_SRDContext& T_SRDParserDefs::context( T_String const& name , T_String const& parent )
|
||||
{
|
||||
if ( !ctx_.contains( name ) ) {
|
||||
ctx_.add( T_SRDContext( name , parent ) );
|
||||
}
|
||||
|
||||
T_SRDContext& c( *( ctx_.get( name ) ) );
|
||||
if ( c.parent( ) != parent ) {
|
||||
throw std::invalid_argument( "incorrect parent name" );
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
bool T_SRDParserDefs::hasEnum( T_String const& name ) const
|
||||
{
|
||||
return enums_.contains( name );
|
||||
}
|
||||
|
||||
T_SRDEnum& T_SRDParserDefs::enumeration( T_String const& name )
|
||||
{
|
||||
if ( !enums_.contains( name ) ) {
|
||||
enums_.add( T_SRDEnum( name ) );
|
||||
}
|
||||
return *( enums_.get( name ) );
|
||||
}
|
||||
|
||||
T_SRDEnum const& T_SRDParserDefs::enumeration( T_String const& name ) const
|
||||
{
|
||||
auto eptr( enums_.get( name ) );
|
||||
if ( eptr == nullptr ) {
|
||||
throw std::invalid_argument( "unknown enum" );
|
||||
}
|
||||
return *eptr;
|
||||
}
|
231
src/SRDIO.cc
Normal file
231
src/SRDIO.cc
Normal file
|
@ -0,0 +1,231 @@
|
|||
/******************************************************************************/
|
||||
/* SRD PARSER AND PREPROCESSOR - COMMON INPUT / OUTPUT CODE *******************/
|
||||
/******************************************************************************/
|
||||
|
||||
|
||||
#include <lw/lib/SRDIO.hh>
|
||||
using namespace lw;
|
||||
|
||||
|
||||
/*= X_SRDWriterError =========================================================*/
|
||||
|
||||
char const* X_SRDWriterError::what( ) const noexcept
|
||||
{
|
||||
return msg_;
|
||||
}
|
||||
|
||||
|
||||
/*= A_SRDWriter ==============================================================*/
|
||||
|
||||
A_SRDWriter& A_SRDWriter::putList( T_SRDList const& list )
|
||||
{
|
||||
const auto sz = list.size( );
|
||||
for ( uint32_t i = 0 ; i < sz ; i ++ ) {
|
||||
putToken( list[ i ] );
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
A_SRDWriter& A_SRDWriter::putToken( T_SRDToken const& token )
|
||||
{
|
||||
switch ( token.type( ) ) {
|
||||
|
||||
case E_SRDTokenType::START:
|
||||
return startList( );
|
||||
|
||||
case E_SRDTokenType::LIST:
|
||||
startList( );
|
||||
putList( token.list( ) );
|
||||
|
||||
case E_SRDTokenType::END:
|
||||
return endList( );
|
||||
|
||||
case E_SRDTokenType::WORD:
|
||||
return putWord( token.stringValue( ) );
|
||||
|
||||
case E_SRDTokenType::VAR:
|
||||
return putVariable( token.stringValue( ) );
|
||||
|
||||
case E_SRDTokenType::STRING:
|
||||
return putString( token.stringValue( ) );
|
||||
|
||||
case E_SRDTokenType::BINARY:
|
||||
return putBinary( token.binary( ) );
|
||||
|
||||
case E_SRDTokenType::INT:
|
||||
return putInt32( int32_t( token.longValue( ) ) );
|
||||
|
||||
case E_SRDTokenType::LONG:
|
||||
return putInt64( token.longValue( ) );
|
||||
|
||||
case E_SRDTokenType::FLOAT:
|
||||
return putFloat( token.floatValue( ) );
|
||||
|
||||
case E_SRDTokenType::COMMENT:
|
||||
return putComment( token.stringValue( ) );
|
||||
|
||||
case E_SRDTokenType::FLUSH:
|
||||
return *this;
|
||||
}
|
||||
throw std::range_error( "unknown token type" );
|
||||
}
|
||||
|
||||
|
||||
/*= T_SRDListFixer ===========================================================*/
|
||||
|
||||
T_SRDListFixer::T_SRDListFixer(
|
||||
A_SRDReaderTarget& output ) noexcept
|
||||
: output_( output )
|
||||
{ }
|
||||
|
||||
void T_SRDListFixer::start(
|
||||
T_SRDErrors& errors )
|
||||
{
|
||||
listStarts_.clear( );
|
||||
output_.start( errors );
|
||||
}
|
||||
|
||||
void T_SRDListFixer::push( T_SRDErrors& errors ,
|
||||
T_SRDToken&& token )
|
||||
{
|
||||
switch ( token.type( ) ) {
|
||||
case E_SRDTokenType::START:
|
||||
listStarts_.add( token.location( ) );
|
||||
break;
|
||||
|
||||
case E_SRDTokenType::END:
|
||||
if ( listStarts_.size( ) == 0 ) {
|
||||
errors.add( "unexpected end of list" , token.location( ) );
|
||||
return;
|
||||
}
|
||||
listStarts_.remove( listStarts_.size( ) - 1 );
|
||||
break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
output_.push( errors , std::move( token ) );
|
||||
}
|
||||
|
||||
void T_SRDListFixer::end(
|
||||
T_SRDErrors& errors )
|
||||
{
|
||||
const auto nls( listStarts_.size( ) );
|
||||
const T_String eolLoc( T_String::Pooled( "*unterminated list*" ) );
|
||||
for ( auto i = 0u ; i < nls ; i ++ ) {
|
||||
errors.add( "unterminated list" , listStarts_[ i ] );
|
||||
auto tok( T_SRDToken::ListEnd( ) );
|
||||
tok.location( eolLoc , nls - i - 1 );
|
||||
output_.push( errors , std::move( tok ) );
|
||||
}
|
||||
output_.end( errors );
|
||||
}
|
||||
|
||||
|
||||
/*= T_SRDMemoryTarget ========================================================*/
|
||||
|
||||
T_SRDMemoryTarget::T_SRDMemoryTarget( bool structured )
|
||||
: structured_( structured ) ,
|
||||
clearFlushToken_( false ) ,
|
||||
list_( T_SRDToken::List( T_SRDList( ) ) ) ,
|
||||
stack_( 128 )
|
||||
{ }
|
||||
|
||||
void T_SRDMemoryTarget::start( T_SRDErrors& )
|
||||
{
|
||||
list_.list( ) = T_SRDList( );
|
||||
current_ = &list_;
|
||||
}
|
||||
|
||||
void T_SRDMemoryTarget::push( T_SRDErrors& errors , T_SRDToken&& token )
|
||||
{
|
||||
assert( current_ != nullptr );
|
||||
|
||||
const auto tt( token.type( ) );
|
||||
if ( tt == E_SRDTokenType::START ) {
|
||||
if ( structured_ ) {
|
||||
auto& c( current_->list( ) );
|
||||
c.add( T_SRDToken::List( T_SRDList( ) ) );
|
||||
|
||||
auto& t( c[ c.size( ) - 1 ] );
|
||||
t.copyLocationOf( token );
|
||||
|
||||
stack_.add( current_ );
|
||||
current_ = &t;
|
||||
} else {
|
||||
auto& l( current_->list( ) );
|
||||
l.add( std::move( token ) );
|
||||
stack_.add( &( l[ l.size( ) - 1 ] ) );
|
||||
}
|
||||
|
||||
} else if ( tt == E_SRDTokenType::END ) {
|
||||
if ( stack_.size( ) == 0 ) {
|
||||
errors.add( "unexpected ')'" , token );
|
||||
} else {
|
||||
const auto last = stack_.size( ) - 1;
|
||||
if ( structured_ ) {
|
||||
current_ = stack_[ last ];
|
||||
} else {
|
||||
current_->list( ).add( std::move( token ) );
|
||||
}
|
||||
stack_.remove( last );
|
||||
}
|
||||
|
||||
} else if ( tt != E_SRDTokenType::FLUSH || !clearFlushToken_ ) {
|
||||
current_->list( ).add( std::move( token ) );
|
||||
}
|
||||
}
|
||||
|
||||
void T_SRDMemoryTarget::end( T_SRDErrors& errors )
|
||||
{
|
||||
const auto stackSize( stack_.size( ) );
|
||||
if ( stackSize != 0 ) {
|
||||
try {
|
||||
const uint32_t start( structured_ ? 1 : 0 );
|
||||
for ( uint32_t i = start ; i < stackSize ; i ++ ) {
|
||||
errors.add( "unterminated list" ,
|
||||
*stack_[ i ] );
|
||||
}
|
||||
if ( structured_ ) {
|
||||
errors.add( "unterminated list" , *current_ );
|
||||
}
|
||||
} catch ( ... ) {
|
||||
stack_.free( );
|
||||
throw;
|
||||
}
|
||||
}
|
||||
stack_.free( );
|
||||
}
|
||||
|
||||
|
||||
/*= T_SRDWriterTarget ========================================================*/
|
||||
|
||||
T_SRDWriterTarget::T_SRDWriterTarget( A_SRDWriter& writer )
|
||||
: writer_( writer )
|
||||
{ }
|
||||
|
||||
void T_SRDWriterTarget::start( T_SRDErrors& errors )
|
||||
{
|
||||
try {
|
||||
writer_.start( );
|
||||
} catch ( X_SRDWriterError const& e ) {
|
||||
errors.add( e.what( ) , T_SRDLocation( ) );
|
||||
}
|
||||
}
|
||||
|
||||
void T_SRDWriterTarget::push( T_SRDErrors& errors , T_SRDToken&& token )
|
||||
{
|
||||
try {
|
||||
writer_.putToken( token );
|
||||
} catch ( X_SRDWriterError const& e ) {
|
||||
errors.add( e.what( ) , token );
|
||||
}
|
||||
}
|
||||
|
||||
void T_SRDWriterTarget::end( T_SRDErrors& errors )
|
||||
{
|
||||
try {
|
||||
writer_.end( );
|
||||
} catch ( X_SRDWriterError const& e ) {
|
||||
errors.add( e.what( ) , T_SRDLocation( ) );
|
||||
}
|
||||
}
|
2518
src/SRDPPCommands.cc
Normal file
2518
src/SRDPPCommands.cc
Normal file
File diff suppressed because it is too large
Load diff
686
src/SRDParser.cc
Normal file
686
src/SRDParser.cc
Normal file
|
@ -0,0 +1,686 @@
|
|||
/******************************************************************************/
|
||||
/* SRD PARSER AND PREPROCESSOR - PARSER ***************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
|
||||
#include <lw/lib/SRDParser.hh>
|
||||
using namespace lw;
|
||||
|
||||
|
||||
/*= T_SRDParserData ==========================================================*/
|
||||
|
||||
T_SRDParserData::T_SRDParserData(
|
||||
T_SRDParserConfig const& config ,
|
||||
T_SRDErrors& errors )
|
||||
: config( config ) , errors( errors )
|
||||
{ }
|
||||
|
||||
|
||||
/*= T_SRDParserPrivate_ ======================================================*/
|
||||
|
||||
namespace {
|
||||
struct T_SRDParserPrivate_
|
||||
{
|
||||
// T_State_ - Internal state information
|
||||
struct T_State_
|
||||
{
|
||||
// Current context
|
||||
uint32_t context;
|
||||
// Are we parsing a rule ?
|
||||
bool inRule;
|
||||
// Rule start location
|
||||
T_SRDLocation ruleStart;
|
||||
// Current state
|
||||
uint32_t state;
|
||||
// Current depth (in-rule)
|
||||
uint32_t depth;
|
||||
// Last rule list output
|
||||
SP_SRDList list;
|
||||
// List/context ambiguity resolution - initial state ID
|
||||
uint32_t lcarState = T_SRDParserConfig::INVALID_END;
|
||||
// List/context ambiguity resolution - tokens to replay
|
||||
SP_SRDList lcarReplay;
|
||||
};
|
||||
|
||||
// E_ESAction_ - Stack actions for the execution
|
||||
enum class E_ESAction_
|
||||
{
|
||||
NONE ,
|
||||
PUSH ,
|
||||
POP
|
||||
};
|
||||
|
||||
// T_Exec_ - Execution list entry
|
||||
struct T_Exec_
|
||||
{
|
||||
// Handler to call
|
||||
F_SRDHandler handler;
|
||||
// Name of the current context
|
||||
T_String currentContext;
|
||||
// Data that matched the rule
|
||||
SP_SRDList input;
|
||||
// Name of the target context
|
||||
T_String targetContext;
|
||||
// Execution data stack action
|
||||
E_ESAction_ stackAction;
|
||||
|
||||
T_Exec_( F_SRDHandler const& handler , T_String const& currentContext );
|
||||
T_Exec_( F_SRDHandler const& handler , T_String const& currentContext , SP_SRDList input );
|
||||
T_Exec_( F_SRDHandler const& handler , T_String const& currentContext , SP_SRDList input ,
|
||||
T_String const& targetContext , E_ESAction_ stackAction );
|
||||
};
|
||||
|
||||
// E_Recovery_ - Error recovery mode
|
||||
enum class E_Recovery_
|
||||
{
|
||||
NONE ,
|
||||
SOL ,
|
||||
EOL ,
|
||||
LIST
|
||||
};
|
||||
|
||||
// Parser configuration data
|
||||
T_SRDParserConfig const& cfg_;
|
||||
// Current state
|
||||
T_State_ current_;
|
||||
// Memory target for accumulation of input
|
||||
T_SRDMemoryTarget accum_;
|
||||
// State stack, changed when entering / exiting contexts
|
||||
T_Array< T_State_ > stack_;
|
||||
// Current error recovery mode
|
||||
E_Recovery_ recovery_;
|
||||
|
||||
// Flush mode
|
||||
E_SRDFlushMode flushMode_;
|
||||
// Accept flush tokens?
|
||||
bool handleFlushTokens_;
|
||||
// Execution list
|
||||
T_Array< T_Exec_ > exec_;
|
||||
// Execution stack
|
||||
T_Array< T_Variant > execStack_;
|
||||
// Current execution data, if any
|
||||
OP_SRDParserData execData_;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
explicit T_SRDParserPrivate_( T_SRDParserConfig const& cfg );
|
||||
|
||||
// Add a token's description to a string builder
|
||||
static void addDescription( T_StringBuilder & sb ,
|
||||
T_SRDToken const& token );
|
||||
// Flush the list/context ambiguity resolution data to the accumulator
|
||||
void flushLCARReplay( T_SRDErrors& errors );
|
||||
// End the current input list
|
||||
void endList( T_SRDErrors & errors );
|
||||
// Add a match error caused by a specific token
|
||||
void addMatchError( T_SRDErrors & errors ,
|
||||
T_SRDToken const& token ) const;
|
||||
// Enter a context
|
||||
void enterContext( T_SRDErrors& errors , uint32_t endId ,
|
||||
uint32_t ctxId ,
|
||||
T_SRDLocation const& startLocation );
|
||||
|
||||
// Handle error recovery if necessary
|
||||
bool handleRecovery( T_SRDToken const& token );
|
||||
// Check for rules starting
|
||||
void checkRuleStart( T_SRDErrors & errors , T_SRDToken const& token );
|
||||
// Check for rules ending
|
||||
bool checkRuleEnd( T_SRDErrors & errors , T_SRDToken const& token ,
|
||||
uint32_t eid );
|
||||
|
||||
// Get the data at the top of the execution stack
|
||||
T_Variant const& getExecStackTop( ) const;
|
||||
|
||||
// Public methods
|
||||
void start( T_SRDErrors & errors );
|
||||
void push( T_SRDErrors & errors , T_SRDToken && token );
|
||||
void end( T_SRDErrors & errors );
|
||||
void flush( );
|
||||
};
|
||||
} // namespace
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
T_SRDParserPrivate_::T_Exec_::T_Exec_(
|
||||
F_SRDHandler const& handler ,
|
||||
T_String const& currentContext )
|
||||
: handler( handler ) , currentContext( currentContext ) ,
|
||||
stackAction( E_ESAction_::NONE )
|
||||
{ }
|
||||
|
||||
T_SRDParserPrivate_::T_Exec_::T_Exec_(
|
||||
F_SRDHandler const& handler ,
|
||||
T_String const& currentContext ,
|
||||
SP_SRDList input )
|
||||
: handler( handler ) , currentContext( currentContext ) ,
|
||||
input( input ) , stackAction( E_ESAction_::NONE )
|
||||
{ }
|
||||
|
||||
T_SRDParserPrivate_::T_Exec_::T_Exec_(
|
||||
F_SRDHandler const& handler ,
|
||||
T_String const& currentContext ,
|
||||
SP_SRDList input ,
|
||||
T_String const& targetContext ,
|
||||
E_ESAction_ stackAction )
|
||||
: handler( handler ) , currentContext( currentContext ) ,
|
||||
input( input ) , targetContext( targetContext ) ,
|
||||
stackAction( stackAction )
|
||||
{ }
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
inline T_SRDParserPrivate_::T_SRDParserPrivate_(
|
||||
T_SRDParserConfig const& cfg )
|
||||
: cfg_( cfg ) , stack_( 16 ) , flushMode_( E_SRDFlushMode::END ) ,
|
||||
handleFlushTokens_( false ) , execStack_( 16 )
|
||||
{ }
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
void T_SRDParserPrivate_::flushLCARReplay( T_SRDErrors& errors )
|
||||
{
|
||||
auto& list( *current_.lcarReplay );
|
||||
const auto size( list.size( ) );
|
||||
for ( uint32_t i = 0 ; i < size ; i ++ ) {
|
||||
accum_.push( errors , std::move( list[ i ] ) );
|
||||
}
|
||||
}
|
||||
|
||||
void T_SRDParserPrivate_::endList( T_SRDErrors& errors )
|
||||
{
|
||||
if ( current_.lcarReplay ) {
|
||||
flushLCARReplay( errors );
|
||||
current_.lcarReplay = SP_SRDList( );
|
||||
}
|
||||
accum_.end( errors );
|
||||
current_.list = NewShared< T_SRDList >( accum_.list( ) );
|
||||
}
|
||||
|
||||
void T_SRDParserPrivate_::addDescription( T_StringBuilder& sb , T_SRDToken const& token )
|
||||
{
|
||||
auto tt( token.type( ) );
|
||||
switch ( tt ) {
|
||||
|
||||
case E_SRDTokenType::WORD:
|
||||
sb << '\'' << token.stringValue( ) << '\'';
|
||||
break;
|
||||
|
||||
case E_SRDTokenType::START:
|
||||
sb << "'('";
|
||||
break;
|
||||
|
||||
case E_SRDTokenType::END:
|
||||
sb << "')'";
|
||||
break;
|
||||
|
||||
default:
|
||||
sb << token.type( ) << " token";
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void T_SRDParserPrivate_::addMatchError( T_SRDErrors& errors , T_SRDToken const& token ) const
|
||||
{
|
||||
const auto nTrans( cfg_.transitions.sizeOf( current_.state ) );
|
||||
const auto eid( cfg_.endStates[ current_.state ] );
|
||||
|
||||
T_StringBuilder sb;
|
||||
if ( nTrans == 0 ) {
|
||||
assert( eid != T_SRDParserConfig::INVALID_END );
|
||||
const auto nctx( cfg_.ruleContexts[ eid ] );
|
||||
if ( nctx != T_SRDParserConfig::INVALID_END ) {
|
||||
sb << "'(' or ";
|
||||
}
|
||||
sb << "')'";
|
||||
|
||||
} else {
|
||||
if ( eid != T_SRDParserConfig::INVALID_END ) {
|
||||
const auto nctx( cfg_.ruleContexts[ eid ] );
|
||||
if ( nctx != T_SRDParserConfig::INVALID_END ) {
|
||||
sb << "'(', ";
|
||||
}
|
||||
sb << "')'";
|
||||
if ( nTrans > 1 ) {
|
||||
sb << ", ";
|
||||
} else {
|
||||
sb << " or ";
|
||||
}
|
||||
}
|
||||
|
||||
for ( uint32_t i = 0 ; i < nTrans ; i ++ ) {
|
||||
auto const& t( cfg_.transitions.get( current_.state , i ) );
|
||||
if ( t.type == E_SRDTransitionType::WORD ) {
|
||||
sb << '\'' << cfg_.words[ t.index ] << '\'';
|
||||
} else if ( t.type == E_SRDTransitionType::ENUM ) {
|
||||
sb << '\'' << cfg_.enums[ t.index ].name( )
|
||||
<< "' enum value";
|
||||
} else {
|
||||
sb << t.tokenType << " token";
|
||||
}
|
||||
if ( i + 2 < nTrans ) {
|
||||
sb << ", ";
|
||||
} else if ( i + 1 < nTrans ) {
|
||||
sb << " or ";
|
||||
}
|
||||
}
|
||||
}
|
||||
sb << " expected, ";
|
||||
addDescription( sb , token );
|
||||
sb << " found instead.";
|
||||
errors.add( sb , token );
|
||||
}
|
||||
|
||||
void T_SRDParserPrivate_::enterContext( T_SRDErrors& errors , uint32_t endId , uint32_t ctxId ,
|
||||
T_SRDLocation const& startLocation )
|
||||
{
|
||||
endList( errors );
|
||||
|
||||
auto const& cctx( cfg_.contexts[ current_.context ] );
|
||||
auto const& rule( cctx.rules( )[ endId ] );
|
||||
auto const& nctx( cfg_.contexts[ ctxId ] );
|
||||
if ( rule.onEnter( ) ) {
|
||||
const auto action( rule.onExit( )
|
||||
? E_ESAction_::PUSH
|
||||
: E_ESAction_::NONE );
|
||||
exec_.addNew( rule.onEnter( ) , cctx.name( ) ,
|
||||
current_.list , nctx.name( ) ,
|
||||
action );
|
||||
}
|
||||
|
||||
stack_.add( std::move( current_ ) );
|
||||
|
||||
current_.context = ctxId;
|
||||
current_.inRule = true;
|
||||
current_.state = cfg_.startStates[ ctxId ];
|
||||
current_.depth = 0;
|
||||
current_.ruleStart = startLocation;
|
||||
|
||||
accum_.start( errors );
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
bool T_SRDParserPrivate_::handleRecovery( T_SRDToken const& token )
|
||||
{
|
||||
const auto tt( token.type( ) );
|
||||
|
||||
switch ( recovery_ ) {
|
||||
|
||||
case E_Recovery_::NONE:
|
||||
return true;
|
||||
|
||||
case E_Recovery_::SOL:
|
||||
// Wait for '(', process it
|
||||
if ( tt == E_SRDTokenType::START ) {
|
||||
recovery_ = E_Recovery_::NONE;
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
case E_Recovery_::EOL:
|
||||
// Wait for the required ')'. Don't process it.
|
||||
if ( tt == E_SRDTokenType::START ) {
|
||||
current_.depth ++;
|
||||
} else if ( tt == E_SRDTokenType::END ) {
|
||||
if ( current_.depth == 0 ) {
|
||||
current_.inRule = false;
|
||||
recovery_ = E_Recovery_::NONE;
|
||||
} else {
|
||||
current_.depth --;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case E_Recovery_::LIST:
|
||||
// Process both '(' and ')'
|
||||
if ( tt == E_SRDTokenType::START || tt == E_SRDTokenType::END ) {
|
||||
recovery_ = E_Recovery_::NONE;
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
throw std::logic_error( "invalid error recovery state" );
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void T_SRDParserPrivate_::checkRuleStart( T_SRDErrors& errors , T_SRDToken const& token )
|
||||
{
|
||||
const auto tt( token.type( ) );
|
||||
const auto ss( stack_.size( ) );
|
||||
if ( tt == E_SRDTokenType::START ) {
|
||||
// Entering a rule
|
||||
current_.inRule = true;
|
||||
current_.state = cfg_.startStates[ current_.context ];
|
||||
current_.depth = 0;
|
||||
current_.ruleStart = token.location( );
|
||||
accum_.start( errors );
|
||||
|
||||
} else if ( ss != 0 && tt == E_SRDTokenType::END ) {
|
||||
// Exiting a context
|
||||
const auto oldCtx( current_.context );
|
||||
current_ = std::move( stack_[ ss - 1 ] );
|
||||
stack_.remove( ss - 1 );
|
||||
|
||||
const auto eid( cfg_.endStates[ current_.state ] );
|
||||
auto const& cctx( cfg_.contexts[ current_.context ] );
|
||||
auto const& rule( cctx.rules( )[ eid ] );
|
||||
auto const& octx( cfg_.contexts[ oldCtx ] );
|
||||
|
||||
if ( rule.onExit( ) ) {
|
||||
const auto action( rule.onEnter( )
|
||||
? E_ESAction_::POP
|
||||
: E_ESAction_::NONE );
|
||||
exec_.addNew( rule.onExit( ) , octx.name( ) ,
|
||||
current_.list , cctx.name( ) ,
|
||||
action );
|
||||
}
|
||||
if ( rule.handler( ) ) {
|
||||
exec_.addNew( rule.handler( ) , cctx.name( ) , current_.list );
|
||||
}
|
||||
|
||||
if ( flushMode_ == E_SRDFlushMode::SENTENCE
|
||||
&& stack_.size( ) == 0 ) {
|
||||
flush( );
|
||||
}
|
||||
|
||||
current_.inRule = false;
|
||||
|
||||
} else {
|
||||
T_StringBuilder sb( "'(' " );
|
||||
if ( ss == 0 ) {
|
||||
recovery_ = E_Recovery_::SOL;
|
||||
} else {
|
||||
sb << "or ')' ";
|
||||
recovery_ = E_Recovery_::LIST;
|
||||
}
|
||||
sb << "expected, ";
|
||||
addDescription( sb , token );
|
||||
sb << " found instead.";
|
||||
errors.add( sb , token );
|
||||
}
|
||||
}
|
||||
|
||||
bool T_SRDParserPrivate_::checkRuleEnd( T_SRDErrors& errors , T_SRDToken const& token , uint32_t eid )
|
||||
{
|
||||
const auto tt( token.type( ) );
|
||||
if ( tt == E_SRDTokenType::END ) {
|
||||
endList( errors );
|
||||
|
||||
auto const& cctx( cfg_.contexts[ current_.context ] );
|
||||
auto const& rule( cctx.rules( )[ eid ] );
|
||||
if ( rule.handler( ) ) {
|
||||
exec_.addNew( rule.handler( ) , cctx.name( ) , current_.list );
|
||||
}
|
||||
|
||||
current_.inRule = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( tt != E_SRDTokenType::START ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto cid( cfg_.ruleContexts.get( current_.context , eid ) );
|
||||
if ( cid == T_SRDParserConfig::INVALID_END ) {
|
||||
return false;
|
||||
}
|
||||
enterContext( errors , eid , cid , token.location( ) );
|
||||
return true;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
inline T_Variant const& T_SRDParserPrivate_::getExecStackTop( ) const
|
||||
{
|
||||
assert( execStack_.size( ) != 0 );
|
||||
const auto stackLast( execStack_.size( ) - 1 );
|
||||
return execStack_[ stackLast ];
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
inline void T_SRDParserPrivate_::start( T_SRDErrors& errors )
|
||||
{
|
||||
execData_ = NewOwned< T_SRDParserData >( cfg_ , errors );
|
||||
execStack_.clear( );
|
||||
execStack_.addNew( );
|
||||
exec_.clear( );
|
||||
if ( cfg_.onStart ) {
|
||||
auto const& dc( cfg_.contexts[ 0 ] );
|
||||
exec_.addNew( cfg_.onStart , dc.name( ) );
|
||||
if ( flushMode_ == E_SRDFlushMode::SENTENCE ) {
|
||||
flush( );
|
||||
}
|
||||
}
|
||||
|
||||
stack_.clear( );
|
||||
current_.context = 0;
|
||||
current_.inRule = false;
|
||||
recovery_ = E_Recovery_::NONE;
|
||||
}
|
||||
|
||||
inline void T_SRDParserPrivate_::push( T_SRDErrors& errors , T_SRDToken&& token )
|
||||
{
|
||||
const auto tt( token.type( ) );
|
||||
if ( tt == E_SRDTokenType::FLUSH ) {
|
||||
if ( handleFlushTokens_ ) {
|
||||
flush( );
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if ( tt == E_SRDTokenType::COMMENT || !handleRecovery( token ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( !current_.inRule ) {
|
||||
checkRuleStart( errors , token );
|
||||
return;
|
||||
}
|
||||
|
||||
const auto prevState( current_.state );
|
||||
const auto eid( cfg_.endStates[ prevState ] );
|
||||
if ( cfg_.transition( current_.state , token ) ) {
|
||||
// Handling of list/context ambiguities
|
||||
if ( tt == E_SRDTokenType::START && eid != T_SRDParserConfig::INVALID_END ) {
|
||||
assert( current_.depth == 0 );
|
||||
const auto cid( cfg_.ruleContexts.get( current_.context , eid ) );
|
||||
if ( cid != T_SRDParserConfig::INVALID_END ) {
|
||||
current_.lcarState = prevState;
|
||||
if ( current_.lcarReplay ) {
|
||||
flushLCARReplay( errors );
|
||||
current_.lcarReplay->clear( );
|
||||
} else {
|
||||
current_.lcarReplay = NewShared< T_SRDList >( 16 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle depth
|
||||
if ( tt == E_SRDTokenType::START ) {
|
||||
current_.depth ++;
|
||||
} else if ( tt == E_SRDTokenType::END ) {
|
||||
assert( current_.depth != 0 );
|
||||
current_.depth --;
|
||||
}
|
||||
|
||||
// Accumulate token
|
||||
if ( current_.lcarState == T_SRDParserConfig::INVALID_END ) {
|
||||
accum_.push( errors , std::move( token ) );
|
||||
} else {
|
||||
current_.lcarReplay->add( std::move( token ) );
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Check for "normal" end of rule
|
||||
if ( current_.depth == 0 && eid != T_SRDParserConfig::INVALID_END
|
||||
&& checkRuleEnd( errors , token , eid ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If we had found a list/context ambiguity, enter the context then
|
||||
// replay what we had.
|
||||
if ( current_.lcarState != T_SRDParserConfig::INVALID_END ) {
|
||||
auto lcarState( current_.lcarState );
|
||||
auto lcarEnd( cfg_.endStates[ lcarState ] );
|
||||
auto lcarContext( cfg_.ruleContexts.get( current_.context , lcarEnd ) );
|
||||
SP_SRDList replay( std::move( current_.lcarReplay ) );
|
||||
current_.lcarState = T_SRDParserConfig::INVALID_END;
|
||||
current_.state = lcarState;
|
||||
|
||||
const auto nTokens( replay->size( ) );
|
||||
enterContext( errors , lcarEnd , lcarContext , (*replay)[ 0 ].location( ) );
|
||||
for ( uint32_t i = 1 ; i < nTokens ; i ++ ) {
|
||||
push( errors , std::move( (*replay)[ i ] ) );
|
||||
}
|
||||
push( errors , std::move( token ) );
|
||||
return;
|
||||
}
|
||||
|
||||
addMatchError( errors , token );
|
||||
if ( token.type( ) == E_SRDTokenType::END ) {
|
||||
if ( current_.depth == 0 ) {
|
||||
// Don't go into recovery mode
|
||||
current_.inRule = false;
|
||||
return;
|
||||
}
|
||||
current_.depth --;
|
||||
}
|
||||
recovery_ = E_Recovery_::EOL;
|
||||
}
|
||||
|
||||
inline void T_SRDParserPrivate_::end( T_SRDErrors& errors )
|
||||
{
|
||||
const auto ss( stack_.size( ) );
|
||||
for ( uint32_t i = 0 ; i < ss ; i ++ ) {
|
||||
auto const& si( stack_[ i ] );
|
||||
errors.add( "Unterminated list." , si.ruleStart );
|
||||
}
|
||||
if ( current_.inRule ) {
|
||||
errors.add( "Unterminated list." , current_.ruleStart );
|
||||
}
|
||||
|
||||
if ( cfg_.onFinish ) {
|
||||
auto const& dc( cfg_.contexts[ 0 ] );
|
||||
exec_.addNew( cfg_.onFinish , dc.name( ) );
|
||||
}
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
void T_SRDParserPrivate_::flush( )
|
||||
{
|
||||
const auto nExec( exec_.size( ) );
|
||||
if ( !nExec ) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto& data( *execData_ );
|
||||
if ( data.errors.size( ) != 0 ) {
|
||||
exec_.clear( );
|
||||
return;
|
||||
}
|
||||
|
||||
bool enabled = true;
|
||||
for ( uint32_t i = 0 ; i < nExec ; i ++ ) {
|
||||
auto const& step( exec_[ i ] );
|
||||
|
||||
if ( step.stackAction == E_ESAction_::PUSH && enabled ) {
|
||||
execStack_.addNew( );
|
||||
}
|
||||
|
||||
const auto stackLast( execStack_.size( ) - 1 );
|
||||
if ( enabled ) {
|
||||
data.input = RPC_SRDList( step.input );
|
||||
data.currentContext = step.currentContext;
|
||||
data.targetContext = step.targetContext;
|
||||
|
||||
if ( step.stackAction == E_ESAction_::PUSH ) {
|
||||
data.currentData = &execStack_[ stackLast - 1 ];
|
||||
data.targetData = &execStack_[ stackLast ];
|
||||
} else {
|
||||
data.currentData = &execStack_[ stackLast ];
|
||||
if ( step.stackAction == E_ESAction_::POP ) {
|
||||
data.targetData = &execStack_[ stackLast - 1 ];
|
||||
}
|
||||
}
|
||||
|
||||
enabled = step.handler( data );
|
||||
enabled = enabled && data.errors.size( ) == 0;
|
||||
}
|
||||
|
||||
if ( step.stackAction == E_ESAction_::POP
|
||||
&& ( enabled || stackLast > 0 ) ) {
|
||||
execStack_.remove( stackLast );
|
||||
}
|
||||
}
|
||||
exec_.clear( );
|
||||
}
|
||||
|
||||
|
||||
/*= T_SRDParser ==============================================================*/
|
||||
|
||||
T_SRDParser::T_SRDParser( T_SRDParserConfig const& cfg )
|
||||
: A_PrivateImplementation( new T_SRDParserPrivate_( cfg ) )
|
||||
{ }
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
void T_SRDParser::start( T_SRDErrors& errors )
|
||||
{
|
||||
p< T_SRDParserPrivate_ >( ).start( errors );
|
||||
}
|
||||
|
||||
void T_SRDParser::push( T_SRDErrors& errors , T_SRDToken&& token )
|
||||
{
|
||||
p< T_SRDParserPrivate_ >( ).push( errors , std::move( token ) );
|
||||
}
|
||||
|
||||
void T_SRDParser::end( T_SRDErrors& errors )
|
||||
{
|
||||
auto& pi( p< T_SRDParserPrivate_ >( ) );
|
||||
pi.end( errors );
|
||||
if ( pi.flushMode_ != E_SRDFlushMode::MANUAL ) {
|
||||
pi.flush( );
|
||||
}
|
||||
}
|
||||
|
||||
void T_SRDParser::flush( )
|
||||
{
|
||||
p< T_SRDParserPrivate_ >( ).flush( );
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
void T_SRDParser::flushMode(
|
||||
const E_SRDFlushMode mode ) noexcept
|
||||
{
|
||||
p< T_SRDParserPrivate_ >( ).flushMode_ = mode;
|
||||
}
|
||||
|
||||
E_SRDFlushMode T_SRDParser::flushMode( ) const noexcept
|
||||
{
|
||||
return p< T_SRDParserPrivate_ >( ).flushMode_;
|
||||
}
|
||||
|
||||
void T_SRDParser::handleFlushToken( bool handleIt ) noexcept
|
||||
{
|
||||
p< T_SRDParserPrivate_ >( ).handleFlushTokens_ = handleIt;
|
||||
}
|
||||
|
||||
bool T_SRDParser::handleFlushToken( ) const noexcept
|
||||
{
|
||||
return p< T_SRDParserPrivate_ >( ).handleFlushTokens_;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
T_Variant const& T_SRDParser::getExecStackTop( ) const
|
||||
{
|
||||
return p< T_SRDParserPrivate_ >( ).getExecStackTop( );
|
||||
}
|
982
src/SRDParserConfig.cc
Normal file
982
src/SRDParserConfig.cc
Normal file
|
@ -0,0 +1,982 @@
|
|||
/******************************************************************************/
|
||||
/* SRD - PARSER CONFIGURATION *************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
#include <lw/lib/SRDParserConfig.hh>
|
||||
using namespace lw;
|
||||
|
||||
namespace {
|
||||
|
||||
|
||||
/*= TEMPORARY CONVERSION DATA ================================================*/
|
||||
|
||||
// E_NodeType_ - Node types for the intermediary RE representation
|
||||
enum class E_NodeType_
|
||||
{ CAT , ALT , STAR , SYM , EPS };
|
||||
|
||||
|
||||
// E_SymNodeType_ - Symbol types for the intermediary RE representation
|
||||
// This includes END symbols, which are not present in the actual
|
||||
// configuration.
|
||||
enum class E_SymNodeType_
|
||||
{ WORD , ENUM , TOKEN , END };
|
||||
|
||||
|
||||
// T_RuleNode_ - A node in the intermediary RE tree
|
||||
struct T_RuleNode_
|
||||
{
|
||||
uint32_t index;
|
||||
E_NodeType_ type;
|
||||
uint32_t left;
|
||||
uint32_t right;
|
||||
uint32_t label = -1;
|
||||
};
|
||||
|
||||
|
||||
// T_Symbol_ - Symbol data for the intermediary representation
|
||||
struct T_Symbol_
|
||||
{
|
||||
E_SymNodeType_ type;
|
||||
uint32_t idx;
|
||||
|
||||
explicit T_Symbol_( T_RuleNode_ const& node )
|
||||
: type( E_SymNodeType_( node.left ) ) ,
|
||||
idx( node.right )
|
||||
{ }
|
||||
};
|
||||
|
||||
|
||||
// T_RuleSource_ - Initial context and rule indices
|
||||
struct T_RuleSource_
|
||||
{
|
||||
uint32_t context;
|
||||
uint32_t rule;
|
||||
|
||||
T_RuleSource_( uint32_t context , uint32_t rule )
|
||||
: context( context ) , rule( rule )
|
||||
{ }
|
||||
};
|
||||
|
||||
|
||||
// T_ContextConverter_ - Definitions to configuration converter
|
||||
struct T_ContextConverter_
|
||||
{
|
||||
typedef T_Array< T_SRDInputItem > T_InSeq_;
|
||||
typedef T_Array< T_RuleNode_ > T_Nodes_;
|
||||
|
||||
T_SRDParserConfig& cfg;
|
||||
T_SRDParserDefs const& defs;
|
||||
|
||||
// Data used to transform definition contexts into actual contexts
|
||||
T_Array< uint32_t > usedContexts;
|
||||
T_MultiArray< T_RuleSource_ > ruleSources;
|
||||
|
||||
// Current context & rule
|
||||
uint32_t cid;
|
||||
uint32_t curRule;
|
||||
|
||||
// RE representation of a context's rules
|
||||
T_Nodes_ nodes;
|
||||
T_Array< uint32_t > symNodes;
|
||||
uint32_t maxLabel;
|
||||
|
||||
// Automaton construction internals
|
||||
T_Array< bool > cancellable;
|
||||
T_MultiArray< uint32_t > firstPos;
|
||||
T_MultiArray< uint32_t > lastPos;
|
||||
T_MultiArray< uint32_t > nextPos;
|
||||
T_Array< uint32_t > nameAccum;
|
||||
T_MultiArray< uint32_t > stateNames;
|
||||
|
||||
// "Alphabet" for a set of rules
|
||||
T_Array< T_Symbol_ > symbols;
|
||||
T_MultiArray< uint32_t > symLabels;
|
||||
|
||||
|
||||
T_ContextConverter_( T_SRDParserConfig& cfg , T_SRDParserDefs const& defs );
|
||||
|
||||
// Go through all rules to check for unbalanced lists
|
||||
void checkUnbalancedRules( ) const;
|
||||
// Unbalanced list check - sequence
|
||||
int checkUBSequence( T_String const& ctx , uint32_t cRule , T_InSeq_ const& sequence ) const;
|
||||
// Unbalanced list check - alternatives
|
||||
int checkUBAlternatives( T_String const& ctx , uint32_t cRule , T_InSeq_ const& alternatives ) const;
|
||||
// Unbalanced list check - single item
|
||||
int checkUBItem( T_String const& ctx , uint32_t cRule , T_SRDInputItem const& item ) const;
|
||||
// Unbalanced list check - throw the error
|
||||
void errorUnbalanced( T_String const& ctx , uint32_t cRule ) const;
|
||||
|
||||
// Find all contexts that are used by another; also check inheritance
|
||||
void findUsedContexts( );
|
||||
// Build the context for the parser's configuration, including parents
|
||||
void buildContext( uint32_t context );
|
||||
// Add a context to the list of contexts to copy
|
||||
void addUsedContext( T_String const& current , uint32_t cRule , T_String const& next );
|
||||
// Find all context IDs required to build a context
|
||||
int findContextsFor( uint32_t sourceContext , uint32_t* output );
|
||||
|
||||
// Add a node, set its index and type, then return it
|
||||
T_RuleNode_& addNode( E_NodeType_ type );
|
||||
// Add a symbol node
|
||||
T_RuleNode_& addSymbolNode( E_SymNodeType_ type , uint32_t idx );
|
||||
// Add a word node. If the word is not in the words index, add it there.
|
||||
T_RuleNode_& addWord( T_String const& word );
|
||||
// Add an enumeration node.
|
||||
T_RuleNode_& addEnum( T_String const& eName );
|
||||
// Add a token node.
|
||||
T_RuleNode_& addToken( E_SRDTokenType token );
|
||||
// Add a branch that represents alternatives
|
||||
T_RuleNode_& addAlternatives( T_InSeq_ const& alts );
|
||||
// Add a branch that represents a sequence of items, using CAT nodes
|
||||
T_RuleNode_& addSequence( T_InSeq_ const& sequence );
|
||||
// Generate a branch that represents repetitions of a sequence.
|
||||
T_RuleNode_& convertRepetitions( T_SRDInputItem const& item );
|
||||
// Convert a rule item into a tree branch
|
||||
T_RuleNode_& convertItem( T_SRDInputItem const& item );
|
||||
|
||||
// Convert all rules in the current context into a RE tree
|
||||
void convertRules( );
|
||||
|
||||
// Generate the "cancellable" value for all nodes
|
||||
void computeCancellable( );
|
||||
// Implementation for compute{First|Last}Pos
|
||||
void computePos( T_MultiArray< uint32_t >& output , bool first );
|
||||
// Generate first positions for all nodes
|
||||
void computeFirstPos( );
|
||||
// Generate last positions for all nodes
|
||||
void computeLastPos( );
|
||||
// Generate next positions for all labels
|
||||
void computeNextPos( );
|
||||
// Gather all symbols and their associated labels
|
||||
void gatherSymbols( );
|
||||
|
||||
// Set the rule index for a state
|
||||
void setEndState( uint32_t state , uint32_t end );
|
||||
// Add values from a label to the state name accumulator
|
||||
void addNameParts( uint32_t label );
|
||||
// Check symbol labels in a state name
|
||||
void checkStateName( uint32_t state , uint32_t first , uint32_t end , uint32_t si );
|
||||
// Try to find an existing state matching the accumulated name.
|
||||
// Returns T_HashIndex::INVALID_INDEX if not found.
|
||||
uint32_t findState( uint32_t firstState );
|
||||
// Add a transition
|
||||
void addTransition( T_Symbol_ const& sym , uint32_t state );
|
||||
// Build the automaton for the current context
|
||||
void buildAutomaton( );
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
/*= T_ContextConverter_ ======================================================*/
|
||||
|
||||
namespace {
|
||||
|
||||
T_ContextConverter_::T_ContextConverter_( T_SRDParserConfig& cfg , T_SRDParserDefs const& defs )
|
||||
: cfg( cfg ) , defs( defs ) , usedContexts( defs.contexts( ) )
|
||||
{ }
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
void T_ContextConverter_::checkUnbalancedRules( ) const
|
||||
{
|
||||
const auto nContexts( defs.contexts( ) );
|
||||
for ( uint32_t i = 0 ; i < nContexts ; i ++ ) {
|
||||
auto const& ctx( defs[ i ] );
|
||||
auto const& cName( ctx.name( ) );
|
||||
|
||||
auto const& rules( ctx.rules( ) );
|
||||
const auto nRules( rules.size( ) );
|
||||
for ( uint32_t j = 0 ; j < nRules ; j ++ ) {
|
||||
auto const& rule( rules[ j ] );
|
||||
if ( checkUBSequence( cName , j + 1 , rule.rule( ) ) != 0 ) {
|
||||
errorUnbalanced( cName , j + 1 );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int T_ContextConverter_::checkUBSequence( T_String const& ctx , uint32_t cRule ,
|
||||
T_InSeq_ const& sequence ) const
|
||||
{
|
||||
const auto length( sequence.size( ) );
|
||||
int sum( 0 );
|
||||
for ( uint32_t i = 0 ; i < length ; i ++ ) {
|
||||
sum += checkUBItem( ctx , cRule , sequence[ i ] );
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
int T_ContextConverter_::checkUBAlternatives( T_String const& ctx , uint32_t cRule ,
|
||||
T_InSeq_ const& alternatives ) const
|
||||
{
|
||||
const auto length( alternatives.size( ) );
|
||||
int current( 0 );
|
||||
for ( uint32_t i = 0 ; i < length ; i ++ ) {
|
||||
const int value( checkUBItem( ctx , cRule , alternatives[ i ] ) );
|
||||
if ( i == 0 ) {
|
||||
current = value;
|
||||
} else if ( value != current ) {
|
||||
errorUnbalanced( ctx , cRule );
|
||||
}
|
||||
}
|
||||
return current;
|
||||
}
|
||||
|
||||
int T_ContextConverter_::checkUBItem( T_String const& ctx , uint32_t cRule ,
|
||||
T_SRDInputItem const& item ) const
|
||||
{
|
||||
const auto iType( item.type( ) );
|
||||
switch ( iType ) {
|
||||
|
||||
case E_SRDInputItem::TOKEN:
|
||||
if ( item.token( ) == E_SRDTokenType::START ) {
|
||||
return 1;
|
||||
} else if ( item.token( ) == E_SRDTokenType::END ) {
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
|
||||
case E_SRDInputItem::ALTERNATIVE:
|
||||
return checkUBAlternatives( ctx , cRule , item.items( ) );
|
||||
|
||||
case E_SRDInputItem::REPETITION:
|
||||
{
|
||||
const int sv( checkUBSequence( ctx , cRule , item.items( ) ) );
|
||||
if ( sv != 0 && item.min( ) != item.max( ) ) {
|
||||
errorUnbalanced( ctx , cRule );
|
||||
} else {
|
||||
return sv * item.min( );
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case E_SRDInputItem::WORD:
|
||||
case E_SRDInputItem::ENUM:
|
||||
break;
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void T_ContextConverter_::errorUnbalanced( T_String const& ctx , uint32_t cRule ) const
|
||||
{
|
||||
T_StringBuilder sb;
|
||||
sb << "In context `" << ctx << "`: rule #" << cRule << " is unbalanced.";
|
||||
throw X_SRDParserConfig( sb );
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
void T_ContextConverter_::findUsedContexts( )
|
||||
{
|
||||
uint32_t pos = 0;
|
||||
usedContexts.add( defs.contextId( defs.defaultContext( ) ) );
|
||||
|
||||
while ( pos < usedContexts.size( ) ) {
|
||||
buildContext( usedContexts[ pos ] );
|
||||
pos ++;
|
||||
}
|
||||
}
|
||||
|
||||
void T_ContextConverter_::buildContext( uint32_t context )
|
||||
{
|
||||
uint32_t list[ defs.contexts( ) ];
|
||||
|
||||
const auto nContexts( findContextsFor( context , list ) );
|
||||
auto const& name( defs[ context ].name( ) );
|
||||
cfg.contexts.addNew( name );
|
||||
|
||||
auto& output( cfg.contexts[ cfg.contexts.size( ) - 1 ] );
|
||||
ruleSources.next( );
|
||||
cfg.ruleContexts.next( );
|
||||
for ( auto c = nContexts - 1 ; c >= 0 ; c -- ) {
|
||||
auto const& sCtx( defs[ list[ c ] ] );
|
||||
auto const& src( sCtx.rules( ) );
|
||||
for ( uint32_t i = 0 ; i < src.size( ) ; i ++ ) {
|
||||
ruleSources.addNew( list[ c ] , i + 1 );
|
||||
auto const& r( src[ i ] );
|
||||
output << r;
|
||||
addUsedContext( sCtx.name( ) , i + 1 , r.context( ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void T_ContextConverter_::addUsedContext( T_String const& current , uint32_t cRule , T_String const& next )
|
||||
{
|
||||
if ( !next ) {
|
||||
cfg.ruleContexts.add( T_SRDParserConfig::INVALID_END );
|
||||
return;
|
||||
}
|
||||
|
||||
const auto id( defs.contextId( next ) );
|
||||
if ( id == T_HashIndex::INVALID_INDEX ) {
|
||||
T_StringBuilder sb;
|
||||
sb << "In context `" << current << "`: rule #" << cRule
|
||||
<< " refers to missing context `" << next << "`.";
|
||||
throw X_SRDParserConfig( sb );
|
||||
}
|
||||
|
||||
for ( uint32_t i = 0 ; i < usedContexts.size( ) ; i ++ ) {
|
||||
if ( usedContexts[ i ] == id ) {
|
||||
cfg.ruleContexts.add( i );
|
||||
return;
|
||||
}
|
||||
}
|
||||
cfg.ruleContexts.add( usedContexts.size( ) );
|
||||
usedContexts.add( id );
|
||||
}
|
||||
|
||||
int T_ContextConverter_::findContextsFor( uint32_t sourceContext , uint32_t* output )
|
||||
{
|
||||
auto spos = 1;
|
||||
output[ 0 ] = sourceContext;
|
||||
|
||||
do {
|
||||
auto const& c( defs[ output[ spos - 1 ] ] );
|
||||
if ( !c.parent( ) ) {
|
||||
break;
|
||||
}
|
||||
|
||||
const auto pid( defs.contextId( c.parent( ) ) );
|
||||
if ( pid == T_HashIndex::INVALID_INDEX ) {
|
||||
T_StringBuilder sb;
|
||||
sb << "Context `" << c.name( ) << "`: unknown parent `"
|
||||
<< c.parent( ) << "`";
|
||||
throw X_SRDParserConfig( sb );
|
||||
}
|
||||
|
||||
for ( auto i = 0 ; i < spos ; i ++ ) {
|
||||
if ( output[ i ] == pid ) {
|
||||
T_StringBuilder sb;
|
||||
sb << "Context `" << c.parent( )
|
||||
<< "`: recursive inheritance";
|
||||
throw X_SRDParserConfig( sb );
|
||||
}
|
||||
}
|
||||
output[ spos ++ ] = pid;
|
||||
} while ( 1 );
|
||||
|
||||
return spos;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
T_RuleNode_& T_ContextConverter_::addNode( E_NodeType_ type )
|
||||
{
|
||||
const uint32_t index( nodes.size( ) );
|
||||
auto& node( nodes.addNew( ) );
|
||||
node.index = index;
|
||||
node.type = type;
|
||||
return node;
|
||||
}
|
||||
|
||||
T_RuleNode_& T_ContextConverter_::addSymbolNode( E_SymNodeType_ type , uint32_t idx )
|
||||
{
|
||||
auto& node( addNode( E_NodeType_::SYM ) );
|
||||
node.left = uint32_t( type );
|
||||
node.right = uint32_t( idx );
|
||||
node.label = ++ maxLabel;
|
||||
symNodes.add( node.index );
|
||||
return node;
|
||||
}
|
||||
|
||||
T_RuleNode_& T_ContextConverter_::addWord( T_String const& word )
|
||||
{
|
||||
const auto hash = ComputeHash( word );
|
||||
uint32_t idx = cfg.wordsIndex.first( hash );
|
||||
while ( idx != T_HashIndex::INVALID_INDEX ) {
|
||||
if ( cfg.words[ idx ] == word ) {
|
||||
break;
|
||||
}
|
||||
idx = cfg.wordsIndex.next( idx );
|
||||
}
|
||||
if ( idx == T_HashIndex::INVALID_INDEX ) {
|
||||
idx = cfg.words.size( );
|
||||
cfg.wordsIndex.add( hash );
|
||||
cfg.words.add( word );
|
||||
}
|
||||
|
||||
return addSymbolNode( E_SymNodeType_::WORD , idx );
|
||||
}
|
||||
|
||||
T_RuleNode_& T_ContextConverter_::addEnum( T_String const& eName )
|
||||
{
|
||||
if ( !cfg.enums.contains( eName ) ) {
|
||||
if ( !defs.hasEnum( eName ) ) {
|
||||
T_RuleSource_ const& src( ruleSources.get( cid , curRule - 1 ) );
|
||||
T_SRDContext const& sCtx( defs[ src.context ] );
|
||||
|
||||
T_StringBuilder sb;
|
||||
sb << "In context `" << sCtx.name( ) << "`: rule #"
|
||||
<< src.rule << " refers to unknown enumeration `" << eName << "`.";
|
||||
throw X_SRDParserConfig( sb );
|
||||
}
|
||||
cfg.enums.add( defs.enumeration( eName ) );
|
||||
}
|
||||
return addSymbolNode( E_SymNodeType_::ENUM ,
|
||||
cfg.enums.indexOf( eName ) );
|
||||
}
|
||||
|
||||
inline T_RuleNode_& T_ContextConverter_::addToken( E_SRDTokenType token )
|
||||
{
|
||||
return addSymbolNode( E_SymNodeType_::TOKEN , uint32_t( token ) );
|
||||
}
|
||||
|
||||
T_RuleNode_& T_ContextConverter_::addAlternatives( T_InSeq_ const& alts )
|
||||
{
|
||||
auto n( alts.size( ) );
|
||||
if ( n == 0 ) {
|
||||
T_RuleSource_ const& src( ruleSources.get( cid , curRule - 1 ) );
|
||||
T_SRDContext const& sCtx( defs[ src.context ] );
|
||||
|
||||
T_StringBuilder sb;
|
||||
sb << "In context `" << sCtx.name( ) << "`: rule #" << src.rule
|
||||
<< " features an empty alternation.";
|
||||
throw X_SRDParserConfig( sb );
|
||||
}
|
||||
|
||||
uint32_t indices[ n ];
|
||||
for ( uint32_t i = 0 ; i < n ; i ++ ) {
|
||||
auto& node( convertItem( alts[ i ] ) );
|
||||
indices[ i ] = node.index;
|
||||
}
|
||||
|
||||
uint32_t nextLeft = indices[ 0 ];
|
||||
for ( uint32_t i = 1 ; i < n ; i ++ ) {
|
||||
auto& node( addNode( E_NodeType_::ALT ) );
|
||||
node.left = nextLeft;
|
||||
node.right = indices[ i ];
|
||||
nextLeft = node.index;
|
||||
}
|
||||
|
||||
return nodes[ nextLeft ];
|
||||
}
|
||||
|
||||
T_RuleNode_& T_ContextConverter_::addSequence( T_InSeq_ const& sequence )
|
||||
{
|
||||
auto n( sequence.size( ) );
|
||||
if ( n == 0 ) {
|
||||
T_RuleSource_ const& src( ruleSources.get( cid , curRule - 1 ) );
|
||||
T_SRDContext const& sCtx( defs[ src.context ] );
|
||||
|
||||
T_StringBuilder sb;
|
||||
sb << "In context `" << sCtx.name( ) << "`: rule #" << src.rule
|
||||
<< " features an empty sequence.";
|
||||
throw X_SRDParserConfig( sb );
|
||||
}
|
||||
|
||||
uint32_t indices[ n ];
|
||||
for ( uint32_t i = 0 ; i < n ; i ++ ) {
|
||||
auto& node( convertItem( sequence[ i ] ) );
|
||||
indices[ i ] = node.index;
|
||||
}
|
||||
|
||||
uint32_t nextLeft = indices[ 0 ];
|
||||
for ( uint32_t i = 1 ; i < n ; i ++ ) {
|
||||
auto& node( addNode( E_NodeType_::CAT ) );
|
||||
node.left = nextLeft;
|
||||
node.right = indices[ i ];
|
||||
nextLeft = node.index;
|
||||
}
|
||||
|
||||
return nodes[ nextLeft ];
|
||||
}
|
||||
|
||||
T_RuleNode_& T_ContextConverter_::convertRepetitions( T_SRDInputItem const& item )
|
||||
{
|
||||
const auto min( item.min( ) );
|
||||
const auto max( item.max( ) );
|
||||
auto const& seq( item.items( ) );
|
||||
|
||||
// Minimum amount of repetitions
|
||||
uint32_t nextLeft = UINT32_MAX;
|
||||
for ( uint32_t i = 0 ; i < min ; i ++ ) {
|
||||
auto const& node( addSequence( seq ) );
|
||||
if ( i > 0 ) {
|
||||
auto& cat( addNode( E_NodeType_::CAT ) );
|
||||
cat.left = nextLeft;
|
||||
cat.right = node.index;
|
||||
nextLeft = cat.index;
|
||||
} else {
|
||||
nextLeft = node.index;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t nextRight = UINT32_MAX;
|
||||
if ( max == UINT32_MAX ) {
|
||||
// Unlimited repetitions
|
||||
auto const& node( addSequence( seq ) );
|
||||
auto& star( addNode( E_NodeType_::STAR ) );
|
||||
star.left = node.index;
|
||||
nextRight = star.index;
|
||||
|
||||
} else if ( max > min ) {
|
||||
// First item: (alt $seq epsilon)
|
||||
auto const& seq0( addSequence( seq ) );
|
||||
auto const& epsilon0( addNode( E_NodeType_::EPS ) );
|
||||
|
||||
auto& alt0( addNode( E_NodeType_::ALT ) );
|
||||
alt0.left = seq0.index;
|
||||
alt0.right = epsilon0.index;
|
||||
nextRight = alt0.index;
|
||||
|
||||
// Other items: (alt (cat $seq $previous) epsilon)
|
||||
const uint32_t count( max - min );
|
||||
for ( uint32_t i = 1 ; i < count ; i ++ ) {
|
||||
auto const& nseq( addSequence( seq ) );
|
||||
|
||||
auto& cat( addNode( E_NodeType_::CAT ) );
|
||||
cat.left = nseq.index;
|
||||
cat.right = nextRight;
|
||||
|
||||
auto const& eps( addNode( E_NodeType_::EPS ) );
|
||||
|
||||
auto& alt( addNode( E_NodeType_::ALT ) );
|
||||
alt.left = cat.index;
|
||||
alt.right = eps.index;
|
||||
nextRight = alt.index;
|
||||
}
|
||||
}
|
||||
|
||||
assert( nextRight != UINT32_MAX || nextLeft != UINT32_MAX );
|
||||
|
||||
// Combine fixed part and variable part if both exist
|
||||
if ( nextRight != UINT32_MAX && nextLeft != UINT32_MAX ) {
|
||||
auto& cat( addNode( E_NodeType_::CAT ) );
|
||||
cat.left = nextLeft;
|
||||
cat.right = nextRight;
|
||||
return cat;
|
||||
}
|
||||
|
||||
if ( nextRight == UINT32_MAX ) {
|
||||
return nodes[ nextLeft ];
|
||||
} else {
|
||||
return nodes[ nextRight ];
|
||||
}
|
||||
}
|
||||
|
||||
T_RuleNode_& T_ContextConverter_::convertItem( T_SRDInputItem const& item )
|
||||
{
|
||||
switch ( item.type( ) ) {
|
||||
|
||||
case E_SRDInputItem::WORD:
|
||||
return addWord( item.word( ) );
|
||||
|
||||
case E_SRDInputItem::ENUM:
|
||||
return addEnum( item.word( ) );
|
||||
|
||||
case E_SRDInputItem::TOKEN:
|
||||
return addToken( item.token( ) );
|
||||
|
||||
case E_SRDInputItem::ALTERNATIVE:
|
||||
return addAlternatives( item.items( ) );
|
||||
|
||||
case E_SRDInputItem::REPETITION:
|
||||
return convertRepetitions( item );
|
||||
|
||||
}
|
||||
throw std::domain_error( "unknown item type" );
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
void T_ContextConverter_::convertRules( )
|
||||
{
|
||||
auto const& ctx( cfg.contexts[ cid ] );
|
||||
nodes.clear( );
|
||||
symNodes.clear( );
|
||||
maxLabel = 0;
|
||||
|
||||
// Access all rules
|
||||
auto const& rules( ctx.rules( ) );
|
||||
const uint32_t nRules( rules.size( ) );
|
||||
if ( nRules == 0 ) {
|
||||
T_StringBuilder sb;
|
||||
sb << "Context `" << ctx.name( )
|
||||
<< "` is empty.";
|
||||
throw X_SRDParserConfig( sb );
|
||||
}
|
||||
|
||||
// Convert each rule
|
||||
uint32_t ruleRoots[ nRules ];
|
||||
for ( curRule = 1 ; curRule <= nRules ; curRule ++ ) {
|
||||
// Convert the rule
|
||||
auto& rNode( addSequence( rules[ curRule - 1 ].rule( ) ) );
|
||||
auto const& ruleEnd( addSymbolNode( E_SymNodeType_::END , curRule - 1 ) );
|
||||
auto& ruleRoot( addNode( E_NodeType_::CAT ) );
|
||||
ruleRoot.left = rNode.index;
|
||||
ruleRoot.right = ruleEnd.index;
|
||||
|
||||
ruleRoots[ curRule - 1 ] = ruleRoot.index;
|
||||
}
|
||||
|
||||
// Add alternations between the rules
|
||||
uint32_t nextLeft = ruleRoots[ 0 ];
|
||||
for ( uint32_t i = 1 ; i < nRules ; i ++ ) {
|
||||
auto& alt( addNode( E_NodeType_::ALT ) );
|
||||
alt.left = nextLeft;
|
||||
alt.right = ruleRoots[ i ];
|
||||
nextLeft = alt.index;
|
||||
}
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
void T_ContextConverter_::computeCancellable( )
|
||||
{
|
||||
const uint32_t nNodes( nodes.size( ) );
|
||||
cancellable.clear( );
|
||||
for ( uint32_t i = 0 ; i < nNodes ; i ++ ) {
|
||||
auto const& node( nodes[ i ] );
|
||||
switch ( node.type ) {
|
||||
|
||||
case E_NodeType_::ALT:
|
||||
{
|
||||
bool l( cancellable[ node.left ] );
|
||||
bool r( cancellable[ node.right ] );
|
||||
cancellable.add( l || r );
|
||||
break;
|
||||
}
|
||||
|
||||
case E_NodeType_::CAT:
|
||||
{
|
||||
bool l( cancellable[ node.left ] );
|
||||
bool r( cancellable[ node.right ] );
|
||||
cancellable.add( l && r );
|
||||
break;
|
||||
}
|
||||
|
||||
case E_NodeType_::SYM:
|
||||
cancellable.add( false );
|
||||
break;
|
||||
|
||||
case E_NodeType_::STAR:
|
||||
case E_NodeType_::EPS:
|
||||
cancellable.add( true );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void T_ContextConverter_::computePos( T_MultiArray< uint32_t >& output , const bool first )
|
||||
{
|
||||
const auto n( nodes.size( ) );
|
||||
output.clear( );
|
||||
for ( uint32_t i = 0 ; i < n ; i ++ ) {
|
||||
auto const& node( nodes[ i ] );
|
||||
output.next( );
|
||||
switch ( node.type ) {
|
||||
|
||||
case E_NodeType_::SYM:
|
||||
output.add( node.label );
|
||||
break;
|
||||
|
||||
case E_NodeType_::STAR:
|
||||
output.copyFrom( node.left );
|
||||
break;
|
||||
|
||||
case E_NodeType_::ALT:
|
||||
case E_NodeType_::CAT:
|
||||
{
|
||||
const auto n1( first ? node.left : node.right );
|
||||
const auto n2( first ? node.right : node.left );
|
||||
output.copyFrom( n1 );
|
||||
if ( node.type == E_NodeType_::ALT
|
||||
|| cancellable[ n1 ] ) {
|
||||
output.copyUnique( n2 );
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case E_NodeType_::EPS:
|
||||
// Do nothing.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void T_ContextConverter_::computeFirstPos( )
|
||||
{
|
||||
computePos( firstPos , true );
|
||||
}
|
||||
|
||||
inline void T_ContextConverter_::computeLastPos( )
|
||||
{
|
||||
computePos( lastPos , false );
|
||||
}
|
||||
|
||||
void T_ContextConverter_::computeNextPos( )
|
||||
{
|
||||
const auto lp( maxLabel + 1 );
|
||||
const auto nn( nodes.size( ) );
|
||||
nextPos.clear( );
|
||||
for ( uint32_t pos = 1 ; pos < lp ; pos ++ ) {
|
||||
nextPos.next( );
|
||||
for ( uint32_t i = 0 ; i < nn ; i ++ ) {
|
||||
auto const& node( nodes[ i ] );
|
||||
if ( node.type == E_NodeType_::CAT ) {
|
||||
if ( lastPos.contains( node.left , pos ) ) {
|
||||
nextPos.copyUnique( firstPos , node.right );
|
||||
}
|
||||
} else if ( node.type == E_NodeType_::STAR ) {
|
||||
if ( lastPos.contains( i , pos ) ) {
|
||||
nextPos.copyUnique( firstPos , i );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void T_ContextConverter_::gatherSymbols( )
|
||||
{
|
||||
symbols.clear( );
|
||||
symLabels.clear( );
|
||||
while ( symNodes.size( ) ) {
|
||||
auto const& first( nodes[ symNodes[ 0 ] ] );
|
||||
symNodes.removeSwap( 0 );
|
||||
symbols.addNew( first );
|
||||
symLabels.next( );
|
||||
symLabels.add( first.label );
|
||||
|
||||
uint32_t i = 0;
|
||||
while ( i < symNodes.size( ) ) {
|
||||
auto const& node( nodes[ symNodes[ i ] ] );
|
||||
if ( first.left == node.left && first.right == node.right ) {
|
||||
symLabels.add( node.label );
|
||||
symNodes.removeSwap( i );
|
||||
} else {
|
||||
i ++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
void T_ContextConverter_::setEndState( uint32_t state , uint32_t end )
|
||||
{
|
||||
const auto curEnd( cfg.endStates[ state ] );
|
||||
if ( curEnd != T_SRDParserConfig::INVALID_END && curEnd != end ) {
|
||||
T_StringBuilder sb;
|
||||
sb << "In context `" << defs[ cid ].name( ) << "`: rule #"
|
||||
<< ( curEnd + 1 ) << " and rule #" << ( end + 1 ) << " are ambiguous.";
|
||||
throw X_SRDParserConfig( sb );
|
||||
}
|
||||
cfg.endStates[ state ] = end;
|
||||
}
|
||||
|
||||
void T_ContextConverter_::addNameParts( uint32_t label )
|
||||
{
|
||||
const auto npf( nextPos.firstOf( label - 1 ) );
|
||||
const auto npl( nextPos.sizeOf( label - 1 ) + npf );
|
||||
for ( uint32_t i = npf ; i < npl ; i ++ ) {
|
||||
const auto p( nextPos[ i ] );
|
||||
const auto nas( nameAccum.size( ) );
|
||||
|
||||
bool found = false;
|
||||
for ( uint32_t j = 0 ; j < nas && !found ; j ++ ) {
|
||||
found = nameAccum[ j ] == p;
|
||||
}
|
||||
|
||||
if ( !found ) {
|
||||
nameAccum.add( p );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void T_ContextConverter_::checkStateName( uint32_t state , uint32_t first , uint32_t end , uint32_t si )
|
||||
{
|
||||
auto const& sym( symbols[ si ] );
|
||||
nameAccum.clear( );
|
||||
for ( uint32_t i = first ; i < end ; i ++ ) {
|
||||
const auto snVal( stateNames[ i ] );
|
||||
if ( !symLabels.contains( si , snVal ) ) {
|
||||
continue;
|
||||
}
|
||||
if ( sym.type == E_SymNodeType_::END ) {
|
||||
setEndState( state , sym.idx );
|
||||
} else {
|
||||
addNameParts( snVal );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t T_ContextConverter_::findState( uint32_t firstState )
|
||||
{
|
||||
const uint32_t nsize( nameAccum.size( ) );
|
||||
const uint32_t snsize( stateNames.size( ) );
|
||||
|
||||
for ( uint32_t i = 0 ; i < snsize ; i ++ ) {
|
||||
if ( stateNames.sizeOf( i ) != nsize ) {
|
||||
continue;
|
||||
}
|
||||
if ( !memcmp( &stateNames[ stateNames.firstOf( i ) ] , &nameAccum[ 0 ] ,
|
||||
nsize * sizeof( uint32_t ) ) ) {
|
||||
return i + firstState;
|
||||
}
|
||||
}
|
||||
return T_HashIndex::INVALID_INDEX;
|
||||
}
|
||||
|
||||
void T_ContextConverter_::addTransition( T_Symbol_ const& sym , uint32_t state )
|
||||
{
|
||||
if ( sym.type == E_SymNodeType_::TOKEN ) {
|
||||
cfg.transitions.addNew( E_SRDTokenType( sym.idx ) , state );
|
||||
} else {
|
||||
const auto type( sym.type == E_SymNodeType_::WORD
|
||||
? E_SRDTransitionType::WORD
|
||||
: E_SRDTransitionType::ENUM );
|
||||
cfg.transitions.addNew( type , sym.idx , state );
|
||||
}
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
void T_ContextConverter_::buildAutomaton( )
|
||||
{
|
||||
static const F_Comparator< T_SRDTransition > transSorter =
|
||||
[]( T_SRDTransition const& a , T_SRDTransition const& b ) -> int {
|
||||
return T_Comparator< decltype( a.type ) >::compare( a.type , b.type );
|
||||
};
|
||||
|
||||
const auto firstState( cfg.endStates.size( ) );
|
||||
cfg.endStates.add( T_SRDParserConfig::INVALID_END );
|
||||
cfg.startStates.add( firstState );
|
||||
stateNames.clear( );
|
||||
stateNames.copyFrom( firstPos , firstPos.size( ) - 1 );
|
||||
stateNames.sort( 0 );
|
||||
|
||||
const auto nsyms( symbols.size( ) );
|
||||
auto state = firstState;
|
||||
while ( state < cfg.endStates.size( ) ) {
|
||||
cfg.transitions.next( );
|
||||
|
||||
const auto snFirst( stateNames.firstOf( state - firstState ) );
|
||||
const auto snEnd( snFirst + stateNames.sizeOf( state - firstState ) );
|
||||
for ( uint32_t si = 0 ; si < nsyms ; si ++ ) {
|
||||
// Find the next state's name
|
||||
checkStateName( state , snFirst , snEnd , si );
|
||||
if ( nameAccum.size( ) == 0 ) {
|
||||
continue;
|
||||
}
|
||||
nameAccum.sort( );
|
||||
|
||||
// Check if the state exists
|
||||
uint32_t found( findState( firstState ) );
|
||||
|
||||
// Add new state if needed
|
||||
if ( found == T_HashIndex::INVALID_INDEX ) {
|
||||
found = cfg.endStates.size( );
|
||||
cfg.endStates.add( T_SRDParserConfig::INVALID_END );
|
||||
stateNames.next( );
|
||||
stateNames.copyFrom( nameAccum );
|
||||
}
|
||||
|
||||
// Add the transition
|
||||
addTransition( symbols[ si ] , found );
|
||||
}
|
||||
|
||||
cfg.transitions.sort( state , transSorter );
|
||||
state ++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
/*= X_SRDParserConfig ========================================================*/
|
||||
|
||||
X_SRDParserConfig::X_SRDParserConfig( T_StringBuilder const& error )
|
||||
: errorString_( error.size( ) + 1 )
|
||||
{
|
||||
memcpy( &errorString_[ 0 ] , error.data( ) , error.size( ) );
|
||||
errorString_[ error.size( ) ] = 0;
|
||||
}
|
||||
|
||||
X_SRDParserConfig::X_SRDParserConfig( T_String const& error )
|
||||
: errorString_( error.size( ) + 1 )
|
||||
{
|
||||
memcpy( &errorString_[ 0 ] , error.data( ) , error.size( ) );
|
||||
errorString_[ error.size( ) ] = 0;
|
||||
}
|
||||
|
||||
char const* X_SRDParserConfig::what( ) const noexcept
|
||||
{
|
||||
return &errorString_[ 0 ];
|
||||
}
|
||||
|
||||
|
||||
/*= T_SRDParserConfig ========================================================*/
|
||||
|
||||
T_SRDParserConfig::T_SRDParserConfig( T_SRDParserDefs const& defs )
|
||||
: onStart( defs.onStart( ) ) , onFinish( defs.onFinish( ) ) , contexts( defs.contexts( ) ) ,
|
||||
enums( []( T_SRDEnum const& e ) -> T_String const& {
|
||||
return e.name( );
|
||||
} , 64 , 64 , 64 ) , wordsIndex( 256 , 256 , 256 ) , words( 256 ) , startStates( defs.contexts( ) )
|
||||
{
|
||||
T_ContextConverter_ converter( *this , defs );
|
||||
converter.checkUnbalancedRules( );
|
||||
converter.findUsedContexts( );
|
||||
|
||||
const auto nc( contexts.size( ) );
|
||||
for ( uint32_t i = 0 ; i < nc ; i ++ ) {
|
||||
converter.cid = i;
|
||||
converter.convertRules( );
|
||||
converter.computeCancellable( );
|
||||
converter.computeFirstPos( );
|
||||
converter.computeLastPos( );
|
||||
converter.computeNextPos( );
|
||||
converter.gatherSymbols( );
|
||||
converter.buildAutomaton( );
|
||||
}
|
||||
}
|
||||
|
||||
bool T_SRDParserConfig::transition( uint32_t& state , T_SRDToken const& token ) const
|
||||
{
|
||||
const auto first( transitions.firstOf( state ) );
|
||||
const auto end( first + transitions.sizeOf( state ) );
|
||||
|
||||
for ( uint32_t i = first ; i < end ; i ++ ) {
|
||||
auto const& t( transitions[ i ] );
|
||||
|
||||
if ( t.type == E_SRDTransitionType::TOKEN ) {
|
||||
if ( token.type( ) == t.tokenType ) {
|
||||
state = t.next;
|
||||
return true;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( token.type( ) != E_SRDTokenType::WORD ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( t.type == E_SRDTransitionType::WORD ) {
|
||||
if ( token.stringValue( ) == words[ t.index ] ) {
|
||||
state = t.next;
|
||||
return true;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
assert( t.type == E_SRDTransitionType::ENUM );
|
||||
if ( enums[ t.index ].contains( token.stringValue( ) ) ) {
|
||||
state = t.next;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
T_Optional< uint32_t > T_SRDParserConfig::enumValue(
|
||||
T_String const& name , T_String const& member ) const noexcept
|
||||
{
|
||||
T_SRDEnum const* const enumData( enums.get( name ) );
|
||||
if ( enumData && enumData->contains( member ) ) {
|
||||
return (*enumData)[ member ];
|
||||
}
|
||||
return T_Optional< uint32_t >( );
|
||||
}
|
1416
src/SRDPreproc.cc
Normal file
1416
src/SRDPreproc.cc
Normal file
File diff suppressed because it is too large
Load diff
1329
src/SRDText.cc
Normal file
1329
src/SRDText.cc
Normal file
File diff suppressed because it is too large
Load diff
42
src/Streams.cc
Normal file
42
src/Streams.cc
Normal file
|
@ -0,0 +1,42 @@
|
|||
/******************************************************************************/
|
||||
/* STREAMS ********************************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
#include <lw/lib/Streams.hh>
|
||||
|
||||
using namespace lw;
|
||||
|
||||
|
||||
/*= X_StreamError ============================================================*/
|
||||
|
||||
char const* X_StreamError::what( ) const noexcept
|
||||
{
|
||||
switch ( error_ ) {
|
||||
case E_StreamError::NOT_SUPPORTED:
|
||||
return "operation not supported";
|
||||
|
||||
case E_StreamError::INVALID_POSITION:
|
||||
return "invalid position";
|
||||
|
||||
case E_StreamError::END:
|
||||
return "stream ended";
|
||||
|
||||
case E_StreamError::BAD_DATA:
|
||||
return "incomplete read/write";
|
||||
|
||||
case E_StreamError::SYSTEM_ERROR:
|
||||
return "system error";
|
||||
|
||||
case E_StreamError::UNAVAILABLE:
|
||||
return "stream no longer available";
|
||||
|
||||
default:
|
||||
return "unknown error";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*= A_OutputStream ===========================================================*/
|
||||
|
||||
void A_OutputStream::flush( )
|
||||
{ }
|
2015
src/Strings.cc
Normal file
2015
src/Strings.cc
Normal file
File diff suppressed because it is too large
Load diff
32
src/TemplateInstantiation.cc
Normal file
32
src/TemplateInstantiation.cc
Normal file
|
@ -0,0 +1,32 @@
|
|||
/******************************************************************************/
|
||||
/* INSTANTIATION OF VARIOUS TEMPLATE CLASSES **********************************/
|
||||
/******************************************************************************/
|
||||
|
||||
#include <lw/lib/Utilities.hh>
|
||||
#include <lw/lib/Arrays.hh>
|
||||
#include <lw/lib/Strings.hh>
|
||||
#include <lw/lib/SRDData.hh>
|
||||
#include <lw/lib/SRDDefinitions.hh>
|
||||
|
||||
namespace lw {
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
template struct T_Comparator< uint32_t >;
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
template class T_Array< uint32_t >;
|
||||
template class T_Array< bool >;
|
||||
template class T_Array< T_String >;
|
||||
template class T_Array< T_SRDToken >;
|
||||
template class T_Array< T_SRDInputItem >;
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
template class T_MultiArray< uint32_t >;
|
||||
template class T_MultiArray< T_String >;
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
}
|
159
src/TextFileLogger.cc
Normal file
159
src/TextFileLogger.cc
Normal file
|
@ -0,0 +1,159 @@
|
|||
/******************************************************************************/
|
||||
/* LOGGING SYSTEM - BUILT-IN LOGGERS - TEXT FILE LOGGER ***********************/
|
||||
/******************************************************************************/
|
||||
|
||||
#include <lw/lib/BuiltinLoggers.hh>
|
||||
#include <lw/lib/SRDParser.hh>
|
||||
using namespace lw;
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
|
||||
char const* const V_Name_ = "text-file";
|
||||
inline T_String Name_( ) { return T_String::Pooled( V_Name_ ); }
|
||||
|
||||
bool TFLCPath_( T_SRDParserData const& data )
|
||||
{
|
||||
auto const& ptok( (*data.input)[ 1 ] );
|
||||
T_VFSPath path( ptok.stringValue( ) );
|
||||
path = path.normalize( );
|
||||
if ( path.type( ) != E_VFSPathType::ABSOLUTE ) {
|
||||
data.errors.add( "invalid path" , ptok );
|
||||
} else {
|
||||
auto lconf( data.targetData->value< RP_LogWriterConfiguration >( ) );
|
||||
( dynamic_cast< T_TextFileLogWriterCfg* >( lconf ) )->setPath( std::move( path ) );
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TFLCAppend_( T_SRDParserData const& data )
|
||||
{
|
||||
auto lconf( data.targetData->value< RP_LogWriterConfiguration >( ) );
|
||||
( dynamic_cast< T_TextFileLogWriterCfg* >( lconf ) )->setAppend( true );
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TFLCTruncate_( T_SRDParserData const& data )
|
||||
{
|
||||
auto lconf( data.targetData->value< RP_LogWriterConfiguration >( ) );
|
||||
( dynamic_cast< T_TextFileLogWriterCfg* >( lconf ) )->setAppend( false );
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*= T_TextFileLogWriterFactory ==================================================*/
|
||||
|
||||
T_TextFileLogWriterFactory::T_TextFileLogWriterFactory( T_VFS& vfs )
|
||||
: A_LogWriterFactory( Name_( ) ) , vfs_( vfs )
|
||||
{ }
|
||||
|
||||
RP_LogWriterConfiguration T_TextFileLogWriterFactory::createConfiguration( T_String const& name ) const
|
||||
{
|
||||
RP_LogWriterConfiguration p( new T_TextFileLogWriterCfg( ) );
|
||||
p->setName( name );
|
||||
return p;
|
||||
}
|
||||
|
||||
OP_LogWriter T_TextFileLogWriterFactory::createLogWriter( OP_LogWriterConfiguration&& configuration ) const
|
||||
{
|
||||
T_TextFileLogWriter* p( new T_TextFileLogWriter( std::move( configuration ) , vfs_ ) );
|
||||
return OwnRawPointer( p );
|
||||
}
|
||||
|
||||
void T_TextFileLogWriterFactory::initializeSyntax( T_SRDParserDefs& , T_SRDContext& main ) const
|
||||
{
|
||||
using namespace lw::SRD;
|
||||
main << ( Rule( ) << "file" << Text( ) << TFLCPath_ );
|
||||
main << ( Rule( ) << "append" << TFLCAppend_ );
|
||||
main << ( Rule( ) << "truncate" << TFLCTruncate_ );
|
||||
}
|
||||
|
||||
|
||||
/*= T_TextFileLogWriterCfg ======================================================*/
|
||||
|
||||
T_TextFileLogWriterCfg::T_TextFileLogWriterCfg( )
|
||||
: T_LogWriterConfiguration( Name_( ) )
|
||||
{ }
|
||||
|
||||
T_TextFileLogWriterCfg::T_TextFileLogWriterCfg( T_TextFileLogWriterCfg const& source )
|
||||
: T_LogWriterConfiguration( source ) , path_( source.path_ ) ,
|
||||
append_( source.append_ )
|
||||
{ }
|
||||
|
||||
OP_LogWriterConfiguration T_TextFileLogWriterCfg::clone( )
|
||||
{
|
||||
T_TextFileLogWriterCfg* ptr( new T_TextFileLogWriterCfg( *this ) );
|
||||
return OwnRawPointer( ptr );
|
||||
}
|
||||
|
||||
void T_TextFileLogWriterCfg::check( T_SRDErrors& errors , T_SRDList const& input )
|
||||
{
|
||||
T_LogWriterConfiguration::check( errors , input );
|
||||
if ( path_.type( ) == E_VFSPathType::UNKNOWN || path_.elements( ) == 0 ) {
|
||||
errors.add( "no file selected" , input[ 0 ] );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*= T_TextFileLogWriter =========================================================*/
|
||||
|
||||
T_TextFileLogWriter::T_TextFileLogWriter( OP_LogWriterConfiguration&& configuration , T_VFS& vfs )
|
||||
: A_LogWriter( std::move( configuration ) ) , vfs_( vfs )
|
||||
{ }
|
||||
|
||||
void T_TextFileLogWriter::log( T_LogTimestamp const& timestamp ,
|
||||
E_LogLevel level , T_LogPath const& path ,
|
||||
T_LogStringData const& data , uint32_t size )
|
||||
{
|
||||
using namespace std::chrono;
|
||||
|
||||
char timeBuffer[ 128 ];
|
||||
std::time_t tst( T_LogTimestamp::clock::to_time_t( timestamp ) );
|
||||
std::strftime( timeBuffer , 128 , "%Y-%m-%d %H:%M:%S" , std::gmtime( &tst ) );
|
||||
const auto ms( ( duration_cast< milliseconds >( timestamp - T_LogTimestamp( ) ) ).count( ) % 1000 );
|
||||
|
||||
T_StringBuilder sb;
|
||||
|
||||
sb << timeBuffer << '.';
|
||||
if ( ms < 100 ) {
|
||||
sb << '0';
|
||||
if ( ms < 10 ) {
|
||||
sb << '0';
|
||||
}
|
||||
}
|
||||
sb << ms << ' ' << path.toString( ) << " - " << level << ": ";
|
||||
sb.append( &( (*data) [ 0 ] ) , size );
|
||||
sb << '\n';
|
||||
|
||||
auto const& cfg( configuration< T_TextFileLogWriterCfg >( ) );
|
||||
auto const& p( cfg.path( ) );
|
||||
if ( !file_ ) {
|
||||
vfs_.mkdir( p.parent( ) );
|
||||
file_ = vfs_.file( p , cfg.append( ) ? E_FileMode::READ_WRITE : E_FileMode::OVERWRITE );
|
||||
if ( !file_ ) {
|
||||
disable( );
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
file_->open( );
|
||||
} catch ( X_StreamError const& ) {
|
||||
disable( );
|
||||
file_.clear( );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
file_->position( 0 , true );
|
||||
file_->write( sb.data( ) , sb.size( ) );
|
||||
file_->flush( );
|
||||
} catch ( X_StreamError ) {
|
||||
disable( );
|
||||
file_.clear( );
|
||||
return;
|
||||
}
|
||||
}
|
160
src/Utilities.cc
Normal file
160
src/Utilities.cc
Normal file
|
@ -0,0 +1,160 @@
|
|||
/******************************************************************************/
|
||||
/* VARIOUS UTILITIES **********************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
|
||||
#include <lw/lib/Utilities.hh>
|
||||
using namespace lw;
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
|
||||
/*= SORTING INTERNALS - QUICKSORT ============================================*/
|
||||
|
||||
static const int32_t C_MIN_QS_ITEMS_ = 4;
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
// T_Stack_ - Quicksort stack
|
||||
|
||||
struct T_Stack_
|
||||
{
|
||||
uint8_t* low;
|
||||
uint8_t* high;
|
||||
};
|
||||
|
||||
|
||||
inline void QSPush_( T_Stack_*& stack , uint8_t* low , uint8_t* high )
|
||||
{
|
||||
stack->low = low;
|
||||
stack->high = high;
|
||||
stack ++;
|
||||
}
|
||||
|
||||
inline void QSPop_( T_Stack_*& stack , uint8_t*& low , uint8_t*& high )
|
||||
{
|
||||
stack --;
|
||||
low = stack->low;
|
||||
high = stack->high;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
inline void Quicksort_( uint8_t* data , uint32_t itemSize , uint32_t items , T_Sorter_::F_Swap swap ,
|
||||
T_Sorter_::F_Cmp cmp )
|
||||
{
|
||||
const int32_t minSize = itemSize * C_MIN_QS_ITEMS_;
|
||||
|
||||
uint8_t* low( data );
|
||||
uint8_t* high( low + itemSize * ( items - 1 ) );
|
||||
|
||||
T_Stack_ stackData[ 8 * sizeof( uint32_t ) ];
|
||||
T_Stack_* stack( &stackData[ 0 ] );
|
||||
QSPush_( stack , nullptr , nullptr );
|
||||
|
||||
while ( stack > &stackData[ 0 ] ) {
|
||||
// Select pivot, sort low/pivot/high
|
||||
uint8_t* mid( low + itemSize * ( ( high - low ) / itemSize >> 1 ) );
|
||||
if ( cmp( mid , low ) < 0 ) {
|
||||
swap( mid , low );
|
||||
}
|
||||
if ( cmp( high , mid ) < 0 ) {
|
||||
swap( mid , high );
|
||||
if ( cmp( mid , low ) < 0 ) {
|
||||
swap( mid , low );
|
||||
}
|
||||
}
|
||||
|
||||
// Partitioning
|
||||
uint8_t* left( low + itemSize ) ,
|
||||
*right( high - itemSize );
|
||||
do {
|
||||
while ( cmp( left , mid ) < 0 ) {
|
||||
left += itemSize;
|
||||
}
|
||||
while ( cmp( mid , right ) < 0 ) {
|
||||
right -= itemSize;
|
||||
}
|
||||
|
||||
if ( left < right ) {
|
||||
swap( left , right );
|
||||
if ( left == mid ) {
|
||||
mid = right;
|
||||
} else if ( right == mid ) {
|
||||
mid = left;
|
||||
}
|
||||
}
|
||||
if ( left <= right ) {
|
||||
left += itemSize;
|
||||
right -= itemSize;
|
||||
}
|
||||
} while ( left <= right );
|
||||
|
||||
// Setup for next iteration
|
||||
if ( right - low <= minSize ) {
|
||||
if ( high - left <= minSize ) {
|
||||
QSPop_( stack , low , high );
|
||||
} else {
|
||||
low = left;
|
||||
}
|
||||
} else if ( high - left <= minSize ) {
|
||||
high = right;
|
||||
} else if ( right - low > high - left ) {
|
||||
QSPush_( stack , low , right );
|
||||
low = left;
|
||||
} else {
|
||||
QSPush_( stack , left , high );
|
||||
high = right;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*= SORTING INTERNALS - INSERTION SORT =======================================*/
|
||||
|
||||
inline void InsertionSort_( uint8_t* data , uint32_t itemSize , uint32_t items , T_Sorter_::F_Swap swap ,
|
||||
T_Sorter_::F_Cmp cmp )
|
||||
{
|
||||
uint8_t* const end( data + itemSize* items );
|
||||
for ( uint8_t* i( data + itemSize ) ; i < end ; i += itemSize ) {
|
||||
auto j = i;
|
||||
while ( j != data && cmp( j - itemSize , j ) > 0 ) {
|
||||
swap( j , j - itemSize );
|
||||
j -= itemSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
/*= T_Sorter_ ================================================================*/
|
||||
|
||||
void T_Sorter_::sort( uint8_t* data , uint32_t itemSize , uint32_t items , F_Swap swap , F_Cmp cmp )
|
||||
{
|
||||
if ( items != 0 ) {
|
||||
if ( items > C_MIN_QS_ITEMS_ ) {
|
||||
Quicksort_( data , itemSize , items , swap , cmp );
|
||||
}
|
||||
InsertionSort_( data , itemSize , items , swap , cmp );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*= HashData( ) ==============================================================*/
|
||||
|
||||
uint32_t lw::HashData( uint8_t const* data , uint32_t size )
|
||||
{
|
||||
uint32_t hash = 111119;
|
||||
while ( size > 0 ) {
|
||||
hash += *data;
|
||||
hash += ( hash << 10 );
|
||||
hash ^= ( hash >> 6 );
|
||||
data ++;
|
||||
size --;
|
||||
}
|
||||
hash += ( hash << 3 );
|
||||
hash ^= ( hash >> 11 );
|
||||
hash += ( hash << 15 );
|
||||
return hash;
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue