Compare commits
311 commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7d4acc28e4 | |||
| 291d4a6831 | |||
| 5bcefd128c | |||
| 36a7954df4 | |||
| 1e73d839f3 | |||
| 0ab3e17467 | |||
| 301f5ff9aa | |||
| 07e75c663d | |||
| cb0933ab51 | |||
| 6706623d6f | |||
| df5e4fe049 | |||
| 7c12a8bc2b | |||
| 917b74003a | |||
| db2804ac17 | |||
| 0a43eb81aa | |||
| 791fdaa14a | |||
| d518d282d4 | |||
| 10195c607c | |||
| 09c5e29f63 | |||
| 22297da809 | |||
| 8460f2205e | |||
| 3a846ec282 | |||
| 7e3cc3c3ed | |||
| dc6efc5e65 | |||
| c45d698424 | |||
| 1daf1619ef | |||
| 050d87bd6f | |||
| bbbac6ff92 | |||
| 8af03c3f3d | |||
| 09ea4c2bc3 | |||
| 97b37d3c53 | |||
| 56fff1178e | |||
| 4d4dc91ff4 | |||
| 5b25b402c7 | |||
| dd36ab6fe1 | |||
| 51fbba95e7 | |||
| 620d5a5bc6 | |||
| 49d097a803 | |||
| 30d0570010 | |||
| 990d2b4c11 | |||
| 74bbc87610 | |||
| 96f782c4ac | |||
| a5f451a120 | |||
| 1f01de6393 | |||
| 505a77d0e2 | |||
| c90c545f40 | |||
| bf91fff5a2 | |||
| 43c8bd95c6 | |||
| a97e7a6d2e | |||
| bb789476b6 | |||
| 6c23fa9f32 | |||
| ef9b9d04c8 | |||
| b7a9f07d5e | |||
| 3a8c955796 | |||
| 84cb27fa6f | |||
| c3da70cdd9 | |||
| 48e35dfc81 | |||
| 42bef33775 | |||
| b001ad2cf2 | |||
| f6680f993f | |||
| 161a635ab5 | |||
| 080ee0d580 | |||
| 3c3e707922 | |||
| acdfb0fb60 | |||
| e1ded8a9ad | |||
| d085a192e8 | |||
| 4b396cabe8 | |||
| 47ae52ed05 | |||
| c49457a817 | |||
| 9645a09a6c | |||
| d10d219eb3 | |||
| 19dfb66301 | |||
| 590f10a756 | |||
| 392871a1ee | |||
| 70576c382a | |||
| 2c2bf09140 | |||
| 217c4709aa | |||
| baf40143b2 | |||
| 3846a1aa3a | |||
| d0d667d6d2 | |||
| 519eb347d1 | |||
| 43cb182aa7 | |||
| 9aa557293a | |||
| b41cdb7186 | |||
| a3d51f7cf3 | |||
| 9b6b6a20b7 | |||
| 584d0326a9 | |||
| ab9ac5e963 | |||
| 8ccfbc0498 | |||
| cf57dfc51a | |||
| 32292a45fa | |||
| fa3708edfb | |||
| 9b076f1533 | |||
| be15d553f1 | |||
| abd38169b1 | |||
| b59b6d85c0 | |||
| 9474153736 | |||
| 2cadffd7d4 | |||
| 3bf72bd78d | |||
| da127ccde3 | |||
| 2b9fec5d82 | |||
| bfd3b8cbce | |||
| 3b713856db | |||
| c5b9d73a96 | |||
| a9c8d84ac2 | |||
| 064ee2e4f1 | |||
| 32b52ace93 | |||
| a955106d18 | |||
| d4f661075d | |||
| c380a3c3cd | |||
| 14db2752ae | |||
| 589b1f23ec | |||
| 781c8cbe9f | |||
| 08bd04d8da | |||
| 5ac721d601 | |||
| c2a4372467 | |||
| a7020545c1 | |||
| f99608085e | |||
| bcf93bb4ce | |||
| 0df6244b8b | |||
| 7297bc5c17 | |||
| e64b9403ac | |||
| b1c818ac20 | |||
| a0fbecf483 | |||
| 4828cb313f | |||
| b56bbf4ced | |||
| ecc6c1efcd | |||
| 92e67215b9 | |||
| 556e13ae74 | |||
| 4cbe9df324 | |||
| 2ade996783 | |||
| 6f4d91af01 | |||
| b1d18a124f | |||
| d79c95be71 | |||
| 3ce6987d78 | |||
| 8831dec40c | |||
| ecb15470ac | |||
| 8d5dfe5154 | |||
| 8275c9baee | |||
| dc1849a786 | |||
| 467edaf02b | |||
| 6dcb9dd37f | |||
| e638764340 | |||
| f03945c0f7 | |||
| 5390600cdd | |||
| 8ea832c090 | |||
| 79c951030d | |||
| b60e27824b | |||
| 5ddfe068a6 | |||
| 8de737decd | |||
| 1a5a46c468 | |||
| 82c7e75e11 | |||
| 57f3154986 | |||
| 0d4b700546 | |||
| 0d6a238b44 | |||
| 662867f529 | |||
| 20b88f6dac | |||
| 964b6a5751 | |||
| d37b82b116 | |||
| 6ddd47fe64 | |||
| d44fa4dd2a | |||
| c80a6e9ac7 | |||
| ea1fac7501 | |||
| b6d7a65ae5 | |||
| 86a4594e7f | |||
| f8ec140f8e | |||
| 3ab7c92d36 | |||
| 0346e21ebd | |||
| 97a172bbe9 | |||
| 3a94433f5c | |||
| f8c7c9c6ea | |||
| 7cfb304296 | |||
| ea6cd488a6 | |||
| 089c4cdc73 | |||
| 627854bc20 | |||
| c00afe1cd1 | |||
| d2b2382c95 | |||
| bad80c9895 | |||
| 6a9c1e87e2 | |||
| 900c667994 | |||
| 63bb28a94a | |||
| 2b9d3a3824 | |||
| f5f47f5a9a | |||
| deff3079b8 | |||
| b878db592c | |||
| 15db0c42d4 | |||
| d69d708b31 | |||
| 1d22e27d81 | |||
| 6f844f7c2a | |||
| 5a8d634590 | |||
| cf7806484f | |||
| e5cb9be1aa | |||
| c185a24f34 | |||
| 12f180a3de | |||
| 19aeb7b14e | |||
| 2036521f42 | |||
| ac8421b5e1 | |||
| 0d2011931c | |||
| c65c6a3cfd | |||
| c564791d1a | |||
| 709453adcb | |||
| 06c2986280 | |||
| 6ed121a039 | |||
| ea43af46ba | |||
| 54ab0d6641 | |||
| 54796a74b7 | |||
| 4d5796e6e7 | |||
| eaabdfddc0 | |||
| e2b5ffaf6c | |||
| 3ec5b20f16 | |||
| 6f04526d36 | |||
| 672ff82e03 | |||
| b85abacd26 | |||
| b85a6aed7b | |||
| b03ad0ac2d | |||
| 76a13e61de | |||
| 2c4f6a4d29 | |||
| daf5c7d8a6 | |||
| 41327c92fd | |||
| 17df0d4adf | |||
| 1eff46006a | |||
| 575ed822b4 | |||
| 0ed3b524f4 | |||
| 523eaef902 | |||
| 49e3395a4c | |||
| 43a1e790cb | |||
| 0b9b5a784d | |||
| 5f02407b06 | |||
| 0a14661da8 | |||
| 573f53b67c | |||
| 2f91e12296 | |||
| 68d0083ba8 | |||
| b62949416b | |||
| 03c037730e | |||
| 98fe95e1a5 | |||
| 693e4fa80d | |||
| 325e9459fd | |||
| 625e3a6f47 | |||
| 7153ec759b | |||
| 09b0065611 | |||
| d65fc16219 | |||
| 6214413e3e | |||
| 5517aadb0a | |||
| 56b79c9cfb | |||
| e7b9ee8257 | |||
| c429be330d | |||
| 87c544cec7 | |||
| 6ff108f360 | |||
| 2a6f72f511 | |||
| 25b246d3ed | |||
| 899064ce42 | |||
| 360bc52080 | |||
| 0e1106aa41 | |||
| 05327fbe7a | |||
| 72e93eccb3 | |||
| 8eb98270af | |||
| 8336753bcf | |||
| ca5cabb6ef | |||
| 2834fa45c6 | |||
| bdd0afddf5 | |||
| b8d0b274b1 | |||
| d12f8c9fa6 | |||
| 557d9a047f | |||
| d20e4154fe | |||
| 687de91a81 | |||
| f59ec98035 | |||
| 6a8bcc4973 | |||
| 3687029bcd | |||
| b4327303ee | |||
| 357bcc19c0 | |||
| 24b07b65f0 | |||
| eb0f93f476 | |||
| dfd57da14f | |||
| a0edcab26d | |||
| 9b00e03b2d | |||
| 882f5614ae | |||
| 2b87d5add6 | |||
| 61134833dc | |||
| 391251940b | |||
| 3ddfd94dfa | |||
| 491972b6c2 | |||
| a2dea2a35f | |||
| fb0f090892 | |||
| fea154a058 | |||
| 98e1fdd4fb | |||
| 301a7fa525 | |||
| 47ca68760a | |||
| c9c1ba5972 | |||
| 7e7960ce72 | |||
| 083aa869d5 | |||
| fe0ebd6cff | |||
| 0b321237b6 | |||
| eded4652a7 | |||
| ccde6a29a1 | |||
| ff1440b6d6 | |||
| 1a37170b9a | |||
| b40e4b07d9 | |||
| 9540bdd26e | |||
| d4cf547683 | |||
| 4ab61d591a | |||
| 0a5db99852 | |||
| 08880e87ac | |||
| c76f986a86 | |||
| 60d0112326 | |||
| 3f56df90a7 | |||
| 2134f6a013 | |||
| ab85d0cd32 | |||
| 22f75f5e86 | |||
| 85213b6f50 | |||
| 104fe40661 | |||
| 11815346af |
144 changed files with 25170 additions and 3733 deletions
10
.gitignore
vendored
10
.gitignore
vendored
|
|
@ -1,6 +1,8 @@
|
|||
*.o
|
||||
src/charles
|
||||
build/
|
||||
*.png
|
||||
|
||||
.sconsign.dblite
|
||||
build/
|
||||
|
||||
*.png
|
||||
*.log
|
||||
|
||||
.DS_Store
|
||||
0
README.md
Normal file
0
README.md
Normal file
267
SConstruct
267
SConstruct
|
|
@ -1,8 +1,5 @@
|
|||
# SConstruct
|
||||
# vim: set ft=python:
|
||||
#
|
||||
# Toplevel Scons build script for the Charles project.
|
||||
#
|
||||
# vim: set ft=python tw=80:
|
||||
# Eryn Wells <eryn@erynwells.me>
|
||||
|
||||
|
||||
|
|
@ -10,89 +7,211 @@
|
|||
# DEFAULT CONFIGURATION VALUES
|
||||
#
|
||||
|
||||
# Enabling debugging does the following things:
|
||||
# 1. Turns on debugging symbols
|
||||
# 2. Turns off all optimization
|
||||
# 3. Sets the DEBUG define
|
||||
DEBUG = True
|
||||
# Settings for the default toolchain binaries. Setting these overrides the
|
||||
# defaults, provided your the given binary exists.
|
||||
CC = None
|
||||
CXX = None
|
||||
AS = None
|
||||
LINK = 'clang++'
|
||||
|
||||
# Show build commands ("cc [args] -o [out] [file], etc"). If this is False, show
|
||||
# some nice messages for each step of the build.
|
||||
BUILD_CMDS = False
|
||||
CCFLAGS = ['-Wall', '-Wextra', '-pedantic']
|
||||
|
||||
# Library directories. Where should scons look for .a files during linking?
|
||||
lib_directories = Split("""
|
||||
/usr/local/lib
|
||||
""")
|
||||
|
||||
# Source directories. New directories should contain a SConscript file and be
|
||||
# added here.
|
||||
source_directories = lib_directories + Split("""
|
||||
#src
|
||||
#test
|
||||
""")
|
||||
|
||||
# Include directories. Where should scons look for headers during preprocessing
|
||||
# and compiling?
|
||||
include_directories = Split("""
|
||||
/usr/local/include
|
||||
#src
|
||||
""")
|
||||
|
||||
#
|
||||
# BUILD STUFF BELOW HERE
|
||||
#
|
||||
|
||||
import os
|
||||
import os.path
|
||||
|
||||
cflags='-Wall -fcolor-diagnostics'
|
||||
env = Environment(CC='clang', CXX='clang++',
|
||||
CFLAGS=cflags + ' -std=c99',
|
||||
CXXFLAGS=cflags + ' -std=c++11',
|
||||
CPPPATH=include_directories,
|
||||
LIBS=['png'],
|
||||
LIBPATH=lib_directories)
|
||||
import sys
|
||||
import SCons.Errors
|
||||
|
||||
|
||||
# Handle command line variables
|
||||
DEBUG = bool(int(ARGUMENTS.get('DEBUG', DEBUG)))
|
||||
if DEBUG:
|
||||
debug_flags=' -g -O0'
|
||||
env.Append(CFLAGS=debug_flags, CXXFLAGS=debug_flags)
|
||||
env.Append(CPPDEFINES=['DEBUG'])
|
||||
else:
|
||||
flags = ' -O2'
|
||||
env.Append(CFLAGS=flags, CXXFLAGS=flags)
|
||||
def which(program):
|
||||
def is_executable(path):
|
||||
return os.path.exists(path) and os.access(path, os.X_OK)
|
||||
|
||||
BUILD_CMDS = bool(int(ARGUMENTS.get('BUILD_CMDS', BUILD_CMDS)))
|
||||
if not BUILD_CMDS:
|
||||
path, name = os.path.split(program)
|
||||
if path:
|
||||
if is_executable(program):
|
||||
return program
|
||||
else:
|
||||
pathext = [''] + os.environ.get('PATHEXT', '').split(os.pathsep)
|
||||
for path in os.environ.get('PATH', '').split(os.pathsep):
|
||||
exe = os.path.join(path, program)
|
||||
for ext in pathext:
|
||||
candidate = exe + ext
|
||||
if is_executable(candidate):
|
||||
return candidate
|
||||
return None
|
||||
|
||||
|
||||
def get_bool_argument(arg):
|
||||
try:
|
||||
return bool(int(arg))
|
||||
except ValueError:
|
||||
pass
|
||||
if arg in ('False', 'FALSE', 'false', ''):
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def set_toolchain_binary(env, var, user_binary, binaries=()):
|
||||
if user_binary and which(user_binary):
|
||||
env[var] = user_binary
|
||||
return
|
||||
for c in binaries:
|
||||
if which(c):
|
||||
env[var] = c
|
||||
break
|
||||
|
||||
common_env = Environment()
|
||||
set_toolchain_binary(common_env, 'CC', CC, ('clang', 'gcc'))
|
||||
set_toolchain_binary(common_env, 'CXX', CXX, ('clang++', 'g++'))
|
||||
set_toolchain_binary(common_env, 'AS', AS)
|
||||
set_toolchain_binary(common_env, 'LINK', LINK)
|
||||
|
||||
|
||||
def verbose_build_cmds():
|
||||
def generate_comstr(action):
|
||||
return '%18s: $TARGET' % (action,)
|
||||
env['CCCOMSTR'] = generate_comstr('Building (C)'),
|
||||
env['CXXCOMSTR'] = generate_comstr('Building (C++)'),
|
||||
env['LINKCOMSTR'] = generate_comstr('Linking'),
|
||||
env['ARCOMSTR'] = generate_comstr('Archiving'),
|
||||
env['RANLIBCOMSTR'] = generate_comstr('Indexing')
|
||||
return '{:>25}: $TARGET'.format(action)
|
||||
common_env['ARCOMSTR'] = generate_comstr('Archiving')
|
||||
common_env['ASCOMSTR'] = generate_comstr('Assembling')
|
||||
common_env['ASPPCOMSTR'] = generate_comstr('Assembling')
|
||||
common_env['CCCOMSTR'] = generate_comstr('Building (C)')
|
||||
common_env['CXXCOMSTR'] = generate_comstr('Building (C++)')
|
||||
common_env['LINKCOMSTR'] = generate_comstr('Linking')
|
||||
common_env['RANLIBCOMSTR'] = generate_comstr('Indexing')
|
||||
common_env['SHCCCOMSTR'] = generate_comstr('Building (C, Shared)')
|
||||
common_env['SHCXXCOMSTR'] = generate_comstr('Building (C++, Shared)')
|
||||
common_env['SHLINKCOMSTR'] = generate_comstr('Linking (Shared)')
|
||||
|
||||
|
||||
# Build charles
|
||||
src_dir = Dir('#src')
|
||||
charles_lib = env.SConscript(os.path.join(src_dir.path, 'SConscript'),
|
||||
exports=['env'],
|
||||
variant_dir=os.path.join('build', src_dir.path),
|
||||
duplicate=0)
|
||||
def succinct_build_cmds():
|
||||
def generate_comstr(action):
|
||||
return ' [{:^6}] $TARGET'.format(action)
|
||||
common_env['ARCOMSTR'] = generate_comstr('AR')
|
||||
common_env['ASCOMSTR'] = generate_comstr('AS')
|
||||
common_env['ASPPCOMSTR'] = generate_comstr('AS')
|
||||
common_env['CCCOMSTR'] = generate_comstr('CC')
|
||||
common_env['CXXCOMSTR'] = generate_comstr('CXX')
|
||||
common_env['LINKCOMSTR'] = generate_comstr('LINK')
|
||||
common_env['RANLIBCOMSTR'] = generate_comstr('RANLIB')
|
||||
common_env['SHCCCOMSTR'] = generate_comstr('SHCC')
|
||||
common_env['SHCXXCOMSTR'] = generate_comstr('SHCXX')
|
||||
common_env['SHLINKCOMSTR'] = generate_comstr('SHLINK')
|
||||
|
||||
# Build test
|
||||
gtest_dir = Dir('#gtest')
|
||||
gtest_include_dir = Dir('#gtest/include')
|
||||
gtest = env.SConscript(os.path.join(gtest_dir.path, 'SConscript'),
|
||||
exports=['env'],
|
||||
variant_dir=os.path.join('build', gtest_dir.path),
|
||||
duplicate=0)
|
||||
test_dir = Dir('#test')
|
||||
env.SConscript(os.path.join(test_dir.path, 'SConscript'),
|
||||
exports=['env', 'gtest', 'gtest_include_dir', 'charles_lib'],
|
||||
variant_dir=os.path.join('build', test_dir.path),
|
||||
duplicate=0)
|
||||
|
||||
env.Default('charles')
|
||||
BUILD_CMDS = get_bool_argument(ARGUMENTS.get('BUILD_CMDS', False))
|
||||
if not BUILD_CMDS:
|
||||
verbose_build_cmds()
|
||||
|
||||
# Separate environment for building libraries because they often don't use the
|
||||
# same CCFLAGS I do.
|
||||
lib_env = common_env.Clone()
|
||||
|
||||
common_env.Append(CCFLAGS=CCFLAGS)
|
||||
common_env.Append(CFLAGS=['-std=c99'])
|
||||
common_env.Append(CXXFLAGS=['-std=c++11'])
|
||||
|
||||
# Separate base environment for building utilities. They're all written by me,
|
||||
# so they need my usual flags, but each should have its own build environment
|
||||
# derived from this one.
|
||||
util_env = common_env.Clone()
|
||||
|
||||
# Add color error messages for clang
|
||||
if sys.stdout.isatty():
|
||||
if 'clang' in common_env['CC'] or 'clang' in common_env['CXX']:
|
||||
common_env.Append(CCFLAGS=['-fcolor-diagnostics'])
|
||||
|
||||
BUILD_DIR = Dir('#build')
|
||||
LIB_DIR = Dir('#lib')
|
||||
SRC_DIR = Dir('#src')
|
||||
TEST_DIR = Dir('#test')
|
||||
UTIL_DIR = Dir('#util')
|
||||
|
||||
|
||||
def create_env(name, appends=None):
|
||||
output_dir = BUILD_DIR.Dir(name)
|
||||
env = common_env.Clone()
|
||||
# Standard env extensions.
|
||||
env.Append(CPPPATH=[SRC_DIR])
|
||||
# Custom env stuff.
|
||||
env['__name'] = name
|
||||
if appends:
|
||||
for k, v in appends.iteritems():
|
||||
if k.startswith('='):
|
||||
env[k[1:]] = v
|
||||
else:
|
||||
env.Append(**{k: v})
|
||||
return env
|
||||
|
||||
|
||||
def do_sconscript(env, build_env, src_dir, out_dir):
|
||||
sconscript = src_dir.File('SConscript')
|
||||
print 'Reading {}'.format(sconscript)
|
||||
# Swapping env and build_env here is a bit wacky. Doing so means that env is
|
||||
# always the Environment that the SConscript should be building with, while
|
||||
# build_env is the Environment we're using to put everything together.
|
||||
env.SConscript(sconscript,
|
||||
{'env': build_env, 'build_env': env},
|
||||
variant_dir=out_dir,
|
||||
duplicate=0)
|
||||
|
||||
|
||||
debug_env = create_env('debug', {
|
||||
'CPPDEFINES': ['DEBUG', 'NRELEASE'],
|
||||
'CCFLAGS': ['-O0', '-g'],
|
||||
})
|
||||
|
||||
beta_env = create_env('beta', {
|
||||
'CPPDEFINES': ['DEBUG', 'NRELEASE'],
|
||||
'CCFLAGS': ['-O3', '-g'],
|
||||
})
|
||||
|
||||
release_env = create_env('release', {
|
||||
'CPPDEFINES': ['NDEBUG', 'RELEASE'],
|
||||
'CCFLAGS': ['-O3']
|
||||
})
|
||||
|
||||
|
||||
modes = {
|
||||
'debug': debug_env,
|
||||
'beta': beta_env,
|
||||
'release': release_env,
|
||||
}
|
||||
|
||||
mode = ARGUMENTS.get('MODE', None)
|
||||
build_modes = []
|
||||
if mode:
|
||||
# If MODE=foo is specified, build only that mode.
|
||||
build_modes.append(mode)
|
||||
else:
|
||||
build_modes = ['debug']
|
||||
|
||||
for mode in build_modes:
|
||||
try:
|
||||
env = modes[mode]
|
||||
except KeyError:
|
||||
print 'Skipping invalid mode: {}'.format(mode)
|
||||
break
|
||||
|
||||
out_dir = BUILD_DIR.Dir(env['__name'])
|
||||
|
||||
# Process all lib dirs.
|
||||
for lib in os.listdir(LIB_DIR.abspath):
|
||||
lib_out_dir = out_dir.Dir('lib').Dir(lib)
|
||||
do_sconscript(env, lib_env, LIB_DIR.Dir(lib), lib_out_dir)
|
||||
env.Append(LIBPATH=[lib_out_dir])
|
||||
|
||||
for util in os.listdir(UTIL_DIR.abspath):
|
||||
util_out_dir = out_dir.Dir('util').Dir(util)
|
||||
do_sconscript(env, util_env.Clone(), UTIL_DIR.Dir(util), util_out_dir)
|
||||
|
||||
# Get test binaries.
|
||||
do_sconscript(env, env, TEST_DIR, out_dir.Dir('test'))
|
||||
|
||||
# Get source files.
|
||||
src_out_dir = out_dir.Dir('src')
|
||||
do_sconscript(env, env, SRC_DIR, src_out_dir)
|
||||
env.Append(LIBPATH=[src_out_dir])
|
||||
|
|
|
|||
10
charles.sublime-project
Normal file
10
charles.sublime-project
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"folders":
|
||||
[
|
||||
{
|
||||
"path": ".",
|
||||
"follow_symlinks": true,
|
||||
"folder_exclude_patterns": ["build"]
|
||||
}
|
||||
]
|
||||
}
|
||||
421
charles.sublime-workspace
Normal file
421
charles.sublime-workspace
Normal file
|
|
@ -0,0 +1,421 @@
|
|||
{
|
||||
"auto_complete":
|
||||
{
|
||||
"selected_items":
|
||||
[
|
||||
]
|
||||
},
|
||||
"buffers":
|
||||
[
|
||||
{
|
||||
"file": "src/yaml/scalarMappingParser.cc",
|
||||
"settings":
|
||||
{
|
||||
"buffer_size": 1390,
|
||||
"line_ending": "Unix"
|
||||
}
|
||||
},
|
||||
{
|
||||
"contents": "/* object_parser.cc\n * vim: set tw=80:\n * Eryn Wells <eryn@erynwells.me>\n */\n/**\n * Implementation of ObjectParser.\n */\n\n#include <cassert>\n#include <string>\n#include <vector>\n\n#include \"yaml/object_parser.hh\"\n\n#include \"object_sphere.h\"\n#include \"yaml/vector_parser.hh\"\n\n\nnamespace yaml {\n\nObjectParser::ObjectParser(Scene& scene,\n ParserStack& parsers)\n : Parser(scene, parsers)\n{ }\n\n\nvoid\nObjectParser::HandleEvent(yaml_event_t& event)\n{\n switch (mSection) {\n case NoSection:\n HandleTopLevelEvent(event);\n break;\n case OriginSection:\n break;\n case RadiusSection:\n break;\n default:\n assert(false);\n break;\n }\n}\n\n\nvoid\nObjectParser::HandleTopLevelEvent(yaml_event_t& event)\n{\n static const std::string ORIGIN = \"origin\";\n static const std::string RADIUS = \"radius\";\n\n if (event.type == YAML_MAPPING_END_EVENT) {\n SetDone(true);\n return;\n }\n\n if (event.type != YAML_SCALAR_EVENT) {\n /* TODO: Clean this up. */\n assert(false);\n }\n\n std::string value = (char *)event.data.scalar.value;\n if (value == ORIGIN) {\n mSection = OriginSection;\n }\n else if (value == RADIUS) {\n mSection = RadiusSection;\n }\n else {\n /* TODO: Clean this up. */\n assert(false);\n }\n}\n\n\nvoid\nObjectParser::HandleOriginEvent(yaml_event_t& event)\n{\n if (event.type != YAML_SEQUENCE_START_EVENT) {\n /* TODO: Clean this up. */\n assert(false);\n }\n\n auto onDone = [this](std::vector<double> origin) {\n if (origin.size() < 3) {\n assert(origin.size() < 3);\n }\n mObject->set_origin(Vector3(origin[0], origin[1], origin[2]));\n mSection = NoSection;\n };\n\n GetParsers().push(new VectorParser<double>(GetScene(), GetParsers(), onDone));\n}\n\n\nvoid\nObjectParser::HandleRadiusEvent(yaml_event_t& event)\n{\n if (event.type != YAML_SCALAR_EVENT) {\n /* TODO: Clean this up. */\n assert(false);\n }\n\n double radius;\n std::string scalar((char *)event.data.scalar.value,\n event.data.scalar.length);\n if (!ParseScalar<double>(scalar, radius)) {\n /* TODO: Clean this up. */\n assert(false);\n }\n mObject->set_radius(radius);\n mSection = NoSection;\n}\n\n} /* namespace yaml */\n",
|
||||
"file": "src/yaml/object_parser.cc",
|
||||
"file_size": 2380,
|
||||
"file_write_time": 130502660140000000,
|
||||
"settings":
|
||||
{
|
||||
"buffer_size": 2380,
|
||||
"line_ending": "Unix"
|
||||
}
|
||||
},
|
||||
{
|
||||
"file": "src/yaml/parsers.hh",
|
||||
"settings":
|
||||
{
|
||||
"buffer_size": 2575,
|
||||
"line_ending": "Unix"
|
||||
}
|
||||
},
|
||||
{
|
||||
"file": "src/yaml/scalarMappingParser.hh",
|
||||
"settings":
|
||||
{
|
||||
"buffer_size": 908,
|
||||
"line_ending": "Unix"
|
||||
}
|
||||
},
|
||||
{
|
||||
"file": "src/yaml/scene_parser.cc",
|
||||
"settings":
|
||||
{
|
||||
"buffer_size": 2049,
|
||||
"line_ending": "Unix"
|
||||
}
|
||||
},
|
||||
{
|
||||
"file": "src/yaml/scene_parser.hh",
|
||||
"settings":
|
||||
{
|
||||
"buffer_size": 789,
|
||||
"line_ending": "Unix"
|
||||
}
|
||||
},
|
||||
{
|
||||
"file": "/Users/eryn/Library/Application Support/Sublime Text 3/Packages/User/Preferences.sublime-settings",
|
||||
"settings":
|
||||
{
|
||||
"buffer_size": 81,
|
||||
"line_ending": "Unix"
|
||||
}
|
||||
}
|
||||
],
|
||||
"build_system": "",
|
||||
"command_palette":
|
||||
{
|
||||
"height": 0.0,
|
||||
"selected_items":
|
||||
[
|
||||
],
|
||||
"width": 0.0
|
||||
},
|
||||
"console":
|
||||
{
|
||||
"height": 0.0,
|
||||
"history":
|
||||
[
|
||||
]
|
||||
},
|
||||
"distraction_free":
|
||||
{
|
||||
"menu_visible": true,
|
||||
"show_minimap": false,
|
||||
"show_open_files": false,
|
||||
"show_tabs": false,
|
||||
"side_bar_visible": false,
|
||||
"status_bar_visible": false
|
||||
},
|
||||
"file_history":
|
||||
[
|
||||
"/Users/eryn/Library/Application Support/Sublime Text 3/Packages/User/Preferences.sublime-settings"
|
||||
],
|
||||
"find":
|
||||
{
|
||||
"height": 0.0
|
||||
},
|
||||
"find_in_files":
|
||||
{
|
||||
"height": 0.0,
|
||||
"where_history":
|
||||
[
|
||||
]
|
||||
},
|
||||
"find_state":
|
||||
{
|
||||
"case_sensitive": false,
|
||||
"find_history":
|
||||
[
|
||||
],
|
||||
"highlight": true,
|
||||
"in_selection": false,
|
||||
"preserve_case": false,
|
||||
"regex": false,
|
||||
"replace_history":
|
||||
[
|
||||
],
|
||||
"reverse": false,
|
||||
"show_context": true,
|
||||
"use_buffer2": true,
|
||||
"whole_word": false,
|
||||
"wrap": true
|
||||
},
|
||||
"groups":
|
||||
[
|
||||
{
|
||||
"selected": 4,
|
||||
"sheets":
|
||||
[
|
||||
{
|
||||
"buffer": 0,
|
||||
"file": "src/yaml/scalarMappingParser.cc",
|
||||
"semi_transient": false,
|
||||
"settings":
|
||||
{
|
||||
"buffer_size": 1390,
|
||||
"regions":
|
||||
{
|
||||
},
|
||||
"selection":
|
||||
[
|
||||
[
|
||||
1162,
|
||||
1162
|
||||
]
|
||||
],
|
||||
"settings":
|
||||
{
|
||||
"syntax": "Packages/C++/C++.tmLanguage",
|
||||
"tab_size": 4,
|
||||
"translate_tabs_to_spaces": true
|
||||
},
|
||||
"translation.x": 0.0,
|
||||
"translation.y": 241.0,
|
||||
"zoom_level": 1.0
|
||||
},
|
||||
"stack_index": 4,
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"buffer": 1,
|
||||
"file": "src/yaml/object_parser.cc",
|
||||
"semi_transient": false,
|
||||
"settings":
|
||||
{
|
||||
"buffer_size": 2380,
|
||||
"regions":
|
||||
{
|
||||
},
|
||||
"selection":
|
||||
[
|
||||
[
|
||||
2192,
|
||||
2192
|
||||
]
|
||||
],
|
||||
"settings":
|
||||
{
|
||||
"syntax": "Packages/C++/C++.tmLanguage",
|
||||
"tab_size": 4,
|
||||
"translate_tabs_to_spaces": true
|
||||
},
|
||||
"translation.x": -0.0,
|
||||
"translation.y": 1029.0,
|
||||
"zoom_level": 1.0
|
||||
},
|
||||
"stack_index": 6,
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"buffer": 2,
|
||||
"file": "src/yaml/parsers.hh",
|
||||
"semi_transient": false,
|
||||
"settings":
|
||||
{
|
||||
"buffer_size": 2575,
|
||||
"regions":
|
||||
{
|
||||
},
|
||||
"selection":
|
||||
[
|
||||
[
|
||||
2501,
|
||||
2501
|
||||
]
|
||||
],
|
||||
"settings":
|
||||
{
|
||||
"syntax": "Packages/C++/C++.tmLanguage",
|
||||
"tab_size": 2,
|
||||
"translate_tabs_to_spaces": true
|
||||
},
|
||||
"translation.x": -0.0,
|
||||
"translation.y": 1369.0,
|
||||
"zoom_level": 1.0
|
||||
},
|
||||
"stack_index": 5,
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"buffer": 3,
|
||||
"file": "src/yaml/scalarMappingParser.hh",
|
||||
"semi_transient": false,
|
||||
"settings":
|
||||
{
|
||||
"buffer_size": 908,
|
||||
"regions":
|
||||
{
|
||||
},
|
||||
"selection":
|
||||
[
|
||||
[
|
||||
597,
|
||||
597
|
||||
]
|
||||
],
|
||||
"settings":
|
||||
{
|
||||
"syntax": "Packages/C++/C++.tmLanguage"
|
||||
},
|
||||
"translation.x": 0.0,
|
||||
"translation.y": 0.0,
|
||||
"zoom_level": 1.0
|
||||
},
|
||||
"stack_index": 3,
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"buffer": 4,
|
||||
"file": "src/yaml/scene_parser.cc",
|
||||
"semi_transient": false,
|
||||
"settings":
|
||||
{
|
||||
"buffer_size": 2049,
|
||||
"regions":
|
||||
{
|
||||
},
|
||||
"selection":
|
||||
[
|
||||
[
|
||||
1575,
|
||||
1575
|
||||
]
|
||||
],
|
||||
"settings":
|
||||
{
|
||||
"syntax": "Packages/C++/C++.tmLanguage",
|
||||
"tab_size": 4,
|
||||
"translate_tabs_to_spaces": true
|
||||
},
|
||||
"translation.x": 0.0,
|
||||
"translation.y": 598.0,
|
||||
"zoom_level": 1.0
|
||||
},
|
||||
"stack_index": 0,
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"buffer": 5,
|
||||
"file": "src/yaml/scene_parser.hh",
|
||||
"semi_transient": true,
|
||||
"settings":
|
||||
{
|
||||
"buffer_size": 789,
|
||||
"regions":
|
||||
{
|
||||
},
|
||||
"selection":
|
||||
[
|
||||
[
|
||||
722,
|
||||
722
|
||||
]
|
||||
],
|
||||
"settings":
|
||||
{
|
||||
"syntax": "Packages/C++/C++.tmLanguage",
|
||||
"tab_size": 4,
|
||||
"translate_tabs_to_spaces": true
|
||||
},
|
||||
"translation.x": 0.0,
|
||||
"translation.y": 0.0,
|
||||
"zoom_level": 1.0
|
||||
},
|
||||
"stack_index": 1,
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"buffer": 6,
|
||||
"file": "/Users/eryn/Library/Application Support/Sublime Text 3/Packages/User/Preferences.sublime-settings",
|
||||
"semi_transient": false,
|
||||
"settings":
|
||||
{
|
||||
"buffer_size": 81,
|
||||
"regions":
|
||||
{
|
||||
},
|
||||
"selection":
|
||||
[
|
||||
[
|
||||
78,
|
||||
78
|
||||
]
|
||||
],
|
||||
"settings":
|
||||
{
|
||||
"syntax": "Packages/JavaScript/JSON.tmLanguage"
|
||||
},
|
||||
"translation.x": 0.0,
|
||||
"translation.y": 0.0,
|
||||
"zoom_level": 1.0
|
||||
},
|
||||
"stack_index": 2,
|
||||
"type": "text"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"incremental_find":
|
||||
{
|
||||
"height": 0.0
|
||||
},
|
||||
"input":
|
||||
{
|
||||
"height": 0.0
|
||||
},
|
||||
"layout":
|
||||
{
|
||||
"cells":
|
||||
[
|
||||
[
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
1
|
||||
]
|
||||
],
|
||||
"cols":
|
||||
[
|
||||
0.0,
|
||||
1.0
|
||||
],
|
||||
"rows":
|
||||
[
|
||||
0.0,
|
||||
1.0
|
||||
]
|
||||
},
|
||||
"menu_visible": true,
|
||||
"output.find_results":
|
||||
{
|
||||
"height": 0.0
|
||||
},
|
||||
"project": "charles.sublime-project",
|
||||
"replace":
|
||||
{
|
||||
"height": 0.0
|
||||
},
|
||||
"save_all_on_build": true,
|
||||
"select_file":
|
||||
{
|
||||
"height": 0.0,
|
||||
"selected_items":
|
||||
[
|
||||
],
|
||||
"width": 0.0
|
||||
},
|
||||
"select_project":
|
||||
{
|
||||
"height": 0.0,
|
||||
"selected_items":
|
||||
[
|
||||
],
|
||||
"width": 0.0
|
||||
},
|
||||
"select_symbol":
|
||||
{
|
||||
"height": 0.0,
|
||||
"selected_items":
|
||||
[
|
||||
],
|
||||
"width": 0.0
|
||||
},
|
||||
"settings":
|
||||
{
|
||||
},
|
||||
"show_minimap": true,
|
||||
"show_open_files": false,
|
||||
"show_tabs": true,
|
||||
"side_bar_visible": true,
|
||||
"side_bar_width": 235.0,
|
||||
"status_bar_visible": true,
|
||||
"template_settings":
|
||||
{
|
||||
}
|
||||
}
|
||||
16
doc/notes.txt
Normal file
16
doc/notes.txt
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
http://www.cs.cmu.edu/afs/cs/academic/class/15462-s09/www/lec/13/lec13.pdf
|
||||
|
||||
Eye/Primary rays: from camera into scene
|
||||
Shadow rays: rays from surface intersection point toward light source
|
||||
Reflection rays: from surface intersection point in mirror direction
|
||||
Transmission rays: from surface intersection point in refracted direction
|
||||
|
||||
Algorithm:
|
||||
- Send ray from camera through each pixel into scene
|
||||
- Compute point of closest intersection with scene object
|
||||
- Shade that point by computing shadow rays
|
||||
- Spawn reflection and refraction/transmission rays and recurse
|
||||
|
||||
When do we stop tracing?
|
||||
- When the ray leaves the scene
|
||||
- When the ray's contribution becomes too small
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
# SConscript
|
||||
# vim: set ft=python:
|
||||
#
|
||||
# SConscript for Google C++ Testing Framework.
|
||||
#
|
||||
# Eryn Wells <eryn@erynwells.me>
|
||||
|
||||
Import('env')
|
||||
|
||||
files = Glob('src/*.cc')
|
||||
|
||||
gtest_env = env.Clone()
|
||||
gtest_env['CPPPATH'] = ['.', './include']
|
||||
gtest_env.Append(CPPDEFINES=['GTEST_USE_OWN_TR1_TUPLE'])
|
||||
|
||||
gtest = gtest_env.Library('gtest', files)
|
||||
env.Alias('gtest', gtest)
|
||||
Return('gtest')
|
||||
|
|
@ -1,350 +0,0 @@
|
|||
// Copyright 2005, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee)
|
||||
//
|
||||
// The Google C++ Testing Framework (Google Test)
|
||||
//
|
||||
// This header file declares the String class and functions used internally by
|
||||
// Google Test. They are subject to change without notice. They should not used
|
||||
// by code external to Google Test.
|
||||
//
|
||||
// This header file is #included by <gtest/internal/gtest-internal.h>.
|
||||
// It should not be #included by other files.
|
||||
|
||||
#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_
|
||||
#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_
|
||||
|
||||
#ifdef __BORLANDC__
|
||||
// string.h is not guaranteed to provide strcpy on C++ Builder.
|
||||
# include <mem.h>
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
#include "gtest/internal/gtest-port.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace testing {
|
||||
namespace internal {
|
||||
|
||||
// String - a UTF-8 string class.
|
||||
//
|
||||
// For historic reasons, we don't use std::string.
|
||||
//
|
||||
// TODO(wan@google.com): replace this class with std::string or
|
||||
// implement it in terms of the latter.
|
||||
//
|
||||
// Note that String can represent both NULL and the empty string,
|
||||
// while std::string cannot represent NULL.
|
||||
//
|
||||
// NULL and the empty string are considered different. NULL is less
|
||||
// than anything (including the empty string) except itself.
|
||||
//
|
||||
// This class only provides minimum functionality necessary for
|
||||
// implementing Google Test. We do not intend to implement a full-fledged
|
||||
// string class here.
|
||||
//
|
||||
// Since the purpose of this class is to provide a substitute for
|
||||
// std::string on platforms where it cannot be used, we define a copy
|
||||
// constructor and assignment operators such that we don't need
|
||||
// conditional compilation in a lot of places.
|
||||
//
|
||||
// In order to make the representation efficient, the d'tor of String
|
||||
// is not virtual. Therefore DO NOT INHERIT FROM String.
|
||||
class GTEST_API_ String {
|
||||
public:
|
||||
// Static utility methods
|
||||
|
||||
// Returns the input enclosed in double quotes if it's not NULL;
|
||||
// otherwise returns "(null)". For example, "\"Hello\"" is returned
|
||||
// for input "Hello".
|
||||
//
|
||||
// This is useful for printing a C string in the syntax of a literal.
|
||||
//
|
||||
// Known issue: escape sequences are not handled yet.
|
||||
static String ShowCStringQuoted(const char* c_str);
|
||||
|
||||
// Clones a 0-terminated C string, allocating memory using new. The
|
||||
// caller is responsible for deleting the return value using
|
||||
// delete[]. Returns the cloned string, or NULL if the input is
|
||||
// NULL.
|
||||
//
|
||||
// This is different from strdup() in string.h, which allocates
|
||||
// memory using malloc().
|
||||
static const char* CloneCString(const char* c_str);
|
||||
|
||||
#if GTEST_OS_WINDOWS_MOBILE
|
||||
// Windows CE does not have the 'ANSI' versions of Win32 APIs. To be
|
||||
// able to pass strings to Win32 APIs on CE we need to convert them
|
||||
// to 'Unicode', UTF-16.
|
||||
|
||||
// Creates a UTF-16 wide string from the given ANSI string, allocating
|
||||
// memory using new. The caller is responsible for deleting the return
|
||||
// value using delete[]. Returns the wide string, or NULL if the
|
||||
// input is NULL.
|
||||
//
|
||||
// The wide string is created using the ANSI codepage (CP_ACP) to
|
||||
// match the behaviour of the ANSI versions of Win32 calls and the
|
||||
// C runtime.
|
||||
static LPCWSTR AnsiToUtf16(const char* c_str);
|
||||
|
||||
// Creates an ANSI string from the given wide string, allocating
|
||||
// memory using new. The caller is responsible for deleting the return
|
||||
// value using delete[]. Returns the ANSI string, or NULL if the
|
||||
// input is NULL.
|
||||
//
|
||||
// The returned string is created using the ANSI codepage (CP_ACP) to
|
||||
// match the behaviour of the ANSI versions of Win32 calls and the
|
||||
// C runtime.
|
||||
static const char* Utf16ToAnsi(LPCWSTR utf16_str);
|
||||
#endif
|
||||
|
||||
// Compares two C strings. Returns true iff they have the same content.
|
||||
//
|
||||
// Unlike strcmp(), this function can handle NULL argument(s). A
|
||||
// NULL C string is considered different to any non-NULL C string,
|
||||
// including the empty string.
|
||||
static bool CStringEquals(const char* lhs, const char* rhs);
|
||||
|
||||
// Converts a wide C string to a String using the UTF-8 encoding.
|
||||
// NULL will be converted to "(null)". If an error occurred during
|
||||
// the conversion, "(failed to convert from wide string)" is
|
||||
// returned.
|
||||
static String ShowWideCString(const wchar_t* wide_c_str);
|
||||
|
||||
// Similar to ShowWideCString(), except that this function encloses
|
||||
// the converted string in double quotes.
|
||||
static String ShowWideCStringQuoted(const wchar_t* wide_c_str);
|
||||
|
||||
// Compares two wide C strings. Returns true iff they have the same
|
||||
// content.
|
||||
//
|
||||
// Unlike wcscmp(), this function can handle NULL argument(s). A
|
||||
// NULL C string is considered different to any non-NULL C string,
|
||||
// including the empty string.
|
||||
static bool WideCStringEquals(const wchar_t* lhs, const wchar_t* rhs);
|
||||
|
||||
// Compares two C strings, ignoring case. Returns true iff they
|
||||
// have the same content.
|
||||
//
|
||||
// Unlike strcasecmp(), this function can handle NULL argument(s).
|
||||
// A NULL C string is considered different to any non-NULL C string,
|
||||
// including the empty string.
|
||||
static bool CaseInsensitiveCStringEquals(const char* lhs,
|
||||
const char* rhs);
|
||||
|
||||
// Compares two wide C strings, ignoring case. Returns true iff they
|
||||
// have the same content.
|
||||
//
|
||||
// Unlike wcscasecmp(), this function can handle NULL argument(s).
|
||||
// A NULL C string is considered different to any non-NULL wide C string,
|
||||
// including the empty string.
|
||||
// NB: The implementations on different platforms slightly differ.
|
||||
// On windows, this method uses _wcsicmp which compares according to LC_CTYPE
|
||||
// environment variable. On GNU platform this method uses wcscasecmp
|
||||
// which compares according to LC_CTYPE category of the current locale.
|
||||
// On MacOS X, it uses towlower, which also uses LC_CTYPE category of the
|
||||
// current locale.
|
||||
static bool CaseInsensitiveWideCStringEquals(const wchar_t* lhs,
|
||||
const wchar_t* rhs);
|
||||
|
||||
// Formats a list of arguments to a String, using the same format
|
||||
// spec string as for printf.
|
||||
//
|
||||
// We do not use the StringPrintf class as it is not universally
|
||||
// available.
|
||||
//
|
||||
// The result is limited to 4096 characters (including the tailing
|
||||
// 0). If 4096 characters are not enough to format the input,
|
||||
// "<buffer exceeded>" is returned.
|
||||
static String Format(const char* format, ...);
|
||||
|
||||
// C'tors
|
||||
|
||||
// The default c'tor constructs a NULL string.
|
||||
String() : c_str_(NULL), length_(0) {}
|
||||
|
||||
// Constructs a String by cloning a 0-terminated C string.
|
||||
String(const char* a_c_str) { // NOLINT
|
||||
if (a_c_str == NULL) {
|
||||
c_str_ = NULL;
|
||||
length_ = 0;
|
||||
} else {
|
||||
ConstructNonNull(a_c_str, strlen(a_c_str));
|
||||
}
|
||||
}
|
||||
|
||||
// Constructs a String by copying a given number of chars from a
|
||||
// buffer. E.g. String("hello", 3) creates the string "hel",
|
||||
// String("a\0bcd", 4) creates "a\0bc", String(NULL, 0) creates "",
|
||||
// and String(NULL, 1) results in access violation.
|
||||
String(const char* buffer, size_t a_length) {
|
||||
ConstructNonNull(buffer, a_length);
|
||||
}
|
||||
|
||||
// The copy c'tor creates a new copy of the string. The two
|
||||
// String objects do not share content.
|
||||
String(const String& str) : c_str_(NULL), length_(0) { *this = str; }
|
||||
|
||||
// D'tor. String is intended to be a final class, so the d'tor
|
||||
// doesn't need to be virtual.
|
||||
~String() { delete[] c_str_; }
|
||||
|
||||
// Allows a String to be implicitly converted to an ::std::string or
|
||||
// ::string, and vice versa. Converting a String containing a NULL
|
||||
// pointer to ::std::string or ::string is undefined behavior.
|
||||
// Converting a ::std::string or ::string containing an embedded NUL
|
||||
// character to a String will result in the prefix up to the first
|
||||
// NUL character.
|
||||
String(const ::std::string& str) {
|
||||
ConstructNonNull(str.c_str(), str.length());
|
||||
}
|
||||
|
||||
operator ::std::string() const { return ::std::string(c_str(), length()); }
|
||||
|
||||
#if GTEST_HAS_GLOBAL_STRING
|
||||
String(const ::string& str) {
|
||||
ConstructNonNull(str.c_str(), str.length());
|
||||
}
|
||||
|
||||
operator ::string() const { return ::string(c_str(), length()); }
|
||||
#endif // GTEST_HAS_GLOBAL_STRING
|
||||
|
||||
// Returns true iff this is an empty string (i.e. "").
|
||||
bool empty() const { return (c_str() != NULL) && (length() == 0); }
|
||||
|
||||
// Compares this with another String.
|
||||
// Returns < 0 if this is less than rhs, 0 if this is equal to rhs, or > 0
|
||||
// if this is greater than rhs.
|
||||
int Compare(const String& rhs) const;
|
||||
|
||||
// Returns true iff this String equals the given C string. A NULL
|
||||
// string and a non-NULL string are considered not equal.
|
||||
bool operator==(const char* a_c_str) const { return Compare(a_c_str) == 0; }
|
||||
|
||||
// Returns true iff this String is less than the given String. A
|
||||
// NULL string is considered less than "".
|
||||
bool operator<(const String& rhs) const { return Compare(rhs) < 0; }
|
||||
|
||||
// Returns true iff this String doesn't equal the given C string. A NULL
|
||||
// string and a non-NULL string are considered not equal.
|
||||
bool operator!=(const char* a_c_str) const { return !(*this == a_c_str); }
|
||||
|
||||
// Returns true iff this String ends with the given suffix. *Any*
|
||||
// String is considered to end with a NULL or empty suffix.
|
||||
bool EndsWith(const char* suffix) const;
|
||||
|
||||
// Returns true iff this String ends with the given suffix, not considering
|
||||
// case. Any String is considered to end with a NULL or empty suffix.
|
||||
bool EndsWithCaseInsensitive(const char* suffix) const;
|
||||
|
||||
// Returns the length of the encapsulated string, or 0 if the
|
||||
// string is NULL.
|
||||
size_t length() const { return length_; }
|
||||
|
||||
// Gets the 0-terminated C string this String object represents.
|
||||
// The String object still owns the string. Therefore the caller
|
||||
// should NOT delete the return value.
|
||||
const char* c_str() const { return c_str_; }
|
||||
|
||||
// Assigns a C string to this object. Self-assignment works.
|
||||
const String& operator=(const char* a_c_str) {
|
||||
return *this = String(a_c_str);
|
||||
}
|
||||
|
||||
// Assigns a String object to this object. Self-assignment works.
|
||||
const String& operator=(const String& rhs) {
|
||||
if (this != &rhs) {
|
||||
delete[] c_str_;
|
||||
if (rhs.c_str() == NULL) {
|
||||
c_str_ = NULL;
|
||||
length_ = 0;
|
||||
} else {
|
||||
ConstructNonNull(rhs.c_str(), rhs.length());
|
||||
}
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
// Constructs a non-NULL String from the given content. This
|
||||
// function can only be called when c_str_ has not been allocated.
|
||||
// ConstructNonNull(NULL, 0) results in an empty string ("").
|
||||
// ConstructNonNull(NULL, non_zero) is undefined behavior.
|
||||
void ConstructNonNull(const char* buffer, size_t a_length) {
|
||||
char* const str = new char[a_length + 1];
|
||||
memcpy(str, buffer, a_length);
|
||||
str[a_length] = '\0';
|
||||
c_str_ = str;
|
||||
length_ = a_length;
|
||||
}
|
||||
|
||||
const char* c_str_;
|
||||
size_t length_;
|
||||
}; // class String
|
||||
|
||||
// Streams a String to an ostream. Each '\0' character in the String
|
||||
// is replaced with "\\0".
|
||||
inline ::std::ostream& operator<<(::std::ostream& os, const String& str) {
|
||||
if (str.c_str() == NULL) {
|
||||
os << "(null)";
|
||||
} else {
|
||||
const char* const c_str = str.c_str();
|
||||
for (size_t i = 0; i != str.length(); i++) {
|
||||
if (c_str[i] == '\0') {
|
||||
os << "\\0";
|
||||
} else {
|
||||
os << c_str[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
return os;
|
||||
}
|
||||
|
||||
// Gets the content of the stringstream's buffer as a String. Each '\0'
|
||||
// character in the buffer is replaced with "\\0".
|
||||
GTEST_API_ String StringStreamToString(::std::stringstream* stream);
|
||||
|
||||
// Converts a streamable value to a String. A NULL pointer is
|
||||
// converted to "(null)". When the input value is a ::string,
|
||||
// ::std::string, ::wstring, or ::std::wstring object, each NUL
|
||||
// character in it is replaced with "\\0".
|
||||
|
||||
// Declared here but defined in gtest.h, so that it has access
|
||||
// to the definition of the Message class, required by the ARM
|
||||
// compiler.
|
||||
template <typename T>
|
||||
String StreamableToString(const T& streamable);
|
||||
|
||||
} // namespace internal
|
||||
} // namespace testing
|
||||
|
||||
#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_
|
||||
|
|
@ -1,3 +1,30 @@
|
|||
Changes for 1.7.0:
|
||||
|
||||
* New feature: death tests are supported on OpenBSD and in iOS
|
||||
simulator now.
|
||||
* New feature: Google Test now implements a protocol to allow
|
||||
a test runner to detect that a test program has exited
|
||||
prematurely and report it as a failure (before it would be
|
||||
falsely reported as a success if the exit code is 0).
|
||||
* New feature: Test::RecordProperty() can now be used outside of the
|
||||
lifespan of a test method, in which case it will be attributed to
|
||||
the current test case or the test program in the XML report.
|
||||
* New feature (potentially breaking): --gtest_list_tests now prints
|
||||
the type parameters and value parameters for each test.
|
||||
* Improvement: char pointers and char arrays are now escaped properly
|
||||
in failure messages.
|
||||
* Improvement: failure summary in XML reports now includes file and
|
||||
line information.
|
||||
* Improvement: the <testsuites> XML element now has a timestamp attribute.
|
||||
* Improvement: When --gtest_filter is specified, XML report now doesn't
|
||||
contain information about tests that are filtered out.
|
||||
* Fixed the bug where long --gtest_filter flag values are truncated in
|
||||
death tests.
|
||||
* Potentially breaking change: RUN_ALL_TESTS() is now implemented as a
|
||||
function instead of a macro in order to work better with Clang.
|
||||
* Compatibility fixes with C++ 11 and various platforms.
|
||||
* Bug/warning fixes.
|
||||
|
||||
Changes for 1.6.0:
|
||||
|
||||
* New feature: ADD_FAILURE_AT() for reporting a test failure at the
|
||||
|
|
@ -119,21 +119,22 @@ and Xcode) to compile
|
|||
|
||||
${GTEST_DIR}/src/gtest-all.cc
|
||||
|
||||
with
|
||||
|
||||
${GTEST_DIR}/include and ${GTEST_DIR}
|
||||
|
||||
in the header search path. Assuming a Linux-like system and gcc,
|
||||
with ${GTEST_DIR}/include in the system header search path and ${GTEST_DIR}
|
||||
in the normal header search path. Assuming a Linux-like system and gcc,
|
||||
something like the following will do:
|
||||
|
||||
g++ -I${GTEST_DIR}/include -I${GTEST_DIR} -c ${GTEST_DIR}/src/gtest-all.cc
|
||||
g++ -isystem ${GTEST_DIR}/include -I${GTEST_DIR} \
|
||||
-pthread -c ${GTEST_DIR}/src/gtest-all.cc
|
||||
ar -rv libgtest.a gtest-all.o
|
||||
|
||||
Next, you should compile your test source file with
|
||||
${GTEST_DIR}/include in the header search path, and link it with gtest
|
||||
and any other necessary libraries:
|
||||
(We need -pthread as Google Test uses threads.)
|
||||
|
||||
g++ -I${GTEST_DIR}/include path/to/your_test.cc libgtest.a -o your_test
|
||||
Next, you should compile your test source file with
|
||||
${GTEST_DIR}/include in the system header search path, and link it
|
||||
with gtest and any other necessary libraries:
|
||||
|
||||
g++ -isystem ${GTEST_DIR}/include -pthread path/to/your_test.cc libgtest.a \
|
||||
-o your_test
|
||||
|
||||
As an example, the make/ directory contains a Makefile that you can
|
||||
use to build Google Test on systems where GNU make is available
|
||||
|
|
@ -217,6 +218,16 @@ default build location. See the "xcodebuild" man page for more
|
|||
information about building different configurations and building in
|
||||
different locations.
|
||||
|
||||
If you wish to use the Google Test Xcode project with Xcode 4.x and
|
||||
above, you need to either:
|
||||
* update the SDK configuration options in xcode/Config/General.xconfig.
|
||||
Comment options SDKROOT, MACOS_DEPLOYMENT_TARGET, and GCC_VERSION. If
|
||||
you choose this route you lose the ability to target earlier versions
|
||||
of MacOS X.
|
||||
* Install an SDK for an earlier version. This doesn't appear to be
|
||||
supported by Apple, but has been reported to work
|
||||
(http://stackoverflow.com/questions/5378518).
|
||||
|
||||
Tweaking Google Test
|
||||
--------------------
|
||||
|
||||
32
lib/gtest/SConscript
Normal file
32
lib/gtest/SConscript
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
# SConscript
|
||||
# vim: set ft=python:
|
||||
#
|
||||
# Eryn Wells <eryn@erynwells.me>
|
||||
|
||||
import os.path
|
||||
|
||||
Import('env')
|
||||
Import('build_env')
|
||||
|
||||
include_dir = env.Dir('include').srcnode()
|
||||
env.Append(CPPPATH=[include_dir])
|
||||
build_env.Append(CPPPATH=[include_dir])
|
||||
|
||||
|
||||
files = [
|
||||
'gtest-all.cc',
|
||||
'gtest-death-test.cc',
|
||||
'gtest-filepath.cc',
|
||||
'gtest-port.cc',
|
||||
'gtest-printers.cc',
|
||||
'gtest-test-part.cc',
|
||||
'gtest-typed-test.cc',
|
||||
'gtest.cc',
|
||||
]
|
||||
|
||||
objs = []
|
||||
for f in files:
|
||||
objs.append(env.Object(f))
|
||||
|
||||
|
||||
gtest = env.Library('gtest', objs)
|
||||
|
|
@ -39,10 +39,10 @@
|
|||
#include "gtest/gtest.h"
|
||||
|
||||
// The following lines pull in the real gtest *.cc files.
|
||||
#include "src/gtest.cc"
|
||||
#include "src/gtest-death-test.cc"
|
||||
#include "src/gtest-filepath.cc"
|
||||
#include "src/gtest-port.cc"
|
||||
#include "src/gtest-printers.cc"
|
||||
#include "src/gtest-test-part.cc"
|
||||
#include "src/gtest-typed-test.cc"
|
||||
#include "gtest.cc"
|
||||
#include "gtest-death-test.cc"
|
||||
#include "gtest-filepath.cc"
|
||||
#include "gtest-port.cc"
|
||||
#include "gtest-printers.cc"
|
||||
#include "gtest-test-part.cc"
|
||||
#include "gtest-typed-test.cc"
|
||||
|
|
@ -43,6 +43,11 @@
|
|||
# include <errno.h>
|
||||
# include <fcntl.h>
|
||||
# include <limits.h>
|
||||
|
||||
# if GTEST_OS_LINUX
|
||||
# include <signal.h>
|
||||
# endif // GTEST_OS_LINUX
|
||||
|
||||
# include <stdarg.h>
|
||||
|
||||
# if GTEST_OS_WINDOWS
|
||||
|
|
@ -52,6 +57,10 @@
|
|||
# include <sys/wait.h>
|
||||
# endif // GTEST_OS_WINDOWS
|
||||
|
||||
# if GTEST_OS_QNX
|
||||
# include <spawn.h>
|
||||
# endif // GTEST_OS_QNX
|
||||
|
||||
#endif // GTEST_HAS_DEATH_TEST
|
||||
|
||||
#include "gtest/gtest-message.h"
|
||||
|
|
@ -63,7 +72,7 @@
|
|||
// prevent a user from accidentally including gtest-internal-inl.h in
|
||||
// his code.
|
||||
#define GTEST_IMPLEMENTATION_ 1
|
||||
#include "src/gtest-internal-inl.h"
|
||||
#include "gtest-internal-inl.h"
|
||||
#undef GTEST_IMPLEMENTATION_
|
||||
|
||||
namespace testing {
|
||||
|
|
@ -100,13 +109,42 @@ GTEST_DEFINE_string_(
|
|||
"Indicates the file, line number, temporal index of "
|
||||
"the single death test to run, and a file descriptor to "
|
||||
"which a success code may be sent, all separated by "
|
||||
"colons. This flag is specified if and only if the current "
|
||||
"the '|' characters. This flag is specified if and only if the current "
|
||||
"process is a sub-process launched for running a thread-safe "
|
||||
"death test. FOR INTERNAL USE ONLY.");
|
||||
} // namespace internal
|
||||
|
||||
#if GTEST_HAS_DEATH_TEST
|
||||
|
||||
namespace internal {
|
||||
|
||||
// Valid only for fast death tests. Indicates the code is running in the
|
||||
// child process of a fast style death test.
|
||||
static bool g_in_fast_death_test_child = false;
|
||||
|
||||
// Returns a Boolean value indicating whether the caller is currently
|
||||
// executing in the context of the death test child process. Tools such as
|
||||
// Valgrind heap checkers may need this to modify their behavior in death
|
||||
// tests. IMPORTANT: This is an internal utility. Using it may break the
|
||||
// implementation of death tests. User code MUST NOT use it.
|
||||
bool InDeathTestChild() {
|
||||
# if GTEST_OS_WINDOWS
|
||||
|
||||
// On Windows, death tests are thread-safe regardless of the value of the
|
||||
// death_test_style flag.
|
||||
return !GTEST_FLAG(internal_run_death_test).empty();
|
||||
|
||||
# else
|
||||
|
||||
if (GTEST_FLAG(death_test_style) == "threadsafe")
|
||||
return !GTEST_FLAG(internal_run_death_test).empty();
|
||||
else
|
||||
return g_in_fast_death_test_child;
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
// ExitedWithCode constructor.
|
||||
ExitedWithCode::ExitedWithCode(int exit_code) : exit_code_(exit_code) {
|
||||
}
|
||||
|
|
@ -141,7 +179,7 @@ namespace internal {
|
|||
|
||||
// Generates a textual description of a given exit code, in the format
|
||||
// specified by wait(2).
|
||||
static String ExitSummary(int exit_code) {
|
||||
static std::string ExitSummary(int exit_code) {
|
||||
Message m;
|
||||
|
||||
# if GTEST_OS_WINDOWS
|
||||
|
|
@ -176,7 +214,7 @@ bool ExitedUnsuccessfully(int exit_status) {
|
|||
// one thread running, or cannot determine the number of threads, prior
|
||||
// to executing the given statement. It is the responsibility of the
|
||||
// caller not to pass a thread_count of 1.
|
||||
static String DeathTestThreadWarning(size_t thread_count) {
|
||||
static std::string DeathTestThreadWarning(size_t thread_count) {
|
||||
Message msg;
|
||||
msg << "Death tests use fork(), which is unsafe particularly"
|
||||
<< " in a threaded context. For this test, " << GTEST_NAME_ << " ";
|
||||
|
|
@ -210,7 +248,7 @@ enum DeathTestOutcome { IN_PROGRESS, DIED, LIVED, RETURNED, THREW };
|
|||
// message is propagated back to the parent process. Otherwise, the
|
||||
// message is simply printed to stderr. In either case, the program
|
||||
// then exits with status 1.
|
||||
void DeathTestAbort(const String& message) {
|
||||
void DeathTestAbort(const std::string& message) {
|
||||
// On a POSIX system, this function may be called from a threadsafe-style
|
||||
// death test child process, which operates on a very small stack. Use
|
||||
// the heap for any additional non-minuscule memory requirements.
|
||||
|
|
@ -234,9 +272,10 @@ void DeathTestAbort(const String& message) {
|
|||
# define GTEST_DEATH_TEST_CHECK_(expression) \
|
||||
do { \
|
||||
if (!::testing::internal::IsTrue(expression)) { \
|
||||
DeathTestAbort(::testing::internal::String::Format( \
|
||||
"CHECK failed: File %s, line %d: %s", \
|
||||
__FILE__, __LINE__, #expression)); \
|
||||
DeathTestAbort( \
|
||||
::std::string("CHECK failed: File ") + __FILE__ + ", line " \
|
||||
+ ::testing::internal::StreamableToString(__LINE__) + ": " \
|
||||
+ #expression); \
|
||||
} \
|
||||
} while (::testing::internal::AlwaysFalse())
|
||||
|
||||
|
|
@ -254,15 +293,16 @@ void DeathTestAbort(const String& message) {
|
|||
gtest_retval = (expression); \
|
||||
} while (gtest_retval == -1 && errno == EINTR); \
|
||||
if (gtest_retval == -1) { \
|
||||
DeathTestAbort(::testing::internal::String::Format( \
|
||||
"CHECK failed: File %s, line %d: %s != -1", \
|
||||
__FILE__, __LINE__, #expression)); \
|
||||
DeathTestAbort( \
|
||||
::std::string("CHECK failed: File ") + __FILE__ + ", line " \
|
||||
+ ::testing::internal::StreamableToString(__LINE__) + ": " \
|
||||
+ #expression + " != -1"); \
|
||||
} \
|
||||
} while (::testing::internal::AlwaysFalse())
|
||||
|
||||
// Returns the message describing the last system error in errno.
|
||||
String GetLastErrnoDescription() {
|
||||
return String(errno == 0 ? "" : posix::StrError(errno));
|
||||
std::string GetLastErrnoDescription() {
|
||||
return errno == 0 ? "" : posix::StrError(errno);
|
||||
}
|
||||
|
||||
// This is called from a death test parent process to read a failure
|
||||
|
|
@ -312,11 +352,11 @@ const char* DeathTest::LastMessage() {
|
|||
return last_death_test_message_.c_str();
|
||||
}
|
||||
|
||||
void DeathTest::set_last_death_test_message(const String& message) {
|
||||
void DeathTest::set_last_death_test_message(const std::string& message) {
|
||||
last_death_test_message_ = message;
|
||||
}
|
||||
|
||||
String DeathTest::last_death_test_message_;
|
||||
std::string DeathTest::last_death_test_message_;
|
||||
|
||||
// Provides cross platform implementation for some death functionality.
|
||||
class DeathTestImpl : public DeathTest {
|
||||
|
|
@ -491,7 +531,7 @@ bool DeathTestImpl::Passed(bool status_ok) {
|
|||
if (!spawned())
|
||||
return false;
|
||||
|
||||
const String error_message = GetCapturedStderr();
|
||||
const std::string error_message = GetCapturedStderr();
|
||||
|
||||
bool success = false;
|
||||
Message buffer;
|
||||
|
|
@ -673,22 +713,19 @@ DeathTest::TestRole WindowsDeathTest::AssumeRole() {
|
|||
FALSE, // The initial state is non-signalled.
|
||||
NULL)); // The even is unnamed.
|
||||
GTEST_DEATH_TEST_CHECK_(event_handle_.Get() != NULL);
|
||||
const String filter_flag = String::Format("--%s%s=%s.%s",
|
||||
GTEST_FLAG_PREFIX_, kFilterFlag,
|
||||
info->test_case_name(),
|
||||
info->name());
|
||||
const String internal_flag = String::Format(
|
||||
"--%s%s=%s|%d|%d|%u|%Iu|%Iu",
|
||||
GTEST_FLAG_PREFIX_,
|
||||
kInternalRunDeathTestFlag,
|
||||
file_, line_,
|
||||
death_test_index,
|
||||
static_cast<unsigned int>(::GetCurrentProcessId()),
|
||||
// size_t has the same with as pointers on both 32-bit and 64-bit
|
||||
const std::string filter_flag =
|
||||
std::string("--") + GTEST_FLAG_PREFIX_ + kFilterFlag + "=" +
|
||||
info->test_case_name() + "." + info->name();
|
||||
const std::string internal_flag =
|
||||
std::string("--") + GTEST_FLAG_PREFIX_ + kInternalRunDeathTestFlag +
|
||||
"=" + file_ + "|" + StreamableToString(line_) + "|" +
|
||||
StreamableToString(death_test_index) + "|" +
|
||||
StreamableToString(static_cast<unsigned int>(::GetCurrentProcessId())) +
|
||||
// size_t has the same width as pointers on both 32-bit and 64-bit
|
||||
// Windows platforms.
|
||||
// See http://msdn.microsoft.com/en-us/library/tcxf1dw6.aspx.
|
||||
reinterpret_cast<size_t>(write_handle),
|
||||
reinterpret_cast<size_t>(event_handle_.Get()));
|
||||
"|" + StreamableToString(reinterpret_cast<size_t>(write_handle)) +
|
||||
"|" + StreamableToString(reinterpret_cast<size_t>(event_handle_.Get()));
|
||||
|
||||
char executable_path[_MAX_PATH + 1]; // NOLINT
|
||||
GTEST_DEATH_TEST_CHECK_(
|
||||
|
|
@ -696,10 +733,9 @@ DeathTest::TestRole WindowsDeathTest::AssumeRole() {
|
|||
executable_path,
|
||||
_MAX_PATH));
|
||||
|
||||
String command_line = String::Format("%s %s \"%s\"",
|
||||
::GetCommandLineA(),
|
||||
filter_flag.c_str(),
|
||||
internal_flag.c_str());
|
||||
std::string command_line =
|
||||
std::string(::GetCommandLineA()) + " " + filter_flag + " \"" +
|
||||
internal_flag + "\"";
|
||||
|
||||
DeathTest::set_last_death_test_message("");
|
||||
|
||||
|
|
@ -816,6 +852,7 @@ DeathTest::TestRole NoExecDeathTest::AssumeRole() {
|
|||
// Event forwarding to the listeners of event listener API mush be shut
|
||||
// down in death test subprocesses.
|
||||
GetUnitTestImpl()->listeners()->SuppressEventForwarding();
|
||||
g_in_fast_death_test_child = true;
|
||||
return EXECUTE_TEST;
|
||||
} else {
|
||||
GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[1]));
|
||||
|
|
@ -835,6 +872,11 @@ class ExecDeathTest : public ForkingDeathTest {
|
|||
ForkingDeathTest(a_statement, a_regex), file_(file), line_(line) { }
|
||||
virtual TestRole AssumeRole();
|
||||
private:
|
||||
static ::std::vector<testing::internal::string>
|
||||
GetArgvsForDeathTestChildProcess() {
|
||||
::std::vector<testing::internal::string> args = GetInjectableArgvs();
|
||||
return args;
|
||||
}
|
||||
// The name of the file in which the death test is located.
|
||||
const char* const file_;
|
||||
// The line number on which the death test is located.
|
||||
|
|
@ -869,6 +911,7 @@ class Arguments {
|
|||
char* const* Argv() {
|
||||
return &args_[0];
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<char*> args_;
|
||||
};
|
||||
|
|
@ -894,6 +937,7 @@ extern "C" char** environ;
|
|||
inline char** GetEnviron() { return environ; }
|
||||
# endif // GTEST_OS_MAC
|
||||
|
||||
# if !GTEST_OS_QNX
|
||||
// The main function for a threadsafe-style death test child process.
|
||||
// This function is called in a clone()-ed process and thus must avoid
|
||||
// any potentially unsafe operations like malloc or libc functions.
|
||||
|
|
@ -908,9 +952,8 @@ static int ExecDeathTestChildMain(void* child_arg) {
|
|||
UnitTest::GetInstance()->original_working_dir();
|
||||
// We can safely call chdir() as it's a direct system call.
|
||||
if (chdir(original_dir) != 0) {
|
||||
DeathTestAbort(String::Format("chdir(\"%s\") failed: %s",
|
||||
original_dir,
|
||||
GetLastErrnoDescription().c_str()));
|
||||
DeathTestAbort(std::string("chdir(\"") + original_dir + "\") failed: " +
|
||||
GetLastErrnoDescription());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
|
|
@ -920,12 +963,12 @@ static int ExecDeathTestChildMain(void* child_arg) {
|
|||
// invoke the test program via a valid path that contains at least
|
||||
// one path separator.
|
||||
execve(args->argv[0], args->argv, GetEnviron());
|
||||
DeathTestAbort(String::Format("execve(%s, ...) in %s failed: %s",
|
||||
args->argv[0],
|
||||
original_dir,
|
||||
GetLastErrnoDescription().c_str()));
|
||||
DeathTestAbort(std::string("execve(") + args->argv[0] + ", ...) in " +
|
||||
original_dir + " failed: " +
|
||||
GetLastErrnoDescription());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
# endif // !GTEST_OS_QNX
|
||||
|
||||
// Two utility routines that together determine the direction the stack
|
||||
// grows.
|
||||
|
|
@ -936,25 +979,75 @@ static int ExecDeathTestChildMain(void* child_arg) {
|
|||
// GTEST_NO_INLINE_ is required to prevent GCC 4.6 from inlining
|
||||
// StackLowerThanAddress into StackGrowsDown, which then doesn't give
|
||||
// correct answer.
|
||||
bool StackLowerThanAddress(const void* ptr) GTEST_NO_INLINE_;
|
||||
bool StackLowerThanAddress(const void* ptr) {
|
||||
void StackLowerThanAddress(const void* ptr, bool* result) GTEST_NO_INLINE_;
|
||||
void StackLowerThanAddress(const void* ptr, bool* result) {
|
||||
int dummy;
|
||||
return &dummy < ptr;
|
||||
*result = (&dummy < ptr);
|
||||
}
|
||||
|
||||
bool StackGrowsDown() {
|
||||
int dummy;
|
||||
return StackLowerThanAddress(&dummy);
|
||||
bool result;
|
||||
StackLowerThanAddress(&dummy, &result);
|
||||
return result;
|
||||
}
|
||||
|
||||
// A threadsafe implementation of fork(2) for threadsafe-style death tests
|
||||
// that uses clone(2). It dies with an error message if anything goes
|
||||
// wrong.
|
||||
static pid_t ExecDeathTestFork(char* const* argv, int close_fd) {
|
||||
// Spawns a child process with the same executable as the current process in
|
||||
// a thread-safe manner and instructs it to run the death test. The
|
||||
// implementation uses fork(2) + exec. On systems where clone(2) is
|
||||
// available, it is used instead, being slightly more thread-safe. On QNX,
|
||||
// fork supports only single-threaded environments, so this function uses
|
||||
// spawn(2) there instead. The function dies with an error message if
|
||||
// anything goes wrong.
|
||||
static pid_t ExecDeathTestSpawnChild(char* const* argv, int close_fd) {
|
||||
ExecDeathTestArgs args = { argv, close_fd };
|
||||
pid_t child_pid = -1;
|
||||
|
||||
# if GTEST_HAS_CLONE
|
||||
# if GTEST_OS_QNX
|
||||
// Obtains the current directory and sets it to be closed in the child
|
||||
// process.
|
||||
const int cwd_fd = open(".", O_RDONLY);
|
||||
GTEST_DEATH_TEST_CHECK_(cwd_fd != -1);
|
||||
GTEST_DEATH_TEST_CHECK_SYSCALL_(fcntl(cwd_fd, F_SETFD, FD_CLOEXEC));
|
||||
// We need to execute the test program in the same environment where
|
||||
// it was originally invoked. Therefore we change to the original
|
||||
// working directory first.
|
||||
const char* const original_dir =
|
||||
UnitTest::GetInstance()->original_working_dir();
|
||||
// We can safely call chdir() as it's a direct system call.
|
||||
if (chdir(original_dir) != 0) {
|
||||
DeathTestAbort(std::string("chdir(\"") + original_dir + "\") failed: " +
|
||||
GetLastErrnoDescription());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
int fd_flags;
|
||||
// Set close_fd to be closed after spawn.
|
||||
GTEST_DEATH_TEST_CHECK_SYSCALL_(fd_flags = fcntl(close_fd, F_GETFD));
|
||||
GTEST_DEATH_TEST_CHECK_SYSCALL_(fcntl(close_fd, F_SETFD,
|
||||
fd_flags | FD_CLOEXEC));
|
||||
struct inheritance inherit = {0};
|
||||
// spawn is a system call.
|
||||
child_pid = spawn(args.argv[0], 0, NULL, &inherit, args.argv, GetEnviron());
|
||||
// Restores the current working directory.
|
||||
GTEST_DEATH_TEST_CHECK_(fchdir(cwd_fd) != -1);
|
||||
GTEST_DEATH_TEST_CHECK_SYSCALL_(close(cwd_fd));
|
||||
|
||||
# else // GTEST_OS_QNX
|
||||
# if GTEST_OS_LINUX
|
||||
// When a SIGPROF signal is received while fork() or clone() are executing,
|
||||
// the process may hang. To avoid this, we ignore SIGPROF here and re-enable
|
||||
// it after the call to fork()/clone() is complete.
|
||||
struct sigaction saved_sigprof_action;
|
||||
struct sigaction ignore_sigprof_action;
|
||||
memset(&ignore_sigprof_action, 0, sizeof(ignore_sigprof_action));
|
||||
sigemptyset(&ignore_sigprof_action.sa_mask);
|
||||
ignore_sigprof_action.sa_handler = SIG_IGN;
|
||||
GTEST_DEATH_TEST_CHECK_SYSCALL_(sigaction(
|
||||
SIGPROF, &ignore_sigprof_action, &saved_sigprof_action));
|
||||
# endif // GTEST_OS_LINUX
|
||||
|
||||
# if GTEST_HAS_CLONE
|
||||
const bool use_fork = GTEST_FLAG(death_test_use_fork);
|
||||
|
||||
if (!use_fork) {
|
||||
|
|
@ -964,21 +1057,37 @@ static pid_t ExecDeathTestFork(char* const* argv, int close_fd) {
|
|||
void* const stack = mmap(NULL, stack_size, PROT_READ | PROT_WRITE,
|
||||
MAP_ANON | MAP_PRIVATE, -1, 0);
|
||||
GTEST_DEATH_TEST_CHECK_(stack != MAP_FAILED);
|
||||
|
||||
// Maximum stack alignment in bytes: For a downward-growing stack, this
|
||||
// amount is subtracted from size of the stack space to get an address
|
||||
// that is within the stack space and is aligned on all systems we care
|
||||
// about. As far as I know there is no ABI with stack alignment greater
|
||||
// than 64. We assume stack and stack_size already have alignment of
|
||||
// kMaxStackAlignment.
|
||||
const size_t kMaxStackAlignment = 64;
|
||||
void* const stack_top =
|
||||
static_cast<char*>(stack) + (stack_grows_down ? stack_size : 0);
|
||||
static_cast<char*>(stack) +
|
||||
(stack_grows_down ? stack_size - kMaxStackAlignment : 0);
|
||||
GTEST_DEATH_TEST_CHECK_(stack_size > kMaxStackAlignment &&
|
||||
reinterpret_cast<intptr_t>(stack_top) % kMaxStackAlignment == 0);
|
||||
|
||||
child_pid = clone(&ExecDeathTestChildMain, stack_top, SIGCHLD, &args);
|
||||
|
||||
GTEST_DEATH_TEST_CHECK_(munmap(stack, stack_size) != -1);
|
||||
}
|
||||
# else
|
||||
# else
|
||||
const bool use_fork = true;
|
||||
# endif // GTEST_HAS_CLONE
|
||||
# endif // GTEST_HAS_CLONE
|
||||
|
||||
if (use_fork && (child_pid = fork()) == 0) {
|
||||
ExecDeathTestChildMain(&args);
|
||||
_exit(0);
|
||||
}
|
||||
# endif // GTEST_OS_QNX
|
||||
# if GTEST_OS_LINUX
|
||||
GTEST_DEATH_TEST_CHECK_SYSCALL_(
|
||||
sigaction(SIGPROF, &saved_sigprof_action, NULL));
|
||||
# endif // GTEST_OS_LINUX
|
||||
|
||||
GTEST_DEATH_TEST_CHECK_(child_pid != -1);
|
||||
return child_pid;
|
||||
|
|
@ -1006,16 +1115,16 @@ DeathTest::TestRole ExecDeathTest::AssumeRole() {
|
|||
// it be closed when the child process does an exec:
|
||||
GTEST_DEATH_TEST_CHECK_(fcntl(pipe_fd[1], F_SETFD, 0) != -1);
|
||||
|
||||
const String filter_flag =
|
||||
String::Format("--%s%s=%s.%s",
|
||||
GTEST_FLAG_PREFIX_, kFilterFlag,
|
||||
info->test_case_name(), info->name());
|
||||
const String internal_flag =
|
||||
String::Format("--%s%s=%s|%d|%d|%d",
|
||||
GTEST_FLAG_PREFIX_, kInternalRunDeathTestFlag,
|
||||
file_, line_, death_test_index, pipe_fd[1]);
|
||||
const std::string filter_flag =
|
||||
std::string("--") + GTEST_FLAG_PREFIX_ + kFilterFlag + "="
|
||||
+ info->test_case_name() + "." + info->name();
|
||||
const std::string internal_flag =
|
||||
std::string("--") + GTEST_FLAG_PREFIX_ + kInternalRunDeathTestFlag + "="
|
||||
+ file_ + "|" + StreamableToString(line_) + "|"
|
||||
+ StreamableToString(death_test_index) + "|"
|
||||
+ StreamableToString(pipe_fd[1]);
|
||||
Arguments args;
|
||||
args.AddArguments(GetArgvs());
|
||||
args.AddArguments(GetArgvsForDeathTestChildProcess());
|
||||
args.AddArgument(filter_flag.c_str());
|
||||
args.AddArgument(internal_flag.c_str());
|
||||
|
||||
|
|
@ -1026,7 +1135,7 @@ DeathTest::TestRole ExecDeathTest::AssumeRole() {
|
|||
// is necessary.
|
||||
FlushInfoLog();
|
||||
|
||||
const pid_t child_pid = ExecDeathTestFork(args.Argv(), pipe_fd[0]);
|
||||
const pid_t child_pid = ExecDeathTestSpawnChild(args.Argv(), pipe_fd[0]);
|
||||
GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[1]));
|
||||
set_child_pid(child_pid);
|
||||
set_read_fd(pipe_fd[0]);
|
||||
|
|
@ -1052,9 +1161,10 @@ bool DefaultDeathTestFactory::Create(const char* statement, const RE* regex,
|
|||
|
||||
if (flag != NULL) {
|
||||
if (death_test_index > flag->index()) {
|
||||
DeathTest::set_last_death_test_message(String::Format(
|
||||
"Death test count (%d) somehow exceeded expected maximum (%d)",
|
||||
death_test_index, flag->index()));
|
||||
DeathTest::set_last_death_test_message(
|
||||
"Death test count (" + StreamableToString(death_test_index)
|
||||
+ ") somehow exceeded expected maximum ("
|
||||
+ StreamableToString(flag->index()) + ")");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -1083,9 +1193,9 @@ bool DefaultDeathTestFactory::Create(const char* statement, const RE* regex,
|
|||
# endif // GTEST_OS_WINDOWS
|
||||
|
||||
else { // NOLINT - this is more readable than unbalanced brackets inside #if.
|
||||
DeathTest::set_last_death_test_message(String::Format(
|
||||
"Unknown death test style \"%s\" encountered",
|
||||
GTEST_FLAG(death_test_style).c_str()));
|
||||
DeathTest::set_last_death_test_message(
|
||||
"Unknown death test style \"" + GTEST_FLAG(death_test_style)
|
||||
+ "\" encountered");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -1123,8 +1233,8 @@ int GetStatusFileDescriptor(unsigned int parent_process_id,
|
|||
FALSE, // Non-inheritable.
|
||||
parent_process_id));
|
||||
if (parent_process_handle.Get() == INVALID_HANDLE_VALUE) {
|
||||
DeathTestAbort(String::Format("Unable to open parent process %u",
|
||||
parent_process_id));
|
||||
DeathTestAbort("Unable to open parent process " +
|
||||
StreamableToString(parent_process_id));
|
||||
}
|
||||
|
||||
// TODO(vladl@google.com): Replace the following check with a
|
||||
|
|
@ -1144,9 +1254,10 @@ int GetStatusFileDescriptor(unsigned int parent_process_id,
|
|||
// DUPLICATE_SAME_ACCESS is used.
|
||||
FALSE, // Request non-inheritable handler.
|
||||
DUPLICATE_SAME_ACCESS)) {
|
||||
DeathTestAbort(String::Format(
|
||||
"Unable to duplicate the pipe handle %Iu from the parent process %u",
|
||||
write_handle_as_size_t, parent_process_id));
|
||||
DeathTestAbort("Unable to duplicate the pipe handle " +
|
||||
StreamableToString(write_handle_as_size_t) +
|
||||
" from the parent process " +
|
||||
StreamableToString(parent_process_id));
|
||||
}
|
||||
|
||||
const HANDLE event_handle = reinterpret_cast<HANDLE>(event_handle_as_size_t);
|
||||
|
|
@ -1157,17 +1268,18 @@ int GetStatusFileDescriptor(unsigned int parent_process_id,
|
|||
0x0,
|
||||
FALSE,
|
||||
DUPLICATE_SAME_ACCESS)) {
|
||||
DeathTestAbort(String::Format(
|
||||
"Unable to duplicate the event handle %Iu from the parent process %u",
|
||||
event_handle_as_size_t, parent_process_id));
|
||||
DeathTestAbort("Unable to duplicate the event handle " +
|
||||
StreamableToString(event_handle_as_size_t) +
|
||||
" from the parent process " +
|
||||
StreamableToString(parent_process_id));
|
||||
}
|
||||
|
||||
const int write_fd =
|
||||
::_open_osfhandle(reinterpret_cast<intptr_t>(dup_write_handle), O_APPEND);
|
||||
if (write_fd == -1) {
|
||||
DeathTestAbort(String::Format(
|
||||
"Unable to convert pipe handle %Iu to a file descriptor",
|
||||
write_handle_as_size_t));
|
||||
DeathTestAbort("Unable to convert pipe handle " +
|
||||
StreamableToString(write_handle_as_size_t) +
|
||||
" to a file descriptor");
|
||||
}
|
||||
|
||||
// Signals the parent that the write end of the pipe has been acquired
|
||||
|
|
@ -1204,9 +1316,8 @@ InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag() {
|
|||
|| !ParseNaturalNumber(fields[3], &parent_process_id)
|
||||
|| !ParseNaturalNumber(fields[4], &write_handle_as_size_t)
|
||||
|| !ParseNaturalNumber(fields[5], &event_handle_as_size_t)) {
|
||||
DeathTestAbort(String::Format(
|
||||
"Bad --gtest_internal_run_death_test flag: %s",
|
||||
GTEST_FLAG(internal_run_death_test).c_str()));
|
||||
DeathTestAbort("Bad --gtest_internal_run_death_test flag: " +
|
||||
GTEST_FLAG(internal_run_death_test));
|
||||
}
|
||||
write_fd = GetStatusFileDescriptor(parent_process_id,
|
||||
write_handle_as_size_t,
|
||||
|
|
@ -1217,9 +1328,8 @@ InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag() {
|
|||
|| !ParseNaturalNumber(fields[1], &line)
|
||||
|| !ParseNaturalNumber(fields[2], &index)
|
||||
|| !ParseNaturalNumber(fields[3], &write_fd)) {
|
||||
DeathTestAbort(String::Format(
|
||||
"Bad --gtest_internal_run_death_test flag: %s",
|
||||
GTEST_FLAG(internal_run_death_test).c_str()));
|
||||
DeathTestAbort("Bad --gtest_internal_run_death_test flag: "
|
||||
+ GTEST_FLAG(internal_run_death_test));
|
||||
}
|
||||
|
||||
# endif // GTEST_OS_WINDOWS
|
||||
|
|
@ -29,6 +29,7 @@
|
|||
//
|
||||
// Authors: keith.ray@gmail.com (Keith Ray)
|
||||
|
||||
#include "gtest/gtest-message.h"
|
||||
#include "gtest/internal/gtest-filepath.h"
|
||||
#include "gtest/internal/gtest-port.h"
|
||||
|
||||
|
|
@ -39,8 +40,8 @@
|
|||
#elif GTEST_OS_WINDOWS
|
||||
# include <direct.h>
|
||||
# include <io.h>
|
||||
#elif GTEST_OS_SYMBIAN || GTEST_OS_NACL
|
||||
// Symbian OpenC and NaCl have PATH_MAX in sys/syslimits.h
|
||||
#elif GTEST_OS_SYMBIAN
|
||||
// Symbian OpenC has PATH_MAX in sys/syslimits.h
|
||||
# include <sys/syslimits.h>
|
||||
#else
|
||||
# include <limits.h>
|
||||
|
|
@ -116,9 +117,10 @@ FilePath FilePath::GetCurrentDir() {
|
|||
// FilePath("dir/file"). If a case-insensitive extension is not
|
||||
// found, returns a copy of the original FilePath.
|
||||
FilePath FilePath::RemoveExtension(const char* extension) const {
|
||||
String dot_extension(String::Format(".%s", extension));
|
||||
if (pathname_.EndsWithCaseInsensitive(dot_extension.c_str())) {
|
||||
return FilePath(String(pathname_.c_str(), pathname_.length() - 4));
|
||||
const std::string dot_extension = std::string(".") + extension;
|
||||
if (String::EndsWithCaseInsensitive(pathname_, dot_extension)) {
|
||||
return FilePath(pathname_.substr(
|
||||
0, pathname_.length() - dot_extension.length()));
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
|
@ -147,7 +149,7 @@ const char* FilePath::FindLastPathSeparator() const {
|
|||
// On Windows platform, '\' is the path separator, otherwise it is '/'.
|
||||
FilePath FilePath::RemoveDirectoryName() const {
|
||||
const char* const last_sep = FindLastPathSeparator();
|
||||
return last_sep ? FilePath(String(last_sep + 1)) : *this;
|
||||
return last_sep ? FilePath(last_sep + 1) : *this;
|
||||
}
|
||||
|
||||
// RemoveFileName returns the directory path with the filename removed.
|
||||
|
|
@ -158,9 +160,9 @@ FilePath FilePath::RemoveDirectoryName() const {
|
|||
// On Windows platform, '\' is the path separator, otherwise it is '/'.
|
||||
FilePath FilePath::RemoveFileName() const {
|
||||
const char* const last_sep = FindLastPathSeparator();
|
||||
String dir;
|
||||
std::string dir;
|
||||
if (last_sep) {
|
||||
dir = String(c_str(), last_sep + 1 - c_str());
|
||||
dir = std::string(c_str(), last_sep + 1 - c_str());
|
||||
} else {
|
||||
dir = kCurrentDirectoryString;
|
||||
}
|
||||
|
|
@ -177,11 +179,12 @@ FilePath FilePath::MakeFileName(const FilePath& directory,
|
|||
const FilePath& base_name,
|
||||
int number,
|
||||
const char* extension) {
|
||||
String file;
|
||||
std::string file;
|
||||
if (number == 0) {
|
||||
file = String::Format("%s.%s", base_name.c_str(), extension);
|
||||
file = base_name.string() + "." + extension;
|
||||
} else {
|
||||
file = String::Format("%s_%d.%s", base_name.c_str(), number, extension);
|
||||
file = base_name.string() + "_" + StreamableToString(number)
|
||||
+ "." + extension;
|
||||
}
|
||||
return ConcatPaths(directory, FilePath(file));
|
||||
}
|
||||
|
|
@ -193,8 +196,7 @@ FilePath FilePath::ConcatPaths(const FilePath& directory,
|
|||
if (directory.IsEmpty())
|
||||
return relative_path;
|
||||
const FilePath dir(directory.RemoveTrailingPathSeparator());
|
||||
return FilePath(String::Format("%s%c%s", dir.c_str(), kPathSeparator,
|
||||
relative_path.c_str()));
|
||||
return FilePath(dir.string() + kPathSeparator + relative_path.string());
|
||||
}
|
||||
|
||||
// Returns true if pathname describes something findable in the file-system,
|
||||
|
|
@ -338,7 +340,7 @@ bool FilePath::CreateFolder() const {
|
|||
// On Windows platform, uses \ as the separator, other platforms use /.
|
||||
FilePath FilePath::RemoveTrailingPathSeparator() const {
|
||||
return IsDirectory()
|
||||
? FilePath(String(pathname_.c_str(), pathname_.length() - 1))
|
||||
? FilePath(pathname_.substr(0, pathname_.length() - 1))
|
||||
: *this;
|
||||
}
|
||||
|
||||
|
|
@ -58,6 +58,11 @@
|
|||
|
||||
#include "gtest/internal/gtest-port.h"
|
||||
|
||||
#if GTEST_CAN_STREAM_RESULTS_
|
||||
# include <arpa/inet.h> // NOLINT
|
||||
# include <netdb.h> // NOLINT
|
||||
#endif
|
||||
|
||||
#if GTEST_OS_WINDOWS
|
||||
# include <windows.h> // NOLINT
|
||||
#endif // GTEST_OS_WINDOWS
|
||||
|
|
@ -112,6 +117,12 @@ GTEST_API_ bool ShouldUseColor(bool stdout_is_tty);
|
|||
// Formats the given time in milliseconds as seconds.
|
||||
GTEST_API_ std::string FormatTimeInMillisAsSeconds(TimeInMillis ms);
|
||||
|
||||
// Converts the given time in milliseconds to a date string in the ISO 8601
|
||||
// format, without the timezone information. N.B.: due to the use the
|
||||
// non-reentrant localtime() function, this function is not thread safe. Do
|
||||
// not use it in any code that can be called from multiple threads.
|
||||
GTEST_API_ std::string FormatEpochTimeInMillisAsIso8601(TimeInMillis ms);
|
||||
|
||||
// Parses a string for an Int32 flag, in the form of "--flag=value".
|
||||
//
|
||||
// On success, stores the value of the flag in *value, and returns
|
||||
|
|
@ -190,37 +201,35 @@ class GTestFlagSaver {
|
|||
GTEST_FLAG(stream_result_to) = stream_result_to_;
|
||||
GTEST_FLAG(throw_on_failure) = throw_on_failure_;
|
||||
}
|
||||
|
||||
private:
|
||||
// Fields for saving the original values of flags.
|
||||
bool also_run_disabled_tests_;
|
||||
bool break_on_failure_;
|
||||
bool catch_exceptions_;
|
||||
String color_;
|
||||
String death_test_style_;
|
||||
std::string color_;
|
||||
std::string death_test_style_;
|
||||
bool death_test_use_fork_;
|
||||
String filter_;
|
||||
String internal_run_death_test_;
|
||||
std::string filter_;
|
||||
std::string internal_run_death_test_;
|
||||
bool list_tests_;
|
||||
String output_;
|
||||
std::string output_;
|
||||
bool print_time_;
|
||||
bool pretty_;
|
||||
internal::Int32 random_seed_;
|
||||
internal::Int32 repeat_;
|
||||
bool shuffle_;
|
||||
internal::Int32 stack_trace_depth_;
|
||||
String stream_result_to_;
|
||||
std::string stream_result_to_;
|
||||
bool throw_on_failure_;
|
||||
} GTEST_ATTRIBUTE_UNUSED_;
|
||||
|
||||
// Converts a Unicode code point to a narrow string in UTF-8 encoding.
|
||||
// code_point parameter is of type UInt32 because wchar_t may not be
|
||||
// wide enough to contain a code point.
|
||||
// The output buffer str must containt at least 32 characters.
|
||||
// The function returns the address of the output buffer.
|
||||
// If the code_point is not a valid Unicode code point
|
||||
// (i.e. outside of Unicode range U+0 to U+10FFFF) it will be output
|
||||
// as '(Invalid Unicode 0xXXXXXXXX)'.
|
||||
GTEST_API_ char* CodePointToUtf8(UInt32 code_point, char* str);
|
||||
// (i.e. outside of Unicode range U+0 to U+10FFFF) it will be converted
|
||||
// to "(Invalid Unicode 0xXXXXXXXX)".
|
||||
GTEST_API_ std::string CodePointToUtf8(UInt32 code_point);
|
||||
|
||||
// Converts a wide string to a narrow string in UTF-8 encoding.
|
||||
// The wide string is assumed to have the following encoding:
|
||||
|
|
@ -235,7 +244,7 @@ GTEST_API_ char* CodePointToUtf8(UInt32 code_point, char* str);
|
|||
// as '(Invalid Unicode 0xXXXXXXXX)'. If the string is in UTF16 encoding
|
||||
// and contains invalid UTF-16 surrogate pairs, values in those pairs
|
||||
// will be encoded as individual Unicode characters from Basic Normal Plane.
|
||||
GTEST_API_ String WideStringToUtf8(const wchar_t* str, int num_chars);
|
||||
GTEST_API_ std::string WideStringToUtf8(const wchar_t* str, int num_chars);
|
||||
|
||||
// Reads the GTEST_SHARD_STATUS_FILE environment variable, and creates the file
|
||||
// if the variable is present. If a file already exists at this location, this
|
||||
|
|
@ -339,16 +348,15 @@ class TestPropertyKeyIs {
|
|||
// Constructor.
|
||||
//
|
||||
// TestPropertyKeyIs has NO default constructor.
|
||||
explicit TestPropertyKeyIs(const char* key)
|
||||
: key_(key) {}
|
||||
explicit TestPropertyKeyIs(const std::string& key) : key_(key) {}
|
||||
|
||||
// Returns true iff the test name of test property matches on key_.
|
||||
bool operator()(const TestProperty& test_property) const {
|
||||
return String(test_property.key()).Compare(key_) == 0;
|
||||
return test_property.key() == key_;
|
||||
}
|
||||
|
||||
private:
|
||||
String key_;
|
||||
std::string key_;
|
||||
};
|
||||
|
||||
// Class UnitTestOptions.
|
||||
|
|
@ -366,12 +374,12 @@ class GTEST_API_ UnitTestOptions {
|
|||
// Functions for processing the gtest_output flag.
|
||||
|
||||
// Returns the output format, or "" for normal printed output.
|
||||
static String GetOutputFormat();
|
||||
static std::string GetOutputFormat();
|
||||
|
||||
// Returns the absolute path of the requested output file, or the
|
||||
// default (test_detail.xml in the original working directory) if
|
||||
// none was explicitly specified.
|
||||
static String GetAbsolutePathToOutputFile();
|
||||
static std::string GetAbsolutePathToOutputFile();
|
||||
|
||||
// Functions for processing the gtest_filter flag.
|
||||
|
||||
|
|
@ -384,8 +392,8 @@ class GTEST_API_ UnitTestOptions {
|
|||
|
||||
// Returns true iff the user-specified filter matches the test case
|
||||
// name and the test name.
|
||||
static bool FilterMatchesTest(const String &test_case_name,
|
||||
const String &test_name);
|
||||
static bool FilterMatchesTest(const std::string &test_case_name,
|
||||
const std::string &test_name);
|
||||
|
||||
#if GTEST_OS_WINDOWS
|
||||
// Function for supporting the gtest_catch_exception flag.
|
||||
|
|
@ -398,7 +406,7 @@ class GTEST_API_ UnitTestOptions {
|
|||
|
||||
// Returns true if "name" matches the ':' separated list of glob-style
|
||||
// filters in "filter".
|
||||
static bool MatchesFilter(const String& name, const char* filter);
|
||||
static bool MatchesFilter(const std::string& name, const char* filter);
|
||||
};
|
||||
|
||||
// Returns the current application's name, removing directory path if that
|
||||
|
|
@ -411,13 +419,13 @@ class OsStackTraceGetterInterface {
|
|||
OsStackTraceGetterInterface() {}
|
||||
virtual ~OsStackTraceGetterInterface() {}
|
||||
|
||||
// Returns the current OS stack trace as a String. Parameters:
|
||||
// Returns the current OS stack trace as an std::string. Parameters:
|
||||
//
|
||||
// max_depth - the maximum number of stack frames to be included
|
||||
// in the trace.
|
||||
// skip_count - the number of top frames to be skipped; doesn't count
|
||||
// against max_depth.
|
||||
virtual String CurrentStackTrace(int max_depth, int skip_count) = 0;
|
||||
virtual string CurrentStackTrace(int max_depth, int skip_count) = 0;
|
||||
|
||||
// UponLeavingGTest() should be called immediately before Google Test calls
|
||||
// user code. It saves some information about the current stack that
|
||||
|
|
@ -432,8 +440,11 @@ class OsStackTraceGetterInterface {
|
|||
class OsStackTraceGetter : public OsStackTraceGetterInterface {
|
||||
public:
|
||||
OsStackTraceGetter() : caller_frame_(NULL) {}
|
||||
virtual String CurrentStackTrace(int max_depth, int skip_count);
|
||||
virtual void UponLeavingGTest();
|
||||
|
||||
virtual string CurrentStackTrace(int max_depth, int skip_count)
|
||||
GTEST_LOCK_EXCLUDED_(mutex_);
|
||||
|
||||
virtual void UponLeavingGTest() GTEST_LOCK_EXCLUDED_(mutex_);
|
||||
|
||||
// This string is inserted in place of stack frames that are part of
|
||||
// Google Test's implementation.
|
||||
|
|
@ -455,7 +466,7 @@ class OsStackTraceGetter : public OsStackTraceGetterInterface {
|
|||
struct TraceInfo {
|
||||
const char* file;
|
||||
int line;
|
||||
String message;
|
||||
std::string message;
|
||||
};
|
||||
|
||||
// This is the default global test part result reporter used in UnitTestImpl.
|
||||
|
|
@ -539,15 +550,25 @@ class GTEST_API_ UnitTestImpl {
|
|||
// Gets the number of failed tests.
|
||||
int failed_test_count() const;
|
||||
|
||||
// Gets the number of disabled tests that will be reported in the XML report.
|
||||
int reportable_disabled_test_count() const;
|
||||
|
||||
// Gets the number of disabled tests.
|
||||
int disabled_test_count() const;
|
||||
|
||||
// Gets the number of tests to be printed in the XML report.
|
||||
int reportable_test_count() const;
|
||||
|
||||
// Gets the number of all tests.
|
||||
int total_test_count() const;
|
||||
|
||||
// Gets the number of tests that should run.
|
||||
int test_to_run_count() const;
|
||||
|
||||
// Gets the time of the test program start, in ms from the start of the
|
||||
// UNIX epoch.
|
||||
TimeInMillis start_timestamp() const { return start_timestamp_; }
|
||||
|
||||
// Gets the elapsed time, in milliseconds.
|
||||
TimeInMillis elapsed_time() const { return elapsed_time_; }
|
||||
|
||||
|
|
@ -596,7 +617,7 @@ class GTEST_API_ UnitTestImpl {
|
|||
// getter, and returns it.
|
||||
OsStackTraceGetterInterface* os_stack_trace_getter();
|
||||
|
||||
// Returns the current OS stack trace as a String.
|
||||
// Returns the current OS stack trace as an std::string.
|
||||
//
|
||||
// The maximum number of stack frames to be included is specified by
|
||||
// the gtest_stack_trace_depth flag. The skip_count parameter
|
||||
|
|
@ -606,7 +627,7 @@ class GTEST_API_ UnitTestImpl {
|
|||
// For example, if Foo() calls Bar(), which in turn calls
|
||||
// CurrentOsStackTraceExceptTop(1), Foo() will be included in the
|
||||
// trace but Bar() and CurrentOsStackTraceExceptTop() won't.
|
||||
String CurrentOsStackTraceExceptTop(int skip_count);
|
||||
std::string CurrentOsStackTraceExceptTop(int skip_count) GTEST_NO_INLINE_;
|
||||
|
||||
// Finds and returns a TestCase with the given name. If one doesn't
|
||||
// exist, creates one and returns it.
|
||||
|
|
@ -696,6 +717,12 @@ class GTEST_API_ UnitTestImpl {
|
|||
ad_hoc_test_result_.Clear();
|
||||
}
|
||||
|
||||
// Adds a TestProperty to the current TestResult object when invoked in a
|
||||
// context of a test or a test case, or to the global property set. If the
|
||||
// result already contains a property with the same key, the value will be
|
||||
// updated.
|
||||
void RecordProperty(const TestProperty& test_property);
|
||||
|
||||
enum ReactionToSharding {
|
||||
HONOR_SHARDING_PROTOCOL,
|
||||
IGNORE_SHARDING_PROTOCOL
|
||||
|
|
@ -880,6 +907,10 @@ class GTEST_API_ UnitTestImpl {
|
|||
// Our random number generator.
|
||||
internal::Random random_;
|
||||
|
||||
// The time of the test program start, in ms from the start of the
|
||||
// UNIX epoch.
|
||||
TimeInMillis start_timestamp_;
|
||||
|
||||
// How long the test took to run, in milliseconds.
|
||||
TimeInMillis elapsed_time_;
|
||||
|
||||
|
|
@ -935,7 +966,7 @@ GTEST_API_ void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv);
|
|||
|
||||
// Returns the message describing the last system error, regardless of the
|
||||
// platform.
|
||||
GTEST_API_ String GetLastErrnoDescription();
|
||||
GTEST_API_ std::string GetLastErrnoDescription();
|
||||
|
||||
# if GTEST_OS_WINDOWS
|
||||
// Provides leak-safe Windows kernel handle ownership.
|
||||
|
|
@ -1018,8 +1049,9 @@ bool ParseNaturalNumber(const ::std::string& str, Integer* number) {
|
|||
class TestResultAccessor {
|
||||
public:
|
||||
static void RecordProperty(TestResult* test_result,
|
||||
const std::string& xml_element,
|
||||
const TestProperty& property) {
|
||||
test_result->RecordProperty(property);
|
||||
test_result->RecordProperty(xml_element, property);
|
||||
}
|
||||
|
||||
static void ClearTestPartResults(TestResult* test_result) {
|
||||
|
|
@ -1032,6 +1064,154 @@ class TestResultAccessor {
|
|||
}
|
||||
};
|
||||
|
||||
#if GTEST_CAN_STREAM_RESULTS_
|
||||
|
||||
// Streams test results to the given port on the given host machine.
|
||||
class StreamingListener : public EmptyTestEventListener {
|
||||
public:
|
||||
// Abstract base class for writing strings to a socket.
|
||||
class AbstractSocketWriter {
|
||||
public:
|
||||
virtual ~AbstractSocketWriter() {}
|
||||
|
||||
// Sends a string to the socket.
|
||||
virtual void Send(const string& message) = 0;
|
||||
|
||||
// Closes the socket.
|
||||
virtual void CloseConnection() {}
|
||||
|
||||
// Sends a string and a newline to the socket.
|
||||
void SendLn(const string& message) {
|
||||
Send(message + "\n");
|
||||
}
|
||||
};
|
||||
|
||||
// Concrete class for actually writing strings to a socket.
|
||||
class SocketWriter : public AbstractSocketWriter {
|
||||
public:
|
||||
SocketWriter(const string& host, const string& port)
|
||||
: sockfd_(-1), host_name_(host), port_num_(port) {
|
||||
MakeConnection();
|
||||
}
|
||||
|
||||
virtual ~SocketWriter() {
|
||||
if (sockfd_ != -1)
|
||||
CloseConnection();
|
||||
}
|
||||
|
||||
// Sends a string to the socket.
|
||||
virtual void Send(const string& message) {
|
||||
GTEST_CHECK_(sockfd_ != -1)
|
||||
<< "Send() can be called only when there is a connection.";
|
||||
|
||||
const int len = static_cast<int>(message.length());
|
||||
if (write(sockfd_, message.c_str(), len) != len) {
|
||||
GTEST_LOG_(WARNING)
|
||||
<< "stream_result_to: failed to stream to "
|
||||
<< host_name_ << ":" << port_num_;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
// Creates a client socket and connects to the server.
|
||||
void MakeConnection();
|
||||
|
||||
// Closes the socket.
|
||||
void CloseConnection() {
|
||||
GTEST_CHECK_(sockfd_ != -1)
|
||||
<< "CloseConnection() can be called only when there is a connection.";
|
||||
|
||||
close(sockfd_);
|
||||
sockfd_ = -1;
|
||||
}
|
||||
|
||||
int sockfd_; // socket file descriptor
|
||||
const string host_name_;
|
||||
const string port_num_;
|
||||
|
||||
GTEST_DISALLOW_COPY_AND_ASSIGN_(SocketWriter);
|
||||
}; // class SocketWriter
|
||||
|
||||
// Escapes '=', '&', '%', and '\n' characters in str as "%xx".
|
||||
static string UrlEncode(const char* str);
|
||||
|
||||
StreamingListener(const string& host, const string& port)
|
||||
: socket_writer_(new SocketWriter(host, port)) { Start(); }
|
||||
|
||||
explicit StreamingListener(AbstractSocketWriter* socket_writer)
|
||||
: socket_writer_(socket_writer) { Start(); }
|
||||
|
||||
void OnTestProgramStart(const UnitTest& /* unit_test */) {
|
||||
SendLn("event=TestProgramStart");
|
||||
}
|
||||
|
||||
void OnTestProgramEnd(const UnitTest& unit_test) {
|
||||
// Note that Google Test current only report elapsed time for each
|
||||
// test iteration, not for the entire test program.
|
||||
SendLn("event=TestProgramEnd&passed=" + FormatBool(unit_test.Passed()));
|
||||
|
||||
// Notify the streaming server to stop.
|
||||
socket_writer_->CloseConnection();
|
||||
}
|
||||
|
||||
void OnTestIterationStart(const UnitTest& /* unit_test */, int iteration) {
|
||||
SendLn("event=TestIterationStart&iteration=" +
|
||||
StreamableToString(iteration));
|
||||
}
|
||||
|
||||
void OnTestIterationEnd(const UnitTest& unit_test, int /* iteration */) {
|
||||
SendLn("event=TestIterationEnd&passed=" +
|
||||
FormatBool(unit_test.Passed()) + "&elapsed_time=" +
|
||||
StreamableToString(unit_test.elapsed_time()) + "ms");
|
||||
}
|
||||
|
||||
void OnTestCaseStart(const TestCase& test_case) {
|
||||
SendLn(std::string("event=TestCaseStart&name=") + test_case.name());
|
||||
}
|
||||
|
||||
void OnTestCaseEnd(const TestCase& test_case) {
|
||||
SendLn("event=TestCaseEnd&passed=" + FormatBool(test_case.Passed())
|
||||
+ "&elapsed_time=" + StreamableToString(test_case.elapsed_time())
|
||||
+ "ms");
|
||||
}
|
||||
|
||||
void OnTestStart(const TestInfo& test_info) {
|
||||
SendLn(std::string("event=TestStart&name=") + test_info.name());
|
||||
}
|
||||
|
||||
void OnTestEnd(const TestInfo& test_info) {
|
||||
SendLn("event=TestEnd&passed=" +
|
||||
FormatBool((test_info.result())->Passed()) +
|
||||
"&elapsed_time=" +
|
||||
StreamableToString((test_info.result())->elapsed_time()) + "ms");
|
||||
}
|
||||
|
||||
void OnTestPartResult(const TestPartResult& test_part_result) {
|
||||
const char* file_name = test_part_result.file_name();
|
||||
if (file_name == NULL)
|
||||
file_name = "";
|
||||
SendLn("event=TestPartResult&file=" + UrlEncode(file_name) +
|
||||
"&line=" + StreamableToString(test_part_result.line_number()) +
|
||||
"&message=" + UrlEncode(test_part_result.message()));
|
||||
}
|
||||
|
||||
private:
|
||||
// Sends the given message and a newline to the socket.
|
||||
void SendLn(const string& message) { socket_writer_->SendLn(message); }
|
||||
|
||||
// Called at the start of streaming to notify the receiver what
|
||||
// protocol we are using.
|
||||
void Start() { SendLn("gtest_streaming_protocol_version=1.0"); }
|
||||
|
||||
string FormatBool(bool value) { return value ? "1" : "0"; }
|
||||
|
||||
const scoped_ptr<AbstractSocketWriter> socket_writer_;
|
||||
|
||||
GTEST_DISALLOW_COPY_AND_ASSIGN_(StreamingListener);
|
||||
}; // class StreamingListener
|
||||
|
||||
#endif // GTEST_CAN_STREAM_RESULTS_
|
||||
|
||||
} // namespace internal
|
||||
} // namespace testing
|
||||
|
||||
|
|
@ -51,6 +51,11 @@
|
|||
# include <mach/vm_map.h>
|
||||
#endif // GTEST_OS_MAC
|
||||
|
||||
#if GTEST_OS_QNX
|
||||
# include <devctl.h>
|
||||
# include <sys/procfs.h>
|
||||
#endif // GTEST_OS_QNX
|
||||
|
||||
#include "gtest/gtest-spi.h"
|
||||
#include "gtest/gtest-message.h"
|
||||
#include "gtest/internal/gtest-internal.h"
|
||||
|
|
@ -62,7 +67,7 @@
|
|||
// prevent a user from accidentally including gtest-internal-inl.h in
|
||||
// his code.
|
||||
#define GTEST_IMPLEMENTATION_ 1
|
||||
#include "src/gtest-internal-inl.h"
|
||||
#include "gtest-internal-inl.h"
|
||||
#undef GTEST_IMPLEMENTATION_
|
||||
|
||||
namespace testing {
|
||||
|
|
@ -98,6 +103,26 @@ size_t GetThreadCount() {
|
|||
}
|
||||
}
|
||||
|
||||
#elif GTEST_OS_QNX
|
||||
|
||||
// Returns the number of threads running in the process, or 0 to indicate that
|
||||
// we cannot detect it.
|
||||
size_t GetThreadCount() {
|
||||
const int fd = open("/proc/self/as", O_RDONLY);
|
||||
if (fd < 0) {
|
||||
return 0;
|
||||
}
|
||||
procfs_info process_info;
|
||||
const int status =
|
||||
devctl(fd, DCMD_PROC_INFO, &process_info, sizeof(process_info), NULL);
|
||||
close(fd);
|
||||
if (status == EOK) {
|
||||
return static_cast<size_t>(process_info.num_threads);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
size_t GetThreadCount() {
|
||||
|
|
@ -222,7 +247,7 @@ bool AtomMatchesChar(bool escaped, char pattern_char, char ch) {
|
|||
}
|
||||
|
||||
// Helper function used by ValidateRegex() to format error messages.
|
||||
String FormatRegexSyntaxError(const char* regex, int index) {
|
||||
std::string FormatRegexSyntaxError(const char* regex, int index) {
|
||||
return (Message() << "Syntax error at index " << index
|
||||
<< " in simple regular expression \"" << regex << "\": ").GetString();
|
||||
}
|
||||
|
|
@ -429,15 +454,15 @@ const char kUnknownFile[] = "unknown file";
|
|||
// Formats a source file path and a line number as they would appear
|
||||
// in an error message from the compiler used to compile this code.
|
||||
GTEST_API_ ::std::string FormatFileLocation(const char* file, int line) {
|
||||
const char* const file_name = file == NULL ? kUnknownFile : file;
|
||||
const std::string file_name(file == NULL ? kUnknownFile : file);
|
||||
|
||||
if (line < 0) {
|
||||
return String::Format("%s:", file_name).c_str();
|
||||
return file_name + ":";
|
||||
}
|
||||
#ifdef _MSC_VER
|
||||
return String::Format("%s(%d):", file_name, line).c_str();
|
||||
return file_name + "(" + StreamableToString(line) + "):";
|
||||
#else
|
||||
return String::Format("%s:%d:", file_name, line).c_str();
|
||||
return file_name + ":" + StreamableToString(line) + ":";
|
||||
#endif // _MSC_VER
|
||||
}
|
||||
|
||||
|
|
@ -448,12 +473,12 @@ GTEST_API_ ::std::string FormatFileLocation(const char* file, int line) {
|
|||
// to the file location it produces, unlike FormatFileLocation().
|
||||
GTEST_API_ ::std::string FormatCompilerIndependentFileLocation(
|
||||
const char* file, int line) {
|
||||
const char* const file_name = file == NULL ? kUnknownFile : file;
|
||||
const std::string file_name(file == NULL ? kUnknownFile : file);
|
||||
|
||||
if (line < 0)
|
||||
return file_name;
|
||||
else
|
||||
return String::Format("%s:%d", file_name, line).c_str();
|
||||
return file_name + ":" + StreamableToString(line);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -488,8 +513,7 @@ GTestLog::~GTestLog() {
|
|||
class CapturedStream {
|
||||
public:
|
||||
// The ctor redirects the stream to a temporary file.
|
||||
CapturedStream(int fd) : fd_(fd), uncaptured_fd_(dup(fd)) {
|
||||
|
||||
explicit CapturedStream(int fd) : fd_(fd), uncaptured_fd_(dup(fd)) {
|
||||
# if GTEST_OS_WINDOWS
|
||||
char temp_dir_path[MAX_PATH + 1] = { '\0' }; // NOLINT
|
||||
char temp_file_path[MAX_PATH + 1] = { '\0' }; // NOLINT
|
||||
|
|
@ -506,10 +530,29 @@ class CapturedStream {
|
|||
<< temp_file_path;
|
||||
filename_ = temp_file_path;
|
||||
# else
|
||||
// There's no guarantee that a test has write access to the
|
||||
// current directory, so we create the temporary file in the /tmp
|
||||
// directory instead.
|
||||
// There's no guarantee that a test has write access to the current
|
||||
// directory, so we create the temporary file in the /tmp directory
|
||||
// instead. We use /tmp on most systems, and /sdcard on Android.
|
||||
// That's because Android doesn't have /tmp.
|
||||
# if GTEST_OS_LINUX_ANDROID
|
||||
// Note: Android applications are expected to call the framework's
|
||||
// Context.getExternalStorageDirectory() method through JNI to get
|
||||
// the location of the world-writable SD Card directory. However,
|
||||
// this requires a Context handle, which cannot be retrieved
|
||||
// globally from native code. Doing so also precludes running the
|
||||
// code as part of a regular standalone executable, which doesn't
|
||||
// run in a Dalvik process (e.g. when running it through 'adb shell').
|
||||
//
|
||||
// The location /sdcard is directly accessible from native code
|
||||
// and is the only location (unofficially) supported by the Android
|
||||
// team. It's generally a symlink to the real SD Card mount point
|
||||
// which can be /mnt/sdcard, /mnt/sdcard0, /system/media/sdcard, or
|
||||
// other OEM-customized locations. Never rely on these, and always
|
||||
// use /sdcard.
|
||||
char name_template[] = "/sdcard/gtest_captured_stream.XXXXXX";
|
||||
# else
|
||||
char name_template[] = "/tmp/captured_stream.XXXXXX";
|
||||
# endif // GTEST_OS_LINUX_ANDROID
|
||||
const int captured_fd = mkstemp(name_template);
|
||||
filename_ = name_template;
|
||||
# endif // GTEST_OS_WINDOWS
|
||||
|
|
@ -522,7 +565,7 @@ class CapturedStream {
|
|||
remove(filename_.c_str());
|
||||
}
|
||||
|
||||
String GetCapturedString() {
|
||||
std::string GetCapturedString() {
|
||||
if (uncaptured_fd_ != -1) {
|
||||
// Restores the original stream.
|
||||
fflush(NULL);
|
||||
|
|
@ -532,14 +575,14 @@ class CapturedStream {
|
|||
}
|
||||
|
||||
FILE* const file = posix::FOpen(filename_.c_str(), "r");
|
||||
const String content = ReadEntireFile(file);
|
||||
const std::string content = ReadEntireFile(file);
|
||||
posix::FClose(file);
|
||||
return content;
|
||||
}
|
||||
|
||||
private:
|
||||
// Reads the entire content of a file as a String.
|
||||
static String ReadEntireFile(FILE* file);
|
||||
// Reads the entire content of a file as an std::string.
|
||||
static std::string ReadEntireFile(FILE* file);
|
||||
|
||||
// Returns the size (in bytes) of a file.
|
||||
static size_t GetFileSize(FILE* file);
|
||||
|
|
@ -559,7 +602,7 @@ size_t CapturedStream::GetFileSize(FILE* file) {
|
|||
}
|
||||
|
||||
// Reads the entire content of a file as a string.
|
||||
String CapturedStream::ReadEntireFile(FILE* file) {
|
||||
std::string CapturedStream::ReadEntireFile(FILE* file) {
|
||||
const size_t file_size = GetFileSize(file);
|
||||
char* const buffer = new char[file_size];
|
||||
|
||||
|
|
@ -575,7 +618,7 @@ String CapturedStream::ReadEntireFile(FILE* file) {
|
|||
bytes_read += bytes_last_read;
|
||||
} while (bytes_last_read > 0 && bytes_read < file_size);
|
||||
|
||||
const String content(buffer, bytes_read);
|
||||
const std::string content(buffer, bytes_read);
|
||||
delete[] buffer;
|
||||
|
||||
return content;
|
||||
|
|
@ -598,8 +641,8 @@ void CaptureStream(int fd, const char* stream_name, CapturedStream** stream) {
|
|||
}
|
||||
|
||||
// Stops capturing the output stream and returns the captured string.
|
||||
String GetCapturedStream(CapturedStream** captured_stream) {
|
||||
const String content = (*captured_stream)->GetCapturedString();
|
||||
std::string GetCapturedStream(CapturedStream** captured_stream) {
|
||||
const std::string content = (*captured_stream)->GetCapturedString();
|
||||
|
||||
delete *captured_stream;
|
||||
*captured_stream = NULL;
|
||||
|
|
@ -618,21 +661,37 @@ void CaptureStderr() {
|
|||
}
|
||||
|
||||
// Stops capturing stdout and returns the captured string.
|
||||
String GetCapturedStdout() { return GetCapturedStream(&g_captured_stdout); }
|
||||
std::string GetCapturedStdout() {
|
||||
return GetCapturedStream(&g_captured_stdout);
|
||||
}
|
||||
|
||||
// Stops capturing stderr and returns the captured string.
|
||||
String GetCapturedStderr() { return GetCapturedStream(&g_captured_stderr); }
|
||||
std::string GetCapturedStderr() {
|
||||
return GetCapturedStream(&g_captured_stderr);
|
||||
}
|
||||
|
||||
#endif // GTEST_HAS_STREAM_REDIRECTION
|
||||
|
||||
#if GTEST_HAS_DEATH_TEST
|
||||
|
||||
// A copy of all command line arguments. Set by InitGoogleTest().
|
||||
::std::vector<String> g_argvs;
|
||||
::std::vector<testing::internal::string> g_argvs;
|
||||
|
||||
// Returns the command line as a vector of strings.
|
||||
const ::std::vector<String>& GetArgvs() { return g_argvs; }
|
||||
static const ::std::vector<testing::internal::string>* g_injected_test_argvs =
|
||||
NULL; // Owned.
|
||||
|
||||
void SetInjectableArgvs(const ::std::vector<testing::internal::string>* argvs) {
|
||||
if (g_injected_test_argvs != argvs)
|
||||
delete g_injected_test_argvs;
|
||||
g_injected_test_argvs = argvs;
|
||||
}
|
||||
|
||||
const ::std::vector<testing::internal::string>& GetInjectableArgvs() {
|
||||
if (g_injected_test_argvs != NULL) {
|
||||
return *g_injected_test_argvs;
|
||||
}
|
||||
return g_argvs;
|
||||
}
|
||||
#endif // GTEST_HAS_DEATH_TEST
|
||||
|
||||
#if GTEST_OS_WINDOWS_MOBILE
|
||||
|
|
@ -647,8 +706,8 @@ void Abort() {
|
|||
// Returns the name of the environment variable corresponding to the
|
||||
// given flag. For example, FlagToEnvVar("foo") will return
|
||||
// "GTEST_FOO" in the open-source version.
|
||||
static String FlagToEnvVar(const char* flag) {
|
||||
const String full_flag =
|
||||
static std::string FlagToEnvVar(const char* flag) {
|
||||
const std::string full_flag =
|
||||
(Message() << GTEST_FLAG_PREFIX_ << flag).GetString();
|
||||
|
||||
Message env_var;
|
||||
|
|
@ -705,7 +764,7 @@ bool ParseInt32(const Message& src_text, const char* str, Int32* value) {
|
|||
//
|
||||
// The value is considered true iff it's not "0".
|
||||
bool BoolFromGTestEnv(const char* flag, bool default_value) {
|
||||
const String env_var = FlagToEnvVar(flag);
|
||||
const std::string env_var = FlagToEnvVar(flag);
|
||||
const char* const string_value = posix::GetEnv(env_var.c_str());
|
||||
return string_value == NULL ?
|
||||
default_value : strcmp(string_value, "0") != 0;
|
||||
|
|
@ -715,7 +774,7 @@ bool BoolFromGTestEnv(const char* flag, bool default_value) {
|
|||
// variable corresponding to the given flag; if it isn't set or
|
||||
// doesn't represent a valid 32-bit integer, returns default_value.
|
||||
Int32 Int32FromGTestEnv(const char* flag, Int32 default_value) {
|
||||
const String env_var = FlagToEnvVar(flag);
|
||||
const std::string env_var = FlagToEnvVar(flag);
|
||||
const char* const string_value = posix::GetEnv(env_var.c_str());
|
||||
if (string_value == NULL) {
|
||||
// The environment variable is not set.
|
||||
|
|
@ -737,7 +796,7 @@ Int32 Int32FromGTestEnv(const char* flag, Int32 default_value) {
|
|||
// Reads and returns the string environment variable corresponding to
|
||||
// the given flag; if it's not set, returns default_value.
|
||||
const char* StringFromGTestEnv(const char* flag, const char* default_value) {
|
||||
const String env_var = FlagToEnvVar(flag);
|
||||
const std::string env_var = FlagToEnvVar(flag);
|
||||
const char* const value = posix::GetEnv(env_var.c_str());
|
||||
return value == NULL ? default_value : value;
|
||||
}
|
||||
|
|
@ -55,14 +55,6 @@ namespace {
|
|||
|
||||
using ::std::ostream;
|
||||
|
||||
#if GTEST_OS_WINDOWS_MOBILE // Windows CE does not define _snprintf_s.
|
||||
# define snprintf _snprintf
|
||||
#elif _MSC_VER >= 1400 // VC 8.0 and later deprecate snprintf and _snprintf.
|
||||
# define snprintf _snprintf_s
|
||||
#elif _MSC_VER
|
||||
# define snprintf _snprintf
|
||||
#endif // GTEST_OS_WINDOWS_MOBILE
|
||||
|
||||
// Prints a segment of bytes in the given object.
|
||||
void PrintByteSegmentInObjectTo(const unsigned char* obj_bytes, size_t start,
|
||||
size_t count, ostream* os) {
|
||||
|
|
@ -77,7 +69,7 @@ void PrintByteSegmentInObjectTo(const unsigned char* obj_bytes, size_t start,
|
|||
else
|
||||
*os << '-';
|
||||
}
|
||||
snprintf(text, sizeof(text), "%02X", obj_bytes[j]);
|
||||
GTEST_SNPRINTF_(text, sizeof(text), "%02X", obj_bytes[j]);
|
||||
*os << text;
|
||||
}
|
||||
}
|
||||
|
|
@ -184,16 +176,16 @@ static CharFormat PrintAsCharLiteralTo(Char c, ostream* os) {
|
|||
*os << static_cast<char>(c);
|
||||
return kAsIs;
|
||||
} else {
|
||||
*os << String::Format("\\x%X", static_cast<UnsignedChar>(c));
|
||||
*os << "\\x" + String::FormatHexInt(static_cast<UnsignedChar>(c));
|
||||
return kHexEscape;
|
||||
}
|
||||
}
|
||||
return kSpecialEscape;
|
||||
}
|
||||
|
||||
// Prints a char c as if it's part of a string literal, escaping it when
|
||||
// Prints a wchar_t c as if it's part of a string literal, escaping it when
|
||||
// necessary; returns how c was formatted.
|
||||
static CharFormat PrintAsWideStringLiteralTo(wchar_t c, ostream* os) {
|
||||
static CharFormat PrintAsStringLiteralTo(wchar_t c, ostream* os) {
|
||||
switch (c) {
|
||||
case L'\'':
|
||||
*os << "'";
|
||||
|
|
@ -208,8 +200,9 @@ static CharFormat PrintAsWideStringLiteralTo(wchar_t c, ostream* os) {
|
|||
|
||||
// Prints a char c as if it's part of a string literal, escaping it when
|
||||
// necessary; returns how c was formatted.
|
||||
static CharFormat PrintAsNarrowStringLiteralTo(char c, ostream* os) {
|
||||
return PrintAsWideStringLiteralTo(static_cast<unsigned char>(c), os);
|
||||
static CharFormat PrintAsStringLiteralTo(char c, ostream* os) {
|
||||
return PrintAsStringLiteralTo(
|
||||
static_cast<wchar_t>(static_cast<unsigned char>(c)), os);
|
||||
}
|
||||
|
||||
// Prints a wide or narrow character c and its code. '\0' is printed
|
||||
|
|
@ -228,7 +221,7 @@ void PrintCharAndCodeTo(Char c, ostream* os) {
|
|||
// obvious).
|
||||
if (c == 0)
|
||||
return;
|
||||
*os << " (" << String::Format("%d", c).c_str();
|
||||
*os << " (" << static_cast<int>(c);
|
||||
|
||||
// For more convenience, we print c's code again in hexidecimal,
|
||||
// unless c was already printed in the form '\x##' or the code is in
|
||||
|
|
@ -236,8 +229,7 @@ void PrintCharAndCodeTo(Char c, ostream* os) {
|
|||
if (format == kHexEscape || (1 <= c && c <= 9)) {
|
||||
// Do nothing.
|
||||
} else {
|
||||
*os << String::Format(", 0x%X",
|
||||
static_cast<UnsignedChar>(c)).c_str();
|
||||
*os << ", 0x" << String::FormatHexInt(static_cast<UnsignedChar>(c));
|
||||
}
|
||||
*os << ")";
|
||||
}
|
||||
|
|
@ -255,48 +247,63 @@ void PrintTo(wchar_t wc, ostream* os) {
|
|||
PrintCharAndCodeTo<wchar_t>(wc, os);
|
||||
}
|
||||
|
||||
// Prints the given array of characters to the ostream.
|
||||
// The array starts at *begin, the length is len, it may include '\0' characters
|
||||
// and may not be null-terminated.
|
||||
static void PrintCharsAsStringTo(const char* begin, size_t len, ostream* os) {
|
||||
*os << "\"";
|
||||
// Prints the given array of characters to the ostream. CharType must be either
|
||||
// char or wchar_t.
|
||||
// The array starts at begin, the length is len, it may include '\0' characters
|
||||
// and may not be NUL-terminated.
|
||||
template <typename CharType>
|
||||
static void PrintCharsAsStringTo(
|
||||
const CharType* begin, size_t len, ostream* os) {
|
||||
const char* const kQuoteBegin = sizeof(CharType) == 1 ? "\"" : "L\"";
|
||||
*os << kQuoteBegin;
|
||||
bool is_previous_hex = false;
|
||||
for (size_t index = 0; index < len; ++index) {
|
||||
const char cur = begin[index];
|
||||
const CharType cur = begin[index];
|
||||
if (is_previous_hex && IsXDigit(cur)) {
|
||||
// Previous character is of '\x..' form and this character can be
|
||||
// interpreted as another hexadecimal digit in its number. Break string to
|
||||
// disambiguate.
|
||||
*os << "\" \"";
|
||||
*os << "\" " << kQuoteBegin;
|
||||
}
|
||||
is_previous_hex = PrintAsNarrowStringLiteralTo(cur, os) == kHexEscape;
|
||||
is_previous_hex = PrintAsStringLiteralTo(cur, os) == kHexEscape;
|
||||
}
|
||||
*os << "\"";
|
||||
}
|
||||
|
||||
// Prints a (const) char/wchar_t array of 'len' elements, starting at address
|
||||
// 'begin'. CharType must be either char or wchar_t.
|
||||
template <typename CharType>
|
||||
static void UniversalPrintCharArray(
|
||||
const CharType* begin, size_t len, ostream* os) {
|
||||
// The code
|
||||
// const char kFoo[] = "foo";
|
||||
// generates an array of 4, not 3, elements, with the last one being '\0'.
|
||||
//
|
||||
// Therefore when printing a char array, we don't print the last element if
|
||||
// it's '\0', such that the output matches the string literal as it's
|
||||
// written in the source code.
|
||||
if (len > 0 && begin[len - 1] == '\0') {
|
||||
PrintCharsAsStringTo(begin, len - 1, os);
|
||||
return;
|
||||
}
|
||||
|
||||
// If, however, the last element in the array is not '\0', e.g.
|
||||
// const char kFoo[] = { 'f', 'o', 'o' };
|
||||
// we must print the entire array. We also print a message to indicate
|
||||
// that the array is not NUL-terminated.
|
||||
PrintCharsAsStringTo(begin, len, os);
|
||||
*os << " (no terminating NUL)";
|
||||
}
|
||||
|
||||
// Prints a (const) char array of 'len' elements, starting at address 'begin'.
|
||||
void UniversalPrintArray(const char* begin, size_t len, ostream* os) {
|
||||
PrintCharsAsStringTo(begin, len, os);
|
||||
UniversalPrintCharArray(begin, len, os);
|
||||
}
|
||||
|
||||
// Prints the given array of wide characters to the ostream.
|
||||
// The array starts at *begin, the length is len, it may include L'\0'
|
||||
// characters and may not be null-terminated.
|
||||
static void PrintWideCharsAsStringTo(const wchar_t* begin, size_t len,
|
||||
ostream* os) {
|
||||
*os << "L\"";
|
||||
bool is_previous_hex = false;
|
||||
for (size_t index = 0; index < len; ++index) {
|
||||
const wchar_t cur = begin[index];
|
||||
if (is_previous_hex && isascii(cur) && IsXDigit(static_cast<char>(cur))) {
|
||||
// Previous character is of '\x..' form and this character can be
|
||||
// interpreted as another hexadecimal digit in its number. Break string to
|
||||
// disambiguate.
|
||||
*os << "\" L\"";
|
||||
}
|
||||
is_previous_hex = PrintAsWideStringLiteralTo(cur, os) == kHexEscape;
|
||||
}
|
||||
*os << "\"";
|
||||
// Prints a (const) wchar_t array of 'len' elements, starting at address
|
||||
// 'begin'.
|
||||
void UniversalPrintArray(const wchar_t* begin, size_t len, ostream* os) {
|
||||
UniversalPrintCharArray(begin, len, os);
|
||||
}
|
||||
|
||||
// Prints the given C string to the ostream.
|
||||
|
|
@ -322,7 +329,7 @@ void PrintTo(const wchar_t* s, ostream* os) {
|
|||
*os << "NULL";
|
||||
} else {
|
||||
*os << ImplicitCast_<const void*>(s) << " pointing to ";
|
||||
PrintWideCharsAsStringTo(s, wcslen(s), os);
|
||||
PrintCharsAsStringTo(s, wcslen(s), os);
|
||||
}
|
||||
}
|
||||
#endif // wchar_t is native
|
||||
|
|
@ -341,13 +348,13 @@ void PrintStringTo(const ::std::string& s, ostream* os) {
|
|||
// Prints a ::wstring object.
|
||||
#if GTEST_HAS_GLOBAL_WSTRING
|
||||
void PrintWideStringTo(const ::wstring& s, ostream* os) {
|
||||
PrintWideCharsAsStringTo(s.data(), s.size(), os);
|
||||
PrintCharsAsStringTo(s.data(), s.size(), os);
|
||||
}
|
||||
#endif // GTEST_HAS_GLOBAL_WSTRING
|
||||
|
||||
#if GTEST_HAS_STD_WSTRING
|
||||
void PrintWideStringTo(const ::std::wstring& s, ostream* os) {
|
||||
PrintWideCharsAsStringTo(s.data(), s.size(), os);
|
||||
PrintCharsAsStringTo(s.data(), s.size(), os);
|
||||
}
|
||||
#endif // GTEST_HAS_STD_WSTRING
|
||||
|
||||
|
|
@ -39,7 +39,7 @@
|
|||
// prevent a user from accidentally including gtest-internal-inl.h in
|
||||
// his code.
|
||||
#define GTEST_IMPLEMENTATION_ 1
|
||||
#include "src/gtest-internal-inl.h"
|
||||
#include "gtest-internal-inl.h"
|
||||
#undef GTEST_IMPLEMENTATION_
|
||||
|
||||
namespace testing {
|
||||
|
|
@ -48,10 +48,10 @@ using internal::GetUnitTestImpl;
|
|||
|
||||
// Gets the summary of the failure message by omitting the stack trace
|
||||
// in it.
|
||||
internal::String TestPartResult::ExtractSummary(const char* message) {
|
||||
std::string TestPartResult::ExtractSummary(const char* message) {
|
||||
const char* const stack_trace = strstr(message, internal::kStackTraceMarker);
|
||||
return stack_trace == NULL ? internal::String(message) :
|
||||
internal::String(message, stack_trace - message);
|
||||
return stack_trace == NULL ? message :
|
||||
std::string(message, stack_trace);
|
||||
}
|
||||
|
||||
// Prints a TestPartResult object.
|
||||
|
|
@ -58,10 +58,10 @@ const char* TypedTestCasePState::VerifyRegisteredTestNames(
|
|||
registered_tests = SkipSpaces(registered_tests);
|
||||
|
||||
Message errors;
|
||||
::std::set<String> tests;
|
||||
::std::set<std::string> tests;
|
||||
for (const char* names = registered_tests; names != NULL;
|
||||
names = SkipComma(names)) {
|
||||
const String name = GetPrefixUntilComma(names);
|
||||
const std::string name = GetPrefixUntilComma(names);
|
||||
if (tests.count(name) != 0) {
|
||||
errors << "Test " << name << " is listed more than once.\n";
|
||||
continue;
|
||||
|
|
@ -93,7 +93,7 @@ const char* TypedTestCasePState::VerifyRegisteredTestNames(
|
|||
}
|
||||
}
|
||||
|
||||
const String& errors_str = errors.GetString();
|
||||
const std::string& errors_str = errors.GetString();
|
||||
if (errors_str != "") {
|
||||
fprintf(stderr, "%s %s", FormatFileLocation(file, line).c_str(),
|
||||
errors_str.c_str());
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -27,13 +27,12 @@
|
|||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <iostream>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
GTEST_API_ int main(int argc, char **argv) {
|
||||
std::cout << "Running main() from gtest_main.cc\n";
|
||||
|
||||
printf("Running main() from gtest_main.cc\n");
|
||||
testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
|
|
@ -51,6 +51,17 @@ GTEST_DECLARE_string_(death_test_style);
|
|||
|
||||
#if GTEST_HAS_DEATH_TEST
|
||||
|
||||
namespace internal {
|
||||
|
||||
// Returns a Boolean value indicating whether the caller is currently
|
||||
// executing in the context of the death test child process. Tools such as
|
||||
// Valgrind heap checkers may need this to modify their behavior in death
|
||||
// tests. IMPORTANT: This is an internal utility. Using it may break the
|
||||
// implementation of death tests. User code MUST NOT use it.
|
||||
GTEST_API_ bool InDeathTestChild();
|
||||
|
||||
} // namespace internal
|
||||
|
||||
// The following macros are useful for writing death tests.
|
||||
|
||||
// Here's what happens when an ASSERT_DEATH* or EXPECT_DEATH* is
|
||||
|
|
@ -75,7 +86,7 @@ GTEST_DECLARE_string_(death_test_style);
|
|||
// for (int i = 0; i < 5; i++) {
|
||||
// EXPECT_DEATH(server.ProcessRequest(i),
|
||||
// "Invalid request .* in ProcessRequest()")
|
||||
// << "Failed to die on request " << i);
|
||||
// << "Failed to die on request " << i;
|
||||
// }
|
||||
//
|
||||
// ASSERT_EXIT(server.ExitNow(), ::testing::ExitedWithCode(0), "Exiting");
|
||||
|
|
@ -245,10 +256,10 @@ class GTEST_API_ KilledBySignal {
|
|||
# ifdef NDEBUG
|
||||
|
||||
# define EXPECT_DEBUG_DEATH(statement, regex) \
|
||||
do { statement; } while (::testing::internal::AlwaysFalse())
|
||||
GTEST_EXECUTE_STATEMENT_(statement, regex)
|
||||
|
||||
# define ASSERT_DEBUG_DEATH(statement, regex) \
|
||||
do { statement; } while (::testing::internal::AlwaysFalse())
|
||||
GTEST_EXECUTE_STATEMENT_(statement, regex)
|
||||
|
||||
# else
|
||||
|
||||
|
|
@ -48,8 +48,11 @@
|
|||
|
||||
#include <limits>
|
||||
|
||||
#include "gtest/internal/gtest-string.h"
|
||||
#include "gtest/internal/gtest-internal.h"
|
||||
#include "gtest/internal/gtest-port.h"
|
||||
|
||||
// Ensures that there is at least one operator<< in the global namespace.
|
||||
// See Message& operator<<(...) below for why.
|
||||
void operator<<(const testing::internal::Secret&, int);
|
||||
|
||||
namespace testing {
|
||||
|
||||
|
|
@ -87,15 +90,7 @@ class GTEST_API_ Message {
|
|||
|
||||
public:
|
||||
// Constructs an empty Message.
|
||||
// We allocate the stringstream separately because otherwise each use of
|
||||
// ASSERT/EXPECT in a procedure adds over 200 bytes to the procedure's
|
||||
// stack frame leading to huge stack frames in some cases; gcc does not reuse
|
||||
// the stack space.
|
||||
Message() : ss_(new ::std::stringstream) {
|
||||
// By default, we want there to be enough precision when printing
|
||||
// a double to a Message.
|
||||
*ss_ << std::setprecision(std::numeric_limits<double>::digits10 + 2);
|
||||
}
|
||||
Message();
|
||||
|
||||
// Copy constructor.
|
||||
Message(const Message& msg) : ss_(new ::std::stringstream) { // NOLINT
|
||||
|
|
@ -118,7 +113,22 @@ class GTEST_API_ Message {
|
|||
// Streams a non-pointer value to this object.
|
||||
template <typename T>
|
||||
inline Message& operator <<(const T& val) {
|
||||
::GTestStreamToHelper(ss_.get(), val);
|
||||
// Some libraries overload << for STL containers. These
|
||||
// overloads are defined in the global namespace instead of ::std.
|
||||
//
|
||||
// C++'s symbol lookup rule (i.e. Koenig lookup) says that these
|
||||
// overloads are visible in either the std namespace or the global
|
||||
// namespace, but not other namespaces, including the testing
|
||||
// namespace which Google Test's Message class is in.
|
||||
//
|
||||
// To allow STL containers (and other types that has a << operator
|
||||
// defined in the global namespace) to be used in Google Test
|
||||
// assertions, testing::Message must access the custom << operator
|
||||
// from the global namespace. With this using declaration,
|
||||
// overloads of << defined in the global namespace and those
|
||||
// visible via Koenig lookup are both exposed in this function.
|
||||
using ::operator <<;
|
||||
*ss_ << val;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
|
@ -140,7 +150,7 @@ class GTEST_API_ Message {
|
|||
if (pointer == NULL) {
|
||||
*ss_ << "(null)";
|
||||
} else {
|
||||
::GTestStreamToHelper(ss_.get(), pointer);
|
||||
*ss_ << pointer;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
|
@ -164,12 +174,8 @@ class GTEST_API_ Message {
|
|||
|
||||
// These two overloads allow streaming a wide C string to a Message
|
||||
// using the UTF-8 encoding.
|
||||
Message& operator <<(const wchar_t* wide_c_str) {
|
||||
return *this << internal::String::ShowWideCString(wide_c_str);
|
||||
}
|
||||
Message& operator <<(wchar_t* wide_c_str) {
|
||||
return *this << internal::String::ShowWideCString(wide_c_str);
|
||||
}
|
||||
Message& operator <<(const wchar_t* wide_c_str);
|
||||
Message& operator <<(wchar_t* wide_c_str);
|
||||
|
||||
#if GTEST_HAS_STD_WSTRING
|
||||
// Converts the given wide string to a narrow string using the UTF-8
|
||||
|
|
@ -183,13 +189,11 @@ class GTEST_API_ Message {
|
|||
Message& operator <<(const ::wstring& wstr);
|
||||
#endif // GTEST_HAS_GLOBAL_WSTRING
|
||||
|
||||
// Gets the text streamed to this object so far as a String.
|
||||
// Gets the text streamed to this object so far as an std::string.
|
||||
// Each '\0' character in the buffer is replaced with "\\0".
|
||||
//
|
||||
// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
|
||||
internal::String GetString() const {
|
||||
return internal::StringStreamToString(ss_.get());
|
||||
}
|
||||
std::string GetString() const;
|
||||
|
||||
private:
|
||||
|
||||
|
|
@ -199,16 +203,20 @@ class GTEST_API_ Message {
|
|||
// decide between class template specializations for T and T*, so a
|
||||
// tr1::type_traits-like is_pointer works, and we can overload on that.
|
||||
template <typename T>
|
||||
inline void StreamHelper(internal::true_type /*dummy*/, T* pointer) {
|
||||
inline void StreamHelper(internal::true_type /*is_pointer*/, T* pointer) {
|
||||
if (pointer == NULL) {
|
||||
*ss_ << "(null)";
|
||||
} else {
|
||||
::GTestStreamToHelper(ss_.get(), pointer);
|
||||
*ss_ << pointer;
|
||||
}
|
||||
}
|
||||
template <typename T>
|
||||
inline void StreamHelper(internal::false_type /*dummy*/, const T& value) {
|
||||
::GTestStreamToHelper(ss_.get(), value);
|
||||
inline void StreamHelper(internal::false_type /*is_pointer*/,
|
||||
const T& value) {
|
||||
// See the comments in Message& operator <<(const T&) above for why
|
||||
// we need this using statement.
|
||||
using ::operator <<;
|
||||
*ss_ << value;
|
||||
}
|
||||
#endif // GTEST_OS_SYMBIAN
|
||||
|
||||
|
|
@ -225,6 +233,18 @@ inline std::ostream& operator <<(std::ostream& os, const Message& sb) {
|
|||
return os << sb.GetString();
|
||||
}
|
||||
|
||||
namespace internal {
|
||||
|
||||
// Converts a streamable value to an std::string. A NULL pointer is
|
||||
// converted to "(null)". When the input value is a ::string,
|
||||
// ::std::string, ::wstring, or ::std::wstring object, each NUL
|
||||
// character in it is replaced with "\\0".
|
||||
template <typename T>
|
||||
std::string StreamableToString(const T& streamable) {
|
||||
return (Message() << streamable).GetString();
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace testing
|
||||
|
||||
#endif // GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_
|
||||
|
|
@ -1257,7 +1257,7 @@ inline internal::ParamGenerator<bool> Bool() {
|
|||
// Boolean flags:
|
||||
//
|
||||
// class FlagDependentTest
|
||||
// : public testing::TestWithParam<tuple(bool, bool)> > {
|
||||
// : public testing::TestWithParam<tuple<bool, bool> > {
|
||||
// virtual void SetUp() {
|
||||
// // Assigns external_flag_1 and external_flag_2 values from the tuple.
|
||||
// tie(external_flag_1, external_flag_2) = GetParam();
|
||||
|
|
@ -414,7 +414,7 @@ inline internal::ParamGenerator<bool> Bool() {
|
|||
// Boolean flags:
|
||||
//
|
||||
// class FlagDependentTest
|
||||
// : public testing::TestWithParam<tuple(bool, bool)> > {
|
||||
// : public testing::TestWithParam<tuple<bool, bool> > {
|
||||
// virtual void SetUp() {
|
||||
// // Assigns external_flag_1 and external_flag_2 values from the tuple.
|
||||
// tie(external_flag_1, external_flag_2) = GetParam();
|
||||
|
|
@ -630,9 +630,12 @@ void UniversalPrintArray(const T* begin, size_t len, ::std::ostream* os) {
|
|||
}
|
||||
}
|
||||
// This overload prints a (const) char array compactly.
|
||||
GTEST_API_ void UniversalPrintArray(const char* begin,
|
||||
size_t len,
|
||||
::std::ostream* os);
|
||||
GTEST_API_ void UniversalPrintArray(
|
||||
const char* begin, size_t len, ::std::ostream* os);
|
||||
|
||||
// This overload prints a (const) wchar_t array compactly.
|
||||
GTEST_API_ void UniversalPrintArray(
|
||||
const wchar_t* begin, size_t len, ::std::ostream* os);
|
||||
|
||||
// Implements printing an array type T[N].
|
||||
template <typename T, size_t N>
|
||||
|
|
@ -673,19 +676,72 @@ class UniversalPrinter<T&> {
|
|||
// Prints a value tersely: for a reference type, the referenced value
|
||||
// (but not the address) is printed; for a (const) char pointer, the
|
||||
// NUL-terminated string (but not the pointer) is printed.
|
||||
|
||||
template <typename T>
|
||||
class UniversalTersePrinter {
|
||||
public:
|
||||
static void Print(const T& value, ::std::ostream* os) {
|
||||
UniversalPrint(value, os);
|
||||
}
|
||||
};
|
||||
template <typename T>
|
||||
class UniversalTersePrinter<T&> {
|
||||
public:
|
||||
static void Print(const T& value, ::std::ostream* os) {
|
||||
UniversalPrint(value, os);
|
||||
}
|
||||
};
|
||||
template <typename T, size_t N>
|
||||
class UniversalTersePrinter<T[N]> {
|
||||
public:
|
||||
static void Print(const T (&value)[N], ::std::ostream* os) {
|
||||
UniversalPrinter<T[N]>::Print(value, os);
|
||||
}
|
||||
};
|
||||
template <>
|
||||
class UniversalTersePrinter<const char*> {
|
||||
public:
|
||||
static void Print(const char* str, ::std::ostream* os) {
|
||||
if (str == NULL) {
|
||||
*os << "NULL";
|
||||
} else {
|
||||
UniversalPrint(string(str), os);
|
||||
}
|
||||
}
|
||||
};
|
||||
template <>
|
||||
class UniversalTersePrinter<char*> {
|
||||
public:
|
||||
static void Print(char* str, ::std::ostream* os) {
|
||||
UniversalTersePrinter<const char*>::Print(str, os);
|
||||
}
|
||||
};
|
||||
|
||||
#if GTEST_HAS_STD_WSTRING
|
||||
template <>
|
||||
class UniversalTersePrinter<const wchar_t*> {
|
||||
public:
|
||||
static void Print(const wchar_t* str, ::std::ostream* os) {
|
||||
if (str == NULL) {
|
||||
*os << "NULL";
|
||||
} else {
|
||||
UniversalPrint(::std::wstring(str), os);
|
||||
}
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
template <>
|
||||
class UniversalTersePrinter<wchar_t*> {
|
||||
public:
|
||||
static void Print(wchar_t* str, ::std::ostream* os) {
|
||||
UniversalTersePrinter<const wchar_t*>::Print(str, os);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
void UniversalTersePrint(const T& value, ::std::ostream* os) {
|
||||
UniversalPrint(value, os);
|
||||
}
|
||||
inline void UniversalTersePrint(const char* str, ::std::ostream* os) {
|
||||
if (str == NULL) {
|
||||
*os << "NULL";
|
||||
} else {
|
||||
UniversalPrint(string(str), os);
|
||||
}
|
||||
}
|
||||
inline void UniversalTersePrint(char* str, ::std::ostream* os) {
|
||||
UniversalTersePrint(static_cast<const char*>(str), os);
|
||||
UniversalTersePrinter<T>::Print(value, os);
|
||||
}
|
||||
|
||||
// Prints a value using the type inferred by the compiler. The
|
||||
|
|
@ -694,7 +750,10 @@ inline void UniversalTersePrint(char* str, ::std::ostream* os) {
|
|||
// NUL-terminated string.
|
||||
template <typename T>
|
||||
void UniversalPrint(const T& value, ::std::ostream* os) {
|
||||
UniversalPrinter<T>::Print(value, os);
|
||||
// A workarond for the bug in VC++ 7.1 that prevents us from instantiating
|
||||
// UniversalPrinter with T directly.
|
||||
typedef T T1;
|
||||
UniversalPrinter<T1>::Print(value, os);
|
||||
}
|
||||
|
||||
#if GTEST_HAS_TR1_TUPLE
|
||||
|
|
@ -787,7 +846,7 @@ Strings UniversalTersePrintTupleFieldsToStrings(const Tuple& value) {
|
|||
template <typename T>
|
||||
::std::string PrintToString(const T& value) {
|
||||
::std::stringstream ss;
|
||||
internal::UniversalTersePrint(value, &ss);
|
||||
internal::UniversalTersePrinter<T>::Print(value, &ss);
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
|
|
@ -223,7 +223,7 @@ class GTEST_API_ SingleFailureChecker {
|
|||
(substr));\
|
||||
{\
|
||||
::testing::ScopedFakeTestPartResultReporter gtest_reporter(\
|
||||
::testing::ScopedFakeTestPartResultReporter::INTERCEPT_ALL_THREADS,\
|
||||
::testing::ScopedFakeTestPartResultReporter::INTERCEPT_ALL_THREADS, \
|
||||
>est_failures);\
|
||||
if (::testing::internal::AlwaysTrue()) { statement; }\
|
||||
}\
|
||||
|
|
@ -62,7 +62,7 @@ class GTEST_API_ TestPartResult {
|
|||
int a_line_number,
|
||||
const char* a_message)
|
||||
: type_(a_type),
|
||||
file_name_(a_file_name),
|
||||
file_name_(a_file_name == NULL ? "" : a_file_name),
|
||||
line_number_(a_line_number),
|
||||
summary_(ExtractSummary(a_message)),
|
||||
message_(a_message) {
|
||||
|
|
@ -73,7 +73,9 @@ class GTEST_API_ TestPartResult {
|
|||
|
||||
// Gets the name of the source file where the test part took place, or
|
||||
// NULL if it's unknown.
|
||||
const char* file_name() const { return file_name_.c_str(); }
|
||||
const char* file_name() const {
|
||||
return file_name_.empty() ? NULL : file_name_.c_str();
|
||||
}
|
||||
|
||||
// Gets the line in the source file where the test part took place,
|
||||
// or -1 if it's unknown.
|
||||
|
|
@ -96,21 +98,22 @@ class GTEST_API_ TestPartResult {
|
|||
|
||||
// Returns true iff the test part fatally failed.
|
||||
bool fatally_failed() const { return type_ == kFatalFailure; }
|
||||
|
||||
private:
|
||||
Type type_;
|
||||
|
||||
// Gets the summary of the failure message by omitting the stack
|
||||
// trace in it.
|
||||
static internal::String ExtractSummary(const char* message);
|
||||
static std::string ExtractSummary(const char* message);
|
||||
|
||||
// The name of the source file where the test part took place, or
|
||||
// NULL if the source file is unknown.
|
||||
internal::String file_name_;
|
||||
// "" if the source file is unknown.
|
||||
std::string file_name_;
|
||||
// The line in the source file where the test part took place, or -1
|
||||
// if the line number is unknown.
|
||||
int line_number_;
|
||||
internal::String summary_; // The test failure summary.
|
||||
internal::String message_; // The test failure message.
|
||||
std::string summary_; // The test failure summary.
|
||||
std::string message_; // The test failure message.
|
||||
};
|
||||
|
||||
// Prints a TestPartResult object.
|
||||
|
|
@ -52,6 +52,7 @@
|
|||
#define GTEST_INCLUDE_GTEST_GTEST_H_
|
||||
|
||||
#include <limits>
|
||||
#include <ostream>
|
||||
#include <vector>
|
||||
|
||||
#include "gtest/internal/gtest-internal.h"
|
||||
|
|
@ -153,25 +154,15 @@ class ExecDeathTest;
|
|||
class NoExecDeathTest;
|
||||
class FinalSuccessChecker;
|
||||
class GTestFlagSaver;
|
||||
class StreamingListenerTest;
|
||||
class TestResultAccessor;
|
||||
class TestEventListenersAccessor;
|
||||
class TestEventRepeater;
|
||||
class UnitTestRecordPropertyTestHelper;
|
||||
class WindowsDeathTest;
|
||||
class UnitTestImpl* GetUnitTestImpl();
|
||||
void ReportFailureInUnknownLocation(TestPartResult::Type result_type,
|
||||
const String& message);
|
||||
|
||||
// Converts a streamable value to a String. A NULL pointer is
|
||||
// converted to "(null)". When the input value is a ::string,
|
||||
// ::std::string, ::wstring, or ::std::wstring object, each NUL
|
||||
// character in it is replaced with "\\0".
|
||||
// Declared in gtest-internal.h but defined here, so that it has access
|
||||
// to the definition of the Message class, required by the ARM
|
||||
// compiler.
|
||||
template <typename T>
|
||||
String StreamableToString(const T& streamable) {
|
||||
return (Message() << streamable).GetString();
|
||||
}
|
||||
const std::string& message);
|
||||
|
||||
} // namespace internal
|
||||
|
||||
|
|
@ -391,20 +382,21 @@ class GTEST_API_ Test {
|
|||
// non-fatal) failure.
|
||||
static bool HasFailure() { return HasFatalFailure() || HasNonfatalFailure(); }
|
||||
|
||||
// Logs a property for the current test. Only the last value for a given
|
||||
// key is remembered.
|
||||
// These are public static so they can be called from utility functions
|
||||
// that are not members of the test fixture.
|
||||
// The arguments are const char* instead strings, as Google Test is used
|
||||
// on platforms where string doesn't compile.
|
||||
//
|
||||
// Note that a driving consideration for these RecordProperty methods
|
||||
// was to produce xml output suited to the Greenspan charting utility,
|
||||
// which at present will only chart values that fit in a 32-bit int. It
|
||||
// is the user's responsibility to restrict their values to 32-bit ints
|
||||
// if they intend them to be used with Greenspan.
|
||||
static void RecordProperty(const char* key, const char* value);
|
||||
static void RecordProperty(const char* key, int value);
|
||||
// Logs a property for the current test, test case, or for the entire
|
||||
// invocation of the test program when used outside of the context of a
|
||||
// test case. Only the last value for a given key is remembered. These
|
||||
// are public static so they can be called from utility functions that are
|
||||
// not members of the test fixture. Calls to RecordProperty made during
|
||||
// lifespan of the test (from the moment its constructor starts to the
|
||||
// moment its destructor finishes) will be output in XML as attributes of
|
||||
// the <testcase> element. Properties recorded from fixture's
|
||||
// SetUpTestCase or TearDownTestCase are logged as attributes of the
|
||||
// corresponding <testsuite> element. Calls to RecordProperty made in the
|
||||
// global context (before or after invocation of RUN_ALL_TESTS and from
|
||||
// SetUp/TearDown method of Environment objects registered with Google
|
||||
// Test) will be output as attributes of the <testsuites> element.
|
||||
static void RecordProperty(const std::string& key, const std::string& value);
|
||||
static void RecordProperty(const std::string& key, int value);
|
||||
|
||||
protected:
|
||||
// Creates a Test object.
|
||||
|
|
@ -473,7 +465,7 @@ class TestProperty {
|
|||
// C'tor. TestProperty does NOT have a default constructor.
|
||||
// Always use this constructor (with parameters) to create a
|
||||
// TestProperty object.
|
||||
TestProperty(const char* a_key, const char* a_value) :
|
||||
TestProperty(const std::string& a_key, const std::string& a_value) :
|
||||
key_(a_key), value_(a_value) {
|
||||
}
|
||||
|
||||
|
|
@ -488,15 +480,15 @@ class TestProperty {
|
|||
}
|
||||
|
||||
// Sets a new value, overriding the one supplied in the constructor.
|
||||
void SetValue(const char* new_value) {
|
||||
void SetValue(const std::string& new_value) {
|
||||
value_ = new_value;
|
||||
}
|
||||
|
||||
private:
|
||||
// The key supplied by the user.
|
||||
internal::String key_;
|
||||
std::string key_;
|
||||
// The value supplied by the user.
|
||||
internal::String value_;
|
||||
std::string value_;
|
||||
};
|
||||
|
||||
// The result of a single Test. This includes a list of
|
||||
|
|
@ -547,6 +539,7 @@ class GTEST_API_ TestResult {
|
|||
|
||||
private:
|
||||
friend class TestInfo;
|
||||
friend class TestCase;
|
||||
friend class UnitTest;
|
||||
friend class internal::DefaultGlobalTestPartResultReporter;
|
||||
friend class internal::ExecDeathTest;
|
||||
|
|
@ -571,13 +564,16 @@ class GTEST_API_ TestResult {
|
|||
// a non-fatal failure if invalid (e.g., if it conflicts with reserved
|
||||
// key names). If a property is already recorded for the same key, the
|
||||
// value will be updated, rather than storing multiple values for the same
|
||||
// key.
|
||||
void RecordProperty(const TestProperty& test_property);
|
||||
// key. xml_element specifies the element for which the property is being
|
||||
// recorded and is used for validation.
|
||||
void RecordProperty(const std::string& xml_element,
|
||||
const TestProperty& test_property);
|
||||
|
||||
// Adds a failure if the key is a reserved attribute of Google Test
|
||||
// testcase tags. Returns true if the property is valid.
|
||||
// TODO(russr): Validate attribute names are legal and human readable.
|
||||
static bool ValidateTestProperty(const TestProperty& test_property);
|
||||
static bool ValidateTestProperty(const std::string& xml_element,
|
||||
const TestProperty& test_property);
|
||||
|
||||
// Adds a test part result to the list.
|
||||
void AddTestPartResult(const TestPartResult& test_part_result);
|
||||
|
|
@ -650,9 +646,9 @@ class GTEST_API_ TestInfo {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
// Returns true if this test should run, that is if the test is not disabled
|
||||
// (or it is disabled but the also_run_disabled_tests flag has been specified)
|
||||
// and its full name matches the user-specified filter.
|
||||
// Returns true if this test should run, that is if the test is not
|
||||
// disabled (or it is disabled but the also_run_disabled_tests flag has
|
||||
// been specified) and its full name matches the user-specified filter.
|
||||
//
|
||||
// Google Test allows the user to filter the tests by their full names.
|
||||
// The full name of a test Bar in test case Foo is defined as
|
||||
|
|
@ -668,19 +664,28 @@ class GTEST_API_ TestInfo {
|
|||
// contains the character 'A' or starts with "Foo.".
|
||||
bool should_run() const { return should_run_; }
|
||||
|
||||
// Returns true iff this test will appear in the XML report.
|
||||
bool is_reportable() const {
|
||||
// For now, the XML report includes all tests matching the filter.
|
||||
// In the future, we may trim tests that are excluded because of
|
||||
// sharding.
|
||||
return matches_filter_;
|
||||
}
|
||||
|
||||
// Returns the result of the test.
|
||||
const TestResult* result() const { return &result_; }
|
||||
|
||||
private:
|
||||
|
||||
#if GTEST_HAS_DEATH_TEST
|
||||
friend class internal::DefaultDeathTestFactory;
|
||||
#endif // GTEST_HAS_DEATH_TEST
|
||||
friend class Test;
|
||||
friend class TestCase;
|
||||
friend class internal::UnitTestImpl;
|
||||
friend class internal::StreamingListenerTest;
|
||||
friend TestInfo* internal::MakeAndRegisterTestInfo(
|
||||
const char* test_case_name, const char* name,
|
||||
const char* test_case_name,
|
||||
const char* name,
|
||||
const char* type_param,
|
||||
const char* value_param,
|
||||
internal::TypeId fixture_class_id,
|
||||
|
|
@ -690,9 +695,10 @@ class GTEST_API_ TestInfo {
|
|||
|
||||
// Constructs a TestInfo object. The newly constructed instance assumes
|
||||
// ownership of the factory object.
|
||||
TestInfo(const char* test_case_name, const char* name,
|
||||
const char* a_type_param,
|
||||
const char* a_value_param,
|
||||
TestInfo(const std::string& test_case_name,
|
||||
const std::string& name,
|
||||
const char* a_type_param, // NULL if not a type-parameterized test
|
||||
const char* a_value_param, // NULL if not a value-parameterized test
|
||||
internal::TypeId fixture_class_id,
|
||||
internal::TestFactoryBase* factory);
|
||||
|
||||
|
|
@ -778,9 +784,15 @@ class GTEST_API_ TestCase {
|
|||
// Gets the number of failed tests in this test case.
|
||||
int failed_test_count() const;
|
||||
|
||||
// Gets the number of disabled tests that will be reported in the XML report.
|
||||
int reportable_disabled_test_count() const;
|
||||
|
||||
// Gets the number of disabled tests in this test case.
|
||||
int disabled_test_count() const;
|
||||
|
||||
// Gets the number of tests to be printed in the XML report.
|
||||
int reportable_test_count() const;
|
||||
|
||||
// Get the number of tests in this test case that should run.
|
||||
int test_to_run_count() const;
|
||||
|
||||
|
|
@ -800,6 +812,10 @@ class GTEST_API_ TestCase {
|
|||
// total_test_count() - 1. If i is not in that range, returns NULL.
|
||||
const TestInfo* GetTestInfo(int i) const;
|
||||
|
||||
// Returns the TestResult that holds test properties recorded during
|
||||
// execution of SetUpTestCase and TearDownTestCase.
|
||||
const TestResult& ad_hoc_test_result() const { return ad_hoc_test_result_; }
|
||||
|
||||
private:
|
||||
friend class Test;
|
||||
friend class internal::UnitTestImpl;
|
||||
|
|
@ -852,11 +868,22 @@ class GTEST_API_ TestCase {
|
|||
return test_info->should_run() && test_info->result()->Failed();
|
||||
}
|
||||
|
||||
// Returns true iff the test is disabled and will be reported in the XML
|
||||
// report.
|
||||
static bool TestReportableDisabled(const TestInfo* test_info) {
|
||||
return test_info->is_reportable() && test_info->is_disabled_;
|
||||
}
|
||||
|
||||
// Returns true iff test is disabled.
|
||||
static bool TestDisabled(const TestInfo* test_info) {
|
||||
return test_info->is_disabled_;
|
||||
}
|
||||
|
||||
// Returns true iff this test will appear in the XML report.
|
||||
static bool TestReportable(const TestInfo* test_info) {
|
||||
return test_info->is_reportable();
|
||||
}
|
||||
|
||||
// Returns true if the given test should run.
|
||||
static bool ShouldRunTest(const TestInfo* test_info) {
|
||||
return test_info->should_run();
|
||||
|
|
@ -869,7 +896,7 @@ class GTEST_API_ TestCase {
|
|||
void UnshuffleTests();
|
||||
|
||||
// Name of the test case.
|
||||
internal::String name_;
|
||||
std::string name_;
|
||||
// Name of the parameter type, or NULL if this is not a typed or a
|
||||
// type-parameterized test.
|
||||
const internal::scoped_ptr<const ::std::string> type_param_;
|
||||
|
|
@ -888,6 +915,9 @@ class GTEST_API_ TestCase {
|
|||
bool should_run_;
|
||||
// Elapsed time, in milliseconds.
|
||||
TimeInMillis elapsed_time_;
|
||||
// Holds test properties recorded during execution of SetUpTestCase and
|
||||
// TearDownTestCase.
|
||||
TestResult ad_hoc_test_result_;
|
||||
|
||||
// We disallow copying TestCases.
|
||||
GTEST_DISALLOW_COPY_AND_ASSIGN_(TestCase);
|
||||
|
|
@ -1107,11 +1137,13 @@ class GTEST_API_ UnitTest {
|
|||
|
||||
// Returns the TestCase object for the test that's currently running,
|
||||
// or NULL if no test is running.
|
||||
const TestCase* current_test_case() const;
|
||||
const TestCase* current_test_case() const
|
||||
GTEST_LOCK_EXCLUDED_(mutex_);
|
||||
|
||||
// Returns the TestInfo object for the test that's currently running,
|
||||
// or NULL if no test is running.
|
||||
const TestInfo* current_test_info() const;
|
||||
const TestInfo* current_test_info() const
|
||||
GTEST_LOCK_EXCLUDED_(mutex_);
|
||||
|
||||
// Returns the random seed used at the start of the current test run.
|
||||
int random_seed() const;
|
||||
|
|
@ -1121,7 +1153,8 @@ class GTEST_API_ UnitTest {
|
|||
// value-parameterized tests and instantiate and register them.
|
||||
//
|
||||
// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
|
||||
internal::ParameterizedTestCaseRegistry& parameterized_test_registry();
|
||||
internal::ParameterizedTestCaseRegistry& parameterized_test_registry()
|
||||
GTEST_LOCK_EXCLUDED_(mutex_);
|
||||
#endif // GTEST_HAS_PARAM_TEST
|
||||
|
||||
// Gets the number of successful test cases.
|
||||
|
|
@ -1143,15 +1176,25 @@ class GTEST_API_ UnitTest {
|
|||
// Gets the number of failed tests.
|
||||
int failed_test_count() const;
|
||||
|
||||
// Gets the number of disabled tests that will be reported in the XML report.
|
||||
int reportable_disabled_test_count() const;
|
||||
|
||||
// Gets the number of disabled tests.
|
||||
int disabled_test_count() const;
|
||||
|
||||
// Gets the number of tests to be printed in the XML report.
|
||||
int reportable_test_count() const;
|
||||
|
||||
// Gets the number of all tests.
|
||||
int total_test_count() const;
|
||||
|
||||
// Gets the number of tests that should run.
|
||||
int test_to_run_count() const;
|
||||
|
||||
// Gets the time of the test program start, in ms from the start of the
|
||||
// UNIX epoch.
|
||||
TimeInMillis start_timestamp() const;
|
||||
|
||||
// Gets the elapsed time, in milliseconds.
|
||||
TimeInMillis elapsed_time() const;
|
||||
|
||||
|
|
@ -1166,6 +1209,10 @@ class GTEST_API_ UnitTest {
|
|||
// total_test_case_count() - 1. If i is not in that range, returns NULL.
|
||||
const TestCase* GetTestCase(int i) const;
|
||||
|
||||
// Returns the TestResult containing information on test failures and
|
||||
// properties logged outside of individual test cases.
|
||||
const TestResult& ad_hoc_test_result() const;
|
||||
|
||||
// Returns the list of event listeners that can be used to track events
|
||||
// inside Google Test.
|
||||
TestEventListeners& listeners();
|
||||
|
|
@ -1189,12 +1236,16 @@ class GTEST_API_ UnitTest {
|
|||
void AddTestPartResult(TestPartResult::Type result_type,
|
||||
const char* file_name,
|
||||
int line_number,
|
||||
const internal::String& message,
|
||||
const internal::String& os_stack_trace);
|
||||
const std::string& message,
|
||||
const std::string& os_stack_trace)
|
||||
GTEST_LOCK_EXCLUDED_(mutex_);
|
||||
|
||||
// Adds a TestProperty to the current TestResult object. If the result already
|
||||
// contains a property with the same key, the value will be updated.
|
||||
void RecordPropertyForCurrentTest(const char* key, const char* value);
|
||||
// Adds a TestProperty to the current TestResult object when invoked from
|
||||
// inside a test, to current TestCase's ad_hoc_test_result_ when invoked
|
||||
// from SetUpTestCase or TearDownTestCase, or to the global property set
|
||||
// when invoked elsewhere. If the result already contains a property with
|
||||
// the same key, the value will be updated.
|
||||
void RecordProperty(const std::string& key, const std::string& value);
|
||||
|
||||
// Gets the i-th test case among all the test cases. i can range from 0 to
|
||||
// total_test_case_count() - 1. If i is not in that range, returns NULL.
|
||||
|
|
@ -1209,11 +1260,13 @@ class GTEST_API_ UnitTest {
|
|||
friend class Test;
|
||||
friend class internal::AssertHelper;
|
||||
friend class internal::ScopedTrace;
|
||||
friend class internal::StreamingListenerTest;
|
||||
friend class internal::UnitTestRecordPropertyTestHelper;
|
||||
friend Environment* AddGlobalTestEnvironment(Environment* env);
|
||||
friend internal::UnitTestImpl* internal::GetUnitTestImpl();
|
||||
friend void internal::ReportFailureInUnknownLocation(
|
||||
TestPartResult::Type result_type,
|
||||
const internal::String& message);
|
||||
const std::string& message);
|
||||
|
||||
// Creates an empty UnitTest.
|
||||
UnitTest();
|
||||
|
|
@ -1223,10 +1276,12 @@ class GTEST_API_ UnitTest {
|
|||
|
||||
// Pushes a trace defined by SCOPED_TRACE() on to the per-thread
|
||||
// Google Test trace stack.
|
||||
void PushGTestTrace(const internal::TraceInfo& trace);
|
||||
void PushGTestTrace(const internal::TraceInfo& trace)
|
||||
GTEST_LOCK_EXCLUDED_(mutex_);
|
||||
|
||||
// Pops a trace from the per-thread Google Test trace stack.
|
||||
void PopGTestTrace();
|
||||
void PopGTestTrace()
|
||||
GTEST_LOCK_EXCLUDED_(mutex_);
|
||||
|
||||
// Protects mutable state in *impl_. This is mutable as some const
|
||||
// methods need to lock it too.
|
||||
|
|
@ -1281,24 +1336,101 @@ GTEST_API_ void InitGoogleTest(int* argc, wchar_t** argv);
|
|||
|
||||
namespace internal {
|
||||
|
||||
// FormatForComparison<ToPrint, OtherOperand>::Format(value) formats a
|
||||
// value of type ToPrint that is an operand of a comparison assertion
|
||||
// (e.g. ASSERT_EQ). OtherOperand is the type of the other operand in
|
||||
// the comparison, and is used to help determine the best way to
|
||||
// format the value. In particular, when the value is a C string
|
||||
// (char pointer) and the other operand is an STL string object, we
|
||||
// want to format the C string as a string, since we know it is
|
||||
// compared by value with the string object. If the value is a char
|
||||
// pointer but the other operand is not an STL string object, we don't
|
||||
// know whether the pointer is supposed to point to a NUL-terminated
|
||||
// string, and thus want to print it as a pointer to be safe.
|
||||
//
|
||||
// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
|
||||
|
||||
// The default case.
|
||||
template <typename ToPrint, typename OtherOperand>
|
||||
class FormatForComparison {
|
||||
public:
|
||||
static ::std::string Format(const ToPrint& value) {
|
||||
return ::testing::PrintToString(value);
|
||||
}
|
||||
};
|
||||
|
||||
// Array.
|
||||
template <typename ToPrint, size_t N, typename OtherOperand>
|
||||
class FormatForComparison<ToPrint[N], OtherOperand> {
|
||||
public:
|
||||
static ::std::string Format(const ToPrint* value) {
|
||||
return FormatForComparison<const ToPrint*, OtherOperand>::Format(value);
|
||||
}
|
||||
};
|
||||
|
||||
// By default, print C string as pointers to be safe, as we don't know
|
||||
// whether they actually point to a NUL-terminated string.
|
||||
|
||||
#define GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(CharType) \
|
||||
template <typename OtherOperand> \
|
||||
class FormatForComparison<CharType*, OtherOperand> { \
|
||||
public: \
|
||||
static ::std::string Format(CharType* value) { \
|
||||
return ::testing::PrintToString(static_cast<const void*>(value)); \
|
||||
} \
|
||||
}
|
||||
|
||||
GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(char);
|
||||
GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const char);
|
||||
GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(wchar_t);
|
||||
GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const wchar_t);
|
||||
|
||||
#undef GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_
|
||||
|
||||
// If a C string is compared with an STL string object, we know it's meant
|
||||
// to point to a NUL-terminated string, and thus can print it as a string.
|
||||
|
||||
#define GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(CharType, OtherStringType) \
|
||||
template <> \
|
||||
class FormatForComparison<CharType*, OtherStringType> { \
|
||||
public: \
|
||||
static ::std::string Format(CharType* value) { \
|
||||
return ::testing::PrintToString(value); \
|
||||
} \
|
||||
}
|
||||
|
||||
GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(char, ::std::string);
|
||||
GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const char, ::std::string);
|
||||
|
||||
#if GTEST_HAS_GLOBAL_STRING
|
||||
GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(char, ::string);
|
||||
GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const char, ::string);
|
||||
#endif
|
||||
|
||||
#if GTEST_HAS_GLOBAL_WSTRING
|
||||
GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(wchar_t, ::wstring);
|
||||
GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const wchar_t, ::wstring);
|
||||
#endif
|
||||
|
||||
#if GTEST_HAS_STD_WSTRING
|
||||
GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(wchar_t, ::std::wstring);
|
||||
GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const wchar_t, ::std::wstring);
|
||||
#endif
|
||||
|
||||
#undef GTEST_IMPL_FORMAT_C_STRING_AS_STRING_
|
||||
|
||||
// Formats a comparison assertion (e.g. ASSERT_EQ, EXPECT_LT, and etc)
|
||||
// operand to be used in a failure message. The type (but not value)
|
||||
// of the other operand may affect the format. This allows us to
|
||||
// print a char* as a raw pointer when it is compared against another
|
||||
// char*, and print it as a C string when it is compared against an
|
||||
// std::string object, for example.
|
||||
//
|
||||
// The default implementation ignores the type of the other operand.
|
||||
// Some specialized versions are used to handle formatting wide or
|
||||
// narrow C strings.
|
||||
// char* or void*, and print it as a C string when it is compared
|
||||
// against an std::string object, for example.
|
||||
//
|
||||
// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
|
||||
template <typename T1, typename T2>
|
||||
String FormatForComparisonFailureMessage(const T1& value,
|
||||
const T2& /* other_operand */) {
|
||||
// C++Builder compiles this incorrectly if the namespace isn't explicitly
|
||||
// given.
|
||||
return ::testing::PrintToString(value);
|
||||
std::string FormatForComparisonFailureMessage(
|
||||
const T1& value, const T2& /* other_operand */) {
|
||||
return FormatForComparison<T1, T2>::Format(value);
|
||||
}
|
||||
|
||||
// The helper function for {ASSERT|EXPECT}_EQ.
|
||||
|
|
@ -1310,7 +1442,7 @@ AssertionResult CmpHelperEQ(const char* expected_expression,
|
|||
#ifdef _MSC_VER
|
||||
# pragma warning(push) // Saves the current warning state.
|
||||
# pragma warning(disable:4389) // Temporarily disables warning on
|
||||
// signed/unsigned mismatch.
|
||||
// signed/unsigned mismatch.
|
||||
#endif
|
||||
|
||||
if (expected == actual) {
|
||||
|
|
@ -1446,11 +1578,11 @@ GTEST_IMPL_CMP_HELPER_(NE, !=);
|
|||
// Implements the helper function for {ASSERT|EXPECT}_LE
|
||||
GTEST_IMPL_CMP_HELPER_(LE, <=);
|
||||
// Implements the helper function for {ASSERT|EXPECT}_LT
|
||||
GTEST_IMPL_CMP_HELPER_(LT, < );
|
||||
GTEST_IMPL_CMP_HELPER_(LT, <);
|
||||
// Implements the helper function for {ASSERT|EXPECT}_GE
|
||||
GTEST_IMPL_CMP_HELPER_(GE, >=);
|
||||
// Implements the helper function for {ASSERT|EXPECT}_GT
|
||||
GTEST_IMPL_CMP_HELPER_(GT, > );
|
||||
GTEST_IMPL_CMP_HELPER_(GT, >);
|
||||
|
||||
#undef GTEST_IMPL_CMP_HELPER_
|
||||
|
||||
|
|
@ -1614,9 +1746,9 @@ class GTEST_API_ AssertHelper {
|
|||
: type(t), file(srcfile), line(line_num), message(msg) { }
|
||||
|
||||
TestPartResult::Type const type;
|
||||
const char* const file;
|
||||
int const line;
|
||||
String const message;
|
||||
const char* const file;
|
||||
int const line;
|
||||
std::string const message;
|
||||
|
||||
private:
|
||||
GTEST_DISALLOW_COPY_AND_ASSIGN_(AssertHelperData);
|
||||
|
|
@ -1675,7 +1807,12 @@ class WithParamInterface {
|
|||
// references static data, to reduce the opportunity for incorrect uses
|
||||
// like writing 'WithParamInterface<bool>::GetParam()' for a test that
|
||||
// uses a fixture whose parameter type is int.
|
||||
const ParamType& GetParam() const { return *parameter_; }
|
||||
const ParamType& GetParam() const {
|
||||
GTEST_CHECK_(parameter_ != NULL)
|
||||
<< "GetParam() can only be called inside a value-parameterized test "
|
||||
<< "-- did you intend to write TEST_P instead of TEST_F?";
|
||||
return *parameter_;
|
||||
}
|
||||
|
||||
private:
|
||||
// Sets parameter value. The caller is responsible for making sure the value
|
||||
|
|
@ -1721,12 +1858,6 @@ class TestWithParam : public Test, public WithParamInterface<T> {
|
|||
// usually want the fail-fast behavior of FAIL and ASSERT_*, but those
|
||||
// writing data-driven tests often find themselves using ADD_FAILURE
|
||||
// and EXPECT_* more.
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// EXPECT_TRUE(server.StatusIsOK());
|
||||
// ASSERT_FALSE(server.HasPendingRequest(port))
|
||||
// << "There are still pending requests " << "on port " << port;
|
||||
|
||||
// Generates a nonfatal failure with a generic message.
|
||||
#define ADD_FAILURE() GTEST_NONFATAL_FAILURE_("Failed")
|
||||
|
|
@ -1900,7 +2031,7 @@ class TestWithParam : public Test, public WithParamInterface<T> {
|
|||
# define ASSERT_GT(val1, val2) GTEST_ASSERT_GT(val1, val2)
|
||||
#endif
|
||||
|
||||
// C String Comparisons. All tests treat NULL and any non-NULL string
|
||||
// C-string Comparisons. All tests treat NULL and any non-NULL string
|
||||
// as different. Two NULLs are equal.
|
||||
//
|
||||
// * {ASSERT|EXPECT}_STREQ(s1, s2): Tests that s1 == s2
|
||||
|
|
@ -2141,15 +2272,20 @@ bool StaticAssertTypeEq() {
|
|||
GTEST_TEST_(test_fixture, test_name, test_fixture, \
|
||||
::testing::internal::GetTypeId<test_fixture>())
|
||||
|
||||
// Use this macro in main() to run all tests. It returns 0 if all
|
||||
} // namespace testing
|
||||
|
||||
// Use this function in main() to run all tests. It returns 0 if all
|
||||
// tests are successful, or 1 otherwise.
|
||||
//
|
||||
// RUN_ALL_TESTS() should be invoked after the command line has been
|
||||
// parsed by InitGoogleTest().
|
||||
//
|
||||
// This function was formerly a macro; thus, it is in the global
|
||||
// namespace and has an all-caps name.
|
||||
int RUN_ALL_TESTS() GTEST_MUST_USE_RESULT_;
|
||||
|
||||
#define RUN_ALL_TESTS()\
|
||||
(::testing::UnitTest::GetInstance()->Run())
|
||||
|
||||
} // namespace testing
|
||||
inline int RUN_ALL_TESTS() {
|
||||
return ::testing::UnitTest::GetInstance()->Run();
|
||||
}
|
||||
|
||||
#endif // GTEST_INCLUDE_GTEST_GTEST_H_
|
||||
|
|
@ -27,7 +27,7 @@
|
|||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// This file is AUTOMATICALLY GENERATED on 09/24/2010 by command
|
||||
// This file is AUTOMATICALLY GENERATED on 10/31/2011 by command
|
||||
// 'gen_gtest_pred_impl.py 5'. DO NOT EDIT BY HAND!
|
||||
//
|
||||
// Implements a family of generic predicate assertion macros.
|
||||
|
|
@ -98,7 +98,7 @@ AssertionResult AssertPred1Helper(const char* pred_text,
|
|||
// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT1.
|
||||
// Don't use this in your code.
|
||||
#define GTEST_PRED_FORMAT1_(pred_format, v1, on_failure)\
|
||||
GTEST_ASSERT_(pred_format(#v1, v1),\
|
||||
GTEST_ASSERT_(pred_format(#v1, v1), \
|
||||
on_failure)
|
||||
|
||||
// Internal macro for implementing {EXPECT|ASSERT}_PRED1. Don't use
|
||||
|
|
@ -144,7 +144,7 @@ AssertionResult AssertPred2Helper(const char* pred_text,
|
|||
// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT2.
|
||||
// Don't use this in your code.
|
||||
#define GTEST_PRED_FORMAT2_(pred_format, v1, v2, on_failure)\
|
||||
GTEST_ASSERT_(pred_format(#v1, #v2, v1, v2),\
|
||||
GTEST_ASSERT_(pred_format(#v1, #v2, v1, v2), \
|
||||
on_failure)
|
||||
|
||||
// Internal macro for implementing {EXPECT|ASSERT}_PRED2. Don't use
|
||||
|
|
@ -197,7 +197,7 @@ AssertionResult AssertPred3Helper(const char* pred_text,
|
|||
// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT3.
|
||||
// Don't use this in your code.
|
||||
#define GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, on_failure)\
|
||||
GTEST_ASSERT_(pred_format(#v1, #v2, #v3, v1, v2, v3),\
|
||||
GTEST_ASSERT_(pred_format(#v1, #v2, #v3, v1, v2, v3), \
|
||||
on_failure)
|
||||
|
||||
// Internal macro for implementing {EXPECT|ASSERT}_PRED3. Don't use
|
||||
|
|
@ -257,7 +257,7 @@ AssertionResult AssertPred4Helper(const char* pred_text,
|
|||
// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT4.
|
||||
// Don't use this in your code.
|
||||
#define GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, on_failure)\
|
||||
GTEST_ASSERT_(pred_format(#v1, #v2, #v3, #v4, v1, v2, v3, v4),\
|
||||
GTEST_ASSERT_(pred_format(#v1, #v2, #v3, #v4, v1, v2, v3, v4), \
|
||||
on_failure)
|
||||
|
||||
// Internal macro for implementing {EXPECT|ASSERT}_PRED4. Don't use
|
||||
|
|
@ -324,7 +324,7 @@ AssertionResult AssertPred5Helper(const char* pred_text,
|
|||
// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT5.
|
||||
// Don't use this in your code.
|
||||
#define GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, on_failure)\
|
||||
GTEST_ASSERT_(pred_format(#v1, #v2, #v3, #v4, #v5, v1, v2, v3, v4, v5),\
|
||||
GTEST_ASSERT_(pred_format(#v1, #v2, #v3, #v4, #v5, v1, v2, v3, v4, v5), \
|
||||
on_failure)
|
||||
|
||||
// Internal macro for implementing {EXPECT|ASSERT}_PRED5. Don't use
|
||||
|
|
@ -127,11 +127,11 @@ class GTEST_API_ DeathTest {
|
|||
// the last death test.
|
||||
static const char* LastMessage();
|
||||
|
||||
static void set_last_death_test_message(const String& message);
|
||||
static void set_last_death_test_message(const std::string& message);
|
||||
|
||||
private:
|
||||
// A string containing a description of the outcome of the last death test.
|
||||
static String last_death_test_message_;
|
||||
static std::string last_death_test_message_;
|
||||
|
||||
GTEST_DISALLOW_COPY_AND_ASSIGN_(DeathTest);
|
||||
};
|
||||
|
|
@ -217,12 +217,23 @@ GTEST_API_ bool ExitedUnsuccessfully(int exit_status);
|
|||
// The symbol "fail" here expands to something into which a message
|
||||
// can be streamed.
|
||||
|
||||
// This macro is for implementing ASSERT/EXPECT_DEBUG_DEATH when compiled in
|
||||
// NDEBUG mode. In this case we need the statements to be executed, the regex is
|
||||
// ignored, and the macro must accept a streamed message even though the message
|
||||
// is never printed.
|
||||
# define GTEST_EXECUTE_STATEMENT_(statement, regex) \
|
||||
GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
|
||||
if (::testing::internal::AlwaysTrue()) { \
|
||||
GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
|
||||
} else \
|
||||
::testing::Message()
|
||||
|
||||
// A class representing the parsed contents of the
|
||||
// --gtest_internal_run_death_test flag, as it existed when
|
||||
// RUN_ALL_TESTS was called.
|
||||
class InternalRunDeathTestFlag {
|
||||
public:
|
||||
InternalRunDeathTestFlag(const String& a_file,
|
||||
InternalRunDeathTestFlag(const std::string& a_file,
|
||||
int a_line,
|
||||
int an_index,
|
||||
int a_write_fd)
|
||||
|
|
@ -234,13 +245,13 @@ class InternalRunDeathTestFlag {
|
|||
posix::Close(write_fd_);
|
||||
}
|
||||
|
||||
String file() const { return file_; }
|
||||
const std::string& file() const { return file_; }
|
||||
int line() const { return line_; }
|
||||
int index() const { return index_; }
|
||||
int write_fd() const { return write_fd_; }
|
||||
|
||||
private:
|
||||
String file_;
|
||||
std::string file_;
|
||||
int line_;
|
||||
int index_;
|
||||
int write_fd_;
|
||||
|
|
@ -61,11 +61,7 @@ class GTEST_API_ FilePath {
|
|||
FilePath() : pathname_("") { }
|
||||
FilePath(const FilePath& rhs) : pathname_(rhs.pathname_) { }
|
||||
|
||||
explicit FilePath(const char* pathname) : pathname_(pathname) {
|
||||
Normalize();
|
||||
}
|
||||
|
||||
explicit FilePath(const String& pathname) : pathname_(pathname) {
|
||||
explicit FilePath(const std::string& pathname) : pathname_(pathname) {
|
||||
Normalize();
|
||||
}
|
||||
|
||||
|
|
@ -78,7 +74,7 @@ class GTEST_API_ FilePath {
|
|||
pathname_ = rhs.pathname_;
|
||||
}
|
||||
|
||||
String ToString() const { return pathname_; }
|
||||
const std::string& string() const { return pathname_; }
|
||||
const char* c_str() const { return pathname_.c_str(); }
|
||||
|
||||
// Returns the current working directory, or "" if unsuccessful.
|
||||
|
|
@ -111,8 +107,8 @@ class GTEST_API_ FilePath {
|
|||
const FilePath& base_name,
|
||||
const char* extension);
|
||||
|
||||
// Returns true iff the path is NULL or "".
|
||||
bool IsEmpty() const { return c_str() == NULL || *c_str() == '\0'; }
|
||||
// Returns true iff the path is "".
|
||||
bool IsEmpty() const { return pathname_.empty(); }
|
||||
|
||||
// If input name has a trailing separator character, removes it and returns
|
||||
// the name, otherwise return the name string unmodified.
|
||||
|
|
@ -201,7 +197,7 @@ class GTEST_API_ FilePath {
|
|||
// separators. Returns NULL if no path separator was found.
|
||||
const char* FindLastPathSeparator() const;
|
||||
|
||||
String pathname_;
|
||||
std::string pathname_;
|
||||
}; // class FilePath
|
||||
|
||||
} // namespace internal
|
||||
|
|
@ -46,12 +46,18 @@
|
|||
# include <unistd.h>
|
||||
#endif // GTEST_OS_LINUX
|
||||
|
||||
#if GTEST_HAS_EXCEPTIONS
|
||||
# include <stdexcept>
|
||||
#endif
|
||||
|
||||
#include <ctype.h>
|
||||
#include <float.h>
|
||||
#include <string.h>
|
||||
#include <iomanip>
|
||||
#include <limits>
|
||||
#include <set>
|
||||
|
||||
#include "gtest/gtest-message.h"
|
||||
#include "gtest/internal/gtest-string.h"
|
||||
#include "gtest/internal/gtest-filepath.h"
|
||||
#include "gtest/internal/gtest-type-util.h"
|
||||
|
|
@ -67,36 +73,6 @@
|
|||
#define GTEST_CONCAT_TOKEN_(foo, bar) GTEST_CONCAT_TOKEN_IMPL_(foo, bar)
|
||||
#define GTEST_CONCAT_TOKEN_IMPL_(foo, bar) foo ## bar
|
||||
|
||||
// Google Test defines the testing::Message class to allow construction of
|
||||
// test messages via the << operator. The idea is that anything
|
||||
// streamable to std::ostream can be streamed to a testing::Message.
|
||||
// This allows a user to use his own types in Google Test assertions by
|
||||
// overloading the << operator.
|
||||
//
|
||||
// util/gtl/stl_logging-inl.h overloads << for STL containers. These
|
||||
// overloads cannot be defined in the std namespace, as that will be
|
||||
// undefined behavior. Therefore, they are defined in the global
|
||||
// namespace instead.
|
||||
//
|
||||
// C++'s symbol lookup rule (i.e. Koenig lookup) says that these
|
||||
// overloads are visible in either the std namespace or the global
|
||||
// namespace, but not other namespaces, including the testing
|
||||
// namespace which Google Test's Message class is in.
|
||||
//
|
||||
// To allow STL containers (and other types that has a << operator
|
||||
// defined in the global namespace) to be used in Google Test assertions,
|
||||
// testing::Message must access the custom << operator from the global
|
||||
// namespace. Hence this helper function.
|
||||
//
|
||||
// Note: Jeffrey Yasskin suggested an alternative fix by "using
|
||||
// ::operator<<;" in the definition of Message's operator<<. That fix
|
||||
// doesn't require a helper function, but unfortunately doesn't
|
||||
// compile with MSVC.
|
||||
template <typename T>
|
||||
inline void GTestStreamToHelper(std::ostream* os, const T& val) {
|
||||
*os << val;
|
||||
}
|
||||
|
||||
class ProtocolMessage;
|
||||
namespace proto2 { class Message; }
|
||||
|
||||
|
|
@ -122,17 +98,12 @@ class TestInfoImpl; // Opaque implementation of TestInfo
|
|||
class UnitTestImpl; // Opaque implementation of UnitTest
|
||||
|
||||
// How many times InitGoogleTest() has been called.
|
||||
extern int g_init_gtest_count;
|
||||
GTEST_API_ extern int g_init_gtest_count;
|
||||
|
||||
// The text used in failure messages to indicate the start of the
|
||||
// stack trace.
|
||||
GTEST_API_ extern const char kStackTraceMarker[];
|
||||
|
||||
// A secret type that Google Test users don't know about. It has no
|
||||
// definition on purpose. Therefore it's impossible to create a
|
||||
// Secret object, which is what we want.
|
||||
class Secret;
|
||||
|
||||
// Two overloaded helpers for checking at compile time whether an
|
||||
// expression is a null pointer literal (i.e. NULL or any 0-valued
|
||||
// compile-time integral constant). Their return values have
|
||||
|
|
@ -163,8 +134,23 @@ char (&IsNullLiteralHelper(...))[2]; // NOLINT
|
|||
#endif // GTEST_ELLIPSIS_NEEDS_POD_
|
||||
|
||||
// Appends the user-supplied message to the Google-Test-generated message.
|
||||
GTEST_API_ String AppendUserMessage(const String& gtest_msg,
|
||||
const Message& user_msg);
|
||||
GTEST_API_ std::string AppendUserMessage(
|
||||
const std::string& gtest_msg, const Message& user_msg);
|
||||
|
||||
#if GTEST_HAS_EXCEPTIONS
|
||||
|
||||
// This exception is thrown by (and only by) a failed Google Test
|
||||
// assertion when GTEST_FLAG(throw_on_failure) is true (if exceptions
|
||||
// are enabled). We derive it from std::runtime_error, which is for
|
||||
// errors presumably detectable only at run time. Since
|
||||
// std::runtime_error inherits from std::exception, many testing
|
||||
// frameworks know how to extract and print the message inside it.
|
||||
class GTEST_API_ GoogleTestFailureException : public ::std::runtime_error {
|
||||
public:
|
||||
explicit GoogleTestFailureException(const TestPartResult& failure);
|
||||
};
|
||||
|
||||
#endif // GTEST_HAS_EXCEPTIONS
|
||||
|
||||
// A helper class for creating scoped traces in user programs.
|
||||
class GTEST_API_ ScopedTrace {
|
||||
|
|
@ -185,77 +171,6 @@ class GTEST_API_ ScopedTrace {
|
|||
// c'tor and d'tor. Therefore it doesn't
|
||||
// need to be used otherwise.
|
||||
|
||||
// Converts a streamable value to a String. A NULL pointer is
|
||||
// converted to "(null)". When the input value is a ::string,
|
||||
// ::std::string, ::wstring, or ::std::wstring object, each NUL
|
||||
// character in it is replaced with "\\0".
|
||||
// Declared here but defined in gtest.h, so that it has access
|
||||
// to the definition of the Message class, required by the ARM
|
||||
// compiler.
|
||||
template <typename T>
|
||||
String StreamableToString(const T& streamable);
|
||||
|
||||
// The Symbian compiler has a bug that prevents it from selecting the
|
||||
// correct overload of FormatForComparisonFailureMessage (see below)
|
||||
// unless we pass the first argument by reference. If we do that,
|
||||
// however, Visual Age C++ 10.1 generates a compiler error. Therefore
|
||||
// we only apply the work-around for Symbian.
|
||||
#if defined(__SYMBIAN32__)
|
||||
# define GTEST_CREF_WORKAROUND_ const&
|
||||
#else
|
||||
# define GTEST_CREF_WORKAROUND_
|
||||
#endif
|
||||
|
||||
// When this operand is a const char* or char*, if the other operand
|
||||
// is a ::std::string or ::string, we print this operand as a C string
|
||||
// rather than a pointer (we do the same for wide strings); otherwise
|
||||
// we print it as a pointer to be safe.
|
||||
|
||||
// This internal macro is used to avoid duplicated code.
|
||||
#define GTEST_FORMAT_IMPL_(operand2_type, operand1_printer)\
|
||||
inline String FormatForComparisonFailureMessage(\
|
||||
operand2_type::value_type* GTEST_CREF_WORKAROUND_ str, \
|
||||
const operand2_type& /*operand2*/) {\
|
||||
return operand1_printer(str);\
|
||||
}\
|
||||
inline String FormatForComparisonFailureMessage(\
|
||||
const operand2_type::value_type* GTEST_CREF_WORKAROUND_ str, \
|
||||
const operand2_type& /*operand2*/) {\
|
||||
return operand1_printer(str);\
|
||||
}
|
||||
|
||||
GTEST_FORMAT_IMPL_(::std::string, String::ShowCStringQuoted)
|
||||
#if GTEST_HAS_STD_WSTRING
|
||||
GTEST_FORMAT_IMPL_(::std::wstring, String::ShowWideCStringQuoted)
|
||||
#endif // GTEST_HAS_STD_WSTRING
|
||||
|
||||
#if GTEST_HAS_GLOBAL_STRING
|
||||
GTEST_FORMAT_IMPL_(::string, String::ShowCStringQuoted)
|
||||
#endif // GTEST_HAS_GLOBAL_STRING
|
||||
#if GTEST_HAS_GLOBAL_WSTRING
|
||||
GTEST_FORMAT_IMPL_(::wstring, String::ShowWideCStringQuoted)
|
||||
#endif // GTEST_HAS_GLOBAL_WSTRING
|
||||
|
||||
#undef GTEST_FORMAT_IMPL_
|
||||
|
||||
// The next four overloads handle the case where the operand being
|
||||
// printed is a char/wchar_t pointer and the other operand is not a
|
||||
// string/wstring object. In such cases, we just print the operand as
|
||||
// a pointer to be safe.
|
||||
#define GTEST_FORMAT_CHAR_PTR_IMPL_(CharType) \
|
||||
template <typename T> \
|
||||
String FormatForComparisonFailureMessage(CharType* GTEST_CREF_WORKAROUND_ p, \
|
||||
const T&) { \
|
||||
return PrintToString(static_cast<const void*>(p)); \
|
||||
}
|
||||
|
||||
GTEST_FORMAT_CHAR_PTR_IMPL_(char)
|
||||
GTEST_FORMAT_CHAR_PTR_IMPL_(const char)
|
||||
GTEST_FORMAT_CHAR_PTR_IMPL_(wchar_t)
|
||||
GTEST_FORMAT_CHAR_PTR_IMPL_(const wchar_t)
|
||||
|
||||
#undef GTEST_FORMAT_CHAR_PTR_IMPL_
|
||||
|
||||
// Constructs and returns the message for an equality assertion
|
||||
// (e.g. ASSERT_EQ, EXPECT_STREQ, etc) failure.
|
||||
//
|
||||
|
|
@ -273,12 +188,12 @@ GTEST_FORMAT_CHAR_PTR_IMPL_(const wchar_t)
|
|||
// be inserted into the message.
|
||||
GTEST_API_ AssertionResult EqFailure(const char* expected_expression,
|
||||
const char* actual_expression,
|
||||
const String& expected_value,
|
||||
const String& actual_value,
|
||||
const std::string& expected_value,
|
||||
const std::string& actual_value,
|
||||
bool ignoring_case);
|
||||
|
||||
// Constructs a failure message for Boolean assertions such as EXPECT_TRUE.
|
||||
GTEST_API_ String GetBoolAssertionFailureMessage(
|
||||
GTEST_API_ std::string GetBoolAssertionFailureMessage(
|
||||
const AssertionResult& assertion_result,
|
||||
const char* expression_text,
|
||||
const char* actual_predicate_value,
|
||||
|
|
@ -353,7 +268,7 @@ class FloatingPoint {
|
|||
// bits. Therefore, 4 should be enough for ordinary use.
|
||||
//
|
||||
// See the following article for more details on ULP:
|
||||
// http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm.
|
||||
// http://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/
|
||||
static const size_t kMaxUlps = 4;
|
||||
|
||||
// Constructs a FloatingPoint from a raw floating-point number.
|
||||
|
|
@ -380,6 +295,9 @@ class FloatingPoint {
|
|||
return ReinterpretBits(kExponentBitMask);
|
||||
}
|
||||
|
||||
// Returns the maximum representable finite floating-point number.
|
||||
static RawType Max();
|
||||
|
||||
// Non-static methods
|
||||
|
||||
// Returns the bits that represents this number.
|
||||
|
|
@ -460,6 +378,13 @@ class FloatingPoint {
|
|||
FloatingPointUnion u_;
|
||||
};
|
||||
|
||||
// We cannot use std::numeric_limits<T>::max() as it clashes with the max()
|
||||
// macro defined by <windows.h>.
|
||||
template <>
|
||||
inline float FloatingPoint<float>::Max() { return FLT_MAX; }
|
||||
template <>
|
||||
inline double FloatingPoint<double>::Max() { return DBL_MAX; }
|
||||
|
||||
// Typedefs the instances of the FloatingPoint template class that we
|
||||
// care to use.
|
||||
typedef FloatingPoint<float> Float;
|
||||
|
|
@ -554,7 +479,7 @@ typedef void (*TearDownTestCaseFunc)();
|
|||
// test_case_name: name of the test case
|
||||
// name: name of the test
|
||||
// type_param the name of the test's type parameter, or NULL if
|
||||
// this is not a typed or a type-parameterized test.
|
||||
// this is not a typed or a type-parameterized test.
|
||||
// value_param text representation of the test's value parameter,
|
||||
// or NULL if this is not a type-parameterized test.
|
||||
// fixture_class_id: ID of the test fixture class
|
||||
|
|
@ -564,7 +489,8 @@ typedef void (*TearDownTestCaseFunc)();
|
|||
// The newly created TestInfo instance will assume
|
||||
// ownership of the factory object.
|
||||
GTEST_API_ TestInfo* MakeAndRegisterTestInfo(
|
||||
const char* test_case_name, const char* name,
|
||||
const char* test_case_name,
|
||||
const char* name,
|
||||
const char* type_param,
|
||||
const char* value_param,
|
||||
TypeId fixture_class_id,
|
||||
|
|
@ -624,9 +550,9 @@ inline const char* SkipComma(const char* str) {
|
|||
|
||||
// Returns the prefix of 'str' before the first comma in it; returns
|
||||
// the entire string if it contains no comma.
|
||||
inline String GetPrefixUntilComma(const char* str) {
|
||||
inline std::string GetPrefixUntilComma(const char* str) {
|
||||
const char* comma = strchr(str, ',');
|
||||
return comma == NULL ? String(str) : String(str, comma - str);
|
||||
return comma == NULL ? str : std::string(str, comma);
|
||||
}
|
||||
|
||||
// TypeParameterizedTest<Fixture, TestSel, Types>::Register()
|
||||
|
|
@ -652,8 +578,8 @@ class TypeParameterizedTest {
|
|||
// First, registers the first type-parameterized test in the type
|
||||
// list.
|
||||
MakeAndRegisterTestInfo(
|
||||
String::Format("%s%s%s/%d", prefix, prefix[0] == '\0' ? "" : "/",
|
||||
case_name, index).c_str(),
|
||||
(std::string(prefix) + (prefix[0] == '\0' ? "" : "/") + case_name + "/"
|
||||
+ StreamableToString(index)).c_str(),
|
||||
GetPrefixUntilComma(test_names).c_str(),
|
||||
GetTypeName<Type>().c_str(),
|
||||
NULL, // No value parameter.
|
||||
|
|
@ -711,7 +637,7 @@ class TypeParameterizedTestCase<Fixture, Templates0, Types> {
|
|||
|
||||
#endif // GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P
|
||||
|
||||
// Returns the current OS stack trace as a String.
|
||||
// Returns the current OS stack trace as an std::string.
|
||||
//
|
||||
// The maximum number of stack frames to be included is specified by
|
||||
// the gtest_stack_trace_depth flag. The skip_count parameter
|
||||
|
|
@ -721,8 +647,8 @@ class TypeParameterizedTestCase<Fixture, Templates0, Types> {
|
|||
// For example, if Foo() calls Bar(), which in turn calls
|
||||
// GetCurrentOsStackTraceExceptTop(..., 1), Foo() will be included in
|
||||
// the trace but Bar() and GetCurrentOsStackTraceExceptTop() won't.
|
||||
GTEST_API_ String GetCurrentOsStackTraceExceptTop(UnitTest* unit_test,
|
||||
int skip_count);
|
||||
GTEST_API_ std::string GetCurrentOsStackTraceExceptTop(
|
||||
UnitTest* unit_test, int skip_count);
|
||||
|
||||
// Helpers for suppressing warnings on unreachable code or constant
|
||||
// condition.
|
||||
|
|
@ -797,13 +723,19 @@ struct RemoveConst<const T> { typedef T type; }; // NOLINT
|
|||
// MSVC 8.0, Sun C++, and IBM XL C++ have a bug which causes the above
|
||||
// definition to fail to remove the const in 'const int[3]' and 'const
|
||||
// char[3][4]'. The following specialization works around the bug.
|
||||
// However, it causes trouble with GCC and thus needs to be
|
||||
// conditionally compiled.
|
||||
#if defined(_MSC_VER) || defined(__SUNPRO_CC) || defined(__IBMCPP__)
|
||||
template <typename T, size_t N>
|
||||
struct RemoveConst<const T[N]> {
|
||||
typedef typename RemoveConst<T>::type type[N];
|
||||
};
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1400
|
||||
// This is the only specialization that allows VC++ 7.1 to remove const in
|
||||
// 'const int[3] and 'const int[3][4]'. However, it causes trouble with GCC
|
||||
// and thus needs to be conditionally compiled.
|
||||
template <typename T, size_t N>
|
||||
struct RemoveConst<T[N]> {
|
||||
typedef typename RemoveConst<T>::type type[N];
|
||||
};
|
||||
#endif
|
||||
|
||||
// A handy wrapper around RemoveConst that works when the argument
|
||||
|
|
@ -105,8 +105,8 @@ class linked_ptr_internal {
|
|||
// framework.
|
||||
|
||||
// Join an existing circle.
|
||||
// L < g_linked_ptr_mutex
|
||||
void join(linked_ptr_internal const* ptr) {
|
||||
void join(linked_ptr_internal const* ptr)
|
||||
GTEST_LOCK_EXCLUDED_(g_linked_ptr_mutex) {
|
||||
MutexLock lock(&g_linked_ptr_mutex);
|
||||
|
||||
linked_ptr_internal const* p = ptr;
|
||||
|
|
@ -117,8 +117,8 @@ class linked_ptr_internal {
|
|||
|
||||
// Leave whatever circle we're part of. Returns true if we were the
|
||||
// last member of the circle. Once this is done, you can join() another.
|
||||
// L < g_linked_ptr_mutex
|
||||
bool depart() {
|
||||
bool depart()
|
||||
GTEST_LOCK_EXCLUDED_(g_linked_ptr_mutex) {
|
||||
MutexLock lock(&g_linked_ptr_mutex);
|
||||
|
||||
if (next_ == this) return true;
|
||||
|
|
@ -95,7 +95,7 @@ class ValueArray2 {
|
|||
|
||||
template <typename T>
|
||||
operator ParamGenerator<T>() const {
|
||||
const T array[] = {v1_, v2_};
|
||||
const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_)};
|
||||
return ValuesIn(array);
|
||||
}
|
||||
|
||||
|
|
@ -114,7 +114,8 @@ class ValueArray3 {
|
|||
|
||||
template <typename T>
|
||||
operator ParamGenerator<T>() const {
|
||||
const T array[] = {v1_, v2_, v3_};
|
||||
const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
|
||||
static_cast<T>(v3_)};
|
||||
return ValuesIn(array);
|
||||
}
|
||||
|
||||
|
|
@ -135,7 +136,8 @@ class ValueArray4 {
|
|||
|
||||
template <typename T>
|
||||
operator ParamGenerator<T>() const {
|
||||
const T array[] = {v1_, v2_, v3_, v4_};
|
||||
const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
|
||||
static_cast<T>(v3_), static_cast<T>(v4_)};
|
||||
return ValuesIn(array);
|
||||
}
|
||||
|
||||
|
|
@ -157,7 +159,8 @@ class ValueArray5 {
|
|||
|
||||
template <typename T>
|
||||
operator ParamGenerator<T>() const {
|
||||
const T array[] = {v1_, v2_, v3_, v4_, v5_};
|
||||
const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
|
||||
static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_)};
|
||||
return ValuesIn(array);
|
||||
}
|
||||
|
||||
|
|
@ -181,7 +184,9 @@ class ValueArray6 {
|
|||
|
||||
template <typename T>
|
||||
operator ParamGenerator<T>() const {
|
||||
const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_};
|
||||
const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
|
||||
static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
|
||||
static_cast<T>(v6_)};
|
||||
return ValuesIn(array);
|
||||
}
|
||||
|
||||
|
|
@ -206,7 +211,9 @@ class ValueArray7 {
|
|||
|
||||
template <typename T>
|
||||
operator ParamGenerator<T>() const {
|
||||
const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_};
|
||||
const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
|
||||
static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
|
||||
static_cast<T>(v6_), static_cast<T>(v7_)};
|
||||
return ValuesIn(array);
|
||||
}
|
||||
|
||||
|
|
@ -233,7 +240,9 @@ class ValueArray8 {
|
|||
|
||||
template <typename T>
|
||||
operator ParamGenerator<T>() const {
|
||||
const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_};
|
||||
const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
|
||||
static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
|
||||
static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_)};
|
||||
return ValuesIn(array);
|
||||
}
|
||||
|
||||
|
|
@ -261,7 +270,10 @@ class ValueArray9 {
|
|||
|
||||
template <typename T>
|
||||
operator ParamGenerator<T>() const {
|
||||
const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_};
|
||||
const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
|
||||
static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
|
||||
static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
|
||||
static_cast<T>(v9_)};
|
||||
return ValuesIn(array);
|
||||
}
|
||||
|
||||
|
|
@ -290,7 +302,10 @@ class ValueArray10 {
|
|||
|
||||
template <typename T>
|
||||
operator ParamGenerator<T>() const {
|
||||
const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_};
|
||||
const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
|
||||
static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
|
||||
static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
|
||||
static_cast<T>(v9_), static_cast<T>(v10_)};
|
||||
return ValuesIn(array);
|
||||
}
|
||||
|
||||
|
|
@ -321,7 +336,10 @@ class ValueArray11 {
|
|||
|
||||
template <typename T>
|
||||
operator ParamGenerator<T>() const {
|
||||
const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_};
|
||||
const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
|
||||
static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
|
||||
static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
|
||||
static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_)};
|
||||
return ValuesIn(array);
|
||||
}
|
||||
|
||||
|
|
@ -353,8 +371,11 @@ class ValueArray12 {
|
|||
|
||||
template <typename T>
|
||||
operator ParamGenerator<T>() const {
|
||||
const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
|
||||
v12_};
|
||||
const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
|
||||
static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
|
||||
static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
|
||||
static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
|
||||
static_cast<T>(v12_)};
|
||||
return ValuesIn(array);
|
||||
}
|
||||
|
||||
|
|
@ -388,8 +409,11 @@ class ValueArray13 {
|
|||
|
||||
template <typename T>
|
||||
operator ParamGenerator<T>() const {
|
||||
const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
|
||||
v12_, v13_};
|
||||
const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
|
||||
static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
|
||||
static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
|
||||
static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
|
||||
static_cast<T>(v12_), static_cast<T>(v13_)};
|
||||
return ValuesIn(array);
|
||||
}
|
||||
|
||||
|
|
@ -424,8 +448,11 @@ class ValueArray14 {
|
|||
|
||||
template <typename T>
|
||||
operator ParamGenerator<T>() const {
|
||||
const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
|
||||
v12_, v13_, v14_};
|
||||
const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
|
||||
static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
|
||||
static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
|
||||
static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
|
||||
static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_)};
|
||||
return ValuesIn(array);
|
||||
}
|
||||
|
||||
|
|
@ -461,8 +488,12 @@ class ValueArray15 {
|
|||
|
||||
template <typename T>
|
||||
operator ParamGenerator<T>() const {
|
||||
const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
|
||||
v12_, v13_, v14_, v15_};
|
||||
const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
|
||||
static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
|
||||
static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
|
||||
static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
|
||||
static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
|
||||
static_cast<T>(v15_)};
|
||||
return ValuesIn(array);
|
||||
}
|
||||
|
||||
|
|
@ -501,8 +532,12 @@ class ValueArray16 {
|
|||
|
||||
template <typename T>
|
||||
operator ParamGenerator<T>() const {
|
||||
const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
|
||||
v12_, v13_, v14_, v15_, v16_};
|
||||
const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
|
||||
static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
|
||||
static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
|
||||
static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
|
||||
static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
|
||||
static_cast<T>(v15_), static_cast<T>(v16_)};
|
||||
return ValuesIn(array);
|
||||
}
|
||||
|
||||
|
|
@ -542,8 +577,12 @@ class ValueArray17 {
|
|||
|
||||
template <typename T>
|
||||
operator ParamGenerator<T>() const {
|
||||
const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
|
||||
v12_, v13_, v14_, v15_, v16_, v17_};
|
||||
const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
|
||||
static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
|
||||
static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
|
||||
static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
|
||||
static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
|
||||
static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_)};
|
||||
return ValuesIn(array);
|
||||
}
|
||||
|
||||
|
|
@ -584,8 +623,13 @@ class ValueArray18 {
|
|||
|
||||
template <typename T>
|
||||
operator ParamGenerator<T>() const {
|
||||
const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
|
||||
v12_, v13_, v14_, v15_, v16_, v17_, v18_};
|
||||
const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
|
||||
static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
|
||||
static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
|
||||
static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
|
||||
static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
|
||||
static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
|
||||
static_cast<T>(v18_)};
|
||||
return ValuesIn(array);
|
||||
}
|
||||
|
||||
|
|
@ -627,8 +671,13 @@ class ValueArray19 {
|
|||
|
||||
template <typename T>
|
||||
operator ParamGenerator<T>() const {
|
||||
const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
|
||||
v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_};
|
||||
const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
|
||||
static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
|
||||
static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
|
||||
static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
|
||||
static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
|
||||
static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
|
||||
static_cast<T>(v18_), static_cast<T>(v19_)};
|
||||
return ValuesIn(array);
|
||||
}
|
||||
|
||||
|
|
@ -672,8 +721,13 @@ class ValueArray20 {
|
|||
|
||||
template <typename T>
|
||||
operator ParamGenerator<T>() const {
|
||||
const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
|
||||
v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_};
|
||||
const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
|
||||
static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
|
||||
static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
|
||||
static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
|
||||
static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
|
||||
static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
|
||||
static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_)};
|
||||
return ValuesIn(array);
|
||||
}
|
||||
|
||||
|
|
@ -719,8 +773,14 @@ class ValueArray21 {
|
|||
|
||||
template <typename T>
|
||||
operator ParamGenerator<T>() const {
|
||||
const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
|
||||
v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_};
|
||||
const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
|
||||
static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
|
||||
static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
|
||||
static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
|
||||
static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
|
||||
static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
|
||||
static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
|
||||
static_cast<T>(v21_)};
|
||||
return ValuesIn(array);
|
||||
}
|
||||
|
||||
|
|
@ -767,8 +827,14 @@ class ValueArray22 {
|
|||
|
||||
template <typename T>
|
||||
operator ParamGenerator<T>() const {
|
||||
const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
|
||||
v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_};
|
||||
const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
|
||||
static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
|
||||
static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
|
||||
static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
|
||||
static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
|
||||
static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
|
||||
static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
|
||||
static_cast<T>(v21_), static_cast<T>(v22_)};
|
||||
return ValuesIn(array);
|
||||
}
|
||||
|
||||
|
|
@ -817,9 +883,14 @@ class ValueArray23 {
|
|||
|
||||
template <typename T>
|
||||
operator ParamGenerator<T>() const {
|
||||
const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
|
||||
v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_,
|
||||
v23_};
|
||||
const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
|
||||
static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
|
||||
static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
|
||||
static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
|
||||
static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
|
||||
static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
|
||||
static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
|
||||
static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_)};
|
||||
return ValuesIn(array);
|
||||
}
|
||||
|
||||
|
|
@ -869,9 +940,15 @@ class ValueArray24 {
|
|||
|
||||
template <typename T>
|
||||
operator ParamGenerator<T>() const {
|
||||
const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
|
||||
v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
|
||||
v24_};
|
||||
const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
|
||||
static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
|
||||
static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
|
||||
static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
|
||||
static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
|
||||
static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
|
||||
static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
|
||||
static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
|
||||
static_cast<T>(v24_)};
|
||||
return ValuesIn(array);
|
||||
}
|
||||
|
||||
|
|
@ -922,9 +999,15 @@ class ValueArray25 {
|
|||
|
||||
template <typename T>
|
||||
operator ParamGenerator<T>() const {
|
||||
const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
|
||||
v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
|
||||
v24_, v25_};
|
||||
const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
|
||||
static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
|
||||
static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
|
||||
static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
|
||||
static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
|
||||
static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
|
||||
static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
|
||||
static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
|
||||
static_cast<T>(v24_), static_cast<T>(v25_)};
|
||||
return ValuesIn(array);
|
||||
}
|
||||
|
||||
|
|
@ -977,9 +1060,15 @@ class ValueArray26 {
|
|||
|
||||
template <typename T>
|
||||
operator ParamGenerator<T>() const {
|
||||
const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
|
||||
v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
|
||||
v24_, v25_, v26_};
|
||||
const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
|
||||
static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
|
||||
static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
|
||||
static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
|
||||
static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
|
||||
static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
|
||||
static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
|
||||
static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
|
||||
static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_)};
|
||||
return ValuesIn(array);
|
||||
}
|
||||
|
||||
|
|
@ -1034,9 +1123,16 @@ class ValueArray27 {
|
|||
|
||||
template <typename T>
|
||||
operator ParamGenerator<T>() const {
|
||||
const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
|
||||
v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
|
||||
v24_, v25_, v26_, v27_};
|
||||
const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
|
||||
static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
|
||||
static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
|
||||
static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
|
||||
static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
|
||||
static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
|
||||
static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
|
||||
static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
|
||||
static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
|
||||
static_cast<T>(v27_)};
|
||||
return ValuesIn(array);
|
||||
}
|
||||
|
||||
|
|
@ -1092,9 +1188,16 @@ class ValueArray28 {
|
|||
|
||||
template <typename T>
|
||||
operator ParamGenerator<T>() const {
|
||||
const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
|
||||
v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
|
||||
v24_, v25_, v26_, v27_, v28_};
|
||||
const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
|
||||
static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
|
||||
static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
|
||||
static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
|
||||
static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
|
||||
static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
|
||||
static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
|
||||
static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
|
||||
static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
|
||||
static_cast<T>(v27_), static_cast<T>(v28_)};
|
||||
return ValuesIn(array);
|
||||
}
|
||||
|
||||
|
|
@ -1151,9 +1254,16 @@ class ValueArray29 {
|
|||
|
||||
template <typename T>
|
||||
operator ParamGenerator<T>() const {
|
||||
const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
|
||||
v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
|
||||
v24_, v25_, v26_, v27_, v28_, v29_};
|
||||
const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
|
||||
static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
|
||||
static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
|
||||
static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
|
||||
static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
|
||||
static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
|
||||
static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
|
||||
static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
|
||||
static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
|
||||
static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_)};
|
||||
return ValuesIn(array);
|
||||
}
|
||||
|
||||
|
|
@ -1212,9 +1322,17 @@ class ValueArray30 {
|
|||
|
||||
template <typename T>
|
||||
operator ParamGenerator<T>() const {
|
||||
const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
|
||||
v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
|
||||
v24_, v25_, v26_, v27_, v28_, v29_, v30_};
|
||||
const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
|
||||
static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
|
||||
static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
|
||||
static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
|
||||
static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
|
||||
static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
|
||||
static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
|
||||
static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
|
||||
static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
|
||||
static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
|
||||
static_cast<T>(v30_)};
|
||||
return ValuesIn(array);
|
||||
}
|
||||
|
||||
|
|
@ -1275,9 +1393,17 @@ class ValueArray31 {
|
|||
|
||||
template <typename T>
|
||||
operator ParamGenerator<T>() const {
|
||||
const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
|
||||
v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
|
||||
v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_};
|
||||
const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
|
||||
static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
|
||||
static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
|
||||
static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
|
||||
static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
|
||||
static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
|
||||
static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
|
||||
static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
|
||||
static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
|
||||
static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
|
||||
static_cast<T>(v30_), static_cast<T>(v31_)};
|
||||
return ValuesIn(array);
|
||||
}
|
||||
|
||||
|
|
@ -1339,9 +1465,17 @@ class ValueArray32 {
|
|||
|
||||
template <typename T>
|
||||
operator ParamGenerator<T>() const {
|
||||
const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
|
||||
v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
|
||||
v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_};
|
||||
const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
|
||||
static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
|
||||
static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
|
||||
static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
|
||||
static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
|
||||
static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
|
||||
static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
|
||||
static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
|
||||
static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
|
||||
static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
|
||||
static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_)};
|
||||
return ValuesIn(array);
|
||||
}
|
||||
|
||||
|
|
@ -1405,9 +1539,18 @@ class ValueArray33 {
|
|||
|
||||
template <typename T>
|
||||
operator ParamGenerator<T>() const {
|
||||
const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
|
||||
v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
|
||||
v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_};
|
||||
const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
|
||||
static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
|
||||
static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
|
||||
static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
|
||||
static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
|
||||
static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
|
||||
static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
|
||||
static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
|
||||
static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
|
||||
static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
|
||||
static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
|
||||
static_cast<T>(v33_)};
|
||||
return ValuesIn(array);
|
||||
}
|
||||
|
||||
|
|
@ -1472,9 +1615,18 @@ class ValueArray34 {
|
|||
|
||||
template <typename T>
|
||||
operator ParamGenerator<T>() const {
|
||||
const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
|
||||
v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
|
||||
v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_};
|
||||
const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
|
||||
static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
|
||||
static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
|
||||
static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
|
||||
static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
|
||||
static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
|
||||
static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
|
||||
static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
|
||||
static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
|
||||
static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
|
||||
static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
|
||||
static_cast<T>(v33_), static_cast<T>(v34_)};
|
||||
return ValuesIn(array);
|
||||
}
|
||||
|
||||
|
|
@ -1540,10 +1692,18 @@ class ValueArray35 {
|
|||
|
||||
template <typename T>
|
||||
operator ParamGenerator<T>() const {
|
||||
const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
|
||||
v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
|
||||
v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_,
|
||||
v35_};
|
||||
const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
|
||||
static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
|
||||
static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
|
||||
static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
|
||||
static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
|
||||
static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
|
||||
static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
|
||||
static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
|
||||
static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
|
||||
static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
|
||||
static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
|
||||
static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_)};
|
||||
return ValuesIn(array);
|
||||
}
|
||||
|
||||
|
|
@ -1611,10 +1771,19 @@ class ValueArray36 {
|
|||
|
||||
template <typename T>
|
||||
operator ParamGenerator<T>() const {
|
||||
const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
|
||||
v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
|
||||
v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,
|
||||
v36_};
|
||||
const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
|
||||
static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
|
||||
static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
|
||||
static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
|
||||
static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
|
||||
static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
|
||||
static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
|
||||
static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
|
||||
static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
|
||||
static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
|
||||
static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
|
||||
static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_),
|
||||
static_cast<T>(v36_)};
|
||||
return ValuesIn(array);
|
||||
}
|
||||
|
||||
|
|
@ -1684,10 +1853,19 @@ class ValueArray37 {
|
|||
|
||||
template <typename T>
|
||||
operator ParamGenerator<T>() const {
|
||||
const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
|
||||
v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
|
||||
v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,
|
||||
v36_, v37_};
|
||||
const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
|
||||
static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
|
||||
static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
|
||||
static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
|
||||
static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
|
||||
static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
|
||||
static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
|
||||
static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
|
||||
static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
|
||||
static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
|
||||
static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
|
||||
static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_),
|
||||
static_cast<T>(v36_), static_cast<T>(v37_)};
|
||||
return ValuesIn(array);
|
||||
}
|
||||
|
||||
|
|
@ -1758,10 +1936,19 @@ class ValueArray38 {
|
|||
|
||||
template <typename T>
|
||||
operator ParamGenerator<T>() const {
|
||||
const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
|
||||
v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
|
||||
v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,
|
||||
v36_, v37_, v38_};
|
||||
const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
|
||||
static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
|
||||
static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
|
||||
static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
|
||||
static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
|
||||
static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
|
||||
static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
|
||||
static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
|
||||
static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
|
||||
static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
|
||||
static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
|
||||
static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_),
|
||||
static_cast<T>(v36_), static_cast<T>(v37_), static_cast<T>(v38_)};
|
||||
return ValuesIn(array);
|
||||
}
|
||||
|
||||
|
|
@ -1833,10 +2020,20 @@ class ValueArray39 {
|
|||
|
||||
template <typename T>
|
||||
operator ParamGenerator<T>() const {
|
||||
const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
|
||||
v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
|
||||
v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,
|
||||
v36_, v37_, v38_, v39_};
|
||||
const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
|
||||
static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
|
||||
static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
|
||||
static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
|
||||
static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
|
||||
static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
|
||||
static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
|
||||
static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
|
||||
static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
|
||||
static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
|
||||
static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
|
||||
static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_),
|
||||
static_cast<T>(v36_), static_cast<T>(v37_), static_cast<T>(v38_),
|
||||
static_cast<T>(v39_)};
|
||||
return ValuesIn(array);
|
||||
}
|
||||
|
||||
|
|
@ -1910,10 +2107,20 @@ class ValueArray40 {
|
|||
|
||||
template <typename T>
|
||||
operator ParamGenerator<T>() const {
|
||||
const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
|
||||
v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
|
||||
v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,
|
||||
v36_, v37_, v38_, v39_, v40_};
|
||||
const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
|
||||
static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
|
||||
static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
|
||||
static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
|
||||
static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
|
||||
static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
|
||||
static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
|
||||
static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
|
||||
static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
|
||||
static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
|
||||
static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
|
||||
static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_),
|
||||
static_cast<T>(v36_), static_cast<T>(v37_), static_cast<T>(v38_),
|
||||
static_cast<T>(v39_), static_cast<T>(v40_)};
|
||||
return ValuesIn(array);
|
||||
}
|
||||
|
||||
|
|
@ -1989,10 +2196,20 @@ class ValueArray41 {
|
|||
|
||||
template <typename T>
|
||||
operator ParamGenerator<T>() const {
|
||||
const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
|
||||
v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
|
||||
v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,
|
||||
v36_, v37_, v38_, v39_, v40_, v41_};
|
||||
const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
|
||||
static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
|
||||
static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
|
||||
static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
|
||||
static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
|
||||
static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
|
||||
static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
|
||||
static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
|
||||
static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
|
||||
static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
|
||||
static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
|
||||
static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_),
|
||||
static_cast<T>(v36_), static_cast<T>(v37_), static_cast<T>(v38_),
|
||||
static_cast<T>(v39_), static_cast<T>(v40_), static_cast<T>(v41_)};
|
||||
return ValuesIn(array);
|
||||
}
|
||||
|
||||
|
|
@ -2069,10 +2286,21 @@ class ValueArray42 {
|
|||
|
||||
template <typename T>
|
||||
operator ParamGenerator<T>() const {
|
||||
const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
|
||||
v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
|
||||
v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,
|
||||
v36_, v37_, v38_, v39_, v40_, v41_, v42_};
|
||||
const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
|
||||
static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
|
||||
static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
|
||||
static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
|
||||
static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
|
||||
static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
|
||||
static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
|
||||
static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
|
||||
static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
|
||||
static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
|
||||
static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
|
||||
static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_),
|
||||
static_cast<T>(v36_), static_cast<T>(v37_), static_cast<T>(v38_),
|
||||
static_cast<T>(v39_), static_cast<T>(v40_), static_cast<T>(v41_),
|
||||
static_cast<T>(v42_)};
|
||||
return ValuesIn(array);
|
||||
}
|
||||
|
||||
|
|
@ -2150,10 +2378,21 @@ class ValueArray43 {
|
|||
|
||||
template <typename T>
|
||||
operator ParamGenerator<T>() const {
|
||||
const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
|
||||
v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
|
||||
v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,
|
||||
v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_};
|
||||
const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
|
||||
static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
|
||||
static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
|
||||
static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
|
||||
static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
|
||||
static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
|
||||
static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
|
||||
static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
|
||||
static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
|
||||
static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
|
||||
static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
|
||||
static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_),
|
||||
static_cast<T>(v36_), static_cast<T>(v37_), static_cast<T>(v38_),
|
||||
static_cast<T>(v39_), static_cast<T>(v40_), static_cast<T>(v41_),
|
||||
static_cast<T>(v42_), static_cast<T>(v43_)};
|
||||
return ValuesIn(array);
|
||||
}
|
||||
|
||||
|
|
@ -2233,10 +2472,21 @@ class ValueArray44 {
|
|||
|
||||
template <typename T>
|
||||
operator ParamGenerator<T>() const {
|
||||
const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
|
||||
v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
|
||||
v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,
|
||||
v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_};
|
||||
const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
|
||||
static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
|
||||
static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
|
||||
static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
|
||||
static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
|
||||
static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
|
||||
static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
|
||||
static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
|
||||
static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
|
||||
static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
|
||||
static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
|
||||
static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_),
|
||||
static_cast<T>(v36_), static_cast<T>(v37_), static_cast<T>(v38_),
|
||||
static_cast<T>(v39_), static_cast<T>(v40_), static_cast<T>(v41_),
|
||||
static_cast<T>(v42_), static_cast<T>(v43_), static_cast<T>(v44_)};
|
||||
return ValuesIn(array);
|
||||
}
|
||||
|
||||
|
|
@ -2317,10 +2567,22 @@ class ValueArray45 {
|
|||
|
||||
template <typename T>
|
||||
operator ParamGenerator<T>() const {
|
||||
const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
|
||||
v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
|
||||
v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,
|
||||
v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_};
|
||||
const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
|
||||
static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
|
||||
static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
|
||||
static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
|
||||
static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
|
||||
static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
|
||||
static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
|
||||
static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
|
||||
static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
|
||||
static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
|
||||
static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
|
||||
static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_),
|
||||
static_cast<T>(v36_), static_cast<T>(v37_), static_cast<T>(v38_),
|
||||
static_cast<T>(v39_), static_cast<T>(v40_), static_cast<T>(v41_),
|
||||
static_cast<T>(v42_), static_cast<T>(v43_), static_cast<T>(v44_),
|
||||
static_cast<T>(v45_)};
|
||||
return ValuesIn(array);
|
||||
}
|
||||
|
||||
|
|
@ -2403,10 +2665,22 @@ class ValueArray46 {
|
|||
|
||||
template <typename T>
|
||||
operator ParamGenerator<T>() const {
|
||||
const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
|
||||
v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
|
||||
v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,
|
||||
v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_, v46_};
|
||||
const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
|
||||
static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
|
||||
static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
|
||||
static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
|
||||
static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
|
||||
static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
|
||||
static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
|
||||
static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
|
||||
static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
|
||||
static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
|
||||
static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
|
||||
static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_),
|
||||
static_cast<T>(v36_), static_cast<T>(v37_), static_cast<T>(v38_),
|
||||
static_cast<T>(v39_), static_cast<T>(v40_), static_cast<T>(v41_),
|
||||
static_cast<T>(v42_), static_cast<T>(v43_), static_cast<T>(v44_),
|
||||
static_cast<T>(v45_), static_cast<T>(v46_)};
|
||||
return ValuesIn(array);
|
||||
}
|
||||
|
||||
|
|
@ -2491,11 +2765,22 @@ class ValueArray47 {
|
|||
|
||||
template <typename T>
|
||||
operator ParamGenerator<T>() const {
|
||||
const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
|
||||
v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
|
||||
v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,
|
||||
v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_, v46_,
|
||||
v47_};
|
||||
const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
|
||||
static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
|
||||
static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
|
||||
static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
|
||||
static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
|
||||
static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
|
||||
static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
|
||||
static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
|
||||
static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
|
||||
static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
|
||||
static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
|
||||
static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_),
|
||||
static_cast<T>(v36_), static_cast<T>(v37_), static_cast<T>(v38_),
|
||||
static_cast<T>(v39_), static_cast<T>(v40_), static_cast<T>(v41_),
|
||||
static_cast<T>(v42_), static_cast<T>(v43_), static_cast<T>(v44_),
|
||||
static_cast<T>(v45_), static_cast<T>(v46_), static_cast<T>(v47_)};
|
||||
return ValuesIn(array);
|
||||
}
|
||||
|
||||
|
|
@ -2581,11 +2866,23 @@ class ValueArray48 {
|
|||
|
||||
template <typename T>
|
||||
operator ParamGenerator<T>() const {
|
||||
const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
|
||||
v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
|
||||
v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,
|
||||
v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_, v46_, v47_,
|
||||
v48_};
|
||||
const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
|
||||
static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
|
||||
static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
|
||||
static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
|
||||
static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
|
||||
static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
|
||||
static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
|
||||
static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
|
||||
static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
|
||||
static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
|
||||
static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
|
||||
static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_),
|
||||
static_cast<T>(v36_), static_cast<T>(v37_), static_cast<T>(v38_),
|
||||
static_cast<T>(v39_), static_cast<T>(v40_), static_cast<T>(v41_),
|
||||
static_cast<T>(v42_), static_cast<T>(v43_), static_cast<T>(v44_),
|
||||
static_cast<T>(v45_), static_cast<T>(v46_), static_cast<T>(v47_),
|
||||
static_cast<T>(v48_)};
|
||||
return ValuesIn(array);
|
||||
}
|
||||
|
||||
|
|
@ -2672,11 +2969,23 @@ class ValueArray49 {
|
|||
|
||||
template <typename T>
|
||||
operator ParamGenerator<T>() const {
|
||||
const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
|
||||
v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
|
||||
v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,
|
||||
v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_, v46_, v47_,
|
||||
v48_, v49_};
|
||||
const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
|
||||
static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
|
||||
static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
|
||||
static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
|
||||
static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
|
||||
static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
|
||||
static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
|
||||
static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
|
||||
static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
|
||||
static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
|
||||
static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
|
||||
static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_),
|
||||
static_cast<T>(v36_), static_cast<T>(v37_), static_cast<T>(v38_),
|
||||
static_cast<T>(v39_), static_cast<T>(v40_), static_cast<T>(v41_),
|
||||
static_cast<T>(v42_), static_cast<T>(v43_), static_cast<T>(v44_),
|
||||
static_cast<T>(v45_), static_cast<T>(v46_), static_cast<T>(v47_),
|
||||
static_cast<T>(v48_), static_cast<T>(v49_)};
|
||||
return ValuesIn(array);
|
||||
}
|
||||
|
||||
|
|
@ -2764,11 +3073,23 @@ class ValueArray50 {
|
|||
|
||||
template <typename T>
|
||||
operator ParamGenerator<T>() const {
|
||||
const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
|
||||
v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
|
||||
v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,
|
||||
v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_, v46_, v47_,
|
||||
v48_, v49_, v50_};
|
||||
const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
|
||||
static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
|
||||
static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
|
||||
static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
|
||||
static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
|
||||
static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
|
||||
static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
|
||||
static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
|
||||
static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
|
||||
static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
|
||||
static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
|
||||
static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_),
|
||||
static_cast<T>(v36_), static_cast<T>(v37_), static_cast<T>(v38_),
|
||||
static_cast<T>(v39_), static_cast<T>(v40_), static_cast<T>(v41_),
|
||||
static_cast<T>(v42_), static_cast<T>(v43_), static_cast<T>(v44_),
|
||||
static_cast<T>(v45_), static_cast<T>(v46_), static_cast<T>(v47_),
|
||||
static_cast<T>(v48_), static_cast<T>(v49_), static_cast<T>(v50_)};
|
||||
return ValuesIn(array);
|
||||
}
|
||||
|
||||
|
|
@ -98,7 +98,7 @@ class ValueArray$i {
|
|||
|
||||
template <typename T>
|
||||
operator ParamGenerator<T>() const {
|
||||
const T array[] = {$for j, [[v$(j)_]]};
|
||||
const T array[] = {$for j, [[static_cast<T>(v$(j)_)]]};
|
||||
return ValuesIn(array);
|
||||
}
|
||||
|
||||
|
|
@ -494,10 +494,10 @@ class ParameterizedTestCaseInfo : public ParameterizedTestCaseInfoBase {
|
|||
const string& instantiation_name = gen_it->first;
|
||||
ParamGenerator<ParamType> generator((*gen_it->second)());
|
||||
|
||||
Message test_case_name_stream;
|
||||
string test_case_name;
|
||||
if ( !instantiation_name.empty() )
|
||||
test_case_name_stream << instantiation_name << "/";
|
||||
test_case_name_stream << test_info->test_case_base_name;
|
||||
test_case_name = instantiation_name + "/";
|
||||
test_case_name += test_info->test_case_base_name;
|
||||
|
||||
int i = 0;
|
||||
for (typename ParamGenerator<ParamType>::iterator param_it =
|
||||
|
|
@ -506,7 +506,7 @@ class ParameterizedTestCaseInfo : public ParameterizedTestCaseInfoBase {
|
|||
Message test_name_stream;
|
||||
test_name_stream << test_info->test_base_name << "/" << i;
|
||||
MakeAndRegisterTestInfo(
|
||||
test_case_name_stream.GetString().c_str(),
|
||||
test_case_name.c_str(),
|
||||
test_name_stream.GetString().c_str(),
|
||||
NULL, // No type parameter.
|
||||
PrintToString(*param_it).c_str(),
|
||||
|
|
@ -32,6 +32,10 @@
|
|||
// Low-level types and utilities for porting Google Test to various
|
||||
// platforms. They are subject to change without notice. DO NOT USE
|
||||
// THEM IN USER CODE.
|
||||
//
|
||||
// This file is fundamental to Google Test. All other Google Test source
|
||||
// files are expected to #include this. Therefore, it cannot #include
|
||||
// any other Google Test header.
|
||||
|
||||
#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_
|
||||
#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_
|
||||
|
|
@ -72,6 +76,8 @@
|
|||
// Test's own tr1 tuple implementation should be
|
||||
// used. Unused when the user sets
|
||||
// GTEST_HAS_TR1_TUPLE to 0.
|
||||
// GTEST_LANG_CXX11 - Define it to 1/0 to indicate that Google Test
|
||||
// is building in C++11/C++98 mode.
|
||||
// GTEST_LINKED_AS_SHARED_LIBRARY
|
||||
// - Define to 1 when compiling tests that use
|
||||
// Google Test as a shared library (known as
|
||||
|
|
@ -90,7 +96,11 @@
|
|||
// GTEST_OS_LINUX - Linux
|
||||
// GTEST_OS_LINUX_ANDROID - Google Android
|
||||
// GTEST_OS_MAC - Mac OS X
|
||||
// GTEST_OS_IOS - iOS
|
||||
// GTEST_OS_IOS_SIMULATOR - iOS simulator
|
||||
// GTEST_OS_NACL - Google Native Client (NaCl)
|
||||
// GTEST_OS_OPENBSD - OpenBSD
|
||||
// GTEST_OS_QNX - QNX
|
||||
// GTEST_OS_SOLARIS - Sun Solaris
|
||||
// GTEST_OS_SYMBIAN - Symbian
|
||||
// GTEST_OS_WINDOWS - Windows (Desktop, MinGW, or Mobile)
|
||||
|
|
@ -175,7 +185,7 @@
|
|||
// GTEST_FLAG() - references a flag.
|
||||
// GTEST_DECLARE_*() - declares a flag.
|
||||
// GTEST_DEFINE_*() - defines a flag.
|
||||
// GetArgvs() - returns the command line as a vector of strings.
|
||||
// GetInjectableArgvs() - returns the command line as a vector of strings.
|
||||
//
|
||||
// Environment variable utilities:
|
||||
// GetEnv() - gets the value of an environment variable.
|
||||
|
|
@ -193,6 +203,11 @@
|
|||
# include <sys/stat.h>
|
||||
#endif // !_WIN32_WCE
|
||||
|
||||
#if defined __APPLE__
|
||||
# include <AvailabilityMacros.h>
|
||||
# include <TargetConditionals.h>
|
||||
#endif
|
||||
|
||||
#include <iostream> // NOLINT
|
||||
#include <sstream> // NOLINT
|
||||
#include <string> // NOLINT
|
||||
|
|
@ -227,11 +242,17 @@
|
|||
# endif // _WIN32_WCE
|
||||
#elif defined __APPLE__
|
||||
# define GTEST_OS_MAC 1
|
||||
# if TARGET_OS_IPHONE
|
||||
# define GTEST_OS_IOS 1
|
||||
# if TARGET_IPHONE_SIMULATOR
|
||||
# define GTEST_OS_IOS_SIMULATOR 1
|
||||
# endif
|
||||
# endif
|
||||
#elif defined __linux__
|
||||
# define GTEST_OS_LINUX 1
|
||||
# ifdef ANDROID
|
||||
# if defined __ANDROID__
|
||||
# define GTEST_OS_LINUX_ANDROID 1
|
||||
# endif // ANDROID
|
||||
# endif
|
||||
#elif defined __MVS__
|
||||
# define GTEST_OS_ZOS 1
|
||||
#elif defined(__sun) && defined(__SVR4)
|
||||
|
|
@ -242,8 +263,25 @@
|
|||
# define GTEST_OS_HPUX 1
|
||||
#elif defined __native_client__
|
||||
# define GTEST_OS_NACL 1
|
||||
#elif defined __OpenBSD__
|
||||
# define GTEST_OS_OPENBSD 1
|
||||
#elif defined __QNX__
|
||||
# define GTEST_OS_QNX 1
|
||||
#endif // __CYGWIN__
|
||||
|
||||
#ifndef GTEST_LANG_CXX11
|
||||
// gcc and clang define __GXX_EXPERIMENTAL_CXX0X__ when
|
||||
// -std={c,gnu}++{0x,11} is passed. The C++11 standard specifies a
|
||||
// value for __cplusplus, and recent versions of clang, gcc, and
|
||||
// probably other compilers set that too in C++11 mode.
|
||||
# if __GXX_EXPERIMENTAL_CXX0X__ || __cplusplus >= 201103L
|
||||
// Compiling in at least C++11 mode.
|
||||
# define GTEST_LANG_CXX11 1
|
||||
# else
|
||||
# define GTEST_LANG_CXX11 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
// Brings in definitions for functions used in the testing::internal::posix
|
||||
// namespace (read, write, close, chdir, isatty, stat). We do not currently
|
||||
// use them on Windows Mobile.
|
||||
|
|
@ -252,20 +290,25 @@
|
|||
// is not the case, we need to include headers that provide the functions
|
||||
// mentioned above.
|
||||
# include <unistd.h>
|
||||
# if !GTEST_OS_NACL
|
||||
// TODO(vladl@google.com): Remove this condition when Native Client SDK adds
|
||||
// strings.h (tracked in
|
||||
// http://code.google.com/p/nativeclient/issues/detail?id=1175).
|
||||
# include <strings.h> // Native Client doesn't provide strings.h.
|
||||
# endif
|
||||
# include <strings.h>
|
||||
#elif !GTEST_OS_WINDOWS_MOBILE
|
||||
# include <direct.h>
|
||||
# include <io.h>
|
||||
#endif
|
||||
|
||||
#if GTEST_OS_LINUX_ANDROID
|
||||
// Used to define __ANDROID_API__ matching the target NDK API level.
|
||||
# include <android/api-level.h> // NOLINT
|
||||
#endif
|
||||
|
||||
// Defines this to true iff Google Test can use POSIX regular expressions.
|
||||
#ifndef GTEST_HAS_POSIX_RE
|
||||
# define GTEST_HAS_POSIX_RE (!GTEST_OS_WINDOWS)
|
||||
# if GTEST_OS_LINUX_ANDROID
|
||||
// On Android, <regex.h> is only available starting with Gingerbread.
|
||||
# define GTEST_HAS_POSIX_RE (__ANDROID_API__ >= 9)
|
||||
# else
|
||||
# define GTEST_HAS_POSIX_RE (!GTEST_OS_WINDOWS)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if GTEST_HAS_POSIX_RE
|
||||
|
|
@ -380,11 +423,27 @@
|
|||
# elif defined(__GNUC__) && (GTEST_GCC_VER_ >= 40302)
|
||||
|
||||
# ifdef __GXX_RTTI
|
||||
# define GTEST_HAS_RTTI 1
|
||||
// When building against STLport with the Android NDK and with
|
||||
// -frtti -fno-exceptions, the build fails at link time with undefined
|
||||
// references to __cxa_bad_typeid. Note sure if STL or toolchain bug,
|
||||
// so disable RTTI when detected.
|
||||
# if GTEST_OS_LINUX_ANDROID && defined(_STLPORT_MAJOR) && \
|
||||
!defined(__EXCEPTIONS)
|
||||
# define GTEST_HAS_RTTI 0
|
||||
# else
|
||||
# define GTEST_HAS_RTTI 1
|
||||
# endif // GTEST_OS_LINUX_ANDROID && __STLPORT_MAJOR && !__EXCEPTIONS
|
||||
# else
|
||||
# define GTEST_HAS_RTTI 0
|
||||
# endif // __GXX_RTTI
|
||||
|
||||
// Clang defines __GXX_RTTI starting with version 3.0, but its manual recommends
|
||||
// using has_feature instead. has_feature(cxx_rtti) is supported since 2.7, the
|
||||
// first version with C++ support.
|
||||
# elif defined(__clang__)
|
||||
|
||||
# define GTEST_HAS_RTTI __has_feature(cxx_rtti)
|
||||
|
||||
// Starting with version 9.0 IBM Visual Age defines __RTTI_ALL__ to 1 if
|
||||
// both the typeid and dynamic_cast features are present.
|
||||
# elif defined(__IBMCPP__) && (__IBMCPP__ >= 900)
|
||||
|
|
@ -417,7 +476,8 @@
|
|||
//
|
||||
// To disable threading support in Google Test, add -DGTEST_HAS_PTHREAD=0
|
||||
// to your compiler flags.
|
||||
# define GTEST_HAS_PTHREAD (GTEST_OS_LINUX || GTEST_OS_MAC || GTEST_OS_HPUX)
|
||||
# define GTEST_HAS_PTHREAD (GTEST_OS_LINUX || GTEST_OS_MAC || GTEST_OS_HPUX \
|
||||
|| GTEST_OS_QNX)
|
||||
#endif // GTEST_HAS_PTHREAD
|
||||
|
||||
#if GTEST_HAS_PTHREAD
|
||||
|
|
@ -433,8 +493,13 @@
|
|||
// this macro to 0 to prevent Google Test from using tuple (any
|
||||
// feature depending on tuple with be disabled in this mode).
|
||||
#ifndef GTEST_HAS_TR1_TUPLE
|
||||
# if GTEST_OS_LINUX_ANDROID && defined(_STLPORT_MAJOR)
|
||||
// STLport, provided with the Android NDK, has neither <tr1/tuple> or <tuple>.
|
||||
# define GTEST_HAS_TR1_TUPLE 0
|
||||
# else
|
||||
// The user didn't tell us not to do it, so we assume it's OK.
|
||||
# define GTEST_HAS_TR1_TUPLE 1
|
||||
# define GTEST_HAS_TR1_TUPLE 1
|
||||
# endif
|
||||
#endif // GTEST_HAS_TR1_TUPLE
|
||||
|
||||
// Determines whether Google Test's own tr1 tuple implementation
|
||||
|
|
@ -443,14 +508,28 @@
|
|||
// The user didn't tell us, so we need to figure it out.
|
||||
|
||||
// We use our own TR1 tuple if we aren't sure the user has an
|
||||
// implementation of it already. At this time, GCC 4.0.0+ and MSVC
|
||||
// 2010 are the only mainstream compilers that come with a TR1 tuple
|
||||
// implementation. NVIDIA's CUDA NVCC compiler pretends to be GCC by
|
||||
// defining __GNUC__ and friends, but cannot compile GCC's tuple
|
||||
// implementation. MSVC 2008 (9.0) provides TR1 tuple in a 323 MB
|
||||
// Feature Pack download, which we cannot assume the user has.
|
||||
# if (defined(__GNUC__) && !defined(__CUDACC__) && (GTEST_GCC_VER_ >= 40000)) \
|
||||
|| _MSC_VER >= 1600
|
||||
// implementation of it already. At this time, libstdc++ 4.0.0+ and
|
||||
// MSVC 2010 are the only mainstream standard libraries that come
|
||||
// with a TR1 tuple implementation. NVIDIA's CUDA NVCC compiler
|
||||
// pretends to be GCC by defining __GNUC__ and friends, but cannot
|
||||
// compile GCC's tuple implementation. MSVC 2008 (9.0) provides TR1
|
||||
// tuple in a 323 MB Feature Pack download, which we cannot assume the
|
||||
// user has. QNX's QCC compiler is a modified GCC but it doesn't
|
||||
// support TR1 tuple. libc++ only provides std::tuple, in C++11 mode,
|
||||
// and it can be used with some compilers that define __GNUC__.
|
||||
# if (defined(__GNUC__) && !defined(__CUDACC__) && (GTEST_GCC_VER_ >= 40000) \
|
||||
&& !GTEST_OS_QNX && !defined(_LIBCPP_VERSION)) || _MSC_VER >= 1600
|
||||
# define GTEST_ENV_HAS_TR1_TUPLE_ 1
|
||||
# endif
|
||||
|
||||
// C++11 specifies that <tuple> provides std::tuple. Use that if gtest is used
|
||||
// in C++11 mode and libstdc++ isn't very old (binaries targeting OS X 10.6
|
||||
// can build with clang but need to use gcc4.2's libstdc++).
|
||||
# if GTEST_LANG_CXX11 && (!defined(__GLIBCXX__) || __GLIBCXX__ > 20110325)
|
||||
# define GTEST_ENV_HAS_STD_TUPLE_ 1
|
||||
# endif
|
||||
|
||||
# if GTEST_ENV_HAS_TR1_TUPLE_ || GTEST_ENV_HAS_STD_TUPLE_
|
||||
# define GTEST_USE_OWN_TR1_TUPLE 0
|
||||
# else
|
||||
# define GTEST_USE_OWN_TR1_TUPLE 1
|
||||
|
|
@ -465,6 +544,22 @@
|
|||
|
||||
# if GTEST_USE_OWN_TR1_TUPLE
|
||||
# include "gtest/internal/gtest-tuple.h"
|
||||
# elif GTEST_ENV_HAS_STD_TUPLE_
|
||||
# include <tuple>
|
||||
// C++11 puts its tuple into the ::std namespace rather than
|
||||
// ::std::tr1. gtest expects tuple to live in ::std::tr1, so put it there.
|
||||
// This causes undefined behavior, but supported compilers react in
|
||||
// the way we intend.
|
||||
namespace std {
|
||||
namespace tr1 {
|
||||
using ::std::get;
|
||||
using ::std::make_tuple;
|
||||
using ::std::tuple;
|
||||
using ::std::tuple_element;
|
||||
using ::std::tuple_size;
|
||||
}
|
||||
}
|
||||
|
||||
# elif GTEST_OS_SYMBIAN
|
||||
|
||||
// On Symbian, BOOST_HAS_TR1_TUPLE causes Boost's TR1 tuple library to
|
||||
|
|
@ -515,7 +610,16 @@
|
|||
// The user didn't tell us, so we need to figure it out.
|
||||
|
||||
# if GTEST_OS_LINUX && !defined(__ia64__)
|
||||
# define GTEST_HAS_CLONE 1
|
||||
# if GTEST_OS_LINUX_ANDROID
|
||||
// On Android, clone() is only available on ARM starting with Gingerbread.
|
||||
# if defined(__arm__) && __ANDROID_API__ >= 9
|
||||
# define GTEST_HAS_CLONE 1
|
||||
# else
|
||||
# define GTEST_HAS_CLONE 0
|
||||
# endif
|
||||
# else
|
||||
# define GTEST_HAS_CLONE 1
|
||||
# endif
|
||||
# else
|
||||
# define GTEST_HAS_CLONE 0
|
||||
# endif // GTEST_OS_LINUX && !defined(__ia64__)
|
||||
|
|
@ -538,9 +642,11 @@
|
|||
// Google Test does not support death tests for VC 7.1 and earlier as
|
||||
// abort() in a VC 7.1 application compiled as GUI in debug config
|
||||
// pops up a dialog window that cannot be suppressed programmatically.
|
||||
#if (GTEST_OS_LINUX || GTEST_OS_MAC || GTEST_OS_CYGWIN || GTEST_OS_SOLARIS || \
|
||||
#if (GTEST_OS_LINUX || GTEST_OS_CYGWIN || GTEST_OS_SOLARIS || \
|
||||
(GTEST_OS_MAC && !GTEST_OS_IOS) || GTEST_OS_IOS_SIMULATOR || \
|
||||
(GTEST_OS_WINDOWS_DESKTOP && _MSC_VER >= 1400) || \
|
||||
GTEST_OS_WINDOWS_MINGW || GTEST_OS_AIX || GTEST_OS_HPUX)
|
||||
GTEST_OS_WINDOWS_MINGW || GTEST_OS_AIX || GTEST_OS_HPUX || \
|
||||
GTEST_OS_OPENBSD || GTEST_OS_QNX)
|
||||
# define GTEST_HAS_DEATH_TEST 1
|
||||
# include <vector> // NOLINT
|
||||
#endif
|
||||
|
|
@ -669,13 +775,23 @@
|
|||
# define GTEST_NO_INLINE_
|
||||
#endif
|
||||
|
||||
// _LIBCPP_VERSION is defined by the libc++ library from the LLVM project.
|
||||
#if defined(__GLIBCXX__) || defined(_LIBCPP_VERSION)
|
||||
# define GTEST_HAS_CXXABI_H_ 1
|
||||
#else
|
||||
# define GTEST_HAS_CXXABI_H_ 0
|
||||
#endif
|
||||
|
||||
namespace testing {
|
||||
|
||||
class Message;
|
||||
|
||||
namespace internal {
|
||||
|
||||
class String;
|
||||
// A secret type that Google Test users don't know about. It has no
|
||||
// definition on purpose. Therefore it's impossible to create a
|
||||
// Secret object, which is what we want.
|
||||
class Secret;
|
||||
|
||||
// The GTEST_COMPILE_ASSERT_ macro can be used to verify that a compile time
|
||||
// expression is true. For example, you could use it to verify the
|
||||
|
|
@ -697,8 +813,8 @@ struct CompileAssert {
|
|||
};
|
||||
|
||||
#define GTEST_COMPILE_ASSERT_(expr, msg) \
|
||||
typedef ::testing::internal::CompileAssert<(bool(expr))> \
|
||||
msg[bool(expr) ? 1 : -1]
|
||||
typedef ::testing::internal::CompileAssert<(static_cast<bool>(expr))> \
|
||||
msg[static_cast<bool>(expr) ? 1 : -1] GTEST_ATTRIBUTE_UNUSED_
|
||||
|
||||
// Implementation details of GTEST_COMPILE_ASSERT_:
|
||||
//
|
||||
|
|
@ -796,6 +912,7 @@ class scoped_ptr {
|
|||
ptr_ = p;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
T* ptr_;
|
||||
|
||||
|
|
@ -858,10 +975,9 @@ class GTEST_API_ RE {
|
|||
private:
|
||||
void Init(const char* regex);
|
||||
|
||||
// We use a const char* instead of a string, as Google Test may be used
|
||||
// where string is not available. We also do not use Google Test's own
|
||||
// String type here, in order to simplify dependencies between the
|
||||
// files.
|
||||
// We use a const char* instead of an std::string, as Google Test used to be
|
||||
// used where std::string is not available. TODO(wan@google.com): change to
|
||||
// std::string.
|
||||
const char* pattern_;
|
||||
bool is_valid_;
|
||||
|
||||
|
|
@ -1044,20 +1160,21 @@ Derived* CheckedDowncastToActualType(Base* base) {
|
|||
// GetCapturedStderr - stops capturing stderr and returns the captured string.
|
||||
//
|
||||
GTEST_API_ void CaptureStdout();
|
||||
GTEST_API_ String GetCapturedStdout();
|
||||
GTEST_API_ std::string GetCapturedStdout();
|
||||
GTEST_API_ void CaptureStderr();
|
||||
GTEST_API_ String GetCapturedStderr();
|
||||
GTEST_API_ std::string GetCapturedStderr();
|
||||
|
||||
#endif // GTEST_HAS_STREAM_REDIRECTION
|
||||
|
||||
|
||||
#if GTEST_HAS_DEATH_TEST
|
||||
|
||||
// A copy of all command line arguments. Set by InitGoogleTest().
|
||||
extern ::std::vector<String> g_argvs;
|
||||
const ::std::vector<testing::internal::string>& GetInjectableArgvs();
|
||||
void SetInjectableArgvs(const ::std::vector<testing::internal::string>*
|
||||
new_argvs);
|
||||
|
||||
// GTEST_HAS_DEATH_TEST implies we have ::std::string.
|
||||
const ::std::vector<String>& GetArgvs();
|
||||
// A copy of all command line arguments. Set by InitGoogleTest().
|
||||
extern ::std::vector<testing::internal::string> g_argvs;
|
||||
|
||||
#endif // GTEST_HAS_DEATH_TEST
|
||||
|
||||
|
|
@ -1084,22 +1201,37 @@ inline void SleepMilliseconds(int n) {
|
|||
// use it in user tests, either directly or indirectly.
|
||||
class Notification {
|
||||
public:
|
||||
Notification() : notified_(false) {}
|
||||
Notification() : notified_(false) {
|
||||
GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_init(&mutex_, NULL));
|
||||
}
|
||||
~Notification() {
|
||||
pthread_mutex_destroy(&mutex_);
|
||||
}
|
||||
|
||||
// Notifies all threads created with this notification to start. Must
|
||||
// be called from the controller thread.
|
||||
void Notify() { notified_ = true; }
|
||||
void Notify() {
|
||||
pthread_mutex_lock(&mutex_);
|
||||
notified_ = true;
|
||||
pthread_mutex_unlock(&mutex_);
|
||||
}
|
||||
|
||||
// Blocks until the controller thread notifies. Must be called from a test
|
||||
// thread.
|
||||
void WaitForNotification() {
|
||||
while(!notified_) {
|
||||
for (;;) {
|
||||
pthread_mutex_lock(&mutex_);
|
||||
const bool notified = notified_;
|
||||
pthread_mutex_unlock(&mutex_);
|
||||
if (notified)
|
||||
break;
|
||||
SleepMilliseconds(10);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
volatile bool notified_;
|
||||
pthread_mutex_t mutex_;
|
||||
bool notified_;
|
||||
|
||||
GTEST_DISALLOW_COPY_AND_ASSIGN_(Notification);
|
||||
};
|
||||
|
|
@ -1207,21 +1339,23 @@ class MutexBase {
|
|||
void Lock() {
|
||||
GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_lock(&mutex_));
|
||||
owner_ = pthread_self();
|
||||
has_owner_ = true;
|
||||
}
|
||||
|
||||
// Releases this mutex.
|
||||
void Unlock() {
|
||||
// We don't protect writing to owner_ here, as it's the caller's
|
||||
// responsibility to ensure that the current thread holds the
|
||||
// Since the lock is being released the owner_ field should no longer be
|
||||
// considered valid. We don't protect writing to has_owner_ here, as it's
|
||||
// the caller's responsibility to ensure that the current thread holds the
|
||||
// mutex when this is called.
|
||||
owner_ = 0;
|
||||
has_owner_ = false;
|
||||
GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_unlock(&mutex_));
|
||||
}
|
||||
|
||||
// Does nothing if the current thread holds the mutex. Otherwise, crashes
|
||||
// with high probability.
|
||||
void AssertHeld() const {
|
||||
GTEST_CHECK_(owner_ == pthread_self())
|
||||
GTEST_CHECK_(has_owner_ && pthread_equal(owner_, pthread_self()))
|
||||
<< "The current thread is not holding the mutex @" << this;
|
||||
}
|
||||
|
||||
|
|
@ -1232,16 +1366,33 @@ class MutexBase {
|
|||
// have to be public.
|
||||
public:
|
||||
pthread_mutex_t mutex_; // The underlying pthread mutex.
|
||||
pthread_t owner_; // The thread holding the mutex; 0 means no one holds it.
|
||||
// has_owner_ indicates whether the owner_ field below contains a valid thread
|
||||
// ID and is therefore safe to inspect (e.g., to use in pthread_equal()). All
|
||||
// accesses to the owner_ field should be protected by a check of this field.
|
||||
// An alternative might be to memset() owner_ to all zeros, but there's no
|
||||
// guarantee that a zero'd pthread_t is necessarily invalid or even different
|
||||
// from pthread_self().
|
||||
bool has_owner_;
|
||||
pthread_t owner_; // The thread holding the mutex.
|
||||
};
|
||||
|
||||
// Forward-declares a static mutex.
|
||||
# define GTEST_DECLARE_STATIC_MUTEX_(mutex) \
|
||||
extern ::testing::internal::MutexBase mutex
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wmissing-field-initializers"
|
||||
|
||||
// Defines and statically (i.e. at link time) initializes a static mutex.
|
||||
// The initialization list here does not explicitly initialize each field,
|
||||
// instead relying on default initialization for the unspecified fields. In
|
||||
// particular, the owner_ field (a pthread_t) is not explicitly initialized.
|
||||
// This allows initialization to work whether pthread_t is a scalar or struct.
|
||||
// The flag -Wmissing-field-initializers must not be specified for this to work.
|
||||
# define GTEST_DEFINE_STATIC_MUTEX_(mutex) \
|
||||
::testing::internal::MutexBase mutex = { PTHREAD_MUTEX_INITIALIZER, 0 }
|
||||
::testing::internal::MutexBase mutex = { PTHREAD_MUTEX_INITIALIZER, false }
|
||||
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
// The Mutex class can only be used for mutexes created at runtime. It
|
||||
// shares its API with MutexBase otherwise.
|
||||
|
|
@ -1249,7 +1400,7 @@ class Mutex : public MutexBase {
|
|||
public:
|
||||
Mutex() {
|
||||
GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_init(&mutex_, NULL));
|
||||
owner_ = 0;
|
||||
has_owner_ = false;
|
||||
}
|
||||
~Mutex() {
|
||||
GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_destroy(&mutex_));
|
||||
|
|
@ -1399,6 +1550,8 @@ class ThreadLocal {
|
|||
class Mutex {
|
||||
public:
|
||||
Mutex() {}
|
||||
void Lock() {}
|
||||
void Unlock() {}
|
||||
void AssertHeld() const {}
|
||||
};
|
||||
|
||||
|
|
@ -1529,6 +1682,10 @@ inline bool IsUpper(char ch) {
|
|||
inline bool IsXDigit(char ch) {
|
||||
return isxdigit(static_cast<unsigned char>(ch)) != 0;
|
||||
}
|
||||
inline bool IsXDigit(wchar_t ch) {
|
||||
const unsigned char low_byte = static_cast<unsigned char>(ch);
|
||||
return ch == low_byte && isxdigit(low_byte) != 0;
|
||||
}
|
||||
|
||||
inline char ToLower(char ch) {
|
||||
return static_cast<char>(tolower(static_cast<unsigned char>(ch)));
|
||||
|
|
@ -1666,6 +1823,23 @@ inline void Abort() { abort(); }
|
|||
|
||||
} // namespace posix
|
||||
|
||||
// MSVC "deprecates" snprintf and issues warnings wherever it is used. In
|
||||
// order to avoid these warnings, we need to use _snprintf or _snprintf_s on
|
||||
// MSVC-based platforms. We map the GTEST_SNPRINTF_ macro to the appropriate
|
||||
// function in order to achieve that. We use macro definition here because
|
||||
// snprintf is a variadic function.
|
||||
#if _MSC_VER >= 1400 && !GTEST_OS_WINDOWS_MOBILE
|
||||
// MSVC 2005 and above support variadic macros.
|
||||
# define GTEST_SNPRINTF_(buffer, size, format, ...) \
|
||||
_snprintf_s(buffer, size, size, format, __VA_ARGS__)
|
||||
#elif defined(_MSC_VER)
|
||||
// Windows CE does not define _snprintf_s and MSVC prior to 2005 doesn't
|
||||
// complain about _snprintf.
|
||||
# define GTEST_SNPRINTF_ _snprintf
|
||||
#else
|
||||
# define GTEST_SNPRINTF_ snprintf
|
||||
#endif
|
||||
|
||||
// The maximum number a BiggestInt can represent. This definition
|
||||
// works no matter BiggestInt is represented in one's complement or
|
||||
// two's complement.
|
||||
|
|
@ -1718,7 +1892,6 @@ class TypeWithSize<4> {
|
|||
template <>
|
||||
class TypeWithSize<8> {
|
||||
public:
|
||||
|
||||
#if GTEST_OS_WINDOWS
|
||||
typedef __int64 Int;
|
||||
typedef unsigned __int64 UInt;
|
||||
|
|
@ -1745,7 +1918,7 @@ typedef TypeWithSize<8>::Int TimeInMillis; // Represents time in milliseconds.
|
|||
#define GTEST_DECLARE_int32_(name) \
|
||||
GTEST_API_ extern ::testing::internal::Int32 GTEST_FLAG(name)
|
||||
#define GTEST_DECLARE_string_(name) \
|
||||
GTEST_API_ extern ::testing::internal::String GTEST_FLAG(name)
|
||||
GTEST_API_ extern ::std::string GTEST_FLAG(name)
|
||||
|
||||
// Macros for defining flags.
|
||||
#define GTEST_DEFINE_bool_(name, default_val, doc) \
|
||||
|
|
@ -1753,7 +1926,11 @@ typedef TypeWithSize<8>::Int TimeInMillis; // Represents time in milliseconds.
|
|||
#define GTEST_DEFINE_int32_(name, default_val, doc) \
|
||||
GTEST_API_ ::testing::internal::Int32 GTEST_FLAG(name) = (default_val)
|
||||
#define GTEST_DEFINE_string_(name, default_val, doc) \
|
||||
GTEST_API_ ::testing::internal::String GTEST_FLAG(name) = (default_val)
|
||||
GTEST_API_ ::std::string GTEST_FLAG(name) = (default_val)
|
||||
|
||||
// Thread annotations
|
||||
#define GTEST_EXCLUSIVE_LOCK_REQUIRED_(locks)
|
||||
#define GTEST_LOCK_EXCLUDED_(locks)
|
||||
|
||||
// Parses 'str' for a 32-bit signed integer. If successful, writes the result
|
||||
// to *value and returns true; otherwise leaves *value unchanged and returns
|
||||
167
lib/gtest/include/gtest/internal/gtest-string.h
Normal file
167
lib/gtest/include/gtest/internal/gtest-string.h
Normal file
|
|
@ -0,0 +1,167 @@
|
|||
// Copyright 2005, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee)
|
||||
//
|
||||
// The Google C++ Testing Framework (Google Test)
|
||||
//
|
||||
// This header file declares the String class and functions used internally by
|
||||
// Google Test. They are subject to change without notice. They should not used
|
||||
// by code external to Google Test.
|
||||
//
|
||||
// This header file is #included by <gtest/internal/gtest-internal.h>.
|
||||
// It should not be #included by other files.
|
||||
|
||||
#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_
|
||||
#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_
|
||||
|
||||
#ifdef __BORLANDC__
|
||||
// string.h is not guaranteed to provide strcpy on C++ Builder.
|
||||
# include <mem.h>
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
#include <string>
|
||||
|
||||
#include "gtest/internal/gtest-port.h"
|
||||
|
||||
namespace testing {
|
||||
namespace internal {
|
||||
|
||||
// String - an abstract class holding static string utilities.
|
||||
class GTEST_API_ String {
|
||||
public:
|
||||
// Static utility methods
|
||||
|
||||
// Clones a 0-terminated C string, allocating memory using new. The
|
||||
// caller is responsible for deleting the return value using
|
||||
// delete[]. Returns the cloned string, or NULL if the input is
|
||||
// NULL.
|
||||
//
|
||||
// This is different from strdup() in string.h, which allocates
|
||||
// memory using malloc().
|
||||
static const char* CloneCString(const char* c_str);
|
||||
|
||||
#if GTEST_OS_WINDOWS_MOBILE
|
||||
// Windows CE does not have the 'ANSI' versions of Win32 APIs. To be
|
||||
// able to pass strings to Win32 APIs on CE we need to convert them
|
||||
// to 'Unicode', UTF-16.
|
||||
|
||||
// Creates a UTF-16 wide string from the given ANSI string, allocating
|
||||
// memory using new. The caller is responsible for deleting the return
|
||||
// value using delete[]. Returns the wide string, or NULL if the
|
||||
// input is NULL.
|
||||
//
|
||||
// The wide string is created using the ANSI codepage (CP_ACP) to
|
||||
// match the behaviour of the ANSI versions of Win32 calls and the
|
||||
// C runtime.
|
||||
static LPCWSTR AnsiToUtf16(const char* c_str);
|
||||
|
||||
// Creates an ANSI string from the given wide string, allocating
|
||||
// memory using new. The caller is responsible for deleting the return
|
||||
// value using delete[]. Returns the ANSI string, or NULL if the
|
||||
// input is NULL.
|
||||
//
|
||||
// The returned string is created using the ANSI codepage (CP_ACP) to
|
||||
// match the behaviour of the ANSI versions of Win32 calls and the
|
||||
// C runtime.
|
||||
static const char* Utf16ToAnsi(LPCWSTR utf16_str);
|
||||
#endif
|
||||
|
||||
// Compares two C strings. Returns true iff they have the same content.
|
||||
//
|
||||
// Unlike strcmp(), this function can handle NULL argument(s). A
|
||||
// NULL C string is considered different to any non-NULL C string,
|
||||
// including the empty string.
|
||||
static bool CStringEquals(const char* lhs, const char* rhs);
|
||||
|
||||
// Converts a wide C string to a String using the UTF-8 encoding.
|
||||
// NULL will be converted to "(null)". If an error occurred during
|
||||
// the conversion, "(failed to convert from wide string)" is
|
||||
// returned.
|
||||
static std::string ShowWideCString(const wchar_t* wide_c_str);
|
||||
|
||||
// Compares two wide C strings. Returns true iff they have the same
|
||||
// content.
|
||||
//
|
||||
// Unlike wcscmp(), this function can handle NULL argument(s). A
|
||||
// NULL C string is considered different to any non-NULL C string,
|
||||
// including the empty string.
|
||||
static bool WideCStringEquals(const wchar_t* lhs, const wchar_t* rhs);
|
||||
|
||||
// Compares two C strings, ignoring case. Returns true iff they
|
||||
// have the same content.
|
||||
//
|
||||
// Unlike strcasecmp(), this function can handle NULL argument(s).
|
||||
// A NULL C string is considered different to any non-NULL C string,
|
||||
// including the empty string.
|
||||
static bool CaseInsensitiveCStringEquals(const char* lhs,
|
||||
const char* rhs);
|
||||
|
||||
// Compares two wide C strings, ignoring case. Returns true iff they
|
||||
// have the same content.
|
||||
//
|
||||
// Unlike wcscasecmp(), this function can handle NULL argument(s).
|
||||
// A NULL C string is considered different to any non-NULL wide C string,
|
||||
// including the empty string.
|
||||
// NB: The implementations on different platforms slightly differ.
|
||||
// On windows, this method uses _wcsicmp which compares according to LC_CTYPE
|
||||
// environment variable. On GNU platform this method uses wcscasecmp
|
||||
// which compares according to LC_CTYPE category of the current locale.
|
||||
// On MacOS X, it uses towlower, which also uses LC_CTYPE category of the
|
||||
// current locale.
|
||||
static bool CaseInsensitiveWideCStringEquals(const wchar_t* lhs,
|
||||
const wchar_t* rhs);
|
||||
|
||||
// Returns true iff the given string ends with the given suffix, ignoring
|
||||
// case. Any string is considered to end with an empty suffix.
|
||||
static bool EndsWithCaseInsensitive(
|
||||
const std::string& str, const std::string& suffix);
|
||||
|
||||
// Formats an int value as "%02d".
|
||||
static std::string FormatIntWidth2(int value); // "%02d" for width == 2
|
||||
|
||||
// Formats an int value as "%X".
|
||||
static std::string FormatHexInt(int value);
|
||||
|
||||
// Formats a byte as "%02X".
|
||||
static std::string FormatByte(unsigned char value);
|
||||
|
||||
private:
|
||||
String(); // Not meant to be instantiated.
|
||||
}; // class String
|
||||
|
||||
// Gets the content of the stringstream's buffer as an std::string. Each '\0'
|
||||
// character in the buffer is replaced with "\\0".
|
||||
GTEST_API_ std::string StringStreamToString(::std::stringstream* stream);
|
||||
|
||||
} // namespace internal
|
||||
} // namespace testing
|
||||
|
||||
#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_
|
||||
|
|
@ -1,4 +1,6 @@
|
|||
// This file was GENERATED by a script. DO NOT EDIT BY HAND!!!
|
||||
// This file was GENERATED by command:
|
||||
// pump.py gtest-tuple.h.pump
|
||||
// DO NOT EDIT BY HAND!!!
|
||||
|
||||
// Copyright 2009 Google Inc.
|
||||
// All Rights Reserved.
|
||||
|
|
@ -140,34 +142,54 @@ template <bool kIndexValid, int kIndex, class Tuple>
|
|||
struct TupleElement;
|
||||
|
||||
template <GTEST_10_TYPENAMES_(T)>
|
||||
struct TupleElement<true, 0, GTEST_10_TUPLE_(T)> { typedef T0 type; };
|
||||
struct TupleElement<true, 0, GTEST_10_TUPLE_(T) > {
|
||||
typedef T0 type;
|
||||
};
|
||||
|
||||
template <GTEST_10_TYPENAMES_(T)>
|
||||
struct TupleElement<true, 1, GTEST_10_TUPLE_(T)> { typedef T1 type; };
|
||||
struct TupleElement<true, 1, GTEST_10_TUPLE_(T) > {
|
||||
typedef T1 type;
|
||||
};
|
||||
|
||||
template <GTEST_10_TYPENAMES_(T)>
|
||||
struct TupleElement<true, 2, GTEST_10_TUPLE_(T)> { typedef T2 type; };
|
||||
struct TupleElement<true, 2, GTEST_10_TUPLE_(T) > {
|
||||
typedef T2 type;
|
||||
};
|
||||
|
||||
template <GTEST_10_TYPENAMES_(T)>
|
||||
struct TupleElement<true, 3, GTEST_10_TUPLE_(T)> { typedef T3 type; };
|
||||
struct TupleElement<true, 3, GTEST_10_TUPLE_(T) > {
|
||||
typedef T3 type;
|
||||
};
|
||||
|
||||
template <GTEST_10_TYPENAMES_(T)>
|
||||
struct TupleElement<true, 4, GTEST_10_TUPLE_(T)> { typedef T4 type; };
|
||||
struct TupleElement<true, 4, GTEST_10_TUPLE_(T) > {
|
||||
typedef T4 type;
|
||||
};
|
||||
|
||||
template <GTEST_10_TYPENAMES_(T)>
|
||||
struct TupleElement<true, 5, GTEST_10_TUPLE_(T)> { typedef T5 type; };
|
||||
struct TupleElement<true, 5, GTEST_10_TUPLE_(T) > {
|
||||
typedef T5 type;
|
||||
};
|
||||
|
||||
template <GTEST_10_TYPENAMES_(T)>
|
||||
struct TupleElement<true, 6, GTEST_10_TUPLE_(T)> { typedef T6 type; };
|
||||
struct TupleElement<true, 6, GTEST_10_TUPLE_(T) > {
|
||||
typedef T6 type;
|
||||
};
|
||||
|
||||
template <GTEST_10_TYPENAMES_(T)>
|
||||
struct TupleElement<true, 7, GTEST_10_TUPLE_(T)> { typedef T7 type; };
|
||||
struct TupleElement<true, 7, GTEST_10_TUPLE_(T) > {
|
||||
typedef T7 type;
|
||||
};
|
||||
|
||||
template <GTEST_10_TYPENAMES_(T)>
|
||||
struct TupleElement<true, 8, GTEST_10_TUPLE_(T)> { typedef T8 type; };
|
||||
struct TupleElement<true, 8, GTEST_10_TUPLE_(T) > {
|
||||
typedef T8 type;
|
||||
};
|
||||
|
||||
template <GTEST_10_TYPENAMES_(T)>
|
||||
struct TupleElement<true, 9, GTEST_10_TUPLE_(T)> { typedef T9 type; };
|
||||
struct TupleElement<true, 9, GTEST_10_TUPLE_(T) > {
|
||||
typedef T9 type;
|
||||
};
|
||||
|
||||
} // namespace gtest_internal
|
||||
|
||||
|
|
@ -708,37 +730,59 @@ inline GTEST_10_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2,
|
|||
template <typename Tuple> struct tuple_size;
|
||||
|
||||
template <GTEST_0_TYPENAMES_(T)>
|
||||
struct tuple_size<GTEST_0_TUPLE_(T)> { static const int value = 0; };
|
||||
struct tuple_size<GTEST_0_TUPLE_(T) > {
|
||||
static const int value = 0;
|
||||
};
|
||||
|
||||
template <GTEST_1_TYPENAMES_(T)>
|
||||
struct tuple_size<GTEST_1_TUPLE_(T)> { static const int value = 1; };
|
||||
struct tuple_size<GTEST_1_TUPLE_(T) > {
|
||||
static const int value = 1;
|
||||
};
|
||||
|
||||
template <GTEST_2_TYPENAMES_(T)>
|
||||
struct tuple_size<GTEST_2_TUPLE_(T)> { static const int value = 2; };
|
||||
struct tuple_size<GTEST_2_TUPLE_(T) > {
|
||||
static const int value = 2;
|
||||
};
|
||||
|
||||
template <GTEST_3_TYPENAMES_(T)>
|
||||
struct tuple_size<GTEST_3_TUPLE_(T)> { static const int value = 3; };
|
||||
struct tuple_size<GTEST_3_TUPLE_(T) > {
|
||||
static const int value = 3;
|
||||
};
|
||||
|
||||
template <GTEST_4_TYPENAMES_(T)>
|
||||
struct tuple_size<GTEST_4_TUPLE_(T)> { static const int value = 4; };
|
||||
struct tuple_size<GTEST_4_TUPLE_(T) > {
|
||||
static const int value = 4;
|
||||
};
|
||||
|
||||
template <GTEST_5_TYPENAMES_(T)>
|
||||
struct tuple_size<GTEST_5_TUPLE_(T)> { static const int value = 5; };
|
||||
struct tuple_size<GTEST_5_TUPLE_(T) > {
|
||||
static const int value = 5;
|
||||
};
|
||||
|
||||
template <GTEST_6_TYPENAMES_(T)>
|
||||
struct tuple_size<GTEST_6_TUPLE_(T)> { static const int value = 6; };
|
||||
struct tuple_size<GTEST_6_TUPLE_(T) > {
|
||||
static const int value = 6;
|
||||
};
|
||||
|
||||
template <GTEST_7_TYPENAMES_(T)>
|
||||
struct tuple_size<GTEST_7_TUPLE_(T)> { static const int value = 7; };
|
||||
struct tuple_size<GTEST_7_TUPLE_(T) > {
|
||||
static const int value = 7;
|
||||
};
|
||||
|
||||
template <GTEST_8_TYPENAMES_(T)>
|
||||
struct tuple_size<GTEST_8_TUPLE_(T)> { static const int value = 8; };
|
||||
struct tuple_size<GTEST_8_TUPLE_(T) > {
|
||||
static const int value = 8;
|
||||
};
|
||||
|
||||
template <GTEST_9_TYPENAMES_(T)>
|
||||
struct tuple_size<GTEST_9_TUPLE_(T)> { static const int value = 9; };
|
||||
struct tuple_size<GTEST_9_TUPLE_(T) > {
|
||||
static const int value = 9;
|
||||
};
|
||||
|
||||
template <GTEST_10_TYPENAMES_(T)>
|
||||
struct tuple_size<GTEST_10_TUPLE_(T)> { static const int value = 10; };
|
||||
struct tuple_size<GTEST_10_TUPLE_(T) > {
|
||||
static const int value = 10;
|
||||
};
|
||||
|
||||
template <int k, class Tuple>
|
||||
struct tuple_element {
|
||||
|
|
@ -922,8 +966,8 @@ template <GTEST_10_TYPENAMES_(T), GTEST_10_TYPENAMES_(U)>
|
|||
inline bool operator==(const GTEST_10_TUPLE_(T)& t,
|
||||
const GTEST_10_TUPLE_(U)& u) {
|
||||
return gtest_internal::SameSizeTuplePrefixComparator<
|
||||
tuple_size<GTEST_10_TUPLE_(T)>::value,
|
||||
tuple_size<GTEST_10_TUPLE_(U)>::value>::Eq(t, u);
|
||||
tuple_size<GTEST_10_TUPLE_(T) >::value,
|
||||
tuple_size<GTEST_10_TUPLE_(U) >::value>::Eq(t, u);
|
||||
}
|
||||
|
||||
template <GTEST_10_TYPENAMES_(T), GTEST_10_TYPENAMES_(U)>
|
||||
|
|
@ -118,8 +118,9 @@ struct TupleElement;
|
|||
|
||||
$for i [[
|
||||
template <GTEST_$(n)_TYPENAMES_(T)>
|
||||
struct TupleElement<true, $i, GTEST_$(n)_TUPLE_(T)> [[]]
|
||||
{ typedef T$i type; };
|
||||
struct TupleElement<true, $i, GTEST_$(n)_TUPLE_(T) > {
|
||||
typedef T$i type;
|
||||
};
|
||||
|
||||
|
||||
]]
|
||||
|
|
@ -220,7 +221,9 @@ template <typename Tuple> struct tuple_size;
|
|||
|
||||
$for j [[
|
||||
template <GTEST_$(j)_TYPENAMES_(T)>
|
||||
struct tuple_size<GTEST_$(j)_TUPLE_(T)> { static const int value = $j; };
|
||||
struct tuple_size<GTEST_$(j)_TUPLE_(T) > {
|
||||
static const int value = $j;
|
||||
};
|
||||
|
||||
|
||||
]]
|
||||
|
|
@ -302,8 +305,8 @@ template <GTEST_$(n)_TYPENAMES_(T), GTEST_$(n)_TYPENAMES_(U)>
|
|||
inline bool operator==(const GTEST_$(n)_TUPLE_(T)& t,
|
||||
const GTEST_$(n)_TUPLE_(U)& u) {
|
||||
return gtest_internal::SameSizeTuplePrefixComparator<
|
||||
tuple_size<GTEST_$(n)_TUPLE_(T)>::value,
|
||||
tuple_size<GTEST_$(n)_TUPLE_(U)>::value>::Eq(t, u);
|
||||
tuple_size<GTEST_$(n)_TUPLE_(T) >::value,
|
||||
tuple_size<GTEST_$(n)_TUPLE_(U) >::value>::Eq(t, u);
|
||||
}
|
||||
|
||||
template <GTEST_$(n)_TYPENAMES_(T), GTEST_$(n)_TYPENAMES_(U)>
|
||||
|
|
@ -45,15 +45,14 @@
|
|||
#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_
|
||||
|
||||
#include "gtest/internal/gtest-port.h"
|
||||
#include "gtest/internal/gtest-string.h"
|
||||
|
||||
// #ifdef __GNUC__ is too general here. It is possible to use gcc without using
|
||||
// libstdc++ (which is where cxxabi.h comes from).
|
||||
# ifdef __GLIBCXX__
|
||||
# if GTEST_HAS_CXXABI_H_
|
||||
# include <cxxabi.h>
|
||||
# elif defined(__HP_aCC)
|
||||
# include <acxx_demangle.h>
|
||||
# endif // __GLIBCXX__
|
||||
# endif // GTEST_HASH_CXXABI_H_
|
||||
|
||||
namespace testing {
|
||||
namespace internal {
|
||||
|
|
@ -62,24 +61,24 @@ namespace internal {
|
|||
// NB: This function is also used in Google Mock, so don't move it inside of
|
||||
// the typed-test-only section below.
|
||||
template <typename T>
|
||||
String GetTypeName() {
|
||||
std::string GetTypeName() {
|
||||
# if GTEST_HAS_RTTI
|
||||
|
||||
const char* const name = typeid(T).name();
|
||||
# if defined(__GLIBCXX__) || defined(__HP_aCC)
|
||||
# if GTEST_HAS_CXXABI_H_ || defined(__HP_aCC)
|
||||
int status = 0;
|
||||
// gcc's implementation of typeid(T).name() mangles the type name,
|
||||
// so we have to demangle it.
|
||||
# ifdef __GLIBCXX__
|
||||
# if GTEST_HAS_CXXABI_H_
|
||||
using abi::__cxa_demangle;
|
||||
# endif // __GLIBCXX__
|
||||
# endif // GTEST_HAS_CXXABI_H_
|
||||
char* const readable_name = __cxa_demangle(name, 0, 0, &status);
|
||||
const String name_str(status == 0 ? readable_name : name);
|
||||
const std::string name_str(status == 0 ? readable_name : name);
|
||||
free(readable_name);
|
||||
return name_str;
|
||||
# else
|
||||
return name;
|
||||
# endif // __GLIBCXX__ || __HP_aCC
|
||||
# endif // GTEST_HAS_CXXABI_H_ || __HP_aCC
|
||||
|
||||
# else
|
||||
|
||||
|
|
@ -3300,7 +3299,9 @@ struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
|
|||
// INSTANTIATE_TYPED_TEST_CASE_P().
|
||||
|
||||
template <typename T>
|
||||
struct TypeList { typedef Types1<T> type; };
|
||||
struct TypeList {
|
||||
typedef Types1<T> type;
|
||||
};
|
||||
|
||||
template <typename T1, typename T2, typename T3, typename T4, typename T5,
|
||||
typename T6, typename T7, typename T8, typename T9, typename T10,
|
||||
|
|
@ -43,15 +43,14 @@ $var n = 50 $$ Maximum length of type lists we want to support.
|
|||
#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_
|
||||
|
||||
#include "gtest/internal/gtest-port.h"
|
||||
#include "gtest/internal/gtest-string.h"
|
||||
|
||||
// #ifdef __GNUC__ is too general here. It is possible to use gcc without using
|
||||
// libstdc++ (which is where cxxabi.h comes from).
|
||||
# ifdef __GLIBCXX__
|
||||
# if GTEST_HAS_CXXABI_H_
|
||||
# include <cxxabi.h>
|
||||
# elif defined(__HP_aCC)
|
||||
# include <acxx_demangle.h>
|
||||
# endif // __GLIBCXX__
|
||||
# endif // GTEST_HASH_CXXABI_H_
|
||||
|
||||
namespace testing {
|
||||
namespace internal {
|
||||
|
|
@ -60,24 +59,24 @@ namespace internal {
|
|||
// NB: This function is also used in Google Mock, so don't move it inside of
|
||||
// the typed-test-only section below.
|
||||
template <typename T>
|
||||
String GetTypeName() {
|
||||
std::string GetTypeName() {
|
||||
# if GTEST_HAS_RTTI
|
||||
|
||||
const char* const name = typeid(T).name();
|
||||
# if defined(__GLIBCXX__) || defined(__HP_aCC)
|
||||
# if GTEST_HAS_CXXABI_H_ || defined(__HP_aCC)
|
||||
int status = 0;
|
||||
// gcc's implementation of typeid(T).name() mangles the type name,
|
||||
// so we have to demangle it.
|
||||
# ifdef __GLIBCXX__
|
||||
# if GTEST_HAS_CXXABI_H_
|
||||
using abi::__cxa_demangle;
|
||||
# endif // __GLIBCXX__
|
||||
# endif // GTEST_HAS_CXXABI_H_
|
||||
char* const readable_name = __cxa_demangle(name, 0, 0, &status);
|
||||
const String name_str(status == 0 ? readable_name : name);
|
||||
const std::string name_str(status == 0 ? readable_name : name);
|
||||
free(readable_name);
|
||||
return name_str;
|
||||
# else
|
||||
return name;
|
||||
# endif // __GLIBCXX__ || __HP_aCC
|
||||
# endif // GTEST_HAS_CXXABI_H_ || __HP_aCC
|
||||
|
||||
# else
|
||||
|
||||
|
|
@ -279,7 +278,9 @@ struct Templates<$for j, [[T$j]]$for k[[, NoneT]]> {
|
|||
// INSTANTIATE_TYPED_TEST_CASE_P().
|
||||
|
||||
template <typename T>
|
||||
struct TypeList { typedef Types1<T> type; };
|
||||
struct TypeList {
|
||||
typedef Types1<T> type;
|
||||
};
|
||||
|
||||
|
||||
$range i 1..n
|
||||
82
lib/gtest/make/Makefile
Normal file
82
lib/gtest/make/Makefile
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
# A sample Makefile for building Google Test and using it in user
|
||||
# tests. Please tweak it to suit your environment and project. You
|
||||
# may want to move it to your project's root directory.
|
||||
#
|
||||
# SYNOPSIS:
|
||||
#
|
||||
# make [all] - makes everything.
|
||||
# make TARGET - makes the given target.
|
||||
# make clean - removes all files generated by make.
|
||||
|
||||
# Please tweak the following variable definitions as needed by your
|
||||
# project, except GTEST_HEADERS, which you can use in your own targets
|
||||
# but shouldn't modify.
|
||||
|
||||
# Points to the root of Google Test, relative to where this file is.
|
||||
# Remember to tweak this if you move this file.
|
||||
GTEST_DIR = ..
|
||||
|
||||
# Where to find user code.
|
||||
USER_DIR = ../samples
|
||||
|
||||
# Flags passed to the preprocessor.
|
||||
# Set Google Test's header directory as a system directory, such that
|
||||
# the compiler doesn't generate warnings in Google Test headers.
|
||||
CPPFLAGS += -isystem $(GTEST_DIR)/include
|
||||
|
||||
# Flags passed to the C++ compiler.
|
||||
CXXFLAGS += -g -Wall -Wextra -pthread
|
||||
|
||||
# All tests produced by this Makefile. Remember to add new tests you
|
||||
# created to the list.
|
||||
TESTS = sample1_unittest
|
||||
|
||||
# All Google Test headers. Usually you shouldn't change this
|
||||
# definition.
|
||||
GTEST_HEADERS = $(GTEST_DIR)/include/gtest/*.h \
|
||||
$(GTEST_DIR)/include/gtest/internal/*.h
|
||||
|
||||
# House-keeping build targets.
|
||||
|
||||
all : $(TESTS)
|
||||
|
||||
clean :
|
||||
rm -f $(TESTS) gtest.a gtest_main.a *.o
|
||||
|
||||
# Builds gtest.a and gtest_main.a.
|
||||
|
||||
# Usually you shouldn't tweak such internal variables, indicated by a
|
||||
# trailing _.
|
||||
GTEST_SRCS_ = $(GTEST_DIR)/src/*.cc $(GTEST_DIR)/src/*.h $(GTEST_HEADERS)
|
||||
|
||||
# For simplicity and to avoid depending on Google Test's
|
||||
# implementation details, the dependencies specified below are
|
||||
# conservative and not optimized. This is fine as Google Test
|
||||
# compiles fast and for ordinary users its source rarely changes.
|
||||
gtest-all.o : $(GTEST_SRCS_)
|
||||
$(CXX) $(CPPFLAGS) -I$(GTEST_DIR) $(CXXFLAGS) -c \
|
||||
$(GTEST_DIR)/src/gtest-all.cc
|
||||
|
||||
gtest_main.o : $(GTEST_SRCS_)
|
||||
$(CXX) $(CPPFLAGS) -I$(GTEST_DIR) $(CXXFLAGS) -c \
|
||||
$(GTEST_DIR)/src/gtest_main.cc
|
||||
|
||||
gtest.a : gtest-all.o
|
||||
$(AR) $(ARFLAGS) $@ $^
|
||||
|
||||
gtest_main.a : gtest-all.o gtest_main.o
|
||||
$(AR) $(ARFLAGS) $@ $^
|
||||
|
||||
# Builds a sample test. A test should link with either gtest.a or
|
||||
# gtest_main.a, depending on whether it defines its own main()
|
||||
# function.
|
||||
|
||||
sample1.o : $(USER_DIR)/sample1.cc $(USER_DIR)/sample1.h $(GTEST_HEADERS)
|
||||
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/sample1.cc
|
||||
|
||||
sample1_unittest.o : $(USER_DIR)/sample1_unittest.cc \
|
||||
$(USER_DIR)/sample1.h $(GTEST_HEADERS)
|
||||
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/sample1_unittest.cc
|
||||
|
||||
sample1_unittest : sample1.o sample1_unittest.o gtest_main.a
|
||||
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
|
||||
19
lib/yaml/LICENSE
Normal file
19
lib/yaml/LICENSE
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
Copyright (c) 2006 Kirill Simonov
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
27
lib/yaml/README
Normal file
27
lib/yaml/README
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
LibYAML - A C library for parsing and emitting YAML.
|
||||
|
||||
To build and install the library, run:
|
||||
$ ./configure
|
||||
$ make
|
||||
# make install
|
||||
|
||||
If you checked the source code from the Subversion repository, run
|
||||
$ ./bootstrap
|
||||
$ ./configure
|
||||
$ make
|
||||
# make install
|
||||
|
||||
For more information, check the LibYAML homepage:
|
||||
'http://pyyaml.org/wiki/LibYAML'.
|
||||
|
||||
Post your questions and opinions to the YAML-Core mailing list:
|
||||
'http://lists.sourceforge.net/lists/listinfo/yaml-core'.
|
||||
|
||||
Submit bug reports and feature requests to the LibYAML bug tracker:
|
||||
'http://pyyaml.org/newticket?component=libyaml'.
|
||||
|
||||
LibYAML is written by Kirill Simonov <xi@resolvent.net>. It is released
|
||||
under the MIT license. See the file LICENSE for more details.
|
||||
|
||||
This project is developed for Python Software Foundation as a part of
|
||||
Google Summer of Code under the mentorship of Clark Evans.
|
||||
37
lib/yaml/SConscript
Normal file
37
lib/yaml/SConscript
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
# SConscript
|
||||
# vim: set ft=python:
|
||||
#
|
||||
# Eryn Wells <eryn@erynwells.me>
|
||||
|
||||
Import('env')
|
||||
Import('build_env')
|
||||
|
||||
|
||||
include_dir = env.Dir('include').srcnode()
|
||||
env.Append(CPPPATH=[include_dir])
|
||||
build_env.Append(CPPPATH=[include_dir])
|
||||
|
||||
env.Append(CPPDEFINES=[('YAML_VERSION_STRING', '\\"0.1.5\\"'),
|
||||
('YAML_VERSION_MAJOR', '0'),
|
||||
('YAML_VERSION_MINOR', '1'),
|
||||
('YAML_VERSION_PATCH', '5')])
|
||||
|
||||
|
||||
files = [
|
||||
'api.c',
|
||||
'dumper.c',
|
||||
'emitter.c',
|
||||
'loader.c',
|
||||
'parser.c',
|
||||
'reader.c',
|
||||
'scanner.c',
|
||||
'writer.c',
|
||||
]
|
||||
|
||||
objs = []
|
||||
for f in files:
|
||||
objs.append(env.Object(f))
|
||||
|
||||
|
||||
yaml = env.Library('yaml', objs)
|
||||
env.Alias('libyaml', yaml)
|
||||
1392
lib/yaml/api.c
Normal file
1392
lib/yaml/api.c
Normal file
File diff suppressed because it is too large
Load diff
394
lib/yaml/dumper.c
Normal file
394
lib/yaml/dumper.c
Normal file
|
|
@ -0,0 +1,394 @@
|
|||
|
||||
#include "yaml_private.h"
|
||||
|
||||
/*
|
||||
* API functions.
|
||||
*/
|
||||
|
||||
YAML_DECLARE(int)
|
||||
yaml_emitter_open(yaml_emitter_t *emitter);
|
||||
|
||||
YAML_DECLARE(int)
|
||||
yaml_emitter_close(yaml_emitter_t *emitter);
|
||||
|
||||
YAML_DECLARE(int)
|
||||
yaml_emitter_dump(yaml_emitter_t *emitter, yaml_document_t *document);
|
||||
|
||||
/*
|
||||
* Clean up functions.
|
||||
*/
|
||||
|
||||
static void
|
||||
yaml_emitter_delete_document_and_anchors(yaml_emitter_t *emitter);
|
||||
|
||||
/*
|
||||
* Anchor functions.
|
||||
*/
|
||||
|
||||
static void
|
||||
yaml_emitter_anchor_node(yaml_emitter_t *emitter, int index);
|
||||
|
||||
static yaml_char_t *
|
||||
yaml_emitter_generate_anchor(yaml_emitter_t *emitter, int anchor_id);
|
||||
|
||||
|
||||
/*
|
||||
* Serialize functions.
|
||||
*/
|
||||
|
||||
static int
|
||||
yaml_emitter_dump_node(yaml_emitter_t *emitter, int index);
|
||||
|
||||
static int
|
||||
yaml_emitter_dump_alias(yaml_emitter_t *emitter, yaml_char_t *anchor);
|
||||
|
||||
static int
|
||||
yaml_emitter_dump_scalar(yaml_emitter_t *emitter, yaml_node_t *node,
|
||||
yaml_char_t *anchor);
|
||||
|
||||
static int
|
||||
yaml_emitter_dump_sequence(yaml_emitter_t *emitter, yaml_node_t *node,
|
||||
yaml_char_t *anchor);
|
||||
|
||||
static int
|
||||
yaml_emitter_dump_mapping(yaml_emitter_t *emitter, yaml_node_t *node,
|
||||
yaml_char_t *anchor);
|
||||
|
||||
/*
|
||||
* Issue a STREAM-START event.
|
||||
*/
|
||||
|
||||
YAML_DECLARE(int)
|
||||
yaml_emitter_open(yaml_emitter_t *emitter)
|
||||
{
|
||||
yaml_event_t event;
|
||||
yaml_mark_t mark = { 0, 0, 0 };
|
||||
|
||||
assert(emitter); /* Non-NULL emitter object is required. */
|
||||
assert(!emitter->opened); /* Emitter should not be opened yet. */
|
||||
|
||||
STREAM_START_EVENT_INIT(event, YAML_ANY_ENCODING, mark, mark);
|
||||
|
||||
if (!yaml_emitter_emit(emitter, &event)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
emitter->opened = 1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Issue a STREAM-END event.
|
||||
*/
|
||||
|
||||
YAML_DECLARE(int)
|
||||
yaml_emitter_close(yaml_emitter_t *emitter)
|
||||
{
|
||||
yaml_event_t event;
|
||||
yaml_mark_t mark = { 0, 0, 0 };
|
||||
|
||||
assert(emitter); /* Non-NULL emitter object is required. */
|
||||
assert(emitter->opened); /* Emitter should be opened. */
|
||||
|
||||
if (emitter->closed) return 1;
|
||||
|
||||
STREAM_END_EVENT_INIT(event, mark, mark);
|
||||
|
||||
if (!yaml_emitter_emit(emitter, &event)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
emitter->closed = 1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Dump a YAML document.
|
||||
*/
|
||||
|
||||
YAML_DECLARE(int)
|
||||
yaml_emitter_dump(yaml_emitter_t *emitter, yaml_document_t *document)
|
||||
{
|
||||
yaml_event_t event;
|
||||
yaml_mark_t mark = { 0, 0, 0 };
|
||||
|
||||
assert(emitter); /* Non-NULL emitter object is required. */
|
||||
assert(document); /* Non-NULL emitter object is expected. */
|
||||
|
||||
emitter->document = document;
|
||||
|
||||
if (!emitter->opened) {
|
||||
if (!yaml_emitter_open(emitter)) goto error;
|
||||
}
|
||||
|
||||
if (STACK_EMPTY(emitter, document->nodes)) {
|
||||
if (!yaml_emitter_close(emitter)) goto error;
|
||||
yaml_emitter_delete_document_and_anchors(emitter);
|
||||
return 1;
|
||||
}
|
||||
|
||||
assert(emitter->opened); /* Emitter should be opened. */
|
||||
|
||||
emitter->anchors = yaml_malloc(sizeof(*(emitter->anchors))
|
||||
* (document->nodes.top - document->nodes.start));
|
||||
if (!emitter->anchors) goto error;
|
||||
memset(emitter->anchors, 0, sizeof(*(emitter->anchors))
|
||||
* (document->nodes.top - document->nodes.start));
|
||||
|
||||
DOCUMENT_START_EVENT_INIT(event, document->version_directive,
|
||||
document->tag_directives.start, document->tag_directives.end,
|
||||
document->start_implicit, mark, mark);
|
||||
if (!yaml_emitter_emit(emitter, &event)) goto error;
|
||||
|
||||
yaml_emitter_anchor_node(emitter, 1);
|
||||
if (!yaml_emitter_dump_node(emitter, 1)) goto error;
|
||||
|
||||
DOCUMENT_END_EVENT_INIT(event, document->end_implicit, mark, mark);
|
||||
if (!yaml_emitter_emit(emitter, &event)) goto error;
|
||||
|
||||
yaml_emitter_delete_document_and_anchors(emitter);
|
||||
|
||||
return 1;
|
||||
|
||||
error:
|
||||
|
||||
yaml_emitter_delete_document_and_anchors(emitter);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Clean up the emitter object after a document is dumped.
|
||||
*/
|
||||
|
||||
static void
|
||||
yaml_emitter_delete_document_and_anchors(yaml_emitter_t *emitter)
|
||||
{
|
||||
int index;
|
||||
|
||||
if (!emitter->anchors) {
|
||||
yaml_document_delete(emitter->document);
|
||||
emitter->document = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
for (index = 0; emitter->document->nodes.start + index
|
||||
< emitter->document->nodes.top; index ++) {
|
||||
yaml_node_t node = emitter->document->nodes.start[index];
|
||||
if (!emitter->anchors[index].serialized) {
|
||||
yaml_free(node.tag);
|
||||
if (node.type == YAML_SCALAR_NODE) {
|
||||
yaml_free(node.data.scalar.value);
|
||||
}
|
||||
}
|
||||
if (node.type == YAML_SEQUENCE_NODE) {
|
||||
STACK_DEL(emitter, node.data.sequence.items);
|
||||
}
|
||||
if (node.type == YAML_MAPPING_NODE) {
|
||||
STACK_DEL(emitter, node.data.mapping.pairs);
|
||||
}
|
||||
}
|
||||
|
||||
STACK_DEL(emitter, emitter->document->nodes);
|
||||
yaml_free(emitter->anchors);
|
||||
|
||||
emitter->anchors = NULL;
|
||||
emitter->last_anchor_id = 0;
|
||||
emitter->document = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check the references of a node and assign the anchor id if needed.
|
||||
*/
|
||||
|
||||
static void
|
||||
yaml_emitter_anchor_node(yaml_emitter_t *emitter, int index)
|
||||
{
|
||||
yaml_node_t *node = emitter->document->nodes.start + index - 1;
|
||||
yaml_node_item_t *item;
|
||||
yaml_node_pair_t *pair;
|
||||
|
||||
emitter->anchors[index-1].references ++;
|
||||
|
||||
if (emitter->anchors[index-1].references == 1) {
|
||||
switch (node->type) {
|
||||
case YAML_SEQUENCE_NODE:
|
||||
for (item = node->data.sequence.items.start;
|
||||
item < node->data.sequence.items.top; item ++) {
|
||||
yaml_emitter_anchor_node(emitter, *item);
|
||||
}
|
||||
break;
|
||||
case YAML_MAPPING_NODE:
|
||||
for (pair = node->data.mapping.pairs.start;
|
||||
pair < node->data.mapping.pairs.top; pair ++) {
|
||||
yaml_emitter_anchor_node(emitter, pair->key);
|
||||
yaml_emitter_anchor_node(emitter, pair->value);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
else if (emitter->anchors[index-1].references == 2) {
|
||||
emitter->anchors[index-1].anchor = (++ emitter->last_anchor_id);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Generate a textual representation for an anchor.
|
||||
*/
|
||||
|
||||
#define ANCHOR_TEMPLATE "id%03d"
|
||||
#define ANCHOR_TEMPLATE_LENGTH 16
|
||||
|
||||
static yaml_char_t *
|
||||
yaml_emitter_generate_anchor(yaml_emitter_t *emitter, int anchor_id)
|
||||
{
|
||||
yaml_char_t *anchor = yaml_malloc(ANCHOR_TEMPLATE_LENGTH);
|
||||
|
||||
if (!anchor) return NULL;
|
||||
|
||||
sprintf((char *)anchor, ANCHOR_TEMPLATE, anchor_id);
|
||||
|
||||
return anchor;
|
||||
}
|
||||
|
||||
/*
|
||||
* Serialize a node.
|
||||
*/
|
||||
|
||||
static int
|
||||
yaml_emitter_dump_node(yaml_emitter_t *emitter, int index)
|
||||
{
|
||||
yaml_node_t *node = emitter->document->nodes.start + index - 1;
|
||||
int anchor_id = emitter->anchors[index-1].anchor;
|
||||
yaml_char_t *anchor = NULL;
|
||||
|
||||
if (anchor_id) {
|
||||
anchor = yaml_emitter_generate_anchor(emitter, anchor_id);
|
||||
if (!anchor) return 0;
|
||||
}
|
||||
|
||||
if (emitter->anchors[index-1].serialized) {
|
||||
return yaml_emitter_dump_alias(emitter, anchor);
|
||||
}
|
||||
|
||||
emitter->anchors[index-1].serialized = 1;
|
||||
|
||||
switch (node->type) {
|
||||
case YAML_SCALAR_NODE:
|
||||
return yaml_emitter_dump_scalar(emitter, node, anchor);
|
||||
case YAML_SEQUENCE_NODE:
|
||||
return yaml_emitter_dump_sequence(emitter, node, anchor);
|
||||
case YAML_MAPPING_NODE:
|
||||
return yaml_emitter_dump_mapping(emitter, node, anchor);
|
||||
default:
|
||||
assert(0); /* Could not happen. */
|
||||
break;
|
||||
}
|
||||
|
||||
return 0; /* Could not happen. */
|
||||
}
|
||||
|
||||
/*
|
||||
* Serialize an alias.
|
||||
*/
|
||||
|
||||
static int
|
||||
yaml_emitter_dump_alias(yaml_emitter_t *emitter, yaml_char_t *anchor)
|
||||
{
|
||||
yaml_event_t event;
|
||||
yaml_mark_t mark = { 0, 0, 0 };
|
||||
|
||||
ALIAS_EVENT_INIT(event, anchor, mark, mark);
|
||||
|
||||
return yaml_emitter_emit(emitter, &event);
|
||||
}
|
||||
|
||||
/*
|
||||
* Serialize a scalar.
|
||||
*/
|
||||
|
||||
static int
|
||||
yaml_emitter_dump_scalar(yaml_emitter_t *emitter, yaml_node_t *node,
|
||||
yaml_char_t *anchor)
|
||||
{
|
||||
yaml_event_t event;
|
||||
yaml_mark_t mark = { 0, 0, 0 };
|
||||
|
||||
int plain_implicit = (strcmp((char *)node->tag,
|
||||
YAML_DEFAULT_SCALAR_TAG) == 0);
|
||||
int quoted_implicit = (strcmp((char *)node->tag,
|
||||
YAML_DEFAULT_SCALAR_TAG) == 0);
|
||||
|
||||
SCALAR_EVENT_INIT(event, anchor, node->tag, node->data.scalar.value,
|
||||
node->data.scalar.length, plain_implicit, quoted_implicit,
|
||||
node->data.scalar.style, mark, mark);
|
||||
|
||||
return yaml_emitter_emit(emitter, &event);
|
||||
}
|
||||
|
||||
/*
|
||||
* Serialize a sequence.
|
||||
*/
|
||||
|
||||
static int
|
||||
yaml_emitter_dump_sequence(yaml_emitter_t *emitter, yaml_node_t *node,
|
||||
yaml_char_t *anchor)
|
||||
{
|
||||
yaml_event_t event;
|
||||
yaml_mark_t mark = { 0, 0, 0 };
|
||||
|
||||
int implicit = (strcmp((char *)node->tag, YAML_DEFAULT_SEQUENCE_TAG) == 0);
|
||||
|
||||
yaml_node_item_t *item;
|
||||
|
||||
SEQUENCE_START_EVENT_INIT(event, anchor, node->tag, implicit,
|
||||
node->data.sequence.style, mark, mark);
|
||||
if (!yaml_emitter_emit(emitter, &event)) return 0;
|
||||
|
||||
for (item = node->data.sequence.items.start;
|
||||
item < node->data.sequence.items.top; item ++) {
|
||||
if (!yaml_emitter_dump_node(emitter, *item)) return 0;
|
||||
}
|
||||
|
||||
SEQUENCE_END_EVENT_INIT(event, mark, mark);
|
||||
if (!yaml_emitter_emit(emitter, &event)) return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Serialize a mapping.
|
||||
*/
|
||||
|
||||
static int
|
||||
yaml_emitter_dump_mapping(yaml_emitter_t *emitter, yaml_node_t *node,
|
||||
yaml_char_t *anchor)
|
||||
{
|
||||
yaml_event_t event;
|
||||
yaml_mark_t mark = { 0, 0, 0 };
|
||||
|
||||
int implicit = (strcmp((char *)node->tag, YAML_DEFAULT_MAPPING_TAG) == 0);
|
||||
|
||||
yaml_node_pair_t *pair;
|
||||
|
||||
MAPPING_START_EVENT_INIT(event, anchor, node->tag, implicit,
|
||||
node->data.mapping.style, mark, mark);
|
||||
if (!yaml_emitter_emit(emitter, &event)) return 0;
|
||||
|
||||
for (pair = node->data.mapping.pairs.start;
|
||||
pair < node->data.mapping.pairs.top; pair ++) {
|
||||
if (!yaml_emitter_dump_node(emitter, pair->key)) return 0;
|
||||
if (!yaml_emitter_dump_node(emitter, pair->value)) return 0;
|
||||
}
|
||||
|
||||
MAPPING_END_EVENT_INIT(event, mark, mark);
|
||||
if (!yaml_emitter_emit(emitter, &event)) return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
2329
lib/yaml/emitter.c
Normal file
2329
lib/yaml/emitter.c
Normal file
File diff suppressed because it is too large
Load diff
1971
lib/yaml/include/yaml.h
Normal file
1971
lib/yaml/include/yaml.h
Normal file
File diff suppressed because it is too large
Load diff
444
lib/yaml/loader.c
Normal file
444
lib/yaml/loader.c
Normal file
|
|
@ -0,0 +1,444 @@
|
|||
|
||||
#include "yaml_private.h"
|
||||
|
||||
/*
|
||||
* API functions.
|
||||
*/
|
||||
|
||||
YAML_DECLARE(int)
|
||||
yaml_parser_load(yaml_parser_t *parser, yaml_document_t *document);
|
||||
|
||||
/*
|
||||
* Error handling.
|
||||
*/
|
||||
|
||||
static int
|
||||
yaml_parser_set_composer_error(yaml_parser_t *parser,
|
||||
const char *problem, yaml_mark_t problem_mark);
|
||||
|
||||
static int
|
||||
yaml_parser_set_composer_error_context(yaml_parser_t *parser,
|
||||
const char *context, yaml_mark_t context_mark,
|
||||
const char *problem, yaml_mark_t problem_mark);
|
||||
|
||||
|
||||
/*
|
||||
* Alias handling.
|
||||
*/
|
||||
|
||||
static int
|
||||
yaml_parser_register_anchor(yaml_parser_t *parser,
|
||||
int index, yaml_char_t *anchor);
|
||||
|
||||
/*
|
||||
* Clean up functions.
|
||||
*/
|
||||
|
||||
static void
|
||||
yaml_parser_delete_aliases(yaml_parser_t *parser);
|
||||
|
||||
/*
|
||||
* Composer functions.
|
||||
*/
|
||||
|
||||
static int
|
||||
yaml_parser_load_document(yaml_parser_t *parser, yaml_event_t *first_event);
|
||||
|
||||
static int
|
||||
yaml_parser_load_node(yaml_parser_t *parser, yaml_event_t *first_event);
|
||||
|
||||
static int
|
||||
yaml_parser_load_alias(yaml_parser_t *parser, yaml_event_t *first_event);
|
||||
|
||||
static int
|
||||
yaml_parser_load_scalar(yaml_parser_t *parser, yaml_event_t *first_event);
|
||||
|
||||
static int
|
||||
yaml_parser_load_sequence(yaml_parser_t *parser, yaml_event_t *first_event);
|
||||
|
||||
static int
|
||||
yaml_parser_load_mapping(yaml_parser_t *parser, yaml_event_t *first_event);
|
||||
|
||||
/*
|
||||
* Load the next document of the stream.
|
||||
*/
|
||||
|
||||
YAML_DECLARE(int)
|
||||
yaml_parser_load(yaml_parser_t *parser, yaml_document_t *document)
|
||||
{
|
||||
yaml_event_t event;
|
||||
|
||||
assert(parser); /* Non-NULL parser object is expected. */
|
||||
assert(document); /* Non-NULL document object is expected. */
|
||||
|
||||
memset(document, 0, sizeof(yaml_document_t));
|
||||
if (!STACK_INIT(parser, document->nodes, INITIAL_STACK_SIZE))
|
||||
goto error;
|
||||
|
||||
if (!parser->stream_start_produced) {
|
||||
if (!yaml_parser_parse(parser, &event)) goto error;
|
||||
assert(event.type == YAML_STREAM_START_EVENT);
|
||||
/* STREAM-START is expected. */
|
||||
}
|
||||
|
||||
if (parser->stream_end_produced) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!yaml_parser_parse(parser, &event)) goto error;
|
||||
if (event.type == YAML_STREAM_END_EVENT) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!STACK_INIT(parser, parser->aliases, INITIAL_STACK_SIZE))
|
||||
goto error;
|
||||
|
||||
parser->document = document;
|
||||
|
||||
if (!yaml_parser_load_document(parser, &event)) goto error;
|
||||
|
||||
yaml_parser_delete_aliases(parser);
|
||||
parser->document = NULL;
|
||||
|
||||
return 1;
|
||||
|
||||
error:
|
||||
|
||||
yaml_parser_delete_aliases(parser);
|
||||
yaml_document_delete(document);
|
||||
parser->document = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set composer error.
|
||||
*/
|
||||
|
||||
static int
|
||||
yaml_parser_set_composer_error(yaml_parser_t *parser,
|
||||
const char *problem, yaml_mark_t problem_mark)
|
||||
{
|
||||
parser->error = YAML_COMPOSER_ERROR;
|
||||
parser->problem = problem;
|
||||
parser->problem_mark = problem_mark;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set composer error with context.
|
||||
*/
|
||||
|
||||
static int
|
||||
yaml_parser_set_composer_error_context(yaml_parser_t *parser,
|
||||
const char *context, yaml_mark_t context_mark,
|
||||
const char *problem, yaml_mark_t problem_mark)
|
||||
{
|
||||
parser->error = YAML_COMPOSER_ERROR;
|
||||
parser->context = context;
|
||||
parser->context_mark = context_mark;
|
||||
parser->problem = problem;
|
||||
parser->problem_mark = problem_mark;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Delete the stack of aliases.
|
||||
*/
|
||||
|
||||
static void
|
||||
yaml_parser_delete_aliases(yaml_parser_t *parser)
|
||||
{
|
||||
while (!STACK_EMPTY(parser, parser->aliases)) {
|
||||
yaml_free(POP(parser, parser->aliases).anchor);
|
||||
}
|
||||
STACK_DEL(parser, parser->aliases);
|
||||
}
|
||||
|
||||
/*
|
||||
* Compose a document object.
|
||||
*/
|
||||
|
||||
static int
|
||||
yaml_parser_load_document(yaml_parser_t *parser, yaml_event_t *first_event)
|
||||
{
|
||||
yaml_event_t event;
|
||||
|
||||
assert(first_event->type == YAML_DOCUMENT_START_EVENT);
|
||||
/* DOCUMENT-START is expected. */
|
||||
|
||||
parser->document->version_directive
|
||||
= first_event->data.document_start.version_directive;
|
||||
parser->document->tag_directives.start
|
||||
= first_event->data.document_start.tag_directives.start;
|
||||
parser->document->tag_directives.end
|
||||
= first_event->data.document_start.tag_directives.end;
|
||||
parser->document->start_implicit
|
||||
= first_event->data.document_start.implicit;
|
||||
parser->document->start_mark = first_event->start_mark;
|
||||
|
||||
if (!yaml_parser_parse(parser, &event)) return 0;
|
||||
|
||||
if (!yaml_parser_load_node(parser, &event)) return 0;
|
||||
|
||||
if (!yaml_parser_parse(parser, &event)) return 0;
|
||||
assert(event.type == YAML_DOCUMENT_END_EVENT);
|
||||
/* DOCUMENT-END is expected. */
|
||||
|
||||
parser->document->end_implicit = event.data.document_end.implicit;
|
||||
parser->document->end_mark = event.end_mark;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compose a node.
|
||||
*/
|
||||
|
||||
static int
|
||||
yaml_parser_load_node(yaml_parser_t *parser, yaml_event_t *first_event)
|
||||
{
|
||||
switch (first_event->type) {
|
||||
case YAML_ALIAS_EVENT:
|
||||
return yaml_parser_load_alias(parser, first_event);
|
||||
case YAML_SCALAR_EVENT:
|
||||
return yaml_parser_load_scalar(parser, first_event);
|
||||
case YAML_SEQUENCE_START_EVENT:
|
||||
return yaml_parser_load_sequence(parser, first_event);
|
||||
case YAML_MAPPING_START_EVENT:
|
||||
return yaml_parser_load_mapping(parser, first_event);
|
||||
default:
|
||||
assert(0); /* Could not happen. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add an anchor.
|
||||
*/
|
||||
|
||||
static int
|
||||
yaml_parser_register_anchor(yaml_parser_t *parser,
|
||||
int index, yaml_char_t *anchor)
|
||||
{
|
||||
yaml_alias_data_t data;
|
||||
yaml_alias_data_t *alias_data;
|
||||
|
||||
if (!anchor) return 1;
|
||||
|
||||
data.anchor = anchor;
|
||||
data.index = index;
|
||||
data.mark = parser->document->nodes.start[index-1].start_mark;
|
||||
|
||||
for (alias_data = parser->aliases.start;
|
||||
alias_data != parser->aliases.top; alias_data ++) {
|
||||
if (strcmp((char *)alias_data->anchor, (char *)anchor) == 0) {
|
||||
yaml_free(anchor);
|
||||
return yaml_parser_set_composer_error_context(parser,
|
||||
"found duplicate anchor; first occurence",
|
||||
alias_data->mark, "second occurence", data.mark);
|
||||
}
|
||||
}
|
||||
|
||||
if (!PUSH(parser, parser->aliases, data)) {
|
||||
yaml_free(anchor);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compose a node corresponding to an alias.
|
||||
*/
|
||||
|
||||
static int
|
||||
yaml_parser_load_alias(yaml_parser_t *parser, yaml_event_t *first_event)
|
||||
{
|
||||
yaml_char_t *anchor = first_event->data.alias.anchor;
|
||||
yaml_alias_data_t *alias_data;
|
||||
|
||||
for (alias_data = parser->aliases.start;
|
||||
alias_data != parser->aliases.top; alias_data ++) {
|
||||
if (strcmp((char *)alias_data->anchor, (char *)anchor) == 0) {
|
||||
yaml_free(anchor);
|
||||
return alias_data->index;
|
||||
}
|
||||
}
|
||||
|
||||
yaml_free(anchor);
|
||||
return yaml_parser_set_composer_error(parser, "found undefined alias",
|
||||
first_event->start_mark);
|
||||
}
|
||||
|
||||
/*
|
||||
* Compose a scalar node.
|
||||
*/
|
||||
|
||||
static int
|
||||
yaml_parser_load_scalar(yaml_parser_t *parser, yaml_event_t *first_event)
|
||||
{
|
||||
yaml_node_t node;
|
||||
int index;
|
||||
yaml_char_t *tag = first_event->data.scalar.tag;
|
||||
|
||||
if (!STACK_LIMIT(parser, parser->document->nodes, INT_MAX-1)) goto error;
|
||||
|
||||
if (!tag || strcmp((char *)tag, "!") == 0) {
|
||||
yaml_free(tag);
|
||||
tag = yaml_strdup((yaml_char_t *)YAML_DEFAULT_SCALAR_TAG);
|
||||
if (!tag) goto error;
|
||||
}
|
||||
|
||||
SCALAR_NODE_INIT(node, tag, first_event->data.scalar.value,
|
||||
first_event->data.scalar.length, first_event->data.scalar.style,
|
||||
first_event->start_mark, first_event->end_mark);
|
||||
|
||||
if (!PUSH(parser, parser->document->nodes, node)) goto error;
|
||||
|
||||
index = parser->document->nodes.top - parser->document->nodes.start;
|
||||
|
||||
if (!yaml_parser_register_anchor(parser, index,
|
||||
first_event->data.scalar.anchor)) return 0;
|
||||
|
||||
return index;
|
||||
|
||||
error:
|
||||
yaml_free(tag);
|
||||
yaml_free(first_event->data.scalar.anchor);
|
||||
yaml_free(first_event->data.scalar.value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compose a sequence node.
|
||||
*/
|
||||
|
||||
static int
|
||||
yaml_parser_load_sequence(yaml_parser_t *parser, yaml_event_t *first_event)
|
||||
{
|
||||
yaml_event_t event;
|
||||
yaml_node_t node;
|
||||
struct {
|
||||
yaml_node_item_t *start;
|
||||
yaml_node_item_t *end;
|
||||
yaml_node_item_t *top;
|
||||
} items = { NULL, NULL, NULL };
|
||||
int index, item_index;
|
||||
yaml_char_t *tag = first_event->data.sequence_start.tag;
|
||||
|
||||
if (!STACK_LIMIT(parser, parser->document->nodes, INT_MAX-1)) goto error;
|
||||
|
||||
if (!tag || strcmp((char *)tag, "!") == 0) {
|
||||
yaml_free(tag);
|
||||
tag = yaml_strdup((yaml_char_t *)YAML_DEFAULT_SEQUENCE_TAG);
|
||||
if (!tag) goto error;
|
||||
}
|
||||
|
||||
if (!STACK_INIT(parser, items, INITIAL_STACK_SIZE)) goto error;
|
||||
|
||||
SEQUENCE_NODE_INIT(node, tag, items.start, items.end,
|
||||
first_event->data.sequence_start.style,
|
||||
first_event->start_mark, first_event->end_mark);
|
||||
|
||||
if (!PUSH(parser, parser->document->nodes, node)) goto error;
|
||||
|
||||
index = parser->document->nodes.top - parser->document->nodes.start;
|
||||
|
||||
if (!yaml_parser_register_anchor(parser, index,
|
||||
first_event->data.sequence_start.anchor)) return 0;
|
||||
|
||||
if (!yaml_parser_parse(parser, &event)) return 0;
|
||||
|
||||
while (event.type != YAML_SEQUENCE_END_EVENT) {
|
||||
if (!STACK_LIMIT(parser,
|
||||
parser->document->nodes.start[index-1].data.sequence.items,
|
||||
INT_MAX-1)) return 0;
|
||||
item_index = yaml_parser_load_node(parser, &event);
|
||||
if (!item_index) return 0;
|
||||
if (!PUSH(parser,
|
||||
parser->document->nodes.start[index-1].data.sequence.items,
|
||||
item_index)) return 0;
|
||||
if (!yaml_parser_parse(parser, &event)) return 0;
|
||||
}
|
||||
|
||||
parser->document->nodes.start[index-1].end_mark = event.end_mark;
|
||||
|
||||
return index;
|
||||
|
||||
error:
|
||||
yaml_free(tag);
|
||||
yaml_free(first_event->data.sequence_start.anchor);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compose a mapping node.
|
||||
*/
|
||||
|
||||
static int
|
||||
yaml_parser_load_mapping(yaml_parser_t *parser, yaml_event_t *first_event)
|
||||
{
|
||||
yaml_event_t event;
|
||||
yaml_node_t node;
|
||||
struct {
|
||||
yaml_node_pair_t *start;
|
||||
yaml_node_pair_t *end;
|
||||
yaml_node_pair_t *top;
|
||||
} pairs = { NULL, NULL, NULL };
|
||||
int index;
|
||||
yaml_node_pair_t pair;
|
||||
yaml_char_t *tag = first_event->data.mapping_start.tag;
|
||||
|
||||
if (!STACK_LIMIT(parser, parser->document->nodes, INT_MAX-1)) goto error;
|
||||
|
||||
if (!tag || strcmp((char *)tag, "!") == 0) {
|
||||
yaml_free(tag);
|
||||
tag = yaml_strdup((yaml_char_t *)YAML_DEFAULT_MAPPING_TAG);
|
||||
if (!tag) goto error;
|
||||
}
|
||||
|
||||
if (!STACK_INIT(parser, pairs, INITIAL_STACK_SIZE)) goto error;
|
||||
|
||||
MAPPING_NODE_INIT(node, tag, pairs.start, pairs.end,
|
||||
first_event->data.mapping_start.style,
|
||||
first_event->start_mark, first_event->end_mark);
|
||||
|
||||
if (!PUSH(parser, parser->document->nodes, node)) goto error;
|
||||
|
||||
index = parser->document->nodes.top - parser->document->nodes.start;
|
||||
|
||||
if (!yaml_parser_register_anchor(parser, index,
|
||||
first_event->data.mapping_start.anchor)) return 0;
|
||||
|
||||
if (!yaml_parser_parse(parser, &event)) return 0;
|
||||
|
||||
while (event.type != YAML_MAPPING_END_EVENT) {
|
||||
if (!STACK_LIMIT(parser,
|
||||
parser->document->nodes.start[index-1].data.mapping.pairs,
|
||||
INT_MAX-1)) return 0;
|
||||
pair.key = yaml_parser_load_node(parser, &event);
|
||||
if (!pair.key) return 0;
|
||||
if (!yaml_parser_parse(parser, &event)) return 0;
|
||||
pair.value = yaml_parser_load_node(parser, &event);
|
||||
if (!pair.value) return 0;
|
||||
if (!PUSH(parser,
|
||||
parser->document->nodes.start[index-1].data.mapping.pairs,
|
||||
pair)) return 0;
|
||||
if (!yaml_parser_parse(parser, &event)) return 0;
|
||||
}
|
||||
|
||||
parser->document->nodes.start[index-1].end_mark = event.end_mark;
|
||||
|
||||
return index;
|
||||
|
||||
error:
|
||||
yaml_free(tag);
|
||||
yaml_free(first_event->data.mapping_start.anchor);
|
||||
return 0;
|
||||
}
|
||||
|
||||
1374
lib/yaml/parser.c
Normal file
1374
lib/yaml/parser.c
Normal file
File diff suppressed because it is too large
Load diff
469
lib/yaml/reader.c
Normal file
469
lib/yaml/reader.c
Normal file
|
|
@ -0,0 +1,469 @@
|
|||
|
||||
#include "yaml_private.h"
|
||||
|
||||
/*
|
||||
* Declarations.
|
||||
*/
|
||||
|
||||
static int
|
||||
yaml_parser_set_reader_error(yaml_parser_t *parser, const char *problem,
|
||||
size_t offset, int value);
|
||||
|
||||
static int
|
||||
yaml_parser_update_raw_buffer(yaml_parser_t *parser);
|
||||
|
||||
static int
|
||||
yaml_parser_determine_encoding(yaml_parser_t *parser);
|
||||
|
||||
YAML_DECLARE(int)
|
||||
yaml_parser_update_buffer(yaml_parser_t *parser, size_t length);
|
||||
|
||||
/*
|
||||
* Set the reader error and return 0.
|
||||
*/
|
||||
|
||||
static int
|
||||
yaml_parser_set_reader_error(yaml_parser_t *parser, const char *problem,
|
||||
size_t offset, int value)
|
||||
{
|
||||
parser->error = YAML_READER_ERROR;
|
||||
parser->problem = problem;
|
||||
parser->problem_offset = offset;
|
||||
parser->problem_value = value;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Byte order marks.
|
||||
*/
|
||||
|
||||
#define BOM_UTF8 "\xef\xbb\xbf"
|
||||
#define BOM_UTF16LE "\xff\xfe"
|
||||
#define BOM_UTF16BE "\xfe\xff"
|
||||
|
||||
/*
|
||||
* Determine the input stream encoding by checking the BOM symbol. If no BOM is
|
||||
* found, the UTF-8 encoding is assumed. Return 1 on success, 0 on failure.
|
||||
*/
|
||||
|
||||
static int
|
||||
yaml_parser_determine_encoding(yaml_parser_t *parser)
|
||||
{
|
||||
/* Ensure that we had enough bytes in the raw buffer. */
|
||||
|
||||
while (!parser->eof
|
||||
&& parser->raw_buffer.last - parser->raw_buffer.pointer < 3) {
|
||||
if (!yaml_parser_update_raw_buffer(parser)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Determine the encoding. */
|
||||
|
||||
if (parser->raw_buffer.last - parser->raw_buffer.pointer >= 2
|
||||
&& !memcmp(parser->raw_buffer.pointer, BOM_UTF16LE, 2)) {
|
||||
parser->encoding = YAML_UTF16LE_ENCODING;
|
||||
parser->raw_buffer.pointer += 2;
|
||||
parser->offset += 2;
|
||||
}
|
||||
else if (parser->raw_buffer.last - parser->raw_buffer.pointer >= 2
|
||||
&& !memcmp(parser->raw_buffer.pointer, BOM_UTF16BE, 2)) {
|
||||
parser->encoding = YAML_UTF16BE_ENCODING;
|
||||
parser->raw_buffer.pointer += 2;
|
||||
parser->offset += 2;
|
||||
}
|
||||
else if (parser->raw_buffer.last - parser->raw_buffer.pointer >= 3
|
||||
&& !memcmp(parser->raw_buffer.pointer, BOM_UTF8, 3)) {
|
||||
parser->encoding = YAML_UTF8_ENCODING;
|
||||
parser->raw_buffer.pointer += 3;
|
||||
parser->offset += 3;
|
||||
}
|
||||
else {
|
||||
parser->encoding = YAML_UTF8_ENCODING;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Update the raw buffer.
|
||||
*/
|
||||
|
||||
static int
|
||||
yaml_parser_update_raw_buffer(yaml_parser_t *parser)
|
||||
{
|
||||
size_t size_read = 0;
|
||||
|
||||
/* Return if the raw buffer is full. */
|
||||
|
||||
if (parser->raw_buffer.start == parser->raw_buffer.pointer
|
||||
&& parser->raw_buffer.last == parser->raw_buffer.end)
|
||||
return 1;
|
||||
|
||||
/* Return on EOF. */
|
||||
|
||||
if (parser->eof) return 1;
|
||||
|
||||
/* Move the remaining bytes in the raw buffer to the beginning. */
|
||||
|
||||
if (parser->raw_buffer.start < parser->raw_buffer.pointer
|
||||
&& parser->raw_buffer.pointer < parser->raw_buffer.last) {
|
||||
memmove(parser->raw_buffer.start, parser->raw_buffer.pointer,
|
||||
parser->raw_buffer.last - parser->raw_buffer.pointer);
|
||||
}
|
||||
parser->raw_buffer.last -=
|
||||
parser->raw_buffer.pointer - parser->raw_buffer.start;
|
||||
parser->raw_buffer.pointer = parser->raw_buffer.start;
|
||||
|
||||
/* Call the read handler to fill the buffer. */
|
||||
|
||||
if (!parser->read_handler(parser->read_handler_data, parser->raw_buffer.last,
|
||||
parser->raw_buffer.end - parser->raw_buffer.last, &size_read)) {
|
||||
return yaml_parser_set_reader_error(parser, "input error",
|
||||
parser->offset, -1);
|
||||
}
|
||||
parser->raw_buffer.last += size_read;
|
||||
if (!size_read) {
|
||||
parser->eof = 1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ensure that the buffer contains at least `length` characters.
|
||||
* Return 1 on success, 0 on failure.
|
||||
*
|
||||
* The length is supposed to be significantly less that the buffer size.
|
||||
*/
|
||||
|
||||
YAML_DECLARE(int)
|
||||
yaml_parser_update_buffer(yaml_parser_t *parser, size_t length)
|
||||
{
|
||||
int first = 1;
|
||||
|
||||
assert(parser->read_handler); /* Read handler must be set. */
|
||||
|
||||
/* If the EOF flag is set and the raw buffer is empty, do nothing. */
|
||||
|
||||
if (parser->eof && parser->raw_buffer.pointer == parser->raw_buffer.last)
|
||||
return 1;
|
||||
|
||||
/* Return if the buffer contains enough characters. */
|
||||
|
||||
if (parser->unread >= length)
|
||||
return 1;
|
||||
|
||||
/* Determine the input encoding if it is not known yet. */
|
||||
|
||||
if (!parser->encoding) {
|
||||
if (!yaml_parser_determine_encoding(parser))
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Move the unread characters to the beginning of the buffer. */
|
||||
|
||||
if (parser->buffer.start < parser->buffer.pointer
|
||||
&& parser->buffer.pointer < parser->buffer.last) {
|
||||
size_t size = parser->buffer.last - parser->buffer.pointer;
|
||||
memmove(parser->buffer.start, parser->buffer.pointer, size);
|
||||
parser->buffer.pointer = parser->buffer.start;
|
||||
parser->buffer.last = parser->buffer.start + size;
|
||||
}
|
||||
else if (parser->buffer.pointer == parser->buffer.last) {
|
||||
parser->buffer.pointer = parser->buffer.start;
|
||||
parser->buffer.last = parser->buffer.start;
|
||||
}
|
||||
|
||||
/* Fill the buffer until it has enough characters. */
|
||||
|
||||
while (parser->unread < length)
|
||||
{
|
||||
/* Fill the raw buffer if necessary. */
|
||||
|
||||
if (!first || parser->raw_buffer.pointer == parser->raw_buffer.last) {
|
||||
if (!yaml_parser_update_raw_buffer(parser)) return 0;
|
||||
}
|
||||
first = 0;
|
||||
|
||||
/* Decode the raw buffer. */
|
||||
|
||||
while (parser->raw_buffer.pointer != parser->raw_buffer.last)
|
||||
{
|
||||
unsigned int value = 0, value2 = 0;
|
||||
int incomplete = 0;
|
||||
unsigned char octet;
|
||||
unsigned int width = 0;
|
||||
int low, high;
|
||||
size_t k;
|
||||
size_t raw_unread = parser->raw_buffer.last - parser->raw_buffer.pointer;
|
||||
|
||||
/* Decode the next character. */
|
||||
|
||||
switch (parser->encoding)
|
||||
{
|
||||
case YAML_UTF8_ENCODING:
|
||||
|
||||
/*
|
||||
* Decode a UTF-8 character. Check RFC 3629
|
||||
* (http://www.ietf.org/rfc/rfc3629.txt) for more details.
|
||||
*
|
||||
* The following table (taken from the RFC) is used for
|
||||
* decoding.
|
||||
*
|
||||
* Char. number range | UTF-8 octet sequence
|
||||
* (hexadecimal) | (binary)
|
||||
* --------------------+------------------------------------
|
||||
* 0000 0000-0000 007F | 0xxxxxxx
|
||||
* 0000 0080-0000 07FF | 110xxxxx 10xxxxxx
|
||||
* 0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
|
||||
* 0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
|
||||
*
|
||||
* Additionally, the characters in the range 0xD800-0xDFFF
|
||||
* are prohibited as they are reserved for use with UTF-16
|
||||
* surrogate pairs.
|
||||
*/
|
||||
|
||||
/* Determine the length of the UTF-8 sequence. */
|
||||
|
||||
octet = parser->raw_buffer.pointer[0];
|
||||
width = (octet & 0x80) == 0x00 ? 1 :
|
||||
(octet & 0xE0) == 0xC0 ? 2 :
|
||||
(octet & 0xF0) == 0xE0 ? 3 :
|
||||
(octet & 0xF8) == 0xF0 ? 4 : 0;
|
||||
|
||||
/* Check if the leading octet is valid. */
|
||||
|
||||
if (!width)
|
||||
return yaml_parser_set_reader_error(parser,
|
||||
"invalid leading UTF-8 octet",
|
||||
parser->offset, octet);
|
||||
|
||||
/* Check if the raw buffer contains an incomplete character. */
|
||||
|
||||
if (width > raw_unread) {
|
||||
if (parser->eof) {
|
||||
return yaml_parser_set_reader_error(parser,
|
||||
"incomplete UTF-8 octet sequence",
|
||||
parser->offset, -1);
|
||||
}
|
||||
incomplete = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Decode the leading octet. */
|
||||
|
||||
value = (octet & 0x80) == 0x00 ? octet & 0x7F :
|
||||
(octet & 0xE0) == 0xC0 ? octet & 0x1F :
|
||||
(octet & 0xF0) == 0xE0 ? octet & 0x0F :
|
||||
(octet & 0xF8) == 0xF0 ? octet & 0x07 : 0;
|
||||
|
||||
/* Check and decode the trailing octets. */
|
||||
|
||||
for (k = 1; k < width; k ++)
|
||||
{
|
||||
octet = parser->raw_buffer.pointer[k];
|
||||
|
||||
/* Check if the octet is valid. */
|
||||
|
||||
if ((octet & 0xC0) != 0x80)
|
||||
return yaml_parser_set_reader_error(parser,
|
||||
"invalid trailing UTF-8 octet",
|
||||
parser->offset+k, octet);
|
||||
|
||||
/* Decode the octet. */
|
||||
|
||||
value = (value << 6) + (octet & 0x3F);
|
||||
}
|
||||
|
||||
/* Check the length of the sequence against the value. */
|
||||
|
||||
if (!((width == 1) ||
|
||||
(width == 2 && value >= 0x80) ||
|
||||
(width == 3 && value >= 0x800) ||
|
||||
(width == 4 && value >= 0x10000)))
|
||||
return yaml_parser_set_reader_error(parser,
|
||||
"invalid length of a UTF-8 sequence",
|
||||
parser->offset, -1);
|
||||
|
||||
/* Check the range of the value. */
|
||||
|
||||
if ((value >= 0xD800 && value <= 0xDFFF) || value > 0x10FFFF)
|
||||
return yaml_parser_set_reader_error(parser,
|
||||
"invalid Unicode character",
|
||||
parser->offset, value);
|
||||
|
||||
break;
|
||||
|
||||
case YAML_UTF16LE_ENCODING:
|
||||
case YAML_UTF16BE_ENCODING:
|
||||
|
||||
low = (parser->encoding == YAML_UTF16LE_ENCODING ? 0 : 1);
|
||||
high = (parser->encoding == YAML_UTF16LE_ENCODING ? 1 : 0);
|
||||
|
||||
/*
|
||||
* The UTF-16 encoding is not as simple as one might
|
||||
* naively think. Check RFC 2781
|
||||
* (http://www.ietf.org/rfc/rfc2781.txt).
|
||||
*
|
||||
* Normally, two subsequent bytes describe a Unicode
|
||||
* character. However a special technique (called a
|
||||
* surrogate pair) is used for specifying character
|
||||
* values larger than 0xFFFF.
|
||||
*
|
||||
* A surrogate pair consists of two pseudo-characters:
|
||||
* high surrogate area (0xD800-0xDBFF)
|
||||
* low surrogate area (0xDC00-0xDFFF)
|
||||
*
|
||||
* The following formulas are used for decoding
|
||||
* and encoding characters using surrogate pairs:
|
||||
*
|
||||
* U = U' + 0x10000 (0x01 00 00 <= U <= 0x10 FF FF)
|
||||
* U' = yyyyyyyyyyxxxxxxxxxx (0 <= U' <= 0x0F FF FF)
|
||||
* W1 = 110110yyyyyyyyyy
|
||||
* W2 = 110111xxxxxxxxxx
|
||||
*
|
||||
* where U is the character value, W1 is the high surrogate
|
||||
* area, W2 is the low surrogate area.
|
||||
*/
|
||||
|
||||
/* Check for incomplete UTF-16 character. */
|
||||
|
||||
if (raw_unread < 2) {
|
||||
if (parser->eof) {
|
||||
return yaml_parser_set_reader_error(parser,
|
||||
"incomplete UTF-16 character",
|
||||
parser->offset, -1);
|
||||
}
|
||||
incomplete = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Get the character. */
|
||||
|
||||
value = parser->raw_buffer.pointer[low]
|
||||
+ (parser->raw_buffer.pointer[high] << 8);
|
||||
|
||||
/* Check for unexpected low surrogate area. */
|
||||
|
||||
if ((value & 0xFC00) == 0xDC00)
|
||||
return yaml_parser_set_reader_error(parser,
|
||||
"unexpected low surrogate area",
|
||||
parser->offset, value);
|
||||
|
||||
/* Check for a high surrogate area. */
|
||||
|
||||
if ((value & 0xFC00) == 0xD800) {
|
||||
|
||||
width = 4;
|
||||
|
||||
/* Check for incomplete surrogate pair. */
|
||||
|
||||
if (raw_unread < 4) {
|
||||
if (parser->eof) {
|
||||
return yaml_parser_set_reader_error(parser,
|
||||
"incomplete UTF-16 surrogate pair",
|
||||
parser->offset, -1);
|
||||
}
|
||||
incomplete = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Get the next character. */
|
||||
|
||||
value2 = parser->raw_buffer.pointer[low+2]
|
||||
+ (parser->raw_buffer.pointer[high+2] << 8);
|
||||
|
||||
/* Check for a low surrogate area. */
|
||||
|
||||
if ((value2 & 0xFC00) != 0xDC00)
|
||||
return yaml_parser_set_reader_error(parser,
|
||||
"expected low surrogate area",
|
||||
parser->offset+2, value2);
|
||||
|
||||
/* Generate the value of the surrogate pair. */
|
||||
|
||||
value = 0x10000 + ((value & 0x3FF) << 10) + (value2 & 0x3FF);
|
||||
}
|
||||
|
||||
else {
|
||||
width = 2;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(1); /* Impossible. */
|
||||
}
|
||||
|
||||
/* Check if the raw buffer contains enough bytes to form a character. */
|
||||
|
||||
if (incomplete) break;
|
||||
|
||||
/*
|
||||
* Check if the character is in the allowed range:
|
||||
* #x9 | #xA | #xD | [#x20-#x7E] (8 bit)
|
||||
* | #x85 | [#xA0-#xD7FF] | [#xE000-#xFFFD] (16 bit)
|
||||
* | [#x10000-#x10FFFF] (32 bit)
|
||||
*/
|
||||
|
||||
if (! (value == 0x09 || value == 0x0A || value == 0x0D
|
||||
|| (value >= 0x20 && value <= 0x7E)
|
||||
|| (value == 0x85) || (value >= 0xA0 && value <= 0xD7FF)
|
||||
|| (value >= 0xE000 && value <= 0xFFFD)
|
||||
|| (value >= 0x10000 && value <= 0x10FFFF)))
|
||||
return yaml_parser_set_reader_error(parser,
|
||||
"control characters are not allowed",
|
||||
parser->offset, value);
|
||||
|
||||
/* Move the raw pointers. */
|
||||
|
||||
parser->raw_buffer.pointer += width;
|
||||
parser->offset += width;
|
||||
|
||||
/* Finally put the character into the buffer. */
|
||||
|
||||
/* 0000 0000-0000 007F -> 0xxxxxxx */
|
||||
if (value <= 0x7F) {
|
||||
*(parser->buffer.last++) = value;
|
||||
}
|
||||
/* 0000 0080-0000 07FF -> 110xxxxx 10xxxxxx */
|
||||
else if (value <= 0x7FF) {
|
||||
*(parser->buffer.last++) = 0xC0 + (value >> 6);
|
||||
*(parser->buffer.last++) = 0x80 + (value & 0x3F);
|
||||
}
|
||||
/* 0000 0800-0000 FFFF -> 1110xxxx 10xxxxxx 10xxxxxx */
|
||||
else if (value <= 0xFFFF) {
|
||||
*(parser->buffer.last++) = 0xE0 + (value >> 12);
|
||||
*(parser->buffer.last++) = 0x80 + ((value >> 6) & 0x3F);
|
||||
*(parser->buffer.last++) = 0x80 + (value & 0x3F);
|
||||
}
|
||||
/* 0001 0000-0010 FFFF -> 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
|
||||
else {
|
||||
*(parser->buffer.last++) = 0xF0 + (value >> 18);
|
||||
*(parser->buffer.last++) = 0x80 + ((value >> 12) & 0x3F);
|
||||
*(parser->buffer.last++) = 0x80 + ((value >> 6) & 0x3F);
|
||||
*(parser->buffer.last++) = 0x80 + (value & 0x3F);
|
||||
}
|
||||
|
||||
parser->unread ++;
|
||||
}
|
||||
|
||||
/* On EOF, put NUL into the buffer and return. */
|
||||
|
||||
if (parser->eof) {
|
||||
*(parser->buffer.last++) = '\0';
|
||||
parser->unread ++;
|
||||
return 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (parser->offset >= PTRDIFF_MAX)
|
||||
return yaml_parser_set_reader_error(parser, "input is too long",
|
||||
PTRDIFF_MAX, -1);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
3580
lib/yaml/scanner.c
Normal file
3580
lib/yaml/scanner.c
Normal file
File diff suppressed because it is too large
Load diff
141
lib/yaml/writer.c
Normal file
141
lib/yaml/writer.c
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
|
||||
#include "yaml_private.h"
|
||||
|
||||
/*
|
||||
* Declarations.
|
||||
*/
|
||||
|
||||
static int
|
||||
yaml_emitter_set_writer_error(yaml_emitter_t *emitter, const char *problem);
|
||||
|
||||
YAML_DECLARE(int)
|
||||
yaml_emitter_flush(yaml_emitter_t *emitter);
|
||||
|
||||
/*
|
||||
* Set the writer error and return 0.
|
||||
*/
|
||||
|
||||
static int
|
||||
yaml_emitter_set_writer_error(yaml_emitter_t *emitter, const char *problem)
|
||||
{
|
||||
emitter->error = YAML_WRITER_ERROR;
|
||||
emitter->problem = problem;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Flush the output buffer.
|
||||
*/
|
||||
|
||||
YAML_DECLARE(int)
|
||||
yaml_emitter_flush(yaml_emitter_t *emitter)
|
||||
{
|
||||
int low, high;
|
||||
|
||||
assert(emitter); /* Non-NULL emitter object is expected. */
|
||||
assert(emitter->write_handler); /* Write handler must be set. */
|
||||
assert(emitter->encoding); /* Output encoding must be set. */
|
||||
|
||||
emitter->buffer.last = emitter->buffer.pointer;
|
||||
emitter->buffer.pointer = emitter->buffer.start;
|
||||
|
||||
/* Check if the buffer is empty. */
|
||||
|
||||
if (emitter->buffer.start == emitter->buffer.last) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* If the output encoding is UTF-8, we don't need to recode the buffer. */
|
||||
|
||||
if (emitter->encoding == YAML_UTF8_ENCODING)
|
||||
{
|
||||
if (emitter->write_handler(emitter->write_handler_data,
|
||||
emitter->buffer.start,
|
||||
emitter->buffer.last - emitter->buffer.start)) {
|
||||
emitter->buffer.last = emitter->buffer.start;
|
||||
emitter->buffer.pointer = emitter->buffer.start;
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
return yaml_emitter_set_writer_error(emitter, "write error");
|
||||
}
|
||||
}
|
||||
|
||||
/* Recode the buffer into the raw buffer. */
|
||||
|
||||
low = (emitter->encoding == YAML_UTF16LE_ENCODING ? 0 : 1);
|
||||
high = (emitter->encoding == YAML_UTF16LE_ENCODING ? 1 : 0);
|
||||
|
||||
while (emitter->buffer.pointer != emitter->buffer.last)
|
||||
{
|
||||
unsigned char octet;
|
||||
unsigned int width;
|
||||
unsigned int value;
|
||||
size_t k;
|
||||
|
||||
/*
|
||||
* See the "reader.c" code for more details on UTF-8 encoding. Note
|
||||
* that we assume that the buffer contains a valid UTF-8 sequence.
|
||||
*/
|
||||
|
||||
/* Read the next UTF-8 character. */
|
||||
|
||||
octet = emitter->buffer.pointer[0];
|
||||
|
||||
width = (octet & 0x80) == 0x00 ? 1 :
|
||||
(octet & 0xE0) == 0xC0 ? 2 :
|
||||
(octet & 0xF0) == 0xE0 ? 3 :
|
||||
(octet & 0xF8) == 0xF0 ? 4 : 0;
|
||||
|
||||
value = (octet & 0x80) == 0x00 ? octet & 0x7F :
|
||||
(octet & 0xE0) == 0xC0 ? octet & 0x1F :
|
||||
(octet & 0xF0) == 0xE0 ? octet & 0x0F :
|
||||
(octet & 0xF8) == 0xF0 ? octet & 0x07 : 0;
|
||||
|
||||
for (k = 1; k < width; k ++) {
|
||||
octet = emitter->buffer.pointer[k];
|
||||
value = (value << 6) + (octet & 0x3F);
|
||||
}
|
||||
|
||||
emitter->buffer.pointer += width;
|
||||
|
||||
/* Write the character. */
|
||||
|
||||
if (value < 0x10000)
|
||||
{
|
||||
emitter->raw_buffer.last[high] = value >> 8;
|
||||
emitter->raw_buffer.last[low] = value & 0xFF;
|
||||
|
||||
emitter->raw_buffer.last += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Write the character using a surrogate pair (check "reader.c"). */
|
||||
|
||||
value -= 0x10000;
|
||||
emitter->raw_buffer.last[high] = 0xD8 + (value >> 18);
|
||||
emitter->raw_buffer.last[low] = (value >> 10) & 0xFF;
|
||||
emitter->raw_buffer.last[high+2] = 0xDC + ((value >> 8) & 0xFF);
|
||||
emitter->raw_buffer.last[low+2] = value & 0xFF;
|
||||
|
||||
emitter->raw_buffer.last += 4;
|
||||
}
|
||||
}
|
||||
|
||||
/* Write the raw buffer. */
|
||||
|
||||
if (emitter->write_handler(emitter->write_handler_data,
|
||||
emitter->raw_buffer.start,
|
||||
emitter->raw_buffer.last - emitter->raw_buffer.start)) {
|
||||
emitter->buffer.last = emitter->buffer.start;
|
||||
emitter->buffer.pointer = emitter->buffer.start;
|
||||
emitter->raw_buffer.last = emitter->raw_buffer.start;
|
||||
emitter->raw_buffer.pointer = emitter->raw_buffer.start;
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
return yaml_emitter_set_writer_error(emitter, "write error");
|
||||
}
|
||||
}
|
||||
|
||||
657
lib/yaml/yaml_private.h
Normal file
657
lib/yaml/yaml_private.h
Normal file
|
|
@ -0,0 +1,657 @@
|
|||
|
||||
#if HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <yaml.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#ifndef _MSC_VER
|
||||
#include <stdint.h>
|
||||
#else
|
||||
#ifdef _WIN64
|
||||
#define PTRDIFF_MAX _I64_MAX
|
||||
#else
|
||||
#define PTRDIFF_MAX INT_MAX
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Memory management.
|
||||
*/
|
||||
|
||||
YAML_DECLARE(void *)
|
||||
yaml_malloc(size_t size);
|
||||
|
||||
YAML_DECLARE(void *)
|
||||
yaml_realloc(void *ptr, size_t size);
|
||||
|
||||
YAML_DECLARE(void)
|
||||
yaml_free(void *ptr);
|
||||
|
||||
YAML_DECLARE(yaml_char_t *)
|
||||
yaml_strdup(const yaml_char_t *);
|
||||
|
||||
/*
|
||||
* Reader: Ensure that the buffer contains at least `length` characters.
|
||||
*/
|
||||
|
||||
YAML_DECLARE(int)
|
||||
yaml_parser_update_buffer(yaml_parser_t *parser, size_t length);
|
||||
|
||||
/*
|
||||
* Scanner: Ensure that the token stack contains at least one token ready.
|
||||
*/
|
||||
|
||||
YAML_DECLARE(int)
|
||||
yaml_parser_fetch_more_tokens(yaml_parser_t *parser);
|
||||
|
||||
/*
|
||||
* The size of the input raw buffer.
|
||||
*/
|
||||
|
||||
#define INPUT_RAW_BUFFER_SIZE 16384
|
||||
|
||||
/*
|
||||
* The size of the input buffer.
|
||||
*
|
||||
* It should be possible to decode the whole raw buffer.
|
||||
*/
|
||||
|
||||
#define INPUT_BUFFER_SIZE (INPUT_RAW_BUFFER_SIZE*3)
|
||||
|
||||
/*
|
||||
* The size of the output buffer.
|
||||
*/
|
||||
|
||||
#define OUTPUT_BUFFER_SIZE 16384
|
||||
|
||||
/*
|
||||
* The size of the output raw buffer.
|
||||
*
|
||||
* It should be possible to encode the whole output buffer.
|
||||
*/
|
||||
|
||||
#define OUTPUT_RAW_BUFFER_SIZE (OUTPUT_BUFFER_SIZE*2+2)
|
||||
|
||||
/*
|
||||
* The size of other stacks and queues.
|
||||
*/
|
||||
|
||||
#define INITIAL_STACK_SIZE 16
|
||||
#define INITIAL_QUEUE_SIZE 16
|
||||
#define INITIAL_STRING_SIZE 16
|
||||
|
||||
/*
|
||||
* Buffer management.
|
||||
*/
|
||||
|
||||
#define BUFFER_INIT(context,buffer,size) \
|
||||
(((buffer).start = yaml_malloc(size)) ? \
|
||||
((buffer).last = (buffer).pointer = (buffer).start, \
|
||||
(buffer).end = (buffer).start+(size), \
|
||||
1) : \
|
||||
((context)->error = YAML_MEMORY_ERROR, \
|
||||
0))
|
||||
|
||||
#define BUFFER_DEL(context,buffer) \
|
||||
(yaml_free((buffer).start), \
|
||||
(buffer).start = (buffer).pointer = (buffer).end = 0)
|
||||
|
||||
/*
|
||||
* String management.
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
yaml_char_t *start;
|
||||
yaml_char_t *end;
|
||||
yaml_char_t *pointer;
|
||||
} yaml_string_t;
|
||||
|
||||
YAML_DECLARE(int)
|
||||
yaml_string_extend(yaml_char_t **start,
|
||||
yaml_char_t **pointer, yaml_char_t **end);
|
||||
|
||||
YAML_DECLARE(int)
|
||||
yaml_string_join(
|
||||
yaml_char_t **a_start, yaml_char_t **a_pointer, yaml_char_t **a_end,
|
||||
yaml_char_t **b_start, yaml_char_t **b_pointer, yaml_char_t **b_end);
|
||||
|
||||
#define NULL_STRING { NULL, NULL, NULL }
|
||||
|
||||
#define STRING(string,length) { (string), (string)+(length), (string) }
|
||||
|
||||
#define STRING_ASSIGN(value,string,length) \
|
||||
((value).start = (string), \
|
||||
(value).end = (string)+(length), \
|
||||
(value).pointer = (string))
|
||||
|
||||
#define STRING_INIT(context,string,size) \
|
||||
(((string).start = yaml_malloc(size)) ? \
|
||||
((string).pointer = (string).start, \
|
||||
(string).end = (string).start+(size), \
|
||||
memset((string).start, 0, (size)), \
|
||||
1) : \
|
||||
((context)->error = YAML_MEMORY_ERROR, \
|
||||
0))
|
||||
|
||||
#define STRING_DEL(context,string) \
|
||||
(yaml_free((string).start), \
|
||||
(string).start = (string).pointer = (string).end = 0)
|
||||
|
||||
#define STRING_EXTEND(context,string) \
|
||||
(((string).pointer+5 < (string).end) \
|
||||
|| yaml_string_extend(&(string).start, \
|
||||
&(string).pointer, &(string).end))
|
||||
|
||||
#define CLEAR(context,string) \
|
||||
((string).pointer = (string).start, \
|
||||
memset((string).start, 0, (string).end-(string).start))
|
||||
|
||||
#define JOIN(context,string_a,string_b) \
|
||||
((yaml_string_join(&(string_a).start, &(string_a).pointer, \
|
||||
&(string_a).end, &(string_b).start, \
|
||||
&(string_b).pointer, &(string_b).end)) ? \
|
||||
((string_b).pointer = (string_b).start, \
|
||||
1) : \
|
||||
((context)->error = YAML_MEMORY_ERROR, \
|
||||
0))
|
||||
|
||||
/*
|
||||
* String check operations.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Check the octet at the specified position.
|
||||
*/
|
||||
|
||||
#define CHECK_AT(string,octet,offset) \
|
||||
((string).pointer[offset] == (yaml_char_t)(octet))
|
||||
|
||||
/*
|
||||
* Check the current octet in the buffer.
|
||||
*/
|
||||
|
||||
#define CHECK(string,octet) CHECK_AT((string),(octet),0)
|
||||
|
||||
/*
|
||||
* Check if the character at the specified position is an alphabetical
|
||||
* character, a digit, '_', or '-'.
|
||||
*/
|
||||
|
||||
#define IS_ALPHA_AT(string,offset) \
|
||||
(((string).pointer[offset] >= (yaml_char_t) '0' && \
|
||||
(string).pointer[offset] <= (yaml_char_t) '9') || \
|
||||
((string).pointer[offset] >= (yaml_char_t) 'A' && \
|
||||
(string).pointer[offset] <= (yaml_char_t) 'Z') || \
|
||||
((string).pointer[offset] >= (yaml_char_t) 'a' && \
|
||||
(string).pointer[offset] <= (yaml_char_t) 'z') || \
|
||||
(string).pointer[offset] == '_' || \
|
||||
(string).pointer[offset] == '-')
|
||||
|
||||
#define IS_ALPHA(string) IS_ALPHA_AT((string),0)
|
||||
|
||||
/*
|
||||
* Check if the character at the specified position is a digit.
|
||||
*/
|
||||
|
||||
#define IS_DIGIT_AT(string,offset) \
|
||||
(((string).pointer[offset] >= (yaml_char_t) '0' && \
|
||||
(string).pointer[offset] <= (yaml_char_t) '9'))
|
||||
|
||||
#define IS_DIGIT(string) IS_DIGIT_AT((string),0)
|
||||
|
||||
/*
|
||||
* Get the value of a digit.
|
||||
*/
|
||||
|
||||
#define AS_DIGIT_AT(string,offset) \
|
||||
((string).pointer[offset] - (yaml_char_t) '0')
|
||||
|
||||
#define AS_DIGIT(string) AS_DIGIT_AT((string),0)
|
||||
|
||||
/*
|
||||
* Check if the character at the specified position is a hex-digit.
|
||||
*/
|
||||
|
||||
#define IS_HEX_AT(string,offset) \
|
||||
(((string).pointer[offset] >= (yaml_char_t) '0' && \
|
||||
(string).pointer[offset] <= (yaml_char_t) '9') || \
|
||||
((string).pointer[offset] >= (yaml_char_t) 'A' && \
|
||||
(string).pointer[offset] <= (yaml_char_t) 'F') || \
|
||||
((string).pointer[offset] >= (yaml_char_t) 'a' && \
|
||||
(string).pointer[offset] <= (yaml_char_t) 'f'))
|
||||
|
||||
#define IS_HEX(string) IS_HEX_AT((string),0)
|
||||
|
||||
/*
|
||||
* Get the value of a hex-digit.
|
||||
*/
|
||||
|
||||
#define AS_HEX_AT(string,offset) \
|
||||
(((string).pointer[offset] >= (yaml_char_t) 'A' && \
|
||||
(string).pointer[offset] <= (yaml_char_t) 'F') ? \
|
||||
((string).pointer[offset] - (yaml_char_t) 'A' + 10) : \
|
||||
((string).pointer[offset] >= (yaml_char_t) 'a' && \
|
||||
(string).pointer[offset] <= (yaml_char_t) 'f') ? \
|
||||
((string).pointer[offset] - (yaml_char_t) 'a' + 10) : \
|
||||
((string).pointer[offset] - (yaml_char_t) '0'))
|
||||
|
||||
#define AS_HEX(string) AS_HEX_AT((string),0)
|
||||
|
||||
/*
|
||||
* Check if the character is ASCII.
|
||||
*/
|
||||
|
||||
#define IS_ASCII_AT(string,offset) \
|
||||
((string).pointer[offset] <= (yaml_char_t) '\x7F')
|
||||
|
||||
#define IS_ASCII(string) IS_ASCII_AT((string),0)
|
||||
|
||||
/*
|
||||
* Check if the character can be printed unescaped.
|
||||
*/
|
||||
|
||||
#define IS_PRINTABLE_AT(string,offset) \
|
||||
(((string).pointer[offset] == 0x0A) /* . == #x0A */ \
|
||||
|| ((string).pointer[offset] >= 0x20 /* #x20 <= . <= #x7E */ \
|
||||
&& (string).pointer[offset] <= 0x7E) \
|
||||
|| ((string).pointer[offset] == 0xC2 /* #0xA0 <= . <= #xD7FF */ \
|
||||
&& (string).pointer[offset+1] >= 0xA0) \
|
||||
|| ((string).pointer[offset] > 0xC2 \
|
||||
&& (string).pointer[offset] < 0xED) \
|
||||
|| ((string).pointer[offset] == 0xED \
|
||||
&& (string).pointer[offset+1] < 0xA0) \
|
||||
|| ((string).pointer[offset] == 0xEE) \
|
||||
|| ((string).pointer[offset] == 0xEF /* #xE000 <= . <= #xFFFD */ \
|
||||
&& !((string).pointer[offset+1] == 0xBB /* && . != #xFEFF */ \
|
||||
&& (string).pointer[offset+2] == 0xBF) \
|
||||
&& !((string).pointer[offset+1] == 0xBF \
|
||||
&& ((string).pointer[offset+2] == 0xBE \
|
||||
|| (string).pointer[offset+2] == 0xBF))))
|
||||
|
||||
#define IS_PRINTABLE(string) IS_PRINTABLE_AT((string),0)
|
||||
|
||||
/*
|
||||
* Check if the character at the specified position is NUL.
|
||||
*/
|
||||
|
||||
#define IS_Z_AT(string,offset) CHECK_AT((string),'\0',(offset))
|
||||
|
||||
#define IS_Z(string) IS_Z_AT((string),0)
|
||||
|
||||
/*
|
||||
* Check if the character at the specified position is BOM.
|
||||
*/
|
||||
|
||||
#define IS_BOM_AT(string,offset) \
|
||||
(CHECK_AT((string),'\xEF',(offset)) \
|
||||
&& CHECK_AT((string),'\xBB',(offset)+1) \
|
||||
&& CHECK_AT((string),'\xBF',(offset)+2)) /* BOM (#xFEFF) */
|
||||
|
||||
#define IS_BOM(string) IS_BOM_AT(string,0)
|
||||
|
||||
/*
|
||||
* Check if the character at the specified position is space.
|
||||
*/
|
||||
|
||||
#define IS_SPACE_AT(string,offset) CHECK_AT((string),' ',(offset))
|
||||
|
||||
#define IS_SPACE(string) IS_SPACE_AT((string),0)
|
||||
|
||||
/*
|
||||
* Check if the character at the specified position is tab.
|
||||
*/
|
||||
|
||||
#define IS_TAB_AT(string,offset) CHECK_AT((string),'\t',(offset))
|
||||
|
||||
#define IS_TAB(string) IS_TAB_AT((string),0)
|
||||
|
||||
/*
|
||||
* Check if the character at the specified position is blank (space or tab).
|
||||
*/
|
||||
|
||||
#define IS_BLANK_AT(string,offset) \
|
||||
(IS_SPACE_AT((string),(offset)) || IS_TAB_AT((string),(offset)))
|
||||
|
||||
#define IS_BLANK(string) IS_BLANK_AT((string),0)
|
||||
|
||||
/*
|
||||
* Check if the character at the specified position is a line break.
|
||||
*/
|
||||
|
||||
#define IS_BREAK_AT(string,offset) \
|
||||
(CHECK_AT((string),'\r',(offset)) /* CR (#xD)*/ \
|
||||
|| CHECK_AT((string),'\n',(offset)) /* LF (#xA) */ \
|
||||
|| (CHECK_AT((string),'\xC2',(offset)) \
|
||||
&& CHECK_AT((string),'\x85',(offset)+1)) /* NEL (#x85) */ \
|
||||
|| (CHECK_AT((string),'\xE2',(offset)) \
|
||||
&& CHECK_AT((string),'\x80',(offset)+1) \
|
||||
&& CHECK_AT((string),'\xA8',(offset)+2)) /* LS (#x2028) */ \
|
||||
|| (CHECK_AT((string),'\xE2',(offset)) \
|
||||
&& CHECK_AT((string),'\x80',(offset)+1) \
|
||||
&& CHECK_AT((string),'\xA9',(offset)+2))) /* PS (#x2029) */
|
||||
|
||||
#define IS_BREAK(string) IS_BREAK_AT((string),0)
|
||||
|
||||
#define IS_CRLF_AT(string,offset) \
|
||||
(CHECK_AT((string),'\r',(offset)) && CHECK_AT((string),'\n',(offset)+1))
|
||||
|
||||
#define IS_CRLF(string) IS_CRLF_AT((string),0)
|
||||
|
||||
/*
|
||||
* Check if the character is a line break or NUL.
|
||||
*/
|
||||
|
||||
#define IS_BREAKZ_AT(string,offset) \
|
||||
(IS_BREAK_AT((string),(offset)) || IS_Z_AT((string),(offset)))
|
||||
|
||||
#define IS_BREAKZ(string) IS_BREAKZ_AT((string),0)
|
||||
|
||||
/*
|
||||
* Check if the character is a line break, space, or NUL.
|
||||
*/
|
||||
|
||||
#define IS_SPACEZ_AT(string,offset) \
|
||||
(IS_SPACE_AT((string),(offset)) || IS_BREAKZ_AT((string),(offset)))
|
||||
|
||||
#define IS_SPACEZ(string) IS_SPACEZ_AT((string),0)
|
||||
|
||||
/*
|
||||
* Check if the character is a line break, space, tab, or NUL.
|
||||
*/
|
||||
|
||||
#define IS_BLANKZ_AT(string,offset) \
|
||||
(IS_BLANK_AT((string),(offset)) || IS_BREAKZ_AT((string),(offset)))
|
||||
|
||||
#define IS_BLANKZ(string) IS_BLANKZ_AT((string),0)
|
||||
|
||||
/*
|
||||
* Determine the width of the character.
|
||||
*/
|
||||
|
||||
#define WIDTH_AT(string,offset) \
|
||||
(((string).pointer[offset] & 0x80) == 0x00 ? 1 : \
|
||||
((string).pointer[offset] & 0xE0) == 0xC0 ? 2 : \
|
||||
((string).pointer[offset] & 0xF0) == 0xE0 ? 3 : \
|
||||
((string).pointer[offset] & 0xF8) == 0xF0 ? 4 : 0)
|
||||
|
||||
#define WIDTH(string) WIDTH_AT((string),0)
|
||||
|
||||
/*
|
||||
* Move the string pointer to the next character.
|
||||
*/
|
||||
|
||||
#define MOVE(string) ((string).pointer += WIDTH((string)))
|
||||
|
||||
/*
|
||||
* Copy a character and move the pointers of both strings.
|
||||
*/
|
||||
|
||||
#define COPY(string_a,string_b) \
|
||||
((*(string_b).pointer & 0x80) == 0x00 ? \
|
||||
(*((string_a).pointer++) = *((string_b).pointer++)) : \
|
||||
(*(string_b).pointer & 0xE0) == 0xC0 ? \
|
||||
(*((string_a).pointer++) = *((string_b).pointer++), \
|
||||
*((string_a).pointer++) = *((string_b).pointer++)) : \
|
||||
(*(string_b).pointer & 0xF0) == 0xE0 ? \
|
||||
(*((string_a).pointer++) = *((string_b).pointer++), \
|
||||
*((string_a).pointer++) = *((string_b).pointer++), \
|
||||
*((string_a).pointer++) = *((string_b).pointer++)) : \
|
||||
(*(string_b).pointer & 0xF8) == 0xF0 ? \
|
||||
(*((string_a).pointer++) = *((string_b).pointer++), \
|
||||
*((string_a).pointer++) = *((string_b).pointer++), \
|
||||
*((string_a).pointer++) = *((string_b).pointer++), \
|
||||
*((string_a).pointer++) = *((string_b).pointer++)) : 0)
|
||||
|
||||
/*
|
||||
* Stack and queue management.
|
||||
*/
|
||||
|
||||
YAML_DECLARE(int)
|
||||
yaml_stack_extend(void **start, void **top, void **end);
|
||||
|
||||
YAML_DECLARE(int)
|
||||
yaml_queue_extend(void **start, void **head, void **tail, void **end);
|
||||
|
||||
#define STACK_INIT(context,stack,size) \
|
||||
(((stack).start = yaml_malloc((size)*sizeof(*(stack).start))) ? \
|
||||
((stack).top = (stack).start, \
|
||||
(stack).end = (stack).start+(size), \
|
||||
1) : \
|
||||
((context)->error = YAML_MEMORY_ERROR, \
|
||||
0))
|
||||
|
||||
#define STACK_DEL(context,stack) \
|
||||
(yaml_free((stack).start), \
|
||||
(stack).start = (stack).top = (stack).end = 0)
|
||||
|
||||
#define STACK_EMPTY(context,stack) \
|
||||
((stack).start == (stack).top)
|
||||
|
||||
#define STACK_LIMIT(context,stack,size) \
|
||||
((stack).top - (stack).start < (size) ? \
|
||||
1 : \
|
||||
((context)->error = YAML_MEMORY_ERROR, \
|
||||
0))
|
||||
|
||||
#define PUSH(context,stack,value) \
|
||||
(((stack).top != (stack).end \
|
||||
|| yaml_stack_extend((void **)&(stack).start, \
|
||||
(void **)&(stack).top, (void **)&(stack).end)) ? \
|
||||
(*((stack).top++) = value, \
|
||||
1) : \
|
||||
((context)->error = YAML_MEMORY_ERROR, \
|
||||
0))
|
||||
|
||||
#define POP(context,stack) \
|
||||
(*(--(stack).top))
|
||||
|
||||
#define QUEUE_INIT(context,queue,size) \
|
||||
(((queue).start = yaml_malloc((size)*sizeof(*(queue).start))) ? \
|
||||
((queue).head = (queue).tail = (queue).start, \
|
||||
(queue).end = (queue).start+(size), \
|
||||
1) : \
|
||||
((context)->error = YAML_MEMORY_ERROR, \
|
||||
0))
|
||||
|
||||
#define QUEUE_DEL(context,queue) \
|
||||
(yaml_free((queue).start), \
|
||||
(queue).start = (queue).head = (queue).tail = (queue).end = 0)
|
||||
|
||||
#define QUEUE_EMPTY(context,queue) \
|
||||
((queue).head == (queue).tail)
|
||||
|
||||
#define ENQUEUE(context,queue,value) \
|
||||
(((queue).tail != (queue).end \
|
||||
|| yaml_queue_extend((void **)&(queue).start, (void **)&(queue).head, \
|
||||
(void **)&(queue).tail, (void **)&(queue).end)) ? \
|
||||
(*((queue).tail++) = value, \
|
||||
1) : \
|
||||
((context)->error = YAML_MEMORY_ERROR, \
|
||||
0))
|
||||
|
||||
#define DEQUEUE(context,queue) \
|
||||
(*((queue).head++))
|
||||
|
||||
#define QUEUE_INSERT(context,queue,index,value) \
|
||||
(((queue).tail != (queue).end \
|
||||
|| yaml_queue_extend((void **)&(queue).start, (void **)&(queue).head, \
|
||||
(void **)&(queue).tail, (void **)&(queue).end)) ? \
|
||||
(memmove((queue).head+(index)+1,(queue).head+(index), \
|
||||
((queue).tail-(queue).head-(index))*sizeof(*(queue).start)), \
|
||||
*((queue).head+(index)) = value, \
|
||||
(queue).tail++, \
|
||||
1) : \
|
||||
((context)->error = YAML_MEMORY_ERROR, \
|
||||
0))
|
||||
|
||||
/*
|
||||
* Token initializers.
|
||||
*/
|
||||
|
||||
#define TOKEN_INIT(token,token_type,token_start_mark,token_end_mark) \
|
||||
(memset(&(token), 0, sizeof(yaml_token_t)), \
|
||||
(token).type = (token_type), \
|
||||
(token).start_mark = (token_start_mark), \
|
||||
(token).end_mark = (token_end_mark))
|
||||
|
||||
#define STREAM_START_TOKEN_INIT(token,token_encoding,start_mark,end_mark) \
|
||||
(TOKEN_INIT((token),YAML_STREAM_START_TOKEN,(start_mark),(end_mark)), \
|
||||
(token).data.stream_start.encoding = (token_encoding))
|
||||
|
||||
#define STREAM_END_TOKEN_INIT(token,start_mark,end_mark) \
|
||||
(TOKEN_INIT((token),YAML_STREAM_END_TOKEN,(start_mark),(end_mark)))
|
||||
|
||||
#define ALIAS_TOKEN_INIT(token,token_value,start_mark,end_mark) \
|
||||
(TOKEN_INIT((token),YAML_ALIAS_TOKEN,(start_mark),(end_mark)), \
|
||||
(token).data.alias.value = (token_value))
|
||||
|
||||
#define ANCHOR_TOKEN_INIT(token,token_value,start_mark,end_mark) \
|
||||
(TOKEN_INIT((token),YAML_ANCHOR_TOKEN,(start_mark),(end_mark)), \
|
||||
(token).data.anchor.value = (token_value))
|
||||
|
||||
#define TAG_TOKEN_INIT(token,token_handle,token_suffix,start_mark,end_mark) \
|
||||
(TOKEN_INIT((token),YAML_TAG_TOKEN,(start_mark),(end_mark)), \
|
||||
(token).data.tag.handle = (token_handle), \
|
||||
(token).data.tag.suffix = (token_suffix))
|
||||
|
||||
#define SCALAR_TOKEN_INIT(token,token_value,token_length,token_style,start_mark,end_mark) \
|
||||
(TOKEN_INIT((token),YAML_SCALAR_TOKEN,(start_mark),(end_mark)), \
|
||||
(token).data.scalar.value = (token_value), \
|
||||
(token).data.scalar.length = (token_length), \
|
||||
(token).data.scalar.style = (token_style))
|
||||
|
||||
#define VERSION_DIRECTIVE_TOKEN_INIT(token,token_major,token_minor,start_mark,end_mark) \
|
||||
(TOKEN_INIT((token),YAML_VERSION_DIRECTIVE_TOKEN,(start_mark),(end_mark)), \
|
||||
(token).data.version_directive.major = (token_major), \
|
||||
(token).data.version_directive.minor = (token_minor))
|
||||
|
||||
#define TAG_DIRECTIVE_TOKEN_INIT(token,token_handle,token_prefix,start_mark,end_mark) \
|
||||
(TOKEN_INIT((token),YAML_TAG_DIRECTIVE_TOKEN,(start_mark),(end_mark)), \
|
||||
(token).data.tag_directive.handle = (token_handle), \
|
||||
(token).data.tag_directive.prefix = (token_prefix))
|
||||
|
||||
/*
|
||||
* Event initializers.
|
||||
*/
|
||||
|
||||
#define EVENT_INIT(event,event_type,event_start_mark,event_end_mark) \
|
||||
(memset(&(event), 0, sizeof(yaml_event_t)), \
|
||||
(event).type = (event_type), \
|
||||
(event).start_mark = (event_start_mark), \
|
||||
(event).end_mark = (event_end_mark))
|
||||
|
||||
#define STREAM_START_EVENT_INIT(event,event_encoding,start_mark,end_mark) \
|
||||
(EVENT_INIT((event),YAML_STREAM_START_EVENT,(start_mark),(end_mark)), \
|
||||
(event).data.stream_start.encoding = (event_encoding))
|
||||
|
||||
#define STREAM_END_EVENT_INIT(event,start_mark,end_mark) \
|
||||
(EVENT_INIT((event),YAML_STREAM_END_EVENT,(start_mark),(end_mark)))
|
||||
|
||||
#define DOCUMENT_START_EVENT_INIT(event,event_version_directive, \
|
||||
event_tag_directives_start,event_tag_directives_end,event_implicit,start_mark,end_mark) \
|
||||
(EVENT_INIT((event),YAML_DOCUMENT_START_EVENT,(start_mark),(end_mark)), \
|
||||
(event).data.document_start.version_directive = (event_version_directive), \
|
||||
(event).data.document_start.tag_directives.start = (event_tag_directives_start), \
|
||||
(event).data.document_start.tag_directives.end = (event_tag_directives_end), \
|
||||
(event).data.document_start.implicit = (event_implicit))
|
||||
|
||||
#define DOCUMENT_END_EVENT_INIT(event,event_implicit,start_mark,end_mark) \
|
||||
(EVENT_INIT((event),YAML_DOCUMENT_END_EVENT,(start_mark),(end_mark)), \
|
||||
(event).data.document_end.implicit = (event_implicit))
|
||||
|
||||
#define ALIAS_EVENT_INIT(event,event_anchor,start_mark,end_mark) \
|
||||
(EVENT_INIT((event),YAML_ALIAS_EVENT,(start_mark),(end_mark)), \
|
||||
(event).data.alias.anchor = (event_anchor))
|
||||
|
||||
#define SCALAR_EVENT_INIT(event,event_anchor,event_tag,event_value,event_length, \
|
||||
event_plain_implicit, event_quoted_implicit,event_style,start_mark,end_mark) \
|
||||
(EVENT_INIT((event),YAML_SCALAR_EVENT,(start_mark),(end_mark)), \
|
||||
(event).data.scalar.anchor = (event_anchor), \
|
||||
(event).data.scalar.tag = (event_tag), \
|
||||
(event).data.scalar.value = (event_value), \
|
||||
(event).data.scalar.length = (event_length), \
|
||||
(event).data.scalar.plain_implicit = (event_plain_implicit), \
|
||||
(event).data.scalar.quoted_implicit = (event_quoted_implicit), \
|
||||
(event).data.scalar.style = (event_style))
|
||||
|
||||
#define SEQUENCE_START_EVENT_INIT(event,event_anchor,event_tag, \
|
||||
event_implicit,event_style,start_mark,end_mark) \
|
||||
(EVENT_INIT((event),YAML_SEQUENCE_START_EVENT,(start_mark),(end_mark)), \
|
||||
(event).data.sequence_start.anchor = (event_anchor), \
|
||||
(event).data.sequence_start.tag = (event_tag), \
|
||||
(event).data.sequence_start.implicit = (event_implicit), \
|
||||
(event).data.sequence_start.style = (event_style))
|
||||
|
||||
#define SEQUENCE_END_EVENT_INIT(event,start_mark,end_mark) \
|
||||
(EVENT_INIT((event),YAML_SEQUENCE_END_EVENT,(start_mark),(end_mark)))
|
||||
|
||||
#define MAPPING_START_EVENT_INIT(event,event_anchor,event_tag, \
|
||||
event_implicit,event_style,start_mark,end_mark) \
|
||||
(EVENT_INIT((event),YAML_MAPPING_START_EVENT,(start_mark),(end_mark)), \
|
||||
(event).data.mapping_start.anchor = (event_anchor), \
|
||||
(event).data.mapping_start.tag = (event_tag), \
|
||||
(event).data.mapping_start.implicit = (event_implicit), \
|
||||
(event).data.mapping_start.style = (event_style))
|
||||
|
||||
#define MAPPING_END_EVENT_INIT(event,start_mark,end_mark) \
|
||||
(EVENT_INIT((event),YAML_MAPPING_END_EVENT,(start_mark),(end_mark)))
|
||||
|
||||
/*
|
||||
* Document initializer.
|
||||
*/
|
||||
|
||||
#define DOCUMENT_INIT(document,document_nodes_start,document_nodes_end, \
|
||||
document_version_directive,document_tag_directives_start, \
|
||||
document_tag_directives_end,document_start_implicit, \
|
||||
document_end_implicit,document_start_mark,document_end_mark) \
|
||||
(memset(&(document), 0, sizeof(yaml_document_t)), \
|
||||
(document).nodes.start = (document_nodes_start), \
|
||||
(document).nodes.end = (document_nodes_end), \
|
||||
(document).nodes.top = (document_nodes_start), \
|
||||
(document).version_directive = (document_version_directive), \
|
||||
(document).tag_directives.start = (document_tag_directives_start), \
|
||||
(document).tag_directives.end = (document_tag_directives_end), \
|
||||
(document).start_implicit = (document_start_implicit), \
|
||||
(document).end_implicit = (document_end_implicit), \
|
||||
(document).start_mark = (document_start_mark), \
|
||||
(document).end_mark = (document_end_mark))
|
||||
|
||||
/*
|
||||
* Node initializers.
|
||||
*/
|
||||
|
||||
#define NODE_INIT(node,node_type,node_tag,node_start_mark,node_end_mark) \
|
||||
(memset(&(node), 0, sizeof(yaml_node_t)), \
|
||||
(node).type = (node_type), \
|
||||
(node).tag = (node_tag), \
|
||||
(node).start_mark = (node_start_mark), \
|
||||
(node).end_mark = (node_end_mark))
|
||||
|
||||
#define SCALAR_NODE_INIT(node,node_tag,node_value,node_length, \
|
||||
node_style,start_mark,end_mark) \
|
||||
(NODE_INIT((node),YAML_SCALAR_NODE,(node_tag),(start_mark),(end_mark)), \
|
||||
(node).data.scalar.value = (node_value), \
|
||||
(node).data.scalar.length = (node_length), \
|
||||
(node).data.scalar.style = (node_style))
|
||||
|
||||
#define SEQUENCE_NODE_INIT(node,node_tag,node_items_start,node_items_end, \
|
||||
node_style,start_mark,end_mark) \
|
||||
(NODE_INIT((node),YAML_SEQUENCE_NODE,(node_tag),(start_mark),(end_mark)), \
|
||||
(node).data.sequence.items.start = (node_items_start), \
|
||||
(node).data.sequence.items.end = (node_items_end), \
|
||||
(node).data.sequence.items.top = (node_items_start), \
|
||||
(node).data.sequence.style = (node_style))
|
||||
|
||||
#define MAPPING_NODE_INIT(node,node_tag,node_pairs_start,node_pairs_end, \
|
||||
node_style,start_mark,end_mark) \
|
||||
(NODE_INIT((node),YAML_MAPPING_NODE,(node_tag),(start_mark),(end_mark)), \
|
||||
(node).data.mapping.pairs.start = (node_pairs_start), \
|
||||
(node).data.mapping.pairs.end = (node_pairs_end), \
|
||||
(node).data.mapping.pairs.top = (node_pairs_start), \
|
||||
(node).data.mapping.style = (node_style))
|
||||
|
||||
17
scenes/boxCoordinates.yml
Normal file
17
scenes/boxCoordinates.yml
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
--- !Scene
|
||||
dimensions: [800, 600]
|
||||
camera:
|
||||
origin: [0, 0, -5]
|
||||
objects:
|
||||
- !Object.Sphere
|
||||
radius: 0.2
|
||||
origin: [0, 0, 0]
|
||||
color: [1, 1, 1]
|
||||
- !Object.Sphere
|
||||
radius: 0.2
|
||||
origin: [-0.5, -0.5, -0.5]
|
||||
color: [1, 0, 0]
|
||||
- !Object.Sphere
|
||||
radius: 0.2
|
||||
origin: [0.5, 0.5, 0.5]
|
||||
color: [0, 1, 1]
|
||||
18
scenes/oneBox.yml
Normal file
18
scenes/oneBox.yml
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
--- !Scene
|
||||
dimensions: [800, 600]
|
||||
camera: !Camera.Perspective
|
||||
origin: [7.48, 6.5, 5.34]
|
||||
lookAt: [0, 0, 0]
|
||||
objects:
|
||||
- !Object.Box
|
||||
near: [-1, -1, -1]
|
||||
far: [1, 1, 1]
|
||||
color: [1, 0, 0]
|
||||
- !Object.Sphere
|
||||
origin: [1.5, 0, 0]
|
||||
radius: 0.25
|
||||
color: [0, 1, 0]
|
||||
- !Object.Plane
|
||||
normal: [0, 1, 0]
|
||||
distance: 1
|
||||
color: [0, 0, 1]
|
||||
14
scenes/oneBoxVectorExpression.yml
Normal file
14
scenes/oneBoxVectorExpression.yml
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
--- !Scene
|
||||
dimensions: [800, 600]
|
||||
camera: !Camera.Perspective
|
||||
origin: [7.48, 6.5, 5.34]
|
||||
lookAt: [0, 0, 0]
|
||||
objects:
|
||||
- !Object.Box
|
||||
near: 3 * y + 2
|
||||
far: [1, 1, 1]
|
||||
color: [1, 0, 0]
|
||||
- !Object.Plane
|
||||
normal: [0, 1, 0]
|
||||
distance: 1
|
||||
color: [0, 0, 1]
|
||||
14
scenes/planeSphere.yml
Normal file
14
scenes/planeSphere.yml
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
--- !Scene
|
||||
dimensions: [800, 600]
|
||||
camera: !Camera.Perspective
|
||||
origin: [0, 3, -6]
|
||||
direction: [0, -0.316228, 0.948683]
|
||||
objects:
|
||||
- !Object.Plane
|
||||
normal: [0, 1, 0]
|
||||
distance: 1
|
||||
color: [0.0, 0.328, 0.8]
|
||||
- !Object.Sphere
|
||||
origin: [0, 1, 0]
|
||||
radius: 1
|
||||
color: [0.8, 0.284, 0.0]
|
||||
34
scenes/sphereGrid.yml
Normal file
34
scenes/sphereGrid.yml
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
--- !Scene
|
||||
dimensions: [800, 600]
|
||||
camera: !Camera.Perspective
|
||||
origin: [1.0, 1.5, -5]
|
||||
direction: [-0.188, -0.282, 0.941]
|
||||
objects:
|
||||
- !Object.Sphere
|
||||
origin: [-1, 0, 0]
|
||||
radius: 0.2
|
||||
color: [1, 0, 0]
|
||||
- !Object.Sphere
|
||||
origin: [0, 0, 0]
|
||||
radius: 0.2
|
||||
color: [0, 1, 0]
|
||||
- !Object.Sphere
|
||||
origin: [1, 0, 0]
|
||||
radius: 0.2
|
||||
color: [0, 0, 1]
|
||||
- !Object.Sphere
|
||||
origin: [0, 1, 0]
|
||||
radius: 0.2
|
||||
color: [1, 1, 0]
|
||||
- !Object.Sphere
|
||||
origin: [0, -1, 0]
|
||||
radius: 0.2
|
||||
color: [1, 0, 1]
|
||||
- !Object.Sphere
|
||||
origin: [0, 0, 1]
|
||||
radius: 0.2
|
||||
color: [0, 1, 1]
|
||||
- !Object.Sphere
|
||||
origin: [0, 0, -1]
|
||||
radius: 0.2
|
||||
color: [1, 1, 1]
|
||||
17
scenes/threeSpheres.yml
Normal file
17
scenes/threeSpheres.yml
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
--- !Scene
|
||||
dimensions: [800, 600]
|
||||
camera: !Camera.Perspective
|
||||
right: [1.33, 0, 0]
|
||||
objects:
|
||||
- !Object.Sphere
|
||||
origin: [0, 0.5, 2]
|
||||
radius: 0.33
|
||||
color: [1, 0, 0]
|
||||
- !Object.Sphere
|
||||
origin: [-0.33, 0, 2]
|
||||
radius: 0.33
|
||||
color: [0, 1, 0]
|
||||
- !Object.Sphere
|
||||
origin: [0.33, 0, 2]
|
||||
radius: 0.33
|
||||
color: [0, 0, 1]
|
||||
|
|
@ -4,20 +4,41 @@
|
|||
|
||||
Import('env')
|
||||
|
||||
files = Split("""
|
||||
basics.cc
|
||||
camera.cc
|
||||
light.cc
|
||||
material.cc
|
||||
object.cc
|
||||
object_sphere.cc
|
||||
object_plane.cc
|
||||
scene.cc
|
||||
writer_png.cc
|
||||
""")
|
||||
|
||||
lib = env.Library('charles', files)
|
||||
prog = env.Program('charles', [lib, 'charles.cc'])
|
||||
objs = []
|
||||
|
||||
subdirs = [
|
||||
'basics',
|
||||
'yaml',
|
||||
]
|
||||
|
||||
for d in subdirs:
|
||||
dir_objs = env.SConscript(env.Dir(d).File('SConscript'), {'env': env})
|
||||
objs.extend(dir_objs)
|
||||
|
||||
|
||||
files = [
|
||||
'camera.cc',
|
||||
'light.cc',
|
||||
'lightPoint.cc',
|
||||
'log.cc',
|
||||
'material.cc',
|
||||
'object.cc',
|
||||
'objectBox.cc',
|
||||
'objectPlane.cc',
|
||||
'objectSphere.cc',
|
||||
'reader_yaml.cc',
|
||||
'scene.cc',
|
||||
'stats.cc',
|
||||
'writer_png.cc',
|
||||
]
|
||||
|
||||
for f in files:
|
||||
objs.append(env.Object(f))
|
||||
|
||||
lib = env.Library('charles', objs)
|
||||
prog = env.Program('charles', ['charles.cc'], LIBS=[lib, 'png', 'yaml'])
|
||||
env.Alias('charles', prog)
|
||||
env.Default('charles')
|
||||
|
||||
Return('lib')
|
||||
env.Default('charles')
|
||||
|
|
|
|||
510
src/basics.cc
510
src/basics.cc
|
|
@ -1,510 +0,0 @@
|
|||
/* basics.c
|
||||
*
|
||||
* Definition of basic types.
|
||||
*
|
||||
* - Vector3 is a three tuple vector of x, y, and z.
|
||||
* - Ray is a vector plus a direction.
|
||||
* - Color is a four tuple of red, green, blue, and alpha.
|
||||
*
|
||||
* Eryn Wells <eryn@erynwells.me>
|
||||
*/
|
||||
|
||||
#include <cmath>
|
||||
#include "basics.h"
|
||||
|
||||
#pragma mark - Vectors
|
||||
|
||||
const Vector3 Vector3::Zero = Vector3();
|
||||
const Vector3 Vector3::X = Vector3(1, 0, 0);
|
||||
const Vector3 Vector3::Y = Vector3(0, 1, 0);
|
||||
const Vector3 Vector3::Z = Vector3(0, 0, 1);
|
||||
|
||||
|
||||
/*
|
||||
* Vector3::Vector3 --
|
||||
*
|
||||
* Default constructor. Create a zero vector.
|
||||
*/
|
||||
Vector3::Vector3()
|
||||
: Vector3(0.0, 0.0, 0.0)
|
||||
{ }
|
||||
|
||||
|
||||
/*
|
||||
* Vector3::Vector3 --
|
||||
*
|
||||
* Constructor. Create a vector consisting of the given coordinates.
|
||||
*/
|
||||
Vector3::Vector3(float _x, float _y, float _z)
|
||||
: x(_x), y(_y), z(_z)
|
||||
{ }
|
||||
|
||||
|
||||
/*
|
||||
* Vector3::operator= --
|
||||
*
|
||||
* Copy the given vector's values into this vector. Return a reference to this vector.
|
||||
*/
|
||||
Vector3 &
|
||||
Vector3::operator=(const Vector3 &v)
|
||||
{
|
||||
x = v.x;
|
||||
y = v.y;
|
||||
z = v.z;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Vector3::operator*= --
|
||||
* Vector3::operator/= --
|
||||
* Vector3::operator+= --
|
||||
* Vector3::operator-= --
|
||||
*
|
||||
* Perform the corresponding arithmetic operation on this vector and the given vector. These methods are destructive and
|
||||
* a reference to this vector is returned.
|
||||
*/
|
||||
Vector3 &
|
||||
Vector3::operator*=(const float &rhs)
|
||||
{
|
||||
x *= rhs;
|
||||
y *= rhs;
|
||||
z *= rhs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Vector3 &
|
||||
Vector3::operator/=(const float &rhs)
|
||||
{
|
||||
return *this *= (1.0f / rhs);
|
||||
}
|
||||
|
||||
Vector3 &
|
||||
Vector3::operator+=(const Vector3 &rhs)
|
||||
{
|
||||
x += rhs.x;
|
||||
y += rhs.y;
|
||||
z += rhs.z;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Vector3 &
|
||||
Vector3::operator-=(const Vector3 &rhs)
|
||||
{
|
||||
return *this += -rhs;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Vector3::operator* --
|
||||
* Vector3::operator/ --
|
||||
* Vector3::operator+ --
|
||||
* Vector3::operator- --
|
||||
*
|
||||
* Perform the corresponding operation on a copy of this vector. Return a new vector.
|
||||
*/
|
||||
Vector3
|
||||
Vector3::operator*(const float &rhs)
|
||||
const
|
||||
{
|
||||
return Vector3(*this) *= rhs;
|
||||
}
|
||||
|
||||
Vector3
|
||||
Vector3::operator/(const float &rhs)
|
||||
const
|
||||
{
|
||||
return Vector3(*this) /= rhs;
|
||||
}
|
||||
|
||||
Vector3
|
||||
Vector3::operator+(const Vector3 &rhs)
|
||||
const
|
||||
{
|
||||
return Vector3(*this) += rhs;
|
||||
}
|
||||
|
||||
Vector3
|
||||
Vector3::operator-(const Vector3 &rhs)
|
||||
const
|
||||
{
|
||||
return Vector3(*this) -= rhs;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Vector3::operator- --
|
||||
*
|
||||
* Negate this vector. Return a new vector.
|
||||
*/
|
||||
Vector3
|
||||
Vector3::operator-()
|
||||
const
|
||||
{
|
||||
return Vector3(-x, -y, -z);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Vector3::operator== --
|
||||
* Vector3::operator!= --
|
||||
*
|
||||
* Compute boolean equality and non-equality of this and the given vectors.
|
||||
*/
|
||||
bool
|
||||
Vector3::operator==(const Vector3 &rhs)
|
||||
const
|
||||
{
|
||||
return x == rhs.x && y == rhs.y && z == rhs.z;
|
||||
}
|
||||
|
||||
bool
|
||||
Vector3::operator!=(const Vector3 &rhs)
|
||||
const
|
||||
{
|
||||
return !(*this == rhs);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Vector3::length2 --
|
||||
*
|
||||
* Compute and return the length-squared of this vector.
|
||||
*/
|
||||
float
|
||||
Vector3::length2()
|
||||
const
|
||||
{
|
||||
return x*x + y*y + z*z;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Vector3::length --
|
||||
*
|
||||
* Compute and return the length of this vector.
|
||||
*/
|
||||
float
|
||||
Vector3::length()
|
||||
const
|
||||
{
|
||||
return sqrtf(length2());
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Vector3::dot --
|
||||
*
|
||||
* Compute and return the dot product of this and the given vectors.
|
||||
*/
|
||||
float
|
||||
Vector3::dot(const Vector3 &v)
|
||||
const
|
||||
{
|
||||
return x*v.x + y*v.y + z*v.z;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Vector3::cross --
|
||||
*
|
||||
* Compute and return the cross product of this and the given vectors.
|
||||
*/
|
||||
Vector3
|
||||
Vector3::cross(const Vector3 &v)
|
||||
const
|
||||
{
|
||||
return Vector3(y*v.z - z*v.y, z*v.x - x*v.z, x*v.y - y*v.x);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Vector3::normalize --
|
||||
*
|
||||
* Normalize this vector in place. That is, make this vector's magnitude (length) 1.0.
|
||||
*/
|
||||
Vector3 &
|
||||
Vector3::normalize()
|
||||
{
|
||||
// Use the overloaded /= compound operator to do this.
|
||||
return *this /= length();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* operator* --
|
||||
*
|
||||
* Multiply the given float by the given vector. Return a new vector.
|
||||
*/
|
||||
const Vector3
|
||||
operator*(const float &lhs, const Vector3 &rhs)
|
||||
{
|
||||
return rhs * lhs;
|
||||
}
|
||||
|
||||
|
||||
std::ostream &
|
||||
operator<<(std::ostream &os, const Vector3 &v)
|
||||
{
|
||||
// Stream the vector like this: <x, y, z>
|
||||
os << "<" << v.x << ", " << v.y << ", " << v.z << ">";
|
||||
return os;
|
||||
}
|
||||
|
||||
#pragma mark - Rays
|
||||
|
||||
/*
|
||||
* Ray::Ray --
|
||||
*
|
||||
* Default constructor. Create a ray at the origin (0, 0, 0) with direction (0, 0, 0).
|
||||
*/
|
||||
Ray::Ray()
|
||||
: Ray(Vector3::Zero, Vector3::Zero)
|
||||
{ }
|
||||
|
||||
|
||||
/*
|
||||
* Ray::Ray --
|
||||
*
|
||||
* Constructor. Create a ray with the given origin and direction.
|
||||
*/
|
||||
Ray::Ray(Vector3 o, Vector3 d)
|
||||
: origin(o), direction(d)
|
||||
{ }
|
||||
|
||||
|
||||
/*
|
||||
* Ray::parameterize --
|
||||
*
|
||||
* Compute and return the point given by parameterizing this Ray by time t.
|
||||
*/
|
||||
Vector3
|
||||
Ray::parameterize(const float t)
|
||||
const
|
||||
{
|
||||
return origin + t * direction;
|
||||
}
|
||||
|
||||
|
||||
std::ostream &
|
||||
operator<<(std::ostream &os, const Ray &r)
|
||||
{
|
||||
os << "[Ray " << r.origin << " " << r.direction << "]";
|
||||
return os;
|
||||
}
|
||||
|
||||
#pragma mark - Colors
|
||||
|
||||
const Color Color::Black = Color();
|
||||
const Color Color::White = Color(1.0, 1.0, 1.0, 1.0);
|
||||
const Color Color::Red = Color(1.0, 0.0, 0.0, 1.0);
|
||||
const Color Color::Green = Color(0.0, 1.0, 0.0, 1.0);
|
||||
const Color Color::Blue = Color(0.0, 0.0, 1.0, 1.0);
|
||||
|
||||
|
||||
/*
|
||||
* Color::Color --
|
||||
*
|
||||
* Default constructor. Create a new Color with zeros for all components (black).
|
||||
*/
|
||||
Color::Color()
|
||||
: Color(0.0, 0.0, 0.0, 0.0)
|
||||
{ }
|
||||
|
||||
|
||||
/*
|
||||
* Color::Color --
|
||||
*
|
||||
* Constructor. Create a new Color with the given RGB components. Alpha is 1.0.
|
||||
*/
|
||||
Color::Color(const float &r, const float &g, const float &b)
|
||||
: Color(r, g, b, 1.0)
|
||||
{ }
|
||||
|
||||
|
||||
/*
|
||||
* Color::Color --
|
||||
*
|
||||
* Constructor. Create a new Color with the given components.
|
||||
*/
|
||||
Color::Color(const float &r, const float &g, const float &b, const float &a)
|
||||
: red(r), green(g), blue(b), alpha(a)
|
||||
{ }
|
||||
|
||||
|
||||
/*
|
||||
* Color::operator*= --
|
||||
* Color::operator/= --
|
||||
* Color::operator+= --
|
||||
* Color::operator-= --
|
||||
*
|
||||
* Perform the corresponding arithmetic operation on this color and the given scalar. These methods are destructive and
|
||||
* a reference to this color is returned.
|
||||
*/
|
||||
Color &
|
||||
Color::operator*=(const float &rhs)
|
||||
{
|
||||
red *= rhs;
|
||||
green *= rhs;
|
||||
blue *= rhs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Color &
|
||||
Color::operator/=(const float &rhs)
|
||||
{
|
||||
return *this *= (1.0 / rhs);
|
||||
}
|
||||
|
||||
Color &
|
||||
Color::operator+=(const float &rhs)
|
||||
{
|
||||
red += rhs;
|
||||
green += rhs;
|
||||
blue += rhs;
|
||||
alpha += rhs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Color &
|
||||
Color::operator-=(const float &rhs)
|
||||
{
|
||||
return *this += -rhs;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Color::operator* --
|
||||
* Color::operator/ --
|
||||
* Color::operator+ --
|
||||
* Color::operator- --
|
||||
*
|
||||
* Perform the corresponding operation on a copy of this color and the given scalar. Return a new vector.
|
||||
*/
|
||||
Color
|
||||
Color::operator*(const float &rhs)
|
||||
const
|
||||
{
|
||||
return Color(*this) *= rhs;
|
||||
}
|
||||
|
||||
Color
|
||||
Color::operator/(const float &rhs)
|
||||
const
|
||||
{
|
||||
return Color(*this) /= rhs;
|
||||
}
|
||||
|
||||
Color
|
||||
Color::operator+(const float &rhs)
|
||||
const
|
||||
{
|
||||
return Color(*this) += rhs;
|
||||
}
|
||||
|
||||
Color
|
||||
Color::operator-(const float &rhs)
|
||||
const
|
||||
{
|
||||
return Color(*this) -= rhs;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Color::operator= --
|
||||
*
|
||||
* Copy the given color's values into this color. Return a reference to this color.
|
||||
*/
|
||||
Color &
|
||||
Color::operator=(const Color &rhs)
|
||||
{
|
||||
red = rhs.red;
|
||||
green = rhs.green;
|
||||
blue = rhs.blue;
|
||||
alpha = rhs.alpha;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
Color &
|
||||
Color::operator*=(const Color &rhs)
|
||||
{
|
||||
red *= rhs.red;
|
||||
green *= rhs.green;
|
||||
blue *= rhs.blue;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Color &
|
||||
Color::operator/=(const Color &rhs)
|
||||
{
|
||||
red *= (1.0 / rhs.red);
|
||||
green *= (1.0 / rhs.green);
|
||||
blue *= (1.0 / rhs.blue);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Color &
|
||||
Color::operator+=(const Color &rhs)
|
||||
{
|
||||
red += rhs.red;
|
||||
green += rhs.green;
|
||||
blue += rhs.blue;
|
||||
alpha += rhs.alpha;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Color &
|
||||
Color::operator-=(const Color &rhs)
|
||||
{
|
||||
red -= rhs.red;
|
||||
green -= rhs.green;
|
||||
blue -= rhs.blue;
|
||||
alpha -= rhs.alpha;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
Color
|
||||
Color::operator*(const Color &rhs)
|
||||
const
|
||||
{
|
||||
return Color(*this) *= rhs;
|
||||
}
|
||||
|
||||
Color
|
||||
Color::operator/(const Color &rhs)
|
||||
const
|
||||
{
|
||||
return Color(*this) /= rhs;
|
||||
}
|
||||
|
||||
Color
|
||||
Color::operator+(const Color &rhs)
|
||||
const
|
||||
{
|
||||
return Color(*this) += rhs;
|
||||
}
|
||||
|
||||
Color
|
||||
Color::operator-(const Color &rhs)
|
||||
const
|
||||
{
|
||||
return Color(*this) -= rhs;
|
||||
}
|
||||
|
||||
|
||||
const Color
|
||||
operator*(const float &lhs, const Color &rhs)
|
||||
{
|
||||
return rhs * lhs;
|
||||
}
|
||||
|
||||
|
||||
std::ostream &
|
||||
operator<<(std::ostream &os, const Color &c)
|
||||
{
|
||||
// Stream colors like this: <r, g, b, a>
|
||||
os << "<" << c.red << ", " << c.green << ", " << c.blue << ", " << c.alpha << ">";
|
||||
return os;
|
||||
}
|
||||
107
src/basics.h
107
src/basics.h
|
|
@ -1,107 +0,0 @@
|
|||
/* basics.h
|
||||
*
|
||||
* Declaration of basic types.
|
||||
*
|
||||
* - Vector3 is a three tuple vector of x, y, and z.
|
||||
* - Ray is a vector plus a direction.
|
||||
* - Color is a four tuple of red, green, blue, and alpha.
|
||||
*
|
||||
* Eryn Wells <eryn@erynwells.me>
|
||||
*/
|
||||
|
||||
#ifndef __BASICS_H__
|
||||
#define __BASICS_H__
|
||||
|
||||
#include <iostream>
|
||||
|
||||
|
||||
struct Vector3
|
||||
{
|
||||
Vector3();
|
||||
Vector3(float x, float y, float z);
|
||||
|
||||
Vector3 &operator=(const Vector3 &v);
|
||||
Vector3 &operator*=(const float &rhs);
|
||||
Vector3 &operator/=(const float &rhs);
|
||||
Vector3 &operator+=(const Vector3 &rhs);
|
||||
Vector3 &operator-=(const Vector3 &rhs);
|
||||
Vector3 operator*(const float &rhs) const;
|
||||
Vector3 operator/(const float &rhs) const;
|
||||
Vector3 operator+(const Vector3 &rhs) const;
|
||||
Vector3 operator-(const Vector3 &rhs) const;
|
||||
Vector3 operator-() const;
|
||||
|
||||
bool operator==(const Vector3 &rhs) const;
|
||||
bool operator!=(const Vector3 &rhs) const;
|
||||
|
||||
float length2() const;
|
||||
float length() const;
|
||||
float dot(const Vector3 &v) const;
|
||||
Vector3 cross(const Vector3 &v) const;
|
||||
|
||||
Vector3 &normalize();
|
||||
|
||||
static const Vector3 Zero;
|
||||
// Unit vectors in each of the three cartesian directions.
|
||||
static const Vector3 X, Y, Z;
|
||||
|
||||
float x, y, z;
|
||||
};
|
||||
|
||||
const Vector3 operator*(const float &lhs, const Vector3 &rhs);
|
||||
std::ostream &operator<<(std::ostream &os, const Vector3 &v);
|
||||
|
||||
|
||||
struct Ray
|
||||
{
|
||||
Ray();
|
||||
Ray(Vector3 o, Vector3 d);
|
||||
|
||||
Vector3 parameterize(const float t) const;
|
||||
|
||||
Vector3 origin, direction;
|
||||
};
|
||||
|
||||
std::ostream &operator<<(std::ostream &os, const Ray &r);
|
||||
|
||||
|
||||
struct Color
|
||||
{
|
||||
Color();
|
||||
Color(const float &r, const float &g, const float &b);
|
||||
Color(const float &r, const float &g, const float &b, const float &a);
|
||||
|
||||
Color &operator*=(const float &rhs);
|
||||
Color &operator/=(const float &rhs);
|
||||
Color &operator+=(const float &rhs);
|
||||
Color &operator-=(const float &rhs);
|
||||
Color operator*(const float &rhs) const;
|
||||
Color operator/(const float &rhs) const;
|
||||
Color operator+(const float &rhs) const;
|
||||
Color operator-(const float &rhs) const;
|
||||
|
||||
Color &operator=(const Color &rhs);
|
||||
|
||||
// These operators blend the two colors.
|
||||
Color &operator*=(const Color &rhs);
|
||||
Color &operator/=(const Color &rhs);
|
||||
Color &operator+=(const Color &rhs);
|
||||
Color &operator-=(const Color &rhs);
|
||||
Color operator*(const Color &rhs) const;
|
||||
Color operator/(const Color &rhs) const;
|
||||
Color operator+(const Color &rhs) const;
|
||||
Color operator-(const Color &rhs) const;
|
||||
|
||||
static const Color Black;
|
||||
static const Color White;
|
||||
static const Color Red;
|
||||
static const Color Green;
|
||||
static const Color Blue;
|
||||
|
||||
float red, green, blue, alpha;
|
||||
};
|
||||
|
||||
const Color operator*(const float &lhs, const Color &rhs);
|
||||
std::ostream &operator<<(std::ostream &os, const Color &c);
|
||||
|
||||
#endif
|
||||
16
src/basics/SConscript
Normal file
16
src/basics/SConscript
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
# SConscript
|
||||
# vim: set ft=python:
|
||||
# Eryn Wells <eryn@erynwells.me>
|
||||
|
||||
Import('env')
|
||||
|
||||
|
||||
files = [
|
||||
'color.cc',
|
||||
'matrix.cc',
|
||||
'ray.cc',
|
||||
'vector.cc',
|
||||
]
|
||||
|
||||
objs = [env.Object(f) for f in files]
|
||||
Return('objs')
|
||||
21
src/basics/basics.hh
Normal file
21
src/basics/basics.hh
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
/* basics.hh
|
||||
* vim: set tw=80:
|
||||
* Eryn Wells <eryn@erynwells.me>
|
||||
*/
|
||||
/**
|
||||
* Top-level include for the basics module.
|
||||
*/
|
||||
|
||||
#ifndef __BASICS_BASICS_HH__
|
||||
#define __BASICS_BASICS_HH__
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include "basics/color.hh"
|
||||
#include "basics/matrix.hh"
|
||||
#include "basics/ray.hh"
|
||||
#include "basics/types.hh"
|
||||
#include "basics/util.hh"
|
||||
#include "basics/vector.hh"
|
||||
|
||||
#endif /* __BASICS_BASICS_HH__ */
|
||||
272
src/basics/color.cc
Normal file
272
src/basics/color.cc
Normal file
|
|
@ -0,0 +1,272 @@
|
|||
/* color.cc
|
||||
* vim: set tw=80:
|
||||
* Eryn Wells <eryn@erynwells.me>
|
||||
*/
|
||||
|
||||
#include <ostream>
|
||||
|
||||
#include "basics/color.hh"
|
||||
|
||||
#include "basics/types.hh"
|
||||
|
||||
|
||||
namespace charles {
|
||||
namespace basics {
|
||||
|
||||
const Color Color::Black = Color();
|
||||
const Color Color::White = Color(1, 1, 1);
|
||||
const Color Color::Red = Color(1, 0, 0);
|
||||
const Color Color::Green = Color(0, 1, 0);
|
||||
const Color Color::Blue = Color(0, 0, 1);
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Color::Color --
|
||||
*/
|
||||
Color::Color()
|
||||
: Color(0.0, 0.0, 0.0, 0.0)
|
||||
{ }
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Color::Color --
|
||||
*/
|
||||
Color::Color(const Double& r,
|
||||
const Double& g,
|
||||
const Double& b,
|
||||
const Double& a)
|
||||
: red(r),
|
||||
green(g),
|
||||
blue(b),
|
||||
alpha(a)
|
||||
{ }
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Color::operator= --
|
||||
*/
|
||||
Color&
|
||||
Color::operator=(const Color& rhs)
|
||||
{
|
||||
red = rhs.red;
|
||||
green = rhs.green;
|
||||
blue = rhs.blue;
|
||||
alpha = rhs.alpha;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Color::operator*= --
|
||||
*/
|
||||
Color&
|
||||
Color::operator*=(const Double& rhs)
|
||||
{
|
||||
red *= rhs;
|
||||
green *= rhs;
|
||||
blue *= rhs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Color::operator/= --
|
||||
*/
|
||||
Color&
|
||||
Color::operator/=(const Double& rhs)
|
||||
{
|
||||
return *this *= (1.0 / rhs);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Color::operator+= --
|
||||
*/
|
||||
Color&
|
||||
Color::operator+=(const Double& rhs)
|
||||
{
|
||||
red += rhs;
|
||||
green += rhs;
|
||||
blue += rhs;
|
||||
alpha += rhs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Color::operator-= --
|
||||
*/
|
||||
Color&
|
||||
Color::operator-=(const Double& rhs)
|
||||
{
|
||||
return *this += -rhs;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Color::operator* --
|
||||
*/
|
||||
Color
|
||||
Color::operator*(const Double& rhs)
|
||||
const
|
||||
{
|
||||
return Color(*this) *= rhs;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Color::operator/ --
|
||||
*/
|
||||
Color
|
||||
Color::operator/(const Double& rhs)
|
||||
const
|
||||
{
|
||||
return Color(*this) /= rhs;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Color::operator+ --
|
||||
*/
|
||||
Color
|
||||
Color::operator+(const Double& rhs)
|
||||
const
|
||||
{
|
||||
return Color(*this) += rhs;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Color::operator- --
|
||||
*/
|
||||
Color
|
||||
Color::operator-(const Double& rhs)
|
||||
const
|
||||
{
|
||||
return Color(*this) -= rhs;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Color::operator*= --
|
||||
*/
|
||||
Color&
|
||||
Color::operator*=(const Color& rhs)
|
||||
{
|
||||
red *= rhs.red;
|
||||
green *= rhs.green;
|
||||
blue *= rhs.blue;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Color::operator/= --
|
||||
*/
|
||||
Color&
|
||||
Color::operator/=(const Color& rhs)
|
||||
{
|
||||
red /= rhs.red;
|
||||
green /= rhs.green;
|
||||
blue /= rhs.blue;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Color::operator+= --
|
||||
*/
|
||||
Color&
|
||||
Color::operator+=(const Color& rhs)
|
||||
{
|
||||
red += rhs.red;
|
||||
green += rhs.green;
|
||||
blue += rhs.blue;
|
||||
alpha += rhs.alpha;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Color::operator-= --
|
||||
*/
|
||||
Color&
|
||||
Color::operator-=(const Color& rhs)
|
||||
{
|
||||
red -= rhs.red;
|
||||
green -= rhs.green;
|
||||
blue -= rhs.blue;
|
||||
alpha -= rhs.alpha;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Color::operator* --
|
||||
*/
|
||||
Color
|
||||
Color::operator*(const Color& rhs)
|
||||
const
|
||||
{
|
||||
return Color(*this) *= rhs;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Color::operator/ --
|
||||
*/
|
||||
Color
|
||||
Color::operator/(const Color& rhs)
|
||||
const
|
||||
{
|
||||
return Color(*this) /= rhs;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Color::operator+ --
|
||||
*/
|
||||
Color
|
||||
Color::operator+(const Color& rhs)
|
||||
const
|
||||
{
|
||||
return Color(*this) += rhs;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Color::operator- --
|
||||
*/
|
||||
Color
|
||||
Color::operator-(const Color& rhs)
|
||||
const
|
||||
{
|
||||
return Color(*this) -= rhs;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::operator* --
|
||||
*/
|
||||
const Color
|
||||
operator*(const Double& lhs,
|
||||
const Color& rhs)
|
||||
{
|
||||
return rhs * lhs;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::operator<< --
|
||||
*/
|
||||
std::ostream &
|
||||
operator<<(std::ostream& os,
|
||||
const Color& c)
|
||||
{
|
||||
// Stream colors like this: <r, g, b, a>
|
||||
os << "<" << c.red << ", " << c.green << ", " << c.blue << ", " << c.alpha << ">";
|
||||
return os;
|
||||
}
|
||||
|
||||
} /* namespace basics */
|
||||
} /* namespace charles */
|
||||
58
src/basics/color.hh
Normal file
58
src/basics/color.hh
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
/* color.hh
|
||||
* vim: set tw=80:
|
||||
* Eryn Wells <eryn@erynwells.me>
|
||||
*/
|
||||
|
||||
#ifndef __BASICS_COLOR_HH__
|
||||
#define __BASICS_COLOR_HH__
|
||||
|
||||
#include "basics/types.hh"
|
||||
|
||||
|
||||
namespace charles {
|
||||
namespace basics {
|
||||
|
||||
struct Color
|
||||
{
|
||||
Color();
|
||||
Color(const Double& r, const Double& g, const Double& b, const Double& a = 1.0);
|
||||
|
||||
Color &operator*=(const Double &rhs);
|
||||
Color &operator/=(const Double &rhs);
|
||||
Color &operator+=(const Double &rhs);
|
||||
Color &operator-=(const Double &rhs);
|
||||
Color operator*(const Double &rhs) const;
|
||||
Color operator/(const Double &rhs) const;
|
||||
Color operator+(const Double &rhs) const;
|
||||
Color operator-(const Double &rhs) const;
|
||||
|
||||
Color &operator=(const Color &rhs);
|
||||
|
||||
// These operators blend the two colors.
|
||||
Color &operator*=(const Color &rhs);
|
||||
Color &operator/=(const Color &rhs);
|
||||
Color &operator+=(const Color &rhs);
|
||||
Color &operator-=(const Color &rhs);
|
||||
Color operator*(const Color &rhs) const;
|
||||
Color operator/(const Color &rhs) const;
|
||||
Color operator+(const Color &rhs) const;
|
||||
Color operator-(const Color &rhs) const;
|
||||
|
||||
static const Color Black;
|
||||
static const Color White;
|
||||
static const Color Red;
|
||||
static const Color Green;
|
||||
static const Color Blue;
|
||||
|
||||
Double red, green, blue, alpha;
|
||||
};
|
||||
|
||||
|
||||
const Color operator*(const Double &lhs, const Color &rhs);
|
||||
|
||||
std::ostream &operator<<(std::ostream &os, const Color &c);
|
||||
|
||||
} /* namespace basics */
|
||||
} /* namespace charles */
|
||||
|
||||
#endif /* __BASICS_COLOR_HH__ */
|
||||
382
src/basics/matrix.cc
Normal file
382
src/basics/matrix.cc
Normal file
|
|
@ -0,0 +1,382 @@
|
|||
/* matrix.cc
|
||||
* vim: set tw=80:
|
||||
* Eryn Wells <eryn@erynwells.me>
|
||||
*/
|
||||
|
||||
#include <cstring>
|
||||
#include <stdexcept>
|
||||
#include <sstream>
|
||||
#include <type_traits>
|
||||
|
||||
#include "basics/matrix.hh"
|
||||
|
||||
#include "basics/util.hh"
|
||||
#include "basics/vector.hh"
|
||||
|
||||
|
||||
namespace charles {
|
||||
namespace basics {
|
||||
|
||||
#pragma mark Static Methods
|
||||
|
||||
/*
|
||||
* charles::basics::Matrix4::Zero --
|
||||
*/
|
||||
/* static */ Matrix4
|
||||
Matrix4::Zero()
|
||||
{
|
||||
Matrix4 m;
|
||||
bzero(m.mData, sizeof(Double) * 16);
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Matrix4::Identity --
|
||||
*/
|
||||
/* static */ Matrix4
|
||||
Matrix4::Identity()
|
||||
{
|
||||
auto m = Matrix4::Zero();
|
||||
for (size_t i = 0; i < 4; i++) {
|
||||
m(i,i) = 1.0;
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Translation --
|
||||
*/
|
||||
/* static */ Matrix4
|
||||
Matrix4::Translation(const Vector4& p)
|
||||
{
|
||||
return Translation(p.X(), p.Y(), p.Z());
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::TranslationMatrix --
|
||||
*/
|
||||
/* static */ Matrix4
|
||||
Matrix4::Translation(Double x,
|
||||
Double y,
|
||||
Double z)
|
||||
{
|
||||
Matrix4 m = Matrix4::Identity();
|
||||
m(0,3) = x;
|
||||
m(1,3) = y;
|
||||
m(2,3) = z;
|
||||
return m;
|
||||
}
|
||||
|
||||
#pragma mark Constructors and Assignment
|
||||
|
||||
/*
|
||||
* charles::basics::Matrix4::Matrix4 --
|
||||
*/
|
||||
Matrix4::Matrix4()
|
||||
: mData(),
|
||||
mTransposed(false)
|
||||
{ }
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Matrix4::Matrix4 --
|
||||
*/
|
||||
Matrix4::Matrix4(const Double data[16])
|
||||
: mTransposed(false)
|
||||
{
|
||||
/* TODO: Replace with std::copy */
|
||||
memcpy(mData, data, sizeof(Double) * 16);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Matrix4::Matrix4 --
|
||||
*/
|
||||
Matrix4::Matrix4(const Matrix4 &rhs)
|
||||
: Matrix4(rhs.mData)
|
||||
{
|
||||
/*
|
||||
* Needs to be in the body instead of the initializer list because
|
||||
* (apparently) delegating constructors must be the only thing in the list.
|
||||
*/
|
||||
mTransposed = rhs.mTransposed;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Matrix4::operator= --
|
||||
*/
|
||||
Matrix4&
|
||||
Matrix4::operator=(const Matrix4 &rhs)
|
||||
{
|
||||
/* TODO: Replace with std::copy */
|
||||
memcpy(mData, rhs.mData, sizeof(Double) * 16);
|
||||
mTransposed = rhs.mTransposed;
|
||||
return *this;
|
||||
}
|
||||
|
||||
#pragma mark Boolean Operators
|
||||
|
||||
/*
|
||||
* charles::basics::Matrix4::operator== --
|
||||
*/
|
||||
bool
|
||||
Matrix4::operator==(const Matrix4 &rhs)
|
||||
const
|
||||
{
|
||||
for (int i = 0; i < 16; i++) {
|
||||
if (!NearlyEqual(mData[i], rhs.mData[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Matrix4::operator!= --
|
||||
*/
|
||||
bool
|
||||
Matrix4::operator!=(const Matrix4 &rhs)
|
||||
const
|
||||
{
|
||||
return !(*this == rhs);
|
||||
}
|
||||
|
||||
#pragma mark Element Access
|
||||
|
||||
/*
|
||||
* charles::basics::Matrix4::operator() --
|
||||
*/
|
||||
Double&
|
||||
Matrix4::operator()(UInt i,
|
||||
UInt j)
|
||||
{
|
||||
if (i >= 4 || j >= 4) {
|
||||
std::stringstream ss;
|
||||
ss << "matrix index out of bounds: i = " << i << ", j = " << j;
|
||||
throw std::out_of_range(ss.str());
|
||||
}
|
||||
|
||||
if (!mTransposed) {
|
||||
return mData[i*4 + j];
|
||||
} else {
|
||||
return mData[i + j*4];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Matrix4::operator() --
|
||||
*/
|
||||
Double
|
||||
Matrix4::operator()(UInt i,
|
||||
UInt j)
|
||||
const
|
||||
{
|
||||
if (i >= 4 || j >= 4) {
|
||||
std::stringstream ss;
|
||||
ss << "matrix index out of bounds: i = " << i << ", j = " << j;
|
||||
throw std::out_of_range(ss.str());
|
||||
}
|
||||
if (!mTransposed) {
|
||||
return mData[i*4 + j];
|
||||
} else {
|
||||
return mData[i + j*4];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Vector4
|
||||
Matrix4::Column(const UInt i)
|
||||
const noexcept
|
||||
{
|
||||
return Vector4(operator()(i,0), operator()(i,1), operator()(i,2), operator()(i,3));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Matrix4::CArray --
|
||||
*/
|
||||
const Double*
|
||||
Matrix4::CArray()
|
||||
const
|
||||
{
|
||||
return mData;
|
||||
}
|
||||
|
||||
#pragma mark Maths
|
||||
|
||||
/*
|
||||
* charles::basics::Matrix4::operator* --
|
||||
*/
|
||||
Matrix4
|
||||
Matrix4::operator*(Double rhs)
|
||||
const
|
||||
{
|
||||
return Matrix4(*this) *= rhs;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Matrix4::operator/ --
|
||||
*/
|
||||
Matrix4
|
||||
Matrix4::operator/(Double rhs)
|
||||
const
|
||||
{
|
||||
return Matrix4(*this) /= rhs;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Matrix4::operator*= --
|
||||
*/
|
||||
Matrix4&
|
||||
Matrix4::operator*=(Double rhs)
|
||||
{
|
||||
for (UInt i = 0; i < 16; i++) {
|
||||
mData[i] *= rhs;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Matrix4::operator/= --
|
||||
*/
|
||||
Matrix4&
|
||||
Matrix4::operator/=(Double rhs)
|
||||
{
|
||||
return *this *= (1.0 / rhs);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Matrix4::operator* --
|
||||
*/
|
||||
Matrix4
|
||||
Matrix4::operator*(const Matrix4& rhs)
|
||||
const
|
||||
{
|
||||
Matrix4 result;
|
||||
for (UInt i = 0; i < 4; i++) {
|
||||
for (UInt j = 0; j < 4; j++) {
|
||||
/* Each cell is Sigma(k=0, M)(lhs[ik] * rhs[kj]) */
|
||||
result(i,j) = 0.0;
|
||||
for (UInt k = 0; k < 4; k++) {
|
||||
result(i,j) += mData[i*4 + k] * rhs(k,j);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Matrix4::operator* --
|
||||
*/
|
||||
Vector4
|
||||
Matrix4::operator*(const Vector4 &rhs)
|
||||
const
|
||||
{
|
||||
Vector4 result;
|
||||
for (UInt i = 0; i < 4; i++) {
|
||||
result(i) = 0.0;
|
||||
for (UInt k = 0; k < 4; k++) {
|
||||
result(i) += mData[i*4 + k] * rhs(k);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Matrix4::Transpose --
|
||||
*/
|
||||
Matrix4&
|
||||
Matrix4::Transpose()
|
||||
{
|
||||
mTransposed = !mTransposed;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
Matrix4&
|
||||
Matrix4::Inverse()
|
||||
{
|
||||
/* XXX: Only translation matrices are supported right now. */
|
||||
operator()(0,3) = -operator()(0,3);
|
||||
operator()(1,3) = -operator()(1,3);
|
||||
operator()(2,3) = -operator()(2,3);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::operator* --
|
||||
*/
|
||||
Matrix4
|
||||
operator*(Double lhs,
|
||||
const Matrix4& rhs)
|
||||
{
|
||||
/* Scalar multiplication is commutative. */
|
||||
return rhs * lhs;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Transposed --
|
||||
*/
|
||||
Matrix4
|
||||
Transpose(Matrix4 m)
|
||||
{
|
||||
return m.Transpose();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Inverse --
|
||||
*/
|
||||
Matrix4
|
||||
Inverse(Matrix4 m)
|
||||
{
|
||||
return m.Inverse();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::operator<< --
|
||||
*/
|
||||
std::ostream&
|
||||
operator<<(std::ostream &ost,
|
||||
const Matrix4 &m)
|
||||
{
|
||||
ost << "[";
|
||||
for (UInt i = 0; i < 4; i++) {
|
||||
if (i != 0) {
|
||||
ost << " ";
|
||||
}
|
||||
ost << "[";
|
||||
for (UInt j = 0; j < 4; j++) {
|
||||
ost << m(i,j);
|
||||
if (j < 3) {
|
||||
ost << " ";
|
||||
}
|
||||
}
|
||||
ost << "]";
|
||||
if (i < 3) {
|
||||
ost << "\n";
|
||||
}
|
||||
}
|
||||
ost << "]";
|
||||
return ost;
|
||||
}
|
||||
|
||||
|
||||
} /* namespace mespace */
|
||||
} /* namespace charles */
|
||||
|
||||
108
src/basics/matrix.hh
Normal file
108
src/basics/matrix.hh
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
/* matrix.hh
|
||||
* vim: set tw=80:
|
||||
* Eryn Wells <eryn@erynwells.me>
|
||||
*/
|
||||
|
||||
#ifndef __BASICS_MATRIX_HH__
|
||||
#define __BASICS_MATRIX_HH__
|
||||
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <type_traits>
|
||||
|
||||
#include "basics/types.hh"
|
||||
|
||||
|
||||
namespace charles {
|
||||
namespace basics {
|
||||
|
||||
struct Vector4;
|
||||
|
||||
|
||||
/** A 4x4 matrix, used for 3D transforms. */
|
||||
struct Matrix4
|
||||
{
|
||||
/** Create a 4x4 matrix of zeros. */
|
||||
static Matrix4 Zero();
|
||||
|
||||
/** Create a 4x4 identity matrix. */
|
||||
static Matrix4 Identity();
|
||||
|
||||
/** Create a 4x4 translation matrix. */
|
||||
static Matrix4 Translation(Double x, Double y, Double z);
|
||||
static Matrix4 Translation(const Vector4 &p);
|
||||
|
||||
Matrix4();
|
||||
Matrix4(const Double *data);
|
||||
Matrix4(const Matrix4 &rhs);
|
||||
|
||||
Matrix4& operator=(const Matrix4 &rhs);
|
||||
|
||||
bool operator==(const Matrix4 &rhs) const;
|
||||
bool operator!=(const Matrix4 &rhs) const;
|
||||
|
||||
/**
|
||||
* Get the ij'th item. In debug builds, this will assert if i or j are
|
||||
* outside the bounds of the array.
|
||||
*/
|
||||
Double& operator()(UInt i, UInt j);
|
||||
Double operator()(UInt i, UInt j) const;
|
||||
Vector4 Column(const UInt i) const noexcept;
|
||||
|
||||
/** Get the underlying C array */
|
||||
const Double *CArray() const;
|
||||
|
||||
/*
|
||||
* TODO: For completeness, matrix addition and subtraction, though I have
|
||||
* yet to find a need for them...
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup Scalar multiplication
|
||||
* @{
|
||||
*/
|
||||
Matrix4 operator*(Double rhs) const;
|
||||
Matrix4 operator/(Double rhs) const;
|
||||
Matrix4& operator*=(Double rhs);
|
||||
Matrix4& operator/=(Double rhs);
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @defgroup Matrix multiplication
|
||||
* @{
|
||||
*/
|
||||
Matrix4 operator*(const Matrix4 &rhs) const;
|
||||
Vector4 operator*(const Vector4 &rhs) const;
|
||||
/** @} */
|
||||
|
||||
Matrix4 &Transpose();
|
||||
Matrix4 &Inverse();
|
||||
|
||||
protected:
|
||||
/** The matrix data */
|
||||
Double mData[16];
|
||||
|
||||
/**
|
||||
* `true` if the matrix has been transposed (i.e. should be indexed in
|
||||
* column-major format).
|
||||
*/
|
||||
bool mTransposed;
|
||||
};
|
||||
|
||||
|
||||
/** Scalar multiplication, scalar factor on the left. */
|
||||
Matrix4 operator*(Double lhs, const Matrix4 &rhs);
|
||||
|
||||
/** Transpose the given matrix. */
|
||||
Matrix4 Transpose(Matrix4 m);
|
||||
|
||||
/** Invert the given matrix. */
|
||||
Matrix4 Inverse(Matrix4 m);
|
||||
|
||||
|
||||
std::ostream& operator<<(std::ostream &ost, const Matrix4 &m);
|
||||
|
||||
} /* namespace basics */
|
||||
} /* namespace charles */
|
||||
|
||||
#endif /* __BASICS_MATRIX_HH__ */
|
||||
35
src/basics/ray.cc
Normal file
35
src/basics/ray.cc
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
/* ray.cc
|
||||
* vim: set tw=80:
|
||||
* Eryn Wells <eryn@erynwells.me>
|
||||
*/
|
||||
|
||||
#include "basics/ray.hh"
|
||||
|
||||
|
||||
namespace charles {
|
||||
namespace basics {
|
||||
|
||||
/*
|
||||
* charles::basics::Ray::Ray --
|
||||
*/
|
||||
Ray::Ray(Vector4 o,
|
||||
Vector4 d)
|
||||
: origin(o),
|
||||
direction(d)
|
||||
{ }
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Ray::Parameterize --
|
||||
*/
|
||||
Vector4
|
||||
Ray::Parameterize(const Double& t)
|
||||
const
|
||||
{
|
||||
return origin + direction * t;
|
||||
}
|
||||
|
||||
|
||||
} /* namespace basics */
|
||||
} /* namespace charles */
|
||||
|
||||
25
src/basics/ray.hh
Normal file
25
src/basics/ray.hh
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
/* ray.hh
|
||||
* vim: set tw=80:
|
||||
* Eryn Wells <eryn@erynwells.me>
|
||||
*/
|
||||
|
||||
#include "basics/types.hh"
|
||||
#include "basics/vector.hh"
|
||||
|
||||
|
||||
namespace charles {
|
||||
namespace basics {
|
||||
|
||||
struct Ray
|
||||
{
|
||||
Ray(Vector4 o = Vector4(), Vector4 d = Vector4());
|
||||
|
||||
Vector4 Parameterize(const Double& t) const;
|
||||
|
||||
Vector4 origin;
|
||||
Vector4 direction;
|
||||
};
|
||||
|
||||
} /* namespace basics */
|
||||
} /* namespace charles */
|
||||
|
||||
21
src/basics/types.hh
Normal file
21
src/basics/types.hh
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
/* types.hh
|
||||
* vim: set tw=80:
|
||||
* Eryn Wells <eryn@erynwells.me>
|
||||
*/
|
||||
/**
|
||||
* Some basic types.
|
||||
*/
|
||||
|
||||
#ifndef __BASICS_TYPES_HH__
|
||||
#define __BASICS_TYPES_HH__
|
||||
|
||||
#include <vector>
|
||||
|
||||
|
||||
typedef double Double;
|
||||
typedef unsigned int UInt;
|
||||
|
||||
typedef std::vector<Double> DoubleVector;
|
||||
typedef DoubleVector TVector;
|
||||
|
||||
#endif /* __BASICS_TYPES_HH__ */
|
||||
68
src/basics/util.hh
Normal file
68
src/basics/util.hh
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
/* util.hh
|
||||
* vim: set tw=80:
|
||||
* Eryn Wells <eryn@erynwells.me>
|
||||
*/
|
||||
|
||||
#ifndef __BASICS_UTIL_HH__
|
||||
#define __BASICS_UTIL_HH__
|
||||
|
||||
#include <cmath>
|
||||
|
||||
|
||||
/**
|
||||
* A very small constant. If a value is between EPSILON and 0.0, it is
|
||||
* considered to be zero.
|
||||
*/
|
||||
const Double EPSILON = 1.0e-10;
|
||||
|
||||
|
||||
/**
|
||||
* The maximum distance a ray can travel. This is the maximum value t can be.
|
||||
*/
|
||||
const Double MAX_DISTANCE = 1.0e7;
|
||||
|
||||
|
||||
/**
|
||||
* Determine if the value is "close enough" to zero. Takes the absolute value
|
||||
* and compares it to `EPSILON`.
|
||||
*
|
||||
* @see EPSILON
|
||||
*
|
||||
* @param [in] value The value to check
|
||||
* @returns `true` if the value is close enough to zero
|
||||
*/
|
||||
template <typename T>
|
||||
inline bool
|
||||
NearZero(T value)
|
||||
{
|
||||
return std::fabs(value) < EPSILON;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Determine if two values are "close enough" to be considered equal. Subtracts
|
||||
* one from the other and checks if the result is near zero.
|
||||
*
|
||||
* @see NearZero
|
||||
*
|
||||
* @param [in] left The left parameter
|
||||
* @param [in] right The right parameter
|
||||
* @returns `true` if the values are close enough to be equal
|
||||
*/
|
||||
template <typename T, typename U>
|
||||
inline bool
|
||||
NearlyEqual(T left,
|
||||
U right)
|
||||
{
|
||||
return NearZero(left - right);
|
||||
}
|
||||
|
||||
|
||||
inline bool
|
||||
TooFar(const Double& value)
|
||||
{
|
||||
return value > MAX_DISTANCE;
|
||||
}
|
||||
|
||||
#endif /* __BASICS_UTIL_HH__ */
|
||||
|
||||
399
src/basics/vector.cc
Normal file
399
src/basics/vector.cc
Normal file
|
|
@ -0,0 +1,399 @@
|
|||
/* vector.cc
|
||||
* vim: set tw=80:
|
||||
* Eryn Wells <eryn@erynwells.me>
|
||||
*/
|
||||
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
|
||||
#include "basics/vector.hh"
|
||||
|
||||
#include "basics/util.hh"
|
||||
|
||||
|
||||
namespace charles {
|
||||
namespace basics {
|
||||
|
||||
#pragma mark Constructors and Assignment
|
||||
|
||||
/*
|
||||
* charles::basics::Vector4::Vector4 --
|
||||
*/
|
||||
Vector4::Vector4()
|
||||
: Vector4(0, 0, 0)
|
||||
{ }
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Vector4::Vector4 --
|
||||
*/
|
||||
Vector4::Vector4(Double x,
|
||||
Double y,
|
||||
Double z)
|
||||
: Vector4(x, y, z, 1.0)
|
||||
{ }
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Vector4::Vector4 --
|
||||
*/
|
||||
Vector4::Vector4(Double x,
|
||||
Double y,
|
||||
Double z,
|
||||
Double w)
|
||||
{
|
||||
mData[0] = x;
|
||||
mData[1] = y;
|
||||
mData[2] = z;
|
||||
mData[3] = w;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Vector4::operator= --
|
||||
*/
|
||||
Vector4&
|
||||
Vector4::operator=(const Vector4 &rhs)
|
||||
{
|
||||
memcpy(mData, rhs.mData, sizeof(Double) * 4);
|
||||
return *this;
|
||||
}
|
||||
|
||||
#pragma mark Component Access
|
||||
|
||||
/*
|
||||
* charles::basics::Vector4::X --
|
||||
*/
|
||||
Double&
|
||||
Vector4::X()
|
||||
{
|
||||
return mData[0];
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Vector4::X --
|
||||
*/
|
||||
Double
|
||||
Vector4::X()
|
||||
const
|
||||
{
|
||||
return mData[0];
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Vector4::Y --
|
||||
*/
|
||||
Double&
|
||||
Vector4::Y()
|
||||
{
|
||||
return mData[1];
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Vector4::Y --
|
||||
*/
|
||||
Double
|
||||
Vector4::Y()
|
||||
const
|
||||
{
|
||||
return mData[1];
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Vector4::Z --
|
||||
*/
|
||||
Double&
|
||||
Vector4::Z()
|
||||
{
|
||||
return mData[2];
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Vector4::Z --
|
||||
*/
|
||||
Double
|
||||
Vector4::Z()
|
||||
const
|
||||
{
|
||||
return mData[2];
|
||||
}
|
||||
|
||||
|
||||
Double&
|
||||
Vector4::operator()(UInt i)
|
||||
{
|
||||
if (i >= 4) {
|
||||
std::stringstream ss;
|
||||
ss << "vector index out of bounds: i = " << i;
|
||||
throw std::out_of_range(ss.str());
|
||||
}
|
||||
return mData[i];
|
||||
}
|
||||
|
||||
|
||||
Double
|
||||
Vector4::operator()(UInt i)
|
||||
const
|
||||
{
|
||||
if (i >= 4) {
|
||||
std::stringstream ss;
|
||||
ss << "vector index out of bounds: i = " << i;
|
||||
throw std::out_of_range(ss.str());
|
||||
}
|
||||
return mData[i];
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Vector4::CArray --
|
||||
*/
|
||||
const Double*
|
||||
Vector4::CArray()
|
||||
const
|
||||
{
|
||||
return mData;
|
||||
}
|
||||
|
||||
#pragma mark Boolean Operators
|
||||
|
||||
/*
|
||||
* charles::basics::Vector4::operator== --
|
||||
*/
|
||||
bool
|
||||
Vector4::operator==(const Vector4 &rhs)
|
||||
const
|
||||
{
|
||||
for (UInt i = 0; i < 4; i++) {
|
||||
if (!NearlyEqual(mData[i], rhs.mData[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Vector4::operator!= --
|
||||
*/
|
||||
bool
|
||||
Vector4::operator!=(const Vector4 &rhs)
|
||||
const
|
||||
{
|
||||
return !(*this == rhs);
|
||||
}
|
||||
|
||||
#pragma mark Maths
|
||||
|
||||
/*
|
||||
* charles::basics::Vector4::operator* --
|
||||
*/
|
||||
Vector4
|
||||
Vector4::operator*(Double rhs)
|
||||
const
|
||||
{
|
||||
return Vector4(*this) *= rhs;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Vector4::operator* --
|
||||
*/
|
||||
Vector4
|
||||
Vector4::operator/(Double rhs)
|
||||
const
|
||||
{
|
||||
return Vector4(*this) /= rhs;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Vector4::operator*= --
|
||||
*/
|
||||
Vector4&
|
||||
Vector4::operator*=(Double rhs)
|
||||
{
|
||||
for (int i = 0; i < 4; i++) {
|
||||
mData[i] *= rhs;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Vector4::operator/= --
|
||||
*/
|
||||
Vector4&
|
||||
Vector4::operator/=(Double rhs)
|
||||
{
|
||||
return *this *= (1.0 / rhs);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Vector4::operator+ --
|
||||
*/
|
||||
Vector4
|
||||
Vector4::operator+(const Vector4 &rhs)
|
||||
const
|
||||
{
|
||||
return Vector4(*this) += rhs;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Vector4::operator- --
|
||||
*/
|
||||
Vector4
|
||||
Vector4::operator-(const Vector4 &rhs)
|
||||
const
|
||||
{
|
||||
return Vector4(*this) -= rhs;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Vector4::operator+= --
|
||||
*/
|
||||
Vector4&
|
||||
Vector4::operator+=(const Vector4 &rhs)
|
||||
{
|
||||
mData[0] += rhs.mData[0];
|
||||
mData[1] += rhs.mData[1];
|
||||
mData[2] += rhs.mData[2];
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Vector4::operator-= --
|
||||
*/
|
||||
Vector4&
|
||||
Vector4::operator-=(const Vector4 &rhs)
|
||||
{
|
||||
return *this += -rhs;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Vector4::operator- --
|
||||
*/
|
||||
Vector4
|
||||
Vector4::operator-()
|
||||
const
|
||||
{
|
||||
return Vector4(-X(), -Y(), -Z());
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Vector4::Length2 --
|
||||
*/
|
||||
Double
|
||||
Vector4::Length2()
|
||||
const
|
||||
{
|
||||
return X()*X() + Y()*Y() + Z()*Z();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Vector4::Length --
|
||||
*/
|
||||
Double
|
||||
Vector4::Length()
|
||||
const
|
||||
{
|
||||
return std::sqrt(Length2());
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Vector4::Dot --
|
||||
*/
|
||||
Double
|
||||
Vector4::Dot(const Vector4& rhs)
|
||||
const
|
||||
{
|
||||
return X()*rhs.X() + Y()*rhs.Y() + Z()*rhs.Z();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Vector4::Cross --
|
||||
*/
|
||||
Vector4
|
||||
Vector4::Cross(const Vector4& rhs)
|
||||
const
|
||||
{
|
||||
return Vector4(mData[1]*rhs.mData[2] - mData[2]*rhs.mData[1],
|
||||
mData[2]*rhs.mData[0] - mData[0]*rhs.mData[2],
|
||||
mData[0]*rhs.mData[1] - mData[1]*rhs.mData[0]);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Vector4::Normalize --
|
||||
*/
|
||||
Vector4&
|
||||
Vector4::Normalize()
|
||||
{
|
||||
return *this /= Length();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::operator* --
|
||||
*/
|
||||
Vector4
|
||||
operator*(Double lhs,
|
||||
const Vector4& rhs)
|
||||
{
|
||||
return rhs * lhs;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Normalized --
|
||||
*/
|
||||
Vector4
|
||||
Normalized(Vector4 v)
|
||||
{
|
||||
return v.Normalize();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::LinearCombination --
|
||||
*/
|
||||
Vector4
|
||||
LinearCombination(const Double k1, const Vector4& v1,
|
||||
const Double k2, const Vector4& v2,
|
||||
const Double k3, const Vector4& v3)
|
||||
{
|
||||
return Vector4(k1 * v1.X() + k2 * v2.X() + k3 * v3.X(),
|
||||
k1 * v1.Y() + k2 * v2.Y() + k3 * v3.Y(),
|
||||
k1 * v1.Z() + k2 * v2.Z() + k3 * v3.Z());
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::operator<< --
|
||||
*/
|
||||
std::ostream&
|
||||
operator<<(std::ostream& os, const Vector4& v)
|
||||
{
|
||||
// Stream the vector like this: <x, y, z>
|
||||
os << "<" << v.X() << ", " << v.Y() << ", " << v.Z() << ">";
|
||||
return os;
|
||||
}
|
||||
|
||||
} /* namespace basics */
|
||||
} /* namespace charles */
|
||||
|
||||
110
src/basics/vector.hh
Normal file
110
src/basics/vector.hh
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
/* vector.hh
|
||||
* vim: set tw=80:
|
||||
* Eryn Wells <eryn@erynwells.me>
|
||||
*/
|
||||
|
||||
#ifndef __BASICS_VECTOR_HH__
|
||||
#define __BASICS_VECTOR_HH__
|
||||
|
||||
#include <ostream>
|
||||
|
||||
#include "basics/matrix.hh"
|
||||
#include "basics/types.hh"
|
||||
|
||||
|
||||
namespace charles {
|
||||
namespace basics {
|
||||
|
||||
/** A 4x1 matrix, used for specifying points and directions in 3D space. */
|
||||
struct Vector4
|
||||
{
|
||||
Vector4();
|
||||
Vector4(Double x, Double y, Double z);
|
||||
Vector4(Double x, Double y, Double z, Double w);
|
||||
|
||||
Vector4 &operator=(const Vector4 &rhs);
|
||||
|
||||
/**
|
||||
* @defgroup Component access
|
||||
* @{
|
||||
*/
|
||||
Double& X();
|
||||
Double X() const;
|
||||
Double& Y();
|
||||
Double Y() const;
|
||||
Double& Z();
|
||||
Double Z() const;
|
||||
|
||||
Double &operator()(UInt i);
|
||||
Double operator()(UInt i) const;
|
||||
|
||||
/** Get the underlying C array. */
|
||||
const Double *CArray() const;
|
||||
/** @} */
|
||||
|
||||
bool operator==(const Vector4 &rhs) const;
|
||||
bool operator!=(const Vector4 &rhs) const;
|
||||
|
||||
/**
|
||||
* @defgroup Scalar multiplication
|
||||
* @{
|
||||
*/
|
||||
Vector4 operator*(Double rhs) const;
|
||||
Vector4 operator/(Double rhs) const;
|
||||
Vector4 &operator*=(Double rhs);
|
||||
Vector4 &operator/=(Double rhs);
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @defgroup Vector addition and subtraction
|
||||
* @{
|
||||
*/
|
||||
Vector4 operator+(const Vector4 &rhs) const;
|
||||
Vector4 operator-(const Vector4 &rhs) const;
|
||||
Vector4 &operator+=(const Vector4 &rhs);
|
||||
Vector4 &operator-=(const Vector4 &rhs);
|
||||
/** @} */
|
||||
|
||||
/** Negate this vector. */
|
||||
Vector4 operator-() const;
|
||||
|
||||
/** Get the length-squared of this vector. */
|
||||
Double Length2() const;
|
||||
|
||||
/** Get the length of this vector. */
|
||||
Double Length() const;
|
||||
|
||||
/** Get the dot product of `this` and `rhs`. */
|
||||
Double Dot(const Vector4 &rhs) const;
|
||||
|
||||
/** Get the cross product of `this` and `rhs`. */
|
||||
Vector4 Cross(const Vector4& rhs) const;
|
||||
|
||||
/** Normalize this vector. */
|
||||
Vector4& Normalize();
|
||||
|
||||
private:
|
||||
Double mData[4];
|
||||
};
|
||||
|
||||
|
||||
/** Scalar multiplication of vectors, with the scalar factor on the left. */
|
||||
Vector4 operator*(Double lhs, const Vector4 &rhs);
|
||||
|
||||
|
||||
/** Normalize a copy of the given vector. */
|
||||
Vector4 Normalized(Vector4 v);
|
||||
|
||||
|
||||
Vector4 LinearCombination(Double k1, const Vector4 &v1,
|
||||
Double k2, const Vector4 &v2,
|
||||
Double k3, const Vector4 &v3);
|
||||
|
||||
|
||||
std::ostream& operator<<(std::ostream &ost, const Vector4 &v);
|
||||
|
||||
} /* namespace basics */
|
||||
} /* namespace charles */
|
||||
|
||||
#endif /* __BASICS_VECTOR_HH__ */
|
||||
|
||||
408
src/camera.cc
408
src/camera.cc
|
|
@ -1,150 +1,360 @@
|
|||
/* camera.h
|
||||
*
|
||||
* The Camera is the eye into the scene. It defines several parameters and a single compute_primary_ray method
|
||||
* that generates rays with which the ray tracer draws the scene.
|
||||
*
|
||||
/* camera.cc
|
||||
* vim: set tw=80:
|
||||
* Eryn Wells <eryn@erynwells.me>
|
||||
*/
|
||||
|
||||
#include "camera.h"
|
||||
#include "camera.hh"
|
||||
#include "log.hh"
|
||||
|
||||
#define LOG_NAME "camera"
|
||||
#include "logModule.hh"
|
||||
|
||||
|
||||
using charles::basics::Ray;
|
||||
using charles::basics::Vector4;
|
||||
|
||||
|
||||
namespace charles {
|
||||
|
||||
#pragma mark - Generic Camera
|
||||
|
||||
/*
|
||||
* charles::Camera::Camera --
|
||||
*/
|
||||
Camera::Camera()
|
||||
: height(Vector3::Y),
|
||||
width(4.0 / 3.0 * Vector3::X),
|
||||
direction(Vector3::Z)
|
||||
: mOrigin(),
|
||||
mDirection(0, 0, 1),
|
||||
mRight(1.33, 0, 0),
|
||||
mUp(0, 1, 0)
|
||||
{ }
|
||||
|
||||
|
||||
/*
|
||||
* charles::Camera::Camera --
|
||||
*/
|
||||
Camera::Camera(const Camera& rhs)
|
||||
: mOrigin(rhs.mOrigin),
|
||||
mDirection(rhs.mDirection),
|
||||
mRight(rhs.mRight),
|
||||
mUp(rhs.mUp)
|
||||
{ }
|
||||
|
||||
|
||||
/*
|
||||
* charles::Camera::~Camera --
|
||||
*/
|
||||
Camera::~Camera()
|
||||
{ }
|
||||
|
||||
|
||||
/*
|
||||
* Camera::get_pixel_width --
|
||||
* Camera::set_pixel_width --
|
||||
* Camera::get_pixel_height --
|
||||
* Camera::set_pixel_height --
|
||||
*
|
||||
* Get and set pixel width and height.
|
||||
* Camera::GetOrigin --
|
||||
*/
|
||||
int
|
||||
Camera::get_pixel_width()
|
||||
const
|
||||
Vector4&
|
||||
Camera::GetOrigin()
|
||||
{
|
||||
return pwidth;
|
||||
}
|
||||
|
||||
void
|
||||
Camera::set_pixel_width(const int &w)
|
||||
{
|
||||
pwidth = w;
|
||||
}
|
||||
|
||||
int
|
||||
Camera::get_pixel_height()
|
||||
const
|
||||
{
|
||||
return pheight;
|
||||
}
|
||||
|
||||
void
|
||||
Camera::set_pixel_height(const int &h)
|
||||
{
|
||||
pheight = h;
|
||||
return mOrigin;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Camera::get_width --
|
||||
* Camera::set_width --
|
||||
* Camera::get_height --
|
||||
* Camera::set_height --
|
||||
*
|
||||
* Get and set width and height vectors.
|
||||
* Camera::GetOrigin --
|
||||
*/
|
||||
const Vector3 &
|
||||
Camera::get_width()
|
||||
const Vector4&
|
||||
Camera::GetOrigin()
|
||||
const
|
||||
{
|
||||
return width;
|
||||
}
|
||||
|
||||
void
|
||||
Camera::set_width(const Vector3 &w)
|
||||
{
|
||||
width = w;
|
||||
}
|
||||
|
||||
const Vector3 &
|
||||
Camera::get_height()
|
||||
const
|
||||
{
|
||||
return height;
|
||||
}
|
||||
|
||||
void
|
||||
Camera::set_height(const Vector3 &h)
|
||||
{
|
||||
height = h;
|
||||
return mOrigin;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Camera::get_direction --
|
||||
* Camera::set_direction --
|
||||
*
|
||||
* Get and set direction vector.
|
||||
* Camera::SetOrigin --
|
||||
*/
|
||||
const Vector3 &
|
||||
Camera::get_direction()
|
||||
const
|
||||
{
|
||||
return direction;
|
||||
}
|
||||
|
||||
void
|
||||
Camera::set_direction(const Vector3 &d)
|
||||
Camera::SetOrigin(const Vector4& origin)
|
||||
{
|
||||
direction = d;
|
||||
mOrigin = origin;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Camera::get_angle --
|
||||
*
|
||||
* Get the angle of view.
|
||||
* Camera::GetDirection --
|
||||
*/
|
||||
float
|
||||
Camera::get_angle()
|
||||
Vector4&
|
||||
Camera::GetDirection()
|
||||
{
|
||||
return mDirection;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Camera::GetDirection --
|
||||
*/
|
||||
const Vector4&
|
||||
Camera::GetDirection()
|
||||
const
|
||||
{
|
||||
return angle;
|
||||
return mDirection;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Camera::SetDirection --
|
||||
*/
|
||||
void
|
||||
Camera::SetDirection(const Vector4& direction)
|
||||
{
|
||||
mDirection = direction;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Camera::GetRight --
|
||||
*/
|
||||
Vector4&
|
||||
Camera::GetRight()
|
||||
{
|
||||
return mRight;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Camera::GetRight --
|
||||
*/
|
||||
const Vector4&
|
||||
Camera::GetRight()
|
||||
const
|
||||
{
|
||||
return mRight;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Camera::SetRight --
|
||||
*/
|
||||
void
|
||||
Camera::SetRight(const Vector4& right)
|
||||
{
|
||||
mRight = right;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Camera::GetUp --
|
||||
*/
|
||||
Vector4&
|
||||
Camera::GetUp()
|
||||
{
|
||||
return mUp;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Camera::GetUp --
|
||||
*/
|
||||
const Vector4&
|
||||
Camera::GetUp()
|
||||
const
|
||||
{
|
||||
return mUp;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Camera::SetUp --
|
||||
*/
|
||||
void
|
||||
Camera::SetUp(const Vector4& up)
|
||||
{
|
||||
mUp = up;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Camera::IsLeftHanded --
|
||||
*/
|
||||
bool
|
||||
Camera::IsLeftHanded()
|
||||
const
|
||||
{
|
||||
/*
|
||||
* The cross product of the up and direction vectors is a vector
|
||||
* perpendicular to the plane containing those vectors. By definition the
|
||||
* right vector is (in almost all cases) perpendicular to that plane.
|
||||
*
|
||||
* The dot product indicates the angle between this vector and the right
|
||||
* vector. If it's greater than 0, then the vector is pointing right of the
|
||||
* up-direction plane and the coordinate system is right handed. If less
|
||||
* than 0, the vector is pointing left of the up-direction plane and the
|
||||
* coordinate system is left-handed.
|
||||
*/
|
||||
return mUp.Cross(mDirection).Dot(mRight) < 0.0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Camera::LookAt --
|
||||
*/
|
||||
void
|
||||
Camera::LookAt(const Vector4& p)
|
||||
{
|
||||
/*
|
||||
* Precalulate these in order to preserve the aspect ratio and orientation
|
||||
* of the camera across the LookAt operation.
|
||||
*/
|
||||
const Double directionLength = mDirection.Length();
|
||||
const Double rightLength = mRight.Length();
|
||||
const Double upLength = mUp.Length();
|
||||
const bool isLeftHanded = IsLeftHanded();
|
||||
|
||||
/* Orient the camera towards the point. */
|
||||
mDirection = basics::Normalized(p - mOrigin);
|
||||
/* TODO: Check for zero length direction vector. */
|
||||
|
||||
/*
|
||||
* Create a new right vector, normalized and perpendicular to the plane
|
||||
* containing the Y unit vector and direction vector.
|
||||
*
|
||||
* The up vector is perpendicular to the plane containing the new right
|
||||
* vector and the direction vector.
|
||||
*
|
||||
* TODO: This is always the Y vector. POV-Ray has a sky vector, which
|
||||
* specifies the vector along which LookAt pans and tilts the camera. It
|
||||
* might be worth looking into, at some point.
|
||||
*/
|
||||
mRight = basics::Normalized(Vector4(0, 1, 0).Cross(mDirection));
|
||||
mUp = mDirection.Cross(mRight);
|
||||
|
||||
/*
|
||||
* Now, fix up the direction, right, and up vectors so that their magnitudes
|
||||
* match what they were before the move.
|
||||
*/
|
||||
mDirection *= directionLength;
|
||||
mRight *= isLeftHanded ? rightLength : -rightLength;
|
||||
mUp *= upLength;
|
||||
|
||||
LOG_DEBUG << "Camera is looking at " << p;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::Camera::GetTypeString --
|
||||
*/
|
||||
std::string
|
||||
Camera::GetTypeString()
|
||||
const
|
||||
{
|
||||
return "GENERIC";
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::Camera::WriteType --
|
||||
*/
|
||||
void
|
||||
Camera::WriteType(std::ostream& ost)
|
||||
const
|
||||
{
|
||||
ost << GetTypeString();
|
||||
}
|
||||
|
||||
#pragma mark - Perspective Camera
|
||||
|
||||
PerspectiveCamera::PerspectiveCamera()
|
||||
: Camera()
|
||||
{ }
|
||||
|
||||
|
||||
PerspectiveCamera::PerspectiveCamera(const Camera& other)
|
||||
: Camera(other)
|
||||
{ }
|
||||
|
||||
|
||||
Ray
|
||||
PerspectiveCamera::PrimaryRay(const int x,
|
||||
const int width,
|
||||
const int y,
|
||||
const int height)
|
||||
const
|
||||
{
|
||||
/*
|
||||
* Center x and y in the pixel and convert them to be coordinates between
|
||||
* -0.5 and 0.5.
|
||||
*/
|
||||
Double x0 = (x + 0.5) / width - 0.5;
|
||||
Double y0 = ((height - 1.0) - (y - 0.5)) / height - 0.5;
|
||||
|
||||
Vector4 direction = LinearCombination(1.0, GetDirection(),
|
||||
x0, GetRight(),
|
||||
y0, GetUp());
|
||||
return Ray(GetOrigin(), basics::Normalized(direction));
|
||||
}
|
||||
|
||||
|
||||
std::string
|
||||
PerspectiveCamera::GetTypeString()
|
||||
const
|
||||
{
|
||||
return "perspective";
|
||||
}
|
||||
|
||||
#pragma mark - Orthographic Camera
|
||||
|
||||
OrthographicCamera::OrthographicCamera()
|
||||
: Camera()
|
||||
{ }
|
||||
|
||||
|
||||
OrthographicCamera::OrthographicCamera(const Camera& other)
|
||||
: Camera(other)
|
||||
{ }
|
||||
|
||||
|
||||
/*
|
||||
* OrthographicCamera::compute_primary_ray --
|
||||
*
|
||||
* Compute a primary ray given an (x,y) coordinate pair. The orthographic camera projects rays parallel to the viewing
|
||||
* direction through the (x,y) coordinate given. Thus, the size of the orthographic camera should be set to the size of
|
||||
* the view into the scene.
|
||||
*/
|
||||
Ray
|
||||
OrthographicCamera::compute_primary_ray(const int &x,
|
||||
const int &y)
|
||||
OrthographicCamera::PrimaryRay(const int x,
|
||||
const int width,
|
||||
const int y,
|
||||
const int height)
|
||||
const
|
||||
{
|
||||
// Calculate the point on the image plane that the given (x,y) coordinate pair corresponds to.
|
||||
float dir_x = (x / get_pixel_width()) + 0.5;
|
||||
float dir_y = (y / get_pixel_height()) + 0.5;
|
||||
Vector3 ray_origin = (dir_x * get_width()) + (dir_y * get_height()) + get_direction();
|
||||
/*
|
||||
* Center x and y in the pixel and convert them to be coordinates between
|
||||
* -0.5 and 0.5.
|
||||
*/
|
||||
Double x0 = (x + 0.5) / width + 0.5;
|
||||
Double y0 = ((height - 1.0) - (y - 0.5)) / height - 0.5;
|
||||
|
||||
// Calculate the direction of the ray, given the camera's origin and normalize that vector.
|
||||
Vector3 ray_direction = (ray_origin - get_origin()).normalize();
|
||||
|
||||
return Ray(get_origin(), ray_direction);
|
||||
Vector4 origin = LinearCombination(1.0, GetOrigin(),
|
||||
x0, GetRight(),
|
||||
y0, GetUp());
|
||||
return Ray(origin, GetDirection());
|
||||
}
|
||||
|
||||
|
||||
std::string
|
||||
OrthographicCamera::GetTypeString()
|
||||
const
|
||||
{
|
||||
return "orthographic";
|
||||
}
|
||||
|
||||
|
||||
std::ostream&
|
||||
operator<<(std::ostream& ost,
|
||||
const Camera& camera)
|
||||
{
|
||||
ost << "[Camera ";
|
||||
camera.WriteType(ost);
|
||||
ost << " origin=" << camera.mOrigin
|
||||
<< " direction=" << camera.mDirection
|
||||
<< " right=" << camera.mRight
|
||||
<< " up=" << camera.mUp
|
||||
<< "]";
|
||||
return ost;
|
||||
}
|
||||
|
||||
} /* namespace charles */
|
||||
|
|
|
|||
60
src/camera.h
60
src/camera.h
|
|
@ -1,60 +0,0 @@
|
|||
/* camera.h
|
||||
*
|
||||
* The Camera is the eye into the scene. It defines several parameters and a single compute_primary_ray method
|
||||
* that generates rays with which the ray tracer draws the scene.
|
||||
*
|
||||
* Eryn Wells <eryn@erynwells.me>
|
||||
*/
|
||||
|
||||
#ifndef __CAMERA_H__
|
||||
#define __CAMERA_H__
|
||||
|
||||
#include "basics.h"
|
||||
#include "object.h"
|
||||
|
||||
|
||||
class Camera
|
||||
: public Object
|
||||
{
|
||||
public:
|
||||
Camera();
|
||||
~Camera();
|
||||
|
||||
int get_pixel_width() const;
|
||||
void set_pixel_width(const int &w);
|
||||
int get_pixel_height() const;
|
||||
void set_pixel_height(const int &h);
|
||||
const Vector3 &get_width() const;
|
||||
void set_width(const Vector3 &w);
|
||||
const Vector3 &get_height() const;
|
||||
void set_height(const Vector3 &h);
|
||||
const Vector3 &get_direction() const;
|
||||
void set_direction(const Vector3 &d);
|
||||
float get_angle() const;
|
||||
|
||||
virtual Ray compute_primary_ray(const int &x, const int &y) const = 0;
|
||||
|
||||
private:
|
||||
// Pixel dimensions of the image plane.
|
||||
int pwidth, pheight;
|
||||
|
||||
// Size of the image plane.
|
||||
Vector3 height, width;
|
||||
|
||||
// Direction. A normalized vector defining where the camera is pointed.
|
||||
Vector3 direction;
|
||||
|
||||
// Horizontal viewing angle.
|
||||
float angle;
|
||||
};
|
||||
|
||||
|
||||
class OrthographicCamera
|
||||
: public Camera
|
||||
{
|
||||
public:
|
||||
Ray compute_primary_ray(const int &x, const int &y) const;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
124
src/camera.hh
Normal file
124
src/camera.hh
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
/* camera.hh
|
||||
* vim: set tw=80:
|
||||
* Eryn Wells <eryn@erynwells.me>
|
||||
*/
|
||||
|
||||
#ifndef __CAMERA_H__
|
||||
#define __CAMERA_H__
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "basics/basics.hh"
|
||||
|
||||
|
||||
namespace charles {
|
||||
|
||||
/**
|
||||
* The Camera is the eye into the scene. It defines several parameters and a
|
||||
* single compute_primary_ray method that generates rays with which the ray
|
||||
* tracer draws the scene.
|
||||
*/
|
||||
struct Camera
|
||||
{
|
||||
typedef std::shared_ptr<Camera> Ptr;
|
||||
|
||||
Camera();
|
||||
Camera(const Camera& other);
|
||||
virtual ~Camera();
|
||||
|
||||
basics::Vector4& GetOrigin();
|
||||
const basics::Vector4& GetOrigin() const;
|
||||
void SetOrigin(const basics::Vector4& origin);
|
||||
|
||||
basics::Vector4& GetDirection();
|
||||
const basics::Vector4& GetDirection() const;
|
||||
void SetDirection(const basics::Vector4& direction);
|
||||
|
||||
basics::Vector4& GetRight();
|
||||
const basics::Vector4& GetRight() const;
|
||||
void SetRight(const basics::Vector4& right);
|
||||
|
||||
basics::Vector4& GetUp();
|
||||
const basics::Vector4& GetUp() const;
|
||||
void SetUp(const basics::Vector4& up);
|
||||
|
||||
/** Get the camera's handedness. Left handed is the default. */
|
||||
bool IsLeftHanded() const;
|
||||
|
||||
/** Pan and tilt the camera towards the given point. */
|
||||
void LookAt(const basics::Vector4& p);
|
||||
|
||||
virtual basics::Ray PrimaryRay(const int x, const int width,
|
||||
const int y, const int height) const = 0;
|
||||
|
||||
virtual std::string GetTypeString() const;
|
||||
|
||||
private:
|
||||
friend std::ostream& operator<<(std::ostream& ost, const Camera& camera);
|
||||
|
||||
void WriteType(std::ostream& ost) const;
|
||||
|
||||
/**
|
||||
* The location of the camera in the scene. Depending on the type of camera,
|
||||
* this is the point from which rays will be emitted.
|
||||
*/
|
||||
basics::Vector4 mOrigin;
|
||||
|
||||
/** A vector defining where the camera is pointed. */
|
||||
basics::Vector4 mDirection;
|
||||
|
||||
/**
|
||||
* A vector defining the width of the camera's image plane. The ratio of
|
||||
* this and mUp determine the aspect ratio of the image.
|
||||
*/
|
||||
basics::Vector4 mRight;
|
||||
|
||||
/**
|
||||
* A vector defining the height of the camera's image plane. The ratio of
|
||||
* this and mRight determine the aspect ratio of the image.
|
||||
*/
|
||||
basics::Vector4 mUp;
|
||||
};
|
||||
|
||||
|
||||
class PerspectiveCamera
|
||||
: public Camera
|
||||
{
|
||||
public:
|
||||
PerspectiveCamera();
|
||||
PerspectiveCamera(const Camera& other);
|
||||
|
||||
basics::Ray PrimaryRay(const int x, const int width,
|
||||
const int y, const int height) const;
|
||||
|
||||
private:
|
||||
std::string GetTypeString() const;
|
||||
};
|
||||
|
||||
|
||||
class OrthographicCamera
|
||||
: public Camera
|
||||
{
|
||||
public:
|
||||
OrthographicCamera();
|
||||
OrthographicCamera(const Camera& other);
|
||||
|
||||
/**
|
||||
* Compute a primary ray given an (x,y) coordinate pair. The orthographic
|
||||
* camera projects rays parallel to the viewing direction through the (x,y)
|
||||
* coordinate given. Thus, the size of the orthographic camera should be set
|
||||
* to the size of the view into the scene.
|
||||
*/
|
||||
basics::Ray PrimaryRay(const int x, const int width,
|
||||
const int y, const int height) const;
|
||||
|
||||
private:
|
||||
std::string GetTypeString() const;
|
||||
};
|
||||
|
||||
|
||||
std::ostream& operator<<(std::ostream& ost, const Camera& camera);
|
||||
|
||||
} /* namespace charles */
|
||||
|
||||
#endif
|
||||
131
src/charles.cc
131
src/charles.cc
|
|
@ -6,62 +6,113 @@
|
|||
*/
|
||||
|
||||
#include <cstdio>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "basics.h"
|
||||
#include "light.h"
|
||||
#include "material.h"
|
||||
#include "object_sphere.h"
|
||||
#include "object_plane.h"
|
||||
#include "scene.h"
|
||||
#include "log.hh"
|
||||
#include "light.hh"
|
||||
#include "reader_yaml.hh"
|
||||
#include "scene.hh"
|
||||
#include "writer_png.h"
|
||||
#include "basics/basics.hh"
|
||||
|
||||
const char *OUT_FILE = "charles_out.png";
|
||||
#define LOG_NAME "ROOT"
|
||||
#include "logModule.hh"
|
||||
|
||||
|
||||
using namespace charles;
|
||||
using namespace charles::basics;
|
||||
|
||||
|
||||
static void
|
||||
usage(const char *progname)
|
||||
{
|
||||
fprintf(stderr, "Usage: %s [-hv] [-l <logfile>] [-L <log level>] [-o <outfile>] <infile ...>\n",
|
||||
progname);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main(int argc,
|
||||
const char *argv[])
|
||||
{
|
||||
Scene scene = Scene();
|
||||
using namespace charles::log;
|
||||
|
||||
scene.get_ambient().set_intensity(1.0);
|
||||
Scene scene;
|
||||
|
||||
Material *m1 = new Material();
|
||||
m1->set_diffuse_color(Color::Red);
|
||||
Material *m2 = new Material();
|
||||
m2->set_diffuse_color(Color::Green);
|
||||
Material *m3 = new Material();
|
||||
m3->set_diffuse_color(Color::Blue);
|
||||
Material *m4 = new Material();
|
||||
m4->set_diffuse_color(Color(1.0, 0.0, 1.0));
|
||||
PointLight *l1 = new PointLight(Vector4(4.0, 6.0, 1.0), Color::White, 0.8);
|
||||
scene.AddLight(l1);
|
||||
|
||||
// Make some spheres.
|
||||
Sphere *s1 = new Sphere(Vector3(233, 290, 0), 80.0);
|
||||
Sphere *s2 = new Sphere(Vector3(407, 290, 0), 80.0);
|
||||
Sphere *s3 = new Sphere(Vector3(320, 140, 0), 80.0);
|
||||
Sphere *s4 = new Sphere(Vector3(620, 360, 0), 20.0);
|
||||
s1->set_material(m1);
|
||||
s2->set_material(m2);
|
||||
s3->set_material(m3);
|
||||
s4->set_material(m4);
|
||||
scene.add_shape(s1);
|
||||
scene.add_shape(s2);
|
||||
scene.add_shape(s3);
|
||||
scene.add_shape(s4);
|
||||
bool shouldRender = true;
|
||||
|
||||
// Make a plane
|
||||
Plane *p1 = new Plane(Vector3(0, 460, 400), Vector3(0, 1, 0.01));
|
||||
p1->set_material(m1);
|
||||
scene.add_shape(p1);
|
||||
std::string logFilename;
|
||||
unsigned int logLevel = 0;
|
||||
|
||||
PointLight *l1 = new PointLight(Vector3(0.0, 240.0, 100.0), Color::White, 1.0);
|
||||
scene.add_light(l1);
|
||||
std::string outfile, infile;
|
||||
|
||||
// Render.
|
||||
scene.render();
|
||||
int opt;
|
||||
while ((opt = getopt(argc, (char *const *)argv, "hl:L:no:v:")) != -1) {
|
||||
switch (opt) {
|
||||
case 'h':
|
||||
usage(argv[0]);
|
||||
exit(0);
|
||||
break;
|
||||
case 'l':
|
||||
logFilename = optarg;
|
||||
break;
|
||||
case 'L':
|
||||
logLevel = std::stoul(optarg);
|
||||
break;
|
||||
case 'n':
|
||||
shouldRender = false;
|
||||
break;
|
||||
case 'o':
|
||||
outfile = optarg;
|
||||
break;
|
||||
case 'v':
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Writer *writer = new PNGWriter();
|
||||
scene.write(*writer, OUT_FILE);
|
||||
/* Set up logging */
|
||||
if (logLevel > 0) {
|
||||
if (logFilename.empty()) {
|
||||
logFilename = "charles.log";
|
||||
}
|
||||
Log::Init(logFilename, logLevel);
|
||||
}
|
||||
|
||||
if (optind >= argc) {
|
||||
LOG_ERROR << "Input file required.";
|
||||
fprintf(stderr, "Input file required.\n");
|
||||
usage(argv[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
infile = argv[optind];
|
||||
|
||||
if (outfile.empty()) {
|
||||
outfile = "charles_out.png";
|
||||
}
|
||||
|
||||
/* Parse YAML files. */
|
||||
YAMLReader reader(scene);
|
||||
for (int i = optind; i < argc; i++) {
|
||||
reader.read_file(infile);
|
||||
}
|
||||
|
||||
/* Call tracer. */
|
||||
if (shouldRender) {
|
||||
LOG_INFO << "Beginning render";
|
||||
scene.Render();
|
||||
|
||||
/* Write rendered scene to PNG file. */
|
||||
PNGWriter writer;
|
||||
scene.Write(writer, outfile);
|
||||
}
|
||||
|
||||
if (logLevel > 0) {
|
||||
Log::Close();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
14
src/charles.hh
Normal file
14
src/charles.hh
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
/* charles.hh
|
||||
* vim: set tw=80:
|
||||
* Eryn Wells <eryn@erynwells.me>
|
||||
*/
|
||||
/**
|
||||
* Some basic defines and things.
|
||||
*/
|
||||
|
||||
#ifndef __CHARLES_HH__
|
||||
#define __CHARLES_HH__
|
||||
|
||||
extern int verbosity;
|
||||
|
||||
#endif /* __CHARLES_HH__ */
|
||||
104
src/light.cc
104
src/light.cc
|
|
@ -1,97 +1,81 @@
|
|||
/* light.cc
|
||||
*
|
||||
* Lights light the scene.
|
||||
*
|
||||
* vim: set tw=80:
|
||||
* Eryn Wells <eryn@erynwells.me>
|
||||
*/
|
||||
|
||||
#include "basics.h"
|
||||
#include "light.h"
|
||||
#include "object.h"
|
||||
#include "light.hh"
|
||||
|
||||
#pragma mark - Ambient Lights
|
||||
|
||||
AmbientLight::AmbientLight()
|
||||
: AmbientLight(Color::White)
|
||||
using charles::basics::Color;
|
||||
|
||||
|
||||
namespace charles {
|
||||
|
||||
Light::Light(const Color& color,
|
||||
const Double& intensity)
|
||||
: mColor(color),
|
||||
mIntensity(ClampIntensity(intensity))
|
||||
{ }
|
||||
|
||||
|
||||
AmbientLight::AmbientLight(const Color &c)
|
||||
: AmbientLight(c, 0.0)
|
||||
Light::~Light()
|
||||
{ }
|
||||
|
||||
|
||||
AmbientLight::AmbientLight(const Color &c, const float &i)
|
||||
: color(c),
|
||||
intensity(i)
|
||||
Color&
|
||||
Light::GetColor()
|
||||
{
|
||||
_clamp_intensity();
|
||||
return mColor;
|
||||
}
|
||||
|
||||
|
||||
const Color &
|
||||
AmbientLight::get_color()
|
||||
const Color&
|
||||
Light::GetColor()
|
||||
const
|
||||
{
|
||||
return color;
|
||||
return mColor;
|
||||
}
|
||||
|
||||
|
||||
const float &
|
||||
AmbientLight::get_intensity()
|
||||
const
|
||||
{
|
||||
return intensity;
|
||||
}
|
||||
|
||||
void
|
||||
AmbientLight::set_intensity(const float &i)
|
||||
Light::SetColor(const Color& color)
|
||||
{
|
||||
intensity = i;
|
||||
_clamp_intensity();
|
||||
mColor = color;
|
||||
}
|
||||
|
||||
|
||||
Double
|
||||
Light::GetIntensity()
|
||||
const
|
||||
{
|
||||
return mIntensity;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Light::SetIntensity(const Double& intensity)
|
||||
{
|
||||
mIntensity = ClampIntensity(intensity);
|
||||
}
|
||||
|
||||
|
||||
Color
|
||||
AmbientLight::compute_color_contribution()
|
||||
Light::Contribution()
|
||||
const
|
||||
{
|
||||
return color * intensity;
|
||||
return mColor * mIntensity;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AmbientLight::_clamp_intensity()
|
||||
Double
|
||||
Light::ClampIntensity(const Double& intensity)
|
||||
{
|
||||
if (intensity < 0.0) {
|
||||
intensity = 0.0;
|
||||
}
|
||||
else if (intensity > 1.0) {
|
||||
intensity = 1.0;
|
||||
return 0.0;
|
||||
} else if (intensity > 1.0) {
|
||||
return 1.0;
|
||||
}
|
||||
return intensity;
|
||||
}
|
||||
|
||||
#pragma mark - Point Lights
|
||||
|
||||
PointLight::PointLight()
|
||||
: PointLight(Vector3())
|
||||
{ }
|
||||
|
||||
|
||||
PointLight::PointLight(const Vector3 &o)
|
||||
: PointLight(o, Color::White)
|
||||
{ }
|
||||
|
||||
|
||||
PointLight::PointLight(const Vector3 &o,
|
||||
const Color &c)
|
||||
: PointLight(o, c, 1.0)
|
||||
{ }
|
||||
|
||||
|
||||
PointLight::PointLight(const Vector3 &o,
|
||||
const Color &c,
|
||||
const float &i)
|
||||
: AmbientLight(c, i),
|
||||
Object(o)
|
||||
{ }
|
||||
} /* namespace charles */
|
||||
|
|
|
|||
48
src/light.h
48
src/light.h
|
|
@ -1,48 +0,0 @@
|
|||
/* light.h
|
||||
*
|
||||
* Lights light the scene.
|
||||
*
|
||||
* Eryn Wells <eryn@erynwells.me>
|
||||
*/
|
||||
|
||||
#ifndef __LIGHT_H__
|
||||
#define __LIGHT_H__
|
||||
|
||||
#include "basics.h"
|
||||
#include "object.h"
|
||||
|
||||
|
||||
class AmbientLight
|
||||
{
|
||||
public:
|
||||
AmbientLight();
|
||||
AmbientLight(const Color &c);
|
||||
AmbientLight(const Color &c, const float &i);
|
||||
|
||||
const Color &get_color() const;
|
||||
const float &get_intensity() const;
|
||||
void set_intensity(const float &i);
|
||||
|
||||
Color compute_color_contribution() const;
|
||||
|
||||
protected:
|
||||
Color color;
|
||||
float intensity;
|
||||
|
||||
private:
|
||||
void _clamp_intensity();
|
||||
};
|
||||
|
||||
|
||||
class PointLight
|
||||
: public AmbientLight,
|
||||
public Object
|
||||
{
|
||||
public:
|
||||
PointLight();
|
||||
PointLight(const Vector3 &o);
|
||||
PointLight(const Vector3 &o, const Color &c);
|
||||
PointLight(const Vector3 &o, const Color &c, const float &i);
|
||||
};
|
||||
|
||||
#endif
|
||||
52
src/light.hh
Normal file
52
src/light.hh
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
/* light.hh
|
||||
* vim: set tw=80:
|
||||
* Eryn Wells <eryn@erynwells.me>
|
||||
*/
|
||||
|
||||
#ifndef __LIGHT_H__
|
||||
#define __LIGHT_H__
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "basics/basics.hh"
|
||||
|
||||
|
||||
namespace charles {
|
||||
|
||||
struct Light
|
||||
{
|
||||
typedef std::shared_ptr<Light> Ptr;
|
||||
|
||||
Light(const basics::Color& color,
|
||||
const Double& intensity = 1.0);
|
||||
|
||||
virtual ~Light();
|
||||
|
||||
basics::Color& GetColor();
|
||||
const basics::Color& GetColor() const;
|
||||
void SetColor(const basics::Color& color);
|
||||
|
||||
Double GetIntensity() const;
|
||||
void SetIntensity(const Double& intensity);
|
||||
|
||||
virtual basics::Color Contribution() const;
|
||||
|
||||
private:
|
||||
Double ClampIntensity(const Double& intensity);
|
||||
|
||||
/** The color of the light. */
|
||||
basics::Color mColor;
|
||||
|
||||
/**
|
||||
* The intensity of the light. Normal values range from 0.0 to 1.0, but
|
||||
* they can be set higher.
|
||||
*/
|
||||
Double mIntensity;
|
||||
};
|
||||
|
||||
|
||||
typedef Light AmbientLight;
|
||||
|
||||
} /* namespace charles */
|
||||
|
||||
#endif
|
||||
37
src/lightPoint.cc
Normal file
37
src/lightPoint.cc
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
/* lightPoint.cc
|
||||
* vim: set tw=80:
|
||||
* Eryn Wells <eryn@erynwells.me>
|
||||
*/
|
||||
|
||||
#include "lightPoint.hh"
|
||||
|
||||
|
||||
using charles::basics::Color;
|
||||
using charles::basics::Vector4;
|
||||
|
||||
|
||||
namespace charles {
|
||||
|
||||
PointLight::PointLight(const Vector4& origin,
|
||||
const Color& color,
|
||||
const Double& intensity)
|
||||
: Light(color, intensity),
|
||||
mOrigin(origin)
|
||||
{ }
|
||||
|
||||
|
||||
Vector4&
|
||||
PointLight::GetOrigin()
|
||||
{
|
||||
return mOrigin;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PointLight::SetOrigin(const Vector4& origin)
|
||||
{
|
||||
mOrigin = origin;
|
||||
}
|
||||
|
||||
} /* namespace charles */
|
||||
|
||||
35
src/lightPoint.hh
Normal file
35
src/lightPoint.hh
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
/* lightPoint.hh
|
||||
* vim: set tw=80:
|
||||
* Eryn Wells <eryn@erynwells.me>
|
||||
*/
|
||||
|
||||
#ifndef __LIGHTPOINT_HH__
|
||||
#define __LIGHTPOINT_HH__
|
||||
|
||||
#include "light.hh"
|
||||
|
||||
|
||||
namespace charles {
|
||||
|
||||
/**
|
||||
* The simplest light source. Emits light in all directions uniformly, without
|
||||
* falloff.
|
||||
*/
|
||||
class PointLight
|
||||
: public Light
|
||||
{
|
||||
public:
|
||||
PointLight(const basics::Vector4 &origin,
|
||||
const basics::Color& color,
|
||||
const Double& intensity);
|
||||
|
||||
basics::Vector4& GetOrigin();
|
||||
void SetOrigin(const basics::Vector4& origin);
|
||||
|
||||
private:
|
||||
basics::Vector4 mOrigin;
|
||||
};
|
||||
|
||||
} /* namespace charles */
|
||||
|
||||
#endif /* __LIGHTPOINT_HH__ */
|
||||
119
src/log.cc
Normal file
119
src/log.cc
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
/* log.cc
|
||||
* vim: set tw=80:
|
||||
* Eryn Wells <eryn@erynwells.me>
|
||||
*/
|
||||
|
||||
#include "log.hh"
|
||||
|
||||
|
||||
namespace charles {
|
||||
namespace log {
|
||||
|
||||
/** Useful predefined levels. */
|
||||
namespace level {
|
||||
const unsigned int Error = 10;
|
||||
const unsigned int Warning = 20;
|
||||
const unsigned int Info = 30;
|
||||
const unsigned int Debug = 40;
|
||||
const unsigned int Trace = 50;
|
||||
};
|
||||
|
||||
|
||||
unsigned int Log::sLevel = 0;
|
||||
std::ostream* Log::sOutput = nullptr;
|
||||
Log::LoggerMap Log::sLoggers;
|
||||
|
||||
|
||||
/* static */ void
|
||||
Log::Init(const std::string& filename,
|
||||
unsigned int level)
|
||||
{
|
||||
assert(sOutput == nullptr);
|
||||
sOutput = new std::ofstream(filename);
|
||||
sLevel = level;
|
||||
|
||||
Log("ROOT", 1) << "Opening log file " << filename;
|
||||
Log("ROOT", 1) << "Log level set to " << sLevel;
|
||||
}
|
||||
|
||||
|
||||
/* static */ void
|
||||
Log::Close()
|
||||
{
|
||||
assert(sOutput != nullptr);
|
||||
delete sOutput;
|
||||
sOutput = nullptr;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Construct a Log object.
|
||||
*
|
||||
* @param [in] name The name of the log stream. If this name hasn't been
|
||||
* seen before, a new one will be created for you.
|
||||
* @param [in] level The level. If this is higher than the level of the log
|
||||
* stream, nothing will be output.
|
||||
*/
|
||||
Log::Log(const std::string& name,
|
||||
unsigned int level)
|
||||
: mName(name),
|
||||
mLevel(level),
|
||||
mOutput(Log::GetLogger(name))
|
||||
{
|
||||
using namespace std::chrono;
|
||||
|
||||
/* Write a log message leader: "<time with millis> - <name>:<level> - ". */
|
||||
auto now = system_clock::now();
|
||||
auto nowMillis =
|
||||
duration_cast<milliseconds>(now.time_since_epoch() % seconds(1));
|
||||
auto cNow = system_clock::to_time_t(now);
|
||||
*this << std::put_time(std::localtime(&cNow), "%F %T")
|
||||
<< "." << std::left << std::setw(3) << nowMillis.count()
|
||||
<< " - " << mName
|
||||
<< ":" << std::left << std::setw(2) << mLevel << " - ";
|
||||
}
|
||||
|
||||
|
||||
Log::~Log()
|
||||
{
|
||||
/* Add a newline at the end of this log message. */
|
||||
*this << "\n";
|
||||
}
|
||||
|
||||
|
||||
/* static */ Log::Logger&
|
||||
Log::GetLogger(const std::string& name)
|
||||
{
|
||||
/*
|
||||
* TODO: For now, output is always the same: sOutput. In the future, figure
|
||||
* out a way to set different outputs for different streams.
|
||||
*/
|
||||
auto pair = sLoggers.emplace(name, sLevel);
|
||||
return pair.first->second;
|
||||
}
|
||||
|
||||
#pragma mark Log::Logger
|
||||
|
||||
Log::Logger::Logger(unsigned int l)
|
||||
: level(l)
|
||||
{ }
|
||||
|
||||
|
||||
#pragma mark Tracer
|
||||
|
||||
Tracer::Tracer(const std::string& name,
|
||||
const std::string& function)
|
||||
: mName(name),
|
||||
mFunction(function)
|
||||
{
|
||||
Log(mName, level::Trace) << "--> " << mFunction;
|
||||
}
|
||||
|
||||
|
||||
Tracer::~Tracer()
|
||||
{
|
||||
Log(mName, level::Trace) << "<-- " << mFunction;
|
||||
}
|
||||
|
||||
} /* namespace log */
|
||||
} /* namespace charles */
|
||||
103
src/log.hh
Normal file
103
src/log.hh
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
/* log.hh
|
||||
* vim: set tw=80:
|
||||
* Eryn Wells <eryn@erynwells.me>
|
||||
*/
|
||||
|
||||
#ifndef __LOG_HH__
|
||||
#define __LOG_HH__
|
||||
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
|
||||
#include <chrono>
|
||||
#include <iomanip>
|
||||
#include <map>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
|
||||
|
||||
namespace charles {
|
||||
namespace log {
|
||||
|
||||
/** Useful predefined levels. */
|
||||
namespace level {
|
||||
extern const unsigned int Error;
|
||||
extern const unsigned int Warning;
|
||||
extern const unsigned int Info;
|
||||
extern const unsigned int Debug;
|
||||
extern const unsigned int Trace;
|
||||
};
|
||||
|
||||
|
||||
struct Log
|
||||
{
|
||||
static void Init(const std::string& filename,
|
||||
unsigned int level = level::Info);
|
||||
static void Close();
|
||||
|
||||
Log(const std::string& name = "ROOT", unsigned int level = level::Info);
|
||||
~Log();
|
||||
|
||||
template<typename T> Log& operator<<(const T& item);
|
||||
|
||||
private:
|
||||
struct Logger
|
||||
{
|
||||
Logger(unsigned int level = level::Info);
|
||||
|
||||
unsigned int level;
|
||||
};
|
||||
|
||||
typedef std::map<std::string, Logger> LoggerMap;
|
||||
|
||||
static unsigned int sLevel;
|
||||
static std::ostream* sOutput;
|
||||
static LoggerMap sLoggers;
|
||||
|
||||
static Logger& GetLogger(const std::string& name);
|
||||
|
||||
const std::string& mName;
|
||||
unsigned int mLevel;
|
||||
Logger& mOutput;
|
||||
};
|
||||
|
||||
|
||||
struct Tracer
|
||||
{
|
||||
Tracer(const std::string& name,
|
||||
const std::string& function);
|
||||
~Tracer();
|
||||
|
||||
private:
|
||||
const std::string mName;
|
||||
const std::string mFunction;
|
||||
};
|
||||
|
||||
|
||||
template<typename T>
|
||||
Log&
|
||||
Log::operator<<(const T& item)
|
||||
{
|
||||
if (mLevel <= mOutput.level) {
|
||||
assert(sOutput != nullptr);
|
||||
*sOutput << item;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
} /* namespace log */
|
||||
} /* namespace charles */
|
||||
|
||||
|
||||
#define LOG_NAME_LEVEL(name, level) charles::log::Log((name), (level))
|
||||
#define LOG_ERROR_NAME(name) LOG_NAME_LEVEL(name, charles::log::level::Error)
|
||||
#define LOG_WARN_NAME(name) LOG_NAME_LEVEL(name, charles::log::level::Warning)
|
||||
#define LOG_INFO_NAME(name) LOG_NAME_LEVEL(name, charles::log::level::Info)
|
||||
#define LOG_DEBUG_NAME(name) LOG_NAME_LEVEL(name, charles::log::level::Debug)
|
||||
#define LOG_TRACE_NAME(name) LOG_NAME_LEVEL(name, charles::log::level::Trace)
|
||||
|
||||
#define TRACE_FUNC_NAME(name) \
|
||||
auto __tracer = charles::log::Tracer((name), __PRETTY_FUNCTION__)
|
||||
|
||||
#endif /* __LOG_HH__ */
|
||||
27
src/logModule.hh
Normal file
27
src/logModule.hh
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
/* logModule.hh
|
||||
* vim: set tw=80:
|
||||
* Eryn Wells <eryn@erynwells.me>
|
||||
*/
|
||||
/**
|
||||
* Defines some helper macros for logging that simplify the ones defined in
|
||||
* log.hh.
|
||||
*/
|
||||
|
||||
#ifndef __LOGMODULE_HH__
|
||||
#define __LOGMODULE_HH__
|
||||
|
||||
#if !defined(LOG_NAME)
|
||||
#warning "Log stream name undefined. Using ROOT log stream."
|
||||
#define LOG_NAME "ROOT"
|
||||
#endif
|
||||
|
||||
#define LOG_LEVEL(level) LOG_NAME_LEVEL(LOG_NAME, level)
|
||||
#define LOG_ERROR LOG_ERROR_NAME(LOG_NAME)
|
||||
#define LOG_WARN LOG_WARN_NAME(LOG_NAME)
|
||||
#define LOG_INFO LOG_INFO_NAME(LOG_NAME)
|
||||
#define LOG_DEBUG LOG_DEBUG_NAME(LOG_NAME)
|
||||
#define LOG_TRACE LOG_TRACE_NAME(LOG_NAME)
|
||||
|
||||
#define TRACE_FUNC TRACE_FUNC_NAME(LOG_NAME)
|
||||
|
||||
#endif /* __LOGMODULE_HH__ */
|
||||
|
|
@ -1,85 +1,88 @@
|
|||
/* material.h
|
||||
*
|
||||
* Materials are applied to shapes and determine color, texture mapping, shading, etc.
|
||||
*
|
||||
/* material.cc
|
||||
* vim: set tw=80:
|
||||
* Eryn Wells <eryn@erynwells.me>
|
||||
*/
|
||||
|
||||
#include "material.h"
|
||||
#include "material.hh"
|
||||
|
||||
|
||||
using charles::basics::Color;
|
||||
|
||||
|
||||
namespace charles {
|
||||
|
||||
Material::Material()
|
||||
: diffuse_level(0.8),
|
||||
diffuse_color(Color::White),
|
||||
specular_level(0.5),
|
||||
specular_color(Color::White)
|
||||
: mDiffuseModel(DiffuseShaderModel::Lambert),
|
||||
mDiffuseIntensity(0.8),
|
||||
mDiffuseColor(Color::White),
|
||||
mSpecularModel(SpecularShaderModel::Phong),
|
||||
mSpecularIntensity(0.0),
|
||||
mSpecularColor(Color::White)
|
||||
{ }
|
||||
|
||||
|
||||
float
|
||||
Material::get_diffuse_level()
|
||||
Double
|
||||
Material::GetDiffuseIntensity()
|
||||
const
|
||||
{
|
||||
return diffuse_level;
|
||||
return mDiffuseIntensity;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Material::set_diffuse_level(const float &kd)
|
||||
Material::SetDiffuseIntensity(const Double& kd)
|
||||
{
|
||||
diffuse_level = kd;
|
||||
_clamp_parameter(diffuse_level);
|
||||
mDiffuseIntensity = kd;
|
||||
ClampParameter(mDiffuseIntensity);
|
||||
}
|
||||
|
||||
|
||||
const Color &
|
||||
Material::get_diffuse_color()
|
||||
Color&
|
||||
Material::GetDiffuseColor()
|
||||
{
|
||||
return mDiffuseColor;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Material::SetDiffuseColor(const Color& color)
|
||||
{
|
||||
mDiffuseColor = color;
|
||||
}
|
||||
|
||||
|
||||
Double
|
||||
Material::GetSpecularIntensity()
|
||||
const
|
||||
{
|
||||
return diffuse_color;
|
||||
return mSpecularIntensity;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Material::set_diffuse_color(const Color &c)
|
||||
Material::SetSpecularIntensity(const Double& ks)
|
||||
{
|
||||
diffuse_color = c;
|
||||
mSpecularIntensity = ks;
|
||||
ClampParameter(mSpecularIntensity);
|
||||
}
|
||||
|
||||
|
||||
float
|
||||
Material::get_specular_level()
|
||||
const
|
||||
Color&
|
||||
Material::GetSpecularColor()
|
||||
{
|
||||
return specular_level;
|
||||
return mSpecularColor;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Material::set_specular_level(const float &ks)
|
||||
Material::SetSpecularColor(const Color& color)
|
||||
{
|
||||
specular_level = ks;
|
||||
_clamp_parameter(specular_level);
|
||||
}
|
||||
|
||||
|
||||
const Color &
|
||||
Material::get_specular_color()
|
||||
const
|
||||
{
|
||||
return specular_color;
|
||||
mSpecularColor = color;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Material::set_specular_color(const Color &c)
|
||||
{
|
||||
specular_color = c;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Material::_clamp_parameter(float ¶m)
|
||||
Material::ClampParameter(Double& param)
|
||||
{
|
||||
if (param < 0.0) {
|
||||
param = 0.0;
|
||||
|
|
@ -88,3 +91,5 @@ Material::_clamp_parameter(float ¶m)
|
|||
param = 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
} /* namespace charles */
|
||||
|
|
|
|||
|
|
@ -1,45 +0,0 @@
|
|||
/* material.h
|
||||
*
|
||||
* Materials are applied to shapes and determine color, texture mapping, shading, etc.
|
||||
*
|
||||
* Eryn Wells <eryn@erynwells.me>
|
||||
*/
|
||||
|
||||
#ifndef __MATERIAL_H__
|
||||
#define __MATERIAL_H__
|
||||
|
||||
#include "basics.h"
|
||||
|
||||
|
||||
class Material
|
||||
{
|
||||
public:
|
||||
enum {
|
||||
DiffuseLightingTypeLambert = 1,
|
||||
} DiffuseLightingType;
|
||||
|
||||
Material();
|
||||
|
||||
float get_diffuse_level() const;
|
||||
void set_diffuse_level(const float &kd);
|
||||
const Color &get_diffuse_color() const;
|
||||
void set_diffuse_color(const Color &c);
|
||||
|
||||
float get_specular_level() const;
|
||||
void set_specular_level(const float &kd);
|
||||
const Color &get_specular_color() const;
|
||||
void set_specular_color(const Color &c);
|
||||
|
||||
private:
|
||||
void _clamp_parameter(float ¶m);
|
||||
|
||||
// Diffuse parameters.
|
||||
float diffuse_level;
|
||||
Color diffuse_color;
|
||||
|
||||
// Specular parameters.
|
||||
float specular_level;
|
||||
Color specular_color;
|
||||
};
|
||||
|
||||
#endif
|
||||
59
src/material.hh
Normal file
59
src/material.hh
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
/* material.hh
|
||||
* vim: set tw=80:
|
||||
* Eryn Wells <eryn@erynwells.me>
|
||||
*/
|
||||
|
||||
#ifndef __MATERIAL_HH__
|
||||
#define __MATERIAL_HH__
|
||||
|
||||
#include "basics/basics.hh"
|
||||
|
||||
|
||||
namespace charles {
|
||||
|
||||
/**
|
||||
* Materials are applied to shapes and determine color, texture mapping,
|
||||
* shading, etc.
|
||||
*/
|
||||
struct Material
|
||||
{
|
||||
enum class DiffuseShaderModel {
|
||||
Lambert,
|
||||
};
|
||||
|
||||
enum class SpecularShaderModel {
|
||||
Blinn,
|
||||
Phong
|
||||
};
|
||||
|
||||
Material();
|
||||
|
||||
Double GetDiffuseIntensity() const;
|
||||
void SetDiffuseIntensity(const Double& kd);
|
||||
|
||||
basics::Color& GetDiffuseColor();
|
||||
void SetDiffuseColor(const basics::Color& c);
|
||||
|
||||
Double GetSpecularIntensity() const;
|
||||
void SetSpecularIntensity(const Double& kd);
|
||||
|
||||
basics::Color& GetSpecularColor();
|
||||
void SetSpecularColor(const basics::Color& c);
|
||||
|
||||
private:
|
||||
void ClampParameter(Double& param);
|
||||
|
||||
// Diffuse parameters.
|
||||
DiffuseShaderModel mDiffuseModel;
|
||||
Double mDiffuseIntensity;
|
||||
basics::Color mDiffuseColor;
|
||||
|
||||
// Specular parameters.
|
||||
SpecularShaderModel mSpecularModel;
|
||||
Double mSpecularIntensity;
|
||||
basics::Color mSpecularColor;
|
||||
};
|
||||
|
||||
} /* namespace charles */
|
||||
|
||||
#endif
|
||||
194
src/object.cc
194
src/object.cc
|
|
@ -9,106 +9,148 @@
|
|||
#include <cmath>
|
||||
#include <cstdlib>
|
||||
|
||||
#include "basics.h"
|
||||
#include "material.h"
|
||||
#include "object.h"
|
||||
#include "object.hh"
|
||||
|
||||
#pragma mark - Objects
|
||||
#include "material.hh"
|
||||
#include "basics/basics.hh"
|
||||
|
||||
|
||||
using charles::basics::Ray;
|
||||
using charles::basics::Matrix4;
|
||||
using charles::basics::Vector4;
|
||||
|
||||
|
||||
namespace charles {
|
||||
|
||||
/*
|
||||
* Object::Object --
|
||||
*
|
||||
* Default constructor. Create a new Object with an origin at (0, 0, 0).
|
||||
* charles::Object::Object --
|
||||
*/
|
||||
Object::Object()
|
||||
: Object(Vector3::Zero)
|
||||
Object::Object(const Vector4& origin)
|
||||
: mTranslation(Matrix4::Translation(origin)),
|
||||
mMaterial()
|
||||
{ }
|
||||
|
||||
|
||||
/*
|
||||
* Object::Object --
|
||||
*
|
||||
* Constructor. Create a new Object with an origin at o.
|
||||
* charles::Object::~Object --
|
||||
*/
|
||||
Object::Object(Vector3 o)
|
||||
: origin(o)
|
||||
Object::~Object()
|
||||
{ }
|
||||
|
||||
|
||||
/*
|
||||
* Object::get_origin --
|
||||
* Object::set_origin --
|
||||
*
|
||||
* Get and set the Object's origin.
|
||||
* charles::Object::GetMaterial --
|
||||
*/
|
||||
Vector3
|
||||
Object::get_origin()
|
||||
Material&
|
||||
Object::GetMaterial()
|
||||
{
|
||||
return mMaterial;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::Object::Place --
|
||||
*/
|
||||
void
|
||||
Object::Place(const Vector4 &p)
|
||||
{
|
||||
mTranslation = Matrix4::Translation(-p);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::Object::SetMaterial --
|
||||
*/
|
||||
void
|
||||
Object::SetMaterial(const Material& material)
|
||||
{
|
||||
mMaterial = material;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::Object::Intersect --
|
||||
*/
|
||||
bool
|
||||
Object::Intersect(const basics::Ray& ray,
|
||||
TVector& t,
|
||||
Stats& stats)
|
||||
const
|
||||
{
|
||||
return origin;
|
||||
}
|
||||
|
||||
void
|
||||
Object::set_origin(Vector3 v)
|
||||
{
|
||||
origin = v;
|
||||
Ray objSpaceRay = ToObjectSpace(ray);
|
||||
return DoIntersect(objSpaceRay, t, stats);
|
||||
}
|
||||
|
||||
|
||||
std::ostream &
|
||||
operator<<(std::ostream &os, const Object &o)
|
||||
{
|
||||
// Stream objects like this: [Object origin]
|
||||
os << "[Object " << o.origin << "]";
|
||||
return os;
|
||||
}
|
||||
|
||||
#pragma mark - Shapes
|
||||
|
||||
/*
|
||||
* Shape::Shape --
|
||||
*
|
||||
* Default constructor. Create a new Shape with an origin at (0, 0, 0).
|
||||
* charles::Object::Normal --
|
||||
*/
|
||||
Shape::Shape()
|
||||
: Object()
|
||||
{ }
|
||||
|
||||
|
||||
/*
|
||||
* Shape::Shape --
|
||||
*
|
||||
* Constructor. Create a new Shape with an origin at o.
|
||||
*/
|
||||
Shape::Shape(Vector3 o)
|
||||
: Object(o)
|
||||
{ }
|
||||
|
||||
|
||||
/*
|
||||
* Shape::~Shape() --
|
||||
*
|
||||
* Destructor.
|
||||
*/
|
||||
Shape::~Shape()
|
||||
{ }
|
||||
|
||||
|
||||
/*
|
||||
* Shape::get_material --
|
||||
* Shape::set_material --
|
||||
*
|
||||
* Get and set the Material applied to this shape.
|
||||
*/
|
||||
Material &
|
||||
Shape::get_material()
|
||||
Vector4
|
||||
Object::Normal(const Vector4& p)
|
||||
const
|
||||
{
|
||||
return *material;
|
||||
Vector4 norm = Transpose(mTranslation) * DoNormal(ToObjectSpace(p));
|
||||
return norm;
|
||||
}
|
||||
|
||||
void
|
||||
Shape::set_material(Material *mat)
|
||||
|
||||
/*
|
||||
* charles::Object::ToObjectSpace --
|
||||
*/
|
||||
Ray
|
||||
Object::ToObjectSpace(Ray ray)
|
||||
const
|
||||
{
|
||||
material = mat;
|
||||
ray.origin = ToObjectSpace(ray.origin);
|
||||
//ray.direction = ToObjectSpace(ray.direction).Normalize();
|
||||
return ray;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::Object::ToObjectSpace --
|
||||
*/
|
||||
Vector4
|
||||
Object::ToObjectSpace(const Vector4& v)
|
||||
const
|
||||
{
|
||||
return mTranslation * v;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::Object::FromObjectSpace --
|
||||
*/
|
||||
Vector4
|
||||
Object::FromObjectSpace(const Vector4& v)
|
||||
const
|
||||
{
|
||||
return Inverse(mTranslation) * v;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::Object::Write --
|
||||
*/
|
||||
void
|
||||
Object::Write(std::ostream& ost)
|
||||
const
|
||||
{
|
||||
ost << "[Object]";
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::operator<< --
|
||||
*/
|
||||
std::ostream&
|
||||
operator<<(std::ostream& ost,
|
||||
const Object& object)
|
||||
{
|
||||
ost << "[";
|
||||
object.Write(ost);
|
||||
ost << " translate=" << object.mTranslation.Column(3) << "]";
|
||||
return ost;
|
||||
}
|
||||
|
||||
} /* namespace charles */
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue