Compare commits

...
Sign in to create a new pull request.

150 commits

Author SHA1 Message Date
fdd96dbc27 Print pixel progress
Not entirely convinced this is a good idea yet. It slows down rendering by almost 2x.
2014-08-02 00:51:55 -07:00
ea1fac7501 Add ctags file 2014-08-02 00:42:59 -07:00
b6d7a65ae5 Merge branch 'feature/logging' into develop 2014-08-02 00:40:52 -07:00
86a4594e7f Initialize logging based on passed in parameters 2014-08-02 00:40:38 -07:00
f8ec140f8e Do some logging in Scene 2014-08-02 00:28:02 -07:00
3ab7c92d36 Duplicate logging symbols :( 2014-08-02 00:27:50 -07:00
0346e21ebd Set the log level to trace. 2014-08-02 00:02:11 -07:00
97a172bbe9 Add logModule.hh
Defines some helper macros to make it easier to log message. Define LOG_NAME before including this file and a number of logging macros will be defined that will allow users to skip specifying the name of the log stream for each statement.
2014-08-02 00:02:01 -07:00
3a94433f5c Set global default level in Init() 2014-08-01 23:49:52 -07:00
f8c7c9c6ea Add function Tracer 2014-08-01 23:49:33 -07:00
7cfb304296 Update logging stuff in main() 2014-08-01 23:28:13 -07:00
ea6cd488a6 LOG_FOO macros to help with printing messages 2014-08-01 23:27:32 -07:00
089c4cdc73 Print milliseconds 2014-08-01 23:27:18 -07:00
627854bc20 Use logging! 2014-08-01 22:28:47 -07:00
c00afe1cd1 Rudimentary logging! 2014-08-01 22:28:41 -07:00
d2b2382c95 Include <memory> in object.h 2014-07-25 15:10:29 -07:00
bad80c9895 Scons default build target: charles 2014-07-25 13:31:09 -07:00
6a9c1e87e2 Ignore *.log files 2014-07-24 08:05:03 -07:00
900c667994 Couple more scenes to test coordinate grids 2014-07-24 08:03:13 -07:00
63bb28a94a Push tNear and tFar onto t&, rather than t0 and t1 2014-07-23 07:39:55 -07:00
2b9d3a3824 Add a new scene with a single unit-box at the origin 2014-07-22 21:40:39 -07:00
f5f47f5a9a Print number of objects in the scene before rendering 2014-07-22 21:40:25 -07:00
deff3079b8 Update ObjectParser for boxes
ObjectParser's constructor takes the tag value, which determines the type of object constructed.

ObjectParser adds "near" and "far" sections for boxes.
2014-07-22 21:40:13 -07:00
b878db592c Getters and setters for Near and Far vectors 2014-07-22 21:37:49 -07:00
15db0c42d4 Box objects, parallel to the coordinate axes
This change implements Kay-Kajiya intersection (with slabs) too!
2014-07-22 20:46:47 -07:00
d69d708b31 Convert Vector3 to use Doubles 2014-07-22 20:46:10 -07:00
1d22e27d81 Specify object types in threeSpheres.yml
These don't actually do anything yet, but I'd like to get this going once I start
adding more object types.
2014-07-20 16:55:52 -07:00
6f844f7c2a Update ObjectParser for new code style... 2014-07-20 16:55:26 -07:00
5a8d634590 Update Scene a bit for new code style and namespaces in Object and Sphere 2014-07-20 16:54:10 -07:00
cf7806484f Some generic, useful types
- Double -> double
- DoubleVector -> std::vector<Double>
- TVector -> DoubleVector
2014-07-20 16:53:39 -07:00
e5cb9be1aa Don't include or build object_plane.{cc,h} because it hasn't been updated and it doesn't work. 2014-07-20 16:53:03 -07:00
c185a24f34 Define shared_ptr<Sphere> as Sphere::Ptr 2014-07-20 16:51:58 -07:00
12f180a3de Light implements its own origin 2014-07-20 16:51:20 -07:00
19aeb7b14e Update Sphere to inherit from Object
- Had to do a couple updates here to adapt to the new code style...
- Update DoesIntersect for code style and to pass back t values in the vector
instead of the float array.
2014-07-20 16:49:55 -07:00
2036521f42 Update code style for Object
- Remove Shape, because it seems to be mostly extra. All renderable objects now
derive from Object, rather than Shape
- Light (which inherited from Object before) now defines its own origin, but
this is coming in a later commit...
- Use charles namespace

- Use a std::vector<double> instead of float** to pass back intersection points.
This is kind of a biggie because it made the render process 50% slower :( I'll
have to work out why and maybe fix it...
2014-07-20 16:48:09 -07:00
ac8421b5e1 Update code style for Material objects 2014-07-20 16:45:40 -07:00
0d2011931c Account all types of rays -- print them at the end 2014-07-20 14:21:12 -07:00
c65c6a3cfd Use shared_ptr for Scene::mCamera
Makes memory management a bit easier...
2014-07-20 12:37:31 -07:00
c564791d1a Camera doesn't inherit from Object; defines its own origin. 2014-07-20 12:37:04 -07:00
709453adcb Fix a comment about Camera::mUp 2014-07-20 12:19:59 -07:00
06c2986280 Don't duplicate build files
Turns out keeping files in place, instead of symlinking or hard linking into
build/ means that Xcode can actually break on files in src/. This is cool!

There's still a problem with Xcode not getting appropriate type information
though.
2014-07-20 12:17:55 -07:00
6ed121a039 Some notes 2014-07-20 08:36:46 -07:00
ea43af46ba charles.hh – defines extern'd verbosity 2014-07-19 21:20:50 -07:00
54ab0d6641 Fix aspect ratio of the three-spheres scene 2014-07-19 21:19:32 -07:00
54796a74b7 Notify end-of-section after camera stuff 2014-07-19 21:12:45 -07:00
4d5796e6e7 Parse the camera section of a scene 2014-07-19 21:00:34 -07:00
eaabdfddc0 OHGOD TABS WERE HERE INSTEAD OF SPACES 2014-07-19 21:00:15 -07:00
e2b5ffaf6c Fixing up CameraParser
- Compiler errors
- Coulple name tweaks
- Headers
2014-07-19 20:59:48 -07:00
3ec5b20f16 Rename Scene::camera -> mCamera 2014-07-19 20:57:12 -07:00
6f04526d36 Default and copy constructors for Perspective and Orthographic cameras 2014-07-19 20:56:47 -07:00
672ff82e03 add cameraParser.cc to the build 2014-07-19 17:25:54 -07:00
b85abacd26 Move camera_parser -> cameraParser 2014-07-19 17:25:17 -07:00
b85a6aed7b Bit more clean up of cameras 2014-07-19 17:24:52 -07:00
b03ad0ac2d Add CameraParser 2014-07-19 17:24:28 -07:00
76a13e61de Update call sites and instantiation for Vector3 and Color parsers 2014-07-19 17:19:54 -07:00
2c4f6a4d29 Some more helpful utility parsers
- Rename VectorParser -> ScalarSequenceParser
- Add Vector3Parser and ColorParser, subclasses of the above, which handle
  Vector3s and Colors
2014-07-19 17:17:33 -07:00
daf5c7d8a6 Clean up camera module 2014-07-19 16:30:26 -07:00
41327c92fd Remove a bunch of debugging printfs and add verbosity levels 2014-07-19 16:04:47 -07:00
17df0d4adf Add "Three Spheres" scene 2014-07-19 15:53:47 -07:00
1eff46006a Comment out adding objects from main() – they come from YAML now!! :D 2014-07-19 15:46:38 -07:00
575ed822b4 Set shouldExpectKey after finishing radius; clean up asserts in ObjectParser 2014-07-19 15:46:06 -07:00
0ed3b524f4 Print all events; properly handle document and mapping-start events from top-level run loop 2014-07-19 15:45:04 -07:00
523eaef902 ScalarMappingParser::mShouldExpectKey should be true to start/end the top-level mapping 2014-07-19 15:44:29 -07:00
49e3395a4c Add objects parsing to SceneParser 2014-07-19 15:43:44 -07:00
43a1e790cb Initialize Parser::mDone 2014-07-19 15:42:53 -07:00
0b9b5a784d Add radius section for ObjectParser 2014-07-19 15:42:31 -07:00
5f02407b06 Initialize a new Sphere in ObjectParser and add it to the scene 2014-07-19 15:41:45 -07:00
0a14661da8 Set material to NULL in Shape 2014-07-19 15:41:17 -07:00
573f53b67c ObjectParser using ScalarMappingParser 2014-07-19 14:45:37 -07:00
2f91e12296 Catch end-of-mapping event in ScalarMappingParser 2014-07-19 14:22:30 -07:00
68d0083ba8 Object::get_material returns a pointer instead of a reference 2014-07-19 14:09:47 -07:00
b62949416b Rename object_parser.{cc,hh} -> objectParser.{cc,hh} 2014-07-19 13:42:36 -07:00
03c037730e Move scene_parser.{cc,hh} to sceneParser.{cc,hh} 2014-07-19 11:43:09 -07:00
98fe95e1a5 Declare valueString before passing to ParseScalar
This is to account for the length of the scalar string value, which is passed as
an element of event.data.scalar.
2014-07-19 11:40:02 -07:00
693e4fa80d Make SceneParser a subclass of ScalarMappingParser 2014-07-19 11:39:22 -07:00
325e9459fd Create scalar value string before passing to ParseScalar in ObjectParser 2014-07-19 11:34:19 -07:00
625e3a6f47 Add ScalarMappingParser 2014-07-19 11:28:03 -07:00
7153ec759b Sublime project and workspace settings 2014-07-19 11:27:32 -07:00
09b0065611 Use a stringstream instead of sscanf for ParseScalar 2014-07-19 10:59:22 -07:00
d65fc16219 Ignore unused parameters in PNG error functions 2014-07-19 10:15:00 -07:00
6214413e3e NDEBUG *removes* asserts -- whoops 2014-07-19 10:11:51 -07:00
5517aadb0a Remove prints from SConscript 2014-07-18 21:27:17 -07:00
56b79c9cfb Parse test sconscripts before src -- i should probably push this commit up to base 2014-07-17 20:18:20 -07:00
e7b9ee8257 Reformat some comments 2014-07-17 20:17:17 -07:00
c429be330d Reset SceneParser::mSection after parsing dimensions vector 2014-07-17 20:15:44 -07:00
87c544cec7 '%lf' for doubles, not '%ld' 2014-07-17 20:15:20 -07:00
6ff108f360 Implement ObjectParser 2014-07-17 20:14:52 -07:00
2a6f72f511 Use new coordinates to place spheres with the perspective camera
It works!
2014-07-16 23:33:37 -07:00
25b246d3ed Use the PerspectiveCamera to generate primary rays. 2014-07-16 23:32:44 -07:00
899064ce42 Add a perspective camera
Finally! :D Verified (mostly) and carefully thought through by looking at the
Pov-Ray code and doing the linear algebra by hand. Fun times.
2014-07-16 23:31:39 -07:00
360bc52080 I don't really know if this is correct; I have not verified it 2014-07-16 23:30:25 -07:00
0e1106aa41 Update the call signature of compute_primary_ray
It takes the current X and Y coordinates and the height and width of the image.
2014-07-16 23:29:54 -07:00
05327fbe7a Missed a few things when I…
- Removed the (viewing) angle member
- Added Up and Right vectors
2014-07-16 23:29:01 -07:00
72e93eccb3 Reformat description of OrthographicCamera::compute_primary_ray 2014-07-16 23:26:41 -07:00
8eb98270af Add Up and Right vectors to the camera 2014-07-16 23:25:54 -07:00
8336753bcf Remove pixel dimensions from camera
The scene computes those and gives them to the camera for each ray
2014-07-16 23:24:32 -07:00
ca5cabb6ef Add LinearCombination for Vectors 2014-07-16 23:23:26 -07:00
2834fa45c6 Replace dimensions code in SceneParser with a few lines of VectorParser magic
Neat!
2014-07-15 23:33:02 -07:00
bdd0afddf5 Define format strings for int and double ParseScalar() methods 2014-07-15 23:32:20 -07:00
b8d0b274b1 Implement templated VectorParser 2014-07-15 23:31:48 -07:00
d12f8c9fa6 Define ParseScalar<T> and ParseScalarTraits
For parsing single YAML scalar values into C++ datatypes (mostly ints and doubles).
2014-07-15 23:28:59 -07:00
557d9a047f Define the Notify() method on UtilityParser 2014-07-15 23:27:24 -07:00
d20e4154fe Big YAML parser cleanup 2014-07-15 17:27:27 -07:00
687de91a81 Quick 'n dirty setters for height and width 2014-07-13 20:12:10 -07:00
f59ec98035 HOLY CRAP I CAN READ DIMENSIONS FROM YAML FILES 2014-07-13 20:11:50 -07:00
6a8bcc4973 Add back a bunch of the programatic scene stuff 2014-07-13 20:11:37 -07:00
3687029bcd Parse YAML files in main() 2014-07-13 18:06:21 -07:00
b4327303ee Add YAML reader 2014-07-13 18:06:03 -07:00
357bcc19c0 Remove libyaml Makefiles 2014-07-13 09:47:51 -07:00
24b07b65f0 libyaml 2014-07-13 09:47:37 -07:00
eb0f93f476 Merge remote-tracking branch 'base/master' into develop 2014-07-13 09:23:57 -07:00
dfd57da14f Correcting some build problems with old-style SConscripts 2014-07-13 09:23:42 -07:00
a0edcab26d Comment about swapping env and build_env in do_sconscript() 2014-07-13 09:22:53 -07:00
9b00e03b2d Get rid of broken check for lib dir existence 2014-07-13 09:21:11 -07:00
882f5614ae Add build_env (as env) to sconscript environment 2014-07-13 09:12:08 -07:00
2b87d5add6 Use -O3 for production 2014-07-13 09:10:41 -07:00
61134833dc Remove gtest in top-level directory 2014-07-13 08:56:12 -07:00
391251940b Merge remote-tracking branch 'base/master' into develop
Conflicts:
	.gitignore
	SConstruct
	src/SConscript
	test/SConscript
2014-07-13 08:24:16 -07:00
3ddfd94dfa No planes 2014-07-13 07:43:18 -07:00
491972b6c2 Merge branch 'develop' 2014-07-13 07:42:08 -07:00
a2dea2a35f Add beta environment -- debug, with optimization 2014-07-13 07:42:00 -07:00
fb0f090892 Add succinct build commands, but don't use 'em yet 2014-07-04 11:09:39 -07:00
fea154a058 So much clean up...
Brought in the SConscript from Late Fish, which is where a lot of these changes
were made. Cleaned up a bunch of stuff. Moved repeated code to functions.
Implemented dynamically building libraries in lib/.
2014-07-04 10:55:34 -07:00
98e1fdd4fb Add test environment 2014-02-28 17:40:49 -08:00
301a7fa525 Fixing up gtest to work with scons (better!) 2014-02-28 17:40:32 -08:00
47ca68760a Add test SConscript 2014-02-28 17:40:32 -08:00
c9c1ba5972 Add SConscript for gtest 2014-02-28 17:40:32 -08:00
7e7960ce72 Update gtest-all.cc to find src files 2014-02-28 17:40:32 -08:00
083aa869d5 Move src files to root of gtest 2014-02-28 17:40:32 -08:00
fe0ebd6cff Remove the cruft 2014-02-28 17:40:32 -08:00
0b321237b6 Add base gtest distribution 1.7.0 2014-02-28 17:40:31 -08:00
eded4652a7 Redo environments, just a bit... 2014-02-28 17:39:41 -08:00
ccde6a29a1 Add color diagnostics for clang 2014-02-27 22:20:29 -08:00
ff1440b6d6 Add "Shared" COMSTR variants 2014-02-27 21:57:20 -08:00
1a37170b9a Clean up env creation 2014-01-31 08:42:41 -08:00
b40e4b07d9 Clean build directories -- still doesn't clean build/ though 2014-01-31 08:34:11 -08:00
9540bdd26e Build only the given mode 2014-01-31 08:27:37 -08:00
d4cf547683 Clean up set_toolchain_binary 2014-01-30 21:01:20 -08:00
4ab61d591a Fix syntax error in set_compiler 2014-01-30 20:47:24 -08:00
0a5db99852 Add linker override 2014-01-30 20:43:09 -08:00
08880e87ac More tweaks for setting default compilers 2014-01-30 20:39:56 -08:00
c76f986a86 Add definable overrides for C/C++ compilers and the assembler; add override for CFLAGS 2014-01-30 20:36:38 -08:00
60d0112326 Few more tweaks 2014-01-30 15:42:25 -08:00
3f56df90a7 Ignore build/ 2014-01-30 15:14:13 -08:00
2134f6a013 Basic template SConscript 2014-01-30 15:13:54 -08:00
ab85d0cd32 Fixing up SConstruct 2014-01-30 15:09:28 -08:00
22f75f5e86 Ignore Scons stuff 2014-01-30 14:10:40 -08:00
85213b6f50 Add empty src/SConscript 2014-01-30 14:08:20 -08:00
104fe40661 Add base SConstruct 2014-01-30 14:08:11 -08:00
11815346af Initial commit 2014-01-30 13:39:51 -08:00
107 changed files with 19535 additions and 2191 deletions

8
.gitignore vendored
View file

@ -1,6 +1,6 @@
*.o
src/charles
build/
*.png
.sconsign.dblite
build/
*.png
*.log

0
README.md Normal file
View file

View file

@ -1,8 +1,5 @@
# SConstruct
# vim: set ft=python:
#
# Toplevel Scons build script for the Charles project.
#
# Eryn Wells <eryn@erynwells.me>
@ -10,89 +7,201 @@
# 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'])
# 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')
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])
# 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
View file

