Compare commits

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

311 commits

Author SHA1 Message Date
7d4acc28e4 Add a scene file with some vector expressions
Something for yamldumper to munch on. No actual vectors variables defined yet, though.
2014-08-22 07:34:42 -07:00
291d4a6831 [yamldumper] Print the scalar value 2014-08-21 09:02:11 -07:00
5bcefd128c Print time it took to parse scene file 2014-08-20 10:36:49 -07:00
36a7954df4 Add yamldumper utility
Just dumps YAML parser events to the console. Handy for a few things I'm pondering...
2014-08-20 10:36:34 -07:00
1e73d839f3 Get rid of some dead code in reader_yaml.cc 2014-08-20 10:08:08 -07:00
0ab3e17467 Objects need to be translated by their negation
Translating by the negation of the given vector puts them in the right place from the ray's perspective. Without the negation, things are mirrored.
2014-08-20 10:06:22 -07:00
301f5ff9aa Use ToObjectSpace and FromObjectSpace for ray components 2014-08-20 10:05:17 -07:00
07e75c663d Convert normal from object to world space
Properly doing this is a bit more complicated because it has to be normalized and pointing in the right direction. Just applying the inverse of the transform matrix doesn't quite do it.
2014-08-20 10:04:38 -07:00
cb0933ab51 threeSpheres.yml should be 800x600 2014-08-18 09:04:40 -07:00
6706623d6f Manually initialize Vector4 instead of using bzero 2014-08-18 09:04:26 -07:00
df5e4fe049 Initialize Camera::mOrigin
Whoops...
2014-08-18 09:04:11 -07:00
7c12a8bc2b Return a Color by value from Light::Contribution() 2014-08-18 09:02:13 -07:00
917b74003a Declare overrides for Box methods 2014-08-16 20:45:06 -07:00
db2804ac17 Merge branch 'feature/transform-matrix' into develop 2014-08-16 20:36:35 -07:00
0a43eb81aa Explicitly declare overrides in Sphere 2014-08-16 20:36:02 -07:00
791fdaa14a Use the Vector4 version of Matrix4::Translation for object origins 2014-08-16 20:35:49 -07:00
d518d282d4 Notes in Matrix4 about using std::copy
Not entirely sure what it does, but it's standard C++… :shrugs:
2014-08-16 20:35:01 -07:00
10195c607c operator<< for pretty-printing an entire Matrix4 2014-08-16 16:57:58 -07:00
09c5e29f63 Add a vector translation multiplication test 2014-08-16 16:57:08 -07:00
22297da809 Add includes to testObject.cc
No unit tests for objects yet...
2014-08-16 16:56:53 -07:00
8460f2205e Remake test_object -> testObject.cc
This was a *really* old class...
2014-08-16 08:54:33 -07:00
3a846ec282 Add -n option for "should render" 2014-08-16 08:52:40 -07:00
7e3cc3c3ed Copy properties of log tracer
The log tracer needs to copy its parameters, otherwise weird things happen.
2014-08-16 08:33:12 -07:00
dc6efc5e65 Fix up Transposed -> Tranpose in unit tests 2014-08-16 00:44:07 -07:00
c45d698424 Get a column vector of a matrix 2014-08-16 00:43:43 -07:00
1daf1619ef A few more objects for the oneBox scene -- it's not really one box anymore 2014-08-15 22:33:52 -07:00
050d87bd6f Place an object by its origin (only applies to spheres) 2014-08-15 22:33:34 -07:00
bbbac6ff92 Fix up Object object space conversions
- Ray directions shouldn't be translated
- Implement vector translation to global space
2014-08-15 22:33:22 -07:00
8af03c3f3d Implement Object::Place
Places the object by manipulating its translation matrix.
2014-08-15 22:32:44 -07:00
09ea4c2bc3 Mostly default Doxyfile 2014-08-13 09:04:11 -07:00
97b37d3c53 Just little tweaks
Mostly style, also the name of the Transposed() function -> Transpose().
2014-08-11 07:58:47 -07:00
56fff1178e ToObjectSpace copies the Ray anyway, so pass by value 2014-08-10 16:58:05 -07:00
4d4dc91ff4 Add Matrix4 Inverse and Transpose
Transpose is easy, with a bool flag to determine whether to access elements in row-major or column-major format. Inverse is more difficult, so this change only does translation inverses.
2014-08-10 16:57:34 -07:00
5b25b402c7 Merge branch 'matrix4' into feature/transform-matrix 2014-08-10 11:39:56 -07:00
dd36ab6fe1 Fill in missing Matrix4 symbols 2014-08-10 11:39:25 -07:00
51fbba95e7 Rename some matrix tests 2014-08-10 11:39:05 -07:00
620d5a5bc6 Fill in missing Vector4 symbols
Add assignment and call operators, bool operators, etc
2014-08-10 11:38:55 -07:00
49d097a803 Get rid of Matrix<N,M>, just use Matrix4 2014-08-10 10:51:12 -07:00
30d0570010 Add TooFar to util.hh 2014-08-10 10:49:45 -07:00
990d2b4c11 Add basics/util.hh
A place for NearZero, etc
2014-08-10 10:48:54 -07:00
74bbc87610 Trying to get this copy/move thing right between matrices and vectors 2014-08-10 09:42:02 -07:00
96f782c4ac Add tests for matrix multiplication
By identity matrix
With vectors
2014-08-10 09:41:48 -07:00
a5f451a120 Basics unit tests found some bugs! 2014-08-09 22:00:54 -07:00
1f01de6393 Remove VectorParser and ColorParser destructors
They weren't being used.
2014-08-09 22:00:43 -07:00
505a77d0e2 LOG_TRACE YAML events 2014-08-09 22:00:23 -07:00
c90c545f40 Define color constants 2014-08-09 21:30:28 -07:00
bf91fff5a2 More compiler fixups 2014-08-09 21:23:11 -07:00
43c8bd95c6 Remove basics.cc from the build 2014-08-09 21:22:40 -07:00
a97e7a6d2e Lights get virtual destructor and correct types 2014-08-09 21:22:12 -07:00
bb789476b6 New basics gets the remainder of the stuff from old basics
EPSILON, MAX_DISTANCE, NearZeor, NearlyEqual, TooFar.
2014-08-09 21:21:57 -07:00
6c23fa9f32 Get rid of the old basics! 2014-08-09 21:21:27 -07:00
ef9b9d04c8 Put all the parsers in the charles namespace 2014-08-09 20:53:04 -07:00
b7a9f07d5e Lots of little niggling compiler errors 2014-08-09 20:46:26 -07:00
3a8c955796 Put the readers and writers in charles namespace 2014-08-09 20:46:14 -07:00
84cb27fa6f Allow passing intensity in PointLight constructor 2014-08-09 20:45:45 -07:00
c3da70cdd9 Clean up some dependencies between scene, material, and color 2014-08-09 20:34:23 -07:00
48e35dfc81 Update material.{cc,hh} 2014-08-09 20:31:18 -07:00
42bef33775 Get rid of Color implementation in old basics.cc 2014-08-09 20:24:45 -07:00
b001ad2cf2 light.hh include in scene.hh 2014-08-09 20:24:18 -07:00
f6680f993f Clean up includes and old code in charles.cc 2014-08-09 20:24:11 -07:00
161a635ab5 reader.hh
Fix up includes, put it in charles namespace
2014-08-09 20:24:00 -07:00
080ee0d580 Remove Color and Vector3 from old basics 2014-08-09 20:23:23 -07:00
3c3e707922 Light has a shared_ptr type, and an overridable Contribution() 2014-08-09 20:23:08 -07:00
acdfb0fb60 Add PointLight in lightPoint.cc 2014-08-09 20:22:35 -07:00
e1ded8a9ad Clean up for Lights (and AmbientLights) 2014-08-09 20:04:42 -07:00
d085a192e8 Clean up basics::Color 2014-08-09 19:39:41 -07:00
4b396cabe8 Move Color over to basics 2014-08-09 19:30:47 -07:00
47ae52ed05 Woo Scene updates... 2014-08-09 12:26:12 -07:00
c49457a817 Implement Normalized, LinearCombination, and operator<< on Vector4s 2014-08-09 11:55:10 -07:00
9645a09a6c So much clean up for cameras 2014-08-09 11:26:17 -07:00
d10d219eb3 Comment out old Ray 2014-08-09 11:04:26 -07:00
19dfb66301 Cleanup for Spheres 2014-08-09 11:04:17 -07:00
590f10a756 Updates for Plane 2014-08-09 10:58:30 -07:00
392871a1ee Updates for Box 2014-08-09 10:54:00 -07:00
70576c382a Do all the clean up needed for Object 2014-08-09 10:42:49 -07:00
2c2bf09140 Compiler errors in Box::DoIntersect, hidden until now... 2014-08-09 10:11:44 -07:00
217c4709aa Vector4's constructor takes default arguments 2014-08-09 10:08:44 -07:00
baf40143b2 DoIntersect is an abstract method 2014-08-09 10:08:29 -07:00
3846a1aa3a Move Box intersection code to DoIntersect 2014-08-09 10:08:21 -07:00
d0d667d6d2 Object::Intersect
A new intersect method that converts to object space before doing the intersection. Now all objects are at their own origin!
2014-08-09 09:59:00 -07:00
519eb347d1 Vector4 constructor from Matrix<4,1> 2014-08-09 09:57:35 -07:00
43cb182aa7 Have to use operator() for Matrix<>::operator*
Matrix<N,P> is a different class from Matrix<N,M> so Matrix<N,M> can't access protected member data on Matrix<N,P>. There must be a better way that having to do the multiplies requires for operator().
2014-08-09 09:57:09 -07:00
9aa557293a A Ray class in basics! 2014-08-09 09:33:22 -07:00
b41cdb7186 Vector4 +, -, negation, and *
+, -, and negation were easy. Multiplication is wacky because the Matrix class does it. So, to do binary * (not *=) I needed to dynamic_cast the resulting Matrix<4,1> to a Vector4&&.
2014-08-09 09:32:48 -07:00
a3d51f7cf3 TranslationMatrix() is not static 2014-08-09 09:02:04 -07:00
9b6b6a20b7 Const versions of Vector4's X(), Y(), and Z() 2014-08-09 09:01:52 -07:00
584d0326a9 Get rid of object's origin 2014-08-09 08:59:11 -07:00
ab9ac5e963 Clean up constructors for Object and Sphere
Use default arguments instead of multiple constructors. I forgot about those! Use Vector4s all around.
2014-08-09 08:57:41 -07:00
8ccfbc0498 Scalar multiplication Doxygen group 2014-08-09 08:31:37 -07:00
cf57dfc51a I give up on Normalization
Compiler was complaining about casting between Vector4 and Matrix<4,1> so I just did the division by hand.

I bet operator* and operator/ are broken for Vector4s as well...
2014-08-09 08:31:25 -07:00
32292a45fa Move EPSILON and MAX_DISTANCE back to basics.h 2014-08-09 08:30:29 -07:00
fa3708edfb Implement a bunch of the useful Vector operations 2014-08-08 23:05:38 -07:00
9b076f1533 Implement more robust * and / for Matrix 2014-08-08 23:05:24 -07:00
be15d553f1 Move EPSILON and MAX_DISTANCE to basics/basics.hh 2014-08-08 23:04:52 -07:00
abd38169b1 Comment out all the old Matrix4 stuff 2014-08-08 22:14:36 -07:00
b59b6d85c0 Add Matrix4, implement TranslationMatrix() 2014-08-08 22:14:20 -07:00
9474153736 Move Zero() and Identity() definitions to the right place 2014-08-08 22:13:51 -07:00
2cadffd7d4 Fix Vector4 constructors and clean up compiler errors 2014-08-08 21:47:44 -07:00
3bf72bd78d Build basics! 2014-08-08 21:12:44 -07:00
da127ccde3 Vector4 subclass instead of typedef 2014-08-08 21:12:37 -07:00
2b9fec5d82 Const operator== 2014-08-08 21:12:18 -07:00
bfd3b8cbce uint –> UInt 2014-08-08 21:12:06 -07:00
3b713856db Vector, a single-column Matrix 2014-08-08 20:44:43 -07:00
c5b9d73a96 Add constructors and operator== to Matrix<> 2014-08-08 20:44:31 -07:00
a9c8d84ac2 Top-level include for basics 2014-08-08 17:38:13 -07:00
064ee2e4f1 Include <vector> in basics types.hh 2014-08-08 17:38:05 -07:00
32b52ace93 Templated matrix class 2014-08-08 17:35:34 -07:00
a955106d18 Implement a Matrix4 class
A 4x4 matrix that implements matrix multiplication and multiplication by
scalars. Some unit tests too, to test that this stuff works.
2014-08-07 22:12:53 -07:00
d4f661075d A few more objects for the oneBox scene -- it's not really one box anymore 2014-08-06 20:46:35 -07:00
c380a3c3cd Ignore .DS_Store files 2014-08-04 07:09:42 -07:00
14db2752ae Log where the camera is looking 2014-08-03 20:13:00 -07:00
589b1f23ec Camera GetTypeString and WriteType declarations 2014-08-03 20:12:40 -07:00
781c8cbe9f Log camera before logging scene objects 2014-08-03 20:12:10 -07:00
08bd04d8da Fancier way of logging the camera's parameters 2014-08-03 20:12:00 -07:00
5ac721d601 Lots of comments about what LookAt is doing 2014-08-03 20:11:22 -07:00
c2a4372467 Add Camera::IsLeftHanded()
A method that returns true if the camera's coordinate system is left-handed.
2014-08-03 20:10:52 -07:00
a7020545c1 New header comment for camera.cc 2014-08-03 19:10:43 -07:00
f99608085e Log the camera before rendering
Implement an operator<< for Cameras. Log the scene's camera.
2014-08-03 19:10:31 -07:00
bcf93bb4ce LookAt comments 2014-08-03 18:51:49 -07:00
0df6244b8b Bit of code clean up in LookAt 2014-08-03 18:51:41 -07:00
7297bc5c17 Add Camera::LookAt
This is identical to the POV-Ray look_at keyword for cameras. In fact, I stole the code almost directly from them… It's super handy for panning and tilting the camera towards a particular point, and saves me having to do dubiously accurate direction vector calculations by hand.

