publish meeting summary and scons-RfC (sync with master)
2
.gitignore
vendored
|
|
@ -7,6 +7,8 @@
|
|||
*.gch
|
||||
,valgrind.log*
|
||||
*.pyc
|
||||
/.sconf_temp
|
||||
/.settings
|
||||
optcache
|
||||
Makefile.in
|
||||
build/*
|
||||
|
|
|
|||
440
SConstruct
|
|
@ -1,6 +1,6 @@
|
|||
# -*- python -*-
|
||||
##
|
||||
## SConstruct - SCons based build-sytem for Lumiera
|
||||
## SConstruct - SCons based build-system for Lumiera
|
||||
##
|
||||
|
||||
# Copyright (C) Lumiera.org
|
||||
|
|
@ -23,424 +23,62 @@
|
|||
|
||||
|
||||
# NOTE: scons -h for help.
|
||||
# This script /defines/ the components and how they fit together.
|
||||
# SCons will derive dependencies and the necessary build steps.
|
||||
# Read more about the SCons build system at: http://www.scons.org
|
||||
# Basically, this script just /defines/ the components and how they
|
||||
# fit together. SCons will derive the necessary build steps.
|
||||
|
||||
|
||||
#-----------------------------------Configuration
|
||||
TARGDIR = 'target'
|
||||
VERSION = '0.pre.01'
|
||||
TOOLDIR = './admin/scons' # SCons plugins
|
||||
SCRIPTDIR = './admin'
|
||||
OPTCACHE = 'optcache'
|
||||
CUSTOPTFILE = 'custom-options'
|
||||
|
||||
# these are accessible via env.path.xxxx
|
||||
srcIcon = 'icons'
|
||||
srcConf = 'data/config'
|
||||
buildExe = '#$TARGDIR'
|
||||
buildLib = '#$TARGDIR/modules'
|
||||
buildPlug = '#$TARGDIR/modules'
|
||||
buildIcon = '#$TARGDIR/gui/icons'
|
||||
buildUIRes = '#$TARGDIR/'
|
||||
buildConf = '#$TARGDIR/config'
|
||||
installExe = '#$DESTDIR/lib/lumiera'
|
||||
installLib = '#$DESTDIR/lib/lumiera/modules'
|
||||
installPlug = '#$DESTDIR/lib/lumiera/modules'
|
||||
installIcon = '#$DESTDIR/share/lumiera/icons'
|
||||
installUIRes = '#$DESTDIR/share/lumiera/'
|
||||
installConf = '#$DESTDIR/lib/lumiera/config'
|
||||
|
||||
localDefinitions = locals()
|
||||
#-----------------------------------Configuration
|
||||
|
||||
|
||||
|
||||
import os
|
||||
# SCons plugins and extension modules
|
||||
#------------------------------------------------
|
||||
import sys
|
||||
sys.path.append('./admin/scons')
|
||||
#------------------------------------------------
|
||||
|
||||
sys.path.append(TOOLDIR)
|
||||
sys.path.append(SCRIPTDIR)
|
||||
|
||||
import Setup
|
||||
import Options
|
||||
import Platform
|
||||
|
||||
from Buildhelper import *
|
||||
from LumieraEnvironment import *
|
||||
|
||||
|
||||
#####################################################################
|
||||
|
||||
def setupBasicEnvironment(localDefinitions):
|
||||
""" define cmdline options, build type decisions
|
||||
"""
|
||||
EnsurePythonVersion(2,4)
|
||||
EnsureSConsVersion(1,0)
|
||||
|
||||
Decider('MD5-timestamp') # detect changed files by timestamp, then do a MD5
|
||||
|
||||
vars = defineCmdlineVariables()
|
||||
env = LumieraEnvironment(variables=vars
|
||||
,toolpath = [TOOLDIR]
|
||||
,pathConfig = extract_localPathDefs(localDefinitions) # e.g. buildExe -> env.path.buildExe
|
||||
,TARGDIR = TARGDIR
|
||||
,DESTDIR = '$INSTALLDIR/$PREFIX'
|
||||
,VERSION = VERSION
|
||||
)
|
||||
handleVerboseMessages(env)
|
||||
|
||||
env.Append ( CCCOM=' -std=gnu99')
|
||||
env.Append ( SHCCCOM=' -std=gnu99') # workaround for a bug: CCCOM currently doesn't honour CFLAGS, only CCFLAGS
|
||||
env.Replace( CPPPATH =["#src"] # used to find includes, "#" means always absolute to build-root
|
||||
, CPPDEFINES=['LUMIERA_VERSION='+VERSION ] # note: it's a list to append further defines
|
||||
, CCFLAGS='-Wall -Wextra '
|
||||
, CFLAGS='-std=gnu99'
|
||||
)
|
||||
handleNoBugSwitches(env)
|
||||
|
||||
env.Append(CPPDEFINES = '_GNU_SOURCE')
|
||||
appendCppDefine(env,'DEBUG','DEBUG', 'NDEBUG')
|
||||
# appendCppDefine(env,'OPENGL','USE_OPENGL')
|
||||
appendVal(env,'ARCHFLAGS','CCFLAGS') # for both C and C++
|
||||
appendVal(env,'OPTIMIZE', 'CCFLAGS', val=' -O3')
|
||||
appendVal(env,'DEBUG', 'CCFLAGS', val=' -ggdb')
|
||||
|
||||
# setup search path for Lumiera plugins
|
||||
appendCppDefine(env,'PKGLIBDIR','LUMIERA_PLUGIN_PATH=\\"$PKGLIBDIR/:ORIGIN/modules\\"'
|
||||
,'LUMIERA_PLUGIN_PATH=\\"ORIGIN/modules\\"')
|
||||
appendCppDefine(env,'PKGDATADIR','LUMIERA_CONFIG_PATH=\\"$PKGLIBDIR/:.\\"'
|
||||
,'LUMIERA_CONFIG_PATH=\\"$DESTDIR/share/lumiera/:.\\"')
|
||||
|
||||
prepareOptionsHelp(vars,env)
|
||||
vars.Save(OPTCACHE, env)
|
||||
return env
|
||||
|
||||
def appendCppDefine(env,var,cppVar, elseVal=''):
|
||||
if env[var]:
|
||||
env.Append(CPPDEFINES = env.subst(cppVar) )
|
||||
elif elseVal:
|
||||
env.Append(CPPDEFINES = env.subst(elseVal))
|
||||
|
||||
def appendVal(env,var,targetVar,val=None):
|
||||
if env[var]:
|
||||
env.Append( **{targetVar: env.subst(val) or env[var]})
|
||||
|
||||
|
||||
def handleNoBugSwitches(env):
|
||||
""" set the build level for NoBug.
|
||||
Release builds imply no DEBUG
|
||||
whereas ALPHA and BETA require DEBUG
|
||||
"""
|
||||
level = env['BUILDLEVEL']
|
||||
if level in ['ALPHA', 'BETA']:
|
||||
if not env['DEBUG']:
|
||||
print 'Warning: NoBug ALPHA or BETA builds requires DEBUG=yes, switching DEBUG on!'
|
||||
env.Replace( DEBUG = 1 )
|
||||
env.Append(CPPDEFINES = 'EBUG_'+level)
|
||||
elif level == 'RELEASE':
|
||||
env.Replace( DEBUG = 0 )
|
||||
|
||||
def handleVerboseMessages(env):
|
||||
""" toggle verbose build output """
|
||||
if not env['VERBOSE']:
|
||||
# SetOption('silent', True)
|
||||
env['CCCOMSTR'] = env['SHCCCOMSTR'] = " Compiling $SOURCE"
|
||||
env['CXXCOMSTR'] = env['SHCXXCOMSTR'] = " Compiling++ $SOURCE"
|
||||
env['LINKCOMSTR'] = " Linking --> $TARGET"
|
||||
env['LDMODULECOMSTR'] = " creating module [ $TARGET ]"
|
||||
|
||||
|
||||
|
||||
|
||||
def defineCmdlineVariables():
|
||||
""" several toggles and configuration variables can be set on the commandline,
|
||||
current settings will be persisted in a options cache file.
|
||||
you may define custom variable settings in a separate file.
|
||||
Commandline will override both.
|
||||
"""
|
||||
vars = Variables([OPTCACHE, CUSTOPTFILE])
|
||||
vars.AddVariables(
|
||||
('ARCHFLAGS', 'Set architecture-specific compilation flags (passed literally to gcc)','')
|
||||
,('CC', 'Set the C compiler to use.', 'gcc')
|
||||
,('CXX', 'Set the C++ compiler to use.', 'g++')
|
||||
,PathVariable('CCACHE', 'Integrate with CCache', '', PathVariable.PathAccept)
|
||||
,PathVariable('DISTCC', 'Invoke C/C++ compiler commands through DistCC', '', PathVariable.PathAccept)
|
||||
,EnumVariable('BUILDLEVEL', 'NoBug build level for debugging', 'ALPHA', allowed_values=('ALPHA', 'BETA', 'RELEASE'))
|
||||
,BoolVariable('DEBUG', 'Build with debugging information and no optimisations', False)
|
||||
,BoolVariable('OPTIMIZE', 'Build with strong optimisation (-O3)', False)
|
||||
,BoolVariable('VALGRIND', 'Run Testsuite under valgrind control', True)
|
||||
,BoolVariable('VERBOSE', 'Print full build commands', False)
|
||||
,('TESTSUITES', 'Run only Testsuites matching the given pattern', '')
|
||||
# ,BoolVariable('OPENGL', 'Include support for OpenGL preview rendering', False)
|
||||
# ,EnumVariable('DIST_TARGET', 'Build target architecture', 'auto',
|
||||
# allowed_values=('auto', 'i386', 'i686', 'x86_64' ), ignorecase=2)
|
||||
,PathVariable('PREFIX', 'Installation dir prefix', 'usr/local', PathVariable.PathAccept)
|
||||
,PathVariable('INSTALLDIR', 'Root output directory for install. Final installation will happen in INSTALLDIR/PREFIX/... ', '/', PathVariable.PathIsDir)
|
||||
,PathVariable('PKGLIBDIR', 'Installation dir for plugins, defaults to PREFIX/lib/lumiera/modules', '',PathVariable.PathAccept)
|
||||
,PathVariable('PKGDATADIR', 'Installation dir for default config, usually PREFIX/share/lumiera', '',PathVariable.PathAccept)
|
||||
)
|
||||
|
||||
return vars
|
||||
|
||||
|
||||
|
||||
def prepareOptionsHelp(vars,env):
|
||||
prelude = """
|
||||
USAGE: scons [-c] [OPTS] [key=val [key=val...]] [TARGETS]
|
||||
Build and optionally install Lumiera.
|
||||
Without specifying any target, just the (re)build target will run.
|
||||
Add -c to the commandline to clean up anything a given target would produce
|
||||
|
||||
Special Targets:
|
||||
build : just compile and link
|
||||
testcode: additionally compile the Testsuite
|
||||
check : build and run the Testsuite
|
||||
doc : generate documentation (Doxygen)
|
||||
all : build and testcode and doc
|
||||
install : install created artifacts at PREFIX
|
||||
|
||||
Configuration Options:
|
||||
"""
|
||||
Help(prelude + vars.GenerateHelpText(env))
|
||||
|
||||
|
||||
|
||||
|
||||
def configurePlatform(env):
|
||||
""" locate required libs.
|
||||
setup platform specific options.
|
||||
Abort build in case of failure.
|
||||
"""
|
||||
conf = env.Configure()
|
||||
# run all configuration checks in the given env
|
||||
|
||||
# Perform checks for prerequisites --------------------------------------------
|
||||
problems = []
|
||||
if not conf.TryAction('pkg-config --version > $TARGET')[0]:
|
||||
problems.append('We need pkg-config for including library configurations, exiting.')
|
||||
|
||||
if not conf.CheckLibWithHeader('m', 'math.h','C'):
|
||||
problems.append('Did not find math.h / libm.')
|
||||
|
||||
if not conf.CheckLibWithHeader('dl', 'dlfcn.h', 'C'):
|
||||
problems.append('Functions for runtime dynamic loading not available.')
|
||||
|
||||
if not conf.CheckLibWithHeader('pthread', 'pthread.h', 'C'):
|
||||
problems.append('Did not find the pthread lib or pthread.h.')
|
||||
else:
|
||||
conf.env.Append(CPPFLAGS = ' -DHAVE_PTHREAD')
|
||||
conf.env.Append(CCFLAGS = ' -pthread')
|
||||
|
||||
if conf.CheckCHeader('execinfo.h'):
|
||||
conf.env.Append(CPPFLAGS = ' -DHAVE_EXECINFO_H')
|
||||
|
||||
if conf.CheckCHeader('valgrind/valgrind.h'):
|
||||
conf.env.Append(CPPFLAGS = ' -DHAVE_VALGRIND_H')
|
||||
else:
|
||||
print 'Valgrind not found. The use of Valgrind is optional; building without.'
|
||||
|
||||
if not conf.CheckPkgConfig('nobugmt', 201006.1):
|
||||
problems.append('Did not find NoBug [http://www.lumiera.org/nobug_manual.html].')
|
||||
else:
|
||||
conf.env.mergeConf('nobugmt')
|
||||
|
||||
if not conf.CheckCXXHeader('tr1/memory'):
|
||||
problems.append('We rely on the std::tr1 standard C++ extension for shared_ptr.')
|
||||
|
||||
if not conf.CheckCXXHeader('boost/config.hpp'):
|
||||
problems.append('We need the C++ boost-libraries.')
|
||||
else:
|
||||
if not conf.CheckCXXHeader('boost/scoped_ptr.hpp'):
|
||||
problems.append('We need boost::scoped_ptr (scoped_ptr.hpp).')
|
||||
if not conf.CheckCXXHeader('boost/format.hpp'):
|
||||
problems.append('We need boost::format (header).')
|
||||
if not conf.CheckLibWithHeader('boost_program_options-mt','boost/program_options.hpp','C++'):
|
||||
problems.append('We need boost::program_options (including binary lib for linking).')
|
||||
if not conf.CheckLibWithHeader('boost_system-mt','boost/system/error_code.hpp','C++'):
|
||||
problems.append('We need the boost::system support library (including binary lib).')
|
||||
if not conf.CheckLibWithHeader('boost_filesystem-mt','boost/filesystem.hpp','C++'):
|
||||
problems.append('We need the boost::filesystem lib (including binary lib for linking).')
|
||||
if not conf.CheckLibWithHeader('boost_regex-mt','boost/regex.hpp','C++'):
|
||||
problems.append('We need the boost regular expression lib (incl. binary lib for linking).')
|
||||
|
||||
|
||||
if conf.CheckLib(symbol='clock_gettime'):
|
||||
print 'Using function clock_gettime() as defined in the C-lib...'
|
||||
else:
|
||||
if not conf.CheckLib(symbol='clock_gettime', library='rt'):
|
||||
problems.append('No library known to provide the clock_gettime() function.')
|
||||
|
||||
if not conf.CheckPkgConfig('gavl', 1.0):
|
||||
problems.append('Did not find Gmerlin Audio Video Lib [http://gmerlin.sourceforge.net/gavl.html].')
|
||||
else:
|
||||
conf.env.mergeConf('gavl')
|
||||
|
||||
if not conf.CheckPkgConfig('gtkmm-2.4', 2.8):
|
||||
problems.append('Unable to configure GTK--')
|
||||
|
||||
if not conf.CheckPkgConfig('glibmm-2.4', '2.16'):
|
||||
problems.append('Unable to configure Lib glib--')
|
||||
|
||||
if not conf.CheckPkgConfig('gthread-2.0', '2.12.4'):
|
||||
problems.append('Need gthread support lib for glib-- based thread handling.')
|
||||
|
||||
if not conf.CheckPkgConfig('cairomm-1.0', 0.6):
|
||||
problems.append('Unable to configure Cairo--')
|
||||
|
||||
verGDL = '2.27.1'
|
||||
if not conf.CheckPkgConfig('gdl-1.0', verGDL, alias='gdl'):
|
||||
print 'No sufficiently recent (>=%s) version of GDL found. Maybe use custom package gdl-lum?' % verGDL
|
||||
if not conf.CheckPkgConfig('gdl-lum', verGDL, alias='gdl'):
|
||||
problems.append('GNOME Docking Library not found. We either need a sufficiently recent GDL '
|
||||
'version (>=%s), or the custom package "gdl-lum" from Lumiera.org.' % verGDL)
|
||||
|
||||
if not conf.CheckPkgConfig('librsvg-2.0', '2.18.1'):
|
||||
problems.append('Need rsvg Library for rendering icons.')
|
||||
|
||||
if not conf.CheckCHeader(['X11/Xutil.h', 'X11/Xlib.h'],'<>'):
|
||||
problems.append('Xlib.h and Xutil.h required. Please install libx11-dev.')
|
||||
|
||||
if not conf.CheckPkgConfig('xv') : problems.append('Need libXv...')
|
||||
if not conf.CheckPkgConfig('xext'): problems.append('Need libXext.')
|
||||
|
||||
|
||||
# report missing dependencies
|
||||
if problems:
|
||||
print "*** unable to build due to the following problems:"
|
||||
for isue in problems:
|
||||
print " * %s" % isue
|
||||
print
|
||||
print "build aborted."
|
||||
Exit(1)
|
||||
|
||||
print "** Gathered Library Info: %s" % conf.env.libInfo.keys()
|
||||
|
||||
|
||||
# create new env containing the finished configuration
|
||||
return conf.Finish()
|
||||
|
||||
|
||||
|
||||
def defineSetupTargets(env, artifacts):
|
||||
""" build operations and targets to be done /before/ compiling.
|
||||
things like creating a source tarball or preparing a version header.
|
||||
"""
|
||||
pass ## currently none
|
||||
|
||||
|
||||
|
||||
def defineBuildTargets(env, artifacts):
|
||||
""" define the source file/dirs comprising each artifact to be built.
|
||||
setup sub-environments with special build options if necessary.
|
||||
We use a custom function to declare a whole tree of srcfiles.
|
||||
"""
|
||||
|
||||
# use PCH to speed up building // disabled for now due to strange failures
|
||||
# env['GCH'] = ( env.PrecompiledHeader('src/pre.hpp')
|
||||
# + env.PrecompiledHeader('src/pre_a.hpp')
|
||||
# )
|
||||
|
||||
|
||||
|
||||
lLib = env.SharedLibrary('lumiera', srcSubtree(env,'src/lib'), install=True)
|
||||
lApp = env.SharedLibrary('lumieracommon', srcSubtree(env,'src/common'), install=True, LIBS=lLib)
|
||||
lBack = env.SharedLibrary('lumierabackend', srcSubtree(env,'src/backend'),install=True)
|
||||
lProc = env.SharedLibrary('lumieraproc', srcSubtree(env,'src/proc'), install=True)
|
||||
|
||||
core = lLib+lApp+lBack+lProc
|
||||
|
||||
artifacts['corelib'] = core
|
||||
artifacts['support'] = lLib
|
||||
artifacts['config'] = ( env.ConfigData(env.path.srcConf+'setup.ini', targetDir='$ORIGIN')
|
||||
+ env.ConfigData(env.path.srcConf+'dummy_lumiera.ini')
|
||||
)
|
||||
artifacts['lumiera'] = ( env.Program('lumiera', ['src/lumiera/main.cpp'] + core, install=True)
|
||||
+ artifacts['config']
|
||||
)
|
||||
|
||||
# building Lumiera Plugins
|
||||
artifacts['plugins'] = [] # currently none
|
||||
|
||||
# render and install Icons
|
||||
vector_icon_dir = env.path.srcIcon+'svg'
|
||||
prerendered_icon_dir = env.path.srcIcon+'prerendered'
|
||||
artifacts['icons'] = ( [env.IconRender(f) for f in scanSubtree(vector_icon_dir, ['*.svg'])]
|
||||
+ [env.IconResource(f) for f in scanSubtree(prerendered_icon_dir, ['*.png'])]
|
||||
)
|
||||
|
||||
# the Lumiera GTK GUI
|
||||
envGtk = env.Clone()
|
||||
envGtk.mergeConf(['gtkmm-2.4','gthread-2.0','cairomm-1.0','gdl','xv','xext','sm'])
|
||||
envGtk.Append(LIBS=core)
|
||||
|
||||
objgui = srcSubtree(envGtk,'src/gui', appendCPP='LUMIERA_PLUGIN')
|
||||
guimodule = envGtk.LumieraPlugin('gtk_gui', objgui, install=True)
|
||||
artifacts['gui'] = ( guimodule
|
||||
+ [env.GuiResource(f) for f in env.Glob('src/gui/*.rc')]
|
||||
+ artifacts['icons']
|
||||
)
|
||||
|
||||
# call subdir SConscript(s) for independent components
|
||||
SConscript(dirs=['src/tool'], exports='env artifacts core')
|
||||
SConscript(dirs=['tests'], exports='env artifacts core')
|
||||
|
||||
|
||||
|
||||
def definePostBuildTargets(env, artifacts):
|
||||
""" define further actions after the core build (e.g. Documentaion).
|
||||
define alias targets to trigger the installing.
|
||||
"""
|
||||
build = env.Alias('build', ( artifacts['lumiera']
|
||||
+ artifacts['plugins']
|
||||
+ artifacts['tools']
|
||||
+ artifacts['gui']
|
||||
))
|
||||
# additional files to be cleaned when cleaning 'build'
|
||||
env.Clean ('build', [ 'scache.conf', '.sconf_temp', '.sconsign.dblite', 'config.log' ])
|
||||
env.Clean ('build', [ 'src/pre.gch' ])
|
||||
|
||||
doxydoc = artifacts['doxydoc'] = env.Doxygen('doc/devel/Doxyfile')
|
||||
env.Alias ('doc', doxydoc)
|
||||
env.Clean ('doc', doxydoc + ['doc/devel/,doxylog','doc/devel/warnings.txt'])
|
||||
|
||||
env.Alias ('all', build+artifacts['testsuite']+doxydoc)
|
||||
env.Default('build')
|
||||
# SCons default target
|
||||
|
||||
|
||||
def defineInstallTargets(env, artifacts):
|
||||
""" define additional artifacts to be installed into target locations.
|
||||
@note: we use customised SCons builders defining install targets
|
||||
for all executables automatically. see LumieraEnvironment.py
|
||||
"""
|
||||
env.SymLink('$DESTDIR/bin/lumiera',env.path.installExe+'lumiera','../lib/lumiera/lumiera')
|
||||
# env.Install(dir = '$DESTDIR/share/doc/lumiera$VERSION/devel', source=artifacts['doxydoc'])
|
||||
|
||||
env.Alias('install', artifacts['gui'])
|
||||
env.Alias('install', '$DESTDIR')
|
||||
|
||||
#####################################################################
|
||||
|
||||
env = Setup.defineBuildEnvironment() # dirs & compiler flags
|
||||
env = Platform.configure(env) # library dependencies
|
||||
|
||||
|
||||
|
||||
### === MAIN BUILD === ##############################################
|
||||
|
||||
# call subdir SConscript(s) to define the actual build targets...
|
||||
SConscript(dirs=['data','src','src/tool','research','tests','doc'], exports='env')
|
||||
|
||||
|
||||
|
||||
|
||||
### === MAIN === ####################################################
|
||||
# additional files to be cleaned when cleaning 'build'
|
||||
env.Clean ('build', [ 'scache.conf', '.sconf_temp', '.sconsign.dblite', 'config.log' ])
|
||||
env.Clean ('build', [ 'src/pre.gch' ])
|
||||
|
||||
env = setupBasicEnvironment(localDefinitions)
|
||||
|
||||
if not (isCleanupOperation(env) or isHelpRequest()):
|
||||
env = configurePlatform(env)
|
||||
|
||||
artifacts = {}
|
||||
# the various things we build.
|
||||
# Each entry actually is a SCons-Node list.
|
||||
# Passing these entries to other builders defines dependencies.
|
||||
# 'lumiera' : the App
|
||||
# 'gui' : the GTK UI (plugin)
|
||||
# 'plugins' : plugin shared lib
|
||||
# 'tools' : small tool applications (e.g mpegtoc)
|
||||
|
||||
defineSetupTargets(env, artifacts)
|
||||
defineBuildTargets(env, artifacts)
|
||||
definePostBuildTargets(env, artifacts)
|
||||
defineInstallTargets(env, artifacts)
|
||||
### === Alias Targets === ###########################################
|
||||
|
||||
# pick up the targets defined by the sub SConscripts
|
||||
Import('lumiera plugins tools gui testsuite doxydoc')
|
||||
|
||||
build = env.Alias('build', lumiera + plugins + tools +gui)
|
||||
env.Default('build')
|
||||
# SCons default target
|
||||
|
||||
|
||||
env.Alias ('all', build + testsuite + doxydoc)
|
||||
env.Alias ('doc', doxydoc)
|
||||
|
||||
env.Alias('install', gui)
|
||||
env.Alias('install', '$DESTDIR')
|
||||
|
||||
#####################################################################
|
||||
|
|
|
|||
|
|
@ -1,213 +0,0 @@
|
|||
#!/usr/bin/python
|
||||
#
|
||||
# render_icons.py - Icon rendering utility script
|
||||
#
|
||||
# Copyright (C) Lumiera.org
|
||||
# 2008, Joel Holdsworth <joel@airwebreathe.org.uk>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License as
|
||||
# published by the Free Software Foundation; either version 2 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
import sys
|
||||
import getopt
|
||||
from xml.dom import minidom
|
||||
import os
|
||||
import shutil
|
||||
|
||||
#svgDir = "svg"
|
||||
#prerenderedDir = "prerendered"
|
||||
inkscapePath = "/usr/bin/inkscape"
|
||||
rsvgPath = "./rsvg-convert"
|
||||
artworkLayerPrefix = "artwork:"
|
||||
|
||||
#
|
||||
# 2/2011 some notes by Ichthyo
|
||||
# The purpose of this python script is
|
||||
# - to parse a SVG
|
||||
# - to invoke Inkscape to render this SVG into a raster image (icon)
|
||||
#
|
||||
# For the actual call into Incscape we rely on an executable 'rsvg-convert',
|
||||
# which is built during the Lumiera build process.
|
||||
#
|
||||
# Judging from the code and the actual SVGs, this seems to work as follows:
|
||||
# The SVG contains a design to be rendered into raster images of various sizes.
|
||||
# These sizes are determined by special rectangles, which act as bounding box and
|
||||
# are placed on a special 'plate' layer, which is a child layer of the main
|
||||
# 'artwork:' layer. The grid of the SVG is setup such as to result in pixel sizes
|
||||
# suitable for icon generation. The actual size of the generated icons are then
|
||||
# parsed from the height and width attributes of the mentioned bounding box
|
||||
# rectangles.
|
||||
#
|
||||
# The parser seems to be rather simplistic; the sizes and positions need to be
|
||||
# integral numbers. In one instance we had a float number in the y coordinate,
|
||||
# which resulted in an invalid, zero sized output icon
|
||||
#
|
||||
#
|
||||
|
||||
|
||||
def createDirectory( name ):
|
||||
try:
|
||||
if os.path.isfile(name):
|
||||
os.remove(name)
|
||||
if not os.path.exists(name):
|
||||
os.mkdir(name)
|
||||
except:
|
||||
print 'WARNING: createDirectory("%s") failed. Permission problems?' % name
|
||||
|
||||
|
||||
def copyMergeDirectory( src, dst ):
|
||||
listing = os.listdir(src)
|
||||
for file_name in listing:
|
||||
src_file_path = os.path.join(src, file_name)
|
||||
dst_file_path = os.path.join(dst, file_name)
|
||||
shutil.copyfile(src_file_path, dst_file_path)
|
||||
|
||||
def getDocumentSize( svg_element ):
|
||||
width = float(svg_element.getAttribute("width"))
|
||||
height = float(svg_element.getAttribute("height"))
|
||||
return [width, height]
|
||||
|
||||
def findChildLayerElement( parent_element ):
|
||||
for node in parent_element.childNodes:
|
||||
if node.nodeType == minidom.Node.ELEMENT_NODE:
|
||||
if node.tagName == "g":
|
||||
if node.getAttribute("inkscape:groupmode") == "layer":
|
||||
return node
|
||||
return None
|
||||
|
||||
def parsePlateLayer( layer ):
|
||||
rectangles = []
|
||||
for node in layer.childNodes:
|
||||
if node.nodeType == minidom.Node.ELEMENT_NODE:
|
||||
if node.tagName == "rect":
|
||||
x = float(node.getAttribute("x"))
|
||||
y = float(node.getAttribute("y"))
|
||||
width = float(node.getAttribute("width"))
|
||||
height = float(node.getAttribute("height"))
|
||||
rectangles.append([x, y, width, height])
|
||||
return rectangles
|
||||
|
||||
def parseSVG( file_path ):
|
||||
print "Parsing " + file_path
|
||||
svgdoc = minidom.parse(file_path)
|
||||
for root_node in svgdoc.childNodes:
|
||||
if root_node.nodeType == minidom.Node.ELEMENT_NODE:
|
||||
if root_node.tagName == "svg":
|
||||
size = getDocumentSize( root_node )
|
||||
layer = findChildLayerElement( root_node )
|
||||
if layer != None:
|
||||
layer_name = layer.getAttribute("inkscape:label")
|
||||
if layer_name[:len(artworkLayerPrefix)] == artworkLayerPrefix:
|
||||
artwork_name = layer_name[len(artworkLayerPrefix):]
|
||||
plate = findChildLayerElement( layer )
|
||||
if plate != None:
|
||||
return artwork_name, size, parsePlateLayer( plate )
|
||||
return None
|
||||
|
||||
def renderSvgInkscape(file_path, out_dir, artwork_name, rectangle, doc_size):
|
||||
|
||||
# Calculate the rendering rectangle
|
||||
x1 = rectangle[0]
|
||||
y1 = doc_size[1] - rectangle[1] - rectangle[3]
|
||||
x2 = x1 + rectangle[2]
|
||||
y2 = y1 + rectangle[3]
|
||||
|
||||
# Call Inkscape to do the render
|
||||
os.spawnlp(os.P_WAIT, inkscapePath, inkscapePath,
|
||||
file_path,
|
||||
"-z",
|
||||
"-a %g:%g:%g:%g" % (x1, y1, x2, y2),
|
||||
"-w %g" % (rectangle[2]), "-h %g" % (rectangle[3]),
|
||||
"--export-png=" + os.path.join(out_dir, "%gx%g/%s.png" % (rectangle[2], rectangle[3], artwork_name)))
|
||||
|
||||
def renderSvgRsvg(file_path, out_dir, artwork_name, rectangle, doc_size):
|
||||
# Prepare a Cairo context
|
||||
width = int(rectangle[2])
|
||||
height = int(rectangle[3])
|
||||
|
||||
if not os.path.exists(rsvgPath):
|
||||
print "Error: executable %s not found." % rsvgPath
|
||||
|
||||
os.spawnlp(os.P_WAIT, rsvgPath, rsvgPath,
|
||||
"--source-rect=%g:%g:%g:%g" % (rectangle[0], rectangle[1], rectangle[2], rectangle[3]),
|
||||
"--output=" + os.path.join(out_dir, "%gx%g/%s.png" % (rectangle[2], rectangle[3], artwork_name)),
|
||||
file_path)
|
||||
|
||||
def renderSvgIcon(file_path, out_dir):
|
||||
artwork_name, doc_size, rectangles = parseSVG(file_path)
|
||||
for rectangle in rectangles:
|
||||
renderSvgRsvg(file_path, out_dir, artwork_name, rectangle, doc_size)
|
||||
|
||||
def getTargetNames(file_path):
|
||||
"""get a list of target names to be rendered from the given source SVG
|
||||
usable to setup the build targets for SCons
|
||||
"""
|
||||
artwork_name, _ , rectangles = parseSVG(file_path)
|
||||
return ["%gx%g/%s.png" % (rectangle[2], rectangle[3], artwork_name) for rectangle in rectangles ]
|
||||
|
||||
#def renderSvgIcons():
|
||||
# listing = os.listdir(svgDir)
|
||||
# for file_path in listing:
|
||||
# [root, extension] = os.path.splitext(file_path)
|
||||
# if extension.lower() == ".svg":
|
||||
# renderSvgIcon(os.path.join(svgDir, file_path))
|
||||
|
||||
#def copyPrerenderedIcons():
|
||||
# listing = os.listdir(prerenderedDir)
|
||||
# for list_item in listing:
|
||||
# src_dir = os.path.join(prerenderedDir, list_item)
|
||||
# copyMergeDirectory(src_dir, list_item)
|
||||
|
||||
def printHelp():
|
||||
print "render-icon.py SRCFILE.svg TARGETDIR"
|
||||
print "An icon rendering utility script for lumiera"
|
||||
|
||||
def parseArguments(argv):
|
||||
optlist, args = getopt.getopt(argv, "")
|
||||
|
||||
if len(args) == 2:
|
||||
return args[0], args[1]
|
||||
|
||||
printHelp()
|
||||
return None, None
|
||||
|
||||
def main(argv):
|
||||
in_path, out_dir = parseArguments(argv)
|
||||
|
||||
if not (in_path and out_dir):
|
||||
print "Missing arguments in_path and out_dir."
|
||||
sys.exit(1)
|
||||
|
||||
if os.path.isfile(out_dir):
|
||||
print "Unable to use '%s' as output directory, because it\'s a file." % out_dir
|
||||
sys.exit(1)
|
||||
if not os.path.isdir(out_dir):
|
||||
print "Output directory '%s' not found." % out_dir
|
||||
sys.exit(1)
|
||||
|
||||
# Create the icons folders
|
||||
createDirectory(os.path.join(out_dir, "48x48"))
|
||||
createDirectory(os.path.join(out_dir, "32x32"))
|
||||
createDirectory(os.path.join(out_dir, "24x24"))
|
||||
createDirectory(os.path.join(out_dir, "22x22"))
|
||||
createDirectory(os.path.join(out_dir, "16x16"))
|
||||
|
||||
renderSvgIcon(in_path, out_dir)
|
||||
|
||||
# Copy in prerendered icons
|
||||
#copyPrerenderedIcons()
|
||||
|
||||
if __name__=="__main__":
|
||||
main(sys.argv[1:])
|
||||
|
||||
|
|
@ -336,7 +336,7 @@ function change_state()
|
|||
local state="$2"
|
||||
|
||||
local nl=$'\n'
|
||||
local comment=".State -> $state$nl//add reason$nl $(date +%c) $(git config --get user.name) <$(git config --get user.email)>$nl"
|
||||
local comment=".State -> $state$nl//add reason$nl$nl$(git config --get user.name):: '$(date +%c)' ~<$(git config --get user.email)>~$nl"
|
||||
edit_state "$name" "$state" "$comment"
|
||||
edit "$name" -4 "endof_comments"
|
||||
process_file "$name"
|
||||
|
|
|
|||
|
|
@ -25,11 +25,8 @@ import os
|
|||
import sys
|
||||
import glob
|
||||
import fnmatch
|
||||
import re
|
||||
import tarfile
|
||||
|
||||
from SCons import Util
|
||||
from SCons.Action import Action
|
||||
|
||||
|
||||
|
||||
|
|
@ -49,20 +46,11 @@ def isHelpRequest():
|
|||
|
||||
|
||||
|
||||
def srcSubtree(env,tree,isShared=True,builder=None,appendCPP=None, **args):
|
||||
""" convenience wrapper: scans the given subtree, which is
|
||||
relative to the current SConscript, find all source files and
|
||||
declare them as Static or SharedObjects for compilation
|
||||
def srcSubtree(tree, **args):
|
||||
""" convenience wrapper: scan the given subtree, which is relative
|
||||
to the current SConscript, and find all source files.
|
||||
"""
|
||||
if appendCPP: env.Append(CPPDEFINES=appendCPP)
|
||||
root = env.subst(tree) # expand Construction Vars
|
||||
if not builder:
|
||||
if isShared:
|
||||
builder = lambda f: env.SharedObject(f, **args)
|
||||
else:
|
||||
builder = lambda f: env.Object(f, **args)
|
||||
|
||||
return [builder(f) for f in scanSubtree(root)]
|
||||
return list(scanSubtree(tree, **args))
|
||||
|
||||
|
||||
|
||||
|
|
@ -74,12 +62,12 @@ def scanSubtree(roots, patterns=SRCPATTERNS):
|
|||
(python generator function)
|
||||
"""
|
||||
for root in globRootdirs(roots):
|
||||
for (dir,_,files) in os.walk(root):
|
||||
if dir.startswith('./'):
|
||||
dir = dir[2:]
|
||||
for (d,_,files) in os.walk(root):
|
||||
if d.startswith('./'):
|
||||
d = d[2:]
|
||||
for p in patterns:
|
||||
for f in fnmatch.filter(files, p):
|
||||
yield os.path.join(dir,f)
|
||||
yield os.path.join(d,f)
|
||||
|
||||
|
||||
|
||||
|
|
@ -87,16 +75,16 @@ def globRootdirs(roots):
|
|||
""" helper: expand shell wildcards and filter the resulting list,
|
||||
so that it only contains existing directories
|
||||
"""
|
||||
filter = lambda f: os.path.isdir(f) and os.path.exists(f)
|
||||
isDirectory = lambda f: os.path.isdir(f) and os.path.exists(f)
|
||||
roots = glob.glob(roots)
|
||||
return (dir for dir in roots if filter(dir) )
|
||||
return (d for d in roots if isDirectory(d) )
|
||||
|
||||
|
||||
|
||||
def findSrcTrees(location, patterns=SRCPATTERNS):
|
||||
""" find possible source tree roots, starting with the given location.
|
||||
When delving down from the initial location(s), a source tree is defined
|
||||
as a directory containing source files and possibly further sub directories.
|
||||
as a directory containidsource files and possibly further sub directories.
|
||||
After having initially expanded the given location with #globRootdirs, each
|
||||
directory is examined depth first, until encountering a directory containing
|
||||
source files, which then yields a result. Especially, this can be used to traverse
|
||||
|
|
@ -104,11 +92,11 @@ def findSrcTrees(location, patterns=SRCPATTERNS):
|
|||
to be built into packages, plugins, individual tool executables etc.
|
||||
@return: the relative path names of all source root dirs found (generator function).
|
||||
"""
|
||||
for dir in globRootdirs(location):
|
||||
if isSrcDir(dir,patterns):
|
||||
yield dir
|
||||
for directory in globRootdirs(location):
|
||||
if isSrcDir (directory,patterns):
|
||||
yield directory
|
||||
else:
|
||||
for result in findSrcTrees(str(dir)+'/*'):
|
||||
for result in findSrcTrees (str(directory)+'/*'):
|
||||
yield result
|
||||
|
||||
|
||||
|
|
@ -118,7 +106,7 @@ def isSrcDir(path, patterns=SRCPATTERNS):
|
|||
@return: True if it's a directory containing any source file
|
||||
"""
|
||||
if not os.path.isdir(path):
|
||||
return False
|
||||
return False
|
||||
else:
|
||||
for p in patterns:
|
||||
if glob.glob(path+'/'+p):
|
||||
|
|
@ -133,38 +121,39 @@ def filterNodes(nlist, removeName=None):
|
|||
if removeName:
|
||||
predicate = lambda n : not fnmatch.fnmatch(os.path.basename(str(n[0])), removeName)
|
||||
else:
|
||||
predicate = lambda n : True;
|
||||
predicate = lambda n : True
|
||||
|
||||
return filter(predicate, nlist)
|
||||
|
||||
|
||||
|
||||
def getDirname(dir, basePrefix=None):
|
||||
def getDirname (d, basePrefix=None):
|
||||
""" extract directory name without leading path,
|
||||
or without the explicitly given basePrefix
|
||||
"""
|
||||
dir = os.path.realpath(dir)
|
||||
if not os.path.isdir(dir):
|
||||
dir,_ = os.path.split(dir)
|
||||
d = os.path.realpath(d)
|
||||
if not os.path.isdir(d):
|
||||
d,_ = os.path.split(d)
|
||||
if basePrefix:
|
||||
basePrefix = os.path.realpath(basePrefix)
|
||||
if str(dir).startswith(basePrefix):
|
||||
name = str(dir)[len(basePrefix):]
|
||||
name = str(d)
|
||||
if str(d).startswith(basePrefix):
|
||||
name = name[len(basePrefix):]
|
||||
else:
|
||||
_, name = os.path.split(dir)
|
||||
_, name = os.path.split(d)
|
||||
return name
|
||||
|
||||
|
||||
|
||||
def createPlugins(env, dir, **kw):
|
||||
def createPlugins(env, directory, **kw):
|
||||
""" investigate the given source directory to identify all contained source trees.
|
||||
@return: a list of build nodes defining a plugin for each of these source trees.
|
||||
"""
|
||||
return [env.LumieraPlugin( getDirname(tree)
|
||||
, srcSubtree(env, tree, appendCPP='LUMIERA_PLUGIN')
|
||||
, srcSubtree(tree)
|
||||
, **kw
|
||||
)
|
||||
for tree in findSrcTrees(dir)
|
||||
for tree in findSrcTrees(directory)
|
||||
]
|
||||
|
||||
|
||||
|
|
|
|||
186
admin/scons/IconSvgRenderer.py
Executable file
|
|
@ -0,0 +1,186 @@
|
|||
#!/usr/bin/python
|
||||
#
|
||||
# IconSvgRenderer.py - Icon rendering utility script
|
||||
#
|
||||
# Copyright (C) Lumiera.org
|
||||
# 2008, Joel Holdsworth <joel@airwebreathe.org.uk>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License as
|
||||
# published by the Free Software Foundation; either version 2 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
import os
|
||||
import sys
|
||||
import getopt
|
||||
import shutil
|
||||
from xml.dom import minidom
|
||||
|
||||
|
||||
rsvgPath = "./rsvg-convert"
|
||||
artworkLayerPrefix = "artwork:"
|
||||
|
||||
#
|
||||
# 2/2011 some notes by Ichthyo
|
||||
# The purpose of this python script is
|
||||
# - to parse a SVG
|
||||
# - to invoke Inkscape to render this SVG into a raster image (icon)
|
||||
#
|
||||
# For the actual Cairo based SVG rendering we rely on an executable 'rsvg-convert',
|
||||
# which is built during the Lumiera build process.
|
||||
#
|
||||
# Judging from the code and the actual SVGs, this seems to work as follows:
|
||||
# The SVG contains a design to be rendered into raster images of various sizes.
|
||||
# These sizes are determined by special rectangles, which act as bounding box and
|
||||
# are placed on a special 'plate' layer, which is a child layer of the main
|
||||
# 'artwork:' layer. The grid of the SVG is setup such as to result in pixel sizes
|
||||
# suitable for icon generation. The actual size of the generated icons are then
|
||||
# parsed from the height and width attributes of the mentioned bounding box
|
||||
# rectangles.
|
||||
#
|
||||
# The parser seems to be rather simplistic; the sizes and positions need to be
|
||||
# integral numbers. In one instance we had a float number in the y coordinate,
|
||||
# which resulted in an invalid, zero sized output icon
|
||||
#
|
||||
#
|
||||
|
||||
|
||||
def createDirectory (name):
|
||||
try:
|
||||
if os.path.isfile (name):
|
||||
os.remove (name)
|
||||
if not os.path.exists (name):
|
||||
os.mkdir (name)
|
||||
except:
|
||||
print 'WARNING: createDirectory("%s") failed. Permission problems?' % name
|
||||
|
||||
|
||||
def copyMergeDirectory (src, dst):
|
||||
listing = os.listdir (src)
|
||||
for file_name in listing:
|
||||
src_file_path = os.path.join (src, file_name)
|
||||
dst_file_path = os.path.join (dst, file_name)
|
||||
shutil.copyfile (src_file_path, dst_file_path)
|
||||
|
||||
def getDocumentSize (svg_element):
|
||||
width = float(svg_element.getAttribute("width"))
|
||||
height = float(svg_element.getAttribute("height"))
|
||||
return [width, height]
|
||||
|
||||
def findChildLayerElement (parent_element):
|
||||
for node in parent_element.childNodes:
|
||||
if node.nodeType == minidom.Node.ELEMENT_NODE:
|
||||
if node.tagName == "g":
|
||||
if node.getAttribute("inkscape:groupmode") == "layer":
|
||||
return node
|
||||
return None
|
||||
|
||||
def parsePlateLayer (layer):
|
||||
rectangles = []
|
||||
for node in layer.childNodes:
|
||||
if node.nodeType == minidom.Node.ELEMENT_NODE:
|
||||
if node.tagName == "rect":
|
||||
x = float(node.getAttribute("x"))
|
||||
y = float(node.getAttribute("y"))
|
||||
width = float(node.getAttribute("width"))
|
||||
height = float(node.getAttribute("height"))
|
||||
rectangles.append([x, y, width, height])
|
||||
return rectangles
|
||||
|
||||
|
||||
def parseSVG (file_path):
|
||||
print "Parsing " + file_path
|
||||
svgdoc = minidom.parse (file_path)
|
||||
for root_node in svgdoc.childNodes:
|
||||
if root_node.nodeType == minidom.Node.ELEMENT_NODE:
|
||||
if root_node.tagName == "svg":
|
||||
size = getDocumentSize (root_node)
|
||||
layer = findChildLayerElement (root_node)
|
||||
if layer != None:
|
||||
layer_name = layer.getAttribute ("inkscape:label")
|
||||
if layer_name[:len(artworkLayerPrefix)] == artworkLayerPrefix:
|
||||
artwork_name = layer_name[len(artworkLayerPrefix):]
|
||||
plate = findChildLayerElement(layer)
|
||||
if plate != None:
|
||||
return artwork_name, size, parsePlateLayer(plate)
|
||||
return None
|
||||
|
||||
|
||||
def renderSvgRsvg (file_path, out_dir, artwork_name, rectangle, _doc_size):
|
||||
# Prepare a Cairo context
|
||||
width = int(rectangle[2])
|
||||
height = int(rectangle[3])
|
||||
|
||||
if not os.path.exists(rsvgPath):
|
||||
print "Error: executable %s not found." % rsvgPath
|
||||
|
||||
os.spawnlp(os.P_WAIT, rsvgPath, rsvgPath,
|
||||
"--source-rect=%g:%g:%g:%g" % (rectangle[0], rectangle[1], width, height),
|
||||
"--output=" + os.path.join(out_dir, "%gx%g/%s.png" % (width, height, artwork_name)),
|
||||
file_path)
|
||||
|
||||
def renderSvgIcon (file_path, out_dir):
|
||||
artwork_name, doc_size, rectangles = parseSVG (file_path)
|
||||
for rectangle in rectangles:
|
||||
renderSvgRsvg(file_path, out_dir, artwork_name, rectangle, doc_size)
|
||||
|
||||
def getTargetNames (file_path):
|
||||
"""get a list of target names to be rendered from the given source SVG
|
||||
usable to setup the build targets for SCons
|
||||
"""
|
||||
artwork_name, _ , rectangles = parseSVG (file_path)
|
||||
return ["%gx%g/%s.png" % (rectangle[2], rectangle[3], artwork_name) for rectangle in rectangles ]
|
||||
|
||||
|
||||
def printHelp():
|
||||
print "render-icon.py SRCFILE.svg TARGETDIR"
|
||||
print "An icon rendering utility script for lumiera"
|
||||
|
||||
def parseArguments(argv):
|
||||
_optlist, args = getopt.getopt(argv, "")
|
||||
|
||||
if len(args) == 2:
|
||||
return args[0], args[1]
|
||||
|
||||
printHelp()
|
||||
return None, None
|
||||
|
||||
|
||||
def main (argv):
|
||||
in_path, out_dir = parseArguments(argv)
|
||||
|
||||
if not (in_path and out_dir):
|
||||
print "Missing arguments in_path and out_dir."
|
||||
sys.exit(1)
|
||||
|
||||
if os.path.isfile(out_dir):
|
||||
print "Unable to use '%s' as output directory, because it\'s a file." % out_dir
|
||||
sys.exit(1)
|
||||
if not os.path.isdir(out_dir):
|
||||
print "Output directory '%s' not found." % out_dir
|
||||
sys.exit(1)
|
||||
|
||||
# Create the icons folders
|
||||
createDirectory(os.path.join(out_dir, "48x48"))
|
||||
createDirectory(os.path.join(out_dir, "32x32"))
|
||||
createDirectory(os.path.join(out_dir, "24x24"))
|
||||
createDirectory(os.path.join(out_dir, "22x22"))
|
||||
createDirectory(os.path.join(out_dir, "16x16"))
|
||||
|
||||
renderSvgIcon (in_path, out_dir)
|
||||
|
||||
|
||||
|
||||
|
||||
if __name__=="__main__":
|
||||
main(sys.argv[1:])
|
||||
|
||||
|
|
@ -22,11 +22,10 @@
|
|||
#####################################################################
|
||||
|
||||
|
||||
import os
|
||||
from os import path
|
||||
|
||||
import SCons
|
||||
import SCons.SConf
|
||||
from SCons.Action import Action
|
||||
from SCons.Environment import Environment
|
||||
|
||||
from Buildhelper import *
|
||||
|
|
@ -38,9 +37,15 @@ class LumieraEnvironment(Environment):
|
|||
This allows us to carry structured config data without
|
||||
using global vars. Idea inspired by Ardour.
|
||||
"""
|
||||
def __init__(self, pathConfig, **kw):
|
||||
Environment.__init__ (self,**kw)
|
||||
self.path = Record (pathConfig)
|
||||
def __init__(self, buildSetup, buildVars, **kw):
|
||||
kw.update(VERSION = buildSetup.VERSION
|
||||
,TARGDIR = buildSetup.TARGDIR
|
||||
,DESTDIR = '$INSTALLDIR/$PREFIX'
|
||||
,toolpath = [buildSetup.TOOLDIR ]
|
||||
,variables = buildVars
|
||||
)
|
||||
Environment.__init__ (self, **kw)
|
||||
self.path = Record (extract_localPathDefs(buildSetup)) # e.g. buildExe -> env.path.buildExe
|
||||
self.libInfo = {}
|
||||
self.Tool("BuilderGCH")
|
||||
self.Tool("BuilderDoxygen")
|
||||
|
|
@ -49,6 +54,7 @@ class LumieraEnvironment(Environment):
|
|||
register_LumieraResourceBuilder(self)
|
||||
register_LumieraCustomBuilders(self)
|
||||
|
||||
|
||||
def Configure (self, *args, **kw):
|
||||
kw['env'] = self
|
||||
return apply(LumieraConfigContext, args, kw)
|
||||
|
|
@ -123,7 +129,7 @@ def register_LumieraResourceBuilder(env):
|
|||
used to generate png from the svg source using librsvg.
|
||||
"""
|
||||
|
||||
import render_icon as renderer # load Joel's python script for invoking the rsvg-convert (SVG render)
|
||||
import IconSvgRenderer as renderer # load Joel's python script for invoking the rsvg-convert (SVG render)
|
||||
renderer.rsvgPath = env.subst("$TARGDIR/rsvg-convert")
|
||||
|
||||
def invokeRenderer(target, source, env):
|
||||
|
|
@ -151,43 +157,44 @@ def register_LumieraResourceBuilder(env):
|
|||
return (generateTargets, source)
|
||||
|
||||
def IconResource(env, source):
|
||||
"""Copy icon pixmap to corresponding icon dir. """
|
||||
subdir = getDirname(str(source))
|
||||
toBuild = env.path.buildIcon+subdir
|
||||
toInstall = env.path.installIcon+subdir
|
||||
env.Install (toInstall, source)
|
||||
return env.Install(toBuild, source)
|
||||
"""Copy icon pixmap to corresponding icon dir. """
|
||||
subdir = getDirname(str(source))
|
||||
toBuild = env.path.buildIcon+subdir
|
||||
toInstall = env.path.installIcon+subdir
|
||||
env.Install (toInstall, source)
|
||||
return env.Install(toBuild, source)
|
||||
|
||||
def GuiResource(env, source):
|
||||
subdir = getDirname(str(source))
|
||||
toBuild = env.path.buildUIRes+subdir
|
||||
toInstall = env.path.installUIRes+subdir
|
||||
env.Install (toInstall, source)
|
||||
return env.Install(toBuild, source)
|
||||
subdir = getDirname(str(source))
|
||||
toBuild = env.path.buildUIRes+subdir
|
||||
toInstall = env.path.installUIRes+subdir
|
||||
env.Install (toInstall, source)
|
||||
return env.Install(toBuild, source)
|
||||
|
||||
def ConfigData(env, source, targetDir=None):
|
||||
""" install (copy) configuration- and metadata.
|
||||
target dir is either the install location configured (in SConstruct),
|
||||
or an explicitly given absolute or relative path segment, which might refer
|
||||
to the location of the executable through the $ORIGIN token
|
||||
"""
|
||||
subdir = getDirname(str(source), env.path.srcConf) # removes source location path prefix
|
||||
if targetDir:
|
||||
if path.isabs(targetDir):
|
||||
toBuild = toInstall = path.join(targetDir,subdir)
|
||||
else:
|
||||
if targetDir.startswith('$ORIGIN'):
|
||||
targetDir = targetDir[len('$ORIGIN'):]
|
||||
toBuild = path.join(env.path.buildExe, targetDir, subdir)
|
||||
toInstall = path.join(env.path.installExe, targetDir, subdir)
|
||||
else:
|
||||
toBuild = path.join(env.path.buildConf, targetDir, subdir)
|
||||
toInstall = path.join(env.path.installConf, targetDir, subdir)
|
||||
else:
|
||||
toBuild = path.join(env.path.buildConf,subdir)
|
||||
toInstall = path.join(env.path.installConf,subdir)
|
||||
env.Install (toInstall, source)
|
||||
return env.Install(toBuild, source)
|
||||
def ConfigData(env, prefix, source, targetDir=None):
|
||||
""" install (copy) configuration- and metadata.
|
||||
target dir is either the install location configured (in SConstruct),
|
||||
or an explicitly given absolute or relative path segment, which might refer
|
||||
to the location of the executable through the $ORIGIN token
|
||||
"""
|
||||
source = path.join(prefix,str(source))
|
||||
subdir = getDirname(source, prefix) # removes source location path prefix
|
||||
if targetDir:
|
||||
if path.isabs(targetDir):
|
||||
toBuild = toInstall = path.join(targetDir,subdir)
|
||||
else:
|
||||
if targetDir.startswith('$ORIGIN'):
|
||||
targetDir = targetDir[len('$ORIGIN'):]
|
||||
toBuild = path.join(env.path.buildExe, targetDir, subdir)
|
||||
toInstall = path.join(env.path.installExe, targetDir, subdir)
|
||||
else:
|
||||
toBuild = path.join(env.path.buildConf, targetDir, subdir)
|
||||
toInstall = path.join(env.path.installConf, targetDir, subdir)
|
||||
else:
|
||||
toBuild = path.join(env.path.buildConf,subdir)
|
||||
toInstall = path.join(env.path.installConf,subdir)
|
||||
env.Install (toInstall, source)
|
||||
return env.Install(toBuild, source)
|
||||
|
||||
|
||||
buildIcon = env.Builder( action = Action(invokeRenderer, "rendering Icon: $SOURCE --> $TARGETS")
|
||||
|
|
@ -205,8 +212,8 @@ def register_LumieraResourceBuilder(env):
|
|||
class WrappedStandardExeBuilder(SCons.Util.Proxy):
|
||||
""" Helper to add customisations and default configurations to SCons standard builders.
|
||||
The original builder object is wrapped and most calls are simply forwarded to this
|
||||
wrapped object by Python magic. But some calls are intecepted in order to inject
|
||||
suitalbe default configuration based on the project setup.
|
||||
wrapped object by Python magic. But some calls are intercepted in order to inject
|
||||
suitable default configuration based on the project setup.
|
||||
"""
|
||||
|
||||
def __init__(self, originalBuilder):
|
||||
|
|
@ -291,7 +298,7 @@ class LumieraModuleBuilder(WrappedStandardExeBuilder):
|
|||
explicit spec, falling back on the lib filename
|
||||
"""
|
||||
if 'soname' in kw:
|
||||
soname = self.subst(kw['soname']) # explicitely defined by user
|
||||
soname = self.subst(kw['soname']) # explicitly defined by user
|
||||
else: # else: use the library filename as DT_SONAME
|
||||
if SCons.Util.is_String(target):
|
||||
pathname = target.strip()
|
||||
|
|
@ -331,7 +338,7 @@ class LumieraPluginBuilder(LumieraModuleBuilder):
|
|||
|
||||
|
||||
def register_LumieraCustomBuilders (lumiEnv):
|
||||
""" install the customised builder versions tightly integrated with our buildsystem.
|
||||
""" install the customised builder versions tightly integrated with our build system.
|
||||
Especially, these builders automatically add the build and installation locations
|
||||
and set the RPATH and SONAME in a way to allow a relocatable Lumiera directory structure
|
||||
"""
|
||||
|
|
@ -362,7 +369,7 @@ def register_LumieraCustomBuilders (lumiEnv):
|
|||
action = Action(makeLink, "Install link: $TARGET -> "+srcSpec)
|
||||
env.Command (target,source, action)
|
||||
|
||||
# adding SymLink direclty as method on the environment object
|
||||
# adding SymLink directly as method on the environment object
|
||||
# Probably that should better be a real builder, but I couldn't figure out
|
||||
# how to get the linktext through literally, which is necessary for relative links.
|
||||
# Judging from the sourcecode of SCons.Builder.BuilderBase, there seems to be no way
|
||||
|
|
|
|||
81
admin/scons/Options.py
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
# -*- python -*-
|
||||
##
|
||||
## Options.py - SCons build: command line options and help
|
||||
##
|
||||
|
||||
# Copyright (C) Lumiera.org
|
||||
# 2012, Hermann Vosseler <Ichthyostega@web.de>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License as
|
||||
# published by the Free Software Foundation; either version 2 of
|
||||
# the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
#####################################################################
|
||||
|
||||
|
||||
from SCons.Script import PathVariable, EnumVariable, BoolVariable, Help
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def defineCmdlineVariables(buildVars):
|
||||
""" several toggles and configuration variables can be set on the commandline,
|
||||
current settings will be persisted in a options cache file.
|
||||
you may define custom variable settings in a separate file.
|
||||
Commandline will override both.
|
||||
"""
|
||||
buildVars.AddVariables(
|
||||
('ARCHFLAGS', 'Set architecture-specific compilation flags (passed literally to gcc)','')
|
||||
,('CC', 'Set the C compiler to use.', 'gcc')
|
||||
,('CXX', 'Set the C++ compiler to use.', 'g++')
|
||||
,PathVariable('CCACHE', 'Integrate with CCache', '', PathVariable.PathAccept)
|
||||
,PathVariable('DISTCC', 'Invoke C/C++ compiler commands through DistCC', '', PathVariable.PathAccept)
|
||||
,EnumVariable('BUILDLEVEL', 'NoBug build level for debugging', 'ALPHA', allowed_values=('ALPHA', 'BETA', 'RELEASE'))
|
||||
,BoolVariable('DEBUG', 'Build with debugging information and no optimisations', False)
|
||||
,BoolVariable('OPTIMIZE', 'Build with strong optimisation (-O3)', False)
|
||||
,BoolVariable('VALGRIND', 'Run Testsuite under valgrind control', True)
|
||||
,BoolVariable('VERBOSE', 'Print full build commands', False)
|
||||
,('TESTSUITES', 'Run only Testsuites matching the given pattern', '')
|
||||
# ,BoolVariable('OPENGL', 'Include support for OpenGL preview rendering', False)
|
||||
# ,EnumVariable('DIST_TARGET', 'Build target architecture', 'auto',
|
||||
# allowed_values=('auto', 'i386', 'i686', 'x86_64' ), ignorecase=2)
|
||||
,PathVariable('PREFIX', 'Installation dir prefix', 'usr/local', PathVariable.PathAccept)
|
||||
,PathVariable('INSTALLDIR', 'Root output directory for install. Final installation will happen in INSTALLDIR/PREFIX/... ', '/', PathVariable.PathIsDir)
|
||||
,PathVariable('PKGLIBDIR', 'Installation dir for plugins, defaults to PREFIX/lib/lumiera/modules', '',PathVariable.PathAccept)
|
||||
,PathVariable('PKGDATADIR', 'Installation dir for default config, usually PREFIX/share/lumiera', '',PathVariable.PathAccept)
|
||||
)
|
||||
|
||||
|
||||
|
||||
def prepareOptionsHelp(buildVars,env):
|
||||
prelude = """
|
||||
USAGE: scons [-c] [OPTS] [key=val [key=val...]] [TARGETS]
|
||||
Build and optionally install Lumiera.
|
||||
Without specifying any target, just the (re)build target will run.
|
||||
Add -c to the commandline to clean up anything a given target would produce
|
||||
|
||||
Special Targets:
|
||||
build : just compile and link
|
||||
research: build experimental code (might fail)
|
||||
testcode: additionally compile the Testsuite
|
||||
check : build and run the Testsuite
|
||||
doc : generate documentation (Doxygen)
|
||||
all : build and testcode and doc
|
||||
install : install created artifacts at PREFIX
|
||||
|
||||
Configuration Options:
|
||||
"""
|
||||
Help(prelude + buildVars.GenerateHelpText(env))
|
||||
|
||||
|
||||
|
||||
149
admin/scons/Platform.py
Normal file
|
|
@ -0,0 +1,149 @@
|
|||
# -*- python -*-
|
||||
##
|
||||
## Platform.py - SCons build: platform configuration and library detection
|
||||
##
|
||||
|
||||
# Copyright (C) Lumiera.org
|
||||
# 2012, Hermann Vosseler <Ichthyostega@web.de>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License as
|
||||
# published by the Free Software Foundation; either version 2 of
|
||||
# the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
#####################################################################
|
||||
|
||||
|
||||
from SCons.Script import Exit
|
||||
from Buildhelper import isCleanupOperation, isHelpRequest
|
||||
|
||||
|
||||
|
||||
|
||||
def configure(env):
|
||||
""" locate required libraries.
|
||||
setup platform specific options.
|
||||
Abort build in case of failure.
|
||||
"""
|
||||
if isCleanupOperation(env) or isHelpRequest():
|
||||
return env # skip configure in these cases
|
||||
|
||||
conf = env.Configure()
|
||||
# run all configuration checks in the build environment defined thus far
|
||||
|
||||
# Perform checks for prerequisites --------------------------------------------
|
||||
problems = []
|
||||
if not conf.TryAction('pkg-config --version > $TARGET')[0]:
|
||||
problems.append('We need pkg-config for including library configurations, exiting.')
|
||||
|
||||
if not conf.CheckLibWithHeader('m', 'math.h','C'):
|
||||
problems.append('Did not find math.h / libm.')
|
||||
|
||||
if not conf.CheckLibWithHeader('dl', 'dlfcn.h', 'C'):
|
||||
problems.append('Functions for runtime dynamic loading not available.')
|
||||
|
||||
if not conf.CheckLibWithHeader('pthread', 'pthread.h', 'C'):
|
||||
problems.append('Did not find the pthread lib or pthread.h.')
|
||||
else:
|
||||
conf.env.Append(CPPFLAGS = ' -DHAVE_PTHREAD')
|
||||
conf.env.Append(CCFLAGS = ' -pthread')
|
||||
|
||||
if conf.CheckCHeader('execinfo.h'):
|
||||
conf.env.Append(CPPFLAGS = ' -DHAVE_EXECINFO_H')
|
||||
|
||||
if conf.CheckCHeader('valgrind/valgrind.h'):
|
||||
conf.env.Append(CPPFLAGS = ' -DHAVE_VALGRIND_H')
|
||||
else:
|
||||
print 'Valgrind not found. The use of Valgrind is optional; building without.'
|
||||
|
||||
if not conf.CheckPkgConfig('nobugmt', 201006.1):
|
||||
problems.append('Did not find NoBug [http://www.lumiera.org/nobug_manual.html].')
|
||||
else:
|
||||
conf.env.mergeConf('nobugmt')
|
||||
|
||||
if not conf.CheckCXXHeader('tr1/memory'):
|
||||
problems.append('We rely on the std::tr1 standard C++ extension for shared_ptr.')
|
||||
|
||||
if not conf.CheckCXXHeader('boost/config.hpp'):
|
||||
problems.append('We need the C++ boost-libraries.')
|
||||
else:
|
||||
if not conf.CheckCXXHeader('boost/scoped_ptr.hpp'):
|
||||
problems.append('We need boost::scoped_ptr (scoped_ptr.hpp).')
|
||||
if not conf.CheckCXXHeader('boost/format.hpp'):
|
||||
problems.append('We need boost::format (header).')
|
||||
if not conf.CheckLibWithHeader('boost_program_options-mt','boost/program_options.hpp','C++'):
|
||||
problems.append('We need boost::program_options (including binary lib for linking).')
|
||||
if not conf.CheckLibWithHeader('boost_system-mt','boost/system/error_code.hpp','C++'):
|
||||
problems.append('We need the boost::system support library (including binary lib).')
|
||||
if not conf.CheckLibWithHeader('boost_filesystem-mt','boost/filesystem.hpp','C++'):
|
||||
problems.append('We need the boost::filesystem lib (including binary lib for linking).')
|
||||
if not conf.CheckLibWithHeader('boost_regex-mt','boost/regex.hpp','C++'):
|
||||
problems.append('We need the boost regular expression lib (incl. binary lib for linking).')
|
||||
|
||||
|
||||
if conf.CheckLib(symbol='clock_gettime'):
|
||||
print 'Using function clock_gettime() as defined in the C-lib...'
|
||||
else:
|
||||
if not conf.CheckLib(symbol='clock_gettime', library='rt'):
|
||||
problems.append('No library known to provide the clock_gettime() function.')
|
||||
|
||||
if not conf.CheckPkgConfig('gavl', 1.0):
|
||||
problems.append('Did not find Gmerlin Audio Video Lib [http://gmerlin.sourceforge.net/gavl.html].')
|
||||
else:
|
||||
conf.env.mergeConf('gavl')
|
||||
|
||||
if not conf.CheckPkgConfig('alsa', '1.0.23'):
|
||||
problems.append('Support for ALSA sound output is required')
|
||||
|
||||
if not conf.CheckPkgConfig('gtkmm-2.4', 2.8):
|
||||
problems.append('Unable to configure GTK--')
|
||||
|
||||
if not conf.CheckPkgConfig('glibmm-2.4', '2.16'):
|
||||
problems.append('Unable to configure Lib glib--')
|
||||
|
||||
if not conf.CheckPkgConfig('gthread-2.0', '2.12.4'):
|
||||
problems.append('Need gthread support lib for glib-- based thread handling.')
|
||||
|
||||
if not conf.CheckPkgConfig('cairomm-1.0', 0.6):
|
||||
problems.append('Unable to configure Cairo--')
|
||||
|
||||
verGDL = '2.27.1'
|
||||
if not conf.CheckPkgConfig('gdl-1.0', verGDL, alias='gdl'):
|
||||
print 'No sufficiently recent (>=%s) version of GDL found. Maybe use custom package gdl-lum?' % verGDL
|
||||
if not conf.CheckPkgConfig('gdl-lum', verGDL, alias='gdl'):
|
||||
problems.append('GNOME Docking Library not found. We either need a sufficiently recent GDL '
|
||||
'version (>=%s), or the custom package "gdl-lum" from Lumiera.org.' % verGDL)
|
||||
|
||||
if not conf.CheckPkgConfig('librsvg-2.0', '2.18.1'):
|
||||
problems.append('Need rsvg Library for rendering icons.')
|
||||
|
||||
if not conf.CheckCHeader(['X11/Xutil.h', 'X11/Xlib.h'],'<>'):
|
||||
problems.append('Xlib.h and Xutil.h required. Please install libx11-dev.')
|
||||
|
||||
if not conf.CheckPkgConfig('xv') : problems.append('Need libXv...')
|
||||
if not conf.CheckPkgConfig('xext'): problems.append('Need libXext.')
|
||||
|
||||
|
||||
# report missing dependencies
|
||||
if problems:
|
||||
print "*** unable to build due to the following problems:"
|
||||
for isue in problems:
|
||||
print " * %s" % isue
|
||||
print
|
||||
print "build aborted."
|
||||
Exit(1)
|
||||
|
||||
print "** Gathered Library Info: %s" % conf.env.libInfo.keys()
|
||||
|
||||
|
||||
# create new env containing the finished configuration
|
||||
return conf.Finish()
|
||||
|
||||
137
admin/scons/Setup.py
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
# -*- python -*-
|
||||
##
|
||||
## Setup.py - SCons build: setup, definitions and compiler flags
|
||||
##
|
||||
|
||||
# Copyright (C) Lumiera.org
|
||||
# 2012, Hermann Vosseler <Ichthyostega@web.de>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License as
|
||||
# published by the Free Software Foundation; either version 2 of
|
||||
# the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
#####################################################################
|
||||
|
||||
from SCons.Script import EnsurePythonVersion, EnsureSConsVersion, Variables, Decider
|
||||
|
||||
from LumieraEnvironment import *
|
||||
from Buildhelper import *
|
||||
import Options
|
||||
|
||||
|
||||
|
||||
#-------------------------------------------------------Configuration
|
||||
TARGDIR = 'target'
|
||||
VERSION = '0.pre.01'
|
||||
TOOLDIR = './admin/scons' # SCons plugins
|
||||
OPTCACHE = 'optcache'
|
||||
CUSTOPTFILE = 'custom-options'
|
||||
|
||||
# these are accessible via env.path.xxxx
|
||||
buildExe = '#$TARGDIR'
|
||||
buildLib = '#$TARGDIR/modules'
|
||||
buildPlug = '#$TARGDIR/modules'
|
||||
buildIcon = '#$TARGDIR/gui/icons'
|
||||
buildUIRes = '#$TARGDIR/'
|
||||
buildConf = '#$TARGDIR/config'
|
||||
installExe = '#$DESTDIR/lib/lumiera'
|
||||
installLib = '#$DESTDIR/lib/lumiera/modules'
|
||||
installPlug = '#$DESTDIR/lib/lumiera/modules'
|
||||
installIcon = '#$DESTDIR/share/lumiera/icons'
|
||||
installUIRes = '#$DESTDIR/share/lumiera/'
|
||||
installConf = '#$DESTDIR/lib/lumiera/config'
|
||||
|
||||
#-------------------------------------------------------Configuration
|
||||
buildSetup = Record(locals())
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def defineBuildEnvironment():
|
||||
""" create a custom build environment,
|
||||
define the basic compiler and linker flags,
|
||||
define locations in source and target tree,
|
||||
parse the commandline and pick up options
|
||||
"""
|
||||
EnsureSConsVersion(1,0)
|
||||
EnsurePythonVersion(2,4)
|
||||
Decider('MD5-timestamp') # detect changed files by timestamp, then do a MD5
|
||||
|
||||
buildVars = Variables([OPTCACHE, CUSTOPTFILE])
|
||||
Options.defineCmdlineVariables(buildVars)
|
||||
env = LumieraEnvironment(buildSetup, buildVars)
|
||||
|
||||
env.Replace( CPPPATH =["#src"] # used to find includes, "#" means always absolute to build-root
|
||||
, CPPDEFINES=['LUMIERA_VERSION='+VERSION ] # note: it's a list to append further defines
|
||||
, CCFLAGS='-Wall -Wextra '
|
||||
, CFLAGS='-std=gnu99'
|
||||
)
|
||||
handleVerboseMessages(env)
|
||||
handleNoBugSwitches(env)
|
||||
|
||||
env.Append(CPPDEFINES = '_GNU_SOURCE')
|
||||
appendCppDefine(env,'DEBUG','DEBUG', 'NDEBUG')
|
||||
# appendCppDefine(env,'OPENGL','USE_OPENGL')
|
||||
appendVal(env,'ARCHFLAGS','CCFLAGS') # for both C and C++
|
||||
appendVal(env,'OPTIMIZE', 'CCFLAGS', val=' -O3')
|
||||
appendVal(env,'DEBUG', 'CCFLAGS', val=' -ggdb')
|
||||
|
||||
# setup search path for Lumiera plugins
|
||||
appendCppDefine(env,'PKGLIBDIR','LUMIERA_PLUGIN_PATH=\\"$PKGLIBDIR/:ORIGIN/modules\\"'
|
||||
,'LUMIERA_PLUGIN_PATH=\\"ORIGIN/modules\\"')
|
||||
appendCppDefine(env,'PKGDATADIR','LUMIERA_CONFIG_PATH=\\"$PKGLIBDIR/:.\\"'
|
||||
,'LUMIERA_CONFIG_PATH=\\"$DESTDIR/share/lumiera/:.\\"')
|
||||
|
||||
Options.prepareOptionsHelp(buildVars,env)
|
||||
buildVars.Save(OPTCACHE, env)
|
||||
return env
|
||||
|
||||
|
||||
|
||||
def appendCppDefine(env,var,cppVar, elseVal=''):
|
||||
if env[var]:
|
||||
env.Append(CPPDEFINES = env.subst(cppVar) )
|
||||
elif elseVal:
|
||||
env.Append(CPPDEFINES = env.subst(elseVal))
|
||||
|
||||
def appendVal(env,var,targetVar,val=None):
|
||||
if env[var]:
|
||||
env.Append( **{targetVar: env.subst(val) or env[var]})
|
||||
|
||||
|
||||
def handleNoBugSwitches(env):
|
||||
""" set the build level for NoBug.
|
||||
Release builds imply no DEBUG
|
||||
whereas ALPHA and BETA require DEBUG
|
||||
"""
|
||||
level = env['BUILDLEVEL']
|
||||
if level in ['ALPHA', 'BETA']:
|
||||
if not env['DEBUG']:
|
||||
print 'Warning: NoBug ALPHA or BETA builds requires DEBUG=yes, switching DEBUG on!'
|
||||
env.Replace( DEBUG = 1 )
|
||||
env.Append(CPPDEFINES = 'EBUG_'+level)
|
||||
elif level == 'RELEASE':
|
||||
env.Replace( DEBUG = 0 )
|
||||
|
||||
|
||||
def handleVerboseMessages(env):
|
||||
""" toggle verbose build output """
|
||||
if not env['VERBOSE']:
|
||||
# SetOption('silent', True)
|
||||
env['CCCOMSTR'] = env['SHCCCOMSTR'] = " Compiling $SOURCE"
|
||||
env['CXXCOMSTR'] = env['SHCXXCOMSTR'] = " Compiling++ $SOURCE"
|
||||
env['LINKCOMSTR'] = " Linking --> $TARGET"
|
||||
env['LDMODULECOMSTR'] = " creating module [ $TARGET ]"
|
||||
|
||||
|
||||
|
||||
25
data/SConscript
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
# -*- python -*-
|
||||
##
|
||||
## SConscript - SCons buildscript for Icons and Resources
|
||||
##
|
||||
|
||||
from Buildhelper import scanSubtree
|
||||
|
||||
Import('env')
|
||||
|
||||
|
||||
# define Icons to render and install
|
||||
vector_icon_dir = 'icons/svg'
|
||||
prerendered_icon_dir = 'icons/prerendered'
|
||||
|
||||
icons = ( [env.IconRender(f) for f in scanSubtree(vector_icon_dir, ['*.svg'])]
|
||||
+ [env.IconResource(f) for f in scanSubtree(prerendered_icon_dir, ['*.png'])]
|
||||
)
|
||||
|
||||
#define Configuration files to install (dir-prefix, name)
|
||||
config = ( env.ConfigData('config','setup.ini', targetDir='$ORIGIN')
|
||||
+ env.ConfigData('config','dummy_lumiera.ini')
|
||||
)
|
||||
|
||||
|
||||
Export('icons config')
|
||||
26
data/icons/README
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
#
|
||||
# Lumiera Icon Artwork
|
||||
#
|
||||
# Copyright (C) Lumiera.org
|
||||
# 2008, Joel Holdsworth <joel@airwebreathe.org.uk>
|
||||
#
|
||||
# Icon Artwork and similar materials accompanying the Lumiera Application
|
||||
# is dual-licensed under the GNU General Public License version 2 or above,
|
||||
# and
|
||||
# Creative Commons Attribution-ShareAlike 3.0 Unported License
|
||||
#
|
||||
#
|
||||
|
||||
|
||||
This directory holds Icons and similar graphics resources for the Lumiera GUI.
|
||||
|
||||
- prerendered: Raster image Icons rendered into a selection of sizes
|
||||
- svg: Scalable Vector Grahpics Icons, to be rendered into suitable sizes
|
||||
by the build process. Rendering is done with the help of lib Cairo.
|
||||
The build creates an executable from src/tools/rsvg-convert.c
|
||||
The invocation of the icon rendering is done with the help of a
|
||||
Python script IconSvgRenderer.py, which first parses the SVG document
|
||||
and then invokes rsvg-convert to generate the raster images.
|
||||
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 540 B After Width: | Height: | Size: 540 B |
|
Before Width: | Height: | Size: 453 B After Width: | Height: | Size: 453 B |
|
Before Width: | Height: | Size: 631 B After Width: | Height: | Size: 631 B |
|
Before Width: | Height: | Size: 695 B After Width: | Height: | Size: 695 B |
|
Before Width: | Height: | Size: 788 B After Width: | Height: | Size: 788 B |
|
Before Width: | Height: | Size: 1 KiB After Width: | Height: | Size: 1 KiB |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 58 KiB After Width: | Height: | Size: 58 KiB |
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 7.2 KiB After Width: | Height: | Size: 7.2 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
17
doc/SConscript
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
# -*- python -*-
|
||||
##
|
||||
## SConscript - SCons buildscript for Documentation
|
||||
##
|
||||
|
||||
from Buildhelper import scanSubtree
|
||||
|
||||
Import('env')
|
||||
|
||||
|
||||
doxydoc = env.Doxygen('devel/Doxyfile')
|
||||
|
||||
# env.Install(dir = '$DESTDIR/share/doc/lumiera$VERSION/devel', source=documentation)
|
||||
env.Clean (doxydoc, doxydoc + ['devel/,doxylog','devel/warnings.txt'])
|
||||
|
||||
|
||||
Export('doxydoc')
|
||||
37
doc/devel/meeting_summary/2012-01-11.txt
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
2012-01-11 Lumiera Developers Meeting
|
||||
=====================================
|
||||
:Author: cehteh
|
||||
:Date: 2012-01-11
|
||||
|
||||
Jan 11, 2011 on #lumiera 20:00 - 22:30
|
||||
|
||||
__Participants__
|
||||
|
||||
* cehteh
|
||||
* ichthyo
|
||||
* benn
|
||||
* raffa
|
||||
|
||||
Conclusions
|
||||
-----------
|
||||
|
||||
. _ichthyo_ removed most of the TiddlyWikis, and worked the content into the website
|
||||
. _cehteh_ reports that Lumiera got another donation (75 €), arrangements with
|
||||
the FFIS to get access (view) about the donations account are under way. We'll
|
||||
ask donors then if they want to be published or stay anonymous and will set up
|
||||
a wiki page listing donations and expenses.
|
||||
. _ichthyo_ reworked the SCons build, as discussed last time
|
||||
. _cehteh_ writes a very short RfC, to document that we're using SCons for now.
|
||||
. possibly no one going to LAC, too far away
|
||||
. we discussed a link checker / link resolver for the website.
|
||||
The idea is to have a semi automatic tool, which is used locally when
|
||||
authoring website content to find cross references.
|
||||
. _benny_ and _ichthyo_ follow up on the
|
||||
link:http://libregraphicsmag.com/[Libre Graphics Magazine]'s offer to promote
|
||||
graphics and media projects and try to get into discussion with them and see
|
||||
what can be done within our limited time.
|
||||
. when it comes to have a working example for media file output, we stick to the
|
||||
mainstream solutions *ffmpeg* and or *gstreamer*, but care not to lock ourselves
|
||||
into a single solution. Concluded that we do this over plugin interfaces --
|
||||
it mostly boils down to support ffmpeg -- besides we'll investigate simple
|
||||
alternatives for basic output.
|
||||
88
doc/devel/rfc/MakeSconsTheOfficialBuildSystem.txt
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
Make Scons the official build System
|
||||
====================================
|
||||
|
||||
// please don't remove the //word: comments
|
||||
|
||||
[grid="all"]
|
||||
`------------`-----------------------
|
||||
*State* _Final_
|
||||
*Date* _Mi 11 Jan 2012 21:45:58 CET_
|
||||
*Proposed by* Christian Thaeter <ct@pipapo.org>
|
||||
-------------------------------------
|
||||
|
||||
********************************************************************************
|
||||
.Abstract
|
||||
_Bless SCons the default build system for Lumiera._
|
||||
********************************************************************************
|
||||
|
||||
Description
|
||||
-----------
|
||||
//description: add a detailed description:
|
||||
|
||||
So far we using autotools and scons in parallel. Over time the need arose to have one
|
||||
reliable supported build system. This shall be SCons.
|
||||
|
||||
|
||||
Tasks
|
||||
~~~~~
|
||||
// List what needs to be done to implement this Proposal:
|
||||
// * first step ([green]#✔ done#)
|
||||
// * second step [,yellow]#WIP#
|
||||
Nothing to do except for releases SCons _must be working_ and all non functional
|
||||
build systems will be stripped on the release branches.
|
||||
|
||||
|
||||
////
|
||||
Discussion
|
||||
~~~~~~~~~~
|
||||
|
||||
Pros
|
||||
^^^^
|
||||
// add a fact list/enumeration which make this suitable:
|
||||
// * foo
|
||||
// * bar ...
|
||||
|
||||
|
||||
|
||||
Cons
|
||||
^^^^
|
||||
// fact list of the known/considered bad implications:
|
||||
|
||||
|
||||
|
||||
Alternatives
|
||||
^^^^^^^^^^^^
|
||||
//alternatives: explain alternatives and tell why they are not viable:
|
||||
|
||||
|
||||
|
||||
Rationale
|
||||
---------
|
||||
//rationale: Give a concise summary why it should be done *this* way:
|
||||
|
||||
////
|
||||
|
||||
|
||||
Conclusion
|
||||
----------
|
||||
//conclusion: When approbate (this proposal becomes a Final)
|
||||
// write some conclusions about its process:
|
||||
|
||||
result of discussions and evaluation during the last years
|
||||
|
||||
|
||||
Comments
|
||||
--------
|
||||
//comments: append below
|
||||
|
||||
.State -> Final
|
||||
//add reason
|
||||
Decided on the December 2011 Developer meeting.
|
||||
|
||||
Christian Thaeter:: 'Wed 11 Jan 2012 22:28:36 CET' ~<ct@pipapo.org>~
|
||||
|
||||
//endof_comments:
|
||||
|
||||
''''
|
||||
Back to link:/documentation/devel/rfc.html[Lumiera Design Process overview]
|
||||
|
||||
BIN
doc/devel/uml/fig151685.png
Normal file
|
After Width: | Height: | Size: 25 KiB |
|
|
@ -1,97 +0,0 @@
|
|||
# Copyright (C) Lumiera.org
|
||||
# 2008, Joel Holdsworth <joel@airwebreathe.org.uk>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License as
|
||||
# published by the Free Software Foundation; either version 2 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
svgdir = $(top_srcdir)/icons/svg
|
||||
prerendereddir = $(top_srcdir)/icons/prerendered
|
||||
icondir = $(top_builddir)
|
||||
iconcommand = python $(top_srcdir)/admin/render_icon.py
|
||||
|
||||
16x16 = $(icondir)/16x16
|
||||
22x22 = $(icondir)/22x22
|
||||
24x24 = $(icondir)/24x24
|
||||
32x32 = $(icondir)/32x32
|
||||
48x48 = $(icondir)/48x48
|
||||
|
||||
16x16pre = $(prerendereddir)/16x16
|
||||
22x22pre = $(prerendereddir)/22x22
|
||||
24x24pre = $(prerendereddir)/24x24
|
||||
32x32pre = $(prerendereddir)/32x32
|
||||
48x48pre = $(prerendereddir)/48x48
|
||||
|
||||
icons = \
|
||||
$(16x16)/app-icon.png $(22x22)/app-icon.png $(24x24)/app-icon.png $(32x32)/app-icon.png $(48x48)/app-icon.png \
|
||||
$(16x16)/tool-arrow.png $(22x22)/tool-arrow.png $(24x24)/tool-arrow.png $(32x32)/tool-arrow.png $(48x48)/tool-arrow.png \
|
||||
$(16x16)/tool-i-beam.png $(22x22)/tool-i-beam.png $(24x24)/tool-i-beam.png $(32x32)/tool-i-beam.png $(48x48)/tool-i-beam.png \
|
||||
$(16x16)/track-disabled.png \
|
||||
$(16x16)/track-enabled.png \
|
||||
$(16x16)/track-locked.png \
|
||||
$(16x16)/track-unlocked.png \
|
||||
$(16x16)/panel-assets.png $(22x22)/panel-assets.png $(32x32)/panel-assets.png \
|
||||
$(16x16)/panel-timeline.png \
|
||||
$(16x16)/panel-viewer.png $(22x22)/panel-viewer.png $(32x32)/panel-viewer.png
|
||||
|
||||
dist_pkgdata_DATA += $(icons)
|
||||
|
||||
all: $(icons)
|
||||
|
||||
clean-local:
|
||||
rm -rf $(16x16) $(22x22) $(24x24) $(32x32) $(48x48)
|
||||
|
||||
# ========== SVG Icons ==========
|
||||
|
||||
# App Icon
|
||||
|
||||
$(16x16)/app-icon.png $(22x22)/app-icon.png $(24x24)/app-icon.png $(32x32)/app-icon.png $(48x48)/app-icon.png : $(svgdir)/app-icon.svg $(top_builddir)/rsvg-convert
|
||||
$(iconcommand) $< $(icondir)
|
||||
|
||||
# Timeline Tools
|
||||
|
||||
$(16x16)/tool-arrow.png $(22x22)/tool-arrow.png $(24x24)/tool-arrow.png $(32x32)/tool-arrow.png $(48x48)/tool-arrow.png : $(svgdir)/tool-arrow.svg $(top_builddir)/rsvg-convert
|
||||
$(iconcommand) $< $(icondir)
|
||||
$(16x16)/tool-i-beam.png $(22x22)/tool-i-beam.png $(24x24)/tool-i-beam.png $(32x32)/tool-i-beam.png $(48x48)/tool-i-beam.png : $(svgdir)/tool-i-beam.svg $(top_builddir)/rsvg-convert
|
||||
$(iconcommand) $< $(icondir)
|
||||
|
||||
# Timeline Tracks
|
||||
$(16x16)/track-disabled.png : $(svgdir)/track-disabled.svg $(top_builddir)/rsvg-convert
|
||||
$(iconcommand) $< $(icondir)
|
||||
$(16x16)/track-enabled.png : $(svgdir)/track-enabled.svg $(top_builddir)/rsvg-convert
|
||||
$(iconcommand) $< $(icondir)
|
||||
$(16x16)/track-locked.png : $(svgdir)/track-locked.svg $(top_builddir)/rsvg-convert
|
||||
$(iconcommand) $< $(icondir)
|
||||
$(16x16)/track-unlocked.png : $(svgdir)/track-unlocked.svg $(top_builddir)/rsvg-convert
|
||||
$(iconcommand) $< $(icondir)
|
||||
|
||||
# ========== Prerendered Icons ==========
|
||||
|
||||
# Panels
|
||||
|
||||
$(16x16)/panel-assets.png: $(16x16pre)/panel-assets.png
|
||||
cp $(16x16pre)/panel-assets.png $(16x16)
|
||||
$(22x22)/panel-assets.png: $(22x22pre)/panel-assets.png
|
||||
cp $(22x22pre)/panel-assets.png $(22x22)
|
||||
$(32x32)/panel-assets.png: $(32x32pre)/panel-assets.png
|
||||
cp $(32x32pre)/panel-assets.png $(32x32)
|
||||
|
||||
$(16x16)/panel-timeline.png: $(16x16pre)/panel-timeline.png
|
||||
cp $(16x16pre)/panel-timeline.png $(16x16)
|
||||
|
||||
$(16x16)/panel-viewer.png: $(16x16pre)/panel-viewer.png
|
||||
cp $(16x16pre)/panel-viewer.png $(16x16)
|
||||
$(22x22)/panel-viewer.png: $(22x22pre)/panel-viewer.png
|
||||
cp $(22x22pre)/panel-viewer.png $(22x22)
|
||||
$(32x32)/panel-viewer.png: $(32x32pre)/panel-viewer.png
|
||||
cp $(32x32pre)/panel-viewer.png $(32x32)
|
||||
1
research/DIR_INFO
Normal file
|
|
@ -0,0 +1 @@
|
|||
Experiments and Investigations. Not installed
|
||||
22
research/SConscript
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
# -*- python -*-
|
||||
##
|
||||
## SConscript - SCons buildscript for experiments and investigations.
|
||||
## Things defined here usuall won't be installed
|
||||
##
|
||||
|
||||
Import('env core support_lib')
|
||||
|
||||
|
||||
|
||||
envR = env.Clone()
|
||||
# envR.Append(CCFLAGS=' -O3 ')
|
||||
|
||||
# build additional test and administrative tools....
|
||||
experiments = [ envR.Program('try', ['try.cpp'] + support_lib) #### to try out some feature...
|
||||
]
|
||||
|
||||
#
|
||||
# define Phony targets
|
||||
# - 'scons research' triggers building of experimental code
|
||||
#
|
||||
env.Alias('research', experiments )
|
||||
165
research/try.cpp
Normal file
|
|
@ -0,0 +1,165 @@
|
|||
/* try.cpp - for trying out some language features....
|
||||
* scons will create the binary bin/try
|
||||
*
|
||||
*/
|
||||
|
||||
// 8/07 - how to control NOBUG??
|
||||
// execute with NOBUG_LOG='ttt:TRACE' bin/try
|
||||
// 1/08 - working out a static initialisation problem for Visitor (Tag creation)
|
||||
// 1/08 - check 64bit longs
|
||||
// 4/08 - comparison operators on shared_ptr<Asset>
|
||||
// 4/08 - conversions on the value_type used for boost::any
|
||||
// 5/08 - how to guard a downcasting access, so it is compiled in only if the involved types are convertible
|
||||
// 7/08 - combining partial specialisation and subclasses
|
||||
// 10/8 - abusing the STL containers to hold noncopyable values
|
||||
// 6/09 - investigating how to build a mixin template providing an operator bool()
|
||||
// 12/9 - tracking down a strange "warning: type qualifiers ignored on function return type"
|
||||
// 1/10 - can we determine at compile time the presence of a certain function (for duck-typing)?
|
||||
// 4/10 - pretty printing STL containers with python enabled GDB?
|
||||
// 1/11 - exploring numeric limits
|
||||
// 1/11 - integer floor and wrap operation(s)
|
||||
// 1/11 - how to fetch the path of the own executable -- at least under Linux?
|
||||
// 10/11 - simple demo using a pointer and a struct
|
||||
// 11/11 - using the boost random number generator(s)
|
||||
// 12/11 - how to detect if string conversion is possible?
|
||||
// 1/12 - is partial application of member functions possible?
|
||||
|
||||
|
||||
/** @file try.cpp
|
||||
** Research: perform a partial application of a member function.
|
||||
** The result of this partial application should be a functor expecting the remaining arguments.
|
||||
** The idea was to use this at various library functions expecting a functor or callback, so to
|
||||
** improve readability of the client code: clients could then just pass a member pointer, without
|
||||
** the need to use any tr1::bind expression.
|
||||
**
|
||||
** \par Costs in code size
|
||||
** While this turned out to be possible, even without much work, just based on the existing
|
||||
** templates for partial functor application (function-closure.hpp), the resulting code size
|
||||
** is rather sobering. Especially in debug mode, quite some overhead is created, which makes
|
||||
** usage of this convenience feature in general purpose library code rather questionable.
|
||||
** When compiling with -O3 though, most of the overhead will be removed
|
||||
**
|
||||
** The following numbers could be observed:
|
||||
** \code
|
||||
** debug / stripped // debug-O3 / stripped
|
||||
** just using a member pointer: 39013 / 7048 42061 / 7056
|
||||
** using tr1::bind and function: 90375 / 15416 65415 / 9376
|
||||
** partial apply, passing functor: 158727 / 23576 97479 / 11296
|
||||
** partial apply with mem pointer: 119495 / 17816 78031 / 9440
|
||||
** \endcode
|
||||
*/
|
||||
|
||||
|
||||
#include "lib/meta/tuple.hpp"
|
||||
#include "lib/meta/function-closure.hpp"
|
||||
|
||||
//#include <tr1/functional>
|
||||
#include <iostream>
|
||||
|
||||
using lib::meta::Types;
|
||||
using lib::meta::Tuple;
|
||||
//using std::tr1::placeholders::_1;
|
||||
//using std::tr1::placeholders::_2;
|
||||
using std::tr1::function;
|
||||
using std::tr1::bind;
|
||||
|
||||
using std::string;
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
|
||||
|
||||
namespace lib {
|
||||
namespace meta{
|
||||
namespace func{
|
||||
|
||||
|
||||
template<typename SIG, uint num>
|
||||
struct _PupS
|
||||
{
|
||||
typedef typename _Fun<SIG>::Ret Ret;
|
||||
typedef typename _Fun<SIG>::Args::List Args;
|
||||
typedef typename Splice<Args,NullType,num>::Front ArgsFront;
|
||||
typedef typename Splice<Args,NullType,num>::Back ArgsBack;
|
||||
typedef typename Types<ArgsFront>::Seq ArgsToClose;
|
||||
typedef typename Types<ArgsBack>::Seq ArgsRemaining;
|
||||
typedef typename _Sig<Ret,ArgsRemaining>::Type ReducedSignature;
|
||||
|
||||
typedef function<ReducedSignature> Function;
|
||||
};
|
||||
|
||||
template<typename SIG, typename A1>
|
||||
inline
|
||||
typename _PupS<SIG,1>::Function
|
||||
papply (SIG f, A1 a1)
|
||||
{
|
||||
typedef typename _PupS<SIG,1>::ArgsToClose ArgsToClose;
|
||||
typedef Tuple<ArgsToClose> ArgTuple;
|
||||
ArgTuple val(a1);
|
||||
return PApply<SIG,ArgsToClose>::bindFront (f, val);
|
||||
}
|
||||
|
||||
template<typename SIG, typename A1, typename A2>
|
||||
inline
|
||||
typename _PupS<SIG,2>::Function
|
||||
papply (SIG f, A1 a1, A2 a2)
|
||||
{
|
||||
typedef typename _PupS<SIG,2>::ArgPrefix ArgsToClose;
|
||||
typedef Tuple<ArgsToClose> ArgTuple;
|
||||
ArgTuple val(a1,a2);
|
||||
return PApply<SIG,ArgsToClose>::bindFront (f, val);
|
||||
}
|
||||
|
||||
|
||||
}}} // namespace lib::meta::func
|
||||
|
||||
class Something
|
||||
{
|
||||
int i_;
|
||||
|
||||
void
|
||||
privateFun(char a)
|
||||
{
|
||||
char aa(a + i_);
|
||||
cout << "Char-->" << aa <<endl;
|
||||
}
|
||||
|
||||
public:
|
||||
Something(int ii=0)
|
||||
: i_(ii)
|
||||
{ }
|
||||
|
||||
typedef function<void(char)> FunP;
|
||||
|
||||
FunP
|
||||
getBinding()
|
||||
{
|
||||
// function<void(Something*,char)> memf = bind (&Something::privateFun, _1, _2);
|
||||
// return lib::meta::func::papply (memf, this);
|
||||
return lib::meta::func::papply (&Something::privateFun, this);
|
||||
}
|
||||
|
||||
// typedef void (Something::*FunP) (char);
|
||||
//
|
||||
// FunP
|
||||
// getBinding()
|
||||
// {
|
||||
// return &Something::privateFun;
|
||||
// }
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int
|
||||
main (int, char**)
|
||||
{
|
||||
Something some(23);
|
||||
Something::FunP fup = some.getBinding();
|
||||
|
||||
fup ('a');
|
||||
|
||||
cout << "\n.gulp.\n";
|
||||
|
||||
return 0;
|
||||
}
|
||||
48
src/SConscript
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
# -*- python -*-
|
||||
##
|
||||
## SConscript - SCons buildscript for the Lumiera Application.
|
||||
## Definitions how to build the main tree
|
||||
##
|
||||
|
||||
from Buildhelper import srcSubtree
|
||||
from Buildhelper import scanSubtree
|
||||
|
||||
Import('env icons config')
|
||||
|
||||
# define the source file/dirs comprising each artifact to be built.
|
||||
|
||||
lLib = env.SharedLibrary('lumiera', srcSubtree('lib'), install=True)
|
||||
lApp = env.SharedLibrary('lumieracommon', srcSubtree('common'), install=True, LIBS=lLib)
|
||||
lBack = env.SharedLibrary('lumierabackend', srcSubtree('backend'),install=True)
|
||||
lProc = env.SharedLibrary('lumieraproc', srcSubtree('proc'), install=True)
|
||||
|
||||
core = lLib+lApp+lBack+lProc
|
||||
core_lib = core
|
||||
support_lib = lLib
|
||||
|
||||
lumiera = ( env.Program('lumiera', ['lumiera/main.cpp'] + core, install=True)
|
||||
+ config
|
||||
)
|
||||
|
||||
# Install the lumiera application:
|
||||
# symlink the executable into the bin dir
|
||||
env.SymLink('#$DESTDIR/bin/lumiera',env.path.installExe+'lumiera','../lib/lumiera/lumiera')
|
||||
|
||||
|
||||
# building Lumiera Plugins
|
||||
plugins = [] # currently none
|
||||
|
||||
|
||||
# the Lumiera GTK GUI
|
||||
envGtk = env.Clone()
|
||||
envGtk.mergeConf(['gtkmm-2.4','gthread-2.0','cairomm-1.0','gdl','xv','xext','sm'])
|
||||
envGtk.Append(LIBS=core)
|
||||
|
||||
guimodule = envGtk.LumieraPlugin('gtk_gui', srcSubtree('gui'), install=True)
|
||||
gui = ( guimodule
|
||||
+ icons
|
||||
+ [env.GuiResource(f) for f in env.Glob('gui/*.rc')]
|
||||
)
|
||||
|
||||
|
||||
Export('lumiera core core_lib support_lib plugins gui')
|
||||
|
|
@ -83,8 +83,8 @@ namespace backend {
|
|||
|
||||
|
||||
/**
|
||||
* Descriptor holding the global informations,
|
||||
* needed for further handling this media within Lumiera.
|
||||
* Descriptor holding the global information record
|
||||
* required for further handling this kind of media within Lumiera.
|
||||
*/
|
||||
struct MediaDesc
|
||||
{
|
||||
|
|
|
|||
|
|
@ -188,7 +188,7 @@ namespace backend {
|
|||
|
||||
|
||||
/** @note by design there is no possibility to find out
|
||||
* just based on the thread handle, if the thread is alive.
|
||||
* just based on the thread handle if some thread is alive.
|
||||
* We define our own accounting here based on the internals
|
||||
* of the thread wrapper. This will break down, if you mix
|
||||
* uses of the C++ wrapper with the raw C functions. */
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@
|
|||
#include <errno.h>
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @file threads.c
|
||||
*
|
||||
*/
|
||||
|
||||
|
|
@ -93,17 +93,17 @@ thread_loop (void* thread)
|
|||
do {
|
||||
lumiera_threadpool_release_thread(t);
|
||||
LUMIERA_CONDITION_WAIT (t->state != LUMIERA_THREADSTATE_IDLE);
|
||||
INFO (threads, "Thread awaken with state %s", lumiera_threadstate_names[t->state]);
|
||||
TRACE (threads, "Thread awaken with state %s", lumiera_threadstate_names[t->state]);
|
||||
|
||||
// NULL function means: no work to do
|
||||
INFO (threads, "function %p", t->function);
|
||||
TRACE (threads, "function %p", t->function);
|
||||
if (t->function)
|
||||
t->function (t->arguments);
|
||||
TRACE (threads, "function done");
|
||||
|
||||
if (t->kind & LUMIERA_THREAD_JOINABLE)
|
||||
{
|
||||
INFO (threads, "Thread zombified");
|
||||
TRACE (threads, "Thread zombified");
|
||||
/* move error state to data the other thread will it pick up from there */
|
||||
t->arguments = (void*)lumiera_error ();
|
||||
t->state = LUMIERA_THREADSTATE_ZOMBIE;
|
||||
|
|
@ -111,14 +111,14 @@ thread_loop (void* thread)
|
|||
|
||||
LUMIERA_CONDITION_SIGNAL;
|
||||
LUMIERA_CONDITION_WAIT (t->state == LUMIERA_THREADSTATE_JOINED);
|
||||
INFO (threads, "Thread joined");
|
||||
TRACE (threads, "Thread joined");
|
||||
}
|
||||
|
||||
} while (t->state != LUMIERA_THREADSTATE_SHUTDOWN);
|
||||
// SHUTDOWN state
|
||||
|
||||
|
||||
INFO (threads, "Thread Shutdown");
|
||||
TRACE (threads, "Thread done.");
|
||||
}
|
||||
//////////////////////////////////////////////////////////////////////TICKET #844 no error must be pending here, else do app shutdown
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@
|
|||
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @file threads.h
|
||||
*
|
||||
*/
|
||||
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@
|
|||
namespace lumiera { ///////TODO: shouldn't that be namespace lib? or proc?
|
||||
|
||||
using std::string;
|
||||
using lumiera::P;
|
||||
using lib::P;
|
||||
|
||||
|
||||
|
||||
|
|
@ -185,7 +185,7 @@ namespace lumiera { ///////TODO: shouldn't that be namespace lib? or proc?
|
|||
*/
|
||||
template<typename TYPES>
|
||||
class ConfigRules
|
||||
: public typelist::InstantiateForEach<TYPES, QueryHandler>
|
||||
: public lib::meta::InstantiateForEach<TYPES, QueryHandler>
|
||||
{
|
||||
protected:
|
||||
ConfigRules () {}
|
||||
|
|
@ -212,13 +212,13 @@ namespace lumiera { ///////TODO: shouldn't that be namespace lib? or proc?
|
|||
* the list of all concrete types participating in the
|
||||
* rule based config query system
|
||||
*/
|
||||
typedef lumiera::typelist::Types < mobject::session::Track
|
||||
, asset::Pipe
|
||||
, const asset::ProcPatt
|
||||
, asset::Timeline
|
||||
, asset::Sequence
|
||||
> ::List
|
||||
InterfaceTypes;
|
||||
typedef lib::meta::Types < proc::mobject::session::Track
|
||||
, proc::asset::Pipe
|
||||
, const proc::asset::ProcPatt
|
||||
, proc::asset::Timeline
|
||||
, proc::asset::Sequence
|
||||
> ::List
|
||||
InterfaceTypes;
|
||||
|
||||
/**
|
||||
* user-visible Interface to the ConfigRules subsystem.
|
||||
|
|
|
|||
|
|
@ -248,7 +248,7 @@ lumiera_plugin_discover (LumieraPlugin (*callback_load)(const char* plugin),
|
|||
LumieraPlugin
|
||||
lumiera_plugin_load (const char* plugin)
|
||||
{
|
||||
TRACE (pluginloader_dbg);
|
||||
TRACE (pluginloader_dbg, "plugin=%s", plugin);
|
||||
|
||||
/* dispatch on ext, call the registered function */
|
||||
const char* ext = strrchr (plugin, '.');
|
||||
|
|
@ -417,6 +417,7 @@ lumiera_plugin_delete_fn (PSplaynode node)
|
|||
LUMIERA_INTERFACE_CAST(lumieraorg__plugin, 0) self->plugin;
|
||||
lumiera_interfaceregistry_bulkremove_interfaces (handle->plugin_interfaces ());
|
||||
}
|
||||
TRACE (pluginloader_dbg, "unloading plugin/module %s", self->name);
|
||||
itr->lumiera_plugin_unload_fn (self);
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@
|
|||
LumieraPlugin
|
||||
lumiera_plugin_load_DYNLIB (const char* name)
|
||||
{
|
||||
TRACE (pluginloader_dbg);
|
||||
TRACE (pluginloader_dbg, "load DYNLIB: %s", name);
|
||||
REQUIRE (name);
|
||||
LumieraPlugin self = lumiera_plugin_new (name);
|
||||
LumieraInterface plugin = NULL;
|
||||
|
|
|
|||
|
|
@ -54,10 +54,13 @@
|
|||
namespace lumiera {
|
||||
namespace query {
|
||||
|
||||
namespace asset = proc::asset;
|
||||
|
||||
using asset::Pipe;
|
||||
using asset::ProcPatt;
|
||||
using asset::PProcPatt;
|
||||
using mobject::Session;
|
||||
using proc::mobject::Session;
|
||||
using lib::meta::InstantiateChained;
|
||||
|
||||
using util::isnil;
|
||||
|
||||
|
|
@ -246,10 +249,10 @@ namespace lumiera {
|
|||
* values for some types of interest for testing and debugging.
|
||||
*/
|
||||
class MockConfigRules
|
||||
: public typelist::InstantiateChained < InterfaceTypes
|
||||
, LookupPreconfigured // building block used for each of the types
|
||||
, MockTable // for implementing the base class (interface)
|
||||
>
|
||||
: public InstantiateChained < InterfaceTypes
|
||||
, LookupPreconfigured // building block used for each of the types
|
||||
, MockTable // for implementing the base class (interface)
|
||||
>
|
||||
{
|
||||
protected:
|
||||
MockConfigRules (); ///< to be used only by the singleton factory
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Notification(Proxy) - public service allowing to push informations into the GUI
|
||||
Notification(Proxy) - public service allowing to push information into the GUI
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2008, Hermann Vosseler <Ichthyostega@web.de>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
NotificationService - public service allowing to push informations into the GUI
|
||||
NotificationService - public service allowing to push information into the GUI
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2008, Hermann Vosseler <Ichthyostega@web.de>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
NOTIFICATION-SERVICE.hpp - public service allowing to push informations into the GUI
|
||||
NOTIFICATION-SERVICE.hpp - public service allowing to push information into the GUI
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2008, Hermann Vosseler <Ichthyostega@web.de>
|
||||
|
|
|
|||
|
|
@ -189,8 +189,7 @@ TimeCode::set_widget_name(string name)
|
|||
void
|
||||
TimeCode::setup_events()
|
||||
{
|
||||
// FIXME: change to set_can_focus(true) once Debian squeeze is released
|
||||
clock_base.set_flags(CAN_FOCUS);
|
||||
clock_base.set_can_focus(true);
|
||||
|
||||
const Gdk::EventMask eventMask =
|
||||
Gdk::BUTTON_PRESS_MASK|
|
||||
|
|
@ -210,15 +209,14 @@ TimeCode::setup_events()
|
|||
ms_seconds_ebox.add_events(eventMask);
|
||||
audio_frames_ebox.add_events(eventMask);
|
||||
|
||||
// FIXME: change to set_can_focus(true) once Debian squeeze is released
|
||||
hours_ebox.set_flags(CAN_FOCUS);
|
||||
minutes_ebox.set_flags(CAN_FOCUS);
|
||||
seconds_ebox.set_flags(CAN_FOCUS);
|
||||
frames_ebox.set_flags(CAN_FOCUS);
|
||||
audio_frames_ebox.set_flags(CAN_FOCUS);
|
||||
ms_hours_ebox.set_flags(CAN_FOCUS);
|
||||
ms_minutes_ebox.set_flags(CAN_FOCUS);
|
||||
ms_seconds_ebox.set_flags(CAN_FOCUS);
|
||||
hours_ebox.set_can_focus(true);
|
||||
minutes_ebox.set_can_focus(true);
|
||||
seconds_ebox.set_can_focus(true);
|
||||
frames_ebox.set_can_focus(true);
|
||||
audio_frames_ebox.set_can_focus(true);
|
||||
ms_hours_ebox.set_can_focus(true);
|
||||
ms_minutes_ebox.set_can_focus(true);
|
||||
ms_seconds_ebox.set_can_focus(true);
|
||||
|
||||
hours_ebox.signal_motion_notify_event().connect(bind(mem_fun(
|
||||
*this, &TimeCode::field_motion_notify_event), SMPTE_Hours));
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ public:
|
|||
* from the session / current timeline to be displayed. It doesn't
|
||||
* make sense to display raw time values here, as each timeline might
|
||||
* turn out to have a different origin; this is the result of resolving
|
||||
* a placement, and only the session has the necessary informations...
|
||||
* a placement, and only the session has the necessary information...
|
||||
*/
|
||||
Offset get_time_offset() const;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
GUINOTIFICATION-FACADE.h - access point for pushing informations into the GUI
|
||||
GUINOTIFICATION-FACADE.h - access point for pushing information into the GUI
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2008, Hermann Vosseler <Ichthyostega@web.de>
|
||||
|
|
@ -24,7 +24,7 @@
|
|||
** Major public Interface of the Lumiera GUI. While generally speaking, the GUI
|
||||
** controls the application and thus acts on its own, it exposes some services
|
||||
** usable by scripts or the two lower layers. The main purpose of these services
|
||||
** is to push informations and status updates into the GUI.
|
||||
** is to push status updates and similar information up into the GUI.
|
||||
**
|
||||
** @see notification-service.hpp implementation
|
||||
** @see gui::GuiFacade
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ namespace lumiera {
|
|||
|
||||
|
||||
/******************************************************************
|
||||
* Interface to the Player subsystem of Lumiera (Proc-Layer).
|
||||
* Interface to the Player subsystem of Lumiera (Proc-Layer).
|
||||
* Global access point for starting playback and render processes,
|
||||
* calculating media data by running the render engine.
|
||||
*
|
||||
|
|
@ -100,7 +100,7 @@ namespace lumiera {
|
|||
void play(bool); ///< play/pause toggle
|
||||
void scrub(bool); ///< scrubbing playback
|
||||
void adjustSpeed(double); ///< playback speed control
|
||||
void go(lib::time::Time); ///< skip to the given point in time
|
||||
void go(time::Time); ///< skip to the given point in time
|
||||
|
||||
void controlPlayhead (time::Control<time::Time> & ctrl);
|
||||
void controlDuration (time::Control<time::Duration> & ctrl);
|
||||
|
|
@ -119,13 +119,13 @@ namespace lumiera {
|
|||
};
|
||||
|
||||
|
||||
typedef lib::IterSource<mobject::ModelPort>::iterator ModelPorts;
|
||||
typedef lib::IterSource<mobject::OutputDesignation>::iterator Pipes;
|
||||
typedef lib::IterSource<proc::mobject::ModelPort>::iterator ModelPorts;
|
||||
typedef lib::IterSource<proc::mobject::OutputDesignation>::iterator Pipes;
|
||||
typedef proc::play::POutputManager Output;
|
||||
typedef mobject::session::PClipMO Clip;
|
||||
typedef mobject::PTrack Track;
|
||||
typedef asset::PTimeline Timeline;
|
||||
typedef asset::PViewer Viewer;
|
||||
typedef proc::mobject::session::PClipMO Clip;
|
||||
typedef proc::mobject::PTrack Track;
|
||||
typedef proc::asset::PTimeline Timeline;
|
||||
typedef proc::asset::PViewer Viewer;
|
||||
|
||||
/** core operation: create a new playback process
|
||||
* outputting to the given viewer/display */
|
||||
|
|
|
|||
|
|
@ -103,6 +103,8 @@
|
|||
namespace lib {
|
||||
namespace advice {
|
||||
|
||||
namespace error = lumiera::error;
|
||||
|
||||
using std::tr1::placeholders::_1;
|
||||
using std::tr1::unordered_map;
|
||||
using lib::iter_stl::eachVal;
|
||||
|
|
@ -118,7 +120,6 @@ namespace advice {
|
|||
using std::cout;
|
||||
using std::endl;
|
||||
|
||||
using namespace lumiera;
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -21,15 +21,15 @@
|
|||
*/
|
||||
|
||||
/** @file diagnostic-context.hpp
|
||||
** Facility for collecting diagnostic informations explicitly.
|
||||
** Facility for collecting diagnostic context information explicitly.
|
||||
** Unlike a trace logging run, this facility is intended to be fed explicitly with
|
||||
** diagnostic information describing the currently ongoing operation in a semantic
|
||||
** high-level manner. The rationale is to pinpoint \em those informations which aren't
|
||||
** obvious when just looking at a callstack with the debugger. Instances of the class
|
||||
** DiagnosticContext should be placed explicitly as automatic (stack) variable
|
||||
** into selected relevant scopes; these "information frames" can be accessed
|
||||
** from an enclosed scope as a per-thread stack. DiagnosticContext provides
|
||||
** an controlled environment for adding diagnostic code on demand; typically
|
||||
** high-level manner. The rationale is to pinpoint \em those pieces of information,
|
||||
** which aren't obvious when just looking at a callstack with the debugger.
|
||||
** Instances of the class DiagnosticContext should be placed explicitly as automatic
|
||||
** (stack) variable into selected relevant scopes; these "information frames" could
|
||||
** be accessed from an enclosed scope as a per-thread stack. DiagnosticContext
|
||||
** provides an controlled environment for adding diagnostic code on demand; typically
|
||||
** to be configured such as to resolve into an empty class for release builds.
|
||||
**
|
||||
** As of 2/10, this is an experimental feature in evaluation. To start with,
|
||||
|
|
@ -57,26 +57,23 @@ namespace lib {
|
|||
|
||||
|
||||
|
||||
#ifdef NOBUG_MODE_ALPHA ////////////////////////TODO don't we need the handle in BETA builds for resource logging?
|
||||
|
||||
/**
|
||||
* Diagnostic data frame to collect specific informations concerning a scope.
|
||||
* Diagnostic data frame to collect specific information concerning a scope.
|
||||
* To be placed explicitly as an automatic (stack) variable. Provides a controlled
|
||||
* environment for hooking up diagnostic code. Within each thread, a stack of
|
||||
* such information frames concerning nested scopes is maintained automatically.
|
||||
* It can be accessed via static API.
|
||||
* @warning never store this into global data structures.
|
||||
* @note as of 2/10 used for housing the NoBug resource tracker handle
|
||||
* in conjunction with object monitor based locking
|
||||
* @see sync.hpp
|
||||
* @warning relies on thread-local access; never use this within global data structures.
|
||||
*/
|
||||
template<typename VAL>
|
||||
class DiagnosticContext
|
||||
: boost::noncopyable
|
||||
{
|
||||
typedef nobug_resource_user* Handle;
|
||||
typedef ThreadLocalPtr<DiagnosticContext> ThreadLocalAccess;
|
||||
typedef std::vector<VAL> ValSequence;
|
||||
|
||||
Handle handle_;
|
||||
const VAL value_;
|
||||
DiagnosticContext * const prev_;
|
||||
|
||||
/** embedded thread local pointer
|
||||
|
|
@ -90,8 +87,8 @@ namespace lib {
|
|||
|
||||
|
||||
public:
|
||||
DiagnosticContext()
|
||||
: handle_(0)
|
||||
DiagnosticContext(VAL const& value_to_log = VAL())
|
||||
: value_(value_to_log)
|
||||
, prev_(current().get())
|
||||
{
|
||||
current().set (this);
|
||||
|
|
@ -104,9 +101,9 @@ namespace lib {
|
|||
}
|
||||
|
||||
|
||||
operator Handle* () ///< payload: NoBug resource tracker user handle
|
||||
operator VAL const&() ///< access the payload by conversion
|
||||
{
|
||||
return &handle_;
|
||||
return value_;
|
||||
}
|
||||
|
||||
/** accessing the innermost diagnostic context created */
|
||||
|
|
@ -116,39 +113,37 @@ namespace lib {
|
|||
DiagnosticContext* innermost = current().get();
|
||||
if (!innermost)
|
||||
throw lumiera::error::Logic ("Accessing Diagnostic context out of order; "
|
||||
"an instance should have been created in "
|
||||
"an instance should have been created within "
|
||||
"an enclosing scope");
|
||||
return *innermost;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#else /* not NOBUG_ALPHA */
|
||||
|
||||
|
||||
/**
|
||||
* Disabled placeholder for the Diagnostic context, not used in release builds.
|
||||
*/
|
||||
class DiagnosticContext
|
||||
: boost::noncopyable
|
||||
{
|
||||
|
||||
|
||||
public:
|
||||
|
||||
operator Handle* () ///< payload: NoBug resource tracker user handle
|
||||
/** snapshot of the current stack of diagnostic frames
|
||||
* @return vector with all the payload values currently
|
||||
* on the thread-local diagnostic stack. Might
|
||||
* be empty. Values start with frame next to
|
||||
* the current scope and end with outermost.
|
||||
* @warning can be inefficient on very large stacks
|
||||
* @todo benchmark and improve the data structure
|
||||
* used for the snapshot. Vector is not
|
||||
* an optimal choice here.
|
||||
*/
|
||||
static ValSequence
|
||||
extractStack()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** accessing the innermost diagnostic context created */
|
||||
static DiagnosticContext&
|
||||
access ()
|
||||
{
|
||||
UNIMPLEMENTED ("how to disable DiagnosticContext with minimum overhead");
|
||||
ValSequence loggedValues;
|
||||
DiagnosticContext* next = current().get();
|
||||
while (next)
|
||||
{
|
||||
loggedValues.push_back (*next);
|
||||
next = next->prev_;
|
||||
}
|
||||
return loggedValues;
|
||||
}
|
||||
};
|
||||
#endif /* NOBUG_ALPHA? */
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -66,7 +66,6 @@
|
|||
|
||||
namespace lib {
|
||||
|
||||
using lumiera::P;
|
||||
using util::isSameObject;
|
||||
|
||||
/**
|
||||
|
|
@ -189,7 +188,7 @@ namespace lib {
|
|||
}
|
||||
|
||||
|
||||
typedef lumiera::P<TAR> PTarget;
|
||||
typedef P<TAR> PTarget;
|
||||
|
||||
/** factory for creating smart-ptr managed
|
||||
* TAR instances, automatically registered
|
||||
|
|
|
|||
|
|
@ -125,6 +125,8 @@ namespace lumiera {
|
|||
LUMIERA_ERROR_DECLARE (LIFECYCLE); ///< Lifecycle assumptions violated
|
||||
LUMIERA_ERROR_DECLARE (WRONG_TYPE); ///< runtime type mismatch
|
||||
LUMIERA_ERROR_DECLARE (ITER_EXHAUST); ///< end of sequence reached
|
||||
LUMIERA_ERROR_DECLARE (CAPACITY); ///< predefined fixed storage capacity
|
||||
LUMIERA_ERROR_DECLARE (INDEX_BOUNDS); ///< index out of bounds
|
||||
LUMIERA_ERROR_DECLARE (BOTTOM_VALUE); ///< invalid or NIL value
|
||||
LUMIERA_ERROR_DECLARE (UNCONNECTED); ///< missing connection
|
||||
LUMIERA_ERROR_DECLARE (UNIMPLEMENTED);///< unimplemented feature
|
||||
|
|
|
|||
|
|
@ -82,6 +82,8 @@ namespace lumiera {
|
|||
LUMIERA_ERROR_DEFINE (LIFECYCLE, "Lifecycle assumptions violated");
|
||||
LUMIERA_ERROR_DEFINE (WRONG_TYPE, "runtime type mismatch");
|
||||
LUMIERA_ERROR_DEFINE (ITER_EXHAUST, "end of sequence reached");
|
||||
LUMIERA_ERROR_DEFINE (CAPACITY, "predefined fixed storage capacity");
|
||||
LUMIERA_ERROR_DEFINE (INDEX_BOUNDS, "index out of bounds");
|
||||
LUMIERA_ERROR_DEFINE (BOTTOM_VALUE, "invalid or NIL value");
|
||||
LUMIERA_ERROR_DEFINE (UNCONNECTED, "missing connection");
|
||||
LUMIERA_ERROR_DEFINE (UNIMPLEMENTED, "using a feature not yet implemented....");
|
||||
|
|
|
|||
259
src/lib/format-string.cpp
Normal file
|
|
@ -0,0 +1,259 @@
|
|||
/*
|
||||
FormatString - string template formatting based on boost::format
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2011, Hermann Vosseler <Ichthyostega@web.de>
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
* *****************************************************/
|
||||
|
||||
/** @file format-string.cpp
|
||||
** Implementation for printf-style formatting, based on boost::format.
|
||||
** This file holds the generic implementation of our format frontend,
|
||||
** which actually just invokes boost::format. The corresponding header
|
||||
** format-string.hpp provides some template functions and classes,
|
||||
** either invoking a custom string conversion, or passing primitive
|
||||
** values down unaltered.
|
||||
**
|
||||
** Here, we define explicit specialisations for the frontend to invoke,
|
||||
** which in turn just pass on the given argument value to the embedded
|
||||
** boost::format object, which in turn dumps the formatted result
|
||||
** into an embedded string stream.
|
||||
**
|
||||
** To avoid exposing boost::format in the frontend header, we use an
|
||||
** opaque buffer of appropriate size to piggyback the formatter object.
|
||||
** @warning unfortunately this requires a hard coded buffer size constant
|
||||
** in the front-end, which we define there manually, based on
|
||||
** the current implementation layout found in the boost libraries.
|
||||
** If Boost eventually changes the implementation, the assertion
|
||||
** in our constructor will trigger.
|
||||
**
|
||||
** @see FormatString_test
|
||||
**
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include "lib/error.hpp"
|
||||
#include "lib/format-util.hpp"
|
||||
#include "lib/format-string.hpp"
|
||||
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <boost/format.hpp>
|
||||
#include <iostream>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
namespace util {
|
||||
|
||||
using boost::format;
|
||||
|
||||
|
||||
namespace { // implementation details...
|
||||
|
||||
inline boost::format&
|
||||
accessImpl (char* buffer)
|
||||
{
|
||||
return reinterpret_cast<boost::format&> (*buffer);
|
||||
}
|
||||
|
||||
|
||||
inline void
|
||||
destroyImpl (char* buffer)
|
||||
{
|
||||
accessImpl(buffer).~format();
|
||||
}
|
||||
|
||||
|
||||
/** in case the formatting of a (primitive) value fails,
|
||||
* we try to supply an error indicator instead */
|
||||
void
|
||||
pushFailsafeReplacement (char* formatter, const char* errorMsg =NULL)
|
||||
try {
|
||||
string placeholder("<Error");
|
||||
if (errorMsg){
|
||||
placeholder += ": ";
|
||||
placeholder += errorMsg;
|
||||
}
|
||||
placeholder += ">";
|
||||
|
||||
accessImpl(formatter) % placeholder;
|
||||
}
|
||||
ERROR_LOG_AND_IGNORE (progress, "Supplying placeholder for problematic format parameter")
|
||||
|
||||
|
||||
inline void
|
||||
suppressInsufficientArgumentErrors (char* formatter)
|
||||
{
|
||||
using namespace boost::io;
|
||||
accessImpl(formatter).exceptions (all_error_bits ^ too_few_args_bit);
|
||||
}
|
||||
|
||||
|
||||
}//(End) implementation details
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** Build a formatter object based on the given format string.
|
||||
* The actual implementation is delegated to an boost::format object,
|
||||
* which is placement-constructed into an opaque buffer embedded into
|
||||
* this object. Defining the necessary size for this buffer relies
|
||||
* on a implementation details of boost::format (and might break)
|
||||
*/
|
||||
_Fmt::_Fmt (string formatString)
|
||||
try {
|
||||
BOOST_STATIC_ASSERT (sizeof(boost::format) <= FORMATTER_SIZE);
|
||||
|
||||
new(formatter_) boost::format(formatString);
|
||||
suppressInsufficientArgumentErrors (formatter_);
|
||||
}
|
||||
catch (boost::io::bad_format_string& syntaxError)
|
||||
{
|
||||
throw lumiera::error::Fatal (syntaxError
|
||||
, _Fmt("Format string '%s' is broken") % formatString
|
||||
, LUMIERA_ERROR_FORMAT_SYNTAX);
|
||||
}
|
||||
|
||||
|
||||
_Fmt::~_Fmt ()
|
||||
{
|
||||
destroyImpl (formatter_);
|
||||
}
|
||||
|
||||
|
||||
/** @internal access point for the frontend,
|
||||
* allowing to push a single parameter value down
|
||||
* into the implementation for the actual formatting.
|
||||
* Only selected primitive types are handled directly this way,
|
||||
* while all custom conversions, the handling of pointers and the
|
||||
* fallback (showing a type string) is done in the frontend.
|
||||
* @note we need to generate instantiations of this template function
|
||||
* explicitly for all basic types to be supported for direct handling,
|
||||
* otherwise we'll get linker errors. Lumiera uses the ``inclusion model''
|
||||
* for template instantiation, which means there is no compiler magic
|
||||
* involved and a template function either needs to be \em defined in
|
||||
* a header or explicitly instantiated in some translation unit.
|
||||
*/
|
||||
template<typename VAL>
|
||||
void
|
||||
_Fmt::format (const VAL val, Implementation& formatter)
|
||||
try {
|
||||
accessImpl(formatter) % val;
|
||||
}
|
||||
|
||||
catch (boost::io::too_many_args& argErr)
|
||||
{
|
||||
WARN (progress, "Format: excess argument '%s' of type %s ignored."
|
||||
, cStr(str(val))
|
||||
, cStr(tyStr(val)));
|
||||
}
|
||||
catch (std::exception& failure)
|
||||
{
|
||||
_clear_errorflag();
|
||||
WARN (progress, "Format: Parameter '%s' causes problems: %s"
|
||||
, cStr(str(val))
|
||||
, failure.what());
|
||||
pushFailsafeReplacement (formatter, failure.what());
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
_clear_errorflag();
|
||||
WARN (progress, "Format: Unexpected problems accepting format parameter '%s'", cStr(str(val)));
|
||||
pushFailsafeReplacement (formatter);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* ===== explicitly supported =================== */
|
||||
|
||||
template void _Fmt::format (const char, Implementation&);
|
||||
template void _Fmt::format (const uchar, Implementation&);
|
||||
template void _Fmt::format (const int, Implementation&);
|
||||
template void _Fmt::format (const uint, Implementation&);
|
||||
template void _Fmt::format (const short, Implementation&);
|
||||
template void _Fmt::format (const ushort, Implementation&);
|
||||
template void _Fmt::format (const int64_t, Implementation&);
|
||||
template void _Fmt::format (const uint64_t,Implementation&);
|
||||
template void _Fmt::format (const float, Implementation&);
|
||||
template void _Fmt::format (const double, Implementation&);
|
||||
template void _Fmt::format (const string, Implementation&);
|
||||
template void _Fmt::format (const void *, Implementation&);
|
||||
template void _Fmt::format (const char *, Implementation&);
|
||||
|
||||
|
||||
|
||||
|
||||
/** @remarks usually the _Fmt helper is used inline
|
||||
* at places where a string is expected. The '%' operator
|
||||
* used to fed parameters has a higher precedence than the
|
||||
* assignment or comparison operators, ensuring that all parameters
|
||||
* are evaluated and formatted prior to receiving the formatted result
|
||||
*/
|
||||
_Fmt::operator string() const
|
||||
try {
|
||||
return accessImpl(formatter_).str();
|
||||
}
|
||||
|
||||
catch (std::exception& failure)
|
||||
{
|
||||
_clear_errorflag();
|
||||
WARN (progress, "Format: Failure to receive formatted result: %s", failure.what());
|
||||
return "<formatting failure>";
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
_clear_errorflag();
|
||||
WARN (progress, "Format: Unexpected problems while formatting output.");
|
||||
return "<unexpected problems>";
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** send the formatted buffer directly to the output stream.
|
||||
* @note this is more efficient than creating a string and outputting that,
|
||||
* because boost::format internally uses a string-stream to generate
|
||||
* the formatted representation, relying on the C++ output framework
|
||||
*/
|
||||
std::ostream&
|
||||
operator<< (std::ostream& os, _Fmt const& fmt)
|
||||
try {
|
||||
return os << accessImpl(fmt.formatter_);
|
||||
}
|
||||
|
||||
catch(std::exception& failure)
|
||||
{
|
||||
_clear_errorflag();
|
||||
WARN (progress, "Format: Failure when outputting formatted result: %s", failure.what());
|
||||
return os << "<formatting failure>";
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
_clear_errorflag();
|
||||
WARN (progress, "Format: Unexpected problems while producing formatted output.");
|
||||
return os << "<unexpected problems>";
|
||||
}
|
||||
|
||||
|
||||
LUMIERA_ERROR_DEFINE (FORMAT_SYNTAX, "Syntax error in format string for boost::format");
|
||||
|
||||
|
||||
|
||||
} // namespace util
|
||||
421
src/lib/format-string.hpp
Normal file
|
|
@ -0,0 +1,421 @@
|
|||
/*
|
||||
FORMAT-STRING.hpp - string template formatting based on boost::format
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2011, Hermann Vosseler <Ichthyostega@web.de>
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
/** @file format-string.hpp
|
||||
** Front-end for printf-style string template interpolation.
|
||||
** While the actual implementation just delegates to boost::format, this front-end
|
||||
** hides the direct dependency, additionally invokes a custom toSting conversion
|
||||
** whenever possible, provides a direct automatic conversion to the formatted result
|
||||
** to string and catches any exceptions.
|
||||
**
|
||||
** This front-end is used pervasively for diagnostics and logging, so keeping down the
|
||||
** compilation and object size cost and reliably handling any error is more important
|
||||
** than the (small) performance gain of directly invoking boost::format (which is
|
||||
** known to be 10 times slower than printf anyway).
|
||||
**
|
||||
** \par Implementation notes
|
||||
** To perform the formatting, usually a \c _Fmt object is created as an anonymous
|
||||
** temporary, but it may as well be stored into a variable. Copying is not permitted.
|
||||
** Individual parameters are then fed for formatting through the \c '%' operator.
|
||||
** Each instance of _Fmt uses its own embedded boost::format object for implementation,
|
||||
** but this formatter resides within an opaque buffer embedded into the frontend object.
|
||||
** The rationale for this admittedly tricky approach is to confine any usage of boost::format
|
||||
** to the implementation translation unit (format-string.cpp).
|
||||
**
|
||||
** The implementation is invoked by the frontend through a set of explicit specialisations
|
||||
** for all the relevant \em primitive data types. For custom types, we prefer to invoke
|
||||
** operator string() if possible, which is determined by a simple metaprogramming test,
|
||||
** which is defined in lib/meta/util.pp, without relying on boost. As a fallback, for
|
||||
** all other types without built-in or custom string conversion, we use the mangled
|
||||
** type string produced by RTTI.
|
||||
**
|
||||
** The compile time and object size overhead incurred by using this header was verified
|
||||
** to be negligible, in comparison to using boost::format. When compiling a demo example
|
||||
** on x86_64, the following executable sizes could be observed:
|
||||
**
|
||||
** debug stripped
|
||||
** just string concatenation ............... 42k 8.8k
|
||||
** including and using format-string.hpp ... 50k 9.4k
|
||||
** including and using boost::format ....... 420k 140k
|
||||
**
|
||||
** In addition, we need to take the implementation translation unit (format-string.cpp)
|
||||
** into account, which is required once per application and contains the specialisations
|
||||
** for all primitive types. In the test showed above, the corresponding object file
|
||||
** had a size of 1300k (with debug information) resp. 290k (stripped).
|
||||
**
|
||||
** \par Usage
|
||||
** The syntax of the format string is defined by boost::format and closely mimics
|
||||
** the printf formatting directives. The notable difference is that boost::format
|
||||
** uses the C++ stream output framework, and thus avoiding the perils of printf.
|
||||
** The individual formatting placeholders just set the corresponding flags on
|
||||
** an embedded string stream, thus the actual parameter types cause the
|
||||
** selection of a suitable format, not the definitions within the
|
||||
** format string.
|
||||
**
|
||||
** An illegal format string will raise an error::Fatal. Any other error during usage of
|
||||
** the formatter is caught, logged and suppressed, inserting an error indicator into
|
||||
** the formatted result instead
|
||||
**
|
||||
** A formatter is usually created as an anonymous object, at places where a string
|
||||
** is expected. An arbitrary number of parameters is then supplied using the \c '%' operator.
|
||||
** The result can be obtained
|
||||
** - by string conversion
|
||||
** - by feeding into an output stream.
|
||||
**
|
||||
** Code example:
|
||||
** \code
|
||||
** double total = 22.9499;
|
||||
** const char * currency = "€";
|
||||
** cout << _Fmt("price %+5.2f %s") % total % currency << endl;
|
||||
** \endcode
|
||||
**
|
||||
** @remarks See the unit-test for extensive usage examples and corner cases.
|
||||
** The header format-util.hpp provides an alternative string conversion,
|
||||
** using a bit of boost type traits and lexical_cast, but no boost::format.
|
||||
** @warning not suited for performance critical code. About 10 times slower than printf.
|
||||
**
|
||||
** @see FormatString_test
|
||||
** @see format-util.hpp
|
||||
**
|
||||
*/
|
||||
|
||||
|
||||
#ifndef UTIL_FORMAT_STRING_H
|
||||
#define UTIL_FORMAT_STRING_H
|
||||
|
||||
#include "lib/error.hpp"
|
||||
#include "lib/meta/util.hpp"
|
||||
#include "lib/meta/size-trait.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <typeinfo>
|
||||
#include <boost/noncopyable.hpp>
|
||||
#include <boost/utility/enable_if.hpp>
|
||||
|
||||
|
||||
|
||||
namespace std { // forward declaration to avoid including <iostream>
|
||||
|
||||
template<typename C>
|
||||
class char_traits;
|
||||
|
||||
template<typename C, class _TRAITS>
|
||||
class basic_ostream;
|
||||
|
||||
typedef basic_ostream<char, char_traits<char> > ostream;
|
||||
}
|
||||
|
||||
|
||||
|
||||
namespace util {
|
||||
|
||||
using std::string;
|
||||
using boost::enable_if;
|
||||
|
||||
typedef unsigned char uchar;
|
||||
|
||||
LUMIERA_ERROR_DECLARE (FORMAT_SYNTAX); ///< "Syntax error in format string for boost::format"
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A front-end for using printf-style formatting.
|
||||
* Values to be formatted can be supplied through the
|
||||
* operator%. Custom defined string conversions on objects
|
||||
* will be used, any errors while invoking the format operation
|
||||
* will be suppressed. The implementation is based on boost::format,
|
||||
* but kept opaque to keep code size and compilation times down.
|
||||
* @see FormatString_test
|
||||
*/
|
||||
class _Fmt
|
||||
: boost::noncopyable
|
||||
{
|
||||
/** size of an opaque implementation Buffer */
|
||||
enum{ FORMATTER_SIZE = lib::meta::SizeTrait::BOOST_FORMAT };
|
||||
|
||||
typedef char Implementation[FORMATTER_SIZE];
|
||||
|
||||
|
||||
/** @internal buffer to hold a boost::format */
|
||||
mutable Implementation formatter_;
|
||||
|
||||
|
||||
template<typename VAL>
|
||||
static void format (const VAL, Implementation&);
|
||||
|
||||
/** helper to prepare parameters for inclusion */
|
||||
template<typename VAL, class SEL =void>
|
||||
struct Converter;
|
||||
|
||||
|
||||
|
||||
public:
|
||||
~_Fmt ();
|
||||
_Fmt (string formatString);
|
||||
|
||||
operator string() const; ///< get the formatted result
|
||||
|
||||
template<typename VAL>
|
||||
_Fmt&
|
||||
operator% (VAL const&);
|
||||
|
||||
|
||||
friend std::ostream&
|
||||
operator<< (std::ostream& os, _Fmt const&);
|
||||
|
||||
friend bool operator== (_Fmt const&, _Fmt const&);
|
||||
friend bool operator== (_Fmt const&, string const&);
|
||||
friend bool operator== (_Fmt const&, const char * const);
|
||||
friend bool operator== (string const& , _Fmt const&);
|
||||
friend bool operator== (const char * const, _Fmt const&);
|
||||
|
||||
template<typename X>
|
||||
friend bool operator != (_Fmt const& fmt, X const& x) { return !(fmt == x); }
|
||||
template<typename X>
|
||||
friend bool operator != (X const& x, _Fmt const& fmt) { return !(x == fmt); }
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* ===== forwarding into the implementation ====== */
|
||||
|
||||
/** The percent operator (\c '%' ) is used do feed parameter values
|
||||
* to be included into the formatted result, at the positions marked
|
||||
* by printf-style placeholders within the format string.
|
||||
*
|
||||
* \par type specific treatment
|
||||
* Basic types (numbers, chars, strings) are passed to the implementation
|
||||
* (= boost::format) literally. For custom types, we try to use a custom
|
||||
* string conversion, if applicable. Non-NULL pointers will be dereferenced,
|
||||
* with the exception of C-Strings and \c void*. Any other type gets just
|
||||
* translated into a type-ID (using the mangled RTTI info). In case of errors
|
||||
* during the conversion, a string representation of the error is returned
|
||||
* @param val arbitrary value or pointer to be included into the result
|
||||
* @warning you need to provide exactly the right number of parameters,
|
||||
* i.e. matching the number of fields in the format string.
|
||||
*/
|
||||
template<typename VAL>
|
||||
inline _Fmt&
|
||||
_Fmt::operator% (VAL const& val)
|
||||
{
|
||||
Converter<VAL>::dump (val, formatter_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
namespace { // helpers to pick a suitable specialisation....
|
||||
|
||||
/**
|
||||
* by default we don't allow to
|
||||
* treat any types directly by boost::format.
|
||||
* As fallback we rather just produce a type-ID
|
||||
*/
|
||||
template<typename X>
|
||||
struct _allow_call { enum{ value = false };};
|
||||
|
||||
/* the following definitions enable some primitive types
|
||||
* to be handed over to the boost::format implementation */
|
||||
template<> struct _allow_call<string> { enum{ value = true }; };
|
||||
template<> struct _allow_call<char> { enum{ value = true }; };
|
||||
template<> struct _allow_call<uchar> { enum{ value = true }; };
|
||||
template<> struct _allow_call<int> { enum{ value = true }; };
|
||||
template<> struct _allow_call<uint> { enum{ value = true }; };
|
||||
template<> struct _allow_call<short> { enum{ value = true }; };
|
||||
template<> struct _allow_call<ushort> { enum{ value = true }; };
|
||||
template<> struct _allow_call<int64_t> { enum{ value = true }; };
|
||||
template<> struct _allow_call<uint64_t>{ enum{ value = true }; };
|
||||
template<> struct _allow_call<float> { enum{ value = true }; };
|
||||
template<> struct _allow_call<double> { enum{ value = true }; };
|
||||
|
||||
template<typename X>
|
||||
struct _shall_format_directly
|
||||
{
|
||||
typedef typename lib::meta::UnConst<X>::Type BaseType;
|
||||
|
||||
enum{ value = _allow_call<BaseType>::value };
|
||||
};
|
||||
|
||||
|
||||
|
||||
template<typename X>
|
||||
struct _shall_convert_toString
|
||||
{
|
||||
enum{ value = ! _shall_format_directly<X>::value
|
||||
&& lib::meta::can_convertToString<X>::value
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
inline void
|
||||
_clear_errorflag()
|
||||
{
|
||||
const char* errID = lumiera_error();
|
||||
TRACE_IF (errID, progress, "Lumiera errorstate '%s' cleared.", errID);
|
||||
}
|
||||
|
||||
inline string
|
||||
_log_and_stringify (std::exception const& ex)
|
||||
{
|
||||
_clear_errorflag();
|
||||
WARN (progress, "Error while invoking custom string conversion: %s", ex.what());
|
||||
try {
|
||||
return string("<string conversion failed: ")+ex.what()+">";
|
||||
}
|
||||
catch(...) { /* secondary errors ignored */ }
|
||||
return "(formatting failure)";
|
||||
}
|
||||
|
||||
inline string
|
||||
_log_unknown_exception()
|
||||
{
|
||||
const char* errID = lumiera_error();
|
||||
if (errID)
|
||||
ERROR (progress, "Unknown error while invoking custom string conversion. Lumiera error flag = %s", errID);
|
||||
else
|
||||
ERROR (progress, "Unknown error while invoking custom string conversion. No Lumiera error flag set.");
|
||||
return "<Unknown error in string conversion>";
|
||||
}
|
||||
|
||||
}//(End) guards/helpers
|
||||
|
||||
|
||||
|
||||
|
||||
/* === explicit specialisations to control the kind of conversion === */
|
||||
|
||||
/** default/fallback: just indicate the (static) type */
|
||||
template<typename VAL, class SEL>
|
||||
struct _Fmt::Converter
|
||||
{
|
||||
static void
|
||||
dump (VAL const&, Implementation& impl)
|
||||
{
|
||||
format (string("«")+typeid(VAL).name()+"»", impl);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename VAL>
|
||||
struct _Fmt::Converter<VAL*>
|
||||
{
|
||||
static void
|
||||
dump (const VAL *pVal, Implementation& impl)
|
||||
{
|
||||
if (pVal)
|
||||
Converter<VAL>::dump(*pVal, impl);
|
||||
else
|
||||
format ("<null>", impl);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct _Fmt::Converter<void *>
|
||||
{
|
||||
static void
|
||||
dump (const void* address, Implementation& impl)
|
||||
{
|
||||
format (address, impl);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct _Fmt::Converter<const char *>
|
||||
{
|
||||
static void
|
||||
dump (const char* cString, Implementation& impl)
|
||||
{
|
||||
format (cString? cString : "↯", impl);
|
||||
}
|
||||
};
|
||||
|
||||
/** some custom types explicitly provide a string representation */
|
||||
template<typename VAL>
|
||||
struct _Fmt::Converter<VAL, typename enable_if< _shall_convert_toString<VAL> >::type>
|
||||
{
|
||||
static void
|
||||
dump (VAL const& val, Implementation& impl)
|
||||
try {
|
||||
format (string(val), impl);
|
||||
}
|
||||
catch(std::exception const& ex)
|
||||
{
|
||||
format (_log_and_stringify(ex), impl);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
format (_log_unknown_exception(), impl);
|
||||
}
|
||||
};
|
||||
|
||||
/** some basic types are directly forwarded down to the implementation;
|
||||
* @note this requires explicit specialisations in format-string.cpp */
|
||||
template<typename VAL>
|
||||
struct _Fmt::Converter<VAL, typename enable_if< _shall_format_directly<VAL> >::type>
|
||||
{
|
||||
static void
|
||||
dump (const VAL val, Implementation& impl)
|
||||
{
|
||||
format (val, impl);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* === comparison of formatter objects === */
|
||||
|
||||
inline bool
|
||||
operator== (_Fmt const& left, _Fmt const& right)
|
||||
{
|
||||
return string(left) == string(right);
|
||||
}
|
||||
|
||||
inline bool
|
||||
operator== (_Fmt const& fmt, string const& str)
|
||||
{
|
||||
return string(fmt) == str;
|
||||
}
|
||||
|
||||
inline bool
|
||||
operator== (_Fmt const& fmt, const char * const cString)
|
||||
{
|
||||
return string(fmt) == string(cString);
|
||||
}
|
||||
|
||||
inline bool
|
||||
operator== (string const& str, _Fmt const& fmt)
|
||||
{
|
||||
return fmt == str;
|
||||
}
|
||||
|
||||
inline bool
|
||||
operator== (const char * const cString, _Fmt const& fmt)
|
||||
{
|
||||
return fmt == cString;
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace util
|
||||
#endif
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
FORMAT.hpp - helpers for formatting and diagnostics
|
||||
FORMAT-UTIL.hpp - helpers for formatting and diagnostics
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2009, Hermann Vosseler <Ichthyostega@web.de>
|
||||
|
|
@ -21,20 +21,25 @@
|
|||
*/
|
||||
|
||||
|
||||
/** @file format.hpp
|
||||
/** @file format-util.hpp
|
||||
** Collection of small helpers and convenience shortcuts for diagnostics & formatting.
|
||||
** - util::str() performs a failsafe to-String conversion, thereby preferring a
|
||||
** built-in conversion operator, falling back to just a mangled type string.
|
||||
** - util::tyStr() generates a string corresponding to the type of the given object.
|
||||
** Currently just implemented through the mangled RTTI type string
|
||||
**
|
||||
** @todo we could add a facade to boost::format here, see Ticket #166
|
||||
** @see FormatHelper_test
|
||||
** @see format-string.hpp frontend for boost::format, printf-style
|
||||
**
|
||||
*/
|
||||
|
||||
|
||||
#ifndef UTIL_FORMAT_H
|
||||
#define UTIL_FORMAT_H
|
||||
#ifndef LIB_FORMAT_UTIL_H
|
||||
#define LIB_FORMAT_UTIL_H
|
||||
|
||||
//#include "lib/util.hpp"
|
||||
#include "lib/meta/trait.hpp"
|
||||
#include "lib/symbol.hpp"
|
||||
#include "lib/util.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
|
|
@ -46,61 +51,65 @@
|
|||
|
||||
namespace util {
|
||||
|
||||
using boost::enable_if;
|
||||
using lib::meta::can_ToString;
|
||||
using lib::meta::can_lexical2string;
|
||||
using lib::Symbol;
|
||||
using boost::enable_if;
|
||||
using boost::disable_if;
|
||||
using util::isnil;
|
||||
using std::string;
|
||||
|
||||
|
||||
namespace { // we need to guard the string conversion
|
||||
// to avoid a compiler error in case the type isn't convertible....
|
||||
|
||||
template<typename X>
|
||||
inline string
|
||||
invoke_2string ( typename enable_if< can_ToString<X>,
|
||||
X >::type const& val)
|
||||
{
|
||||
return string(val);
|
||||
}
|
||||
|
||||
template<typename X>
|
||||
inline string
|
||||
invoke_2string ( typename disable_if< can_ToString<X>,
|
||||
X >::type const&)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
struct use_StringConversion : can_ToString<X> { };
|
||||
|
||||
template<typename X>
|
||||
inline string
|
||||
invoke_indirect2string ( typename enable_if< can_lexical2string<X>,
|
||||
X >::type const& val)
|
||||
{
|
||||
try { return boost::lexical_cast<string> (val); }
|
||||
catch(...) { return ""; }
|
||||
}
|
||||
struct use_LexicalConversion
|
||||
{
|
||||
enum { value = can_lexical2string<X>::value
|
||||
&& !can_ToString<X>::value
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/** helper: reliably get some string representation for type X */
|
||||
template<typename X, typename COND =void>
|
||||
struct _InvokeFailsafe
|
||||
{
|
||||
static string toString (X const&) { return ""; }
|
||||
};
|
||||
|
||||
template<typename X>
|
||||
inline string
|
||||
invoke_indirect2string ( typename disable_if< can_lexical2string<X>,
|
||||
X >::type const&)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
}
|
||||
struct _InvokeFailsafe<X, typename enable_if< use_StringConversion<X> >::type>
|
||||
{
|
||||
static string
|
||||
toString (X const& val)
|
||||
try { return string(val); }
|
||||
catch(...) { return ""; }
|
||||
};
|
||||
|
||||
template<typename X>
|
||||
struct _InvokeFailsafe<X, typename enable_if< use_LexicalConversion<X> >::type>
|
||||
{
|
||||
static string
|
||||
toString (X const& val)
|
||||
try { return boost::lexical_cast<string> (val); }
|
||||
catch(...) { return ""; }
|
||||
};
|
||||
}//(End) guards/helpers
|
||||
|
||||
|
||||
|
||||
|
||||
/** try to get an object converted to string.
|
||||
* An custom/standard conversion to string is used,
|
||||
* A custom/standard conversion to string is used,
|
||||
* if applicable; otherwise, some standard types can be
|
||||
* converted by a lexical_cast (based on operator<< ).
|
||||
* Otherwise, either the fallback string is used, or just
|
||||
* a string denoting the (mangled) type.
|
||||
* a string based on the (mangled) type.
|
||||
*/
|
||||
template<typename TY>
|
||||
inline string
|
||||
|
|
@ -109,24 +118,16 @@ namespace util {
|
|||
, Symbol fallback =0 /// < replacement text to show if string conversion fails
|
||||
)
|
||||
{
|
||||
if (can_ToString<TY>::value)
|
||||
return string(prefix) + invoke_2string<TY>(val);
|
||||
|
||||
string res = _InvokeFailsafe<TY>::toString(val);
|
||||
if (!isnil (res))
|
||||
return string(prefix) + res;
|
||||
else
|
||||
{
|
||||
if (can_lexical2string<TY>::value)
|
||||
{
|
||||
string res (invoke_indirect2string<TY> (val));
|
||||
if ("" != res)
|
||||
return string(prefix) + res;
|
||||
}
|
||||
|
||||
return fallback? string(fallback)
|
||||
: tyStr(val);
|
||||
}
|
||||
return fallback? string(fallback)
|
||||
: tyStr(val);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** @return a string denoting the type. */
|
||||
template<typename TY>
|
||||
inline string
|
||||
|
|
@ -142,5 +143,4 @@ namespace util {
|
|||
|
||||
|
||||
} // namespace util
|
||||
|
||||
#endif /*UTIL_FORMAT_H*/
|
||||
#endif
|
||||
|
|
@ -25,6 +25,7 @@
|
|||
#define LUMIERA_FRAMEID_H
|
||||
|
||||
|
||||
#include <boost/operators.hpp>
|
||||
|
||||
namespace lumiera {
|
||||
|
||||
|
|
|
|||
|
|
@ -191,15 +191,6 @@ namespace lib {
|
|||
return *this;
|
||||
}
|
||||
|
||||
IterAdapter
|
||||
operator++(int)
|
||||
{
|
||||
_maybe_throw();
|
||||
IterAdapter oldPos(*this);
|
||||
iterate();
|
||||
return oldPos;
|
||||
}
|
||||
|
||||
bool
|
||||
isValid () const
|
||||
{
|
||||
|
|
@ -334,13 +325,6 @@ namespace lib {
|
|||
return *this;
|
||||
}
|
||||
|
||||
RangeIter
|
||||
operator++(int)
|
||||
{
|
||||
_maybe_throw();
|
||||
return RangeIter (p_++,e_);
|
||||
}
|
||||
|
||||
bool
|
||||
isValid () const
|
||||
{
|
||||
|
|
@ -551,12 +535,6 @@ namespace lib {
|
|||
return *this;
|
||||
}
|
||||
|
||||
PtrDerefIter
|
||||
operator++(int)
|
||||
{
|
||||
return PtrDerefIter (i_++);
|
||||
}
|
||||
|
||||
bool
|
||||
isValid () const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -339,10 +339,10 @@ namespace lib {
|
|||
|
||||
/** pipes a given Lumiera Forward Iterator through
|
||||
* a transformation function and wraps the resulting
|
||||
* transforming Iterator, exposing just a IterSource.
|
||||
* transforming Iterator, exposing just an IterSource.
|
||||
* This convenience shortcut can be used to build a
|
||||
* processing chain; the resulting IterSource will
|
||||
* hide any involved detail types.
|
||||
* hide any detail types involved.
|
||||
* @note as with any IterSource, there is one virtual
|
||||
* function call for every fetched element.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -491,7 +491,7 @@ namespace lib {
|
|||
|
||||
namespace { // Helper to pick up the produced value type automatically
|
||||
|
||||
using lumiera::typelist::FunctionSignature;
|
||||
using lib::meta::FunctionSignature;
|
||||
|
||||
template<typename SIG>
|
||||
struct _ProducedOutput
|
||||
|
|
@ -543,7 +543,7 @@ namespace lib {
|
|||
/** filters away repeated values
|
||||
* emitted by source iterator */
|
||||
template<class IT>
|
||||
FilterIter<IT>
|
||||
inline FilterIter<IT>
|
||||
filterRepetitions (IT const& source)
|
||||
{
|
||||
typedef typename IT::value_type Val;
|
||||
|
|
|
|||
|
|
@ -48,7 +48,6 @@
|
|||
#ifndef LIB_MAYBE_H
|
||||
#define LIB_MAYBE_H
|
||||
|
||||
//#include "pre.hpp"
|
||||
#include "lib/error.hpp"
|
||||
//#include "lib/wrapper.hpp"
|
||||
#include "lib/util.hpp"
|
||||
|
|
|
|||
|
|
@ -45,28 +45,28 @@
|
|||
*/
|
||||
|
||||
|
||||
#ifndef LUMIERA_META_CONFIGFLAGS_H
|
||||
#define LUMIERA_META_CONFIGFLAGS_H
|
||||
#ifndef LIB_META_CONFIGFLAGS_H
|
||||
#define LIB_META_CONFIGFLAGS_H
|
||||
|
||||
|
||||
#include "lib/meta/typelist.hpp"
|
||||
|
||||
|
||||
namespace lumiera {
|
||||
namespace typelist{
|
||||
namespace lib {
|
||||
namespace meta{
|
||||
|
||||
const size_t CONFIG_FLAGS_MAX = 5;
|
||||
|
||||
|
||||
template<char bit> struct Flag { typedef Flag ID; };
|
||||
template<uint bit> struct Flag { typedef Flag ID; };
|
||||
template<> struct Flag<0> { typedef NullType ID; };
|
||||
|
||||
|
||||
template< char f1=0
|
||||
, char f2=0
|
||||
, char f3=0
|
||||
, char f4=0
|
||||
, char f5=0
|
||||
template< uint f1=0
|
||||
, uint f2=0
|
||||
, uint f3=0
|
||||
, uint f4=0
|
||||
, uint f5=0
|
||||
>
|
||||
struct Flags
|
||||
{
|
||||
|
|
@ -81,11 +81,11 @@ namespace typelist{
|
|||
};
|
||||
|
||||
|
||||
template< char f1=0
|
||||
, char f2=0
|
||||
, char f3=0
|
||||
, char f4=0
|
||||
, char f5=0
|
||||
template< uint f1=0
|
||||
, uint f2=0
|
||||
, uint f3=0
|
||||
, uint f4=0
|
||||
, uint f5=0
|
||||
>
|
||||
struct Config ///< distinct type representing a configuration
|
||||
{
|
||||
|
|
@ -95,31 +95,31 @@ namespace typelist{
|
|||
|
||||
|
||||
|
||||
template<char Fl, class CONF>
|
||||
template<uint Fl, class CONF>
|
||||
struct ConfigSetFlag; ///< set (prepend) the Flag to the given config
|
||||
|
||||
template< char Fl
|
||||
, char f1
|
||||
, char f2
|
||||
, char f3
|
||||
, char f4
|
||||
, char IGN
|
||||
template< uint Fl
|
||||
, uint f1
|
||||
, uint f2
|
||||
, uint f3
|
||||
, uint f4
|
||||
, uint IGN
|
||||
>
|
||||
struct ConfigSetFlag<Fl, Config<f1,f2,f3,f4,IGN> >
|
||||
{
|
||||
typedef typelist::Config<Fl,f1,f2,f3,f4> Config;
|
||||
typedef lib::meta::Config<Fl,f1,f2,f3,f4> Config;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/** build a configuration type from a list-of-flags */
|
||||
template<class FLAGS, class CONF=typelist::Config<> >
|
||||
template<class FLAGS, class CONF=Config<> >
|
||||
struct BuildConfigFromFlags
|
||||
{
|
||||
typedef CONF Config;
|
||||
typedef Config Type;
|
||||
};
|
||||
template<char Fl, class FLAGS, class CONF>
|
||||
template<uint Fl, class FLAGS, class CONF>
|
||||
struct BuildConfigFromFlags< Node<Flag<Fl>,FLAGS>, CONF>
|
||||
{
|
||||
typedef typename ConfigSetFlag< Fl
|
||||
|
|
@ -134,8 +134,8 @@ namespace typelist{
|
|||
|
||||
|
||||
namespace {
|
||||
/** helper comparing enum values and chars (flags) */
|
||||
template<char ii, char jj>
|
||||
/** helper comparing enum values and flags */
|
||||
template<uint ii, uint jj>
|
||||
struct maxC
|
||||
{
|
||||
enum{ VAL = ii < jj? jj : ii };
|
||||
|
|
@ -157,7 +157,7 @@ namespace typelist{
|
|||
template<class FLAGS>
|
||||
struct FlagInfo;
|
||||
|
||||
template<char ff, class FLAGS>
|
||||
template<uint ff, class FLAGS>
|
||||
struct FlagInfo<Node<Flag<ff>, FLAGS> >
|
||||
{
|
||||
enum{ BITS = maxC< ff, FlagInfo<FLAGS>::BITS> ::VAL
|
||||
|
|
@ -199,5 +199,5 @@ namespace typelist{
|
|||
|
||||
|
||||
|
||||
}} // namespace lumiera::typelist
|
||||
}} // namespace lib::meta
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@
|
|||
** Because, if we can get a \c bool answer to such a question <i>at compile time,</i> we can use
|
||||
** \c boost::enable_if to pick a special implementation based on the test result. Together, these
|
||||
** techniques allow to adopt a duck-typed programming style, where an arbitrary object is allowed
|
||||
** to enter a given API function, provided this object supports some special operations.
|
||||
** to enter a given API function, provided this object supports some specific operations.
|
||||
**
|
||||
** While C++ certainly isn't a dynamic language and doesn't provide any kind of run time introspection,
|
||||
** doing such check-and branch at compile time allows even to combine such a flexible approach with
|
||||
|
|
@ -92,16 +92,6 @@
|
|||
|
||||
#include "lib/meta/util.hpp"
|
||||
|
||||
namespace lib {
|
||||
namespace meta{
|
||||
|
||||
///////////////TICKET #175 sort out meta namespace
|
||||
using lumiera::Yes_t;
|
||||
using lumiera::No_t;
|
||||
|
||||
}} // namespace lib::meta
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -44,8 +44,8 @@
|
|||
*/
|
||||
|
||||
|
||||
#ifndef LUMIERA_META_FUNCTION_CLOSURE_H
|
||||
#define LUMIERA_META_FUNCTION_CLOSURE_H
|
||||
#ifndef LIB_META_FUNCTION_CLOSURE_H
|
||||
#define LIB_META_FUNCTION_CLOSURE_H
|
||||
|
||||
#include "lib/meta/function.hpp"
|
||||
#include "lib/meta/tuple.hpp"
|
||||
|
|
@ -54,9 +54,9 @@
|
|||
|
||||
|
||||
|
||||
namespace lumiera {
|
||||
namespace typelist{
|
||||
namespace func {
|
||||
namespace lib {
|
||||
namespace meta{
|
||||
namespace func{
|
||||
|
||||
using std::tr1::function;
|
||||
|
||||
|
|
@ -67,18 +67,26 @@ namespace func {
|
|||
|
||||
using tuple::element;
|
||||
|
||||
/**
|
||||
* Helper to dissect an arbitrary function signature,
|
||||
* irrespective if the parameter is given as function reference,
|
||||
* function pointer, member function pointer or functor object.
|
||||
* The base case assumes a (language) function reference.
|
||||
*/
|
||||
template<typename SIG>
|
||||
struct _Fun
|
||||
{
|
||||
typedef typename FunctionSignature<function<SIG> >::Ret Ret;
|
||||
typedef typename FunctionSignature<function<SIG> >::Args Args;
|
||||
};
|
||||
/** Specialisation for using a function pointer */
|
||||
template<typename SIG>
|
||||
struct _Fun<SIG*>
|
||||
{
|
||||
typedef typename FunctionSignature<function<SIG> >::Ret Ret;
|
||||
typedef typename FunctionSignature<function<SIG> >::Args Args;
|
||||
};
|
||||
/** Specialisation for passing a functor */
|
||||
template<typename SIG>
|
||||
struct _Fun<function<SIG> >
|
||||
{
|
||||
|
|
@ -86,6 +94,115 @@ namespace func {
|
|||
typedef typename FunctionSignature<function<SIG> >::Args Args;
|
||||
};
|
||||
|
||||
/** Specialisations for member function pointers */
|
||||
template<typename RET, class CLASS>
|
||||
struct _Fun<RET (CLASS::*) (void) >
|
||||
{
|
||||
typedef RET Ret;
|
||||
typedef Types<CLASS* const> Args;
|
||||
};
|
||||
|
||||
template< typename RET, class CLASS
|
||||
, typename A1
|
||||
>
|
||||
struct _Fun<RET (CLASS::*) (A1) >
|
||||
{
|
||||
typedef RET Ret;
|
||||
typedef Types<CLASS* const, A1> Args;
|
||||
};
|
||||
|
||||
template< typename RET, class CLASS
|
||||
, typename A1
|
||||
, typename A2
|
||||
>
|
||||
struct _Fun<RET (CLASS::*) (A1,A2) >
|
||||
{
|
||||
typedef RET Ret;
|
||||
typedef Types<CLASS* const, A1,A2> Args;
|
||||
};
|
||||
|
||||
template< typename RET, class CLASS
|
||||
, typename A1
|
||||
, typename A2
|
||||
, typename A3
|
||||
>
|
||||
struct _Fun<RET (CLASS::*) (A1,A2,A3) >
|
||||
{
|
||||
typedef RET Ret;
|
||||
typedef Types<CLASS* const, A1,A2,A3> Args;
|
||||
};
|
||||
|
||||
template< typename RET, class CLASS
|
||||
, typename A1
|
||||
, typename A2
|
||||
, typename A3
|
||||
, typename A4
|
||||
>
|
||||
struct _Fun<RET (CLASS::*) (A1,A2,A3,A4) >
|
||||
{
|
||||
typedef RET Ret;
|
||||
typedef Types<CLASS* const, A1,A2,A3,A4> Args;
|
||||
};
|
||||
|
||||
template< typename RET, class CLASS
|
||||
, typename A1
|
||||
, typename A2
|
||||
, typename A3
|
||||
, typename A4
|
||||
, typename A5
|
||||
>
|
||||
struct _Fun<RET (CLASS::*) (A1,A2,A3,A4,A5) >
|
||||
{
|
||||
typedef RET Ret;
|
||||
typedef Types<CLASS* const, A1,A2,A3,A4,A5> Args;
|
||||
};
|
||||
|
||||
template< typename RET, class CLASS
|
||||
, typename A1
|
||||
, typename A2
|
||||
, typename A3
|
||||
, typename A4
|
||||
, typename A5
|
||||
, typename A6
|
||||
>
|
||||
struct _Fun<RET (CLASS::*) (A1,A2,A3,A4,A5,A6) >
|
||||
{
|
||||
typedef RET Ret;
|
||||
typedef Types<CLASS* const, A1,A2,A3,A4,A5,A6> Args;
|
||||
};
|
||||
|
||||
template< typename RET, class CLASS
|
||||
, typename A1
|
||||
, typename A2
|
||||
, typename A3
|
||||
, typename A4
|
||||
, typename A5
|
||||
, typename A6
|
||||
, typename A7
|
||||
>
|
||||
struct _Fun<RET (CLASS::*) (A1,A2,A3,A4,A5,A6,A7) >
|
||||
{
|
||||
typedef RET Ret;
|
||||
typedef Types<CLASS* const, A1,A2,A3,A4,A5,A6,A7> Args;
|
||||
};
|
||||
|
||||
template< typename RET, class CLASS
|
||||
, typename A1
|
||||
, typename A2
|
||||
, typename A3
|
||||
, typename A4
|
||||
, typename A5
|
||||
, typename A6
|
||||
, typename A7
|
||||
, typename A8
|
||||
>
|
||||
struct _Fun<RET (CLASS::*) (A1,A2,A3,A4,A5,A6,A7,A8) >
|
||||
{
|
||||
typedef RET Ret;
|
||||
typedef Types<CLASS* const, A1,A2,A3,A4,A5,A6,A7,A8> Args;
|
||||
};
|
||||
|
||||
|
||||
template<typename FUN>
|
||||
struct is_Functor { static const bool value = false; };
|
||||
template<typename SIG>
|
||||
|
|
@ -796,10 +913,11 @@ namespace func {
|
|||
/* ========== function-style interface ============= */
|
||||
|
||||
/** build a TupleApplicator, which embodies the given
|
||||
* argument tuple and can be used to apply various
|
||||
* functions to them.
|
||||
* argument tuple and can be used to apply them
|
||||
* to various functions repeatedly.
|
||||
*/
|
||||
template<typename ARG>
|
||||
inline
|
||||
typename _Sig<void, ARG>::Applicator
|
||||
tupleApplicator (Tuple<ARG>& args)
|
||||
{
|
||||
|
|
@ -810,6 +928,7 @@ namespace func {
|
|||
|
||||
/** apply the given function to the argument tuple */
|
||||
template<typename SIG, typename ARG>
|
||||
inline
|
||||
typename _Fun<SIG>::Ret
|
||||
apply (SIG& f, Tuple<ARG>& args)
|
||||
{
|
||||
|
|
@ -824,6 +943,7 @@ namespace func {
|
|||
* invoked later to yield the
|
||||
* function result. */
|
||||
template<typename SIG, typename ARG>
|
||||
inline
|
||||
typename _Clo<SIG,ARG>::Type
|
||||
closure (SIG& f, Tuple<ARG>& args)
|
||||
{
|
||||
|
|
@ -836,6 +956,7 @@ namespace func {
|
|||
|
||||
/** close the given function over the first argument */
|
||||
template<typename SIG, typename ARG>
|
||||
inline
|
||||
typename _PapS<SIG>::Function
|
||||
applyFirst (SIG& f, ARG arg)
|
||||
{
|
||||
|
|
@ -848,6 +969,7 @@ namespace func {
|
|||
|
||||
/** close the given function over the last argument */
|
||||
template<typename SIG, typename ARG>
|
||||
inline
|
||||
typename _PapE<SIG>::Function
|
||||
applyLast (SIG& f, ARG arg)
|
||||
{
|
||||
|
|
@ -862,6 +984,7 @@ namespace func {
|
|||
/** bind the last function argument to an arbitrary term,
|
||||
* which especially might be a (nested) binder... */
|
||||
template<typename SIG, typename TERM>
|
||||
inline
|
||||
typename _PapE<SIG>::Function
|
||||
bindLast (SIG& f, TERM const& arg)
|
||||
{
|
||||
|
|
@ -875,6 +998,7 @@ namespace func {
|
|||
|
||||
/** build a functor chaining the given functions */
|
||||
template<typename SIG1, typename SIG2>
|
||||
inline
|
||||
typename _Chain<SIG1,SIG2>::Function
|
||||
chained (SIG1& f1, SIG2& f2)
|
||||
{
|
||||
|
|
@ -884,5 +1008,5 @@ namespace func {
|
|||
|
||||
|
||||
|
||||
}}} // namespace lumiera::typelist::func
|
||||
}}} // namespace lib::meta::func
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -52,8 +52,8 @@
|
|||
*/
|
||||
|
||||
|
||||
#ifndef LUMIERA_META_FUNCTION_ERASURE_H
|
||||
#define LUMIERA_META_FUNCTION_ERASURE_H
|
||||
#ifndef LIB_META_FUNCTION_ERASURE_H
|
||||
#define LIB_META_FUNCTION_ERASURE_H
|
||||
|
||||
#include "lib/util.hpp"
|
||||
#include "lib/error.hpp"
|
||||
|
|
@ -64,8 +64,8 @@
|
|||
#include <tr1/functional>
|
||||
|
||||
|
||||
namespace lumiera {
|
||||
namespace typelist{
|
||||
namespace lib {
|
||||
namespace meta{
|
||||
|
||||
using std::tr1::function;
|
||||
using util::unConst;
|
||||
|
|
@ -240,5 +240,5 @@ namespace typelist{
|
|||
|
||||
|
||||
|
||||
}} // namespace lumiera::typelist
|
||||
}} // namespace lib::meta
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -44,8 +44,8 @@
|
|||
*/
|
||||
|
||||
|
||||
#ifndef LUMIERA_META_FUNCTION_H
|
||||
#define LUMIERA_META_FUNCTION_H
|
||||
#ifndef LIB_META_FUNCTION_H
|
||||
#define LIB_META_FUNCTION_H
|
||||
|
||||
#include "lib/meta/typelist.hpp"
|
||||
|
||||
|
|
@ -53,8 +53,8 @@
|
|||
|
||||
|
||||
|
||||
namespace lumiera {
|
||||
namespace typelist{
|
||||
namespace lib {
|
||||
namespace meta{
|
||||
|
||||
using std::tr1::function;
|
||||
|
||||
|
|
@ -357,5 +357,5 @@ namespace typelist{
|
|||
|
||||
|
||||
|
||||
}} // namespace lumiera::typelist
|
||||
}} // namespace lib::meta
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -33,8 +33,8 @@
|
|||
*/
|
||||
|
||||
|
||||
#ifndef LUMIERA_META_GENERATOR_COMBINATIONS_H
|
||||
#define LUMIERA_META_GENERATOR_COMBINATIONS_H
|
||||
#ifndef LIB_META_GENERATOR_COMBINATIONS_H
|
||||
#define LIB_META_GENERATOR_COMBINATIONS_H
|
||||
|
||||
#include "lib/meta/typelist.hpp"
|
||||
#include "lib/meta/typelist-manip.hpp"
|
||||
|
|
@ -42,8 +42,8 @@
|
|||
|
||||
|
||||
|
||||
namespace lumiera {
|
||||
namespace typelist{
|
||||
namespace lib {
|
||||
namespace meta{
|
||||
|
||||
|
||||
template<class TYPES_1, class TYPES_2>
|
||||
|
|
@ -97,5 +97,5 @@ namespace typelist{
|
|||
|
||||
|
||||
|
||||
}} // namespace lumiera::typelist
|
||||
}} // namespace lib::meta
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ This code is heavily inspired by
|
|||
|
||||
|
||||
/** @file generator.hpp
|
||||
** Helpers for working with lumiera::typelist::Types (i.e. lists-of-types).
|
||||
** Helpers for working with lib::meta::Types (i.e. lists-of-types).
|
||||
** The main purpose is to build interfaces and polymorphic implementations
|
||||
** (using virtual functions) based on templated Types or Collections of types,
|
||||
** which is not possible without Template Metaprogramming.
|
||||
|
|
@ -56,15 +56,15 @@ This code is heavily inspired by
|
|||
*/
|
||||
|
||||
|
||||
#ifndef LUMIERA_META_GENERATOR_H
|
||||
#define LUMIERA_META_GENERATOR_H
|
||||
#ifndef LIB_META_GENERATOR_H
|
||||
#define LIB_META_GENERATOR_H
|
||||
|
||||
#include "lib/meta/typelist.hpp"
|
||||
|
||||
|
||||
|
||||
namespace lumiera {
|
||||
namespace typelist{
|
||||
namespace lib {
|
||||
namespace meta{
|
||||
|
||||
/**
|
||||
* Apply a template to a collection of types.
|
||||
|
|
@ -207,5 +207,5 @@ namespace typelist{
|
|||
};
|
||||
|
||||
|
||||
}} // namespace lumiera::typelist
|
||||
}} // namespace lib::meta
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -21,8 +21,8 @@
|
|||
*/
|
||||
|
||||
|
||||
#ifndef LUMIERA_META_MAYBE_COMPARE_H
|
||||
#define LUMIERA_META_MAYBE_COMPARE_H
|
||||
#ifndef LIB_META_MAYBE_COMPARE_H
|
||||
#define LIB_META_MAYBE_COMPARE_H
|
||||
|
||||
|
||||
#include "lib/functor-util.hpp"
|
||||
|
|
@ -30,8 +30,8 @@
|
|||
#include <tr1/functional>
|
||||
|
||||
|
||||
namespace lumiera {
|
||||
namespace typelist {
|
||||
namespace lib {
|
||||
namespace meta{
|
||||
|
||||
using std::tr1::function;
|
||||
|
||||
|
|
@ -72,5 +72,5 @@ namespace typelist {
|
|||
}
|
||||
|
||||
|
||||
}} // namespace lumiera::typelist
|
||||
}} // namespace lib::meta
|
||||
#endif
|
||||
|
|
|
|||
149
src/lib/meta/size-trait.hpp
Normal file
|
|
@ -0,0 +1,149 @@
|
|||
/*
|
||||
SIZE-TRAIT.hpp - helpers and definitions to deal with the size of some known types
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2011, Hermann Vosseler <Ichthyostega@web.de>
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#ifndef LIB_META_SIZE_TRAIT_H
|
||||
#define LIB_META_SIZE_TRAIT_H
|
||||
|
||||
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
|
||||
namespace lib {
|
||||
namespace meta {
|
||||
|
||||
|
||||
/**
|
||||
* A collection of constants to describe the expected size
|
||||
* of some known classes, without needing to include the
|
||||
* respective headers. This is an optimisation to improve
|
||||
* compilation times and/or reduce size of the generated
|
||||
* object files in debug mode. To get those sizes computed
|
||||
* in a fairly portable way, but without much overhead,
|
||||
* we mimic the memory layout of "the real thing"
|
||||
* with some reasonable simplifications:
|
||||
* - the size of vectors doesn't really depend on the elements
|
||||
* - our strings, streams and buffers use just simple chars
|
||||
*
|
||||
* \par Interface
|
||||
* The purpose of this whole construction is to pull off
|
||||
* some constants based on sizeof expressions:
|
||||
* - the size of a string
|
||||
* - the size of a vector
|
||||
* - the size of a boost::format
|
||||
*
|
||||
* @warning this setup is quite fragile and directly relies
|
||||
* on the implementation layout of the GNU STL and Boost.
|
||||
* Whenever using this stuff, make sure to place an assertion
|
||||
* somewhere down in the implementation level to check against
|
||||
* the size of the real thing.
|
||||
*/
|
||||
class SizeTrait
|
||||
{
|
||||
//-------------------------------------mimicked-definitions--
|
||||
|
||||
typedef std::vector<size_t> Vector;
|
||||
typedef std::vector<bool> BVector;
|
||||
|
||||
struct CompatAllocator
|
||||
: std::allocator<char>
|
||||
{ };
|
||||
|
||||
struct Locale
|
||||
{
|
||||
void* _M_impl;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
struct Optional
|
||||
{
|
||||
bool m_initialized_;
|
||||
T m_storage_;
|
||||
};
|
||||
|
||||
enum IOS_Openmode
|
||||
{
|
||||
_S_app = 1L << 0,
|
||||
_S_ate = 1L << 1,
|
||||
_S_bin = 1L << 2,
|
||||
_S_in = 1L << 3,
|
||||
_S_out = 1L << 4,
|
||||
_S_trunc = 1L << 5,
|
||||
_S_ios_openmode_end = 1L << 16
|
||||
};
|
||||
|
||||
struct BasicStringbuf
|
||||
{
|
||||
char * _M_in_beg;
|
||||
char * _M_in_cur;
|
||||
char * _M_in_end;
|
||||
char * _M_out_beg;
|
||||
char * _M_out_cur;
|
||||
char * _M_out_end;
|
||||
|
||||
Locale _M_buf_locale;
|
||||
|
||||
virtual ~BasicStringbuf() { }
|
||||
};
|
||||
|
||||
struct BasicAltstringbuf
|
||||
: BasicStringbuf
|
||||
{
|
||||
char * putend_;
|
||||
bool is_allocated_;
|
||||
IOS_Openmode mode_;
|
||||
CompatAllocator alloc_;
|
||||
};
|
||||
|
||||
struct BoostFormat
|
||||
{
|
||||
Vector items_;
|
||||
BVector bound_; // note: differs in size
|
||||
int style_;
|
||||
int cur_arg_;
|
||||
int num_args_;
|
||||
mutable bool dumped_;
|
||||
std::string prefix_;
|
||||
unsigned char exceptions;
|
||||
BasicAltstringbuf buf_;
|
||||
Optional<Locale> loc_;
|
||||
};
|
||||
//-------------------------------------mimicked-definitions--
|
||||
|
||||
|
||||
public:/* ===== Interface: size constants ===== */
|
||||
|
||||
enum { ALIGNMENT = sizeof(size_t)
|
||||
|
||||
, STRING = sizeof(std::string)
|
||||
, VECTOR = sizeof(Vector)
|
||||
, BVECTOR = sizeof(BVector)
|
||||
|
||||
, BOOST_FORMAT = sizeof(BoostFormat)
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
}} // namespace lib::meta
|
||||
#endif
|
||||
|
|
@ -33,7 +33,7 @@
|
|||
#include <boost/type_traits/remove_reference.hpp>
|
||||
#include <boost/type_traits/remove_pointer.hpp>
|
||||
#include <boost/type_traits/remove_cv.hpp>
|
||||
#include <boost/utility/enable_if.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
//Forward declarations for the Unwrap helper....
|
||||
|
|
@ -42,14 +42,14 @@ namespace boost{
|
|||
}
|
||||
namespace std {
|
||||
namespace tr1 {
|
||||
template<class X> class reference_wrapper;
|
||||
template<class X> class reference_wrapper;
|
||||
template<class X> class shared_ptr;
|
||||
}}
|
||||
namespace lumiera{
|
||||
template<class X, class B> class P;
|
||||
namespace lib{
|
||||
template<class X, class B> class P;
|
||||
}
|
||||
namespace mobject{
|
||||
template<class X, class B> class Placement;
|
||||
template<class X, class B> class Placement;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -127,12 +127,12 @@ namespace meta {
|
|||
};
|
||||
|
||||
template<typename X, class B>
|
||||
struct Unwrap<lumiera::P<X, B> >
|
||||
struct Unwrap<P<X, B> >
|
||||
{
|
||||
typedef X Type;
|
||||
|
||||
static X&
|
||||
extract (lumiera::P<X,B> ptr)
|
||||
extract (P<X,B> ptr)
|
||||
{
|
||||
ASSERT (ptr);
|
||||
return *ptr;
|
||||
|
|
|
|||
|
|
@ -44,8 +44,8 @@
|
|||
*/
|
||||
|
||||
|
||||
#ifndef LUMIERA_META_TUPLE_H
|
||||
#define LUMIERA_META_TUPLE_H
|
||||
#ifndef LIB_META_TUPLE_H
|
||||
#define LIB_META_TUPLE_H
|
||||
|
||||
#include "lib/meta/typelist.hpp"
|
||||
#include "lib/meta/typelist-util.hpp"
|
||||
|
|
@ -54,8 +54,8 @@
|
|||
|
||||
|
||||
|
||||
namespace lumiera {
|
||||
namespace typelist{
|
||||
namespace lib {
|
||||
namespace meta {
|
||||
|
||||
|
||||
|
||||
|
|
@ -283,6 +283,7 @@ namespace typelist{
|
|||
namespace tuple { // some convenience access functions
|
||||
|
||||
template<uint n, class TUP>
|
||||
inline
|
||||
typename Shifted<TUP,n>::Head&
|
||||
element (TUP& tup)
|
||||
{
|
||||
|
|
@ -743,5 +744,5 @@ namespace typelist{
|
|||
|
||||
|
||||
|
||||
}} // namespace lumiera::typelist
|
||||
}} // namespace lib::meta
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -49,15 +49,17 @@
|
|||
*/
|
||||
|
||||
|
||||
#ifndef LUMIERA_META_TYPELIST_MANIP_H
|
||||
#define LUMIERA_META_TYPELIST_MANIP_H
|
||||
#ifndef LIB_META_TYPELIST_MANIP_H
|
||||
#define LIB_META_TYPELIST_MANIP_H
|
||||
|
||||
|
||||
|
||||
#include "lib/meta/typelist.hpp"
|
||||
|
||||
namespace lumiera {
|
||||
namespace typelist{
|
||||
#include <sys/types.h>
|
||||
|
||||
namespace lib {
|
||||
namespace meta {
|
||||
|
||||
|
||||
/** pick the n-th element from a typelist */
|
||||
|
|
@ -325,5 +327,5 @@ namespace typelist{
|
|||
|
||||
|
||||
|
||||
}} // namespace lumiera::typelist
|
||||
}} // namespace lib::meta
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@
|
|||
/** @file typelist-util.hpp
|
||||
** Metaprogramming: simple helpers for working with lists-of-types.
|
||||
** This header provides some very basic "meta functions" for extracting
|
||||
** some informations from a list-of-types. In Lumiera, we use template
|
||||
** pieces of information from a list-of-types. In Lumiera, we use template
|
||||
** metaprogramming and especially such lists-of-types, whenever we build
|
||||
** some common implementation backbone, without being able to subsume all
|
||||
** participating types (classes) into a single inheritance hierarchy.
|
||||
|
|
@ -42,15 +42,15 @@
|
|||
*/
|
||||
|
||||
|
||||
#ifndef LUMIERA_META_TYPELIST_UTIL_H
|
||||
#define LUMIERA_META_TYPELIST_UTIL_H
|
||||
#ifndef LIB_META_TYPELIST_UTIL_H
|
||||
#define LIB_META_TYPELIST_UTIL_H
|
||||
|
||||
|
||||
|
||||
#include "lib/meta/typelist.hpp"
|
||||
|
||||
namespace lumiera {
|
||||
namespace typelist{
|
||||
namespace lib {
|
||||
namespace meta {
|
||||
|
||||
|
||||
/**
|
||||
|
|
@ -123,5 +123,5 @@ namespace typelist{
|
|||
|
||||
|
||||
|
||||
}} // namespace lumiera::typelist
|
||||
}} // namespace lib::meta
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ This code is heavily inspired by
|
|||
** effectively this is a flavour of functional programming. Just the
|
||||
** "execution environment" is the compiler, during compilation.
|
||||
**
|
||||
** @see lumiera::visitor::Applicable usage example
|
||||
** @see lib::visitor::Applicable usage example
|
||||
** @see control::CommandSignature more elaborate usage example (dissecting a functor signature)
|
||||
** @see TypeList_test
|
||||
** @see TypeListManip_test
|
||||
|
|
@ -63,14 +63,14 @@ This code is heavily inspired by
|
|||
*/
|
||||
|
||||
|
||||
#ifndef LUMIERA_META_TYPELIST_H
|
||||
#define LUMIERA_META_TYPELIST_H
|
||||
#ifndef LIB_META_TYPELIST_H
|
||||
#define LIB_META_TYPELIST_H
|
||||
|
||||
|
||||
|
||||
|
||||
namespace lumiera {
|
||||
namespace typelist{
|
||||
namespace lib {
|
||||
namespace meta {
|
||||
|
||||
struct NullType
|
||||
{
|
||||
|
|
@ -129,5 +129,5 @@ namespace typelist{
|
|||
typedef Node<NullType,NullType> NodeNull;
|
||||
|
||||
|
||||
}} // namespace lumiera::typelist
|
||||
}} // namespace lib::meta
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -41,8 +41,8 @@
|
|||
*/
|
||||
|
||||
|
||||
#ifndef LUMIERA_META_TYPESEQ_UTIL_H
|
||||
#define LUMIERA_META_TYPESEQ_UTIL_H
|
||||
#ifndef LIB_META_TYPESEQ_UTIL_H
|
||||
#define LIB_META_TYPESEQ_UTIL_H
|
||||
|
||||
#include "lib/meta/typelist.hpp"
|
||||
#include "lib/meta/typelist-manip.hpp"
|
||||
|
|
@ -50,8 +50,8 @@
|
|||
|
||||
|
||||
|
||||
namespace lumiera {
|
||||
namespace typelist{
|
||||
namespace lib {
|
||||
namespace meta {
|
||||
|
||||
|
||||
|
||||
|
|
@ -203,5 +203,5 @@ namespace typelist{
|
|||
|
||||
|
||||
|
||||
}} // namespace lumiera::typelist
|
||||
}} // namespace lib::meta
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -21,92 +21,154 @@
|
|||
*/
|
||||
|
||||
|
||||
#ifndef LUMIERA_META_UTIL_H
|
||||
#define LUMIERA_META_UTIL_H
|
||||
/** @file util.hpp
|
||||
** Simple and lightweight helpers for metaprogramming and type detection.
|
||||
** This header is a collection of very basic type detection and metaprogramming utilities.
|
||||
** @warning indirectly, this header gets included into the majority of compilation units.
|
||||
** Avoid anything here which increases compilation times or adds much debugging info.
|
||||
**
|
||||
** @see MetaUtils_test
|
||||
** @see trait.hpp
|
||||
** @see typelist.hpp
|
||||
**
|
||||
*/
|
||||
|
||||
|
||||
#ifndef LIB_META_UTIL_H
|
||||
#define LIB_META_UTIL_H
|
||||
|
||||
|
||||
#include <string>
|
||||
|
||||
|
||||
namespace lib {
|
||||
namespace meta {
|
||||
|
||||
|
||||
namespace lumiera {
|
||||
|
||||
|
||||
/* types for figuring out the overload resolution chosen by the compiler */
|
||||
|
||||
typedef char Yes_t;
|
||||
struct No_t { char padding[8]; };
|
||||
|
||||
|
||||
|
||||
namespace typelist {
|
||||
|
||||
/** Compile-time Type equality:
|
||||
* Simple Trait template to pick up types considered
|
||||
* \em identical by the compiler.
|
||||
* @warning identical, not sub-type!
|
||||
*/
|
||||
template<typename T1, typename T2>
|
||||
struct is_sameType
|
||||
{
|
||||
static const bool value = false;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct is_sameType<T,T>
|
||||
{
|
||||
static const bool value = true;
|
||||
};
|
||||
|
||||
|
||||
/** semi-automatic detection if an instantiation is possible.
|
||||
* Requires help by the template to be tested, which needs to define
|
||||
* a typedef member \c is_defined. The embedded metafunction Test can be used
|
||||
* as a predicate for filtering types which may yield a valid instantiation
|
||||
* of the candidate template in question.
|
||||
* \par
|
||||
* A fully automated solution for this problem is impossible by theoretic reasons.
|
||||
* Any non trivial use of such a \c is_defined trait would break the "One Definition Rule",
|
||||
* as the state of any type can change from "partially defined" to "fully defined" over
|
||||
* the course of any translation unit. Thus, even if there may be a \em solution out there,
|
||||
* we can expect it to break at some point by improvements/fixes to the C++ Language.
|
||||
*/
|
||||
template<template<class> class _CandidateTemplate_>
|
||||
struct Instantiation
|
||||
{
|
||||
|
||||
template<class X>
|
||||
class Test
|
||||
{
|
||||
typedef _CandidateTemplate_<X> Instance;
|
||||
|
||||
template<class U>
|
||||
static Yes_t check(typename U::is_defined *);
|
||||
template<class U>
|
||||
static No_t check(...);
|
||||
|
||||
public:
|
||||
static const bool value = (sizeof(Yes_t)==sizeof(check<Instance>(0)));
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/** Trait template for detecting a typelist type.
|
||||
* For example, this allows to write specialisations with the help of
|
||||
* boost::enable_if
|
||||
*/
|
||||
template<typename TY>
|
||||
class is_Typelist
|
||||
{
|
||||
template<class X>
|
||||
static Yes_t check(typename X::List *);
|
||||
template<class>
|
||||
static No_t check(...);
|
||||
|
||||
public:
|
||||
static const bool value = (sizeof(Yes_t)==sizeof(check<TY>(0)));
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace typelist
|
||||
|
||||
} // namespace lumiera
|
||||
typedef char Yes_t;
|
||||
struct No_t { char more_than_one[4]; };
|
||||
|
||||
|
||||
|
||||
|
||||
/** Compile-time Type equality:
|
||||
* Simple Trait template to pick up types considered
|
||||
* \em identical by the compiler.
|
||||
* @warning identical, not sub-type!
|
||||
*/
|
||||
template<typename T1, typename T2>
|
||||
struct is_sameType
|
||||
{
|
||||
static const bool value = false;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct is_sameType<T,T>
|
||||
{
|
||||
static const bool value = true;
|
||||
};
|
||||
|
||||
|
||||
/** detect possibility of a conversion to string.
|
||||
* Naive implementation just trying a the direct conversion.
|
||||
* The embedded constant #value will be true in case this succeeds.
|
||||
* Might fail in more tricky situations (references, const, volatile)
|
||||
* @see string-util.hpp more elaborate solution including lexical_cast
|
||||
*/
|
||||
template<typename T>
|
||||
struct can_convertToString
|
||||
{
|
||||
static T & probe();
|
||||
|
||||
static Yes_t check(std::string);
|
||||
static No_t check(...);
|
||||
|
||||
public:
|
||||
static const bool value = (sizeof(Yes_t)==sizeof(check(probe())));
|
||||
};
|
||||
|
||||
|
||||
/** strip const from type: naive implementation */
|
||||
template<typename T>
|
||||
struct UnConst
|
||||
{
|
||||
typedef T Type;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct UnConst<const T>
|
||||
{
|
||||
typedef T Type;
|
||||
};
|
||||
template<typename T>
|
||||
struct UnConst<const T *>
|
||||
{
|
||||
typedef T* Type;
|
||||
};
|
||||
template<typename T>
|
||||
struct UnConst<T * const>
|
||||
{
|
||||
typedef T* Type;
|
||||
};
|
||||
template<typename T>
|
||||
struct UnConst<const T * const>
|
||||
{
|
||||
typedef T* Type;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/** semi-automatic detection if an instantiation is possible.
|
||||
* Requires help by the template to be tested, which needs to define
|
||||
* a typedef member \c is_defined. The embedded metafunction Test can be used
|
||||
* as a predicate for filtering types which may yield a valid instantiation
|
||||
* of the candidate template in question.
|
||||
* \par
|
||||
* A fully automated solution for this problem is impossible by theoretic reasons.
|
||||
* Any non trivial use of such a \c is_defined trait would break the "One Definition Rule",
|
||||
* as the state of any type can change from "partially defined" to "fully defined" over
|
||||
* the course of any translation unit. Thus, even if there may be a \em solution out there,
|
||||
* we can expect it to break at some point by improvements/fixes to the C++ Language.
|
||||
*/
|
||||
template<template<class> class _CandidateTemplate_>
|
||||
struct Instantiation
|
||||
{
|
||||
|
||||
template<class X>
|
||||
class Test
|
||||
{
|
||||
typedef _CandidateTemplate_<X> Instance;
|
||||
|
||||
template<class U>
|
||||
static Yes_t check(typename U::is_defined *);
|
||||
template<class U>
|
||||
static No_t check(...);
|
||||
|
||||
public:
|
||||
static const bool value = (sizeof(Yes_t)==sizeof(check<Instance>(0)));
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/** Trait template for detecting a typelist type.
|
||||
* For example, this allows to write specialisations with the help of
|
||||
* boost::enable_if
|
||||
*/
|
||||
template<typename TY>
|
||||
class is_Typelist
|
||||
{
|
||||
template<class X>
|
||||
static Yes_t check(typename X::List *);
|
||||
template<class>
|
||||
static No_t check(...);
|
||||
|
||||
public:
|
||||
static const bool value = (sizeof(Yes_t)==sizeof(check<TY>(0)));
|
||||
};
|
||||
|
||||
|
||||
|
||||
}} // namespace lib::meta
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -54,9 +54,9 @@ namespace lib {
|
|||
namespace factory {
|
||||
|
||||
|
||||
using lumiera::typelist::Types;
|
||||
using lumiera::typelist::FunctionSignature;
|
||||
using lumiera::typelist::FunctionTypedef;
|
||||
using lib::meta::Types;
|
||||
using lib::meta::FunctionSignature;
|
||||
using lib::meta::FunctionTypedef;
|
||||
using std::tr1::function;
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@
|
|||
*/
|
||||
|
||||
/** @file multifact.hpp
|
||||
** Building blocks of a configurable factory, generating families of related objects.
|
||||
** Building blocks to create a configurable factory, generating families of related objects.
|
||||
** Serving the "classical" factory situation: obtaining objects of various kinds, which
|
||||
** are related somehow (usually through an common interface). The creation of these
|
||||
** objects is non-trivial while number and exact parametrisation aren't known beforehand
|
||||
|
|
@ -70,7 +70,7 @@
|
|||
namespace lib {
|
||||
namespace factory {
|
||||
|
||||
//////TODO: couldn't these wrappers be extracted into a separate header?
|
||||
/////////////////////////////////TICKET #470 : couldn't these wrappers be extracted into a separate header?
|
||||
|
||||
/**
|
||||
* Dummy "wrapper",
|
||||
|
|
|
|||
104
src/lib/nobug-resource-handle-context.hpp
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
NOBUG-RESOURCE-HANDLE-CONTEXT.hpp - thread local stack to manage NoBug resource handles
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2010, Hermann Vosseler <Ichthyostega@web.de>
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
*/
|
||||
|
||||
/** @file nobug-resource-handle-context.hpp
|
||||
** Thread-local stack of NoBug resource handles.
|
||||
** This helper allows to access the resource handle in the nearest enclosing scope.
|
||||
** The motivation for this approach was to avoid passing the resource handle over
|
||||
** several intermediary function calls when using a scoped variable to control
|
||||
** object monitor locking. Within this usage context, the necessity of passing
|
||||
** a NoBug resource handle seems to be a cross-cutting concern, and not directly
|
||||
** related to the core concern (controlling a mutex).
|
||||
**
|
||||
** @remarks as of 8/2011, this feature is not used anymore. In 12/2011, the concept
|
||||
** of a diagnostic context stack was generalised. At that point, this header was
|
||||
** created as an off-spin, now based on the generalised feature, to document this
|
||||
** usage possibility, which might be required again at some point in the future.
|
||||
**
|
||||
** @see lib::DiagnosticContext
|
||||
** @see diagnostic-context-test.hpp
|
||||
**
|
||||
**/
|
||||
|
||||
|
||||
#ifndef LIB_NOBUG_RESOURCE_HANDLE_CONTEXT_H
|
||||
#define LIB_NOBUG_RESOURCE_HANDLE_CONTEXT_H
|
||||
|
||||
|
||||
#include "lib/error.hpp"
|
||||
#include "lib/thread-local.hpp"
|
||||
|
||||
#include <boost/noncopyable.hpp>
|
||||
#include <nobug.h>
|
||||
|
||||
|
||||
|
||||
namespace lib {
|
||||
|
||||
|
||||
|
||||
#ifdef NOBUG_MODE_ALPHA ////////////////////////TODO don't we need the handle in BETA builds for resource logging?
|
||||
|
||||
/**
|
||||
* Diagnostic data frame to hold a NoBug resource handle.
|
||||
* This way, code in nested function calls may pick up the nearest available handle.
|
||||
* @warning relies on thread-local access; never use this within global data structures.
|
||||
*/
|
||||
class NobugResourceHandleContext
|
||||
: DiagnosticContext<nobug_resource_user*>
|
||||
{
|
||||
public:
|
||||
};
|
||||
|
||||
|
||||
#else /* not NOBUG_ALPHA */
|
||||
|
||||
|
||||
/**
|
||||
* Disabled placeholder for the Diagnostic context, not used in release builds.
|
||||
*/
|
||||
class NobugResourceHandleContext
|
||||
: boost::noncopyable
|
||||
{
|
||||
|
||||
typedef nobug_resource_user* Handle;
|
||||
|
||||
public:
|
||||
|
||||
operator Handle () ///< payload: NoBug resource tracker user handle
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** accessing the innermost diagnostic context created */
|
||||
static NobugResourceHandleContext&
|
||||
access ()
|
||||
{
|
||||
UNIMPLEMENTED ("how to disable DiagnosticContext with minimum overhead");
|
||||
}
|
||||
};
|
||||
#endif /* NOBUG_ALPHA? */
|
||||
|
||||
|
||||
|
||||
} // namespace lib
|
||||
#endif
|
||||
|
|
@ -73,6 +73,7 @@
|
|||
#include "lib/util.hpp"
|
||||
|
||||
#include <boost/noncopyable.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
|
||||
|
||||
namespace lib {
|
||||
|
|
@ -252,6 +253,8 @@ namespace lib {
|
|||
template<typename SUB>
|
||||
struct Buff : Buffer
|
||||
{
|
||||
BOOST_STATIC_ASSERT (siz >= sizeof(SUB));
|
||||
|
||||
SUB&
|
||||
get() const ///< core operation: target is contained within the inline buffer
|
||||
{
|
||||
|
|
@ -266,7 +269,6 @@ namespace lib {
|
|||
explicit
|
||||
Buff (SUB const& obj)
|
||||
{
|
||||
REQUIRE (siz >= sizeof(SUB));
|
||||
new(Buffer::ptr()) SUB (obj);
|
||||
}
|
||||
|
||||
|
|
@ -613,6 +615,8 @@ namespace lib {
|
|||
void
|
||||
placeDefault()
|
||||
{
|
||||
BOOST_STATIC_ASSERT (siz >= sizeof(DEFAULT));
|
||||
|
||||
new(&buf_) DEFAULT();
|
||||
}
|
||||
|
||||
|
|
@ -640,13 +644,14 @@ namespace lib {
|
|||
destroy(); \
|
||||
try \
|
||||
{ \
|
||||
REQUIRE (siz >= sizeof(TY)); \
|
||||
return *new(&buf_) _CTOR_CALL_; \
|
||||
} \
|
||||
catch (...) \
|
||||
{ \
|
||||
placeDefault(); \
|
||||
throw; \
|
||||
BOOST_STATIC_ASSERT (siz >= sizeof(TY));\
|
||||
\
|
||||
return *new(&buf_) _CTOR_CALL_; \
|
||||
} \
|
||||
catch (...) \
|
||||
{ \
|
||||
placeDefault(); \
|
||||
throw; \
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -46,15 +46,15 @@
|
|||
*/
|
||||
|
||||
|
||||
#ifndef LUMIERA_P_H
|
||||
#define LUMIERA_P_H
|
||||
#ifndef LIB_P_H
|
||||
#define LIB_P_H
|
||||
|
||||
|
||||
#include "lib/error.hpp"
|
||||
#include <tr1/memory>
|
||||
|
||||
|
||||
namespace lumiera {
|
||||
namespace lib {
|
||||
|
||||
using std::tr1::shared_ptr;
|
||||
using std::tr1::weak_ptr;
|
||||
|
|
@ -125,5 +125,5 @@ namespace lumiera {
|
|||
};
|
||||
|
||||
|
||||
} // namespace lumiera
|
||||
} // namespace lib
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -34,8 +34,8 @@
|
|||
** assume the presence of a garbage collector or similar mechanism,
|
||||
** so 'objects' need just to be mentioned by reference.
|
||||
**
|
||||
** In C++ to employ many of the well known techniques, you're more or less
|
||||
** bound to explicitly put the objects somewhere in heap allocated memory
|
||||
** In C++, in order to employ many of the well known techniques, we're bound
|
||||
** more or less to explicitly put the objects somewhere in heap allocated memory
|
||||
** and then pass an interface pointer or reference into the actual algorithm.
|
||||
** Often, this hinders a design based on constant values and small descriptor
|
||||
** objects used inline, thus forcing into unnecessarily complex and heavyweight
|
||||
|
|
@ -68,7 +68,7 @@
|
|||
** Moreover, the PolymorphicValue container provides static builder functions,
|
||||
** allowing to place a concrete instance of a subclass into the content buffer.
|
||||
** After construction, the actual type of this instance will be forgotten
|
||||
** (``type erasure''), but because the embedded vtable, on access the
|
||||
** (``type erasure''), but because of the embedded vtable, on access the
|
||||
** proper implementation functions will be invoked.
|
||||
**
|
||||
** Expanding on that pattern, the copying and cloning operations of the whole
|
||||
|
|
@ -86,7 +86,7 @@
|
|||
** the copy or clone operations, we need to do an elaborate re-cast operation,
|
||||
** first going down to the leaf type and then back up into the mixed in
|
||||
** management interface. Basically this operation is performed by using
|
||||
** an \c dynamic_cast<CopyAPI&>(bufferContents)
|
||||
** a \c dynamic_cast<CopyAPI&>(bufferContents)
|
||||
** - but when the used client types provide some collaboration and implement
|
||||
** this management interface either directly on the API or as an immediate
|
||||
** sub-interface, then this copy/management interface is located within the
|
||||
|
|
@ -146,6 +146,7 @@
|
|||
#include "lib/meta/duck-detector.hpp"
|
||||
|
||||
#include <boost/utility/enable_if.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
|
||||
|
||||
namespace lib {
|
||||
|
|
@ -155,8 +156,8 @@ namespace lib {
|
|||
|
||||
namespace error = lumiera::error;
|
||||
using boost::enable_if;
|
||||
using lumiera::Yes_t;
|
||||
using lumiera::No_t;
|
||||
using lib::meta::Yes_t;
|
||||
using lib::meta::No_t;
|
||||
|
||||
struct EmptyBase{ };
|
||||
|
||||
|
|
@ -345,7 +346,7 @@ namespace lib {
|
|||
* - the caller cares for thread safety. No concurrent get calls while in mutation!
|
||||
*
|
||||
* @warning when a create or copy-into operation fails with exception, the whole
|
||||
* PolymorphicValue object is in undefined state and must not be used further.
|
||||
* PolymorphicValue object is in undefined state and must not be used henceforth.
|
||||
*/
|
||||
template
|
||||
< class IFA ///< the nominal Base/Interface class for a family of types
|
||||
|
|
@ -384,7 +385,8 @@ namespace lib {
|
|||
template<class IMP>
|
||||
PolymorphicValue (IMP*)
|
||||
{
|
||||
REQUIRE (siz >= sizeof(IMP));
|
||||
BOOST_STATIC_ASSERT (siz >= sizeof(IMP));
|
||||
|
||||
new(&buf_) IMP();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -40,7 +40,6 @@
|
|||
#ifndef LIB_RESULT_H
|
||||
#define LIB_RESULT_H
|
||||
|
||||
//#include "pre.hpp"
|
||||
#include "lib/error.hpp"
|
||||
#include "lib/wrapper.hpp"
|
||||
#include "lib/util.hpp"
|
||||
|
|
|
|||
614
src/lib/scoped-collection.hpp
Normal file
|
|
@ -0,0 +1,614 @@
|
|||
/*
|
||||
SCOPED-COLLECTION.hpp - managing a fixed collection of noncopyable polymorphic objects
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2012, Hermann Vosseler <Ichthyostega@web.de>
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
*/
|
||||
|
||||
/** @file scoped-collection.hpp
|
||||
** Managing a collection of noncopyable polymorphic objects in compact storage.
|
||||
** This helper supports the frequently encountered situation where a service
|
||||
** implementation internally manages a collection of implementation related
|
||||
** sub-components with reference semantics. Typically, those objects are
|
||||
** being used polymorphically, and often they are also added step by step.
|
||||
** The storage holding all those child objects is allocated in one chunk
|
||||
** and never adjusted.
|
||||
**
|
||||
** \par usage patterns
|
||||
** The common ground for all usage of this container is to hold and some
|
||||
** with exclusive ownership; when the enclosing container goes out of scope,
|
||||
** all the dtors of the embedded objects will be invoked. Frequently this
|
||||
** side effect is the reason for using the container: we want to own some
|
||||
** resource handles to be available exactly as long as the managing object
|
||||
** needs and accesses them.
|
||||
**
|
||||
** There are two different usage patterns for populating a ScopedCollection
|
||||
** - the "stack style" usage creates an empty container (using the one arg
|
||||
** ctor just to specify the maximum size). The storage to hold up to this
|
||||
** number of objects is (heap) allocated right away, but no objects are
|
||||
** created. Later on, individual objects are "pushed" into the collection
|
||||
** by invoking #appendNewElement() to create a new element of the default
|
||||
** type I) or #appendNew<Type>(args) to create some subtype. This way,
|
||||
** the container is being filled successively.
|
||||
** - the "RAII style" usage strives to create all of the content objects
|
||||
** right away, immediately after the memory allocation. This usage pattern
|
||||
** avoids any kind of "lifecycle state". Either the container comes up sane
|
||||
** and fully populated, or the ctor call fails and any already created
|
||||
** objects are discarded.
|
||||
** @note intentionally there is no operation to discard individual objects,
|
||||
** all you can do is to #clear() the whole container.
|
||||
** @note the container can hold instances of a subclass of the type defined
|
||||
** by the template parameter I. But you need to ensure in this case
|
||||
** that the defined buffer size for each element (2nt template parameter)
|
||||
** is sufficient to hold any of these subclass instances. This condition
|
||||
** is protected by a static assertion (compilation failure).
|
||||
** @warning when using subclasses, a virtual dtor is mandatory
|
||||
** @warning deliberately \em not threadsafe
|
||||
**
|
||||
** @see ScopedCollection_test
|
||||
** @see scoped-ptrvect.hpp quite similar, but using individual heap pointers
|
||||
*/
|
||||
|
||||
|
||||
#ifndef LIB_SCOPED_COLLECTION_H
|
||||
#define LIB_SCOPED_COLLECTION_H
|
||||
|
||||
|
||||
#include "lib/error.hpp"
|
||||
#include "lib/iter-adapter.hpp"
|
||||
|
||||
#include <boost/noncopyable.hpp>
|
||||
#include <boost/scoped_array.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <boost/type_traits/is_same.hpp>
|
||||
#include <boost/type_traits/is_base_of.hpp>
|
||||
|
||||
|
||||
namespace lib {
|
||||
|
||||
namespace error = lumiera::error;
|
||||
using error::LUMIERA_ERROR_CAPACITY;
|
||||
using error::LUMIERA_ERROR_INDEX_BOUNDS;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A fixed collection of noncopyable polymorphic objects.
|
||||
*
|
||||
* All child objects reside in a common chunk of storage
|
||||
* and are owned and managed by this collection holder.
|
||||
* Array style access and iteration.
|
||||
*/
|
||||
template
|
||||
< class I ///< the nominal Base/Interface class for a family of types
|
||||
, size_t siz = sizeof(I) ///< maximum storage required for the targets to be held inline
|
||||
>
|
||||
class ScopedCollection
|
||||
: boost::noncopyable
|
||||
{
|
||||
|
||||
public:
|
||||
/**
|
||||
* Storage Frame to hold one Child object.
|
||||
* The storage will be an heap allocated
|
||||
* array of such Wrapper objects.
|
||||
* @note doesn't manage the Child
|
||||
*/
|
||||
class ElementHolder
|
||||
: boost::noncopyable
|
||||
{
|
||||
|
||||
mutable char buf_[siz];
|
||||
|
||||
public:
|
||||
|
||||
I&
|
||||
accessObj() const
|
||||
{
|
||||
return reinterpret_cast<I&> (buf_);
|
||||
}
|
||||
|
||||
void
|
||||
destroy()
|
||||
{
|
||||
accessObj().~I();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#define TYPE_SANITY_CHECK \
|
||||
BOOST_STATIC_ASSERT ((boost::is_base_of<I,TY>::value || boost::is_same<I,TY>::value))
|
||||
|
||||
/** Abbreviation for placement new */
|
||||
#define EMBEDDED_ELEMENT_CTOR(_CTOR_CALL_) \
|
||||
TYPE_SANITY_CHECK; \
|
||||
return *new(&buf_) _CTOR_CALL_; \
|
||||
|
||||
|
||||
template<class TY>
|
||||
TY&
|
||||
create ()
|
||||
{
|
||||
EMBEDDED_ELEMENT_CTOR ( TY() )
|
||||
}
|
||||
|
||||
|
||||
template<class TY, typename A1>
|
||||
TY& //___________________________________________
|
||||
create (A1 a1) ///< place object of type TY, using 1-arg ctor
|
||||
{
|
||||
EMBEDDED_ELEMENT_CTOR ( TY(a1) )
|
||||
}
|
||||
|
||||
|
||||
template< class TY
|
||||
, typename A1
|
||||
, typename A2
|
||||
>
|
||||
TY& //___________________________________________
|
||||
create (A1 a1, A2 a2) ///< place object of type TY, using 2-arg ctor
|
||||
{
|
||||
EMBEDDED_ELEMENT_CTOR ( TY(a1,a2) )
|
||||
}
|
||||
|
||||
|
||||
template< class TY
|
||||
, typename A1
|
||||
, typename A2
|
||||
, typename A3
|
||||
>
|
||||
TY& //___________________________________________
|
||||
create (A1 a1, A2 a2, A3 a3) ///< place object of type TY, using 3-arg ctor
|
||||
{
|
||||
EMBEDDED_ELEMENT_CTOR ( TY(a1,a2,a3) )
|
||||
}
|
||||
|
||||
|
||||
template< class TY
|
||||
, typename A1
|
||||
, typename A2
|
||||
, typename A3
|
||||
, typename A4
|
||||
>
|
||||
TY& //___________________________________________
|
||||
create (A1 a1, A2 a2, A3 a3, A4 a4) ///< place object of type TY, using 4-arg ctor
|
||||
{
|
||||
EMBEDDED_ELEMENT_CTOR ( TY(a1,a2,a3,a4) )
|
||||
}
|
||||
|
||||
|
||||
template< class TY
|
||||
, typename A1
|
||||
, typename A2
|
||||
, typename A3
|
||||
, typename A4
|
||||
, typename A5
|
||||
>
|
||||
TY& //___________________________________________
|
||||
create (A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) ///< place object of type TY, using 5-arg ctor
|
||||
{
|
||||
EMBEDDED_ELEMENT_CTOR ( TY(a1,a2,a3,a4,a5) )
|
||||
}
|
||||
#undef EMBEDDED_ELEMENT_CTOR
|
||||
#undef TYPE_SANITY_CHECK
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
~ScopedCollection ()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
explicit
|
||||
ScopedCollection (size_t maxElements)
|
||||
: level_(0)
|
||||
, capacity_(maxElements)
|
||||
, elements_(new ElementHolder[maxElements])
|
||||
{ }
|
||||
|
||||
/** creating a ScopedCollection in RAII-style:
|
||||
* The embedded elements will be created immediately.
|
||||
* Ctor fails in case of any error during element creation.
|
||||
* @param builder functor to be invoked for each "slot".
|
||||
* It gets an ElementHolder& as parameter, and should
|
||||
* use this to create an object of some I-subclass
|
||||
*/
|
||||
template<class CTOR>
|
||||
ScopedCollection (size_t maxElements, CTOR builder)
|
||||
: level_(0)
|
||||
, capacity_(maxElements)
|
||||
, elements_(new ElementHolder[maxElements])
|
||||
{
|
||||
populate_by (builder);
|
||||
}
|
||||
|
||||
/** variation of RAII-style: using a builder function,
|
||||
* which is a member of some object. This supports the
|
||||
* typical usage situation, where a manager object builds
|
||||
* a ScopedCollection of some components
|
||||
* @param builder member function used to create the elements
|
||||
* @param instance the owning class instance, on which the
|
||||
* builder member function will be invoked ("this").
|
||||
*/
|
||||
template<class TY>
|
||||
ScopedCollection (size_t maxElements, void (TY::*builder) (ElementHolder&), TY * const instance)
|
||||
: level_(0)
|
||||
, capacity_(maxElements)
|
||||
, elements_(new ElementHolder[maxElements])
|
||||
{
|
||||
populate_by (builder,instance);
|
||||
}
|
||||
|
||||
/* == some pre-defined Builders == */
|
||||
|
||||
class FillAll; ///< fills the ScopedCollection with default constructed I-instances
|
||||
|
||||
template<typename TY>
|
||||
class FillWith; ///< fills the ScopedCollection with default constructed TY-instances
|
||||
|
||||
template<typename IT>
|
||||
class PullFrom; ///< fills by copy-constructing values pulled from the iterator IT
|
||||
|
||||
template<typename IT>
|
||||
static PullFrom<IT>
|
||||
pull (IT iter) ///< convenience shortcut to pull from any given Lumiera Forward Iterator
|
||||
{
|
||||
return PullFrom<IT> (iter);
|
||||
}
|
||||
|
||||
void
|
||||
clear()
|
||||
{
|
||||
REQUIRE (level_ <= capacity_, "Storage corrupted");
|
||||
|
||||
while (level_)
|
||||
{
|
||||
--level_;
|
||||
try {
|
||||
elements_[level_].destroy();
|
||||
}
|
||||
ERROR_LOG_AND_IGNORE (progress, "Clean-up of element in ScopedCollection")
|
||||
}
|
||||
}
|
||||
|
||||
/** init all elements default constructed */
|
||||
void
|
||||
populate()
|
||||
try {
|
||||
while (level_ < capacity_)
|
||||
{
|
||||
elements_[level_].template create<I>();
|
||||
++level_;
|
||||
}
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
WARN (progress, "Failure while populating ScopedCollection. "
|
||||
"All elements will be discarded");
|
||||
clear();
|
||||
throw;
|
||||
}
|
||||
|
||||
/** init all elements at once,
|
||||
* invoking a builder functor for each.
|
||||
* @param builder to create the individual elements
|
||||
* this functor is responsible to invoke the appropriate
|
||||
* ElementHolder#create function, which places a new element
|
||||
* into the storage frame passed as parameter.
|
||||
*/
|
||||
template<class CTOR>
|
||||
void
|
||||
populate_by (CTOR builder)
|
||||
try {
|
||||
while (level_ < capacity_)
|
||||
{
|
||||
ElementHolder& storageFrame (elements_[level_]);
|
||||
builder (storageFrame);
|
||||
++level_;
|
||||
} }
|
||||
catch(...)
|
||||
{
|
||||
WARN (progress, "Failure while populating ScopedCollection. "
|
||||
"All elements will be discarded");
|
||||
clear();
|
||||
throw;
|
||||
}
|
||||
|
||||
/** variation of element initialisation,
|
||||
* invoking a member function of some manager object
|
||||
* for each collection element to be created.
|
||||
*/
|
||||
template<class TY>
|
||||
void
|
||||
populate_by (void (TY::*builder) (ElementHolder&), TY * const instance)
|
||||
try {
|
||||
while (level_ < capacity_)
|
||||
{
|
||||
ElementHolder& storageFrame (elements_[level_]);
|
||||
(instance->*builder) (storageFrame);
|
||||
++level_;
|
||||
} }
|
||||
catch(...)
|
||||
{
|
||||
WARN (progress, "Failure while populating ScopedCollection. "
|
||||
"All elements will be discarded");
|
||||
clear();
|
||||
throw;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** push a new element of default type
|
||||
* to the end of this container
|
||||
* @note EX_STRONG */
|
||||
I& appendNewElement() { return appendNew<I>(); }
|
||||
|
||||
|
||||
template< class TY >
|
||||
TY& //_________________________________________
|
||||
appendNew () ///< add object of type TY, using 0-arg ctor
|
||||
{
|
||||
__ensureSufficientCapacity();
|
||||
TY& newElm = elements_[level_].template create<TY>();
|
||||
++level_;
|
||||
return newElm;
|
||||
}
|
||||
|
||||
|
||||
template< class TY
|
||||
, typename A1
|
||||
>
|
||||
TY& //_________________________________________
|
||||
appendNew (A1 a1) ///< add object of type TY, using 1-arg ctor
|
||||
{
|
||||
__ensureSufficientCapacity();
|
||||
TY& newElm = elements_[level_].template create<TY>(a1);
|
||||
++level_;
|
||||
return newElm;
|
||||
}
|
||||
|
||||
|
||||
template< class TY
|
||||
, typename A1
|
||||
, typename A2
|
||||
>
|
||||
TY& //_________________________________________
|
||||
appendNew (A1 a1, A2 a2) ///< add object of type TY, using 2-arg ctor
|
||||
{
|
||||
__ensureSufficientCapacity();
|
||||
TY& newElm = elements_[level_].template create<TY>(a1,a2);
|
||||
++level_;
|
||||
return newElm;
|
||||
}
|
||||
|
||||
|
||||
template< class TY
|
||||
, typename A1
|
||||
, typename A2
|
||||
, typename A3
|
||||
>
|
||||
TY& //_________________________________________
|
||||
appendNew (A1 a1, A2 a2, A3 a3) ///< add object of type TY, using 3-arg ctor
|
||||
{
|
||||
__ensureSufficientCapacity();
|
||||
TY& newElm = elements_[level_].template create<TY>(a1,a2,a3);
|
||||
++level_;
|
||||
return newElm;
|
||||
}
|
||||
|
||||
|
||||
template< class TY
|
||||
, typename A1
|
||||
, typename A2
|
||||
, typename A3
|
||||
, typename A4
|
||||
>
|
||||
TY& //_________________________________________
|
||||
appendNew (A1 a1, A2 a2, A3 a3, A4 a4) ///< add object of type TY, using 4-arg ctor
|
||||
{
|
||||
__ensureSufficientCapacity();
|
||||
TY& newElm = elements_[level_].template create<TY>(a1,a2,a3,a4);
|
||||
++level_;
|
||||
return newElm;
|
||||
}
|
||||
|
||||
|
||||
template< class TY
|
||||
, typename A1
|
||||
, typename A2
|
||||
, typename A3
|
||||
, typename A4
|
||||
, typename A5
|
||||
>
|
||||
TY& //_________________________________________
|
||||
appendNew (A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) ///< add object of type TY, using 5-arg ctor
|
||||
{
|
||||
__ensureSufficientCapacity();
|
||||
TY& newElm = elements_[level_].template create<TY>(a1,a2,a3,a4,a5);
|
||||
++level_;
|
||||
return newElm;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* === Element access and iteration === */
|
||||
|
||||
I&
|
||||
operator[] (size_t index) const
|
||||
{
|
||||
if (index < level_)
|
||||
return elements_[index].accessObj();
|
||||
|
||||
throw error::Logic ("Attempt to access not (yet) existing object in ScopedCollection"
|
||||
, LUMIERA_ERROR_INDEX_BOUNDS);
|
||||
}
|
||||
|
||||
|
||||
|
||||
typedef IterAdapter< I *, const ScopedCollection *> iterator;
|
||||
typedef IterAdapter<const I *, const ScopedCollection *> const_iterator;
|
||||
|
||||
|
||||
iterator begin() { return iterator (this, _access_begin()); }
|
||||
const_iterator begin() const { return const_iterator (this, _access_begin()); }
|
||||
iterator end () { return iterator(); }
|
||||
const_iterator end () const { return const_iterator(); }
|
||||
|
||||
|
||||
size_t size () const { return level_; }
|
||||
size_t capacity () const { return capacity_; }
|
||||
bool empty () const { return 0 == level_; }
|
||||
|
||||
|
||||
|
||||
private:
|
||||
/* ==== Storage: heap allocated array of element buffers ==== */
|
||||
|
||||
typedef boost::scoped_array<ElementHolder> ElementStorage;
|
||||
|
||||
size_t level_;
|
||||
size_t capacity_;
|
||||
ElementStorage elements_;
|
||||
|
||||
|
||||
|
||||
void
|
||||
__ensureSufficientCapacity()
|
||||
{
|
||||
if (level_ >= capacity_)
|
||||
throw error::State ("ScopedCollection exceeding the initially defined capacity"
|
||||
, LUMIERA_ERROR_CAPACITY);
|
||||
}
|
||||
|
||||
|
||||
/* ==== internal callback API for the iterator ==== */
|
||||
|
||||
/** Iteration-logic: switch to next position
|
||||
* @note assuming here that the start address of the embedded object
|
||||
* coincides with the start of an array element (ElementHolder)
|
||||
*/
|
||||
friend void
|
||||
iterNext (const ScopedCollection*, I* & pos)
|
||||
{
|
||||
ElementHolder* & storageLocation = reinterpret_cast<ElementHolder* &> (pos);
|
||||
++storageLocation;
|
||||
}
|
||||
|
||||
friend void
|
||||
iterNext (const ScopedCollection*, const I* & pos)
|
||||
{
|
||||
const ElementHolder* & storageLocation = reinterpret_cast<const ElementHolder* &> (pos);
|
||||
++storageLocation;
|
||||
}
|
||||
|
||||
/** Iteration-logic: detect iteration end. */
|
||||
template<typename POS>
|
||||
friend bool
|
||||
hasNext (const ScopedCollection* src, POS & pos)
|
||||
{
|
||||
REQUIRE (src);
|
||||
if ((pos) && (pos < src->_access_end()))
|
||||
return true;
|
||||
else
|
||||
{
|
||||
pos = 0;
|
||||
return false;
|
||||
} }
|
||||
|
||||
|
||||
I* _access_begin() const { return & elements_[0].accessObj(); }
|
||||
I* _access_end() const { return & elements_[level_].accessObj(); }
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
/* === Supplement: pre-defined element builders === */
|
||||
|
||||
/** \par usage
|
||||
* Pass an instance of this builder functor as 2nd parameter
|
||||
* to ScopedCollections's ctor. (an anonymous instance is OK).
|
||||
* Using this variant of the compiler switches the collection to RAII-style:
|
||||
* It will immediately try to create all the embedded objects, invoking this
|
||||
* builder functor for each "slot" to hold such an embedded object. Actually,
|
||||
* this "slot" is an ElementHolder instance, which provides functions for
|
||||
* placement-creating objects into this embedded buffer.
|
||||
*/
|
||||
template<class I, size_t siz>
|
||||
class ScopedCollection<I,siz>::FillAll
|
||||
{
|
||||
public:
|
||||
void
|
||||
operator() (typename ScopedCollection<I,siz>::ElementHolder& storage)
|
||||
{
|
||||
storage.template create<I>();
|
||||
}
|
||||
};
|
||||
|
||||
template<class I, size_t siz>
|
||||
template<typename TY>
|
||||
class ScopedCollection<I,siz>::FillWith
|
||||
{
|
||||
public:
|
||||
void
|
||||
operator() (typename ScopedCollection<I,siz>::ElementHolder& storage)
|
||||
{
|
||||
storage.template create<TY>();
|
||||
}
|
||||
};
|
||||
|
||||
/** \par usage
|
||||
* This variant allows to "pull" elements from an iterator.
|
||||
* Actually, the collection will try to create each element right away,
|
||||
* by invoking the copy ctor and passing the value yielded by the iterator.
|
||||
* @note anything in accordance to the Lumera Forward Iterator pattern is OK.
|
||||
* This rules out just passing a plain STL iterator (because these can't
|
||||
* tell for themselves when they're exhausted). Use an suitable iter-adapter
|
||||
* instead, e.g. by invoking lib::iter_stl::eachElm(stl_container)
|
||||
*/
|
||||
template<class I, size_t siz>
|
||||
template<typename IT>
|
||||
class ScopedCollection<I,siz>::PullFrom
|
||||
{
|
||||
IT iter_;
|
||||
|
||||
typedef typename iter::TypeBinding<IT>::value_type ElementType;
|
||||
|
||||
public:
|
||||
PullFrom (IT source)
|
||||
: iter_(source)
|
||||
{ }
|
||||
|
||||
void
|
||||
operator() (typename ScopedCollection<I,siz>::ElementHolder& storage)
|
||||
{
|
||||
storage.template create<ElementType> (*iter_);
|
||||
++iter_;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace lib
|
||||
#endif
|
||||
|
|
@ -35,6 +35,8 @@
|
|||
** - TODO: detaching of objects...
|
||||
** - TODO: retro-fit with RefArray interface
|
||||
**
|
||||
** @warning deliberately \em not threadsafe
|
||||
**
|
||||
** @see scoped-ptrvect-test.cpp
|
||||
** @see scoped-holder.hpp
|
||||
** @see gui::DisplayService usage example
|
||||
|
|
|
|||
|
|
@ -46,11 +46,10 @@
|
|||
#ifndef LIB_SIMPLE_ALLOCATOR_H
|
||||
#define LIB_SIMPLE_ALLOCATOR_H
|
||||
|
||||
//#include "pre.hpp"
|
||||
#include "lib/error.hpp"
|
||||
#include "lib/meta/generator.hpp"
|
||||
#include "lib/meta/typelist-util.hpp"
|
||||
#include "lib/format.hpp"
|
||||
#include "lib/format-util.hpp"
|
||||
#include "lib/typed-counter.hpp"
|
||||
#include "include/logging.h"
|
||||
|
||||
|
|
@ -61,9 +60,9 @@
|
|||
|
||||
namespace lib {
|
||||
|
||||
using lumiera::typelist::Types;
|
||||
using lumiera::typelist::IsInList;
|
||||
using lumiera::typelist::InstantiateForEach;
|
||||
using lib::meta::Types;
|
||||
using lib::meta::IsInList;
|
||||
using lib::meta::InstantiateForEach;
|
||||
|
||||
|
||||
|
||||
|
|
@ -144,7 +143,7 @@ namespace lib {
|
|||
: InstantiateForEach< typename TYPES::List // for each of those types...
|
||||
, CustomAllocator // ...mix in the custom allocator
|
||||
>
|
||||
, COUNTER
|
||||
, COUNTER // ...Instantiation accounting policy
|
||||
{
|
||||
|
||||
/** forward plain memory allocation */
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@
|
|||
#ifndef LIB_SUB_ID_H
|
||||
#define LIB_SUB_ID_H
|
||||
|
||||
#include "lib/format.hpp"
|
||||
#include "lib/format-util.hpp"
|
||||
|
||||
//#include <functional>
|
||||
#include <boost/functional/hash.hpp> /////TODO better push the hash implementation into a cpp file (and btw, do it more seriously!)
|
||||
|
|
|
|||
|
|
@ -130,8 +130,8 @@ namespace test{
|
|||
namespace mock {
|
||||
|
||||
using boost::enable_if;
|
||||
using lumiera::Yes_t;
|
||||
using lumiera::No_t;
|
||||
using lib::meta::Yes_t;
|
||||
using lib::meta::No_t;
|
||||
|
||||
/**
|
||||
* Metafunction: does the Type in question
|
||||
|
|
|
|||
|
|
@ -36,15 +36,12 @@
|
|||
#ifndef TESTHELPER_RUN_H
|
||||
#define TESTHELPER_RUN_H
|
||||
|
||||
#include "pre.hpp"
|
||||
|
||||
|
||||
#include "proc/common.hpp"
|
||||
#include "include/logging.h"
|
||||
|
||||
#include "lib/test/suite.hpp"
|
||||
#include "lib/util.hpp"
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
/*
|
||||
test.h - macros for running tests
|
||||
TEST.h - support macros for plain-C tests
|
||||
|
||||
Copyright (C)
|
||||
2008, 2009, 2010, Christian Thaeter <ct@pipapo.org>
|
||||
Copyright (C) Lumiera.org
|
||||
2008, 2010 Christian Thaeter <ct@pipapo.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
|
|
@ -17,10 +17,21 @@
|
|||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef TEST_H
|
||||
#define TEST_H
|
||||
/** @file test.h
|
||||
** Helpers and support macros for defining test executables in C.
|
||||
** These macros provide some building blocks to assemble a \c main() function,
|
||||
** which checks a test name parameter and invokes the matching embedded code block.
|
||||
**
|
||||
** @see test-mpool.c C test example
|
||||
** @see HelloWorld_test C++ test example
|
||||
*/
|
||||
|
||||
|
||||
#ifndef LIB_TEST_TEST_H
|
||||
#define LIB_TEST_TEST_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
|
@ -51,10 +62,10 @@ main (int argc, const char** argv) \
|
|||
fprintf (stderr, " "#name" (planned)\n"); \
|
||||
else if (!++testcnt)
|
||||
|
||||
#define TESTS_END \
|
||||
if (!testcnt && argc !=1) \
|
||||
fprintf (stderr,"no such test: %s\n", argv[1]); \
|
||||
return ret; \
|
||||
#define TESTS_END \
|
||||
if (!testcnt && argc !=1) \
|
||||
fprintf (stderr,"no such test: %s\n", argv[1]); \
|
||||
return ret; \
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -48,14 +48,22 @@ namespace test{
|
|||
: val_(v)
|
||||
{ init(); }
|
||||
|
||||
~Dummy()
|
||||
virtual ~Dummy()
|
||||
{
|
||||
checksum() -= val_;
|
||||
}
|
||||
|
||||
long add (int i) { return val_+i; }
|
||||
virtual long
|
||||
acc (int i) ///< dummy API operation
|
||||
{
|
||||
return val_+i;
|
||||
}
|
||||
|
||||
int getVal() const { return val_; }
|
||||
int
|
||||
getVal() const
|
||||
{
|
||||
return val_;
|
||||
}
|
||||
|
||||
void
|
||||
setVal (int newVal)
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ namespace lib {
|
|||
|
||||
private:
|
||||
TAR*
|
||||
accessChecked()
|
||||
accessChecked() const
|
||||
{
|
||||
TAR *p(get());
|
||||
if (!p)
|
||||
|
|
|
|||
|
|
@ -115,7 +115,7 @@ namespace time {
|
|||
namespace mutation {
|
||||
|
||||
using boost::disable_if;
|
||||
using lumiera::typelist::is_sameType;
|
||||
using lib::meta::is_sameType;
|
||||
using std::tr1::placeholders::_1;
|
||||
using std::tr1::function;
|
||||
using std::tr1::bind;
|
||||
|
|
|
|||
|
|
@ -162,9 +162,9 @@ namespace time {
|
|||
|
||||
/* == Descriptor to define Support for specific formats == */
|
||||
|
||||
using lumiera::typelist::Types;
|
||||
using lumiera::typelist::Node;
|
||||
using lumiera::typelist::NullType;
|
||||
using lib::meta::Types;
|
||||
using lib::meta::Node;
|
||||
using lib::meta::NullType;
|
||||
|
||||
/**
|
||||
* Descriptor to denote support for a specific (timecode) format.
|
||||
|
|
@ -187,7 +187,7 @@ namespace time {
|
|||
std::bitset<MAXID> flags_;
|
||||
|
||||
template<class F>
|
||||
size_t
|
||||
IxID
|
||||
typeID() const
|
||||
{
|
||||
return TypedContext<Supported>::ID<F>::get();
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ namespace time {
|
|||
* grid point, usable for grid aligning values.
|
||||
*
|
||||
* \par usage
|
||||
* For one there is the lib::time::Quantiser, which directly
|
||||
* First off, there is the lib::time::Quantiser, which directly
|
||||
* implements this interface and plays a central role when it comes
|
||||
* to converting continuous time into any kind of frame based timecode.
|
||||
* Besides that, the session stores asset::TimeGrid definitions, which
|
||||
|
|
|
|||
|
|
@ -41,6 +41,9 @@ namespace time {
|
|||
const Time Time::MIN ( TimeValue::buildRaw_(-_raw(Time::MAX) ) );
|
||||
const Time Time::ZERO;
|
||||
|
||||
const Time Time::ANYTIME(Time::MAX);
|
||||
const Time Time::NEVER (Time::MIN);
|
||||
|
||||
const Offset Offset::ZERO (Time::ZERO);
|
||||
|
||||
|
||||
|
|
|
|||