@ -0,0 +1,10 @@
{
"folders":
[
{
"path": ".",
"follow_symlinks": true,
"folder_exclude_patterns": ["build"]
}
]
}

421
charles.sublime-workspace Normal file
View 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
View 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

View file

@ -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')

View file

@ -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_

View file

@ -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

View file

@ -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
View 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)

View file

@ -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"

View file

@ -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

View file

@ -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;
}

View file

@ -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

View file

@ -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;
}

View file

@ -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

View file

@ -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.

View file

@ -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

View file

@ -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();
}

View file

@ -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

View file

@ -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_

View file

@ -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();

View file

@ -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();

View file

@ -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();
}

View file

@ -223,7 +223,7 @@ class GTEST_API_ SingleFailureChecker {
(substr));\
{\
::testing::ScopedFakeTestPartResultReporter gtest_reporter(\
::testing::ScopedFakeTestPartResultReporter::INTERCEPT_ALL_THREADS,\
::testing::ScopedFakeTestPartResultReporter::INTERCEPT_ALL_THREADS, \
&gtest_failures);\
if (::testing::internal::AlwaysTrue()) { statement; }\
}\

View file

@ -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.

View file

@ -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_

View file

@ -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

View file

@ -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_;

View file

@ -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

View file

@ -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

View file

@ -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;

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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(),

View file

@ -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

View 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_

View file

@ -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)>

View file

@ -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)>

View file

@ -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,

View file

@ -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
View 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
View 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
View 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
View 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

File diff suppressed because it is too large Load diff

394
lib/yaml/dumper.c Normal file
View 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

File diff suppressed because it is too large Load diff

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
View 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

File diff suppressed because it is too large Load diff

469
lib/yaml/reader.c Normal file
View 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

File diff suppressed because it is too large Load diff

141
lib/yaml/writer.c Normal file
View 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
View 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
View 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]

8
scenes/oneBox.yml Normal file
View file

@ -0,0 +1,8 @@
--- !Scene
dimensions: [800, 600]
camera: !Camera.Perspective
right: [1.77, 0, 0]
objects:
- !Object.Box
near: [-0.5, -0.5, -0.5]
far: [0.5, 0.5, 0.5]

34
scenes/sphereGrid.yml Normal file
View 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
View file

@ -0,0 +1,17 @@
--- !Scene
dimensions: [1920, 1080]
camera: !Camera.Perspective
right: [1.77, 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]

View file

@ -4,20 +4,39 @@
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 = [
'yaml',
]
for d in subdirs:
dir_objs = env.SConscript(env.Dir(d).File('SConscript'), {'env': env})
objs.extend(dir_objs)
files = [
'basics.cc',
'camera.cc',
'light.cc',
'log.cc',
'material.cc',
'object.cc',
'objectBox.cc',
'object_sphere.cc',
#'object_plane.cc',
'reader_yaml.cc',
'scene.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')