I still need to figure out what exactly this math is doing.
2014-08-03 18:34:00 -07:00
e64b9403ac Log some extra spaces when logging scene objects 2014-08-03 17:38:22 -07:00
b1c818ac20 Modernize object_sphere
Rename files objectSphere. Clean up dependencies.
2014-08-03 17:35:12 -07:00
a0fbecf483 Log all objects before starting the render 2014-08-03 17:25:25 -07:00
4828cb313f Add Write methods to scene objects
Write methods are polymorphic, overridden by subclasses. There is a single operator<< for Objects that calls the right Write() method for the object. Neat.
2014-08-03 17:25:00 -07:00
b56bbf4ced Root logger is called "ROOT" not "root" 2014-08-03 17:02:25 -07:00
ecc6c1efcd TODO about raising an error for non-intersecting normals 2014-08-03 16:37:03 -07:00
92e67215b9 Get rid of commented out Box intersection code 2014-08-03 16:36:12 -07:00
556e13ae74 I was a little to hasty with this clean up
I actually need this check to get the closest shape for intersection.
2014-08-03 13:05:22 -07:00
4cbe9df324 Legacy code clean up for t values
Intersection methods push values into the t vector in ascending order, so no need to check them in TraceRay.
2014-08-03 12:46:14 -07:00
2ade996783 p.z comparison was comparing against mFar.y 2014-08-03 12:45:34 -07:00
6f4d91af01 Ray parameterization takes a Double 2014-08-03 12:44:53 -07:00
b1d18a124f Move the oneBox camera to see the angles 2014-08-03 12:24:15 -07:00
d79c95be71 Playing with the implementation of slab intersection
This stuff is commented out anyway because it all moved to IntersectSlab...
2014-08-03 12:23:59 -07:00
3ce6987d78 Add the declaration of Box::IntersectSlab 2014-08-03 12:23:19 -07:00
8831dec40c Use NearlyEqual in Box::compute_normal 2014-08-03 12:23:05 -07:00
ecb15470ac Some tweaks to floating point utility methods
- Implement NearlyEqual
- NearZero and TooFar take const Double&
- NearZero and NearlyEqual are templated to take Double& and Double&& (and anything else that can be subtracted and/or passed into std::fabs.
2014-08-03 12:22:30 -07:00
8d5dfe5154 Move slab intersection to Box::IntersectSlab
Makes it easier to debug because I don't have to change things in three places.

This change also includes the fix! The swap was the problem. I didn't have the optimization right. I'll have to go back and figure it out.
2014-08-03 12:20:48 -07:00
8275c9baee Update header for basics.h 2014-08-03 12:18:53 -07:00
dc1849a786 Test reverse subtraction (v2 - v1) 2014-08-03 10:51:38 -07:00
467edaf02b planeSphere scene: move some stuff around
To get a better view of where things are supposed to be.
2014-08-03 08:18:13 -07:00
6dcb9dd37f The problem was this one subtraction. Seriously. 2014-08-02 23:46:02 -07:00
e638764340 Put the light where I actually want it to be 2014-08-02 23:45:49 -07:00
f03945c0f7 Always return the normal, even if the point isn't in the plane
Getting so much closer!
2014-08-02 15:40:24 -07:00
5390600cdd TODO: what does this (apparently) random conditional do? 2014-08-02 15:32:27 -07:00
8ea832c090 Disable specular calculations for now.
Just to simplify things while I'm figuring out the lighting model...
2014-08-02 15:23:22 -07:00
79c951030d Move Stats to its own module
Move Stats to its own module and pass it around to the intersection methods to keep track of how many tests and successful intersections there are.
2014-08-02 15:21:14 -07:00
b60e27824b Forgot declaration of shadowRay <- shadow_ray 2014-08-02 14:33:50 -07:00
5ddfe068a6 No specular reflections (for now) 2014-08-02 14:33:32 -07:00
8de737decd Little bit of code clean up in TraceRay 2014-08-02 14:30:40 -07:00
1a5a46c468 Use NearZero in plane intersection calculations
Also clean up the "point on surface" logic and remove the normal flipping (doesn't make sense without a ray origin anyway).
2014-08-02 14:12:01 -07:00
82c7e75e11 Normalize primary ray direction vectors 2014-08-02 14:10:28 -07:00
57f3154986 Add a NearZero for temporary values 2014-08-02 14:10:04 -07:00
0d4b700546 Add EPSILON, MAX_DISTANCE, and NearZero and TooFar 2014-08-02 12:19:46 -07:00
0d6a238b44 Clean up some implementation header comments 2014-08-02 10:40:41 -07:00
662867f529 Return the appropriate normal
I'm not actually sure this is necessary...
2014-08-02 10:39:56 -07:00
20b88f6dac Clarify some notation in plane intersection 2014-08-02 10:39:29 -07:00
964b6a5751 Add Plane object parsing to ObjectParser 2014-08-02 10:13:39 -07:00
d37b82b116 A new scene: plane with a sphere above it 2014-08-02 10:04:10 -07:00
6ddd47fe64 Redo planes in normal-distance form
This is how POV-Ray does it. This is how The Book does it. I'm just going along for the ride… :) But seriously, it seems to make some things easier.
2014-08-02 10:00:54 -07:00
d44fa4dd2a Add Vector3::normalized()
Makes a copy of the vector, normalizes it, and returns it.
2014-08-02 10:00:00 -07:00
c80a6e9ac7 Rename object_plane -> objectPlane 2014-08-02 09:26:22 -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
144 changed files with 25170 additions and 3733 deletions

10
.gitignore vendored
View file

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

2310
Doxyfile Normal file

File diff suppressed because it is too large Load diff

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.
#
# vim: set ft=python tw=80:
# Eryn Wells <eryn@erynwells.me>
@ -10,89 +7,211 @@
# DEFAULT CONFIGURATION VALUES
#
# Enabling debugging does the following things:
# 1. Turns on debugging symbols
# 2. Turns off all optimization
# 3. Sets the DEBUG define
DEBUG = True
# Settings for the default toolchain binaries. Setting these overrides the
# defaults, provided your the given binary exists.
CC = None
CXX = None
AS = None
LINK = 'clang++'
# Show build commands ("cc [args] -o [out] [file], etc"). If this is False, show
# some nice messages for each step of the build.
BUILD_CMDS = False
CCFLAGS = ['-Wall', '-Wextra', '-pedantic']
# Library directories. Where should scons look for .a files during linking?
lib_directories = Split("""
/usr/local/lib
""")
# Source directories. New directories should contain a SConscript file and be
# added here.
source_directories = lib_directories + Split("""
#src
#test
""")
# Include directories. Where should scons look for headers during preprocessing
# and compiling?
include_directories = Split("""
/usr/local/include
#src
""")
#
# BUILD STUFF BELOW HERE
#
import os
import os.path
cflags='-Wall -fcolor-diagnostics'
env = Environment(CC='clang', CXX='clang++',
CFLAGS=cflags + ' -std=c99',
CXXFLAGS=cflags + ' -std=c++11',
CPPPATH=include_directories,
LIBS=['png'],
LIBPATH=lib_directories)
import sys
import SCons.Errors
# Handle command line variables
DEBUG = bool(int(ARGUMENTS.get('DEBUG', DEBUG)))
if DEBUG:
debug_flags=' -g -O0'
env.Append(CFLAGS=debug_flags, CXXFLAGS=debug_flags)
env.Append(CPPDEFINES=['DEBUG'])
else:
flags = ' -O2'
env.Append(CFLAGS=flags, CXXFLAGS=flags)
def which(program):
def is_executable(path):
return os.path.exists(path) and os.access(path, os.X_OK)
BUILD_CMDS = bool(int(ARGUMENTS.get('BUILD_CMDS', BUILD_CMDS)))
if not BUILD_CMDS:
path, name = os.path.split(program)
if path:
if is_executable(program):
return program
else:
pathext = [''] + os.environ.get('PATHEXT', '').split(os.pathsep)
for path in os.environ.get('PATH', '').split(os.pathsep):
exe = os.path.join(path, program)
for ext in pathext:
candidate = exe + ext
if is_executable(candidate):
return candidate
return None
def get_bool_argument(arg):
try:
return bool(int(arg))
except ValueError:
pass
if arg in ('False', 'FALSE', 'false', ''):
return False
return True
def set_toolchain_binary(env, var, user_binary, binaries=()):
if user_binary and which(user_binary):
env[var] = user_binary
return
for c in binaries:
if which(c):
env[var] = c
break
common_env = Environment()
set_toolchain_binary(common_env, 'CC', CC, ('clang', 'gcc'))
set_toolchain_binary(common_env, 'CXX', CXX, ('clang++', 'g++'))
set_toolchain_binary(common_env, 'AS', AS)
set_toolchain_binary(common_env, 'LINK', LINK)
def verbose_build_cmds():
def generate_comstr(action):
return '%18s: $TARGET' % (action,)
env['CCCOMSTR'] = generate_comstr('Building (C)'),
env['CXXCOMSTR'] = generate_comstr('Building (C++)'),
env['LINKCOMSTR'] = generate_comstr('Linking'),
env['ARCOMSTR'] = generate_comstr('Archiving'),
env['RANLIBCOMSTR'] = generate_comstr('Indexing')
return '{:>25}: $TARGET'.format(action)
common_env['ARCOMSTR'] = generate_comstr('Archiving')
common_env['ASCOMSTR'] = generate_comstr('Assembling')
common_env['ASPPCOMSTR'] = generate_comstr('Assembling')
common_env['CCCOMSTR'] = generate_comstr('Building (C)')
common_env['CXXCOMSTR'] = generate_comstr('Building (C++)')
common_env['LINKCOMSTR'] = generate_comstr('Linking')
common_env['RANLIBCOMSTR'] = generate_comstr('Indexing')
common_env['SHCCCOMSTR'] = generate_comstr('Building (C, Shared)')
common_env['SHCXXCOMSTR'] = generate_comstr('Building (C++, Shared)')
common_env['SHLINKCOMSTR'] = generate_comstr('Linking (Shared)')
# Build charles
src_dir = Dir('#src')
charles_lib = env.SConscript(os.path.join(src_dir.path, 'SConscript'),
exports=['env'],
variant_dir=os.path.join('build', src_dir.path),
duplicate=0)
def succinct_build_cmds():
def generate_comstr(action):
return ' [{:^6}] $TARGET'.format(action)
common_env['ARCOMSTR'] = generate_comstr('AR')
common_env['ASCOMSTR'] = generate_comstr('AS')
common_env['ASPPCOMSTR'] = generate_comstr('AS')
common_env['CCCOMSTR'] = generate_comstr('CC')
common_env['CXXCOMSTR'] = generate_comstr('CXX')
common_env['LINKCOMSTR'] = generate_comstr('LINK')
common_env['RANLIBCOMSTR'] = generate_comstr('RANLIB')
common_env['SHCCCOMSTR'] = generate_comstr('SHCC')
common_env['SHCXXCOMSTR'] = generate_comstr('SHCXX')
common_env['SHLINKCOMSTR'] = generate_comstr('SHLINK')
# Build test
gtest_dir = Dir('#gtest')
gtest_include_dir = Dir('#gtest/include')
gtest = env.SConscript(os.path.join(gtest_dir.path, 'SConscript'),
exports=['env'],
variant_dir=os.path.join('build', gtest_dir.path),
duplicate=0)
test_dir = Dir('#test')
env.SConscript(os.path.join(test_dir.path, 'SConscript'),
exports=['env', 'gtest', 'gtest_include_dir', 'charles_lib'],
variant_dir=os.path.join('build', test_dir.path),
duplicate=0)
env.Default('charles')
BUILD_CMDS = get_bool_argument(ARGUMENTS.get('BUILD_CMDS', False))
if not BUILD_CMDS:
verbose_build_cmds()
# Separate environment for building libraries because they often don't use the
# same CCFLAGS I do.
lib_env = common_env.Clone()
common_env.Append(CCFLAGS=CCFLAGS)
common_env.Append(CFLAGS=['-std=c99'])
common_env.Append(CXXFLAGS=['-std=c++11'])
# Separate base environment for building utilities. They're all written by me,
# so they need my usual flags, but each should have its own build environment
# derived from this one.
util_env = common_env.Clone()
# Add color error messages for clang
if sys.stdout.isatty():
if 'clang' in common_env['CC'] or 'clang' in common_env['CXX']:
common_env.Append(CCFLAGS=['-fcolor-diagnostics'])
BUILD_DIR = Dir('#build')
LIB_DIR = Dir('#lib')
SRC_DIR = Dir('#src')
TEST_DIR = Dir('#test')
UTIL_DIR = Dir('#util')
def create_env(name, appends=None):
output_dir = BUILD_DIR.Dir(name)
env = common_env.Clone()
# Standard env extensions.
env.Append(CPPPATH=[SRC_DIR])
# Custom env stuff.
env['__name'] = name
if appends:
for k, v in appends.iteritems():
if k.startswith('='):
env[k[1:]] = v
else:
env.Append(**{k: v})
return env
def do_sconscript(env, build_env, src_dir, out_dir):
sconscript = src_dir.File('SConscript')
print 'Reading {}'.format(sconscript)
# Swapping env and build_env here is a bit wacky. Doing so means that env is
# always the Environment that the SConscript should be building with, while
# build_env is the Environment we're using to put everything together.
env.SConscript(sconscript,
{'env': build_env, 'build_env': env},
variant_dir=out_dir,
duplicate=0)
debug_env = create_env('debug', {
'CPPDEFINES': ['DEBUG', 'NRELEASE'],
'CCFLAGS': ['-O0', '-g'],
})
beta_env = create_env('beta', {
'CPPDEFINES': ['DEBUG', 'NRELEASE'],
'CCFLAGS': ['-O3', '-g'],
})
release_env = create_env('release', {
'CPPDEFINES': ['NDEBUG', 'RELEASE'],
'CCFLAGS': ['-O3']
})
modes = {
'debug': debug_env,
'beta': beta_env,
'release': release_env,
}
mode = ARGUMENTS.get('MODE', None)
build_modes = []
if mode:
# If MODE=foo is specified, build only that mode.
build_modes.append(mode)
else:
build_modes = ['debug']
for mode in build_modes:
try:
env = modes[mode]
except KeyError:
print 'Skipping invalid mode: {}'.format(mode)
break
out_dir = BUILD_DIR.Dir(env['__name'])
# Process all lib dirs.
for lib in os.listdir(LIB_DIR.abspath):
lib_out_dir = out_dir.Dir('lib').Dir(lib)
do_sconscript(env, lib_env, LIB_DIR.Dir(lib), lib_out_dir)
env.Append(LIBPATH=[lib_out_dir])
for util in os.listdir(UTIL_DIR.abspath):
util_out_dir = out_dir.Dir('util').Dir(util)
do_sconscript(env, util_env.Clone(), UTIL_DIR.Dir(util), util_out_dir)
# Get test binaries.
do_sconscript(env, env, TEST_DIR, out_dir.Dir('test'))
# Get source files.
src_out_dir = out_dir.Dir('src')
do_sconscript(env, env, SRC_DIR, src_out_dir)
env.Append(LIBPATH=[src_out_dir])

10
charles.sublime-project Normal file
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]

18
scenes/oneBox.yml Normal file
View file

@ -0,0 +1,18 @@
--- !Scene
dimensions: [800, 600]
camera: !Camera.Perspective
origin: [7.48, 6.5, 5.34]
lookAt: [0, 0, 0]
objects:
- !Object.Box
near: [-1, -1, -1]
far: [1, 1, 1]
color: [1, 0, 0]
- !Object.Sphere
origin: [1.5, 0, 0]
radius: 0.25
color: [0, 1, 0]
- !Object.Plane
normal: [0, 1, 0]
distance: 1
color: [0, 0, 1]

View file

@ -0,0 +1,14 @@
--- !Scene
dimensions: [800, 600]
camera: !Camera.Perspective
origin: [7.48, 6.5, 5.34]
lookAt: [0, 0, 0]
objects:
- !Object.Box
near: 3 * y + 2
far: [1, 1, 1]
color: [1, 0, 0]
- !Object.Plane
normal: [0, 1, 0]
distance: 1
color: [0, 0, 1]

14
scenes/planeSphere.yml Normal file
View file

@ -0,0 +1,14 @@
--- !Scene
dimensions: [800, 600]
camera: !Camera.Perspective
origin: [0, 3, -6]
direction: [0, -0.316228, 0.948683]
objects:
- !Object.Plane
normal: [0, 1, 0]
distance: 1
color: [0.0, 0.328, 0.8]
- !Object.Sphere
origin: [0, 1, 0]
radius: 1
color: [0.8, 0.284, 0.0]

34
scenes/sphereGrid.yml Normal file
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: [800, 600]
camera: !Camera.Perspective
right: [1.33, 0, 0]
objects:
- !Object.Sphere
origin: [0, 0.5, 2]
radius: 0.33
color: [1, 0, 0]
- !Object.Sphere
origin: [-0.33, 0, 2]
radius: 0.33
color: [0, 1, 0]
- !Object.Sphere
origin: [0.33, 0, 2]
radius: 0.33
color: [0, 0, 1]

View file

@ -4,20 +4,41 @@
Import('env')
files = Split("""
basics.cc
camera.cc
light.cc
material.cc
object.cc
object_sphere.cc
object_plane.cc
scene.cc
writer_png.cc
""")
lib = env.Library('charles', files)
prog = env.Program('charles', [lib, 'charles.cc'])
objs = []
subdirs = [
'basics',
'yaml',
]
for d in subdirs:
dir_objs = env.SConscript(env.Dir(d).File('SConscript'), {'env': env})
objs.extend(dir_objs)
files = [
'camera.cc',
'light.cc',
'lightPoint.cc',
'log.cc',
'material.cc',
'object.cc',
'objectBox.cc',
'objectPlane.cc',
'objectSphere.cc',
'reader_yaml.cc',
'scene.cc',
'stats.cc',
'writer_png.cc',
]
for f in files:
objs.append(env.Object(f))
lib = env.Library('charles', objs)
prog = env.Program('charles', ['charles.cc'], LIBS=[lib, 'png', 'yaml'])
env.Alias('charles', prog)
env.Default('charles')
Return('lib')
env.Default('charles')

View file

@ -1,510 +0,0 @@
/* basics.c
*
* Definition of basic types.
*
* - Vector3 is a three tuple vector of x, y, and z.
* - Ray is a vector plus a direction.
* - Color is a four tuple of red, green, blue, and alpha.
*
* Eryn Wells <eryn@erynwells.me>
*/
#include <cmath>
#include "basics.h"
#pragma mark - Vectors
const Vector3 Vector3::Zero = Vector3();
const Vector3 Vector3::X = Vector3(1, 0, 0);
const Vector3 Vector3::Y = Vector3(0, 1, 0);
const Vector3 Vector3::Z = Vector3(0, 0, 1);
/*
* Vector3::Vector3 --
*
* Default constructor. Create a zero vector.
*/
Vector3::Vector3()
: Vector3(0.0, 0.0, 0.0)
{ }
/*
* Vector3::Vector3 --
*
* Constructor. Create a vector consisting of the given coordinates.
*/
Vector3::Vector3(float _x, float _y, float _z)
: x(_x), y(_y), z(_z)
{ }
/*
* Vector3::operator= --
*
* Copy the given vector's values into this vector. Return a reference to this vector.
*/
Vector3 &
Vector3::operator=(const Vector3 &v)
{
x = v.x;
y = v.y;
z = v.z;
return *this;
}
/*
* Vector3::operator*= --
* Vector3::operator/= --
* Vector3::operator+= --
* Vector3::operator-= --
*
* Perform the corresponding arithmetic operation on this vector and the given vector. These methods are destructive and
* a reference to this vector is returned.
*/
Vector3 &
Vector3::operator*=(const float &rhs)
{
x *= rhs;
y *= rhs;
z *= rhs;
return *this;
}
Vector3 &
Vector3::operator/=(const float &rhs)
{
return *this *= (1.0f / rhs);
}
Vector3 &
Vector3::operator+=(const Vector3 &rhs)
{
x += rhs.x;
y += rhs.y;
z += rhs.z;
return *this;
}
Vector3 &
Vector3::operator-=(const Vector3 &rhs)
{
return *this += -rhs;
}
/*
* Vector3::operator* --
* Vector3::operator/ --
* Vector3::operator+ --
* Vector3::operator- --
*
* Perform the corresponding operation on a copy of this vector. Return a new vector.
*/
Vector3
Vector3::operator*(const float &rhs)
const
{
return Vector3(*this) *= rhs;
}
Vector3
Vector3::operator/(const float &rhs)
const
{
return Vector3(*this) /= rhs;
}
Vector3
Vector3::operator+(const Vector3 &rhs)
const
{
return Vector3(*this) += rhs;
}
Vector3
Vector3::operator-(const Vector3 &rhs)
const
{
return Vector3(*this) -= rhs;
}
/*
* Vector3::operator- --
*
* Negate this vector. Return a new vector.
*/
Vector3
Vector3::operator-()
const
{
return Vector3(-x, -y, -z);
}
/*
* Vector3::operator== --
* Vector3::operator!= --
*
* Compute boolean equality and non-equality of this and the given vectors.
*/
bool
Vector3::operator==(const Vector3 &rhs)
const
{
return x == rhs.x && y == rhs.y && z == rhs.z;
}
bool
Vector3::operator!=(const Vector3 &rhs)
const
{
return !(*this == rhs);
}
/*
* Vector3::length2 --
*
* Compute and return the length-squared of this vector.
*/
float
Vector3::length2()
const
{
return x*x + y*y + z*z;
}
/*
* Vector3::length --
*
* Compute and return the length of this vector.
*/
float
Vector3::length()
const
{
return sqrtf(length2());
}
/*
* Vector3::dot --
*
* Compute and return the dot product of this and the given vectors.
*/
float
Vector3::dot(const Vector3 &v)
const
{
return x*v.x + y*v.y + z*v.z;
}
/*
* Vector3::cross --
*
* Compute and return the cross product of this and the given vectors.
*/
Vector3
Vector3::cross(const Vector3 &v)
const
{
return Vector3(y*v.z - z*v.y, z*v.x - x*v.z, x*v.y - y*v.x);
}
/*
* Vector3::normalize --
*
* Normalize this vector in place. That is, make this vector's magnitude (length) 1.0.
*/
Vector3 &
Vector3::normalize()
{
// Use the overloaded /= compound operator to do this.
return *this /= length();
}
/*
* operator* --
*
* Multiply the given float by the given vector. Return a new vector.
*/
const Vector3
operator*(const float &lhs, const Vector3 &rhs)
{
return rhs * lhs;
}
std::ostream &
operator<<(std::ostream &os, const Vector3 &v)
{
// Stream the vector like this: <x, y, z>
os << "<" << v.x << ", " << v.y << ", " << v.z << ">";
return os;
}
#pragma mark - Rays
/*
* Ray::Ray --
*
* Default constructor. Create a ray at the origin (0, 0, 0) with direction (0, 0, 0).
*/
Ray::Ray()
: Ray(Vector3::Zero, Vector3::Zero)
{ }
/*
* Ray::Ray --
*
* Constructor. Create a ray with the given origin and direction.
*/
Ray::Ray(Vector3 o, Vector3 d)
: origin(o), direction(d)
{ }
/*
* Ray::parameterize --
*
* Compute and return the point given by parameterizing this Ray by time t.
*/
Vector3
Ray::parameterize(const float t)
const
{
return origin + t * direction;
}
std::ostream &
operator<<(std::ostream &os, const Ray &r)
{
os << "[Ray " << r.origin << " " << r.direction << "]";
return os;
}
#pragma mark - Colors
const Color Color::Black = Color();
const Color Color::White = Color(1.0, 1.0, 1.0, 1.0);
const Color Color::Red = Color(1.0, 0.0, 0.0, 1.0);
const Color Color::Green = Color(0.0, 1.0, 0.0, 1.0);
const Color Color::Blue = Color(0.0, 0.0, 1.0, 1.0);
/*
* Color::Color --
*
* Default constructor. Create a new Color with zeros for all components (black).
*/
Color::Color()
: Color(0.0, 0.0, 0.0, 0.0)
{ }
/*
* Color::Color --
*
* Constructor. Create a new Color with the given RGB components. Alpha is 1.0.
*/
Color::Color(const float &r, const float &g, const float &b)
: Color(r, g, b, 1.0)
{ }
/*
* Color::Color --
*
* Constructor. Create a new Color with the given components.
*/
Color::Color(const float &r, const float &g, const float &b, const float &a)
: red(r), green(g), blue(b), alpha(a)
{ }
/*
* Color::operator*= --
* Color::operator/= --
* Color::operator+= --
* Color::operator-= --
*
* Perform the corresponding arithmetic operation on this color and the given scalar. These methods are destructive and
* a reference to this color is returned.
*/
Color &
Color::operator*=(const float &rhs)
{
red *= rhs;
green *= rhs;
blue *= rhs;
return *this;
}
Color &
Color::operator/=(const float &rhs)
{
return *this *= (1.0 / rhs);
}
Color &
Color::operator+=(const float &rhs)
{
red += rhs;
green += rhs;
blue += rhs;
alpha += rhs;
return *this;
}
Color &
Color::operator-=(const float &rhs)
{
return *this += -rhs;
}
/*
* Color::operator* --
* Color::operator/ --
* Color::operator+ --
* Color::operator- --
*
* Perform the corresponding operation on a copy of this color and the given scalar. Return a new vector.
*/
Color
Color::operator*(const float &rhs)
const
{
return Color(*this) *= rhs;
}
Color
Color::operator/(const float &rhs)
const
{
return Color(*this) /= rhs;
}
Color
Color::operator+(const float &rhs)
const
{
return Color(*this) += rhs;
}
Color
Color::operator-(const float &rhs)
const
{
return Color(*this) -= rhs;
}
/*
* Color::operator= --
*
* Copy the given color's values into this color. Return a reference to this color.
*/
Color &
Color::operator=(const Color &rhs)
{
red = rhs.red;
green = rhs.green;
blue = rhs.blue;
alpha = rhs.alpha;
return *this;
}
Color &
Color::operator*=(const Color &rhs)
{
red *= rhs.red;
green *= rhs.green;
blue *= rhs.blue;
return *this;
}
Color &
Color::operator/=(const Color &rhs)
{
red *= (1.0 / rhs.red);
green *= (1.0 / rhs.green);
blue *= (1.0 / rhs.blue);
return *this;
}
Color &
Color::operator+=(const Color &rhs)
{
red += rhs.red;
green += rhs.green;
blue += rhs.blue;
alpha += rhs.alpha;
return *this;
}
Color &
Color::operator-=(const Color &rhs)
{
red -= rhs.red;
green -= rhs.green;
blue -= rhs.blue;
alpha -= rhs.alpha;
return *this;
}
Color
Color::operator*(const Color &rhs)
const
{
return Color(*this) *= rhs;
}
Color
Color::operator/(const Color &rhs)
const
{
return Color(*this) /= rhs;
}
Color
Color::operator+(const Color &rhs)
const
{
return Color(*this) += rhs;
}
Color
Color::operator-(const Color &rhs)
const
{
return Color(*this) -= rhs;
}
const Color
operator*(const float &lhs, const Color &rhs)
{
return rhs * lhs;
}
std::ostream &
operator<<(std::ostream &os, const Color &c)
{
// Stream colors like this: <r, g, b, a>
os << "<" << c.red << ", " << c.green << ", " << c.blue << ", " << c.alpha << ">";
return os;
}

View file

@ -1,107 +0,0 @@
/* basics.h
*
* Declaration of basic types.
*
* - Vector3 is a three tuple vector of x, y, and z.
* - Ray is a vector plus a direction.
* - Color is a four tuple of red, green, blue, and alpha.
*
* Eryn Wells <eryn@erynwells.me>
*/
#ifndef __BASICS_H__
#define __BASICS_H__
#include <iostream>
struct Vector3
{
Vector3();
Vector3(float x, float y, float z);
Vector3 &operator=(const Vector3 &v);
Vector3 &operator*=(const float &rhs);
Vector3 &operator/=(const float &rhs);
Vector3 &operator+=(const Vector3 &rhs);
Vector3 &operator-=(const Vector3 &rhs);
Vector3 operator*(const float &rhs) const;
Vector3 operator/(const float &rhs) const;
Vector3 operator+(const Vector3 &rhs) const;
Vector3 operator-(const Vector3 &rhs) const;
Vector3 operator-() const;
bool operator==(const Vector3 &rhs) const;
bool operator!=(const Vector3 &rhs) const;
float length2() const;
float length() const;
float dot(const Vector3 &v) const;
Vector3 cross(const Vector3 &v) const;
Vector3 &normalize();
static const Vector3 Zero;
// Unit vectors in each of the three cartesian directions.
static const Vector3 X, Y, Z;
float x, y, z;
};
const Vector3 operator*(const float &lhs, const Vector3 &rhs);
std::ostream &operator<<(std::ostream &os, const Vector3 &v);
struct Ray
{
Ray();
Ray(Vector3 o, Vector3 d);
Vector3 parameterize(const float t) const;
Vector3 origin, direction;
};
std::ostream &operator<<(std::ostream &os, const Ray &r);
struct Color
{
Color();
Color(const float &r, const float &g, const float &b);
Color(const float &r, const float &g, const float &b, const float &a);
Color &operator*=(const float &rhs);
Color &operator/=(const float &rhs);
Color &operator+=(const float &rhs);
Color &operator-=(const float &rhs);
Color operator*(const float &rhs) const;
Color operator/(const float &rhs) const;
Color operator+(const float &rhs) const;
Color operator-(const float &rhs) const;
Color &operator=(const Color &rhs);
// These operators blend the two colors.
Color &operator*=(const Color &rhs);
Color &operator/=(const Color &rhs);
Color &operator+=(const Color &rhs);
Color &operator-=(const Color &rhs);
Color operator*(const Color &rhs) const;
Color operator/(const Color &rhs) const;
Color operator+(const Color &rhs) const;
Color operator-(const Color &rhs) const;
static const Color Black;
static const Color White;
static const Color Red;
static const Color Green;
static const Color Blue;
float red, green, blue, alpha;
};
const Color operator*(const float &lhs, const Color &rhs);
std::ostream &operator<<(std::ostream &os, const Color &c);
#endif

16
src/basics/SConscript Normal file
View file

@ -0,0 +1,16 @@
# SConscript
# vim: set ft=python:
# Eryn Wells <eryn@erynwells.me>
Import('env')
files = [
'color.cc',
'matrix.cc',
'ray.cc',
'vector.cc',
]
objs = [env.Object(f) for f in files]
Return('objs')

21
src/basics/basics.hh Normal file
View file

@ -0,0 +1,21 @@
/* basics.hh
* vim: set tw=80:
* Eryn Wells <eryn@erynwells.me>
*/
/**
* Top-level include for the basics module.
*/
#ifndef __BASICS_BASICS_HH__
#define __BASICS_BASICS_HH__
#include <cmath>
#include "basics/color.hh"
#include "basics/matrix.hh"
#include "basics/ray.hh"
#include "basics/types.hh"
#include "basics/util.hh"
#include "basics/vector.hh"
#endif /* __BASICS_BASICS_HH__ */

272
src/basics/color.cc Normal file
View file

@ -0,0 +1,272 @@
/* color.cc
* vim: set tw=80:
* Eryn Wells <eryn@erynwells.me>
*/
#include <ostream>
#include "basics/color.hh"
#include "basics/types.hh"
namespace charles {
namespace basics {
const Color Color::Black = Color();
const Color Color::White = Color(1, 1, 1);
const Color Color::Red = Color(1, 0, 0);
const Color Color::Green = Color(0, 1, 0);
const Color Color::Blue = Color(0, 0, 1);
/*
* charles::basics::Color::Color --
*/
Color::Color()
: Color(0.0, 0.0, 0.0, 0.0)
{ }
/*
* charles::basics::Color::Color --
*/
Color::Color(const Double& r,
const Double& g,
const Double& b,
const Double& a)
: red(r),
green(g),
blue(b),
alpha(a)
{ }
/*
* charles::basics::Color::operator= --
*/
Color&
Color::operator=(const Color& rhs)
{
red = rhs.red;
green = rhs.green;
blue = rhs.blue;
alpha = rhs.alpha;
return *this;
}
/*
* charles::basics::Color::operator*= --
*/
Color&
Color::operator*=(const Double& rhs)
{
red *= rhs;
green *= rhs;
blue *= rhs;
return *this;
}
/*
* charles::basics::Color::operator/= --
*/
Color&
Color::operator/=(const Double& rhs)
{
return *this *= (1.0 / rhs);
}
/*
* charles::basics::Color::operator+= --
*/
Color&
Color::operator+=(const Double& rhs)
{
red += rhs;
green += rhs;
blue += rhs;
alpha += rhs;
return *this;
}
/*
* charles::basics::Color::operator-= --
*/
Color&
Color::operator-=(const Double& rhs)
{
return *this += -rhs;
}
/*
* charles::basics::Color::operator* --
*/
Color
Color::operator*(const Double& rhs)
const
{
return Color(*this) *= rhs;
}
/*
* charles::basics::Color::operator/ --
*/
Color
Color::operator/(const Double& rhs)
const
{
return Color(*this) /= rhs;
}
/*
* charles::basics::Color::operator+ --
*/
Color
Color::operator+(const Double& rhs)
const
{
return Color(*this) += rhs;
}
/*
* charles::basics::Color::operator- --
*/
Color
Color::operator-(const Double& rhs)
const
{
return Color(*this) -= rhs;
}
/*
* charles::basics::Color::operator*= --
*/
Color&
Color::operator*=(const Color& rhs)
{
red *= rhs.red;
green *= rhs.green;
blue *= rhs.blue;
return *this;
}
/*
* charles::basics::Color::operator/= --
*/
Color&
Color::operator/=(const Color& rhs)
{
red /= rhs.red;
green /= rhs.green;
blue /= rhs.blue;
return *this;
}
/*
* charles::basics::Color::operator+= --
*/
Color&
Color::operator+=(const Color& rhs)
{
red += rhs.red;
green += rhs.green;
blue += rhs.blue;
alpha += rhs.alpha;
return *this;
}
/*
* charles::basics::Color::operator-= --
*/
Color&
Color::operator-=(const Color& rhs)
{
red -= rhs.red;
green -= rhs.green;
blue -= rhs.blue;
alpha -= rhs.alpha;
return *this;
}
/*
* charles::basics::Color::operator* --
*/
Color
Color::operator*(const Color& rhs)
const
{
return Color(*this) *= rhs;
}
/*
* charles::basics::Color::operator/ --
*/
Color
Color::operator/(const Color& rhs)
const
{
return Color(*this) /= rhs;
}
/*
* charles::basics::Color::operator+ --
*/
Color
Color::operator+(const Color& rhs)
const
{
return Color(*this) += rhs;
}
/*
* charles::basics::Color::operator- --
*/
Color
Color::operator-(const Color& rhs)
const
{
return Color(*this) -= rhs;
}
/*
* charles::basics::operator* --
*/
const Color
operator*(const Double& lhs,
const Color& rhs)
{
return rhs * lhs;
}
/*
* charles::basics::operator<< --
*/
std::ostream &
operator<<(std::ostream& os,
const Color& c)
{
// Stream colors like this: <r, g, b, a>
os << "<" << c.red << ", " << c.green << ", " << c.blue << ", " << c.alpha << ">";
return os;
}
} /* namespace basics */
} /* namespace charles */

58
src/basics/color.hh Normal file
View file

@ -0,0 +1,58 @@
/* color.hh
* vim: set tw=80:
* Eryn Wells <eryn@erynwells.me>
*/
#ifndef __BASICS_COLOR_HH__
#define __BASICS_COLOR_HH__
#include "basics/types.hh"
namespace charles {
namespace basics {
struct Color
{
Color();
Color(const Double& r, const Double& g, const Double& b, const Double& a = 1.0);
Color &operator*=(const Double &rhs);
Color &operator/=(const Double &rhs);
Color &operator+=(const Double &rhs);
Color &operator-=(const Double &rhs);
Color operator*(const Double &rhs) const;
Color operator/(const Double &rhs) const;
Color operator+(const Double &rhs) const;
Color operator-(const Double &rhs) const;
Color &operator=(const Color &rhs);
// These operators blend the two colors.
Color &operator*=(const Color &rhs);
Color &operator/=(const Color &rhs);
Color &operator+=(const Color &rhs);
Color &operator-=(const Color &rhs);
Color operator*(const Color &rhs) const;
Color operator/(const Color &rhs) const;
Color operator+(const Color &rhs) const;
Color operator-(const Color &rhs) const;
static const Color Black;
static const Color White;
static const Color Red;
static const Color Green;
static const Color Blue;
Double red, green, blue, alpha;
};
const Color operator*(const Double &lhs, const Color &rhs);
std::ostream &operator<<(std::ostream &os, const Color &c);
} /* namespace basics */
} /* namespace charles */
#endif /* __BASICS_COLOR_HH__ */

382
src/basics/matrix.cc Normal file
View file

@ -0,0 +1,382 @@
/* matrix.cc
* vim: set tw=80:
* Eryn Wells <eryn@erynwells.me>
*/
#include <cstring>
#include <stdexcept>
#include <sstream>
#include <type_traits>
#include "basics/matrix.hh"
#include "basics/util.hh"
#include "basics/vector.hh"
namespace charles {
namespace basics {
#pragma mark Static Methods
/*
* charles::basics::Matrix4::Zero --
*/
/* static */ Matrix4
Matrix4::Zero()
{
Matrix4 m;
bzero(m.mData, sizeof(Double) * 16);
return m;
}
/*
* charles::basics::Matrix4::Identity --
*/
/* static */ Matrix4
Matrix4::Identity()
{
auto m = Matrix4::Zero();
for (size_t i = 0; i < 4; i++) {
m(i,i) = 1.0;
}
return m;
}
/*
* charles::basics::Translation --
*/
/* static */ Matrix4
Matrix4::Translation(const Vector4& p)
{
return Translation(p.X(), p.Y(), p.Z());
}
/*
* charles::basics::TranslationMatrix --
*/
/* static */ Matrix4
Matrix4::Translation(Double x,
Double y,
Double z)
{
Matrix4 m = Matrix4::Identity();
m(0,3) = x;
m(1,3) = y;
m(2,3) = z;
return m;
}
#pragma mark Constructors and Assignment
/*
* charles::basics::Matrix4::Matrix4 --
*/
Matrix4::Matrix4()
: mData(),
mTransposed(false)
{ }
/*
* charles::basics::Matrix4::Matrix4 --
*/
Matrix4::Matrix4(const Double data[16])
: mTransposed(false)
{
/* TODO: Replace with std::copy */
memcpy(mData, data, sizeof(Double) * 16);
}
/*
* charles::basics::Matrix4::Matrix4 --
*/
Matrix4::Matrix4(const Matrix4 &rhs)
: Matrix4(rhs.mData)
{
/*
* Needs to be in the body instead of the initializer list because
* (apparently) delegating constructors must be the only thing in the list.
*/
mTransposed = rhs.mTransposed;
}
/*
* charles::basics::Matrix4::operator= --
*/
Matrix4&
Matrix4::operator=(const Matrix4 &rhs)
{
/* TODO: Replace with std::copy */
memcpy(mData, rhs.mData, sizeof(Double) * 16);
mTransposed = rhs.mTransposed;
return *this;
}
#pragma mark Boolean Operators
/*
* charles::basics::Matrix4::operator== --
*/
bool
Matrix4::operator==(const Matrix4 &rhs)
const
{
for (int i = 0; i < 16; i++) {
if (!NearlyEqual(mData[i], rhs.mData[i])) {
return false;
}
}
return true;
}
/*
* charles::basics::Matrix4::operator!= --
*/
bool
Matrix4::operator!=(const Matrix4 &rhs)
const
{
return !(*this == rhs);
}
#pragma mark Element Access
/*
* charles::basics::Matrix4::operator() --
*/
Double&
Matrix4::operator()(UInt i,
UInt j)
{
if (i >= 4 || j >= 4) {
std::stringstream ss;
ss << "matrix index out of bounds: i = " << i << ", j = " << j;
throw std::out_of_range(ss.str());
}
if (!mTransposed) {
return mData[i*4 + j];
} else {
return mData[i + j*4];
}
}
/*
* charles::basics::Matrix4::operator() --
*/
Double
Matrix4::operator()(UInt i,
UInt j)
const
{
if (i >= 4 || j >= 4) {
std::stringstream ss;
ss << "matrix index out of bounds: i = " << i << ", j = " << j;
throw std::out_of_range(ss.str());
}
if (!mTransposed) {
return mData[i*4 + j];
} else {
return mData[i + j*4];
}
}
Vector4
Matrix4::Column(const UInt i)
const noexcept
{
return Vector4(operator()(i,0), operator()(i,1), operator()(i,2), operator()(i,3));
}
/*
* charles::basics::Matrix4::CArray --
*/
const Double*
Matrix4::CArray()
const
{
return mData;
}
#pragma mark Maths
/*
* charles::basics::Matrix4::operator* --
*/
Matrix4
Matrix4::operator*(Double rhs)
const
{
return Matrix4(*this) *= rhs;
}
/*
* charles::basics::Matrix4::operator/ --
*/
Matrix4
Matrix4::operator/(Double rhs)
const
{
return Matrix4(*this) /= rhs;
}
/*
* charles::basics::Matrix4::operator*= --
*/
Matrix4&
Matrix4::operator*=(Double rhs)
{
for (UInt i = 0; i < 16; i++) {
mData[i] *= rhs;
}
return *this;
}
/*
* charles::basics::Matrix4::operator/= --
*/
Matrix4&
Matrix4::operator/=(Double rhs)
{
return *this *= (1.0 / rhs);
}
/*
* charles::basics::Matrix4::operator* --
*/
Matrix4
Matrix4::operator*(const Matrix4& rhs)
const
{
Matrix4 result;
for (UInt i = 0; i < 4; i++) {
for (UInt j = 0; j < 4; j++) {
/* Each cell is Sigma(k=0, M)(lhs[ik] * rhs[kj]) */
result(i,j) = 0.0;
for (UInt k = 0; k < 4; k++) {
result(i,j) += mData[i*4 + k] * rhs(k,j);
}
}
}
return result;
}
/*
* charles::basics::Matrix4::operator* --
*/
Vector4
Matrix4::operator*(const Vector4 &rhs)
const
{
Vector4 result;
for (UInt i = 0; i < 4; i++) {
result(i) = 0.0;
for (UInt k = 0; k < 4; k++) {
result(i) += mData[i*4 + k] * rhs(k);
}
}
return result;
}
/*
* charles::basics::Matrix4::Transpose --
*/
Matrix4&
Matrix4::Transpose()
{
mTransposed = !mTransposed;
return *this;
}
Matrix4&
Matrix4::Inverse()
{
/* XXX: Only translation matrices are supported right now. */
operator()(0,3) = -operator()(0,3);
operator()(1,3) = -operator()(1,3);
operator()(2,3) = -operator()(2,3);
return *this;
}
/*
* charles::basics::operator* --
*/
Matrix4
operator*(Double lhs,
const Matrix4& rhs)
{
/* Scalar multiplication is commutative. */
return rhs * lhs;
}
/*
* charles::basics::Transposed --
*/
Matrix4
Transpose(Matrix4 m)
{
return m.Transpose();
}
/*
* charles::basics::Inverse --
*/
Matrix4
Inverse(Matrix4 m)
{
return m.Inverse();
}
/*
* charles::basics::operator<< --
*/
std::ostream&
operator<<(std::ostream &ost,
const Matrix4 &m)
{
ost << "[";
for (UInt i = 0; i < 4; i++) {
if (i != 0) {
ost << " ";
}
ost << "[";
for (UInt j = 0; j < 4; j++) {
ost << m(i,j);
if (j < 3) {
ost << " ";
}
}
ost << "]";
if (i < 3) {
ost << "\n";
}
}
ost << "]";
return ost;
}
} /* namespace mespace */
} /* namespace charles */

108
src/basics/matrix.hh Normal file
View file

@ -0,0 +1,108 @@
/* matrix.hh
* vim: set tw=80:
* Eryn Wells <eryn@erynwells.me>
*/
#ifndef __BASICS_MATRIX_HH__
#define __BASICS_MATRIX_HH__
#include <cassert>
#include <cstring>
#include <type_traits>
#include "basics/types.hh"
namespace charles {
namespace basics {
struct Vector4;
/** A 4x4 matrix, used for 3D transforms. */
struct Matrix4
{
/** Create a 4x4 matrix of zeros. */
static Matrix4 Zero();
/** Create a 4x4 identity matrix. */
static Matrix4 Identity();
/** Create a 4x4 translation matrix. */
static Matrix4 Translation(Double x, Double y, Double z);
static Matrix4 Translation(const Vector4 &p);
Matrix4();
Matrix4(const Double *data);
Matrix4(const Matrix4 &rhs);
Matrix4& operator=(const Matrix4 &rhs);
bool operator==(const Matrix4 &rhs) const;
bool operator!=(const Matrix4 &rhs) const;
/**
* Get the ij'th item. In debug builds, this will assert if i or j are
* outside the bounds of the array.
*/
Double& operator()(UInt i, UInt j);
Double operator()(UInt i, UInt j) const;
Vector4 Column(const UInt i) const noexcept;
/** Get the underlying C array */
const Double *CArray() const;
/*
* TODO: For completeness, matrix addition and subtraction, though I have
* yet to find a need for them...
*/
/**
* @defgroup Scalar multiplication
* @{
*/
Matrix4 operator*(Double rhs) const;
Matrix4 operator/(Double rhs) const;
Matrix4& operator*=(Double rhs);
Matrix4& operator/=(Double rhs);
/** @} */
/**
* @defgroup Matrix multiplication
* @{
*/
Matrix4 operator*(const Matrix4 &rhs) const;
Vector4 operator*(const Vector4 &rhs) const;
/** @} */
Matrix4 &Transpose();
Matrix4 &Inverse();
protected:
/** The matrix data */
Double mData[16];
/**
* `true` if the matrix has been transposed (i.e. should be indexed in
* column-major format).
*/
bool mTransposed;
};
/** Scalar multiplication, scalar factor on the left. */
Matrix4 operator*(Double lhs, const Matrix4 &rhs);
/** Transpose the given matrix. */
Matrix4 Transpose(Matrix4 m);
/** Invert the given matrix. */
Matrix4 Inverse(Matrix4 m);
std::ostream& operator<<(std::ostream &ost, const Matrix4 &m);
} /* namespace basics */
} /* namespace charles */
#endif /* __BASICS_MATRIX_HH__ */

35
src/basics/ray.cc Normal file
View file

@ -0,0 +1,35 @@
/* ray.cc
* vim: set tw=80:
* Eryn Wells <eryn@erynwells.me>
*/
#include "basics/ray.hh"
namespace charles {
namespace basics {
/*
* charles::basics::Ray::Ray --
*/
Ray::Ray(Vector4 o,
Vector4 d)
: origin(o),
direction(d)
{ }
/*
* charles::basics::Ray::Parameterize --
*/
Vector4
Ray::Parameterize(const Double& t)
const
{
return origin + direction * t;
}
} /* namespace basics */
} /* namespace charles */

25
src/basics/ray.hh Normal file
View file

@ -0,0 +1,25 @@
/* ray.hh
* vim: set tw=80:
* Eryn Wells <eryn@erynwells.me>
*/
#include "basics/types.hh"
#include "basics/vector.hh"
namespace charles {
namespace basics {
struct Ray
{
Ray(Vector4 o = Vector4(), Vector4 d = Vector4());
Vector4 Parameterize(const Double& t) const;
Vector4 origin;
Vector4 direction;
};
} /* namespace basics */
} /* namespace charles */

21
src/basics/types.hh Normal file
View file

@ -0,0 +1,21 @@
/* types.hh
* vim: set tw=80:
* Eryn Wells <eryn@erynwells.me>
*/
/**
* Some basic types.
*/
#ifndef __BASICS_TYPES_HH__
#define __BASICS_TYPES_HH__
#include <vector>
typedef double Double;
typedef unsigned int UInt;
typedef std::vector<Double> DoubleVector;
typedef DoubleVector TVector;
#endif /* __BASICS_TYPES_HH__ */

68
src/basics/util.hh Normal file
View file

@ -0,0 +1,68 @@
/* util.hh
* vim: set tw=80:
* Eryn Wells <eryn@erynwells.me>
*/
#ifndef __BASICS_UTIL_HH__
#define __BASICS_UTIL_HH__
#include <cmath>
/**
* A very small constant. If a value is between EPSILON and 0.0, it is
* considered to be zero.
*/
const Double EPSILON = 1.0e-10;
/**
* The maximum distance a ray can travel. This is the maximum value t can be.
*/
const Double MAX_DISTANCE = 1.0e7;
/**
* Determine if the value is "close enough" to zero. Takes the absolute value
* and compares it to `EPSILON`.
*
* @see EPSILON
*
* @param [in] value The value to check
* @returns `true` if the value is close enough to zero
*/
template <typename T>
inline bool
NearZero(T value)
{
return std::fabs(value) < EPSILON;
}
/**
* Determine if two values are "close enough" to be considered equal. Subtracts
* one from the other and checks if the result is near zero.
*
* @see NearZero
*
* @param [in] left The left parameter
* @param [in] right The right parameter
* @returns `true` if the values are close enough to be equal
*/
template <typename T, typename U>
inline bool
NearlyEqual(T left,
U right)
{
return NearZero(left - right);
}
inline bool
TooFar(const Double& value)
{
return value > MAX_DISTANCE;
}
#endif /* __BASICS_UTIL_HH__ */

399
src/basics/vector.cc Normal file
View file

@ -0,0 +1,399 @@
/* vector.cc
* vim: set tw=80:
* Eryn Wells <eryn@erynwells.me>
*/
#include <cmath>
#include <cstring>
#include <sstream>
#include <stdexcept>
#include "basics/vector.hh"
#include "basics/util.hh"
namespace charles {
namespace basics {
#pragma mark Constructors and Assignment
/*
* charles::basics::Vector4::Vector4 --
*/
Vector4::Vector4()
: Vector4(0, 0, 0)
{ }
/*
* charles::basics::Vector4::Vector4 --
*/
Vector4::Vector4(Double x,
Double y,
Double z)
: Vector4(x, y, z, 1.0)
{ }
/*
* charles::basics::Vector4::Vector4 --
*/
Vector4::Vector4(Double x,
Double y,
Double z,
Double w)
{
mData[0] = x;
mData[1] = y;
mData[2] = z;
mData[3] = w;
}
/*
* charles::basics::Vector4::operator= --
*/
Vector4&
Vector4::operator=(const Vector4 &rhs)
{
memcpy(mData, rhs.mData, sizeof(Double) * 4);
return *this;
}
#pragma mark Component Access
/*
* charles::basics::Vector4::X --
*/
Double&
Vector4::X()
{
return mData[0];
}
/*
* charles::basics::Vector4::X --
*/
Double
Vector4::X()
const
{
return mData[0];
}
/*
* charles::basics::Vector4::Y --
*/
Double&
Vector4::Y()
{
return mData[1];
}
/*
* charles::basics::Vector4::Y --
*/
Double
Vector4::Y()
const
{
return mData[1];
}
/*
* charles::basics::Vector4::Z --
*/
Double&
Vector4::Z()
{
return mData[2];
}
/*
* charles::basics::Vector4::Z --
*/
Double
Vector4::Z()
const
{
return mData[2];
}
Double&
Vector4::operator()(UInt i)
{
if (i >= 4) {
std::stringstream ss;
ss << "vector index out of bounds: i = " << i;
throw std::out_of_range(ss.str());
}
return mData[i];
}
Double
Vector4::operator()(UInt i)
const
{
if (i >= 4) {
std::stringstream ss;
ss << "vector index out of bounds: i = " << i;
throw std::out_of_range(ss.str());
}
return mData[i];
}
/*
* charles::basics::Vector4::CArray --
*/
const Double*
Vector4::CArray()
const
{
return mData;
}
#pragma mark Boolean Operators
/*
* charles::basics::Vector4::operator== --
*/
bool
Vector4::operator==(const Vector4 &rhs)
const
{
for (UInt i = 0; i < 4; i++) {
if (!NearlyEqual(mData[i], rhs.mData[i])) {
return false;
}
}
return true;
}
/*
* charles::basics::Vector4::operator!= --
*/
bool
Vector4::operator!=(const Vector4 &rhs)
const
{
return !(*this == rhs);
}
#pragma mark Maths
/*
* charles::basics::Vector4::operator* --
*/
Vector4
Vector4::operator*(Double rhs)
const
{
return Vector4(*this) *= rhs;
}
/*
* charles::basics::Vector4::operator* --
*/
Vector4
Vector4::operator/(Double rhs)
const
{
return Vector4(*this) /= rhs;
}
/*
* charles::basics::Vector4::operator*= --
*/
Vector4&
Vector4::operator*=(Double rhs)
{
for (int i = 0; i < 4; i++) {
mData[i] *= rhs;
}
return *this;
}
/*
* charles::basics::Vector4::operator/= --
*/
Vector4&
Vector4::operator/=(Double rhs)
{
return *this *= (1.0 / rhs);
}
/*
* charles::basics::Vector4::operator+ --
*/
Vector4
Vector4::operator+(const Vector4 &rhs)
const
{
return Vector4(*this) += rhs;
}
/*
* charles::basics::Vector4::operator- --
*/
Vector4
Vector4::operator-(const Vector4 &rhs)
const
{
return Vector4(*this) -= rhs;
}
/*
* charles::basics::Vector4::operator+= --
*/
Vector4&
Vector4::operator+=(const Vector4 &rhs)
{
mData[0] += rhs.mData[0];
mData[1] += rhs.mData[1];
mData[2] += rhs.mData[2];
return *this;
}
/*
* charles::basics::Vector4::operator-= --
*/
Vector4&
Vector4::operator-=(const Vector4 &rhs)
{
return *this += -rhs;
}
/*
* charles::basics::Vector4::operator- --
*/
Vector4
Vector4::operator-()
const
{
return Vector4(-X(), -Y(), -Z());
}
/*
* charles::basics::Vector4::Length2 --
*/
Double
Vector4::Length2()
const
{
return X()*X() + Y()*Y() + Z()*Z();
}
/*
* charles::basics::Vector4::Length --
*/
Double
Vector4::Length()
const
{
return std::sqrt(Length2());
}
/*
* charles::basics::Vector4::Dot --
*/
Double
Vector4::Dot(const Vector4& rhs)
const
{
return X()*rhs.X() + Y()*rhs.Y() + Z()*rhs.Z();
}
/*
* charles::basics::Vector4::Cross --
*/
Vector4
Vector4::Cross(const Vector4& rhs)
const
{
return Vector4(mData[1]*rhs.mData[2] - mData[2]*rhs.mData[1],
mData[2]*rhs.mData[0] - mData[0]*rhs.mData[2],
mData[0]*rhs.mData[1] - mData[1]*rhs.mData[0]);
}
/*
* charles::basics::Vector4::Normalize --
*/
Vector4&
Vector4::Normalize()
{
return *this /= Length();
}
/*
* charles::basics::operator* --
*/
Vector4
operator*(Double lhs,
const Vector4& rhs)
{
return rhs * lhs;
}
/*
* charles::basics::Normalized --
*/
Vector4
Normalized(Vector4 v)
{
return v.Normalize();
}
/*
* charles::basics::LinearCombination --
*/
Vector4
LinearCombination(const Double k1, const Vector4& v1,
const Double k2, const Vector4& v2,
const Double k3, const Vector4& v3)
{
return Vector4(k1 * v1.X() + k2 * v2.X() + k3 * v3.X(),
k1 * v1.Y() + k2 * v2.Y() + k3 * v3.Y(),
k1 * v1.Z() + k2 * v2.Z() + k3 * v3.Z());
}
/*
* charles::basics::operator<< --
*/
std::ostream&
operator<<(std::ostream& os, const Vector4& v)
{
// Stream the vector like this: <x, y, z>
os << "<" << v.X() << ", " << v.Y() << ", " << v.Z() << ">";
return os;
}
} /* namespace basics */
} /* namespace charles */

110
src/basics/vector.hh Normal file
View file

@ -0,0 +1,110 @@
/* vector.hh
* vim: set tw=80:
* Eryn Wells <eryn@erynwells.me>
*/
#ifndef __BASICS_VECTOR_HH__
#define __BASICS_VECTOR_HH__
#include <ostream>
#include "basics/matrix.hh"
#include "basics/types.hh"
namespace charles {
namespace basics {
/** A 4x1 matrix, used for specifying points and directions in 3D space. */
struct Vector4
{
Vector4();
Vector4(Double x, Double y, Double z);
Vector4(Double x, Double y, Double z, Double w);
Vector4 &operator=(const Vector4 &rhs);
/**
* @defgroup Component access
* @{
*/
Double& X();
Double X() const;
Double& Y();
Double Y() const;
Double& Z();
Double Z() const;
Double &operator()(UInt i);
Double operator()(UInt i) const;
/** Get the underlying C array. */
const Double *CArray() const;
/** @} */
bool operator==(const Vector4 &rhs) const;
bool operator!=(const Vector4 &rhs) const;
/**
* @defgroup Scalar multiplication
* @{
*/
Vector4 operator*(Double rhs) const;
Vector4 operator/(Double rhs) const;
Vector4 &operator*=(Double rhs);
Vector4 &operator/=(Double rhs);
/** @} */
/**
* @defgroup Vector addition and subtraction
* @{
*/
Vector4 operator+(const Vector4 &rhs) const;
Vector4 operator-(const Vector4 &rhs) const;
Vector4 &operator+=(const Vector4 &rhs);
Vector4 &operator-=(const Vector4 &rhs);
/** @} */
/** Negate this vector. */
Vector4 operator-() const;
/** Get the length-squared of this vector. */
Double Length2() const;
/** Get the length of this vector. */
Double Length() const;
/** Get the dot product of `this` and `rhs`. */
Double Dot(const Vector4 &rhs) const;
/** Get the cross product of `this` and `rhs`. */
Vector4 Cross(const Vector4& rhs) const;
/** Normalize this vector. */
Vector4& Normalize();
private:
Double mData[4];
};
/** Scalar multiplication of vectors, with the scalar factor on the left. */
Vector4 operator*(Double lhs, const Vector4 &rhs);
/** Normalize a copy of the given vector. */
Vector4 Normalized(Vector4 v);
Vector4 LinearCombination(Double k1, const Vector4 &v1,
Double k2, const Vector4 &v2,
Double k3, const Vector4 &v3);
std::ostream& operator<<(std::ostream &ost, const Vector4 &v);
} /* namespace basics */
} /* namespace charles */
#endif /* __BASICS_VECTOR_HH__ */

View file

@ -1,150 +1,360 @@
/* camera.h
*
* The Camera is the eye into the scene. It defines several parameters and a single compute_primary_ray method
* that generates rays with which the ray tracer draws the scene.
*
/* camera.cc
* vim: set tw=80:
* Eryn Wells <eryn@erynwells.me>
*/
#include "camera.h"
#include "camera.hh"
#include "log.hh"
#define LOG_NAME "camera"
#include "logModule.hh"
using charles::basics::Ray;
using charles::basics::Vector4;
namespace charles {
#pragma mark - Generic Camera
/*
* charles::Camera::Camera --
*/
Camera::Camera()
: height(Vector3::Y),
width(4.0 / 3.0 * Vector3::X),
direction(Vector3::Z)
: mOrigin(),
mDirection(0, 0, 1),
mRight(1.33, 0, 0),
mUp(0, 1, 0)
{ }
/*
* charles::Camera::Camera --
*/
Camera::Camera(const Camera& rhs)
: mOrigin(rhs.mOrigin),
mDirection(rhs.mDirection),
mRight(rhs.mRight),
mUp(rhs.mUp)
{ }
/*
* charles::Camera::~Camera --
*/
Camera::~Camera()
{ }
/*
* Camera::get_pixel_width --
* Camera::set_pixel_width --
* Camera::get_pixel_height --
* Camera::set_pixel_height --
*
* Get and set pixel width and height.
* Camera::GetOrigin --
*/
int
Camera::get_pixel_width()
const
Vector4&
Camera::GetOrigin()
{
return pwidth;
}
void
Camera::set_pixel_width(const int &w)
{
pwidth = w;
}
int
Camera::get_pixel_height()
const
{
return pheight;
}
void
Camera::set_pixel_height(const int &h)
{
pheight = h;
return mOrigin;
}
/*
* Camera::get_width --
* Camera::set_width --
* Camera::get_height --
* Camera::set_height --
*
* Get and set width and height vectors.
* Camera::GetOrigin --
*/
const Vector3 &
Camera::get_width()
const Vector4&
Camera::GetOrigin()
const
{
return width;
}
void
Camera::set_width(const Vector3 &w)
{
width = w;
}
const Vector3 &
Camera::get_height()
const
{
return height;
}
void
Camera::set_height(const Vector3 &h)
{
height = h;
return mOrigin;
}
/*
* Camera::get_direction --
* Camera::set_direction --
*
* Get and set direction vector.
* Camera::SetOrigin --
*/
const Vector3 &
Camera::get_direction()
const
{
return direction;
}
void
Camera::set_direction(const Vector3 &d)
Camera::SetOrigin(const Vector4& origin)
{
direction = d;
mOrigin = origin;
}
/*
* Camera::get_angle --
*
* Get the angle of view.
* Camera::GetDirection --
*/
float
Camera::get_angle()
Vector4&
Camera::GetDirection()
{
return mDirection;
}
/*
* Camera::GetDirection --
*/
const Vector4&
Camera::GetDirection()
const
{
return angle;
return mDirection;
}
/*
* Camera::SetDirection --
*/
void
Camera::SetDirection(const Vector4& direction)
{
mDirection = direction;
}
/*
* Camera::GetRight --
*/
Vector4&
Camera::GetRight()
{
return mRight;
}
/*
* Camera::GetRight --
*/
const Vector4&
Camera::GetRight()
const
{
return mRight;
}
/*
* Camera::SetRight --
*/
void
Camera::SetRight(const Vector4& right)
{
mRight = right;
}
/*
* Camera::GetUp --
*/
Vector4&
Camera::GetUp()
{
return mUp;
}
/*
* Camera::GetUp --
*/
const Vector4&
Camera::GetUp()
const
{
return mUp;
}
/*
* Camera::SetUp --
*/
void
Camera::SetUp(const Vector4& up)
{
mUp = up;
}
/*
* Camera::IsLeftHanded --
*/
bool
Camera::IsLeftHanded()
const
{
/*
* The cross product of the up and direction vectors is a vector
* perpendicular to the plane containing those vectors. By definition the
* right vector is (in almost all cases) perpendicular to that plane.
*
* The dot product indicates the angle between this vector and the right
* vector. If it's greater than 0, then the vector is pointing right of the
* up-direction plane and the coordinate system is right handed. If less
* than 0, the vector is pointing left of the up-direction plane and the
* coordinate system is left-handed.
*/
return mUp.Cross(mDirection).Dot(mRight) < 0.0;
}
/*
* Camera::LookAt --
*/
void
Camera::LookAt(const Vector4& p)
{
/*
* Precalulate these in order to preserve the aspect ratio and orientation
* of the camera across the LookAt operation.
*/
const Double directionLength = mDirection.Length();
const Double rightLength = mRight.Length();
const Double upLength = mUp.Length();
const bool isLeftHanded = IsLeftHanded();
/* Orient the camera towards the point. */
mDirection = basics::Normalized(p - mOrigin);
/* TODO: Check for zero length direction vector. */
/*
* Create a new right vector, normalized and perpendicular to the plane
* containing the Y unit vector and direction vector.
*
* The up vector is perpendicular to the plane containing the new right
* vector and the direction vector.
*
* TODO: This is always the Y vector. POV-Ray has a sky vector, which
* specifies the vector along which LookAt pans and tilts the camera. It
* might be worth looking into, at some point.
*/
mRight = basics::Normalized(Vector4(0, 1, 0).Cross(mDirection));
mUp = mDirection.Cross(mRight);
/*
* Now, fix up the direction, right, and up vectors so that their magnitudes
* match what they were before the move.
*/
mDirection *= directionLength;
mRight *= isLeftHanded ? rightLength : -rightLength;
mUp *= upLength;
LOG_DEBUG << "Camera is looking at " << p;
}
/*
* charles::Camera::GetTypeString --
*/
std::string
Camera::GetTypeString()
const
{
return "GENERIC";
}
/*
* charles::Camera::WriteType --
*/
void
Camera::WriteType(std::ostream& ost)
const
{
ost << GetTypeString();
}
#pragma mark - Perspective Camera
PerspectiveCamera::PerspectiveCamera()
: Camera()
{ }
PerspectiveCamera::PerspectiveCamera(const Camera& other)
: Camera(other)
{ }
Ray
PerspectiveCamera::PrimaryRay(const int x,
const int width,
const int y,
const int height)
const
{
/*
* Center x and y in the pixel and convert them to be coordinates between
* -0.5 and 0.5.
*/
Double x0 = (x + 0.5) / width - 0.5;
Double y0 = ((height - 1.0) - (y - 0.5)) / height - 0.5;
Vector4 direction = LinearCombination(1.0, GetDirection(),
x0, GetRight(),
y0, GetUp());
return Ray(GetOrigin(), basics::Normalized(direction));
}
std::string
PerspectiveCamera::GetTypeString()
const
{
return "perspective";
}
#pragma mark - Orthographic Camera
OrthographicCamera::OrthographicCamera()
: Camera()
{ }
OrthographicCamera::OrthographicCamera(const Camera& other)
: Camera(other)
{ }
/*
* OrthographicCamera::compute_primary_ray --
*
* Compute a primary ray given an (x,y) coordinate pair. The orthographic camera projects rays parallel to the viewing
* direction through the (x,y) coordinate given. Thus, the size of the orthographic camera should be set to the size of
* the view into the scene.
*/
Ray
OrthographicCamera::compute_primary_ray(const int &x,
const int &y)
OrthographicCamera::PrimaryRay(const int x,
const int width,
const int y,
const int height)
const
{
// Calculate the point on the image plane that the given (x,y) coordinate pair corresponds to.
float dir_x = (x / get_pixel_width()) + 0.5;
float dir_y = (y / get_pixel_height()) + 0.5;
Vector3 ray_origin = (dir_x * get_width()) + (dir_y * get_height()) + get_direction();
/*
* Center x and y in the pixel and convert them to be coordinates between
* -0.5 and 0.5.
*/
Double x0 = (x + 0.5) / width + 0.5;
Double y0 = ((height - 1.0) - (y - 0.5)) / height - 0.5;
// Calculate the direction of the ray, given the camera's origin and normalize that vector.
Vector3 ray_direction = (ray_origin - get_origin()).normalize();
return Ray(get_origin(), ray_direction);
Vector4 origin = LinearCombination(1.0, GetOrigin(),
x0, GetRight(),
y0, GetUp());
return Ray(origin, GetDirection());
}
std::string
OrthographicCamera::GetTypeString()
const
{
return "orthographic";
}
std::ostream&
operator<<(std::ostream& ost,
const Camera& camera)
{
ost << "[Camera ";
camera.WriteType(ost);
ost << " origin=" << camera.mOrigin
<< " direction=" << camera.mDirection
<< " right=" << camera.mRight
<< " up=" << camera.mUp
<< "]";
return ost;
}
} /* namespace charles */

View file

@ -1,60 +0,0 @@
/* camera.h
*
* The Camera is the eye into the scene. It defines several parameters and a single compute_primary_ray method
* that generates rays with which the ray tracer draws the scene.
*
* Eryn Wells <eryn@erynwells.me>
*/
#ifndef __CAMERA_H__
#define __CAMERA_H__
#include "basics.h"
#include "object.h"
class Camera
: public Object
{
public:
Camera();
~Camera();
int get_pixel_width() const;
void set_pixel_width(const int &w);
int get_pixel_height() const;
void set_pixel_height(const int &h);
const Vector3 &get_width() const;
void set_width(const Vector3 &w);
const Vector3 &get_height() const;
void set_height(const Vector3 &h);
const Vector3 &get_direction() const;
void set_direction(const Vector3 &d);
float get_angle() const;
virtual Ray compute_primary_ray(const int &x, const int &y) const = 0;
private:
// Pixel dimensions of the image plane.
int pwidth, pheight;
// Size of the image plane.
Vector3 height, width;
// Direction. A normalized vector defining where the camera is pointed.
Vector3 direction;
// Horizontal viewing angle.
float angle;
};
class OrthographicCamera
: public Camera
{
public:
Ray compute_primary_ray(const int &x, const int &y) const;
};
#endif

124
src/camera.hh Normal file
View file

@ -0,0 +1,124 @@
/* camera.hh
* vim: set tw=80:
* Eryn Wells <eryn@erynwells.me>
*/
#ifndef __CAMERA_H__
#define __CAMERA_H__
#include <memory>
#include "basics/basics.hh"
namespace charles {
/**
* The Camera is the eye into the scene. It defines several parameters and a
* single compute_primary_ray method that generates rays with which the ray
* tracer draws the scene.
*/
struct Camera
{
typedef std::shared_ptr<Camera> Ptr;
Camera();
Camera(const Camera& other);
virtual ~Camera();
basics::Vector4& GetOrigin();
const basics::Vector4& GetOrigin() const;
void SetOrigin(const basics::Vector4& origin);
basics::Vector4& GetDirection();
const basics::Vector4& GetDirection() const;
void SetDirection(const basics::Vector4& direction);
basics::Vector4& GetRight();
const basics::Vector4& GetRight() const;
void SetRight(const basics::Vector4& right);
basics::Vector4& GetUp();
const basics::Vector4& GetUp() const;
void SetUp(const basics::Vector4& up);
/** Get the camera's handedness. Left handed is the default. */
bool IsLeftHanded() const;
/** Pan and tilt the camera towards the given point. */
void LookAt(const basics::Vector4& p);
virtual basics::Ray PrimaryRay(const int x, const int width,
const int y, const int height) const = 0;
virtual std::string GetTypeString() const;
private:
friend std::ostream& operator<<(std::ostream& ost, const Camera& camera);
void WriteType(std::ostream& ost) const;
/**
* The location of the camera in the scene. Depending on the type of camera,
* this is the point from which rays will be emitted.
*/
basics::Vector4 mOrigin;
/** A vector defining where the camera is pointed. */
basics::Vector4 mDirection;
/**
* A vector defining the width of the camera's image plane. The ratio of
* this and mUp determine the aspect ratio of the image.
*/
basics::Vector4 mRight;
/**
* A vector defining the height of the camera's image plane. The ratio of
* this and mRight determine the aspect ratio of the image.
*/
basics::Vector4 mUp;
};
class PerspectiveCamera
: public Camera
{
public:
PerspectiveCamera();
PerspectiveCamera(const Camera& other);
basics::Ray PrimaryRay(const int x, const int width,
const int y, const int height) const;
private:
std::string GetTypeString() const;
};
class OrthographicCamera
: public Camera
{
public:
OrthographicCamera();
OrthographicCamera(const Camera& other);
/**
* Compute a primary ray given an (x,y) coordinate pair. The orthographic
* camera projects rays parallel to the viewing direction through the (x,y)
* coordinate given. Thus, the size of the orthographic camera should be set
* to the size of the view into the scene.
*/
basics::Ray PrimaryRay(const int x, const int width,
const int y, const int height) const;
private:
std::string GetTypeString() const;
};
std::ostream& operator<<(std::ostream& ost, const Camera& camera);
} /* namespace charles */
#endif

View file

@ -6,62 +6,113 @@
*/
#include <cstdio>
#include <unistd.h>
#include "basics.h"
#include "light.h"
#include "material.h"
#include "object_sphere.h"
#include "object_plane.h"
#include "scene.h"
#include "log.hh"
#include "light.hh"
#include "reader_yaml.hh"
#include "scene.hh"
#include "writer_png.h"
#include "basics/basics.hh"
const char *OUT_FILE = "charles_out.png";
#define LOG_NAME "ROOT"
#include "logModule.hh"
using namespace charles;
using namespace charles::basics;
static void
usage(const char *progname)
{
fprintf(stderr, "Usage: %s [-hv] [-l <logfile>] [-L <log level>] [-o <outfile>] <infile ...>\n",
progname);
}
int
main(int argc,
const char *argv[])
{
Scene scene = Scene();
using namespace charles::log;
scene.get_ambient().set_intensity(1.0);
Scene scene;
Material *m1 = new Material();
m1->set_diffuse_color(Color::Red);
Material *m2 = new Material();
m2->set_diffuse_color(Color::Green);
Material *m3 = new Material();
m3->set_diffuse_color(Color::Blue);
Material *m4 = new Material();
m4->set_diffuse_color(Color(1.0, 0.0, 1.0));
PointLight *l1 = new PointLight(Vector4(4.0, 6.0, 1.0), Color::White, 0.8);
scene.AddLight(l1);
// Make some spheres.
Sphere *s1 = new Sphere(Vector3(233, 290, 0), 80.0);
Sphere *s2 = new Sphere(Vector3(407, 290, 0), 80.0);
Sphere *s3 = new Sphere(Vector3(320, 140, 0), 80.0);
Sphere *s4 = new Sphere(Vector3(620, 360, 0), 20.0);
s1->set_material(m1);
s2->set_material(m2);
s3->set_material(m3);
s4->set_material(m4);
scene.add_shape(s1);
scene.add_shape(s2);
scene.add_shape(s3);
scene.add_shape(s4);
bool shouldRender = true;
// Make a plane
Plane *p1 = new Plane(Vector3(0, 460, 400), Vector3(0, 1, 0.01));
p1->set_material(m1);
scene.add_shape(p1);
std::string logFilename;
unsigned int logLevel = 0;
PointLight *l1 = new PointLight(Vector3(0.0, 240.0, 100.0), Color::White, 1.0);
scene.add_light(l1);
std::string outfile, infile;
// Render.
scene.render();
int opt;
while ((opt = getopt(argc, (char *const *)argv, "hl:L:no:v:")) != -1) {
switch (opt) {
case 'h':
usage(argv[0]);
exit(0);
break;
case 'l':
logFilename = optarg;
break;
case 'L':
logLevel = std::stoul(optarg);
break;
case 'n':
shouldRender = false;
break;
case 'o':
outfile = optarg;
break;
case 'v':
break;
}
}
Writer *writer = new PNGWriter();
scene.write(*writer, OUT_FILE);
/* Set up logging */
if (logLevel > 0) {
if (logFilename.empty()) {
logFilename = "charles.log";
}
Log::Init(logFilename, logLevel);
}
if (optind >= argc) {
LOG_ERROR << "Input file required.";
fprintf(stderr, "Input file required.\n");
usage(argv[0]);
return -1;
}
infile = argv[optind];
if (outfile.empty()) {
outfile = "charles_out.png";
}
/* Parse YAML files. */
YAMLReader reader(scene);
for (int i = optind; i < argc; i++) {
reader.read_file(infile);
}
/* Call tracer. */
if (shouldRender) {
LOG_INFO << "Beginning render";
scene.Render();
/* Write rendered scene to PNG file. */
PNGWriter writer;
scene.Write(writer, outfile);
}
if (logLevel > 0) {
Log::Close();
}
return 0;
}

14
src/charles.hh Normal file
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

@ -1,97 +1,81 @@
/* light.cc
*
* Lights light the scene.
*
* vim: set tw=80:
* Eryn Wells <eryn@erynwells.me>
*/
#include "basics.h"
#include "light.h"
#include "object.h"
#include "light.hh"
#pragma mark - Ambient Lights
AmbientLight::AmbientLight()
: AmbientLight(Color::White)
using charles::basics::Color;
namespace charles {
Light::Light(const Color& color,
const Double& intensity)
: mColor(color),
mIntensity(ClampIntensity(intensity))
{ }
AmbientLight::AmbientLight(const Color &c)
: AmbientLight(c, 0.0)
Light::~Light()
{ }
AmbientLight::AmbientLight(const Color &c, const float &i)
: color(c),
intensity(i)
Color&
Light::GetColor()
{
_clamp_intensity();
return mColor;
}
const Color &
AmbientLight::get_color()
const Color&
Light::GetColor()
const
{
return color;
return mColor;
}
const float &
AmbientLight::get_intensity()
const
{
return intensity;
}
void
AmbientLight::set_intensity(const float &i)
Light::SetColor(const Color& color)
{
intensity = i;
_clamp_intensity();
mColor = color;
}
Double
Light::GetIntensity()
const
{
return mIntensity;
}
void
Light::SetIntensity(const Double& intensity)
{
mIntensity = ClampIntensity(intensity);
}
Color
AmbientLight::compute_color_contribution()
Light::Contribution()
const
{
return color * intensity;
return mColor * mIntensity;
}
void
AmbientLight::_clamp_intensity()
Double
Light::ClampIntensity(const Double& intensity)
{
if (intensity < 0.0) {
intensity = 0.0;
}
else if (intensity > 1.0) {
intensity = 1.0;
return 0.0;
} else if (intensity > 1.0) {
return 1.0;
}
return intensity;
}
#pragma mark - Point Lights
PointLight::PointLight()
: PointLight(Vector3())
{ }
PointLight::PointLight(const Vector3 &o)
: PointLight(o, Color::White)
{ }
PointLight::PointLight(const Vector3 &o,
const Color &c)
: PointLight(o, c, 1.0)
{ }
PointLight::PointLight(const Vector3 &o,
const Color &c,
const float &i)
: AmbientLight(c, i),
Object(o)
{ }
} /* namespace charles */

View file

@ -1,48 +0,0 @@
/* light.h
*
* Lights light the scene.
*
* Eryn Wells <eryn@erynwells.me>
*/
#ifndef __LIGHT_H__
#define __LIGHT_H__
#include "basics.h"
#include "object.h"
class AmbientLight
{
public:
AmbientLight();
AmbientLight(const Color &c);
AmbientLight(const Color &c, const float &i);
const Color &get_color() const;
const float &get_intensity() const;
void set_intensity(const float &i);
Color compute_color_contribution() const;
protected:
Color color;
float intensity;
private:
void _clamp_intensity();
};
class PointLight
: public AmbientLight,
public Object
{
public:
PointLight();
PointLight(const Vector3 &o);
PointLight(const Vector3 &o, const Color &c);
PointLight(const Vector3 &o, const Color &c, const float &i);
};
#endif

52
src/light.hh Normal file
View file

@ -0,0 +1,52 @@
/* light.hh
* vim: set tw=80:
* Eryn Wells <eryn@erynwells.me>
*/
#ifndef __LIGHT_H__
#define __LIGHT_H__
#include <memory>
#include "basics/basics.hh"
namespace charles {
struct Light
{
typedef std::shared_ptr<Light> Ptr;
Light(const basics::Color& color,
const Double& intensity = 1.0);
virtual ~Light();
basics::Color& GetColor();
const basics::Color& GetColor() const;
void SetColor(const basics::Color& color);
Double GetIntensity() const;
void SetIntensity(const Double& intensity);
virtual basics::Color Contribution() const;
private:
Double ClampIntensity(const Double& intensity);
/** The color of the light. */
basics::Color mColor;
/**
* The intensity of the light. Normal values range from 0.0 to 1.0, but
* they can be set higher.
*/
Double mIntensity;
};
typedef Light AmbientLight;
} /* namespace charles */
#endif

37
src/lightPoint.cc Normal file
View file

@ -0,0 +1,37 @@
/* lightPoint.cc
* vim: set tw=80:
* Eryn Wells <eryn@erynwells.me>
*/
#include "lightPoint.hh"
using charles::basics::Color;
using charles::basics::Vector4;
namespace charles {
PointLight::PointLight(const Vector4& origin,
const Color& color,
const Double& intensity)
: Light(color, intensity),
mOrigin(origin)
{ }
Vector4&
PointLight::GetOrigin()
{
return mOrigin;
}
void
PointLight::SetOrigin(const Vector4& origin)
{
mOrigin = origin;
}
} /* namespace charles */

35
src/lightPoint.hh Normal file
View file

@ -0,0 +1,35 @@
/* lightPoint.hh
* vim: set tw=80:
* Eryn Wells <eryn@erynwells.me>
*/
#ifndef __LIGHTPOINT_HH__
#define __LIGHTPOINT_HH__
#include "light.hh"
namespace charles {
/**
* The simplest light source. Emits light in all directions uniformly, without
* falloff.
*/
class PointLight
: public Light
{
public:
PointLight(const basics::Vector4 &origin,
const basics::Color& color,
const Double& intensity);
basics::Vector4& GetOrigin();
void SetOrigin(const basics::Vector4& origin);
private:
basics::Vector4 mOrigin;
};
} /* namespace charles */
#endif /* __LIGHTPOINT_HH__ */

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

@ -1,85 +1,88 @@
/* material.h
*
* Materials are applied to shapes and determine color, texture mapping, shading, etc.
*
/* material.cc
* vim: set tw=80:
* Eryn Wells <eryn@erynwells.me>
*/
#include "material.h"
#include "material.hh"
using charles::basics::Color;
namespace charles {
Material::Material()
: diffuse_level(0.8),
diffuse_color(Color::White),
specular_level(0.5),
specular_color(Color::White)
: mDiffuseModel(DiffuseShaderModel::Lambert),
mDiffuseIntensity(0.8),
mDiffuseColor(Color::White),
mSpecularModel(SpecularShaderModel::Phong),
mSpecularIntensity(0.0),
mSpecularColor(Color::White)
{ }
float
Material::get_diffuse_level()
Double
Material::GetDiffuseIntensity()
const
{
return diffuse_level;
return mDiffuseIntensity;
}
void
Material::set_diffuse_level(const float &kd)
Material::SetDiffuseIntensity(const Double& kd)
{
diffuse_level = kd;
_clamp_parameter(diffuse_level);
mDiffuseIntensity = kd;
ClampParameter(mDiffuseIntensity);
}
const Color &
Material::get_diffuse_color()
Color&
Material::GetDiffuseColor()
{
return mDiffuseColor;
}
void
Material::SetDiffuseColor(const Color& color)
{
mDiffuseColor = color;
}
Double
Material::GetSpecularIntensity()
const
{
return diffuse_color;
return mSpecularIntensity;
}
void
Material::set_diffuse_color(const Color &c)
Material::SetSpecularIntensity(const Double& ks)
{
diffuse_color = c;
mSpecularIntensity = ks;
ClampParameter(mSpecularIntensity);
}
float
Material::get_specular_level()
const
Color&
Material::GetSpecularColor()
{
return specular_level;
return mSpecularColor;
}
void
Material::set_specular_level(const float &ks)
Material::SetSpecularColor(const Color& color)
{
specular_level = ks;
_clamp_parameter(specular_level);
}
const Color &
Material::get_specular_color()
const
{
return specular_color;
mSpecularColor = color;
}
void
Material::set_specular_color(const Color &c)
{
specular_color = c;
}
void
Material::_clamp_parameter(float &param)
Material::ClampParameter(Double& param)
{
if (param < 0.0) {
param = 0.0;
@ -88,3 +91,5 @@ Material::_clamp_parameter(float &param)
param = 1.0;
}
}
} /* namespace charles */

View file

@ -1,45 +0,0 @@
/* material.h
*
* Materials are applied to shapes and determine color, texture mapping, shading, etc.
*
* Eryn Wells <eryn@erynwells.me>
*/
#ifndef __MATERIAL_H__
#define __MATERIAL_H__
#include "basics.h"
class Material
{
public:
enum {
DiffuseLightingTypeLambert = 1,
} DiffuseLightingType;
Material();
float get_diffuse_level() const;
void set_diffuse_level(const float &kd);
const Color &get_diffuse_color() const;
void set_diffuse_color(const Color &c);
float get_specular_level() const;
void set_specular_level(const float &kd);
const Color &get_specular_color() const;
void set_specular_color(const Color &c);
private:
void _clamp_parameter(float &param);
// Diffuse parameters.
float diffuse_level;
Color diffuse_color;
// Specular parameters.
float specular_level;
Color specular_color;
};
#endif

59
src/material.hh Normal file
View file

@ -0,0 +1,59 @@
/* material.hh
* vim: set tw=80:
* Eryn Wells <eryn@erynwells.me>
*/
#ifndef __MATERIAL_HH__
#define __MATERIAL_HH__
#include "basics/basics.hh"
namespace charles {
/**
* Materials are applied to shapes and determine color, texture mapping,
* shading, etc.
*/
struct Material
{
enum class DiffuseShaderModel {
Lambert,
};
enum class SpecularShaderModel {
Blinn,
Phong
};
Material();
Double GetDiffuseIntensity() const;
void SetDiffuseIntensity(const Double& kd);
basics::Color& GetDiffuseColor();
void SetDiffuseColor(const basics::Color& c);
Double GetSpecularIntensity() const;
void SetSpecularIntensity(const Double& kd);
basics::Color& GetSpecularColor();
void SetSpecularColor(const basics::Color& c);
private:
void ClampParameter(Double& param);
// Diffuse parameters.
DiffuseShaderModel mDiffuseModel;
Double mDiffuseIntensity;
basics::Color mDiffuseColor;
// Specular parameters.
SpecularShaderModel mSpecularModel;
Double mSpecularIntensity;
basics::Color mSpecularColor;
};
} /* namespace charles */
#endif

View file

@ -9,106 +9,148 @@
#include <cmath>
#include <cstdlib>
#include "basics.h"
#include "material.h"
#include "object.h"
#include "object.hh"
#pragma mark - Objects
#include "material.hh"
#include "basics/basics.hh"
using charles::basics::Ray;
using charles::basics::Matrix4;
using charles::basics::Vector4;
namespace charles {
/*
* Object::Object --
*
* Default constructor. Create a new Object with an origin at (0, 0, 0).
* charles::Object::Object --
*/
Object::Object()
: Object(Vector3::Zero)
Object::Object(const Vector4& origin)
: mTranslation(Matrix4::Translation(origin)),
mMaterial()
{ }
/*
* Object::Object --
*
* Constructor. Create a new Object with an origin at o.
* charles::Object::~Object --
*/
Object::Object(Vector3 o)
: origin(o)
Object::~Object()
{ }
/*
* Object::get_origin --
* Object::set_origin --
*
* Get and set the Object's origin.
* charles::Object::GetMaterial --
*/
Vector3
Object::get_origin()
Material&
Object::GetMaterial()
{
return mMaterial;
}
/*
* charles::Object::Place --
*/
void
Object::Place(const Vector4 &p)
{
mTranslation = Matrix4::Translation(-p);
}
/*
* charles::Object::SetMaterial --
*/
void
Object::SetMaterial(const Material& material)
{
mMaterial = material;
}
/*
* charles::Object::Intersect --
*/
bool
Object::Intersect(const basics::Ray& ray,
TVector& t,
Stats& stats)
const
{
return origin;
}
void
Object::set_origin(Vector3 v)
{
origin = v;
Ray objSpaceRay = ToObjectSpace(ray);
return DoIntersect(objSpaceRay, t, stats);
}
std::ostream &
operator<<(std::ostream &os, const Object &o)
{
// Stream objects like this: [Object origin]
os << "[Object " << o.origin << "]";
return os;
}
#pragma mark - Shapes
/*
* Shape::Shape --
*
* Default constructor. Create a new Shape with an origin at (0, 0, 0).
* charles::Object::Normal --
*/
Shape::Shape()
: Object()
{ }
/*
* Shape::Shape --
*
* Constructor. Create a new Shape with an origin at o.
*/
Shape::Shape(Vector3 o)
: Object(o)
{ }
/*
* Shape::~Shape() --
*
* Destructor.
*/
Shape::~Shape()
{ }
/*
* Shape::get_material --
* Shape::set_material --
*
* Get and set the Material applied to this shape.
*/
Material &
Shape::get_material()
Vector4
Object::Normal(const Vector4& p)
const
{
return *material;
Vector4 norm = Transpose(mTranslation) * DoNormal(ToObjectSpace(p));
return norm;
}
void
Shape::set_material(Material *mat)
/*
* charles::Object::ToObjectSpace --
*/
Ray
Object::ToObjectSpace(Ray ray)
const
{
material = mat;
ray.origin = ToObjectSpace(ray.origin);
//ray.direction = ToObjectSpace(ray.direction).Normalize();
return ray;
}
/*
* charles::Object::ToObjectSpace --
*/
Vector4
Object::ToObjectSpace(const Vector4& v)
const
{
return mTranslation * v;
}
/*
* charles::Object::FromObjectSpace --
*/
Vector4
Object::FromObjectSpace(const Vector4& v)
const
{
return Inverse(mTranslation) * v;
}
/*
* charles::Object::Write --
*/
void
Object::Write(std::ostream& ost)
const
{
ost << "[Object]";
}
/*
* charles::operator<< --
*/
std::ostream&
operator<<(std::ostream& ost,
const Object& object)
{
ost << "[";
object.Write(ost);
ost << " translate=" << object.mTranslation.Column(3) << "]";
return ost;
}
} /* namespace charles */

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