View file

@ -35,7 +35,7 @@ Vector3::Vector3()
*
* Constructor. Create a vector consisting of the given coordinates.
*/
Vector3::Vector3(float _x, float _y, float _z)
Vector3::Vector3(Double _x, Double _y, Double _z)
: x(_x), y(_y), z(_z)
{ }
@ -65,7 +65,7 @@ Vector3::operator=(const Vector3 &v)
* a reference to this vector is returned.
*/
Vector3 &
Vector3::operator*=(const float &rhs)
Vector3::operator*=(const Double &rhs)
{
x *= rhs;
y *= rhs;
@ -74,7 +74,7 @@ Vector3::operator*=(const float &rhs)
}
Vector3 &
Vector3::operator/=(const float &rhs)
Vector3::operator/=(const Double &rhs)
{
return *this *= (1.0f / rhs);
}
@ -104,14 +104,14 @@ Vector3::operator-=(const Vector3 &rhs)
* Perform the corresponding operation on a copy of this vector. Return a new vector.
*/
Vector3
Vector3::operator*(const float &rhs)
Vector3::operator*(const Double &rhs)
const
{
return Vector3(*this) *= rhs;
}
Vector3
Vector3::operator/(const float &rhs)
Vector3::operator/(const Double &rhs)
const
{
return Vector3(*this) /= rhs;
@ -171,7 +171,7 @@ Vector3::operator!=(const Vector3 &rhs)
*
* Compute and return the length-squared of this vector.
*/
float
Double
Vector3::length2()
const
{
@ -184,11 +184,11 @@ Vector3::length2()
*
* Compute and return the length of this vector.
*/
float
Double
Vector3::length()
const
{
return sqrtf(length2());
return sqrt(length2());
}
@ -197,7 +197,7 @@ Vector3::length()
*
* Compute and return the dot product of this and the given vectors.
*/
float
Double
Vector3::dot(const Vector3 &v)
const
{
@ -237,7 +237,7 @@ Vector3::normalize()
* Multiply the given float by the given vector. Return a new vector.
*/
const Vector3
operator*(const float &lhs, const Vector3 &rhs)
operator*(const Double &lhs, const Vector3 &rhs)
{
return rhs * lhs;
}
@ -251,6 +251,17 @@ operator<<(std::ostream &os, const Vector3 &v)
return os;
}
Vector3
LinearCombination(const Double k1, const Vector3& v1,
const Double k2, const Vector3& v2,
const Double k3, const Vector3& v3)
{
return Vector3(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);
}
#pragma mark - Rays
/*

View file

@ -14,19 +14,27 @@
#include <iostream>
#include "types.hh"
/*
* XXX: THIS SHOULD NOT BE HERE. REMOVE IT WHEN MOVING TO CHARLES NAMESPACE IS
* DONE.
*/
using charles::Double;
struct Vector3
{
Vector3();
Vector3(float x, float y, float z);
Vector3(Double x, Double y, Double z);
Vector3 &operator=(const Vector3 &v);
Vector3 &operator*=(const float &rhs);
Vector3 &operator/=(const float &rhs);
Vector3 &operator*=(const Double &rhs);
Vector3 &operator/=(const Double &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 Double &rhs) const;
Vector3 operator/(const Double &rhs) const;
Vector3 operator+(const Vector3 &rhs) const;
Vector3 operator-(const Vector3 &rhs) const;
Vector3 operator-() const;
@ -34,9 +42,9 @@ struct Vector3
bool operator==(const Vector3 &rhs) const;
bool operator!=(const Vector3 &rhs) const;
float length2() const;
float length() const;
float dot(const Vector3 &v) const;
Double length2() const;
Double length() const;
Double dot(const Vector3 &v) const;
Vector3 cross(const Vector3 &v) const;
Vector3 &normalize();
@ -45,13 +53,18 @@ struct Vector3
// Unit vectors in each of the three cartesian directions.
static const Vector3 X, Y, Z;
float x, y, z;
Double x, y, z;
};
const Vector3 operator*(const float &lhs, const Vector3 &rhs);
const Vector3 operator*(const Double &lhs, const Vector3 &rhs);
std::ostream &operator<<(std::ostream &os, const Vector3 &v);
Vector3 LinearCombination(const Double k1, const Vector3& v1,
const Double k2, const Vector3& v2,
const Double k3, const Vector3& v3);
struct Ray
{
Ray();

View file

@ -12,9 +12,16 @@
#pragma mark - Generic Camera
Camera::Camera()
: height(Vector3::Y),
width(4.0 / 3.0 * Vector3::X),
direction(Vector3::Z)
: mDirection(Vector3::Z),
mRight(1.33, 0, 0),
mUp(Vector3::Y)
{ }
Camera::Camera(const Camera& other)
: mDirection(other.mDirection),
mRight(other.mRight),
mUp(other.mUp)
{ }
@ -23,128 +30,138 @@ 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 Vector3&
Camera::GetOrigin()
const
{
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::SetOrigin --
*/
const Vector3 &
Camera::get_width()
const
{
return width;
}
void
Camera::set_width(const Vector3 &w)
Camera::SetOrigin(const Vector3 &origin)
{
width = w;
}
const Vector3 &
Camera::get_height()
const
{
return height;
}
void
Camera::set_height(const Vector3 &h)
{
height = h;
mOrigin = origin;
}
/*
* Camera::get_direction --
* Camera::set_direction --
*
* Get and set direction vector.
*/
const Vector3 &
const Vector3&
Camera::get_direction()
const
{
return direction;
return mDirection;
}
void
Camera::set_direction(const Vector3 &d)
Camera::set_direction(const Vector3 &direction)
{
direction = d;
mDirection = direction;
}
/*
* Camera::get_angle --
*
* Get the angle of view.
*/
float
Camera::get_angle()
const Vector3&
Camera::GetRight()
const
{
return angle;
return mRight;
}
void
Camera::SetRight(const Vector3& right)
{
mRight = right;
}
const Vector3&
Camera::GetUp()
const
{
return mUp;
}
void
Camera::SetUp(const Vector3& up)
{
mUp = up;
}
#pragma mark - Perspective Camera
PerspectiveCamera::PerspectiveCamera()
: Camera()
{ }
PerspectiveCamera::PerspectiveCamera(const Camera& other)
: Camera(other)
{ }
Ray
PerspectiveCamera::compute_primary_ray(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;
Vector3 direction = LinearCombination(1.0, get_direction(),
x0, GetRight(),
y0, GetUp());
return Ray(GetOrigin(), direction);
}
#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
*/
/**
* 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::compute_primary_ray(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);
Vector3 origin = LinearCombination(1.0, GetOrigin(),
x0, GetRight(),
y0, GetUp());
return Ray(origin, get_direction());
}

View file

@ -1,7 +1,8 @@
/* 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.
* 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>
*/
@ -9,43 +10,67 @@
#ifndef __CAMERA_H__
#define __CAMERA_H__
#include <memory>
#include "basics.h"
#include "object.h"
class Camera
: public Object
struct Camera
{
public:
typedef std::shared_ptr<Camera> Ptr;
Camera();
~Camera();
Camera(const Camera& other);
virtual ~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;
const Vector3& GetOrigin() const;
void SetOrigin(const Vector3& origin);
virtual Ray compute_primary_ray(const int &x, const int &y) const = 0;
const Vector3& get_direction() const;
void set_direction(const Vector3& direction);
const Vector3& GetRight() const;
void SetRight(const Vector3& right);
const Vector3& GetUp() const;
void SetUp(const Vector3& up);
virtual Ray compute_primary_ray(const int x, const int width,
const int y, const int height) const = 0;
private:
// Pixel dimensions of the image plane.
int pwidth, pheight;
/**
* The location of the camera in the scene. Depending on the type of camera,
* this is the point from which rays will be emitted.
*/
Vector3 mOrigin;
// Size of the image plane.
Vector3 height, width;
/** A normalized vector defining where the camera is pointed. */
Vector3 mDirection;
// Direction. A normalized vector defining where the camera is pointed.
Vector3 direction;
/**
* A vector defining the width of the camera's image plane. The ratio of
* this and mUp determine the aspect ratio of the image.
*/
Vector3 mRight;
// Horizontal viewing angle.
float angle;
/**
* A vector defining the height of the camera's image plane. The ratio of
* this and mRight determine the aspect ratio of the image.
*/
Vector3 mUp;
};
class PerspectiveCamera
: public Camera
{
public:
PerspectiveCamera();
PerspectiveCamera(const Camera& other);
Ray compute_primary_ray(const int x, const int width,
const int y, const int height) const;
};
@ -53,7 +78,11 @@ class OrthographicCamera
: public Camera
{
public:
Ray compute_primary_ray(const int &x, const int &y) const;
OrthographicCamera();
OrthographicCamera(const Camera& other);
Ray compute_primary_ray(const int x, const int width,
const int y, const int height) const;
};

View file

@ -6,62 +6,137 @@
*/
#include <cstdio>
#include <unistd.h>
#include "basics.h"
#include "log.hh"
#include "light.h"
#include "material.h"
#include "object_sphere.h"
#include "object_plane.h"
//#include "object_plane.h"
#include "reader_yaml.hh"
#include "scene.h"
#include "writer_png.h"
const char *OUT_FILE = "charles_out.png";
#define LOG_NAME "ROOT"
#include "logModule.hh"
int verbosity = 0;
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 scene;
scene.get_ambient().set_intensity(1.0);
#if 0
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));
// 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);
Sphere *s1 = new Sphere(Vector3(0, 0.5, 2), 0.33);
Sphere *s2 = new Sphere(Vector3(-0.33, 0, 2), 0.33);
Sphere *s3 = new Sphere(Vector3(0.33, 0, 2), 0.33);
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);
// Make a plane
/*
Plane *p1 = new Plane(Vector3(0, 460, 400), Vector3(0, 1, 0.01));
p1->set_material(m1);
scene.add_shape(p1);
*/
#endif
PointLight *l1 = new PointLight(Vector3(0.0, 240.0, 100.0), Color::White, 1.0);
PointLight *l1 = new PointLight(Vector3(6.0, -4.0, 2), Color::White, 1.0);
scene.add_light(l1);
// Render.
std::string logFilename;
unsigned int logLevel = 0;
std::string outfile, infile;
int opt;
while ((opt = getopt(argc, (char *const *)argv, "hl:L:o: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 'o':
outfile = optarg;
break;
case 'v':
break;
}
}
/* 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. */
LOG_INFO << "Beginning render";
scene.render();
Writer *writer = new PNGWriter();
scene.write(*writer, OUT_FILE);
/* 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
View 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__ */

View file

@ -93,5 +93,20 @@ PointLight::PointLight(const Vector3 &o,
const Color &c,
const float &i)
: AmbientLight(c, i),
Object(o)
mOrigin(o)
{ }
const Vector3&
PointLight::GetOrigin()
const
{
return mOrigin;
}
void
PointLight::SetOrigin(const Vector3& origin)
{
mOrigin = origin;
}

View file

@ -9,7 +9,6 @@
#define __LIGHT_H__
#include "basics.h"
#include "object.h"
class AmbientLight
@ -35,14 +34,20 @@ private:
class PointLight
: public AmbientLight,
public Object
: public AmbientLight
{
public:
PointLight();
PointLight(const Vector3 &o);
PointLight(const Vector3 &o, const Color &c);
PointLight(const Vector3 &o, const Color &c, const float &i);
const Vector3& GetOrigin() const;
void SetOrigin(const Vector3& origin);
private:
Vector3 mOrigin;
};
#endif

119
src/log.cc Normal file
View 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
View 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
View 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__ */

View file

@ -8,78 +8,82 @@
#include "material.h"
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.5),
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()
const Color&
Material::GetDiffuseColor()
const
{
return diffuse_color;
return mDiffuseColor;
}
void
Material::set_diffuse_color(const Color &c)
Material::SetDiffuseColor(const Color& color)
{
diffuse_color = c;
mDiffuseColor = color;
}
float
Material::get_specular_level()
Double
Material::GetSpecularIntensity()
const
{
return specular_level;
return mSpecularIntensity;
}
void
Material::set_specular_level(const float &ks)
Material::SetSpecularIntensity(const Double& ks)
{
specular_level = ks;
_clamp_parameter(specular_level);
mSpecularIntensity = ks;
ClampParameter(mSpecularIntensity);
}
const Color &
Material::get_specular_color()
const Color&
Material::GetSpecularColor()
const
{
return specular_color;
return mSpecularColor;
}
void
Material::set_specular_color(const Color &c)
Material::SetSpecularColor(const Color& color)
{
specular_color = c;
mSpecularColor = color;
}
void
Material::_clamp_parameter(float &param)
Material::ClampParameter(Double& param)
{
if (param < 0.0) {
param = 0.0;
@ -88,3 +92,5 @@ Material::_clamp_parameter(float &param)
param = 1.0;
}
}
} /* namespace charles */

View file

@ -9,37 +9,49 @@
#define __MATERIAL_H__
#include "basics.h"
#include "types.hh"
namespace charles {
class Material
struct Material
{
public:
enum {
DiffuseLightingTypeLambert = 1,
} DiffuseLightingType;
enum class DiffuseShaderModel {
Lambert,
};
enum class SpecularShaderModel {
Blinn,
Phong
};
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);
Double GetDiffuseIntensity() const;
void SetDiffuseIntensity(const Double& kd);
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);
const Color& GetDiffuseColor() const;
void SetDiffuseColor(const Color& c);
Double GetSpecularIntensity() const;
void SetSpecularIntensity(const Double& kd);
const Color &GetSpecularColor() const;
void SetSpecularColor(const Color& c);
private:
void _clamp_parameter(float &param);
void ClampParameter(Double& param);
// Diffuse parameters.
float diffuse_level;
Color diffuse_color;
DiffuseShaderModel mDiffuseModel;
Double mDiffuseIntensity;
Color mDiffuseColor;
// Specular parameters.
float specular_level;
Color specular_color;
SpecularShaderModel mSpecularModel;
Double mSpecularIntensity;
Color mSpecularColor;
};
} /* namespace charles */
#endif

View file

@ -13,6 +13,8 @@
#include "material.h"
#include "object.h"
namespace charles {
#pragma mark - Objects
/*
@ -30,85 +32,42 @@ Object::Object()
*
* Constructor. Create a new Object with an origin at o.
*/
Object::Object(Vector3 o)
: origin(o)
Object::Object(Vector3 origin)
: mOrigin(origin),
mMaterial()
{ }
/*
* Object::get_origin --
* Object::set_origin --
*
* Get and set the Object's origin.
*/
Vector3
Object::get_origin()
Object::GetOrigin()
const
{
return origin;
return mOrigin;
}
Object::~Object()
{ }
void
Object::set_origin(Vector3 v)
Object::SetOrigin(const Vector3& origin)
{
origin = v;
mOrigin = origin;
}
std::ostream &
operator<<(std::ostream &os, const Object &o)
Material&
Object::GetMaterial()
{
// Stream objects like this: [Object origin]
os << "[Object " << o.origin << "]";
return os;
return mMaterial;
}
#pragma mark - Shapes
/*
* Shape::Shape --
*
* Default constructor. Create a new Shape with an origin at (0, 0, 0).
*/
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()
const
{
return *material;
}
void
Shape::set_material(Material *mat)
Object::SetMaterial(const Material& material)
{
material = mat;
mMaterial = material;
}
} /* namespace charles */

View file

@ -10,47 +10,50 @@
#define __OBJECT_H__
#include <iostream>
#include <memory>
#include <vector>
#include "basics.h"
#include "material.h"
#include "texture.h"
#include "types.hh"
namespace charles {
class Object
struct Object
{
public:
typedef std::shared_ptr<Object> Ptr;
Object();
Object(Vector3 o);
virtual ~Object();
Vector3 get_origin() const;
void set_origin(Vector3 v);
Vector3 GetOrigin() const;
void SetOrigin(const Vector3& origin);
friend std::ostream &operator<<(std::ostream &os, const Object &o);
Material& GetMaterial();
void SetMaterial(const Material& material);
private:
Vector3 origin;
};
std::ostream &operator<<(std::ostream &os, const Object &o);
class Shape
: public Object
{
public:
Shape();
Shape(Vector3 o);
virtual ~Shape();
Material &get_material() const;
void set_material(Material *mat);
virtual int does_intersect(const Ray &ray, float **t) const = 0;
/**
* Determines if the given ray intersects with this object. All intersection
* t values are returned in the `t` argument, in increasing order.
*
* @param [in] ray The ray to test for intersection
* @param [out] t A vector of all intersection t values
* @return `true` if the ray intersects with this object
*/
virtual bool DoesIntersect(const Ray& ray, TVector& t) const = 0;
virtual bool point_is_on_surface(const Vector3 &p) const = 0;
virtual Vector3 compute_normal(const Vector3 &p) const = 0;
private:
Material *material;
/** The location of this object. */
Vector3 mOrigin;
/** This object's material, surface properties, etc. */
Material mMaterial;
};
} /* namespace charles */
#endif

225
src/objectBox.cc Normal file
View file

@ -0,0 +1,225 @@
/* objectBox.cc
* vim: set tw=80:
* Eryn Wells <eryn@erynwells.me>
*/
#include <limits>
#include "objectBox.hh"
namespace charles {
Box::Box()
/* A unit box centered on the origin. */
: Box(Vector3(-0.5, -0.5, -0.5), Vector3(0.5, 0.5, 0.5))
{ }
Box::Box(const Vector3& near, const Vector3& far)
: Object(),
mNear(near),
mFar(far)
{ }
Vector3&
Box::GetNear()
{
return mNear;
}
void
Box::SetNear(const Vector3& near)
{
mNear = near;
}
Vector3&
Box::GetFar()
{
return mFar;
}
void
Box::SetFar(const Vector3& far)
{
mFar = far;
}
bool
Box::DoesIntersect(const Ray& ray,
TVector& t)
const
{
/*
* XXX: For now, I'm assuming that all boxes are parallel to the coordinate
* axes. This is the Kay-Kajiya box intersection algorithm.
*/
Double t0, t1;
Double tNear = -std::numeric_limits<Double>::infinity();
Double tFar = std::numeric_limits<Double>::infinity();
/*
* From the Ray Tracing book:
*
* For a more efficient algorithm, unwrap the loop, expand the swap of t0
* and t1 into two branches, and change the calculations to multiply by
* the inverse of the ray's direction to avoid divisions. Unwrapping the
* loop allows elimination of comparing t0 adn t1 to tNear and tFar [for
* the X planes], as tNear will always be set to the smaller and tFar the
* larger of t0 and t1.
*
* Initially there was a for loop iterating over each parallel pair of
* planes (X, Y, and Z planes).
*/
/*
* Unrolling the loop means lots of duplicated code. So we start with the X
* planes...
*/
if (ray.direction.x == 0.0) {
/* The ray is parallel to the X axis. */
if (ray.origin.x < mNear.x || ray.origin.x > mFar.x) {
/* The ray's origin is not between the slabs, so no intersection. */
return false;
}
} else {
Double invX = 1.0 / ray.direction.x;
t0 = (mNear.x - ray.origin.x) * invX;
t1 = (mFar.x - ray.origin.x) * invX;
if (t0 > t1) {
tNear = t1;
tFar = t0;
} else {
tNear = t0;
tFar = t1;
}
if (tNear > tFar) {
/* Box is missed. */
return false;
}
if (tFar < 0.0) {
/* Box is behind the ray. */
return false;
}
}
/* Now the Y planes. */
if (ray.direction.y == 0.0) {
/* The ray is parallel to the Y axis. */
if (ray.origin.y < mNear.y || ray.origin.y > mFar.y) {
/* The ray's origin is not between the slabs, so no intersection. */
return false;
}
} else {
/* The ray isn't parallel, so calculate the intersection points. */
Double invY = 1.0 / ray.direction.y;
t0 = (mNear.y - ray.origin.y) * invY;
t1 = (mFar.y - ray.origin.y) * invY;
if (t0 > t1) {
tNear = t1;
tFar = t0;
} else {
tNear = t0;
tFar = t1;
}
if (tNear > tFar) {
/* Box is missed. */
return false;
}
if (tFar < 0.0) {
/* Box is behind the ray. */
return false;
}
}
/* Finally, the Z planes. */
if (ray.direction.z == 0.0) {
/* The ray is parallel to the Z axis. */
if (ray.origin.z < mNear.z || ray.origin.z > mFar.z) {
/* The ray's origin is not between the slabs, so no intersection. */
return false;
}
} else {
Double invZ = 1.0 / ray.direction.z;
t0 = (mNear.z - ray.origin.z) * invZ;
t1 = (mFar.z - ray.origin.z) * invZ;
if (t0 > t1) {
tNear = t1;
tFar = t0;
} else {
tNear = t0;
tFar = t1;
}
if (tNear > tFar) {
/* Box is missed. */
return false;
}
if (tFar < 0.0) {
/* Box is behind the ray. */
return false;
}
}
/* We have an intersection! */
t.push_back(tNear);
t.push_back(tFar);
return true;
}
bool
Box::point_is_on_surface(const Vector3& p)
const
{
if (p.x == mNear.x || p.x == mFar.x) {
return (p.y > mNear.y && p.y < mFar.y)
&& (p.z > mNear.z && p.z < mFar.z);
} else if (p.y == mNear.y || p.y == mFar.y) {
return (p.x > mNear.x && p.x < mFar.x)
&& (p.z > mNear.z && p.z < mFar.z);
} else if (p.z == mNear.z || p.z == mFar.z) {
return (p.x > mNear.x && p.x < mFar.x)
&& (p.y > mNear.y && p.y < mFar.y);
}
return false;
}
Vector3
Box::compute_normal(const Vector3& p)
const
{
const Double EPS = 0.01;
if (abs(p.x - mNear.x) < EPS) {
return Vector3(-1, 0, 0);
} else if (abs(p.x - mFar.x) < EPS) {
return Vector3(1, 0, 0);
} else if (abs(p.y - mNear.y) < EPS) {
return Vector3(0, -1, 0);
} else if (abs(p.y - mFar.y) < EPS) {
return Vector3(0, 1, 0);
} else if (abs(p.z - mNear.z) < EPS) {
return Vector3(0, 0, -1);
} else if (abs(p.z - mFar.y) < EPS) {
return Vector3(0, 0, 1);
}
return Vector3();
}
} /* namespace charles */

36
src/objectBox.hh Normal file
View file

@ -0,0 +1,36 @@
/* objectBox.hh
* vim: set tw=80:
* Eryn Wells <eryn@erynwells.me>
*/
#include "basics.h"
#include "object.h"
#include "types.hh"
namespace charles {
struct Box
: public Object
{
Box();
Box(const Vector3& near, const Vector3& far);
Vector3& GetNear();
void SetNear(const Vector3& near);
Vector3& GetFar();
void SetFar(const Vector3& far);
bool DoesIntersect(const Ray& ray, TVector& t) const;
bool point_is_on_surface(const Vector3 &p) const;
Vector3 compute_normal(const Vector3 &p) const;
private:
/** The near, lower left corner. */
Vector3 mNear;
/** The far, upper right corner. */
Vector3 mFar;
};
} /* namespace charles */

View file

@ -14,6 +14,7 @@
#include "object.h"
#include "object_sphere.h"
namespace charles {
/*
* Sphere::Sphere --
@ -36,7 +37,7 @@ Sphere::Sphere(float r)
Sphere::Sphere(Vector3 o, float r)
: Shape(o),
: Object(o),
radius(r)
{ }
@ -61,69 +62,64 @@ Sphere::set_radius(float r)
/*
* Sphere::does_intersect --
*
* Compute the intersection of a ray with this Sphere. All intersection t values are returned in the **t argument. The
* number of values returned therein is indicated by the return value. Memory is allocated at *t. It is the caller's
* responsibility to free it when it is no longer needed. If 0 is returned, no memory needs to be freed.
* Sphere::DoesIntersect --
*/
int
Sphere::does_intersect(const Ray &ray, float **t)
bool
Sphere::DoesIntersect(const Ray& ray,
TVector& t)
const
{
// Origin of the vector in object space.
Vector3 ray_origin_obj = ray.origin - get_origin();
/* Origin of the vector in object space. */
Vector3 rayOriginObj = ray.origin - GetOrigin();
// Coefficients for quadratic equation.
float a = ray.direction.dot(ray.direction);
float b = ray.direction.dot(ray_origin_obj) * 2.0;
float c = ray_origin_obj.dot(ray_origin_obj) - (radius * radius);
/* Coefficients for quadratic equation. */
Double a = ray.direction.dot(ray.direction);
Double b = ray.direction.dot(rayOriginObj) * 2.0;
Double c = rayOriginObj.dot(rayOriginObj) - (radius * radius);
// Discriminant for the quadratic equation.
float discrim = (b * b) - (4.0 * a * c);
/* Discriminant for the quadratic equation. */
Double discrim = (b * b) - (4.0 * a * c);
// If the discriminant is less than zero, there are no real (as in not imaginary) solutions to this intersection.
/*
* If the discriminant is less than zero, there are no real (as in not
* imaginary) solutions to this intersection.
*/
if (discrim < 0) {
return 0;
}
// Compute the intersections, the roots of the quadratic equation. Spheres have at most two intersections.
float sqrt_discrim = sqrtf(discrim);
float t0 = (-b - sqrt_discrim) / (2.0 * a);
float t1 = (-b + sqrt_discrim) / (2.0 * a);
// If t[1] is less than t[0], swap them (t[0] will always be the first intersection).
if (t1 < t0) {
float tmp = t0;
t0 = t1;
t1 = tmp;
return false;
}
/*
* If the farther intersection of the two is in the negative direction, the sphere is in the ray's negative
* direction.
* Compute the intersections, the roots of the quadratic equation. Spheres
* have at most two intersections.
*/
Double sqrtDiscrim = sqrt(discrim);
Double t0 = (-b - sqrtDiscrim) / (2.0 * a);
Double t1 = (-b + sqrtDiscrim) / (2.0 * a);
/*
* If the farther intersection of the two is in the negative direction, the
* sphere is in the ray's negative direction.
*/
if (t1 < 0) {
return 0;
return false;
}
/*
* Allocate the memory and store the values. It's possible the two values are equal. Only allocate enough memory to
* store the required number of values.
*/
int nints = (t0 != t1) ? 2 : 1;
if (t != NULL) {
*t = new float[nints];
if (*t == NULL) {
return 0;
if (t0 == t1) {
t.push_back(t0);
}
else {
/* Push these on in ascending order, nearest intersection to farthest. */
if (t0 < t1) {
t.push_back(t0);
t.push_back(t1);
}
(*t)[0] = t0;
if (nints > 1) {
(*t)[1] = t1;
else {
t.push_back(t1);
t.push_back(t0);
}
}
return nints;
return true;
}
@ -136,7 +132,7 @@ bool
Sphere::point_is_on_surface(const Vector3 &p)
const
{
Vector3 o = get_origin();
Vector3 o = GetOrigin();
float x = p.x - o.x;
float y = p.y - o.y;
float z = p.z - o.z;
@ -156,7 +152,9 @@ Sphere::compute_normal(const Vector3 &p)
const
{
// The fun thing about sphere is the normal to any point on the sphere is the point itself. Woo!
Vector3 normal = p - get_origin();
Vector3 normal = p - GetOrigin();
normal.normalize();
return normal;
}
} /* namespace charles */

View file

@ -11,11 +11,14 @@
#include "basics.h"
#include "object.h"
namespace charles {
class Sphere
: public Shape
: public Object
{
public:
typedef std::shared_ptr<Sphere> Ptr;
Sphere();
Sphere(float r);
Sphere(Vector3 o, float r);
@ -23,11 +26,13 @@ public:
float get_radius();
void set_radius(float r);
int does_intersect(const Ray &ray, float **t) const;
bool DoesIntersect(const Ray& ray, TVector& t) const;
bool point_is_on_surface(const Vector3 &p) const;
Vector3 compute_normal(const Vector3 &p) const;
private:
float radius;
};
} /* namespace charles */
#endif

32
src/reader.hh Normal file
View file

@ -0,0 +1,32 @@
/* reader.hh
* vim: set tw=80:
* Eryn Wells <eryn@erynwells.me>
*/
/**
* Interface for an input file reader.
*/
#ifndef __READER_HH__
#define __READER_HH__
#include "scene.h"
struct Reader
{
Reader(Scene& scene)
: mScene(scene)
{ }
virtual
~Reader()
{ }
virtual ssize_t read_file(const std::string& filename) = 0;
protected:
Scene& mScene;
};
#endif /* __READER_HH__ */

154
src/reader_yaml.cc Normal file
View file

@ -0,0 +1,154 @@
/* reader_yaml.cc
* vim: set tw=80:
* Eryn Wells <eryn@erynwells.me>
*/
/**
* An input file reader for YAML files.
*/
#include <cstdio>
#include <cstdlib>
#include <stack>
#include <string>
#include "yaml.h"
#include "charles.hh"
#include "reader_yaml.hh"
#include "yaml/parsers.hh"
#include "yaml/sceneParser.hh"
#if 0
struct ObjectParser
: public Parser
{
ObjectParser(Scene& scene, ParserStack& parsers)
: Parser(scene, parsers),
mSection(NoSection)
{
printf("ObjectParser\n");
}
~ObjectParser()
{
printf("~ObjectParser\n");
}
void
handle_event(yaml_event_t& event)
{
switch (mSection) {
case NoSection:
break;
case TypeSection:
break;
case OriginSection:
break;
}
}
private:
enum {
NoSection,
TypeSection,
OriginSection,
} mSection;
};
#endif
ssize_t
YAMLReader::read_file(const std::string& filename)
{
FILE *yaml_infile = fopen(filename.c_str(), "rb");
if (!yaml_infile) {
fprintf(stderr, "Couldn't open file: %s\n", filename.c_str());
return -1;
}
yaml_parser_t parser;
yaml_parser_initialize(&parser);
printf("Reading %s\n", filename.c_str());
yaml_parser_set_input_file(&parser, yaml_infile);
yaml::ParserStack parsers;
bool success = true;
bool done = false;
bool sawDocument = false;
yaml_event_t event;
while (!done) {
if (!yaml_parser_parse(&parser, &event)) {
success = false;
goto error;
}
if (verbosity >= 4) {
switch (event.type) {
case YAML_NO_EVENT:
printf("YAML_NO_EVENT\n");
break;
case YAML_STREAM_START_EVENT:
printf("YAML_STREAM_START_EVENT\n");
break;
case YAML_STREAM_END_EVENT:
printf("YAML_STREAM_END_EVENT\n");
break;
case YAML_DOCUMENT_START_EVENT:
printf("YAML_DOCUMENT_START_EVENT\n");
break;
case YAML_DOCUMENT_END_EVENT:
printf("YAML_DOCUMENT_END_EVENT\n");
break;
case YAML_ALIAS_EVENT:
printf("YAML_ALIAS_EVENT\n");
break;
case YAML_SCALAR_EVENT:
printf("YAML_SCALAR_EVENT\n");
break;
case YAML_SEQUENCE_START_EVENT:
printf("YAML_SEQUENCE_START_EVENT\n");
break;
case YAML_SEQUENCE_END_EVENT:
printf("YAML_SEQUENCE_END_EVENT\n");
break;
case YAML_MAPPING_START_EVENT:
printf("YAML_MAPPING_START_EVENT\n");
break;
case YAML_MAPPING_END_EVENT:
printf("YAML_MAPPING_END_EVENT\n");
break;
}
}
if (event.type == YAML_DOCUMENT_START_EVENT) {
sawDocument = true;
parsers.push(new yaml::SceneParser(mScene, parsers));
}
else {
sawDocument = false;
if (!parsers.empty()) {
parsers.top()->HandleEvent(event);
if (parsers.top()->GetDone()) {
delete parsers.top();
parsers.pop();
}
}
}
done = (event.type == YAML_STREAM_END_EVENT);
yaml_event_delete(&event);
}
error:
yaml_parser_delete(&parser);
return success;
}

29
src/reader_yaml.hh Normal file
View file

@ -0,0 +1,29 @@
/* reader_yaml.hh
* vim: set tw=80:
* Eryn Wells <eryn@erynwells.me>
*/
/**
* An input file reader for YAML files.
*/
#ifndef __READER_YAML_HH__
#define __READER_YAML_HH__
#include "reader.hh"
#include "scene.h"
struct YAMLReader
: public Reader
{
YAMLReader(Scene& scene)
: Reader(scene)
{ }
~YAMLReader() { }
ssize_t read_file(const std::string& filename);
};
#endif /* __READER_YAML_HH__ */

View file

@ -11,32 +11,38 @@
#include "basics.h"
#include "light.h"
#include "log.hh"
#include "object.h"
#include "scene.h"
#include "writer.h"
#define LOG_NAME "scene"
#include "logModule.hh"
using namespace charles;
Scene::Scene()
: width(640), height(480),
mCamera(new PerspectiveCamera()),
max_depth(5),
min_weight(1e-4),
ambient(new AmbientLight()),
shapes(),
lights(),
nrays(0),
mStats(),
pixels(NULL)
{ }
Scene::~Scene()
{
mCamera.reset();
if (ambient != NULL) {
delete ambient;
}
for (Shape *s : shapes) {
delete s;
}
shapes.clear();
for (PointLight *l : lights) {
@ -75,6 +81,27 @@ Scene::get_height()
}
/*
* Scene::GetCamera --
*/
Camera::Ptr
Scene::GetCamera()
const
{
return mCamera;
}
/*
* Scene::SetCamera --
*/
void
Scene::SetCamera(Camera* camera)
{
mCamera.reset(camera);
}
AmbientLight &
Scene::get_ambient()
const
@ -121,30 +148,41 @@ Scene::write(Writer &writer, const std::string &filename)
void
Scene::render()
{
LOG_INFO << "Rendering scene with " << shapes.size() << " objects.";
printf("Rendering scene with %lu objects.\n", shapes.size());
std::chrono::time_point<std::chrono::system_clock> start, end;
start = std::chrono::system_clock::now();
pixels = new Color[width * height];
unsigned long numPrimaryRays = width * height;
Ray primary_ray;
Vector3 o, d;
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
// Assemble a ray and trace it.
o = Vector3(x, y, -1000);
d = Vector3(0, 0, 1);
d.normalize();
primary_ray = Ray(o, d);
mStats.primaryRays++;
printf("\rRendering pixels... (%ld/%ld) %3.0f%%",
mStats.primaryRays, numPrimaryRays,
((float)mStats.primaryRays / (float)numPrimaryRays) * 100);
primary_ray = mCamera->compute_primary_ray(x, width, y, height);
Color c = trace_ray(primary_ray);
pixels[y * width + x] = c;
}
}
printf("\n");
end = std::chrono::system_clock::now();
std::chrono::duration<float> seconds = end - start;
_is_rendered = true;
printf("Scene rendered. %d rays traced in %f seconds.\n", nrays, seconds.count());
printf("Rendering completed in %f seconds.\n\n", seconds.count());
LOG_INFO << "Rendering completed in " << seconds.count() << " seconds.";
mStats.PrintRayTable();
}
@ -154,7 +192,7 @@ Scene::render()
* Add a shape to the scene.
*/
void
Scene::add_shape(Shape *shape)
Scene::add_shape(Object::Ptr shape)
{
shapes.push_back(shape);
}
@ -187,38 +225,35 @@ Scene::trace_ray(const Ray &ray,
}
Color out_color = Color::Black;
Shape *intersected_shape = NULL;
float *t = NULL;
float nearest_t = INFINITY;
int nints;
Object::Ptr intersected_shape;
TVector ts;
Double nearest_t = INFINITY;
// Keep stats.
nrays++;
ts.reserve(2);
// Find intersections of this ray with objects in the scene.
for (Shape *s : shapes) {
nints = s->does_intersect(ray, &t);
if (nints > 0) {
for (int i = 0; i < nints; i++) {
if (t[i] < 1e-2) {
for (Object::Ptr s : shapes) {
ts.clear();
if (s->DoesIntersect(ray, ts)) {
for (Double t : ts) {
if (t < 1e-2) {
break;
}
if (t[i] < nearest_t) {
if (t < nearest_t) {
intersected_shape = s;
nearest_t = t[i];
nearest_t = t;
}
}
delete[] t;
}
}
// If there was no intersection, return black.
if (intersected_shape == NULL) {
if (!intersected_shape) {
return out_color;
}
Material shape_material = intersected_shape->get_material();
Color shape_color = shape_material.get_diffuse_color();
Material& shape_material = intersected_shape->GetMaterial();
const Color& shape_color = shape_material.GetDiffuseColor();
Vector3 intersection = ray.parameterize(nearest_t);
Vector3 normal = intersected_shape->compute_normal(intersection);
@ -228,29 +263,32 @@ Scene::trace_ray(const Ray &ray,
*/
Vector3 light_direction;
float ldotn, diffuse_level, ambient_level;
Double ldotn, diffuse_level, ambient_level;
Ray shadow_ray;
for (PointLight *l : lights) {
light_direction = (intersection - l->get_origin()).normalize();
light_direction = (intersection - l->GetOrigin()).normalize();
ldotn = light_direction.dot(normal);
if (ldotn < 0) {
ldotn = 0.0;
}
diffuse_level = shape_material.get_diffuse_level();
diffuse_level = shape_material.GetDiffuseIntensity();
ambient_level = 1.0 - diffuse_level;
shadow_ray = Ray(intersection, light_direction);
for (Shape *s : shapes) {
for (Object::Ptr s : shapes) {
// Skip the intersected shape.
if (s == intersected_shape) {
continue;
}
mStats.shadowRays++;
// Figure out if we're in shadow.
if (s->does_intersect(shadow_ray, NULL) > 0) {
ts.clear();
if (s->DoesIntersect(shadow_ray, ts)) {
diffuse_level = 0.0;
break;
}
@ -267,24 +305,65 @@ Scene::trace_ray(const Ray &ray,
* Specular lighting. (Reflections, etc.)
*/
float specular_level = shape_material.get_specular_level();
const Color &specular_color = shape_material.get_specular_color();
Double specular_level = shape_material.GetSpecularIntensity();
const Color& specular_color = shape_material.GetSpecularColor();
/*
* Compute the reflection ray. Computing the direction of the reflection ray is done by the following formula:
* Compute the reflection ray. Computing the direction of the reflection ray
* is done by the following formula:
*
* d = dr - 2n(dr . n)
*
* where d is the direction, dr is the direction of the incoming ray, and n is the normal vector. Period (.)
* indicates the dot product.
* where d is the direction, dr is the direction of the incoming ray, and n
* is the normal vector. Period (.) indicates the dot product.
*
* The origin of the reflection ray is the point on the surface where the incoming ray intersected with it.
* The origin of the reflection ray is the point on the surface where the
* incoming ray intersected with it.
*/
Ray reflection_ray = Ray(intersection, ray.direction - 2.0 * normal * ray.direction.dot(normal));
Color reflection_color = trace_ray(reflection_ray, depth + 1, weight * specular_level);
Ray reflection_ray = Ray(intersection,
ray.direction - 2.0 * normal * ray.direction.dot(normal));
mStats.reflectionRays++;
Color reflection_color = trace_ray(reflection_ray,
depth + 1,
weight * specular_level);
// TODO: Mix in specular_color of material.
out_color += specular_level * specular_color * reflection_color;
return out_color;
}
unsigned long
Scene::Stats::TotalRays()
const
{
return primaryRays + shadowRays + reflectionRays + transmissionRays;
}
void
Scene::Stats::PrintRayTable()
const
{
printf("RAY TYPE NUM %%\n");
printf("-------------- ---------- ------\n");
PrintRayRow("primary", primaryRays);
PrintRayRow("shadow", shadowRays);
PrintRayRow("reflection", reflectionRays);
PrintRayRow("transmission", transmissionRays);
PrintRayRow("total", TotalRays());
}
void
Scene::Stats::PrintRayRow(const std::string& title,
const unsigned long& value)
const
{
double totalRays = TotalRays();
printf("%-14s %10ld %#5.1lf%%\n",
title.c_str(),
value,
double(value) / totalRays * 100.0);
}

View file

@ -14,11 +14,12 @@
#include <list>
#include <string>
#include "basics.h"
#include "camera.h"
#include "object.h"
class AmbientLight;
class PointLight;
class Shape;
class Writer;
@ -29,8 +30,15 @@ public:
~Scene();
bool is_rendered() const;
int get_width() const;
void set_width(int w) { width = w; }
int get_height() const;
void set_height(int h) { height = h; }
Camera::Ptr GetCamera() const;
void SetCamera(Camera* camera);
AmbientLight &get_ambient() const;
const Color *get_pixels() const;
@ -38,7 +46,7 @@ public:
void write(Writer &writer, const std::string &filename);
void render();
void add_shape(Shape *obj);
void add_shape(charles::Object::Ptr obj);
void add_light(PointLight *light);
private:
@ -47,6 +55,8 @@ private:
// Pixel dimensions of the image.
int width, height;
Camera::Ptr mCamera;
/*
* Ray tracing parameters. max_depth indicates the maximum depth of the ray tree. min_weight indicates the minimum
* specular weight to apply before giving up.
@ -56,11 +66,25 @@ private:
// Scene objects.
AmbientLight *ambient;
std::list<Shape *> shapes;
std::list<charles::Object::Ptr> shapes;
std::list<PointLight *> lights;
// Rendering stats
unsigned int nrays;
struct Stats
{
unsigned long TotalRays() const;
void PrintRayTable() const;
unsigned long primaryRays;
unsigned long shadowRays;
unsigned long reflectionRays;
unsigned long transmissionRays;
private:
void PrintRayRow(const std::string& title,
const unsigned long& value) const;
} mStats;
// Rendering output.
bool _is_rendered;

23
src/types.hh Normal file
View file

@ -0,0 +1,23 @@
/* types.hh
* vim: set tw=80:
* Eryn Wells <eryn@erynwells.me>
*/
#ifndef __CHARLES_TYPES_HH__
#define __CHARLES_TYPES_HH__
#include <vector>
namespace charles {
/* Basic types */
typedef double Double;
typedef std::vector<Double> DoubleVector;
typedef DoubleVector TVector;
} /* namespace charles */
#endif /* __CHARLES_TYPES_HH__ */

View file

@ -104,6 +104,9 @@ PNGWriter::write_scene(const Scene &scene, const std::string &filename)
}
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-parameter"
/*
* png_user_error --
*
@ -113,9 +116,7 @@ PNGWriter::write_scene(const Scene &scene, const std::string &filename)
/* static */ void
png_user_error(png_structp png,
png_const_charp msg)
{
}
{ }
/*
@ -127,6 +128,6 @@ png_user_error(png_structp png,
/* static */ void
png_user_warning(png_structp png,
png_const_charp msg)
{
{ }
}
#pragma clang diagnostic pop

21
src/yaml/SConscript Normal file
View file

@ -0,0 +1,21 @@
# SConscript
# vim: set ft=python:
# Eryn Wells <eryn@erynwells.me>
Import('env')
files = [
'cameraParser.cc',
'objectParser.cc',
'parsers.cc',
'scalarMappingParser.cc',
'sceneParser.cc',
'vectorParser.cc'
]
objs = []
for f in files:
objs.append(env.Object(f))
Return('objs')

186
src/yaml/cameraParser.cc Normal file
View file

@ -0,0 +1,186 @@
/* camera_parser.cc
* vim: set tw=80:
* Eryn Wells <eryn@erynwells.me>
*/
#include <cassert>
#include "camera.h"
#include "yaml/cameraParser.hh"
#include "yaml/vectorParser.hh"
namespace yaml {
CameraParser::CameraParser(Scene& scene,
ParserStack& parsers)
: ScalarMappingParser(scene, parsers),
mCamera(new PerspectiveCamera()),
mSection(NoSection),
mType(TypePerspective)
{
GetScene().SetCamera(mCamera);
}
CameraParser::~CameraParser()
{ }
void
CameraParser::HandleKeyEvent(const std::string& key)
{
static const std::map<std::string, Section> sSections = {
{"direction", DirectionSection},
{"origin", OriginSection},
{"right", RightSection},
{"type", TypeSection},
{"up", UpSection},
};
if (sSections.count(key) > 0) {
mSection = sSections.at(key);
}
else {
mSection = NoSection;
}
}
void
CameraParser::HandleValueEvent(yaml_event_t& event)
{
switch (mSection) {
case DirectionSection:
HandleDirectionEvent(event);
break;
case OriginSection:
HandleOriginEvent(event);
break;
case RightSection:
HandleRightEvent(event);
break;
case TypeSection:
HandleTypeEvent(event);
break;
case UpSection:
HandleUpEvent(event);
break;
default:
assert(false);
break;
}
}
void
CameraParser::HandleDirectionEvent(yaml_event_t& event)
{
if (event.type != YAML_SEQUENCE_START_EVENT) {
/* TODO: Clean this up. */
assert(event.type != YAML_SEQUENCE_START_EVENT);
return;
}
auto onDone = [this](Vector3 origin) {
mCamera->set_direction(origin);
mSection = NoSection;
SetShouldExpectKey(true);
};
GetParsers().push(new Vector3Parser(GetScene(), GetParsers(), onDone));
}
void
CameraParser::HandleOriginEvent(yaml_event_t& event)
{
if (event.type != YAML_SEQUENCE_START_EVENT) {
/* TODO: Clean this up. */
assert(event.type != YAML_SEQUENCE_START_EVENT);
return;
}
auto onDone = [this](Vector3 origin) {
mCamera->SetOrigin(origin);
mSection = NoSection;
SetShouldExpectKey(true);
};
GetParsers().push(new Vector3Parser(GetScene(), GetParsers(), onDone));
}
void
CameraParser::HandleRightEvent(yaml_event_t& event)
{
if (event.type != YAML_SEQUENCE_START_EVENT) {
/* TODO: Clean this up. */
assert(event.type != YAML_SEQUENCE_START_EVENT);
return;
}
auto onDone = [this](Vector3 right) {
mCamera->SetRight(right);
mSection = NoSection;
SetShouldExpectKey(true);
};
GetParsers().push(new Vector3Parser(GetScene(), GetParsers(), onDone));
}
void
CameraParser::HandleTypeEvent(yaml_event_t& event)
{
if (event.type != YAML_SCALAR_EVENT) {
assert(event.type != YAML_SCALAR_EVENT);
return;
}
std::string value = std::string((char*)event.data.scalar.value,
event.data.scalar.length);
if (value == "perspective") {
if (mType == TypeOrthographic) {
Camera *newCamera = new PerspectiveCamera(*mCamera);
delete mCamera;
mCamera = newCamera;
GetScene().SetCamera(newCamera);
}
}
else if (value == "orthographic") {
if (mType == TypePerspective) {
Camera *newCamera = new OrthographicCamera(*mCamera);
delete mCamera;
mCamera = newCamera;
GetScene().SetCamera(newCamera);
}
}
else {
assert(false);
}
mSection = NoSection;
SetShouldExpectKey(true);
}
void
CameraParser::HandleUpEvent(yaml_event_t& event)
{
if (event.type != YAML_SEQUENCE_START_EVENT) {
/* TODO: Clean this up. */
assert(event.type != YAML_SEQUENCE_START_EVENT);
return;
}
auto onDone = [this](Vector3 origin) {
mCamera->SetUp(origin);
mSection = NoSection;
SetShouldExpectKey(true);
};
GetParsers().push(new Vector3Parser(GetScene(), GetParsers(), onDone));
}
} /* namespace yaml */

56
src/yaml/cameraParser.hh Normal file
View file

@ -0,0 +1,56 @@
/* camera_parser.hh
* vim: set tw=80:
* Eryn Wells <eryn@erynwells.me>
*/
#ifndef __YAML_CAMERAPARSER_HH__
#define __YAML_CAMERAPARSER_HH__
#include "yaml/scalarMappingParser.hh"
struct Camera;
namespace yaml {
struct CameraParser
: public ScalarMappingParser
{
CameraParser(Scene& scene, ParserStack& parsers);
~CameraParser();
protected:
void HandleKeyEvent(const std::string& key);
void HandleValueEvent(yaml_event_t& event);
private:
enum Section {
NoSection,
DirectionSection,
OriginSection,
RightSection,
TypeSection,
UpSection
};
enum Type {
TypePerspective,
TypeOrthographic
};
void HandleDirectionEvent(yaml_event_t& event);
void HandleOriginEvent(yaml_event_t& event);
void HandleRightEvent(yaml_event_t& event);
void HandleTypeEvent(yaml_event_t& event);
void HandleUpEvent(yaml_event_t& event);
Camera *mCamera;
Section mSection;
Type mType;
};
} /* namespace yaml */
#endif /* __YAML_CAMERAPARSER_HH__ */

214
src/yaml/objectParser.cc Normal file
View file

@ -0,0 +1,214 @@
/* object_parser.cc
* vim: set tw=80:
* Eryn Wells <eryn@erynwells.me>
*/
/**
* Implementation of ObjectParser.
*/
#include <cassert>
#include <string>
#include <vector>
#include "material.h"
#include "object.h"
#include "objectBox.hh"
#include "object_sphere.h"
#include "yaml/objectParser.hh"
#include "yaml/vectorParser.hh"
using namespace charles;
namespace yaml {
ObjectParser::ObjectParser(Scene& scene,
ParserStack& parsers,
const std::string& tag)
: ScalarMappingParser(scene, parsers),
mObject(nullptr),
mSection(NoSection)
{
if (tag == "!Object.Box") {
mType = Type::Box;
mObject.reset(new Box());
} else if (tag == "!Object.Sphere") {
mType = Type::Sphere;
mObject.reset(new Sphere());
} else {
assert(false);
}
GetScene().add_shape(mObject);
}
ObjectParser::~ObjectParser()
{
mObject.reset();
}
void
ObjectParser::HandleKeyEvent(const std::string& key)
{
static const std::map<std::string, Section> sCommonSections = {
{"color", ColorSection}
};
static const std::map<std::string, Section> sSphereSections = {
{"origin", OriginSection},
{"radius", RadiusSection}
};
static const std::map<std::string, Section> sBoxSections = {
{"near", NearSection},
{"far", FarSection}
};
if (sCommonSections.count(key) > 0) {
mSection = sCommonSections.at(key);
return;
}
if (mType == Type::Box) {
if (sBoxSections.count(key) > 0) {
mSection = sBoxSections.at(key);
} else {
mSection = NoSection;
}
} else if (mType == Type::Sphere) {
if (sSphereSections.count(key) > 0) {
mSection = sSphereSections.at(key);
} else {
mSection = NoSection;
}
} else {
assert(false);
}
}
void
ObjectParser::HandleValueEvent(yaml_event_t& event)
{
switch (mSection) {
case ColorSection:
HandleColorEvent(event);
break;
case OriginSection:
HandleOriginEvent(event);
break;
case RadiusSection:
HandleRadiusEvent(event);
break;
case NearSection:
HandleNearEvent(event);
break;
case FarSection:
HandleFarEvent(event);
break;
default:
assert(false);
break;
}
}
void
ObjectParser::HandleColorEvent(yaml_event_t& event)
{
if (event.type != YAML_SEQUENCE_START_EVENT) {
/* TODO: Clean this up. */
assert(event.type != YAML_SEQUENCE_START_EVENT);
return;
}
auto onDone = [this](Color color) {
mObject->GetMaterial().SetDiffuseColor(color);
mSection = NoSection;
SetShouldExpectKey(true);
};
GetParsers().push(new ColorParser(GetScene(), GetParsers(), onDone));
}
void
ObjectParser::HandleOriginEvent(yaml_event_t& event)
{
if (event.type != YAML_SEQUENCE_START_EVENT) {
/* TODO: Clean this up. */
assert(event.type != YAML_SEQUENCE_START_EVENT);
return;
}
auto onDone = [this](Vector3 origin) {
mObject->SetOrigin(origin);
mSection = NoSection;
SetShouldExpectKey(true);
};
GetParsers().push(new Vector3Parser(GetScene(), GetParsers(), onDone));
}
void
ObjectParser::HandleRadiusEvent(yaml_event_t& event)
{
if (event.type != YAML_SCALAR_EVENT) {
/* TODO: Clean this up. */
assert(false);
}
double radius;
std::string scalar((char *)event.data.scalar.value,
event.data.scalar.length);
if (!ParseScalar<double>(scalar, radius)) {
/* TODO: Clean this up. */
assert(false);
}
std::dynamic_pointer_cast<Sphere>(mObject)->set_radius(radius);
mSection = NoSection;
SetShouldExpectKey(true);
}
void
ObjectParser::HandleNearEvent(yaml_event_t& event)
{
if (event.type != YAML_SEQUENCE_START_EVENT) {
/* TODO: Clean this up. */
assert(event.type != YAML_SEQUENCE_START_EVENT);
return;
}
auto onDone = [this](Vector3 near) {
std::dynamic_pointer_cast<Box>(mObject)->SetNear(near);
mSection = NoSection;
SetShouldExpectKey(true);
};
GetParsers().push(new Vector3Parser(GetScene(), GetParsers(), onDone));
}
void
ObjectParser::HandleFarEvent(yaml_event_t& event)
{
if (event.type != YAML_SEQUENCE_START_EVENT) {
/* TODO: Clean this up. */
assert(event.type != YAML_SEQUENCE_START_EVENT);
return;
}
auto onDone = [this](Vector3 far) {
std::dynamic_pointer_cast<Box>(mObject)->SetFar(far);
mSection = NoSection;
SetShouldExpectKey(true);
};
GetParsers().push(new Vector3Parser(GetScene(), GetParsers(), onDone));
}
} /* namespace yaml */

63
src/yaml/objectParser.hh Normal file
View file

@ -0,0 +1,63 @@
/* object_parser.hh
* vim: set tw=80:
* Eryn Wells <eryn@erynwells.me>
*/
/**
* An ObjectParser parses objects of various sorts.
*/
#ifndef __YAML_OBJECTPARSER_HH__
#define __YAML_OBJECTPARSER_HH__
#include "object_sphere.h"
#include "yaml/parsers.hh"
#include "yaml/scalarMappingParser.hh"
namespace yaml {
struct ObjectParser
: public ScalarMappingParser
{
ObjectParser(Scene& scene, ParserStack& parsers, const std::string& tag);
~ObjectParser();
protected:
void HandleKeyEvent(const std::string& key);
void HandleValueEvent(yaml_event_t& event);
private:
enum class Type {
Box,
Sphere
};
enum Section {
NoSection,
ColorSection,
/* Sphere sections */
OriginSection,
RadiusSection,
/* Box sections */
NearSection,
FarSection
};
void HandleColorEvent(yaml_event_t& event);
void HandleOriginEvent(yaml_event_t& event);
void HandleRadiusEvent(yaml_event_t& event);
void HandleNearEvent(yaml_event_t& event);
void HandleFarEvent(yaml_event_t& event);
charles::Object::Ptr mObject;
Type mType;
Section mSection;
};
} /* namespace yaml */
#endif /* __YAML_OBJECTPARSER_HH__ */

83
src/yaml/parsers.cc Normal file
View file

@ -0,0 +1,83 @@
/* parsers.cc
* vim: set tw=80:
* Eryn Wells <eryn@erynwells.me>
*/
/**
* YAML parser superclasses.
*/
#include <cassert>
#include "yaml.h"
#include "parsers.hh"
namespace yaml {
#pragma mark Parser
Parser::Parser(Scene& scene,
ParserStack& parsers)
: mScene(scene),
mParsers(parsers),
mDone(false)
{ }
Parser::~Parser()
{ }
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-parameter"
void
Parser::HandleEvent(yaml_event_t& event)
{
/* Shouldn't ever get here. */
assert(false);
}
#pragma clang diagnostic pop
void
Parser::SetDone(bool done)
{
mDone = done;
}
bool
Parser::GetDone()
const
{
return mDone;
}
Scene&
Parser::GetScene()
const
{
return mScene;
}
ParserStack&
Parser::GetParsers()
const
{
return mParsers;
}
#pragma mark ParseScalar
template<>
const char* ScalarParserTraits<int>::fmt = "%d";
template<>
const char* ScalarParserTraits<double>::fmt = "%lf";
} /* namespace yaml */

148
src/yaml/parsers.hh Normal file
View file

@ -0,0 +1,148 @@
/* parsers.hh
* vim: set tw=80:
* Eryn Wells <eryn@erynwells.me>
*/
/**
* Some top-level YAML parser objects.
*/
#ifndef __YAML_PARSERS_HH__
#define __YAML_PARSERS_HH__
#include <functional>
#include <stack>
#include <sstream>
#include "yaml.h"
#include "scene.h"
namespace yaml {
struct Parser;
typedef std::stack<Parser*> ParserStack;
/**
* A Parser handles parsing a chunk of YAML, updating its mScene member as
* necessary.
*/
struct Parser
{
/** Constructor */
Parser(Scene& scene, ParserStack& parsers);
/** Destructor */
virtual ~Parser();
/**
* Called by the parser event loop to handle a libyaml parser event.
*
* @param [in] event A libyaml parser event object
*/
virtual void HandleEvent(yaml_event_t& event);
/** Set the done flag. */
void SetDone(bool done);
/**
* Returns true if the parser is done parsing.
*
* @returns `true` if done, `false` if not
*/
bool GetDone() const;
protected:
Scene& GetScene() const;
ParserStack& GetParsers() const;
private:
/** The Scene being described by the YAML this parser is parsing. */
Scene& mScene;
/** The stack of parsers. */
ParserStack& mParsers;
/** `true` if the parser is done parsing */
bool mDone;
};
/**
* UtilityParsers handle small reusable bits of YAML. Their constructors take a
* C++11 lambda, which will be called back with the result of the parsed data.
*/
template<typename T>
struct UtilityParser
: public Parser
{
typedef std::function<void (T)> CallbackFunction;
UtilityParser(Scene& scene,
ParserStack& parsers)
: Parser(scene, parsers),
mCallback()
{ }
UtilityParser(Scene& scene,
ParserStack& parsers,
CallbackFunction callback)
: Parser(scene, parsers),
mCallback(callback)
{ }
virtual
~UtilityParser()
{ }
void
Notify(T value)
{
if (mCallback) {
mCallback(value);
}
}
void
SetCallback(CallbackFunction callback)
{
mCallback = callback;
}
private:
CallbackFunction mCallback;
};
/**
* Defines traits for the ParseScalar function. In particular, defines the
* format strings for supported scalar types.
*/
template<typename T>
struct ScalarParserTraits
{
static const char* fmt;
};
/**
* Parse a YAML scalar value into a native datatype.
*
* @param [in] scalar The YAML scalar value
* @param [out] value The parsed value of the scalar value
* @return `true` if the conversion succeeded
*/
template<typename T>
bool
ParseScalar(const std::string& scalar,
T& value)
{
std::stringstream s(scalar);
return (bool)(s >> value);
}
} /* namespace yaml */
#endif /* __YAML_PARSERS_HH__ */

View file

@ -0,0 +1,85 @@
/* scalarMappingParser.cc
* vim: set tw=80:
* Eryn Wells <eryn@erynwells.me>
*/
/**
* Implementation of ScalarMappingParser.
*/
#include <cassert>
#include <cstdio>
#include "scalarMappingParser.hh"
namespace yaml {
ScalarMappingParser::ScalarMappingParser(Scene& scene,
ParserStack& parsers)
: Parser(scene, parsers),
mShouldExpectKey(true)
{ }
ScalarMappingParser::~ScalarMappingParser()
{ }
void
ScalarMappingParser::HandleEvent(yaml_event_t& event)
{
if (mShouldExpectKey && event.type == YAML_MAPPING_START_EVENT) {
return;
}
else if (mShouldExpectKey && event.type == YAML_MAPPING_END_EVENT) {
SetDone(true);
return;
}
if (mShouldExpectKey && event.type == YAML_SCALAR_EVENT) {
HandleKeyEvent(std::string((char*)event.data.scalar.value,
event.data.scalar.length));
mShouldExpectKey = false;
}
else {
HandleValueEvent(event);
}
}
#pragma mark key/value handling
void
ScalarMappingParser::HandleKeyEvent(const std::string& key)
{
printf("%s: key = %s\n", __PRETTY_FUNCTION__, key.c_str());
assert(false);
}
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-parameter"
void
ScalarMappingParser::HandleValueEvent(yaml_event_t& event)
{
assert(false);
}
#pragma clang diagnostic pop
void
ScalarMappingParser::SetShouldExpectKey(bool shouldExpectKey)
{
mShouldExpectKey = shouldExpectKey;
}
bool
ScalarMappingParser::GetShouldExpectKey()
const
{
return mShouldExpectKey;
}
} /* namespace yaml */

Some files were not shown because too many files have changed in this diff Show more