Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/extern
diff options
context:
space:
mode:
Diffstat (limited to 'extern')
-rw-r--r--extern/ceres/CMakeLists.txt576
-rw-r--r--extern/ceres/ChangeLog839
-rwxr-xr-xextern/ceres/bundle.sh9
-rw-r--r--extern/ceres/files.txt81
-rw-r--r--extern/ceres/include/ceres/autodiff_cost_function.h89
-rw-r--r--extern/ceres/include/ceres/autodiff_first_order_function.h151
-rw-r--r--extern/ceres/include/ceres/autodiff_local_parameterization.h40
-rw-r--r--extern/ceres/include/ceres/c_api.h4
-rw-r--r--extern/ceres/include/ceres/ceres.h9
-rw-r--r--extern/ceres/include/ceres/conditioned_cost_function.h16
-rw-r--r--extern/ceres/include/ceres/context.h56
-rw-r--r--extern/ceres/include/ceres/cost_function.h27
-rw-r--r--extern/ceres/include/ceres/cost_function_to_functor.h612
-rw-r--r--extern/ceres/include/ceres/covariance.h79
-rw-r--r--extern/ceres/include/ceres/crs_matrix.h5
-rw-r--r--extern/ceres/include/ceres/cubic_interpolation.h436
-rw-r--r--extern/ceres/include/ceres/dynamic_autodiff_cost_function.h95
-rw-r--r--extern/ceres/include/ceres/dynamic_cost_function.h56
-rw-r--r--extern/ceres/include/ceres/dynamic_cost_function_to_functor.h62
-rw-r--r--extern/ceres/include/ceres/dynamic_numeric_diff_cost_function.h125
-rw-r--r--extern/ceres/include/ceres/evaluation_callback.h80
-rw-r--r--extern/ceres/include/ceres/first_order_function.h54
-rw-r--r--extern/ceres/include/ceres/gradient_checker.h23
-rw-r--r--extern/ceres/include/ceres/gradient_problem.h25
-rw-r--r--extern/ceres/include/ceres/gradient_problem_solver.h128
-rw-r--r--extern/ceres/include/ceres/internal/array_selector.h95
-rw-r--r--extern/ceres/include/ceres/internal/autodiff.h291
-rw-r--r--extern/ceres/include/ceres/internal/disable_warnings.h2
-rw-r--r--extern/ceres/include/ceres/internal/eigen.h41
-rw-r--r--extern/ceres/include/ceres/internal/fixed_array.h573
-rw-r--r--extern/ceres/include/ceres/internal/householder_vector.h (renamed from extern/ceres/internal/ceres/householder_vector.h)19
-rw-r--r--extern/ceres/include/ceres/internal/integer_sequence_algorithm.h165
-rw-r--r--extern/ceres/include/ceres/internal/line_parameterization.h183
-rw-r--r--extern/ceres/include/ceres/internal/macros.h170
-rw-r--r--extern/ceres/include/ceres/internal/manual_constructor.h208
-rw-r--r--extern/ceres/include/ceres/internal/memory.h90
-rw-r--r--extern/ceres/include/ceres/internal/numeric_diff.h198
-rw-r--r--extern/ceres/include/ceres/internal/parameter_dims.h124
-rw-r--r--extern/ceres/include/ceres/internal/port.h62
-rw-r--r--extern/ceres/include/ceres/internal/scoped_ptr.h310
-rw-r--r--extern/ceres/include/ceres/internal/variadic_evaluate.h210
-rw-r--r--extern/ceres/include/ceres/iteration_callback.h64
-rw-r--r--extern/ceres/include/ceres/jet.h693
-rw-r--r--extern/ceres/include/ceres/local_parameterization.h186
-rw-r--r--extern/ceres/include/ceres/loss_function.h85
-rw-r--r--extern/ceres/include/ceres/normal_prior.h12
-rw-r--r--extern/ceres/include/ceres/numeric_diff_cost_function.h147
-rw-r--r--extern/ceres/include/ceres/numeric_diff_options.h22
-rw-r--r--extern/ceres/include/ceres/ordered_groups.h47
-rw-r--r--extern/ceres/include/ceres/problem.h235
-rw-r--r--extern/ceres/include/ceres/rotation.h255
-rw-r--r--extern/ceres/include/ceres/sized_cost_function.h51
-rw-r--r--extern/ceres/include/ceres/solver.h494
-rw-r--r--extern/ceres/include/ceres/tiny_solver.h368
-rw-r--r--extern/ceres/include/ceres/tiny_solver_autodiff_function.h206
-rw-r--r--extern/ceres/include/ceres/tiny_solver_cost_function_adapter.h142
-rw-r--r--extern/ceres/include/ceres/types.h71
-rw-r--r--extern/ceres/include/ceres/version.h6
-rw-r--r--extern/ceres/internal/ceres/accelerate_sparse.cc289
-rw-r--r--extern/ceres/internal/ceres/accelerate_sparse.h147
-rw-r--r--extern/ceres/internal/ceres/array_utils.cc14
-rw-r--r--extern/ceres/internal/ceres/array_utils.h4
-rw-r--r--extern/ceres/internal/ceres/block_jacobi_preconditioner.cc1
-rw-r--r--extern/ceres/internal/ceres/block_jacobi_preconditioner.h18
-rw-r--r--extern/ceres/internal/ceres/block_jacobian_writer.cc3
-rw-r--r--extern/ceres/internal/ceres/block_jacobian_writer.h1
-rw-r--r--extern/ceres/internal/ceres/block_random_access_dense_matrix.cc1
-rw-r--r--extern/ceres/internal/ceres/block_random_access_dense_matrix.h29
-rw-r--r--extern/ceres/internal/ceres/block_random_access_diagonal_matrix.cc6
-rw-r--r--extern/ceres/internal/ceres/block_random_access_diagonal_matrix.h34
-rw-r--r--extern/ceres/internal/ceres/block_random_access_matrix.h17
-rw-r--r--extern/ceres/internal/ceres/block_random_access_sparse_matrix.cc53
-rw-r--r--extern/ceres/internal/ceres/block_random_access_sparse_matrix.h46
-rw-r--r--extern/ceres/internal/ceres/block_sparse_matrix.cc182
-rw-r--r--extern/ceres/internal/ceres/block_sparse_matrix.h102
-rw-r--r--extern/ceres/internal/ceres/block_structure.h9
-rw-r--r--extern/ceres/internal/ceres/c_api.cc6
-rw-r--r--extern/ceres/internal/ceres/callbacks.cc24
-rw-r--r--extern/ceres/internal/ceres/callbacks.h19
-rw-r--r--extern/ceres/internal/ceres/canonical_views_clustering.cc232
-rw-r--r--extern/ceres/internal/ceres/canonical_views_clustering.h124
-rw-r--r--extern/ceres/internal/ceres/cgnr_linear_operator.h12
-rw-r--r--extern/ceres/internal/ceres/cgnr_solver.cc39
-rw-r--r--extern/ceres/internal/ceres/cgnr_solver.h13
-rw-r--r--extern/ceres/internal/ceres/collections_port.h196
-rw-r--r--extern/ceres/internal/ceres/compressed_col_sparse_matrix_utils.cc6
-rw-r--r--extern/ceres/internal/ceres/compressed_row_jacobian_writer.cc6
-rw-r--r--extern/ceres/internal/ceres/compressed_row_jacobian_writer.h2
-rw-r--r--extern/ceres/internal/ceres/compressed_row_sparse_matrix.cc682
-rw-r--r--extern/ceres/internal/ceres/compressed_row_sparse_matrix.h173
-rw-r--r--extern/ceres/internal/ceres/concurrent_queue.h159
-rw-r--r--extern/ceres/internal/ceres/conditioned_cost_function.cc2
-rw-r--r--extern/ceres/internal/ceres/conjugate_gradients_solver.cc13
-rw-r--r--extern/ceres/internal/ceres/conjugate_gradients_solver.h10
-rw-r--r--extern/ceres/internal/ceres/context.cc41
-rw-r--r--extern/ceres/internal/ceres/context_impl.cc43
-rw-r--r--extern/ceres/internal/ceres/context_impl.h67
-rw-r--r--extern/ceres/internal/ceres/coordinate_descent_minimizer.cc137
-rw-r--r--extern/ceres/internal/ceres/coordinate_descent_minimizer.h14
-rw-r--r--extern/ceres/internal/ceres/corrector.cc4
-rw-r--r--extern/ceres/internal/ceres/corrector.h2
-rw-r--r--extern/ceres/internal/ceres/covariance.cc10
-rw-r--r--extern/ceres/internal/ceres/covariance_impl.cc257
-rw-r--r--extern/ceres/internal/ceres/covariance_impl.h8
-rw-r--r--extern/ceres/internal/ceres/cxsparse.cc284
-rw-r--r--extern/ceres/internal/ceres/cxsparse.h59
-rw-r--r--extern/ceres/internal/ceres/dense_normal_cholesky_solver.cc1
-rw-r--r--extern/ceres/internal/ceres/dense_normal_cholesky_solver.h6
-rw-r--r--extern/ceres/internal/ceres/dense_qr_solver.cc2
-rw-r--r--extern/ceres/internal/ceres/dense_qr_solver.h6
-rw-r--r--extern/ceres/internal/ceres/dense_sparse_matrix.cc2
-rw-r--r--extern/ceres/internal/ceres/dense_sparse_matrix.h28
-rw-r--r--extern/ceres/internal/ceres/dogleg_strategy.cc12
-rw-r--r--extern/ceres/internal/ceres/dogleg_strategy.h15
-rw-r--r--extern/ceres/internal/ceres/dynamic_compressed_row_jacobian_writer.cc41
-rw-r--r--extern/ceres/internal/ceres/dynamic_compressed_row_sparse_matrix.h4
-rw-r--r--extern/ceres/internal/ceres/dynamic_sparse_normal_cholesky_solver.cc286
-rw-r--r--extern/ceres/internal/ceres/dynamic_sparse_normal_cholesky_solver.h86
-rw-r--r--extern/ceres/internal/ceres/eigensparse.cc190
-rw-r--r--extern/ceres/internal/ceres/eigensparse.h90
-rw-r--r--extern/ceres/internal/ceres/evaluator.cc8
-rw-r--r--extern/ceres/internal/ceres/evaluator.h61
-rw-r--r--extern/ceres/internal/ceres/execution_summary.h38
-rw-r--r--extern/ceres/internal/ceres/float_cxsparse.cc47
-rw-r--r--extern/ceres/internal/ceres/float_cxsparse.h58
-rw-r--r--extern/ceres/internal/ceres/float_suitesparse.cc47
-rw-r--r--extern/ceres/internal/ceres/float_suitesparse.h58
-rw-r--r--extern/ceres/internal/ceres/function_sample.cc (renamed from extern/ceres/internal/ceres/integral_types.h)86
-rw-r--r--extern/ceres/internal/ceres/function_sample.h94
-rw-r--r--extern/ceres/internal/ceres/generate_template_specializations.py246
-rw-r--r--extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_2_2.cc5
-rw-r--r--extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_2_3.cc5
-rw-r--r--extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_2_4.cc5
-rw-r--r--extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_2_d.cc5
-rw-r--r--extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_3_3.cc5
-rw-r--r--extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_3_4.cc5
-rw-r--r--extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_3_6.cc5
-rw-r--r--extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_3_9.cc5
-rw-r--r--extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_3_d.cc5
-rw-r--r--extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_4_3.cc5
-rw-r--r--extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_4_4.cc5
-rw-r--r--extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_4_6.cc58
-rw-r--r--extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_4_8.cc5
-rw-r--r--extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_4_9.cc5
-rw-r--r--extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_4_d.cc5
-rw-r--r--extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_d_d.cc5
-rw-r--r--extern/ceres/internal/ceres/generated/partitioned_matrix_view_3_3_3.cc58
-rw-r--r--extern/ceres/internal/ceres/generated/partitioned_matrix_view_4_4_2.cc5
-rw-r--r--extern/ceres/internal/ceres/generated/partitioned_matrix_view_4_4_3.cc5
-rw-r--r--extern/ceres/internal/ceres/generated/partitioned_matrix_view_4_4_4.cc5
-rw-r--r--extern/ceres/internal/ceres/generated/partitioned_matrix_view_4_4_d.cc5
-rw-r--r--extern/ceres/internal/ceres/generated/partitioned_matrix_view_d_d_d.cc5
-rw-r--r--extern/ceres/internal/ceres/generated/schur_eliminator_2_2_2.cc5
-rw-r--r--extern/ceres/internal/ceres/generated/schur_eliminator_2_2_3.cc5
-rw-r--r--extern/ceres/internal/ceres/generated/schur_eliminator_2_2_4.cc5
-rw-r--r--extern/ceres/internal/ceres/generated/schur_eliminator_2_2_d.cc5
-rw-r--r--extern/ceres/internal/ceres/generated/schur_eliminator_2_3_3.cc5
-rw-r--r--extern/ceres/internal/ceres/generated/schur_eliminator_2_3_4.cc5
-rw-r--r--extern/ceres/internal/ceres/generated/schur_eliminator_2_3_6.cc5
-rw-r--r--extern/ceres/internal/ceres/generated/schur_eliminator_2_3_9.cc5
-rw-r--r--extern/ceres/internal/ceres/generated/schur_eliminator_2_3_d.cc5
-rw-r--r--extern/ceres/internal/ceres/generated/schur_eliminator_2_4_3.cc5
-rw-r--r--extern/ceres/internal/ceres/generated/schur_eliminator_2_4_4.cc5
-rw-r--r--extern/ceres/internal/ceres/generated/schur_eliminator_2_4_6.cc58
-rw-r--r--extern/ceres/internal/ceres/generated/schur_eliminator_2_4_8.cc5
-rw-r--r--extern/ceres/internal/ceres/generated/schur_eliminator_2_4_9.cc5
-rw-r--r--extern/ceres/internal/ceres/generated/schur_eliminator_2_4_d.cc5
-rw-r--r--extern/ceres/internal/ceres/generated/schur_eliminator_2_d_d.cc5
-rw-r--r--extern/ceres/internal/ceres/generated/schur_eliminator_3_3_3.cc58
-rw-r--r--extern/ceres/internal/ceres/generated/schur_eliminator_4_4_2.cc5
-rw-r--r--extern/ceres/internal/ceres/generated/schur_eliminator_4_4_3.cc5
-rw-r--r--extern/ceres/internal/ceres/generated/schur_eliminator_4_4_4.cc5
-rw-r--r--extern/ceres/internal/ceres/generated/schur_eliminator_4_4_d.cc5
-rw-r--r--extern/ceres/internal/ceres/generated/schur_eliminator_d_d_d.cc5
-rw-r--r--extern/ceres/internal/ceres/gradient_checker.cc19
-rw-r--r--extern/ceres/internal/ceres/gradient_checking_cost_function.cc34
-rw-r--r--extern/ceres/internal/ceres/gradient_checking_cost_function.h7
-rw-r--r--extern/ceres/internal/ceres/gradient_problem_evaluator.h43
-rw-r--r--extern/ceres/internal/ceres/gradient_problem_solver.cc89
-rw-r--r--extern/ceres/internal/ceres/graph.h55
-rw-r--r--extern/ceres/internal/ceres/graph_algorithms.h84
-rw-r--r--extern/ceres/internal/ceres/implicit_schur_complement.cc1
-rw-r--r--extern/ceres/internal/ceres/implicit_schur_complement.h16
-rw-r--r--extern/ceres/internal/ceres/inner_product_computer.cc330
-rw-r--r--extern/ceres/internal/ceres/inner_product_computer.h157
-rw-r--r--extern/ceres/internal/ceres/invert_psd_matrix.h79
-rw-r--r--extern/ceres/internal/ceres/iterative_refiner.cc74
-rw-r--r--extern/ceres/internal/ceres/iterative_refiner.h93
-rw-r--r--extern/ceres/internal/ceres/iterative_schur_complement_solver.cc108
-rw-r--r--extern/ceres/internal/ceres/iterative_schur_complement_solver.h16
-rw-r--r--extern/ceres/internal/ceres/lapack.cc3
-rw-r--r--extern/ceres/internal/ceres/levenberg_marquardt_strategy.cc12
-rw-r--r--extern/ceres/internal/ceres/levenberg_marquardt_strategy.h12
-rw-r--r--extern/ceres/internal/ceres/line_search.cc219
-rw-r--r--extern/ceres/internal/ceres/line_search.h98
-rw-r--r--extern/ceres/internal/ceres/line_search_minimizer.cc122
-rw-r--r--extern/ceres/internal/ceres/line_search_minimizer.h6
-rw-r--r--extern/ceres/internal/ceres/line_search_preprocessor.cc7
-rw-r--r--extern/ceres/internal/ceres/line_search_preprocessor.h6
-rw-r--r--extern/ceres/internal/ceres/linear_least_squares_problems.cc19
-rw-r--r--extern/ceres/internal/ceres/linear_least_squares_problems.h15
-rw-r--r--extern/ceres/internal/ceres/linear_solver.cc15
-rw-r--r--extern/ceres/internal/ceres/linear_solver.h122
-rw-r--r--extern/ceres/internal/ceres/local_parameterization.cc154
-rw-r--r--extern/ceres/internal/ceres/loss_function.cc19
-rw-r--r--extern/ceres/internal/ceres/low_rank_inverse_hessian.cc10
-rw-r--r--extern/ceres/internal/ceres/low_rank_inverse_hessian.h10
-rw-r--r--extern/ceres/internal/ceres/minimizer.h9
-rw-r--r--extern/ceres/internal/ceres/mutex.h329
-rw-r--r--extern/ceres/internal/ceres/normal_prior.cc1
-rw-r--r--extern/ceres/internal/ceres/pair_hash.h112
-rw-r--r--extern/ceres/internal/ceres/parallel_for.h67
-rw-r--r--extern/ceres/internal/ceres/parallel_for_cxx.cc247
-rw-r--r--extern/ceres/internal/ceres/parallel_for_nothreads.cc78
-rw-r--r--extern/ceres/internal/ceres/parallel_for_openmp.cc88
-rw-r--r--extern/ceres/internal/ceres/parallel_utils.cc90
-rw-r--r--extern/ceres/internal/ceres/parallel_utils.h67
-rw-r--r--extern/ceres/internal/ceres/parameter_block.h217
-rw-r--r--extern/ceres/internal/ceres/parameter_block_ordering.cc35
-rw-r--r--extern/ceres/internal/ceres/partitioned_matrix_view.cc224
-rw-r--r--extern/ceres/internal/ceres/partitioned_matrix_view.h28
-rw-r--r--extern/ceres/internal/ceres/partitioned_matrix_view_impl.h2
-rw-r--r--extern/ceres/internal/ceres/partitioned_matrix_view_template.py (renamed from extern/ceres/internal/ceres/generate_partitioned_matrix_view_specializations.py)86
-rw-r--r--extern/ceres/internal/ceres/polynomial.cc18
-rw-r--r--extern/ceres/internal/ceres/polynomial.h24
-rw-r--r--extern/ceres/internal/ceres/preconditioner.cc3
-rw-r--r--extern/ceres/internal/ceres/preconditioner.h54
-rw-r--r--extern/ceres/internal/ceres/preprocessor.cc25
-rw-r--r--extern/ceres/internal/ceres/preprocessor.h21
-rw-r--r--extern/ceres/internal/ceres/problem.cc207
-rw-r--r--extern/ceres/internal/ceres/problem_impl.cc629
-rw-r--r--extern/ceres/internal/ceres/problem_impl.h121
-rw-r--r--extern/ceres/internal/ceres/program.cc153
-rw-r--r--extern/ceres/internal/ceres/program.h15
-rw-r--r--extern/ceres/internal/ceres/program_evaluator.h252
-rw-r--r--extern/ceres/internal/ceres/random.h6
-rw-r--r--extern/ceres/internal/ceres/reorder_program.cc87
-rw-r--r--extern/ceres/internal/ceres/reorder_program.h17
-rw-r--r--extern/ceres/internal/ceres/residual_block.cc48
-rw-r--r--extern/ceres/internal/ceres/residual_block.h11
-rw-r--r--extern/ceres/internal/ceres/residual_block_utils.cc4
-rw-r--r--extern/ceres/internal/ceres/schur_complement_solver.cc442
-rw-r--r--extern/ceres/internal/ceres/schur_complement_solver.h102
-rw-r--r--extern/ceres/internal/ceres/schur_eliminator.cc204
-rw-r--r--extern/ceres/internal/ceres/schur_eliminator.h352
-rw-r--r--extern/ceres/internal/ceres/schur_eliminator_impl.h336
-rw-r--r--extern/ceres/internal/ceres/schur_eliminator_template.py (renamed from extern/ceres/internal/ceres/generate_eliminator_specialization.py)86
-rw-r--r--extern/ceres/internal/ceres/schur_jacobi_preconditioner.cc35
-rw-r--r--extern/ceres/internal/ceres/schur_jacobi_preconditioner.h21
-rw-r--r--extern/ceres/internal/ceres/schur_templates.cc227
-rw-r--r--extern/ceres/internal/ceres/schur_templates.h46
-rw-r--r--extern/ceres/internal/ceres/scoped_thread_token.h61
-rw-r--r--extern/ceres/internal/ceres/scratch_evaluate_preparer.h4
-rw-r--r--extern/ceres/internal/ceres/single_linkage_clustering.cc94
-rw-r--r--extern/ceres/internal/ceres/single_linkage_clustering.h (renamed from extern/ceres/include/ceres/fpclassify.h)60
-rw-r--r--extern/ceres/internal/ceres/small_blas.h244
-rw-r--r--extern/ceres/internal/ceres/small_blas_generic.h315
-rw-r--r--extern/ceres/internal/ceres/solver.cc398
-rw-r--r--extern/ceres/internal/ceres/solver_utils.cc6
-rw-r--r--extern/ceres/internal/ceres/sparse_cholesky.cc163
-rw-r--r--extern/ceres/internal/ceres/sparse_cholesky.h138
-rw-r--r--extern/ceres/internal/ceres/sparse_matrix.h2
-rw-r--r--extern/ceres/internal/ceres/sparse_normal_cholesky_solver.cc467
-rw-r--r--extern/ceres/internal/ceres/sparse_normal_cholesky_solver.h83
-rw-r--r--extern/ceres/internal/ceres/split.cc2
-rw-r--r--extern/ceres/internal/ceres/stringprintf.cc22
-rw-r--r--extern/ceres/internal/ceres/subset_preconditioner.cc117
-rw-r--r--extern/ceres/internal/ceres/subset_preconditioner.h91
-rw-r--r--extern/ceres/internal/ceres/suitesparse.cc430
-rw-r--r--extern/ceres/internal/ceres/suitesparse.h44
-rw-r--r--extern/ceres/internal/ceres/thread_pool.cc116
-rw-r--r--extern/ceres/internal/ceres/thread_pool.h120
-rw-r--r--extern/ceres/internal/ceres/thread_token_provider.cc76
-rw-r--r--extern/ceres/internal/ceres/thread_token_provider.h97
-rw-r--r--extern/ceres/internal/ceres/triplet_sparse_matrix.cc77
-rw-r--r--extern/ceres/internal/ceres/triplet_sparse_matrix.h62
-rw-r--r--extern/ceres/internal/ceres/trust_region_minimizer.cc73
-rw-r--r--extern/ceres/internal/ceres/trust_region_minimizer.h12
-rw-r--r--extern/ceres/internal/ceres/trust_region_preprocessor.cc173
-rw-r--r--extern/ceres/internal/ceres/trust_region_preprocessor.h6
-rw-r--r--extern/ceres/internal/ceres/trust_region_step_evaluator.cc10
-rw-r--r--extern/ceres/internal/ceres/trust_region_step_evaluator.h4
-rw-r--r--extern/ceres/internal/ceres/trust_region_strategy.h54
-rw-r--r--extern/ceres/internal/ceres/types.cc51
-rw-r--r--extern/ceres/internal/ceres/visibility.cc152
-rw-r--r--extern/ceres/internal/ceres/visibility.h78
-rw-r--r--extern/ceres/internal/ceres/visibility_based_preconditioner.cc585
-rw-r--r--extern/ceres/internal/ceres/visibility_based_preconditioner.h82
-rw-r--r--extern/ceres/internal/ceres/wall_time.cc31
-rw-r--r--extern/ceres/internal/ceres/wall_time.h2
-rw-r--r--extern/ceres/patches/series2
-rw-r--r--extern/ceres/patches/unused_parameter.patch13
-rw-r--r--extern/ceres/patches/unused_variable.patch12
-rw-r--r--extern/draco/CMakeLists.txt2
-rw-r--r--extern/glog/AUTHORS3
-rw-r--r--extern/glog/CMakeLists.txt13
-rw-r--r--extern/glog/ChangeLog15
-rw-r--r--extern/glog/README.blender2
-rw-r--r--extern/glog/include/glog/logging.h97
-rw-r--r--extern/glog/include/glog/raw_logging.h7
-rw-r--r--extern/glog/src/config.h4
-rw-r--r--extern/glog/src/config_mac.h6
-rw-r--r--extern/glog/src/demangle.cc64
-rw-r--r--extern/glog/src/logging.cc130
-rw-r--r--extern/glog/src/raw_logging.cc16
-rw-r--r--extern/glog/src/signalhandler.cc44
-rw-r--r--extern/glog/src/stacktrace.h3
-rw-r--r--extern/glog/src/stacktrace_windows-inl.h50
-rw-r--r--extern/glog/src/stacktrace_x86-inl.h15
-rw-r--r--extern/glog/src/symbolize.cc249
-rw-r--r--extern/glog/src/symbolize.h15
-rw-r--r--extern/glog/src/utilities.cc42
-rw-r--r--extern/glog/src/utilities.h16
-rw-r--r--extern/glog/src/vlog_is_on.cc6
-rw-r--r--extern/glog/src/windows/glog/logging.h35
-rw-r--r--extern/glog/src/windows/glog/raw_logging.h5
-rw-r--r--extern/glog/src/windows/port.cc13
-rw-r--r--extern/glog/src/windows/port.h23
-rwxr-xr-xextern/glog/src/windows/preprocess.sh2
-rw-r--r--extern/gmock/CHANGES126
-rw-r--r--extern/gmock/CMakeLists.txt11
-rw-r--r--extern/gmock/README.blender6
-rw-r--r--extern/gmock/README.md361
-rw-r--r--extern/gmock/include/gmock/gmock-actions.h555
-rw-r--r--extern/gmock/include/gmock/gmock-cardinalities.h32
-rw-r--r--extern/gmock/include/gmock/gmock-function-mocker.h253
-rw-r--r--extern/gmock/include/gmock/gmock-generated-actions.h1109
-rw-r--r--extern/gmock/include/gmock/gmock-generated-function-mockers.h1003
-rw-r--r--extern/gmock/include/gmock/gmock-generated-matchers.h1672
-rw-r--r--extern/gmock/include/gmock/gmock-generated-nice-strict.h397
-rw-r--r--extern/gmock/include/gmock/gmock-matchers.h2701
-rw-r--r--extern/gmock/include/gmock/gmock-more-actions.h110
-rw-r--r--extern/gmock/include/gmock/gmock-more-matchers.h44
-rw-r--r--extern/gmock/include/gmock/gmock-nice-strict.h215
-rw-r--r--extern/gmock/include/gmock/gmock-spec-builders.h636
-rw-r--r--extern/gmock/include/gmock/gmock.h17
-rw-r--r--extern/gmock/include/gmock/internal/custom/README.md16
-rw-r--r--extern/gmock/include/gmock/internal/custom/gmock-generated-actions.h2
-rw-r--r--extern/gmock/include/gmock/internal/custom/gmock-matchers.h13
-rw-r--r--extern/gmock/include/gmock/internal/custom/gmock-port.h13
-rw-r--r--extern/gmock/include/gmock/internal/gmock-generated-internal-utils.h279
-rw-r--r--extern/gmock/include/gmock/internal/gmock-internal-utils.h248
-rw-r--r--extern/gmock/include/gmock/internal/gmock-port.h30
-rw-r--r--extern/gmock/include/gmock/internal/gmock-pp.h317
-rw-r--r--extern/gmock/src/gmock-all.cc3
-rw-r--r--extern/gmock/src/gmock-cardinalities.cc15
-rw-r--r--extern/gmock/src/gmock-internal-utils.cc56
-rw-r--r--extern/gmock/src/gmock-matchers.cc290
-rw-r--r--extern/gmock/src/gmock-spec-builders.cc249
-rw-r--r--extern/gmock/src/gmock.cc56
-rw-r--r--extern/gmock/src/gmock_main.cc17
-rw-r--r--extern/gtest/CHANGES157
-rw-r--r--extern/gtest/CMakeLists.txt19
-rw-r--r--extern/gtest/CONTRIBUTORS37
-rw-r--r--extern/gtest/README.blender6
-rw-r--r--extern/gtest/README.md60
-rw-r--r--extern/gtest/include/gtest/gtest-death-test.h71
-rw-r--r--extern/gtest/include/gtest/gtest-matchers.h750
-rw-r--r--extern/gtest/include/gtest/gtest-message.h56
-rw-r--r--extern/gtest/include/gtest/gtest-param-test.h1225
-rw-r--r--extern/gtest/include/gtest/gtest-printers.h473
-rw-r--r--extern/gtest/include/gtest/gtest-spi.h20
-rw-r--r--extern/gtest/include/gtest/gtest-test-part.h43
-rw-r--r--extern/gtest/include/gtest/gtest-typed-test.h255
-rw-r--r--extern/gtest/include/gtest/gtest.h852
-rw-r--r--extern/gtest/include/gtest/gtest_pred_impl.h81
-rw-r--r--extern/gtest/include/gtest/gtest_prod.h17
-rw-r--r--extern/gtest/include/gtest/internal/custom/README.md56
-rw-r--r--extern/gtest/include/gtest/internal/custom/gtest-port.h34
-rw-r--r--extern/gtest/include/gtest/internal/custom/gtest-printers.h4
-rw-r--r--extern/gtest/include/gtest/internal/custom/gtest.h6
-rw-r--r--extern/gtest/include/gtest/internal/gtest-death-test-internal.h175
-rw-r--r--extern/gtest/include/gtest/internal/gtest-filepath.h13
-rw-r--r--extern/gtest/include/gtest/internal/gtest-internal.h720
-rw-r--r--extern/gtest/include/gtest/internal/gtest-linked_ptr.h243
-rw-r--r--extern/gtest/include/gtest/internal/gtest-param-util-generated.h5146
-rw-r--r--extern/gtest/include/gtest/internal/gtest-param-util.h502
-rw-r--r--extern/gtest/include/gtest/internal/gtest-port-arch.h24
-rw-r--r--extern/gtest/include/gtest/internal/gtest-port.h895
-rw-r--r--extern/gtest/include/gtest/internal/gtest-string.h30
-rw-r--r--extern/gtest/include/gtest/internal/gtest-tuple.h1020
-rw-r--r--extern/gtest/include/gtest/internal/gtest-type-util.h42
-rw-r--r--extern/gtest/src/gtest-all.cc6
-rw-r--r--extern/gtest/src/gtest-death-test.cc567
-rw-r--r--extern/gtest/src/gtest-filepath.cc40
-rw-r--r--extern/gtest/src/gtest-internal-inl.h304
-rw-r--r--extern/gtest/src/gtest-matchers.cc97
-rw-r--r--extern/gtest/src/gtest-port.cc452
-rw-r--r--extern/gtest/src/gtest-printers.cc123
-rw-r--r--extern/gtest/src/gtest-test-part.cc34
-rw-r--r--extern/gtest/src/gtest-typed-test.cc10
-rw-r--r--extern/gtest/src/gtest.cc2487
-rw-r--r--extern/gtest/src/gtest_main.cc15
-rw-r--r--extern/mantaflow/CMakeLists.txt8
-rw-r--r--extern/mantaflow/helper/pwrapper/pconvert.cpp93
-rw-r--r--extern/mantaflow/helper/pwrapper/pconvert.h11
-rw-r--r--extern/mantaflow/helper/util/randomstream.h4
-rw-r--r--extern/mantaflow/preprocessed/fileio/iogrids.cpp565
-rw-r--r--extern/mantaflow/preprocessed/fileio/iomeshes.cpp74
-rw-r--r--extern/mantaflow/preprocessed/fileio/ioparticles.cpp49
-rw-r--r--extern/mantaflow/preprocessed/fileio/ioutil.cpp56
-rw-r--r--extern/mantaflow/preprocessed/fileio/iovdb.cpp618
-rw-r--r--extern/mantaflow/preprocessed/fileio/mantaio.cpp144
-rw-r--r--extern/mantaflow/preprocessed/fileio/mantaio.h110
-rw-r--r--extern/mantaflow/preprocessed/gitinfo.h2
-rw-r--r--extern/mantaflow/preprocessed/grid.cpp42
-rw-r--r--extern/mantaflow/preprocessed/grid.h16
-rw-r--r--extern/mantaflow/preprocessed/grid4d.cpp14
-rw-r--r--extern/mantaflow/preprocessed/grid4d.h10
-rw-r--r--extern/mantaflow/preprocessed/particle.cpp50
-rw-r--r--extern/mantaflow/preprocessed/particle.h33
-rw-r--r--extern/mantaflow/preprocessed/plugin/secondaryparticles.cpp4
-rw-r--r--extern/mantaflow/preprocessed/python/defines.py.reg.cpp3
-rw-r--r--extern/mantaflow/preprocessed/registration.cpp4
414 files changed, 30277 insertions, 27484 deletions
diff --git a/extern/ceres/CMakeLists.txt b/extern/ceres/CMakeLists.txt
index 009445ea690..51cf9657319 100644
--- a/extern/ceres/CMakeLists.txt
+++ b/extern/ceres/CMakeLists.txt
@@ -37,223 +37,279 @@ set(INC_SYS
)
set(SRC
- internal/ceres/array_utils.cc
- internal/ceres/blas.cc
- internal/ceres/block_evaluate_preparer.cc
- internal/ceres/block_jacobian_writer.cc
- internal/ceres/block_jacobi_preconditioner.cc
- internal/ceres/block_random_access_dense_matrix.cc
- internal/ceres/block_random_access_diagonal_matrix.cc
- internal/ceres/block_random_access_matrix.cc
- internal/ceres/block_random_access_sparse_matrix.cc
- internal/ceres/block_sparse_matrix.cc
- internal/ceres/block_structure.cc
- internal/ceres/callbacks.cc
- internal/ceres/c_api.cc
- internal/ceres/cgnr_solver.cc
- internal/ceres/compressed_col_sparse_matrix_utils.cc
- internal/ceres/compressed_row_jacobian_writer.cc
- internal/ceres/compressed_row_sparse_matrix.cc
- internal/ceres/conditioned_cost_function.cc
- internal/ceres/conjugate_gradients_solver.cc
- internal/ceres/coordinate_descent_minimizer.cc
- internal/ceres/corrector.cc
- internal/ceres/covariance.cc
- internal/ceres/covariance_impl.cc
- internal/ceres/dense_normal_cholesky_solver.cc
- internal/ceres/dense_qr_solver.cc
- internal/ceres/dense_sparse_matrix.cc
- internal/ceres/detect_structure.cc
- internal/ceres/dogleg_strategy.cc
- internal/ceres/dynamic_compressed_row_jacobian_writer.cc
- internal/ceres/dynamic_compressed_row_sparse_matrix.cc
- internal/ceres/evaluator.cc
- internal/ceres/file.cc
- internal/ceres/generated/partitioned_matrix_view_d_d_d.cc
- internal/ceres/generated/schur_eliminator_d_d_d.cc
- internal/ceres/gradient_checker.cc
- internal/ceres/gradient_checking_cost_function.cc
- internal/ceres/gradient_problem.cc
- internal/ceres/gradient_problem_solver.cc
- internal/ceres/implicit_schur_complement.cc
- internal/ceres/is_close.cc
- internal/ceres/iterative_schur_complement_solver.cc
- internal/ceres/lapack.cc
- internal/ceres/levenberg_marquardt_strategy.cc
- internal/ceres/linear_least_squares_problems.cc
- internal/ceres/linear_operator.cc
- internal/ceres/linear_solver.cc
- internal/ceres/line_search.cc
- internal/ceres/line_search_direction.cc
- internal/ceres/line_search_minimizer.cc
- internal/ceres/line_search_preprocessor.cc
- internal/ceres/local_parameterization.cc
- internal/ceres/loss_function.cc
- internal/ceres/low_rank_inverse_hessian.cc
- internal/ceres/minimizer.cc
- internal/ceres/normal_prior.cc
- internal/ceres/parameter_block_ordering.cc
- internal/ceres/partitioned_matrix_view.cc
- internal/ceres/polynomial.cc
- internal/ceres/preconditioner.cc
- internal/ceres/preprocessor.cc
- internal/ceres/problem.cc
- internal/ceres/problem_impl.cc
- internal/ceres/program.cc
- internal/ceres/reorder_program.cc
- internal/ceres/residual_block.cc
- internal/ceres/residual_block_utils.cc
- internal/ceres/schur_complement_solver.cc
- internal/ceres/schur_eliminator.cc
- internal/ceres/schur_jacobi_preconditioner.cc
- internal/ceres/scratch_evaluate_preparer.cc
- internal/ceres/solver.cc
- internal/ceres/solver_utils.cc
- internal/ceres/sparse_matrix.cc
- internal/ceres/sparse_normal_cholesky_solver.cc
- internal/ceres/split.cc
- internal/ceres/stringprintf.cc
- internal/ceres/triplet_sparse_matrix.cc
- internal/ceres/trust_region_minimizer.cc
- internal/ceres/trust_region_preprocessor.cc
- internal/ceres/trust_region_step_evaluator.cc
- internal/ceres/trust_region_strategy.cc
- internal/ceres/types.cc
- internal/ceres/wall_time.cc
+ internal/ceres/accelerate_sparse.cc
+ internal/ceres/array_utils.cc
+ internal/ceres/blas.cc
+ internal/ceres/block_evaluate_preparer.cc
+ internal/ceres/block_jacobian_writer.cc
+ internal/ceres/block_jacobi_preconditioner.cc
+ internal/ceres/block_random_access_dense_matrix.cc
+ internal/ceres/block_random_access_diagonal_matrix.cc
+ internal/ceres/block_random_access_matrix.cc
+ internal/ceres/block_random_access_sparse_matrix.cc
+ internal/ceres/block_sparse_matrix.cc
+ internal/ceres/block_structure.cc
+ internal/ceres/callbacks.cc
+ internal/ceres/canonical_views_clustering.cc
+ internal/ceres/c_api.cc
+ internal/ceres/cgnr_solver.cc
+ internal/ceres/compressed_col_sparse_matrix_utils.cc
+ internal/ceres/compressed_row_jacobian_writer.cc
+ internal/ceres/compressed_row_sparse_matrix.cc
+ internal/ceres/conditioned_cost_function.cc
+ internal/ceres/conjugate_gradients_solver.cc
+ internal/ceres/context.cc
+ internal/ceres/context_impl.cc
+ internal/ceres/coordinate_descent_minimizer.cc
+ internal/ceres/corrector.cc
+ internal/ceres/covariance.cc
+ internal/ceres/covariance_impl.cc
+ internal/ceres/cxsparse.cc
+ internal/ceres/dense_normal_cholesky_solver.cc
+ internal/ceres/dense_qr_solver.cc
+ internal/ceres/dense_sparse_matrix.cc
+ internal/ceres/detect_structure.cc
+ internal/ceres/dogleg_strategy.cc
+ internal/ceres/dynamic_compressed_row_jacobian_writer.cc
+ internal/ceres/dynamic_compressed_row_sparse_matrix.cc
+ internal/ceres/dynamic_sparse_normal_cholesky_solver.cc
+ internal/ceres/eigensparse.cc
+ internal/ceres/evaluator.cc
+ internal/ceres/file.cc
+ internal/ceres/float_cxsparse.cc
+ internal/ceres/float_suitesparse.cc
+ internal/ceres/function_sample.cc
+ internal/ceres/generated/partitioned_matrix_view_d_d_d.cc
+ internal/ceres/generated/schur_eliminator_d_d_d.cc
+ internal/ceres/gradient_checker.cc
+ internal/ceres/gradient_checking_cost_function.cc
+ internal/ceres/gradient_problem.cc
+ internal/ceres/gradient_problem_solver.cc
+ internal/ceres/implicit_schur_complement.cc
+ internal/ceres/inner_product_computer.cc
+ internal/ceres/is_close.cc
+ internal/ceres/iterative_refiner.cc
+ internal/ceres/iterative_schur_complement_solver.cc
+ internal/ceres/lapack.cc
+ internal/ceres/levenberg_marquardt_strategy.cc
+ internal/ceres/linear_least_squares_problems.cc
+ internal/ceres/linear_operator.cc
+ internal/ceres/linear_solver.cc
+ internal/ceres/line_search.cc
+ internal/ceres/line_search_direction.cc
+ internal/ceres/line_search_minimizer.cc
+ internal/ceres/line_search_preprocessor.cc
+ internal/ceres/local_parameterization.cc
+ internal/ceres/loss_function.cc
+ internal/ceres/low_rank_inverse_hessian.cc
+ internal/ceres/minimizer.cc
+ internal/ceres/normal_prior.cc
+ internal/ceres/parallel_for_cxx.cc
+ internal/ceres/parallel_for_nothreads.cc
+ internal/ceres/parallel_for_openmp.cc
+ internal/ceres/parallel_utils.cc
+ internal/ceres/parameter_block_ordering.cc
+ internal/ceres/partitioned_matrix_view.cc
+ internal/ceres/polynomial.cc
+ internal/ceres/preconditioner.cc
+ internal/ceres/preprocessor.cc
+ internal/ceres/problem.cc
+ internal/ceres/problem_impl.cc
+ internal/ceres/program.cc
+ internal/ceres/reorder_program.cc
+ internal/ceres/residual_block.cc
+ internal/ceres/residual_block_utils.cc
+ internal/ceres/schur_complement_solver.cc
+ internal/ceres/schur_eliminator.cc
+ internal/ceres/schur_jacobi_preconditioner.cc
+ internal/ceres/schur_templates.cc
+ internal/ceres/scratch_evaluate_preparer.cc
+ internal/ceres/single_linkage_clustering.cc
+ internal/ceres/solver.cc
+ internal/ceres/solver_utils.cc
+ internal/ceres/sparse_cholesky.cc
+ internal/ceres/sparse_matrix.cc
+ internal/ceres/sparse_normal_cholesky_solver.cc
+ internal/ceres/split.cc
+ internal/ceres/stringprintf.cc
+ internal/ceres/subset_preconditioner.cc
+ internal/ceres/suitesparse.cc
+ internal/ceres/thread_pool.cc
+ internal/ceres/thread_token_provider.cc
+ internal/ceres/triplet_sparse_matrix.cc
+ internal/ceres/trust_region_minimizer.cc
+ internal/ceres/trust_region_preprocessor.cc
+ internal/ceres/trust_region_step_evaluator.cc
+ internal/ceres/trust_region_strategy.cc
+ internal/ceres/types.cc
+ internal/ceres/visibility_based_preconditioner.cc
+ internal/ceres/visibility.cc
+ internal/ceres/wall_time.cc
- include/ceres/autodiff_cost_function.h
- include/ceres/autodiff_local_parameterization.h
- include/ceres/c_api.h
- include/ceres/ceres.h
- include/ceres/conditioned_cost_function.h
- include/ceres/cost_function.h
- include/ceres/cost_function_to_functor.h
- include/ceres/covariance.h
- include/ceres/crs_matrix.h
- include/ceres/dynamic_autodiff_cost_function.h
- include/ceres/dynamic_cost_function_to_functor.h
- include/ceres/dynamic_numeric_diff_cost_function.h
- include/ceres/fpclassify.h
- include/ceres/gradient_checker.h
- include/ceres/gradient_problem.h
- include/ceres/gradient_problem_solver.h
- include/ceres/internal/autodiff.h
- include/ceres/internal/disable_warnings.h
- include/ceres/internal/eigen.h
- include/ceres/internal/fixed_array.h
- include/ceres/internal/macros.h
- include/ceres/internal/manual_constructor.h
- include/ceres/internal/numeric_diff.h
- include/ceres/internal/port.h
- include/ceres/internal/reenable_warnings.h
- include/ceres/internal/scoped_ptr.h
- include/ceres/internal/variadic_evaluate.h
- include/ceres/iteration_callback.h
- include/ceres/jet.h
- include/ceres/local_parameterization.h
- include/ceres/loss_function.h
- include/ceres/normal_prior.h
- include/ceres/numeric_diff_cost_function.h
- include/ceres/numeric_diff_options.h
- include/ceres/ordered_groups.h
- include/ceres/problem.h
- include/ceres/rotation.h
- include/ceres/sized_cost_function.h
- include/ceres/solver.h
- include/ceres/types.h
- include/ceres/version.h
- internal/ceres/array_utils.h
- internal/ceres/blas.h
- internal/ceres/block_evaluate_preparer.h
- internal/ceres/block_jacobian_writer.h
- internal/ceres/block_jacobi_preconditioner.h
- internal/ceres/block_random_access_dense_matrix.h
- internal/ceres/block_random_access_diagonal_matrix.h
- internal/ceres/block_random_access_matrix.h
- internal/ceres/block_random_access_sparse_matrix.h
- internal/ceres/block_sparse_matrix.h
- internal/ceres/block_structure.h
- internal/ceres/callbacks.h
- internal/ceres/casts.h
- internal/ceres/cgnr_linear_operator.h
- internal/ceres/cgnr_solver.h
- internal/ceres/collections_port.h
- internal/ceres/compressed_col_sparse_matrix_utils.h
- internal/ceres/compressed_row_jacobian_writer.h
- internal/ceres/compressed_row_sparse_matrix.h
- internal/ceres/conjugate_gradients_solver.h
- internal/ceres/coordinate_descent_minimizer.h
- internal/ceres/corrector.h
- internal/ceres/covariance_impl.h
- internal/ceres/cxsparse.h
- internal/ceres/dense_jacobian_writer.h
- internal/ceres/dense_normal_cholesky_solver.h
- internal/ceres/dense_qr_solver.h
- internal/ceres/dense_sparse_matrix.h
- internal/ceres/detect_structure.h
- internal/ceres/dogleg_strategy.h
- internal/ceres/dynamic_compressed_row_finalizer.h
- internal/ceres/dynamic_compressed_row_jacobian_writer.h
- internal/ceres/dynamic_compressed_row_sparse_matrix.h
- internal/ceres/evaluator.h
- internal/ceres/execution_summary.h
- internal/ceres/file.h
- internal/ceres/gradient_checking_cost_function.h
- internal/ceres/gradient_problem_evaluator.h
- internal/ceres/graph_algorithms.h
- internal/ceres/graph.h
- internal/ceres/householder_vector.h
- internal/ceres/implicit_schur_complement.h
- internal/ceres/integral_types.h
- internal/ceres/is_close.h
- internal/ceres/iterative_schur_complement_solver.h
- internal/ceres/lapack.h
- internal/ceres/levenberg_marquardt_strategy.h
- internal/ceres/linear_least_squares_problems.h
- internal/ceres/linear_operator.h
- internal/ceres/linear_solver.h
- internal/ceres/line_search_direction.h
- internal/ceres/line_search.h
- internal/ceres/line_search_minimizer.h
- internal/ceres/line_search_preprocessor.h
- internal/ceres/low_rank_inverse_hessian.h
- internal/ceres/map_util.h
- internal/ceres/minimizer.h
- internal/ceres/mutex.h
- internal/ceres/parameter_block.h
- internal/ceres/parameter_block_ordering.h
- internal/ceres/partitioned_matrix_view.h
- internal/ceres/partitioned_matrix_view_impl.h
- internal/ceres/polynomial.h
- internal/ceres/preconditioner.h
- internal/ceres/preprocessor.h
- internal/ceres/problem_impl.h
- internal/ceres/program_evaluator.h
- internal/ceres/program.h
- internal/ceres/random.h
- internal/ceres/reorder_program.h
- internal/ceres/residual_block.h
- internal/ceres/residual_block_utils.h
- internal/ceres/schur_complement_solver.h
- internal/ceres/schur_eliminator.h
- internal/ceres/schur_eliminator_impl.h
- internal/ceres/schur_jacobi_preconditioner.h
- internal/ceres/scratch_evaluate_preparer.h
- internal/ceres/small_blas.h
- internal/ceres/solver_utils.h
- internal/ceres/sparse_matrix.h
- internal/ceres/sparse_normal_cholesky_solver.h
- internal/ceres/split.h
- internal/ceres/stl_util.h
- internal/ceres/stringprintf.h
- internal/ceres/suitesparse.h
- internal/ceres/triplet_sparse_matrix.h
- internal/ceres/trust_region_minimizer.h
- internal/ceres/trust_region_preprocessor.h
- internal/ceres/trust_region_step_evaluator.h
- internal/ceres/trust_region_strategy.h
- internal/ceres/visibility_based_preconditioner.h
- internal/ceres/wall_time.h
+ include/ceres/autodiff_cost_function.h
+ include/ceres/autodiff_first_order_function.h
+ include/ceres/autodiff_local_parameterization.h
+ include/ceres/c_api.h
+ include/ceres/ceres.h
+ include/ceres/conditioned_cost_function.h
+ include/ceres/context.h
+ include/ceres/cost_function.h
+ include/ceres/cost_function_to_functor.h
+ include/ceres/covariance.h
+ include/ceres/crs_matrix.h
+ include/ceres/cubic_interpolation.h
+ include/ceres/dynamic_autodiff_cost_function.h
+ include/ceres/dynamic_cost_function.h
+ include/ceres/dynamic_cost_function_to_functor.h
+ include/ceres/dynamic_numeric_diff_cost_function.h
+ include/ceres/evaluation_callback.h
+ include/ceres/first_order_function.h
+ include/ceres/gradient_checker.h
+ include/ceres/gradient_problem.h
+ include/ceres/gradient_problem_solver.h
+ include/ceres/internal/array_selector.h
+ include/ceres/internal/autodiff.h
+ include/ceres/internal/disable_warnings.h
+ include/ceres/internal/eigen.h
+ include/ceres/internal/fixed_array.h
+ include/ceres/internal/householder_vector.h
+ include/ceres/internal/integer_sequence_algorithm.h
+ include/ceres/internal/line_parameterization.h
+ include/ceres/internal/memory.h
+ include/ceres/internal/numeric_diff.h
+ include/ceres/internal/parameter_dims.h
+ include/ceres/internal/port.h
+ include/ceres/internal/reenable_warnings.h
+ include/ceres/internal/variadic_evaluate.h
+ include/ceres/iteration_callback.h
+ include/ceres/jet.h
+ include/ceres/local_parameterization.h
+ include/ceres/loss_function.h
+ include/ceres/normal_prior.h
+ include/ceres/numeric_diff_cost_function.h
+ include/ceres/numeric_diff_options.h
+ include/ceres/ordered_groups.h
+ include/ceres/problem.h
+ include/ceres/rotation.h
+ include/ceres/sized_cost_function.h
+ include/ceres/solver.h
+ include/ceres/tiny_solver_autodiff_function.h
+ include/ceres/tiny_solver_cost_function_adapter.h
+ include/ceres/tiny_solver.h
+ include/ceres/types.h
+ include/ceres/version.h
+ internal/ceres/accelerate_sparse.h
+ internal/ceres/array_utils.h
+ internal/ceres/blas.h
+ internal/ceres/block_evaluate_preparer.h
+ internal/ceres/block_jacobian_writer.h
+ internal/ceres/block_jacobi_preconditioner.h
+ internal/ceres/block_random_access_dense_matrix.h
+ internal/ceres/block_random_access_diagonal_matrix.h
+ internal/ceres/block_random_access_matrix.h
+ internal/ceres/block_random_access_sparse_matrix.h
+ internal/ceres/block_sparse_matrix.h
+ internal/ceres/block_structure.h
+ internal/ceres/callbacks.h
+ internal/ceres/canonical_views_clustering.h
+ internal/ceres/casts.h
+ internal/ceres/cgnr_linear_operator.h
+ internal/ceres/cgnr_solver.h
+ internal/ceres/compressed_col_sparse_matrix_utils.h
+ internal/ceres/compressed_row_jacobian_writer.h
+ internal/ceres/compressed_row_sparse_matrix.h
+ internal/ceres/concurrent_queue.h
+ internal/ceres/conjugate_gradients_solver.h
+ internal/ceres/context_impl.h
+ internal/ceres/coordinate_descent_minimizer.h
+ internal/ceres/corrector.h
+ internal/ceres/covariance_impl.h
+ internal/ceres/cxsparse.h
+ internal/ceres/dense_jacobian_writer.h
+ internal/ceres/dense_normal_cholesky_solver.h
+ internal/ceres/dense_qr_solver.h
+ internal/ceres/dense_sparse_matrix.h
+ internal/ceres/detect_structure.h
+ internal/ceres/dogleg_strategy.h
+ internal/ceres/dynamic_compressed_row_finalizer.h
+ internal/ceres/dynamic_compressed_row_jacobian_writer.h
+ internal/ceres/dynamic_compressed_row_sparse_matrix.h
+ internal/ceres/dynamic_sparse_normal_cholesky_solver.h
+ internal/ceres/eigensparse.h
+ internal/ceres/evaluator.h
+ internal/ceres/execution_summary.h
+ internal/ceres/file.h
+ internal/ceres/float_cxsparse.h
+ internal/ceres/float_suitesparse.h
+ internal/ceres/function_sample.h
+ internal/ceres/gradient_checking_cost_function.h
+ internal/ceres/gradient_problem_evaluator.h
+ internal/ceres/graph_algorithms.h
+ internal/ceres/graph.h
+ internal/ceres/implicit_schur_complement.h
+ internal/ceres/inner_product_computer.h
+ internal/ceres/invert_psd_matrix.h
+ internal/ceres/is_close.h
+ internal/ceres/iterative_refiner.h
+ internal/ceres/iterative_schur_complement_solver.h
+ internal/ceres/lapack.h
+ internal/ceres/levenberg_marquardt_strategy.h
+ internal/ceres/linear_least_squares_problems.h
+ internal/ceres/linear_operator.h
+ internal/ceres/linear_solver.h
+ internal/ceres/line_search_direction.h
+ internal/ceres/line_search.h
+ internal/ceres/line_search_minimizer.h
+ internal/ceres/line_search_preprocessor.h
+ internal/ceres/low_rank_inverse_hessian.h
+ internal/ceres/map_util.h
+ internal/ceres/minimizer.h
+ internal/ceres/pair_hash.h
+ internal/ceres/parallel_for.h
+ internal/ceres/parallel_utils.h
+ internal/ceres/parameter_block.h
+ internal/ceres/parameter_block_ordering.h
+ internal/ceres/partitioned_matrix_view.h
+ internal/ceres/partitioned_matrix_view_impl.h
+ internal/ceres/polynomial.h
+ internal/ceres/preconditioner.h
+ internal/ceres/preprocessor.h
+ internal/ceres/problem_impl.h
+ internal/ceres/program_evaluator.h
+ internal/ceres/program.h
+ internal/ceres/random.h
+ internal/ceres/reorder_program.h
+ internal/ceres/residual_block.h
+ internal/ceres/residual_block_utils.h
+ internal/ceres/schur_complement_solver.h
+ internal/ceres/schur_eliminator.h
+ internal/ceres/schur_eliminator_impl.h
+ internal/ceres/schur_jacobi_preconditioner.h
+ internal/ceres/schur_templates.h
+ internal/ceres/scoped_thread_token.h
+ internal/ceres/scratch_evaluate_preparer.h
+ internal/ceres/single_linkage_clustering.h
+ internal/ceres/small_blas_generic.h
+ internal/ceres/small_blas.h
+ internal/ceres/solver_utils.h
+ internal/ceres/sparse_cholesky.h
+ internal/ceres/sparse_matrix.h
+ internal/ceres/sparse_normal_cholesky_solver.h
+ internal/ceres/split.h
+ internal/ceres/stl_util.h
+ internal/ceres/stringprintf.h
+ internal/ceres/subset_preconditioner.h
+ internal/ceres/suitesparse.h
+ internal/ceres/thread_pool.h
+ internal/ceres/thread_token_provider.h
+ internal/ceres/triplet_sparse_matrix.h
+ internal/ceres/trust_region_minimizer.h
+ internal/ceres/trust_region_preprocessor.h
+ internal/ceres/trust_region_step_evaluator.h
+ internal/ceres/trust_region_strategy.h
+ internal/ceres/visibility_based_preconditioner.h
+ internal/ceres/visibility.h
+ internal/ceres/wall_time.h
)
set(LIB
@@ -263,44 +319,48 @@ set(LIB
if(WITH_LIBMV_SCHUR_SPECIALIZATIONS)
list(APPEND SRC
- internal/ceres/generated/partitioned_matrix_view_2_2_2.cc
- internal/ceres/generated/partitioned_matrix_view_2_2_3.cc
- internal/ceres/generated/partitioned_matrix_view_2_2_4.cc
- internal/ceres/generated/partitioned_matrix_view_2_2_d.cc
- internal/ceres/generated/partitioned_matrix_view_2_3_3.cc
- internal/ceres/generated/partitioned_matrix_view_2_3_4.cc
- internal/ceres/generated/partitioned_matrix_view_2_3_6.cc
- internal/ceres/generated/partitioned_matrix_view_2_3_9.cc
- internal/ceres/generated/partitioned_matrix_view_2_3_d.cc
- internal/ceres/generated/partitioned_matrix_view_2_4_3.cc
- internal/ceres/generated/partitioned_matrix_view_2_4_4.cc
- internal/ceres/generated/partitioned_matrix_view_2_4_8.cc
- internal/ceres/generated/partitioned_matrix_view_2_4_9.cc
- internal/ceres/generated/partitioned_matrix_view_2_4_d.cc
- internal/ceres/generated/partitioned_matrix_view_2_d_d.cc
- internal/ceres/generated/partitioned_matrix_view_4_4_2.cc
- internal/ceres/generated/partitioned_matrix_view_4_4_3.cc
- internal/ceres/generated/partitioned_matrix_view_4_4_4.cc
- internal/ceres/generated/partitioned_matrix_view_4_4_d.cc
- internal/ceres/generated/schur_eliminator_2_2_2.cc
- internal/ceres/generated/schur_eliminator_2_2_3.cc
- internal/ceres/generated/schur_eliminator_2_2_4.cc
- internal/ceres/generated/schur_eliminator_2_2_d.cc
- internal/ceres/generated/schur_eliminator_2_3_3.cc
- internal/ceres/generated/schur_eliminator_2_3_4.cc
- internal/ceres/generated/schur_eliminator_2_3_6.cc
- internal/ceres/generated/schur_eliminator_2_3_9.cc
- internal/ceres/generated/schur_eliminator_2_3_d.cc
- internal/ceres/generated/schur_eliminator_2_4_3.cc
- internal/ceres/generated/schur_eliminator_2_4_4.cc
- internal/ceres/generated/schur_eliminator_2_4_8.cc
- internal/ceres/generated/schur_eliminator_2_4_9.cc
- internal/ceres/generated/schur_eliminator_2_4_d.cc
- internal/ceres/generated/schur_eliminator_2_d_d.cc
- internal/ceres/generated/schur_eliminator_4_4_2.cc
- internal/ceres/generated/schur_eliminator_4_4_3.cc
- internal/ceres/generated/schur_eliminator_4_4_4.cc
- internal/ceres/generated/schur_eliminator_4_4_d.cc
+ internal/ceres/generated/partitioned_matrix_view_2_2_2.cc
+ internal/ceres/generated/partitioned_matrix_view_2_2_3.cc
+ internal/ceres/generated/partitioned_matrix_view_2_2_4.cc
+ internal/ceres/generated/partitioned_matrix_view_2_2_d.cc
+ internal/ceres/generated/partitioned_matrix_view_2_3_3.cc
+ internal/ceres/generated/partitioned_matrix_view_2_3_4.cc
+ internal/ceres/generated/partitioned_matrix_view_2_3_6.cc
+ internal/ceres/generated/partitioned_matrix_view_2_3_9.cc
+ internal/ceres/generated/partitioned_matrix_view_2_3_d.cc
+ internal/ceres/generated/partitioned_matrix_view_2_4_3.cc
+ internal/ceres/generated/partitioned_matrix_view_2_4_4.cc
+ internal/ceres/generated/partitioned_matrix_view_2_4_6.cc
+ internal/ceres/generated/partitioned_matrix_view_2_4_8.cc
+ internal/ceres/generated/partitioned_matrix_view_2_4_9.cc
+ internal/ceres/generated/partitioned_matrix_view_2_4_d.cc
+ internal/ceres/generated/partitioned_matrix_view_2_d_d.cc
+ internal/ceres/generated/partitioned_matrix_view_3_3_3.cc
+ internal/ceres/generated/partitioned_matrix_view_4_4_2.cc
+ internal/ceres/generated/partitioned_matrix_view_4_4_3.cc
+ internal/ceres/generated/partitioned_matrix_view_4_4_4.cc
+ internal/ceres/generated/partitioned_matrix_view_4_4_d.cc
+ internal/ceres/generated/schur_eliminator_2_2_2.cc
+ internal/ceres/generated/schur_eliminator_2_2_3.cc
+ internal/ceres/generated/schur_eliminator_2_2_4.cc
+ internal/ceres/generated/schur_eliminator_2_2_d.cc
+ internal/ceres/generated/schur_eliminator_2_3_3.cc
+ internal/ceres/generated/schur_eliminator_2_3_4.cc
+ internal/ceres/generated/schur_eliminator_2_3_6.cc
+ internal/ceres/generated/schur_eliminator_2_3_9.cc
+ internal/ceres/generated/schur_eliminator_2_3_d.cc
+ internal/ceres/generated/schur_eliminator_2_4_3.cc
+ internal/ceres/generated/schur_eliminator_2_4_4.cc
+ internal/ceres/generated/schur_eliminator_2_4_6.cc
+ internal/ceres/generated/schur_eliminator_2_4_8.cc
+ internal/ceres/generated/schur_eliminator_2_4_9.cc
+ internal/ceres/generated/schur_eliminator_2_4_d.cc
+ internal/ceres/generated/schur_eliminator_2_d_d.cc
+ internal/ceres/generated/schur_eliminator_3_3_3.cc
+ internal/ceres/generated/schur_eliminator_4_4_2.cc
+ internal/ceres/generated/schur_eliminator_4_4_3.cc
+ internal/ceres/generated/schur_eliminator_4_4_4.cc
+ internal/ceres/generated/schur_eliminator_4_4_d.cc
)
else()
add_definitions(-DCERES_RESTRICT_SCHUR_SPECIALIZATION)
@@ -315,13 +375,9 @@ add_definitions(
-DCERES_NO_SUITESPARSE
-DCERES_NO_CXSPARSE
-DCERES_NO_LAPACK
+ -DCERES_NO_ACCELERATE_SPARSE
-DCERES_HAVE_RWLOCK
+ -DCERES_USE_CXX_THREADS
)
-if(WITH_OPENMP)
- add_definitions(
- -DCERES_USE_OPENMP
- )
-endif()
-
blender_add_lib(extern_ceres "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
diff --git a/extern/ceres/ChangeLog b/extern/ceres/ChangeLog
index ae8d42a7c95..64c75e572f4 100644
--- a/extern/ceres/ChangeLog
+++ b/extern/ceres/ChangeLog
@@ -1,588 +1,587 @@
-commit 8590e6e8e057adba4ec0083446d00268565bb444
-Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Thu Oct 27 12:29:37 2016 -0700
+commit e39d9ed1d60dfeb58dd2a0df4622c683f87b28e3
+Author: Carl Dehlin <carl@dehlin.com>
+Date: Tue Jun 16 09:02:05 2020 +0200
- Remove two checks from rotation.h
-
- This allows rotation.h to remove its dependency on glog.
+ Add a missing term and remove a superfluous word
- Change-Id: Ia6aede93ee51a4bd4039570dc8edd100a7045329
+ Change-Id: I25f40f0bf241302b975e6fc14690aa863c0728b0
-commit e892499e8d8977b9178a760348bdd201ec5f3489
-Author: Je Hyeong Hong <jhh37@outlook.com>
-Date: Tue Oct 18 22:49:11 2016 +0100
+commit 27cab77b699a1a2b5354820c57a91c92eaeb21e3
+Author: Carl Dehlin <carl@dehlin.com>
+Date: Mon Jun 15 20:01:18 2020 +0200
- Relax the tolerance in QuaternionParameterizationTestHelper.
-
- This commit relaxes the tolerance value for comparing between the actual
- local matrix and the expected local matrix. Without this fix,
- EigenQuaternionParameterization.ZeroTest could fail as the difference
- exactly matches the value of std::numeric_limits<double>::epsilon().
+ Reformulate some sentences
- Change-Id: Ic4d3f26c0acdf5f16fead80dfdc53df9e7dabbf9
+ Change-Id: I4841aa8e8522008dd816261d9ad98e5fb8ad1758
-commit 7ed9e2fb7f1dff264c5e4fbaa89ee1c4c99df269
-Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Wed Oct 19 04:45:23 2016 -0700
+commit 8ac6655ce85a4462f2882fcb9e9118a7057ebe09
+Author: Carl Dehlin <carl@dehlin.com>
+Date: Mon Jun 15 19:10:12 2020 +0200
- Occured -> Occurred.
-
- Thanks to Phillip Huebner for reporting this.
+ Fix documentation formatting issues
- Change-Id: I9cddfbb373aeb496961d08e434fe661bff4abd29
+ Change-Id: Iea3a6e75dc3a7376eda866ab24e535a6df84f8ea
-commit b82f97279682962d8c8ae1b6d9e801ba072a0ab1
-Author: Je Hyeong Hong <jhh37@outlook.com>
-Date: Tue Oct 18 21:18:32 2016 +0100
+commit 7ef83e07592ead74eeacc227b642df1959d2a246
+Author: Alex Stewart <alexs.mac@gmail.com>
+Date: Sat May 30 11:30:01 2020 +0100
- Fix a test error in autodiff_test.cc.
+ Update minimum required C++ version for Ceres to C++14
- Previously, the test for the projective camera model would fail as no
- tolerance is set in line 144. To resolve this, this commit changes
- assert_equal to assert_near.
+ - Removes all workarounds for pre-C++14 versions
+ - Removes '11' qualifier from C++ threading option and associated
+ defines.
+ - Fix missing inclusion of 'Multithreading' in reported Ceres components
+ when C++ threading model is enabled.
+ - Update Sphinx documentation to specify C++14 as minimum requirement.
- Change-Id: I6cd3379083b1a10c7cd0a9cc83fd6962bb993cc9
+ Change-Id: I706c8b367b3221e3c4d1a0aaf669a8f9c911e438
-commit 5690b447de5beed6bdda99b7f30f372283c2fb1a
+commit 1d75e7568172dc5a4dc97937dcf66e0f5d28272c
Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Thu Oct 13 09:52:02 2016 -0700
+Date: Mon May 25 18:09:50 2020 -0700
- Fix documentation source for templated functions in rotation.h
+ Improve documentation for LocalParameterization
- Change-Id: Ic1b2e6f0e6eb9914f419fd0bb5af77b66252e57c
+ Change-Id: I63fa81206e67bfac56cc42bf2bb4915a3a11332b
-commit 2f8f98f7e8940e465de126fb51282396f42bea20
+commit 763398ca4ed56952f48c48df6a98e277e3e05381
Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Thu Oct 13 09:35:18 2016 -0700
+Date: Mon May 25 12:12:03 2020 -0700
- Prepare for 1.12.0RC1
+ Update the section on Preconditioners
- Change-Id: I23eaf0b46117a01440143001b74dacfa5e57cbf0
-
-commit 55c12d2e9569fe4aeac3ba688ac36810935a37ba
-Author: Damon Kohler <damonkohler@google.com>
-Date: Wed Oct 5 16:30:31 2016 +0200
-
- Adds package.xml to support Catkin.
+ Re-organize the section, add some more references and details for
+ existing preconditioners and add documentation for the SUBSET
+ precondition.
- Change-Id: I8ad4d36a8b036417604a54644e0bb70dd1615feb
-
-commit 0bcce6565202f5476e40f12afc0a99eb44bd9dfb
-Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Mon Oct 10 23:30:42 2016 -0700
-
- Fix tabs in Android.mk
+ https://github.com/ceres-solver/ceres-solver/issues/490
- Change-Id: Ie5ab9a8ba2b727721565e1ded242609b6df5f8f5
+ Change-Id: I93d0af819c160f5e4ce48b18202f629ddb92ca7b
-commit e6ffe2667170d2fc435443685c0163396fc52d7b
+commit a614f788a34ea86dd9f679b779ffbf920db45aa6
Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Mon Oct 10 22:47:08 2016 -0700
+Date: Fri May 22 13:52:53 2020 -0700
- Update the version history.
+ Call EvaluationCallback before evaluating the fixed cost.
- Change-Id: I9a57b0541d6cebcb695ecb364a1d4ca04ea4e06c
-
-commit 0a4ccb7ee939ab35b22e26758401e039b033b176
-Author: David Gossow <dgossow@google.com>
-Date: Wed Sep 7 21:38:12 2016 +0200
-
- Relaxing Jacobian matching in Gradient Checker test.
+ Fixe a subtle bug in Program::RemoveFixedBlocks, where we call
+ ResidualBlock::Evaluate on residual blocks with all constant parameter
+ blocks without paying attention to the presence of an
+ EvaluationCallback.
+
+ In the process also run clang-format on some of the files touched by
+ this change.
- Any result of an arithmetic operation on floating-point matrices
- should never be checked for strict equality with some expected
- value, due to limited floating point precision on different machines.
- This fixes some occurences of exact checks in the gradient checker
- unit test that were causing problems on some platforms.
+ https://github.com/ceres-solver/ceres-solver/issues/482
- Change-Id: I48e804c9c705dc485ce74ddfe51037d4957c8fcb
+ Change-Id: I342b66f6f975fdee2eef139a31f24d4a3e568e84
-commit ee44fc91b59584921c1d1c8db153fda6d633b092
-Author: Je Hyeong Hong <jhh37@outlook.com>
-Date: Mon Oct 3 12:19:30 2016 +0100
+commit 70308f7bb9cac560db250262079c0f8b030b9d6b
+Author: Sameer Agarwal <sameeragarwal@google.com>
+Date: Tue May 26 06:12:13 2020 -0700
- Fix an Intel compiler error in covariance_impl.cc.
+ Simplify documentation generation.
- Intel C compiler strictly asks for parallel loops with collapse to be
- perfectly nested. Otherwise, compiling Ceres with ICC will throw an
- error at line 348 of covariance_impl.cc.
+ 1. The MathJax font configuration is moved into conf.py and removed
+ from make_docs.py along with better font sizing.
+ 2. Remove the bread crumb replacement as it is not working anymore.
+ 3. Fix a parsing error in nnls_modeling.rst which the new version of
+ sphinx barfed on.
- Change-Id: I1ecb68e89b7faf79e4153dfe6675c390d1780db4
+ Change-Id: Ia3c2e732323a8b5cabafe851ac5ca0f0c82da071
-commit 9026d69d1ce1e0bcd21debd54a38246d85c7c6e4
-Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Thu Sep 22 17:20:14 2016 -0700
-
- Allow SubsetParameterization to hold all parameters constant
-
- 1. SubsetParameterization can now be constructed such that all
- parameters are constant. This is required for it be used as part
- of a ProductParameterization to hold a part of parameter block
- constant. For example, a parameter block consisting of a rotation
- as a quaternion and a translation vector can now have a local
- parameterization where the translation part is constant and the
- quaternion part has a QuaternionParameterization associated with it.
-
- 2. The check for the tangent space of a parameterization being
- positive dimensional. We were not doing this check up till now
- and the user could accidentally create parameterizations like this
- and create a problem for themselves. This will ensure that even
- though one can construct a SubsetParameterization where all
- parameters are constant, you cannot actually use it as a local
- parameterization for an entire parameter block. Which is how
- it was before, but the check was inside the SubsetParameterization
- constructor.
-
- 3. Added more tests and refactored existing tests to be more
- granular.
-
- Change-Id: Ic0184a1f30e3bd8a416b02341781a9d98e855ff7
-
-commit a36693f83da7a3fd19dce473d060231d4cc97499
+commit e886d7e65368e73e9d35c2ead895d81ced677977
Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Sat Sep 17 16:31:41 2016 -0700
+Date: Mon May 25 13:09:39 2020 -0700
- Update version history
+ Reduce the number of minimizer iterations in evaluation_callback_test.cc
- Change-Id: Ib2f0138ed7a1879ca3b2173e54092f7ae8dd5c9d
+ This should reduce the probability of the test heuristic failing due
+ to floating point issues.
+
+ https://github.com/ceres-solver/ceres-solver/issues/562
+ https://github.com/ceres-solver/ceres-solver/issues/392
+
+ Change-Id: I8ccf4164a8d595f5930d378f464313d4a2cae419
-commit 01e23e3d33178fdd050973666505c1080cfe04c3
-Author: David Gossow <dgossow@google.com>
-Date: Thu Sep 8 12:22:28 2016 +0200
+commit 9483e6f2f57bf51bad7cefd155cd5b48ca672c63
+Author: Sameer Agarwal <sameeragarwal@google.com>
+Date: Tue May 12 05:16:32 2020 -0700
- Removing duplicate include directive.
+ Simplify DynamicCompressedRowJacobianWriter::Write
- Change-Id: I729ae6501497746d1bb615cb893ad592e16ddf3f
+ Change-Id: I67aa2959bd479909b5cada79359c5cfdb8a37ef7
-commit 99b8210cee92cb972267537fb44bebf56f812d52
+commit 323cc55bb92a513924e566f487b54556052a716f
Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Wed Sep 7 15:31:30 2016 -0700
+Date: Mon May 25 10:38:35 2020 -0700
- Update Android.mk to include new files.
+ Update the version in package.xml to 2.0.0.
- Change-Id: Id543ee7d2a65b65c868554a17f593c0a4958e873
+ Change-Id: Ibac053916520e8c597c875a8c7f5668bb35b6ba1
-commit 195d8d13a6a3962ac39ef7fcdcc6add0216eb8bc
-Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Tue Sep 6 07:12:23 2016 -0700
+commit 303b078b50bd3311a9c86fc256be3e9f2f334411
+Author: Bayes Nie <niebayes@gmail.com>
+Date: Sun May 24 16:08:52 2020 +0800
- Remove two DCHECKs from CubicHermiteSpline.
+ Fix few typos and alter a NULL to nullptr.
- They were present as debugging checks but were causing problems
- with the build on 32bit i386 due to numerical cancellation issues,
- where x ~ -epsilon.
+ Fix typos in docs/source/features.rst and examples/helloworld.cc. Alter a NULL to nullptr in include/ceres/autodiff_cost_function.h
- Removing these checks only changes the behaviour in Debug mode.
- We are already handling such small negative numbers in production
- if they occur. All that this change does is to remove the crash.
+ Change-Id: Ibcf00b6ef665ad6be9af14b3add2dd4f3852e7e6
+
+commit cca93fed63dd4117f3d6dd5339131fc7674e6e0a
+Author: Alex Stewart <alexs.mac@gmail.com>
+Date: Sun May 24 18:05:05 2020 +0100
+
+ Bypass Ceres' FindGlog.cmake in CeresConfig.cmake if possible
- https://github.com/ceres-solver/ceres-solver/issues/212
+ - If the version of glog detected and used to build Ceres was built with
+ CMake (i.e. Config mode) then we now use Config mode directly in
+ CeresConfig.cmake and do not install Ceres' FindGlog.cmake module.
+ - This has the benefit of removing any hard-coded paths from
+ CeresConfig.cmake provided that all dependencies were also built with
+ CMake.
- Thanks to @NeroBurner and @debalance for reporting this.
+ Change-Id: I85af8a953fd6d300e8bc0cdeb0b3636fec182f68
+
+commit 77fc1d0fc4159ebb3a0a84a16651564eb2ce3c9d
+Author: Alex Stewart <alexs.mac@gmail.com>
+Date: Sun May 24 19:07:26 2020 +0100
+
+ Use build_depend for private dependencies in Catkin package.xml
- Change-Id: I66480e86d4fa0a4b621204f2ff44cc3ff8d01c04
+ Change-Id: If0c0569e7ebbf37c0d8e8daaf7765e20a6282531
-commit 83041ac84f2d67c28559c67515e0e596a3f3aa20
-Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Fri Sep 2 19:10:35 2016 -0700
+commit a09682f00d8e50ada3c7ed16f8c48fa71a423f60
+Author: Alex Stewart <alexs.mac@gmail.com>
+Date: Sun May 24 16:49:28 2020 +0100
- Fix some compiler warnings.
+ Fix MSVC version check to support use of clang-cl front-end
- Reported by Richard Trieu.
+ - Raised as issue: #521
- Change-Id: I202b7a7df09cc19c92582d276ccf171edf88a9fb
+ Change-Id: Iaea6b43484b90ec8789bda0447c8a90759974ec1
-commit 8c4623c63a2676e79e7917bb0561f903760f19b9
-Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Thu Sep 1 00:05:09 2016 -0700
+commit b70687fcc86624c7d5520d25734938fa95d2af73
+Author: Alex Stewart <alexs.mac@gmail.com>
+Date: Sun May 24 20:28:12 2020 +0100
- Update ExpectArraysClose to use ExpectClose instead of EXPECT_NEAR
+ Add namespace qualified Ceres::ceres CMake target
- The documentation for ExpectArraysClose and its implementation
- did not match.
+ - This reflects modern CMake style, and also provides a measure of
+ protection against missing find_package() imports in downstream
+ clients resulting in linker errors when 'ceres' matches the compiled
+ library and not the imported target.
+ - The original 'ceres' target remains, as a local imported interface
+ target created by CeresConfig for backwards compatibility.
- This change makes the polynomial_test not fail on 64bit AMD builds.
+ Change-Id: Ie9ed8de9b7059bc0cae1ae5002bb94d8fe617188
+
+commit 99efa54bdb4e14c3f4382a166baf6772113f74a8
+Author: Alex Stewart <alexs.mac@gmail.com>
+Date: Sun May 24 19:18:38 2020 +0100
+
+ Replace type aliases deprecated/removed in C++17/C++20 from FixedArray
- Thanks to Phillip Huebner for reporting this.
+ - Raised as issue #551
+ - Also adds C++20 to the set of ALLOWED_CXX_STANDARDS, although this
+ will require a version of CMake >= 3.12.
- Change-Id: I503f2d3317a28d5885a34f8bdbccd49d20ae9ba2
+ Change-Id: I0f13c72e93a35391fd2d18590b4243a329a2322c
-commit 2fd39fcecb47eebce727081c9ffb8edf86c33669
+commit adb973e4a337c372aa81ca1a4f3bb704068c08b7
Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Thu Sep 1 16:05:06 2016 -0700
+Date: Thu May 21 14:45:28 2020 -0700
- FindWithDefault returns by value rather than reference.
-
- Returning by reference leads to lifetime issues with the default
- value which may go out of scope by the time it is used.
-
- Thanks to @Ardavel for reporting this, as this causes graph_test
- to fail on VS2015x64.
-
- https://github.com/ceres-solver/ceres-solver/issues/216
+ NULL -> nullptr
- Change-Id: I596481219cfbf7622d49a6511ea29193b82c8ba3
+ Change-Id: Iaeea2ef7912d328653a76b65976adc8025a5be35
-commit 716f049a7b91a8f3a4632c367d9534d1d9190a81
-Author: Mike Vitus <vitus@google.com>
-Date: Wed Aug 31 13:38:30 2016 -0700
+commit 27b717951b58c134b3a5a9f664a66c7480364d6c
+Author: Alastair Harrison <aharrison24@gmail.com>
+Date: Fri May 15 10:10:12 2020 +0100
- Convert pose graph 2D example to glog and gflags.
+ Respect FIND_QUIETLY flag in cmake config file
- Change-Id: I0ed75a60718ef95199bb36f33d9eb99157d11d40
+ Ensure that Ceres does not print any log messages when somebody has
+ used 'find_package(Ceres QUIET)' in their CMake project.
+
+ Change-Id: Id6b68859cc8a5857f3fa78f29736cb82fd5a0943
-commit 46c5ce89dda308088a5fdc238d0c126fdd2c2b58
-Author: David Gossow <dgossow@google.com>
-Date: Wed Aug 31 18:40:57 2016 +0200
+commit 646959ef118a1f10bf93741d97cf64265d42f8c6
+Author: huangqinjin <huangqinjin@gmail.com>
+Date: Sat Apr 25 02:03:11 2020 +0800
- Fix compiler errors on some systems
+ Do not export class template LineParameterization
- This fixes some signed-unsigned comparisons and a missing header
- include.
+ For MSVC, instantiating a dllimport class template will cause error C2491:
+ definition of dllimport function not allowed.
- Change-Id: Ieb2bf6e905faa74851bc4ac4658d2f1da24b6ecc
+ Change-Id: Icc7f7ea84598df0a5436f48ffc2bab5cfab93921
-commit b102d53e1dd7dab132e58411183b6fffc2090590
-Author: David Gossow <dgossow@google.com>
-Date: Wed Aug 31 10:21:20 2016 +0200
+commit 1f128d070a24224d12eb901bc74ba393ccdbd0c3
+Author: huangqinjin <huangqinjin@gmail.com>
+Date: Mon Mar 4 13:14:43 2019 +0800
- Gradient checker multithreading bugfix.
+ Change the type of parameter index/offset to match their getter/setter
- This is a follow-up on c/7470. GradientCheckingCostFunction calls
- callback_->SetGradientErrorDetected() in its Evaluate method,
- which will run in multiple threads simultaneously when enabling
- this option in the solver. Thus, the string append operation
- inside that method has to be protected by a mutex.
+ Change-Id: If28b795e792f39db9775ada105e9038570195329
+
+commit 072c8f070e16cb32f211473c40196c6b5618d5a9
+Author: huangqinjin <huangqinjin@gmail.com>
+Date: Sat Apr 25 00:04:58 2020 +0800
+
+ Initialize integer variables with integer instead of double
- Change-Id: I314ef1df2be52595370d9af05851bf6da39bb45e
+ Change-Id: I652aca4ceb3129706a5d5e38afe9f16b61200a5b
-commit 79a28d1e49af53f67af7f3387d07e7c9b7339433
-Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Wed Aug 31 06:47:45 2016 -0700
+commit 8c36bcc81fbd4f78a2faa2c914ef40af264f4c31
+Author: Alex Stewart <alexs.mac@gmail.com>
+Date: Mon Apr 27 18:33:25 2020 +0100
- Rename a confusingly named member of Solver::Options
+ Use inline & -inlinehint-threshold in auto-diff benchmarks
- Solver::Options::numeric_derivative_relative_step_size to
- Solver::Options::gradient_check_numeric_derivative_relative_step_size
+ - This results in the same performance as the original solution of
+ increasing -inline-threshold, but this approach is more viable to
+ incorporate in a large code base as its effects are more targeted.
- Change-Id: Ib89ae3f87e588d4aba2a75361770d2cec26f07aa
+ Change-Id: Id798dbca7d3050de0ea847a5ecc69484ac78a2cf
-commit 358ae741c8c4545b03d95c91fa546d9a36683677
+commit 57cf20aa5d3c1b2f25d255814f4fff5260db81c6
Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Wed Aug 31 06:58:41 2016 -0700
+Date: Tue Apr 21 10:10:01 2020 -0700
- Note that Problem::Evaluate cannot be called from an IterationCallback
+ static const -> static constexpr where we can.
- Change-Id: Ieabdc2d40715e6b547ab22156ba32e9c8444b7ed
+ Change-Id: I8a6d26a89c4377dd440fa6dcf23513b7556533fc
-commit 44044e25b14d7e623baae4505a17c913bdde59f8
+commit 40b27482a202c8b0a5f9e8f2b4be0192d34195f5
Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Wed Aug 31 05:50:58 2016 -0700
+Date: Tue Apr 21 09:35:30 2020 -0700
- Update the NumTraits for Jets
+ Add std::numeric_limit specialization for Jets
- 1. Use AVX if EIGEN_VECTORIZE_AVX is defined.
- 2. Make the cost of division same as the cost of multiplication.
+ This allows users to use std::numeric_limits on templated functors.
- These are updates to the original numtraits update needed for eigen 3.3
- that Shaheen Gandhi sent out.
-
- Change-Id: Ic1e3ed7d05a659c7badc79a894679b2dd61c51b9
+ Change-Id: I403cec5c9826033ce7dfd6047deb64f66c35f806
-commit 4b6ad5d88e45ce8638c882d3e8f08161089b6dba
-Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Sat Aug 27 23:21:55 2016 -0700
+commit e751d6e4f0daa9f691c5ed25ca8dc564875d8bef
+Author: Darius Rueckert <darius.rueckert@fau.de>
+Date: Wed Apr 8 10:43:53 2020 +0200
- Use ProductParameterization in bundle_adjuster.cc
-
- Previously, when using a quaternion to parameterize the camera
- orientation, the camera parameter block was split into two
- parameter blocks. One for the rotation and another for the
- translation and intrinsics. This was to enable the use of the
- Quaternion parameterization.
+ Remove AutodiffCodegen
- Now that we have a ProductParameterization which allows us
- to compose multiple parameterizations, this is no longer needed
- and we use a size 10 parameter block instead.
+ - Remove Codegen files
+ - Revert Jet and Rotation
- This leads to a more than 2x improvements in the linear solver time.
-
- Change-Id: I78b8f06696f81fee54cfe1a4ae193ee8a5f8e920
+ Change-Id: I005c5f98f2b6dfa5c7fd88d998b6aa83e47dab60
-commit bfc916cf1cf753b85c1e2ac037e2019ee891f6f9
-Author: Shaheen Gandhi <visigoth@gmail.com>
-Date: Thu Aug 4 12:10:14 2016 -0700
+commit e9eb76f8ef9835940659cfb3a312ed6822c48152
+Author: Darius Rueckert <darius.rueckert@fau.de>
+Date: Mon Apr 6 11:11:43 2020 +0200
- Allow ceres to be used with the latest version of Eigen
+ Remove AutodiffCodegen CMake integration
- Change-Id: Ief3b0f6b405484ec04ecd9ab6a1e1e5409a594c2
+ Change-Id: I403597540df8429378336626b8f748b7821fe6f5
-commit edbd48ab502aa418ad9700ee5c3ada5f9268b90a
-Author: Alex Stewart <alexs.mac@gmail.com>
-Date: Sun Jul 10 14:13:51 2016 +0100
+commit 9435e08a7a7c903897e18e1dc24d801caf4f62a4
+Author: Sameer Agarwal <sameeragarwal@google.com>
+Date: Fri Apr 3 11:50:09 2020 -0700
- Enable support for OpenMP in Clang if detected.
-
- - Previously we disabled OpenMP if Clang was detected, as it did not
- support it. However as of Clang 3.8 (and potentially Xcode 8) OpenMP
- is supported.
+ More clang-tidy and wjr@ comment fixes
- Change-Id: Ia39dac9fe746f1fc6310e08553f85f3c37349707
+ Change-Id: I5736ae482f736fc56c00d21c659b1f8d41da68e9
-commit f6df6c05dd83b19fa90044106ebaca40957998ae
-Author: Mike Vitus <vitus@google.com>
-Date: Thu Aug 18 19:27:43 2016 -0700
+commit d93fac4b7ab670a936ce821284a0b9d099b4688c
+Author: Darius Rueckert <darius.rueckert@fau.de>
+Date: Fri Apr 3 09:33:17 2020 +0200
- Add an example for modeling and solving a 3D pose graph SLAM problem.
+ Remove AutodiffCodegen Tests
- Change-Id: I750ca5f20c495edfee5f60ffedccc5bd8ba2bb37
+ Change-Id: Icd194db7b22add518844f1b507d0fdd3e0fe17fe
-commit ac3b8e82175122e38bafaaa9cd419ba3cee11087
-Author: David Gossow <dgossow@google.com>
-Date: Fri Apr 29 16:07:11 2016 +0200
+commit 2281c6ed24d2c12f133fa6039f224b3da18cebe3
+Author: Sameer Agarwal <sameeragarwal@google.com>
+Date: Thu Apr 2 16:43:42 2020 -0700
- Gradient checking cleanup and local parameterization bugfix
-
- Change the Ceres gradient checking API to make is useful for
- unit testing, clean up code duplication and fix interaction between
- gradient checking and local parameterizations.
-
- There were two gradient checking implementations, one being used
- when using the check_gradients flag in the Solver, the other
- being a standalone class. The standalone version was restricted
- to cost functions with fixed parameter sizes at compile time, which
- is being lifted here. This enables it to be used inside the
- GradientCheckingCostFunction as well.
+ Fixes for comments from William Rucklidge
- In addition, this installs new hooks in the Solver to ensure
- that Solve will fail if any incorrect gradients are detected. This
- way, you can set the check_gradient flags to true and detect
- errors in an automated way, instead of just printing error information
- to the log. The error log is now also returned in the Solver summary
- instead of being printed directly. The user can then decide what to
- do with it. The existing hooks for user callbacks are used for
- this purpose to keep the internal API changes minimal and non-invasive.
-
- The last and biggest change is the way the the interaction between
- local parameterizations and the gradient checker works. Before,
- local parameterizations would be ignored by the checker. However,
- if a cost function does not compute its Jacobian along the null
- space of the local parameterization, this wil not have any effect
- on the solver, but would result in a gradient checker error.
- With this change, the Jacobians are multiplied by the Jacobians
- of the respective local parameterization and thus being compared
- in the tangent space only.
-
- The typical use case for this are quaternion parameters, where
- a cost function will typically assume that the quaternion is
- always normalized, skipping the correct computation of the Jacobian
- along the normal to save computation cost.
-
- Change-Id: I5e1bb97b8a899436cea25101efe5011b0bb13282
+ Change-Id: I64fcc25532cc66dc4cb7e2ea7ccfb220b0cb7e1f
-commit d4264ec10d9a270b53b5db86c0245ae8cbd2cf18
-Author: Mike Vitus <vitus@google.com>
-Date: Wed Aug 17 13:39:05 2016 -0700
+commit d797a87a4091af6ae0063e3c8291429c15318bdc
+Author: Sameer Agarwal <sameeragarwal@google.com>
+Date: Thu Apr 2 13:57:56 2020 -0700
- Add a quaternion local parameterization for Eigen's quaternion element convention.
+ Use Ridders' method in GradientChecker.
- Change-Id: I7046e8b24805313c5fb6a767de581d0054fcdb83
-
-commit fd7cab65ef30fbc33612220abed52dd5073413c4
-Author: Mike Vitus <vitus@google.com>
-Date: Wed Aug 10 09:29:12 2016 -0700
-
- Fix typos in the pose graph 2D example.
+ Using Ridders' method gives orders of magnitude more accuracy compared
+ to central differences. This will make things slower, but this is
+ primarily a testing/debugging feature and the speed hit is not a
+ concern. This should also reduce the false positive rates when users
+ enable check_gradients. This is reflected the increased sensitivity of
+ the tests for GradientChecker.
+
+ https://github.com/ceres-solver/ceres-solver/issues/554
- Change-Id: Ie024ff6b6cab9f2e8011d21121a91931bd987bd1
+ Change-Id: I6b871c72df55be1c31175ba062cf3c1e94e4b662
-commit 375dc348745081f89693607142d8b6744a7fb6b4
-Author: Mike Vitus <vitus@google.com>
-Date: Wed Aug 3 18:51:16 2016 -0700
+commit 41675682dc9df836bf15845064cfe1087619c79d
+Author: Sameer Agarwal <sameeragarwal@google.com>
+Date: Thu Apr 2 07:28:38 2020 -0700
- Remove duplicate entry for the NIST example in the docs.
+ Fix a MSVC type deduction bug in ComputeHouseholderVector
- Change-Id: Ic4e8f9b68b77b5235b5c96fe588cc56866dab759
+ A recent change made this function templated and MSVC 16 has trouble
+ doing automatic argument deduction, so the type of the template is
+ simplified and all callsites are explicitly annotated with the type
+ of the arguments.
+
+ Change-Id: I83cd0269e6e82c4a8f4e391f5fc03b92c942f74d
-commit f554681bf22d769abc12dd6d346ef65f9bb22431
-Author: Mike Vitus <vitus@google.com>
-Date: Mon Jul 25 18:30:48 2016 -0700
+commit 947ec0c1fa0f67c89e21daaf8d1648822ae5293a
+Author: Darius Rueckert <darius.rueckert@fau.de>
+Date: Thu Apr 2 09:52:53 2020 +0200
- Add an example for modeling and solving a 2D pose graph SLAM problem.
+ Remove AutodiffCodegen autodiff benchmarks
- Change-Id: Ia89b12af7afa33e7b1b9a68d69cf2a0b53416737
+ Change-Id: If1eaad31710cc91d40323ea6cae7cabe6fa64b1f
-commit e1bcc6e0f51512f43aa7bfb7b0d62f7ac1d0cd4b
+commit 27183d661ecae246dbce6d03cacf84f39fba1f1e
Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Wed May 18 07:52:48 2016 -0700
+Date: Thu Jul 11 16:30:59 2019 +0200
- Add additional logging for analyzing orderings
+ Allow LocalParameterizations to have zero local size.
+
+ Local parameterizations with zero tangent/local size will cause the
+ corresponding parameter block to be treated as constant.
- Change-Id: Ic68d2959db35254e2895f11294fb25de4d4b8a81
+ https://github.com/ceres-solver/ceres-solver/issues/347
+
+ Change-Id: I554a2acc420f5dd9d0cc7f97b691877eb057b2c0
-commit 16980b4fec846f86910c18772b8145bcb55f4728
-Author: Mike Vitus <vitus@google.com>
-Date: Fri Jul 15 13:37:49 2016 -0700
+commit 7ac7d79dca2ac6b482da50fd9ad0227ba8d6c632
+Author: Darius Rueckert <darius.rueckert@fau.de>
+Date: Wed Apr 1 14:51:12 2020 +0200
- Delete the remove_definitons command from sampled_functions
- CMakeLists.txt because it will be inherited from the top level examples
- CMakeLists.txt.
+ Remove HelloWorldCodegen example
- Change-Id: I25593587df0ae84fd8ddddc589bc2a13f3777427
+ Change-Id: I2584f41d591a5d648b4832385c2a779bb25fc04d
-commit a04490be97800e78e59db5eb67fa46226738ffba
-Author: Mike Vitus <vitus@google.com>
-Date: Thu Jul 14 10:10:13 2016 -0700
+commit 8c8738bf832f0fc27f0d4a9585fc59b2eaa6a828
+Author: Nikolaus Demmel <nikolaus@nikolaus-demmel.de>
+Date: Sun Mar 29 13:29:02 2020 +0200
- Add readme for the sampled_function example.
+ Add photometric and relative-pose residuals to autodiff benchmarks
- Change-Id: I9468b6a7b9f2ffdd2bf9f0dd1f4e1d5f894e540c
+ Change-Id: Id100ff2656ab63bb4fd19a51b95e78281cfd8b4a
-commit ff11d0e63d4678188e8cabd40a532ba06912fe5a
-Author: Alex Stewart <alexs.mac@gmail.com>
-Date: Wed Jun 29 09:31:45 2016 +0100
+commit 9f7fb66d62014ed62ba6aa617364e8591211c797
+Author: Darius Rueckert <darius.rueckert@fau.de>
+Date: Wed Mar 25 11:41:39 2020 +0100
- Use _j[0,1,n]() Bessel functions on MSVC to avoid deprecation errors.
+ Add a constant cost function to the autodiff benchmarks
+
+ The constant cost function is run with a variable number of
+ parameters to test at which point, different compilers fail
+ to optimize the autodiff code.
- - Microsoft deprecated the POSIX Bessel functions: j[0,1,n]() in favour
- of _j[0,1,n](), it appears since at least MSVC 2005:
- https://msdn.microsoft.com/en-us/library/ms235384(v=vs.100).aspx.
- - As this occurs in jet.h (templated public header), although Ceres
- suppresses the warning when it itself is built (to suppress a warning
- about the insecurity of using std::copy), it will crop up again in
- client code (without this fix) unless it is explicitly suppressed
- there also.
- - Raised as Issue #190:
- https://github.com/ceres-solver/ceres-solver/issues/190.
+ Clang achieves expected performance which fails at >50 parameters.
+ G++ fails already at 20 parameters
- Change-Id: If7ac5dbb856748f9900be93ec0452a40c0b00524
+ Change-Id: I75d8c683ef0011d813ec6d966d7ad58f86530f44
-commit 8ea86e1614cf77644ce782e43cde6565a54444f5
-Author: Nicolai Wojke <nwojke@uni-koblenz.de>
-Date: Mon Apr 25 14:24:41 2016 +0200
+commit ab0d373e465f46ce483db640d0fb2f244f48702d
+Author: Sameer Agarwal <sameeragarwal@google.com>
+Date: Tue Mar 24 12:30:46 2020 -0700
- Fix: Copy minimizer option 'is_silent' to LinSearchDirection::Options
+ Fix a comment in autodiff.h
- Change-Id: I23b4c3383cad30033c539ac93883d77c8dd4ba1a
+ Change-Id: I613e537c834e3f29cd92808c65ddb74f112974cc
-commit 080ca4c5f2ac42620971a07f06d2d13deb7befa8
-Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Sun Apr 24 22:46:54 2016 -0700
+commit 27bb997144d00dd4494d440627f1e782bf4adf43
+Author: Johannes Beck <Jodebo_Beck@gmx.de>
+Date: Tue Mar 24 08:05:43 2020 +0100
- Fix typos in users.rst
+ Change SVD algorithm in covariance computation.
- Change-Id: Ifdc67638a39403354bc9589f42a1b42cb9984dd2
+ Switch from JacobiSVD to BDCSVD in
+ ComputeCovarianceValuesUsingDenseSVD. This should increase
+ the performance for larger covariance matrices. See
+ https://eigen.tuxfamily.org/dox/classEigen_1_1BDCSVD.html
+
+ Change-Id: Icde4dec89f506b638b0f9f1aee3b7cfc9e4d72fc
-commit 21ab397dc55335c147fdd795899b1f8981037b09
-Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Sun Apr 24 21:13:00 2016 -0700
+commit 84fdac38e033c8f9a63c6e6fca7b44219110f7df
+Author: Johannes Beck <Jodebo_Beck@gmx.de>
+Date: Tue Mar 24 08:02:21 2020 +0100
- Make some Jet comparisons exact.
+ Add const to GetCovarianceMatrix*
+
+ This CL adds const to the functions GetCovarianceMatrix and
+ GetCovarianceMatrixInTangentSpace.
- Change-Id: Ia08c72f3b8779df96f5c0d5a954b2c0a1dd3a061
+ Change-Id: Ibe2cafebede47977a9aabcac8d245f30af184fd1
-commit ee40f954cf464087eb8943abf4d9db8917a33fbe
-Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Sun Apr 24 07:49:55 2016 -0700
+commit 6bde61d6be9d81a2cd759a6bbb4a8cd3c24a529c
+Author: Johannes Beck <Jodebo_Beck@gmx.de>
+Date: Sat Dec 28 13:29:19 2019 +0100
- Add colmap to users.rst
+ Add line local parameterization.
+
+ This CL adds a local parameterization for a n-dimensional
+ line, which is represented as an origin point and a direction.
+ The line direction is updated in the same way as a
+ homogeneous vector and the origin point is updated
+ perpendicular to the line direction.
- Change-Id: I452a8c1dc6a3bc55734b2fc3a4002ff7939ba863
+ Change-Id: I733f395e5cc4250abf9778c26fe0a5ae1de6b624
-commit 9665e099022bd06e53b0779550e9aebded7f274d
+commit 2c1c0932e9d3f91691e5c5fce46b4440e181a8bc
Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Mon Apr 18 06:00:58 2016 -0700
+Date: Mon Mar 23 11:15:32 2020 -0700
- Fix step norm evaluation in LineSearchMinimizer
+ Update documentation in autodiff.h
- TrustRegionMinimizer evaluates the size of the step
- taken in the ambient space, where as the LineSearchMinimizer
- was using the norm in the tangent space. This change fixes
- this discrepancy.
-
- Change-Id: I9fef64cbb5622c9769c0413003cfb1dc6e89cfa3
+ Change-Id: Icc2753b4f5be95022ffd92e479cdd3d9d7959d4c
-commit 620ca9d0668cd4a00402264fddca3cf6bd2e7265
-Author: Alex Stewart <alexs.mac@gmail.com>
-Date: Mon Apr 18 15:14:11 2016 +0100
+commit 8904fa4887ed7b3e6d110ad5a98efbc2df48595e
+Author: Darius Rueckert <darius.rueckert@fau.de>
+Date: Mon Mar 23 14:59:26 2020 +0100
- Remove use of -Werror when compiling Ceres.
+ Inline Jet initialization in Autodiff
+
+ Inlining the Jet initialzation is mandatory for good performance
+ in autodiff, because all the constants in the dual part can be
+ propagated into the cost functor.
- - As noted in Issue #193 (in that case for GCC 6), Ceres' use of -Werror
- when compiling on *nix can prevent compilation on new compilers that
- add new warnings and there is an inevitable delay between new compiler
- versions and Ceres versions.
- - Removing the explicit use of -Werror, and relying on indirect
- verification by maintainers should fix build issues for Ceres releases
- on newer compilers.
+ This patch unrolls the initialization loop with templates and adds
+ EIGEN_ALWAYS_INLINE to the constructors.
- Change-Id: I38e9ade28d4a90e53dcd918a7d470f1a1debd7b4
+ Change-Id: Ic89d645984f3e1df6c63948236da823ba60d9620
-commit 0c63bd3efbf1d41151c9fab41d4b77dc64c572c8
-Author: Mike Vitus <vitus@google.com>
-Date: Thu Apr 14 10:25:52 2016 -0700
+commit 18a464d4e566e17930005876af19e32cc8796fa3
+Author: Sameer Agarwal <sameeragarwal@google.com>
+Date: Mon Mar 23 07:12:12 2020 -0700
- Add floor and ceil functions to the Jet implementation.
+ Remove an errant CR from local_parameterization.cc
- Change-Id: I72ebfb0e9ade2964dbf3a014225ead345d5ae352
+ Change-Id: Iff98a96f06de5755062a1c79523604dca78b298e
-commit 9843f3280356c158d23c06a16085c6c5ba35e053
-Author: Alex Stewart <alexs.mac@gmail.com>
-Date: Mon Mar 7 21:24:32 2016 +0000
+commit 5c85f21799804d39cbfd20ec451aa219511e4212
+Author: Darius Rueckert <darius.rueckert@fau.de>
+Date: Mon Mar 23 10:12:00 2020 +0100
- Report Ceres compile options as components in find_package().
+ Use ArraySelector in Autodiff
- - Users can now specify particular components from Ceres, such as
- SuiteSparse support) that must be present in a detected version of
- Ceres in order for it to be reported as found by find_package().
- - This allows users to specify for example that they require a version
- of Ceres with SuiteSparse support at configure time, rather than
- finding out only at run time that Ceres was not compiled with the
- options they require.
- - The list of available components are built directly from the Ceres
- compile options.
- - The meta-module SparseLinearAlgebraLibrary is present if at least
- one sparse linear algebra backend is available.
+ The class ArraySelector is now used in autodiff to store the
+ parameters and residuals. This reduces overhead of FixedArray
+ for fixed-sized residuals and allows more optimizations due
+ to inlining and unrolling.
- Change-Id: I65f1ddfd7697e6dd25bb4ac7e54f5097d3ca6266
+ Change-Id: Ibadc5644e64d672f7a555e250fb1f8da262f9d4f
-commit e4d4d88bbe51b9cc0f7450171511abbea0779790
-Author: Timer <linyicx@126.com>
-Date: Fri Apr 8 15:42:18 2016 +0800
+commit 80477ff073ab7af03cfb248cab4ef41a87f913d0
+Author: Darius Rueckert <darius.rueckert@fau.de>
+Date: Fri Mar 20 16:26:55 2020 +0100
- Fix a spelling error in nnls_modeling.rst
+ Add class ArraySelector
- Change-Id: I341d901d3df993bc5397ed15e6cb330b0c38fd72
+ The ArraySelector selects the best array implementation based on
+ template arguments.
+
+ Change-Id: I93c6db1a638e924b85292e63bca9525610ec2e2f
-commit 5512f58536e1be0d92010d8325b606e7b4733a08
-Author: Keir Mierle <mierle@gmail.com>
-Date: Thu Apr 7 12:03:16 2016 -0700
+commit e7a30359ee754057f9bd7b349c98c291138d91f4
+Author: Darius Rueckert <darius.rueckert@fau.de>
+Date: Fri Mar 20 15:50:37 2020 +0100
- Only use collapse() directive with OpenMP 3.0 or higher
+ Pass kNumResiduals to Autodiff
+
+ The compile-time constant kNumResiduals is now passed to the
+ autodiff functions as a template parameter. This will be used
+ by future patches to optimize autodiff performance.
- Change-Id: Icba544c0494763c57eb6dc61e98379312ca15972
+ Change-Id: Ia2b2cc99b88752e8f12f4ce2542b1963bda552f5
-commit d61e94da5225217cab7b4f93b72f97055094681f
-Author: Thomas Schneider <schneith@ethz.ch>
-Date: Wed Apr 6 10:40:29 2016 +0200
+commit f339d71dd64e4d871cc883f278a153f212f0d1f0
+Author: Sameer Agarwal <sameeragarwal@google.com>
+Date: Thu Mar 19 12:08:28 2020 -0700
+
+ Refactor the automatic differentiation benchmarks.
+
+ 1. Merge them into a single binary.
+ 2. All benchmarks now do the Residual and the Residual + Jacobian
+ evaluation.
+ 3. Re-organize and simplify the CMake file in this directory.
+ 4. Fix a bug in the file where the Clang compiler was not being matched.
+
+ autodiff_benchmarks
+ ---------------------------------------------------------------------------
+ Benchmark Time CPU Iterations
+ ---------------------------------------------------------------------------
+ BM_Linear1CodeGen/0 3.02 ns 3.01 ns 233870456
+ BM_Linear1CodeGen/1 3.02 ns 3.01 ns 233059100
+ BM_Linear1AutoDiff/0 3.78 ns 3.77 ns 185791712
+ BM_Linear1AutoDiff/1 14.0 ns 13.8 ns 53927875
+ BM_Linear10CodeGen/0 5.10 ns 5.10 ns 126745007
+ BM_Linear10CodeGen/1 29.1 ns 29.1 ns 23949310
+ BM_Linear10AutoDiff/0 6.50 ns 6.49 ns 107516972
+ BM_Linear10AutoDiff/1 169 ns 169 ns 4153218
+ BM_Rat43AutoDiff/0 52.7 ns 51.2 ns 16444586
+ BM_Rat43AutoDiff/1 91.8 ns 91.5 ns 7302316
+ BM_SnavelyReprojectionCodeGen/0 38.0 ns 36.2 ns 21131501
+ BM_SnavelyReprojectionCodeGen/1 113 ns 112 ns 5627779
+ BM_SnavelyReprojectionAutoDiff/0 34.4 ns 34.3 ns 20476937
+ BM_SnavelyReprojectionAutoDiff/1 242 ns 240 ns 2930611
+ BM_BrdfCodeGen/0 53.9 ns 53.7 ns 11950083
+ BM_BrdfCodeGen/1 507 ns 505 ns 1396732
+ BM_BrdfAutoDiff/0 58.3 ns 57.8 ns 12220670
+ BM_BrdfAutoDiff/1 2034 ns 1999 ns 257003
+
+ autodiff_benchmarks_fast_math
+ ---------------------------------------------------------------------------
+ Benchmark Time CPU Iterations
+ ---------------------------------------------------------------------------
+ BM_Linear1CodeGen/0 3.19 ns 3.16 ns 215313065
+ BM_Linear1CodeGen/1 2.78 ns 2.76 ns 201497994
+ BM_Linear1AutoDiff/0 3.27 ns 3.26 ns 206154598
+ BM_Linear1AutoDiff/1 13.2 ns 13.1 ns 57257840
+ BM_Linear10CodeGen/0 5.70 ns 5.51 ns 121849325
+ BM_Linear10CodeGen/1 33.9 ns 33.3 ns 21829295
+ BM_Linear10AutoDiff/0 6.85 ns 6.78 ns 106813153
+ BM_Linear10AutoDiff/1 173 ns 171 ns 3849877
+ BM_Rat43AutoDiff/0 44.8 ns 44.2 ns 15577017
+ BM_Rat43AutoDiff/1 96.2 ns 94.6 ns 7374864
+ BM_SnavelyReprojectionCodeGen/0 33.9 ns 33.5 ns 20508373
+ BM_SnavelyReprojectionCodeGen/1 89.7 ns 88.4 ns 7620624
+ BM_SnavelyReprojectionAutoDiff/0 36.5 ns 35.8 ns 20546176
+ BM_SnavelyReprojectionAutoDiff/1 257 ns 252 ns 3044325
+ BM_BrdfCodeGen/0 61.1 ns 58.5 ns 11334013
+ BM_BrdfCodeGen/1 265 ns 265 ns 2625459
+ BM_BrdfAutoDiff/0 52.5 ns 52.5 ns 12938763
+ BM_BrdfAutoDiff/1 1560 ns 1560 ns 440909
+
+ Change-Id: I2d1a4293d3245a50f73af6cf5e5138084321ae6f
+
+commit d37b4cb150c4af65268f9ce5739d1c67e73cb358
+Author: Sameer Agarwal <sameeragarwal@google.com>
+Date: Thu Mar 19 07:36:58 2020 -0700
- Add IsParameterBlockConstant to the ceres::Problem class.
+ Fix some include headers in codegen/test_utils.cc/h
- Change-Id: I7d0e828e81324443209c17fa54dd1d37605e5bfe
+ Change-Id: I769029ce2797eba0de6c7baeb76dc3f2782b6305
-commit 77d94b34741574e958a417561702d6093fba87fb
-Author: Alex Stewart <alexs.mac@gmail.com>
-Date: Sun Feb 14 16:54:03 2016 +0000
+commit 550766e6da49dca895a6e2056b0872c557157c5b
+Author: Darius Rueckert <darius.rueckert@fau.de>
+Date: Wed Mar 18 20:09:20 2020 +0100
- Fix install path for CeresConfig.cmake to be architecture-aware.
+ Add Autodiff Brdf Benchmark
- - Previously we were auto-detecting a "64" suffix for the install path
- for the Ceres library on non-Debian/Arch Linux distributions, but
- we were installing CeresConfig.cmake to an architecture independent
- location.
- - We now install CeresConfig.cmake to lib${LIB_SUFFIX}/cmake/Ceres.
- - Also make LIB_SUFFIX visible to the user in the CMake GUI s/t they can
- easily override the auto-detected value if desired.
- - Reported by jpgr87@gmail.com as Issue #194.
+ The disney brdf is a good benchmark cost functor, because it has
+ - 28 parameters in 7 blocks
+ - 3 residuals
+ - Lots of low-level arithmetic
- Change-Id: If126260d7af685779487c01220ae178ac31f7aea
+ Change-Id: I62c8a717d0aecb64639158f971bdccf6afdfae36
diff --git a/extern/ceres/bundle.sh b/extern/ceres/bundle.sh
index 02af59faf28..573db5a0a2f 100755
--- a/extern/ceres/bundle.sh
+++ b/extern/ceres/bundle.sh
@@ -9,7 +9,6 @@ fi
repo="https://ceres-solver.googlesource.com/ceres-solver"
branch="master"
-#tag="1.4.0"
tag=""
tmp=`mktemp -d`
checkout="$tmp/ceres"
@@ -157,14 +156,10 @@ add_definitions(
-DCERES_NO_SUITESPARSE
-DCERES_NO_CXSPARSE
-DCERES_NO_LAPACK
+ -DCERES_NO_ACCELERATE_SPARSE
-DCERES_HAVE_RWLOCK
+ -DCERES_USE_CXX_THREADS
)
-if(WITH_OPENMP)
- add_definitions(
- -DCERES_USE_OPENMP
- )
-endif()
-
blender_add_lib(extern_ceres "\${SRC}" "\${INC}" "\${INC_SYS}" "\${LIB}")
EOF
diff --git a/extern/ceres/files.txt b/extern/ceres/files.txt
index 4d973bbcdc2..bfbd57090c9 100644
--- a/extern/ceres/files.txt
+++ b/extern/ceres/files.txt
@@ -1,29 +1,37 @@
include/ceres/autodiff_cost_function.h
+include/ceres/autodiff_first_order_function.h
include/ceres/autodiff_local_parameterization.h
include/ceres/c_api.h
include/ceres/ceres.h
include/ceres/conditioned_cost_function.h
+include/ceres/context.h
include/ceres/cost_function.h
include/ceres/cost_function_to_functor.h
include/ceres/covariance.h
include/ceres/crs_matrix.h
+include/ceres/cubic_interpolation.h
include/ceres/dynamic_autodiff_cost_function.h
+include/ceres/dynamic_cost_function.h
include/ceres/dynamic_cost_function_to_functor.h
include/ceres/dynamic_numeric_diff_cost_function.h
-include/ceres/fpclassify.h
+include/ceres/evaluation_callback.h
+include/ceres/first_order_function.h
include/ceres/gradient_checker.h
include/ceres/gradient_problem.h
include/ceres/gradient_problem_solver.h
+include/ceres/internal/array_selector.h
include/ceres/internal/autodiff.h
include/ceres/internal/disable_warnings.h
include/ceres/internal/eigen.h
include/ceres/internal/fixed_array.h
-include/ceres/internal/macros.h
-include/ceres/internal/manual_constructor.h
+include/ceres/internal/householder_vector.h
+include/ceres/internal/integer_sequence_algorithm.h
+include/ceres/internal/line_parameterization.h
+include/ceres/internal/memory.h
include/ceres/internal/numeric_diff.h
+include/ceres/internal/parameter_dims.h
include/ceres/internal/port.h
include/ceres/internal/reenable_warnings.h
-include/ceres/internal/scoped_ptr.h
include/ceres/internal/variadic_evaluate.h
include/ceres/iteration_callback.h
include/ceres/jet.h
@@ -37,8 +45,13 @@ include/ceres/problem.h
include/ceres/rotation.h
include/ceres/sized_cost_function.h
include/ceres/solver.h
+include/ceres/tiny_solver_autodiff_function.h
+include/ceres/tiny_solver_cost_function_adapter.h
+include/ceres/tiny_solver.h
include/ceres/types.h
include/ceres/version.h
+internal/ceres/accelerate_sparse.cc
+internal/ceres/accelerate_sparse.h
internal/ceres/array_utils.cc
internal/ceres/array_utils.h
internal/ceres/blas.cc
@@ -63,21 +76,26 @@ internal/ceres/block_structure.cc
internal/ceres/block_structure.h
internal/ceres/callbacks.cc
internal/ceres/callbacks.h
+internal/ceres/canonical_views_clustering.cc
+internal/ceres/canonical_views_clustering.h
internal/ceres/c_api.cc
internal/ceres/casts.h
internal/ceres/cgnr_linear_operator.h
internal/ceres/cgnr_solver.cc
internal/ceres/cgnr_solver.h
-internal/ceres/collections_port.h
internal/ceres/compressed_col_sparse_matrix_utils.cc
internal/ceres/compressed_col_sparse_matrix_utils.h
internal/ceres/compressed_row_jacobian_writer.cc
internal/ceres/compressed_row_jacobian_writer.h
internal/ceres/compressed_row_sparse_matrix.cc
internal/ceres/compressed_row_sparse_matrix.h
+internal/ceres/concurrent_queue.h
internal/ceres/conditioned_cost_function.cc
internal/ceres/conjugate_gradients_solver.cc
internal/ceres/conjugate_gradients_solver.h
+internal/ceres/context.cc
+internal/ceres/context_impl.cc
+internal/ceres/context_impl.h
internal/ceres/coordinate_descent_minimizer.cc
internal/ceres/coordinate_descent_minimizer.h
internal/ceres/corrector.cc
@@ -85,6 +103,7 @@ internal/ceres/corrector.h
internal/ceres/covariance.cc
internal/ceres/covariance_impl.cc
internal/ceres/covariance_impl.h
+internal/ceres/cxsparse.cc
internal/ceres/cxsparse.h
internal/ceres/dense_jacobian_writer.h
internal/ceres/dense_normal_cholesky_solver.cc
@@ -102,11 +121,21 @@ internal/ceres/dynamic_compressed_row_jacobian_writer.cc
internal/ceres/dynamic_compressed_row_jacobian_writer.h
internal/ceres/dynamic_compressed_row_sparse_matrix.cc
internal/ceres/dynamic_compressed_row_sparse_matrix.h
+internal/ceres/dynamic_sparse_normal_cholesky_solver.cc
+internal/ceres/dynamic_sparse_normal_cholesky_solver.h
+internal/ceres/eigensparse.cc
+internal/ceres/eigensparse.h
internal/ceres/evaluator.cc
internal/ceres/evaluator.h
internal/ceres/execution_summary.h
internal/ceres/file.cc
internal/ceres/file.h
+internal/ceres/float_cxsparse.cc
+internal/ceres/float_cxsparse.h
+internal/ceres/float_suitesparse.cc
+internal/ceres/float_suitesparse.h
+internal/ceres/function_sample.cc
+internal/ceres/function_sample.h
internal/ceres/generated/partitioned_matrix_view_2_2_2.cc
internal/ceres/generated/partitioned_matrix_view_2_2_3.cc
internal/ceres/generated/partitioned_matrix_view_2_2_4.cc
@@ -118,10 +147,12 @@ internal/ceres/generated/partitioned_matrix_view_2_3_9.cc
internal/ceres/generated/partitioned_matrix_view_2_3_d.cc
internal/ceres/generated/partitioned_matrix_view_2_4_3.cc
internal/ceres/generated/partitioned_matrix_view_2_4_4.cc
+internal/ceres/generated/partitioned_matrix_view_2_4_6.cc
internal/ceres/generated/partitioned_matrix_view_2_4_8.cc
internal/ceres/generated/partitioned_matrix_view_2_4_9.cc
internal/ceres/generated/partitioned_matrix_view_2_4_d.cc
internal/ceres/generated/partitioned_matrix_view_2_d_d.cc
+internal/ceres/generated/partitioned_matrix_view_3_3_3.cc
internal/ceres/generated/partitioned_matrix_view_4_4_2.cc
internal/ceres/generated/partitioned_matrix_view_4_4_3.cc
internal/ceres/generated/partitioned_matrix_view_4_4_4.cc
@@ -138,17 +169,18 @@ internal/ceres/generated/schur_eliminator_2_3_9.cc
internal/ceres/generated/schur_eliminator_2_3_d.cc
internal/ceres/generated/schur_eliminator_2_4_3.cc
internal/ceres/generated/schur_eliminator_2_4_4.cc
+internal/ceres/generated/schur_eliminator_2_4_6.cc
internal/ceres/generated/schur_eliminator_2_4_8.cc
internal/ceres/generated/schur_eliminator_2_4_9.cc
internal/ceres/generated/schur_eliminator_2_4_d.cc
internal/ceres/generated/schur_eliminator_2_d_d.cc
+internal/ceres/generated/schur_eliminator_3_3_3.cc
internal/ceres/generated/schur_eliminator_4_4_2.cc
internal/ceres/generated/schur_eliminator_4_4_3.cc
internal/ceres/generated/schur_eliminator_4_4_4.cc
internal/ceres/generated/schur_eliminator_4_4_d.cc
internal/ceres/generated/schur_eliminator_d_d_d.cc
-internal/ceres/generate_eliminator_specialization.py
-internal/ceres/generate_partitioned_matrix_view_specializations.py
+internal/ceres/generate_template_specializations.py
internal/ceres/gradient_checker.cc
internal/ceres/gradient_checking_cost_function.cc
internal/ceres/gradient_checking_cost_function.h
@@ -157,12 +189,15 @@ internal/ceres/gradient_problem_evaluator.h
internal/ceres/gradient_problem_solver.cc
internal/ceres/graph_algorithms.h
internal/ceres/graph.h
-internal/ceres/householder_vector.h
internal/ceres/implicit_schur_complement.cc
internal/ceres/implicit_schur_complement.h
-internal/ceres/integral_types.h
+internal/ceres/inner_product_computer.cc
+internal/ceres/inner_product_computer.h
+internal/ceres/invert_psd_matrix.h
internal/ceres/is_close.cc
internal/ceres/is_close.h
+internal/ceres/iterative_refiner.cc
+internal/ceres/iterative_refiner.h
internal/ceres/iterative_schur_complement_solver.cc
internal/ceres/iterative_schur_complement_solver.h
internal/ceres/lapack.cc
@@ -190,14 +225,21 @@ internal/ceres/low_rank_inverse_hessian.h
internal/ceres/map_util.h
internal/ceres/minimizer.cc
internal/ceres/minimizer.h
-internal/ceres/mutex.h
internal/ceres/normal_prior.cc
+internal/ceres/pair_hash.h
+internal/ceres/parallel_for_cxx.cc
+internal/ceres/parallel_for.h
+internal/ceres/parallel_for_nothreads.cc
+internal/ceres/parallel_for_openmp.cc
+internal/ceres/parallel_utils.cc
+internal/ceres/parallel_utils.h
internal/ceres/parameter_block.h
internal/ceres/parameter_block_ordering.cc
internal/ceres/parameter_block_ordering.h
internal/ceres/partitioned_matrix_view.cc
internal/ceres/partitioned_matrix_view.h
internal/ceres/partitioned_matrix_view_impl.h
+internal/ceres/partitioned_matrix_view_template.py
internal/ceres/polynomial.cc
internal/ceres/polynomial.h
internal/ceres/preconditioner.cc
@@ -222,14 +264,23 @@ internal/ceres/schur_complement_solver.h
internal/ceres/schur_eliminator.cc
internal/ceres/schur_eliminator.h
internal/ceres/schur_eliminator_impl.h
+internal/ceres/schur_eliminator_template.py
internal/ceres/schur_jacobi_preconditioner.cc
internal/ceres/schur_jacobi_preconditioner.h
+internal/ceres/schur_templates.cc
+internal/ceres/schur_templates.h
+internal/ceres/scoped_thread_token.h
internal/ceres/scratch_evaluate_preparer.cc
internal/ceres/scratch_evaluate_preparer.h
+internal/ceres/single_linkage_clustering.cc
+internal/ceres/single_linkage_clustering.h
+internal/ceres/small_blas_generic.h
internal/ceres/small_blas.h
internal/ceres/solver.cc
internal/ceres/solver_utils.cc
internal/ceres/solver_utils.h
+internal/ceres/sparse_cholesky.cc
+internal/ceres/sparse_cholesky.h
internal/ceres/sparse_matrix.cc
internal/ceres/sparse_matrix.h
internal/ceres/sparse_normal_cholesky_solver.cc
@@ -239,7 +290,14 @@ internal/ceres/split.h
internal/ceres/stl_util.h
internal/ceres/stringprintf.cc
internal/ceres/stringprintf.h
+internal/ceres/subset_preconditioner.cc
+internal/ceres/subset_preconditioner.h
+internal/ceres/suitesparse.cc
internal/ceres/suitesparse.h
+internal/ceres/thread_pool.cc
+internal/ceres/thread_pool.h
+internal/ceres/thread_token_provider.cc
+internal/ceres/thread_token_provider.h
internal/ceres/triplet_sparse_matrix.cc
internal/ceres/triplet_sparse_matrix.h
internal/ceres/trust_region_minimizer.cc
@@ -251,7 +309,10 @@ internal/ceres/trust_region_step_evaluator.h
internal/ceres/trust_region_strategy.cc
internal/ceres/trust_region_strategy.h
internal/ceres/types.cc
+internal/ceres/visibility_based_preconditioner.cc
internal/ceres/visibility_based_preconditioner.h
+internal/ceres/visibility.cc
+internal/ceres/visibility.h
internal/ceres/wall_time.cc
internal/ceres/wall_time.h
config/ceres/internal/config.h
diff --git a/extern/ceres/include/ceres/autodiff_cost_function.h b/extern/ceres/include/ceres/autodiff_cost_function.h
index e7893e4828e..5e6e9c55db5 100644
--- a/extern/ceres/include/ceres/autodiff_cost_function.h
+++ b/extern/ceres/include/ceres/autodiff_cost_function.h
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2019 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -30,7 +30,7 @@
//
// Create CostFunctions as needed by the least squares framework, with
// Jacobians computed via automatic differentiation. For more
-// information on automatic differentation, see the wikipedia article
+// information on automatic differentiation, see the wikipedia article
// at http://en.wikipedia.org/wiki/Automatic_differentiation
//
// To get an auto differentiated cost function, you must define a class with a
@@ -54,7 +54,7 @@
// for a series of measurements, where there is an instance of the cost function
// for each measurement k.
//
-// The actual cost added to the total problem is e^2, or (k - x'k)^2; however,
+// The actual cost added to the total problem is e^2, or (k - x'y)^2; however,
// the squaring is implicitly done by the optimization framework.
//
// To write an auto-differentiable cost function for the above model, first
@@ -90,7 +90,7 @@
// Dimension of x ---------------+ |
// Dimension of y ------------------+
//
-// In this example, there is usually an instance for each measumerent of k.
+// In this example, there is usually an instance for each measurement of k.
//
// In the instantiation above, the template parameters following
// "MyScalarCostFunctor", "1, 2, 2", describe the functor as computing a
@@ -110,12 +110,8 @@
// Dimension of x ------------------------------------+ |
// Dimension of y ---------------------------------------+
//
-// The framework can currently accommodate cost functions of up to 10
-// independent variables, and there is no limit on the dimensionality
-// of each of them.
-//
// WARNING #1: Since the functor will get instantiated with different types for
-// T, you must to convert from other numeric types to T before mixing
+// T, you must convert from other numeric types to T before mixing
// computations with other variables of type T. In the example above, this is
// seen where instead of using k_ directly, k_ is wrapped with T(k_).
//
@@ -129,8 +125,9 @@
#ifndef CERES_PUBLIC_AUTODIFF_COST_FUNCTION_H_
#define CERES_PUBLIC_AUTODIFF_COST_FUNCTION_H_
+#include <memory>
+
#include "ceres/internal/autodiff.h"
-#include "ceres/internal/scoped_ptr.h"
#include "ceres/sized_cost_function.h"
#include "ceres/types.h"
#include "glog/logging.h"
@@ -138,7 +135,7 @@
namespace ceres {
// A cost function which computes the derivative of the cost with respect to
-// the parameters (a.k.a. the jacobian) using an autodifferentiation framework.
+// the parameters (a.k.a. the jacobian) using an auto differentiation framework.
// The first template argument is the functor object, described in the header
// comment. The second argument is the dimension of the residual (or
// ceres::DYNAMIC to indicate it will be set at runtime), and subsequent
@@ -153,27 +150,15 @@ namespace ceres {
// of residuals for a single autodiff cost function at runtime.
template <typename CostFunctor,
int kNumResiduals, // Number of residuals, or ceres::DYNAMIC.
- int N0, // Number of parameters in block 0.
- int N1 = 0, // Number of parameters in block 1.
- int N2 = 0, // Number of parameters in block 2.
- int N3 = 0, // Number of parameters in block 3.
- int N4 = 0, // Number of parameters in block 4.
- int N5 = 0, // Number of parameters in block 5.
- int N6 = 0, // Number of parameters in block 6.
- int N7 = 0, // Number of parameters in block 7.
- int N8 = 0, // Number of parameters in block 8.
- int N9 = 0> // Number of parameters in block 9.
-class AutoDiffCostFunction : public SizedCostFunction<kNumResiduals,
- N0, N1, N2, N3, N4,
- N5, N6, N7, N8, N9> {
+ int... Ns> // Number of parameters in each parameter block.
+class AutoDiffCostFunction : public SizedCostFunction<kNumResiduals, Ns...> {
public:
// Takes ownership of functor. Uses the template-provided value for the
// number of residuals ("kNumResiduals").
- explicit AutoDiffCostFunction(CostFunctor* functor)
- : functor_(functor) {
- CHECK_NE(kNumResiduals, DYNAMIC)
- << "Can't run the fixed-size constructor if the "
- << "number of residuals is set to ceres::DYNAMIC.";
+ explicit AutoDiffCostFunction(CostFunctor* functor) : functor_(functor) {
+ static_assert(kNumResiduals != DYNAMIC,
+ "Can't run the fixed-size constructor if the number of "
+ "residuals is set to ceres::DYNAMIC.");
}
// Takes ownership of functor. Ignores the template-provided
@@ -183,13 +168,10 @@ class AutoDiffCostFunction : public SizedCostFunction<kNumResiduals,
// numbers of residuals at runtime.
AutoDiffCostFunction(CostFunctor* functor, int num_residuals)
: functor_(functor) {
- CHECK_EQ(kNumResiduals, DYNAMIC)
- << "Can't run the dynamic-size constructor if the "
- << "number of residuals is not ceres::DYNAMIC.";
- SizedCostFunction<kNumResiduals,
- N0, N1, N2, N3, N4,
- N5, N6, N7, N8, N9>
- ::set_num_residuals(num_residuals);
+ static_assert(kNumResiduals == DYNAMIC,
+ "Can't run the dynamic-size constructor if the number of "
+ "residuals is not ceres::DYNAMIC.");
+ SizedCostFunction<kNumResiduals, Ns...>::set_num_residuals(num_residuals);
}
virtual ~AutoDiffCostFunction() {}
@@ -197,29 +179,28 @@ class AutoDiffCostFunction : public SizedCostFunction<kNumResiduals,
// Implementation details follow; clients of the autodiff cost function should
// not have to examine below here.
//
- // To handle varardic cost functions, some template magic is needed. It's
+ // To handle variadic cost functions, some template magic is needed. It's
// mostly hidden inside autodiff.h.
- virtual bool Evaluate(double const* const* parameters,
- double* residuals,
- double** jacobians) const {
+ bool Evaluate(double const* const* parameters,
+ double* residuals,
+ double** jacobians) const override {
+ using ParameterDims =
+ typename SizedCostFunction<kNumResiduals, Ns...>::ParameterDims;
+
if (!jacobians) {
- return internal::VariadicEvaluate<
- CostFunctor, double, N0, N1, N2, N3, N4, N5, N6, N7, N8, N9>
- ::Call(*functor_, parameters, residuals);
+ return internal::VariadicEvaluate<ParameterDims>(
+ *functor_, parameters, residuals);
}
- return internal::AutoDiff<CostFunctor, double,
- N0, N1, N2, N3, N4, N5, N6, N7, N8, N9>::Differentiate(
- *functor_,
- parameters,
- SizedCostFunction<kNumResiduals,
- N0, N1, N2, N3, N4,
- N5, N6, N7, N8, N9>::num_residuals(),
- residuals,
- jacobians);
- }
+ return internal::AutoDifferentiate<kNumResiduals, ParameterDims>(
+ *functor_,
+ parameters,
+ SizedCostFunction<kNumResiduals, Ns...>::num_residuals(),
+ residuals,
+ jacobians);
+ };
private:
- internal::scoped_ptr<CostFunctor> functor_;
+ std::unique_ptr<CostFunctor> functor_;
};
} // namespace ceres
diff --git a/extern/ceres/include/ceres/autodiff_first_order_function.h b/extern/ceres/include/ceres/autodiff_first_order_function.h
new file mode 100644
index 00000000000..b98d845655b
--- /dev/null
+++ b/extern/ceres/include/ceres/autodiff_first_order_function.h
@@ -0,0 +1,151 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2019 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#ifndef CERES_PUBLIC_AUTODIFF_FIRST_ORDER_FUNCTION_H_
+#define CERES_PUBLIC_AUTODIFF_FIRST_ORDER_FUNCTION_H_
+
+#include <memory>
+
+#include "ceres/first_order_function.h"
+#include "ceres/internal/eigen.h"
+#include "ceres/internal/fixed_array.h"
+#include "ceres/jet.h"
+#include "ceres/types.h"
+
+namespace ceres {
+
+// Create FirstOrderFunctions as needed by the GradientProblem
+// framework, with gradients computed via automatic
+// differentiation. For more information on automatic differentiation,
+// see the wikipedia article at
+// http://en.wikipedia.org/wiki/Automatic_differentiation
+//
+// To get an auto differentiated function, you must define a class
+// with a templated operator() (a functor) that computes the cost
+// function in terms of the template parameter T. The autodiff
+// framework substitutes appropriate "jet" objects for T in order to
+// compute the derivative when necessary, but this is hidden, and you
+// should write the function as if T were a scalar type (e.g. a
+// double-precision floating point number).
+//
+// The function must write the computed value in the last argument
+// (the only non-const one) and return true to indicate
+// success.
+//
+// For example, consider a scalar error e = x'y - a, where both x and y are
+// two-dimensional column vector parameters, the prime sign indicates
+// transposition, and a is a constant.
+//
+// To write an auto-differentiable FirstOrderFunction for the above model, first
+// define the object
+//
+// class QuadraticCostFunctor {
+// public:
+// explicit QuadraticCostFunctor(double a) : a_(a) {}
+// template <typename T>
+// bool operator()(const T* const xy, T* cost) const {
+// const T* const x = xy;
+// const T* const y = xy + 2;
+// *cost = x[0] * y[0] + x[1] * y[1] - T(a_);
+// return true;
+// }
+//
+// private:
+// double a_;
+// };
+//
+// Note that in the declaration of operator() the input parameters xy come
+// first, and are passed as const pointers to arrays of T. The
+// output is the last parameter.
+//
+// Then given this class definition, the auto differentiated FirstOrderFunction
+// for it can be constructed as follows.
+//
+// FirstOrderFunction* function =
+// new AutoDiffFirstOrderFunction<QuadraticCostFunctor, 4>(
+// new QuadraticCostFunctor(1.0)));
+//
+// In the instantiation above, the template parameters following
+// "QuadraticCostFunctor", "4", describe the functor as computing a
+// 1-dimensional output from a four dimensional vector.
+//
+// WARNING: Since the functor will get instantiated with different types for
+// T, you must convert from other numeric types to T before mixing
+// computations with other variables of type T. In the example above, this is
+// seen where instead of using a_ directly, a_ is wrapped with T(a_).
+
+template <typename FirstOrderFunctor, int kNumParameters>
+class AutoDiffFirstOrderFunction : public FirstOrderFunction {
+ public:
+ // Takes ownership of functor.
+ explicit AutoDiffFirstOrderFunction(FirstOrderFunctor* functor)
+ : functor_(functor) {
+ static_assert(kNumParameters > 0, "kNumParameters must be positive");
+ }
+
+ virtual ~AutoDiffFirstOrderFunction() {}
+
+ bool Evaluate(const double* const parameters,
+ double* cost,
+ double* gradient) const override {
+ if (gradient == nullptr) {
+ return (*functor_)(parameters, cost);
+ }
+
+ typedef Jet<double, kNumParameters> JetT;
+ internal::FixedArray<JetT, (256 * 7) / sizeof(JetT)> x(kNumParameters);
+ for (int i = 0; i < kNumParameters; ++i) {
+ x[i].a = parameters[i];
+ x[i].v.setZero();
+ x[i].v[i] = 1.0;
+ }
+
+ JetT output;
+ output.a = kImpossibleValue;
+ output.v.setConstant(kImpossibleValue);
+
+ if (!(*functor_)(x.data(), &output)) {
+ return false;
+ }
+
+ *cost = output.a;
+ VectorRef(gradient, kNumParameters) = output.v;
+ return true;
+ }
+
+ int NumParameters() const override { return kNumParameters; }
+
+ private:
+ std::unique_ptr<FirstOrderFunctor> functor_;
+};
+
+} // namespace ceres
+
+#endif // CERES_PUBLIC_AUTODIFF_FIRST_ORDER_FUNCTION_H_
diff --git a/extern/ceres/include/ceres/autodiff_local_parameterization.h b/extern/ceres/include/ceres/autodiff_local_parameterization.h
index 27397e20d3b..d694376fdd1 100644
--- a/extern/ceres/include/ceres/autodiff_local_parameterization.h
+++ b/extern/ceres/include/ceres/autodiff_local_parameterization.h
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2019 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -33,9 +33,10 @@
#ifndef CERES_PUBLIC_AUTODIFF_LOCAL_PARAMETERIZATION_H_
#define CERES_PUBLIC_AUTODIFF_LOCAL_PARAMETERIZATION_H_
-#include "ceres/local_parameterization.h"
+#include <memory>
+
#include "ceres/internal/autodiff.h"
-#include "ceres/internal/scoped_ptr.h"
+#include "ceres/local_parameterization.h"
namespace ceres {
@@ -107,21 +108,20 @@ namespace ceres {
template <typename Functor, int kGlobalSize, int kLocalSize>
class AutoDiffLocalParameterization : public LocalParameterization {
public:
- AutoDiffLocalParameterization() :
- functor_(new Functor()) {}
+ AutoDiffLocalParameterization() : functor_(new Functor()) {}
// Takes ownership of functor.
- explicit AutoDiffLocalParameterization(Functor* functor) :
- functor_(functor) {}
+ explicit AutoDiffLocalParameterization(Functor* functor)
+ : functor_(functor) {}
virtual ~AutoDiffLocalParameterization() {}
- virtual bool Plus(const double* x,
- const double* delta,
- double* x_plus_delta) const {
+ bool Plus(const double* x,
+ const double* delta,
+ double* x_plus_delta) const override {
return (*functor_)(x, delta, x_plus_delta);
}
- virtual bool ComputeJacobian(const double* x, double* jacobian) const {
+ bool ComputeJacobian(const double* x, double* jacobian) const override {
double zero_delta[kLocalSize];
for (int i = 0; i < kLocalSize; ++i) {
zero_delta[i] = 0.0;
@@ -133,20 +133,18 @@ class AutoDiffLocalParameterization : public LocalParameterization {
}
const double* parameter_ptrs[2] = {x, zero_delta};
- double* jacobian_ptrs[2] = { NULL, jacobian };
- return internal::AutoDiff<Functor, double, kGlobalSize, kLocalSize>
- ::Differentiate(*functor_,
- parameter_ptrs,
- kGlobalSize,
- x_plus_delta,
- jacobian_ptrs);
+ double* jacobian_ptrs[2] = {NULL, jacobian};
+ return internal::AutoDifferentiate<
+ kGlobalSize,
+ internal::StaticParameterDims<kGlobalSize, kLocalSize>>(
+ *functor_, parameter_ptrs, kGlobalSize, x_plus_delta, jacobian_ptrs);
}
- virtual int GlobalSize() const { return kGlobalSize; }
- virtual int LocalSize() const { return kLocalSize; }
+ int GlobalSize() const override { return kGlobalSize; }
+ int LocalSize() const override { return kLocalSize; }
private:
- internal::scoped_ptr<Functor> functor_;
+ std::unique_ptr<Functor> functor_;
};
} // namespace ceres
diff --git a/extern/ceres/include/ceres/c_api.h b/extern/ceres/include/ceres/c_api.h
index df7c9b6d671..0e6e590d0f5 100644
--- a/extern/ceres/include/ceres/c_api.h
+++ b/extern/ceres/include/ceres/c_api.h
@@ -1,5 +1,5 @@
/* Ceres Solver - A fast non-linear least squares minimizer
- * Copyright 2015 Google Inc. All rights reserved.
+ * Copyright 2019 Google Inc. All rights reserved.
* http://ceres-solver.org/
*
* Redistribution and use in source and binary forms, with or without
@@ -143,4 +143,4 @@ CERES_EXPORT void ceres_solve(ceres_problem_t* problem);
#include "ceres/internal/reenable_warnings.h"
-#endif /* CERES_PUBLIC_C_API_H_ */
+#endif /* CERES_PUBLIC_C_API_H_ */
diff --git a/extern/ceres/include/ceres/ceres.h b/extern/ceres/include/ceres/ceres.h
index 64ffb99798a..d249351694c 100644
--- a/extern/ceres/include/ceres/ceres.h
+++ b/extern/ceres/include/ceres/ceres.h
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2019 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -36,12 +36,18 @@
#include "ceres/autodiff_cost_function.h"
#include "ceres/autodiff_local_parameterization.h"
+#include "ceres/conditioned_cost_function.h"
+#include "ceres/context.h"
#include "ceres/cost_function.h"
#include "ceres/cost_function_to_functor.h"
#include "ceres/covariance.h"
#include "ceres/crs_matrix.h"
#include "ceres/dynamic_autodiff_cost_function.h"
+#include "ceres/dynamic_cost_function.h"
+#include "ceres/dynamic_cost_function_to_functor.h"
#include "ceres/dynamic_numeric_diff_cost_function.h"
+#include "ceres/evaluation_callback.h"
+#include "ceres/gradient_checker.h"
#include "ceres/gradient_problem.h"
#include "ceres/gradient_problem_solver.h"
#include "ceres/iteration_callback.h"
@@ -49,6 +55,7 @@
#include "ceres/local_parameterization.h"
#include "ceres/loss_function.h"
#include "ceres/numeric_diff_cost_function.h"
+#include "ceres/numeric_diff_options.h"
#include "ceres/ordered_groups.h"
#include "ceres/problem.h"
#include "ceres/sized_cost_function.h"
diff --git a/extern/ceres/include/ceres/conditioned_cost_function.h b/extern/ceres/include/ceres/conditioned_cost_function.h
index 29597d935cb..a57ee209b80 100644
--- a/extern/ceres/include/ceres/conditioned_cost_function.h
+++ b/extern/ceres/include/ceres/conditioned_cost_function.h
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2019 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -34,12 +34,12 @@
#ifndef CERES_PUBLIC_CONDITIONED_COST_FUNCTION_H_
#define CERES_PUBLIC_CONDITIONED_COST_FUNCTION_H_
+#include <memory>
#include <vector>
#include "ceres/cost_function.h"
-#include "ceres/internal/scoped_ptr.h"
-#include "ceres/types.h"
#include "ceres/internal/disable_warnings.h"
+#include "ceres/types.h"
namespace ceres {
@@ -77,17 +77,19 @@ class CERES_EXPORT ConditionedCostFunction : public CostFunction {
// per-residual conditioner. Takes ownership of all of the wrapped cost
// functions, or not, depending on the ownership parameter. Conditioners
// may be NULL, in which case the corresponding residual is not modified.
+ //
+ // The conditioners can repeat.
ConditionedCostFunction(CostFunction* wrapped_cost_function,
const std::vector<CostFunction*>& conditioners,
Ownership ownership);
virtual ~ConditionedCostFunction();
- virtual bool Evaluate(double const* const* parameters,
- double* residuals,
- double** jacobians) const;
+ bool Evaluate(double const* const* parameters,
+ double* residuals,
+ double** jacobians) const override;
private:
- internal::scoped_ptr<CostFunction> wrapped_cost_function_;
+ std::unique_ptr<CostFunction> wrapped_cost_function_;
std::vector<CostFunction*> conditioners_;
Ownership ownership_;
};
diff --git a/extern/ceres/include/ceres/context.h b/extern/ceres/include/ceres/context.h
new file mode 100644
index 00000000000..d08e32b31a8
--- /dev/null
+++ b/extern/ceres/include/ceres/context.h
@@ -0,0 +1,56 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2019 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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.
+//
+// Author: vitus@google.com (Michael Vitus)
+
+#ifndef CERES_PUBLIC_CONTEXT_H_
+#define CERES_PUBLIC_CONTEXT_H_
+
+namespace ceres {
+
+// A global context for processing data in Ceres. This provides a mechanism to
+// allow Ceres to reuse items that are expensive to create between multiple
+// calls; for example, thread pools. The same Context can be used on multiple
+// Problems, either serially or in parallel. When using it with multiple
+// Problems at the same time, they may end up contending for resources
+// (e.g. threads) managed by the Context.
+class Context {
+ public:
+ Context() {}
+ Context(const Context&) = delete;
+ void operator=(const Context&) = delete;
+
+ virtual ~Context() {}
+
+ // Creates a context object and the caller takes ownership.
+ static Context* Create();
+};
+
+} // namespace ceres
+
+#endif // CERES_PUBLIC_CONTEXT_H_
diff --git a/extern/ceres/include/ceres/cost_function.h b/extern/ceres/include/ceres/cost_function.h
index f051a897c0d..d1550c119e8 100644
--- a/extern/ceres/include/ceres/cost_function.h
+++ b/extern/ceres/include/ceres/cost_function.h
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2019 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -44,18 +44,18 @@
#ifndef CERES_PUBLIC_COST_FUNCTION_H_
#define CERES_PUBLIC_COST_FUNCTION_H_
+#include <cstdint>
#include <vector>
-#include "ceres/internal/macros.h"
-#include "ceres/internal/port.h"
-#include "ceres/types.h"
+
#include "ceres/internal/disable_warnings.h"
+#include "ceres/internal/port.h"
namespace ceres {
// This class implements the computation of the cost (a.k.a. residual) terms as
// a function of the input (control) variables, and is the interface for users
// to describe their least squares problem to Ceres. In other words, this is the
-// modelling layer between users and the Ceres optimizer. The signature of the
+// modeling layer between users and the Ceres optimizer. The signature of the
// function (number and sizes of input parameter blocks and number of outputs)
// is stored in parameter_block_sizes_ and num_residuals_ respectively. User
// code inheriting from this class is expected to set these two members with the
@@ -64,6 +64,8 @@ namespace ceres {
class CERES_EXPORT CostFunction {
public:
CostFunction() : num_residuals_(0) {}
+ CostFunction(const CostFunction&) = delete;
+ void operator=(const CostFunction&) = delete;
virtual ~CostFunction() {}
@@ -115,29 +117,24 @@ class CERES_EXPORT CostFunction {
double* residuals,
double** jacobians) const = 0;
- const std::vector<int32>& parameter_block_sizes() const {
+ const std::vector<int32_t>& parameter_block_sizes() const {
return parameter_block_sizes_;
}
- int num_residuals() const {
- return num_residuals_;
- }
+ int num_residuals() const { return num_residuals_; }
protected:
- std::vector<int32>* mutable_parameter_block_sizes() {
+ std::vector<int32_t>* mutable_parameter_block_sizes() {
return &parameter_block_sizes_;
}
- void set_num_residuals(int num_residuals) {
- num_residuals_ = num_residuals;
- }
+ void set_num_residuals(int num_residuals) { num_residuals_ = num_residuals; }
private:
// Cost function signature metadata: number of inputs & their sizes,
// number of outputs (residuals).
- std::vector<int32> parameter_block_sizes_;
+ std::vector<int32_t> parameter_block_sizes_;
int num_residuals_;
- CERES_DISALLOW_COPY_AND_ASSIGN(CostFunction);
};
} // namespace ceres
diff --git a/extern/ceres/include/ceres/cost_function_to_functor.h b/extern/ceres/include/ceres/cost_function_to_functor.h
index d2dc94725e4..1beeb906063 100644
--- a/extern/ceres/include/ceres/cost_function_to_functor.h
+++ b/extern/ceres/include/ceres/cost_function_to_functor.h
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2019 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -30,7 +30,7 @@
//
// CostFunctionToFunctor is an adapter class that allows users to use
// SizedCostFunction objects in templated functors which are to be used for
-// automatic differentiation. This allows the user to seamlessly mix
+// automatic differentiation. This allows the user to seamlessly mix
// analytic, numeric and automatic differentiation.
//
// For example, let us assume that
@@ -38,16 +38,15 @@
// class IntrinsicProjection : public SizedCostFunction<2, 5, 3> {
// public:
// IntrinsicProjection(const double* observation);
-// virtual bool Evaluate(double const* const* parameters,
-// double* residuals,
-// double** jacobians) const;
+// bool Evaluate(double const* const* parameters,
+// double* residuals,
+// double** jacobians) const override;
// };
//
// is a cost function that implements the projection of a point in its
// local coordinate system onto its image plane and subtracts it from
// the observed point projection. It can compute its residual and
-// either via analytic or numerical differentiation can compute its
-// jacobians.
+// jacobians either via analytic or numerical differentiation.
//
// Now we would like to compose the action of this CostFunction with
// the action of camera extrinsics, i.e., rotation and
@@ -87,594 +86,83 @@
#ifndef CERES_PUBLIC_COST_FUNCTION_TO_FUNCTOR_H_
#define CERES_PUBLIC_COST_FUNCTION_TO_FUNCTOR_H_
+#include <cstdint>
#include <numeric>
+#include <tuple>
+#include <utility>
#include <vector>
#include "ceres/cost_function.h"
#include "ceres/dynamic_cost_function_to_functor.h"
#include "ceres/internal/fixed_array.h"
+#include "ceres/internal/parameter_dims.h"
#include "ceres/internal/port.h"
-#include "ceres/internal/scoped_ptr.h"
+#include "ceres/types.h"
namespace ceres {
-template <int kNumResiduals,
- int N0, int N1 = 0, int N2 = 0, int N3 = 0, int N4 = 0,
- int N5 = 0, int N6 = 0, int N7 = 0, int N8 = 0, int N9 = 0>
+template <int kNumResiduals, int... Ns>
class CostFunctionToFunctor {
public:
// Takes ownership of cost_function.
explicit CostFunctionToFunctor(CostFunction* cost_function)
: cost_functor_(cost_function) {
- CHECK_NOTNULL(cost_function);
+ CHECK(cost_function != nullptr);
CHECK(kNumResiduals > 0 || kNumResiduals == DYNAMIC);
- // This block breaks the 80 column rule to keep it somewhat readable.
- CHECK((!N1 && !N2 && !N3 && !N4 && !N5 && !N6 && !N7 && !N8 && !N9) ||
- ((N1 > 0) && !N2 && !N3 && !N4 && !N5 && !N6 && !N7 && !N8 && !N9) ||
- ((N1 > 0) && (N2 > 0) && !N3 && !N4 && !N5 && !N6 && !N7 && !N8 && !N9) || // NOLINT
- ((N1 > 0) && (N2 > 0) && (N3 > 0) && !N4 && !N5 && !N6 && !N7 && !N8 && !N9) || // NOLINT
- ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && !N5 && !N6 && !N7 && !N8 && !N9) || // NOLINT
- ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && (N5 > 0) && !N6 && !N7 && !N8 && !N9) || // NOLINT
- ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && (N5 > 0) && (N6 > 0) && !N7 && !N8 && !N9) || // NOLINT
- ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && (N5 > 0) && (N6 > 0) && (N7 > 0) && !N8 && !N9) || // NOLINT
- ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && (N5 > 0) && (N6 > 0) && (N7 > 0) && (N8 > 0) && !N9) || // NOLINT
- ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && (N5 > 0) && (N6 > 0) && (N7 > 0) && (N8 > 0) && (N9 > 0))) // NOLINT
- << "Zero block cannot precede a non-zero block. Block sizes are "
- << "(ignore trailing 0s): " << N0 << ", " << N1 << ", " << N2 << ", "
- << N3 << ", " << N4 << ", " << N5 << ", " << N6 << ", " << N7 << ", "
- << N8 << ", " << N9;
-
- const std::vector<int32>& parameter_block_sizes =
+ const std::vector<int32_t>& parameter_block_sizes =
cost_function->parameter_block_sizes();
- const int num_parameter_blocks =
- (N0 > 0) + (N1 > 0) + (N2 > 0) + (N3 > 0) + (N4 > 0) +
- (N5 > 0) + (N6 > 0) + (N7 > 0) + (N8 > 0) + (N9 > 0);
+ const int num_parameter_blocks = ParameterDims::kNumParameterBlocks;
CHECK_EQ(static_cast<int>(parameter_block_sizes.size()),
num_parameter_blocks);
- CHECK_EQ(N0, parameter_block_sizes[0]);
- if (parameter_block_sizes.size() > 1) CHECK_EQ(N1, parameter_block_sizes[1]); // NOLINT
- if (parameter_block_sizes.size() > 2) CHECK_EQ(N2, parameter_block_sizes[2]); // NOLINT
- if (parameter_block_sizes.size() > 3) CHECK_EQ(N3, parameter_block_sizes[3]); // NOLINT
- if (parameter_block_sizes.size() > 4) CHECK_EQ(N4, parameter_block_sizes[4]); // NOLINT
- if (parameter_block_sizes.size() > 5) CHECK_EQ(N5, parameter_block_sizes[5]); // NOLINT
- if (parameter_block_sizes.size() > 6) CHECK_EQ(N6, parameter_block_sizes[6]); // NOLINT
- if (parameter_block_sizes.size() > 7) CHECK_EQ(N7, parameter_block_sizes[7]); // NOLINT
- if (parameter_block_sizes.size() > 8) CHECK_EQ(N8, parameter_block_sizes[8]); // NOLINT
- if (parameter_block_sizes.size() > 9) CHECK_EQ(N9, parameter_block_sizes[9]); // NOLINT
-
- CHECK_EQ(accumulate(parameter_block_sizes.begin(),
- parameter_block_sizes.end(), 0),
- N0 + N1 + N2 + N3 + N4 + N5 + N6 + N7 + N8 + N9);
- }
-
- bool operator()(const double* x0, double* residuals) const {
- CHECK_NE(N0, 0);
- CHECK_EQ(N1, 0);
- CHECK_EQ(N2, 0);
- CHECK_EQ(N3, 0);
- CHECK_EQ(N4, 0);
- CHECK_EQ(N5, 0);
- CHECK_EQ(N6, 0);
- CHECK_EQ(N7, 0);
- CHECK_EQ(N8, 0);
- CHECK_EQ(N9, 0);
-
- return cost_functor_(&x0, residuals);
- }
-
- bool operator()(const double* x0,
- const double* x1,
- double* residuals) const {
- CHECK_NE(N0, 0);
- CHECK_NE(N1, 0);
- CHECK_EQ(N2, 0);
- CHECK_EQ(N3, 0);
- CHECK_EQ(N4, 0);
- CHECK_EQ(N5, 0);
- CHECK_EQ(N6, 0);
- CHECK_EQ(N7, 0);
- CHECK_EQ(N8, 0);
- CHECK_EQ(N9, 0);
- internal::FixedArray<const double*> parameter_blocks(2);
- parameter_blocks[0] = x0;
- parameter_blocks[1] = x1;
- return cost_functor_(parameter_blocks.get(), residuals);
- }
-
- bool operator()(const double* x0,
- const double* x1,
- const double* x2,
- double* residuals) const {
- CHECK_NE(N0, 0);
- CHECK_NE(N1, 0);
- CHECK_NE(N2, 0);
- CHECK_EQ(N3, 0);
- CHECK_EQ(N4, 0);
- CHECK_EQ(N5, 0);
- CHECK_EQ(N6, 0);
- CHECK_EQ(N7, 0);
- CHECK_EQ(N8, 0);
- CHECK_EQ(N9, 0);
- internal::FixedArray<const double*> parameter_blocks(3);
- parameter_blocks[0] = x0;
- parameter_blocks[1] = x1;
- parameter_blocks[2] = x2;
- return cost_functor_(parameter_blocks.get(), residuals);
- }
+ if (parameter_block_sizes.size() == num_parameter_blocks) {
+ for (int block = 0; block < num_parameter_blocks; ++block) {
+ CHECK_EQ(ParameterDims::GetDim(block), parameter_block_sizes[block])
+ << "Parameter block size missmatch. The specified static parameter "
+ "block dimension does not match the one from the cost function.";
+ }
+ }
- bool operator()(const double* x0,
- const double* x1,
- const double* x2,
- const double* x3,
- double* residuals) const {
- CHECK_NE(N0, 0);
- CHECK_NE(N1, 0);
- CHECK_NE(N2, 0);
- CHECK_NE(N3, 0);
- CHECK_EQ(N4, 0);
- CHECK_EQ(N5, 0);
- CHECK_EQ(N6, 0);
- CHECK_EQ(N7, 0);
- CHECK_EQ(N8, 0);
- CHECK_EQ(N9, 0);
- internal::FixedArray<const double*> parameter_blocks(4);
- parameter_blocks[0] = x0;
- parameter_blocks[1] = x1;
- parameter_blocks[2] = x2;
- parameter_blocks[3] = x3;
- return cost_functor_(parameter_blocks.get(), residuals);
+ CHECK_EQ(accumulate(
+ parameter_block_sizes.begin(), parameter_block_sizes.end(), 0),
+ ParameterDims::kNumParameters);
}
- bool operator()(const double* x0,
- const double* x1,
- const double* x2,
- const double* x3,
- const double* x4,
- double* residuals) const {
- CHECK_NE(N0, 0);
- CHECK_NE(N1, 0);
- CHECK_NE(N2, 0);
- CHECK_NE(N3, 0);
- CHECK_NE(N4, 0);
- CHECK_EQ(N5, 0);
- CHECK_EQ(N6, 0);
- CHECK_EQ(N7, 0);
- CHECK_EQ(N8, 0);
- CHECK_EQ(N9, 0);
- internal::FixedArray<const double*> parameter_blocks(5);
- parameter_blocks[0] = x0;
- parameter_blocks[1] = x1;
- parameter_blocks[2] = x2;
- parameter_blocks[3] = x3;
- parameter_blocks[4] = x4;
- return cost_functor_(parameter_blocks.get(), residuals);
- }
+ template <typename T, typename... Ts>
+ bool operator()(const T* p1, Ts*... ps) const {
+ // Add one because of residual block.
+ static_assert(sizeof...(Ts) + 1 == ParameterDims::kNumParameterBlocks + 1,
+ "Invalid number of parameter blocks specified.");
- bool operator()(const double* x0,
- const double* x1,
- const double* x2,
- const double* x3,
- const double* x4,
- const double* x5,
- double* residuals) const {
- CHECK_NE(N0, 0);
- CHECK_NE(N1, 0);
- CHECK_NE(N2, 0);
- CHECK_NE(N3, 0);
- CHECK_NE(N4, 0);
- CHECK_NE(N5, 0);
- CHECK_EQ(N6, 0);
- CHECK_EQ(N7, 0);
- CHECK_EQ(N8, 0);
- CHECK_EQ(N9, 0);
- internal::FixedArray<const double*> parameter_blocks(6);
- parameter_blocks[0] = x0;
- parameter_blocks[1] = x1;
- parameter_blocks[2] = x2;
- parameter_blocks[3] = x3;
- parameter_blocks[4] = x4;
- parameter_blocks[5] = x5;
- return cost_functor_(parameter_blocks.get(), residuals);
- }
+ auto params = std::make_tuple(p1, ps...);
- bool operator()(const double* x0,
- const double* x1,
- const double* x2,
- const double* x3,
- const double* x4,
- const double* x5,
- const double* x6,
- double* residuals) const {
- CHECK_NE(N0, 0);
- CHECK_NE(N1, 0);
- CHECK_NE(N2, 0);
- CHECK_NE(N3, 0);
- CHECK_NE(N4, 0);
- CHECK_NE(N5, 0);
- CHECK_NE(N6, 0);
- CHECK_EQ(N7, 0);
- CHECK_EQ(N8, 0);
- CHECK_EQ(N9, 0);
- internal::FixedArray<const double*> parameter_blocks(7);
- parameter_blocks[0] = x0;
- parameter_blocks[1] = x1;
- parameter_blocks[2] = x2;
- parameter_blocks[3] = x3;
- parameter_blocks[4] = x4;
- parameter_blocks[5] = x5;
- parameter_blocks[6] = x6;
- return cost_functor_(parameter_blocks.get(), residuals);
- }
+ // Extract residual pointer from params. The residual pointer is the
+ // last pointer.
+ constexpr int kResidualIndex = ParameterDims::kNumParameterBlocks;
+ T* residuals = std::get<kResidualIndex>(params);
- bool operator()(const double* x0,
- const double* x1,
- const double* x2,
- const double* x3,
- const double* x4,
- const double* x5,
- const double* x6,
- const double* x7,
- double* residuals) const {
- CHECK_NE(N0, 0);
- CHECK_NE(N1, 0);
- CHECK_NE(N2, 0);
- CHECK_NE(N3, 0);
- CHECK_NE(N4, 0);
- CHECK_NE(N5, 0);
- CHECK_NE(N6, 0);
- CHECK_NE(N7, 0);
- CHECK_EQ(N8, 0);
- CHECK_EQ(N9, 0);
- internal::FixedArray<const double*> parameter_blocks(8);
- parameter_blocks[0] = x0;
- parameter_blocks[1] = x1;
- parameter_blocks[2] = x2;
- parameter_blocks[3] = x3;
- parameter_blocks[4] = x4;
- parameter_blocks[5] = x5;
- parameter_blocks[6] = x6;
- parameter_blocks[7] = x7;
- return cost_functor_(parameter_blocks.get(), residuals);
- }
-
- bool operator()(const double* x0,
- const double* x1,
- const double* x2,
- const double* x3,
- const double* x4,
- const double* x5,
- const double* x6,
- const double* x7,
- const double* x8,
- double* residuals) const {
- CHECK_NE(N0, 0);
- CHECK_NE(N1, 0);
- CHECK_NE(N2, 0);
- CHECK_NE(N3, 0);
- CHECK_NE(N4, 0);
- CHECK_NE(N5, 0);
- CHECK_NE(N6, 0);
- CHECK_NE(N7, 0);
- CHECK_NE(N8, 0);
- CHECK_EQ(N9, 0);
- internal::FixedArray<const double*> parameter_blocks(9);
- parameter_blocks[0] = x0;
- parameter_blocks[1] = x1;
- parameter_blocks[2] = x2;
- parameter_blocks[3] = x3;
- parameter_blocks[4] = x4;
- parameter_blocks[5] = x5;
- parameter_blocks[6] = x6;
- parameter_blocks[7] = x7;
- parameter_blocks[8] = x8;
- return cost_functor_(parameter_blocks.get(), residuals);
- }
-
- bool operator()(const double* x0,
- const double* x1,
- const double* x2,
- const double* x3,
- const double* x4,
- const double* x5,
- const double* x6,
- const double* x7,
- const double* x8,
- const double* x9,
- double* residuals) const {
- CHECK_NE(N0, 0);
- CHECK_NE(N1, 0);
- CHECK_NE(N2, 0);
- CHECK_NE(N3, 0);
- CHECK_NE(N4, 0);
- CHECK_NE(N5, 0);
- CHECK_NE(N6, 0);
- CHECK_NE(N7, 0);
- CHECK_NE(N8, 0);
- CHECK_NE(N9, 0);
- internal::FixedArray<const double*> parameter_blocks(10);
- parameter_blocks[0] = x0;
- parameter_blocks[1] = x1;
- parameter_blocks[2] = x2;
- parameter_blocks[3] = x3;
- parameter_blocks[4] = x4;
- parameter_blocks[5] = x5;
- parameter_blocks[6] = x6;
- parameter_blocks[7] = x7;
- parameter_blocks[8] = x8;
- parameter_blocks[9] = x9;
- return cost_functor_(parameter_blocks.get(), residuals);
- }
+ // Extract parameter block pointers from params.
+ using Indices =
+ std::make_integer_sequence<int,
+ ParameterDims::kNumParameterBlocks>;
+ std::array<const T*, ParameterDims::kNumParameterBlocks> parameter_blocks =
+ GetParameterPointers<T>(params, Indices());
- template <typename JetT>
- bool operator()(const JetT* x0, JetT* residuals) const {
- CHECK_NE(N0, 0);
- CHECK_EQ(N1, 0);
- CHECK_EQ(N2, 0);
- CHECK_EQ(N3, 0);
- CHECK_EQ(N4, 0);
- CHECK_EQ(N5, 0);
- CHECK_EQ(N6, 0);
- CHECK_EQ(N7, 0);
- CHECK_EQ(N8, 0);
- CHECK_EQ(N9, 0);
- return cost_functor_(&x0, residuals);
+ return cost_functor_(parameter_blocks.data(), residuals);
}
- template <typename JetT>
- bool operator()(const JetT* x0,
- const JetT* x1,
- JetT* residuals) const {
- CHECK_NE(N0, 0);
- CHECK_NE(N1, 0);
- CHECK_EQ(N2, 0);
- CHECK_EQ(N3, 0);
- CHECK_EQ(N4, 0);
- CHECK_EQ(N5, 0);
- CHECK_EQ(N6, 0);
- CHECK_EQ(N7, 0);
- CHECK_EQ(N8, 0);
- CHECK_EQ(N9, 0);
- internal::FixedArray<const JetT*> jets(2);
- jets[0] = x0;
- jets[1] = x1;
- return cost_functor_(jets.get(), residuals);
- }
-
- template <typename JetT>
- bool operator()(const JetT* x0,
- const JetT* x1,
- const JetT* x2,
- JetT* residuals) const {
- CHECK_NE(N0, 0);
- CHECK_NE(N1, 0);
- CHECK_NE(N2, 0);
- CHECK_EQ(N3, 0);
- CHECK_EQ(N4, 0);
- CHECK_EQ(N5, 0);
- CHECK_EQ(N6, 0);
- CHECK_EQ(N7, 0);
- CHECK_EQ(N8, 0);
- CHECK_EQ(N9, 0);
- internal::FixedArray<const JetT*> jets(3);
- jets[0] = x0;
- jets[1] = x1;
- jets[2] = x2;
- return cost_functor_(jets.get(), residuals);
- }
-
- template <typename JetT>
- bool operator()(const JetT* x0,
- const JetT* x1,
- const JetT* x2,
- const JetT* x3,
- JetT* residuals) const {
- CHECK_NE(N0, 0);
- CHECK_NE(N1, 0);
- CHECK_NE(N2, 0);
- CHECK_NE(N3, 0);
- CHECK_EQ(N4, 0);
- CHECK_EQ(N5, 0);
- CHECK_EQ(N6, 0);
- CHECK_EQ(N7, 0);
- CHECK_EQ(N8, 0);
- CHECK_EQ(N9, 0);
- internal::FixedArray<const JetT*> jets(4);
- jets[0] = x0;
- jets[1] = x1;
- jets[2] = x2;
- jets[3] = x3;
- return cost_functor_(jets.get(), residuals);
- }
-
- template <typename JetT>
- bool operator()(const JetT* x0,
- const JetT* x1,
- const JetT* x2,
- const JetT* x3,
- const JetT* x4,
- JetT* residuals) const {
- CHECK_NE(N0, 0);
- CHECK_NE(N1, 0);
- CHECK_NE(N2, 0);
- CHECK_NE(N3, 0);
- CHECK_NE(N4, 0);
- CHECK_EQ(N5, 0);
- CHECK_EQ(N6, 0);
- CHECK_EQ(N7, 0);
- CHECK_EQ(N8, 0);
- CHECK_EQ(N9, 0);
- internal::FixedArray<const JetT*> jets(5);
- jets[0] = x0;
- jets[1] = x1;
- jets[2] = x2;
- jets[3] = x3;
- jets[4] = x4;
- return cost_functor_(jets.get(), residuals);
- }
-
- template <typename JetT>
- bool operator()(const JetT* x0,
- const JetT* x1,
- const JetT* x2,
- const JetT* x3,
- const JetT* x4,
- const JetT* x5,
- JetT* residuals) const {
- CHECK_NE(N0, 0);
- CHECK_NE(N1, 0);
- CHECK_NE(N2, 0);
- CHECK_NE(N3, 0);
- CHECK_NE(N4, 0);
- CHECK_NE(N5, 0);
- CHECK_EQ(N6, 0);
- CHECK_EQ(N7, 0);
- CHECK_EQ(N8, 0);
- CHECK_EQ(N9, 0);
- internal::FixedArray<const JetT*> jets(6);
- jets[0] = x0;
- jets[1] = x1;
- jets[2] = x2;
- jets[3] = x3;
- jets[4] = x4;
- jets[5] = x5;
- return cost_functor_(jets.get(), residuals);
- }
-
- template <typename JetT>
- bool operator()(const JetT* x0,
- const JetT* x1,
- const JetT* x2,
- const JetT* x3,
- const JetT* x4,
- const JetT* x5,
- const JetT* x6,
- JetT* residuals) const {
- CHECK_NE(N0, 0);
- CHECK_NE(N1, 0);
- CHECK_NE(N2, 0);
- CHECK_NE(N3, 0);
- CHECK_NE(N4, 0);
- CHECK_NE(N5, 0);
- CHECK_NE(N6, 0);
- CHECK_EQ(N7, 0);
- CHECK_EQ(N8, 0);
- CHECK_EQ(N9, 0);
- internal::FixedArray<const JetT*> jets(7);
- jets[0] = x0;
- jets[1] = x1;
- jets[2] = x2;
- jets[3] = x3;
- jets[4] = x4;
- jets[5] = x5;
- jets[6] = x6;
- return cost_functor_(jets.get(), residuals);
- }
-
- template <typename JetT>
- bool operator()(const JetT* x0,
- const JetT* x1,
- const JetT* x2,
- const JetT* x3,
- const JetT* x4,
- const JetT* x5,
- const JetT* x6,
- const JetT* x7,
- JetT* residuals) const {
- CHECK_NE(N0, 0);
- CHECK_NE(N1, 0);
- CHECK_NE(N2, 0);
- CHECK_NE(N3, 0);
- CHECK_NE(N4, 0);
- CHECK_NE(N5, 0);
- CHECK_NE(N6, 0);
- CHECK_NE(N7, 0);
- CHECK_EQ(N8, 0);
- CHECK_EQ(N9, 0);
- internal::FixedArray<const JetT*> jets(8);
- jets[0] = x0;
- jets[1] = x1;
- jets[2] = x2;
- jets[3] = x3;
- jets[4] = x4;
- jets[5] = x5;
- jets[6] = x6;
- jets[7] = x7;
- return cost_functor_(jets.get(), residuals);
- }
-
- template <typename JetT>
- bool operator()(const JetT* x0,
- const JetT* x1,
- const JetT* x2,
- const JetT* x3,
- const JetT* x4,
- const JetT* x5,
- const JetT* x6,
- const JetT* x7,
- const JetT* x8,
- JetT* residuals) const {
- CHECK_NE(N0, 0);
- CHECK_NE(N1, 0);
- CHECK_NE(N2, 0);
- CHECK_NE(N3, 0);
- CHECK_NE(N4, 0);
- CHECK_NE(N5, 0);
- CHECK_NE(N6, 0);
- CHECK_NE(N7, 0);
- CHECK_NE(N8, 0);
- CHECK_EQ(N9, 0);
- internal::FixedArray<const JetT*> jets(9);
- jets[0] = x0;
- jets[1] = x1;
- jets[2] = x2;
- jets[3] = x3;
- jets[4] = x4;
- jets[5] = x5;
- jets[6] = x6;
- jets[7] = x7;
- jets[8] = x8;
- return cost_functor_(jets.get(), residuals);
- }
+ private:
+ using ParameterDims = internal::StaticParameterDims<Ns...>;
- template <typename JetT>
- bool operator()(const JetT* x0,
- const JetT* x1,
- const JetT* x2,
- const JetT* x3,
- const JetT* x4,
- const JetT* x5,
- const JetT* x6,
- const JetT* x7,
- const JetT* x8,
- const JetT* x9,
- JetT* residuals) const {
- CHECK_NE(N0, 0);
- CHECK_NE(N1, 0);
- CHECK_NE(N2, 0);
- CHECK_NE(N3, 0);
- CHECK_NE(N4, 0);
- CHECK_NE(N5, 0);
- CHECK_NE(N6, 0);
- CHECK_NE(N7, 0);
- CHECK_NE(N8, 0);
- CHECK_NE(N9, 0);
- internal::FixedArray<const JetT*> jets(10);
- jets[0] = x0;
- jets[1] = x1;
- jets[2] = x2;
- jets[3] = x3;
- jets[4] = x4;
- jets[5] = x5;
- jets[6] = x6;
- jets[7] = x7;
- jets[8] = x8;
- jets[9] = x9;
- return cost_functor_(jets.get(), residuals);
+ template <typename T, typename Tuple, int... Indices>
+ static std::array<const T*, ParameterDims::kNumParameterBlocks>
+ GetParameterPointers(const Tuple& paramPointers,
+ std::integer_sequence<int, Indices...>) {
+ return std::array<const T*, ParameterDims::kNumParameterBlocks>{
+ {std::get<Indices>(paramPointers)...}};
}
- private:
DynamicCostFunctionToFunctor cost_functor_;
};
diff --git a/extern/ceres/include/ceres/covariance.h b/extern/ceres/include/ceres/covariance.h
index 930f96cf3ae..99825c425ad 100644
--- a/extern/ceres/include/ceres/covariance.h
+++ b/extern/ceres/include/ceres/covariance.h
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2019 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -31,12 +31,13 @@
#ifndef CERES_PUBLIC_COVARIANCE_H_
#define CERES_PUBLIC_COVARIANCE_H_
+#include <memory>
#include <utility>
#include <vector>
+
+#include "ceres/internal/disable_warnings.h"
#include "ceres/internal/port.h"
-#include "ceres/internal/scoped_ptr.h"
#include "ceres/types.h"
-#include "ceres/internal/disable_warnings.h"
namespace ceres {
@@ -60,7 +61,7 @@ class CovarianceImpl;
// Background
// ==========
// One way to assess the quality of the solution returned by a
-// non-linear least squares solve is to analyze the covariance of the
+// non-linear least squares solver is to analyze the covariance of the
// solution.
//
// Let us consider the non-linear regression problem
@@ -158,7 +159,7 @@ class CovarianceImpl;
// Gauge Invariance
// ----------------
// In structure from motion (3D reconstruction) problems, the
-// reconstruction is ambiguous upto a similarity transform. This is
+// reconstruction is ambiguous up to a similarity transform. This is
// known as a Gauge Ambiguity. Handling Gauges correctly requires the
// use of SVD or custom inversion algorithms. For small problems the
// user can use the dense algorithm. For more details see
@@ -183,7 +184,7 @@ class CovarianceImpl;
// Covariance::Options options;
// Covariance covariance(options);
//
-// std::vector<std::pair<const double*, const double*> > covariance_blocks;
+// std::vector<std::pair<const double*, const double*>> covariance_blocks;
// covariance_blocks.push_back(make_pair(x, x));
// covariance_blocks.push_back(make_pair(y, y));
// covariance_blocks.push_back(make_pair(x, y));
@@ -200,19 +201,19 @@ class CovarianceImpl;
class CERES_EXPORT Covariance {
public:
struct CERES_EXPORT Options {
- Options()
-#ifndef CERES_NO_SUITESPARSE
- : algorithm_type(SUITE_SPARSE_QR),
+ // Sparse linear algebra library to use when a sparse matrix
+ // factorization is being used to compute the covariance matrix.
+ //
+ // Currently this only applies to SPARSE_QR.
+ SparseLinearAlgebraLibraryType sparse_linear_algebra_library_type =
+#if !defined(CERES_NO_SUITESPARSE)
+ SUITE_SPARSE;
#else
- : algorithm_type(EIGEN_SPARSE_QR),
+ // Eigen's QR factorization is always available.
+ EIGEN_SPARSE;
#endif
- min_reciprocal_condition_number(1e-14),
- null_space_rank(0),
- num_threads(1),
- apply_loss_function(true) {
- }
- // Ceres supports three different algorithms for covariance
+ // Ceres supports two different algorithms for covariance
// estimation, which represent different tradeoffs in speed,
// accuracy and reliability.
//
@@ -229,23 +230,20 @@ class CERES_EXPORT Covariance {
// for small to moderate sized problems. It can handle
// full-rank as well as rank deficient Jacobians.
//
- // 2. EIGEN_SPARSE_QR uses the sparse QR factorization algorithm
- // in Eigen to compute the decomposition
+ // 2. SPARSE_QR uses the sparse QR factorization algorithm
+ // to compute the decomposition
//
// Q * R = J
//
// [J'J]^-1 = [R*R']^-1
//
- // It is a moderately fast algorithm for sparse matrices.
- //
- // 3. SUITE_SPARSE_QR uses the SuiteSparseQR sparse QR
- // factorization algorithm. It uses dense linear algebra and is
- // multi threaded, so for large sparse sparse matrices it is
- // significantly faster than EIGEN_SPARSE_QR.
- //
- // Neither EIGEN_SPARSE_QR not SUITE_SPARSE_QR are capable of
- // computing the covariance if the Jacobian is rank deficient.
- CovarianceAlgorithmType algorithm_type;
+ // SPARSE_QR is not capable of computing the covariance if the
+ // Jacobian is rank deficient. Depending on the value of
+ // Covariance::Options::sparse_linear_algebra_library_type, either
+ // Eigen's Sparse QR factorization algorithm will be used or
+ // SuiteSparse's high performance SuiteSparseQR algorithm will be
+ // used.
+ CovarianceAlgorithmType algorithm_type = SPARSE_QR;
// If the Jacobian matrix is near singular, then inverting J'J
// will result in unreliable results, e.g, if
@@ -270,7 +268,7 @@ class CERES_EXPORT Covariance {
// where min_sigma and max_sigma are the minimum and maxiumum
// singular values of J respectively.
//
- // 2. SUITE_SPARSE_QR and EIGEN_SPARSE_QR
+ // 2. SPARSE_QR
//
// rank(J) < num_col(J)
//
@@ -278,7 +276,7 @@ class CERES_EXPORT Covariance {
// sparse QR factorization algorithm. It is a fairly reliable
// indication of rank deficiency.
//
- double min_reciprocal_condition_number;
+ double min_reciprocal_condition_number = 1e-14;
// When using DENSE_SVD, the user has more control in dealing with
// singular and near singular covariance matrices.
@@ -313,9 +311,9 @@ class CERES_EXPORT Covariance {
//
// This option has no effect on the SUITE_SPARSE_QR and
// EIGEN_SPARSE_QR algorithms.
- int null_space_rank;
+ int null_space_rank = 0;
- int num_threads;
+ int num_threads = 1;
// Even though the residual blocks in the problem may contain loss
// functions, setting apply_loss_function to false will turn off
@@ -323,7 +321,7 @@ class CERES_EXPORT Covariance {
// function and in turn its effect on the covariance.
//
// TODO(sameergaarwal): Expand this based on Jim's experiments.
- bool apply_loss_function;
+ bool apply_loss_function = true;
};
explicit Covariance(const Options& options);
@@ -352,10 +350,9 @@ class CERES_EXPORT Covariance {
// covariance computation. Please see the documentation for
// Covariance::Options for more on the conditions under which this
// function returns false.
- bool Compute(
- const std::vector<std::pair<const double*,
- const double*> >& covariance_blocks,
- Problem* problem);
+ bool Compute(const std::vector<std::pair<const double*, const double*>>&
+ covariance_blocks,
+ Problem* problem);
// Compute a part of the covariance matrix.
//
@@ -428,8 +425,8 @@ class CERES_EXPORT Covariance {
// a square matrix whose row and column count is equal to the sum of
// the sizes of the individual parameter blocks. The covariance
// matrix will be a row-major matrix.
- bool GetCovarianceMatrix(const std::vector<const double *> &parameter_blocks,
- double *covariance_matrix);
+ bool GetCovarianceMatrix(const std::vector<const double*>& parameter_blocks,
+ double* covariance_matrix) const;
// Return the covariance matrix corresponding to parameter_blocks
// in the tangent space if a local parameterization is associated
@@ -448,10 +445,10 @@ class CERES_EXPORT Covariance {
// blocks. The covariance matrix will be a row-major matrix.
bool GetCovarianceMatrixInTangentSpace(
const std::vector<const double*>& parameter_blocks,
- double* covariance_matrix);
+ double* covariance_matrix) const;
private:
- internal::scoped_ptr<internal::CovarianceImpl> impl_;
+ std::unique_ptr<internal::CovarianceImpl> impl_;
};
} // namespace ceres
diff --git a/extern/ceres/include/ceres/crs_matrix.h b/extern/ceres/include/ceres/crs_matrix.h
index 23687c4670e..bc618fa0905 100644
--- a/extern/ceres/include/ceres/crs_matrix.h
+++ b/extern/ceres/include/ceres/crs_matrix.h
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2019 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -32,8 +32,9 @@
#define CERES_PUBLIC_CRS_MATRIX_H_
#include <vector>
-#include "ceres/internal/port.h"
+
#include "ceres/internal/disable_warnings.h"
+#include "ceres/internal/port.h"
namespace ceres {
diff --git a/extern/ceres/include/ceres/cubic_interpolation.h b/extern/ceres/include/ceres/cubic_interpolation.h
new file mode 100644
index 00000000000..9b9ea4a942c
--- /dev/null
+++ b/extern/ceres/include/ceres/cubic_interpolation.h
@@ -0,0 +1,436 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2019 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#ifndef CERES_PUBLIC_CUBIC_INTERPOLATION_H_
+#define CERES_PUBLIC_CUBIC_INTERPOLATION_H_
+
+#include "Eigen/Core"
+#include "ceres/internal/port.h"
+#include "glog/logging.h"
+
+namespace ceres {
+
+// Given samples from a function sampled at four equally spaced points,
+//
+// p0 = f(-1)
+// p1 = f(0)
+// p2 = f(1)
+// p3 = f(2)
+//
+// Evaluate the cubic Hermite spline (also known as the Catmull-Rom
+// spline) at a point x that lies in the interval [0, 1].
+//
+// This is also the interpolation kernel (for the case of a = 0.5) as
+// proposed by R. Keys, in:
+//
+// "Cubic convolution interpolation for digital image processing".
+// IEEE Transactions on Acoustics, Speech, and Signal Processing
+// 29 (6): 1153-1160.
+//
+// For more details see
+//
+// http://en.wikipedia.org/wiki/Cubic_Hermite_spline
+// http://en.wikipedia.org/wiki/Bicubic_interpolation
+//
+// f if not NULL will contain the interpolated function values.
+// dfdx if not NULL will contain the interpolated derivative values.
+template <int kDataDimension>
+void CubicHermiteSpline(const Eigen::Matrix<double, kDataDimension, 1>& p0,
+ const Eigen::Matrix<double, kDataDimension, 1>& p1,
+ const Eigen::Matrix<double, kDataDimension, 1>& p2,
+ const Eigen::Matrix<double, kDataDimension, 1>& p3,
+ const double x,
+ double* f,
+ double* dfdx) {
+ typedef Eigen::Matrix<double, kDataDimension, 1> VType;
+ const VType a = 0.5 * (-p0 + 3.0 * p1 - 3.0 * p2 + p3);
+ const VType b = 0.5 * (2.0 * p0 - 5.0 * p1 + 4.0 * p2 - p3);
+ const VType c = 0.5 * (-p0 + p2);
+ const VType d = p1;
+
+ // Use Horner's rule to evaluate the function value and its
+ // derivative.
+
+ // f = ax^3 + bx^2 + cx + d
+ if (f != NULL) {
+ Eigen::Map<VType>(f, kDataDimension) = d + x * (c + x * (b + x * a));
+ }
+
+ // dfdx = 3ax^2 + 2bx + c
+ if (dfdx != NULL) {
+ Eigen::Map<VType>(dfdx, kDataDimension) = c + x * (2.0 * b + 3.0 * a * x);
+ }
+}
+
+// Given as input an infinite one dimensional grid, which provides the
+// following interface.
+//
+// class Grid {
+// public:
+// enum { DATA_DIMENSION = 2; };
+// void GetValue(int n, double* f) const;
+// };
+//
+// Here, GetValue gives the value of a function f (possibly vector
+// valued) for any integer n.
+//
+// The enum DATA_DIMENSION indicates the dimensionality of the
+// function being interpolated. For example if you are interpolating
+// rotations in axis-angle format over time, then DATA_DIMENSION = 3.
+//
+// CubicInterpolator uses cubic Hermite splines to produce a smooth
+// approximation to it that can be used to evaluate the f(x) and f'(x)
+// at any point on the real number line.
+//
+// For more details on cubic interpolation see
+//
+// http://en.wikipedia.org/wiki/Cubic_Hermite_spline
+//
+// Example usage:
+//
+// const double data[] = {1.0, 2.0, 5.0, 6.0};
+// Grid1D<double, 1> grid(data, 0, 4);
+// CubicInterpolator<Grid1D<double, 1>> interpolator(grid);
+// double f, dfdx;
+// interpolator.Evaluator(1.5, &f, &dfdx);
+template <typename Grid>
+class CubicInterpolator {
+ public:
+ explicit CubicInterpolator(const Grid& grid) : grid_(grid) {
+ // The + casts the enum into an int before doing the
+ // comparison. It is needed to prevent
+ // "-Wunnamed-type-template-args" related errors.
+ CHECK_GE(+Grid::DATA_DIMENSION, 1);
+ }
+
+ void Evaluate(double x, double* f, double* dfdx) const {
+ const int n = std::floor(x);
+ Eigen::Matrix<double, Grid::DATA_DIMENSION, 1> p0, p1, p2, p3;
+ grid_.GetValue(n - 1, p0.data());
+ grid_.GetValue(n, p1.data());
+ grid_.GetValue(n + 1, p2.data());
+ grid_.GetValue(n + 2, p3.data());
+ CubicHermiteSpline<Grid::DATA_DIMENSION>(p0, p1, p2, p3, x - n, f, dfdx);
+ }
+
+ // The following two Evaluate overloads are needed for interfacing
+ // with automatic differentiation. The first is for when a scalar
+ // evaluation is done, and the second one is for when Jets are used.
+ void Evaluate(const double& x, double* f) const { Evaluate(x, f, NULL); }
+
+ template <typename JetT>
+ void Evaluate(const JetT& x, JetT* f) const {
+ double fx[Grid::DATA_DIMENSION], dfdx[Grid::DATA_DIMENSION];
+ Evaluate(x.a, fx, dfdx);
+ for (int i = 0; i < Grid::DATA_DIMENSION; ++i) {
+ f[i].a = fx[i];
+ f[i].v = dfdx[i] * x.v;
+ }
+ }
+
+ private:
+ const Grid& grid_;
+};
+
+// An object that implements an infinite one dimensional grid needed
+// by the CubicInterpolator where the source of the function values is
+// an array of type T on the interval
+//
+// [begin, ..., end - 1]
+//
+// Since the input array is finite and the grid is infinite, values
+// outside this interval needs to be computed. Grid1D uses the value
+// from the nearest edge.
+//
+// The function being provided can be vector valued, in which case
+// kDataDimension > 1. The dimensional slices of the function maybe
+// interleaved, or they maybe stacked, i.e, if the function has
+// kDataDimension = 2, if kInterleaved = true, then it is stored as
+//
+// f01, f02, f11, f12 ....
+//
+// and if kInterleaved = false, then it is stored as
+//
+// f01, f11, .. fn1, f02, f12, .. , fn2
+//
+template <typename T, int kDataDimension = 1, bool kInterleaved = true>
+struct Grid1D {
+ public:
+ enum { DATA_DIMENSION = kDataDimension };
+
+ Grid1D(const T* data, const int begin, const int end)
+ : data_(data), begin_(begin), end_(end), num_values_(end - begin) {
+ CHECK_LT(begin, end);
+ }
+
+ EIGEN_STRONG_INLINE void GetValue(const int n, double* f) const {
+ const int idx = std::min(std::max(begin_, n), end_ - 1) - begin_;
+ if (kInterleaved) {
+ for (int i = 0; i < kDataDimension; ++i) {
+ f[i] = static_cast<double>(data_[kDataDimension * idx + i]);
+ }
+ } else {
+ for (int i = 0; i < kDataDimension; ++i) {
+ f[i] = static_cast<double>(data_[i * num_values_ + idx]);
+ }
+ }
+ }
+
+ private:
+ const T* data_;
+ const int begin_;
+ const int end_;
+ const int num_values_;
+};
+
+// Given as input an infinite two dimensional grid like object, which
+// provides the following interface:
+//
+// struct Grid {
+// enum { DATA_DIMENSION = 1 };
+// void GetValue(int row, int col, double* f) const;
+// };
+//
+// Where, GetValue gives us the value of a function f (possibly vector
+// valued) for any pairs of integers (row, col), and the enum
+// DATA_DIMENSION indicates the dimensionality of the function being
+// interpolated. For example if you are interpolating a color image
+// with three channels (Red, Green & Blue), then DATA_DIMENSION = 3.
+//
+// BiCubicInterpolator uses the cubic convolution interpolation
+// algorithm of R. Keys, to produce a smooth approximation to it that
+// can be used to evaluate the f(r,c), df(r, c)/dr and df(r,c)/dc at
+// any point in the real plane.
+//
+// For more details on the algorithm used here see:
+//
+// "Cubic convolution interpolation for digital image processing".
+// Robert G. Keys, IEEE Trans. on Acoustics, Speech, and Signal
+// Processing 29 (6): 1153-1160, 1981.
+//
+// http://en.wikipedia.org/wiki/Cubic_Hermite_spline
+// http://en.wikipedia.org/wiki/Bicubic_interpolation
+//
+// Example usage:
+//
+// const double data[] = {1.0, 3.0, -1.0, 4.0,
+// 3.6, 2.1, 4.2, 2.0,
+// 2.0, 1.0, 3.1, 5.2};
+// Grid2D<double, 1> grid(data, 3, 4);
+// BiCubicInterpolator<Grid2D<double, 1>> interpolator(grid);
+// double f, dfdr, dfdc;
+// interpolator.Evaluate(1.2, 2.5, &f, &dfdr, &dfdc);
+
+template <typename Grid>
+class BiCubicInterpolator {
+ public:
+ explicit BiCubicInterpolator(const Grid& grid) : grid_(grid) {
+ // The + casts the enum into an int before doing the
+ // comparison. It is needed to prevent
+ // "-Wunnamed-type-template-args" related errors.
+ CHECK_GE(+Grid::DATA_DIMENSION, 1);
+ }
+
+ // Evaluate the interpolated function value and/or its
+ // derivative. Uses the nearest point on the grid boundary if r or
+ // c is out of bounds.
+ void Evaluate(
+ double r, double c, double* f, double* dfdr, double* dfdc) const {
+ // BiCubic interpolation requires 16 values around the point being
+ // evaluated. We will use pij, to indicate the elements of the
+ // 4x4 grid of values.
+ //
+ // col
+ // p00 p01 p02 p03
+ // row p10 p11 p12 p13
+ // p20 p21 p22 p23
+ // p30 p31 p32 p33
+ //
+ // The point (r,c) being evaluated is assumed to lie in the square
+ // defined by p11, p12, p22 and p21.
+
+ const int row = std::floor(r);
+ const int col = std::floor(c);
+
+ Eigen::Matrix<double, Grid::DATA_DIMENSION, 1> p0, p1, p2, p3;
+
+ // Interpolate along each of the four rows, evaluating the function
+ // value and the horizontal derivative in each row.
+ Eigen::Matrix<double, Grid::DATA_DIMENSION, 1> f0, f1, f2, f3;
+ Eigen::Matrix<double, Grid::DATA_DIMENSION, 1> df0dc, df1dc, df2dc, df3dc;
+
+ grid_.GetValue(row - 1, col - 1, p0.data());
+ grid_.GetValue(row - 1, col, p1.data());
+ grid_.GetValue(row - 1, col + 1, p2.data());
+ grid_.GetValue(row - 1, col + 2, p3.data());
+ CubicHermiteSpline<Grid::DATA_DIMENSION>(
+ p0, p1, p2, p3, c - col, f0.data(), df0dc.data());
+
+ grid_.GetValue(row, col - 1, p0.data());
+ grid_.GetValue(row, col, p1.data());
+ grid_.GetValue(row, col + 1, p2.data());
+ grid_.GetValue(row, col + 2, p3.data());
+ CubicHermiteSpline<Grid::DATA_DIMENSION>(
+ p0, p1, p2, p3, c - col, f1.data(), df1dc.data());
+
+ grid_.GetValue(row + 1, col - 1, p0.data());
+ grid_.GetValue(row + 1, col, p1.data());
+ grid_.GetValue(row + 1, col + 1, p2.data());
+ grid_.GetValue(row + 1, col + 2, p3.data());
+ CubicHermiteSpline<Grid::DATA_DIMENSION>(
+ p0, p1, p2, p3, c - col, f2.data(), df2dc.data());
+
+ grid_.GetValue(row + 2, col - 1, p0.data());
+ grid_.GetValue(row + 2, col, p1.data());
+ grid_.GetValue(row + 2, col + 1, p2.data());
+ grid_.GetValue(row + 2, col + 2, p3.data());
+ CubicHermiteSpline<Grid::DATA_DIMENSION>(
+ p0, p1, p2, p3, c - col, f3.data(), df3dc.data());
+
+ // Interpolate vertically the interpolated value from each row and
+ // compute the derivative along the columns.
+ CubicHermiteSpline<Grid::DATA_DIMENSION>(f0, f1, f2, f3, r - row, f, dfdr);
+ if (dfdc != NULL) {
+ // Interpolate vertically the derivative along the columns.
+ CubicHermiteSpline<Grid::DATA_DIMENSION>(
+ df0dc, df1dc, df2dc, df3dc, r - row, dfdc, NULL);
+ }
+ }
+
+ // The following two Evaluate overloads are needed for interfacing
+ // with automatic differentiation. The first is for when a scalar
+ // evaluation is done, and the second one is for when Jets are used.
+ void Evaluate(const double& r, const double& c, double* f) const {
+ Evaluate(r, c, f, NULL, NULL);
+ }
+
+ template <typename JetT>
+ void Evaluate(const JetT& r, const JetT& c, JetT* f) const {
+ double frc[Grid::DATA_DIMENSION];
+ double dfdr[Grid::DATA_DIMENSION];
+ double dfdc[Grid::DATA_DIMENSION];
+ Evaluate(r.a, c.a, frc, dfdr, dfdc);
+ for (int i = 0; i < Grid::DATA_DIMENSION; ++i) {
+ f[i].a = frc[i];
+ f[i].v = dfdr[i] * r.v + dfdc[i] * c.v;
+ }
+ }
+
+ private:
+ const Grid& grid_;
+};
+
+// An object that implements an infinite two dimensional grid needed
+// by the BiCubicInterpolator where the source of the function values
+// is an grid of type T on the grid
+//
+// [(row_start, col_start), ..., (row_start, col_end - 1)]
+// [ ... ]
+// [(row_end - 1, col_start), ..., (row_end - 1, col_end - 1)]
+//
+// Since the input grid is finite and the grid is infinite, values
+// outside this interval needs to be computed. Grid2D uses the value
+// from the nearest edge.
+//
+// The function being provided can be vector valued, in which case
+// kDataDimension > 1. The data maybe stored in row or column major
+// format and the various dimensional slices of the function maybe
+// interleaved, or they maybe stacked, i.e, if the function has
+// kDataDimension = 2, is stored in row-major format and if
+// kInterleaved = true, then it is stored as
+//
+// f001, f002, f011, f012, ...
+//
+// A commonly occuring example are color images (RGB) where the three
+// channels are stored interleaved.
+//
+// If kInterleaved = false, then it is stored as
+//
+// f001, f011, ..., fnm1, f002, f012, ...
+template <typename T,
+ int kDataDimension = 1,
+ bool kRowMajor = true,
+ bool kInterleaved = true>
+struct Grid2D {
+ public:
+ enum { DATA_DIMENSION = kDataDimension };
+
+ Grid2D(const T* data,
+ const int row_begin,
+ const int row_end,
+ const int col_begin,
+ const int col_end)
+ : data_(data),
+ row_begin_(row_begin),
+ row_end_(row_end),
+ col_begin_(col_begin),
+ col_end_(col_end),
+ num_rows_(row_end - row_begin),
+ num_cols_(col_end - col_begin),
+ num_values_(num_rows_ * num_cols_) {
+ CHECK_GE(kDataDimension, 1);
+ CHECK_LT(row_begin, row_end);
+ CHECK_LT(col_begin, col_end);
+ }
+
+ EIGEN_STRONG_INLINE void GetValue(const int r, const int c, double* f) const {
+ const int row_idx =
+ std::min(std::max(row_begin_, r), row_end_ - 1) - row_begin_;
+ const int col_idx =
+ std::min(std::max(col_begin_, c), col_end_ - 1) - col_begin_;
+
+ const int n = (kRowMajor) ? num_cols_ * row_idx + col_idx
+ : num_rows_ * col_idx + row_idx;
+
+ if (kInterleaved) {
+ for (int i = 0; i < kDataDimension; ++i) {
+ f[i] = static_cast<double>(data_[kDataDimension * n + i]);
+ }
+ } else {
+ for (int i = 0; i < kDataDimension; ++i) {
+ f[i] = static_cast<double>(data_[i * num_values_ + n]);
+ }
+ }
+ }
+
+ private:
+ const T* data_;
+ const int row_begin_;
+ const int row_end_;
+ const int col_begin_;
+ const int col_end_;
+ const int num_rows_;
+ const int num_cols_;
+ const int num_values_;
+};
+
+} // namespace ceres
+
+#endif // CERES_PUBLIC_CUBIC_INTERPOLATOR_H_
diff --git a/extern/ceres/include/ceres/dynamic_autodiff_cost_function.h b/extern/ceres/include/ceres/dynamic_autodiff_cost_function.h
index e6d26111f18..7b75150b5ce 100644
--- a/extern/ceres/include/ceres/dynamic_autodiff_cost_function.h
+++ b/extern/ceres/include/ceres/dynamic_autodiff_cost_function.h
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2019 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -28,7 +28,22 @@
//
// Author: sameeragarwal@google.com (Sameer Agarwal)
// mierle@gmail.com (Keir Mierle)
-//
+
+#ifndef CERES_PUBLIC_DYNAMIC_AUTODIFF_COST_FUNCTION_H_
+#define CERES_PUBLIC_DYNAMIC_AUTODIFF_COST_FUNCTION_H_
+
+#include <cmath>
+#include <memory>
+#include <numeric>
+#include <vector>
+
+#include "ceres/dynamic_cost_function.h"
+#include "ceres/internal/fixed_array.h"
+#include "ceres/jet.h"
+#include "glog/logging.h"
+
+namespace ceres {
+
// This autodiff implementation differs from the one found in
// autodiff_cost_function.h by supporting autodiff on cost functions
// with variable numbers of parameters with variable sizes. With the
@@ -43,7 +58,7 @@
// bool operator()(T const* const* parameters, T* residuals) const {
// // Use parameters[i] to access the i'th parameter block.
// }
-// }
+// };
//
// Since the sizing of the parameters is done at runtime, you must
// also specify the sizes after creating the dynamic autodiff cost
@@ -60,40 +75,17 @@
// default, controlled by the Stride template parameter) with each
// pass. There is a tradeoff with the size of the passes; you may want
// to experiment with the stride.
-
-#ifndef CERES_PUBLIC_DYNAMIC_AUTODIFF_COST_FUNCTION_H_
-#define CERES_PUBLIC_DYNAMIC_AUTODIFF_COST_FUNCTION_H_
-
-#include <cmath>
-#include <numeric>
-#include <vector>
-
-#include "ceres/cost_function.h"
-#include "ceres/internal/scoped_ptr.h"
-#include "ceres/jet.h"
-#include "glog/logging.h"
-
-namespace ceres {
-
template <typename CostFunctor, int Stride = 4>
-class DynamicAutoDiffCostFunction : public CostFunction {
+class DynamicAutoDiffCostFunction : public DynamicCostFunction {
public:
explicit DynamicAutoDiffCostFunction(CostFunctor* functor)
- : functor_(functor) {}
+ : functor_(functor) {}
virtual ~DynamicAutoDiffCostFunction() {}
- void AddParameterBlock(int size) {
- mutable_parameter_block_sizes()->push_back(size);
- }
-
- void SetNumResiduals(int num_residuals) {
- set_num_residuals(num_residuals);
- }
-
- virtual bool Evaluate(double const* const* parameters,
- double* residuals,
- double** jacobians) const {
+ bool Evaluate(double const* const* parameters,
+ double* residuals,
+ double** jacobians) const override {
CHECK_GT(num_residuals(), 0)
<< "You must call DynamicAutoDiffCostFunction::SetNumResiduals() "
<< "before DynamicAutoDiffCostFunction::Evaluate().";
@@ -112,20 +104,23 @@ class DynamicAutoDiffCostFunction : public CostFunction {
// depends on.
//
// To work around this issue, the solution here is to evaluate the
- // jacobians in a series of passes, each one computing Stripe *
+ // jacobians in a series of passes, each one computing Stride *
// num_residuals() derivatives. This is done with small, fixed-size jets.
- const int num_parameter_blocks = parameter_block_sizes().size();
- const int num_parameters = std::accumulate(parameter_block_sizes().begin(),
- parameter_block_sizes().end(),
- 0);
+ const int num_parameter_blocks =
+ static_cast<int>(parameter_block_sizes().size());
+ const int num_parameters = std::accumulate(
+ parameter_block_sizes().begin(), parameter_block_sizes().end(), 0);
// Allocate scratch space for the strided evaluation.
- std::vector<Jet<double, Stride> > input_jets(num_parameters);
- std::vector<Jet<double, Stride> > output_jets(num_residuals());
+ using JetT = Jet<double, Stride>;
+ internal::FixedArray<JetT, (256 * 7) / sizeof(JetT)> input_jets(
+ num_parameters);
+ internal::FixedArray<JetT, (256 * 7) / sizeof(JetT)> output_jets(
+ num_residuals());
// Make the parameter pack that is sent to the functor (reused).
- std::vector<Jet<double, Stride>* > jet_parameters(num_parameter_blocks,
- static_cast<Jet<double, Stride>* >(NULL));
+ internal::FixedArray<Jet<double, Stride>*> jet_parameters(
+ num_parameter_blocks, nullptr);
int num_active_parameters = 0;
// To handle constant parameters between non-constant parameter blocks, the
@@ -172,8 +167,8 @@ class DynamicAutoDiffCostFunction : public CostFunction {
// Evaluate all of the strides. Each stride is a chunk of the derivative to
// evaluate, typically some size proportional to the size of the SIMD
// registers of the CPU.
- int num_strides = static_cast<int>(ceil(num_active_parameters /
- static_cast<float>(Stride)));
+ int num_strides = static_cast<int>(
+ ceil(num_active_parameters / static_cast<float>(Stride)));
int current_derivative_section = 0;
int current_derivative_section_cursor = 0;
@@ -183,7 +178,7 @@ class DynamicAutoDiffCostFunction : public CostFunction {
// non-constant #Stride parameters.
const int initial_derivative_section = current_derivative_section;
const int initial_derivative_section_cursor =
- current_derivative_section_cursor;
+ current_derivative_section_cursor;
int active_parameter_count = 0;
parameter_cursor = 0;
@@ -193,9 +188,9 @@ class DynamicAutoDiffCostFunction : public CostFunction {
++j, parameter_cursor++) {
input_jets[parameter_cursor].v.setZero();
if (active_parameter_count < Stride &&
- parameter_cursor >= (
- start_derivative_section[current_derivative_section] +
- current_derivative_section_cursor)) {
+ parameter_cursor >=
+ (start_derivative_section[current_derivative_section] +
+ current_derivative_section_cursor)) {
if (jacobians[i] != NULL) {
input_jets[parameter_cursor].v[active_parameter_count] = 1.0;
++active_parameter_count;
@@ -222,9 +217,9 @@ class DynamicAutoDiffCostFunction : public CostFunction {
for (int j = 0; j < parameter_block_sizes()[i];
++j, parameter_cursor++) {
if (active_parameter_count < Stride &&
- parameter_cursor >= (
- start_derivative_section[current_derivative_section] +
- current_derivative_section_cursor)) {
+ parameter_cursor >=
+ (start_derivative_section[current_derivative_section] +
+ current_derivative_section_cursor)) {
if (jacobians[i] != NULL) {
for (int k = 0; k < num_residuals(); ++k) {
jacobians[i][k * parameter_block_sizes()[i] + j] =
@@ -252,7 +247,7 @@ class DynamicAutoDiffCostFunction : public CostFunction {
}
private:
- internal::scoped_ptr<CostFunctor> functor_;
+ std::unique_ptr<CostFunctor> functor_;
};
} // namespace ceres
diff --git a/extern/ceres/include/ceres/dynamic_cost_function.h b/extern/ceres/include/ceres/dynamic_cost_function.h
new file mode 100644
index 00000000000..6e8a076ecd0
--- /dev/null
+++ b/extern/ceres/include/ceres/dynamic_cost_function.h
@@ -0,0 +1,56 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2019 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#ifndef CERES_PUBLIC_DYNAMIC_COST_FUNCTION_H_
+#define CERES_PUBLIC_DYNAMIC_COST_FUNCTION_H_
+
+#include "ceres/cost_function.h"
+
+namespace ceres {
+
+// A common base class for DynamicAutoDiffCostFunction and
+// DynamicNumericDiffCostFunction which depend on methods that can add
+// parameter blocks and set the number of residuals at run time.
+class CERES_EXPORT DynamicCostFunction : public CostFunction {
+ public:
+ ~DynamicCostFunction() {}
+
+ virtual void AddParameterBlock(int size) {
+ mutable_parameter_block_sizes()->push_back(size);
+ }
+
+ virtual void SetNumResiduals(int num_residuals) {
+ set_num_residuals(num_residuals);
+ }
+};
+
+} // namespace ceres
+
+#endif // CERES_PUBLIC_DYNAMIC_COST_FUNCTION_H_
diff --git a/extern/ceres/include/ceres/dynamic_cost_function_to_functor.h b/extern/ceres/include/ceres/dynamic_cost_function_to_functor.h
index 9339a503ea0..8d174d8ecc2 100644
--- a/extern/ceres/include/ceres/dynamic_cost_function_to_functor.h
+++ b/extern/ceres/include/ceres/dynamic_cost_function_to_functor.h
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2019 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -28,7 +28,20 @@
//
// Author: sameeragarwal@google.com (Sameer Agarwal)
// dgossow@google.com (David Gossow)
-//
+
+#ifndef CERES_PUBLIC_DYNAMIC_COST_FUNCTION_TO_FUNCTOR_H_
+#define CERES_PUBLIC_DYNAMIC_COST_FUNCTION_TO_FUNCTOR_H_
+
+#include <memory>
+#include <numeric>
+#include <vector>
+
+#include "ceres/dynamic_cost_function.h"
+#include "ceres/internal/fixed_array.h"
+#include "ceres/internal/port.h"
+
+namespace ceres {
+
// DynamicCostFunctionToFunctor allows users to use CostFunction
// objects in templated functors which are to be used for automatic
// differentiation. It works similar to CostFunctionToFunctor, with the
@@ -40,9 +53,9 @@
// class IntrinsicProjection : public CostFunction {
// public:
// IntrinsicProjection(const double* observation);
-// virtual bool Evaluate(double const* const* parameters,
-// double* residuals,
-// double** jacobians) const;
+// bool Evaluate(double const* const* parameters,
+// double* residuals,
+// double** jacobians) const override;
// };
//
// is a cost function that implements the projection of a point in its
@@ -87,26 +100,12 @@
// private:
// DynamicCostFunctionToFunctor intrinsic_projection_;
// };
-
-#ifndef CERES_PUBLIC_DYNAMIC_COST_FUNCTION_TO_FUNCTOR_H_
-#define CERES_PUBLIC_DYNAMIC_COST_FUNCTION_TO_FUNCTOR_H_
-
-#include <numeric>
-#include <vector>
-
-#include "ceres/cost_function.h"
-#include "ceres/internal/fixed_array.h"
-#include "ceres/internal/port.h"
-#include "ceres/internal/scoped_ptr.h"
-
-namespace ceres {
-
class DynamicCostFunctionToFunctor {
public:
// Takes ownership of cost_function.
explicit DynamicCostFunctionToFunctor(CostFunction* cost_function)
: cost_function_(cost_function) {
- CHECK_NOTNULL(cost_function);
+ CHECK(cost_function != nullptr);
}
bool operator()(double const* const* parameters, double* residuals) const {
@@ -115,12 +114,13 @@ class DynamicCostFunctionToFunctor {
template <typename JetT>
bool operator()(JetT const* const* inputs, JetT* output) const {
- const std::vector<int32>& parameter_block_sizes =
+ const std::vector<int32_t>& parameter_block_sizes =
cost_function_->parameter_block_sizes();
- const int num_parameter_blocks = parameter_block_sizes.size();
+ const int num_parameter_blocks =
+ static_cast<int>(parameter_block_sizes.size());
const int num_residuals = cost_function_->num_residuals();
- const int num_parameters = std::accumulate(parameter_block_sizes.begin(),
- parameter_block_sizes.end(), 0);
+ const int num_parameters = std::accumulate(
+ parameter_block_sizes.begin(), parameter_block_sizes.end(), 0);
internal::FixedArray<double> parameters(num_parameters);
internal::FixedArray<double*> parameter_blocks(num_parameter_blocks);
@@ -130,8 +130,8 @@ class DynamicCostFunctionToFunctor {
// Build a set of arrays to get the residuals and jacobians from
// the CostFunction wrapped by this functor.
- double* parameter_ptr = parameters.get();
- double* jacobian_ptr = jacobians.get();
+ double* parameter_ptr = parameters.data();
+ double* jacobian_ptr = jacobians.data();
for (int i = 0; i < num_parameter_blocks; ++i) {
parameter_blocks[i] = parameter_ptr;
jacobian_blocks[i] = jacobian_ptr;
@@ -141,9 +141,9 @@ class DynamicCostFunctionToFunctor {
jacobian_ptr += num_residuals * parameter_block_sizes[i];
}
- if (!cost_function_->Evaluate(parameter_blocks.get(),
- residuals.get(),
- jacobian_blocks.get())) {
+ if (!cost_function_->Evaluate(parameter_blocks.data(),
+ residuals.data(),
+ jacobian_blocks.data())) {
return false;
}
@@ -170,7 +170,7 @@ class DynamicCostFunctionToFunctor {
output[i].v.setZero();
for (int j = 0; j < num_parameter_blocks; ++j) {
- const int32 block_size = parameter_block_sizes[j];
+ const int32_t block_size = parameter_block_sizes[j];
for (int k = 0; k < parameter_block_sizes[j]; ++k) {
output[i].v +=
jacobian_blocks[j][i * block_size + k] * inputs[j][k].v;
@@ -182,7 +182,7 @@ class DynamicCostFunctionToFunctor {
}
private:
- internal::scoped_ptr<CostFunction> cost_function_;
+ std::unique_ptr<CostFunction> cost_function_;
};
} // namespace ceres
diff --git a/extern/ceres/include/ceres/dynamic_numeric_diff_cost_function.h b/extern/ceres/include/ceres/dynamic_numeric_diff_cost_function.h
index 5770946a115..119b3f85e8e 100644
--- a/extern/ceres/include/ceres/dynamic_numeric_diff_cost_function.h
+++ b/extern/ceres/include/ceres/dynamic_numeric_diff_cost_function.h
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2019 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -30,7 +30,24 @@
// sameeragarwal@google.com (Sameer Agarwal)
// thadh@gmail.com (Thad Hughes)
// tbennun@gmail.com (Tal Ben-Nun)
-//
+
+#ifndef CERES_PUBLIC_DYNAMIC_NUMERIC_DIFF_COST_FUNCTION_H_
+#define CERES_PUBLIC_DYNAMIC_NUMERIC_DIFF_COST_FUNCTION_H_
+
+#include <cmath>
+#include <memory>
+#include <numeric>
+#include <vector>
+
+#include "ceres/dynamic_cost_function.h"
+#include "ceres/internal/eigen.h"
+#include "ceres/internal/numeric_diff.h"
+#include "ceres/internal/parameter_dims.h"
+#include "ceres/numeric_diff_options.h"
+#include "glog/logging.h"
+
+namespace ceres {
+
// This numeric diff implementation differs from the one found in
// numeric_diff_cost_function.h by supporting numericdiff on cost
// functions with variable numbers of parameters with variable
@@ -42,7 +59,9 @@
// numeric diff; the expected interface for the cost functors is:
//
// struct MyCostFunctor {
-// bool operator()(double const* const* parameters, double* residuals) const {
+// bool operator()(double const*
+// const* parameters,
+// double* residuals) const {
// // Use parameters[i] to access the i'th parameter block.
// }
// }
@@ -56,34 +75,14 @@
// cost_function.AddParameterBlock(5);
// cost_function.AddParameterBlock(10);
// cost_function.SetNumResiduals(21);
-
-#ifndef CERES_PUBLIC_DYNAMIC_NUMERIC_DIFF_COST_FUNCTION_H_
-#define CERES_PUBLIC_DYNAMIC_NUMERIC_DIFF_COST_FUNCTION_H_
-
-#include <cmath>
-#include <numeric>
-#include <vector>
-
-#include "ceres/cost_function.h"
-#include "ceres/internal/scoped_ptr.h"
-#include "ceres/internal/eigen.h"
-#include "ceres/internal/numeric_diff.h"
-#include "ceres/numeric_diff_options.h"
-#include "glog/logging.h"
-
-namespace ceres {
-
template <typename CostFunctor, NumericDiffMethodType method = CENTRAL>
-class DynamicNumericDiffCostFunction : public CostFunction {
+class DynamicNumericDiffCostFunction : public DynamicCostFunction {
public:
explicit DynamicNumericDiffCostFunction(
const CostFunctor* functor,
Ownership ownership = TAKE_OWNERSHIP,
const NumericDiffOptions& options = NumericDiffOptions())
- : functor_(functor),
- ownership_(ownership),
- options_(options) {
- }
+ : functor_(functor), ownership_(ownership), options_(options) {}
virtual ~DynamicNumericDiffCostFunction() {
if (ownership_ != TAKE_OWNERSHIP) {
@@ -91,28 +90,22 @@ class DynamicNumericDiffCostFunction : public CostFunction {
}
}
- void AddParameterBlock(int size) {
- mutable_parameter_block_sizes()->push_back(size);
- }
-
- void SetNumResiduals(int num_residuals) {
- set_num_residuals(num_residuals);
- }
-
- virtual bool Evaluate(double const* const* parameters,
- double* residuals,
- double** jacobians) const {
+ bool Evaluate(double const* const* parameters,
+ double* residuals,
+ double** jacobians) const override {
using internal::NumericDiff;
CHECK_GT(num_residuals(), 0)
<< "You must call DynamicNumericDiffCostFunction::SetNumResiduals() "
<< "before DynamicNumericDiffCostFunction::Evaluate().";
- const std::vector<int32>& block_sizes = parameter_block_sizes();
+ const std::vector<int32_t>& block_sizes = parameter_block_sizes();
CHECK(!block_sizes.empty())
<< "You must call DynamicNumericDiffCostFunction::AddParameterBlock() "
<< "before DynamicNumericDiffCostFunction::Evaluate().";
- const bool status = EvaluateCostFunctor(parameters, residuals);
+ const bool status =
+ internal::VariadicEvaluate<internal::DynamicParameterDims>(
+ *functor_.get(), parameters, residuals);
if (jacobians == NULL || !status) {
return status;
}
@@ -123,8 +116,8 @@ class DynamicNumericDiffCostFunction : public CostFunction {
std::vector<double*> parameters_references_copy(block_sizes.size());
parameters_references_copy[0] = &parameters_copy[0];
for (size_t block = 1; block < block_sizes.size(); ++block) {
- parameters_references_copy[block] = parameters_references_copy[block - 1]
- + block_sizes[block - 1];
+ parameters_references_copy[block] =
+ parameters_references_copy[block - 1] + block_sizes[block - 1];
}
// Copy the parameters into the local temp space.
@@ -136,18 +129,20 @@ class DynamicNumericDiffCostFunction : public CostFunction {
for (size_t block = 0; block < block_sizes.size(); ++block) {
if (jacobians[block] != NULL &&
- !NumericDiff<CostFunctor, method, DYNAMIC,
- DYNAMIC, DYNAMIC, DYNAMIC, DYNAMIC, DYNAMIC,
- DYNAMIC, DYNAMIC, DYNAMIC, DYNAMIC, DYNAMIC,
- DYNAMIC, DYNAMIC>::EvaluateJacobianForParameterBlock(
- functor_.get(),
- residuals,
- options_,
- this->num_residuals(),
- block,
- block_sizes[block],
- &parameters_references_copy[0],
- jacobians[block])) {
+ !NumericDiff<CostFunctor,
+ method,
+ ceres::DYNAMIC,
+ internal::DynamicParameterDims,
+ ceres::DYNAMIC,
+ ceres::DYNAMIC>::
+ EvaluateJacobianForParameterBlock(functor_.get(),
+ residuals,
+ options_,
+ this->num_residuals(),
+ block,
+ block_sizes[block],
+ &parameters_references_copy[0],
+ jacobians[block])) {
return false;
}
}
@@ -155,31 +150,7 @@ class DynamicNumericDiffCostFunction : public CostFunction {
}
private:
- bool EvaluateCostFunctor(double const* const* parameters,
- double* residuals) const {
- return EvaluateCostFunctorImpl(functor_.get(),
- parameters,
- residuals,
- functor_.get());
- }
-
- // Helper templates to allow evaluation of a functor or a
- // CostFunction.
- bool EvaluateCostFunctorImpl(const CostFunctor* functor,
- double const* const* parameters,
- double* residuals,
- const void* /* NOT USED */) const {
- return (*functor)(parameters, residuals);
- }
-
- bool EvaluateCostFunctorImpl(const CostFunctor* functor,
- double const* const* parameters,
- double* residuals,
- const CostFunction* /* NOT USED */) const {
- return functor->Evaluate(parameters, residuals, NULL);
- }
-
- internal::scoped_ptr<const CostFunctor> functor_;
+ std::unique_ptr<const CostFunctor> functor_;
Ownership ownership_;
NumericDiffOptions options_;
};
diff --git a/extern/ceres/include/ceres/evaluation_callback.h b/extern/ceres/include/ceres/evaluation_callback.h
new file mode 100644
index 00000000000..b9f5bbb5194
--- /dev/null
+++ b/extern/ceres/include/ceres/evaluation_callback.h
@@ -0,0 +1,80 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2019 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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.
+//
+// Author: mierle@gmail.com (Keir Mierle)
+
+#ifndef CERES_PUBLIC_EVALUATION_CALLBACK_H_
+#define CERES_PUBLIC_EVALUATION_CALLBACK_H_
+
+#include "ceres/internal/port.h"
+
+namespace ceres {
+
+// Using this callback interface, Ceres can notify you when it is
+// about to evaluate the residuals or jacobians. With the callback,
+// you can share computation between residual blocks by doing the
+// shared computation in PrepareForEvaluation() before Ceres calls
+// CostFunction::Evaluate(). It also enables caching results between a
+// pure residual evaluation and a residual & jacobian evaluation, via
+// the new_evaluation_point argument.
+//
+// One use case for this callback is if the cost function compute is
+// moved to the GPU. In that case, the prepare call does the actual
+// cost function evaluation, and subsequent calls from Ceres to the
+// actual cost functions merely copy the results from the GPU onto the
+// corresponding blocks for Ceres to plug into the solver.
+//
+// NOTE: Ceres provides no mechanism to share data other than the
+// notification from the callback. Users must provide access to
+// pre-computed shared data to their cost functions behind the scenes;
+// this all happens without Ceres knowing.
+//
+// One approach is to put a pointer to the shared data in each cost
+// function (recommended) or to use a global shared variable
+// (discouraged; bug-prone). As far as Ceres is concerned, it is
+// evaluating cost functions like any other; it just so happens that
+// behind the scenes the cost functions reuse pre-computed data to
+// execute faster.
+class CERES_EXPORT EvaluationCallback {
+ public:
+ virtual ~EvaluationCallback() {}
+
+ // Called before Ceres requests residuals or jacobians for a given setting of
+ // the parameters. User parameters (the double* values provided to the cost
+ // functions) are fixed until the next call to PrepareForEvaluation(). If
+ // new_evaluation_point == true, then this is a new point that is different
+ // from the last evaluated point. Otherwise, it is the same point that was
+ // evaluated previously (either jacobian or residual) and the user can use
+ // cached results from previous evaluations.
+ virtual void PrepareForEvaluation(bool evaluate_jacobians,
+ bool new_evaluation_point) = 0;
+};
+
+} // namespace ceres
+
+#endif // CERES_PUBLIC_EVALUATION_CALLBACK_H_
diff --git a/extern/ceres/include/ceres/first_order_function.h b/extern/ceres/include/ceres/first_order_function.h
new file mode 100644
index 00000000000..1420153b2aa
--- /dev/null
+++ b/extern/ceres/include/ceres/first_order_function.h
@@ -0,0 +1,54 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2019 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#ifndef CERES_PUBLIC_FIRST_ORDER_FUNCTION_H_
+#define CERES_PUBLIC_FIRST_ORDER_FUNCTION_H_
+
+#include "ceres/internal/port.h"
+
+namespace ceres {
+
+// A FirstOrderFunction object implements the evaluation of a function
+// and its gradient.
+class CERES_EXPORT FirstOrderFunction {
+ public:
+ virtual ~FirstOrderFunction() {}
+
+ // cost is never null. gradient may be null. The return value
+ // indicates whether the evaluation was successful or not.
+ virtual bool Evaluate(const double* const parameters,
+ double* cost,
+ double* gradient) const = 0;
+ virtual int NumParameters() const = 0;
+};
+
+} // namespace ceres
+
+#endif // CERES_PUBLIC_FIRST_ORDER_FUNCTION_H_
diff --git a/extern/ceres/include/ceres/gradient_checker.h b/extern/ceres/include/ceres/gradient_checker.h
index 6d285daf1d9..b79cf86b314 100644
--- a/extern/ceres/include/ceres/gradient_checker.h
+++ b/extern/ceres/include/ceres/gradient_checker.h
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2019 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -34,15 +34,14 @@
#ifndef CERES_PUBLIC_GRADIENT_CHECKER_H_
#define CERES_PUBLIC_GRADIENT_CHECKER_H_
-#include <vector>
+#include <memory>
#include <string>
+#include <vector>
#include "ceres/cost_function.h"
#include "ceres/dynamic_numeric_diff_cost_function.h"
#include "ceres/internal/eigen.h"
#include "ceres/internal/fixed_array.h"
-#include "ceres/internal/macros.h"
-#include "ceres/internal/scoped_ptr.h"
#include "ceres/local_parameterization.h"
#include "glog/logging.h"
@@ -64,13 +63,13 @@ namespace ceres {
//
// How to use: Fill in an array of pointers to parameter blocks for your
// CostFunction, and then call Probe(). Check that the return value is 'true'.
-class GradientChecker {
+class CERES_EXPORT GradientChecker {
public:
// This will not take ownership of the cost function or local
// parameterizations.
//
// function: The cost function to probe.
- // local_parameterization: A vector of local parameterizations for each
+ // local_parameterizations: A vector of local parameterizations for each
// parameter. May be NULL or contain NULL pointers to indicate that the
// respective parameter does not have a local parameterization.
// options: Options to use for numerical differentiation.
@@ -80,7 +79,7 @@ class GradientChecker {
const NumericDiffOptions& options);
// Contains results from a call to Probe for later inspection.
- struct ProbeResults {
+ struct CERES_EXPORT ProbeResults {
// The return value of the cost function.
bool return_value;
@@ -100,10 +99,10 @@ class GradientChecker {
// Derivatives as computed by the cost function in local space.
std::vector<Matrix> local_jacobians;
- // Derivatives as computed by nuerical differentiation in local space.
+ // Derivatives as computed by numerical differentiation in local space.
std::vector<Matrix> numeric_jacobians;
- // Derivatives as computed by nuerical differentiation in local space.
+ // Derivatives as computed by numerical differentiation in local space.
std::vector<Matrix> local_numeric_jacobians;
// Contains the maximum relative error found in the local Jacobians.
@@ -137,11 +136,13 @@ class GradientChecker {
ProbeResults* results) const;
private:
- CERES_DISALLOW_IMPLICIT_CONSTRUCTORS(GradientChecker);
+ GradientChecker() = delete;
+ GradientChecker(const GradientChecker&) = delete;
+ void operator=(const GradientChecker&) = delete;
std::vector<const LocalParameterization*> local_parameterizations_;
const CostFunction* function_;
- internal::scoped_ptr<CostFunction> finite_diff_cost_function_;
+ std::unique_ptr<CostFunction> finite_diff_cost_function_;
};
} // namespace ceres
diff --git a/extern/ceres/include/ceres/gradient_problem.h b/extern/ceres/include/ceres/gradient_problem.h
index 1226a4cd895..49d605ea2d6 100644
--- a/extern/ceres/include/ceres/gradient_problem.h
+++ b/extern/ceres/include/ceres/gradient_problem.h
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2019 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -31,9 +31,10 @@
#ifndef CERES_PUBLIC_GRADIENT_PROBLEM_H_
#define CERES_PUBLIC_GRADIENT_PROBLEM_H_
-#include "ceres/internal/macros.h"
+#include <memory>
+
+#include "ceres/first_order_function.h"
#include "ceres/internal/port.h"
-#include "ceres/internal/scoped_ptr.h"
#include "ceres/local_parameterization.h"
namespace ceres {
@@ -105,21 +106,9 @@ class CERES_EXPORT GradientProblem {
bool Plus(const double* x, const double* delta, double* x_plus_delta) const;
private:
- internal::scoped_ptr<FirstOrderFunction> function_;
- internal::scoped_ptr<LocalParameterization> parameterization_;
- internal::scoped_array<double> scratch_;
-};
-
-// A FirstOrderFunction object implements the evaluation of a function
-// and its gradient.
-class CERES_EXPORT FirstOrderFunction {
- public:
- virtual ~FirstOrderFunction() {}
- // cost is never NULL. gradient may be null.
- virtual bool Evaluate(const double* const parameters,
- double* cost,
- double* gradient) const = 0;
- virtual int NumParameters() const = 0;
+ std::unique_ptr<FirstOrderFunction> function_;
+ std::unique_ptr<LocalParameterization> parameterization_;
+ std::unique_ptr<double[]> scratch_;
};
} // namespace ceres
diff --git a/extern/ceres/include/ceres/gradient_problem_solver.h b/extern/ceres/include/ceres/gradient_problem_solver.h
index a7d0121ea0c..181699d8fd4 100644
--- a/extern/ceres/include/ceres/gradient_problem_solver.h
+++ b/extern/ceres/include/ceres/gradient_problem_solver.h
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2019 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -34,11 +34,11 @@
#include <cmath>
#include <string>
#include <vector>
-#include "ceres/internal/macros.h"
+
+#include "ceres/internal/disable_warnings.h"
#include "ceres/internal/port.h"
#include "ceres/iteration_callback.h"
#include "ceres/types.h"
-#include "ceres/internal/disable_warnings.h"
namespace ceres {
@@ -54,39 +54,15 @@ class CERES_EXPORT GradientProblemSolver {
//
// The constants are defined inside types.h
struct CERES_EXPORT Options {
- // Default constructor that sets up a generic sparse problem.
- Options() {
- line_search_direction_type = LBFGS;
- line_search_type = WOLFE;
- nonlinear_conjugate_gradient_type = FLETCHER_REEVES;
- max_lbfgs_rank = 20;
- use_approximate_eigenvalue_bfgs_scaling = false;
- line_search_interpolation_type = CUBIC;
- min_line_search_step_size = 1e-9;
- line_search_sufficient_function_decrease = 1e-4;
- max_line_search_step_contraction = 1e-3;
- min_line_search_step_contraction = 0.6;
- max_num_line_search_step_size_iterations = 20;
- max_num_line_search_direction_restarts = 5;
- line_search_sufficient_curvature_decrease = 0.9;
- max_line_search_step_expansion = 10.0;
- max_num_iterations = 50;
- max_solver_time_in_seconds = 1e9;
- function_tolerance = 1e-6;
- gradient_tolerance = 1e-10;
- logging_type = PER_MINIMIZER_ITERATION;
- minimizer_progress_to_stdout = false;
- }
-
// Returns true if the options struct has a valid
// configuration. Returns false otherwise, and fills in *error
// with a message describing the problem.
bool IsValid(std::string* error) const;
// Minimizer options ----------------------------------------
- LineSearchDirectionType line_search_direction_type;
- LineSearchType line_search_type;
- NonlinearConjugateGradientType nonlinear_conjugate_gradient_type;
+ LineSearchDirectionType line_search_direction_type = LBFGS;
+ LineSearchType line_search_type = WOLFE;
+ NonlinearConjugateGradientType nonlinear_conjugate_gradient_type = FLETCHER_REEVES;
// The LBFGS hessian approximation is a low rank approximation to
// the inverse of the Hessian matrix. The rank of the
@@ -111,8 +87,8 @@ class CERES_EXPORT GradientProblemSolver {
// method, please see:
//
// Nocedal, J. (1980). "Updating Quasi-Newton Matrices with
- // Limited Storage". Mathematics of Computation 35 (151): 773–782.
- int max_lbfgs_rank;
+ // Limited Storage". Mathematics of Computation 35 (151): 773-782.
+ int max_lbfgs_rank = 20;
// As part of the (L)BFGS update step (BFGS) / right-multiply step (L-BFGS),
// the initial inverse Hessian approximation is taken to be the Identity.
@@ -134,18 +110,18 @@ class CERES_EXPORT GradientProblemSolver {
// Oren S.S., Self-scaling variable metric (SSVM) algorithms
// Part II: Implementation and experiments, Management Science,
// 20(5), 863-874, 1974.
- bool use_approximate_eigenvalue_bfgs_scaling;
+ bool use_approximate_eigenvalue_bfgs_scaling = false;
// Degree of the polynomial used to approximate the objective
// function. Valid values are BISECTION, QUADRATIC and CUBIC.
//
// BISECTION corresponds to pure backtracking search with no
// interpolation.
- LineSearchInterpolationType line_search_interpolation_type;
+ LineSearchInterpolationType line_search_interpolation_type = CUBIC;
// If during the line search, the step_size falls below this
// value, it is truncated to zero.
- double min_line_search_step_size;
+ double min_line_search_step_size = 1e-9;
// Line search parameters.
@@ -159,7 +135,7 @@ class CERES_EXPORT GradientProblemSolver {
//
// f(step_size) <= f(0) + sufficient_decrease * f'(0) * step_size
//
- double line_search_sufficient_function_decrease;
+ double line_search_sufficient_function_decrease = 1e-4;
// In each iteration of the line search,
//
@@ -169,7 +145,7 @@ class CERES_EXPORT GradientProblemSolver {
//
// 0 < max_step_contraction < min_step_contraction < 1
//
- double max_line_search_step_contraction;
+ double max_line_search_step_contraction = 1e-3;
// In each iteration of the line search,
//
@@ -179,19 +155,19 @@ class CERES_EXPORT GradientProblemSolver {
//
// 0 < max_step_contraction < min_step_contraction < 1
//
- double min_line_search_step_contraction;
+ double min_line_search_step_contraction = 0.6;
// Maximum number of trial step size iterations during each line search,
// if a step size satisfying the search conditions cannot be found within
// this number of trials, the line search will terminate.
- int max_num_line_search_step_size_iterations;
+ int max_num_line_search_step_size_iterations = 20;
// Maximum number of restarts of the line search direction algorithm before
// terminating the optimization. Restarts of the line search direction
// algorithm occur when the current algorithm fails to produce a new descent
// direction. This typically indicates a numerical failure, or a breakdown
// in the validity of the approximations used.
- int max_num_line_search_direction_restarts;
+ int max_num_line_search_direction_restarts = 5;
// The strong Wolfe conditions consist of the Armijo sufficient
// decrease condition, and an additional requirement that the
@@ -204,7 +180,7 @@ class CERES_EXPORT GradientProblemSolver {
//
// Where f() is the line search objective and f'() is the derivative
// of f w.r.t step_size (d f / d step_size).
- double line_search_sufficient_curvature_decrease;
+ double line_search_sufficient_curvature_decrease = 0.9;
// During the bracketing phase of the Wolfe search, the step size is
// increased until either a point satisfying the Wolfe conditions is
@@ -215,36 +191,49 @@ class CERES_EXPORT GradientProblemSolver {
// new_step_size <= max_step_expansion * step_size.
//
// By definition for expansion, max_step_expansion > 1.0.
- double max_line_search_step_expansion;
+ double max_line_search_step_expansion = 10.0;
// Maximum number of iterations for the minimizer to run for.
- int max_num_iterations;
+ int max_num_iterations = 50;
// Maximum time for which the minimizer should run for.
- double max_solver_time_in_seconds;
+ double max_solver_time_in_seconds = 1e9;
// Minimizer terminates when
//
// (new_cost - old_cost) < function_tolerance * old_cost;
//
- double function_tolerance;
+ double function_tolerance = 1e-6;
// Minimizer terminates when
//
// max_i |x - Project(Plus(x, -g(x))| < gradient_tolerance
//
// This value should typically be 1e-4 * function_tolerance.
- double gradient_tolerance;
+ double gradient_tolerance = 1e-10;
+
+ // Minimizer terminates when
+ //
+ // |step|_2 <= parameter_tolerance * ( |x|_2 + parameter_tolerance)
+ //
+ double parameter_tolerance = 1e-8;
// Logging options ---------------------------------------------------------
- LoggingType logging_type;
+ LoggingType logging_type = PER_MINIMIZER_ITERATION;
// By default the Minimizer progress is logged to VLOG(1), which
// is sent to STDERR depending on the vlog level. If this flag is
// set to true, and logging_type is not SILENT, the logging output
// is sent to STDOUT.
- bool minimizer_progress_to_stdout;
+ bool minimizer_progress_to_stdout = false;
+
+ // If true, the user's parameter blocks are updated at the end of
+ // every Minimizer iteration, otherwise they are updated when the
+ // Minimizer terminates. This is useful if, for example, the user
+ // wishes to visualize the state of the optimization every
+ // iteration.
+ bool update_state_every_iteration = false;
// Callbacks that are executed at the end of each iteration of the
// Minimizer. An iteration may terminate midway, either due to
@@ -265,8 +254,6 @@ class CERES_EXPORT GradientProblemSolver {
};
struct CERES_EXPORT Summary {
- Summary();
-
// A brief one line description of the state of the solver after
// termination.
std::string BriefReport() const;
@@ -278,65 +265,72 @@ class CERES_EXPORT GradientProblemSolver {
bool IsSolutionUsable() const;
// Minimizer summary -------------------------------------------------
- TerminationType termination_type;
+ TerminationType termination_type = FAILURE;
// Reason why the solver terminated.
- std::string message;
+ std::string message = "ceres::GradientProblemSolve was not called.";
// Cost of the problem (value of the objective function) before
// the optimization.
- double initial_cost;
+ double initial_cost = -1.0;
// Cost of the problem (value of the objective function) after the
// optimization.
- double final_cost;
+ double final_cost = -1.0;
// IterationSummary for each minimizer iteration in order.
std::vector<IterationSummary> iterations;
+ // Number of times the cost (and not the gradient) was evaluated.
+ int num_cost_evaluations = -1;
+
+ // Number of times the gradient (and the cost) were evaluated.
+ int num_gradient_evaluations = -1;
+
// Sum total of all time spent inside Ceres when Solve is called.
- double total_time_in_seconds;
+ double total_time_in_seconds = -1.0;
// Time (in seconds) spent evaluating the cost.
- double cost_evaluation_time_in_seconds;
+ double cost_evaluation_time_in_seconds = -1.0;
// Time (in seconds) spent evaluating the gradient.
- double gradient_evaluation_time_in_seconds;
+ double gradient_evaluation_time_in_seconds = -1.0;
// Time (in seconds) spent minimizing the interpolating polynomial
// to compute the next candidate step size as part of a line search.
- double line_search_polynomial_minimization_time_in_seconds;
+ double line_search_polynomial_minimization_time_in_seconds = -1.0;
- // Number of parameters in the probem.
- int num_parameters;
+ // Number of parameters in the problem.
+ int num_parameters = -1;
// Dimension of the tangent space of the problem.
- int num_local_parameters;
+ int num_local_parameters = -1;
// Type of line search direction used.
- LineSearchDirectionType line_search_direction_type;
+ LineSearchDirectionType line_search_direction_type = LBFGS;
// Type of the line search algorithm used.
- LineSearchType line_search_type;
+ LineSearchType line_search_type = WOLFE;
// When performing line search, the degree of the polynomial used
// to approximate the objective function.
- LineSearchInterpolationType line_search_interpolation_type;
+ LineSearchInterpolationType line_search_interpolation_type = CUBIC;
// If the line search direction is NONLINEAR_CONJUGATE_GRADIENT,
// then this indicates the particular variant of non-linear
// conjugate gradient used.
- NonlinearConjugateGradientType nonlinear_conjugate_gradient_type;
+ NonlinearConjugateGradientType nonlinear_conjugate_gradient_type =
+ FLETCHER_REEVES;
// If the type of the line search direction is LBFGS, then this
// indicates the rank of the Hessian approximation.
- int max_lbfgs_rank;
+ int max_lbfgs_rank = -1;
};
// Once a least squares problem has been built, this function takes
// the problem and optimizes it based on the values of the options
// parameters. Upon return, a detailed summary of the work performed
- // by the preprocessor, the non-linear minmizer and the linear
+ // by the preprocessor, the non-linear minimizer and the linear
// solver are reported in the summary object.
virtual void Solve(const GradientProblemSolver::Options& options,
const GradientProblem& problem,
diff --git a/extern/ceres/include/ceres/internal/array_selector.h b/extern/ceres/include/ceres/internal/array_selector.h
new file mode 100644
index 00000000000..841797f4c69
--- /dev/null
+++ b/extern/ceres/include/ceres/internal/array_selector.h
@@ -0,0 +1,95 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2020 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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.
+//
+// Author: darius.rueckert@fau.de (Darius Rueckert)
+//
+
+#ifndef CERES_PUBLIC_INTERNAL_ARRAY_SELECTOR_H_
+#define CERES_PUBLIC_INTERNAL_ARRAY_SELECTOR_H_
+
+#include <array>
+#include <vector>
+
+#include "ceres/internal/fixed_array.h"
+#include "ceres/types.h"
+
+namespace ceres {
+namespace internal {
+
+// StaticFixedArray selects the best array implementation based on template
+// arguments. If the size is not known at compile-time, pass
+// ceres::DYNAMIC as a size-template argument.
+//
+// Three different containers are selected in different scenarios:
+//
+// num_elements == DYNAMIC:
+// -> ceres::internal::FixedArray<T, max_stack_size>(size)
+
+// num_elements != DYNAMIC && num_elements <= max_stack_size
+// -> std::array<T,num_elements>
+
+// num_elements != DYNAMIC && num_elements > max_stack_size
+// -> std::vector<T>(num_elements)
+//
+template <typename T,
+ int num_elements,
+ int max_num_elements_on_stack,
+ bool dynamic = (num_elements == DYNAMIC),
+ bool fits_on_stack = (num_elements <= max_num_elements_on_stack)>
+struct ArraySelector {};
+
+template <typename T,
+ int num_elements,
+ int max_num_elements_on_stack,
+ bool fits_on_stack>
+struct ArraySelector<T,
+ num_elements,
+ max_num_elements_on_stack,
+ true,
+ fits_on_stack>
+ : ceres::internal::FixedArray<T, max_num_elements_on_stack> {
+ ArraySelector(int s)
+ : ceres::internal::FixedArray<T, max_num_elements_on_stack>(s) {}
+};
+
+template <typename T, int num_elements, int max_num_elements_on_stack>
+struct ArraySelector<T, num_elements, max_num_elements_on_stack, false, true>
+ : std::array<T, num_elements> {
+ ArraySelector(int s) { CHECK_EQ(s, num_elements); }
+};
+
+template <typename T, int num_elements, int max_num_elements_on_stack>
+struct ArraySelector<T, num_elements, max_num_elements_on_stack, false, false>
+ : std::vector<T> {
+ ArraySelector(int s) : std::vector<T>(s) { CHECK_EQ(s, num_elements); }
+};
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_PUBLIC_INTERNAL_ARRAY_SELECTOR_H_
diff --git a/extern/ceres/include/ceres/internal/autodiff.h b/extern/ceres/include/ceres/internal/autodiff.h
index 136152a36cd..cb7b1aca5b9 100644
--- a/extern/ceres/include/ceres/internal/autodiff.h
+++ b/extern/ceres/include/ceres/internal/autodiff.h
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2019 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -30,10 +30,10 @@
//
// Computation of the Jacobian matrix for vector-valued functions of multiple
// variables, using automatic differentiation based on the implementation of
-// dual numbers in jet.h. Before reading the rest of this file, it is adivsable
+// dual numbers in jet.h. Before reading the rest of this file, it is advisable
// to read jet.h's header comment in detail.
//
-// The helper wrapper AutoDiff::Differentiate() computes the jacobian of
+// The helper wrapper AutoDifferentiate() computes the jacobian of
// functors with templated operator() taking this form:
//
// struct F {
@@ -57,7 +57,7 @@
// [ * ]
//
// Similar to the 2-parameter example for f described in jet.h, computing the
-// jacobian dy/dx is done by substutiting a suitable jet object for x and all
+// jacobian dy/dx is done by substituting a suitable jet object for x and all
// intermediate steps of the computation of F. Since x is has 4 dimensions, use
// a Jet<double, 4>.
//
@@ -142,16 +142,33 @@
#include <stddef.h>
-#include "ceres/jet.h"
+#include <array>
+#include <utility>
+
+#include "ceres/internal/array_selector.h"
#include "ceres/internal/eigen.h"
#include "ceres/internal/fixed_array.h"
+#include "ceres/internal/parameter_dims.h"
#include "ceres/internal/variadic_evaluate.h"
+#include "ceres/jet.h"
+#include "ceres/types.h"
#include "glog/logging.h"
+// If the number of parameters exceeds this values, the corresponding jets are
+// placed on the heap. This will reduce performance by a factor of 2-5 on
+// current compilers.
+#ifndef CERES_AUTODIFF_MAX_PARAMETERS_ON_STACK
+#define CERES_AUTODIFF_MAX_PARAMETERS_ON_STACK 50
+#endif
+
+#ifndef CERES_AUTODIFF_MAX_RESIDUALS_ON_STACK
+#define CERES_AUTODIFF_MAX_RESIDUALS_ON_STACK 20
+#endif
+
namespace ceres {
namespace internal {
-// Extends src by a 1st order pertubation for every dimension and puts it in
+// Extends src by a 1st order perturbation for every dimension and puts it in
// dst. The size of src is N. Since this is also used for perturbations in
// blocked arrays, offset is used to shift which part of the jet the
// perturbation occurs. This is used to set up the extended x augmented by an
@@ -165,21 +182,62 @@ namespace internal {
//
// is what would get put in dst if N was 3, offset was 3, and the jet type JetT
// was 8-dimensional.
-template <typename JetT, typename T, int N>
-inline void Make1stOrderPerturbation(int offset, const T* src, JetT* dst) {
- DCHECK(src);
- DCHECK(dst);
- for (int j = 0; j < N; ++j) {
- dst[j].a = src[j];
- dst[j].v.setZero();
- dst[j].v[offset + j] = T(1.0);
+template <int j, int N, int Offset, typename T, typename JetT>
+struct Make1stOrderPerturbation {
+ public:
+ inline static void Apply(const T* src, JetT* dst) {
+ if (j == 0) {
+ DCHECK(src);
+ DCHECK(dst);
+ }
+ dst[j] = JetT(src[j], j + Offset);
+ Make1stOrderPerturbation<j + 1, N, Offset, T, JetT>::Apply(src, dst);
}
-}
+};
+
+template <int N, int Offset, typename T, typename JetT>
+struct Make1stOrderPerturbation<N, N, Offset, T, JetT> {
+ public:
+ static void Apply(const T* /*src*/, JetT* /*dst*/) {}
+};
+
+// Calls Make1stOrderPerturbation for every parameter block.
+//
+// Example:
+// If one having three parameter blocks with dimensions (3, 2, 4), the call
+// Make1stOrderPerturbations<integer_sequence<3, 2, 4>::Apply(params, x);
+// will result in the following calls to Make1stOrderPerturbation:
+// Make1stOrderPerturbation<0, 3, 0>::Apply(params[0], x + 0);
+// Make1stOrderPerturbation<0, 2, 3>::Apply(params[1], x + 3);
+// Make1stOrderPerturbation<0, 4, 5>::Apply(params[2], x + 5);
+template <typename Seq, int ParameterIdx = 0, int Offset = 0>
+struct Make1stOrderPerturbations;
+
+template <int N, int... Ns, int ParameterIdx, int Offset>
+struct Make1stOrderPerturbations<std::integer_sequence<int, N, Ns...>,
+ ParameterIdx,
+ Offset> {
+ template <typename T, typename JetT>
+ inline static void Apply(T const* const* parameters, JetT* x) {
+ Make1stOrderPerturbation<0, N, Offset, T, JetT>::Apply(
+ parameters[ParameterIdx], x + Offset);
+ Make1stOrderPerturbations<std::integer_sequence<int, Ns...>,
+ ParameterIdx + 1,
+ Offset + N>::Apply(parameters, x);
+ }
+};
+
+// End of 'recursion'. Nothing more to do.
+template <int ParameterIdx, int Total>
+struct Make1stOrderPerturbations<std::integer_sequence<int>, ParameterIdx, Total> {
+ template <typename T, typename JetT>
+ static void Apply(T const* const* /* NOT USED */, JetT* /* NOT USED */) {}
+};
// Takes the 0th order part of src, assumed to be a Jet type, and puts it in
// dst. This is used to pick out the "vector" part of the extended y.
template <typename JetT, typename T>
-inline void Take0thOrderPart(int M, const JetT *src, T dst) {
+inline void Take0thOrderPart(int M, const JetT* src, T dst) {
DCHECK(src);
for (int i = 0; i < M; ++i) {
dst[i] = src[i].a;
@@ -188,128 +246,117 @@ inline void Take0thOrderPart(int M, const JetT *src, T dst) {
// Takes N 1st order parts, starting at index N0, and puts them in the M x N
// matrix 'dst'. This is used to pick out the "matrix" parts of the extended y.
-template <typename JetT, typename T, int N0, int N>
-inline void Take1stOrderPart(const int M, const JetT *src, T *dst) {
+template <int N0, int N, typename JetT, typename T>
+inline void Take1stOrderPart(const int M, const JetT* src, T* dst) {
DCHECK(src);
DCHECK(dst);
for (int i = 0; i < M; ++i) {
- Eigen::Map<Eigen::Matrix<T, N, 1> >(dst + N * i, N) =
+ Eigen::Map<Eigen::Matrix<T, N, 1>>(dst + N * i, N) =
src[i].v.template segment<N>(N0);
}
}
-// This is in a struct because default template parameters on a
-// function are not supported in C++03 (though it is available in
-// C++0x). N0 through N5 are the dimension of the input arguments to
-// the user supplied functor.
-template <typename Functor, typename T,
- int N0 = 0, int N1 = 0, int N2 = 0, int N3 = 0, int N4 = 0,
- int N5 = 0, int N6 = 0, int N7 = 0, int N8 = 0, int N9 = 0>
-struct AutoDiff {
- static bool Differentiate(const Functor& functor,
- T const *const *parameters,
- int num_outputs,
- T *function_value,
- T **jacobians) {
- // This block breaks the 80 column rule to keep it somewhat readable.
- DCHECK_GT(num_outputs, 0);
- DCHECK((!N1 && !N2 && !N3 && !N4 && !N5 && !N6 && !N7 && !N8 && !N9) ||
- ((N1 > 0) && !N2 && !N3 && !N4 && !N5 && !N6 && !N7 && !N8 && !N9) ||
- ((N1 > 0) && (N2 > 0) && !N3 && !N4 && !N5 && !N6 && !N7 && !N8 && !N9) || // NOLINT
- ((N1 > 0) && (N2 > 0) && (N3 > 0) && !N4 && !N5 && !N6 && !N7 && !N8 && !N9) || // NOLINT
- ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && !N5 && !N6 && !N7 && !N8 && !N9) || // NOLINT
- ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && (N5 > 0) && !N6 && !N7 && !N8 && !N9) || // NOLINT
- ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && (N5 > 0) && (N6 > 0) && !N7 && !N8 && !N9) || // NOLINT
- ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && (N5 > 0) && (N6 > 0) && (N7 > 0) && !N8 && !N9) || // NOLINT
- ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && (N5 > 0) && (N6 > 0) && (N7 > 0) && (N8 > 0) && !N9) || // NOLINT
- ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && (N5 > 0) && (N6 > 0) && (N7 > 0) && (N8 > 0) && (N9 > 0))) // NOLINT
- << "Zero block cannot precede a non-zero block. Block sizes are "
- << "(ignore trailing 0s): " << N0 << ", " << N1 << ", " << N2 << ", "
- << N3 << ", " << N4 << ", " << N5 << ", " << N6 << ", " << N7 << ", "
- << N8 << ", " << N9;
+// Calls Take1stOrderPart for every parameter block.
+//
+// Example:
+// If one having three parameter blocks with dimensions (3, 2, 4), the call
+// Take1stOrderParts<integer_sequence<3, 2, 4>::Apply(num_outputs,
+// output,
+// jacobians);
+// will result in the following calls to Take1stOrderPart:
+// if (jacobians[0]) {
+// Take1stOrderPart<0, 3>(num_outputs, output, jacobians[0]);
+// }
+// if (jacobians[1]) {
+// Take1stOrderPart<3, 2>(num_outputs, output, jacobians[1]);
+// }
+// if (jacobians[2]) {
+// Take1stOrderPart<5, 4>(num_outputs, output, jacobians[2]);
+// }
+template <typename Seq, int ParameterIdx = 0, int Offset = 0>
+struct Take1stOrderParts;
- typedef Jet<T, N0 + N1 + N2 + N3 + N4 + N5 + N6 + N7 + N8 + N9> JetT;
- FixedArray<JetT, (256 * 7) / sizeof(JetT)> x(
- N0 + N1 + N2 + N3 + N4 + N5 + N6 + N7 + N8 + N9 + num_outputs);
+template <int N, int... Ns, int ParameterIdx, int Offset>
+struct Take1stOrderParts<std::integer_sequence<int, N, Ns...>,
+ ParameterIdx,
+ Offset> {
+ template <typename JetT, typename T>
+ inline static void Apply(int num_outputs, JetT* output, T** jacobians) {
+ if (jacobians[ParameterIdx]) {
+ Take1stOrderPart<Offset, N>(num_outputs, output, jacobians[ParameterIdx]);
+ }
+ Take1stOrderParts<std::integer_sequence<int, Ns...>,
+ ParameterIdx + 1,
+ Offset + N>::Apply(num_outputs, output, jacobians);
+ }
+};
- // These are the positions of the respective jets in the fixed array x.
- const int jet0 = 0;
- const int jet1 = N0;
- const int jet2 = N0 + N1;
- const int jet3 = N0 + N1 + N2;
- const int jet4 = N0 + N1 + N2 + N3;
- const int jet5 = N0 + N1 + N2 + N3 + N4;
- const int jet6 = N0 + N1 + N2 + N3 + N4 + N5;
- const int jet7 = N0 + N1 + N2 + N3 + N4 + N5 + N6;
- const int jet8 = N0 + N1 + N2 + N3 + N4 + N5 + N6 + N7;
- const int jet9 = N0 + N1 + N2 + N3 + N4 + N5 + N6 + N7 + N8;
+// End of 'recursion'. Nothing more to do.
+template <int ParameterIdx, int Offset>
+struct Take1stOrderParts<std::integer_sequence<int>, ParameterIdx, Offset> {
+ template <typename T, typename JetT>
+ static void Apply(int /* NOT USED*/,
+ JetT* /* NOT USED*/,
+ T** /* NOT USED */) {}
+};
- const JetT *unpacked_parameters[10] = {
- x.get() + jet0,
- x.get() + jet1,
- x.get() + jet2,
- x.get() + jet3,
- x.get() + jet4,
- x.get() + jet5,
- x.get() + jet6,
- x.get() + jet7,
- x.get() + jet8,
- x.get() + jet9,
- };
+template <int kNumResiduals,
+ typename ParameterDims,
+ typename Functor,
+ typename T>
+inline bool AutoDifferentiate(const Functor& functor,
+ T const* const* parameters,
+ int dynamic_num_outputs,
+ T* function_value,
+ T** jacobians) {
+ typedef Jet<T, ParameterDims::kNumParameters> JetT;
+ using Parameters = typename ParameterDims::Parameters;
- JetT* output = x.get() + N0 + N1 + N2 + N3 + N4 + N5 + N6 + N7 + N8 + N9;
+ if (kNumResiduals != DYNAMIC) {
+ DCHECK_EQ(kNumResiduals, dynamic_num_outputs);
+ }
-#define CERES_MAKE_1ST_ORDER_PERTURBATION(i) \
- if (N ## i) { \
- internal::Make1stOrderPerturbation<JetT, T, N ## i>( \
- jet ## i, \
- parameters[i], \
- x.get() + jet ## i); \
- }
- CERES_MAKE_1ST_ORDER_PERTURBATION(0);
- CERES_MAKE_1ST_ORDER_PERTURBATION(1);
- CERES_MAKE_1ST_ORDER_PERTURBATION(2);
- CERES_MAKE_1ST_ORDER_PERTURBATION(3);
- CERES_MAKE_1ST_ORDER_PERTURBATION(4);
- CERES_MAKE_1ST_ORDER_PERTURBATION(5);
- CERES_MAKE_1ST_ORDER_PERTURBATION(6);
- CERES_MAKE_1ST_ORDER_PERTURBATION(7);
- CERES_MAKE_1ST_ORDER_PERTURBATION(8);
- CERES_MAKE_1ST_ORDER_PERTURBATION(9);
-#undef CERES_MAKE_1ST_ORDER_PERTURBATION
+ ArraySelector<JetT,
+ ParameterDims::kNumParameters,
+ CERES_AUTODIFF_MAX_PARAMETERS_ON_STACK>
+ parameters_as_jets(ParameterDims::kNumParameters);
- if (!VariadicEvaluate<Functor, JetT,
- N0, N1, N2, N3, N4, N5, N6, N7, N8, N9>::Call(
- functor, unpacked_parameters, output)) {
- return false;
- }
+ // Pointers to the beginning of each parameter block
+ std::array<JetT*, ParameterDims::kNumParameterBlocks> unpacked_parameters =
+ ParameterDims::GetUnpackedParameters(parameters_as_jets.data());
- internal::Take0thOrderPart(num_outputs, output, function_value);
+ // If the number of residuals is fixed, we use the template argument as the
+ // number of outputs. Otherwise we use the num_outputs parameter. Note: The
+ // ?-operator here is compile-time evaluated, therefore num_outputs is also
+ // a compile-time constant for functors with fixed residuals.
+ const int num_outputs =
+ kNumResiduals == DYNAMIC ? dynamic_num_outputs : kNumResiduals;
+ DCHECK_GT(num_outputs, 0);
-#define CERES_TAKE_1ST_ORDER_PERTURBATION(i) \
- if (N ## i) { \
- if (jacobians[i]) { \
- internal::Take1stOrderPart<JetT, T, \
- jet ## i, \
- N ## i>(num_outputs, \
- output, \
- jacobians[i]); \
- } \
- }
- CERES_TAKE_1ST_ORDER_PERTURBATION(0);
- CERES_TAKE_1ST_ORDER_PERTURBATION(1);
- CERES_TAKE_1ST_ORDER_PERTURBATION(2);
- CERES_TAKE_1ST_ORDER_PERTURBATION(3);
- CERES_TAKE_1ST_ORDER_PERTURBATION(4);
- CERES_TAKE_1ST_ORDER_PERTURBATION(5);
- CERES_TAKE_1ST_ORDER_PERTURBATION(6);
- CERES_TAKE_1ST_ORDER_PERTURBATION(7);
- CERES_TAKE_1ST_ORDER_PERTURBATION(8);
- CERES_TAKE_1ST_ORDER_PERTURBATION(9);
-#undef CERES_TAKE_1ST_ORDER_PERTURBATION
- return true;
+ ArraySelector<JetT, kNumResiduals, CERES_AUTODIFF_MAX_RESIDUALS_ON_STACK>
+ residuals_as_jets(num_outputs);
+
+ // Invalidate the output Jets, so that we can detect if the user
+ // did not assign values to all of them.
+ for (int i = 0; i < num_outputs; ++i) {
+ residuals_as_jets[i].a = kImpossibleValue;
+ residuals_as_jets[i].v.setConstant(kImpossibleValue);
}
-};
+
+ Make1stOrderPerturbations<Parameters>::Apply(parameters,
+ parameters_as_jets.data());
+
+ if (!VariadicEvaluate<ParameterDims>(
+ functor, unpacked_parameters.data(), residuals_as_jets.data())) {
+ return false;
+ }
+
+ Take0thOrderPart(num_outputs, residuals_as_jets.data(), function_value);
+ Take1stOrderParts<Parameters>::Apply(
+ num_outputs, residuals_as_jets.data(), jacobians);
+
+ return true;
+}
} // namespace internal
} // namespace ceres
diff --git a/extern/ceres/include/ceres/internal/disable_warnings.h b/extern/ceres/include/ceres/internal/disable_warnings.h
index 094124f7159..fd848feec0f 100644
--- a/extern/ceres/include/ceres/internal/disable_warnings.h
+++ b/extern/ceres/include/ceres/internal/disable_warnings.h
@@ -35,7 +35,7 @@
#ifdef _MSC_VER
#pragma warning( push )
-// Disable the warning C4251 which is trigerred by stl classes in
+// Disable the warning C4251 which is triggered by stl classes in
// Ceres' public interface. To quote MSDN: "C4251 can be ignored "
// "if you are deriving from a type in the Standard C++ Library"
#pragma warning( disable : 4251 )
diff --git a/extern/ceres/include/ceres/internal/eigen.h b/extern/ceres/include/ceres/internal/eigen.h
index 7138804ace4..59545dfd9c9 100644
--- a/extern/ceres/include/ceres/internal/eigen.h
+++ b/extern/ceres/include/ceres/internal/eigen.h
@@ -52,40 +52,27 @@ typedef Eigen::Matrix<double,
Eigen::ColMajor> ColMajorMatrix;
typedef Eigen::Map<ColMajorMatrix, 0,
- Eigen::Stride<Eigen::Dynamic, 1> > ColMajorMatrixRef;
+ Eigen::Stride<Eigen::Dynamic, 1>> ColMajorMatrixRef;
typedef Eigen::Map<const ColMajorMatrix,
0,
- Eigen::Stride<Eigen::Dynamic, 1> > ConstColMajorMatrixRef;
-
-
+ Eigen::Stride<Eigen::Dynamic, 1>> ConstColMajorMatrixRef;
// C++ does not support templated typdefs, thus the need for this
// struct so that we can support statically sized Matrix and Maps.
-template <int num_rows = Eigen::Dynamic, int num_cols = Eigen::Dynamic>
+ template <int num_rows = Eigen::Dynamic, int num_cols = Eigen::Dynamic>
struct EigenTypes {
- typedef Eigen::Matrix <double, num_rows, num_cols, Eigen::RowMajor>
- Matrix;
-
- typedef Eigen::Map<
- Eigen::Matrix<double, num_rows, num_cols, Eigen::RowMajor> >
- MatrixRef;
-
- typedef Eigen::Matrix <double, num_rows, 1>
- Vector;
-
- typedef Eigen::Map <
- Eigen::Matrix<double, num_rows, 1> >
- VectorRef;
-
-
- typedef Eigen::Map<
- const Eigen::Matrix<double, num_rows, num_cols, Eigen::RowMajor> >
- ConstMatrixRef;
-
- typedef Eigen::Map <
- const Eigen::Matrix<double, num_rows, 1> >
- ConstVectorRef;
+ typedef Eigen::Matrix<double,
+ num_rows,
+ num_cols,
+ num_cols == 1 ? Eigen::ColMajor : Eigen::RowMajor>
+ Matrix;
+
+ typedef Eigen::Map<Matrix> MatrixRef;
+ typedef Eigen::Map<const Matrix> ConstMatrixRef;
+ typedef Eigen::Matrix<double, num_rows, 1> Vector;
+ typedef Eigen::Map<Eigen::Matrix<double, num_rows, 1>> VectorRef;
+ typedef Eigen::Map<const Eigen::Matrix<double, num_rows, 1>> ConstVectorRef;
};
} // namespace ceres
diff --git a/extern/ceres/include/ceres/internal/fixed_array.h b/extern/ceres/include/ceres/internal/fixed_array.h
index 387298c58d0..f8ef02d40e8 100644
--- a/extern/ceres/include/ceres/internal/fixed_array.h
+++ b/extern/ceres/include/ceres/internal/fixed_array.h
@@ -1,189 +1,466 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
-// http://ceres-solver.org/
+// Copyright 2018 The Abseil Authors.
//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
//
-// * 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.
+// https://www.apache.org/licenses/LICENSE-2.0
//
-// 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.
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
//
-// Author: rennie@google.com (Jeffrey Rennie)
-// Author: sanjay@google.com (Sanjay Ghemawat) -- renamed to FixedArray
+// -----------------------------------------------------------------------------
+// File: fixed_array.h
+// -----------------------------------------------------------------------------
+//
+// A `FixedArray<T>` represents a non-resizable array of `T` where the length of
+// the array can be determined at run-time. It is a good replacement for
+// non-standard and deprecated uses of `alloca()` and variable length arrays
+// within the GCC extension. (See
+// https://gcc.gnu.org/onlinedocs/gcc/Variable-Length.html).
+//
+// `FixedArray` allocates small arrays inline, keeping performance fast by
+// avoiding heap operations. It also helps reduce the chances of
+// accidentally overflowing your stack if large input is passed to
+// your function.
#ifndef CERES_PUBLIC_INTERNAL_FIXED_ARRAY_H_
#define CERES_PUBLIC_INTERNAL_FIXED_ARRAY_H_
+#include <algorithm>
+#include <array>
#include <cstddef>
-#include "Eigen/Core"
-#include "ceres/internal/macros.h"
-#include "ceres/internal/manual_constructor.h"
+#include <memory>
+#include <tuple>
+#include <type_traits>
+
+#include <Eigen/Core> // For Eigen::aligned_allocator
+
+#include "ceres/internal/memory.h"
#include "glog/logging.h"
namespace ceres {
namespace internal {
-// A FixedArray<T> represents a non-resizable array of T where the
-// length of the array does not need to be a compile time constant.
-//
-// FixedArray allocates small arrays inline, and large arrays on
-// the heap. It is a good replacement for non-standard and deprecated
-// uses of alloca() and variable length arrays (a GCC extension).
-//
-// FixedArray keeps performance fast for small arrays, because it
-// avoids heap operations. It also helps reduce the chances of
-// accidentally overflowing your stack if large input is passed to
-// your function.
+constexpr static auto kFixedArrayUseDefault = static_cast<size_t>(-1);
+
+// The default fixed array allocator.
//
-// Also, FixedArray is useful for writing portable code. Not all
-// compilers support arrays of dynamic size.
+// As one can not easily detect if a struct contains or inherits from a fixed
+// size Eigen type, to be safe the Eigen::aligned_allocator is used by default.
+// But trivial types can never contain Eigen types, so std::allocator is used to
+// safe some heap memory.
+template <typename T>
+using FixedArrayDefaultAllocator =
+ typename std::conditional<std::is_trivial<T>::value,
+ std::allocator<T>,
+ Eigen::aligned_allocator<T>>::type;
-// Most users should not specify an inline_elements argument and let
-// FixedArray<> automatically determine the number of elements
-// to store inline based on sizeof(T).
+// -----------------------------------------------------------------------------
+// FixedArray
+// -----------------------------------------------------------------------------
+//
+// A `FixedArray` provides a run-time fixed-size array, allocating a small array
+// inline for efficiency.
//
-// If inline_elements is specified, the FixedArray<> implementation
-// will store arrays of length <= inline_elements inline.
+// Most users should not specify an `inline_elements` argument and let
+// `FixedArray` automatically determine the number of elements
+// to store inline based on `sizeof(T)`. If `inline_elements` is specified, the
+// `FixedArray` implementation will use inline storage for arrays with a
+// length <= `inline_elements`.
//
-// Finally note that unlike vector<T> FixedArray<T> will not zero-initialize
-// simple types like int, double, bool, etc.
+// Note that a `FixedArray` constructed with a `size_type` argument will
+// default-initialize its values by leaving trivially constructible types
+// uninitialized (e.g. int, int[4], double), and others default-constructed.
+// This matches the behavior of c-style arrays and `std::array`, but not
+// `std::vector`.
//
-// Non-POD types will be default-initialized just like regular vectors or
-// arrays.
+// Note that `FixedArray` does not provide a public allocator; if it requires a
+// heap allocation, it will do so with global `::operator new[]()` and
+// `::operator delete[]()`, even if T provides class-scope overrides for these
+// operators.
+template <typename T,
+ size_t N = kFixedArrayUseDefault,
+ typename A = FixedArrayDefaultAllocator<T>>
+class FixedArray {
+ static_assert(!std::is_array<T>::value || std::extent<T>::value > 0,
+ "Arrays with unknown bounds cannot be used with FixedArray.");
-#if defined(_WIN64)
- typedef __int64 ssize_t;
-#elif defined(_WIN32)
- typedef __int32 ssize_t;
-#endif
+ static constexpr size_t kInlineBytesDefault = 256;
+
+ using AllocatorTraits = std::allocator_traits<A>;
+ // std::iterator_traits isn't guaranteed to be SFINAE-friendly until C++17,
+ // but this seems to be mostly pedantic.
+ template <typename Iterator>
+ using EnableIfForwardIterator = typename std::enable_if<std::is_convertible<
+ typename std::iterator_traits<Iterator>::iterator_category,
+ std::forward_iterator_tag>::value>::type;
+ static constexpr bool DefaultConstructorIsNonTrivial() {
+ return !std::is_trivially_default_constructible<StorageElement>::value;
+ }
-template <typename T, ssize_t inline_elements = -1>
-class FixedArray {
public:
- // For playing nicely with stl:
- typedef T value_type;
- typedef T* iterator;
- typedef T const* const_iterator;
- typedef T& reference;
- typedef T const& const_reference;
- typedef T* pointer;
- typedef std::ptrdiff_t difference_type;
- typedef size_t size_type;
-
- // REQUIRES: n >= 0
- // Creates an array object that can store "n" elements.
- //
- // FixedArray<T> will not zero-initialiaze POD (simple) types like int,
- // double, bool, etc.
- // Non-POD types will be default-initialized just like regular vectors or
- // arrays.
- explicit FixedArray(size_type n);
-
- // Releases any resources.
- ~FixedArray();
-
- // Returns the length of the array.
- inline size_type size() const { return size_; }
-
- // Returns the memory size of the array in bytes.
- inline size_t memsize() const { return size_ * sizeof(T); }
-
- // Returns a pointer to the underlying element array.
- inline const T* get() const { return &array_[0].element; }
- inline T* get() { return &array_[0].element; }
+ using allocator_type = typename AllocatorTraits::allocator_type;
+ using value_type = typename AllocatorTraits::value_type;
+ using pointer = typename AllocatorTraits::pointer;
+ using const_pointer = typename AllocatorTraits::const_pointer;
+ using reference = value_type&;
+ using const_reference = const value_type&;
+ using size_type = typename AllocatorTraits::size_type;
+ using difference_type = typename AllocatorTraits::difference_type;
+ using iterator = pointer;
+ using const_iterator = const_pointer;
+ using reverse_iterator = std::reverse_iterator<iterator>;
+ using const_reverse_iterator = std::reverse_iterator<const_iterator>;
+
+ static constexpr size_type inline_elements =
+ (N == kFixedArrayUseDefault ? kInlineBytesDefault / sizeof(value_type)
+ : static_cast<size_type>(N));
+
+ FixedArray(const FixedArray& other,
+ const allocator_type& a = allocator_type())
+ : FixedArray(other.begin(), other.end(), a) {}
+
+ FixedArray(FixedArray&& other, const allocator_type& a = allocator_type())
+ : FixedArray(std::make_move_iterator(other.begin()),
+ std::make_move_iterator(other.end()),
+ a) {}
+
+ // Creates an array object that can store `n` elements.
+ // Note that trivially constructible elements will be uninitialized.
+ explicit FixedArray(size_type n, const allocator_type& a = allocator_type())
+ : storage_(n, a) {
+ if (DefaultConstructorIsNonTrivial()) {
+ ConstructRange(storage_.alloc(), storage_.begin(), storage_.end());
+ }
+ }
+ // Creates an array initialized with `n` copies of `val`.
+ FixedArray(size_type n,
+ const value_type& val,
+ const allocator_type& a = allocator_type())
+ : storage_(n, a) {
+ ConstructRange(storage_.alloc(), storage_.begin(), storage_.end(), val);
+ }
+
+ // Creates an array initialized with the size and contents of `init_list`.
+ FixedArray(std::initializer_list<value_type> init_list,
+ const allocator_type& a = allocator_type())
+ : FixedArray(init_list.begin(), init_list.end(), a) {}
+
+ // Creates an array initialized with the elements from the input
+ // range. The array's size will always be `std::distance(first, last)`.
+ // REQUIRES: Iterator must be a forward_iterator or better.
+ template <typename Iterator, EnableIfForwardIterator<Iterator>* = nullptr>
+ FixedArray(Iterator first,
+ Iterator last,
+ const allocator_type& a = allocator_type())
+ : storage_(std::distance(first, last), a) {
+ CopyRange(storage_.alloc(), storage_.begin(), first, last);
+ }
+
+ ~FixedArray() noexcept {
+ for (auto* cur = storage_.begin(); cur != storage_.end(); ++cur) {
+ AllocatorTraits::destroy(storage_.alloc(), cur);
+ }
+ }
+
+ // Assignments are deleted because they break the invariant that the size of a
+ // `FixedArray` never changes.
+ void operator=(FixedArray&&) = delete;
+ void operator=(const FixedArray&) = delete;
+
+ // FixedArray::size()
+ //
+ // Returns the length of the fixed array.
+ size_type size() const { return storage_.size(); }
+
+ // FixedArray::max_size()
+ //
+ // Returns the largest possible value of `std::distance(begin(), end())` for a
+ // `FixedArray<T>`. This is equivalent to the most possible addressable bytes
+ // over the number of bytes taken by T.
+ constexpr size_type max_size() const {
+ return (std::numeric_limits<difference_type>::max)() / sizeof(value_type);
+ }
+
+ // FixedArray::empty()
+ //
+ // Returns whether or not the fixed array is empty.
+ bool empty() const { return size() == 0; }
+
+ // FixedArray::memsize()
+ //
+ // Returns the memory size of the fixed array in bytes.
+ size_t memsize() const { return size() * sizeof(value_type); }
+
+ // FixedArray::data()
+ //
+ // Returns a const T* pointer to elements of the `FixedArray`. This pointer
+ // can be used to access (but not modify) the contained elements.
+ const_pointer data() const { return AsValueType(storage_.begin()); }
+
+ // Overload of FixedArray::data() to return a T* pointer to elements of the
+ // fixed array. This pointer can be used to access and modify the contained
+ // elements.
+ pointer data() { return AsValueType(storage_.begin()); }
+
+ // FixedArray::operator[]
+ //
+ // Returns a reference the ith element of the fixed array.
// REQUIRES: 0 <= i < size()
- // Returns a reference to the "i"th element.
- inline T& operator[](size_type i) {
- DCHECK_LT(i, size_);
- return array_[i].element;
+ reference operator[](size_type i) {
+ DCHECK_LT(i, size());
+ return data()[i];
}
+ // Overload of FixedArray::operator()[] to return a const reference to the
+ // ith element of the fixed array.
// REQUIRES: 0 <= i < size()
- // Returns a reference to the "i"th element.
- inline const T& operator[](size_type i) const {
- DCHECK_LT(i, size_);
- return array_[i].element;
+ const_reference operator[](size_type i) const {
+ DCHECK_LT(i, size());
+ return data()[i];
+ }
+
+ // FixedArray::front()
+ //
+ // Returns a reference to the first element of the fixed array.
+ reference front() { return *begin(); }
+
+ // Overload of FixedArray::front() to return a reference to the first element
+ // of a fixed array of const values.
+ const_reference front() const { return *begin(); }
+
+ // FixedArray::back()
+ //
+ // Returns a reference to the last element of the fixed array.
+ reference back() { return *(end() - 1); }
+
+ // Overload of FixedArray::back() to return a reference to the last element
+ // of a fixed array of const values.
+ const_reference back() const { return *(end() - 1); }
+
+ // FixedArray::begin()
+ //
+ // Returns an iterator to the beginning of the fixed array.
+ iterator begin() { return data(); }
+
+ // Overload of FixedArray::begin() to return a const iterator to the
+ // beginning of the fixed array.
+ const_iterator begin() const { return data(); }
+
+ // FixedArray::cbegin()
+ //
+ // Returns a const iterator to the beginning of the fixed array.
+ const_iterator cbegin() const { return begin(); }
+
+ // FixedArray::end()
+ //
+ // Returns an iterator to the end of the fixed array.
+ iterator end() { return data() + size(); }
+
+ // Overload of FixedArray::end() to return a const iterator to the end of the
+ // fixed array.
+ const_iterator end() const { return data() + size(); }
+
+ // FixedArray::cend()
+ //
+ // Returns a const iterator to the end of the fixed array.
+ const_iterator cend() const { return end(); }
+
+ // FixedArray::rbegin()
+ //
+ // Returns a reverse iterator from the end of the fixed array.
+ reverse_iterator rbegin() { return reverse_iterator(end()); }
+
+ // Overload of FixedArray::rbegin() to return a const reverse iterator from
+ // the end of the fixed array.
+ const_reverse_iterator rbegin() const {
+ return const_reverse_iterator(end());
}
- inline iterator begin() { return &array_[0].element; }
- inline iterator end() { return &array_[size_].element; }
+ // FixedArray::crbegin()
+ //
+ // Returns a const reverse iterator from the end of the fixed array.
+ const_reverse_iterator crbegin() const { return rbegin(); }
- inline const_iterator begin() const { return &array_[0].element; }
- inline const_iterator end() const { return &array_[size_].element; }
+ // FixedArray::rend()
+ //
+ // Returns a reverse iterator from the beginning of the fixed array.
+ reverse_iterator rend() { return reverse_iterator(begin()); }
+
+ // Overload of FixedArray::rend() for returning a const reverse iterator
+ // from the beginning of the fixed array.
+ const_reverse_iterator rend() const {
+ return const_reverse_iterator(begin());
+ }
+
+ // FixedArray::crend()
+ //
+ // Returns a reverse iterator from the beginning of the fixed array.
+ const_reverse_iterator crend() const { return rend(); }
+
+ // FixedArray::fill()
+ //
+ // Assigns the given `value` to all elements in the fixed array.
+ void fill(const value_type& val) { std::fill(begin(), end(), val); }
+
+ // Relational operators. Equality operators are elementwise using
+ // `operator==`, while order operators order FixedArrays lexicographically.
+ friend bool operator==(const FixedArray& lhs, const FixedArray& rhs) {
+ return std::equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
+ }
+
+ friend bool operator!=(const FixedArray& lhs, const FixedArray& rhs) {
+ return !(lhs == rhs);
+ }
+
+ friend bool operator<(const FixedArray& lhs, const FixedArray& rhs) {
+ return std::lexicographical_compare(
+ lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
+ }
+
+ friend bool operator>(const FixedArray& lhs, const FixedArray& rhs) {
+ return rhs < lhs;
+ }
+
+ friend bool operator<=(const FixedArray& lhs, const FixedArray& rhs) {
+ return !(rhs < lhs);
+ }
+
+ friend bool operator>=(const FixedArray& lhs, const FixedArray& rhs) {
+ return !(lhs < rhs);
+ }
private:
- // Container to hold elements of type T. This is necessary to handle
- // the case where T is a a (C-style) array. The size of InnerContainer
- // and T must be the same, otherwise callers' assumptions about use
- // of this code will be broken.
- struct InnerContainer {
- T element;
+ // StorageElement
+ //
+ // For FixedArrays with a C-style-array value_type, StorageElement is a POD
+ // wrapper struct called StorageElementWrapper that holds the value_type
+ // instance inside. This is needed for construction and destruction of the
+ // entire array regardless of how many dimensions it has. For all other cases,
+ // StorageElement is just an alias of value_type.
+ //
+ // Maintainer's Note: The simpler solution would be to simply wrap value_type
+ // in a struct whether it's an array or not. That causes some paranoid
+ // diagnostics to misfire, believing that 'data()' returns a pointer to a
+ // single element, rather than the packed array that it really is.
+ // e.g.:
+ //
+ // FixedArray<char> buf(1);
+ // sprintf(buf.data(), "foo");
+ //
+ // error: call to int __builtin___sprintf_chk(etc...)
+ // will always overflow destination buffer [-Werror]
+ //
+ template <typename OuterT,
+ typename InnerT = typename std::remove_extent<OuterT>::type,
+ size_t InnerN = std::extent<OuterT>::value>
+ struct StorageElementWrapper {
+ InnerT array[InnerN];
};
- // How many elements should we store inline?
- // a. If not specified, use a default of 256 bytes (256 bytes
- // seems small enough to not cause stack overflow or unnecessary
- // stack pollution, while still allowing stack allocation for
- // reasonably long character arrays.
- // b. Never use 0 length arrays (not ISO C++)
- static const size_type S1 = ((inline_elements < 0)
- ? (256/sizeof(T)) : inline_elements);
- static const size_type S2 = (S1 <= 0) ? 1 : S1;
- static const size_type kInlineElements = S2;
-
- size_type const size_;
- InnerContainer* const array_;
-
- // Allocate some space, not an array of elements of type T, so that we can
- // skip calling the T constructors and destructors for space we never use.
- ManualConstructor<InnerContainer> inline_space_[kInlineElements];
-};
+ using StorageElement =
+ typename std::conditional<std::is_array<value_type>::value,
+ StorageElementWrapper<value_type>,
+ value_type>::type;
-// Implementation details follow
-
-template <class T, ssize_t S>
-inline FixedArray<T, S>::FixedArray(typename FixedArray<T, S>::size_type n)
- : size_(n),
- array_((n <= kInlineElements
- ? reinterpret_cast<InnerContainer*>(inline_space_)
- : new InnerContainer[n])) {
- // Construct only the elements actually used.
- if (array_ == reinterpret_cast<InnerContainer*>(inline_space_)) {
- for (size_t i = 0; i != size_; ++i) {
- inline_space_[i].Init();
- }
+ static pointer AsValueType(pointer ptr) { return ptr; }
+ static pointer AsValueType(StorageElementWrapper<value_type>* ptr) {
+ return std::addressof(ptr->array);
}
-}
-template <class T, ssize_t S>
-inline FixedArray<T, S>::~FixedArray() {
- if (array_ != reinterpret_cast<InnerContainer*>(inline_space_)) {
- delete[] array_;
- } else {
- for (size_t i = 0; i != size_; ++i) {
- inline_space_[i].Destroy();
+ static_assert(sizeof(StorageElement) == sizeof(value_type), "");
+ static_assert(alignof(StorageElement) == alignof(value_type), "");
+
+ class NonEmptyInlinedStorage {
+ public:
+ StorageElement* data() { return reinterpret_cast<StorageElement*>(buff_); }
+ void AnnotateConstruct(size_type) {}
+ void AnnotateDestruct(size_type) {}
+
+ // #ifdef ADDRESS_SANITIZER
+ // void* RedzoneBegin() { return &redzone_begin_; }
+ // void* RedzoneEnd() { return &redzone_end_ + 1; }
+ // #endif // ADDRESS_SANITIZER
+
+ private:
+ // ADDRESS_SANITIZER_REDZONE(redzone_begin_);
+ alignas(StorageElement) char buff_[sizeof(StorageElement[inline_elements])];
+ // ADDRESS_SANITIZER_REDZONE(redzone_end_);
+ };
+
+ class EmptyInlinedStorage {
+ public:
+ StorageElement* data() { return nullptr; }
+ void AnnotateConstruct(size_type) {}
+ void AnnotateDestruct(size_type) {}
+ };
+
+ using InlinedStorage =
+ typename std::conditional<inline_elements == 0,
+ EmptyInlinedStorage,
+ NonEmptyInlinedStorage>::type;
+
+ // Storage
+ //
+ // An instance of Storage manages the inline and out-of-line memory for
+ // instances of FixedArray. This guarantees that even when construction of
+ // individual elements fails in the FixedArray constructor body, the
+ // destructor for Storage will still be called and out-of-line memory will be
+ // properly deallocated.
+ //
+ class Storage : public InlinedStorage {
+ public:
+ Storage(size_type n, const allocator_type& a)
+ : size_alloc_(n, a), data_(InitializeData()) {}
+
+ ~Storage() noexcept {
+ if (UsingInlinedStorage(size())) {
+ InlinedStorage::AnnotateDestruct(size());
+ } else {
+ AllocatorTraits::deallocate(alloc(), AsValueType(begin()), size());
+ }
}
- }
-}
+
+ size_type size() const { return std::get<0>(size_alloc_); }
+ StorageElement* begin() const { return data_; }
+ StorageElement* end() const { return begin() + size(); }
+ allocator_type& alloc() { return std::get<1>(size_alloc_); }
+
+ private:
+ static bool UsingInlinedStorage(size_type n) {
+ return n <= inline_elements;
+ }
+
+ StorageElement* InitializeData() {
+ if (UsingInlinedStorage(size())) {
+ InlinedStorage::AnnotateConstruct(size());
+ return InlinedStorage::data();
+ } else {
+ return reinterpret_cast<StorageElement*>(
+ AllocatorTraits::allocate(alloc(), size()));
+ }
+ }
+
+ // Using std::tuple and not absl::CompressedTuple, as it has a lot of
+ // dependencies to other absl headers.
+ std::tuple<size_type, allocator_type> size_alloc_;
+ StorageElement* data_;
+ };
+
+ Storage storage_;
+};
+
+template <typename T, size_t N, typename A>
+constexpr size_t FixedArray<T, N, A>::kInlineBytesDefault;
+
+template <typename T, size_t N, typename A>
+constexpr typename FixedArray<T, N, A>::size_type
+ FixedArray<T, N, A>::inline_elements;
} // namespace internal
} // namespace ceres
diff --git a/extern/ceres/internal/ceres/householder_vector.h b/extern/ceres/include/ceres/internal/householder_vector.h
index f54feea054d..55f68e526a0 100644
--- a/extern/ceres/internal/ceres/householder_vector.h
+++ b/extern/ceres/include/ceres/internal/householder_vector.h
@@ -28,8 +28,8 @@
//
// Author: vitus@google.com (Michael Vitus)
-#ifndef CERES_PUBLIC_HOUSEHOLDER_VECTOR_H_
-#define CERES_PUBLIC_HOUSEHOLDER_VECTOR_H_
+#ifndef CERES_PUBLIC_INTERNAL_HOUSEHOLDER_VECTOR_H_
+#define CERES_PUBLIC_INTERNAL_HOUSEHOLDER_VECTOR_H_
#include "Eigen/Core"
#include "glog/logging.h"
@@ -42,12 +42,15 @@ namespace internal {
// vector as pivot instead of first. This computes the vector v with v(n) = 1
// and beta such that H = I - beta * v * v^T is orthogonal and
// H * x = ||x||_2 * e_n.
-template <typename Scalar>
-void ComputeHouseholderVector(const Eigen::Matrix<Scalar, Eigen::Dynamic, 1>& x,
- Eigen::Matrix<Scalar, Eigen::Dynamic, 1>* v,
+//
+// NOTE: Some versions of MSVC have trouble deducing the type of v if
+// you do not specify all the template arguments explicitly.
+template <typename XVectorType, typename Scalar, int N>
+void ComputeHouseholderVector(const XVectorType& x,
+ Eigen::Matrix<Scalar, N, 1>* v,
Scalar* beta) {
- CHECK_NOTNULL(beta);
- CHECK_NOTNULL(v);
+ CHECK(beta != nullptr);
+ CHECK(v != nullptr);
CHECK_GT(x.rows(), 1);
CHECK_EQ(x.rows(), v->rows());
@@ -82,4 +85,4 @@ void ComputeHouseholderVector(const Eigen::Matrix<Scalar, Eigen::Dynamic, 1>& x,
} // namespace internal
} // namespace ceres
-#endif // CERES_PUBLIC_HOUSEHOLDER_VECTOR_H_
+#endif // CERES_PUBLIC_INTERNAL_HOUSEHOLDER_VECTOR_H_
diff --git a/extern/ceres/include/ceres/internal/integer_sequence_algorithm.h b/extern/ceres/include/ceres/internal/integer_sequence_algorithm.h
new file mode 100644
index 00000000000..170acac2832
--- /dev/null
+++ b/extern/ceres/include/ceres/internal/integer_sequence_algorithm.h
@@ -0,0 +1,165 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2018 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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.
+//
+// Author: jodebo_beck@gmx.de (Johannes Beck)
+//
+// Algorithms to be used together with integer_sequence, like computing the sum
+// or the exclusive scan (sometimes called exclusive prefix sum) at compile
+// time.
+
+#ifndef CERES_PUBLIC_INTERNAL_INTEGER_SEQUENCE_ALGORITHM_H_
+#define CERES_PUBLIC_INTERNAL_INTEGER_SEQUENCE_ALGORITHM_H_
+
+#include <utility>
+
+namespace ceres {
+namespace internal {
+
+// Implementation of calculating the sum of an integer sequence.
+// Recursively instantiate SumImpl and calculate the sum of the N first
+// numbers. This reduces the number of instantiations and speeds up
+// compilation.
+//
+// Examples:
+// 1) integer_sequence<int, 5>:
+// Value = 5
+//
+// 2) integer_sequence<int, 4, 2>:
+// Value = 4 + 2 + SumImpl<integer_sequence<int>>::Value
+// Value = 4 + 2 + 0
+//
+// 3) integer_sequence<int, 2, 1, 4>:
+// Value = 2 + 1 + SumImpl<integer_sequence<int, 4>>::Value
+// Value = 2 + 1 + 4
+template <typename Seq>
+struct SumImpl;
+
+// Strip of and sum the first number.
+template <typename T, T N, T... Ns>
+struct SumImpl<std::integer_sequence<T, N, Ns...>> {
+ static constexpr T Value = N + SumImpl<std::integer_sequence<T, Ns...>>::Value;
+};
+
+// Strip of and sum the first two numbers.
+template <typename T, T N1, T N2, T... Ns>
+struct SumImpl<std::integer_sequence<T, N1, N2, Ns...>> {
+ static constexpr T Value =
+ N1 + N2 + SumImpl<std::integer_sequence<T, Ns...>>::Value;
+};
+
+// Strip of and sum the first four numbers.
+template <typename T, T N1, T N2, T N3, T N4, T... Ns>
+struct SumImpl<std::integer_sequence<T, N1, N2, N3, N4, Ns...>> {
+ static constexpr T Value =
+ N1 + N2 + N3 + N4 + SumImpl<std::integer_sequence<T, Ns...>>::Value;
+};
+
+// Only one number is left. 'Value' is just that number ('recursion' ends).
+template <typename T, T N>
+struct SumImpl<std::integer_sequence<T, N>> {
+ static constexpr T Value = N;
+};
+
+// No number is left. 'Value' is the identity element (for sum this is zero).
+template <typename T>
+struct SumImpl<std::integer_sequence<T>> {
+ static constexpr T Value = T(0);
+};
+
+// Calculate the sum of an integer sequence. The resulting sum will be stored in
+// 'Value'.
+template <typename Seq>
+class Sum {
+ using T = typename Seq::value_type;
+
+ public:
+ static constexpr T Value = SumImpl<Seq>::Value;
+};
+
+// Implementation of calculating an exclusive scan (exclusive prefix sum) of an
+// integer sequence. Exclusive means that the i-th input element is not included
+// in the i-th sum. Calculating the exclusive scan for an input array I results
+// in the following output R:
+//
+// R[0] = 0
+// R[1] = I[0];
+// R[2] = I[0] + I[1];
+// R[3] = I[0] + I[1] + I[2];
+// ...
+//
+// In C++17 std::exclusive_scan does the same operation at runtime (but
+// cannot be used to calculate the prefix sum at compile time). See
+// https://en.cppreference.com/w/cpp/algorithm/exclusive_scan for a more
+// detailed description.
+//
+// Example for integer_sequence<int, 1, 4, 3> (seq := integer_sequence):
+// T , Sum, Ns... , Rs...
+// ExclusiveScanImpl<int, 0, seq<int, 1, 4, 3>, seq<int >>
+// ExclusiveScanImpl<int, 1, seq<int, 4, 3>, seq<int, 0 >>
+// ExclusiveScanImpl<int, 5, seq<int, 3>, seq<int, 0, 1 >>
+// ExclusiveScanImpl<int, 8, seq<int >, seq<int, 0, 1, 5>>
+// ^^^^^^^^^^^^^^^^^
+// resulting sequence
+template <typename T, T Sum, typename SeqIn, typename SeqOut>
+struct ExclusiveScanImpl;
+
+template <typename T, T Sum, T N, T... Ns, T... Rs>
+struct ExclusiveScanImpl<T, Sum, std::integer_sequence<T, N, Ns...>,
+ std::integer_sequence<T, Rs...>> {
+ using Type =
+ typename ExclusiveScanImpl<T, Sum + N, std::integer_sequence<T, Ns...>,
+ std::integer_sequence<T, Rs..., Sum>>::Type;
+};
+
+// End of 'recursion'. The resulting type is SeqOut.
+template <typename T, T Sum, typename SeqOut>
+struct ExclusiveScanImpl<T, Sum, std::integer_sequence<T>, SeqOut> {
+ using Type = SeqOut;
+};
+
+// Calculates the exclusive scan of the specified integer sequence. The last
+// element (the total) is not included in the resulting sequence so they have
+// same length. This means the exclusive scan of integer_sequence<int, 1, 2, 3>
+// will be integer_sequence<int, 0, 1, 3>.
+template <typename Seq>
+class ExclusiveScanT {
+ using T = typename Seq::value_type;
+
+ public:
+ using Type =
+ typename ExclusiveScanImpl<T, T(0), Seq, std::integer_sequence<T>>::Type;
+};
+
+// Helper to use exclusive scan without typename.
+template <typename Seq>
+using ExclusiveScan = typename ExclusiveScanT<Seq>::Type;
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_PUBLIC_INTERNAL_INTEGER_SEQUENCE_ALGORITHM_H_
diff --git a/extern/ceres/include/ceres/internal/line_parameterization.h b/extern/ceres/include/ceres/internal/line_parameterization.h
new file mode 100644
index 00000000000..eda390148df
--- /dev/null
+++ b/extern/ceres/include/ceres/internal/line_parameterization.h
@@ -0,0 +1,183 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2020 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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.
+//
+// Author: jodebo_beck@gmx.de (Johannes Beck)
+//
+
+#ifndef CERES_PUBLIC_INTERNAL_LINE_PARAMETERIZATION_H_
+#define CERES_PUBLIC_INTERNAL_LINE_PARAMETERIZATION_H_
+
+#include "householder_vector.h"
+
+namespace ceres {
+
+template <int AmbientSpaceDimension>
+bool LineParameterization<AmbientSpaceDimension>::Plus(
+ const double* x_ptr,
+ const double* delta_ptr,
+ double* x_plus_delta_ptr) const {
+ // We seek a box plus operator of the form
+ //
+ // [o*, d*] = Plus([o, d], [delta_o, delta_d])
+ //
+ // where o is the origin point, d is the direction vector, delta_o is
+ // the delta of the origin point and delta_d the delta of the direction and
+ // o* and d* is the updated origin point and direction.
+ //
+ // We separate the Plus operator into the origin point and directional part
+ // d* = Plus_d(d, delta_d)
+ // o* = Plus_o(o, d, delta_o)
+ //
+ // The direction update function Plus_d is the same as for the homogeneous
+ // vector parameterization:
+ //
+ // d* = H_{v(d)} [0.5 sinc(0.5 |delta_d|) delta_d, cos(0.5 |delta_d|)]^T
+ //
+ // where H is the householder matrix
+ // H_{v} = I - (2 / |v|^2) v v^T
+ // and
+ // v(d) = d - sign(d_n) |d| e_n.
+ //
+ // The origin point update function Plus_o is defined as
+ //
+ // o* = o + H_{v(d)} [0.5 delta_o, 0]^T.
+
+ static constexpr int kDim = AmbientSpaceDimension;
+ using AmbientVector = Eigen::Matrix<double, kDim, 1>;
+ using AmbientVectorRef = Eigen::Map<Eigen::Matrix<double, kDim, 1>>;
+ using ConstAmbientVectorRef =
+ Eigen::Map<const Eigen::Matrix<double, kDim, 1>>;
+ using ConstTangentVectorRef =
+ Eigen::Map<const Eigen::Matrix<double, kDim - 1, 1>>;
+
+ ConstAmbientVectorRef o(x_ptr);
+ ConstAmbientVectorRef d(x_ptr + kDim);
+
+ ConstTangentVectorRef delta_o(delta_ptr);
+ ConstTangentVectorRef delta_d(delta_ptr + kDim - 1);
+ AmbientVectorRef o_plus_delta(x_plus_delta_ptr);
+ AmbientVectorRef d_plus_delta(x_plus_delta_ptr + kDim);
+
+ const double norm_delta_d = delta_d.norm();
+
+ o_plus_delta = o;
+
+ // Shortcut for zero delta direction.
+ if (norm_delta_d == 0.0) {
+ d_plus_delta = d;
+
+ if (delta_o.isZero(0.0)) {
+ return true;
+ }
+ }
+
+ // Calculate the householder transformation which is needed for f_d and f_o.
+ AmbientVector v;
+ double beta;
+
+ // NOTE: The explicit template arguments are needed here because
+ // ComputeHouseholderVector is templated and some versions of MSVC
+ // have trouble deducing the type of v automatically.
+ internal::ComputeHouseholderVector<ConstAmbientVectorRef, double, kDim>(
+ d, &v, &beta);
+
+ if (norm_delta_d != 0.0) {
+ // Map the delta from the minimum representation to the over parameterized
+ // homogeneous vector. See section A6.9.2 on page 624 of Hartley & Zisserman
+ // (2nd Edition) for a detailed description. Note there is a typo on Page
+ // 625, line 4 so check the book errata.
+ const double norm_delta_div_2 = 0.5 * norm_delta_d;
+ const double sin_delta_by_delta =
+ std::sin(norm_delta_div_2) / norm_delta_div_2;
+
+ // Apply the delta update to remain on the unit sphere. See section A6.9.3
+ // on page 625 of Hartley & Zisserman (2nd Edition) for a detailed
+ // description.
+ AmbientVector y;
+ y.template head<kDim - 1>() = 0.5 * sin_delta_by_delta * delta_d;
+ y[kDim - 1] = std::cos(norm_delta_div_2);
+
+ d_plus_delta = d.norm() * (y - v * (beta * (v.transpose() * y)));
+ }
+
+ // The null space is in the direction of the line, so the tangent space is
+ // perpendicular to the line direction. This is achieved by using the
+ // householder matrix of the direction and allow only movements
+ // perpendicular to e_n.
+ //
+ // The factor of 0.5 is used to be consistent with the line direction
+ // update.
+ AmbientVector y;
+ y << 0.5 * delta_o, 0;
+ o_plus_delta += y - v * (beta * (v.transpose() * y));
+
+ return true;
+}
+
+template <int AmbientSpaceDimension>
+bool LineParameterization<AmbientSpaceDimension>::ComputeJacobian(
+ const double* x_ptr, double* jacobian_ptr) const {
+ static constexpr int kDim = AmbientSpaceDimension;
+ using AmbientVector = Eigen::Matrix<double, kDim, 1>;
+ using ConstAmbientVectorRef =
+ Eigen::Map<const Eigen::Matrix<double, kDim, 1>>;
+ using MatrixRef = Eigen::Map<
+ Eigen::Matrix<double, 2 * kDim, 2 * (kDim - 1), Eigen::RowMajor>>;
+
+ ConstAmbientVectorRef d(x_ptr + kDim);
+ MatrixRef jacobian(jacobian_ptr);
+
+ // Clear the Jacobian as only half of the matrix is not zero.
+ jacobian.setZero();
+
+ AmbientVector v;
+ double beta;
+
+ // NOTE: The explicit template arguments are needed here because
+ // ComputeHouseholderVector is templated and some versions of MSVC
+ // have trouble deducing the type of v automatically.
+ internal::ComputeHouseholderVector<ConstAmbientVectorRef, double, kDim>(
+ d, &v, &beta);
+
+ // The Jacobian is equal to J = 0.5 * H.leftCols(kDim - 1) where H is
+ // the Householder matrix (H = I - beta * v * v') for the origin point. For
+ // the line direction part the Jacobian is scaled by the norm of the
+ // direction.
+ for (int i = 0; i < kDim - 1; ++i) {
+ jacobian.block(0, i, kDim, 1) = -0.5 * beta * v(i) * v;
+ jacobian.col(i)(i) += 0.5;
+ }
+
+ jacobian.template block<kDim, kDim - 1>(kDim, kDim - 1) =
+ jacobian.template block<kDim, kDim - 1>(0, 0) * d.norm();
+ return true;
+}
+
+} // namespace ceres
+
+#endif // CERES_PUBLIC_INTERNAL_LINE_PARAMETERIZATION_H_
diff --git a/extern/ceres/include/ceres/internal/macros.h b/extern/ceres/include/ceres/internal/macros.h
deleted file mode 100644
index bebb965e25b..00000000000
--- a/extern/ceres/include/ceres/internal/macros.h
+++ /dev/null
@@ -1,170 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
-// http://ceres-solver.org/
-//
-// 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.
-//
-//
-// Various Google-specific macros.
-//
-// This code is compiled directly on many platforms, including client
-// platforms like Windows, Mac, and embedded systems. Before making
-// any changes here, make sure that you're not breaking any platforms.
-
-#ifndef CERES_PUBLIC_INTERNAL_MACROS_H_
-#define CERES_PUBLIC_INTERNAL_MACROS_H_
-
-#include <cstddef> // For size_t.
-
-// A macro to disallow the copy constructor and operator= functions
-// This should be used in the private: declarations for a class
-//
-// For disallowing only assign or copy, write the code directly, but declare
-// the intend in a comment, for example:
-//
-// void operator=(const TypeName&); // _DISALLOW_ASSIGN
-
-// Note, that most uses of CERES_DISALLOW_ASSIGN and CERES_DISALLOW_COPY
-// are broken semantically, one should either use disallow both or
-// neither. Try to avoid these in new code.
-#define CERES_DISALLOW_COPY_AND_ASSIGN(TypeName) \
- TypeName(const TypeName&); \
- void operator=(const TypeName&)
-
-// A macro to disallow all the implicit constructors, namely the
-// default constructor, copy constructor and operator= functions.
-//
-// This should be used in the private: declarations for a class
-// that wants to prevent anyone from instantiating it. This is
-// especially useful for classes containing only static methods.
-#define CERES_DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \
- TypeName(); \
- CERES_DISALLOW_COPY_AND_ASSIGN(TypeName)
-
-// The arraysize(arr) macro returns the # of elements in an array arr.
-// The expression is a compile-time constant, and therefore can be
-// used in defining new arrays, for example. If you use arraysize on
-// a pointer by mistake, you will get a compile-time error.
-//
-// One caveat is that arraysize() doesn't accept any array of an
-// anonymous type or a type defined inside a function. In these rare
-// cases, you have to use the unsafe ARRAYSIZE() macro below. This is
-// due to a limitation in C++'s template system. The limitation might
-// eventually be removed, but it hasn't happened yet.
-
-// This template function declaration is used in defining arraysize.
-// Note that the function doesn't need an implementation, as we only
-// use its type.
-template <typename T, size_t N>
-char (&ArraySizeHelper(T (&array)[N]))[N];
-
-// That gcc wants both of these prototypes seems mysterious. VC, for
-// its part, can't decide which to use (another mystery). Matching of
-// template overloads: the final frontier.
-#ifndef _WIN32
-template <typename T, size_t N>
-char (&ArraySizeHelper(const T (&array)[N]))[N];
-#endif
-
-#define arraysize(array) (sizeof(ArraySizeHelper(array)))
-
-// ARRAYSIZE performs essentially the same calculation as arraysize,
-// but can be used on anonymous types or types defined inside
-// functions. It's less safe than arraysize as it accepts some
-// (although not all) pointers. Therefore, you should use arraysize
-// whenever possible.
-//
-// The expression ARRAYSIZE(a) is a compile-time constant of type
-// size_t.
-//
-// ARRAYSIZE catches a few type errors. If you see a compiler error
-//
-// "warning: division by zero in ..."
-//
-// when using ARRAYSIZE, you are (wrongfully) giving it a pointer.
-// You should only use ARRAYSIZE on statically allocated arrays.
-//
-// The following comments are on the implementation details, and can
-// be ignored by the users.
-//
-// ARRAYSIZE(arr) works by inspecting sizeof(arr) (the # of bytes in
-// the array) and sizeof(*(arr)) (the # of bytes in one array
-// element). If the former is divisible by the latter, perhaps arr is
-// indeed an array, in which case the division result is the # of
-// elements in the array. Otherwise, arr cannot possibly be an array,
-// and we generate a compiler error to prevent the code from
-// compiling.
-//
-// Since the size of bool is implementation-defined, we need to cast
-// !(sizeof(a) & sizeof(*(a))) to size_t in order to ensure the final
-// result has type size_t.
-//
-// This macro is not perfect as it wrongfully accepts certain
-// pointers, namely where the pointer size is divisible by the pointee
-// size. Since all our code has to go through a 32-bit compiler,
-// where a pointer is 4 bytes, this means all pointers to a type whose
-// size is 3 or greater than 4 will be (righteously) rejected.
-//
-// Kudos to Jorg Brown for this simple and elegant implementation.
-//
-// - wan 2005-11-16
-//
-// Starting with Visual C++ 2005, WinNT.h includes ARRAYSIZE. However,
-// the definition comes from the over-broad windows.h header that
-// introduces a macro, ERROR, that conflicts with the logging framework
-// that Ceres uses. Instead, rename ARRAYSIZE to CERES_ARRAYSIZE.
-#define CERES_ARRAYSIZE(a) \
- ((sizeof(a) / sizeof(*(a))) / \
- static_cast<size_t>(!(sizeof(a) % sizeof(*(a)))))
-
-// Tell the compiler to warn about unused return values for functions
-// declared with this macro. The macro should be used on function
-// declarations following the argument list:
-//
-// Sprocket* AllocateSprocket() MUST_USE_RESULT;
-//
-#if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) \
- && !defined(COMPILER_ICC)
-#define CERES_MUST_USE_RESULT __attribute__ ((warn_unused_result))
-#else
-#define CERES_MUST_USE_RESULT
-#endif
-
-// Platform independent macros to get aligned memory allocations.
-// For example
-//
-// MyFoo my_foo CERES_ALIGN_ATTRIBUTE(16);
-//
-// Gives us an instance of MyFoo which is aligned at a 16 byte
-// boundary.
-#if defined(_MSC_VER)
-#define CERES_ALIGN_ATTRIBUTE(n) __declspec(align(n))
-#define CERES_ALIGN_OF(T) __alignof(T)
-#elif defined(__GNUC__)
-#define CERES_ALIGN_ATTRIBUTE(n) __attribute__((aligned(n)))
-#define CERES_ALIGN_OF(T) __alignof(T)
-#endif
-
-#endif // CERES_PUBLIC_INTERNAL_MACROS_H_
diff --git a/extern/ceres/include/ceres/internal/manual_constructor.h b/extern/ceres/include/ceres/internal/manual_constructor.h
deleted file mode 100644
index 0d7633cef83..00000000000
--- a/extern/ceres/include/ceres/internal/manual_constructor.h
+++ /dev/null
@@ -1,208 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
-// http://ceres-solver.org/
-//
-// 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.
-//
-// Author: kenton@google.com (Kenton Varda)
-//
-// ManualConstructor statically-allocates space in which to store some
-// object, but does not initialize it. You can then call the constructor
-// and destructor for the object yourself as you see fit. This is useful
-// for memory management optimizations, where you want to initialize and
-// destroy an object multiple times but only allocate it once.
-//
-// (When I say ManualConstructor statically allocates space, I mean that
-// the ManualConstructor object itself is forced to be the right size.)
-
-#ifndef CERES_PUBLIC_INTERNAL_MANUAL_CONSTRUCTOR_H_
-#define CERES_PUBLIC_INTERNAL_MANUAL_CONSTRUCTOR_H_
-
-#include <new>
-
-namespace ceres {
-namespace internal {
-
-// ------- Define CERES_ALIGNED_CHAR_ARRAY --------------------------------
-
-#ifndef CERES_ALIGNED_CHAR_ARRAY
-
-// Because MSVC and older GCCs require that the argument to their alignment
-// construct to be a literal constant integer, we use a template instantiated
-// at all the possible powers of two.
-template<int alignment, int size> struct AlignType { };
-template<int size> struct AlignType<0, size> { typedef char result[size]; };
-
-#if !defined(CERES_ALIGN_ATTRIBUTE)
-#define CERES_ALIGNED_CHAR_ARRAY you_must_define_CERES_ALIGNED_CHAR_ARRAY_for_your_compiler
-#else // !defined(CERES_ALIGN_ATTRIBUTE)
-
-#define CERES_ALIGN_TYPE_TEMPLATE(X) \
- template<int size> struct AlignType<X, size> { \
- typedef CERES_ALIGN_ATTRIBUTE(X) char result[size]; \
- }
-
-CERES_ALIGN_TYPE_TEMPLATE(1);
-CERES_ALIGN_TYPE_TEMPLATE(2);
-CERES_ALIGN_TYPE_TEMPLATE(4);
-CERES_ALIGN_TYPE_TEMPLATE(8);
-CERES_ALIGN_TYPE_TEMPLATE(16);
-CERES_ALIGN_TYPE_TEMPLATE(32);
-CERES_ALIGN_TYPE_TEMPLATE(64);
-CERES_ALIGN_TYPE_TEMPLATE(128);
-CERES_ALIGN_TYPE_TEMPLATE(256);
-CERES_ALIGN_TYPE_TEMPLATE(512);
-CERES_ALIGN_TYPE_TEMPLATE(1024);
-CERES_ALIGN_TYPE_TEMPLATE(2048);
-CERES_ALIGN_TYPE_TEMPLATE(4096);
-CERES_ALIGN_TYPE_TEMPLATE(8192);
-// Any larger and MSVC++ will complain.
-
-#undef CERES_ALIGN_TYPE_TEMPLATE
-
-#define CERES_ALIGNED_CHAR_ARRAY(T, Size) \
- typename AlignType<CERES_ALIGN_OF(T), sizeof(T) * Size>::result
-
-#endif // !defined(CERES_ALIGN_ATTRIBUTE)
-
-#endif // CERES_ALIGNED_CHAR_ARRAY
-
-template <typename Type>
-class ManualConstructor {
- public:
- // No constructor or destructor because one of the most useful uses of
- // this class is as part of a union, and members of a union cannot have
- // constructors or destructors. And, anyway, the whole point of this
- // class is to bypass these.
-
- inline Type* get() {
- return reinterpret_cast<Type*>(space_);
- }
- inline const Type* get() const {
- return reinterpret_cast<const Type*>(space_);
- }
-
- inline Type* operator->() { return get(); }
- inline const Type* operator->() const { return get(); }
-
- inline Type& operator*() { return *get(); }
- inline const Type& operator*() const { return *get(); }
-
- // This is needed to get around the strict aliasing warning GCC generates.
- inline void* space() {
- return reinterpret_cast<void*>(space_);
- }
-
- // You can pass up to four constructor arguments as arguments of Init().
- inline void Init() {
- new(space()) Type;
- }
-
- template <typename T1>
- inline void Init(const T1& p1) {
- new(space()) Type(p1);
- }
-
- template <typename T1, typename T2>
- inline void Init(const T1& p1, const T2& p2) {
- new(space()) Type(p1, p2);
- }
-
- template <typename T1, typename T2, typename T3>
- inline void Init(const T1& p1, const T2& p2, const T3& p3) {
- new(space()) Type(p1, p2, p3);
- }
-
- template <typename T1, typename T2, typename T3, typename T4>
- inline void Init(const T1& p1, const T2& p2, const T3& p3, const T4& p4) {
- new(space()) Type(p1, p2, p3, p4);
- }
-
- template <typename T1, typename T2, typename T3, typename T4, typename T5>
- inline void Init(const T1& p1, const T2& p2, const T3& p3, const T4& p4,
- const T5& p5) {
- new(space()) Type(p1, p2, p3, p4, p5);
- }
-
- template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6>
- inline void Init(const T1& p1, const T2& p2, const T3& p3, const T4& p4,
- const T5& p5, const T6& p6) {
- new(space()) Type(p1, p2, p3, p4, p5, p6);
- }
-
- template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7>
- inline void Init(const T1& p1, const T2& p2, const T3& p3, const T4& p4,
- const T5& p5, const T6& p6, const T7& p7) {
- new(space()) Type(p1, p2, p3, p4, p5, p6, p7);
- }
-
- template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8>
- inline void Init(const T1& p1, const T2& p2, const T3& p3, const T4& p4,
- const T5& p5, const T6& p6, const T7& p7, const T8& p8) {
- new(space()) Type(p1, p2, p3, p4, p5, p6, p7, p8);
- }
-
- template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9>
- inline void Init(const T1& p1, const T2& p2, const T3& p3, const T4& p4,
- const T5& p5, const T6& p6, const T7& p7, const T8& p8,
- const T9& p9) {
- new(space()) Type(p1, p2, p3, p4, p5, p6, p7, p8, p9);
- }
-
- template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10>
- inline void Init(const T1& p1, const T2& p2, const T3& p3, const T4& p4,
- const T5& p5, const T6& p6, const T7& p7, const T8& p8,
- const T9& p9, const T10& p10) {
- new(space()) Type(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10);
- }
-
- template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11>
- inline void Init(const T1& p1, const T2& p2, const T3& p3, const T4& p4,
- const T5& p5, const T6& p6, const T7& p7, const T8& p8,
- const T9& p9, const T10& p10, const T11& p11) {
- new(space()) Type(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11);
- }
-
- inline void Destroy() {
- get()->~Type();
- }
-
- private:
- CERES_ALIGNED_CHAR_ARRAY(Type, 1) space_;
-};
-
-#undef CERES_ALIGNED_CHAR_ARRAY
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_PUBLIC_INTERNAL_MANUAL_CONSTRUCTOR_H_
diff --git a/extern/ceres/include/ceres/internal/memory.h b/extern/ceres/include/ceres/internal/memory.h
new file mode 100644
index 00000000000..45c5b67c353
--- /dev/null
+++ b/extern/ceres/include/ceres/internal/memory.h
@@ -0,0 +1,90 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// File: memory.h
+// -----------------------------------------------------------------------------
+//
+// This header file contains utility functions for managing the creation and
+// conversion of smart pointers. This file is an extension to the C++
+// standard <memory> library header file.
+
+#ifndef CERES_PUBLIC_INTERNAL_MEMORY_H_
+#define CERES_PUBLIC_INTERNAL_MEMORY_H_
+
+#include <memory>
+
+#ifdef CERES_HAVE_EXCEPTIONS
+#define CERES_INTERNAL_TRY try
+#define CERES_INTERNAL_CATCH_ANY catch (...)
+#define CERES_INTERNAL_RETHROW \
+ do { \
+ throw; \
+ } while (false)
+#else // CERES_HAVE_EXCEPTIONS
+#define CERES_INTERNAL_TRY if (true)
+#define CERES_INTERNAL_CATCH_ANY else if (false)
+#define CERES_INTERNAL_RETHROW \
+ do { \
+ } while (false)
+#endif // CERES_HAVE_EXCEPTIONS
+
+namespace ceres {
+namespace internal {
+
+template <typename Allocator, typename Iterator, typename... Args>
+void ConstructRange(Allocator& alloc,
+ Iterator first,
+ Iterator last,
+ const Args&... args) {
+ for (Iterator cur = first; cur != last; ++cur) {
+ CERES_INTERNAL_TRY {
+ std::allocator_traits<Allocator>::construct(
+ alloc, std::addressof(*cur), args...);
+ }
+ CERES_INTERNAL_CATCH_ANY {
+ while (cur != first) {
+ --cur;
+ std::allocator_traits<Allocator>::destroy(alloc, std::addressof(*cur));
+ }
+ CERES_INTERNAL_RETHROW;
+ }
+ }
+}
+
+template <typename Allocator, typename Iterator, typename InputIterator>
+void CopyRange(Allocator& alloc,
+ Iterator destination,
+ InputIterator first,
+ InputIterator last) {
+ for (Iterator cur = destination; first != last;
+ static_cast<void>(++cur), static_cast<void>(++first)) {
+ CERES_INTERNAL_TRY {
+ std::allocator_traits<Allocator>::construct(
+ alloc, std::addressof(*cur), *first);
+ }
+ CERES_INTERNAL_CATCH_ANY {
+ while (cur != destination) {
+ --cur;
+ std::allocator_traits<Allocator>::destroy(alloc, std::addressof(*cur));
+ }
+ CERES_INTERNAL_RETHROW;
+ }
+ }
+}
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_PUBLIC_INTERNAL_MEMORY_H_
diff --git a/extern/ceres/include/ceres/internal/numeric_diff.h b/extern/ceres/include/ceres/internal/numeric_diff.h
index 11e8275b1d3..fb2e00baca5 100644
--- a/extern/ceres/include/ceres/internal/numeric_diff.h
+++ b/extern/ceres/include/ceres/internal/numeric_diff.h
@@ -36,12 +36,12 @@
#define CERES_PUBLIC_INTERNAL_NUMERIC_DIFF_H_
#include <cstring>
+#include <utility>
#include "Eigen/Dense"
#include "Eigen/StdVector"
#include "ceres/cost_function.h"
#include "ceres/internal/fixed_array.h"
-#include "ceres/internal/scoped_ptr.h"
#include "ceres/internal/variadic_evaluate.h"
#include "ceres/numeric_diff_options.h"
#include "ceres/types.h"
@@ -51,42 +51,11 @@
namespace ceres {
namespace internal {
-// Helper templates that allow evaluation of a variadic functor or a
-// CostFunction object.
-template <typename CostFunctor,
- int N0, int N1, int N2, int N3, int N4,
- int N5, int N6, int N7, int N8, int N9 >
-bool EvaluateImpl(const CostFunctor* functor,
- double const* const* parameters,
- double* residuals,
- const void* /* NOT USED */) {
- return VariadicEvaluate<CostFunctor,
- double,
- N0, N1, N2, N3, N4, N5, N6, N7, N8, N9>::Call(
- *functor,
- parameters,
- residuals);
-}
-
-template <typename CostFunctor,
- int N0, int N1, int N2, int N3, int N4,
- int N5, int N6, int N7, int N8, int N9 >
-bool EvaluateImpl(const CostFunctor* functor,
- double const* const* parameters,
- double* residuals,
- const CostFunction* /* NOT USED */) {
- return functor->Evaluate(parameters, residuals, NULL);
-}
-
// This is split from the main class because C++ doesn't allow partial template
// specializations for member functions. The alternative is to repeat the main
// class for differing numbers of parameters, which is also unfortunate.
-template <typename CostFunctor,
- NumericDiffMethodType kMethod,
- int kNumResiduals,
- int N0, int N1, int N2, int N3, int N4,
- int N5, int N6, int N7, int N8, int N9,
- int kParameterBlock,
+template <typename CostFunctor, NumericDiffMethodType kMethod,
+ int kNumResiduals, typename ParameterDims, int kParameterBlock,
int kParameterBlockSize>
struct NumericDiff {
// Mutates parameters but must restore them before return.
@@ -104,6 +73,8 @@ struct NumericDiff {
using Eigen::RowMajor;
using Eigen::ColMajor;
+ DCHECK(jacobian);
+
const int num_residuals_internal =
(kNumResiduals != ceres::DYNAMIC ? kNumResiduals : num_residuals);
const int parameter_block_index_internal =
@@ -155,7 +126,7 @@ struct NumericDiff {
// compute the derivative for that parameter.
FixedArray<double> temp_residual_array(num_residuals_internal);
FixedArray<double> residual_array(num_residuals_internal);
- Map<ResidualVector> residuals(residual_array.get(),
+ Map<ResidualVector> residuals(residual_array.data(),
num_residuals_internal);
for (int j = 0; j < parameter_block_size_internal; ++j) {
@@ -170,8 +141,8 @@ struct NumericDiff {
residuals_at_eval_point,
parameters,
x_plus_delta.data(),
- temp_residual_array.get(),
- residual_array.get())) {
+ temp_residual_array.data(),
+ residual_array.data())) {
return false;
}
} else {
@@ -182,8 +153,8 @@ struct NumericDiff {
residuals_at_eval_point,
parameters,
x_plus_delta.data(),
- temp_residual_array.get(),
- residual_array.get())) {
+ temp_residual_array.data(),
+ residual_array.data())) {
return false;
}
}
@@ -220,8 +191,9 @@ struct NumericDiff {
// Mutate 1 element at a time and then restore.
x_plus_delta(parameter_index) = x(parameter_index) + delta;
- if (!EvaluateImpl<CostFunctor, N0, N1, N2, N3, N4, N5, N6, N7, N8, N9>(
- functor, parameters, residuals.data(), functor)) {
+ if (!VariadicEvaluate<ParameterDims>(*functor,
+ parameters,
+ residuals.data())) {
return false;
}
@@ -234,8 +206,9 @@ struct NumericDiff {
// Compute the function on the other side of x(parameter_index).
x_plus_delta(parameter_index) = x(parameter_index) - delta;
- if (!EvaluateImpl<CostFunctor, N0, N1, N2, N3, N4, N5, N6, N7, N8, N9>(
- functor, parameters, temp_residuals.data(), functor)) {
+ if (!VariadicEvaluate<ParameterDims>(*functor,
+ parameters,
+ temp_residuals.data())) {
return false;
}
@@ -407,35 +380,116 @@ struct NumericDiff {
}
};
-template <typename CostFunctor,
- NumericDiffMethodType kMethod,
- int kNumResiduals,
- int N0, int N1, int N2, int N3, int N4,
- int N5, int N6, int N7, int N8, int N9,
- int kParameterBlock>
-struct NumericDiff<CostFunctor, kMethod, kNumResiduals,
- N0, N1, N2, N3, N4, N5, N6, N7, N8, N9,
- kParameterBlock, 0> {
- // Mutates parameters but must restore them before return.
- static bool EvaluateJacobianForParameterBlock(
- const CostFunctor* functor,
- const double* residuals_at_eval_point,
- const NumericDiffOptions& options,
- const int num_residuals,
- const int parameter_block_index,
- const int parameter_block_size,
- double **parameters,
- double *jacobian) {
- // Silence unused parameter compiler warnings.
- (void)functor;
- (void)residuals_at_eval_point;
- (void)options;
- (void)num_residuals;
- (void)parameter_block_index;
- (void)parameter_block_size;
- (void)parameters;
- (void)jacobian;
- LOG(FATAL) << "Control should never reach here.";
+// This function calls NumericDiff<...>::EvaluateJacobianForParameterBlock for
+// each parameter block.
+//
+// Example:
+// A call to
+// EvaluateJacobianForParameterBlocks<StaticParameterDims<2, 3>>(
+// functor,
+// residuals_at_eval_point,
+// options,
+// num_residuals,
+// parameters,
+// jacobians);
+// will result in the following calls to
+// NumericDiff<...>::EvaluateJacobianForParameterBlock:
+//
+// if (jacobians[0] != nullptr) {
+// if (!NumericDiff<
+// CostFunctor,
+// method,
+// kNumResiduals,
+// StaticParameterDims<2, 3>,
+// 0,
+// 2>::EvaluateJacobianForParameterBlock(functor,
+// residuals_at_eval_point,
+// options,
+// num_residuals,
+// 0,
+// 2,
+// parameters,
+// jacobians[0])) {
+// return false;
+// }
+// }
+// if (jacobians[1] != nullptr) {
+// if (!NumericDiff<
+// CostFunctor,
+// method,
+// kNumResiduals,
+// StaticParameterDims<2, 3>,
+// 1,
+// 3>::EvaluateJacobianForParameterBlock(functor,
+// residuals_at_eval_point,
+// options,
+// num_residuals,
+// 1,
+// 3,
+// parameters,
+// jacobians[1])) {
+// return false;
+// }
+// }
+template <typename ParameterDims,
+ typename Parameters = typename ParameterDims::Parameters,
+ int ParameterIdx = 0>
+struct EvaluateJacobianForParameterBlocks;
+
+template <typename ParameterDims, int N, int... Ns, int ParameterIdx>
+struct EvaluateJacobianForParameterBlocks<ParameterDims,
+ std::integer_sequence<int, N, Ns...>,
+ ParameterIdx> {
+ template <NumericDiffMethodType method,
+ int kNumResiduals,
+ typename CostFunctor>
+ static bool Apply(const CostFunctor* functor,
+ const double* residuals_at_eval_point,
+ const NumericDiffOptions& options,
+ int num_residuals,
+ double** parameters,
+ double** jacobians) {
+ if (jacobians[ParameterIdx] != nullptr) {
+ if (!NumericDiff<
+ CostFunctor,
+ method,
+ kNumResiduals,
+ ParameterDims,
+ ParameterIdx,
+ N>::EvaluateJacobianForParameterBlock(functor,
+ residuals_at_eval_point,
+ options,
+ num_residuals,
+ ParameterIdx,
+ N,
+ parameters,
+ jacobians[ParameterIdx])) {
+ return false;
+ }
+ }
+
+ return EvaluateJacobianForParameterBlocks<ParameterDims,
+ std::integer_sequence<int, Ns...>,
+ ParameterIdx + 1>::
+ template Apply<method, kNumResiduals>(functor,
+ residuals_at_eval_point,
+ options,
+ num_residuals,
+ parameters,
+ jacobians);
+ }
+};
+
+// End of 'recursion'. Nothing more to do.
+template <typename ParameterDims, int ParameterIdx>
+struct EvaluateJacobianForParameterBlocks<ParameterDims, std::integer_sequence<int>,
+ ParameterIdx> {
+ template <NumericDiffMethodType method, int kNumResiduals,
+ typename CostFunctor>
+ static bool Apply(const CostFunctor* /* NOT USED*/,
+ const double* /* NOT USED*/,
+ const NumericDiffOptions& /* NOT USED*/, int /* NOT USED*/,
+ double** /* NOT USED*/, double** /* NOT USED*/) {
return true;
}
};
diff --git a/extern/ceres/include/ceres/internal/parameter_dims.h b/extern/ceres/include/ceres/internal/parameter_dims.h
new file mode 100644
index 00000000000..24021061416
--- /dev/null
+++ b/extern/ceres/include/ceres/internal/parameter_dims.h
@@ -0,0 +1,124 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2018 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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.
+//
+// Author: jodebo_beck@gmx.de (Johannes Beck)
+
+#ifndef CERES_PUBLIC_INTERNAL_PARAMETER_DIMS_H_
+#define CERES_PUBLIC_INTERNAL_PARAMETER_DIMS_H_
+
+#include <array>
+#include <utility>
+
+#include "ceres/internal/integer_sequence_algorithm.h"
+
+namespace ceres {
+namespace internal {
+
+// Checks, whether the given parameter block sizes are valid. Valid means every
+// dimension is bigger than zero.
+constexpr bool IsValidParameterDimensionSequence(std::integer_sequence<int>) {
+ return true;
+}
+
+template <int N, int... Ts>
+constexpr bool IsValidParameterDimensionSequence(
+ std::integer_sequence<int, N, Ts...>) {
+ return (N <= 0) ? false
+ : IsValidParameterDimensionSequence(
+ std::integer_sequence<int, Ts...>());
+}
+
+// Helper class that represents the parameter dimensions. The parameter
+// dimensions are either dynamic or the sizes are known at compile time. It is
+// used to pass parameter block dimensions around (e.g. between functions or
+// classes).
+//
+// As an example if one have three parameter blocks with dimensions (2, 4, 1),
+// one would use 'StaticParameterDims<2, 4, 1>' which is a synonym for
+// 'ParameterDims<false, 2, 4, 1>'.
+// For dynamic parameter dims, one would just use 'DynamicParameterDims', which
+// is a synonym for 'ParameterDims<true>'.
+template <bool IsDynamic, int... Ns>
+class ParameterDims {
+ public:
+ using Parameters = std::integer_sequence<int, Ns...>;
+
+ // The parameter dimensions are only valid if all parameter block dimensions
+ // are greater than zero.
+ static constexpr bool kIsValid =
+ IsValidParameterDimensionSequence(Parameters());
+ static_assert(kIsValid,
+ "Invalid parameter block dimension detected. Each parameter "
+ "block dimension must be bigger than zero.");
+
+ static constexpr bool kIsDynamic = IsDynamic;
+ static constexpr int kNumParameterBlocks = sizeof...(Ns);
+ static_assert(kIsDynamic || kNumParameterBlocks > 0,
+ "At least one parameter block must be specified.");
+
+ static constexpr int kNumParameters =
+ Sum<std::integer_sequence<int, Ns...>>::Value;
+
+ static constexpr int GetDim(int dim) { return params_[dim]; }
+
+ // If one has all parameters packed into a single array this function unpacks
+ // the parameters.
+ template <typename T>
+ static inline std::array<T*, kNumParameterBlocks> GetUnpackedParameters(
+ T* ptr) {
+ using Offsets = ExclusiveScan<Parameters>;
+ return GetUnpackedParameters(ptr, Offsets());
+ }
+
+ private:
+ template <typename T, int... Indices>
+ static inline std::array<T*, kNumParameterBlocks> GetUnpackedParameters(
+ T* ptr, std::integer_sequence<int, Indices...>) {
+ return std::array<T*, kNumParameterBlocks>{{ptr + Indices...}};
+ }
+
+ static constexpr std::array<int, kNumParameterBlocks> params_{Ns...};
+};
+
+// Even static constexpr member variables needs to be defined (not only
+// declared). As the ParameterDims class is tempalted this definition must
+// be in the header file.
+template <bool IsDynamic, int... Ns>
+constexpr std::array<int, ParameterDims<IsDynamic, Ns...>::kNumParameterBlocks>
+ ParameterDims<IsDynamic, Ns...>::params_;
+
+// Using declarations for static and dynamic parameter dims. This makes client
+// code easier to read.
+template <int... Ns>
+using StaticParameterDims = ParameterDims<false, Ns...>;
+using DynamicParameterDims = ParameterDims<true>;
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_PUBLIC_INTERNAL_PARAMETER_DIMS_H_
diff --git a/extern/ceres/include/ceres/internal/port.h b/extern/ceres/include/ceres/internal/port.h
index f4dcaee7bd8..958b0d15cb7 100644
--- a/extern/ceres/include/ceres/internal/port.h
+++ b/extern/ceres/include/ceres/internal/port.h
@@ -32,45 +32,41 @@
#define CERES_PUBLIC_INTERNAL_PORT_H_
// This file needs to compile as c code.
-#ifdef __cplusplus
-#include <cstddef>
#include "ceres/internal/config.h"
-#if defined(CERES_TR1_MEMORY_HEADER)
-#include <tr1/memory>
-#else
-#include <memory>
-#endif
-namespace ceres {
-
-#if defined(CERES_TR1_SHARED_PTR)
-using std::tr1::shared_ptr;
+#if defined(CERES_USE_OPENMP)
+# if defined(CERES_USE_CXX_THREADS) || defined(CERES_NO_THREADS)
+# error CERES_USE_OPENMP is mutually exclusive to CERES_USE_CXX_THREADS and CERES_NO_THREADS
+# endif
+#elif defined(CERES_USE_CXX_THREADS)
+# if defined(CERES_USE_OPENMP) || defined(CERES_NO_THREADS)
+# error CERES_USE_CXX_THREADS is mutually exclusive to CERES_USE_OPENMP, CERES_USE_CXX_THREADS and CERES_NO_THREADS
+# endif
+#elif defined(CERES_NO_THREADS)
+# if defined(CERES_USE_OPENMP) || defined(CERES_USE_CXX_THREADS)
+# error CERES_NO_THREADS is mutually exclusive to CERES_USE_OPENMP and CERES_USE_CXX_THREADS
+# endif
#else
-using std::shared_ptr;
+# error One of CERES_USE_OPENMP, CERES_USE_CXX_THREADS or CERES_NO_THREADS must be defined.
#endif
-// We allocate some Eigen objects on the stack and other places they
-// might not be aligned to 16-byte boundaries. If we have C++11, we
-// can specify their alignment anyway, and thus can safely enable
-// vectorization on those matrices; in C++99, we are out of luck. Figure out
-// what case we're in and write macros that do the right thing.
-#ifdef CERES_USE_CXX11
-namespace port_constants {
-static constexpr size_t kMaxAlignBytes =
- // Work around a GCC 4.8 bug
- // (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56019) where
- // std::max_align_t is misplaced.
-#if defined (__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ == 8
- alignof(::max_align_t);
-#else
- alignof(std::max_align_t);
+// CERES_NO_SPARSE should be automatically defined by config.h if Ceres was
+// compiled without any sparse back-end. Verify that it has not subsequently
+// been inconsistently redefined.
+#if defined(CERES_NO_SPARSE)
+# if !defined(CERES_NO_SUITESPARSE)
+# error CERES_NO_SPARSE requires CERES_NO_SUITESPARSE.
+# endif
+# if !defined(CERES_NO_CXSPARSE)
+# error CERES_NO_SPARSE requires CERES_NO_CXSPARSE
+# endif
+# if !defined(CERES_NO_ACCELERATE_SPARSE)
+# error CERES_NO_SPARSE requires CERES_NO_ACCELERATE_SPARSE
+# endif
+# if defined(CERES_USE_EIGEN_SPARSE)
+# error CERES_NO_SPARSE requires !CERES_USE_EIGEN_SPARSE
+# endif
#endif
-} // namespace port_constants
-#endif
-
-} // namespace ceres
-
-#endif // __cplusplus
// A macro to signal which functions and classes are exported when
// building a DLL with MSVC.
diff --git a/extern/ceres/include/ceres/internal/scoped_ptr.h b/extern/ceres/include/ceres/internal/scoped_ptr.h
deleted file mode 100644
index fa0ac25a031..00000000000
--- a/extern/ceres/include/ceres/internal/scoped_ptr.h
+++ /dev/null
@@ -1,310 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
-// http://ceres-solver.org/
-//
-// 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.
-//
-// Author: jorg@google.com (Jorg Brown)
-//
-// This is an implementation designed to match the anticipated future TR2
-// implementation of the scoped_ptr class, and its closely-related brethren,
-// scoped_array, scoped_ptr_malloc, and make_scoped_ptr.
-
-#ifndef CERES_PUBLIC_INTERNAL_SCOPED_PTR_H_
-#define CERES_PUBLIC_INTERNAL_SCOPED_PTR_H_
-
-#include <assert.h>
-#include <stdlib.h>
-#include <cstddef>
-#include <algorithm>
-
-namespace ceres {
-namespace internal {
-
-template <class C> class scoped_ptr;
-template <class C, class Free> class scoped_ptr_malloc;
-template <class C> class scoped_array;
-
-template <class C>
-scoped_ptr<C> make_scoped_ptr(C *);
-
-// A scoped_ptr<T> is like a T*, except that the destructor of
-// scoped_ptr<T> automatically deletes the pointer it holds (if
-// any). That is, scoped_ptr<T> owns the T object that it points
-// to. Like a T*, a scoped_ptr<T> may hold either NULL or a pointer to
-// a T object. Also like T*, scoped_ptr<T> is thread-compatible, and
-// once you dereference it, you get the threadsafety guarantees of T.
-//
-// The size of a scoped_ptr is small: sizeof(scoped_ptr<C>) == sizeof(C*)
-template <class C>
-class scoped_ptr {
- public:
- // The element type
- typedef C element_type;
-
- // Constructor. Defaults to intializing with NULL.
- // There is no way to create an uninitialized scoped_ptr.
- // The input parameter must be allocated with new.
- explicit scoped_ptr(C* p = NULL) : ptr_(p) { }
-
- // Destructor. If there is a C object, delete it.
- // We don't need to test ptr_ == NULL because C++ does that for us.
- ~scoped_ptr() {
- enum { type_must_be_complete = sizeof(C) };
- delete ptr_;
- }
-
- // Reset. Deletes the current owned object, if any.
- // Then takes ownership of a new object, if given.
- // this->reset(this->get()) works.
- void reset(C* p = NULL) {
- if (p != ptr_) {
- enum { type_must_be_complete = sizeof(C) };
- delete ptr_;
- ptr_ = p;
- }
- }
-
- // Accessors to get the owned object.
- // operator* and operator-> will assert() if there is no current object.
- C& operator*() const {
- assert(ptr_ != NULL);
- return *ptr_;
- }
- C* operator->() const {
- assert(ptr_ != NULL);
- return ptr_;
- }
- C* get() const { return ptr_; }
-
- // Comparison operators.
- // These return whether a scoped_ptr and a raw pointer refer to
- // the same object, not just to two different but equal objects.
- bool operator==(const C* p) const { return ptr_ == p; }
- bool operator!=(const C* p) const { return ptr_ != p; }
-
- // Swap two scoped pointers.
- void swap(scoped_ptr& p2) {
- C* tmp = ptr_;
- ptr_ = p2.ptr_;
- p2.ptr_ = tmp;
- }
-
- // Release a pointer.
- // The return value is the current pointer held by this object.
- // If this object holds a NULL pointer, the return value is NULL.
- // After this operation, this object will hold a NULL pointer,
- // and will not own the object any more.
- C* release() {
- C* retVal = ptr_;
- ptr_ = NULL;
- return retVal;
- }
-
- private:
- C* ptr_;
-
- // google3 friend class that can access copy ctor (although if it actually
- // calls a copy ctor, there will be a problem) see below
- friend scoped_ptr<C> make_scoped_ptr<C>(C *p);
-
- // Forbid comparison of scoped_ptr types. If C2 != C, it totally doesn't
- // make sense, and if C2 == C, it still doesn't make sense because you should
- // never have the same object owned by two different scoped_ptrs.
- template <class C2> bool operator==(scoped_ptr<C2> const& p2) const;
- template <class C2> bool operator!=(scoped_ptr<C2> const& p2) const;
-
- // Disallow evil constructors
- scoped_ptr(const scoped_ptr&);
- void operator=(const scoped_ptr&);
-};
-
-// Free functions
-template <class C>
-inline void swap(scoped_ptr<C>& p1, scoped_ptr<C>& p2) {
- p1.swap(p2);
-}
-
-template <class C>
-inline bool operator==(const C* p1, const scoped_ptr<C>& p2) {
- return p1 == p2.get();
-}
-
-template <class C>
-inline bool operator==(const C* p1, const scoped_ptr<const C>& p2) {
- return p1 == p2.get();
-}
-
-template <class C>
-inline bool operator!=(const C* p1, const scoped_ptr<C>& p2) {
- return p1 != p2.get();
-}
-
-template <class C>
-inline bool operator!=(const C* p1, const scoped_ptr<const C>& p2) {
- return p1 != p2.get();
-}
-
-template <class C>
-scoped_ptr<C> make_scoped_ptr(C *p) {
- // This does nothing but to return a scoped_ptr of the type that the passed
- // pointer is of. (This eliminates the need to specify the name of T when
- // making a scoped_ptr that is used anonymously/temporarily.) From an
- // access control point of view, we construct an unnamed scoped_ptr here
- // which we return and thus copy-construct. Hence, we need to have access
- // to scoped_ptr::scoped_ptr(scoped_ptr const &). However, it is guaranteed
- // that we never actually call the copy constructor, which is a good thing
- // as we would call the temporary's object destructor (and thus delete p)
- // if we actually did copy some object, here.
- return scoped_ptr<C>(p);
-}
-
-// scoped_array<C> is like scoped_ptr<C>, except that the caller must allocate
-// with new [] and the destructor deletes objects with delete [].
-//
-// As with scoped_ptr<C>, a scoped_array<C> either points to an object
-// or is NULL. A scoped_array<C> owns the object that it points to.
-// scoped_array<T> is thread-compatible, and once you index into it,
-// the returned objects have only the threadsafety guarantees of T.
-//
-// Size: sizeof(scoped_array<C>) == sizeof(C*)
-template <class C>
-class scoped_array {
- public:
- // The element type
- typedef C element_type;
-
- // Constructor. Defaults to intializing with NULL.
- // There is no way to create an uninitialized scoped_array.
- // The input parameter must be allocated with new [].
- explicit scoped_array(C* p = NULL) : array_(p) { }
-
- // Destructor. If there is a C object, delete it.
- // We don't need to test ptr_ == NULL because C++ does that for us.
- ~scoped_array() {
- enum { type_must_be_complete = sizeof(C) };
- delete[] array_;
- }
-
- // Reset. Deletes the current owned object, if any.
- // Then takes ownership of a new object, if given.
- // this->reset(this->get()) works.
- void reset(C* p = NULL) {
- if (p != array_) {
- enum { type_must_be_complete = sizeof(C) };
- delete[] array_;
- array_ = p;
- }
- }
-
- // Get one element of the current object.
- // Will assert() if there is no current object, or index i is negative.
- C& operator[](std::ptrdiff_t i) const {
- assert(i >= 0);
- assert(array_ != NULL);
- return array_[i];
- }
-
- // Get a pointer to the zeroth element of the current object.
- // If there is no current object, return NULL.
- C* get() const {
- return array_;
- }
-
- // Comparison operators.
- // These return whether a scoped_array and a raw pointer refer to
- // the same array, not just to two different but equal arrays.
- bool operator==(const C* p) const { return array_ == p; }
- bool operator!=(const C* p) const { return array_ != p; }
-
- // Swap two scoped arrays.
- void swap(scoped_array& p2) {
- C* tmp = array_;
- array_ = p2.array_;
- p2.array_ = tmp;
- }
-
- // Release an array.
- // The return value is the current pointer held by this object.
- // If this object holds a NULL pointer, the return value is NULL.
- // After this operation, this object will hold a NULL pointer,
- // and will not own the object any more.
- C* release() {
- C* retVal = array_;
- array_ = NULL;
- return retVal;
- }
-
- private:
- C* array_;
-
- // Forbid comparison of different scoped_array types.
- template <class C2> bool operator==(scoped_array<C2> const& p2) const;
- template <class C2> bool operator!=(scoped_array<C2> const& p2) const;
-
- // Disallow evil constructors
- scoped_array(const scoped_array&);
- void operator=(const scoped_array&);
-};
-
-// Free functions
-template <class C>
-inline void swap(scoped_array<C>& p1, scoped_array<C>& p2) {
- p1.swap(p2);
-}
-
-template <class C>
-inline bool operator==(const C* p1, const scoped_array<C>& p2) {
- return p1 == p2.get();
-}
-
-template <class C>
-inline bool operator==(const C* p1, const scoped_array<const C>& p2) {
- return p1 == p2.get();
-}
-
-template <class C>
-inline bool operator!=(const C* p1, const scoped_array<C>& p2) {
- return p1 != p2.get();
-}
-
-template <class C>
-inline bool operator!=(const C* p1, const scoped_array<const C>& p2) {
- return p1 != p2.get();
-}
-
-// This class wraps the c library function free() in a class that can be
-// passed as a template argument to scoped_ptr_malloc below.
-class ScopedPtrMallocFree {
- public:
- inline void operator()(void* x) const {
- free(x);
- }
-};
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_PUBLIC_INTERNAL_SCOPED_PTR_H_
diff --git a/extern/ceres/include/ceres/internal/variadic_evaluate.h b/extern/ceres/include/ceres/internal/variadic_evaluate.h
index b3515b96d18..046832c0bb4 100644
--- a/extern/ceres/include/ceres/internal/variadic_evaluate.h
+++ b/extern/ceres/include/ceres/internal/variadic_evaluate.h
@@ -28,165 +28,77 @@
//
// Author: sameeragarwal@google.com (Sameer Agarwal)
// mierle@gmail.com (Keir Mierle)
+// jodebo_beck@gmx.de (Johannes Beck)
#ifndef CERES_PUBLIC_INTERNAL_VARIADIC_EVALUATE_H_
#define CERES_PUBLIC_INTERNAL_VARIADIC_EVALUATE_H_
#include <stddef.h>
-#include "ceres/jet.h"
-#include "ceres/types.h"
-#include "ceres/internal/eigen.h"
-#include "ceres/internal/fixed_array.h"
-#include "glog/logging.h"
+#include <type_traits>
+#include <utility>
+
+#include "ceres/cost_function.h"
+#include "ceres/internal/parameter_dims.h"
namespace ceres {
namespace internal {
-// This block of quasi-repeated code calls the user-supplied functor, which may
-// take a variable number of arguments. This is accomplished by specializing the
-// struct based on the size of the trailing parameters; parameters with 0 size
-// are assumed missing.
-template<typename Functor, typename T, int N0, int N1, int N2, int N3, int N4,
- int N5, int N6, int N7, int N8, int N9>
-struct VariadicEvaluate {
- static bool Call(const Functor& functor, T const *const *input, T* output) {
- return functor(input[0],
- input[1],
- input[2],
- input[3],
- input[4],
- input[5],
- input[6],
- input[7],
- input[8],
- input[9],
- output);
- }
-};
-
-template<typename Functor, typename T, int N0, int N1, int N2, int N3, int N4,
- int N5, int N6, int N7, int N8>
-struct VariadicEvaluate<Functor, T, N0, N1, N2, N3, N4, N5, N6, N7, N8, 0> {
- static bool Call(const Functor& functor, T const *const *input, T* output) {
- return functor(input[0],
- input[1],
- input[2],
- input[3],
- input[4],
- input[5],
- input[6],
- input[7],
- input[8],
- output);
- }
-};
-
-template<typename Functor, typename T, int N0, int N1, int N2, int N3, int N4,
- int N5, int N6, int N7>
-struct VariadicEvaluate<Functor, T, N0, N1, N2, N3, N4, N5, N6, N7, 0, 0> {
- static bool Call(const Functor& functor, T const *const *input, T* output) {
- return functor(input[0],
- input[1],
- input[2],
- input[3],
- input[4],
- input[5],
- input[6],
- input[7],
- output);
- }
-};
-
-template<typename Functor, typename T, int N0, int N1, int N2, int N3, int N4,
- int N5, int N6>
-struct VariadicEvaluate<Functor, T, N0, N1, N2, N3, N4, N5, N6, 0, 0, 0> {
- static bool Call(const Functor& functor, T const *const *input, T* output) {
- return functor(input[0],
- input[1],
- input[2],
- input[3],
- input[4],
- input[5],
- input[6],
- output);
- }
-};
-
-template<typename Functor, typename T, int N0, int N1, int N2, int N3, int N4,
- int N5>
-struct VariadicEvaluate<Functor, T, N0, N1, N2, N3, N4, N5, 0, 0, 0, 0> {
- static bool Call(const Functor& functor, T const *const *input, T* output) {
- return functor(input[0],
- input[1],
- input[2],
- input[3],
- input[4],
- input[5],
- output);
- }
-};
-
-template<typename Functor, typename T, int N0, int N1, int N2, int N3, int N4>
-struct VariadicEvaluate<Functor, T, N0, N1, N2, N3, N4, 0, 0, 0, 0, 0> {
- static bool Call(const Functor& functor, T const *const *input, T* output) {
- return functor(input[0],
- input[1],
- input[2],
- input[3],
- input[4],
- output);
- }
-};
-
-template<typename Functor, typename T, int N0, int N1, int N2, int N3>
-struct VariadicEvaluate<Functor, T, N0, N1, N2, N3, 0, 0, 0, 0, 0, 0> {
- static bool Call(const Functor& functor, T const *const *input, T* output) {
- return functor(input[0],
- input[1],
- input[2],
- input[3],
- output);
- }
-};
-
-template<typename Functor, typename T, int N0, int N1, int N2>
-struct VariadicEvaluate<Functor, T, N0, N1, N2, 0, 0, 0, 0, 0, 0, 0> {
- static bool Call(const Functor& functor, T const *const *input, T* output) {
- return functor(input[0],
- input[1],
- input[2],
- output);
- }
-};
-
-template<typename Functor, typename T, int N0, int N1>
-struct VariadicEvaluate<Functor, T, N0, N1, 0, 0, 0, 0, 0, 0, 0, 0> {
- static bool Call(const Functor& functor, T const *const *input, T* output) {
- return functor(input[0],
- input[1],
- output);
- }
-};
-
-template<typename Functor, typename T, int N0>
-struct VariadicEvaluate<Functor, T, N0, 0, 0, 0, 0, 0, 0, 0, 0, 0> {
- static bool Call(const Functor& functor, T const *const *input, T* output) {
- return functor(input[0],
- output);
- }
-};
-
-// Template instantiation for dynamically-sized functors.
-template<typename Functor, typename T>
-struct VariadicEvaluate<Functor, T, ceres::DYNAMIC, ceres::DYNAMIC,
- ceres::DYNAMIC, ceres::DYNAMIC, ceres::DYNAMIC,
- ceres::DYNAMIC, ceres::DYNAMIC, ceres::DYNAMIC,
- ceres::DYNAMIC, ceres::DYNAMIC> {
- static bool Call(const Functor& functor, T const *const *input, T* output) {
- return functor(input, output);
- }
-};
+// For fixed size cost functors
+template <typename Functor, typename T, int... Indices>
+inline bool VariadicEvaluateImpl(const Functor& functor, T const* const* input,
+ T* output, std::false_type /*is_dynamic*/,
+ std::integer_sequence<int, Indices...>) {
+ static_assert(sizeof...(Indices),
+ "Invalid number of parameter blocks. At least one parameter "
+ "block must be specified.");
+ return functor(input[Indices]..., output);
+}
+
+// For dynamic sized cost functors
+template <typename Functor, typename T>
+inline bool VariadicEvaluateImpl(const Functor& functor, T const* const* input,
+ T* output, std::true_type /*is_dynamic*/,
+ std::integer_sequence<int>) {
+ return functor(input, output);
+}
+
+// For ceres cost functors (not ceres::CostFunction)
+template <typename ParameterDims, typename Functor, typename T>
+inline bool VariadicEvaluateImpl(const Functor& functor, T const* const* input,
+ T* output, const void* /* NOT USED */) {
+ using ParameterBlockIndices =
+ std::make_integer_sequence<int, ParameterDims::kNumParameterBlocks>;
+ using IsDynamic = std::integral_constant<bool, ParameterDims::kIsDynamic>;
+ return VariadicEvaluateImpl(functor, input, output, IsDynamic(),
+ ParameterBlockIndices());
+}
+
+// For ceres::CostFunction
+template <typename ParameterDims, typename Functor, typename T>
+inline bool VariadicEvaluateImpl(const Functor& functor, T const* const* input,
+ T* output,
+ const CostFunction* /* NOT USED */) {
+ return functor.Evaluate(input, output, nullptr);
+}
+
+// Variadic evaluate is a helper function to evaluate ceres cost function or
+// functors using an input, output and the parameter dimensions. There are
+// several ways different possibilities:
+// 1) If the passed functor is a 'ceres::CostFunction' its evaluate method is
+// called.
+// 2) If the functor is not a 'ceres::CostFunction' and the specified parameter
+// dims is dynamic, the functor must have the following signature
+// 'bool(T const* const* input, T* output)'.
+// 3) If the functor is not a 'ceres::CostFunction' and the specified parameter
+// dims is not dynamic, the input is expanded by using the number of parameter
+// blocks. The signature of the functor must have the following signature
+// 'bool()(const T* i_1, const T* i_2, ... const T* i_n, T* output)'.
+template <typename ParameterDims, typename Functor, typename T>
+inline bool VariadicEvaluate(const Functor& functor, T const* const* input,
+ T* output) {
+ return VariadicEvaluateImpl<ParameterDims>(functor, input, output, &functor);
+}
} // namespace internal
} // namespace ceres
diff --git a/extern/ceres/include/ceres/iteration_callback.h b/extern/ceres/include/ceres/iteration_callback.h
index db5d0efe53a..0a743ecc26f 100644
--- a/extern/ceres/include/ceres/iteration_callback.h
+++ b/extern/ceres/include/ceres/iteration_callback.h
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2019 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -35,42 +35,22 @@
#ifndef CERES_PUBLIC_ITERATION_CALLBACK_H_
#define CERES_PUBLIC_ITERATION_CALLBACK_H_
-#include "ceres/types.h"
#include "ceres/internal/disable_warnings.h"
+#include "ceres/types.h"
namespace ceres {
// This struct describes the state of the optimizer after each
// iteration of the minimization.
struct CERES_EXPORT IterationSummary {
- IterationSummary()
- : iteration(0),
- step_is_valid(false),
- step_is_nonmonotonic(false),
- step_is_successful(false),
- cost(0.0),
- cost_change(0.0),
- gradient_max_norm(0.0),
- gradient_norm(0.0),
- step_norm(0.0),
- eta(0.0),
- step_size(0.0),
- line_search_function_evaluations(0),
- line_search_gradient_evaluations(0),
- line_search_iterations(0),
- linear_solver_iterations(0),
- iteration_time_in_seconds(0.0),
- step_solver_time_in_seconds(0.0),
- cumulative_time_in_seconds(0.0) {}
-
// Current iteration number.
- int32 iteration;
+ int iteration = 0;
// Step was numerically valid, i.e., all values are finite and the
// step reduces the value of the linearized model.
//
// Note: step_is_valid is always true when iteration = 0.
- bool step_is_valid;
+ bool step_is_valid = false;
// Step did not reduce the value of the objective function
// sufficiently, but it was accepted because of the relaxed
@@ -78,7 +58,7 @@ struct CERES_EXPORT IterationSummary {
// algorithm.
//
// Note: step_is_nonmonotonic is always false when iteration = 0;
- bool step_is_nonmonotonic;
+ bool step_is_nonmonotonic = false;
// Whether or not the minimizer accepted this step or not. If the
// ordinary trust region algorithm is used, this means that the
@@ -90,68 +70,68 @@ struct CERES_EXPORT IterationSummary {
// step and the step is declared successful.
//
// Note: step_is_successful is always true when iteration = 0.
- bool step_is_successful;
+ bool step_is_successful = false;
// Value of the objective function.
- double cost;
+ double cost = 0.90;
// Change in the value of the objective function in this
// iteration. This can be positive or negative.
- double cost_change;
+ double cost_change = 0.0;
// Infinity norm of the gradient vector.
- double gradient_max_norm;
+ double gradient_max_norm = 0.0;
// 2-norm of the gradient vector.
- double gradient_norm;
+ double gradient_norm = 0.0;
// 2-norm of the size of the step computed by the optimization
// algorithm.
- double step_norm;
+ double step_norm = 0.0;
// For trust region algorithms, the ratio of the actual change in
// cost and the change in the cost of the linearized approximation.
- double relative_decrease;
+ double relative_decrease = 0.0;
// Size of the trust region at the end of the current iteration. For
// the Levenberg-Marquardt algorithm, the regularization parameter
// mu = 1.0 / trust_region_radius.
- double trust_region_radius;
+ double trust_region_radius = 0.0;
// For the inexact step Levenberg-Marquardt algorithm, this is the
// relative accuracy with which the Newton(LM) step is solved. This
// number affects only the iterative solvers capable of solving
// linear systems inexactly. Factorization-based exact solvers
// ignore it.
- double eta;
+ double eta = 0.0;
// Step sized computed by the line search algorithm.
- double step_size;
+ double step_size = 0.0;
// Number of function value evaluations used by the line search algorithm.
- int line_search_function_evaluations;
+ int line_search_function_evaluations = 0;
// Number of function gradient evaluations used by the line search algorithm.
- int line_search_gradient_evaluations;
+ int line_search_gradient_evaluations = 0;
// Number of iterations taken by the line search algorithm.
- int line_search_iterations;
+ int line_search_iterations = 0;
// Number of iterations taken by the linear solver to solve for the
// Newton step.
- int linear_solver_iterations;
+ int linear_solver_iterations = 0;
// All times reported below are wall times.
// Time (in seconds) spent inside the minimizer loop in the current
// iteration.
- double iteration_time_in_seconds;
+ double iteration_time_in_seconds = 0.0;
// Time (in seconds) spent inside the trust region step solver.
- double step_solver_time_in_seconds;
+ double step_solver_time_in_seconds = 0.0;
// Time (in seconds) since the user called Solve().
- double cumulative_time_in_seconds;
+ double cumulative_time_in_seconds = 0.0;
};
// Interface for specifying callbacks that are executed at the end of
diff --git a/extern/ceres/include/ceres/jet.h b/extern/ceres/include/ceres/jet.h
index a104707298c..7aafaa01d30 100644
--- a/extern/ceres/include/ceres/jet.h
+++ b/extern/ceres/include/ceres/jet.h
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2019 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -31,7 +31,7 @@
// A simple implementation of N-dimensional dual numbers, for automatically
// computing exact derivatives of functions.
//
-// While a complete treatment of the mechanics of automatic differentation is
+// While a complete treatment of the mechanics of automatic differentiation is
// beyond the scope of this header (see
// http://en.wikipedia.org/wiki/Automatic_differentiation for details), the
// basic idea is to extend normal arithmetic with an extra element, "e," often
@@ -49,7 +49,7 @@
// f(x) = x^2 ,
//
// evaluated at 10. Using normal arithmetic, f(10) = 100, and df/dx(10) = 20.
-// Next, augument 10 with an infinitesimal to get:
+// Next, argument 10 with an infinitesimal to get:
//
// f(10 + e) = (10 + e)^2
// = 100 + 2 * 10 * e + e^2
@@ -102,8 +102,9 @@
// }
//
// // The "2" means there should be 2 dual number components.
-// Jet<double, 2> x(0); // Pick the 0th dual number for x.
-// Jet<double, 2> y(1); // Pick the 1st dual number for y.
+// // It computes the partial derivative at x=10, y=20.
+// Jet<double, 2> x(10, 0); // Pick the 0th dual number for x.
+// Jet<double, 2> y(20, 1); // Pick the 1st dual number for y.
// Jet<double, 2> z = f(x, y);
//
// LOG(INFO) << "df/dx = " << z.v[0]
@@ -124,7 +125,7 @@
//
// x = a + \sum_i v[i] t_i
//
-// A shorthand is to write an element as x = a + u, where u is the pertubation.
+// A shorthand is to write an element as x = a + u, where u is the perturbation.
// Then, the main point about the arithmetic of jets is that the product of
// perturbations is zero:
//
@@ -163,7 +164,6 @@
#include <string>
#include "Eigen/Core"
-#include "ceres/fpclassify.h"
#include "ceres/internal/port.h"
namespace ceres {
@@ -171,26 +171,25 @@ namespace ceres {
template <typename T, int N>
struct Jet {
enum { DIMENSION = N };
+ typedef T Scalar;
// Default-construct "a" because otherwise this can lead to false errors about
// uninitialized uses when other classes relying on default constructed T
// (where T is a Jet<T, N>). This usually only happens in opt mode. Note that
// the C++ standard mandates that e.g. default constructed doubles are
// initialized to 0.0; see sections 8.5 of the C++03 standard.
- Jet() : a() {
- v.setZero();
- }
+ Jet() : a() { v.setConstant(Scalar()); }
// Constructor from scalar: a + 0.
explicit Jet(const T& value) {
a = value;
- v.setZero();
+ v.setConstant(Scalar());
}
// Constructor from scalar plus variable: a + t_i.
Jet(const T& value, int k) {
a = value;
- v.setZero();
+ v.setConstant(Scalar());
v[k] = T(1.0);
}
@@ -198,58 +197,66 @@ struct Jet {
// The use of Eigen::DenseBase allows Eigen expressions
// to be passed in without being fully evaluated until
// they are assigned to v
- template<typename Derived>
- EIGEN_STRONG_INLINE Jet(const T& a, const Eigen::DenseBase<Derived> &v)
- : a(a), v(v) {
- }
+ template <typename Derived>
+ EIGEN_STRONG_INLINE Jet(const T& a, const Eigen::DenseBase<Derived>& v)
+ : a(a), v(v) {}
// Compound operators
- Jet<T, N>& operator+=(const Jet<T, N> &y) {
+ Jet<T, N>& operator+=(const Jet<T, N>& y) {
*this = *this + y;
return *this;
}
- Jet<T, N>& operator-=(const Jet<T, N> &y) {
+ Jet<T, N>& operator-=(const Jet<T, N>& y) {
*this = *this - y;
return *this;
}
- Jet<T, N>& operator*=(const Jet<T, N> &y) {
+ Jet<T, N>& operator*=(const Jet<T, N>& y) {
*this = *this * y;
return *this;
}
- Jet<T, N>& operator/=(const Jet<T, N> &y) {
+ Jet<T, N>& operator/=(const Jet<T, N>& y) {
*this = *this / y;
return *this;
}
+ // Compound with scalar operators.
+ Jet<T, N>& operator+=(const T& s) {
+ *this = *this + s;
+ return *this;
+ }
+
+ Jet<T, N>& operator-=(const T& s) {
+ *this = *this - s;
+ return *this;
+ }
+
+ Jet<T, N>& operator*=(const T& s) {
+ *this = *this * s;
+ return *this;
+ }
+
+ Jet<T, N>& operator/=(const T& s) {
+ *this = *this / s;
+ return *this;
+ }
+
// The scalar part.
T a;
// The infinitesimal part.
+ Eigen::Matrix<T, N, 1> v;
- // We allocate Jets on the stack and other places they
- // might not be aligned to 16-byte boundaries. If we have C++11, we
- // can specify their alignment anyway, and thus can safely enable
- // vectorization on those matrices; in C++99, we are out of luck. Figure out
- // what case we're in and do the right thing.
-#ifndef CERES_USE_CXX11
- // fall back to safe version:
- Eigen::Matrix<T, N, 1, Eigen::DontAlign> v;
-#else
- static constexpr bool kShouldAlignMatrix =
- 16 <= ::ceres::port_constants::kMaxAlignBytes;
- static constexpr int kAlignHint = kShouldAlignMatrix ?
- Eigen::AutoAlign : Eigen::DontAlign;
- static constexpr size_t kAlignment = kShouldAlignMatrix ? 16 : 1;
- alignas(kAlignment) Eigen::Matrix<T, N, 1, kAlignHint> v;
-#endif
+ // This struct needs to have an Eigen aligned operator new as it contains
+ // fixed-size Eigen types.
+ EIGEN_MAKE_ALIGNED_OPERATOR_NEW
};
// Unary +
-template<typename T, int N> inline
-Jet<T, N> const& operator+(const Jet<T, N>& f) {
+template <typename T, int N>
+inline Jet<T, N> const& operator+(const Jet<T, N>& f) {
return f;
}
@@ -257,72 +264,68 @@ Jet<T, N> const& operator+(const Jet<T, N>& f) {
// see if it causes a performance increase.
// Unary -
-template<typename T, int N> inline
-Jet<T, N> operator-(const Jet<T, N>&f) {
+template <typename T, int N>
+inline Jet<T, N> operator-(const Jet<T, N>& f) {
return Jet<T, N>(-f.a, -f.v);
}
// Binary +
-template<typename T, int N> inline
-Jet<T, N> operator+(const Jet<T, N>& f,
- const Jet<T, N>& g) {
+template <typename T, int N>
+inline Jet<T, N> operator+(const Jet<T, N>& f, const Jet<T, N>& g) {
return Jet<T, N>(f.a + g.a, f.v + g.v);
}
// Binary + with a scalar: x + s
-template<typename T, int N> inline
-Jet<T, N> operator+(const Jet<T, N>& f, T s) {
+template <typename T, int N>
+inline Jet<T, N> operator+(const Jet<T, N>& f, T s) {
return Jet<T, N>(f.a + s, f.v);
}
// Binary + with a scalar: s + x
-template<typename T, int N> inline
-Jet<T, N> operator+(T s, const Jet<T, N>& f) {
+template <typename T, int N>
+inline Jet<T, N> operator+(T s, const Jet<T, N>& f) {
return Jet<T, N>(f.a + s, f.v);
}
// Binary -
-template<typename T, int N> inline
-Jet<T, N> operator-(const Jet<T, N>& f,
- const Jet<T, N>& g) {
+template <typename T, int N>
+inline Jet<T, N> operator-(const Jet<T, N>& f, const Jet<T, N>& g) {
return Jet<T, N>(f.a - g.a, f.v - g.v);
}
// Binary - with a scalar: x - s
-template<typename T, int N> inline
-Jet<T, N> operator-(const Jet<T, N>& f, T s) {
+template <typename T, int N>
+inline Jet<T, N> operator-(const Jet<T, N>& f, T s) {
return Jet<T, N>(f.a - s, f.v);
}
// Binary - with a scalar: s - x
-template<typename T, int N> inline
-Jet<T, N> operator-(T s, const Jet<T, N>& f) {
+template <typename T, int N>
+inline Jet<T, N> operator-(T s, const Jet<T, N>& f) {
return Jet<T, N>(s - f.a, -f.v);
}
// Binary *
-template<typename T, int N> inline
-Jet<T, N> operator*(const Jet<T, N>& f,
- const Jet<T, N>& g) {
+template <typename T, int N>
+inline Jet<T, N> operator*(const Jet<T, N>& f, const Jet<T, N>& g) {
return Jet<T, N>(f.a * g.a, f.a * g.v + f.v * g.a);
}
// Binary * with a scalar: x * s
-template<typename T, int N> inline
-Jet<T, N> operator*(const Jet<T, N>& f, T s) {
+template <typename T, int N>
+inline Jet<T, N> operator*(const Jet<T, N>& f, T s) {
return Jet<T, N>(f.a * s, f.v * s);
}
// Binary * with a scalar: s * x
-template<typename T, int N> inline
-Jet<T, N> operator*(T s, const Jet<T, N>& f) {
+template <typename T, int N>
+inline Jet<T, N> operator*(T s, const Jet<T, N>& f) {
return Jet<T, N>(f.a * s, f.v * s);
}
// Binary /
-template<typename T, int N> inline
-Jet<T, N> operator/(const Jet<T, N>& f,
- const Jet<T, N>& g) {
+template <typename T, int N>
+inline Jet<T, N> operator/(const Jet<T, N>& f, const Jet<T, N>& g) {
// This uses:
//
// a + u (a + u)(b - v) (a + u)(b - v)
@@ -332,43 +335,43 @@ Jet<T, N> operator/(const Jet<T, N>& f,
// which holds because v*v = 0.
const T g_a_inverse = T(1.0) / g.a;
const T f_a_by_g_a = f.a * g_a_inverse;
- return Jet<T, N>(f.a * g_a_inverse, (f.v - f_a_by_g_a * g.v) * g_a_inverse);
+ return Jet<T, N>(f_a_by_g_a, (f.v - f_a_by_g_a * g.v) * g_a_inverse);
}
// Binary / with a scalar: s / x
-template<typename T, int N> inline
-Jet<T, N> operator/(T s, const Jet<T, N>& g) {
+template <typename T, int N>
+inline Jet<T, N> operator/(T s, const Jet<T, N>& g) {
const T minus_s_g_a_inverse2 = -s / (g.a * g.a);
return Jet<T, N>(s / g.a, g.v * minus_s_g_a_inverse2);
}
// Binary / with a scalar: x / s
-template<typename T, int N> inline
-Jet<T, N> operator/(const Jet<T, N>& f, T s) {
- const T s_inverse = 1.0 / s;
+template <typename T, int N>
+inline Jet<T, N> operator/(const Jet<T, N>& f, T s) {
+ const T s_inverse = T(1.0) / s;
return Jet<T, N>(f.a * s_inverse, f.v * s_inverse);
}
// Binary comparison operators for both scalars and jets.
-#define CERES_DEFINE_JET_COMPARISON_OPERATOR(op) \
-template<typename T, int N> inline \
-bool operator op(const Jet<T, N>& f, const Jet<T, N>& g) { \
- return f.a op g.a; \
-} \
-template<typename T, int N> inline \
-bool operator op(const T& s, const Jet<T, N>& g) { \
- return s op g.a; \
-} \
-template<typename T, int N> inline \
-bool operator op(const Jet<T, N>& f, const T& s) { \
- return f.a op s; \
-}
-CERES_DEFINE_JET_COMPARISON_OPERATOR( < ) // NOLINT
-CERES_DEFINE_JET_COMPARISON_OPERATOR( <= ) // NOLINT
-CERES_DEFINE_JET_COMPARISON_OPERATOR( > ) // NOLINT
-CERES_DEFINE_JET_COMPARISON_OPERATOR( >= ) // NOLINT
-CERES_DEFINE_JET_COMPARISON_OPERATOR( == ) // NOLINT
-CERES_DEFINE_JET_COMPARISON_OPERATOR( != ) // NOLINT
+#define CERES_DEFINE_JET_COMPARISON_OPERATOR(op) \
+ template <typename T, int N> \
+ inline bool operator op(const Jet<T, N>& f, const Jet<T, N>& g) { \
+ return f.a op g.a; \
+ } \
+ template <typename T, int N> \
+ inline bool operator op(const T& s, const Jet<T, N>& g) { \
+ return s op g.a; \
+ } \
+ template <typename T, int N> \
+ inline bool operator op(const Jet<T, N>& f, const T& s) { \
+ return f.a op s; \
+ }
+CERES_DEFINE_JET_COMPARISON_OPERATOR(<) // NOLINT
+CERES_DEFINE_JET_COMPARISON_OPERATOR(<=) // NOLINT
+CERES_DEFINE_JET_COMPARISON_OPERATOR(>) // NOLINT
+CERES_DEFINE_JET_COMPARISON_OPERATOR(>=) // NOLINT
+CERES_DEFINE_JET_COMPARISON_OPERATOR(==) // NOLINT
+CERES_DEFINE_JET_COMPARISON_OPERATOR(!=) // NOLINT
#undef CERES_DEFINE_JET_COMPARISON_OPERATOR
// Pull some functions from namespace std.
@@ -376,112 +379,128 @@ CERES_DEFINE_JET_COMPARISON_OPERATOR( != ) // NOLINT
// This is necessary because we want to use the same name (e.g. 'sqrt') for
// double-valued and Jet-valued functions, but we are not allowed to put
// Jet-valued functions inside namespace std.
-//
-// TODO(keir): Switch to "using".
-inline double abs (double x) { return std::abs(x); }
-inline double log (double x) { return std::log(x); }
-inline double exp (double x) { return std::exp(x); }
-inline double sqrt (double x) { return std::sqrt(x); }
-inline double cos (double x) { return std::cos(x); }
-inline double acos (double x) { return std::acos(x); }
-inline double sin (double x) { return std::sin(x); }
-inline double asin (double x) { return std::asin(x); }
-inline double tan (double x) { return std::tan(x); }
-inline double atan (double x) { return std::atan(x); }
-inline double sinh (double x) { return std::sinh(x); }
-inline double cosh (double x) { return std::cosh(x); }
-inline double tanh (double x) { return std::tanh(x); }
-inline double floor (double x) { return std::floor(x); }
-inline double ceil (double x) { return std::ceil(x); }
-inline double pow (double x, double y) { return std::pow(x, y); }
-inline double atan2(double y, double x) { return std::atan2(y, x); }
+using std::abs;
+using std::acos;
+using std::asin;
+using std::atan;
+using std::atan2;
+using std::cbrt;
+using std::ceil;
+using std::cos;
+using std::cosh;
+using std::exp;
+using std::exp2;
+using std::floor;
+using std::fmax;
+using std::fmin;
+using std::hypot;
+using std::isfinite;
+using std::isinf;
+using std::isnan;
+using std::isnormal;
+using std::log;
+using std::log2;
+using std::pow;
+using std::sin;
+using std::sinh;
+using std::sqrt;
+using std::tan;
+using std::tanh;
+
+// Legacy names from pre-C++11 days.
+// clang-format off
+inline bool IsFinite(double x) { return std::isfinite(x); }
+inline bool IsInfinite(double x) { return std::isinf(x); }
+inline bool IsNaN(double x) { return std::isnan(x); }
+inline bool IsNormal(double x) { return std::isnormal(x); }
+// clang-format on
// In general, f(a + h) ~= f(a) + f'(a) h, via the chain rule.
// abs(x + h) ~= x + h or -(x + h)
-template <typename T, int N> inline
-Jet<T, N> abs(const Jet<T, N>& f) {
- return f.a < T(0.0) ? -f : f;
+template <typename T, int N>
+inline Jet<T, N> abs(const Jet<T, N>& f) {
+ return (f.a < T(0.0) ? -f : f);
}
// log(a + h) ~= log(a) + h / a
-template <typename T, int N> inline
-Jet<T, N> log(const Jet<T, N>& f) {
+template <typename T, int N>
+inline Jet<T, N> log(const Jet<T, N>& f) {
const T a_inverse = T(1.0) / f.a;
return Jet<T, N>(log(f.a), f.v * a_inverse);
}
// exp(a + h) ~= exp(a) + exp(a) h
-template <typename T, int N> inline
-Jet<T, N> exp(const Jet<T, N>& f) {
+template <typename T, int N>
+inline Jet<T, N> exp(const Jet<T, N>& f) {
const T tmp = exp(f.a);
return Jet<T, N>(tmp, tmp * f.v);
}
// sqrt(a + h) ~= sqrt(a) + h / (2 sqrt(a))
-template <typename T, int N> inline
-Jet<T, N> sqrt(const Jet<T, N>& f) {
+template <typename T, int N>
+inline Jet<T, N> sqrt(const Jet<T, N>& f) {
const T tmp = sqrt(f.a);
const T two_a_inverse = T(1.0) / (T(2.0) * tmp);
return Jet<T, N>(tmp, f.v * two_a_inverse);
}
// cos(a + h) ~= cos(a) - sin(a) h
-template <typename T, int N> inline
-Jet<T, N> cos(const Jet<T, N>& f) {
- return Jet<T, N>(cos(f.a), - sin(f.a) * f.v);
+template <typename T, int N>
+inline Jet<T, N> cos(const Jet<T, N>& f) {
+ return Jet<T, N>(cos(f.a), -sin(f.a) * f.v);
}
// acos(a + h) ~= acos(a) - 1 / sqrt(1 - a^2) h
-template <typename T, int N> inline
-Jet<T, N> acos(const Jet<T, N>& f) {
- const T tmp = - T(1.0) / sqrt(T(1.0) - f.a * f.a);
+template <typename T, int N>
+inline Jet<T, N> acos(const Jet<T, N>& f) {
+ const T tmp = -T(1.0) / sqrt(T(1.0) - f.a * f.a);
return Jet<T, N>(acos(f.a), tmp * f.v);
}
// sin(a + h) ~= sin(a) + cos(a) h
-template <typename T, int N> inline
-Jet<T, N> sin(const Jet<T, N>& f) {
+template <typename T, int N>
+inline Jet<T, N> sin(const Jet<T, N>& f) {
return Jet<T, N>(sin(f.a), cos(f.a) * f.v);
}
// asin(a + h) ~= asin(a) + 1 / sqrt(1 - a^2) h
-template <typename T, int N> inline
-Jet<T, N> asin(const Jet<T, N>& f) {
+template <typename T, int N>
+inline Jet<T, N> asin(const Jet<T, N>& f) {
const T tmp = T(1.0) / sqrt(T(1.0) - f.a * f.a);
return Jet<T, N>(asin(f.a), tmp * f.v);
}
// tan(a + h) ~= tan(a) + (1 + tan(a)^2) h
-template <typename T, int N> inline
-Jet<T, N> tan(const Jet<T, N>& f) {
+template <typename T, int N>
+inline Jet<T, N> tan(const Jet<T, N>& f) {
const T tan_a = tan(f.a);
const T tmp = T(1.0) + tan_a * tan_a;
return Jet<T, N>(tan_a, tmp * f.v);
}
// atan(a + h) ~= atan(a) + 1 / (1 + a^2) h
-template <typename T, int N> inline
-Jet<T, N> atan(const Jet<T, N>& f) {
+template <typename T, int N>
+inline Jet<T, N> atan(const Jet<T, N>& f) {
const T tmp = T(1.0) / (T(1.0) + f.a * f.a);
return Jet<T, N>(atan(f.a), tmp * f.v);
}
// sinh(a + h) ~= sinh(a) + cosh(a) h
-template <typename T, int N> inline
-Jet<T, N> sinh(const Jet<T, N>& f) {
+template <typename T, int N>
+inline Jet<T, N> sinh(const Jet<T, N>& f) {
return Jet<T, N>(sinh(f.a), cosh(f.a) * f.v);
}
// cosh(a + h) ~= cosh(a) + sinh(a) h
-template <typename T, int N> inline
-Jet<T, N> cosh(const Jet<T, N>& f) {
+template <typename T, int N>
+inline Jet<T, N> cosh(const Jet<T, N>& f) {
return Jet<T, N>(cosh(f.a), sinh(f.a) * f.v);
}
// tanh(a + h) ~= tanh(a) + (1 - tanh(a)^2) h
-template <typename T, int N> inline
-Jet<T, N> tanh(const Jet<T, N>& f) {
+template <typename T, int N>
+inline Jet<T, N> tanh(const Jet<T, N>& f) {
const T tanh_a = tanh(f.a);
const T tmp = T(1.0) - tanh_a * tanh_a;
return Jet<T, N>(tanh_a, tmp * f.v);
@@ -491,8 +510,8 @@ Jet<T, N> tanh(const Jet<T, N>& f) {
// result in a zero derivative which provides no information to the solver.
//
// floor(a + h) ~= floor(a) + 0
-template <typename T, int N> inline
-Jet<T, N> floor(const Jet<T, N>& f) {
+template <typename T, int N>
+inline Jet<T, N> floor(const Jet<T, N>& f) {
return Jet<T, N>(floor(f.a));
}
@@ -500,11 +519,60 @@ Jet<T, N> floor(const Jet<T, N>& f) {
// result in a zero derivative which provides no information to the solver.
//
// ceil(a + h) ~= ceil(a) + 0
-template <typename T, int N> inline
-Jet<T, N> ceil(const Jet<T, N>& f) {
+template <typename T, int N>
+inline Jet<T, N> ceil(const Jet<T, N>& f) {
return Jet<T, N>(ceil(f.a));
}
+// Some new additions to C++11:
+
+// cbrt(a + h) ~= cbrt(a) + h / (3 a ^ (2/3))
+template <typename T, int N>
+inline Jet<T, N> cbrt(const Jet<T, N>& f) {
+ const T derivative = T(1.0) / (T(3.0) * cbrt(f.a * f.a));
+ return Jet<T, N>(cbrt(f.a), f.v * derivative);
+}
+
+// exp2(x + h) = 2^(x+h) ~= 2^x + h*2^x*log(2)
+template <typename T, int N>
+inline Jet<T, N> exp2(const Jet<T, N>& f) {
+ const T tmp = exp2(f.a);
+ const T derivative = tmp * log(T(2));
+ return Jet<T, N>(tmp, f.v * derivative);
+}
+
+// log2(x + h) ~= log2(x) + h / (x * log(2))
+template <typename T, int N>
+inline Jet<T, N> log2(const Jet<T, N>& f) {
+ const T derivative = T(1.0) / (f.a * log(T(2)));
+ return Jet<T, N>(log2(f.a), f.v * derivative);
+}
+
+// Like sqrt(x^2 + y^2),
+// but acts to prevent underflow/overflow for small/large x/y.
+// Note that the function is non-smooth at x=y=0,
+// so the derivative is undefined there.
+template <typename T, int N>
+inline Jet<T, N> hypot(const Jet<T, N>& x, const Jet<T, N>& y) {
+ // d/da sqrt(a) = 0.5 / sqrt(a)
+ // d/dx x^2 + y^2 = 2x
+ // So by the chain rule:
+ // d/dx sqrt(x^2 + y^2) = 0.5 / sqrt(x^2 + y^2) * 2x = x / sqrt(x^2 + y^2)
+ // d/dy sqrt(x^2 + y^2) = y / sqrt(x^2 + y^2)
+ const T tmp = hypot(x.a, y.a);
+ return Jet<T, N>(tmp, x.a / tmp * x.v + y.a / tmp * y.v);
+}
+
+template <typename T, int N>
+inline Jet<T, N> fmax(const Jet<T, N>& x, const Jet<T, N>& y) {
+ return x < y ? y : x;
+}
+
+template <typename T, int N>
+inline Jet<T, N> fmin(const Jet<T, N>& x, const Jet<T, N>& y) {
+ return y < x ? y : x;
+}
+
// Bessel functions of the first kind with integer order equal to 0, 1, n.
//
// Microsoft has deprecated the j[0,1,n]() POSIX Bessel functions in favour of
@@ -512,21 +580,21 @@ Jet<T, N> ceil(const Jet<T, N>& f) {
// function errors in client code (the specific warning is suppressed when
// Ceres itself is built).
inline double BesselJ0(double x) {
-#if defined(_MSC_VER) && defined(_j0)
+#if defined(CERES_MSVC_USE_UNDERSCORE_PREFIXED_BESSEL_FUNCTIONS)
return _j0(x);
#else
return j0(x);
#endif
}
inline double BesselJ1(double x) {
-#if defined(_MSC_VER) && defined(_j1)
+#if defined(CERES_MSVC_USE_UNDERSCORE_PREFIXED_BESSEL_FUNCTIONS)
return _j1(x);
#else
return j1(x);
#endif
}
inline double BesselJn(int n, double x) {
-#if defined(_MSC_VER) && defined(_jn)
+#if defined(CERES_MSVC_USE_UNDERSCORE_PREFIXED_BESSEL_FUNCTIONS)
return _jn(n, x);
#else
return jn(n, x);
@@ -541,32 +609,32 @@ inline double BesselJn(int n, double x) {
// See formula http://dlmf.nist.gov/10.6#E3
// j0(a + h) ~= j0(a) - j1(a) h
-template <typename T, int N> inline
-Jet<T, N> BesselJ0(const Jet<T, N>& f) {
- return Jet<T, N>(BesselJ0(f.a),
- -BesselJ1(f.a) * f.v);
+template <typename T, int N>
+inline Jet<T, N> BesselJ0(const Jet<T, N>& f) {
+ return Jet<T, N>(BesselJ0(f.a), -BesselJ1(f.a) * f.v);
}
// See formula http://dlmf.nist.gov/10.6#E1
// j1(a + h) ~= j1(a) + 0.5 ( j0(a) - j2(a) ) h
-template <typename T, int N> inline
-Jet<T, N> BesselJ1(const Jet<T, N>& f) {
+template <typename T, int N>
+inline Jet<T, N> BesselJ1(const Jet<T, N>& f) {
return Jet<T, N>(BesselJ1(f.a),
T(0.5) * (BesselJ0(f.a) - BesselJn(2, f.a)) * f.v);
}
// See formula http://dlmf.nist.gov/10.6#E1
// j_n(a + h) ~= j_n(a) + 0.5 ( j_{n-1}(a) - j_{n+1}(a) ) h
-template <typename T, int N> inline
-Jet<T, N> BesselJn(int n, const Jet<T, N>& f) {
- return Jet<T, N>(BesselJn(n, f.a),
- T(0.5) * (BesselJn(n - 1, f.a) - BesselJn(n + 1, f.a)) * f.v);
+template <typename T, int N>
+inline Jet<T, N> BesselJn(int n, const Jet<T, N>& f) {
+ return Jet<T, N>(
+ BesselJn(n, f.a),
+ T(0.5) * (BesselJn(n - 1, f.a) - BesselJn(n + 1, f.a)) * f.v);
}
// Jet Classification. It is not clear what the appropriate semantics are for
-// these classifications. This picks that IsFinite and isnormal are "all"
-// operations, i.e. all elements of the jet must be finite for the jet itself
-// to be finite (or normal). For IsNaN and IsInfinite, the answer is less
+// these classifications. This picks that std::isfinite and std::isnormal are
+// "all" operations, i.e. all elements of the jet must be finite for the jet
+// itself to be finite (or normal). For IsNaN and IsInfinite, the answer is less
// clear. This takes a "any" approach for IsNaN and IsInfinite such that if any
// part of a jet is nan or inf, then the entire jet is nan or inf. This leads
// to strange situations like a jet can be both IsInfinite and IsNaN, but in
@@ -574,81 +642,88 @@ Jet<T, N> BesselJn(int n, const Jet<T, N>& f) {
// derivatives are sane.
// The jet is finite if all parts of the jet are finite.
-template <typename T, int N> inline
-bool IsFinite(const Jet<T, N>& f) {
- if (!IsFinite(f.a)) {
- return false;
- }
+template <typename T, int N>
+inline bool isfinite(const Jet<T, N>& f) {
+ // Branchless implementation. This is more efficient for the false-case and
+ // works with the codegen system.
+ auto result = isfinite(f.a);
for (int i = 0; i < N; ++i) {
- if (!IsFinite(f.v[i])) {
- return false;
- }
+ result = result & isfinite(f.v[i]);
}
- return true;
+ return result;
}
-// The jet is infinite if any part of the jet is infinite.
-template <typename T, int N> inline
-bool IsInfinite(const Jet<T, N>& f) {
- if (IsInfinite(f.a)) {
- return true;
- }
- for (int i = 0; i < N; i++) {
- if (IsInfinite(f.v[i])) {
- return true;
- }
+// The jet is infinite if any part of the Jet is infinite.
+template <typename T, int N>
+inline bool isinf(const Jet<T, N>& f) {
+ auto result = isinf(f.a);
+ for (int i = 0; i < N; ++i) {
+ result = result | isinf(f.v[i]);
}
- return false;
+ return result;
}
// The jet is NaN if any part of the jet is NaN.
-template <typename T, int N> inline
-bool IsNaN(const Jet<T, N>& f) {
- if (IsNaN(f.a)) {
- return true;
- }
+template <typename T, int N>
+inline bool isnan(const Jet<T, N>& f) {
+ auto result = isnan(f.a);
for (int i = 0; i < N; ++i) {
- if (IsNaN(f.v[i])) {
- return true;
- }
+ result = result | isnan(f.v[i]);
}
- return false;
+ return result;
}
// The jet is normal if all parts of the jet are normal.
-template <typename T, int N> inline
-bool IsNormal(const Jet<T, N>& f) {
- if (!IsNormal(f.a)) {
- return false;
- }
+template <typename T, int N>
+inline bool isnormal(const Jet<T, N>& f) {
+ auto result = isnormal(f.a);
for (int i = 0; i < N; ++i) {
- if (!IsNormal(f.v[i])) {
- return false;
- }
+ result = result & isnormal(f.v[i]);
}
- return true;
+ return result;
+}
+
+// Legacy functions from the pre-C++11 days.
+template <typename T, int N>
+inline bool IsFinite(const Jet<T, N>& f) {
+ return isfinite(f);
+}
+
+template <typename T, int N>
+inline bool IsNaN(const Jet<T, N>& f) {
+ return isnan(f);
+}
+
+template <typename T, int N>
+inline bool IsNormal(const Jet<T, N>& f) {
+ return isnormal(f);
+}
+
+// The jet is infinite if any part of the jet is infinite.
+template <typename T, int N>
+inline bool IsInfinite(const Jet<T, N>& f) {
+ return isinf(f);
}
// atan2(b + db, a + da) ~= atan2(b, a) + (- b da + a db) / (a^2 + b^2)
//
// In words: the rate of change of theta is 1/r times the rate of
// change of (x, y) in the positive angular direction.
-template <typename T, int N> inline
-Jet<T, N> atan2(const Jet<T, N>& g, const Jet<T, N>& f) {
+template <typename T, int N>
+inline Jet<T, N> atan2(const Jet<T, N>& g, const Jet<T, N>& f) {
// Note order of arguments:
//
// f = a + da
// g = b + db
T const tmp = T(1.0) / (f.a * f.a + g.a * g.a);
- return Jet<T, N>(atan2(g.a, f.a), tmp * (- g.a * f.v + f.a * g.v));
+ return Jet<T, N>(atan2(g.a, f.a), tmp * (-g.a * f.v + f.a * g.v));
}
-
// pow -- base is a differentiable function, exponent is a constant.
// (a+da)^p ~= a^p + p*a^(p-1) da
-template <typename T, int N> inline
-Jet<T, N> pow(const Jet<T, N>& f, double g) {
+template <typename T, int N>
+inline Jet<T, N> pow(const Jet<T, N>& f, double g) {
T const tmp = g * pow(f.a, g - T(1.0));
return Jet<T, N>(pow(f.a, g), tmp * f.v);
}
@@ -664,26 +739,30 @@ Jet<T, N> pow(const Jet<T, N>& f, double g) {
// 3. For f < 0 and integer g we have: (f)^(g + dg) ~= f^g but if dg
// != 0, the derivatives are not defined and we return NaN.
-template <typename T, int N> inline
-Jet<T, N> pow(double f, const Jet<T, N>& g) {
- if (f == 0 && g.a > 0) {
+template <typename T, int N>
+inline Jet<T, N> pow(T f, const Jet<T, N>& g) {
+ Jet<T, N> result;
+
+ if (f == T(0) && g.a > T(0)) {
// Handle case 2.
- return Jet<T, N>(T(0.0));
- }
- if (f < 0 && g.a == floor(g.a)) {
- // Handle case 3.
- Jet<T, N> ret(pow(f, g.a));
- for (int i = 0; i < N; i++) {
- if (g.v[i] != T(0.0)) {
- // Return a NaN when g.v != 0.
- ret.v[i] = std::numeric_limits<T>::quiet_NaN();
+ result = Jet<T, N>(T(0.0));
+ } else {
+ if (f < 0 && g.a == floor(g.a)) { // Handle case 3.
+ result = Jet<T, N>(pow(f, g.a));
+ for (int i = 0; i < N; i++) {
+ if (g.v[i] != T(0.0)) {
+ // Return a NaN when g.v != 0.
+ result.v[i] = std::numeric_limits<T>::quiet_NaN();
+ }
}
+ } else {
+ // Handle case 1.
+ T const tmp = pow(f, g.a);
+ result = Jet<T, N>(tmp, log(f) * tmp * g.v);
}
- return ret;
}
- // Handle case 1.
- T const tmp = pow(f, g.a);
- return Jet<T, N>(tmp, log(f) * tmp * g.v);
+
+ return result;
}
// pow -- both base and exponent are differentiable functions. This has a
@@ -722,73 +801,48 @@ Jet<T, N> pow(double f, const Jet<T, N>& g) {
//
// 9. For f < 0, g noninteger: The value and derivatives of f^g are not finite.
-template <typename T, int N> inline
-Jet<T, N> pow(const Jet<T, N>& f, const Jet<T, N>& g) {
- if (f.a == 0 && g.a >= 1) {
+template <typename T, int N>
+inline Jet<T, N> pow(const Jet<T, N>& f, const Jet<T, N>& g) {
+ Jet<T, N> result;
+
+ if (f.a == T(0) && g.a >= T(1)) {
// Handle cases 2 and 3.
- if (g.a > 1) {
- return Jet<T, N>(T(0.0));
+ if (g.a > T(1)) {
+ result = Jet<T, N>(T(0.0));
+ } else {
+ result = f;
}
- return f;
- }
- if (f.a < 0 && g.a == floor(g.a)) {
- // Handle cases 7 and 8.
- T const tmp = g.a * pow(f.a, g.a - T(1.0));
- Jet<T, N> ret(pow(f.a, g.a), tmp * f.v);
- for (int i = 0; i < N; i++) {
- if (g.v[i] != T(0.0)) {
- // Return a NaN when g.v != 0.
- ret.v[i] = std::numeric_limits<T>::quiet_NaN();
+
+ } else {
+ if (f.a < T(0) && g.a == floor(g.a)) {
+ // Handle cases 7 and 8.
+ T const tmp = g.a * pow(f.a, g.a - T(1.0));
+ result = Jet<T, N>(pow(f.a, g.a), tmp * f.v);
+ for (int i = 0; i < N; i++) {
+ if (g.v[i] != T(0.0)) {
+ // Return a NaN when g.v != 0.
+ result.v[i] = T(std::numeric_limits<double>::quiet_NaN());
+ }
}
+ } else {
+ // Handle the remaining cases. For cases 4,5,6,9 we allow the log()
+ // function to generate -HUGE_VAL or NaN, since those cases result in a
+ // nonfinite derivative.
+ T const tmp1 = pow(f.a, g.a);
+ T const tmp2 = g.a * pow(f.a, g.a - T(1.0));
+ T const tmp3 = tmp1 * log(f.a);
+ result = Jet<T, N>(tmp1, tmp2 * f.v + tmp3 * g.v);
}
- return ret;
}
- // Handle the remaining cases. For cases 4,5,6,9 we allow the log() function
- // to generate -HUGE_VAL or NaN, since those cases result in a nonfinite
- // derivative.
- T const tmp1 = pow(f.a, g.a);
- T const tmp2 = g.a * pow(f.a, g.a - T(1.0));
- T const tmp3 = tmp1 * log(f.a);
- return Jet<T, N>(tmp1, tmp2 * f.v + tmp3 * g.v);
-}
-
-// Define the helper functions Eigen needs to embed Jet types.
-//
-// NOTE(keir): machine_epsilon() and precision() are missing, because they don't
-// work with nested template types (e.g. where the scalar is itself templated).
-// Among other things, this means that decompositions of Jet's does not work,
-// for example
-//
-// Matrix<Jet<T, N> ... > A, x, b;
-// ...
-// A.solve(b, &x)
-//
-// does not work and will fail with a strange compiler error.
-//
-// TODO(keir): This is an Eigen 2.0 limitation that is lifted in 3.0. When we
-// switch to 3.0, also add the rest of the specialization functionality.
-template<typename T, int N> inline const Jet<T, N>& ei_conj(const Jet<T, N>& x) { return x; } // NOLINT
-template<typename T, int N> inline const Jet<T, N>& ei_real(const Jet<T, N>& x) { return x; } // NOLINT
-template<typename T, int N> inline Jet<T, N> ei_imag(const Jet<T, N>& ) { return Jet<T, N>(0.0); } // NOLINT
-template<typename T, int N> inline Jet<T, N> ei_abs (const Jet<T, N>& x) { return fabs(x); } // NOLINT
-template<typename T, int N> inline Jet<T, N> ei_abs2(const Jet<T, N>& x) { return x * x; } // NOLINT
-template<typename T, int N> inline Jet<T, N> ei_sqrt(const Jet<T, N>& x) { return sqrt(x); } // NOLINT
-template<typename T, int N> inline Jet<T, N> ei_exp (const Jet<T, N>& x) { return exp(x); } // NOLINT
-template<typename T, int N> inline Jet<T, N> ei_log (const Jet<T, N>& x) { return log(x); } // NOLINT
-template<typename T, int N> inline Jet<T, N> ei_sin (const Jet<T, N>& x) { return sin(x); } // NOLINT
-template<typename T, int N> inline Jet<T, N> ei_cos (const Jet<T, N>& x) { return cos(x); } // NOLINT
-template<typename T, int N> inline Jet<T, N> ei_tan (const Jet<T, N>& x) { return tan(x); } // NOLINT
-template<typename T, int N> inline Jet<T, N> ei_atan(const Jet<T, N>& x) { return atan(x); } // NOLINT
-template<typename T, int N> inline Jet<T, N> ei_sinh(const Jet<T, N>& x) { return sinh(x); } // NOLINT
-template<typename T, int N> inline Jet<T, N> ei_cosh(const Jet<T, N>& x) { return cosh(x); } // NOLINT
-template<typename T, int N> inline Jet<T, N> ei_tanh(const Jet<T, N>& x) { return tanh(x); } // NOLINT
-template<typename T, int N> inline Jet<T, N> ei_pow (const Jet<T, N>& x, Jet<T, N> y) { return pow(x, y); } // NOLINT
+
+ return result;
+}
// Note: This has to be in the ceres namespace for argument dependent lookup to
// function correctly. Otherwise statements like CHECK_LE(x, 2.0) fail with
// strange compile errors.
template <typename T, int N>
-inline std::ostream &operator<<(std::ostream &s, const Jet<T, N>& z) {
+inline std::ostream& operator<<(std::ostream& s, const Jet<T, N>& z) {
s << "[" << z.a << " ; ";
for (int i = 0; i < N; ++i) {
s << z.v[i];
@@ -799,15 +853,78 @@ inline std::ostream &operator<<(std::ostream &s, const Jet<T, N>& z) {
s << "]";
return s;
}
-
} // namespace ceres
+namespace std {
+template <typename T, int N>
+struct numeric_limits<ceres::Jet<T, N>> {
+ static constexpr bool is_specialized = true;
+ static constexpr bool is_signed = std::numeric_limits<T>::is_signed;
+ static constexpr bool is_integer = std::numeric_limits<T>::is_integer;
+ static constexpr bool is_exact = std::numeric_limits<T>::is_exact;
+ static constexpr bool has_infinity = std::numeric_limits<T>::has_infinity;
+ static constexpr bool has_quiet_NaN = std::numeric_limits<T>::has_quiet_NaN;
+ static constexpr bool has_signaling_NaN =
+ std::numeric_limits<T>::has_signaling_NaN;
+ static constexpr bool is_iec559 = std::numeric_limits<T>::is_iec559;
+ static constexpr bool is_bounded = std::numeric_limits<T>::is_bounded;
+ static constexpr bool is_modulo = std::numeric_limits<T>::is_modulo;
+
+ static constexpr std::float_denorm_style has_denorm =
+ std::numeric_limits<T>::has_denorm;
+ static constexpr std::float_round_style round_style =
+ std::numeric_limits<T>::round_style;
+
+ static constexpr int digits = std::numeric_limits<T>::digits;
+ static constexpr int digits10 = std::numeric_limits<T>::digits10;
+ static constexpr int max_digits10 = std::numeric_limits<T>::max_digits10;
+ static constexpr int radix = std::numeric_limits<T>::radix;
+ static constexpr int min_exponent = std::numeric_limits<T>::min_exponent;
+ static constexpr int min_exponent10 = std::numeric_limits<T>::max_exponent10;
+ static constexpr int max_exponent = std::numeric_limits<T>::max_exponent;
+ static constexpr int max_exponent10 = std::numeric_limits<T>::max_exponent10;
+ static constexpr bool traps = std::numeric_limits<T>::traps;
+ static constexpr bool tinyness_before =
+ std::numeric_limits<T>::tinyness_before;
+
+ static constexpr ceres::Jet<T, N> min() noexcept {
+ return ceres::Jet<T, N>(std::numeric_limits<T>::min());
+ }
+ static constexpr ceres::Jet<T, N> lowest() noexcept {
+ return ceres::Jet<T, N>(std::numeric_limits<T>::lowest());
+ }
+ static constexpr ceres::Jet<T, N> epsilon() noexcept {
+ return ceres::Jet<T, N>(std::numeric_limits<T>::epsilon());
+ }
+ static constexpr ceres::Jet<T, N> round_error() noexcept {
+ return ceres::Jet<T, N>(std::numeric_limits<T>::round_error());
+ }
+ static constexpr ceres::Jet<T, N> infinity() noexcept {
+ return ceres::Jet<T, N>(std::numeric_limits<T>::infinity());
+ }
+ static constexpr ceres::Jet<T, N> quiet_NaN() noexcept {
+ return ceres::Jet<T, N>(std::numeric_limits<T>::quiet_NaN());
+ }
+ static constexpr ceres::Jet<T, N> signaling_NaN() noexcept {
+ return ceres::Jet<T, N>(std::numeric_limits<T>::signaling_NaN());
+ }
+ static constexpr ceres::Jet<T, N> denorm_min() noexcept {
+ return ceres::Jet<T, N>(std::numeric_limits<T>::denorm_min());
+ }
+
+ static constexpr ceres::Jet<T, N> max() noexcept {
+ return ceres::Jet<T, N>(std::numeric_limits<T>::max());
+ }
+};
+
+} // namespace std
+
namespace Eigen {
// Creating a specialization of NumTraits enables placing Jet objects inside
// Eigen arrays, getting all the goodness of Eigen combined with autodiff.
-template<typename T, int N>
-struct NumTraits<ceres::Jet<T, N> > {
+template <typename T, int N>
+struct NumTraits<ceres::Jet<T, N>> {
typedef ceres::Jet<T, N> Real;
typedef ceres::Jet<T, N> NonInteger;
typedef ceres::Jet<T, N> Nested;
@@ -821,6 +938,8 @@ struct NumTraits<ceres::Jet<T, N> > {
return Real(std::numeric_limits<T>::epsilon());
}
+ static inline int digits10() { return NumTraits<T>::digits10(); }
+
enum {
IsComplex = 0,
IsInteger = 0,
@@ -833,7 +952,7 @@ struct NumTraits<ceres::Jet<T, N> > {
RequireInitialization = 1
};
- template<bool Vectorized>
+ template <bool Vectorized>
struct Div {
enum {
#if defined(EIGEN_VECTORIZE_AVX)
@@ -847,6 +966,24 @@ struct NumTraits<ceres::Jet<T, N> > {
Cost = 3
};
};
+
+ static inline Real highest() { return Real(std::numeric_limits<T>::max()); }
+ static inline Real lowest() { return Real(-std::numeric_limits<T>::max()); }
+};
+
+// Specifying the return type of binary operations between Jets and scalar types
+// allows you to perform matrix/array operations with Eigen matrices and arrays
+// such as addition, subtraction, multiplication, and division where one Eigen
+// matrix/array is of type Jet and the other is a scalar type. This improves
+// performance by using the optimized scalar-to-Jet binary operations but
+// is only available on Eigen versions >= 3.3
+template <typename BinaryOp, typename T, int N>
+struct ScalarBinaryOpTraits<ceres::Jet<T, N>, T, BinaryOp> {
+ typedef ceres::Jet<T, N> ReturnType;
+};
+template <typename BinaryOp, typename T, int N>
+struct ScalarBinaryOpTraits<T, ceres::Jet<T, N>, BinaryOp> {
+ typedef ceres::Jet<T, N> ReturnType;
};
} // namespace Eigen
diff --git a/extern/ceres/include/ceres/local_parameterization.h b/extern/ceres/include/ceres/local_parameterization.h
index 379fc684921..1576e829e73 100644
--- a/extern/ceres/include/ceres/local_parameterization.h
+++ b/extern/ceres/include/ceres/local_parameterization.h
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2019 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -32,10 +32,12 @@
#ifndef CERES_PUBLIC_LOCAL_PARAMETERIZATION_H_
#define CERES_PUBLIC_LOCAL_PARAMETERIZATION_H_
+#include <array>
+#include <memory>
#include <vector>
-#include "ceres/internal/port.h"
-#include "ceres/internal/scoped_ptr.h"
+
#include "ceres/internal/disable_warnings.h"
+#include "ceres/internal/port.h"
namespace ceres {
@@ -61,7 +63,7 @@ namespace ceres {
// optimize over two dimensional vector delta in the tangent space at
// that point and then "move" to the point x + delta, where the move
// operation involves projecting back onto the sphere. Doing so
-// removes a redundent dimension from the optimization, making it
+// removes a redundant dimension from the optimization, making it
// numerically more robust and efficient.
//
// More generally we can define a function
@@ -154,17 +156,16 @@ class CERES_EXPORT IdentityParameterization : public LocalParameterization {
public:
explicit IdentityParameterization(int size);
virtual ~IdentityParameterization() {}
- virtual bool Plus(const double* x,
- const double* delta,
- double* x_plus_delta) const;
- virtual bool ComputeJacobian(const double* x,
- double* jacobian) const;
- virtual bool MultiplyByJacobian(const double* x,
- const int num_cols,
- const double* global_matrix,
- double* local_matrix) const;
- virtual int GlobalSize() const { return size_; }
- virtual int LocalSize() const { return size_; }
+ bool Plus(const double* x,
+ const double* delta,
+ double* x_plus_delta) const override;
+ bool ComputeJacobian(const double* x, double* jacobian) const override;
+ bool MultiplyByJacobian(const double* x,
+ const int num_cols,
+ const double* global_matrix,
+ double* local_matrix) const override;
+ int GlobalSize() const override { return size_; }
+ int LocalSize() const override { return size_; }
private:
const int size_;
@@ -176,19 +177,18 @@ class CERES_EXPORT SubsetParameterization : public LocalParameterization {
explicit SubsetParameterization(int size,
const std::vector<int>& constant_parameters);
virtual ~SubsetParameterization() {}
- virtual bool Plus(const double* x,
- const double* delta,
- double* x_plus_delta) const;
- virtual bool ComputeJacobian(const double* x,
- double* jacobian) const;
- virtual bool MultiplyByJacobian(const double* x,
- const int num_cols,
- const double* global_matrix,
- double* local_matrix) const;
- virtual int GlobalSize() const {
+ bool Plus(const double* x,
+ const double* delta,
+ double* x_plus_delta) const override;
+ bool ComputeJacobian(const double* x, double* jacobian) const override;
+ bool MultiplyByJacobian(const double* x,
+ const int num_cols,
+ const double* global_matrix,
+ double* local_matrix) const override;
+ int GlobalSize() const override {
return static_cast<int>(constancy_mask_.size());
}
- virtual int LocalSize() const { return local_size_; }
+ int LocalSize() const override { return local_size_; }
private:
const int local_size_;
@@ -202,13 +202,12 @@ class CERES_EXPORT SubsetParameterization : public LocalParameterization {
class CERES_EXPORT QuaternionParameterization : public LocalParameterization {
public:
virtual ~QuaternionParameterization() {}
- virtual bool Plus(const double* x,
- const double* delta,
- double* x_plus_delta) const;
- virtual bool ComputeJacobian(const double* x,
- double* jacobian) const;
- virtual int GlobalSize() const { return 4; }
- virtual int LocalSize() const { return 3; }
+ bool Plus(const double* x,
+ const double* delta,
+ double* x_plus_delta) const override;
+ bool ComputeJacobian(const double* x, double* jacobian) const override;
+ int GlobalSize() const override { return 4; }
+ int LocalSize() const override { return 3; }
};
// Implements the quaternion local parameterization for Eigen's representation
@@ -222,16 +221,16 @@ class CERES_EXPORT QuaternionParameterization : public LocalParameterization {
//
// Plus(x, delta) = [sin(|delta|) delta / |delta|, cos(|delta|)] * x
// with * being the quaternion multiplication operator.
-class EigenQuaternionParameterization : public ceres::LocalParameterization {
+class CERES_EXPORT EigenQuaternionParameterization
+ : public ceres::LocalParameterization {
public:
virtual ~EigenQuaternionParameterization() {}
- virtual bool Plus(const double* x,
- const double* delta,
- double* x_plus_delta) const;
- virtual bool ComputeJacobian(const double* x,
- double* jacobian) const;
- virtual int GlobalSize() const { return 4; }
- virtual int LocalSize() const { return 3; }
+ bool Plus(const double* x,
+ const double* delta,
+ double* x_plus_delta) const override;
+ bool ComputeJacobian(const double* x, double* jacobian) const override;
+ int GlobalSize() const override { return 4; }
+ int LocalSize() const override { return 3; }
};
// This provides a parameterization for homogeneous vectors which are commonly
@@ -247,32 +246,55 @@ class EigenQuaternionParameterization : public ceres::LocalParameterization {
// remain on the sphere. We assume that the last element of x is the scalar
// component. The size of the homogeneous vector is required to be greater than
// 1.
-class CERES_EXPORT HomogeneousVectorParameterization :
- public LocalParameterization {
+class CERES_EXPORT HomogeneousVectorParameterization
+ : public LocalParameterization {
public:
explicit HomogeneousVectorParameterization(int size);
virtual ~HomogeneousVectorParameterization() {}
- virtual bool Plus(const double* x,
- const double* delta,
- double* x_plus_delta) const;
- virtual bool ComputeJacobian(const double* x,
- double* jacobian) const;
- virtual int GlobalSize() const { return size_; }
- virtual int LocalSize() const { return size_ - 1; }
+ bool Plus(const double* x,
+ const double* delta,
+ double* x_plus_delta) const override;
+ bool ComputeJacobian(const double* x, double* jacobian) const override;
+ int GlobalSize() const override { return size_; }
+ int LocalSize() const override { return size_ - 1; }
private:
const int size_;
};
+// This provides a parameterization for lines, where the line is
+// over-parameterized by an origin point and a direction vector. So the
+// parameter vector size needs to be two times the ambient space dimension,
+// where the first half is interpreted as the origin point and the second half
+// as the direction.
+//
+// The plus operator for the line direction is the same as for the
+// HomogeneousVectorParameterization. The update of the origin point is
+// perpendicular to the line direction before the update.
+//
+// This local parameterization is a special case of the affine Grassmannian
+// manifold (see https://en.wikipedia.org/wiki/Affine_Grassmannian_(manifold))
+// for the case Graff_1(R^n).
+template <int AmbientSpaceDimension>
+class LineParameterization : public LocalParameterization {
+ public:
+ static_assert(AmbientSpaceDimension >= 2,
+ "The ambient space must be at least 2");
+
+ bool Plus(const double* x,
+ const double* delta,
+ double* x_plus_delta) const override;
+ bool ComputeJacobian(const double* x, double* jacobian) const override;
+ int GlobalSize() const override { return 2 * AmbientSpaceDimension; }
+ int LocalSize() const override { return 2 * (AmbientSpaceDimension - 1); }
+};
+
// Construct a local parameterization by taking the Cartesian product
// of a number of other local parameterizations. This is useful, when
// a parameter block is the cartesian product of two or more
// manifolds. For example the parameters of a camera consist of a
// rotation and a translation, i.e., SO(3) x R^3.
//
-// Currently this class supports taking the cartesian product of up to
-// four local parameterizations.
-//
// Example usage:
//
// ProductParameterization product_param(new QuaterionionParameterization(),
@@ -282,35 +304,49 @@ class CERES_EXPORT HomogeneousVectorParameterization :
// rotation is represented using a quaternion.
class CERES_EXPORT ProductParameterization : public LocalParameterization {
public:
+ ProductParameterization(const ProductParameterization&) = delete;
+ ProductParameterization& operator=(const ProductParameterization&) = delete;
//
- // NOTE: All the constructors take ownership of the input local
+ // NOTE: The constructor takes ownership of the input local
// parameterizations.
//
- ProductParameterization(LocalParameterization* local_param1,
- LocalParameterization* local_param2);
+ template <typename... LocalParams>
+ ProductParameterization(LocalParams*... local_params)
+ : local_params_(sizeof...(LocalParams)),
+ local_size_{0},
+ global_size_{0},
+ buffer_size_{0} {
+ constexpr int kNumLocalParams = sizeof...(LocalParams);
+ static_assert(kNumLocalParams >= 2,
+ "At least two local parameterizations must be specified.");
- ProductParameterization(LocalParameterization* local_param1,
- LocalParameterization* local_param2,
- LocalParameterization* local_param3);
+ using LocalParameterizationPtr = std::unique_ptr<LocalParameterization>;
- ProductParameterization(LocalParameterization* local_param1,
- LocalParameterization* local_param2,
- LocalParameterization* local_param3,
- LocalParameterization* local_param4);
+ // Wrap all raw pointers into std::unique_ptr for exception safety.
+ std::array<LocalParameterizationPtr, kNumLocalParams> local_params_array{
+ LocalParameterizationPtr(local_params)...};
- virtual ~ProductParameterization();
- virtual bool Plus(const double* x,
- const double* delta,
- double* x_plus_delta) const;
- virtual bool ComputeJacobian(const double* x,
- double* jacobian) const;
- virtual int GlobalSize() const { return global_size_; }
- virtual int LocalSize() const { return local_size_; }
+ // Initialize internal state.
+ for (int i = 0; i < kNumLocalParams; ++i) {
+ LocalParameterizationPtr& param = local_params_[i];
+ param = std::move(local_params_array[i]);
- private:
- void Init();
+ buffer_size_ =
+ std::max(buffer_size_, param->LocalSize() * param->GlobalSize());
+ global_size_ += param->GlobalSize();
+ local_size_ += param->LocalSize();
+ }
+ }
+
+ bool Plus(const double* x,
+ const double* delta,
+ double* x_plus_delta) const override;
+ bool ComputeJacobian(const double* x, double* jacobian) const override;
+ int GlobalSize() const override { return global_size_; }
+ int LocalSize() const override { return local_size_; }
- std::vector<LocalParameterization*> local_params_;
+ private:
+ std::vector<std::unique_ptr<LocalParameterization>> local_params_;
int local_size_;
int global_size_;
int buffer_size_;
@@ -319,5 +355,7 @@ class CERES_EXPORT ProductParameterization : public LocalParameterization {
} // namespace ceres
#include "ceres/internal/reenable_warnings.h"
+#include "ceres/internal/line_parameterization.h"
#endif // CERES_PUBLIC_LOCAL_PARAMETERIZATION_H_
+
diff --git a/extern/ceres/include/ceres/loss_function.h b/extern/ceres/include/ceres/loss_function.h
index 0512c135143..7aabf7dfce1 100644
--- a/extern/ceres/include/ceres/loss_function.h
+++ b/extern/ceres/include/ceres/loss_function.h
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2019 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -57,7 +57,7 @@
// anything special (i.e. if we used a basic quadratic loss), the
// residual for the erroneous measurement will result in extreme error
// due to the quadratic nature of squared loss. This results in the
-// entire solution getting pulled away from the optimimum to reduce
+// entire solution getting pulled away from the optimum to reduce
// the large error that would otherwise be attributed to the wrong
// measurement.
//
@@ -75,11 +75,11 @@
#ifndef CERES_PUBLIC_LOSS_FUNCTION_H_
#define CERES_PUBLIC_LOSS_FUNCTION_H_
-#include "glog/logging.h"
-#include "ceres/internal/macros.h"
-#include "ceres/internal/scoped_ptr.h"
-#include "ceres/types.h"
+#include <memory>
+
#include "ceres/internal/disable_warnings.h"
+#include "ceres/types.h"
+#include "glog/logging.h"
namespace ceres {
@@ -119,7 +119,6 @@ class CERES_EXPORT LossFunction {
// Note: in the region of interest (i.e. s < 3) we have:
// TrivialLoss >= HuberLoss >= SoftLOneLoss >= CauchyLoss
-
// This corresponds to no robustification.
//
// rho(s) = s
@@ -131,7 +130,7 @@ class CERES_EXPORT LossFunction {
// thing.
class CERES_EXPORT TrivialLoss : public LossFunction {
public:
- virtual void Evaluate(double, double*) const;
+ void Evaluate(double, double*) const override;
};
// Scaling
@@ -174,8 +173,8 @@ class CERES_EXPORT TrivialLoss : public LossFunction {
// http://en.wikipedia.org/wiki/Huber_Loss_Function
class CERES_EXPORT HuberLoss : public LossFunction {
public:
- explicit HuberLoss(double a) : a_(a), b_(a * a) { }
- virtual void Evaluate(double, double*) const;
+ explicit HuberLoss(double a) : a_(a), b_(a * a) {}
+ void Evaluate(double, double*) const override;
private:
const double a_;
@@ -187,11 +186,11 @@ class CERES_EXPORT HuberLoss : public LossFunction {
//
// rho(s) = 2 (sqrt(1 + s) - 1).
//
-// At s = 0: rho = [0, 1, -1/2].
+// At s = 0: rho = [0, 1, -1 / (2 * a^2)].
class CERES_EXPORT SoftLOneLoss : public LossFunction {
public:
- explicit SoftLOneLoss(double a) : b_(a * a), c_(1 / b_) { }
- virtual void Evaluate(double, double*) const;
+ explicit SoftLOneLoss(double a) : b_(a * a), c_(1 / b_) {}
+ void Evaluate(double, double*) const override;
private:
// b = a^2.
@@ -204,11 +203,11 @@ class CERES_EXPORT SoftLOneLoss : public LossFunction {
//
// rho(s) = log(1 + s).
//
-// At s = 0: rho = [0, 1, -1].
+// At s = 0: rho = [0, 1, -1 / a^2].
class CERES_EXPORT CauchyLoss : public LossFunction {
public:
- explicit CauchyLoss(double a) : b_(a * a), c_(1 / b_) { }
- virtual void Evaluate(double, double*) const;
+ explicit CauchyLoss(double a) : b_(a * a), c_(1 / b_) {}
+ void Evaluate(double, double*) const override;
private:
// b = a^2.
@@ -228,8 +227,8 @@ class CERES_EXPORT CauchyLoss : public LossFunction {
// At s = 0: rho = [0, 1, 0].
class CERES_EXPORT ArctanLoss : public LossFunction {
public:
- explicit ArctanLoss(double a) : a_(a), b_(1 / (a * a)) { }
- virtual void Evaluate(double, double*) const;
+ explicit ArctanLoss(double a) : a_(a), b_(1 / (a * a)) {}
+ void Evaluate(double, double*) const override;
private:
const double a_;
@@ -268,7 +267,7 @@ class CERES_EXPORT ArctanLoss : public LossFunction {
class CERES_EXPORT TolerantLoss : public LossFunction {
public:
explicit TolerantLoss(double a, double b);
- virtual void Evaluate(double, double*) const;
+ void Evaluate(double, double*) const override;
private:
const double a_, b_, c_;
@@ -277,16 +276,17 @@ class CERES_EXPORT TolerantLoss : public LossFunction {
// This is the Tukey biweight loss function which aggressively
// attempts to suppress large errors.
//
-// The term is computed as:
+// The term is computed as follows where the equations are scaled by a
+// factor of 2 because the cost function is given by 1/2 rho(s):
//
-// rho(s) = a^2 / 6 * (1 - (1 - s / a^2)^3 ) for s <= a^2,
-// rho(s) = a^2 / 6 for s > a^2.
+// rho(s) = a^2 / 3 * (1 - (1 - s / a^2)^3 ) for s <= a^2,
+// rho(s) = a^2 / 3 for s > a^2.
//
-// At s = 0: rho = [0, 0.5, -1 / a^2]
+// At s = 0: rho = [0, 1, -2 / a^2]
class CERES_EXPORT TukeyLoss : public ceres::LossFunction {
public:
- explicit TukeyLoss(double a) : a_squared_(a * a) { }
- virtual void Evaluate(double, double*) const;
+ explicit TukeyLoss(double a) : a_squared_(a * a) {}
+ void Evaluate(double, double*) const override;
private:
const double a_squared_;
@@ -297,13 +297,15 @@ class CERES_EXPORT TukeyLoss : public ceres::LossFunction {
// The loss functions must not be NULL.
class CERES_EXPORT ComposedLoss : public LossFunction {
public:
- explicit ComposedLoss(const LossFunction* f, Ownership ownership_f,
- const LossFunction* g, Ownership ownership_g);
+ explicit ComposedLoss(const LossFunction* f,
+ Ownership ownership_f,
+ const LossFunction* g,
+ Ownership ownership_g);
virtual ~ComposedLoss();
- virtual void Evaluate(double, double*) const;
+ void Evaluate(double, double*) const override;
private:
- internal::scoped_ptr<const LossFunction> f_, g_;
+ std::unique_ptr<const LossFunction> f_, g_;
const Ownership ownership_f_, ownership_g_;
};
@@ -329,21 +331,22 @@ class CERES_EXPORT ScaledLoss : public LossFunction {
// Constructs a ScaledLoss wrapping another loss function. Takes
// ownership of the wrapped loss function or not depending on the
// ownership parameter.
- ScaledLoss(const LossFunction* rho, double a, Ownership ownership) :
- rho_(rho), a_(a), ownership_(ownership) { }
+ ScaledLoss(const LossFunction* rho, double a, Ownership ownership)
+ : rho_(rho), a_(a), ownership_(ownership) {}
+ ScaledLoss(const ScaledLoss&) = delete;
+ void operator=(const ScaledLoss&) = delete;
virtual ~ScaledLoss() {
if (ownership_ == DO_NOT_TAKE_OWNERSHIP) {
rho_.release();
}
}
- virtual void Evaluate(double, double*) const;
+ void Evaluate(double, double*) const override;
private:
- internal::scoped_ptr<const LossFunction> rho_;
+ std::unique_ptr<const LossFunction> rho_;
const double a_;
const Ownership ownership_;
- CERES_DISALLOW_COPY_AND_ASSIGN(ScaledLoss);
};
// Sometimes after the optimization problem has been constructed, we
@@ -387,8 +390,10 @@ class CERES_EXPORT ScaledLoss : public LossFunction {
class CERES_EXPORT LossFunctionWrapper : public LossFunction {
public:
LossFunctionWrapper(LossFunction* rho, Ownership ownership)
- : rho_(rho), ownership_(ownership) {
- }
+ : rho_(rho), ownership_(ownership) {}
+
+ LossFunctionWrapper(const LossFunctionWrapper&) = delete;
+ void operator=(const LossFunctionWrapper&) = delete;
virtual ~LossFunctionWrapper() {
if (ownership_ == DO_NOT_TAKE_OWNERSHIP) {
@@ -396,13 +401,12 @@ class CERES_EXPORT LossFunctionWrapper : public LossFunction {
}
}
- virtual void Evaluate(double sq_norm, double out[3]) const {
+ void Evaluate(double sq_norm, double out[3]) const override {
if (rho_.get() == NULL) {
out[0] = sq_norm;
out[1] = 1.0;
out[2] = 0.0;
- }
- else {
+ } else {
rho_->Evaluate(sq_norm, out);
}
}
@@ -416,9 +420,8 @@ class CERES_EXPORT LossFunctionWrapper : public LossFunction {
}
private:
- internal::scoped_ptr<const LossFunction> rho_;
+ std::unique_ptr<const LossFunction> rho_;
Ownership ownership_;
- CERES_DISALLOW_COPY_AND_ASSIGN(LossFunctionWrapper);
};
} // namespace ceres
diff --git a/extern/ceres/include/ceres/normal_prior.h b/extern/ceres/include/ceres/normal_prior.h
index cd98b4c846b..14ab379f4af 100644
--- a/extern/ceres/include/ceres/normal_prior.h
+++ b/extern/ceres/include/ceres/normal_prior.h
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2019 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -35,8 +35,8 @@
#define CERES_PUBLIC_NORMAL_PRIOR_H_
#include "ceres/cost_function.h"
-#include "ceres/internal/eigen.h"
#include "ceres/internal/disable_warnings.h"
+#include "ceres/internal/eigen.h"
namespace ceres {
@@ -57,15 +57,15 @@ namespace ceres {
// which would be the case if the covariance matrix S is rank
// deficient.
-class CERES_EXPORT NormalPrior: public CostFunction {
+class CERES_EXPORT NormalPrior : public CostFunction {
public:
// Check that the number of rows in the vector b are the same as the
// number of columns in the matrix A, crash otherwise.
NormalPrior(const Matrix& A, const Vector& b);
+ bool Evaluate(double const* const* parameters,
+ double* residuals,
+ double** jacobians) const override;
- virtual bool Evaluate(double const* const* parameters,
- double* residuals,
- double** jacobians) const;
private:
Matrix A_;
Vector b_;
diff --git a/extern/ceres/include/ceres/numeric_diff_cost_function.h b/extern/ceres/include/ceres/numeric_diff_cost_function.h
index 5dfaeab6241..c69f262f572 100644
--- a/extern/ceres/include/ceres/numeric_diff_cost_function.h
+++ b/extern/ceres/include/ceres/numeric_diff_cost_function.h
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2019 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -52,16 +52,16 @@
// The actual cost added to the total problem is e^2, or (k - x'k)^2; however,
// the squaring is implicitly done by the optimization framework.
//
-// To write an numerically-differentiable cost function for the above model, first
-// define the object
+// To write an numerically-differentiable cost function for the above model,
+// first define the object
//
// class MyScalarCostFunctor {
-// MyScalarCostFunctor(double k): k_(k) {}
+// explicit MyScalarCostFunctor(double k): k_(k) {}
//
// bool operator()(const double* const x,
// const double* const y,
// double* residuals) const {
-// residuals[0] = k_ - x[0] * y[0] + x[1] * y[1];
+// residuals[0] = k_ - x[0] * y[0] - x[1] * y[1];
// return true;
// }
//
@@ -98,6 +98,8 @@
// NumericDiffCostFunction also supports cost functions with a
// runtime-determined number of residuals. For example:
//
+// clang-format off
+//
// CostFunction* cost_function
// = new NumericDiffCostFunction<MyScalarCostFunctor, CENTRAL, DYNAMIC, 2, 2>(
// new CostFunctorWithDynamicNumResiduals(1.0), ^ ^ ^
@@ -109,10 +111,8 @@
// Indicate dynamic number of residuals --------------------+ | |
// Dimension of x ------------------------------------------------+ |
// Dimension of y ---------------------------------------------------+
+// clang-format on
//
-// The framework can currently accommodate cost functions of up to 10
-// independent variables, and there is no limit on the dimensionality
-// of each of them.
//
// The central difference method is considerably more accurate at the cost of
// twice as many function evaluations than forward difference. Consider using
@@ -161,10 +161,13 @@
#ifndef CERES_PUBLIC_NUMERIC_DIFF_COST_FUNCTION_H_
#define CERES_PUBLIC_NUMERIC_DIFF_COST_FUNCTION_H_
+#include <array>
+#include <memory>
+
#include "Eigen/Dense"
#include "ceres/cost_function.h"
#include "ceres/internal/numeric_diff.h"
-#include "ceres/internal/scoped_ptr.h"
+#include "ceres/internal/parameter_dims.h"
#include "ceres/numeric_diff_options.h"
#include "ceres/sized_cost_function.h"
#include "ceres/types.h"
@@ -175,34 +178,17 @@ namespace ceres {
template <typename CostFunctor,
NumericDiffMethodType method = CENTRAL,
int kNumResiduals = 0, // Number of residuals, or ceres::DYNAMIC
- int N0 = 0, // Number of parameters in block 0.
- int N1 = 0, // Number of parameters in block 1.
- int N2 = 0, // Number of parameters in block 2.
- int N3 = 0, // Number of parameters in block 3.
- int N4 = 0, // Number of parameters in block 4.
- int N5 = 0, // Number of parameters in block 5.
- int N6 = 0, // Number of parameters in block 6.
- int N7 = 0, // Number of parameters in block 7.
- int N8 = 0, // Number of parameters in block 8.
- int N9 = 0> // Number of parameters in block 9.
-class NumericDiffCostFunction
- : public SizedCostFunction<kNumResiduals,
- N0, N1, N2, N3, N4,
- N5, N6, N7, N8, N9> {
+ int... Ns> // Parameters dimensions for each block.
+class NumericDiffCostFunction : public SizedCostFunction<kNumResiduals, Ns...> {
public:
NumericDiffCostFunction(
CostFunctor* functor,
Ownership ownership = TAKE_OWNERSHIP,
int num_residuals = kNumResiduals,
const NumericDiffOptions& options = NumericDiffOptions())
- : functor_(functor),
- ownership_(ownership),
- options_(options) {
+ : functor_(functor), ownership_(ownership), options_(options) {
if (kNumResiduals == DYNAMIC) {
- SizedCostFunction<kNumResiduals,
- N0, N1, N2, N3, N4,
- N5, N6, N7, N8, N9>
- ::set_num_residuals(num_residuals);
+ SizedCostFunction<kNumResiduals, Ns...>::set_num_residuals(num_residuals);
}
}
@@ -212,24 +198,21 @@ class NumericDiffCostFunction
}
}
- virtual bool Evaluate(double const* const* parameters,
- double* residuals,
- double** jacobians) const {
+ bool Evaluate(double const* const* parameters,
+ double* residuals,
+ double** jacobians) const override {
using internal::FixedArray;
using internal::NumericDiff;
- const int kNumParameters = N0 + N1 + N2 + N3 + N4 + N5 + N6 + N7 + N8 + N9;
- const int kNumParameterBlocks =
- (N0 > 0) + (N1 > 0) + (N2 > 0) + (N3 > 0) + (N4 > 0) +
- (N5 > 0) + (N6 > 0) + (N7 > 0) + (N8 > 0) + (N9 > 0);
+ using ParameterDims =
+ typename SizedCostFunction<kNumResiduals, Ns...>::ParameterDims;
+
+ constexpr int kNumParameters = ParameterDims::kNumParameters;
+ constexpr int kNumParameterBlocks = ParameterDims::kNumParameterBlocks;
// Get the function value (residuals) at the the point to evaluate.
- if (!internal::EvaluateImpl<CostFunctor,
- N0, N1, N2, N3, N4, N5, N6, N7, N8, N9>(
- functor_.get(),
- parameters,
- residuals,
- functor_.get())) {
+ if (!internal::VariadicEvaluate<ParameterDims>(
+ *functor_, parameters, residuals)) {
return false;
}
@@ -239,77 +222,29 @@ class NumericDiffCostFunction
// Create a copy of the parameters which will get mutated.
FixedArray<double> parameters_copy(kNumParameters);
- FixedArray<double*> parameters_reference_copy(kNumParameterBlocks);
-
- parameters_reference_copy[0] = parameters_copy.get();
- if (N1) parameters_reference_copy[1] = parameters_reference_copy[0] + N0;
- if (N2) parameters_reference_copy[2] = parameters_reference_copy[1] + N1;
- if (N3) parameters_reference_copy[3] = parameters_reference_copy[2] + N2;
- if (N4) parameters_reference_copy[4] = parameters_reference_copy[3] + N3;
- if (N5) parameters_reference_copy[5] = parameters_reference_copy[4] + N4;
- if (N6) parameters_reference_copy[6] = parameters_reference_copy[5] + N5;
- if (N7) parameters_reference_copy[7] = parameters_reference_copy[6] + N6;
- if (N8) parameters_reference_copy[8] = parameters_reference_copy[7] + N7;
- if (N9) parameters_reference_copy[9] = parameters_reference_copy[8] + N8;
+ std::array<double*, kNumParameterBlocks> parameters_reference_copy =
+ ParameterDims::GetUnpackedParameters(parameters_copy.data());
-#define CERES_COPY_PARAMETER_BLOCK(block) \
- if (N ## block) memcpy(parameters_reference_copy[block], \
- parameters[block], \
- sizeof(double) * N ## block); // NOLINT
-
- CERES_COPY_PARAMETER_BLOCK(0);
- CERES_COPY_PARAMETER_BLOCK(1);
- CERES_COPY_PARAMETER_BLOCK(2);
- CERES_COPY_PARAMETER_BLOCK(3);
- CERES_COPY_PARAMETER_BLOCK(4);
- CERES_COPY_PARAMETER_BLOCK(5);
- CERES_COPY_PARAMETER_BLOCK(6);
- CERES_COPY_PARAMETER_BLOCK(7);
- CERES_COPY_PARAMETER_BLOCK(8);
- CERES_COPY_PARAMETER_BLOCK(9);
-
-#undef CERES_COPY_PARAMETER_BLOCK
-
-#define CERES_EVALUATE_JACOBIAN_FOR_BLOCK(block) \
- if (N ## block && jacobians[block] != NULL) { \
- if (!NumericDiff<CostFunctor, \
- method, \
- kNumResiduals, \
- N0, N1, N2, N3, N4, N5, N6, N7, N8, N9, \
- block, \
- N ## block >::EvaluateJacobianForParameterBlock( \
- functor_.get(), \
- residuals, \
- options_, \
- SizedCostFunction<kNumResiduals, \
- N0, N1, N2, N3, N4, \
- N5, N6, N7, N8, N9>::num_residuals(), \
- block, \
- N ## block, \
- parameters_reference_copy.get(), \
- jacobians[block])) { \
- return false; \
- } \
+ for (int block = 0; block < kNumParameterBlocks; ++block) {
+ memcpy(parameters_reference_copy[block],
+ parameters[block],
+ sizeof(double) * ParameterDims::GetDim(block));
}
- CERES_EVALUATE_JACOBIAN_FOR_BLOCK(0);
- CERES_EVALUATE_JACOBIAN_FOR_BLOCK(1);
- CERES_EVALUATE_JACOBIAN_FOR_BLOCK(2);
- CERES_EVALUATE_JACOBIAN_FOR_BLOCK(3);
- CERES_EVALUATE_JACOBIAN_FOR_BLOCK(4);
- CERES_EVALUATE_JACOBIAN_FOR_BLOCK(5);
- CERES_EVALUATE_JACOBIAN_FOR_BLOCK(6);
- CERES_EVALUATE_JACOBIAN_FOR_BLOCK(7);
- CERES_EVALUATE_JACOBIAN_FOR_BLOCK(8);
- CERES_EVALUATE_JACOBIAN_FOR_BLOCK(9);
-
-#undef CERES_EVALUATE_JACOBIAN_FOR_BLOCK
+ internal::EvaluateJacobianForParameterBlocks<ParameterDims>::
+ template Apply<method, kNumResiduals>(
+ functor_.get(),
+ residuals,
+ options_,
+ SizedCostFunction<kNumResiduals, Ns...>::num_residuals(),
+ parameters_reference_copy.data(),
+ jacobians);
return true;
}
private:
- internal::scoped_ptr<CostFunctor> functor_;
+ std::unique_ptr<CostFunctor> functor_;
Ownership ownership_;
NumericDiffOptions options_;
};
diff --git a/extern/ceres/include/ceres/numeric_diff_options.h b/extern/ceres/include/ceres/numeric_diff_options.h
index 119c8a86596..64919ed5ab1 100644
--- a/extern/ceres/include/ceres/numeric_diff_options.h
+++ b/extern/ceres/include/ceres/numeric_diff_options.h
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2019 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -32,23 +32,17 @@
#ifndef CERES_PUBLIC_NUMERIC_DIFF_OPTIONS_H_
#define CERES_PUBLIC_NUMERIC_DIFF_OPTIONS_H_
+#include "ceres/internal/port.h"
+
namespace ceres {
// Options pertaining to numeric differentiation (e.g., convergence criteria,
// step sizes).
struct CERES_EXPORT NumericDiffOptions {
- NumericDiffOptions() {
- relative_step_size = 1e-6;
- ridders_relative_initial_step_size = 1e-2;
- max_num_ridders_extrapolations = 10;
- ridders_epsilon = 1e-12;
- ridders_step_shrink_factor = 2.0;
- }
-
// Numeric differentiation step size (multiplied by parameter block's
// order of magnitude). If parameters are close to zero, the step size
// is set to sqrt(machine_epsilon).
- double relative_step_size;
+ double relative_step_size = 1e-6;
// Initial step size for Ridders adaptive numeric differentiation (multiplied
// by parameter block's order of magnitude).
@@ -59,19 +53,19 @@ struct CERES_EXPORT NumericDiffOptions {
// Note: For Ridders' method to converge, the step size should be initialized
// to a value that is large enough to produce a significant change in the
// function. As the derivative is estimated, the step size decreases.
- double ridders_relative_initial_step_size;
+ double ridders_relative_initial_step_size = 1e-2;
// Maximal number of adaptive extrapolations (sampling) in Ridders' method.
- int max_num_ridders_extrapolations;
+ int max_num_ridders_extrapolations = 10;
// Convergence criterion on extrapolation error for Ridders adaptive
// differentiation. The available error estimation methods are defined in
// NumericDiffErrorType and set in the "ridders_error_method" field.
- double ridders_epsilon;
+ double ridders_epsilon = 1e-12;
// The factor in which to shrink the step size with each extrapolation in
// Ridders' method.
- double ridders_step_shrink_factor;
+ double ridders_step_shrink_factor = 2.0;
};
} // namespace ceres
diff --git a/extern/ceres/include/ceres/ordered_groups.h b/extern/ceres/include/ceres/ordered_groups.h
index aa1bd3a7da1..954663c97e6 100644
--- a/extern/ceres/include/ceres/ordered_groups.h
+++ b/extern/ceres/include/ceres/ordered_groups.h
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2019 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -33,7 +33,9 @@
#include <map>
#include <set>
+#include <unordered_map>
#include <vector>
+
#include "ceres/internal/port.h"
#include "glog/logging.h"
@@ -63,8 +65,7 @@ class OrderedGroups {
return false;
}
- typename std::map<T, int>::const_iterator it =
- element_to_group_.find(element);
+ auto it = element_to_group_.find(element);
if (it != element_to_group_.end()) {
if (it->second == group) {
// Element is already in the right group, nothing to do.
@@ -126,17 +127,14 @@ class OrderedGroups {
return;
}
- typename std::map<int, std::set<T> >::reverse_iterator it =
- group_to_elements_.rbegin();
- std::map<int, std::set<T> > new_group_to_elements;
+ auto it = group_to_elements_.rbegin();
+ std::map<int, std::set<T>> new_group_to_elements;
new_group_to_elements[it->first] = it->second;
int new_group_id = it->first + 1;
for (++it; it != group_to_elements_.rend(); ++it) {
- for (typename std::set<T>::const_iterator element_it = it->second.begin();
- element_it != it->second.end();
- ++element_it) {
- element_to_group_[*element_it] = new_group_id;
+ for (const auto& element : it->second) {
+ element_to_group_[element] = new_group_id;
}
new_group_to_elements[new_group_id] = it->second;
new_group_id++;
@@ -148,8 +146,7 @@ class OrderedGroups {
// Return the group id for the element. If the element is not a
// member of any group, return -1.
int GroupId(const T element) const {
- typename std::map<T, int>::const_iterator it =
- element_to_group_.find(element);
+ auto it = element_to_group_.find(element);
if (it == element_to_group_.end()) {
return -1;
}
@@ -157,27 +154,21 @@ class OrderedGroups {
}
bool IsMember(const T element) const {
- typename std::map<T, int>::const_iterator it =
- element_to_group_.find(element);
+ auto it = element_to_group_.find(element);
return (it != element_to_group_.end());
}
// This function always succeeds, i.e., implicitly there exists a
// group for every integer.
int GroupSize(const int group) const {
- typename std::map<int, std::set<T> >::const_iterator it =
- group_to_elements_.find(group);
- return (it == group_to_elements_.end()) ? 0 : it->second.size();
+ auto it = group_to_elements_.find(group);
+ return (it == group_to_elements_.end()) ? 0 : it->second.size();
}
- int NumElements() const {
- return element_to_group_.size();
- }
+ int NumElements() const { return element_to_group_.size(); }
// Number of groups with one or more elements.
- int NumGroups() const {
- return group_to_elements_.size();
- }
+ int NumGroups() const { return group_to_elements_.size(); }
// The first group with one or more elements. Calling this when
// there are no groups with non-zero elements will result in a
@@ -187,17 +178,15 @@ class OrderedGroups {
return group_to_elements_.begin()->first;
}
- const std::map<int, std::set<T> >& group_to_elements() const {
+ const std::map<int, std::set<T>>& group_to_elements() const {
return group_to_elements_;
}
- const std::map<T, int>& element_to_group() const {
- return element_to_group_;
- }
+ const std::map<T, int>& element_to_group() const { return element_to_group_; }
private:
- std::map<int, std::set<T> > group_to_elements_;
- std::map<T, int> element_to_group_;
+ std::map<int, std::set<T>> group_to_elements_;
+ std::unordered_map<T, int> element_to_group_;
};
// Typedef for the most commonly used version of OrderedGroups.
diff --git a/extern/ceres/include/ceres/problem.h b/extern/ceres/include/ceres/problem.h
index 27ed4ef15da..88f99663f65 100644
--- a/extern/ceres/include/ceres/problem.h
+++ b/extern/ceres/include/ceres/problem.h
@@ -34,22 +34,23 @@
#ifndef CERES_PUBLIC_PROBLEM_H_
#define CERES_PUBLIC_PROBLEM_H_
+#include <array>
#include <cstddef>
#include <map>
+#include <memory>
#include <set>
#include <vector>
-#include "glog/logging.h"
-#include "ceres/internal/macros.h"
+#include "ceres/context.h"
+#include "ceres/internal/disable_warnings.h"
#include "ceres/internal/port.h"
-#include "ceres/internal/scoped_ptr.h"
#include "ceres/types.h"
-#include "ceres/internal/disable_warnings.h"
-
+#include "glog/logging.h"
namespace ceres {
class CostFunction;
+class EvaluationCallback;
class LossFunction;
class LocalParameterization;
class Solver;
@@ -114,20 +115,13 @@ typedef internal::ResidualBlock* ResidualBlockId;
//
// Problem problem;
//
-// problem.AddResidualBlock(new MyUnaryCostFunction(...), x1);
-// problem.AddResidualBlock(new MyBinaryCostFunction(...), x2, x3);
+// problem.AddResidualBlock(new MyUnaryCostFunction(...), nullptr, x1);
+// problem.AddResidualBlock(new MyBinaryCostFunction(...), nullptr, x2, x3);
//
// Please see cost_function.h for details of the CostFunction object.
class CERES_EXPORT Problem {
public:
struct CERES_EXPORT Options {
- Options()
- : cost_function_ownership(TAKE_OWNERSHIP),
- loss_function_ownership(TAKE_OWNERSHIP),
- local_parameterization_ownership(TAKE_OWNERSHIP),
- enable_fast_removal(false),
- disable_all_safety_checks(false) {}
-
// These flags control whether the Problem object owns the cost
// functions, loss functions, and parameterizations passed into
// the Problem. If set to TAKE_OWNERSHIP, then the problem object
@@ -135,25 +129,25 @@ class CERES_EXPORT Problem {
// destruction. The destructor is careful to delete the pointers
// only once, since sharing cost/loss/parameterizations is
// allowed.
- Ownership cost_function_ownership;
- Ownership loss_function_ownership;
- Ownership local_parameterization_ownership;
+ Ownership cost_function_ownership = TAKE_OWNERSHIP;
+ Ownership loss_function_ownership = TAKE_OWNERSHIP;
+ Ownership local_parameterization_ownership = TAKE_OWNERSHIP;
// If true, trades memory for faster RemoveResidualBlock() and
// RemoveParameterBlock() operations.
//
// By default, RemoveParameterBlock() and RemoveResidualBlock() take time
// proportional to the size of the entire problem. If you only ever remove
- // parameters or residuals from the problem occassionally, this might be
+ // parameters or residuals from the problem occasionally, this might be
// acceptable. However, if you have memory to spare, enable this option to
// make RemoveParameterBlock() take time proportional to the number of
// residual blocks that depend on it, and RemoveResidualBlock() take (on
// average) constant time.
//
- // The increase in memory usage is twofold: an additonal hash set per
+ // The increase in memory usage is twofold: an additional hash set per
// parameter block containing all the residuals that depend on the parameter
// block; and a hash set in the problem containing all residuals.
- bool enable_fast_removal;
+ bool enable_fast_removal = false;
// By default, Ceres performs a variety of safety checks when constructing
// the problem. There is a small but measurable performance penalty to
@@ -164,22 +158,51 @@ class CERES_EXPORT Problem {
//
// WARNING: Do not set this to true, unless you are absolutely sure of what
// you are doing.
- bool disable_all_safety_checks;
+ bool disable_all_safety_checks = false;
+
+ // A Ceres global context to use for solving this problem. This may help to
+ // reduce computation time as Ceres can reuse expensive objects to create.
+ // The context object can be nullptr, in which case Ceres may create one.
+ //
+ // Ceres does NOT take ownership of the pointer.
+ Context* context = nullptr;
+
+ // Using this callback interface, Ceres can notify you when it is
+ // about to evaluate the residuals or jacobians. With the
+ // callback, you can share computation between residual blocks by
+ // doing the shared computation in
+ // EvaluationCallback::PrepareForEvaluation() before Ceres calls
+ // CostFunction::Evaluate(). It also enables caching results
+ // between a pure residual evaluation and a residual & jacobian
+ // evaluation.
+ //
+ // Problem DOES NOT take ownership of the callback.
+ //
+ // NOTE: Evaluation callbacks are incompatible with inner
+ // iterations. So calling Solve with
+ // Solver::Options::use_inner_iterations = true on a Problem with
+ // a non-null evaluation callback is an error.
+ EvaluationCallback* evaluation_callback = nullptr;
};
// The default constructor is equivalent to the
// invocation Problem(Problem::Options()).
Problem();
explicit Problem(const Options& options);
+ Problem(Problem&&);
+ Problem& operator=(Problem&&);
+
+ Problem(const Problem&) = delete;
+ Problem& operator=(const Problem&) = delete;
~Problem();
// Add a residual block to the overall cost function. The cost
- // function carries with it information about the sizes of the
+ // function carries with its information about the sizes of the
// parameter blocks it expects. The function checks that these match
// the sizes of the parameter blocks listed in parameter_blocks. The
// program aborts if a mismatch is detected. loss_function can be
- // NULL, in which case the cost of the term is just the squared norm
+ // nullptr, in which case the cost of the term is just the squared norm
// of the residuals.
//
// The user has the option of explicitly adding the parameter blocks
@@ -208,59 +231,35 @@ class CERES_EXPORT Problem {
//
// Problem problem;
//
- // problem.AddResidualBlock(new MyUnaryCostFunction(...), NULL, x1);
- // problem.AddResidualBlock(new MyBinaryCostFunction(...), NULL, x2, x1);
+ // problem.AddResidualBlock(new MyUnaryCostFunction(...), nullptr, x1);
+ // problem.AddResidualBlock(new MyBinaryCostFunction(...), nullptr, x2, x1);
//
+ // Add a residual block by listing the parameter block pointers
+ // directly instead of wapping them in a container.
+ template <typename... Ts>
+ ResidualBlockId AddResidualBlock(CostFunction* cost_function,
+ LossFunction* loss_function,
+ double* x0,
+ Ts*... xs) {
+ const std::array<double*, sizeof...(Ts) + 1> parameter_blocks{{x0, xs...}};
+ return AddResidualBlock(cost_function,
+ loss_function,
+ parameter_blocks.data(),
+ static_cast<int>(parameter_blocks.size()));
+ }
+
+ // Add a residual block by providing a vector of parameter blocks.
ResidualBlockId AddResidualBlock(
CostFunction* cost_function,
LossFunction* loss_function,
const std::vector<double*>& parameter_blocks);
- // Convenience methods for adding residuals with a small number of
- // parameters. This is the common case. Instead of specifying the
- // parameter block arguments as a vector, list them as pointers.
- ResidualBlockId AddResidualBlock(CostFunction* cost_function,
- LossFunction* loss_function,
- double* x0);
- ResidualBlockId AddResidualBlock(CostFunction* cost_function,
- LossFunction* loss_function,
- double* x0, double* x1);
+ // Add a residual block by providing a pointer to the parameter block array
+ // and the number of parameter blocks.
ResidualBlockId AddResidualBlock(CostFunction* cost_function,
LossFunction* loss_function,
- double* x0, double* x1, double* x2);
- ResidualBlockId AddResidualBlock(CostFunction* cost_function,
- LossFunction* loss_function,
- double* x0, double* x1, double* x2,
- double* x3);
- ResidualBlockId AddResidualBlock(CostFunction* cost_function,
- LossFunction* loss_function,
- double* x0, double* x1, double* x2,
- double* x3, double* x4);
- ResidualBlockId AddResidualBlock(CostFunction* cost_function,
- LossFunction* loss_function,
- double* x0, double* x1, double* x2,
- double* x3, double* x4, double* x5);
- ResidualBlockId AddResidualBlock(CostFunction* cost_function,
- LossFunction* loss_function,
- double* x0, double* x1, double* x2,
- double* x3, double* x4, double* x5,
- double* x6);
- ResidualBlockId AddResidualBlock(CostFunction* cost_function,
- LossFunction* loss_function,
- double* x0, double* x1, double* x2,
- double* x3, double* x4, double* x5,
- double* x6, double* x7);
- ResidualBlockId AddResidualBlock(CostFunction* cost_function,
- LossFunction* loss_function,
- double* x0, double* x1, double* x2,
- double* x3, double* x4, double* x5,
- double* x6, double* x7, double* x8);
- ResidualBlockId AddResidualBlock(CostFunction* cost_function,
- LossFunction* loss_function,
- double* x0, double* x1, double* x2,
- double* x3, double* x4, double* x5,
- double* x6, double* x7, double* x8,
- double* x9);
+ double* const* const parameter_blocks,
+ int num_parameter_blocks);
// Add a parameter block with appropriate size to the problem.
// Repeated calls with the same arguments are ignored. Repeated
@@ -290,7 +289,7 @@ class CERES_EXPORT Problem {
// ordering, rendering the jacobian or residuals returned from the solver
// uninterpretable. If you depend on the evaluated jacobian, do not use
// remove! This may change in a future release.
- void RemoveParameterBlock(double* values);
+ void RemoveParameterBlock(const double* values);
// Remove a residual block from the problem. Any parameters that the residual
// block depends on are not removed. The cost and loss functions for the
@@ -304,32 +303,43 @@ class CERES_EXPORT Problem {
void RemoveResidualBlock(ResidualBlockId residual_block);
// Hold the indicated parameter block constant during optimization.
- void SetParameterBlockConstant(double* values);
+ void SetParameterBlockConstant(const double* values);
// Allow the indicated parameter block to vary during optimization.
void SetParameterBlockVariable(double* values);
- // Returns true if a parameter block is set constant, and false otherwise.
- bool IsParameterBlockConstant(double* values) const;
+ // Returns true if a parameter block is set constant, and false
+ // otherwise. A parameter block may be set constant in two ways:
+ // either by calling SetParameterBlockConstant or by associating a
+ // LocalParameterization with a zero dimensional tangent space with
+ // it.
+ bool IsParameterBlockConstant(const double* values) const;
// Set the local parameterization for one of the parameter blocks.
// The local_parameterization is owned by the Problem by default. It
// is acceptable to set the same parameterization for multiple
// parameters; the destructor is careful to delete local
- // parameterizations only once. The local parameterization can only
- // be set once per parameter, and cannot be changed once set.
+ // parameterizations only once. Calling SetParameterization with
+ // nullptr will clear any previously set parameterization.
void SetParameterization(double* values,
LocalParameterization* local_parameterization);
// Get the local parameterization object associated with this
// parameter block. If there is no parameterization object
- // associated then NULL is returned.
- const LocalParameterization* GetParameterization(double* values) const;
+ // associated then nullptr is returned.
+ const LocalParameterization* GetParameterization(const double* values) const;
- // Set the lower/upper bound for the parameter with position "index".
+ // Set the lower/upper bound for the parameter at position "index".
void SetParameterLowerBound(double* values, int index, double lower_bound);
void SetParameterUpperBound(double* values, int index, double upper_bound);
+ // Get the lower/upper bound for the parameter at position
+ // "index". If the parameter is not bounded by the user, then its
+ // lower bound is -std::numeric_limits<double>::max() and upper
+ // bound is std::numeric_limits<double>::max().
+ double GetParameterLowerBound(const double* values, int index) const;
+ double GetParameterUpperBound(const double* values, int index) const;
+
// Number of parameter blocks in the problem. Always equals
// parameter_blocks().size() and parameter_block_sizes().size().
int NumParameterBlocks() const;
@@ -376,7 +386,7 @@ class CERES_EXPORT Problem {
const CostFunction* GetCostFunctionForResidualBlock(
const ResidualBlockId residual_block) const;
- // Get the LossFunction for the given residual block. Returns NULL
+ // Get the LossFunction for the given residual block. Returns nullptr
// if no loss function is associated with this residual block.
const LossFunction* GetLossFunctionForResidualBlock(
const ResidualBlockId residual_block) const;
@@ -393,11 +403,6 @@ class CERES_EXPORT Problem {
// Options struct to control Problem::Evaluate.
struct EvaluateOptions {
- EvaluateOptions()
- : apply_loss_function(true),
- num_threads(1) {
- }
-
// The set of parameter blocks for which evaluation should be
// performed. This vector determines the order that parameter
// blocks occur in the gradient vector and in the columns of the
@@ -430,12 +435,12 @@ class CERES_EXPORT Problem {
// function. This is of use for example if the user wishes to
// analyse the solution quality by studying the distribution of
// residuals before and after the solve.
- bool apply_loss_function;
+ bool apply_loss_function = true;
- int num_threads;
+ int num_threads = 1;
};
- // Evaluate Problem. Any of the output pointers can be NULL. Which
+ // Evaluate Problem. Any of the output pointers can be nullptr. Which
// residual blocks and parameter blocks are used is controlled by
// the EvaluateOptions struct above.
//
@@ -445,16 +450,16 @@ class CERES_EXPORT Problem {
//
// Problem problem;
// double x = 1;
- // problem.AddResidualBlock(new MyCostFunction, NULL, &x);
+ // problem.AddResidualBlock(new MyCostFunction, nullptr, &x);
//
// double cost = 0.0;
- // problem.Evaluate(Problem::EvaluateOptions(), &cost, NULL, NULL, NULL);
+ // problem.Evaluate(Problem::EvaluateOptions(), &cost, nullptr, nullptr, nullptr);
//
// The cost is evaluated at x = 1. If you wish to evaluate the
// problem at x = 2, then
//
- // x = 2;
- // problem.Evaluate(Problem::EvaluateOptions(), &cost, NULL, NULL, NULL);
+ // x = 2;
+ // problem.Evaluate(Problem::EvaluateOptions(), &cost, nullptr, nullptr, nullptr);
//
// is the way to do so.
//
@@ -468,17 +473,63 @@ class CERES_EXPORT Problem {
// Note 3: This function cannot be called while the problem is being
// solved, for example it cannot be called from an IterationCallback
// at the end of an iteration during a solve.
+ //
+ // Note 4: If an EvaluationCallback is associated with the problem,
+ // then its PrepareForEvaluation method will be called everytime
+ // this method is called with new_point = true.
bool Evaluate(const EvaluateOptions& options,
double* cost,
std::vector<double>* residuals,
std::vector<double>* gradient,
CRSMatrix* jacobian);
+ // Evaluates the residual block, storing the scalar cost in *cost,
+ // the residual components in *residuals, and the jacobians between
+ // the parameters and residuals in jacobians[i], in row-major order.
+ //
+ // If residuals is nullptr, the residuals are not computed.
+ //
+ // If jacobians is nullptr, no Jacobians are computed. If
+ // jacobians[i] is nullptr, then the Jacobian for that parameter
+ // block is not computed.
+ //
+ // It is not okay to request the Jacobian w.r.t a parameter block
+ // that is constant.
+ //
+ // The return value indicates the success or failure. Even if the
+ // function returns false, the caller should expect the output
+ // memory locations to have been modified.
+ //
+ // The returned cost and jacobians have had robustification and
+ // local parameterizations applied already; for example, the
+ // jacobian for a 4-dimensional quaternion parameter using the
+ // "QuaternionParameterization" is num_residuals by 3 instead of
+ // num_residuals by 4.
+ //
+ // apply_loss_function as the name implies allows the user to switch
+ // the application of the loss function on and off.
+ //
+ // WARNING: If an EvaluationCallback is associated with the problem
+ // then it is the user's responsibility to call it before calling
+ // this method.
+ //
+ // This is because, if the user calls this method multiple times, we
+ // cannot tell if the underlying parameter blocks have changed
+ // between calls or not. So if EvaluateResidualBlock was responsible
+ // for calling the EvaluationCallback, it will have to do it
+ // everytime it is called. Which makes the common case where the
+ // parameter blocks do not change, inefficient. So we leave it to
+ // the user to call the EvaluationCallback as needed.
+ bool EvaluateResidualBlock(ResidualBlockId residual_block_id,
+ bool apply_loss_function,
+ double* cost,
+ double* residuals,
+ double** jacobians) const;
+
private:
friend class Solver;
friend class Covariance;
- internal::scoped_ptr<internal::ProblemImpl> problem_impl_;
- CERES_DISALLOW_COPY_AND_ASSIGN(Problem);
+ std::unique_ptr<internal::ProblemImpl> impl_;
};
} // namespace ceres
diff --git a/extern/ceres/include/ceres/rotation.h b/extern/ceres/include/ceres/rotation.h
index b6a06f772c4..7d5c8ef1fb2 100644
--- a/extern/ceres/include/ceres/rotation.h
+++ b/extern/ceres/include/ceres/rotation.h
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2019 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -49,6 +49,8 @@
#include <cmath>
#include <limits>
+#include "glog/logging.h"
+
namespace ceres {
// Trivial wrapper to index linear arrays as matrices, given a fixed
@@ -82,47 +84,44 @@ MatrixAdapter<T, 3, 1> RowMajorAdapter3x3(T* pointer);
// and quaternion is a 4-tuple that will contain the resulting quaternion.
// The implementation may be used with auto-differentiation up to the first
// derivative, higher derivatives may have unexpected results near the origin.
-template<typename T>
+template <typename T>
void AngleAxisToQuaternion(const T* angle_axis, T* quaternion);
// Convert a quaternion to the equivalent combined axis-angle representation.
// The value quaternion must be a unit quaternion - it is not normalized first,
// and angle_axis will be filled with a value whose norm is the angle of
// rotation in radians, and whose direction is the axis of rotation.
-// The implemention may be used with auto-differentiation up to the first
+// The implementation may be used with auto-differentiation up to the first
// derivative, higher derivatives may have unexpected results near the origin.
-template<typename T>
+template <typename T>
void QuaternionToAngleAxis(const T* quaternion, T* angle_axis);
// Conversions between 3x3 rotation matrix (in column major order) and
-// quaternion rotation representations. Templated for use with
+// quaternion rotation representations. Templated for use with
// autodifferentiation.
template <typename T>
void RotationMatrixToQuaternion(const T* R, T* quaternion);
template <typename T, int row_stride, int col_stride>
void RotationMatrixToQuaternion(
- const MatrixAdapter<const T, row_stride, col_stride>& R,
- T* quaternion);
+ const MatrixAdapter<const T, row_stride, col_stride>& R, T* quaternion);
// Conversions between 3x3 rotation matrix (in column major order) and
-// axis-angle rotation representations. Templated for use with
+// axis-angle rotation representations. Templated for use with
// autodifferentiation.
template <typename T>
void RotationMatrixToAngleAxis(const T* R, T* angle_axis);
template <typename T, int row_stride, int col_stride>
void RotationMatrixToAngleAxis(
- const MatrixAdapter<const T, row_stride, col_stride>& R,
- T* angle_axis);
+ const MatrixAdapter<const T, row_stride, col_stride>& R, T* angle_axis);
template <typename T>
void AngleAxisToRotationMatrix(const T* angle_axis, T* R);
template <typename T, int row_stride, int col_stride>
void AngleAxisToRotationMatrix(
- const T* angle_axis,
- const MatrixAdapter<T, row_stride, col_stride>& R);
+ const T* angle_axis, const MatrixAdapter<T, row_stride, col_stride>& R);
// Conversions between 3x3 rotation matrix (in row major order) and
// Euler angle (in degrees) rotation representations.
@@ -135,8 +134,7 @@ void EulerAnglesToRotationMatrix(const T* euler, int row_stride, T* R);
template <typename T, int row_stride, int col_stride>
void EulerAnglesToRotationMatrix(
- const T* euler,
- const MatrixAdapter<T, row_stride, col_stride>& R);
+ const T* euler, const MatrixAdapter<T, row_stride, col_stride>& R);
// Convert a 4-vector to a 3x3 scaled rotation matrix.
//
@@ -157,25 +155,23 @@ void EulerAnglesToRotationMatrix(
// such that det(Q) = 1 and Q*Q' = I
//
// WARNING: The rotation matrix is ROW MAJOR
-template <typename T> inline
-void QuaternionToScaledRotation(const T q[4], T R[3 * 3]);
+template <typename T>
+inline void QuaternionToScaledRotation(const T q[4], T R[3 * 3]);
-template <typename T, int row_stride, int col_stride> inline
-void QuaternionToScaledRotation(
- const T q[4],
- const MatrixAdapter<T, row_stride, col_stride>& R);
+template <typename T, int row_stride, int col_stride>
+inline void QuaternionToScaledRotation(
+ const T q[4], const MatrixAdapter<T, row_stride, col_stride>& R);
// Same as above except that the rotation matrix is normalized by the
// Frobenius norm, so that R * R' = I (and det(R) = 1).
//
// WARNING: The rotation matrix is ROW MAJOR
-template <typename T> inline
-void QuaternionToRotation(const T q[4], T R[3 * 3]);
+template <typename T>
+inline void QuaternionToRotation(const T q[4], T R[3 * 3]);
-template <typename T, int row_stride, int col_stride> inline
-void QuaternionToRotation(
- const T q[4],
- const MatrixAdapter<T, row_stride, col_stride>& R);
+template <typename T, int row_stride, int col_stride>
+inline void QuaternionToRotation(
+ const T q[4], const MatrixAdapter<T, row_stride, col_stride>& R);
// Rotates a point pt by a quaternion q:
//
@@ -185,37 +181,54 @@ void QuaternionToRotation(
// write the transform as (something)*pt + pt, as is clear from the
// formula below. If you pass in a quaternion with |q|^2 = 2 then you
// WILL NOT get back 2 times the result you get for a unit quaternion.
-template <typename T> inline
-void UnitQuaternionRotatePoint(const T q[4], const T pt[3], T result[3]);
+//
+// Inplace rotation is not supported. pt and result must point to different
+// memory locations, otherwise the result will be undefined.
+template <typename T>
+inline void UnitQuaternionRotatePoint(const T q[4], const T pt[3], T result[3]);
// With this function you do not need to assume that q has unit norm.
// It does assume that the norm is non-zero.
-template <typename T> inline
-void QuaternionRotatePoint(const T q[4], const T pt[3], T result[3]);
+//
+// Inplace rotation is not supported. pt and result must point to different
+// memory locations, otherwise the result will be undefined.
+template <typename T>
+inline void QuaternionRotatePoint(const T q[4], const T pt[3], T result[3]);
// zw = z * w, where * is the Quaternion product between 4 vectors.
-template<typename T> inline
-void QuaternionProduct(const T z[4], const T w[4], T zw[4]);
+//
+// Inplace quaternion product is not supported. The resulting quaternion zw must
+// not share the memory with the input quaternion z and w, otherwise the result
+// will be undefined.
+template <typename T>
+inline void QuaternionProduct(const T z[4], const T w[4], T zw[4]);
// xy = x cross y;
-template<typename T> inline
-void CrossProduct(const T x[3], const T y[3], T x_cross_y[3]);
+//
+// Inplace cross product is not supported. The resulting vector x_cross_y must
+// not share the memory with the input vectors x and y, otherwise the result
+// will be undefined.
+template <typename T>
+inline void CrossProduct(const T x[3], const T y[3], T x_cross_y[3]);
-template<typename T> inline
-T DotProduct(const T x[3], const T y[3]);
+template <typename T>
+inline T DotProduct(const T x[3], const T y[3]);
// y = R(angle_axis) * x;
-template<typename T> inline
-void AngleAxisRotatePoint(const T angle_axis[3], const T pt[3], T result[3]);
+//
+// Inplace rotation is not supported. pt and result must point to different
+// memory locations, otherwise the result will be undefined.
+template <typename T>
+inline void AngleAxisRotatePoint(const T angle_axis[3],
+ const T pt[3],
+ T result[3]);
// --- IMPLEMENTATION
-template<typename T, int row_stride, int col_stride>
+template <typename T, int row_stride, int col_stride>
struct MatrixAdapter {
T* pointer_;
- explicit MatrixAdapter(T* pointer)
- : pointer_(pointer)
- {}
+ explicit MatrixAdapter(T* pointer) : pointer_(pointer) {}
T& operator()(int r, int c) const {
return pointer_[r * row_stride + c * col_stride];
@@ -232,7 +245,7 @@ MatrixAdapter<T, 3, 1> RowMajorAdapter3x3(T* pointer) {
return MatrixAdapter<T, 3, 1>(pointer);
}
-template<typename T>
+template <typename T>
inline void AngleAxisToQuaternion(const T* angle_axis, T* quaternion) {
const T& a0 = angle_axis[0];
const T& a1 = angle_axis[1];
@@ -261,7 +274,7 @@ inline void AngleAxisToQuaternion(const T* angle_axis, T* quaternion) {
}
}
-template<typename T>
+template <typename T>
inline void QuaternionToAngleAxis(const T* quaternion, T* angle_axis) {
const T& q1 = quaternion[1];
const T& q2 = quaternion[2];
@@ -288,9 +301,8 @@ inline void QuaternionToAngleAxis(const T* quaternion, T* angle_axis) {
// = atan(-sin(theta), -cos(theta))
//
const T two_theta =
- T(2.0) * ((cos_theta < 0.0)
- ? atan2(-sin_theta, -cos_theta)
- : atan2(sin_theta, cos_theta));
+ T(2.0) * ((cos_theta < T(0.0)) ? atan2(-sin_theta, -cos_theta)
+ : atan2(sin_theta, cos_theta));
const T k = two_theta / sin_theta;
angle_axis[0] = q1 * k;
angle_axis[1] = q2 * k;
@@ -316,8 +328,7 @@ void RotationMatrixToQuaternion(const T* R, T* angle_axis) {
// Ken Shoemake, 1987 SIGGRAPH course notes
template <typename T, int row_stride, int col_stride>
void RotationMatrixToQuaternion(
- const MatrixAdapter<const T, row_stride, col_stride>& R,
- T* quaternion) {
+ const MatrixAdapter<const T, row_stride, col_stride>& R, T* quaternion) {
const T trace = R(0, 0) + R(1, 1) + R(2, 2);
if (trace >= 0.0) {
T t = sqrt(trace + T(1.0));
@@ -359,8 +370,7 @@ inline void RotationMatrixToAngleAxis(const T* R, T* angle_axis) {
template <typename T, int row_stride, int col_stride>
void RotationMatrixToAngleAxis(
- const MatrixAdapter<const T, row_stride, col_stride>& R,
- T* angle_axis) {
+ const MatrixAdapter<const T, row_stride, col_stride>& R, T* angle_axis) {
T quaternion[4];
RotationMatrixToQuaternion(R, quaternion);
QuaternionToAngleAxis(quaternion, angle_axis);
@@ -374,8 +384,7 @@ inline void AngleAxisToRotationMatrix(const T* angle_axis, T* R) {
template <typename T, int row_stride, int col_stride>
void AngleAxisToRotationMatrix(
- const T* angle_axis,
- const MatrixAdapter<T, row_stride, col_stride>& R) {
+ const T* angle_axis, const MatrixAdapter<T, row_stride, col_stride>& R) {
static const T kOne = T(1.0);
const T theta2 = DotProduct(angle_axis, angle_axis);
if (theta2 > T(std::numeric_limits<double>::epsilon())) {
@@ -390,6 +399,7 @@ void AngleAxisToRotationMatrix(
const T costheta = cos(theta);
const T sintheta = sin(theta);
+ // clang-format off
R(0, 0) = costheta + wx*wx*(kOne - costheta);
R(1, 0) = wz*sintheta + wx*wy*(kOne - costheta);
R(2, 0) = -wy*sintheta + wx*wz*(kOne - costheta);
@@ -399,15 +409,16 @@ void AngleAxisToRotationMatrix(
R(0, 2) = wy*sintheta + wx*wz*(kOne - costheta);
R(1, 2) = -wx*sintheta + wy*wz*(kOne - costheta);
R(2, 2) = costheta + wz*wz*(kOne - costheta);
+ // clang-format on
} else {
// Near zero, we switch to using the first order Taylor expansion.
- R(0, 0) = kOne;
- R(1, 0) = angle_axis[2];
+ R(0, 0) = kOne;
+ R(1, 0) = angle_axis[2];
R(2, 0) = -angle_axis[1];
R(0, 1) = -angle_axis[2];
- R(1, 1) = kOne;
- R(2, 1) = angle_axis[0];
- R(0, 2) = angle_axis[1];
+ R(1, 1) = kOne;
+ R(2, 1) = angle_axis[0];
+ R(0, 2) = angle_axis[1];
R(1, 2) = -angle_axis[0];
R(2, 2) = kOne;
}
@@ -422,8 +433,7 @@ inline void EulerAnglesToRotationMatrix(const T* euler,
template <typename T, int row_stride, int col_stride>
void EulerAnglesToRotationMatrix(
- const T* euler,
- const MatrixAdapter<T, row_stride, col_stride>& R) {
+ const T* euler, const MatrixAdapter<T, row_stride, col_stride>& R) {
const double kPi = 3.14159265358979323846;
const T degrees_to_radians(kPi / 180.0);
@@ -438,28 +448,27 @@ void EulerAnglesToRotationMatrix(
const T c3 = cos(pitch);
const T s3 = sin(pitch);
- R(0, 0) = c1*c2;
- R(0, 1) = -s1*c3 + c1*s2*s3;
- R(0, 2) = s1*s3 + c1*s2*c3;
+ R(0, 0) = c1 * c2;
+ R(0, 1) = -s1 * c3 + c1 * s2 * s3;
+ R(0, 2) = s1 * s3 + c1 * s2 * c3;
- R(1, 0) = s1*c2;
- R(1, 1) = c1*c3 + s1*s2*s3;
- R(1, 2) = -c1*s3 + s1*s2*c3;
+ R(1, 0) = s1 * c2;
+ R(1, 1) = c1 * c3 + s1 * s2 * s3;
+ R(1, 2) = -c1 * s3 + s1 * s2 * c3;
R(2, 0) = -s2;
- R(2, 1) = c2*s3;
- R(2, 2) = c2*c3;
+ R(2, 1) = c2 * s3;
+ R(2, 2) = c2 * c3;
}
-template <typename T> inline
-void QuaternionToScaledRotation(const T q[4], T R[3 * 3]) {
+template <typename T>
+inline void QuaternionToScaledRotation(const T q[4], T R[3 * 3]) {
QuaternionToScaledRotation(q, RowMajorAdapter3x3(R));
}
-template <typename T, int row_stride, int col_stride> inline
-void QuaternionToScaledRotation(
- const T q[4],
- const MatrixAdapter<T, row_stride, col_stride>& R) {
+template <typename T, int row_stride, int col_stride>
+inline void QuaternionToScaledRotation(
+ const T q[4], const MatrixAdapter<T, row_stride, col_stride>& R) {
// Make convenient names for elements of q.
T a = q[0];
T b = q[1];
@@ -478,22 +487,24 @@ void QuaternionToScaledRotation(
T cd = c * d;
T dd = d * d;
- R(0, 0) = aa + bb - cc - dd; R(0, 1) = T(2) * (bc - ad); R(0, 2) = T(2) * (ac + bd); // NOLINT
- R(1, 0) = T(2) * (ad + bc); R(1, 1) = aa - bb + cc - dd; R(1, 2) = T(2) * (cd - ab); // NOLINT
- R(2, 0) = T(2) * (bd - ac); R(2, 1) = T(2) * (ab + cd); R(2, 2) = aa - bb - cc + dd; // NOLINT
+ // clang-format off
+ R(0, 0) = aa + bb - cc - dd; R(0, 1) = T(2) * (bc - ad); R(0, 2) = T(2) * (ac + bd);
+ R(1, 0) = T(2) * (ad + bc); R(1, 1) = aa - bb + cc - dd; R(1, 2) = T(2) * (cd - ab);
+ R(2, 0) = T(2) * (bd - ac); R(2, 1) = T(2) * (ab + cd); R(2, 2) = aa - bb - cc + dd;
+ // clang-format on
}
-template <typename T> inline
-void QuaternionToRotation(const T q[4], T R[3 * 3]) {
+template <typename T>
+inline void QuaternionToRotation(const T q[4], T R[3 * 3]) {
QuaternionToRotation(q, RowMajorAdapter3x3(R));
}
-template <typename T, int row_stride, int col_stride> inline
-void QuaternionToRotation(const T q[4],
- const MatrixAdapter<T, row_stride, col_stride>& R) {
+template <typename T, int row_stride, int col_stride>
+inline void QuaternionToRotation(
+ const T q[4], const MatrixAdapter<T, row_stride, col_stride>& R) {
QuaternionToScaledRotation(q, R);
- T normalizer = q[0]*q[0] + q[1]*q[1] + q[2]*q[2] + q[3]*q[3];
+ T normalizer = q[0] * q[0] + q[1] * q[1] + q[2] * q[2] + q[3] * q[3];
normalizer = T(1) / normalizer;
for (int i = 0; i < 3; ++i) {
@@ -503,8 +514,13 @@ void QuaternionToRotation(const T q[4],
}
}
-template <typename T> inline
-void UnitQuaternionRotatePoint(const T q[4], const T pt[3], T result[3]) {
+template <typename T>
+inline void UnitQuaternionRotatePoint(const T q[4],
+ const T pt[3],
+ T result[3]) {
+ DCHECK_NE(pt, result) << "Inplace rotation is not supported.";
+
+ // clang-format off
const T t2 = q[0] * q[1];
const T t3 = q[0] * q[2];
const T t4 = q[0] * q[3];
@@ -517,50 +533,63 @@ void UnitQuaternionRotatePoint(const T q[4], const T pt[3], T result[3]) {
result[0] = T(2) * ((t8 + t1) * pt[0] + (t6 - t4) * pt[1] + (t3 + t7) * pt[2]) + pt[0]; // NOLINT
result[1] = T(2) * ((t4 + t6) * pt[0] + (t5 + t1) * pt[1] + (t9 - t2) * pt[2]) + pt[1]; // NOLINT
result[2] = T(2) * ((t7 - t3) * pt[0] + (t2 + t9) * pt[1] + (t5 + t8) * pt[2]) + pt[2]; // NOLINT
+ // clang-format on
}
-template <typename T> inline
-void QuaternionRotatePoint(const T q[4], const T pt[3], T result[3]) {
+template <typename T>
+inline void QuaternionRotatePoint(const T q[4], const T pt[3], T result[3]) {
+ DCHECK_NE(pt, result) << "Inplace rotation is not supported.";
+
// 'scale' is 1 / norm(q).
- const T scale = T(1) / sqrt(q[0] * q[0] +
- q[1] * q[1] +
- q[2] * q[2] +
- q[3] * q[3]);
+ const T scale =
+ T(1) / sqrt(q[0] * q[0] + q[1] * q[1] + q[2] * q[2] + q[3] * q[3]);
// Make unit-norm version of q.
const T unit[4] = {
- scale * q[0],
- scale * q[1],
- scale * q[2],
- scale * q[3],
+ scale * q[0],
+ scale * q[1],
+ scale * q[2],
+ scale * q[3],
};
UnitQuaternionRotatePoint(unit, pt, result);
}
-template<typename T> inline
-void QuaternionProduct(const T z[4], const T w[4], T zw[4]) {
+template <typename T>
+inline void QuaternionProduct(const T z[4], const T w[4], T zw[4]) {
+ DCHECK_NE(z, zw) << "Inplace quaternion product is not supported.";
+ DCHECK_NE(w, zw) << "Inplace quaternion product is not supported.";
+
+ // clang-format off
zw[0] = z[0] * w[0] - z[1] * w[1] - z[2] * w[2] - z[3] * w[3];
zw[1] = z[0] * w[1] + z[1] * w[0] + z[2] * w[3] - z[3] * w[2];
zw[2] = z[0] * w[2] - z[1] * w[3] + z[2] * w[0] + z[3] * w[1];
zw[3] = z[0] * w[3] + z[1] * w[2] - z[2] * w[1] + z[3] * w[0];
+ // clang-format on
}
// xy = x cross y;
-template<typename T> inline
-void CrossProduct(const T x[3], const T y[3], T x_cross_y[3]) {
+template <typename T>
+inline void CrossProduct(const T x[3], const T y[3], T x_cross_y[3]) {
+ DCHECK_NE(x, x_cross_y) << "Inplace cross product is not supported.";
+ DCHECK_NE(y, x_cross_y) << "Inplace cross product is not supported.";
+
x_cross_y[0] = x[1] * y[2] - x[2] * y[1];
x_cross_y[1] = x[2] * y[0] - x[0] * y[2];
x_cross_y[2] = x[0] * y[1] - x[1] * y[0];
}
-template<typename T> inline
-T DotProduct(const T x[3], const T y[3]) {
+template <typename T>
+inline T DotProduct(const T x[3], const T y[3]) {
return (x[0] * y[0] + x[1] * y[1] + x[2] * y[2]);
}
-template<typename T> inline
-void AngleAxisRotatePoint(const T angle_axis[3], const T pt[3], T result[3]) {
+template <typename T>
+inline void AngleAxisRotatePoint(const T angle_axis[3],
+ const T pt[3],
+ T result[3]) {
+ DCHECK_NE(pt, result) << "Inplace rotation is not supported.";
+
const T theta2 = DotProduct(angle_axis, angle_axis);
if (theta2 > T(std::numeric_limits<double>::epsilon())) {
// Away from zero, use the rodriguez formula
@@ -576,17 +605,17 @@ void AngleAxisRotatePoint(const T angle_axis[3], const T pt[3], T result[3]) {
const T theta = sqrt(theta2);
const T costheta = cos(theta);
const T sintheta = sin(theta);
- const T theta_inverse = 1.0 / theta;
+ const T theta_inverse = T(1.0) / theta;
- const T w[3] = { angle_axis[0] * theta_inverse,
- angle_axis[1] * theta_inverse,
- angle_axis[2] * theta_inverse };
+ const T w[3] = {angle_axis[0] * theta_inverse,
+ angle_axis[1] * theta_inverse,
+ angle_axis[2] * theta_inverse};
// Explicitly inlined evaluation of the cross product for
// performance reasons.
- const T w_cross_pt[3] = { w[1] * pt[2] - w[2] * pt[1],
- w[2] * pt[0] - w[0] * pt[2],
- w[0] * pt[1] - w[1] * pt[0] };
+ const T w_cross_pt[3] = {w[1] * pt[2] - w[2] * pt[1],
+ w[2] * pt[0] - w[0] * pt[2],
+ w[0] * pt[1] - w[1] * pt[0]};
const T tmp =
(w[0] * pt[0] + w[1] * pt[1] + w[2] * pt[2]) * (T(1.0) - costheta);
@@ -611,9 +640,9 @@ void AngleAxisRotatePoint(const T angle_axis[3], const T pt[3], T result[3]) {
//
// Explicitly inlined evaluation of the cross product for
// performance reasons.
- const T w_cross_pt[3] = { angle_axis[1] * pt[2] - angle_axis[2] * pt[1],
- angle_axis[2] * pt[0] - angle_axis[0] * pt[2],
- angle_axis[0] * pt[1] - angle_axis[1] * pt[0] };
+ const T w_cross_pt[3] = {angle_axis[1] * pt[2] - angle_axis[2] * pt[1],
+ angle_axis[2] * pt[0] - angle_axis[0] * pt[2],
+ angle_axis[0] * pt[1] - angle_axis[1] * pt[0]};
result[0] = pt[0] + w_cross_pt[0];
result[1] = pt[1] + w_cross_pt[1];
diff --git a/extern/ceres/include/ceres/sized_cost_function.h b/extern/ceres/include/ceres/sized_cost_function.h
index b10421e81be..8e92f1b796c 100644
--- a/extern/ceres/include/ceres/sized_cost_function.h
+++ b/extern/ceres/include/ceres/sized_cost_function.h
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2019 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -38,55 +38,30 @@
#ifndef CERES_PUBLIC_SIZED_COST_FUNCTION_H_
#define CERES_PUBLIC_SIZED_COST_FUNCTION_H_
-#include "ceres/types.h"
#include "ceres/cost_function.h"
+#include "ceres/types.h"
#include "glog/logging.h"
+#include "internal/parameter_dims.h"
namespace ceres {
-template<int kNumResiduals,
- int N0 = 0, int N1 = 0, int N2 = 0, int N3 = 0, int N4 = 0,
- int N5 = 0, int N6 = 0, int N7 = 0, int N8 = 0, int N9 = 0>
+template <int kNumResiduals, int... Ns>
class SizedCostFunction : public CostFunction {
public:
- SizedCostFunction() {
- CHECK(kNumResiduals > 0 || kNumResiduals == DYNAMIC)
- << "Cost functions must have at least one residual block.";
+ static_assert(kNumResiduals > 0 || kNumResiduals == DYNAMIC,
+ "Cost functions must have at least one residual block.");
+ static_assert(internal::StaticParameterDims<Ns...>::kIsValid,
+ "Invalid parameter block dimension detected. Each parameter "
+ "block dimension must be bigger than zero.");
- // This block breaks the 80 column rule to keep it somewhat readable.
- CHECK((!N1 && !N2 && !N3 && !N4 && !N5 && !N6 && !N7 && !N8 && !N9) ||
- ((N1 > 0) && !N2 && !N3 && !N4 && !N5 && !N6 && !N7 && !N8 && !N9) ||
- ((N1 > 0) && (N2 > 0) && !N3 && !N4 && !N5 && !N6 && !N7 && !N8 && !N9) || // NOLINT
- ((N1 > 0) && (N2 > 0) && (N3 > 0) && !N4 && !N5 && !N6 && !N7 && !N8 && !N9) || // NOLINT
- ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && !N5 && !N6 && !N7 && !N8 && !N9) || // NOLINT
- ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && (N5 > 0) && !N6 && !N7 && !N8 && !N9) || // NOLINT
- ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && (N5 > 0) && (N6 > 0) && !N7 && !N8 && !N9) || // NOLINT
- ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && (N5 > 0) && (N6 > 0) && (N7 > 0) && !N8 && !N9) || // NOLINT
- ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && (N5 > 0) && (N6 > 0) && (N7 > 0) && (N8 > 0) && !N9) || // NOLINT
- ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && (N5 > 0) && (N6 > 0) && (N7 > 0) && (N8 > 0) && (N9 > 0))) // NOLINT
- << "Zero block cannot precede a non-zero block. Block sizes are "
- << "(ignore trailing 0s): " << N0 << ", " << N1 << ", " << N2 << ", "
- << N3 << ", " << N4 << ", " << N5 << ", " << N6 << ", " << N7 << ", "
- << N8 << ", " << N9;
+ using ParameterDims = internal::StaticParameterDims<Ns...>;
+ SizedCostFunction() {
set_num_residuals(kNumResiduals);
-
-#define CERES_ADD_PARAMETER_BLOCK(N) \
- if (N) mutable_parameter_block_sizes()->push_back(N);
- CERES_ADD_PARAMETER_BLOCK(N0);
- CERES_ADD_PARAMETER_BLOCK(N1);
- CERES_ADD_PARAMETER_BLOCK(N2);
- CERES_ADD_PARAMETER_BLOCK(N3);
- CERES_ADD_PARAMETER_BLOCK(N4);
- CERES_ADD_PARAMETER_BLOCK(N5);
- CERES_ADD_PARAMETER_BLOCK(N6);
- CERES_ADD_PARAMETER_BLOCK(N7);
- CERES_ADD_PARAMETER_BLOCK(N8);
- CERES_ADD_PARAMETER_BLOCK(N9);
-#undef CERES_ADD_PARAMETER_BLOCK
+ *mutable_parameter_block_sizes() = std::vector<int32_t>{Ns...};
}
- virtual ~SizedCostFunction() { }
+ virtual ~SizedCostFunction() {}
// Subclasses must implement Evaluate().
};
diff --git a/extern/ceres/include/ceres/solver.h b/extern/ceres/include/ceres/solver.h
index 0d77d242dfe..62631744fe2 100644
--- a/extern/ceres/include/ceres/solver.h
+++ b/extern/ceres/include/ceres/solver.h
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2019 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -32,20 +32,21 @@
#define CERES_PUBLIC_SOLVER_H_
#include <cmath>
+#include <memory>
#include <string>
+#include <unordered_set>
#include <vector>
+
#include "ceres/crs_matrix.h"
-#include "ceres/internal/macros.h"
+#include "ceres/internal/disable_warnings.h"
#include "ceres/internal/port.h"
#include "ceres/iteration_callback.h"
#include "ceres/ordered_groups.h"
+#include "ceres/problem.h"
#include "ceres/types.h"
-#include "ceres/internal/disable_warnings.h"
namespace ceres {
-class Problem;
-
// Interface for non-linear least squares solvers.
class CERES_EXPORT Solver {
public:
@@ -57,87 +58,6 @@ class CERES_EXPORT Solver {
//
// The constants are defined inside types.h
struct CERES_EXPORT Options {
- // Default constructor that sets up a generic sparse problem.
- Options() {
- minimizer_type = TRUST_REGION;
- line_search_direction_type = LBFGS;
- line_search_type = WOLFE;
- nonlinear_conjugate_gradient_type = FLETCHER_REEVES;
- max_lbfgs_rank = 20;
- use_approximate_eigenvalue_bfgs_scaling = false;
- line_search_interpolation_type = CUBIC;
- min_line_search_step_size = 1e-9;
- line_search_sufficient_function_decrease = 1e-4;
- max_line_search_step_contraction = 1e-3;
- min_line_search_step_contraction = 0.6;
- max_num_line_search_step_size_iterations = 20;
- max_num_line_search_direction_restarts = 5;
- line_search_sufficient_curvature_decrease = 0.9;
- max_line_search_step_expansion = 10.0;
- trust_region_strategy_type = LEVENBERG_MARQUARDT;
- dogleg_type = TRADITIONAL_DOGLEG;
- use_nonmonotonic_steps = false;
- max_consecutive_nonmonotonic_steps = 5;
- max_num_iterations = 50;
- max_solver_time_in_seconds = 1e9;
- num_threads = 1;
- initial_trust_region_radius = 1e4;
- max_trust_region_radius = 1e16;
- min_trust_region_radius = 1e-32;
- min_relative_decrease = 1e-3;
- min_lm_diagonal = 1e-6;
- max_lm_diagonal = 1e32;
- max_num_consecutive_invalid_steps = 5;
- function_tolerance = 1e-6;
- gradient_tolerance = 1e-10;
- parameter_tolerance = 1e-8;
-
-#if defined(CERES_NO_SUITESPARSE) && defined(CERES_NO_CXSPARSE) && !defined(CERES_ENABLE_LGPL_CODE) // NOLINT
- linear_solver_type = DENSE_QR;
-#else
- linear_solver_type = SPARSE_NORMAL_CHOLESKY;
-#endif
-
- preconditioner_type = JACOBI;
- visibility_clustering_type = CANONICAL_VIEWS;
- dense_linear_algebra_library_type = EIGEN;
-
- // Choose a default sparse linear algebra library in the order:
- //
- // SUITE_SPARSE > CX_SPARSE > EIGEN_SPARSE > NO_SPARSE
- sparse_linear_algebra_library_type = NO_SPARSE;
-#if !defined(CERES_NO_SUITESPARSE)
- sparse_linear_algebra_library_type = SUITE_SPARSE;
-#else
- #if !defined(CERES_NO_CXSPARSE)
- sparse_linear_algebra_library_type = CX_SPARSE;
- #else
- #if defined(CERES_USE_EIGEN_SPARSE)
- sparse_linear_algebra_library_type = EIGEN_SPARSE;
- #endif
- #endif
-#endif
-
- num_linear_solver_threads = 1;
- use_explicit_schur_complement = false;
- use_postordering = false;
- dynamic_sparsity = false;
- min_linear_solver_iterations = 0;
- max_linear_solver_iterations = 500;
- eta = 1e-1;
- jacobi_scaling = true;
- use_inner_iterations = false;
- inner_iteration_tolerance = 1e-3;
- logging_type = PER_MINIMIZER_ITERATION;
- minimizer_progress_to_stdout = false;
- trust_region_problem_dump_directory = "/tmp";
- trust_region_problem_dump_format_type = TEXTFILE;
- check_gradients = false;
- gradient_check_relative_precision = 1e-8;
- gradient_check_numeric_derivative_relative_step_size = 1e-6;
- update_state_every_iteration = false;
- }
-
// Returns true if the options struct has a valid
// configuration. Returns false otherwise, and fills in *error
// with a message describing the problem.
@@ -157,7 +77,7 @@ class CERES_EXPORT Solver {
// exactly or inexactly.
//
// 2. The trust region approach approximates the objective
- // function using using a model function (often a quadratic) over
+ // function using a model function (often a quadratic) over
// a subset of the search space known as the trust region. If the
// model function succeeds in minimizing the true objective
// function the trust region is expanded; conversely, otherwise it
@@ -168,11 +88,12 @@ class CERES_EXPORT Solver {
// trust region methods first choose a step size (the size of the
// trust region) and then a step direction while line search methods
// first choose a step direction and then a step size.
- MinimizerType minimizer_type;
+ MinimizerType minimizer_type = TRUST_REGION;
- LineSearchDirectionType line_search_direction_type;
- LineSearchType line_search_type;
- NonlinearConjugateGradientType nonlinear_conjugate_gradient_type;
+ LineSearchDirectionType line_search_direction_type = LBFGS;
+ LineSearchType line_search_type = WOLFE;
+ NonlinearConjugateGradientType nonlinear_conjugate_gradient_type =
+ FLETCHER_REEVES;
// The LBFGS hessian approximation is a low rank approximation to
// the inverse of the Hessian matrix. The rank of the
@@ -197,8 +118,8 @@ class CERES_EXPORT Solver {
// method, please see:
//
// Nocedal, J. (1980). "Updating Quasi-Newton Matrices with
- // Limited Storage". Mathematics of Computation 35 (151): 773–782.
- int max_lbfgs_rank;
+ // Limited Storage". Mathematics of Computation 35 (151): 773-782.
+ int max_lbfgs_rank = 20;
// As part of the (L)BFGS update step (BFGS) / right-multiply step (L-BFGS),
// the initial inverse Hessian approximation is taken to be the Identity.
@@ -220,18 +141,18 @@ class CERES_EXPORT Solver {
// Oren S.S., Self-scaling variable metric (SSVM) algorithms
// Part II: Implementation and experiments, Management Science,
// 20(5), 863-874, 1974.
- bool use_approximate_eigenvalue_bfgs_scaling;
+ bool use_approximate_eigenvalue_bfgs_scaling = false;
// Degree of the polynomial used to approximate the objective
// function. Valid values are BISECTION, QUADRATIC and CUBIC.
//
// BISECTION corresponds to pure backtracking search with no
// interpolation.
- LineSearchInterpolationType line_search_interpolation_type;
+ LineSearchInterpolationType line_search_interpolation_type = CUBIC;
// If during the line search, the step_size falls below this
// value, it is truncated to zero.
- double min_line_search_step_size;
+ double min_line_search_step_size = 1e-9;
// Line search parameters.
@@ -245,7 +166,7 @@ class CERES_EXPORT Solver {
//
// f(step_size) <= f(0) + sufficient_decrease * f'(0) * step_size
//
- double line_search_sufficient_function_decrease;
+ double line_search_sufficient_function_decrease = 1e-4;
// In each iteration of the line search,
//
@@ -255,7 +176,7 @@ class CERES_EXPORT Solver {
//
// 0 < max_step_contraction < min_step_contraction < 1
//
- double max_line_search_step_contraction;
+ double max_line_search_step_contraction = 1e-3;
// In each iteration of the line search,
//
@@ -265,19 +186,25 @@ class CERES_EXPORT Solver {
//
// 0 < max_step_contraction < min_step_contraction < 1
//
- double min_line_search_step_contraction;
+ double min_line_search_step_contraction = 0.6;
- // Maximum number of trial step size iterations during each line search,
- // if a step size satisfying the search conditions cannot be found within
- // this number of trials, the line search will terminate.
- int max_num_line_search_step_size_iterations;
+ // Maximum number of trial step size iterations during each line
+ // search, if a step size satisfying the search conditions cannot
+ // be found within this number of trials, the line search will
+ // terminate.
+
+ // The minimum allowed value is 0 for trust region minimizer and 1
+ // otherwise. If 0 is specified for the trust region minimizer,
+ // then line search will not be used when solving constrained
+ // optimization problems.
+ int max_num_line_search_step_size_iterations = 20;
// Maximum number of restarts of the line search direction algorithm before
// terminating the optimization. Restarts of the line search direction
// algorithm occur when the current algorithm fails to produce a new descent
// direction. This typically indicates a numerical failure, or a breakdown
// in the validity of the approximations used.
- int max_num_line_search_direction_restarts;
+ int max_num_line_search_direction_restarts = 5;
// The strong Wolfe conditions consist of the Armijo sufficient
// decrease condition, and an additional requirement that the
@@ -290,7 +217,7 @@ class CERES_EXPORT Solver {
//
// Where f() is the line search objective and f'() is the derivative
// of f w.r.t step_size (d f / d step_size).
- double line_search_sufficient_curvature_decrease;
+ double line_search_sufficient_curvature_decrease = 0.9;
// During the bracketing phase of the Wolfe search, the step size is
// increased until either a point satisfying the Wolfe conditions is
@@ -301,12 +228,12 @@ class CERES_EXPORT Solver {
// new_step_size <= max_step_expansion * step_size.
//
// By definition for expansion, max_step_expansion > 1.0.
- double max_line_search_step_expansion;
+ double max_line_search_step_expansion = 10.0;
- TrustRegionStrategyType trust_region_strategy_type;
+ TrustRegionStrategyType trust_region_strategy_type = LEVENBERG_MARQUARDT;
// Type of dogleg strategy to use.
- DoglegType dogleg_type;
+ DoglegType dogleg_type = TRADITIONAL_DOGLEG;
// The classical trust region methods are descent methods, in that
// they only accept a point if it strictly reduces the value of
@@ -317,7 +244,7 @@ class CERES_EXPORT Solver {
// in the value of the objective function.
//
// This is because allowing for non-decreasing objective function
- // values in a princpled manner allows the algorithm to "jump over
+ // values in a principled manner allows the algorithm to "jump over
// boulders" as the method is not restricted to move into narrow
// valleys while preserving its convergence properties.
//
@@ -333,30 +260,30 @@ class CERES_EXPORT Solver {
// than the minimum value encountered over the course of the
// optimization, the final parameters returned to the user are the
// ones corresponding to the minimum cost over all iterations.
- bool use_nonmonotonic_steps;
- int max_consecutive_nonmonotonic_steps;
+ bool use_nonmonotonic_steps = false;
+ int max_consecutive_nonmonotonic_steps = 5;
// Maximum number of iterations for the minimizer to run for.
- int max_num_iterations;
+ int max_num_iterations = 50;
// Maximum time for which the minimizer should run for.
- double max_solver_time_in_seconds;
+ double max_solver_time_in_seconds = 1e9;
// Number of threads used by Ceres for evaluating the cost and
// jacobians.
- int num_threads;
+ int num_threads = 1;
// Trust region minimizer settings.
- double initial_trust_region_radius;
- double max_trust_region_radius;
+ double initial_trust_region_radius = 1e4;
+ double max_trust_region_radius = 1e16;
// Minimizer terminates when the trust region radius becomes
// smaller than this value.
- double min_trust_region_radius;
+ double min_trust_region_radius = 1e-32;
// Lower bound for the relative decrease before a step is
// accepted.
- double min_relative_decrease;
+ double min_relative_decrease = 1e-3;
// For the Levenberg-Marquadt algorithm, the scaled diagonal of
// the normal equations J'J is used to control the size of the
@@ -365,46 +292,75 @@ class CERES_EXPORT Solver {
// fail. max_lm_diagonal and min_lm_diagonal, clamp the values of
// diag(J'J) from above and below. In the normal course of
// operation, the user should not have to modify these parameters.
- double min_lm_diagonal;
- double max_lm_diagonal;
+ double min_lm_diagonal = 1e-6;
+ double max_lm_diagonal = 1e32;
// Sometimes due to numerical conditioning problems or linear
// solver flakiness, the trust region strategy may return a
// numerically invalid step that can be fixed by reducing the
// trust region size. So the TrustRegionMinimizer allows for a few
// successive invalid steps before it declares NUMERICAL_FAILURE.
- int max_num_consecutive_invalid_steps;
+ int max_num_consecutive_invalid_steps = 5;
// Minimizer terminates when
//
// (new_cost - old_cost) < function_tolerance * old_cost;
//
- double function_tolerance;
+ double function_tolerance = 1e-6;
// Minimizer terminates when
//
// max_i |x - Project(Plus(x, -g(x))| < gradient_tolerance
//
// This value should typically be 1e-4 * function_tolerance.
- double gradient_tolerance;
+ double gradient_tolerance = 1e-10;
// Minimizer terminates when
//
// |step|_2 <= parameter_tolerance * ( |x|_2 + parameter_tolerance)
//
- double parameter_tolerance;
+ double parameter_tolerance = 1e-8;
// Linear least squares solver options -------------------------------------
- LinearSolverType linear_solver_type;
+ LinearSolverType linear_solver_type =
+#if defined(CERES_NO_SPARSE)
+ DENSE_QR;
+#else
+ SPARSE_NORMAL_CHOLESKY;
+#endif
// Type of preconditioner to use with the iterative linear solvers.
- PreconditionerType preconditioner_type;
+ PreconditionerType preconditioner_type = JACOBI;
// Type of clustering algorithm to use for visibility based
// preconditioning. This option is used only when the
// preconditioner_type is CLUSTER_JACOBI or CLUSTER_TRIDIAGONAL.
- VisibilityClusteringType visibility_clustering_type;
+ VisibilityClusteringType visibility_clustering_type = CANONICAL_VIEWS;
+
+ // Subset preconditioner is a preconditioner for problems with
+ // general sparsity. Given a subset of residual blocks of a
+ // problem, it uses the corresponding subset of the rows of the
+ // Jacobian to construct a preconditioner.
+ //
+ // Suppose the Jacobian J has been horizontally partitioned as
+ //
+ // J = [P]
+ // [Q]
+ //
+ // Where, Q is the set of rows corresponding to the residual
+ // blocks in residual_blocks_for_subset_preconditioner.
+ //
+ // The preconditioner is the inverse of the matrix Q'Q.
+ //
+ // Obviously, the efficacy of the preconditioner depends on how
+ // well the matrix Q approximates J'J, or how well the chosen
+ // residual blocks approximate the non-linear least squares
+ // problem.
+ //
+ // If Solver::Options::preconditioner_type == SUBSET, then
+ // residual_blocks_for_subset_preconditioner must be non-empty.
+ std::unordered_set<ResidualBlockId> residual_blocks_for_subset_preconditioner;
// Ceres supports using multiple dense linear algebra libraries
// for dense matrix factorizations. Currently EIGEN and LAPACK are
@@ -413,22 +369,28 @@ class CERES_EXPORT Solver {
// available.
//
// This setting affects the DENSE_QR, DENSE_NORMAL_CHOLESKY and
- // DENSE_SCHUR solvers. For small to moderate sized probem EIGEN
+ // DENSE_SCHUR solvers. For small to moderate sized problem EIGEN
// is a fine choice but for large problems, an optimized LAPACK +
// BLAS implementation can make a substantial difference in
// performance.
- DenseLinearAlgebraLibraryType dense_linear_algebra_library_type;
+ DenseLinearAlgebraLibraryType dense_linear_algebra_library_type = EIGEN;
// Ceres supports using multiple sparse linear algebra libraries
// for sparse matrix ordering and factorizations. Currently,
// SUITE_SPARSE and CX_SPARSE are the valid choices, depending on
// whether they are linked into Ceres at build time.
- SparseLinearAlgebraLibraryType sparse_linear_algebra_library_type;
-
- // Number of threads used by Ceres to solve the Newton
- // step. Currently only the SPARSE_SCHUR solver is capable of
- // using this setting.
- int num_linear_solver_threads;
+ SparseLinearAlgebraLibraryType sparse_linear_algebra_library_type =
+#if !defined(CERES_NO_SUITESPARSE)
+ SUITE_SPARSE;
+#elif defined(CERES_USE_EIGEN_SPARSE)
+ EIGEN_SPARSE;
+#elif !defined(CERES_NO_CXSPARSE)
+ CX_SPARSE;
+#elif !defined(CERES_NO_ACCELERATE_SPARSE)
+ ACCELERATE_SPARSE;
+#else
+ NO_SPARSE;
+#endif
// The order in which variables are eliminated in a linear solver
// can have a significant of impact on the efficiency and accuracy
@@ -456,7 +418,7 @@ class CERES_EXPORT Solver {
//
// Given such an ordering, Ceres ensures that the parameter blocks in
// the lowest numbered group are eliminated first, and then the
- // parmeter blocks in the next lowest numbered group and so on. Within
+ // parameter blocks in the next lowest numbered group and so on. Within
// each group, Ceres is free to order the parameter blocks as it
// chooses.
//
@@ -496,13 +458,13 @@ class CERES_EXPORT Solver {
// the parameter blocks into two groups, one for the points and one
// for the cameras, where the group containing the points has an id
// smaller than the group containing cameras.
- shared_ptr<ParameterBlockOrdering> linear_solver_ordering;
+ std::shared_ptr<ParameterBlockOrdering> linear_solver_ordering;
// Use an explicitly computed Schur complement matrix with
// ITERATIVE_SCHUR.
//
// By default this option is disabled and ITERATIVE_SCHUR
- // evaluates evaluates matrix-vector products between the Schur
+ // evaluates matrix-vector products between the Schur
// complement and a vector implicitly by exploiting the algebraic
// expression for the Schur complement.
//
@@ -519,7 +481,7 @@ class CERES_EXPORT Solver {
//
// NOTE: This option can only be used with the SCHUR_JACOBI
// preconditioner.
- bool use_explicit_schur_complement;
+ bool use_explicit_schur_complement = false;
// Sparse Cholesky factorization algorithms use a fill-reducing
// ordering to permute the columns of the Jacobian matrix. There
@@ -540,7 +502,7 @@ class CERES_EXPORT Solver {
// reordering algorithm which has slightly better runtime
// performance at the expense of an extra copy of the Jacobian
// matrix. Setting use_postordering to true enables this tradeoff.
- bool use_postordering;
+ bool use_postordering = false;
// Some non-linear least squares problems are symbolically dense but
// numerically sparse. i.e. at any given state only a small number
@@ -554,8 +516,32 @@ class CERES_EXPORT Solver {
// then it is probably best to keep this false, otherwise it will
// likely lead to worse performance.
- // This settings affects the SPARSE_NORMAL_CHOLESKY solver.
- bool dynamic_sparsity;
+ // This settings only affects the SPARSE_NORMAL_CHOLESKY solver.
+ bool dynamic_sparsity = false;
+
+ // TODO(sameeragarwal): Further expand the documentation for the
+ // following two options.
+
+ // NOTE1: EXPERIMENTAL FEATURE, UNDER DEVELOPMENT, USE AT YOUR OWN RISK.
+ //
+ // If use_mixed_precision_solves is true, the Gauss-Newton matrix
+ // is computed in double precision, but its factorization is
+ // computed in single precision. This can result in significant
+ // time and memory savings at the cost of some accuracy in the
+ // Gauss-Newton step. Iterative refinement is used to recover some
+ // of this accuracy back.
+ //
+ // If use_mixed_precision_solves is true, we recommend setting
+ // max_num_refinement_iterations to 2-3.
+ //
+ // NOTE2: The following two options are currently only applicable
+ // if sparse_linear_algebra_library_type is EIGEN_SPARSE and
+ // linear_solver_type is SPARSE_NORMAL_CHOLESKY, or SPARSE_SCHUR.
+ bool use_mixed_precision_solves = false;
+
+ // Number steps of the iterative refinement process to run when
+ // computing the Gauss-Newton step.
+ int max_num_refinement_iterations = 0;
// Some non-linear least squares problems have additional
// structure in the way the parameter blocks interact that it is
@@ -583,7 +569,7 @@ class CERES_EXPORT Solver {
// known as Wiberg's algorithm.
//
// Ruhe & Wedin (Algorithms for Separable Nonlinear Least Squares
- // Problems, SIAM Reviews, 22(3), 1980) present an analyis of
+ // Problems, SIAM Reviews, 22(3), 1980) present an analysis of
// various algorithms for solving separable non-linear least
// squares problems and refer to "Variable Projection" as
// Algorithm I in their paper.
@@ -615,7 +601,7 @@ class CERES_EXPORT Solver {
// displays better convergence behaviour per iteration. Setting
// Solver::Options::num_threads to the maximum number possible is
// highly recommended.
- bool use_inner_iterations;
+ bool use_inner_iterations = false;
// If inner_iterations is true, then the user has two choices.
//
@@ -627,7 +613,7 @@ class CERES_EXPORT Solver {
// the lower numbered groups are optimized before the higher
// number groups. Each group must be an independent set. Not
// all parameter blocks need to be present in the ordering.
- shared_ptr<ParameterBlockOrdering> inner_iteration_ordering;
+ std::shared_ptr<ParameterBlockOrdering> inner_iteration_ordering;
// Generally speaking, inner iterations make significant progress
// in the early stages of the solve and then their contribution
@@ -638,17 +624,17 @@ class CERES_EXPORT Solver {
// inner iterations drops below inner_iteration_tolerance, the use
// of inner iterations in subsequent trust region minimizer
// iterations is disabled.
- double inner_iteration_tolerance;
+ double inner_iteration_tolerance = 1e-3;
// Minimum number of iterations for which the linear solver should
// run, even if the convergence criterion is satisfied.
- int min_linear_solver_iterations;
+ int min_linear_solver_iterations = 0;
// Maximum number of iterations for which the linear solver should
// run. If the solver does not converge in less than
// max_linear_solver_iterations, then it returns MAX_ITERATIONS,
// as its termination type.
- int max_linear_solver_iterations;
+ int max_linear_solver_iterations = 500;
// Forcing sequence parameter. The truncated Newton solver uses
// this number to control the relative accuracy with which the
@@ -658,21 +644,21 @@ class CERES_EXPORT Solver {
// it to terminate the iterations when
//
// (Q_i - Q_{i-1})/Q_i < eta/i
- double eta;
+ double eta = 1e-1;
// Normalize the jacobian using Jacobi scaling before calling
// the linear least squares solver.
- bool jacobi_scaling;
+ bool jacobi_scaling = true;
// Logging options ---------------------------------------------------------
- LoggingType logging_type;
+ LoggingType logging_type = PER_MINIMIZER_ITERATION;
// By default the Minimizer progress is logged to VLOG(1), which
// is sent to STDERR depending on the vlog level. If this flag is
// set to true, and logging_type is not SILENT, the logging output
// is sent to STDOUT.
- bool minimizer_progress_to_stdout;
+ bool minimizer_progress_to_stdout = false;
// List of iterations at which the minimizer should dump the trust
// region problem. Useful for testing and benchmarking. If empty
@@ -683,8 +669,8 @@ class CERES_EXPORT Solver {
// non-empty if trust_region_minimizer_iterations_to_dump is
// non-empty and trust_region_problem_dump_format_type is not
// CONSOLE.
- std::string trust_region_problem_dump_directory;
- DumpFormatType trust_region_problem_dump_format_type;
+ std::string trust_region_problem_dump_directory = "/tmp";
+ DumpFormatType trust_region_problem_dump_format_type = TEXTFILE;
// Finite differences options ----------------------------------------------
@@ -694,12 +680,12 @@ class CERES_EXPORT Solver {
// etc), then also computing it using finite differences. The
// results are compared, and if they differ substantially, details
// are printed to the log.
- bool check_gradients;
+ bool check_gradients = false;
// Relative precision to check for in the gradient checker. If the
// relative difference between an element in a jacobian exceeds
// this number, then the jacobian for that cost term is dumped.
- double gradient_check_relative_precision;
+ double gradient_check_relative_precision = 1e-8;
// WARNING: This option only applies to the to the numeric
// differentiation used for checking the user provided derivatives
@@ -723,7 +709,7 @@ class CERES_EXPORT Solver {
//
// The finite differencing is done along each dimension. The
// reason to use a relative (rather than absolute) step size is
- // that this way, numeric differentation works for functions where
+ // that this way, numeric differentiation works for functions where
// the arguments are typically large (e.g. 1e9) and when the
// values are small (e.g. 1e-5). It is possible to construct
// "torture cases" which break this finite difference heuristic,
@@ -733,14 +719,21 @@ class CERES_EXPORT Solver {
// theory a good choice is sqrt(eps) * x, which for doubles means
// about 1e-8 * x. However, I have found this number too
// optimistic. This number should be exposed for users to change.
- double gradient_check_numeric_derivative_relative_step_size;
-
- // If true, the user's parameter blocks are updated at the end of
- // every Minimizer iteration, otherwise they are updated when the
- // Minimizer terminates. This is useful if, for example, the user
- // wishes to visualize the state of the optimization every
- // iteration.
- bool update_state_every_iteration;
+ double gradient_check_numeric_derivative_relative_step_size = 1e-6;
+
+ // If update_state_every_iteration is true, then Ceres Solver will
+ // guarantee that at the end of every iteration and before any
+ // user provided IterationCallback is called, the parameter blocks
+ // are updated to the current best solution found by the
+ // solver. Thus the IterationCallback can inspect the values of
+ // the parameter blocks for purposes of computation, visualization
+ // or termination.
+
+ // If update_state_every_iteration is false then there is no such
+ // guarantee, and user provided IterationCallbacks should not
+ // expect to look at the parameter blocks and interpret their
+ // values.
+ bool update_state_every_iteration = false;
// Callbacks that are executed at the end of each iteration of the
// Minimizer. An iteration may terminate midway, either due to
@@ -749,20 +742,18 @@ class CERES_EXPORT Solver {
// executed.
// Callbacks are executed in the order that they are specified in
- // this vector. By default, parameter blocks are updated only at
- // the end of the optimization, i.e when the Minimizer
- // terminates. This behaviour is controlled by
- // update_state_every_variable. If the user wishes to have access
- // to the update parameter blocks when his/her callbacks are
- // executed, then set update_state_every_iteration to true.
+ // this vector. By default, parameter blocks are updated only at the
+ // end of the optimization, i.e when the Minimizer terminates. This
+ // behaviour is controlled by update_state_every_iteration. If the
+ // user wishes to have access to the updated parameter blocks when
+ // his/her callbacks are executed, then set
+ // update_state_every_iteration to true.
//
// The solver does NOT take ownership of these pointers.
std::vector<IterationCallback*> callbacks;
};
struct CERES_EXPORT Summary {
- Summary();
-
// A brief one line description of the state of the solver after
// termination.
std::string BriefReport() const;
@@ -774,25 +765,25 @@ class CERES_EXPORT Solver {
bool IsSolutionUsable() const;
// Minimizer summary -------------------------------------------------
- MinimizerType minimizer_type;
+ MinimizerType minimizer_type = TRUST_REGION;
- TerminationType termination_type;
+ TerminationType termination_type = FAILURE;
// Reason why the solver terminated.
- std::string message;
+ std::string message = "ceres::Solve was not called.";
// Cost of the problem (value of the objective function) before
// the optimization.
- double initial_cost;
+ double initial_cost = -1.0;
// Cost of the problem (value of the objective function) after the
// optimization.
- double final_cost;
+ double final_cost = -1.0;
// The part of the total cost that comes from residual blocks that
// were held fixed by the preprocessor because all the parameter
// blocks that they depend on were fixed.
- double fixed_cost;
+ double fixed_cost = -1.0;
// IterationSummary for each minimizer iteration in order.
std::vector<IterationSummary> iterations;
@@ -801,22 +792,22 @@ class CERES_EXPORT Solver {
// accepted. Unless use_non_monotonic_steps is true this is also
// the number of steps in which the objective function value/cost
// went down.
- int num_successful_steps;
+ int num_successful_steps = -1;
// Number of minimizer iterations in which the step was rejected
// either because it did not reduce the cost enough or the step
// was not numerically valid.
- int num_unsuccessful_steps;
+ int num_unsuccessful_steps = -1;
// Number of times inner iterations were performed.
- int num_inner_iteration_steps;
+ int num_inner_iteration_steps = -1;
// Total number of iterations inside the line search algorithm
// across all invocations. We call these iterations "steps" to
// distinguish them from the outer iterations of the line search
// and trust region minimizer algorithms which call the line
// search algorithm as a subroutine.
- int num_line_search_steps;
+ int num_line_search_steps = -1;
// All times reported below are wall times.
@@ -824,31 +815,42 @@ class CERES_EXPORT Solver {
// occurs, Ceres performs a number of preprocessing steps. These
// include error checks, memory allocations, and reorderings. This
// time is accounted for as preprocessing time.
- double preprocessor_time_in_seconds;
+ double preprocessor_time_in_seconds = -1.0;
// Time spent in the TrustRegionMinimizer.
- double minimizer_time_in_seconds;
+ double minimizer_time_in_seconds = -1.0;
// After the Minimizer is finished, some time is spent in
// re-evaluating residuals etc. This time is accounted for in the
// postprocessor time.
- double postprocessor_time_in_seconds;
+ double postprocessor_time_in_seconds = -1.0;
// Some total of all time spent inside Ceres when Solve is called.
- double total_time_in_seconds;
+ double total_time_in_seconds = -1.0;
// Time (in seconds) spent in the linear solver computing the
// trust region step.
- double linear_solver_time_in_seconds;
+ double linear_solver_time_in_seconds = -1.0;
+
+ // Number of times the Newton step was computed by solving a
+ // linear system. This does not include linear solves used by
+ // inner iterations.
+ int num_linear_solves = -1;
// Time (in seconds) spent evaluating the residual vector.
- double residual_evaluation_time_in_seconds;
+ double residual_evaluation_time_in_seconds = 1.0;
+
+ // Number of residual only evaluations.
+ int num_residual_evaluations = -1;
// Time (in seconds) spent evaluating the jacobian matrix.
- double jacobian_evaluation_time_in_seconds;
+ double jacobian_evaluation_time_in_seconds = -1.0;
+
+ // Number of Jacobian (and residual) evaluations.
+ int num_jacobian_evaluations = -1;
// Time (in seconds) spent doing inner iterations.
- double inner_iteration_time_in_seconds;
+ double inner_iteration_time_in_seconds = -1.0;
// Cumulative timing information for line searches performed as part of the
// solve. Note that in addition to the case when the Line Search minimizer
@@ -857,89 +859,89 @@ class CERES_EXPORT Solver {
// Time (in seconds) spent evaluating the univariate cost function as part
// of a line search.
- double line_search_cost_evaluation_time_in_seconds;
+ double line_search_cost_evaluation_time_in_seconds = -1.0;
// Time (in seconds) spent evaluating the gradient of the univariate cost
// function as part of a line search.
- double line_search_gradient_evaluation_time_in_seconds;
+ double line_search_gradient_evaluation_time_in_seconds = -1.0;
// Time (in seconds) spent minimizing the interpolating polynomial
// to compute the next candidate step size as part of a line search.
- double line_search_polynomial_minimization_time_in_seconds;
+ double line_search_polynomial_minimization_time_in_seconds = -1.0;
// Total time (in seconds) spent performing line searches.
- double line_search_total_time_in_seconds;
+ double line_search_total_time_in_seconds = -1.0;
// Number of parameter blocks in the problem.
- int num_parameter_blocks;
+ int num_parameter_blocks = -1;
- // Number of parameters in the probem.
- int num_parameters;
+ // Number of parameters in the problem.
+ int num_parameters = -1;
// Dimension of the tangent space of the problem (or the number of
// columns in the Jacobian for the problem). This is different
// from num_parameters if a parameter block is associated with a
// LocalParameterization
- int num_effective_parameters;
+ int num_effective_parameters = -1;
// Number of residual blocks in the problem.
- int num_residual_blocks;
+ int num_residual_blocks = -1;
// Number of residuals in the problem.
- int num_residuals;
+ int num_residuals = -1;
// Number of parameter blocks in the problem after the inactive
// and constant parameter blocks have been removed. A parameter
// block is inactive if no residual block refers to it.
- int num_parameter_blocks_reduced;
+ int num_parameter_blocks_reduced = -1;
// Number of parameters in the reduced problem.
- int num_parameters_reduced;
+ int num_parameters_reduced = -1;
// Dimension of the tangent space of the reduced problem (or the
// number of columns in the Jacobian for the reduced
// problem). This is different from num_parameters_reduced if a
// parameter block in the reduced problem is associated with a
// LocalParameterization.
- int num_effective_parameters_reduced;
+ int num_effective_parameters_reduced = -1;
// Number of residual blocks in the reduced problem.
- int num_residual_blocks_reduced;
+ int num_residual_blocks_reduced = -1;
// Number of residuals in the reduced problem.
- int num_residuals_reduced;
+ int num_residuals_reduced = -1;
// Is the reduced problem bounds constrained.
- bool is_constrained;
+ bool is_constrained = false;
// Number of threads specified by the user for Jacobian and
// residual evaluation.
- int num_threads_given;
+ int num_threads_given = -1;
// Number of threads actually used by the solver for Jacobian and
// residual evaluation. This number is not equal to
// num_threads_given if OpenMP is not available.
- int num_threads_used;
-
- // Number of threads specified by the user for solving the trust
- // region problem.
- int num_linear_solver_threads_given;
-
- // Number of threads actually used by the solver for solving the
- // trust region problem. This number is not equal to
- // num_threads_given if OpenMP is not available.
- int num_linear_solver_threads_used;
+ int num_threads_used = -1;
// Type of the linear solver requested by the user.
- LinearSolverType linear_solver_type_given;
-
+ LinearSolverType linear_solver_type_given =
+#if defined(CERES_NO_SPARSE)
+ DENSE_QR;
+#else
+ SPARSE_NORMAL_CHOLESKY;
+#endif
// Type of the linear solver actually used. This may be different
// from linear_solver_type_given if Ceres determines that the
// problem structure is not compatible with the linear solver
// requested or if the linear solver requested by the user is not
// available, e.g. The user requested SPARSE_NORMAL_CHOLESKY but
// no sparse linear algebra library was available.
- LinearSolverType linear_solver_type_used;
+ LinearSolverType linear_solver_type_used =
+#if defined(CERES_NO_SPARSE)
+ DENSE_QR;
+#else
+ SPARSE_NORMAL_CHOLESKY;
+#endif
// Size of the elimination groups given by the user as hints to
// the linear solver.
@@ -953,15 +955,29 @@ class CERES_EXPORT Solver {
// parameter blocks.
std::vector<int> linear_solver_ordering_used;
+ // For Schur type linear solvers, this string describes the
+ // template specialization which was detected in the problem and
+ // should be used.
+ std::string schur_structure_given;
+
+ // This is the Schur template specialization that was actually
+ // instantiated and used. The reason this will be different from
+ // schur_structure_given is because the corresponding template
+ // specialization does not exist.
+ //
+ // Template specializations can be added to ceres by editing
+ // internal/ceres/generate_template_specializations.py
+ std::string schur_structure_used;
+
// True if the user asked for inner iterations to be used as part
// of the optimization.
- bool inner_iterations_given;
+ bool inner_iterations_given = false;
// True if the user asked for inner iterations to be used as part
// of the optimization and the problem structure was such that
// they were actually performed. e.g., in a problem with just one
// parameter block, inner iterations are not performed.
- bool inner_iterations_used;
+ bool inner_iterations_used = false;
// Size of the parameter groups given by the user for performing
// inner iterations.
@@ -976,57 +992,59 @@ class CERES_EXPORT Solver {
std::vector<int> inner_iteration_ordering_used;
// Type of the preconditioner requested by the user.
- PreconditionerType preconditioner_type_given;
+ PreconditionerType preconditioner_type_given = IDENTITY;
// Type of the preconditioner actually used. This may be different
// from linear_solver_type_given if Ceres determines that the
// problem structure is not compatible with the linear solver
// requested or if the linear solver requested by the user is not
// available.
- PreconditionerType preconditioner_type_used;
+ PreconditionerType preconditioner_type_used = IDENTITY;
// Type of clustering algorithm used for visibility based
// preconditioning. Only meaningful when the preconditioner_type
// is CLUSTER_JACOBI or CLUSTER_TRIDIAGONAL.
- VisibilityClusteringType visibility_clustering_type;
+ VisibilityClusteringType visibility_clustering_type = CANONICAL_VIEWS;
// Type of trust region strategy.
- TrustRegionStrategyType trust_region_strategy_type;
+ TrustRegionStrategyType trust_region_strategy_type = LEVENBERG_MARQUARDT;
// Type of dogleg strategy used for solving the trust region
// problem.
- DoglegType dogleg_type;
+ DoglegType dogleg_type = TRADITIONAL_DOGLEG;
// Type of the dense linear algebra library used.
- DenseLinearAlgebraLibraryType dense_linear_algebra_library_type;
+ DenseLinearAlgebraLibraryType dense_linear_algebra_library_type = EIGEN;
// Type of the sparse linear algebra library used.
- SparseLinearAlgebraLibraryType sparse_linear_algebra_library_type;
+ SparseLinearAlgebraLibraryType sparse_linear_algebra_library_type =
+ NO_SPARSE;
// Type of line search direction used.
- LineSearchDirectionType line_search_direction_type;
+ LineSearchDirectionType line_search_direction_type = LBFGS;
// Type of the line search algorithm used.
- LineSearchType line_search_type;
+ LineSearchType line_search_type = WOLFE;
// When performing line search, the degree of the polynomial used
// to approximate the objective function.
- LineSearchInterpolationType line_search_interpolation_type;
+ LineSearchInterpolationType line_search_interpolation_type = CUBIC;
// If the line search direction is NONLINEAR_CONJUGATE_GRADIENT,
// then this indicates the particular variant of non-linear
// conjugate gradient used.
- NonlinearConjugateGradientType nonlinear_conjugate_gradient_type;
+ NonlinearConjugateGradientType nonlinear_conjugate_gradient_type =
+ FLETCHER_REEVES;
// If the type of the line search direction is LBFGS, then this
// indicates the rank of the Hessian approximation.
- int max_lbfgs_rank;
+ int max_lbfgs_rank = -1;
};
// Once a least squares problem has been built, this function takes
// the problem and optimizes it based on the values of the options
// parameters. Upon return, a detailed summary of the work performed
- // by the preprocessor, the non-linear minmizer and the linear
+ // by the preprocessor, the non-linear minimizer and the linear
// solver are reported in the summary object.
virtual void Solve(const Options& options,
Problem* problem,
@@ -1035,8 +1053,8 @@ class CERES_EXPORT Solver {
// Helper function which avoids going through the interface.
CERES_EXPORT void Solve(const Solver::Options& options,
- Problem* problem,
- Solver::Summary* summary);
+ Problem* problem,
+ Solver::Summary* summary);
} // namespace ceres
diff --git a/extern/ceres/include/ceres/tiny_solver.h b/extern/ceres/include/ceres/tiny_solver.h
new file mode 100644
index 00000000000..47db5824dc5
--- /dev/null
+++ b/extern/ceres/include/ceres/tiny_solver.h
@@ -0,0 +1,368 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2019 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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.
+//
+// Author: mierle@gmail.com (Keir Mierle)
+//
+// WARNING WARNING WARNING
+// WARNING WARNING WARNING Tiny solver is experimental and will change.
+// WARNING WARNING WARNING
+//
+// A tiny least squares solver using Levenberg-Marquardt, intended for solving
+// small dense problems with low latency and low overhead. The implementation
+// takes care to do all allocation up front, so that no memory is allocated
+// during solving. This is especially useful when solving many similar problems;
+// for example, inverse pixel distortion for every pixel on a grid.
+//
+// Note: This code has no dependencies beyond Eigen, including on other parts of
+// Ceres, so it is possible to take this file alone and put it in another
+// project without the rest of Ceres.
+//
+// Algorithm based off of:
+//
+// [1] K. Madsen, H. Nielsen, O. Tingleoff.
+// Methods for Non-linear Least Squares Problems.
+// http://www2.imm.dtu.dk/pubdb/views/edoc_download.php/3215/pdf/imm3215.pdf
+
+#ifndef CERES_PUBLIC_TINY_SOLVER_H_
+#define CERES_PUBLIC_TINY_SOLVER_H_
+
+#include <cassert>
+#include <cmath>
+
+#include "Eigen/Dense"
+
+namespace ceres {
+
+// To use tiny solver, create a class or struct that allows computing the cost
+// function (described below). This is similar to a ceres::CostFunction, but is
+// different to enable statically allocating all memory for the solver
+// (specifically, enum sizes). Key parts are the Scalar typedef, the enums to
+// describe problem sizes (needed to remove all heap allocations), and the
+// operator() overload to evaluate the cost and (optionally) jacobians.
+//
+// struct TinySolverCostFunctionTraits {
+// typedef double Scalar;
+// enum {
+// NUM_RESIDUALS = <int> OR Eigen::Dynamic,
+// NUM_PARAMETERS = <int> OR Eigen::Dynamic,
+// };
+// bool operator()(const double* parameters,
+// double* residuals,
+// double* jacobian) const;
+//
+// int NumResiduals() const; -- Needed if NUM_RESIDUALS == Eigen::Dynamic.
+// int NumParameters() const; -- Needed if NUM_PARAMETERS == Eigen::Dynamic.
+// };
+//
+// For operator(), the size of the objects is:
+//
+// double* parameters -- NUM_PARAMETERS or NumParameters()
+// double* residuals -- NUM_RESIDUALS or NumResiduals()
+// double* jacobian -- NUM_RESIDUALS * NUM_PARAMETERS in column-major format
+// (Eigen's default); or NULL if no jacobian requested.
+//
+// An example (fully statically sized):
+//
+// struct MyCostFunctionExample {
+// typedef double Scalar;
+// enum {
+// NUM_RESIDUALS = 2,
+// NUM_PARAMETERS = 3,
+// };
+// bool operator()(const double* parameters,
+// double* residuals,
+// double* jacobian) const {
+// residuals[0] = x + 2*y + 4*z;
+// residuals[1] = y * z;
+// if (jacobian) {
+// jacobian[0 * 2 + 0] = 1; // First column (x).
+// jacobian[0 * 2 + 1] = 0;
+//
+// jacobian[1 * 2 + 0] = 2; // Second column (y).
+// jacobian[1 * 2 + 1] = z;
+//
+// jacobian[2 * 2 + 0] = 4; // Third column (z).
+// jacobian[2 * 2 + 1] = y;
+// }
+// return true;
+// }
+// };
+//
+// The solver supports either statically or dynamically sized cost
+// functions. If the number of residuals is dynamic then the Function
+// must define:
+//
+// int NumResiduals() const;
+//
+// If the number of parameters is dynamic then the Function must
+// define:
+//
+// int NumParameters() const;
+//
+template <typename Function,
+ typename LinearSolver =
+ Eigen::LDLT<Eigen::Matrix<typename Function::Scalar,
+ Function::NUM_PARAMETERS,
+ Function::NUM_PARAMETERS>>>
+class TinySolver {
+ public:
+ // This class needs to have an Eigen aligned operator new as it contains
+ // fixed-size Eigen types.
+ EIGEN_MAKE_ALIGNED_OPERATOR_NEW
+
+ enum {
+ NUM_RESIDUALS = Function::NUM_RESIDUALS,
+ NUM_PARAMETERS = Function::NUM_PARAMETERS
+ };
+ typedef typename Function::Scalar Scalar;
+ typedef typename Eigen::Matrix<Scalar, NUM_PARAMETERS, 1> Parameters;
+
+ enum Status {
+ GRADIENT_TOO_SMALL, // eps > max(J'*f(x))
+ RELATIVE_STEP_SIZE_TOO_SMALL, // eps > ||dx|| / (||x|| + eps)
+ COST_TOO_SMALL, // eps > ||f(x)||^2 / 2
+ HIT_MAX_ITERATIONS,
+
+ // TODO(sameeragarwal): Deal with numerical failures.
+ };
+
+ struct Options {
+ Scalar gradient_tolerance = 1e-10; // eps > max(J'*f(x))
+ Scalar parameter_tolerance = 1e-8; // eps > ||dx|| / ||x||
+ Scalar cost_threshold = // eps > ||f(x)||
+ std::numeric_limits<Scalar>::epsilon();
+ Scalar initial_trust_region_radius = 1e4;
+ int max_num_iterations = 50;
+ };
+
+ struct Summary {
+ Scalar initial_cost = -1; // 1/2 ||f(x)||^2
+ Scalar final_cost = -1; // 1/2 ||f(x)||^2
+ Scalar gradient_max_norm = -1; // max(J'f(x))
+ int iterations = -1;
+ Status status = HIT_MAX_ITERATIONS;
+ };
+
+ bool Update(const Function& function, const Parameters& x) {
+ if (!function(x.data(), error_.data(), jacobian_.data())) {
+ return false;
+ }
+
+ error_ = -error_;
+
+ // On the first iteration, compute a diagonal (Jacobi) scaling
+ // matrix, which we store as a vector.
+ if (summary.iterations == 0) {
+ // jacobi_scaling = 1 / (1 + diagonal(J'J))
+ //
+ // 1 is added to the denominator to regularize small diagonal
+ // entries.
+ jacobi_scaling_ = 1.0 / (1.0 + jacobian_.colwise().norm().array());
+ }
+
+ // This explicitly computes the normal equations, which is numerically
+ // unstable. Nevertheless, it is often good enough and is fast.
+ //
+ // TODO(sameeragarwal): Refactor this to allow for DenseQR
+ // factorization.
+ jacobian_ = jacobian_ * jacobi_scaling_.asDiagonal();
+ jtj_ = jacobian_.transpose() * jacobian_;
+ g_ = jacobian_.transpose() * error_;
+ summary.gradient_max_norm = g_.array().abs().maxCoeff();
+ cost_ = error_.squaredNorm() / 2;
+ return true;
+ }
+
+ const Summary& Solve(const Function& function, Parameters* x_and_min) {
+ Initialize<NUM_RESIDUALS, NUM_PARAMETERS>(function);
+ assert(x_and_min);
+ Parameters& x = *x_and_min;
+ summary = Summary();
+ summary.iterations = 0;
+
+ // TODO(sameeragarwal): Deal with failure here.
+ Update(function, x);
+ summary.initial_cost = cost_;
+ summary.final_cost = cost_;
+
+ if (summary.gradient_max_norm < options.gradient_tolerance) {
+ summary.status = GRADIENT_TOO_SMALL;
+ return summary;
+ }
+
+ if (cost_ < options.cost_threshold) {
+ summary.status = COST_TOO_SMALL;
+ return summary;
+ }
+
+ Scalar u = 1.0 / options.initial_trust_region_radius;
+ Scalar v = 2;
+
+ for (summary.iterations = 1;
+ summary.iterations < options.max_num_iterations;
+ summary.iterations++) {
+ jtj_regularized_ = jtj_;
+ const Scalar min_diagonal = 1e-6;
+ const Scalar max_diagonal = 1e32;
+ for (int i = 0; i < lm_diagonal_.rows(); ++i) {
+ lm_diagonal_[i] = std::sqrt(
+ u * std::min(std::max(jtj_(i, i), min_diagonal), max_diagonal));
+ jtj_regularized_(i, i) += lm_diagonal_[i] * lm_diagonal_[i];
+ }
+
+ // TODO(sameeragarwal): Check for failure and deal with it.
+ linear_solver_.compute(jtj_regularized_);
+ lm_step_ = linear_solver_.solve(g_);
+ dx_ = jacobi_scaling_.asDiagonal() * lm_step_;
+
+ // Adding parameter_tolerance to x.norm() ensures that this
+ // works if x is near zero.
+ const Scalar parameter_tolerance =
+ options.parameter_tolerance *
+ (x.norm() + options.parameter_tolerance);
+ if (dx_.norm() < parameter_tolerance) {
+ summary.status = RELATIVE_STEP_SIZE_TOO_SMALL;
+ break;
+ }
+ x_new_ = x + dx_;
+
+ // TODO(keir): Add proper handling of errors from user eval of cost
+ // functions.
+ function(&x_new_[0], &f_x_new_[0], NULL);
+
+ const Scalar cost_change = (2 * cost_ - f_x_new_.squaredNorm());
+
+ // TODO(sameeragarwal): Better more numerically stable evaluation.
+ const Scalar model_cost_change = lm_step_.dot(2 * g_ - jtj_ * lm_step_);
+
+ // rho is the ratio of the actual reduction in error to the reduction
+ // in error that would be obtained if the problem was linear. See [1]
+ // for details.
+ Scalar rho(cost_change / model_cost_change);
+ if (rho > 0) {
+ // Accept the Levenberg-Marquardt step because the linear
+ // model fits well.
+ x = x_new_;
+
+ // TODO(sameeragarwal): Deal with failure.
+ Update(function, x);
+ if (summary.gradient_max_norm < options.gradient_tolerance) {
+ summary.status = GRADIENT_TOO_SMALL;
+ break;
+ }
+
+ if (cost_ < options.cost_threshold) {
+ summary.status = COST_TOO_SMALL;
+ break;
+ }
+
+ Scalar tmp = Scalar(2 * rho - 1);
+ u = u * std::max(1 / 3., 1 - tmp * tmp * tmp);
+ v = 2;
+ continue;
+ }
+
+ // Reject the update because either the normal equations failed to solve
+ // or the local linear model was not good (rho < 0). Instead, increase u
+ // to move closer to gradient descent.
+ u *= v;
+ v *= 2;
+ }
+
+ summary.final_cost = cost_;
+ return summary;
+ }
+
+ Options options;
+ Summary summary;
+
+ private:
+ // Preallocate everything, including temporary storage needed for solving the
+ // linear system. This allows reusing the intermediate storage across solves.
+ LinearSolver linear_solver_;
+ Scalar cost_;
+ Parameters dx_, x_new_, g_, jacobi_scaling_, lm_diagonal_, lm_step_;
+ Eigen::Matrix<Scalar, NUM_RESIDUALS, 1> error_, f_x_new_;
+ Eigen::Matrix<Scalar, NUM_RESIDUALS, NUM_PARAMETERS> jacobian_;
+ Eigen::Matrix<Scalar, NUM_PARAMETERS, NUM_PARAMETERS> jtj_, jtj_regularized_;
+
+ // The following definitions are needed for template metaprogramming.
+ template <bool Condition, typename T>
+ struct enable_if;
+
+ template <typename T>
+ struct enable_if<true, T> {
+ typedef T type;
+ };
+
+ // The number of parameters and residuals are dynamically sized.
+ template <int R, int P>
+ typename enable_if<(R == Eigen::Dynamic && P == Eigen::Dynamic), void>::type
+ Initialize(const Function& function) {
+ Initialize(function.NumResiduals(), function.NumParameters());
+ }
+
+ // The number of parameters is dynamically sized and the number of
+ // residuals is statically sized.
+ template <int R, int P>
+ typename enable_if<(R == Eigen::Dynamic && P != Eigen::Dynamic), void>::type
+ Initialize(const Function& function) {
+ Initialize(function.NumResiduals(), P);
+ }
+
+ // The number of parameters is statically sized and the number of
+ // residuals is dynamically sized.
+ template <int R, int P>
+ typename enable_if<(R != Eigen::Dynamic && P == Eigen::Dynamic), void>::type
+ Initialize(const Function& function) {
+ Initialize(R, function.NumParameters());
+ }
+
+ // The number of parameters and residuals are statically sized.
+ template <int R, int P>
+ typename enable_if<(R != Eigen::Dynamic && P != Eigen::Dynamic), void>::type
+ Initialize(const Function& /* function */) {}
+
+ void Initialize(int num_residuals, int num_parameters) {
+ dx_.resize(num_parameters);
+ x_new_.resize(num_parameters);
+ g_.resize(num_parameters);
+ jacobi_scaling_.resize(num_parameters);
+ lm_diagonal_.resize(num_parameters);
+ lm_step_.resize(num_parameters);
+ error_.resize(num_residuals);
+ f_x_new_.resize(num_residuals);
+ jacobian_.resize(num_residuals, num_parameters);
+ jtj_.resize(num_parameters, num_parameters);
+ jtj_regularized_.resize(num_parameters, num_parameters);
+ }
+};
+
+} // namespace ceres
+
+#endif // CERES_PUBLIC_TINY_SOLVER_H_
diff --git a/extern/ceres/include/ceres/tiny_solver_autodiff_function.h b/extern/ceres/include/ceres/tiny_solver_autodiff_function.h
new file mode 100644
index 00000000000..b782f549cc1
--- /dev/null
+++ b/extern/ceres/include/ceres/tiny_solver_autodiff_function.h
@@ -0,0 +1,206 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2019 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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.
+//
+// Author: mierle@gmail.com (Keir Mierle)
+//
+// WARNING WARNING WARNING
+// WARNING WARNING WARNING Tiny solver is experimental and will change.
+// WARNING WARNING WARNING
+
+#ifndef CERES_PUBLIC_TINY_SOLVER_AUTODIFF_FUNCTION_H_
+#define CERES_PUBLIC_TINY_SOLVER_AUTODIFF_FUNCTION_H_
+
+#include <memory>
+#include <type_traits>
+
+#include "Eigen/Core"
+#include "ceres/jet.h"
+#include "ceres/types.h" // For kImpossibleValue.
+
+namespace ceres {
+
+// An adapter around autodiff-style CostFunctors to enable easier use of
+// TinySolver. See the example below showing how to use it:
+//
+// // Example for cost functor with static residual size.
+// // Same as an autodiff cost functor, but taking only 1 parameter.
+// struct MyFunctor {
+// template<typename T>
+// bool operator()(const T* const parameters, T* residuals) const {
+// const T& x = parameters[0];
+// const T& y = parameters[1];
+// const T& z = parameters[2];
+// residuals[0] = x + 2.*y + 4.*z;
+// residuals[1] = y * z;
+// return true;
+// }
+// };
+//
+// typedef TinySolverAutoDiffFunction<MyFunctor, 2, 3>
+// AutoDiffFunction;
+//
+// MyFunctor my_functor;
+// AutoDiffFunction f(my_functor);
+//
+// Vec3 x = ...;
+// TinySolver<AutoDiffFunction> solver;
+// solver.Solve(f, &x);
+//
+// // Example for cost functor with dynamic residual size.
+// // NumResiduals() supplies dynamic size of residuals.
+// // Same functionality as in tiny_solver.h but with autodiff.
+// struct MyFunctorWithDynamicResiduals {
+// int NumResiduals() const {
+// return 2;
+// }
+//
+// template<typename T>
+// bool operator()(const T* const parameters, T* residuals) const {
+// const T& x = parameters[0];
+// const T& y = parameters[1];
+// const T& z = parameters[2];
+// residuals[0] = x + static_cast<T>(2.)*y + static_cast<T>(4.)*z;
+// residuals[1] = y * z;
+// return true;
+// }
+// };
+//
+// typedef TinySolverAutoDiffFunction<MyFunctorWithDynamicResiduals,
+// Eigen::Dynamic,
+// 3>
+// AutoDiffFunctionWithDynamicResiduals;
+//
+// MyFunctorWithDynamicResiduals my_functor_dyn;
+// AutoDiffFunctionWithDynamicResiduals f(my_functor_dyn);
+//
+// Vec3 x = ...;
+// TinySolver<AutoDiffFunctionWithDynamicResiduals> solver;
+// solver.Solve(f, &x);
+//
+// WARNING: The cost function adapter is not thread safe.
+template <typename CostFunctor,
+ int kNumResiduals,
+ int kNumParameters,
+ typename T = double>
+class TinySolverAutoDiffFunction {
+ public:
+ // This class needs to have an Eigen aligned operator new as it contains
+ // as a member a Jet type, which itself has a fixed-size Eigen type as member.
+ EIGEN_MAKE_ALIGNED_OPERATOR_NEW
+
+ TinySolverAutoDiffFunction(const CostFunctor& cost_functor)
+ : cost_functor_(cost_functor) {
+ Initialize<kNumResiduals>(cost_functor);
+ }
+
+ typedef T Scalar;
+ enum {
+ NUM_PARAMETERS = kNumParameters,
+ NUM_RESIDUALS = kNumResiduals,
+ };
+
+ // This is similar to AutoDifferentiate(), but since there is only one
+ // parameter block it is easier to inline to avoid overhead.
+ bool operator()(const T* parameters, T* residuals, T* jacobian) const {
+ if (jacobian == NULL) {
+ // No jacobian requested, so just directly call the cost function with
+ // doubles, skipping jets and derivatives.
+ return cost_functor_(parameters, residuals);
+ }
+ // Initialize the input jets with passed parameters.
+ for (int i = 0; i < kNumParameters; ++i) {
+ jet_parameters_[i].a = parameters[i]; // Scalar part.
+ jet_parameters_[i].v.setZero(); // Derivative part.
+ jet_parameters_[i].v[i] = T(1.0);
+ }
+
+ // Initialize the output jets such that we can detect user errors.
+ for (int i = 0; i < num_residuals_; ++i) {
+ jet_residuals_[i].a = kImpossibleValue;
+ jet_residuals_[i].v.setConstant(kImpossibleValue);
+ }
+
+ // Execute the cost function, but with jets to find the derivative.
+ if (!cost_functor_(jet_parameters_, jet_residuals_.data())) {
+ return false;
+ }
+
+ // Copy the jacobian out of the derivative part of the residual jets.
+ Eigen::Map<Eigen::Matrix<T, kNumResiduals, kNumParameters>> jacobian_matrix(
+ jacobian, num_residuals_, kNumParameters);
+ for (int r = 0; r < num_residuals_; ++r) {
+ residuals[r] = jet_residuals_[r].a;
+ // Note that while this looks like a fast vectorized write, in practice it
+ // unfortunately thrashes the cache since the writes to the column-major
+ // jacobian are strided (e.g. rows are non-contiguous).
+ jacobian_matrix.row(r) = jet_residuals_[r].v;
+ }
+ return true;
+ }
+
+ int NumResiduals() const {
+ return num_residuals_; // Set by Initialize.
+ }
+
+ private:
+ const CostFunctor& cost_functor_;
+
+ // The number of residuals at runtime.
+ // This will be overriden if NUM_RESIDUALS == Eigen::Dynamic.
+ int num_residuals_ = kNumResiduals;
+
+ // To evaluate the cost function with jets, temporary storage is needed. These
+ // are the buffers that are used during evaluation; parameters for the input,
+ // and jet_residuals_ are where the final cost and derivatives end up.
+ //
+ // Since this buffer is used for evaluation, the adapter is not thread safe.
+ using JetType = Jet<T, kNumParameters>;
+ mutable JetType jet_parameters_[kNumParameters];
+ // Eigen::Matrix serves as static or dynamic container.
+ mutable Eigen::Matrix<JetType, kNumResiduals, 1> jet_residuals_;
+
+ // The number of residuals is dynamically sized and the number of
+ // parameters is statically sized.
+ template <int R>
+ typename std::enable_if<(R == Eigen::Dynamic), void>::type Initialize(
+ const CostFunctor& function) {
+ jet_residuals_.resize(function.NumResiduals());
+ num_residuals_ = function.NumResiduals();
+ }
+
+ // The number of parameters and residuals are statically sized.
+ template <int R>
+ typename std::enable_if<(R != Eigen::Dynamic), void>::type Initialize(
+ const CostFunctor& /* function */) {
+ num_residuals_ = kNumResiduals;
+ }
+};
+
+} // namespace ceres
+
+#endif // CERES_PUBLIC_TINY_SOLVER_AUTODIFF_FUNCTION_H_
diff --git a/extern/ceres/include/ceres/tiny_solver_cost_function_adapter.h b/extern/ceres/include/ceres/tiny_solver_cost_function_adapter.h
new file mode 100644
index 00000000000..18ccb398f90
--- /dev/null
+++ b/extern/ceres/include/ceres/tiny_solver_cost_function_adapter.h
@@ -0,0 +1,142 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2019 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#ifndef CERES_PUBLIC_TINY_SOLVER_COST_FUNCTION_ADAPTER_H_
+#define CERES_PUBLIC_TINY_SOLVER_COST_FUNCTION_ADAPTER_H_
+
+#include "Eigen/Core"
+#include "ceres/cost_function.h"
+#include "glog/logging.h"
+
+namespace ceres {
+
+// An adapter class that lets users of TinySolver use
+// ceres::CostFunction objects that have exactly one parameter block.
+//
+// The adapter allows for the number of residuals and the size of the
+// parameter block to be specified at compile or run-time.
+//
+// WARNING: This object is not thread-safe.
+//
+// Example usage:
+//
+// CostFunction* cost_function = ...
+//
+// Number of residuals and parameter block size known at compile time:
+//
+// TinySolverCostFunctionAdapter<kNumResiduals, kNumParameters>
+// cost_function_adapter(*cost_function);
+//
+// Number of residuals known at compile time and the parameter block
+// size not known at compile time.
+//
+// TinySolverCostFunctionAdapter<kNumResiduals, Eigen::Dynamic>
+// cost_function_adapter(*cost_function);
+//
+// Number of residuals not known at compile time and the parameter
+// block size known at compile time.
+//
+// TinySolverCostFunctionAdapter<Eigen::Dynamic, kParameterBlockSize>
+// cost_function_adapter(*cost_function);
+//
+// Number of residuals not known at compile time and the parameter
+// block size not known at compile time.
+//
+// TinySolverCostFunctionAdapter cost_function_adapter(*cost_function);
+//
+template <int kNumResiduals = Eigen::Dynamic,
+ int kNumParameters = Eigen::Dynamic>
+class TinySolverCostFunctionAdapter {
+ public:
+ typedef double Scalar;
+ enum ComponentSizeType {
+ NUM_PARAMETERS = kNumParameters,
+ NUM_RESIDUALS = kNumResiduals
+ };
+
+ // This struct needs to have an Eigen aligned operator new as it contains
+ // fixed-size Eigen types.
+ EIGEN_MAKE_ALIGNED_OPERATOR_NEW
+
+ TinySolverCostFunctionAdapter(const CostFunction& cost_function)
+ : cost_function_(cost_function) {
+ CHECK_EQ(cost_function_.parameter_block_sizes().size(), 1)
+ << "Only CostFunctions with exactly one parameter blocks are allowed.";
+
+ const int parameter_block_size = cost_function_.parameter_block_sizes()[0];
+ if (NUM_PARAMETERS == Eigen::Dynamic || NUM_RESIDUALS == Eigen::Dynamic) {
+ if (NUM_RESIDUALS != Eigen::Dynamic) {
+ CHECK_EQ(cost_function_.num_residuals(), NUM_RESIDUALS);
+ }
+ if (NUM_PARAMETERS != Eigen::Dynamic) {
+ CHECK_EQ(parameter_block_size, NUM_PARAMETERS);
+ }
+
+ row_major_jacobian_.resize(cost_function_.num_residuals(),
+ parameter_block_size);
+ }
+ }
+
+ bool operator()(const double* parameters,
+ double* residuals,
+ double* jacobian) const {
+ if (!jacobian) {
+ return cost_function_.Evaluate(&parameters, residuals, NULL);
+ }
+
+ double* jacobians[1] = {row_major_jacobian_.data()};
+ if (!cost_function_.Evaluate(&parameters, residuals, jacobians)) {
+ return false;
+ }
+
+ // The Function object used by TinySolver takes its Jacobian in a
+ // column-major layout, and the CostFunction objects use row-major
+ // Jacobian matrices. So the following bit of code does the
+ // conversion from row-major Jacobians to column-major Jacobians.
+ Eigen::Map<Eigen::Matrix<double, NUM_RESIDUALS, NUM_PARAMETERS>>
+ col_major_jacobian(jacobian, NumResiduals(), NumParameters());
+ col_major_jacobian = row_major_jacobian_;
+ return true;
+ }
+
+ int NumResiduals() const { return cost_function_.num_residuals(); }
+ int NumParameters() const {
+ return cost_function_.parameter_block_sizes()[0];
+ }
+
+ private:
+ const CostFunction& cost_function_;
+ mutable Eigen::Matrix<double, NUM_RESIDUALS, NUM_PARAMETERS, Eigen::RowMajor>
+ row_major_jacobian_;
+};
+
+} // namespace ceres
+
+#endif // CERES_PUBLIC_TINY_SOLVER_COST_FUNCTION_ADAPTER_H_
diff --git a/extern/ceres/include/ceres/types.h b/extern/ceres/include/ceres/types.h
index 2ea41803629..3a19b7333b2 100644
--- a/extern/ceres/include/ceres/types.h
+++ b/extern/ceres/include/ceres/types.h
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2019 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -39,15 +39,11 @@
#include <string>
-#include "ceres/internal/port.h"
#include "ceres/internal/disable_warnings.h"
+#include "ceres/internal/port.h"
namespace ceres {
-// Basic integer types. These typedefs are in the Ceres namespace to avoid
-// conflicts with other packages having similar typedefs.
-typedef int int32;
-
// Argument type used in interfaces that can optionally take ownership
// of a passed in argument. If TAKE_OWNERSHIP is passed, the called
// object takes ownership of the pointer argument, and will call
@@ -116,10 +112,29 @@ enum PreconditionerType {
// the scene to determine the sparsity structure of the
// preconditioner. This is done using a clustering algorithm. The
// available visibility clustering algorithms are described below.
- //
- // Note: Requires SuiteSparse.
CLUSTER_JACOBI,
- CLUSTER_TRIDIAGONAL
+ CLUSTER_TRIDIAGONAL,
+
+ // Subset preconditioner is a general purpose preconditioner
+ // linear least squares problems. Given a set of residual blocks,
+ // it uses the corresponding subset of the rows of the Jacobian to
+ // construct a preconditioner.
+ //
+ // Suppose the Jacobian J has been horizontally partitioned as
+ //
+ // J = [P]
+ // [Q]
+ //
+ // Where, Q is the set of rows corresponding to the residual
+ // blocks in residual_blocks_for_subset_preconditioner.
+ //
+ // The preconditioner is the inverse of the matrix Q'Q.
+ //
+ // Obviously, the efficacy of the preconditioner depends on how
+ // well the matrix Q approximates J'J, or how well the chosen
+ // residual blocks approximate the non-linear least squares
+ // problem.
+ SUBSET,
};
enum VisibilityClusteringType {
@@ -150,7 +165,7 @@ enum SparseLinearAlgebraLibraryType {
// minimum degree ordering.
SUITE_SPARSE,
- // A lightweight replacment for SuiteSparse, which does not require
+ // A lightweight replacement for SuiteSparse, which does not require
// a LAPACK/BLAS implementation. Consequently, its performance is
// also a bit lower than SuiteSparse.
CX_SPARSE,
@@ -159,6 +174,9 @@ enum SparseLinearAlgebraLibraryType {
// the Simplicial LDLT routines.
EIGEN_SPARSE,
+ // Apple's Accelerate framework sparse linear algebra routines.
+ ACCELERATE_SPARSE,
+
// No sparse linear solver should be used. This does not necessarily
// imply that Ceres was built without any sparse library, although that
// is the likely use case, merely that one should not be used.
@@ -202,7 +220,7 @@ enum LineSearchDirectionType {
// symmetric matrix but only N conditions are specified by the Secant
// equation. The requirement that the Hessian approximation be positive
// definite imposes another N additional constraints, but that still leaves
- // remaining degrees-of-freedom. (L)BFGS methods uniquely deteremine the
+ // remaining degrees-of-freedom. (L)BFGS methods uniquely determine the
// approximate Hessian by imposing the additional constraints that the
// approximation at the next iteration must be the 'closest' to the current
// approximation (the nature of how this proximity is measured is actually
@@ -222,26 +240,26 @@ enum LineSearchDirectionType {
// For more details on BFGS see:
//
// Broyden, C.G., "The Convergence of a Class of Double-rank Minimization
- // Algorithms,"; J. Inst. Maths. Applics., Vol. 6, pp 76–90, 1970.
+ // Algorithms,"; J. Inst. Maths. Applics., Vol. 6, pp 76-90, 1970.
//
// Fletcher, R., "A New Approach to Variable Metric Algorithms,"
- // Computer Journal, Vol. 13, pp 317–322, 1970.
+ // Computer Journal, Vol. 13, pp 317-322, 1970.
//
// Goldfarb, D., "A Family of Variable Metric Updates Derived by Variational
- // Means," Mathematics of Computing, Vol. 24, pp 23–26, 1970.
+ // Means," Mathematics of Computing, Vol. 24, pp 23-26, 1970.
//
// Shanno, D.F., "Conditioning of Quasi-Newton Methods for Function
- // Minimization," Mathematics of Computing, Vol. 24, pp 647–656, 1970.
+ // Minimization," Mathematics of Computing, Vol. 24, pp 647-656, 1970.
//
// For more details on L-BFGS see:
//
// Nocedal, J. (1980). "Updating Quasi-Newton Matrices with Limited
- // Storage". Mathematics of Computation 35 (151): 773–782.
+ // Storage". Mathematics of Computation 35 (151): 773-782.
//
// Byrd, R. H.; Nocedal, J.; Schnabel, R. B. (1994).
// "Representations of Quasi-Newton Matrices and their use in
// Limited Memory Methods". Mathematical Programming 63 (4):
- // 129–156.
+ // 129-156.
//
// A general reference for both methods:
//
@@ -250,7 +268,7 @@ enum LineSearchDirectionType {
BFGS,
};
-// Nonliner conjugate gradient methods are a generalization of the
+// Nonlinear conjugate gradient methods are a generalization of the
// method of Conjugate Gradients for linear systems. The
// generalization can be carried out in a number of different ways
// leading to number of different rules for computing the search
@@ -420,10 +438,16 @@ enum LineSearchInterpolationType {
enum CovarianceAlgorithmType {
DENSE_SVD,
- SUITE_SPARSE_QR,
- EIGEN_SPARSE_QR
+ SPARSE_QR,
};
+// It is a near impossibility that user code generates this exact
+// value in normal operation, thus we will use it to fill arrays
+// before passing them to user code. If on return an element of the
+// array still contains this value, we will assume that the user code
+// did not write to that memory location.
+const double kImpossibleValue = 1e302;
+
CERES_EXPORT const char* LinearSolverTypeToString(
LinearSolverType type);
CERES_EXPORT bool StringToLinearSolverType(std::string value,
@@ -493,6 +517,13 @@ CERES_EXPORT bool StringToNumericDiffMethodType(
std::string value,
NumericDiffMethodType* type);
+CERES_EXPORT const char* LoggingTypeToString(LoggingType type);
+CERES_EXPORT bool StringtoLoggingType(std::string value, LoggingType* type);
+
+CERES_EXPORT const char* DumpFormatTypeToString(DumpFormatType type);
+CERES_EXPORT bool StringtoDumpFormatType(std::string value, DumpFormatType* type);
+CERES_EXPORT bool StringtoDumpFormatType(std::string value, LoggingType* type);
+
CERES_EXPORT const char* TerminationTypeToString(TerminationType type);
CERES_EXPORT bool IsSchurType(LinearSolverType type);
diff --git a/extern/ceres/include/ceres/version.h b/extern/ceres/include/ceres/version.h
index 2f1cc297a38..50aa2124e75 100644
--- a/extern/ceres/include/ceres/version.h
+++ b/extern/ceres/include/ceres/version.h
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2019 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -31,8 +31,8 @@
#ifndef CERES_PUBLIC_VERSION_H_
#define CERES_PUBLIC_VERSION_H_
-#define CERES_VERSION_MAJOR 1
-#define CERES_VERSION_MINOR 12
+#define CERES_VERSION_MAJOR 2
+#define CERES_VERSION_MINOR 0
#define CERES_VERSION_REVISION 0
// Classic CPP stringifcation; the extra level of indirection allows the
diff --git a/extern/ceres/internal/ceres/accelerate_sparse.cc b/extern/ceres/internal/ceres/accelerate_sparse.cc
new file mode 100644
index 00000000000..eb04e7113d7
--- /dev/null
+++ b/extern/ceres/internal/ceres/accelerate_sparse.cc
@@ -0,0 +1,289 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2018 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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.
+//
+// Author: alexs.mac@gmail.com (Alex Stewart)
+
+// This include must come before any #ifndef check on Ceres compile options.
+#include "ceres/internal/port.h"
+
+#ifndef CERES_NO_ACCELERATE_SPARSE
+
+#include "ceres/accelerate_sparse.h"
+
+#include <algorithm>
+#include <string>
+#include <vector>
+
+#include "ceres/compressed_col_sparse_matrix_utils.h"
+#include "ceres/compressed_row_sparse_matrix.h"
+#include "ceres/triplet_sparse_matrix.h"
+#include "glog/logging.h"
+
+#define CASESTR(x) case x: return #x
+
+namespace ceres {
+namespace internal {
+
+namespace {
+const char* SparseStatusToString(SparseStatus_t status) {
+ switch (status) {
+ CASESTR(SparseStatusOK);
+ CASESTR(SparseFactorizationFailed);
+ CASESTR(SparseMatrixIsSingular);
+ CASESTR(SparseInternalError);
+ CASESTR(SparseParameterError);
+ CASESTR(SparseStatusReleased);
+ default:
+ return "UKNOWN";
+ }
+}
+} // namespace.
+
+// Resizes workspace as required to contain at least required_size bytes
+// aligned to kAccelerateRequiredAlignment and returns a pointer to the
+// aligned start.
+void* ResizeForAccelerateAlignment(const size_t required_size,
+ std::vector<uint8_t> *workspace) {
+ // As per the Accelerate documentation, all workspace memory passed to the
+ // sparse solver functions must be 16-byte aligned.
+ constexpr int kAccelerateRequiredAlignment = 16;
+ // Although malloc() on macOS should always be 16-byte aligned, it is unclear
+ // if this holds for new(), or on other Apple OSs (phoneOS, watchOS etc).
+ // As such we assume it is not and use std::align() to create a (potentially
+ // offset) 16-byte aligned sub-buffer of the specified size within workspace.
+ workspace->resize(required_size + kAccelerateRequiredAlignment);
+ size_t size_from_aligned_start = workspace->size();
+ void* aligned_solve_workspace_start =
+ reinterpret_cast<void*>(workspace->data());
+ aligned_solve_workspace_start =
+ std::align(kAccelerateRequiredAlignment,
+ required_size,
+ aligned_solve_workspace_start,
+ size_from_aligned_start);
+ CHECK(aligned_solve_workspace_start != nullptr)
+ << "required_size: " << required_size
+ << ", workspace size: " << workspace->size();
+ return aligned_solve_workspace_start;
+}
+
+template<typename Scalar>
+void AccelerateSparse<Scalar>::Solve(NumericFactorization* numeric_factor,
+ DenseVector* rhs_and_solution) {
+ // From SparseSolve() documentation in Solve.h
+ const int required_size =
+ numeric_factor->solveWorkspaceRequiredStatic +
+ numeric_factor->solveWorkspaceRequiredPerRHS;
+ SparseSolve(*numeric_factor, *rhs_and_solution,
+ ResizeForAccelerateAlignment(required_size, &solve_workspace_));
+}
+
+template<typename Scalar>
+typename AccelerateSparse<Scalar>::ASSparseMatrix
+AccelerateSparse<Scalar>::CreateSparseMatrixTransposeView(
+ CompressedRowSparseMatrix* A) {
+ // Accelerate uses CSC as its sparse storage format whereas Ceres uses CSR.
+ // As this method returns the transpose view we can flip rows/cols to map
+ // from CSR to CSC^T.
+ //
+ // Accelerate's columnStarts is a long*, not an int*. These types might be
+ // different (e.g. ARM on iOS) so always make a copy.
+ column_starts_.resize(A->num_rows() +1); // +1 for final column length.
+ std::copy_n(A->rows(), column_starts_.size(), &column_starts_[0]);
+
+ ASSparseMatrix At;
+ At.structure.rowCount = A->num_cols();
+ At.structure.columnCount = A->num_rows();
+ At.structure.columnStarts = &column_starts_[0];
+ At.structure.rowIndices = A->mutable_cols();
+ At.structure.attributes.transpose = false;
+ At.structure.attributes.triangle = SparseUpperTriangle;
+ At.structure.attributes.kind = SparseSymmetric;
+ At.structure.attributes._reserved = 0;
+ At.structure.attributes._allocatedBySparse = 0;
+ At.structure.blockSize = 1;
+ if (std::is_same<Scalar, double>::value) {
+ At.data = reinterpret_cast<Scalar*>(A->mutable_values());
+ } else {
+ values_ =
+ ConstVectorRef(A->values(), A->num_nonzeros()).template cast<Scalar>();
+ At.data = values_.data();
+ }
+ return At;
+}
+
+template<typename Scalar>
+typename AccelerateSparse<Scalar>::SymbolicFactorization
+AccelerateSparse<Scalar>::AnalyzeCholesky(ASSparseMatrix* A) {
+ return SparseFactor(SparseFactorizationCholesky, A->structure);
+}
+
+template<typename Scalar>
+typename AccelerateSparse<Scalar>::NumericFactorization
+AccelerateSparse<Scalar>::Cholesky(ASSparseMatrix* A,
+ SymbolicFactorization* symbolic_factor) {
+ return SparseFactor(*symbolic_factor, *A);
+}
+
+template<typename Scalar>
+void AccelerateSparse<Scalar>::Cholesky(ASSparseMatrix* A,
+ NumericFactorization* numeric_factor) {
+ // From SparseRefactor() documentation in Solve.h
+ const int required_size = std::is_same<Scalar, double>::value
+ ? numeric_factor->symbolicFactorization.workspaceSize_Double
+ : numeric_factor->symbolicFactorization.workspaceSize_Float;
+ return SparseRefactor(*A, numeric_factor,
+ ResizeForAccelerateAlignment(required_size,
+ &factorization_workspace_));
+}
+
+// Instantiate only for the specific template types required/supported s/t the
+// definition can be in the .cc file.
+template class AccelerateSparse<double>;
+template class AccelerateSparse<float>;
+
+template<typename Scalar>
+std::unique_ptr<SparseCholesky>
+AppleAccelerateCholesky<Scalar>::Create(OrderingType ordering_type) {
+ return std::unique_ptr<SparseCholesky>(
+ new AppleAccelerateCholesky<Scalar>(ordering_type));
+}
+
+template<typename Scalar>
+AppleAccelerateCholesky<Scalar>::AppleAccelerateCholesky(
+ const OrderingType ordering_type)
+ : ordering_type_(ordering_type) {}
+
+template<typename Scalar>
+AppleAccelerateCholesky<Scalar>::~AppleAccelerateCholesky() {
+ FreeSymbolicFactorization();
+ FreeNumericFactorization();
+}
+
+template<typename Scalar>
+CompressedRowSparseMatrix::StorageType
+AppleAccelerateCholesky<Scalar>::StorageType() const {
+ return CompressedRowSparseMatrix::LOWER_TRIANGULAR;
+}
+
+template<typename Scalar>
+LinearSolverTerminationType
+AppleAccelerateCholesky<Scalar>::Factorize(CompressedRowSparseMatrix* lhs,
+ std::string* message) {
+ CHECK_EQ(lhs->storage_type(), StorageType());
+ if (lhs == NULL) {
+ *message = "Failure: Input lhs is NULL.";
+ return LINEAR_SOLVER_FATAL_ERROR;
+ }
+ typename SparseTypesTrait<Scalar>::SparseMatrix as_lhs =
+ as_.CreateSparseMatrixTransposeView(lhs);
+
+ if (!symbolic_factor_) {
+ symbolic_factor_.reset(
+ new typename SparseTypesTrait<Scalar>::SymbolicFactorization(
+ as_.AnalyzeCholesky(&as_lhs)));
+ if (symbolic_factor_->status != SparseStatusOK) {
+ *message = StringPrintf(
+ "Apple Accelerate Failure : Symbolic factorisation failed: %s",
+ SparseStatusToString(symbolic_factor_->status));
+ FreeSymbolicFactorization();
+ return LINEAR_SOLVER_FATAL_ERROR;
+ }
+ }
+
+ if (!numeric_factor_) {
+ numeric_factor_.reset(
+ new typename SparseTypesTrait<Scalar>::NumericFactorization(
+ as_.Cholesky(&as_lhs, symbolic_factor_.get())));
+ } else {
+ // Recycle memory from previous numeric factorization.
+ as_.Cholesky(&as_lhs, numeric_factor_.get());
+ }
+ if (numeric_factor_->status != SparseStatusOK) {
+ *message = StringPrintf(
+ "Apple Accelerate Failure : Numeric factorisation failed: %s",
+ SparseStatusToString(numeric_factor_->status));
+ FreeNumericFactorization();
+ return LINEAR_SOLVER_FAILURE;
+ }
+
+ return LINEAR_SOLVER_SUCCESS;
+}
+
+template<typename Scalar>
+LinearSolverTerminationType
+AppleAccelerateCholesky<Scalar>::Solve(const double* rhs,
+ double* solution,
+ std::string* message) {
+ CHECK_EQ(numeric_factor_->status, SparseStatusOK)
+ << "Solve called without a call to Factorize first ("
+ << SparseStatusToString(numeric_factor_->status) << ").";
+ const int num_cols = numeric_factor_->symbolicFactorization.columnCount;
+
+ typename SparseTypesTrait<Scalar>::DenseVector as_rhs_and_solution;
+ as_rhs_and_solution.count = num_cols;
+ if (std::is_same<Scalar, double>::value) {
+ as_rhs_and_solution.data = reinterpret_cast<Scalar*>(solution);
+ std::copy_n(rhs, num_cols, solution);
+ } else {
+ scalar_rhs_and_solution_ =
+ ConstVectorRef(rhs, num_cols).template cast<Scalar>();
+ as_rhs_and_solution.data = scalar_rhs_and_solution_.data();
+ }
+ as_.Solve(numeric_factor_.get(), &as_rhs_and_solution);
+ if (!std::is_same<Scalar, double>::value) {
+ VectorRef(solution, num_cols) =
+ scalar_rhs_and_solution_.template cast<double>();
+ }
+ return LINEAR_SOLVER_SUCCESS;
+}
+
+template<typename Scalar>
+void AppleAccelerateCholesky<Scalar>::FreeSymbolicFactorization() {
+ if (symbolic_factor_) {
+ SparseCleanup(*symbolic_factor_);
+ symbolic_factor_.reset();
+ }
+}
+
+template<typename Scalar>
+void AppleAccelerateCholesky<Scalar>::FreeNumericFactorization() {
+ if (numeric_factor_) {
+ SparseCleanup(*numeric_factor_);
+ numeric_factor_.reset();
+ }
+}
+
+// Instantiate only for the specific template types required/supported s/t the
+// definition can be in the .cc file.
+template class AppleAccelerateCholesky<double>;
+template class AppleAccelerateCholesky<float>;
+
+}
+}
+
+#endif // CERES_NO_ACCELERATE_SPARSE
diff --git a/extern/ceres/internal/ceres/accelerate_sparse.h b/extern/ceres/internal/ceres/accelerate_sparse.h
new file mode 100644
index 00000000000..43b4ea5fd70
--- /dev/null
+++ b/extern/ceres/internal/ceres/accelerate_sparse.h
@@ -0,0 +1,147 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2018 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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.
+//
+// Author: alexs.mac@gmail.com (Alex Stewart)
+
+#ifndef CERES_INTERNAL_ACCELERATE_SPARSE_H_
+#define CERES_INTERNAL_ACCELERATE_SPARSE_H_
+
+// This include must come before any #ifndef check on Ceres compile options.
+#include "ceres/internal/port.h"
+
+#ifndef CERES_NO_ACCELERATE_SPARSE
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "ceres/linear_solver.h"
+#include "ceres/sparse_cholesky.h"
+#include "Accelerate.h"
+
+namespace ceres {
+namespace internal {
+
+class CompressedRowSparseMatrix;
+class TripletSparseMatrix;
+
+template<typename Scalar>
+struct SparseTypesTrait {
+};
+
+template<>
+struct SparseTypesTrait<double> {
+ typedef DenseVector_Double DenseVector;
+ typedef SparseMatrix_Double SparseMatrix;
+ typedef SparseOpaqueSymbolicFactorization SymbolicFactorization;
+ typedef SparseOpaqueFactorization_Double NumericFactorization;
+};
+
+template<>
+struct SparseTypesTrait<float> {
+ typedef DenseVector_Float DenseVector;
+ typedef SparseMatrix_Float SparseMatrix;
+ typedef SparseOpaqueSymbolicFactorization SymbolicFactorization;
+ typedef SparseOpaqueFactorization_Float NumericFactorization;
+};
+
+template<typename Scalar>
+class AccelerateSparse {
+ public:
+ using DenseVector = typename SparseTypesTrait<Scalar>::DenseVector;
+ // Use ASSparseMatrix to avoid collision with ceres::internal::SparseMatrix.
+ using ASSparseMatrix = typename SparseTypesTrait<Scalar>::SparseMatrix;
+ using SymbolicFactorization = typename SparseTypesTrait<Scalar>::SymbolicFactorization;
+ using NumericFactorization = typename SparseTypesTrait<Scalar>::NumericFactorization;
+
+ // Solves a linear system given its symbolic (reference counted within
+ // NumericFactorization) and numeric factorization.
+ void Solve(NumericFactorization* numeric_factor,
+ DenseVector* rhs_and_solution);
+
+ // Note: Accelerate's API passes/returns its objects by value, but as the
+ // objects contain pointers to the underlying data these copies are
+ // all shallow (in some cases Accelerate also reference counts the
+ // objects internally).
+ ASSparseMatrix CreateSparseMatrixTransposeView(CompressedRowSparseMatrix* A);
+ // Computes a symbolic factorisation of A that can be used in Solve().
+ SymbolicFactorization AnalyzeCholesky(ASSparseMatrix* A);
+ // Compute the numeric Cholesky factorization of A, given its
+ // symbolic factorization.
+ NumericFactorization Cholesky(ASSparseMatrix* A,
+ SymbolicFactorization* symbolic_factor);
+ // Reuse the NumericFactorization from a previous matrix with the same
+ // symbolic factorization to represent a new numeric factorization.
+ void Cholesky(ASSparseMatrix* A, NumericFactorization* numeric_factor);
+
+ private:
+ std::vector<long> column_starts_;
+ std::vector<uint8_t> solve_workspace_;
+ std::vector<uint8_t> factorization_workspace_;
+ // Storage for the values of A if Scalar != double (necessitating a copy).
+ Eigen::Matrix<Scalar, Eigen::Dynamic, 1> values_;
+};
+
+// An implementation of SparseCholesky interface using Apple's Accelerate
+// framework.
+template<typename Scalar>
+class AppleAccelerateCholesky : public SparseCholesky {
+ public:
+ // Factory
+ static std::unique_ptr<SparseCholesky> Create(OrderingType ordering_type);
+
+ // SparseCholesky interface.
+ virtual ~AppleAccelerateCholesky();
+ CompressedRowSparseMatrix::StorageType StorageType() const;
+ LinearSolverTerminationType Factorize(CompressedRowSparseMatrix* lhs,
+ std::string* message) final;
+ LinearSolverTerminationType Solve(const double* rhs,
+ double* solution,
+ std::string* message) final ;
+
+ private:
+ AppleAccelerateCholesky(const OrderingType ordering_type);
+ void FreeSymbolicFactorization();
+ void FreeNumericFactorization();
+
+ const OrderingType ordering_type_;
+ AccelerateSparse<Scalar> as_;
+ std::unique_ptr<typename AccelerateSparse<Scalar>::SymbolicFactorization>
+ symbolic_factor_;
+ std::unique_ptr<typename AccelerateSparse<Scalar>::NumericFactorization>
+ numeric_factor_;
+ // Copy of rhs/solution if Scalar != double (necessitating a copy).
+ Eigen::Matrix<Scalar, Eigen::Dynamic, 1> scalar_rhs_and_solution_;
+};
+
+}
+}
+
+#endif // CERES_NO_ACCELERATE_SPARSE
+
+#endif // CERES_INTERNAL_ACCELERATE_SPARSE_H_
diff --git a/extern/ceres/internal/ceres/array_utils.cc b/extern/ceres/internal/ceres/array_utils.cc
index 7be3c78ce24..32459e6dcd9 100644
--- a/extern/ceres/internal/ceres/array_utils.cc
+++ b/extern/ceres/internal/ceres/array_utils.cc
@@ -35,25 +35,17 @@
#include <cstddef>
#include <string>
#include <vector>
-#include "ceres/fpclassify.h"
#include "ceres/stringprintf.h"
-
+#include "ceres/types.h"
namespace ceres {
namespace internal {
using std::string;
-// It is a near impossibility that user code generates this exact
-// value in normal operation, thus we will use it to fill arrays
-// before passing them to user code. If on return an element of the
-// array still contains this value, we will assume that the user code
-// did not write to that memory location.
-const double kImpossibleValue = 1e302;
-
bool IsArrayValid(const int size, const double* x) {
if (x != NULL) {
for (int i = 0; i < size; ++i) {
- if (!IsFinite(x[i]) || (x[i] == kImpossibleValue)) {
+ if (!std::isfinite(x[i]) || (x[i] == kImpossibleValue)) {
return false;
}
}
@@ -67,7 +59,7 @@ int FindInvalidValue(const int size, const double* x) {
}
for (int i = 0; i < size; ++i) {
- if (!IsFinite(x[i]) || (x[i] == kImpossibleValue)) {
+ if (!std::isfinite(x[i]) || (x[i] == kImpossibleValue)) {
return i;
}
}
diff --git a/extern/ceres/internal/ceres/array_utils.h b/extern/ceres/internal/ceres/array_utils.h
index 2d2ffca8809..1d55733b7b8 100644
--- a/extern/ceres/internal/ceres/array_utils.h
+++ b/extern/ceres/internal/ceres/array_utils.h
@@ -66,11 +66,9 @@ int FindInvalidValue(const int size, const double* x);
// array pointer is NULL, it is treated as an array of zeros.
void AppendArrayToString(const int size, const double* x, std::string* result);
-extern const double kImpossibleValue;
-
// This routine takes an array of integer values, sorts and uniques
// them and then maps each value in the array to its position in the
-// sorted+uniqued array. By doing this, if there are are k unique
+// sorted+uniqued array. By doing this, if there are k unique
// values in the array, each value is replaced by an integer in the
// range [0, k-1], while preserving their relative order.
//
diff --git a/extern/ceres/internal/ceres/block_jacobi_preconditioner.cc b/extern/ceres/internal/ceres/block_jacobi_preconditioner.cc
index 22d4b351c51..772c7af2ba5 100644
--- a/extern/ceres/internal/ceres/block_jacobi_preconditioner.cc
+++ b/extern/ceres/internal/ceres/block_jacobi_preconditioner.cc
@@ -34,7 +34,6 @@
#include "ceres/block_structure.h"
#include "ceres/block_random_access_diagonal_matrix.h"
#include "ceres/casts.h"
-#include "ceres/integral_types.h"
#include "ceres/internal/eigen.h"
namespace ceres {
diff --git a/extern/ceres/internal/ceres/block_jacobi_preconditioner.h b/extern/ceres/internal/ceres/block_jacobi_preconditioner.h
index 14007295823..856b506e073 100644
--- a/extern/ceres/internal/ceres/block_jacobi_preconditioner.h
+++ b/extern/ceres/internal/ceres/block_jacobi_preconditioner.h
@@ -31,9 +31,8 @@
#ifndef CERES_INTERNAL_BLOCK_JACOBI_PRECONDITIONER_H_
#define CERES_INTERNAL_BLOCK_JACOBI_PRECONDITIONER_H_
-#include <vector>
+#include <memory>
#include "ceres/block_random_access_diagonal_matrix.h"
-#include "ceres/internal/scoped_ptr.h"
#include "ceres/preconditioner.h"
namespace ceres {
@@ -56,18 +55,21 @@ class BlockJacobiPreconditioner : public BlockSparseMatrixPreconditioner {
public:
// A must remain valid while the BlockJacobiPreconditioner is.
explicit BlockJacobiPreconditioner(const BlockSparseMatrix& A);
+ BlockJacobiPreconditioner(const BlockJacobiPreconditioner&) = delete;
+ void operator=(const BlockJacobiPreconditioner&) = delete;
+
virtual ~BlockJacobiPreconditioner();
// Preconditioner interface
- virtual void RightMultiply(const double* x, double* y) const;
- virtual int num_rows() const { return m_->num_rows(); }
- virtual int num_cols() const { return m_->num_rows(); }
-
+ void RightMultiply(const double* x, double* y) const final;
+ int num_rows() const final { return m_->num_rows(); }
+ int num_cols() const final { return m_->num_rows(); }
const BlockRandomAccessDiagonalMatrix& matrix() const { return *m_; }
+
private:
- virtual bool UpdateImpl(const BlockSparseMatrix& A, const double* D);
+ bool UpdateImpl(const BlockSparseMatrix& A, const double* D) final;
- scoped_ptr<BlockRandomAccessDiagonalMatrix> m_;
+ std::unique_ptr<BlockRandomAccessDiagonalMatrix> m_;
};
} // namespace internal
diff --git a/extern/ceres/internal/ceres/block_jacobian_writer.cc b/extern/ceres/internal/ceres/block_jacobian_writer.cc
index 7a3fee4fbdf..6998bd66e61 100644
--- a/extern/ceres/internal/ceres/block_jacobian_writer.cc
+++ b/extern/ceres/internal/ceres/block_jacobian_writer.cc
@@ -37,7 +37,6 @@
#include "ceres/residual_block.h"
#include "ceres/internal/eigen.h"
#include "ceres/internal/port.h"
-#include "ceres/internal/scoped_ptr.h"
namespace ceres {
namespace internal {
@@ -206,7 +205,7 @@ SparseMatrix* BlockJacobianWriter::CreateJacobian() const {
}
BlockSparseMatrix* jacobian = new BlockSparseMatrix(bs);
- CHECK_NOTNULL(jacobian);
+ CHECK(jacobian != nullptr);
return jacobian;
}
diff --git a/extern/ceres/internal/ceres/block_jacobian_writer.h b/extern/ceres/internal/ceres/block_jacobian_writer.h
index 8e6f45130a4..c94a0d3f909 100644
--- a/extern/ceres/internal/ceres/block_jacobian_writer.h
+++ b/extern/ceres/internal/ceres/block_jacobian_writer.h
@@ -49,6 +49,7 @@ class BlockEvaluatePreparer;
class Program;
class SparseMatrix;
+// TODO(sameeragarwal): This class needs documemtation.
class BlockJacobianWriter {
public:
BlockJacobianWriter(const Evaluator::Options& options,
diff --git a/extern/ceres/internal/ceres/block_random_access_dense_matrix.cc b/extern/ceres/internal/ceres/block_random_access_dense_matrix.cc
index 61748ef6f7f..f567aa5816b 100644
--- a/extern/ceres/internal/ceres/block_random_access_dense_matrix.cc
+++ b/extern/ceres/internal/ceres/block_random_access_dense_matrix.cc
@@ -32,7 +32,6 @@
#include <vector>
#include "ceres/internal/eigen.h"
-#include "ceres/internal/scoped_ptr.h"
#include "glog/logging.h"
namespace ceres {
diff --git a/extern/ceres/internal/ceres/block_random_access_dense_matrix.h b/extern/ceres/internal/ceres/block_random_access_dense_matrix.h
index 89689082561..8c5e2527ec1 100644
--- a/extern/ceres/internal/ceres/block_random_access_dense_matrix.h
+++ b/extern/ceres/internal/ceres/block_random_access_dense_matrix.h
@@ -33,11 +33,10 @@
#include "ceres/block_random_access_matrix.h"
+#include <memory>
#include <vector>
-#include "ceres/internal/macros.h"
#include "ceres/internal/port.h"
-#include "ceres/internal/scoped_ptr.h"
namespace ceres {
namespace internal {
@@ -57,27 +56,29 @@ class BlockRandomAccessDenseMatrix : public BlockRandomAccessMatrix {
// blocks is a vector of block sizes. The resulting matrix has
// blocks.size() * blocks.size() cells.
explicit BlockRandomAccessDenseMatrix(const std::vector<int>& blocks);
+ BlockRandomAccessDenseMatrix(const BlockRandomAccessDenseMatrix&) = delete;
+ void operator=(const BlockRandomAccessDenseMatrix&) = delete;
// The destructor is not thread safe. It assumes that no one is
// modifying any cells when the matrix is being destroyed.
virtual ~BlockRandomAccessDenseMatrix();
// BlockRandomAccessMatrix interface.
- virtual CellInfo* GetCell(int row_block_id,
- int col_block_id,
- int* row,
- int* col,
- int* row_stride,
- int* col_stride);
+ CellInfo* GetCell(int row_block_id,
+ int col_block_id,
+ int* row,
+ int* col,
+ int* row_stride,
+ int* col_stride) final;
// This is not a thread safe method, it assumes that no cell is
// locked.
- virtual void SetZero();
+ void SetZero() final;
// Since the matrix is square with the same row and column block
// structure, num_rows() = num_cols().
- virtual int num_rows() const { return num_rows_; }
- virtual int num_cols() const { return num_rows_; }
+ int num_rows() const final { return num_rows_; }
+ int num_cols() const final { return num_rows_; }
// The underlying matrix storing the cells.
const double* values() const { return values_.get(); }
@@ -86,10 +87,8 @@ class BlockRandomAccessDenseMatrix : public BlockRandomAccessMatrix {
private:
int num_rows_;
std::vector<int> block_layout_;
- scoped_array<double> values_;
- scoped_array<CellInfo> cell_infos_;
-
- CERES_DISALLOW_COPY_AND_ASSIGN(BlockRandomAccessDenseMatrix);
+ std::unique_ptr<double[]> values_;
+ std::unique_ptr<CellInfo[]> cell_infos_;
};
} // namespace internal
diff --git a/extern/ceres/internal/ceres/block_random_access_diagonal_matrix.cc b/extern/ceres/internal/ceres/block_random_access_diagonal_matrix.cc
index 052690d18be..526d173e4b0 100644
--- a/extern/ceres/internal/ceres/block_random_access_diagonal_matrix.cc
+++ b/extern/ceres/internal/ceres/block_random_access_diagonal_matrix.cc
@@ -34,9 +34,9 @@
#include <set>
#include <utility>
#include <vector>
+
#include "Eigen/Dense"
#include "ceres/internal/port.h"
-#include "ceres/internal/scoped_ptr.h"
#include "ceres/stl_util.h"
#include "ceres/triplet_sparse_matrix.h"
#include "ceres/types.h"
@@ -137,8 +137,8 @@ void BlockRandomAccessDiagonalMatrix::Invert() {
void BlockRandomAccessDiagonalMatrix::RightMultiply(const double* x,
double* y) const {
- CHECK_NOTNULL(x);
- CHECK_NOTNULL(y);
+ CHECK(x != nullptr);
+ CHECK(y != nullptr);
const double* values = tsm_->values();
for (int i = 0; i < blocks_.size(); ++i) {
const int block_size = blocks_[i];
diff --git a/extern/ceres/internal/ceres/block_random_access_diagonal_matrix.h b/extern/ceres/internal/ceres/block_random_access_diagonal_matrix.h
index 07ffc9d4a0d..3bda7d19074 100644
--- a/extern/ceres/internal/ceres/block_random_access_diagonal_matrix.h
+++ b/extern/ceres/internal/ceres/block_random_access_diagonal_matrix.h
@@ -31,17 +31,14 @@
#ifndef CERES_INTERNAL_BLOCK_RANDOM_ACCESS_DIAGONAL_MATRIX_H_
#define CERES_INTERNAL_BLOCK_RANDOM_ACCESS_DIAGONAL_MATRIX_H_
+#include <memory>
#include <set>
-#include <vector>
#include <utility>
-#include "ceres/mutex.h"
+#include <vector>
+
#include "ceres/block_random_access_matrix.h"
-#include "ceres/collections_port.h"
-#include "ceres/triplet_sparse_matrix.h"
-#include "ceres/integral_types.h"
-#include "ceres/internal/macros.h"
#include "ceres/internal/port.h"
-#include "ceres/internal/scoped_ptr.h"
+#include "ceres/triplet_sparse_matrix.h"
#include "ceres/types.h"
namespace ceres {
@@ -53,22 +50,24 @@ class BlockRandomAccessDiagonalMatrix : public BlockRandomAccessMatrix {
public:
// blocks is an array of block sizes.
explicit BlockRandomAccessDiagonalMatrix(const std::vector<int>& blocks);
+ BlockRandomAccessDiagonalMatrix(const BlockRandomAccessDiagonalMatrix&) = delete;
+ void operator=(const BlockRandomAccessDiagonalMatrix&) = delete;
// The destructor is not thread safe. It assumes that no one is
// modifying any cells when the matrix is being destroyed.
virtual ~BlockRandomAccessDiagonalMatrix();
// BlockRandomAccessMatrix Interface.
- virtual CellInfo* GetCell(int row_block_id,
- int col_block_id,
- int* row,
- int* col,
- int* row_stride,
- int* col_stride);
+ CellInfo* GetCell(int row_block_id,
+ int col_block_id,
+ int* row,
+ int* col,
+ int* row_stride,
+ int* col_stride) final;
// This is not a thread safe method, it assumes that no cell is
// locked.
- virtual void SetZero();
+ void SetZero() final;
// Invert the matrix assuming that each block is positive definite.
void Invert();
@@ -77,8 +76,8 @@ class BlockRandomAccessDiagonalMatrix : public BlockRandomAccessMatrix {
void RightMultiply(const double* x, double* y) const;
// Since the matrix is square, num_rows() == num_cols().
- virtual int num_rows() const { return tsm_->num_rows(); }
- virtual int num_cols() const { return tsm_->num_cols(); }
+ int num_rows() const final { return tsm_->num_rows(); }
+ int num_cols() const final { return tsm_->num_cols(); }
const TripletSparseMatrix* matrix() const { return tsm_.get(); }
TripletSparseMatrix* mutable_matrix() { return tsm_.get(); }
@@ -89,10 +88,9 @@ class BlockRandomAccessDiagonalMatrix : public BlockRandomAccessMatrix {
std::vector<CellInfo*> layout_;
// The underlying matrix object which actually stores the cells.
- scoped_ptr<TripletSparseMatrix> tsm_;
+ std::unique_ptr<TripletSparseMatrix> tsm_;
friend class BlockRandomAccessDiagonalMatrixTest;
- CERES_DISALLOW_COPY_AND_ASSIGN(BlockRandomAccessDiagonalMatrix);
};
} // namespace internal
diff --git a/extern/ceres/internal/ceres/block_random_access_matrix.h b/extern/ceres/internal/ceres/block_random_access_matrix.h
index 34c8bf5cd4d..6fcf0dc8a7c 100644
--- a/extern/ceres/internal/ceres/block_random_access_matrix.h
+++ b/extern/ceres/internal/ceres/block_random_access_matrix.h
@@ -33,7 +33,7 @@
#ifndef CERES_INTERNAL_BLOCK_RANDOM_ACCESS_MATRIX_H_
#define CERES_INTERNAL_BLOCK_RANDOM_ACCESS_MATRIX_H_
-#include "ceres/mutex.h"
+#include <mutex>
namespace ceres {
namespace internal {
@@ -77,23 +77,18 @@ namespace internal {
//
// if (cell != NULL) {
// MatrixRef m(cell->values, row_stride, col_stride);
-// CeresMutexLock l(&cell->m);
+// std::lock_guard<std::mutex> l(&cell->m);
// m.block(row, col, row_block_size, col_block_size) = ...
// }
// Structure to carry a pointer to the array containing a cell and the
-// Mutex guarding it.
+// mutex guarding it.
struct CellInfo {
- CellInfo()
- : values(NULL) {
- }
-
- explicit CellInfo(double* ptr)
- : values(ptr) {
- }
+ CellInfo() : values(nullptr) {}
+ explicit CellInfo(double* values) : values(values) {}
double* values;
- Mutex m;
+ std::mutex m;
};
class BlockRandomAccessMatrix {
diff --git a/extern/ceres/internal/ceres/block_random_access_sparse_matrix.cc b/extern/ceres/internal/ceres/block_random_access_sparse_matrix.cc
index 5432ec1064a..9c164546635 100644
--- a/extern/ceres/internal/ceres/block_random_access_sparse_matrix.cc
+++ b/extern/ceres/internal/ceres/block_random_access_sparse_matrix.cc
@@ -31,12 +31,12 @@
#include "ceres/block_random_access_sparse_matrix.h"
#include <algorithm>
+#include <memory>
#include <set>
#include <utility>
#include <vector>
+
#include "ceres/internal/port.h"
-#include "ceres/internal/scoped_ptr.h"
-#include "ceres/mutex.h"
#include "ceres/triplet_sparse_matrix.h"
#include "ceres/types.h"
#include "glog/logging.h"
@@ -51,7 +51,7 @@ using std::vector;
BlockRandomAccessSparseMatrix::BlockRandomAccessSparseMatrix(
const vector<int>& blocks,
- const set<pair<int, int> >& block_pairs)
+ const set<pair<int, int>>& block_pairs)
: kMaxRowBlocks(10 * 1000 * 1000),
blocks_(blocks) {
CHECK_LT(blocks.size(), kMaxRowBlocks);
@@ -69,11 +69,9 @@ BlockRandomAccessSparseMatrix::BlockRandomAccessSparseMatrix(
// object for looking into the values array of the
// TripletSparseMatrix.
int num_nonzeros = 0;
- for (set<pair<int, int> >::const_iterator it = block_pairs.begin();
- it != block_pairs.end();
- ++it) {
- const int row_block_size = blocks_[it->first];
- const int col_block_size = blocks_[it->second];
+ for (const auto& block_pair : block_pairs) {
+ const int row_block_size = blocks_[block_pair.first];
+ const int col_block_size = blocks_[block_pair.second];
num_nonzeros += row_block_size * col_block_size;
}
@@ -88,24 +86,19 @@ BlockRandomAccessSparseMatrix::BlockRandomAccessSparseMatrix(
double* values = tsm_->mutable_values();
int pos = 0;
- for (set<pair<int, int> >::const_iterator it = block_pairs.begin();
- it != block_pairs.end();
- ++it) {
- const int row_block_size = blocks_[it->first];
- const int col_block_size = blocks_[it->second];
- cell_values_.push_back(make_pair(make_pair(it->first, it->second),
- values + pos));
- layout_[IntPairToLong(it->first, it->second)] =
+ for (const auto& block_pair : block_pairs) {
+ const int row_block_size = blocks_[block_pair.first];
+ const int col_block_size = blocks_[block_pair.second];
+ cell_values_.push_back(make_pair(block_pair, values + pos));
+ layout_[IntPairToLong(block_pair.first, block_pair.second)] =
new CellInfo(values + pos);
pos += row_block_size * col_block_size;
}
// Fill the sparsity pattern of the underlying matrix.
- for (set<pair<int, int> >::const_iterator it = block_pairs.begin();
- it != block_pairs.end();
- ++it) {
- const int row_block_id = it->first;
- const int col_block_id = it->second;
+ for (const auto& block_pair : block_pairs) {
+ const int row_block_id = block_pair.first;
+ const int col_block_id = block_pair.second;
const int row_block_size = blocks_[row_block_id];
const int col_block_size = blocks_[col_block_id];
int pos =
@@ -125,10 +118,8 @@ BlockRandomAccessSparseMatrix::BlockRandomAccessSparseMatrix(
// Assume that the user does not hold any locks on any cell blocks
// when they are calling SetZero.
BlockRandomAccessSparseMatrix::~BlockRandomAccessSparseMatrix() {
- for (LayoutType::iterator it = layout_.begin();
- it != layout_.end();
- ++it) {
- delete it->second;
+ for (const auto& entry : layout_) {
+ delete entry.second;
}
}
@@ -163,19 +154,17 @@ void BlockRandomAccessSparseMatrix::SetZero() {
void BlockRandomAccessSparseMatrix::SymmetricRightMultiply(const double* x,
double* y) const {
- vector< pair<pair<int, int>, double*> >::const_iterator it =
- cell_values_.begin();
- for (; it != cell_values_.end(); ++it) {
- const int row = it->first.first;
+ for (const auto& cell_position_and_data : cell_values_) {
+ const int row = cell_position_and_data.first.first;
const int row_block_size = blocks_[row];
const int row_block_pos = block_positions_[row];
- const int col = it->first.second;
+ const int col = cell_position_and_data.first.second;
const int col_block_size = blocks_[col];
const int col_block_pos = block_positions_[col];
MatrixVectorMultiply<Eigen::Dynamic, Eigen::Dynamic, 1>(
- it->second, row_block_size, col_block_size,
+ cell_position_and_data.second, row_block_size, col_block_size,
x + col_block_pos,
y + row_block_pos);
@@ -185,7 +174,7 @@ void BlockRandomAccessSparseMatrix::SymmetricRightMultiply(const double* x,
// triangular multiply also.
if (row != col) {
MatrixTransposeVectorMultiply<Eigen::Dynamic, Eigen::Dynamic, 1>(
- it->second, row_block_size, col_block_size,
+ cell_position_and_data.second, row_block_size, col_block_size,
x + row_block_pos,
y + col_block_pos);
}
diff --git a/extern/ceres/internal/ceres/block_random_access_sparse_matrix.h b/extern/ceres/internal/ceres/block_random_access_sparse_matrix.h
index 2b3c7fdabae..d542a3d64e3 100644
--- a/extern/ceres/internal/ceres/block_random_access_sparse_matrix.h
+++ b/extern/ceres/internal/ceres/block_random_access_sparse_matrix.h
@@ -31,17 +31,16 @@
#ifndef CERES_INTERNAL_BLOCK_RANDOM_ACCESS_SPARSE_MATRIX_H_
#define CERES_INTERNAL_BLOCK_RANDOM_ACCESS_SPARSE_MATRIX_H_
+#include <cstdint>
+#include <memory>
#include <set>
-#include <vector>
+#include <unordered_map>
#include <utility>
-#include "ceres/mutex.h"
+#include <vector>
+
#include "ceres/block_random_access_matrix.h"
-#include "ceres/collections_port.h"
#include "ceres/triplet_sparse_matrix.h"
-#include "ceres/integral_types.h"
-#include "ceres/internal/macros.h"
#include "ceres/internal/port.h"
-#include "ceres/internal/scoped_ptr.h"
#include "ceres/types.h"
#include "ceres/small_blas.h"
@@ -59,23 +58,25 @@ class BlockRandomAccessSparseMatrix : public BlockRandomAccessMatrix {
// of this matrix.
BlockRandomAccessSparseMatrix(
const std::vector<int>& blocks,
- const std::set<std::pair<int, int> >& block_pairs);
+ const std::set<std::pair<int, int>>& block_pairs);
+ BlockRandomAccessSparseMatrix(const BlockRandomAccessSparseMatrix&) = delete;
+ void operator=(const BlockRandomAccessSparseMatrix&) = delete;
// The destructor is not thread safe. It assumes that no one is
// modifying any cells when the matrix is being destroyed.
virtual ~BlockRandomAccessSparseMatrix();
// BlockRandomAccessMatrix Interface.
- virtual CellInfo* GetCell(int row_block_id,
- int col_block_id,
- int* row,
- int* col,
- int* row_stride,
- int* col_stride);
+ CellInfo* GetCell(int row_block_id,
+ int col_block_id,
+ int* row,
+ int* col,
+ int* row_stride,
+ int* col_stride) final;
// This is not a thread safe method, it assumes that no cell is
// locked.
- virtual void SetZero();
+ void SetZero() final;
// Assume that the matrix is symmetric and only one half of the
// matrix is stored.
@@ -84,24 +85,24 @@ class BlockRandomAccessSparseMatrix : public BlockRandomAccessMatrix {
void SymmetricRightMultiply(const double* x, double* y) const;
// Since the matrix is square, num_rows() == num_cols().
- virtual int num_rows() const { return tsm_->num_rows(); }
- virtual int num_cols() const { return tsm_->num_cols(); }
+ int num_rows() const final { return tsm_->num_rows(); }
+ int num_cols() const final { return tsm_->num_cols(); }
// Access to the underlying matrix object.
const TripletSparseMatrix* matrix() const { return tsm_.get(); }
TripletSparseMatrix* mutable_matrix() { return tsm_.get(); }
private:
- int64 IntPairToLong(int row, int col) const {
+ int64_t IntPairToLong(int row, int col) const {
return row * kMaxRowBlocks + col;
}
- void LongToIntPair(int64 index, int* row, int* col) const {
+ void LongToIntPair(int64_t index, int* row, int* col) const {
*row = index / kMaxRowBlocks;
*col = index % kMaxRowBlocks;
}
- const int64 kMaxRowBlocks;
+ const int64_t kMaxRowBlocks;
// row/column block sizes.
const std::vector<int> blocks_;
@@ -109,18 +110,17 @@ class BlockRandomAccessSparseMatrix : public BlockRandomAccessMatrix {
// A mapping from <row_block_id, col_block_id> to the position in
// the values array of tsm_ where the block is stored.
- typedef HashMap<long int, CellInfo* > LayoutType;
+ typedef std::unordered_map<long int, CellInfo* > LayoutType;
LayoutType layout_;
// In order traversal of contents of the matrix. This allows us to
// implement a matrix-vector which is 20% faster than using the
// iterator in the Layout object instead.
- std::vector<std::pair<std::pair<int, int>, double*> > cell_values_;
+ std::vector<std::pair<std::pair<int, int>, double*>> cell_values_;
// The underlying matrix object which actually stores the cells.
- scoped_ptr<TripletSparseMatrix> tsm_;
+ std::unique_ptr<TripletSparseMatrix> tsm_;
friend class BlockRandomAccessSparseMatrixTest;
- CERES_DISALLOW_COPY_AND_ASSIGN(BlockRandomAccessSparseMatrix);
};
} // namespace internal
diff --git a/extern/ceres/internal/ceres/block_sparse_matrix.cc b/extern/ceres/internal/ceres/block_sparse_matrix.cc
index 68d0780156c..8f50f3561e2 100644
--- a/extern/ceres/internal/ceres/block_sparse_matrix.cc
+++ b/extern/ceres/internal/ceres/block_sparse_matrix.cc
@@ -35,6 +35,7 @@
#include <vector>
#include "ceres/block_structure.h"
#include "ceres/internal/eigen.h"
+#include "ceres/random.h"
#include "ceres/small_blas.h"
#include "ceres/triplet_sparse_matrix.h"
#include "glog/logging.h"
@@ -51,9 +52,8 @@ BlockSparseMatrix::BlockSparseMatrix(
: num_rows_(0),
num_cols_(0),
num_nonzeros_(0),
- values_(NULL),
block_structure_(block_structure) {
- CHECK_NOTNULL(block_structure_.get());
+ CHECK(block_structure_ != nullptr);
// Count the number of columns in the matrix.
for (int i = 0; i < block_structure_->cols.size(); ++i) {
@@ -80,7 +80,8 @@ BlockSparseMatrix::BlockSparseMatrix(
VLOG(2) << "Allocating values array with "
<< num_nonzeros_ * sizeof(double) << " bytes."; // NOLINT
values_.reset(new double[num_nonzeros_]);
- CHECK_NOTNULL(values_.get());
+ max_num_nonzeros_ = num_nonzeros_;
+ CHECK(values_ != nullptr);
}
void BlockSparseMatrix::SetZero() {
@@ -88,8 +89,8 @@ void BlockSparseMatrix::SetZero() {
}
void BlockSparseMatrix::RightMultiply(const double* x, double* y) const {
- CHECK_NOTNULL(x);
- CHECK_NOTNULL(y);
+ CHECK(x != nullptr);
+ CHECK(y != nullptr);
for (int i = 0; i < block_structure_->rows.size(); ++i) {
int row_block_pos = block_structure_->rows[i].block.position;
@@ -108,8 +109,8 @@ void BlockSparseMatrix::RightMultiply(const double* x, double* y) const {
}
void BlockSparseMatrix::LeftMultiply(const double* x, double* y) const {
- CHECK_NOTNULL(x);
- CHECK_NOTNULL(y);
+ CHECK(x != nullptr);
+ CHECK(y != nullptr);
for (int i = 0; i < block_structure_->rows.size(); ++i) {
int row_block_pos = block_structure_->rows[i].block.position;
@@ -128,7 +129,7 @@ void BlockSparseMatrix::LeftMultiply(const double* x, double* y) const {
}
void BlockSparseMatrix::SquaredColumnNorm(double* x) const {
- CHECK_NOTNULL(x);
+ CHECK(x != nullptr);
VectorRef(x, num_cols_).setZero();
for (int i = 0; i < block_structure_->rows.size(); ++i) {
int row_block_size = block_structure_->rows[i].block.size;
@@ -145,7 +146,7 @@ void BlockSparseMatrix::SquaredColumnNorm(double* x) const {
}
void BlockSparseMatrix::ScaleColumns(const double* scale) {
- CHECK_NOTNULL(scale);
+ CHECK(scale != nullptr);
for (int i = 0; i < block_structure_->rows.size(); ++i) {
int row_block_size = block_structure_->rows[i].block.size;
@@ -162,7 +163,7 @@ void BlockSparseMatrix::ScaleColumns(const double* scale) {
}
void BlockSparseMatrix::ToDenseMatrix(Matrix* dense_matrix) const {
- CHECK_NOTNULL(dense_matrix);
+ CHECK(dense_matrix != nullptr);
dense_matrix->resize(num_rows_, num_cols_);
dense_matrix->setZero();
@@ -185,7 +186,7 @@ void BlockSparseMatrix::ToDenseMatrix(Matrix* dense_matrix) const {
void BlockSparseMatrix::ToTripletSparseMatrix(
TripletSparseMatrix* matrix) const {
- CHECK_NOTNULL(matrix);
+ CHECK(matrix != nullptr);
matrix->Reserve(num_nonzeros_);
matrix->Resize(num_rows_, num_cols_);
@@ -220,7 +221,7 @@ const CompressedRowBlockStructure* BlockSparseMatrix::block_structure()
}
void BlockSparseMatrix::ToTextFile(FILE* file) const {
- CHECK_NOTNULL(file);
+ CHECK(file != nullptr);
for (int i = 0; i < block_structure_->rows.size(); ++i) {
const int row_block_pos = block_structure_->rows[i].block.position;
const int row_block_size = block_structure_->rows[i].block.size;
@@ -242,5 +243,162 @@ void BlockSparseMatrix::ToTextFile(FILE* file) const {
}
}
+BlockSparseMatrix* BlockSparseMatrix::CreateDiagonalMatrix(
+ const double* diagonal, const std::vector<Block>& column_blocks) {
+ // Create the block structure for the diagonal matrix.
+ CompressedRowBlockStructure* bs = new CompressedRowBlockStructure();
+ bs->cols = column_blocks;
+ int position = 0;
+ bs->rows.resize(column_blocks.size(), CompressedRow(1));
+ for (int i = 0; i < column_blocks.size(); ++i) {
+ CompressedRow& row = bs->rows[i];
+ row.block = column_blocks[i];
+ Cell& cell = row.cells[0];
+ cell.block_id = i;
+ cell.position = position;
+ position += row.block.size * row.block.size;
+ }
+
+ // Create the BlockSparseMatrix with the given block structure.
+ BlockSparseMatrix* matrix = new BlockSparseMatrix(bs);
+ matrix->SetZero();
+
+ // Fill the values array of the block sparse matrix.
+ double* values = matrix->mutable_values();
+ for (int i = 0; i < column_blocks.size(); ++i) {
+ const int size = column_blocks[i].size;
+ for (int j = 0; j < size; ++j) {
+ // (j + 1) * size is compact way of accessing the (j,j) entry.
+ values[j * (size + 1)] = diagonal[j];
+ }
+ diagonal += size;
+ values += size * size;
+ }
+
+ return matrix;
+}
+
+void BlockSparseMatrix::AppendRows(const BlockSparseMatrix& m) {
+ CHECK_EQ(m.num_cols(), num_cols());
+ const CompressedRowBlockStructure* m_bs = m.block_structure();
+ CHECK_EQ(m_bs->cols.size(), block_structure_->cols.size());
+
+ const int old_num_nonzeros = num_nonzeros_;
+ const int old_num_row_blocks = block_structure_->rows.size();
+ block_structure_->rows.resize(old_num_row_blocks + m_bs->rows.size());
+
+ for (int i = 0; i < m_bs->rows.size(); ++i) {
+ const CompressedRow& m_row = m_bs->rows[i];
+ CompressedRow& row = block_structure_->rows[old_num_row_blocks + i];
+ row.block.size = m_row.block.size;
+ row.block.position = num_rows_;
+ num_rows_ += m_row.block.size;
+ row.cells.resize(m_row.cells.size());
+ for (int c = 0; c < m_row.cells.size(); ++c) {
+ const int block_id = m_row.cells[c].block_id;
+ row.cells[c].block_id = block_id;
+ row.cells[c].position = num_nonzeros_;
+ num_nonzeros_ += m_row.block.size * m_bs->cols[block_id].size;
+ }
+ }
+
+ if (num_nonzeros_ > max_num_nonzeros_) {
+ double* new_values = new double[num_nonzeros_];
+ std::copy(values_.get(), values_.get() + old_num_nonzeros, new_values);
+ values_.reset(new_values);
+ max_num_nonzeros_ = num_nonzeros_;
+ }
+
+ std::copy(m.values(),
+ m.values() + m.num_nonzeros(),
+ values_.get() + old_num_nonzeros);
+}
+
+void BlockSparseMatrix::DeleteRowBlocks(const int delta_row_blocks) {
+ const int num_row_blocks = block_structure_->rows.size();
+ int delta_num_nonzeros = 0;
+ int delta_num_rows = 0;
+ const std::vector<Block>& column_blocks = block_structure_->cols;
+ for (int i = 0; i < delta_row_blocks; ++i) {
+ const CompressedRow& row = block_structure_->rows[num_row_blocks - i - 1];
+ delta_num_rows += row.block.size;
+ for (int c = 0; c < row.cells.size(); ++c) {
+ const Cell& cell = row.cells[c];
+ delta_num_nonzeros += row.block.size * column_blocks[cell.block_id].size;
+ }
+ }
+ num_nonzeros_ -= delta_num_nonzeros;
+ num_rows_ -= delta_num_rows;
+ block_structure_->rows.resize(num_row_blocks - delta_row_blocks);
+}
+
+BlockSparseMatrix* BlockSparseMatrix::CreateRandomMatrix(
+ const BlockSparseMatrix::RandomMatrixOptions& options) {
+ CHECK_GT(options.num_row_blocks, 0);
+ CHECK_GT(options.min_row_block_size, 0);
+ CHECK_GT(options.max_row_block_size, 0);
+ CHECK_LE(options.min_row_block_size, options.max_row_block_size);
+ CHECK_GT(options.block_density, 0.0);
+ CHECK_LE(options.block_density, 1.0);
+
+ CompressedRowBlockStructure* bs = new CompressedRowBlockStructure();
+ if (options.col_blocks.empty()) {
+ CHECK_GT(options.num_col_blocks, 0);
+ CHECK_GT(options.min_col_block_size, 0);
+ CHECK_GT(options.max_col_block_size, 0);
+ CHECK_LE(options.min_col_block_size, options.max_col_block_size);
+
+ // Generate the col block structure.
+ int col_block_position = 0;
+ for (int i = 0; i < options.num_col_blocks; ++i) {
+ // Generate a random integer in [min_col_block_size, max_col_block_size]
+ const int delta_block_size =
+ Uniform(options.max_col_block_size - options.min_col_block_size);
+ const int col_block_size = options.min_col_block_size + delta_block_size;
+ bs->cols.push_back(Block(col_block_size, col_block_position));
+ col_block_position += col_block_size;
+ }
+ } else {
+ bs->cols = options.col_blocks;
+ }
+
+ bool matrix_has_blocks = false;
+ while (!matrix_has_blocks) {
+ VLOG(1) << "Clearing";
+ bs->rows.clear();
+ int row_block_position = 0;
+ int value_position = 0;
+ for (int r = 0; r < options.num_row_blocks; ++r) {
+
+ const int delta_block_size =
+ Uniform(options.max_row_block_size - options.min_row_block_size);
+ const int row_block_size = options.min_row_block_size + delta_block_size;
+ bs->rows.push_back(CompressedRow());
+ CompressedRow& row = bs->rows.back();
+ row.block.size = row_block_size;
+ row.block.position = row_block_position;
+ row_block_position += row_block_size;
+ for (int c = 0; c < bs->cols.size(); ++c) {
+ if (RandDouble() > options.block_density) continue;
+
+ row.cells.push_back(Cell());
+ Cell& cell = row.cells.back();
+ cell.block_id = c;
+ cell.position = value_position;
+ value_position += row_block_size * bs->cols[c].size;
+ matrix_has_blocks = true;
+ }
+ }
+ }
+
+ BlockSparseMatrix* matrix = new BlockSparseMatrix(bs);
+ double* values = matrix->mutable_values();
+ for (int i = 0; i < matrix->num_nonzeros(); ++i) {
+ values[i] = RandNormal();
+ }
+
+ return matrix;
+}
+
} // namespace internal
} // namespace ceres
diff --git a/extern/ceres/internal/ceres/block_sparse_matrix.h b/extern/ceres/internal/ceres/block_sparse_matrix.h
index 2f9afb738f8..d0c255de612 100644
--- a/extern/ceres/internal/ceres/block_sparse_matrix.h
+++ b/extern/ceres/internal/ceres/block_sparse_matrix.h
@@ -34,11 +34,10 @@
#ifndef CERES_INTERNAL_BLOCK_SPARSE_MATRIX_H_
#define CERES_INTERNAL_BLOCK_SPARSE_MATRIX_H_
+#include <memory>
#include "ceres/block_structure.h"
#include "ceres/sparse_matrix.h"
#include "ceres/internal/eigen.h"
-#include "ceres/internal/macros.h"
-#include "ceres/internal/scoped_ptr.h"
namespace ceres {
namespace internal {
@@ -64,34 +63,99 @@ class BlockSparseMatrix : public SparseMatrix {
explicit BlockSparseMatrix(CompressedRowBlockStructure* block_structure);
BlockSparseMatrix();
+ BlockSparseMatrix(const BlockSparseMatrix&) = delete;
+ void operator=(const BlockSparseMatrix&) = delete;
+
virtual ~BlockSparseMatrix();
// Implementation of SparseMatrix interface.
- virtual void SetZero();
- virtual void RightMultiply(const double* x, double* y) const;
- virtual void LeftMultiply(const double* x, double* y) const;
- virtual void SquaredColumnNorm(double* x) const;
- virtual void ScaleColumns(const double* scale);
- virtual void ToDenseMatrix(Matrix* dense_matrix) const;
- virtual void ToTextFile(FILE* file) const;
-
- virtual int num_rows() const { return num_rows_; }
- virtual int num_cols() const { return num_cols_; }
- virtual int num_nonzeros() const { return num_nonzeros_; }
- virtual const double* values() const { return values_.get(); }
- virtual double* mutable_values() { return values_.get(); }
+ void SetZero() final;
+ void RightMultiply(const double* x, double* y) const final;
+ void LeftMultiply(const double* x, double* y) const final;
+ void SquaredColumnNorm(double* x) const final;
+ void ScaleColumns(const double* scale) final;
+ void ToDenseMatrix(Matrix* dense_matrix) const final;
+ void ToTextFile(FILE* file) const final;
+
+ int num_rows() const final { return num_rows_; }
+ int num_cols() const final { return num_cols_; }
+ int num_nonzeros() const final { return num_nonzeros_; }
+ const double* values() const final { return values_.get(); }
+ double* mutable_values() final { return values_.get(); }
void ToTripletSparseMatrix(TripletSparseMatrix* matrix) const;
const CompressedRowBlockStructure* block_structure() const;
+ // Append the contents of m to the bottom of this matrix. m must
+ // have the same column blocks structure as this matrix.
+ void AppendRows(const BlockSparseMatrix& m);
+
+ // Delete the bottom delta_rows_blocks.
+ void DeleteRowBlocks(int delta_row_blocks);
+
+ static BlockSparseMatrix* CreateDiagonalMatrix(
+ const double* diagonal,
+ const std::vector<Block>& column_blocks);
+
+ struct RandomMatrixOptions {
+ int num_row_blocks = 0;
+ int min_row_block_size = 0;
+ int max_row_block_size = 0;
+ int num_col_blocks = 0;
+ int min_col_block_size = 0;
+ int max_col_block_size = 0;
+
+ // 0 < block_density <= 1 is the probability of a block being
+ // present in the matrix. A given random matrix will not have
+ // precisely this density.
+ double block_density = 0.0;
+
+ // If col_blocks is non-empty, then the generated random matrix
+ // has this block structure and the column related options in this
+ // struct are ignored.
+ std::vector<Block> col_blocks;
+ };
+
+ // Create a random BlockSparseMatrix whose entries are normally
+ // distributed and whose structure is determined by
+ // RandomMatrixOptions.
+ //
+ // Caller owns the result.
+ static BlockSparseMatrix* CreateRandomMatrix(
+ const RandomMatrixOptions& options);
+
private:
int num_rows_;
int num_cols_;
- int max_num_nonzeros_;
int num_nonzeros_;
- scoped_array<double> values_;
- scoped_ptr<CompressedRowBlockStructure> block_structure_;
- CERES_DISALLOW_COPY_AND_ASSIGN(BlockSparseMatrix);
+ int max_num_nonzeros_;
+ std::unique_ptr<double[]> values_;
+ std::unique_ptr<CompressedRowBlockStructure> block_structure_;
+};
+
+// A number of algorithms like the SchurEliminator do not need
+// access to the full BlockSparseMatrix interface. They only
+// need read only access to the values array and the block structure.
+//
+// BlockSparseDataMatrix a struct that carries these two bits of
+// information
+class BlockSparseMatrixData {
+ public:
+ BlockSparseMatrixData(const BlockSparseMatrix& m)
+ : block_structure_(m.block_structure()), values_(m.values()){};
+
+ BlockSparseMatrixData(const CompressedRowBlockStructure* block_structure,
+ const double* values)
+ : block_structure_(block_structure), values_(values) {}
+
+ const CompressedRowBlockStructure* block_structure() const {
+ return block_structure_;
+ }
+ const double* values() const { return values_; }
+
+ private:
+ const CompressedRowBlockStructure* block_structure_;
+ const double* values_;
};
} // namespace internal
diff --git a/extern/ceres/internal/ceres/block_structure.h b/extern/ceres/internal/ceres/block_structure.h
index 6e7003addb6..b5218c0c2cc 100644
--- a/extern/ceres/internal/ceres/block_structure.h
+++ b/extern/ceres/internal/ceres/block_structure.h
@@ -38,14 +38,14 @@
#ifndef CERES_INTERNAL_BLOCK_STRUCTURE_H_
#define CERES_INTERNAL_BLOCK_STRUCTURE_H_
+#include <cstdint>
#include <vector>
#include "ceres/internal/port.h"
-#include "ceres/types.h"
namespace ceres {
namespace internal {
-typedef int32 BlockSize;
+typedef int32_t BlockSize;
struct Block {
Block() : size(-1), position(-1) {}
@@ -70,6 +70,11 @@ struct Cell {
bool CellLessThan(const Cell& lhs, const Cell& rhs);
struct CompressedList {
+ CompressedList() {}
+
+ // Construct a CompressedList with the cells containing num_cells
+ // entries.
+ CompressedList(int num_cells) : cells(num_cells) {}
Block block;
std::vector<Cell> cells;
};
diff --git a/extern/ceres/internal/ceres/c_api.cc b/extern/ceres/internal/ceres/c_api.cc
index ada8f3e0013..2244909131a 100644
--- a/extern/ceres/internal/ceres/c_api.cc
+++ b/extern/ceres/internal/ceres/c_api.cc
@@ -80,9 +80,9 @@ class CallbackCostFunction : public ceres::CostFunction {
virtual ~CallbackCostFunction() {}
- virtual bool Evaluate(double const* const* parameters,
+ bool Evaluate(double const* const* parameters,
double* residuals,
- double** jacobians) const {
+ double** jacobians) const final {
return (*cost_function_)(user_data_,
const_cast<double**>(parameters),
residuals,
@@ -101,7 +101,7 @@ class CallbackLossFunction : public ceres::LossFunction {
explicit CallbackLossFunction(ceres_loss_function_t loss_function,
void* user_data)
: loss_function_(loss_function), user_data_(user_data) {}
- virtual void Evaluate(double sq_norm, double* rho) const {
+ void Evaluate(double sq_norm, double* rho) const final {
(*loss_function_)(user_data_, sq_norm, rho);
}
diff --git a/extern/ceres/internal/ceres/callbacks.cc b/extern/ceres/internal/ceres/callbacks.cc
index 50a0ec19924..84576e40e7d 100644
--- a/extern/ceres/internal/ceres/callbacks.cc
+++ b/extern/ceres/internal/ceres/callbacks.cc
@@ -47,9 +47,29 @@ StateUpdatingCallback::~StateUpdatingCallback() {}
CallbackReturnType StateUpdatingCallback::operator()(
const IterationSummary& summary) {
+ program_->StateVectorToParameterBlocks(parameters_);
+ program_->CopyParameterBlockStateToUserState();
+ return SOLVER_CONTINUE;
+}
+
+GradientProblemSolverStateUpdatingCallback::
+ GradientProblemSolverStateUpdatingCallback(
+ int num_parameters,
+ const double* internal_parameters,
+ double* user_parameters)
+ : num_parameters_(num_parameters),
+ internal_parameters_(internal_parameters),
+ user_parameters_(user_parameters) {}
+
+GradientProblemSolverStateUpdatingCallback::
+ ~GradientProblemSolverStateUpdatingCallback() {}
+
+CallbackReturnType GradientProblemSolverStateUpdatingCallback::operator()(
+ const IterationSummary& summary) {
if (summary.step_is_successful) {
- program_->StateVectorToParameterBlocks(parameters_);
- program_->CopyParameterBlockStateToUserState();
+ std::copy(internal_parameters_,
+ internal_parameters_ + num_parameters_,
+ user_parameters_);
}
return SOLVER_CONTINUE;
}
diff --git a/extern/ceres/internal/ceres/callbacks.h b/extern/ceres/internal/ceres/callbacks.h
index 33c66df5c11..d68bf7f6301 100644
--- a/extern/ceres/internal/ceres/callbacks.h
+++ b/extern/ceres/internal/ceres/callbacks.h
@@ -46,19 +46,34 @@ class StateUpdatingCallback : public IterationCallback {
public:
StateUpdatingCallback(Program* program, double* parameters);
virtual ~StateUpdatingCallback();
- virtual CallbackReturnType operator()(const IterationSummary& summary);
+ CallbackReturnType operator()(const IterationSummary& summary) final;
private:
Program* program_;
double* parameters_;
};
+// Callback for updating the externally visible state of the
+// parameters vector for GradientProblemSolver.
+class GradientProblemSolverStateUpdatingCallback : public IterationCallback {
+ public:
+ GradientProblemSolverStateUpdatingCallback(int num_parameters,
+ const double* internal_parameters,
+ double* user_parameters);
+ virtual ~GradientProblemSolverStateUpdatingCallback();
+ CallbackReturnType operator()(const IterationSummary& summary) final;
+ private:
+ int num_parameters_;
+ const double* internal_parameters_;
+ double* user_parameters_;
+};
+
// Callback for logging the state of the minimizer to STDERR or
// STDOUT depending on the user's preferences and logging level.
class LoggingCallback : public IterationCallback {
public:
LoggingCallback(MinimizerType minimizer_type, bool log_to_stdout);
virtual ~LoggingCallback();
- virtual CallbackReturnType operator()(const IterationSummary& summary);
+ CallbackReturnType operator()(const IterationSummary& summary) final;
private:
const MinimizerType minimizer_type;
diff --git a/extern/ceres/internal/ceres/canonical_views_clustering.cc b/extern/ceres/internal/ceres/canonical_views_clustering.cc
new file mode 100644
index 00000000000..e927e1f91be
--- /dev/null
+++ b/extern/ceres/internal/ceres/canonical_views_clustering.cc
@@ -0,0 +1,232 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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.
+//
+// Author: David Gallup (dgallup@google.com)
+// Sameer Agarwal (sameeragarwal@google.com)
+
+#include "ceres/canonical_views_clustering.h"
+
+#include <unordered_set>
+#include <unordered_map>
+
+#include "ceres/graph.h"
+#include "ceres/map_util.h"
+#include "glog/logging.h"
+
+namespace ceres {
+namespace internal {
+
+using std::vector;
+
+typedef std::unordered_map<int, int> IntMap;
+typedef std::unordered_set<int> IntSet;
+
+class CanonicalViewsClustering {
+ public:
+ CanonicalViewsClustering() {}
+
+ // Compute the canonical views clustering of the vertices of the
+ // graph. centers will contain the vertices that are the identified
+ // as the canonical views/cluster centers, and membership is a map
+ // from vertices to cluster_ids. The i^th cluster center corresponds
+ // to the i^th cluster. It is possible depending on the
+ // configuration of the clustering algorithm that some of the
+ // vertices may not be assigned to any cluster. In this case they
+ // are assigned to a cluster with id = kInvalidClusterId.
+ void ComputeClustering(const CanonicalViewsClusteringOptions& options,
+ const WeightedGraph<int>& graph,
+ vector<int>* centers,
+ IntMap* membership);
+
+ private:
+ void FindValidViews(IntSet* valid_views) const;
+ double ComputeClusteringQualityDifference(const int candidate,
+ const vector<int>& centers) const;
+ void UpdateCanonicalViewAssignments(const int canonical_view);
+ void ComputeClusterMembership(const vector<int>& centers,
+ IntMap* membership) const;
+
+ CanonicalViewsClusteringOptions options_;
+ const WeightedGraph<int>* graph_;
+ // Maps a view to its representative canonical view (its cluster
+ // center).
+ IntMap view_to_canonical_view_;
+ // Maps a view to its similarity to its current cluster center.
+ std::unordered_map<int, double> view_to_canonical_view_similarity_;
+};
+
+void ComputeCanonicalViewsClustering(
+ const CanonicalViewsClusteringOptions& options,
+ const WeightedGraph<int>& graph,
+ vector<int>* centers,
+ IntMap* membership) {
+ time_t start_time = time(NULL);
+ CanonicalViewsClustering cv;
+ cv.ComputeClustering(options, graph, centers, membership);
+ VLOG(2) << "Canonical views clustering time (secs): "
+ << time(NULL) - start_time;
+}
+
+// Implementation of CanonicalViewsClustering
+void CanonicalViewsClustering::ComputeClustering(
+ const CanonicalViewsClusteringOptions& options,
+ const WeightedGraph<int>& graph,
+ vector<int>* centers,
+ IntMap* membership) {
+ options_ = options;
+ CHECK(centers != nullptr);
+ CHECK(membership != nullptr);
+ centers->clear();
+ membership->clear();
+ graph_ = &graph;
+
+ IntSet valid_views;
+ FindValidViews(&valid_views);
+ while (valid_views.size() > 0) {
+ // Find the next best canonical view.
+ double best_difference = -std::numeric_limits<double>::max();
+ int best_view = 0;
+
+ // TODO(sameeragarwal): Make this loop multi-threaded.
+ for (const auto& view : valid_views) {
+ const double difference =
+ ComputeClusteringQualityDifference(view, *centers);
+ if (difference > best_difference) {
+ best_difference = difference;
+ best_view = view;
+ }
+ }
+
+ CHECK_GT(best_difference, -std::numeric_limits<double>::max());
+
+ // Add canonical view if quality improves, or if minimum is not
+ // yet met, otherwise break.
+ if ((best_difference <= 0) &&
+ (centers->size() >= options_.min_views)) {
+ break;
+ }
+
+ centers->push_back(best_view);
+ valid_views.erase(best_view);
+ UpdateCanonicalViewAssignments(best_view);
+ }
+
+ ComputeClusterMembership(*centers, membership);
+}
+
+// Return the set of vertices of the graph which have valid vertex
+// weights.
+void CanonicalViewsClustering::FindValidViews(
+ IntSet* valid_views) const {
+ const IntSet& views = graph_->vertices();
+ for (const auto& view : views) {
+ if (graph_->VertexWeight(view) != WeightedGraph<int>::InvalidWeight()) {
+ valid_views->insert(view);
+ }
+ }
+}
+
+// Computes the difference in the quality score if 'candidate' were
+// added to the set of canonical views.
+double CanonicalViewsClustering::ComputeClusteringQualityDifference(
+ const int candidate,
+ const vector<int>& centers) const {
+ // View score.
+ double difference =
+ options_.view_score_weight * graph_->VertexWeight(candidate);
+
+ // Compute how much the quality score changes if the candidate view
+ // was added to the list of canonical views and its nearest
+ // neighbors became members of its cluster.
+ const IntSet& neighbors = graph_->Neighbors(candidate);
+ for (const auto& neighbor : neighbors) {
+ const double old_similarity =
+ FindWithDefault(view_to_canonical_view_similarity_, neighbor, 0.0);
+ const double new_similarity = graph_->EdgeWeight(neighbor, candidate);
+ if (new_similarity > old_similarity) {
+ difference += new_similarity - old_similarity;
+ }
+ }
+
+ // Number of views penalty.
+ difference -= options_.size_penalty_weight;
+
+ // Orthogonality.
+ for (int i = 0; i < centers.size(); ++i) {
+ difference -= options_.similarity_penalty_weight *
+ graph_->EdgeWeight(centers[i], candidate);
+ }
+
+ return difference;
+}
+
+// Reassign views if they're more similar to the new canonical view.
+void CanonicalViewsClustering::UpdateCanonicalViewAssignments(
+ const int canonical_view) {
+ const IntSet& neighbors = graph_->Neighbors(canonical_view);
+ for (const auto& neighbor : neighbors) {
+ const double old_similarity =
+ FindWithDefault(view_to_canonical_view_similarity_, neighbor, 0.0);
+ const double new_similarity =
+ graph_->EdgeWeight(neighbor, canonical_view);
+ if (new_similarity > old_similarity) {
+ view_to_canonical_view_[neighbor] = canonical_view;
+ view_to_canonical_view_similarity_[neighbor] = new_similarity;
+ }
+ }
+}
+
+// Assign a cluster id to each view.
+void CanonicalViewsClustering::ComputeClusterMembership(
+ const vector<int>& centers,
+ IntMap* membership) const {
+ CHECK(membership != nullptr);
+ membership->clear();
+
+ // The i^th cluster has cluster id i.
+ IntMap center_to_cluster_id;
+ for (int i = 0; i < centers.size(); ++i) {
+ center_to_cluster_id[centers[i]] = i;
+ }
+
+ static constexpr int kInvalidClusterId = -1;
+
+ const IntSet& views = graph_->vertices();
+ for (const auto& view : views) {
+ auto it = view_to_canonical_view_.find(view);
+ int cluster_id = kInvalidClusterId;
+ if (it != view_to_canonical_view_.end()) {
+ cluster_id = FindOrDie(center_to_cluster_id, it->second);
+ }
+
+ InsertOrDie(membership, view, cluster_id);
+ }
+}
+
+} // namespace internal
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/canonical_views_clustering.h b/extern/ceres/internal/ceres/canonical_views_clustering.h
new file mode 100644
index 00000000000..630adfed717
--- /dev/null
+++ b/extern/ceres/internal/ceres/canonical_views_clustering.h
@@ -0,0 +1,124 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// An implementation of the Canonical Views clustering algorithm from
+// "Scene Summarization for Online Image Collections", Ian Simon, Noah
+// Snavely, Steven M. Seitz, ICCV 2007.
+//
+// More details can be found at
+// http://grail.cs.washington.edu/projects/canonview/
+//
+// Ceres uses this algorithm to perform view clustering for
+// constructing visibility based preconditioners.
+
+#ifndef CERES_INTERNAL_CANONICAL_VIEWS_CLUSTERING_H_
+#define CERES_INTERNAL_CANONICAL_VIEWS_CLUSTERING_H_
+
+#include <unordered_map>
+#include <vector>
+
+#include "ceres/graph.h"
+
+namespace ceres {
+namespace internal {
+
+struct CanonicalViewsClusteringOptions;
+
+// Compute a partitioning of the vertices of the graph using the
+// canonical views clustering algorithm.
+//
+// In the following we will use the terms vertices and views
+// interchangeably. Given a weighted Graph G(V,E), the canonical views
+// of G are the set of vertices that best "summarize" the content
+// of the graph. If w_ij i s the weight connecting the vertex i to
+// vertex j, and C is the set of canonical views. Then the objective
+// of the canonical views algorithm is
+//
+// E[C] = sum_[i in V] max_[j in C] w_ij
+// - size_penalty_weight * |C|
+// - similarity_penalty_weight * sum_[i in C, j in C, j > i] w_ij
+//
+// alpha is the size penalty that penalizes large number of canonical
+// views.
+//
+// beta is the similarity penalty that penalizes canonical views that
+// are too similar to other canonical views.
+//
+// Thus the canonical views algorithm tries to find a canonical view
+// for each vertex in the graph which best explains it, while trying
+// to minimize the number of canonical views and the overlap between
+// them.
+//
+// We further augment the above objective function by allowing for per
+// vertex weights, higher weights indicating a higher preference for
+// being chosen as a canonical view. Thus if w_i is the vertex weight
+// for vertex i, the objective function is then
+//
+// E[C] = sum_[i in V] max_[j in C] w_ij
+// - size_penalty_weight * |C|
+// - similarity_penalty_weight * sum_[i in C, j in C, j > i] w_ij
+// + view_score_weight * sum_[i in C] w_i
+//
+// centers will contain the vertices that are the identified
+// as the canonical views/cluster centers, and membership is a map
+// from vertices to cluster_ids. The i^th cluster center corresponds
+// to the i^th cluster.
+//
+// It is possible depending on the configuration of the clustering
+// algorithm that some of the vertices may not be assigned to any
+// cluster. In this case they are assigned to a cluster with id = -1;
+void ComputeCanonicalViewsClustering(
+ const CanonicalViewsClusteringOptions& options,
+ const WeightedGraph<int>& graph,
+ std::vector<int>* centers,
+ std::unordered_map<int, int>* membership);
+
+struct CanonicalViewsClusteringOptions {
+ // The minimum number of canonical views to compute.
+ int min_views = 3;
+
+ // Penalty weight for the number of canonical views. A higher
+ // number will result in fewer canonical views.
+ double size_penalty_weight = 5.75;
+
+ // Penalty weight for the diversity (orthogonality) of the
+ // canonical views. A higher number will encourage less similar
+ // canonical views.
+ double similarity_penalty_weight = 100;
+
+ // Weight for per-view scores. Lower weight places less
+ // confidence in the view scores.
+ double view_score_weight = 0.0;
+};
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_CANONICAL_VIEWS_CLUSTERING_H_
diff --git a/extern/ceres/internal/ceres/cgnr_linear_operator.h b/extern/ceres/internal/ceres/cgnr_linear_operator.h
index 44c07cabd01..8e8febcc934 100644
--- a/extern/ceres/internal/ceres/cgnr_linear_operator.h
+++ b/extern/ceres/internal/ceres/cgnr_linear_operator.h
@@ -32,8 +32,8 @@
#define CERES_INTERNAL_CGNR_LINEAR_OPERATOR_H_
#include <algorithm>
+#include <memory>
#include "ceres/linear_operator.h"
-#include "ceres/internal/scoped_ptr.h"
#include "ceres/internal/eigen.h"
namespace ceres {
@@ -84,7 +84,7 @@ class CgnrLinearOperator : public LinearOperator {
}
virtual ~CgnrLinearOperator() {}
- virtual void RightMultiply(const double* x, double* y) const {
+ void RightMultiply(const double* x, double* y) const final {
std::fill(z_.get(), z_.get() + A_.num_rows(), 0.0);
// z = Ax
@@ -101,17 +101,17 @@ class CgnrLinearOperator : public LinearOperator {
}
}
- virtual void LeftMultiply(const double* x, double* y) const {
+ void LeftMultiply(const double* x, double* y) const final {
RightMultiply(x, y);
}
- virtual int num_rows() const { return A_.num_cols(); }
- virtual int num_cols() const { return A_.num_cols(); }
+ int num_rows() const final { return A_.num_cols(); }
+ int num_cols() const final { return A_.num_cols(); }
private:
const LinearOperator& A_;
const double* D_;
- scoped_array<double> z_;
+ std::unique_ptr<double[]> z_;
};
} // namespace internal
diff --git a/extern/ceres/internal/ceres/cgnr_solver.cc b/extern/ceres/internal/ceres/cgnr_solver.cc
index 61fae758d5b..9dba1cfb4a8 100644
--- a/extern/ceres/internal/ceres/cgnr_solver.cc
+++ b/extern/ceres/internal/ceres/cgnr_solver.cc
@@ -35,6 +35,7 @@
#include "ceres/conjugate_gradients_solver.h"
#include "ceres/internal/eigen.h"
#include "ceres/linear_solver.h"
+#include "ceres/subset_preconditioner.h"
#include "ceres/wall_time.h"
#include "glog/logging.h"
@@ -42,14 +43,19 @@ namespace ceres {
namespace internal {
CgnrSolver::CgnrSolver(const LinearSolver::Options& options)
- : options_(options),
- preconditioner_(NULL) {
+ : options_(options) {
if (options_.preconditioner_type != JACOBI &&
- options_.preconditioner_type != IDENTITY) {
- LOG(FATAL) << "CGNR only supports IDENTITY and JACOBI preconditioners.";
+ options_.preconditioner_type != IDENTITY &&
+ options_.preconditioner_type != SUBSET) {
+ LOG(FATAL)
+ << "Preconditioner = "
+ << PreconditionerTypeToString(options_.preconditioner_type) << ". "
+ << "Congratulations, you found a bug in Ceres. Please report it.";
}
}
+CgnrSolver::~CgnrSolver() {}
+
LinearSolver::Summary CgnrSolver::SolveImpl(
BlockSparseMatrix* A,
const double* b,
@@ -62,16 +68,31 @@ LinearSolver::Summary CgnrSolver::SolveImpl(
z.setZero();
A->LeftMultiply(b, z.data());
- // Precondition if necessary.
- LinearSolver::PerSolveOptions cg_per_solve_options = per_solve_options;
- if (options_.preconditioner_type == JACOBI) {
- if (preconditioner_.get() == NULL) {
+ if (!preconditioner_) {
+ if (options_.preconditioner_type == JACOBI) {
preconditioner_.reset(new BlockJacobiPreconditioner(*A));
+ } else if (options_.preconditioner_type == SUBSET) {
+ Preconditioner::Options preconditioner_options;
+ preconditioner_options.type = SUBSET;
+ preconditioner_options.subset_preconditioner_start_row_block =
+ options_.subset_preconditioner_start_row_block;
+ preconditioner_options.sparse_linear_algebra_library_type =
+ options_.sparse_linear_algebra_library_type;
+ preconditioner_options.use_postordering = options_.use_postordering;
+ preconditioner_options.num_threads = options_.num_threads;
+ preconditioner_options.context = options_.context;
+ preconditioner_.reset(
+ new SubsetPreconditioner(preconditioner_options, *A));
}
+ }
+
+ if (preconditioner_) {
preconditioner_->Update(*A, per_solve_options.D);
- cg_per_solve_options.preconditioner = preconditioner_.get();
}
+ LinearSolver::PerSolveOptions cg_per_solve_options = per_solve_options;
+ cg_per_solve_options.preconditioner = preconditioner_.get();
+
// Solve (AtA + DtD)x = z (= Atb).
VectorRef(x, A->num_cols()).setZero();
CgnrLinearOperator lhs(*A, per_solve_options.D);
diff --git a/extern/ceres/internal/ceres/cgnr_solver.h b/extern/ceres/internal/ceres/cgnr_solver.h
index f7a15736925..52927333daa 100644
--- a/extern/ceres/internal/ceres/cgnr_solver.h
+++ b/extern/ceres/internal/ceres/cgnr_solver.h
@@ -31,7 +31,7 @@
#ifndef CERES_INTERNAL_CGNR_SOLVER_H_
#define CERES_INTERNAL_CGNR_SOLVER_H_
-#include "ceres/internal/scoped_ptr.h"
+#include <memory>
#include "ceres/linear_solver.h"
namespace ceres {
@@ -51,16 +51,19 @@ class BlockJacobiPreconditioner;
class CgnrSolver : public BlockSparseMatrixSolver {
public:
explicit CgnrSolver(const LinearSolver::Options& options);
- virtual Summary SolveImpl(
+ CgnrSolver(const CgnrSolver&) = delete;
+ void operator=(const CgnrSolver&) = delete;
+ virtual ~CgnrSolver();
+
+ Summary SolveImpl(
BlockSparseMatrix* A,
const double* b,
const LinearSolver::PerSolveOptions& per_solve_options,
- double* x);
+ double* x) final;
private:
const LinearSolver::Options options_;
- scoped_ptr<Preconditioner> preconditioner_;
- CERES_DISALLOW_COPY_AND_ASSIGN(CgnrSolver);
+ std::unique_ptr<Preconditioner> preconditioner_;
};
} // namespace internal
diff --git a/extern/ceres/internal/ceres/collections_port.h b/extern/ceres/internal/ceres/collections_port.h
deleted file mode 100644
index e699a661b8b..00000000000
--- a/extern/ceres/internal/ceres/collections_port.h
+++ /dev/null
@@ -1,196 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
-// http://ceres-solver.org/
-//
-// 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.
-//
-// Author: keir@google.com (Keir Mierle)
-//
-// Portable HashMap and HashSet, and a specialized overload for hashing pairs.
-
-#ifndef CERES_INTERNAL_COLLECTIONS_PORT_H_
-#define CERES_INTERNAL_COLLECTIONS_PORT_H_
-
-#include "ceres/internal/port.h"
-
-#if defined(CERES_NO_UNORDERED_MAP)
-# include <map>
-# include <set>
-#endif
-
-#if defined(CERES_TR1_UNORDERED_MAP)
-# include <tr1/unordered_map>
-# include <tr1/unordered_set>
-# define CERES_HASH_NAMESPACE_START namespace std { namespace tr1 {
-# define CERES_HASH_NAMESPACE_END } }
-#endif
-
-#if defined(CERES_STD_UNORDERED_MAP)
-# include <unordered_map>
-# include <unordered_set>
-# define CERES_HASH_NAMESPACE_START namespace std {
-# define CERES_HASH_NAMESPACE_END }
-#endif
-
-#if defined(CERES_STD_UNORDERED_MAP_IN_TR1_NAMESPACE)
-# include <unordered_map>
-# include <unordered_set>
-# define CERES_HASH_NAMESPACE_START namespace std { namespace tr1 {
-# define CERES_HASH_NAMESPACE_END } }
-#endif
-
-#if !defined(CERES_NO_UNORDERED_MAP) && !defined(CERES_TR1_UNORDERED_MAP) && \
- !defined(CERES_STD_UNORDERED_MAP) && !defined(CERES_STD_UNORDERED_MAP_IN_TR1_NAMESPACE) // NOLINT
-# error One of: CERES_NO_UNORDERED_MAP, CERES_TR1_UNORDERED_MAP,\
- CERES_STD_UNORDERED_MAP, CERES_STD_UNORDERED_MAP_IN_TR1_NAMESPACE must be defined! // NOLINT
-#endif
-
-#include <utility>
-#include "ceres/integral_types.h"
-
-// Some systems don't have access to unordered_map/unordered_set. In
-// that case, substitute the hash map/set with normal map/set. The
-// price to pay is slower speed for some operations.
-#if defined(CERES_NO_UNORDERED_MAP)
-
-namespace ceres {
-namespace internal {
-
-template<typename K, typename V>
-struct HashMap : map<K, V> {};
-
-template<typename K>
-struct HashSet : set<K> {};
-
-} // namespace internal
-} // namespace ceres
-
-#else
-
-namespace ceres {
-namespace internal {
-
-#if defined(CERES_TR1_UNORDERED_MAP) || \
- defined(CERES_STD_UNORDERED_MAP_IN_TR1_NAMESPACE)
-template<typename K, typename V>
-struct HashMap : std::tr1::unordered_map<K, V> {};
-template<typename K>
-struct HashSet : std::tr1::unordered_set<K> {};
-#endif
-
-#if defined(CERES_STD_UNORDERED_MAP)
-template<typename K, typename V>
-struct HashMap : std::unordered_map<K, V> {};
-template<typename K>
-struct HashSet : std::unordered_set<K> {};
-#endif
-
-#if defined(_WIN32) && !defined(__MINGW64__) && !defined(__MINGW32__)
-#define GG_LONGLONG(x) x##I64
-#define GG_ULONGLONG(x) x##UI64
-#else
-#define GG_LONGLONG(x) x##LL
-#define GG_ULONGLONG(x) x##ULL
-#endif
-
-// The hash function is due to Bob Jenkins (see
-// http://burtleburtle.net/bob/hash/index.html). Each mix takes 36 instructions,
-// in 18 cycles if you're lucky. On x86 architectures, this requires 45
-// instructions in 27 cycles, if you're lucky.
-//
-// 32bit version
-inline void hash_mix(uint32& a, uint32& b, uint32& c) {
- a -= b; a -= c; a ^= (c>>13);
- b -= c; b -= a; b ^= (a<<8);
- c -= a; c -= b; c ^= (b>>13);
- a -= b; a -= c; a ^= (c>>12);
- b -= c; b -= a; b ^= (a<<16);
- c -= a; c -= b; c ^= (b>>5);
- a -= b; a -= c; a ^= (c>>3);
- b -= c; b -= a; b ^= (a<<10);
- c -= a; c -= b; c ^= (b>>15);
-}
-
-// 64bit version
-inline void hash_mix(uint64& a, uint64& b, uint64& c) {
- a -= b; a -= c; a ^= (c>>43);
- b -= c; b -= a; b ^= (a<<9);
- c -= a; c -= b; c ^= (b>>8);
- a -= b; a -= c; a ^= (c>>38);
- b -= c; b -= a; b ^= (a<<23);
- c -= a; c -= b; c ^= (b>>5);
- a -= b; a -= c; a ^= (c>>35);
- b -= c; b -= a; b ^= (a<<49);
- c -= a; c -= b; c ^= (b>>11);
-}
-
-inline uint32 Hash32NumWithSeed(uint32 num, uint32 c) {
- // The golden ratio; an arbitrary value.
- uint32 b = 0x9e3779b9UL;
- hash_mix(num, b, c);
- return c;
-}
-
-inline uint64 Hash64NumWithSeed(uint64 num, uint64 c) {
- // More of the golden ratio.
- uint64 b = GG_ULONGLONG(0xe08c1d668b756f82);
- hash_mix(num, b, c);
- return c;
-}
-
-} // namespace internal
-} // namespace ceres
-
-// Since on some platforms this is a doubly-nested namespace (std::tr1) and
-// others it is not, the entire namespace line must be in a macro.
-CERES_HASH_NAMESPACE_START
-
-// The outrageously annoying specializations below are for portability reasons.
-// In short, it's not possible to have two overloads of hash<pair<T1, T2>
-
-// Hasher for STL pairs. Requires hashers for both members to be defined.
-template<typename T>
-struct hash<pair<T, T> > {
- size_t operator()(const pair<T, T>& p) const {
- size_t h1 = hash<T>()(p.first);
- size_t h2 = hash<T>()(p.second);
- // The decision below is at compile time
- return (sizeof(h1) <= sizeof(ceres::internal::uint32)) ?
- ceres::internal::Hash32NumWithSeed(h1, h2) :
- ceres::internal::Hash64NumWithSeed(h1, h2);
- }
- // Less than operator for MSVC.
- bool operator()(const pair<T, T>& a,
- const pair<T, T>& b) const {
- return a < b;
- }
- static const size_t bucket_size = 4; // These are required by MSVC
- static const size_t min_buckets = 8; // 4 and 8 are defaults.
-};
-
-CERES_HASH_NAMESPACE_END
-
-#endif // CERES_NO_UNORDERED_MAP
-#endif // CERES_INTERNAL_COLLECTIONS_PORT_H_
diff --git a/extern/ceres/internal/ceres/compressed_col_sparse_matrix_utils.cc b/extern/ceres/internal/ceres/compressed_col_sparse_matrix_utils.cc
index ebb2a62c544..3f6672f858c 100644
--- a/extern/ceres/internal/ceres/compressed_col_sparse_matrix_utils.cc
+++ b/extern/ceres/internal/ceres/compressed_col_sparse_matrix_utils.cc
@@ -47,8 +47,10 @@ void CompressedColumnScalarMatrixToBlockMatrix(
const vector<int>& col_blocks,
vector<int>* block_rows,
vector<int>* block_cols) {
- CHECK_NOTNULL(block_rows)->clear();
- CHECK_NOTNULL(block_cols)->clear();
+ CHECK(block_rows != nullptr);
+ CHECK(block_cols != nullptr);
+ block_rows->clear();
+ block_cols->clear();
const int num_row_blocks = row_blocks.size();
const int num_col_blocks = col_blocks.size();
diff --git a/extern/ceres/internal/ceres/compressed_row_jacobian_writer.cc b/extern/ceres/internal/ceres/compressed_row_jacobian_writer.cc
index 40977b74c67..1fc0116815c 100644
--- a/extern/ceres/internal/ceres/compressed_row_jacobian_writer.cc
+++ b/extern/ceres/internal/ceres/compressed_row_jacobian_writer.cc
@@ -30,6 +30,7 @@
#include "ceres/compressed_row_jacobian_writer.h"
+#include <iterator>
#include <utility>
#include <vector>
@@ -70,7 +71,7 @@ void CompressedRowJacobianWriter::PopulateJacobianRowAndColumnBlockVectors(
void CompressedRowJacobianWriter::GetOrderedParameterBlocks(
const Program* program,
int residual_id,
- vector<pair<int, int> >* evaluated_jacobian_blocks) {
+ vector<pair<int, int>>* evaluated_jacobian_blocks) {
const ResidualBlock* residual_block =
program->residual_blocks()[residual_id];
const int num_parameter_blocks = residual_block->NumParameterBlocks();
@@ -121,6 +122,7 @@ SparseMatrix* CompressedRowJacobianWriter::CreateJacobian() const {
// seems to be the only way to construct it without doing a memory copy.
int* rows = jacobian->mutable_rows();
int* cols = jacobian->mutable_cols();
+
int row_pos = 0;
rows[0] = 0;
for (int i = 0; i < residual_blocks.size(); ++i) {
@@ -206,7 +208,7 @@ void CompressedRowJacobianWriter::Write(int residual_id,
program_->residual_blocks()[residual_id];
const int num_residuals = residual_block->NumResiduals();
- vector<pair<int, int> > evaluated_jacobian_blocks;
+ vector<pair<int, int>> evaluated_jacobian_blocks;
GetOrderedParameterBlocks(program_, residual_id, &evaluated_jacobian_blocks);
// Where in the current row does the jacobian for a parameter block begin.
diff --git a/extern/ceres/internal/ceres/compressed_row_jacobian_writer.h b/extern/ceres/internal/ceres/compressed_row_jacobian_writer.h
index 1cd01235ccf..9fb414e2519 100644
--- a/extern/ceres/internal/ceres/compressed_row_jacobian_writer.h
+++ b/extern/ceres/internal/ceres/compressed_row_jacobian_writer.h
@@ -83,7 +83,7 @@ class CompressedRowJacobianWriter {
static void GetOrderedParameterBlocks(
const Program* program,
int residual_id,
- std::vector<std::pair<int, int> >* evaluated_jacobian_blocks);
+ std::vector<std::pair<int, int>>* evaluated_jacobian_blocks);
// JacobianWriter interface.
diff --git a/extern/ceres/internal/ceres/compressed_row_sparse_matrix.cc b/extern/ceres/internal/ceres/compressed_row_sparse_matrix.cc
index 91d18bbd604..e56de16bf92 100644
--- a/extern/ceres/internal/ceres/compressed_row_sparse_matrix.cc
+++ b/extern/ceres/internal/ceres/compressed_row_sparse_matrix.cc
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2017 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -35,6 +35,7 @@
#include <vector>
#include "ceres/crs_matrix.h"
#include "ceres/internal/port.h"
+#include "ceres/random.h"
#include "ceres/triplet_sparse_matrix.h"
#include "glog/logging.h"
@@ -54,9 +55,7 @@ namespace {
//
// If this is the case, this functor will not be a StrictWeakOrdering.
struct RowColLessThan {
- RowColLessThan(const int* rows, const int* cols)
- : rows(rows), cols(cols) {
- }
+ RowColLessThan(const int* rows, const int* cols) : rows(rows), cols(cols) {}
bool operator()(const int x, const int y) const {
if (rows[x] == rows[y]) {
@@ -69,6 +68,91 @@ struct RowColLessThan {
const int* cols;
};
+void TransposeForCompressedRowSparseStructure(const int num_rows,
+ const int num_cols,
+ const int num_nonzeros,
+ const int* rows,
+ const int* cols,
+ const double* values,
+ int* transpose_rows,
+ int* transpose_cols,
+ double* transpose_values) {
+ // Explicitly zero out transpose_rows.
+ std::fill(transpose_rows, transpose_rows + num_cols + 1, 0);
+
+ // Count the number of entries in each column of the original matrix
+ // and assign to transpose_rows[col + 1].
+ for (int idx = 0; idx < num_nonzeros; ++idx) {
+ ++transpose_rows[cols[idx] + 1];
+ }
+
+ // Compute the starting position for each row in the transpose by
+ // computing the cumulative sum of the entries of transpose_rows.
+ for (int i = 1; i < num_cols + 1; ++i) {
+ transpose_rows[i] += transpose_rows[i - 1];
+ }
+
+ // Populate transpose_cols and (optionally) transpose_values by
+ // walking the entries of the source matrices. For each entry that
+ // is added, the value of transpose_row is incremented allowing us
+ // to keep track of where the next entry for that row should go.
+ //
+ // As a result transpose_row is shifted to the left by one entry.
+ for (int r = 0; r < num_rows; ++r) {
+ for (int idx = rows[r]; idx < rows[r + 1]; ++idx) {
+ const int c = cols[idx];
+ const int transpose_idx = transpose_rows[c]++;
+ transpose_cols[transpose_idx] = r;
+ if (values != NULL && transpose_values != NULL) {
+ transpose_values[transpose_idx] = values[idx];
+ }
+ }
+ }
+
+ // This loop undoes the left shift to transpose_rows introduced by
+ // the previous loop.
+ for (int i = num_cols - 1; i > 0; --i) {
+ transpose_rows[i] = transpose_rows[i - 1];
+ }
+ transpose_rows[0] = 0;
+}
+
+void AddRandomBlock(const int num_rows,
+ const int num_cols,
+ const int row_block_begin,
+ const int col_block_begin,
+ std::vector<int>* rows,
+ std::vector<int>* cols,
+ std::vector<double>* values) {
+ for (int r = 0; r < num_rows; ++r) {
+ for (int c = 0; c < num_cols; ++c) {
+ rows->push_back(row_block_begin + r);
+ cols->push_back(col_block_begin + c);
+ values->push_back(RandNormal());
+ }
+ }
+}
+
+void AddSymmetricRandomBlock(const int num_rows,
+ const int row_block_begin,
+ std::vector<int>* rows,
+ std::vector<int>* cols,
+ std::vector<double>* values) {
+ for (int r = 0; r < num_rows; ++r) {
+ for (int c = r; c < num_rows; ++c) {
+ const double v = RandNormal();
+ rows->push_back(row_block_begin + r);
+ cols->push_back(row_block_begin + c);
+ values->push_back(v);
+ if (r != c) {
+ rows->push_back(row_block_begin + c);
+ cols->push_back(row_block_begin + r);
+ values->push_back(v);
+ }
+ }
+ }
+}
+
} // namespace
// This constructor gives you a semi-initialized CompressedRowSparseMatrix.
@@ -77,69 +161,96 @@ CompressedRowSparseMatrix::CompressedRowSparseMatrix(int num_rows,
int max_num_nonzeros) {
num_rows_ = num_rows;
num_cols_ = num_cols;
+ storage_type_ = UNSYMMETRIC;
rows_.resize(num_rows + 1, 0);
cols_.resize(max_num_nonzeros, 0);
values_.resize(max_num_nonzeros, 0.0);
+ VLOG(1) << "# of rows: " << num_rows_ << " # of columns: " << num_cols_
+ << " max_num_nonzeros: " << cols_.size() << ". Allocating "
+ << (num_rows_ + 1) * sizeof(int) + // NOLINT
+ cols_.size() * sizeof(int) + // NOLINT
+ cols_.size() * sizeof(double); // NOLINT
+}
+
+CompressedRowSparseMatrix* CompressedRowSparseMatrix::FromTripletSparseMatrix(
+ const TripletSparseMatrix& input) {
+ return CompressedRowSparseMatrix::FromTripletSparseMatrix(input, false);
+}
- VLOG(1) << "# of rows: " << num_rows_
- << " # of columns: " << num_cols_
- << " max_num_nonzeros: " << cols_.size()
- << ". Allocating " << (num_rows_ + 1) * sizeof(int) + // NOLINT
- cols_.size() * sizeof(int) + // NOLINT
- cols_.size() * sizeof(double); // NOLINT
+CompressedRowSparseMatrix*
+CompressedRowSparseMatrix::FromTripletSparseMatrixTransposed(
+ const TripletSparseMatrix& input) {
+ return CompressedRowSparseMatrix::FromTripletSparseMatrix(input, true);
}
-CompressedRowSparseMatrix::CompressedRowSparseMatrix(
- const TripletSparseMatrix& m) {
- num_rows_ = m.num_rows();
- num_cols_ = m.num_cols();
+CompressedRowSparseMatrix* CompressedRowSparseMatrix::FromTripletSparseMatrix(
+ const TripletSparseMatrix& input, bool transpose) {
+ int num_rows = input.num_rows();
+ int num_cols = input.num_cols();
+ const int* rows = input.rows();
+ const int* cols = input.cols();
+ const double* values = input.values();
- rows_.resize(num_rows_ + 1, 0);
- cols_.resize(m.num_nonzeros(), 0);
- values_.resize(m.max_num_nonzeros(), 0.0);
+ if (transpose) {
+ std::swap(num_rows, num_cols);
+ std::swap(rows, cols);
+ }
- // index is the list of indices into the TripletSparseMatrix m.
- vector<int> index(m.num_nonzeros(), 0);
- for (int i = 0; i < m.num_nonzeros(); ++i) {
+ // index is the list of indices into the TripletSparseMatrix input.
+ vector<int> index(input.num_nonzeros(), 0);
+ for (int i = 0; i < input.num_nonzeros(); ++i) {
index[i] = i;
}
// Sort index such that the entries of m are ordered by row and ties
// are broken by column.
- sort(index.begin(), index.end(), RowColLessThan(m.rows(), m.cols()));
+ std::sort(index.begin(), index.end(), RowColLessThan(rows, cols));
+
+ VLOG(1) << "# of rows: " << num_rows << " # of columns: " << num_cols
+ << " num_nonzeros: " << input.num_nonzeros() << ". Allocating "
+ << ((num_rows + 1) * sizeof(int) + // NOLINT
+ input.num_nonzeros() * sizeof(int) + // NOLINT
+ input.num_nonzeros() * sizeof(double)); // NOLINT
+
+ CompressedRowSparseMatrix* output =
+ new CompressedRowSparseMatrix(num_rows, num_cols, input.num_nonzeros());
- VLOG(1) << "# of rows: " << num_rows_
- << " # of columns: " << num_cols_
- << " max_num_nonzeros: " << cols_.size()
- << ". Allocating "
- << ((num_rows_ + 1) * sizeof(int) + // NOLINT
- cols_.size() * sizeof(int) + // NOLINT
- cols_.size() * sizeof(double)); // NOLINT
+ if (num_rows == 0) {
+ // No data to copy.
+ return output;
+ }
// Copy the contents of the cols and values array in the order given
// by index and count the number of entries in each row.
- for (int i = 0; i < m.num_nonzeros(); ++i) {
+ int* output_rows = output->mutable_rows();
+ int* output_cols = output->mutable_cols();
+ double* output_values = output->mutable_values();
+
+ output_rows[0] = 0;
+ for (int i = 0; i < index.size(); ++i) {
const int idx = index[i];
- ++rows_[m.rows()[idx] + 1];
- cols_[i] = m.cols()[idx];
- values_[i] = m.values()[idx];
+ ++output_rows[rows[idx] + 1];
+ output_cols[i] = cols[idx];
+ output_values[i] = values[idx];
}
// Find the cumulative sum of the row counts.
- for (int i = 1; i < num_rows_ + 1; ++i) {
- rows_[i] += rows_[i - 1];
+ for (int i = 1; i < num_rows + 1; ++i) {
+ output_rows[i] += output_rows[i - 1];
}
- CHECK_EQ(num_nonzeros(), m.num_nonzeros());
+ CHECK_EQ(output->num_nonzeros(), input.num_nonzeros());
+ return output;
}
CompressedRowSparseMatrix::CompressedRowSparseMatrix(const double* diagonal,
int num_rows) {
- CHECK_NOTNULL(diagonal);
+ CHECK(diagonal != nullptr);
num_rows_ = num_rows;
num_cols_ = num_rows;
+ storage_type_ = UNSYMMETRIC;
rows_.resize(num_rows + 1);
cols_.resize(num_rows);
values_.resize(num_rows);
@@ -154,47 +265,150 @@ CompressedRowSparseMatrix::CompressedRowSparseMatrix(const double* diagonal,
CHECK_EQ(num_nonzeros(), num_rows);
}
-CompressedRowSparseMatrix::~CompressedRowSparseMatrix() {
-}
+CompressedRowSparseMatrix::~CompressedRowSparseMatrix() {}
void CompressedRowSparseMatrix::SetZero() {
std::fill(values_.begin(), values_.end(), 0);
}
+// TODO(sameeragarwal): Make RightMultiply and LeftMultiply
+// block-aware for higher performance.
void CompressedRowSparseMatrix::RightMultiply(const double* x,
double* y) const {
- CHECK_NOTNULL(x);
- CHECK_NOTNULL(y);
+ CHECK(x != nullptr);
+ CHECK(y != nullptr);
+
+ if (storage_type_ == UNSYMMETRIC) {
+ for (int r = 0; r < num_rows_; ++r) {
+ for (int idx = rows_[r]; idx < rows_[r + 1]; ++idx) {
+ const int c = cols_[idx];
+ const double v = values_[idx];
+ y[r] += v * x[c];
+ }
+ }
+ } else if (storage_type_ == UPPER_TRIANGULAR) {
+ // Because of their block structure, we will have entries that lie
+ // above (below) the diagonal for lower (upper) triangular matrices,
+ // so the loops below need to account for this.
+ for (int r = 0; r < num_rows_; ++r) {
+ int idx = rows_[r];
+ const int idx_end = rows_[r + 1];
+
+ // For upper triangular matrices r <= c, so skip entries with r
+ // > c.
+ while (idx < idx_end && r > cols_[idx]) {
+ ++idx;
+ }
- for (int r = 0; r < num_rows_; ++r) {
- for (int idx = rows_[r]; idx < rows_[r + 1]; ++idx) {
- y[r] += values_[idx] * x[cols_[idx]];
+ for (; idx < idx_end; ++idx) {
+ const int c = cols_[idx];
+ const double v = values_[idx];
+ y[r] += v * x[c];
+ // Since we are only iterating over the upper triangular part
+ // of the matrix, add contributions for the strictly lower
+ // triangular part.
+ if (r != c) {
+ y[c] += v * x[r];
+ }
+ }
+ }
+ } else if (storage_type_ == LOWER_TRIANGULAR) {
+ for (int r = 0; r < num_rows_; ++r) {
+ int idx = rows_[r];
+ const int idx_end = rows_[r + 1];
+ // For lower triangular matrices, we only iterate till we are r >=
+ // c.
+ for (; idx < idx_end && r >= cols_[idx]; ++idx) {
+ const int c = cols_[idx];
+ const double v = values_[idx];
+ y[r] += v * x[c];
+ // Since we are only iterating over the lower triangular part
+ // of the matrix, add contributions for the strictly upper
+ // triangular part.
+ if (r != c) {
+ y[c] += v * x[r];
+ }
+ }
}
+ } else {
+ LOG(FATAL) << "Unknown storage type: " << storage_type_;
}
}
void CompressedRowSparseMatrix::LeftMultiply(const double* x, double* y) const {
- CHECK_NOTNULL(x);
- CHECK_NOTNULL(y);
+ CHECK(x != nullptr);
+ CHECK(y != nullptr);
- for (int r = 0; r < num_rows_; ++r) {
- for (int idx = rows_[r]; idx < rows_[r + 1]; ++idx) {
- y[cols_[idx]] += values_[idx] * x[r];
+ if (storage_type_ == UNSYMMETRIC) {
+ for (int r = 0; r < num_rows_; ++r) {
+ for (int idx = rows_[r]; idx < rows_[r + 1]; ++idx) {
+ y[cols_[idx]] += values_[idx] * x[r];
+ }
}
+ } else {
+ // Since the matrix is symmetric, LeftMultiply = RightMultiply.
+ RightMultiply(x, y);
}
}
void CompressedRowSparseMatrix::SquaredColumnNorm(double* x) const {
- CHECK_NOTNULL(x);
+ CHECK(x != nullptr);
std::fill(x, x + num_cols_, 0.0);
- for (int idx = 0; idx < rows_[num_rows_]; ++idx) {
- x[cols_[idx]] += values_[idx] * values_[idx];
+ if (storage_type_ == UNSYMMETRIC) {
+ for (int idx = 0; idx < rows_[num_rows_]; ++idx) {
+ x[cols_[idx]] += values_[idx] * values_[idx];
+ }
+ } else if (storage_type_ == UPPER_TRIANGULAR) {
+ // Because of their block structure, we will have entries that lie
+ // above (below) the diagonal for lower (upper) triangular
+ // matrices, so the loops below need to account for this.
+ for (int r = 0; r < num_rows_; ++r) {
+ int idx = rows_[r];
+ const int idx_end = rows_[r + 1];
+
+ // For upper triangular matrices r <= c, so skip entries with r
+ // > c.
+ while (idx < idx_end && r > cols_[idx]) {
+ ++idx;
+ }
+
+ for (; idx < idx_end; ++idx) {
+ const int c = cols_[idx];
+ const double v2 = values_[idx] * values_[idx];
+ x[c] += v2;
+ // Since we are only iterating over the upper triangular part
+ // of the matrix, add contributions for the strictly lower
+ // triangular part.
+ if (r != c) {
+ x[r] += v2;
+ }
+ }
+ }
+ } else if (storage_type_ == LOWER_TRIANGULAR) {
+ for (int r = 0; r < num_rows_; ++r) {
+ int idx = rows_[r];
+ const int idx_end = rows_[r + 1];
+ // For lower triangular matrices, we only iterate till we are r >=
+ // c.
+ for (; idx < idx_end && r >= cols_[idx]; ++idx) {
+ const int c = cols_[idx];
+ const double v2 = values_[idx] * values_[idx];
+ x[c] += v2;
+ // Since we are only iterating over the lower triangular part
+ // of the matrix, add contributions for the strictly upper
+ // triangular part.
+ if (r != c) {
+ x[r] += v2;
+ }
+ }
+ }
+ } else {
+ LOG(FATAL) << "Unknown storage type: " << storage_type_;
}
}
-
void CompressedRowSparseMatrix::ScaleColumns(const double* scale) {
- CHECK_NOTNULL(scale);
+ CHECK(scale != nullptr);
for (int idx = 0; idx < rows_[num_rows_]; ++idx) {
values_[idx] *= scale[cols_[idx]];
@@ -202,7 +416,7 @@ void CompressedRowSparseMatrix::ScaleColumns(const double* scale) {
}
void CompressedRowSparseMatrix::ToDenseMatrix(Matrix* dense_matrix) const {
- CHECK_NOTNULL(dense_matrix);
+ CHECK(dense_matrix != nullptr);
dense_matrix->resize(num_rows_, num_cols_);
dense_matrix->setZero();
@@ -216,10 +430,17 @@ void CompressedRowSparseMatrix::ToDenseMatrix(Matrix* dense_matrix) const {
void CompressedRowSparseMatrix::DeleteRows(int delta_rows) {
CHECK_GE(delta_rows, 0);
CHECK_LE(delta_rows, num_rows_);
+ CHECK_EQ(storage_type_, UNSYMMETRIC);
num_rows_ -= delta_rows;
rows_.resize(num_rows_ + 1);
+ // The rest of the code updates the block information. Immediately
+ // return in case of no block information.
+ if (row_blocks_.empty()) {
+ return;
+ }
+
// Walk the list of row blocks until we reach the new number of rows
// and the drop the rest of the row blocks.
int num_row_blocks = 0;
@@ -233,9 +454,11 @@ void CompressedRowSparseMatrix::DeleteRows(int delta_rows) {
}
void CompressedRowSparseMatrix::AppendRows(const CompressedRowSparseMatrix& m) {
+ CHECK_EQ(storage_type_, UNSYMMETRIC);
CHECK_EQ(m.num_cols(), num_cols_);
- CHECK(row_blocks_.size() == 0 || m.row_blocks().size() !=0)
+ CHECK((row_blocks_.empty() && m.row_blocks().empty()) ||
+ (!row_blocks_.empty() && !m.row_blocks().empty()))
<< "Cannot append a matrix with row blocks to one without and vice versa."
<< "This matrix has : " << row_blocks_.size() << " row blocks."
<< "The matrix being appended has: " << m.row_blocks().size()
@@ -254,9 +477,8 @@ void CompressedRowSparseMatrix::AppendRows(const CompressedRowSparseMatrix& m) {
DCHECK_LT(num_nonzeros(), cols_.size());
if (m.num_nonzeros() > 0) {
std::copy(m.cols(), m.cols() + m.num_nonzeros(), &cols_[num_nonzeros()]);
- std::copy(m.values(),
- m.values() + m.num_nonzeros(),
- &values_[num_nonzeros()]);
+ std::copy(
+ m.values(), m.values() + m.num_nonzeros(), &values_[num_nonzeros()]);
}
rows_.resize(num_rows_ + m.num_rows() + 1);
@@ -270,20 +492,22 @@ void CompressedRowSparseMatrix::AppendRows(const CompressedRowSparseMatrix& m) {
}
num_rows_ += m.num_rows();
- row_blocks_.insert(row_blocks_.end(),
- m.row_blocks().begin(),
- m.row_blocks().end());
+
+ // The rest of the code updates the block information. Immediately
+ // return in case of no block information.
+ if (row_blocks_.empty()) {
+ return;
+ }
+
+ row_blocks_.insert(
+ row_blocks_.end(), m.row_blocks().begin(), m.row_blocks().end());
}
void CompressedRowSparseMatrix::ToTextFile(FILE* file) const {
- CHECK_NOTNULL(file);
+ CHECK(file != nullptr);
for (int r = 0; r < num_rows_; ++r) {
for (int idx = rows_[r]; idx < rows_[r + 1]; ++idx) {
- fprintf(file,
- "% 10d % 10d %17f\n",
- r,
- cols_[idx],
- values_[idx]);
+ fprintf(file, "% 10d % 10d %17f\n", r, cols_[idx], values_[idx]);
}
}
}
@@ -308,29 +532,8 @@ void CompressedRowSparseMatrix::SetMaxNumNonZeros(int num_nonzeros) {
values_.resize(num_nonzeros);
}
-void CompressedRowSparseMatrix::SolveLowerTriangularInPlace(
- double* solution) const {
- for (int r = 0; r < num_rows_; ++r) {
- for (int idx = rows_[r]; idx < rows_[r + 1] - 1; ++idx) {
- solution[r] -= values_[idx] * solution[cols_[idx]];
- }
- solution[r] /= values_[rows_[r + 1] - 1];
- }
-}
-
-void CompressedRowSparseMatrix::SolveLowerTriangularTransposeInPlace(
- double* solution) const {
- for (int r = num_rows_ - 1; r >= 0; --r) {
- solution[r] /= values_[rows_[r + 1] - 1];
- for (int idx = rows_[r + 1] - 2; idx >= rows_[r]; --idx) {
- solution[cols_[idx]] -= values_[idx] * solution[r];
- }
- }
-}
-
CompressedRowSparseMatrix* CompressedRowSparseMatrix::CreateBlockDiagonalMatrix(
- const double* diagonal,
- const vector<int>& blocks) {
+ const double* diagonal, const vector<int>& blocks) {
int num_rows = 0;
int num_nonzeros = 0;
for (int i = 0; i < blocks.size(); ++i) {
@@ -373,189 +576,152 @@ CompressedRowSparseMatrix* CompressedRowSparseMatrix::Transpose() const {
CompressedRowSparseMatrix* transpose =
new CompressedRowSparseMatrix(num_cols_, num_rows_, num_nonzeros());
- int* transpose_rows = transpose->mutable_rows();
- int* transpose_cols = transpose->mutable_cols();
- double* transpose_values = transpose->mutable_values();
-
- for (int idx = 0; idx < num_nonzeros(); ++idx) {
- ++transpose_rows[cols_[idx] + 1];
- }
-
- for (int i = 1; i < transpose->num_rows() + 1; ++i) {
- transpose_rows[i] += transpose_rows[i - 1];
- }
-
- for (int r = 0; r < num_rows(); ++r) {
- for (int idx = rows_[r]; idx < rows_[r + 1]; ++idx) {
- const int c = cols_[idx];
- const int transpose_idx = transpose_rows[c]++;
- transpose_cols[transpose_idx] = r;
- transpose_values[transpose_idx] = values_[idx];
- }
- }
-
- for (int i = transpose->num_rows() - 1; i > 0 ; --i) {
- transpose_rows[i] = transpose_rows[i - 1];
+ switch (storage_type_) {
+ case UNSYMMETRIC:
+ transpose->set_storage_type(UNSYMMETRIC);
+ break;
+ case LOWER_TRIANGULAR:
+ transpose->set_storage_type(UPPER_TRIANGULAR);
+ break;
+ case UPPER_TRIANGULAR:
+ transpose->set_storage_type(LOWER_TRIANGULAR);
+ break;
+ default:
+ LOG(FATAL) << "Unknown storage type: " << storage_type_;
+ };
+
+ TransposeForCompressedRowSparseStructure(num_rows(),
+ num_cols(),
+ num_nonzeros(),
+ rows(),
+ cols(),
+ values(),
+ transpose->mutable_rows(),
+ transpose->mutable_cols(),
+ transpose->mutable_values());
+
+ // The rest of the code updates the block information. Immediately
+ // return in case of no block information.
+ if (row_blocks_.empty()) {
+ return transpose;
}
- transpose_rows[0] = 0;
*(transpose->mutable_row_blocks()) = col_blocks_;
*(transpose->mutable_col_blocks()) = row_blocks_;
-
return transpose;
}
-namespace {
-// A ProductTerm is a term in the outer product of a matrix with
-// itself.
-struct ProductTerm {
- ProductTerm(const int row, const int col, const int index)
- : row(row), col(col), index(index) {
- }
-
- bool operator<(const ProductTerm& right) const {
- if (row == right.row) {
- if (col == right.col) {
- return index < right.index;
- }
- return col < right.col;
- }
- return row < right.row;
- }
-
- int row;
- int col;
- int index;
-};
-
-CompressedRowSparseMatrix*
-CompressAndFillProgram(const int num_rows,
- const int num_cols,
- const vector<ProductTerm>& product,
- vector<int>* program) {
- CHECK_GT(product.size(), 0);
-
- // Count the number of unique product term, which in turn is the
- // number of non-zeros in the outer product.
- int num_nonzeros = 1;
- for (int i = 1; i < product.size(); ++i) {
- if (product[i].row != product[i - 1].row ||
- product[i].col != product[i - 1].col) {
- ++num_nonzeros;
- }
- }
-
- CompressedRowSparseMatrix* matrix =
- new CompressedRowSparseMatrix(num_rows, num_cols, num_nonzeros);
-
- int* crsm_rows = matrix->mutable_rows();
- std::fill(crsm_rows, crsm_rows + num_rows + 1, 0);
- int* crsm_cols = matrix->mutable_cols();
- std::fill(crsm_cols, crsm_cols + num_nonzeros, 0);
-
- CHECK_NOTNULL(program)->clear();
- program->resize(product.size());
-
- // Iterate over the sorted product terms. This means each row is
- // filled one at a time, and we are able to assign a position in the
- // values array to each term.
- //
- // If terms repeat, i.e., they contribute to the same entry in the
- // result matrix), then they do not affect the sparsity structure of
- // the result matrix.
- int nnz = 0;
- crsm_cols[0] = product[0].col;
- crsm_rows[product[0].row + 1]++;
- (*program)[product[0].index] = nnz;
- for (int i = 1; i < product.size(); ++i) {
- const ProductTerm& previous = product[i - 1];
- const ProductTerm& current = product[i];
-
- // Sparsity structure is updated only if the term is not a repeat.
- if (previous.row != current.row || previous.col != current.col) {
- crsm_cols[++nnz] = current.col;
- crsm_rows[current.row + 1]++;
- }
-
- // All terms get assigned the position in the values array where
- // their value is accumulated.
- (*program)[current.index] = nnz;
- }
-
- for (int i = 1; i < num_rows + 1; ++i) {
- crsm_rows[i] += crsm_rows[i - 1];
- }
-
- return matrix;
-}
-
-} // namespace
-
-CompressedRowSparseMatrix*
-CompressedRowSparseMatrix::CreateOuterProductMatrixAndProgram(
- const CompressedRowSparseMatrix& m,
- vector<int>* program) {
- CHECK_NOTNULL(program)->clear();
- CHECK_GT(m.num_nonzeros(), 0)
- << "Congratulations, "
- << "you found a bug in Ceres. Please report it.";
-
- vector<ProductTerm> product;
- const vector<int>& row_blocks = m.row_blocks();
- int row_block_begin = 0;
- // Iterate over row blocks
- for (int row_block = 0; row_block < row_blocks.size(); ++row_block) {
- const int row_block_end = row_block_begin + row_blocks[row_block];
- // Compute the outer product terms for just one row per row block.
- const int r = row_block_begin;
- // Compute the lower triangular part of the product.
- for (int idx1 = m.rows()[r]; idx1 < m.rows()[r + 1]; ++idx1) {
- for (int idx2 = m.rows()[r]; idx2 <= idx1; ++idx2) {
- product.push_back(ProductTerm(m.cols()[idx1],
- m.cols()[idx2],
- product.size()));
- }
+CompressedRowSparseMatrix* CompressedRowSparseMatrix::CreateRandomMatrix(
+ CompressedRowSparseMatrix::RandomMatrixOptions options) {
+ CHECK_GT(options.num_row_blocks, 0);
+ CHECK_GT(options.min_row_block_size, 0);
+ CHECK_GT(options.max_row_block_size, 0);
+ CHECK_LE(options.min_row_block_size, options.max_row_block_size);
+
+ if (options.storage_type == UNSYMMETRIC) {
+ CHECK_GT(options.num_col_blocks, 0);
+ CHECK_GT(options.min_col_block_size, 0);
+ CHECK_GT(options.max_col_block_size, 0);
+ CHECK_LE(options.min_col_block_size, options.max_col_block_size);
+ } else {
+ // Symmetric matrices (LOWER_TRIANGULAR or UPPER_TRIANGULAR);
+ options.num_col_blocks = options.num_row_blocks;
+ options.min_col_block_size = options.min_row_block_size;
+ options.max_col_block_size = options.max_row_block_size;
+ }
+
+ CHECK_GT(options.block_density, 0.0);
+ CHECK_LE(options.block_density, 1.0);
+
+ vector<int> row_blocks;
+ vector<int> col_blocks;
+
+ // Generate the row block structure.
+ for (int i = 0; i < options.num_row_blocks; ++i) {
+ // Generate a random integer in [min_row_block_size, max_row_block_size]
+ const int delta_block_size =
+ Uniform(options.max_row_block_size - options.min_row_block_size);
+ row_blocks.push_back(options.min_row_block_size + delta_block_size);
+ }
+
+ if (options.storage_type == UNSYMMETRIC) {
+ // Generate the col block structure.
+ for (int i = 0; i < options.num_col_blocks; ++i) {
+ // Generate a random integer in [min_col_block_size, max_col_block_size]
+ const int delta_block_size =
+ Uniform(options.max_col_block_size - options.min_col_block_size);
+ col_blocks.push_back(options.min_col_block_size + delta_block_size);
}
- row_block_begin = row_block_end;
- }
- CHECK_EQ(row_block_begin, m.num_rows());
- sort(product.begin(), product.end());
- return CompressAndFillProgram(m.num_cols(), m.num_cols(), product, program);
-}
+ } else {
+ // Symmetric matrices (LOWER_TRIANGULAR or UPPER_TRIANGULAR);
+ col_blocks = row_blocks;
+ }
+
+ vector<int> tsm_rows;
+ vector<int> tsm_cols;
+ vector<double> tsm_values;
+
+ // For ease of construction, we are going to generate the
+ // CompressedRowSparseMatrix by generating it as a
+ // TripletSparseMatrix and then converting it to a
+ // CompressedRowSparseMatrix.
+
+ // It is possible that the random matrix is empty which is likely
+ // not what the user wants, so do the matrix generation till we have
+ // at least one non-zero entry.
+ while (tsm_values.empty()) {
+ tsm_rows.clear();
+ tsm_cols.clear();
+ tsm_values.clear();
+
+ int row_block_begin = 0;
+ for (int r = 0; r < options.num_row_blocks; ++r) {
+ int col_block_begin = 0;
+ for (int c = 0; c < options.num_col_blocks; ++c) {
+ if (((options.storage_type == UPPER_TRIANGULAR) && (r > c)) ||
+ ((options.storage_type == LOWER_TRIANGULAR) && (r < c))) {
+ col_block_begin += col_blocks[c];
+ continue;
+ }
-void CompressedRowSparseMatrix::ComputeOuterProduct(
- const CompressedRowSparseMatrix& m,
- const vector<int>& program,
- CompressedRowSparseMatrix* result) {
- result->SetZero();
- double* values = result->mutable_values();
- const vector<int>& row_blocks = m.row_blocks();
-
- int cursor = 0;
- int row_block_begin = 0;
- const double* m_values = m.values();
- const int* m_rows = m.rows();
- // Iterate over row blocks.
- for (int row_block = 0; row_block < row_blocks.size(); ++row_block) {
- const int row_block_end = row_block_begin + row_blocks[row_block];
- const int saved_cursor = cursor;
- for (int r = row_block_begin; r < row_block_end; ++r) {
- // Reuse the program segment for each row in this row block.
- cursor = saved_cursor;
- const int row_begin = m_rows[r];
- const int row_end = m_rows[r + 1];
- for (int idx1 = row_begin; idx1 < row_end; ++idx1) {
- const double v1 = m_values[idx1];
- for (int idx2 = row_begin; idx2 <= idx1; ++idx2, ++cursor) {
- values[program[cursor]] += v1 * m_values[idx2];
+ // Randomly determine if this block is present or not.
+ if (RandDouble() <= options.block_density) {
+ // If the matrix is symmetric, then we take care to generate
+ // symmetric diagonal blocks.
+ if (options.storage_type == UNSYMMETRIC || r != c) {
+ AddRandomBlock(row_blocks[r],
+ col_blocks[c],
+ row_block_begin,
+ col_block_begin,
+ &tsm_rows,
+ &tsm_cols,
+ &tsm_values);
+ } else {
+ AddSymmetricRandomBlock(row_blocks[r],
+ row_block_begin,
+ &tsm_rows,
+ &tsm_cols,
+ &tsm_values);
+ }
}
+ col_block_begin += col_blocks[c];
}
+ row_block_begin += row_blocks[r];
}
- row_block_begin = row_block_end;
}
- CHECK_EQ(row_block_begin, m.num_rows());
- CHECK_EQ(cursor, program.size());
+ const int num_rows = std::accumulate(row_blocks.begin(), row_blocks.end(), 0);
+ const int num_cols = std::accumulate(col_blocks.begin(), col_blocks.end(), 0);
+ const bool kDoNotTranspose = false;
+ CompressedRowSparseMatrix* matrix =
+ CompressedRowSparseMatrix::FromTripletSparseMatrix(
+ TripletSparseMatrix(
+ num_rows, num_cols, tsm_rows, tsm_cols, tsm_values),
+ kDoNotTranspose);
+ (*matrix->mutable_row_blocks()) = row_blocks;
+ (*matrix->mutable_col_blocks()) = col_blocks;
+ matrix->set_storage_type(options.storage_type);
+ return matrix;
}
} // namespace internal
diff --git a/extern/ceres/internal/ceres/compressed_row_sparse_matrix.h b/extern/ceres/internal/ceres/compressed_row_sparse_matrix.h
index 987339d09a1..758b40bbc8a 100644
--- a/extern/ceres/internal/ceres/compressed_row_sparse_matrix.h
+++ b/extern/ceres/internal/ceres/compressed_row_sparse_matrix.h
@@ -32,7 +32,6 @@
#define CERES_INTERNAL_COMPRESSED_ROW_SPARSE_MATRIX_H_
#include <vector>
-#include "ceres/internal/macros.h"
#include "ceres/internal/port.h"
#include "ceres/sparse_matrix.h"
#include "ceres/types.h"
@@ -48,13 +47,35 @@ class TripletSparseMatrix;
class CompressedRowSparseMatrix : public SparseMatrix {
public:
- // Build a matrix with the same content as the TripletSparseMatrix
- // m. TripletSparseMatrix objects are easier to construct
- // incrementally, so we use them to initialize SparseMatrix
- // objects.
+ enum StorageType {
+ UNSYMMETRIC,
+ // Matrix is assumed to be symmetric but only the lower triangular
+ // part of the matrix is stored.
+ LOWER_TRIANGULAR,
+ // Matrix is assumed to be symmetric but only the upper triangular
+ // part of the matrix is stored.
+ UPPER_TRIANGULAR
+ };
+
+ // Create a matrix with the same content as the TripletSparseMatrix
+ // input. We assume that input does not have any repeated
+ // entries.
//
- // We assume that m does not have any repeated entries.
- explicit CompressedRowSparseMatrix(const TripletSparseMatrix& m);
+ // The storage type of the matrix is set to UNSYMMETRIC.
+ //
+ // Caller owns the result.
+ static CompressedRowSparseMatrix* FromTripletSparseMatrix(
+ const TripletSparseMatrix& input);
+
+ // Create a matrix with the same content as the TripletSparseMatrix
+ // input transposed. We assume that input does not have any repeated
+ // entries.
+ //
+ // The storage type of the matrix is set to UNSYMMETRIC.
+ //
+ // Caller owns the result.
+ static CompressedRowSparseMatrix* FromTripletSparseMatrixTransposed(
+ const TripletSparseMatrix& input);
// Use this constructor only if you know what you are doing. This
// creates a "blank" matrix with the appropriate amount of memory
@@ -67,30 +88,30 @@ class CompressedRowSparseMatrix : public SparseMatrix {
// manually, instead of going via the indirect route of first
// constructing a TripletSparseMatrix, which leads to more than
// double the peak memory usage.
- CompressedRowSparseMatrix(int num_rows,
- int num_cols,
- int max_num_nonzeros);
+ //
+ // The storage type is set to UNSYMMETRIC.
+ CompressedRowSparseMatrix(int num_rows, int num_cols, int max_num_nonzeros);
// Build a square sparse diagonal matrix with num_rows rows and
// columns. The diagonal m(i,i) = diagonal(i);
+ //
+ // The storage type is set to UNSYMMETRIC
CompressedRowSparseMatrix(const double* diagonal, int num_rows);
- virtual ~CompressedRowSparseMatrix();
-
// SparseMatrix interface.
- virtual void SetZero();
- virtual void RightMultiply(const double* x, double* y) const;
- virtual void LeftMultiply(const double* x, double* y) const;
- virtual void SquaredColumnNorm(double* x) const;
- virtual void ScaleColumns(const double* scale);
-
- virtual void ToDenseMatrix(Matrix* dense_matrix) const;
- virtual void ToTextFile(FILE* file) const;
- virtual int num_rows() const { return num_rows_; }
- virtual int num_cols() const { return num_cols_; }
- virtual int num_nonzeros() const { return rows_[num_rows_]; }
- virtual const double* values() const { return &values_[0]; }
- virtual double* mutable_values() { return &values_[0]; }
+ virtual ~CompressedRowSparseMatrix();
+ void SetZero() final;
+ void RightMultiply(const double* x, double* y) const final;
+ void LeftMultiply(const double* x, double* y) const final;
+ void SquaredColumnNorm(double* x) const final;
+ void ScaleColumns(const double* scale) final;
+ void ToDenseMatrix(Matrix* dense_matrix) const final;
+ void ToTextFile(FILE* file) const final;
+ int num_rows() const final { return num_rows_; }
+ int num_cols() const final { return num_cols_; }
+ int num_nonzeros() const final { return rows_[num_rows_]; }
+ const double* values() const final { return &values_[0]; }
+ double* mutable_values() final { return &values_[0]; }
// Delete the bottom delta_rows.
// num_rows -= delta_rows
@@ -102,6 +123,15 @@ class CompressedRowSparseMatrix : public SparseMatrix {
void ToCRSMatrix(CRSMatrix* matrix) const;
+ CompressedRowSparseMatrix* Transpose() const;
+
+ // Destructive array resizing method.
+ void SetMaxNumNonZeros(int num_nonzeros);
+
+ // Non-destructive array resizing method.
+ void set_num_rows(const int num_rows) { num_rows_ = num_rows; }
+ void set_num_cols(const int num_cols) { num_cols_ = num_cols; }
+
// Low level access methods that expose the structure of the matrix.
const int* cols() const { return &cols_[0]; }
int* mutable_cols() { return &cols_[0]; }
@@ -109,60 +139,79 @@ class CompressedRowSparseMatrix : public SparseMatrix {
const int* rows() const { return &rows_[0]; }
int* mutable_rows() { return &rows_[0]; }
+ const StorageType storage_type() const { return storage_type_; }
+ void set_storage_type(const StorageType storage_type) {
+ storage_type_ = storage_type;
+ }
+
const std::vector<int>& row_blocks() const { return row_blocks_; }
std::vector<int>* mutable_row_blocks() { return &row_blocks_; }
const std::vector<int>& col_blocks() const { return col_blocks_; }
std::vector<int>* mutable_col_blocks() { return &col_blocks_; }
- // Destructive array resizing method.
- void SetMaxNumNonZeros(int num_nonzeros);
-
- // Non-destructive array resizing method.
- void set_num_rows(const int num_rows) { num_rows_ = num_rows; }
- void set_num_cols(const int num_cols) { num_cols_ = num_cols; }
-
- void SolveLowerTriangularInPlace(double* solution) const;
- void SolveLowerTriangularTransposeInPlace(double* solution) const;
-
- CompressedRowSparseMatrix* Transpose() const;
-
+ // Create a block diagonal CompressedRowSparseMatrix with the given
+ // block structure. The individual blocks are assumed to be laid out
+ // contiguously in the diagonal array, one block at a time.
+ //
+ // Caller owns the result.
static CompressedRowSparseMatrix* CreateBlockDiagonalMatrix(
- const double* diagonal,
- const std::vector<int>& blocks);
+ const double* diagonal, const std::vector<int>& blocks);
- // Compute the sparsity structure of the product m.transpose() * m
- // and create a CompressedRowSparseMatrix corresponding to it.
+ // Options struct to control the generation of random block sparse
+ // matrices in compressed row sparse format.
+ //
+ // The random matrix generation proceeds as follows.
//
- // Also compute a "program" vector, which for every term in the
- // outer product points to the entry in the values array of the
- // result matrix where it should be accumulated.
+ // First the row and column block structure is determined by
+ // generating random row and column block sizes that lie within the
+ // given bounds.
//
- // This program is used by the ComputeOuterProduct function below to
- // compute the outer product.
+ // Then we walk the block structure of the resulting matrix, and with
+ // probability block_density detemine whether they are structurally
+ // zero or not. If the answer is no, then we generate entries for the
+ // block which are distributed normally.
+ struct RandomMatrixOptions {
+ // Type of matrix to create.
+ //
+ // If storage_type is UPPER_TRIANGULAR (LOWER_TRIANGULAR), then
+ // create a square symmetric matrix with just the upper triangular
+ // (lower triangular) part. In this case, num_col_blocks,
+ // min_col_block_size and max_col_block_size will be ignored and
+ // assumed to be equal to the corresponding row settings.
+ StorageType storage_type = UNSYMMETRIC;
+
+ int num_row_blocks = 0;
+ int min_row_block_size = 0;
+ int max_row_block_size = 0;
+ int num_col_blocks = 0;
+ int min_col_block_size = 0;
+ int max_col_block_size = 0;
+
+ // 0 < block_density <= 1 is the probability of a block being
+ // present in the matrix. A given random matrix will not have
+ // precisely this density.
+ double block_density = 0.0;
+ };
+
+ // Create a random CompressedRowSparseMatrix whose entries are
+ // normally distributed and whose structure is determined by
+ // RandomMatrixOptions.
//
- // Since the entries of the program are the same for rows with the
- // same sparsity structure, the program only stores the result for
- // one row per row block. The ComputeOuterProduct function reuses
- // this information for each row in the row block.
- static CompressedRowSparseMatrix* CreateOuterProductMatrixAndProgram(
- const CompressedRowSparseMatrix& m,
- std::vector<int>* program);
-
- // Compute the values array for the expression m.transpose() * m,
- // where the matrix used to store the result and a program have been
- // created using the CreateOuterProductMatrixAndProgram function
- // above.
- static void ComputeOuterProduct(const CompressedRowSparseMatrix& m,
- const std::vector<int>& program,
- CompressedRowSparseMatrix* result);
+ // Caller owns the result.
+ static CompressedRowSparseMatrix* CreateRandomMatrix(
+ RandomMatrixOptions options);
private:
+ static CompressedRowSparseMatrix* FromTripletSparseMatrix(
+ const TripletSparseMatrix& input, bool transpose);
+
int num_rows_;
int num_cols_;
std::vector<int> rows_;
std::vector<int> cols_;
std::vector<double> values_;
+ StorageType storage_type_;
// If the matrix has an underlying block structure, then it can also
// carry with it row and column block sizes. This is auxilliary and
@@ -171,8 +220,6 @@ class CompressedRowSparseMatrix : public SparseMatrix {
// any way.
std::vector<int> row_blocks_;
std::vector<int> col_blocks_;
-
- CERES_DISALLOW_COPY_AND_ASSIGN(CompressedRowSparseMatrix);
};
} // namespace internal
diff --git a/extern/ceres/internal/ceres/concurrent_queue.h b/extern/ceres/internal/ceres/concurrent_queue.h
new file mode 100644
index 00000000000..52e2903022b
--- /dev/null
+++ b/extern/ceres/internal/ceres/concurrent_queue.h
@@ -0,0 +1,159 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2018 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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.
+//
+// Author: vitus@google.com (Michael Vitus)
+
+#ifndef CERES_INTERNAL_CONCURRENT_QUEUE_H_
+#define CERES_INTERNAL_CONCURRENT_QUEUE_H_
+
+#include <condition_variable>
+#include <mutex>
+#include <queue>
+#include <thread>
+
+#include "glog/logging.h"
+
+namespace ceres {
+namespace internal {
+
+// A thread-safe multi-producer, multi-consumer queue for queueing items that
+// are typically handled asynchronously by multiple threads. The ConcurrentQueue
+// has two states which only affect the Wait call:
+//
+// (1) Waiters have been enabled (enabled by default or calling
+// EnableWaiters). The call to Wait will block until an item is available.
+// Push and pop will operate as expected.
+//
+// (2) StopWaiters has been called. All threads blocked in a Wait() call will
+// be woken up and pop any available items from the queue. All future Wait
+// requests will either return an element from the queue or return
+// immediately if no element is present. Push and pop will operate as
+// expected.
+//
+// A common use case is using the concurrent queue as an interface for
+// scheduling tasks for a set of thread workers:
+//
+// ConcurrentQueue<Task> task_queue;
+//
+// [Worker threads]:
+// Task task;
+// while(task_queue.Wait(&task)) {
+// ...
+// }
+//
+// [Producers]:
+// task_queue.Push(...);
+// ..
+// task_queue.Push(...);
+// ...
+// // Signal worker threads to stop blocking on Wait and terminate.
+// task_queue.StopWaiters();
+//
+template <typename T>
+class ConcurrentQueue {
+ public:
+ // Defaults the queue to blocking on Wait calls.
+ ConcurrentQueue() : wait_(true) {}
+
+ // Atomically push an element onto the queue. If a thread was waiting for an
+ // element, wake it up.
+ void Push(const T& value) {
+ std::lock_guard<std::mutex> lock(mutex_);
+ queue_.push(value);
+ work_pending_condition_.notify_one();
+ }
+
+ // Atomically pop an element from the queue. If an element is present, return
+ // true. If the queue was empty, return false.
+ bool Pop(T* value) {
+ CHECK(value != nullptr);
+
+ std::lock_guard<std::mutex> lock(mutex_);
+ return PopUnlocked(value);
+ }
+
+ // Atomically pop an element from the queue. Blocks until one is available or
+ // StopWaiters is called. Returns true if an element was successfully popped
+ // from the queue, otherwise returns false.
+ bool Wait(T* value) {
+ CHECK(value != nullptr);
+
+ std::unique_lock<std::mutex> lock(mutex_);
+ work_pending_condition_.wait(lock,
+ [&]() { return !(wait_ && queue_.empty()); });
+
+ return PopUnlocked(value);
+ }
+
+ // Unblock all threads waiting to pop a value from the queue, and they will
+ // exit Wait() without getting a value. All future Wait requests will return
+ // immediately if no element is present until EnableWaiters is called.
+ void StopWaiters() {
+ std::lock_guard<std::mutex> lock(mutex_);
+ wait_ = false;
+ work_pending_condition_.notify_all();
+ }
+
+ // Enable threads to block on Wait calls.
+ void EnableWaiters() {
+ std::lock_guard<std::mutex> lock(mutex_);
+ wait_ = true;
+ }
+
+ private:
+ // Pops an element from the queue. If an element is present, return
+ // true. If the queue was empty, return false. Not thread-safe. Must acquire
+ // the lock before calling.
+ bool PopUnlocked(T* value) {
+ if (queue_.empty()) {
+ return false;
+ }
+
+ *value = queue_.front();
+ queue_.pop();
+
+ return true;
+ }
+
+ // The mutex controls read and write access to the queue_ and stop_
+ // variables. It is also used to block the calling thread until an element is
+ // available to pop from the queue.
+ std::mutex mutex_;
+ std::condition_variable work_pending_condition_;
+
+ std::queue<T> queue_;
+ // If true, signals that callers of Wait will block waiting to pop an
+ // element off the queue.
+ bool wait_;
+};
+
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_CONCURRENT_QUEUE_H_
diff --git a/extern/ceres/internal/ceres/conditioned_cost_function.cc b/extern/ceres/internal/ceres/conditioned_cost_function.cc
index 08899e3d246..d933ad7c462 100644
--- a/extern/ceres/internal/ceres/conditioned_cost_function.cc
+++ b/extern/ceres/internal/ceres/conditioned_cost_function.cc
@@ -68,7 +68,7 @@ ConditionedCostFunction::ConditionedCostFunction(
ConditionedCostFunction::~ConditionedCostFunction() {
if (ownership_ == TAKE_OWNERSHIP) {
- STLDeleteElements(&conditioners_);
+ STLDeleteUniqueContainerPointers(conditioners_.begin(), conditioners_.end());
} else {
wrapped_cost_function_.release();
}
diff --git a/extern/ceres/internal/ceres/conjugate_gradients_solver.cc b/extern/ceres/internal/ceres/conjugate_gradients_solver.cc
index 3702276a2fb..c6f85c15ea0 100644
--- a/extern/ceres/internal/ceres/conjugate_gradients_solver.cc
+++ b/extern/ceres/internal/ceres/conjugate_gradients_solver.cc
@@ -41,7 +41,6 @@
#include <cmath>
#include <cstddef>
-#include "ceres/fpclassify.h"
#include "ceres/internal/eigen.h"
#include "ceres/linear_operator.h"
#include "ceres/stringprintf.h"
@@ -53,7 +52,7 @@ namespace internal {
namespace {
bool IsZeroOrInfinity(double x) {
- return ((x == 0.0) || (IsInfinite(x)));
+ return ((x == 0.0) || std::isinf(x));
}
} // namespace
@@ -68,9 +67,9 @@ LinearSolver::Summary ConjugateGradientsSolver::Solve(
const double* b,
const LinearSolver::PerSolveOptions& per_solve_options,
double* x) {
- CHECK_NOTNULL(A);
- CHECK_NOTNULL(x);
- CHECK_NOTNULL(b);
+ CHECK(A != nullptr);
+ CHECK(x != nullptr);
+ CHECK(b != nullptr);
CHECK_EQ(A->num_rows(), A->num_cols());
LinearSolver::Summary summary;
@@ -148,7 +147,7 @@ LinearSolver::Summary ConjugateGradientsSolver::Solve(
q.setZero();
A->RightMultiply(p.data(), q.data());
const double pq = p.dot(q);
- if ((pq <= 0) || IsInfinite(pq)) {
+ if ((pq <= 0) || std::isinf(pq)) {
summary.termination_type = LINEAR_SOLVER_NO_CONVERGENCE;
summary.message = StringPrintf(
"Matrix is indefinite, no more progress can be made. "
@@ -158,7 +157,7 @@ LinearSolver::Summary ConjugateGradientsSolver::Solve(
}
const double alpha = rho / pq;
- if (IsInfinite(alpha)) {
+ if (std::isinf(alpha)) {
summary.termination_type = LINEAR_SOLVER_FAILURE;
summary.message =
StringPrintf("Numerical failure. alpha = rho / pq = %e, "
diff --git a/extern/ceres/internal/ceres/conjugate_gradients_solver.h b/extern/ceres/internal/ceres/conjugate_gradients_solver.h
index a1e18334414..d89383e6359 100644
--- a/extern/ceres/internal/ceres/conjugate_gradients_solver.h
+++ b/extern/ceres/internal/ceres/conjugate_gradients_solver.h
@@ -35,7 +35,6 @@
#define CERES_INTERNAL_CONJUGATE_GRADIENTS_SOLVER_H_
#include "ceres/linear_solver.h"
-#include "ceres/internal/macros.h"
namespace ceres {
namespace internal {
@@ -58,14 +57,13 @@ class LinearOperator;
class ConjugateGradientsSolver : public LinearSolver {
public:
explicit ConjugateGradientsSolver(const LinearSolver::Options& options);
- virtual Summary Solve(LinearOperator* A,
- const double* b,
- const LinearSolver::PerSolveOptions& per_solve_options,
- double* x);
+ Summary Solve(LinearOperator* A,
+ const double* b,
+ const LinearSolver::PerSolveOptions& per_solve_options,
+ double* x) final;
private:
const LinearSolver::Options options_;
- CERES_DISALLOW_COPY_AND_ASSIGN(ConjugateGradientsSolver);
};
} // namespace internal
diff --git a/extern/ceres/internal/ceres/context.cc b/extern/ceres/internal/ceres/context.cc
new file mode 100644
index 00000000000..e2232013b4b
--- /dev/null
+++ b/extern/ceres/internal/ceres/context.cc
@@ -0,0 +1,41 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2018 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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.
+//
+// Author: vitus@google.com (Michael Vitus)
+
+#include "ceres/context.h"
+
+#include "ceres/context_impl.h"
+
+namespace ceres {
+
+Context* Context::Create() {
+ return new internal::ContextImpl();
+}
+
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/context_impl.cc b/extern/ceres/internal/ceres/context_impl.cc
new file mode 100644
index 00000000000..622f33a9dc0
--- /dev/null
+++ b/extern/ceres/internal/ceres/context_impl.cc
@@ -0,0 +1,43 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2018 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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.
+//
+// Author: vitus@google.com (Michael Vitus)
+
+#include "ceres/context_impl.h"
+
+namespace ceres {
+namespace internal {
+
+void ContextImpl::EnsureMinimumThreads(int num_threads) {
+#ifdef CERES_USE_CXX_THREADS
+ thread_pool.Resize(num_threads);
+#endif // CERES_USE_CXX_THREADS
+
+}
+} // namespace internal
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/context_impl.h b/extern/ceres/internal/ceres/context_impl.h
new file mode 100644
index 00000000000..5c03ad71bab
--- /dev/null
+++ b/extern/ceres/internal/ceres/context_impl.h
@@ -0,0 +1,67 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2018 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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.
+//
+// Author: vitus@google.com (Michael Vitus)
+
+#ifndef CERES_INTERNAL_CONTEXT_IMPL_H_
+#define CERES_INTERNAL_CONTEXT_IMPL_H_
+
+// This include must come before any #ifndef check on Ceres compile options.
+#include "ceres/internal/port.h"
+
+#include "ceres/context.h"
+
+#ifdef CERES_USE_CXX_THREADS
+#include "ceres/thread_pool.h"
+#endif // CERES_USE_CXX_THREADS
+
+namespace ceres {
+namespace internal {
+
+class ContextImpl : public Context {
+ public:
+ ContextImpl() {}
+ ContextImpl(const ContextImpl&) = delete;
+ void operator=(const ContextImpl&) = delete;
+
+ virtual ~ContextImpl() {}
+
+ // When compiled with C++ threading support, resize the thread pool to have
+ // at min(num_thread, num_hardware_threads) where num_hardware_threads is
+ // defined by the hardware. Otherwise this call is a no-op.
+ void EnsureMinimumThreads(int num_threads);
+
+#ifdef CERES_USE_CXX_THREADS
+ ThreadPool thread_pool;
+#endif // CERES_USE_CXX_THREADS
+};
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_CONTEXT_IMPL_H_
diff --git a/extern/ceres/internal/ceres/coordinate_descent_minimizer.cc b/extern/ceres/internal/ceres/coordinate_descent_minimizer.cc
index c6b42cf1516..c5d56f30bc3 100644
--- a/extern/ceres/internal/ceres/coordinate_descent_minimizer.cc
+++ b/extern/ceres/internal/ceres/coordinate_descent_minimizer.cc
@@ -30,16 +30,16 @@
#include "ceres/coordinate_descent_minimizer.h"
-#ifdef CERES_USE_OPENMP
-#include <omp.h>
-#endif
-
+#include <algorithm>
#include <iterator>
+#include <memory>
#include <numeric>
#include <vector>
+
#include "ceres/evaluator.h"
#include "ceres/linear_solver.h"
#include "ceres/minimizer.h"
+#include "ceres/parallel_for.h"
#include "ceres/parameter_block.h"
#include "ceres/parameter_block_ordering.h"
#include "ceres/problem_impl.h"
@@ -59,6 +59,11 @@ using std::set;
using std::string;
using std::vector;
+CoordinateDescentMinimizer::CoordinateDescentMinimizer(ContextImpl* context)
+ : context_(context) {
+ CHECK(context_ != nullptr);
+}
+
CoordinateDescentMinimizer::~CoordinateDescentMinimizer() {
}
@@ -74,19 +79,16 @@ bool CoordinateDescentMinimizer::Init(
// Serialize the OrderedGroups into a vector of parameter block
// offsets for parallel access.
map<ParameterBlock*, int> parameter_block_index;
- map<int, set<double*> > group_to_elements = ordering.group_to_elements();
- for (map<int, set<double*> >::const_iterator it = group_to_elements.begin();
- it != group_to_elements.end();
- ++it) {
- for (set<double*>::const_iterator ptr_it = it->second.begin();
- ptr_it != it->second.end();
- ++ptr_it) {
- parameter_blocks_.push_back(parameter_map.find(*ptr_it)->second);
+ map<int, set<double*>> group_to_elements = ordering.group_to_elements();
+ for (const auto& g_t_e : group_to_elements) {
+ const auto& elements = g_t_e.second;
+ for (double* parameter_block: elements) {
+ parameter_blocks_.push_back(parameter_map.find(parameter_block)->second);
parameter_block_index[parameter_blocks_.back()] =
parameter_blocks_.size() - 1;
}
independent_set_offsets_.push_back(
- independent_set_offsets_.back() + it->second.size());
+ independent_set_offsets_.back() + elements.size());
}
// The ordering does not have to contain all parameter blocks, so
@@ -109,8 +111,7 @@ bool CoordinateDescentMinimizer::Init(
const int num_parameter_blocks = residual_block->NumParameterBlocks();
for (int j = 0; j < num_parameter_blocks; ++j) {
ParameterBlock* parameter_block = residual_block->parameter_blocks()[j];
- const map<ParameterBlock*, int>::const_iterator it =
- parameter_block_index.find(parameter_block);
+ const auto it = parameter_block_index.find(parameter_block);
if (it != parameter_block_index.end()) {
residual_blocks_[it->second].push_back(residual_block);
}
@@ -120,6 +121,7 @@ bool CoordinateDescentMinimizer::Init(
evaluator_options_.linear_solver_type = DENSE_QR;
evaluator_options_.num_eliminate_blocks = 0;
evaluator_options_.num_threads = 1;
+ evaluator_options_.context = context_;
return true;
}
@@ -135,11 +137,12 @@ void CoordinateDescentMinimizer::Minimize(
parameter_block->SetConstant();
}
- scoped_array<LinearSolver*> linear_solvers(
+ std::unique_ptr<LinearSolver*[]> linear_solvers(
new LinearSolver*[options.num_threads]);
LinearSolver::Options linear_solver_options;
linear_solver_options.type = DENSE_QR;
+ linear_solver_options.context = context_;
for (int i = 0; i < options.num_threads; ++i) {
linear_solvers[i] = LinearSolver::Create(linear_solver_options);
@@ -148,13 +151,11 @@ void CoordinateDescentMinimizer::Minimize(
for (int i = 0; i < independent_set_offsets_.size() - 1; ++i) {
const int num_problems =
independent_set_offsets_[i + 1] - independent_set_offsets_[i];
- // No point paying the price for an OpemMP call if the set is of
- // size zero.
+ // Avoid parallelization overhead call if the set is empty.
if (num_problems == 0) {
continue;
}
-#ifdef CERES_USE_OPENMP
const int num_inner_iteration_threads =
min(options.num_threads, num_problems);
evaluator_options_.num_threads =
@@ -162,47 +163,43 @@ void CoordinateDescentMinimizer::Minimize(
// The parameter blocks in each independent set can be optimized
// in parallel, since they do not co-occur in any residual block.
-#pragma omp parallel for num_threads(num_inner_iteration_threads)
-#endif
- for (int j = independent_set_offsets_[i];
- j < independent_set_offsets_[i + 1];
- ++j) {
-#ifdef CERES_USE_OPENMP
- int thread_id = omp_get_thread_num();
-#else
- int thread_id = 0;
-#endif
-
- ParameterBlock* parameter_block = parameter_blocks_[j];
- const int old_index = parameter_block->index();
- const int old_delta_offset = parameter_block->delta_offset();
- parameter_block->SetVarying();
- parameter_block->set_index(0);
- parameter_block->set_delta_offset(0);
-
- Program inner_program;
- inner_program.mutable_parameter_blocks()->push_back(parameter_block);
- *inner_program.mutable_residual_blocks() = residual_blocks_[j];
-
- // TODO(sameeragarwal): Better error handling. Right now we
- // assume that this is not going to lead to problems of any
- // sort. Basically we should be checking for numerical failure
- // of some sort.
- //
- // On the other hand, if the optimization is a failure, that in
- // some ways is fine, since it won't change the parameters and
- // we are fine.
- Solver::Summary inner_summary;
- Solve(&inner_program,
- linear_solvers[thread_id],
- parameters + parameter_block->state_offset(),
- &inner_summary);
-
- parameter_block->set_index(old_index);
- parameter_block->set_delta_offset(old_delta_offset);
- parameter_block->SetState(parameters + parameter_block->state_offset());
- parameter_block->SetConstant();
- }
+ ParallelFor(
+ context_,
+ independent_set_offsets_[i],
+ independent_set_offsets_[i + 1],
+ num_inner_iteration_threads,
+ [&](int thread_id, int j) {
+ ParameterBlock* parameter_block = parameter_blocks_[j];
+ const int old_index = parameter_block->index();
+ const int old_delta_offset = parameter_block->delta_offset();
+ parameter_block->SetVarying();
+ parameter_block->set_index(0);
+ parameter_block->set_delta_offset(0);
+
+ Program inner_program;
+ inner_program.mutable_parameter_blocks()->push_back(parameter_block);
+ *inner_program.mutable_residual_blocks() = residual_blocks_[j];
+
+ // TODO(sameeragarwal): Better error handling. Right now we
+ // assume that this is not going to lead to problems of any
+ // sort. Basically we should be checking for numerical failure
+ // of some sort.
+ //
+ // On the other hand, if the optimization is a failure, that in
+ // some ways is fine, since it won't change the parameters and
+ // we are fine.
+ Solver::Summary inner_summary;
+ Solve(&inner_program,
+ linear_solvers[thread_id],
+ parameters + parameter_block->state_offset(),
+ &inner_summary);
+
+ parameter_block->set_index(old_index);
+ parameter_block->set_delta_offset(old_delta_offset);
+ parameter_block->SetState(parameters +
+ parameter_block->state_offset());
+ parameter_block->SetConstant();
+ });
}
for (int i = 0; i < parameter_blocks_.size(); ++i) {
@@ -227,14 +224,17 @@ void CoordinateDescentMinimizer::Solve(Program* program,
Minimizer::Options minimizer_options;
minimizer_options.evaluator.reset(
- CHECK_NOTNULL(Evaluator::Create(evaluator_options_, program, &error)));
+ Evaluator::Create(evaluator_options_, program, &error));
+ CHECK(minimizer_options.evaluator != nullptr);
minimizer_options.jacobian.reset(
- CHECK_NOTNULL(minimizer_options.evaluator->CreateJacobian()));
+ minimizer_options.evaluator->CreateJacobian());
+ CHECK(minimizer_options.jacobian != nullptr);
TrustRegionStrategy::Options trs_options;
trs_options.linear_solver = linear_solver;
minimizer_options.trust_region_strategy.reset(
- CHECK_NOTNULL(TrustRegionStrategy::Create(trs_options)));
+ TrustRegionStrategy::Create(trs_options));
+ CHECK(minimizer_options.trust_region_strategy != nullptr);
minimizer_options.is_silent = true;
TrustRegionMinimizer minimizer;
@@ -245,17 +245,16 @@ bool CoordinateDescentMinimizer::IsOrderingValid(
const Program& program,
const ParameterBlockOrdering& ordering,
string* message) {
- const map<int, set<double*> >& group_to_elements =
+ const map<int, set<double*>>& group_to_elements =
ordering.group_to_elements();
// Verify that each group is an independent set
- map<int, set<double*> >::const_iterator it = group_to_elements.begin();
- for (; it != group_to_elements.end(); ++it) {
- if (!program.IsParameterBlockSetIndependent(it->second)) {
+ for (const auto& g_t_e : group_to_elements) {
+ if (!program.IsParameterBlockSetIndependent(g_t_e.second)) {
*message =
StringPrintf("The user-provided "
"parameter_blocks_for_inner_iterations does not "
- "form an independent set. Group Id: %d", it->first);
+ "form an independent set. Group Id: %d", g_t_e.first);
return false;
}
}
@@ -268,7 +267,7 @@ bool CoordinateDescentMinimizer::IsOrderingValid(
// points.
ParameterBlockOrdering* CoordinateDescentMinimizer::CreateOrdering(
const Program& program) {
- scoped_ptr<ParameterBlockOrdering> ordering(new ParameterBlockOrdering);
+ std::unique_ptr<ParameterBlockOrdering> ordering(new ParameterBlockOrdering);
ComputeRecursiveIndependentSetOrdering(program, ordering.get());
ordering->Reverse();
return ordering.release();
diff --git a/extern/ceres/internal/ceres/coordinate_descent_minimizer.h b/extern/ceres/internal/ceres/coordinate_descent_minimizer.h
index 25ea04ce622..7d17d53eb0f 100644
--- a/extern/ceres/internal/ceres/coordinate_descent_minimizer.h
+++ b/extern/ceres/internal/ceres/coordinate_descent_minimizer.h
@@ -34,6 +34,7 @@
#include <string>
#include <vector>
+#include "ceres/context_impl.h"
#include "ceres/evaluator.h"
#include "ceres/minimizer.h"
#include "ceres/problem_impl.h"
@@ -57,6 +58,8 @@ class LinearSolver;
// program are constant.
class CoordinateDescentMinimizer : public Minimizer {
public:
+ explicit CoordinateDescentMinimizer(ContextImpl* context);
+
bool Init(const Program& program,
const ProblemImpl::ParameterMap& parameter_map,
const ParameterBlockOrdering& ordering,
@@ -64,9 +67,10 @@ class CoordinateDescentMinimizer : public Minimizer {
// Minimizer interface.
virtual ~CoordinateDescentMinimizer();
- virtual void Minimize(const Minimizer::Options& options,
- double* parameters,
- Solver::Summary* summary);
+
+ void Minimize(const Minimizer::Options& options,
+ double* parameters,
+ Solver::Summary* summary) final;
// Verify that each group in the ordering forms an independent set.
static bool IsOrderingValid(const Program& program,
@@ -86,7 +90,7 @@ class CoordinateDescentMinimizer : public Minimizer {
Solver::Summary* summary);
std::vector<ParameterBlock*> parameter_blocks_;
- std::vector<std::vector<ResidualBlock*> > residual_blocks_;
+ std::vector<std::vector<ResidualBlock*>> residual_blocks_;
// The optimization is performed in rounds. In each round all the
// parameter blocks that form one independent set are optimized in
// parallel. This array, marks the boundaries of the independent
@@ -94,6 +98,8 @@ class CoordinateDescentMinimizer : public Minimizer {
std::vector<int> independent_set_offsets_;
Evaluator::Options evaluator_options_;
+
+ ContextImpl* context_;
};
} // namespace internal
diff --git a/extern/ceres/internal/ceres/corrector.cc b/extern/ceres/internal/ceres/corrector.cc
index 720182868c1..4ac0dc3cd86 100644
--- a/extern/ceres/internal/ceres/corrector.cc
+++ b/extern/ceres/internal/ceres/corrector.cc
@@ -43,7 +43,7 @@ Corrector::Corrector(const double sq_norm, const double rho[3]) {
sqrt_rho1_ = sqrt(rho[1]);
// If sq_norm = 0.0, the correction becomes trivial, the residual
- // and the jacobian are scaled by the squareroot of the derivative
+ // and the jacobian are scaled by the square root of the derivative
// of rho. Handling this case explicitly avoids the divide by zero
// error that would occur below.
//
@@ -59,7 +59,7 @@ Corrector::Corrector(const double sq_norm, const double rho[3]) {
// correction which re-wights the gradient of the function by the
// square root of the derivative of rho, and the Gauss-Newton
// Hessian gets both the scaling and the rank-1 curvature
- // correction. Normaly, alpha is upper bounded by one, but with this
+ // correction. Normally, alpha is upper bounded by one, but with this
// change, alpha is bounded above by zero.
//
// Empirically we have observed that the full Triggs correction and
diff --git a/extern/ceres/internal/ceres/corrector.h b/extern/ceres/internal/ceres/corrector.h
index 315f012ab1d..a5b03dda803 100644
--- a/extern/ceres/internal/ceres/corrector.h
+++ b/extern/ceres/internal/ceres/corrector.h
@@ -43,7 +43,7 @@ namespace internal {
// radial robust loss.
//
// The key idea here is to look at the expressions for the robustified
-// gauss newton approximation and then take its squareroot to get the
+// gauss newton approximation and then take its square root to get the
// corresponding corrections to the residual and jacobian. For the
// full expressions see Eq. 10 and 11 in BANS by Triggs et al.
class Corrector {
diff --git a/extern/ceres/internal/ceres/covariance.cc b/extern/ceres/internal/ceres/covariance.cc
index cb280a36847..8256078409a 100644
--- a/extern/ceres/internal/ceres/covariance.cc
+++ b/extern/ceres/internal/ceres/covariance.cc
@@ -50,15 +50,15 @@ Covariance::~Covariance() {
}
bool Covariance::Compute(
- const vector<pair<const double*, const double*> >& covariance_blocks,
+ const vector<pair<const double*, const double*>>& covariance_blocks,
Problem* problem) {
- return impl_->Compute(covariance_blocks, problem->problem_impl_.get());
+ return impl_->Compute(covariance_blocks, problem->impl_.get());
}
bool Covariance::Compute(
const vector<const double*>& parameter_blocks,
Problem* problem) {
- return impl_->Compute(parameter_blocks, problem->problem_impl_.get());
+ return impl_->Compute(parameter_blocks, problem->impl_.get());
}
bool Covariance::GetCovarianceBlock(const double* parameter_block1,
@@ -82,7 +82,7 @@ bool Covariance::GetCovarianceBlockInTangentSpace(
bool Covariance::GetCovarianceMatrix(
const vector<const double*>& parameter_blocks,
- double* covariance_matrix) {
+ double* covariance_matrix) const {
return impl_->GetCovarianceMatrixInTangentOrAmbientSpace(parameter_blocks,
true, // ambient
covariance_matrix);
@@ -90,7 +90,7 @@ bool Covariance::GetCovarianceMatrix(
bool Covariance::GetCovarianceMatrixInTangentSpace(
const std::vector<const double *>& parameter_blocks,
- double *covariance_matrix) {
+ double *covariance_matrix) const {
return impl_->GetCovarianceMatrixInTangentOrAmbientSpace(parameter_blocks,
false, // tangent
covariance_matrix);
diff --git a/extern/ceres/internal/ceres/covariance_impl.cc b/extern/ceres/internal/ceres/covariance_impl.cc
index d698f88fa9b..6c26412d854 100644
--- a/extern/ceres/internal/ceres/covariance_impl.cc
+++ b/extern/ceres/internal/ceres/covariance_impl.cc
@@ -30,14 +30,12 @@
#include "ceres/covariance_impl.h"
-#ifdef CERES_USE_OPENMP
-#include <omp.h>
-#endif
-
#include <algorithm>
#include <cstdlib>
+#include <memory>
#include <numeric>
#include <sstream>
+#include <unordered_set>
#include <utility>
#include <vector>
@@ -45,13 +43,14 @@
#include "Eigen/SparseQR"
#include "Eigen/SVD"
-#include "ceres/collections_port.h"
#include "ceres/compressed_col_sparse_matrix_utils.h"
#include "ceres/compressed_row_sparse_matrix.h"
#include "ceres/covariance.h"
#include "ceres/crs_matrix.h"
#include "ceres/internal/eigen.h"
#include "ceres/map_util.h"
+#include "ceres/parallel_for.h"
+#include "ceres/parallel_utils.h"
#include "ceres/parameter_block.h"
#include "ceres/problem_impl.h"
#include "ceres/residual_block.h"
@@ -69,21 +68,22 @@ using std::sort;
using std::swap;
using std::vector;
-typedef vector<pair<const double*, const double*> > CovarianceBlocks;
+typedef vector<pair<const double*, const double*>> CovarianceBlocks;
CovarianceImpl::CovarianceImpl(const Covariance::Options& options)
: options_(options),
is_computed_(false),
is_valid_(false) {
-#ifndef CERES_USE_OPENMP
+#ifdef CERES_NO_THREADS
if (options_.num_threads > 1) {
LOG(WARNING)
- << "OpenMP support is not compiled into this binary; "
+ << "No threading support is compiled into this binary; "
<< "only options.num_threads = 1 is supported. Switching "
<< "to single threaded mode.";
options_.num_threads = 1;
}
#endif
+
evaluate_options_.num_threads = options_.num_threads;
evaluate_options_.apply_loss_function = options_.apply_loss_function;
}
@@ -97,7 +97,7 @@ template <typename T> void CheckForDuplicates(vector<T> blocks) {
std::adjacent_find(blocks.begin(), blocks.end());
if (it != blocks.end()) {
// In case there are duplicates, we search for their location.
- map<T, vector<int> > blocks_map;
+ map<T, vector<int>> blocks_map;
for (int i = 0; i < blocks.size(); ++i) {
blocks_map[blocks[i]].push_back(i);
}
@@ -122,7 +122,7 @@ template <typename T> void CheckForDuplicates(vector<T> blocks) {
bool CovarianceImpl::Compute(const CovarianceBlocks& covariance_blocks,
ProblemImpl* problem) {
- CheckForDuplicates<pair<const double*, const double*> >(covariance_blocks);
+ CheckForDuplicates<pair<const double*, const double*>>(covariance_blocks);
problem_ = problem;
parameter_block_to_row_index_.clear();
covariance_matrix_.reset(NULL);
@@ -333,55 +333,47 @@ bool CovarianceImpl::GetCovarianceMatrixInTangentOrAmbientSpace(
// Assemble the blocks in the covariance matrix.
MatrixRef covariance(covariance_matrix, covariance_size, covariance_size);
const int num_threads = options_.num_threads;
- scoped_array<double> workspace(
+ std::unique_ptr<double[]> workspace(
new double[num_threads * max_covariance_block_size *
max_covariance_block_size]);
bool success = true;
-// The collapse() directive is only supported in OpenMP 3.0 and higher. OpenMP
-// 3.0 was released in May 2008 (hence the version number).
-#if _OPENMP >= 200805
-# pragma omp parallel for num_threads(num_threads) schedule(dynamic) collapse(2)
-#else
-# pragma omp parallel for num_threads(num_threads) schedule(dynamic)
-#endif
- for (int i = 0; i < num_parameters; ++i) {
- for (int j = 0; j < num_parameters; ++j) {
- // The second loop can't start from j = i for compatibility with OpenMP
- // collapse command. The conditional serves as a workaround
- if (j >= i) {
+ // Technically the following code is a double nested loop where
+ // i = 1:n, j = i:n.
+ int iteration_count = (num_parameters * (num_parameters + 1)) / 2;
+ problem_->context()->EnsureMinimumThreads(num_threads);
+ ParallelFor(
+ problem_->context(),
+ 0,
+ iteration_count,
+ num_threads,
+ [&](int thread_id, int k) {
+ int i, j;
+ LinearIndexToUpperTriangularIndex(k, num_parameters, &i, &j);
+
int covariance_row_idx = cum_parameter_size[i];
int covariance_col_idx = cum_parameter_size[j];
int size_i = parameter_sizes[i];
int size_j = parameter_sizes[j];
-#ifdef CERES_USE_OPENMP
- int thread_id = omp_get_thread_num();
-#else
- int thread_id = 0;
-#endif
double* covariance_block =
- workspace.get() +
- thread_id * max_covariance_block_size * max_covariance_block_size;
+ workspace.get() + thread_id * max_covariance_block_size *
+ max_covariance_block_size;
if (!GetCovarianceBlockInTangentOrAmbientSpace(
- parameters[i], parameters[j], lift_covariance_to_ambient_space,
- covariance_block)) {
+ parameters[i], parameters[j],
+ lift_covariance_to_ambient_space, covariance_block)) {
success = false;
}
- covariance.block(covariance_row_idx, covariance_col_idx,
- size_i, size_j) =
- MatrixRef(covariance_block, size_i, size_j);
+ covariance.block(covariance_row_idx, covariance_col_idx, size_i,
+ size_j) = MatrixRef(covariance_block, size_i, size_j);
if (i != j) {
covariance.block(covariance_col_idx, covariance_row_idx,
size_j, size_i) =
MatrixRef(covariance_block, size_i, size_j).transpose();
-
}
- }
- }
- }
+ });
return success;
}
@@ -397,7 +389,7 @@ bool CovarianceImpl::ComputeCovarianceSparsity(
vector<double*> all_parameter_blocks;
problem->GetParameterBlocks(&all_parameter_blocks);
const ProblemImpl::ParameterMap& parameter_map = problem->parameter_map();
- HashSet<ParameterBlock*> parameter_blocks_in_use;
+ std::unordered_set<ParameterBlock*> parameter_blocks_in_use;
vector<ResidualBlock*> residual_blocks;
problem->GetResidualBlocks(&residual_blocks);
@@ -496,13 +488,10 @@ bool CovarianceImpl::ComputeCovarianceSparsity(
// rows of the covariance matrix in order.
int i = 0; // index into covariance_blocks.
int cursor = 0; // index into the covariance matrix.
- for (map<const double*, int>::const_iterator it =
- parameter_block_to_row_index_.begin();
- it != parameter_block_to_row_index_.end();
- ++it) {
- const double* row_block = it->first;
+ for (const auto& entry : parameter_block_to_row_index_) {
+ const double* row_block = entry.first;
const int row_block_size = problem->ParameterBlockLocalSize(row_block);
- int row_begin = it->second;
+ int row_begin = entry.second;
// Iterate over the covariance blocks contained in this row block
// and count the number of columns in this row block.
@@ -538,24 +527,37 @@ bool CovarianceImpl::ComputeCovarianceSparsity(
}
bool CovarianceImpl::ComputeCovarianceValues() {
- switch (options_.algorithm_type) {
- case DENSE_SVD:
- return ComputeCovarianceValuesUsingDenseSVD();
- case SUITE_SPARSE_QR:
-#ifndef CERES_NO_SUITESPARSE
+ if (options_.algorithm_type == DENSE_SVD) {
+ return ComputeCovarianceValuesUsingDenseSVD();
+ }
+
+ if (options_.algorithm_type == SPARSE_QR) {
+ if (options_.sparse_linear_algebra_library_type == EIGEN_SPARSE) {
+ return ComputeCovarianceValuesUsingEigenSparseQR();
+ }
+
+ if (options_.sparse_linear_algebra_library_type == SUITE_SPARSE) {
+#if !defined(CERES_NO_SUITESPARSE)
return ComputeCovarianceValuesUsingSuiteSparseQR();
#else
- LOG(ERROR) << "SuiteSparse is required to use the "
- << "SUITE_SPARSE_QR algorithm.";
+ LOG(ERROR) << "SuiteSparse is required to use the SPARSE_QR algorithm "
+ << "with "
+ << "Covariance::Options::sparse_linear_algebra_library_type "
+ << "= SUITE_SPARSE.";
return false;
#endif
- case EIGEN_SPARSE_QR:
- return ComputeCovarianceValuesUsingEigenSparseQR();
- default:
- LOG(ERROR) << "Unsupported covariance estimation algorithm type: "
- << CovarianceAlgorithmTypeToString(options_.algorithm_type);
- return false;
+ }
+
+ LOG(ERROR) << "Unsupported "
+ << "Covariance::Options::sparse_linear_algebra_library_type "
+ << "= "
+ << SparseLinearAlgebraLibraryTypeToString(
+ options_.sparse_linear_algebra_library_type);
+ return false;
}
+
+ LOG(ERROR) << "Unsupported Covariance::Options::algorithm_type = "
+ << CovarianceAlgorithmTypeToString(options_.algorithm_type);
return false;
}
@@ -649,8 +651,12 @@ bool CovarianceImpl::ComputeCovarianceValuesUsingSuiteSparseQR() {
&permutation,
&cc);
event_logger.AddEvent("Numeric Factorization");
- CHECK_NOTNULL(permutation);
- CHECK_NOTNULL(R);
+ if (R == nullptr) {
+ LOG(ERROR) << "Something is wrong. SuiteSparseQR returned R = nullptr.";
+ free(permutation);
+ cholmod_l_finish(&cc);
+ return false;
+ }
if (rank < cholmod_jacobian.ncol) {
LOG(ERROR) << "Jacobian matrix is rank deficient. "
@@ -663,8 +669,14 @@ bool CovarianceImpl::ComputeCovarianceValuesUsingSuiteSparseQR() {
}
vector<int> inverse_permutation(num_cols);
- for (SuiteSparse_long i = 0; i < num_cols; ++i) {
- inverse_permutation[permutation[i]] = i;
+ if (permutation) {
+ for (SuiteSparse_long i = 0; i < num_cols; ++i) {
+ inverse_permutation[permutation[i]] = i;
+ }
+ } else {
+ for (SuiteSparse_long i = 0; i < num_cols; ++i) {
+ inverse_permutation[i] = i;
+ }
}
const int* rows = covariance_matrix_->rows();
@@ -681,35 +693,29 @@ bool CovarianceImpl::ComputeCovarianceValuesUsingSuiteSparseQR() {
// Since the covariance matrix is symmetric, the i^th row and column
// are equal.
const int num_threads = options_.num_threads;
- scoped_array<double> workspace(new double[num_threads * num_cols]);
-
-#pragma omp parallel for num_threads(num_threads) schedule(dynamic)
- for (int r = 0; r < num_cols; ++r) {
- const int row_begin = rows[r];
- const int row_end = rows[r + 1];
- if (row_end == row_begin) {
- continue;
- }
-
-# ifdef CERES_USE_OPENMP
- int thread_id = omp_get_thread_num();
-# else
- int thread_id = 0;
-# endif
-
- double* solution = workspace.get() + thread_id * num_cols;
- SolveRTRWithSparseRHS<SuiteSparse_long>(
- num_cols,
- static_cast<SuiteSparse_long*>(R->i),
- static_cast<SuiteSparse_long*>(R->p),
- static_cast<double*>(R->x),
- inverse_permutation[r],
- solution);
- for (int idx = row_begin; idx < row_end; ++idx) {
- const int c = cols[idx];
- values[idx] = solution[inverse_permutation[c]];
- }
- }
+ std::unique_ptr<double[]> workspace(new double[num_threads * num_cols]);
+
+ problem_->context()->EnsureMinimumThreads(num_threads);
+ ParallelFor(
+ problem_->context(),
+ 0,
+ num_cols,
+ num_threads,
+ [&](int thread_id, int r) {
+ const int row_begin = rows[r];
+ const int row_end = rows[r + 1];
+ if (row_end != row_begin) {
+ double* solution = workspace.get() + thread_id * num_cols;
+ SolveRTRWithSparseRHS<SuiteSparse_long>(
+ num_cols, static_cast<SuiteSparse_long*>(R->i),
+ static_cast<SuiteSparse_long*>(R->p), static_cast<double*>(R->x),
+ inverse_permutation[r], solution);
+ for (int idx = row_begin; idx < row_end; ++idx) {
+ const int c = cols[idx];
+ values[idx] = solution[inverse_permutation[c]];
+ }
+ }
+ });
free(permutation);
cholmod_l_free_sparse(&R, &cc);
@@ -746,8 +752,8 @@ bool CovarianceImpl::ComputeCovarianceValuesUsingDenseSVD() {
}
event_logger.AddEvent("ConvertToDenseMatrix");
- Eigen::JacobiSVD<Matrix> svd(dense_jacobian,
- Eigen::ComputeThinU | Eigen::ComputeThinV);
+ Eigen::BDCSVD<Matrix> svd(dense_jacobian,
+ Eigen::ComputeThinU | Eigen::ComputeThinV);
event_logger.AddEvent("SingularValueDecomposition");
@@ -838,7 +844,7 @@ bool CovarianceImpl::ComputeCovarianceValuesUsingEigenSparseQR() {
jacobian.rows.data(), jacobian.cols.data(), jacobian.values.data());
event_logger.AddEvent("ConvertToSparseMatrix");
- Eigen::SparseQR<EigenSparseMatrix, Eigen::COLAMDOrdering<int> >
+ Eigen::SparseQR<EigenSparseMatrix, Eigen::COLAMDOrdering<int>>
qr_solver(sparse_jacobian);
event_logger.AddEvent("QRDecomposition");
@@ -873,38 +879,35 @@ bool CovarianceImpl::ComputeCovarianceValuesUsingEigenSparseQR() {
// are equal.
const int num_cols = jacobian.num_cols;
const int num_threads = options_.num_threads;
- scoped_array<double> workspace(new double[num_threads * num_cols]);
-
-#pragma omp parallel for num_threads(num_threads) schedule(dynamic)
- for (int r = 0; r < num_cols; ++r) {
- const int row_begin = rows[r];
- const int row_end = rows[r + 1];
- if (row_end == row_begin) {
- continue;
- }
-
-# ifdef CERES_USE_OPENMP
- int thread_id = omp_get_thread_num();
-# else
- int thread_id = 0;
-# endif
-
- double* solution = workspace.get() + thread_id * num_cols;
- SolveRTRWithSparseRHS<int>(
- num_cols,
- qr_solver.matrixR().innerIndexPtr(),
- qr_solver.matrixR().outerIndexPtr(),
- &qr_solver.matrixR().data().value(0),
- inverse_permutation.indices().coeff(r),
- solution);
-
- // Assign the values of the computed covariance using the
- // inverse permutation used in the QR factorization.
- for (int idx = row_begin; idx < row_end; ++idx) {
- const int c = cols[idx];
- values[idx] = solution[inverse_permutation.indices().coeff(c)];
- }
- }
+ std::unique_ptr<double[]> workspace(new double[num_threads * num_cols]);
+
+ problem_->context()->EnsureMinimumThreads(num_threads);
+ ParallelFor(
+ problem_->context(),
+ 0,
+ num_cols,
+ num_threads,
+ [&](int thread_id, int r) {
+ const int row_begin = rows[r];
+ const int row_end = rows[r + 1];
+ if (row_end != row_begin) {
+ double* solution = workspace.get() + thread_id * num_cols;
+ SolveRTRWithSparseRHS<int>(
+ num_cols,
+ qr_solver.matrixR().innerIndexPtr(),
+ qr_solver.matrixR().outerIndexPtr(),
+ &qr_solver.matrixR().data().value(0),
+ inverse_permutation.indices().coeff(r),
+ solution);
+
+ // Assign the values of the computed covariance using the
+ // inverse permutation used in the QR factorization.
+ for (int idx = row_begin; idx < row_end; ++idx) {
+ const int c = cols[idx];
+ values[idx] = solution[inverse_permutation.indices().coeff(c)];
+ }
+ }
+ });
event_logger.AddEvent("Inverse");
diff --git a/extern/ceres/internal/ceres/covariance_impl.h b/extern/ceres/internal/ceres/covariance_impl.h
index a3f0761f57c..065e43c60fc 100644
--- a/extern/ceres/internal/ceres/covariance_impl.h
+++ b/extern/ceres/internal/ceres/covariance_impl.h
@@ -32,11 +32,11 @@
#define CERES_INTERNAL_COVARIANCE_IMPL_H_
#include <map>
+#include <memory>
#include <set>
#include <utility>
#include <vector>
#include "ceres/covariance.h"
-#include "ceres/internal/scoped_ptr.h"
#include "ceres/problem_impl.h"
#include "ceres/suitesparse.h"
@@ -52,7 +52,7 @@ class CovarianceImpl {
bool Compute(
const std::vector<std::pair<const double*,
- const double*> >& covariance_blocks,
+ const double*>>& covariance_blocks,
ProblemImpl* problem);
bool Compute(
@@ -72,7 +72,7 @@ class CovarianceImpl {
bool ComputeCovarianceSparsity(
const std::vector<std::pair<const double*,
- const double*> >& covariance_blocks,
+ const double*>>& covariance_blocks,
ProblemImpl* problem);
bool ComputeCovarianceValues();
@@ -92,7 +92,7 @@ class CovarianceImpl {
bool is_valid_;
std::map<const double*, int> parameter_block_to_row_index_;
std::set<const double*> constant_parameter_blocks_;
- scoped_ptr<CompressedRowSparseMatrix> covariance_matrix_;
+ std::unique_ptr<CompressedRowSparseMatrix> covariance_matrix_;
};
} // namespace internal
diff --git a/extern/ceres/internal/ceres/cxsparse.cc b/extern/ceres/internal/ceres/cxsparse.cc
new file mode 100644
index 00000000000..5a028773206
--- /dev/null
+++ b/extern/ceres/internal/ceres/cxsparse.cc
@@ -0,0 +1,284 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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.
+//
+// Author: strandmark@google.com (Petter Strandmark)
+
+// This include must come before any #ifndef check on Ceres compile options.
+#include "ceres/internal/port.h"
+
+#ifndef CERES_NO_CXSPARSE
+
+#include "ceres/cxsparse.h"
+
+#include <string>
+#include <vector>
+
+#include "ceres/compressed_col_sparse_matrix_utils.h"
+#include "ceres/compressed_row_sparse_matrix.h"
+#include "ceres/triplet_sparse_matrix.h"
+#include "glog/logging.h"
+
+namespace ceres {
+namespace internal {
+
+using std::vector;
+
+CXSparse::CXSparse() : scratch_(NULL), scratch_size_(0) {}
+
+CXSparse::~CXSparse() {
+ if (scratch_size_ > 0) {
+ cs_di_free(scratch_);
+ }
+}
+
+csn* CXSparse::Cholesky(cs_di* A, cs_dis* symbolic_factor) {
+ return cs_di_chol(A, symbolic_factor);
+}
+
+void CXSparse::Solve(cs_dis* symbolic_factor, csn* numeric_factor, double* b) {
+ // Make sure we have enough scratch space available.
+ const int num_cols = numeric_factor->L->n;
+ if (scratch_size_ < num_cols) {
+ if (scratch_size_ > 0) {
+ cs_di_free(scratch_);
+ }
+ scratch_ =
+ reinterpret_cast<CS_ENTRY*>(cs_di_malloc(num_cols, sizeof(CS_ENTRY)));
+ scratch_size_ = num_cols;
+ }
+
+ // When the Cholesky factor succeeded, these methods are
+ // guaranteed to succeeded as well. In the comments below, "x"
+ // refers to the scratch space.
+ //
+ // Set x = P * b.
+ CHECK(cs_di_ipvec(symbolic_factor->pinv, b, scratch_, num_cols));
+ // Set x = L \ x.
+ CHECK(cs_di_lsolve(numeric_factor->L, scratch_));
+ // Set x = L' \ x.
+ CHECK(cs_di_ltsolve(numeric_factor->L, scratch_));
+ // Set b = P' * x.
+ CHECK(cs_di_pvec(symbolic_factor->pinv, scratch_, b, num_cols));
+}
+
+bool CXSparse::SolveCholesky(cs_di* lhs, double* rhs_and_solution) {
+ return cs_cholsol(1, lhs, rhs_and_solution);
+}
+
+cs_dis* CXSparse::AnalyzeCholesky(cs_di* A) {
+ // order = 1 for Cholesky factor.
+ return cs_schol(1, A);
+}
+
+cs_dis* CXSparse::AnalyzeCholeskyWithNaturalOrdering(cs_di* A) {
+ // order = 0 for Natural ordering.
+ return cs_schol(0, A);
+}
+
+cs_dis* CXSparse::BlockAnalyzeCholesky(cs_di* A,
+ const vector<int>& row_blocks,
+ const vector<int>& col_blocks) {
+ const int num_row_blocks = row_blocks.size();
+ const int num_col_blocks = col_blocks.size();
+
+ vector<int> block_rows;
+ vector<int> block_cols;
+ CompressedColumnScalarMatrixToBlockMatrix(
+ A->i, A->p, row_blocks, col_blocks, &block_rows, &block_cols);
+ cs_di block_matrix;
+ block_matrix.m = num_row_blocks;
+ block_matrix.n = num_col_blocks;
+ block_matrix.nz = -1;
+ block_matrix.nzmax = block_rows.size();
+ block_matrix.p = &block_cols[0];
+ block_matrix.i = &block_rows[0];
+ block_matrix.x = NULL;
+
+ int* ordering = cs_amd(1, &block_matrix);
+ vector<int> block_ordering(num_row_blocks, -1);
+ std::copy(ordering, ordering + num_row_blocks, &block_ordering[0]);
+ cs_free(ordering);
+
+ vector<int> scalar_ordering;
+ BlockOrderingToScalarOrdering(row_blocks, block_ordering, &scalar_ordering);
+
+ cs_dis* symbolic_factor =
+ reinterpret_cast<cs_dis*>(cs_calloc(1, sizeof(cs_dis)));
+ symbolic_factor->pinv = cs_pinv(&scalar_ordering[0], A->n);
+ cs* permuted_A = cs_symperm(A, symbolic_factor->pinv, 0);
+
+ symbolic_factor->parent = cs_etree(permuted_A, 0);
+ int* postordering = cs_post(symbolic_factor->parent, A->n);
+ int* column_counts =
+ cs_counts(permuted_A, symbolic_factor->parent, postordering, 0);
+ cs_free(postordering);
+ cs_spfree(permuted_A);
+
+ symbolic_factor->cp = (int*)cs_malloc(A->n + 1, sizeof(int));
+ symbolic_factor->lnz = cs_cumsum(symbolic_factor->cp, column_counts, A->n);
+ symbolic_factor->unz = symbolic_factor->lnz;
+
+ cs_free(column_counts);
+
+ if (symbolic_factor->lnz < 0) {
+ cs_sfree(symbolic_factor);
+ symbolic_factor = NULL;
+ }
+
+ return symbolic_factor;
+}
+
+cs_di CXSparse::CreateSparseMatrixTransposeView(CompressedRowSparseMatrix* A) {
+ cs_di At;
+ At.m = A->num_cols();
+ At.n = A->num_rows();
+ At.nz = -1;
+ At.nzmax = A->num_nonzeros();
+ At.p = A->mutable_rows();
+ At.i = A->mutable_cols();
+ At.x = A->mutable_values();
+ return At;
+}
+
+cs_di* CXSparse::CreateSparseMatrix(TripletSparseMatrix* tsm) {
+ cs_di_sparse tsm_wrapper;
+ tsm_wrapper.nzmax = tsm->num_nonzeros();
+ tsm_wrapper.nz = tsm->num_nonzeros();
+ tsm_wrapper.m = tsm->num_rows();
+ tsm_wrapper.n = tsm->num_cols();
+ tsm_wrapper.p = tsm->mutable_cols();
+ tsm_wrapper.i = tsm->mutable_rows();
+ tsm_wrapper.x = tsm->mutable_values();
+
+ return cs_compress(&tsm_wrapper);
+}
+
+void CXSparse::ApproximateMinimumDegreeOrdering(cs_di* A, int* ordering) {
+ int* cs_ordering = cs_amd(1, A);
+ std::copy(cs_ordering, cs_ordering + A->m, ordering);
+ cs_free(cs_ordering);
+}
+
+cs_di* CXSparse::TransposeMatrix(cs_di* A) { return cs_di_transpose(A, 1); }
+
+cs_di* CXSparse::MatrixMatrixMultiply(cs_di* A, cs_di* B) {
+ return cs_di_multiply(A, B);
+}
+
+void CXSparse::Free(cs_di* sparse_matrix) { cs_di_spfree(sparse_matrix); }
+
+void CXSparse::Free(cs_dis* symbolic_factor) { cs_di_sfree(symbolic_factor); }
+
+void CXSparse::Free(csn* numeric_factor) { cs_di_nfree(numeric_factor); }
+
+std::unique_ptr<SparseCholesky> CXSparseCholesky::Create(
+ const OrderingType ordering_type) {
+ return std::unique_ptr<SparseCholesky>(new CXSparseCholesky(ordering_type));
+}
+
+CompressedRowSparseMatrix::StorageType CXSparseCholesky::StorageType() const {
+ return CompressedRowSparseMatrix::LOWER_TRIANGULAR;
+}
+
+CXSparseCholesky::CXSparseCholesky(const OrderingType ordering_type)
+ : ordering_type_(ordering_type),
+ symbolic_factor_(NULL),
+ numeric_factor_(NULL) {}
+
+CXSparseCholesky::~CXSparseCholesky() {
+ FreeSymbolicFactorization();
+ FreeNumericFactorization();
+}
+
+LinearSolverTerminationType CXSparseCholesky::Factorize(
+ CompressedRowSparseMatrix* lhs, std::string* message) {
+ CHECK_EQ(lhs->storage_type(), StorageType());
+ if (lhs == NULL) {
+ *message = "Failure: Input lhs is NULL.";
+ return LINEAR_SOLVER_FATAL_ERROR;
+ }
+
+ cs_di cs_lhs = cs_.CreateSparseMatrixTransposeView(lhs);
+
+ if (symbolic_factor_ == NULL) {
+ if (ordering_type_ == NATURAL) {
+ symbolic_factor_ = cs_.AnalyzeCholeskyWithNaturalOrdering(&cs_lhs);
+ } else {
+ if (!lhs->col_blocks().empty() && !(lhs->row_blocks().empty())) {
+ symbolic_factor_ = cs_.BlockAnalyzeCholesky(
+ &cs_lhs, lhs->col_blocks(), lhs->row_blocks());
+ } else {
+ symbolic_factor_ = cs_.AnalyzeCholesky(&cs_lhs);
+ }
+ }
+
+ if (symbolic_factor_ == NULL) {
+ *message = "CXSparse Failure : Symbolic factorization failed.";
+ return LINEAR_SOLVER_FATAL_ERROR;
+ }
+ }
+
+ FreeNumericFactorization();
+ numeric_factor_ = cs_.Cholesky(&cs_lhs, symbolic_factor_);
+ if (numeric_factor_ == NULL) {
+ *message = "CXSparse Failure : Numeric factorization failed.";
+ return LINEAR_SOLVER_FAILURE;
+ }
+
+ return LINEAR_SOLVER_SUCCESS;
+}
+
+LinearSolverTerminationType CXSparseCholesky::Solve(const double* rhs,
+ double* solution,
+ std::string* message) {
+ CHECK(numeric_factor_ != NULL)
+ << "Solve called without a call to Factorize first.";
+ const int num_cols = numeric_factor_->L->n;
+ memcpy(solution, rhs, num_cols * sizeof(*solution));
+ cs_.Solve(symbolic_factor_, numeric_factor_, solution);
+ return LINEAR_SOLVER_SUCCESS;
+}
+
+void CXSparseCholesky::FreeSymbolicFactorization() {
+ if (symbolic_factor_ != NULL) {
+ cs_.Free(symbolic_factor_);
+ symbolic_factor_ = NULL;
+ }
+}
+
+void CXSparseCholesky::FreeNumericFactorization() {
+ if (numeric_factor_ != NULL) {
+ cs_.Free(numeric_factor_);
+ numeric_factor_ = NULL;
+ }
+}
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_NO_CXSPARSE
diff --git a/extern/ceres/internal/ceres/cxsparse.h b/extern/ceres/internal/ceres/cxsparse.h
index 26dd1927a78..dc4740ceaee 100644
--- a/extern/ceres/internal/ceres/cxsparse.h
+++ b/extern/ceres/internal/ceres/cxsparse.h
@@ -36,7 +36,12 @@
#ifndef CERES_NO_CXSPARSE
+#include <memory>
+#include <string>
#include <vector>
+
+#include "ceres/linear_solver.h"
+#include "ceres/sparse_cholesky.h"
#include "cs.h"
namespace ceres {
@@ -47,21 +52,27 @@ class TripletSparseMatrix;
// This object provides access to solving linear systems using Cholesky
// factorization with a known symbolic factorization. This features does not
-// explicity exist in CXSparse. The methods in the class are nonstatic because
+// explicitly exist in CXSparse. The methods in the class are nonstatic because
// the class manages internal scratch space.
class CXSparse {
public:
CXSparse();
~CXSparse();
- // Solves a symmetric linear system A * x = b using Cholesky factorization.
- // A - The system matrix.
- // symbolic_factorization - The symbolic factorization of A. This is obtained
- // from AnalyzeCholesky.
- // b - The right hand size of the linear equation. This
- // array will also recieve the solution.
- // Returns false if Cholesky factorization of A fails.
- bool SolveCholesky(cs_di* A, cs_dis* symbolic_factorization, double* b);
+ // Solve the system lhs * solution = rhs in place by using an
+ // approximate minimum degree fill reducing ordering.
+ bool SolveCholesky(cs_di* lhs, double* rhs_and_solution);
+
+ // Solves a linear system given its symbolic and numeric factorization.
+ void Solve(cs_dis* symbolic_factor,
+ csn* numeric_factor,
+ double* rhs_and_solution);
+
+ // Compute the numeric Cholesky factorization of A, given its
+ // symbolic factorization.
+ //
+ // Caller owns the result.
+ csn* Cholesky(cs_di* A, cs_dis* symbolic_factor);
// Creates a sparse matrix from a compressed-column form. No memory is
// allocated or copied; the structure A is filled out with info from the
@@ -117,6 +128,7 @@ class CXSparse {
void Free(cs_di* sparse_matrix);
void Free(cs_dis* symbolic_factorization);
+ void Free(csn* numeric_factorization);
private:
// Cached scratch space
@@ -124,10 +136,37 @@ class CXSparse {
int scratch_size_;
};
+// An implementation of SparseCholesky interface using the CXSparse
+// library.
+class CXSparseCholesky : public SparseCholesky {
+ public:
+ // Factory
+ static std::unique_ptr<SparseCholesky> Create(OrderingType ordering_type);
+
+ // SparseCholesky interface.
+ virtual ~CXSparseCholesky();
+ CompressedRowSparseMatrix::StorageType StorageType() const final;
+ LinearSolverTerminationType Factorize(CompressedRowSparseMatrix* lhs,
+ std::string* message) final;
+ LinearSolverTerminationType Solve(const double* rhs,
+ double* solution,
+ std::string* message) final;
+
+ private:
+ CXSparseCholesky(const OrderingType ordering_type);
+ void FreeSymbolicFactorization();
+ void FreeNumericFactorization();
+
+ const OrderingType ordering_type_;
+ CXSparse cs_;
+ cs_dis* symbolic_factor_;
+ csn* numeric_factor_;
+};
+
} // namespace internal
} // namespace ceres
-#else // CERES_NO_CXSPARSE
+#else // CERES_NO_CXSPARSE
typedef void cs_dis;
diff --git a/extern/ceres/internal/ceres/dense_normal_cholesky_solver.cc b/extern/ceres/internal/ceres/dense_normal_cholesky_solver.cc
index b13cf3fc9f6..fe7d931a3fd 100644
--- a/extern/ceres/internal/ceres/dense_normal_cholesky_solver.cc
+++ b/extern/ceres/internal/ceres/dense_normal_cholesky_solver.cc
@@ -36,7 +36,6 @@
#include "ceres/blas.h"
#include "ceres/dense_sparse_matrix.h"
#include "ceres/internal/eigen.h"
-#include "ceres/internal/scoped_ptr.h"
#include "ceres/lapack.h"
#include "ceres/linear_solver.h"
#include "ceres/types.h"
diff --git a/extern/ceres/internal/ceres/dense_normal_cholesky_solver.h b/extern/ceres/internal/ceres/dense_normal_cholesky_solver.h
index 11287ebf675..976718e8615 100644
--- a/extern/ceres/internal/ceres/dense_normal_cholesky_solver.h
+++ b/extern/ceres/internal/ceres/dense_normal_cholesky_solver.h
@@ -35,7 +35,6 @@
#define CERES_INTERNAL_DENSE_NORMAL_CHOLESKY_SOLVER_H_
#include "ceres/linear_solver.h"
-#include "ceres/internal/macros.h"
namespace ceres {
namespace internal {
@@ -79,11 +78,11 @@ class DenseNormalCholeskySolver: public DenseSparseMatrixSolver {
explicit DenseNormalCholeskySolver(const LinearSolver::Options& options);
private:
- virtual LinearSolver::Summary SolveImpl(
+ LinearSolver::Summary SolveImpl(
DenseSparseMatrix* A,
const double* b,
const LinearSolver::PerSolveOptions& per_solve_options,
- double* x);
+ double* x) final;
LinearSolver::Summary SolveUsingLAPACK(
DenseSparseMatrix* A,
@@ -98,7 +97,6 @@ class DenseNormalCholeskySolver: public DenseSparseMatrixSolver {
double* x);
const LinearSolver::Options options_;
- CERES_DISALLOW_COPY_AND_ASSIGN(DenseNormalCholeskySolver);
};
} // namespace internal
diff --git a/extern/ceres/internal/ceres/dense_qr_solver.cc b/extern/ceres/internal/ceres/dense_qr_solver.cc
index e85fdfc0c68..161e9c67a00 100644
--- a/extern/ceres/internal/ceres/dense_qr_solver.cc
+++ b/extern/ceres/internal/ceres/dense_qr_solver.cc
@@ -30,12 +30,10 @@
#include "ceres/dense_qr_solver.h"
-
#include <cstddef>
#include "Eigen/Dense"
#include "ceres/dense_sparse_matrix.h"
#include "ceres/internal/eigen.h"
-#include "ceres/internal/scoped_ptr.h"
#include "ceres/lapack.h"
#include "ceres/linear_solver.h"
#include "ceres/types.h"
diff --git a/extern/ceres/internal/ceres/dense_qr_solver.h b/extern/ceres/internal/ceres/dense_qr_solver.h
index 1a6e0898c56..9ea959db68d 100644
--- a/extern/ceres/internal/ceres/dense_qr_solver.h
+++ b/extern/ceres/internal/ceres/dense_qr_solver.h
@@ -34,7 +34,6 @@
#include "ceres/linear_solver.h"
#include "ceres/internal/eigen.h"
-#include "ceres/internal/macros.h"
namespace ceres {
namespace internal {
@@ -84,11 +83,11 @@ class DenseQRSolver: public DenseSparseMatrixSolver {
explicit DenseQRSolver(const LinearSolver::Options& options);
private:
- virtual LinearSolver::Summary SolveImpl(
+ LinearSolver::Summary SolveImpl(
DenseSparseMatrix* A,
const double* b,
const LinearSolver::PerSolveOptions& per_solve_options,
- double* x);
+ double* x) final;
LinearSolver::Summary SolveUsingEigen(
DenseSparseMatrix* A,
@@ -106,7 +105,6 @@ class DenseQRSolver: public DenseSparseMatrixSolver {
ColMajorMatrix lhs_;
Vector rhs_;
Vector work_;
- CERES_DISALLOW_COPY_AND_ASSIGN(DenseQRSolver);
};
} // namespace internal
diff --git a/extern/ceres/internal/ceres/dense_sparse_matrix.cc b/extern/ceres/internal/ceres/dense_sparse_matrix.cc
index 19db867d4aa..72e08360dd0 100644
--- a/extern/ceres/internal/ceres/dense_sparse_matrix.cc
+++ b/extern/ceres/internal/ceres/dense_sparse_matrix.cc
@@ -166,7 +166,7 @@ ColMajorMatrixRef DenseSparseMatrix::mutable_matrix() {
void DenseSparseMatrix::ToTextFile(FILE* file) const {
- CHECK_NOTNULL(file);
+ CHECK(file != nullptr);
const int active_rows =
(has_diagonal_reserved_ && !has_diagonal_appended_)
? (m_.rows() - m_.cols())
diff --git a/extern/ceres/internal/ceres/dense_sparse_matrix.h b/extern/ceres/internal/ceres/dense_sparse_matrix.h
index b011bfddee7..6d3d504ea36 100644
--- a/extern/ceres/internal/ceres/dense_sparse_matrix.h
+++ b/extern/ceres/internal/ceres/dense_sparse_matrix.h
@@ -33,10 +33,8 @@
#ifndef CERES_INTERNAL_DENSE_SPARSE_MATRIX_H_
#define CERES_INTERNAL_DENSE_SPARSE_MATRIX_H_
-#include "ceres/sparse_matrix.h"
#include "ceres/internal/eigen.h"
-#include "ceres/internal/macros.h"
-#include "ceres/internal/scoped_ptr.h"
+#include "ceres/sparse_matrix.h"
#include "ceres/types.h"
namespace ceres {
@@ -57,18 +55,18 @@ class DenseSparseMatrix : public SparseMatrix {
virtual ~DenseSparseMatrix() {}
// SparseMatrix interface.
- virtual void SetZero();
- virtual void RightMultiply(const double* x, double* y) const;
- virtual void LeftMultiply(const double* x, double* y) const;
- virtual void SquaredColumnNorm(double* x) const;
- virtual void ScaleColumns(const double* scale);
- virtual void ToDenseMatrix(Matrix* dense_matrix) const;
- virtual void ToTextFile(FILE* file) const;
- virtual int num_rows() const;
- virtual int num_cols() const;
- virtual int num_nonzeros() const;
- virtual const double* values() const { return m_.data(); }
- virtual double* mutable_values() { return m_.data(); }
+ void SetZero() final;
+ void RightMultiply(const double* x, double* y) const final;
+ void LeftMultiply(const double* x, double* y) const final;
+ void SquaredColumnNorm(double* x) const final;
+ void ScaleColumns(const double* scale) final;
+ void ToDenseMatrix(Matrix* dense_matrix) const final;
+ void ToTextFile(FILE* file) const final;
+ int num_rows() const final;
+ int num_cols() const final;
+ int num_nonzeros() const final;
+ const double* values() const final { return m_.data(); }
+ double* mutable_values() final { return m_.data(); }
ConstColMajorMatrixRef matrix() const;
ColMajorMatrixRef mutable_matrix();
diff --git a/extern/ceres/internal/ceres/dogleg_strategy.cc b/extern/ceres/internal/ceres/dogleg_strategy.cc
index 839e1816338..ecc6b882338 100644
--- a/extern/ceres/internal/ceres/dogleg_strategy.cc
+++ b/extern/ceres/internal/ceres/dogleg_strategy.cc
@@ -30,7 +30,9 @@
#include "ceres/dogleg_strategy.h"
+#include <algorithm>
#include <cmath>
+
#include "Eigen/Dense"
#include "ceres/array_utils.h"
#include "ceres/internal/eigen.h"
@@ -64,7 +66,7 @@ DoglegStrategy::DoglegStrategy(const TrustRegionStrategy::Options& options)
dogleg_step_norm_(0.0),
reuse_(false),
dogleg_type_(options.dogleg_type) {
- CHECK_NOTNULL(linear_solver_);
+ CHECK(linear_solver_ != nullptr);
CHECK_GT(min_diagonal_, 0.0);
CHECK_LE(min_diagonal_, max_diagonal_);
CHECK_GT(max_radius_, 0.0);
@@ -79,9 +81,9 @@ TrustRegionStrategy::Summary DoglegStrategy::ComputeStep(
SparseMatrix* jacobian,
const double* residuals,
double* step) {
- CHECK_NOTNULL(jacobian);
- CHECK_NOTNULL(residuals);
- CHECK_NOTNULL(step);
+ CHECK(jacobian != nullptr);
+ CHECK(residuals != nullptr);
+ CHECK(step != nullptr);
const int n = jacobian->num_cols();
if (reuse_) {
@@ -469,7 +471,7 @@ double DoglegStrategy::EvaluateSubspaceModel(const Vector2d& x) const {
// In the failure case, another step should be taken, such as the traditional
// dogleg step.
bool DoglegStrategy::FindMinimumOnTrustRegionBoundary(Vector2d* minimum) const {
- CHECK_NOTNULL(minimum);
+ CHECK(minimum != nullptr);
// Return (0, 0) in all error cases.
minimum->setZero();
diff --git a/extern/ceres/internal/ceres/dogleg_strategy.h b/extern/ceres/internal/ceres/dogleg_strategy.h
index 046b9d824c9..1150940efd3 100644
--- a/extern/ceres/internal/ceres/dogleg_strategy.h
+++ b/extern/ceres/internal/ceres/dogleg_strategy.h
@@ -58,15 +58,14 @@ class DoglegStrategy : public TrustRegionStrategy {
virtual ~DoglegStrategy() {}
// TrustRegionStrategy interface
- virtual Summary ComputeStep(const PerSolveOptions& per_solve_options,
+ Summary ComputeStep(const PerSolveOptions& per_solve_options,
SparseMatrix* jacobian,
const double* residuals,
- double* step);
- virtual void StepAccepted(double step_quality);
- virtual void StepRejected(double step_quality);
- virtual void StepIsInvalid();
-
- virtual double Radius() const;
+ double* step) final;
+ void StepAccepted(double step_quality) final;
+ void StepRejected(double step_quality) final;
+ void StepIsInvalid();
+ double Radius() const final;
// These functions are predominantly for testing.
Vector gradient() const { return gradient_; }
@@ -103,7 +102,7 @@ class DoglegStrategy : public TrustRegionStrategy {
// mu is used to scale the diagonal matrix used to make the
// Gauss-Newton solve full rank. In each solve, the strategy starts
- // out with mu = min_mu, and tries values upto max_mu. If the user
+ // out with mu = min_mu, and tries values up to max_mu. If the user
// reports an invalid step, the value of mu_ is increased so that
// the next solve starts with a stronger regularization.
//
diff --git a/extern/ceres/internal/ceres/dynamic_compressed_row_jacobian_writer.cc b/extern/ceres/internal/ceres/dynamic_compressed_row_jacobian_writer.cc
index fd5d89e350a..1749449043e 100644
--- a/extern/ceres/internal/ceres/dynamic_compressed_row_jacobian_writer.cc
+++ b/extern/ceres/internal/ceres/dynamic_compressed_row_jacobian_writer.cc
@@ -28,9 +28,10 @@
//
// Author: richie.stebbing@gmail.com (Richard Stebbing)
-#include "ceres/compressed_row_jacobian_writer.h"
#include "ceres/dynamic_compressed_row_jacobian_writer.h"
+
#include "ceres/casts.h"
+#include "ceres/compressed_row_jacobian_writer.h"
#include "ceres/dynamic_compressed_row_sparse_matrix.h"
#include "ceres/parameter_block.h"
#include "ceres/program.h"
@@ -48,43 +49,28 @@ DynamicCompressedRowJacobianWriter::CreateEvaluatePreparers(int num_threads) {
}
SparseMatrix* DynamicCompressedRowJacobianWriter::CreateJacobian() const {
- // Initialize `jacobian` with zero number of `max_num_nonzeros`.
- const int num_residuals = program_->NumResiduals();
- const int num_effective_parameters = program_->NumEffectiveParameters();
-
DynamicCompressedRowSparseMatrix* jacobian =
- new DynamicCompressedRowSparseMatrix(num_residuals,
- num_effective_parameters,
- 0);
-
- vector<int>* row_blocks = jacobian->mutable_row_blocks();
- for (int i = 0; i < jacobian->num_rows(); ++i) {
- row_blocks->push_back(1);
- }
-
- vector<int>* col_blocks = jacobian->mutable_col_blocks();
- for (int i = 0; i < jacobian->num_cols(); ++i) {
- col_blocks->push_back(1);
- }
-
+ new DynamicCompressedRowSparseMatrix(program_->NumResiduals(),
+ program_->NumEffectiveParameters(),
+ 0 /* max_num_nonzeros */);
return jacobian;
}
void DynamicCompressedRowJacobianWriter::Write(int residual_id,
int residual_offset,
- double **jacobians,
+ double** jacobians,
SparseMatrix* base_jacobian) {
DynamicCompressedRowSparseMatrix* jacobian =
- down_cast<DynamicCompressedRowSparseMatrix*>(base_jacobian);
+ down_cast<DynamicCompressedRowSparseMatrix*>(base_jacobian);
// Get the `residual_block` of interest.
const ResidualBlock* residual_block =
program_->residual_blocks()[residual_id];
const int num_residuals = residual_block->NumResiduals();
- vector<pair<int, int> > evaluated_jacobian_blocks;
+ vector<pair<int, int>> evaluated_jacobian_blocks;
CompressedRowJacobianWriter::GetOrderedParameterBlocks(
- program_, residual_id, &evaluated_jacobian_blocks);
+ program_, residual_id, &evaluated_jacobian_blocks);
// `residual_offset` is the residual row in the global jacobian.
// Empty the jacobian rows.
@@ -97,16 +83,17 @@ void DynamicCompressedRowJacobianWriter::Write(int residual_id,
const int parameter_block_jacobian_index =
evaluated_jacobian_blocks[i].second;
const int parameter_block_size = parameter_block->LocalSize();
+ const double* parameter_jacobian =
+ jacobians[parameter_block_jacobian_index];
// For each parameter block only insert its non-zero entries.
for (int r = 0; r < num_residuals; ++r) {
- for (int c = 0; c < parameter_block_size; ++c) {
- const double& v = jacobians[parameter_block_jacobian_index][
- r * parameter_block_size + c];
+ for (int c = 0; c < parameter_block_size; ++c, ++parameter_jacobian) {
+ const double v = *parameter_jacobian;
// Only insert non-zero entries.
if (v != 0.0) {
jacobian->InsertEntry(
- residual_offset + r, parameter_block->delta_offset() + c, v);
+ residual_offset + r, parameter_block->delta_offset() + c, v);
}
}
}
diff --git a/extern/ceres/internal/ceres/dynamic_compressed_row_sparse_matrix.h b/extern/ceres/internal/ceres/dynamic_compressed_row_sparse_matrix.h
index cab860bddbd..ad41da7b15a 100644
--- a/extern/ceres/internal/ceres/dynamic_compressed_row_sparse_matrix.h
+++ b/extern/ceres/internal/ceres/dynamic_compressed_row_sparse_matrix.h
@@ -91,8 +91,8 @@ class DynamicCompressedRowSparseMatrix : public CompressedRowSparseMatrix {
void Finalize(int num_additional_elements);
private:
- std::vector<std::vector<int> > dynamic_cols_;
- std::vector<std::vector<double> > dynamic_values_;
+ std::vector<std::vector<int>> dynamic_cols_;
+ std::vector<std::vector<double>> dynamic_values_;
};
} // namespace internal
diff --git a/extern/ceres/internal/ceres/dynamic_sparse_normal_cholesky_solver.cc b/extern/ceres/internal/ceres/dynamic_sparse_normal_cholesky_solver.cc
new file mode 100644
index 00000000000..25d5417bca8
--- /dev/null
+++ b/extern/ceres/internal/ceres/dynamic_sparse_normal_cholesky_solver.cc
@@ -0,0 +1,286 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2017 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#include "ceres/dynamic_sparse_normal_cholesky_solver.h"
+
+#include <algorithm>
+#include <cstring>
+#include <ctime>
+#include <memory>
+#include <sstream>
+
+#include "Eigen/SparseCore"
+#include "ceres/compressed_row_sparse_matrix.h"
+#include "ceres/cxsparse.h"
+#include "ceres/internal/eigen.h"
+#include "ceres/linear_solver.h"
+#include "ceres/suitesparse.h"
+#include "ceres/triplet_sparse_matrix.h"
+#include "ceres/types.h"
+#include "ceres/wall_time.h"
+
+#ifdef CERES_USE_EIGEN_SPARSE
+#include "Eigen/SparseCholesky"
+#endif
+
+namespace ceres {
+namespace internal {
+
+DynamicSparseNormalCholeskySolver::DynamicSparseNormalCholeskySolver(
+ const LinearSolver::Options& options)
+ : options_(options) {}
+
+LinearSolver::Summary DynamicSparseNormalCholeskySolver::SolveImpl(
+ CompressedRowSparseMatrix* A,
+ const double* b,
+ const LinearSolver::PerSolveOptions& per_solve_options,
+ double* x) {
+ const int num_cols = A->num_cols();
+ VectorRef(x, num_cols).setZero();
+ A->LeftMultiply(b, x);
+
+ if (per_solve_options.D != nullptr) {
+ // Temporarily append a diagonal block to the A matrix, but undo
+ // it before returning the matrix to the user.
+ std::unique_ptr<CompressedRowSparseMatrix> regularizer;
+ if (!A->col_blocks().empty()) {
+ regularizer.reset(CompressedRowSparseMatrix::CreateBlockDiagonalMatrix(
+ per_solve_options.D, A->col_blocks()));
+ } else {
+ regularizer.reset(
+ new CompressedRowSparseMatrix(per_solve_options.D, num_cols));
+ }
+ A->AppendRows(*regularizer);
+ }
+
+ LinearSolver::Summary summary;
+ switch (options_.sparse_linear_algebra_library_type) {
+ case SUITE_SPARSE:
+ summary = SolveImplUsingSuiteSparse(A, x);
+ break;
+ case CX_SPARSE:
+ summary = SolveImplUsingCXSparse(A, x);
+ break;
+ case EIGEN_SPARSE:
+ summary = SolveImplUsingEigen(A, x);
+ break;
+ default:
+ LOG(FATAL) << "Unsupported sparse linear algebra library for "
+ << "dynamic sparsity: "
+ << SparseLinearAlgebraLibraryTypeToString(
+ options_.sparse_linear_algebra_library_type);
+ }
+
+ if (per_solve_options.D != nullptr) {
+ A->DeleteRows(num_cols);
+ }
+
+ return summary;
+}
+
+LinearSolver::Summary DynamicSparseNormalCholeskySolver::SolveImplUsingEigen(
+ CompressedRowSparseMatrix* A, double* rhs_and_solution) {
+#ifndef CERES_USE_EIGEN_SPARSE
+
+ LinearSolver::Summary summary;
+ summary.num_iterations = 0;
+ summary.termination_type = LINEAR_SOLVER_FATAL_ERROR;
+ summary.message =
+ "SPARSE_NORMAL_CHOLESKY cannot be used with EIGEN_SPARSE "
+ "because Ceres was not built with support for "
+ "Eigen's SimplicialLDLT decomposition. "
+ "This requires enabling building with -DEIGENSPARSE=ON.";
+ return summary;
+
+#else
+
+ EventLogger event_logger("DynamicSparseNormalCholeskySolver::Eigen::Solve");
+
+ Eigen::MappedSparseMatrix<double, Eigen::RowMajor> a(A->num_rows(),
+ A->num_cols(),
+ A->num_nonzeros(),
+ A->mutable_rows(),
+ A->mutable_cols(),
+ A->mutable_values());
+
+ Eigen::SparseMatrix<double> lhs = a.transpose() * a;
+ Eigen::SimplicialLDLT<Eigen::SparseMatrix<double>> solver;
+
+ LinearSolver::Summary summary;
+ summary.num_iterations = 1;
+ summary.termination_type = LINEAR_SOLVER_SUCCESS;
+ summary.message = "Success.";
+
+ solver.analyzePattern(lhs);
+ if (VLOG_IS_ON(2)) {
+ std::stringstream ss;
+ solver.dumpMemory(ss);
+ VLOG(2) << "Symbolic Analysis\n" << ss.str();
+ }
+
+ event_logger.AddEvent("Analyze");
+ if (solver.info() != Eigen::Success) {
+ summary.termination_type = LINEAR_SOLVER_FATAL_ERROR;
+ summary.message = "Eigen failure. Unable to find symbolic factorization.";
+ return summary;
+ }
+
+ solver.factorize(lhs);
+ event_logger.AddEvent("Factorize");
+ if (solver.info() != Eigen::Success) {
+ summary.termination_type = LINEAR_SOLVER_FAILURE;
+ summary.message = "Eigen failure. Unable to find numeric factorization.";
+ return summary;
+ }
+
+ const Vector rhs = VectorRef(rhs_and_solution, lhs.cols());
+ VectorRef(rhs_and_solution, lhs.cols()) = solver.solve(rhs);
+ event_logger.AddEvent("Solve");
+ if (solver.info() != Eigen::Success) {
+ summary.termination_type = LINEAR_SOLVER_FAILURE;
+ summary.message = "Eigen failure. Unable to do triangular solve.";
+ return summary;
+ }
+
+ return summary;
+#endif // CERES_USE_EIGEN_SPARSE
+}
+
+LinearSolver::Summary DynamicSparseNormalCholeskySolver::SolveImplUsingCXSparse(
+ CompressedRowSparseMatrix* A, double* rhs_and_solution) {
+#ifdef CERES_NO_CXSPARSE
+
+ LinearSolver::Summary summary;
+ summary.num_iterations = 0;
+ summary.termination_type = LINEAR_SOLVER_FATAL_ERROR;
+ summary.message =
+ "SPARSE_NORMAL_CHOLESKY cannot be used with CX_SPARSE "
+ "because Ceres was not built with support for CXSparse. "
+ "This requires enabling building with -DCXSPARSE=ON.";
+
+ return summary;
+
+#else
+ EventLogger event_logger(
+ "DynamicSparseNormalCholeskySolver::CXSparse::Solve");
+
+ LinearSolver::Summary summary;
+ summary.num_iterations = 1;
+ summary.termination_type = LINEAR_SOLVER_SUCCESS;
+ summary.message = "Success.";
+
+ CXSparse cxsparse;
+
+ // Wrap the augmented Jacobian in a compressed sparse column matrix.
+ cs_di a_transpose = cxsparse.CreateSparseMatrixTransposeView(A);
+
+ // Compute the normal equations. J'J delta = J'f and solve them
+ // using a sparse Cholesky factorization. Notice that when compared
+ // to SuiteSparse we have to explicitly compute the transpose of Jt,
+ // and then the normal equations before they can be
+ // factorized. CHOLMOD/SuiteSparse on the other hand can just work
+ // off of Jt to compute the Cholesky factorization of the normal
+ // equations.
+ cs_di* a = cxsparse.TransposeMatrix(&a_transpose);
+ cs_di* lhs = cxsparse.MatrixMatrixMultiply(&a_transpose, a);
+ cxsparse.Free(a);
+ event_logger.AddEvent("NormalEquations");
+
+ if (!cxsparse.SolveCholesky(lhs, rhs_and_solution)) {
+ summary.termination_type = LINEAR_SOLVER_FAILURE;
+ summary.message = "CXSparse::SolveCholesky failed";
+ }
+ event_logger.AddEvent("Solve");
+
+ cxsparse.Free(lhs);
+ event_logger.AddEvent("TearDown");
+ return summary;
+#endif
+}
+
+LinearSolver::Summary
+DynamicSparseNormalCholeskySolver::SolveImplUsingSuiteSparse(
+ CompressedRowSparseMatrix* A, double* rhs_and_solution) {
+#ifdef CERES_NO_SUITESPARSE
+
+ LinearSolver::Summary summary;
+ summary.num_iterations = 0;
+ summary.termination_type = LINEAR_SOLVER_FATAL_ERROR;
+ summary.message =
+ "SPARSE_NORMAL_CHOLESKY cannot be used with SUITE_SPARSE "
+ "because Ceres was not built with support for SuiteSparse. "
+ "This requires enabling building with -DSUITESPARSE=ON.";
+ return summary;
+
+#else
+
+ EventLogger event_logger(
+ "DynamicSparseNormalCholeskySolver::SuiteSparse::Solve");
+ LinearSolver::Summary summary;
+ summary.termination_type = LINEAR_SOLVER_SUCCESS;
+ summary.num_iterations = 1;
+ summary.message = "Success.";
+
+ SuiteSparse ss;
+ const int num_cols = A->num_cols();
+ cholmod_sparse lhs = ss.CreateSparseMatrixTransposeView(A);
+ event_logger.AddEvent("Setup");
+ cholmod_factor* factor = ss.AnalyzeCholesky(&lhs, &summary.message);
+ event_logger.AddEvent("Analysis");
+
+ if (factor == nullptr) {
+ summary.termination_type = LINEAR_SOLVER_FATAL_ERROR;
+ return summary;
+ }
+
+ summary.termination_type = ss.Cholesky(&lhs, factor, &summary.message);
+ if (summary.termination_type == LINEAR_SOLVER_SUCCESS) {
+ cholmod_dense cholmod_rhs =
+ ss.CreateDenseVectorView(rhs_and_solution, num_cols);
+ cholmod_dense* solution = ss.Solve(factor, &cholmod_rhs, &summary.message);
+ event_logger.AddEvent("Solve");
+ if (solution != nullptr) {
+ memcpy(
+ rhs_and_solution, solution->x, num_cols * sizeof(*rhs_and_solution));
+ ss.Free(solution);
+ } else {
+ summary.termination_type = LINEAR_SOLVER_FAILURE;
+ }
+ }
+
+ ss.Free(factor);
+ event_logger.AddEvent("Teardown");
+ return summary;
+
+#endif
+}
+
+} // namespace internal
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/dynamic_sparse_normal_cholesky_solver.h b/extern/ceres/internal/ceres/dynamic_sparse_normal_cholesky_solver.h
new file mode 100644
index 00000000000..4e31c7a8492
--- /dev/null
+++ b/extern/ceres/internal/ceres/dynamic_sparse_normal_cholesky_solver.h
@@ -0,0 +1,86 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2017 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// A solver for sparse linear least squares problem based on solving
+// the normal equations via a sparse cholesky factorization.
+
+#ifndef CERES_INTERNAL_DYNAMIC_SPARSE_NORMAL_CHOLESKY_SOLVER_H_
+#define CERES_INTERNAL_DYNAMIC_SPARSE_NORMAL_CHOLESKY_SOLVER_H_
+
+// This include must come before any #ifndef check on Ceres compile options.
+#include "ceres/internal/port.h"
+
+#include "ceres/linear_solver.h"
+
+namespace ceres {
+namespace internal {
+
+class CompressedRowSparseMatrix;
+
+// A variant of SparseNormalCholeskySolver in the case where matrix
+// sparsity is not constant across calls to Solve. This means that
+// there is no benefit to symbolically factorizing the matrix and
+// caching this factorization.
+//
+// TODO(alex): Add support for Accelerate sparse solvers:
+// https://github.com/ceres-solver/ceres-solver/issues/397
+class DynamicSparseNormalCholeskySolver
+ : public CompressedRowSparseMatrixSolver {
+ public:
+ explicit DynamicSparseNormalCholeskySolver(
+ const LinearSolver::Options& options);
+ virtual ~DynamicSparseNormalCholeskySolver() {}
+
+ private:
+ LinearSolver::Summary SolveImpl(
+ CompressedRowSparseMatrix* A,
+ const double* b,
+ const LinearSolver::PerSolveOptions& options,
+ double* x) final;
+
+ LinearSolver::Summary SolveImplUsingSuiteSparse(
+ CompressedRowSparseMatrix* A,
+ double* rhs_and_solution);
+
+ LinearSolver::Summary SolveImplUsingCXSparse(
+ CompressedRowSparseMatrix* A,
+ double* rhs_and_solution);
+
+ LinearSolver::Summary SolveImplUsingEigen(
+ CompressedRowSparseMatrix* A,
+ double* rhs_and_solution);
+
+ const LinearSolver::Options options_;
+};
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_DYNAMIC_SPARSE_NORMAL_CHOLESKY_SOLVER_H_
diff --git a/extern/ceres/internal/ceres/eigensparse.cc b/extern/ceres/internal/ceres/eigensparse.cc
new file mode 100644
index 00000000000..22ed2c43b5d
--- /dev/null
+++ b/extern/ceres/internal/ceres/eigensparse.cc
@@ -0,0 +1,190 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2017 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#include "ceres/eigensparse.h"
+
+#ifdef CERES_USE_EIGEN_SPARSE
+
+#include <sstream>
+
+#include "Eigen/SparseCholesky"
+#include "Eigen/SparseCore"
+#include "ceres/compressed_row_sparse_matrix.h"
+#include "ceres/linear_solver.h"
+
+namespace ceres {
+namespace internal {
+
+// TODO(sameeragarwal): Use enable_if to clean up the implementations
+// for when Scalar == double.
+template <typename Solver>
+class EigenSparseCholeskyTemplate : public SparseCholesky {
+ public:
+ EigenSparseCholeskyTemplate() : analyzed_(false) {}
+ virtual ~EigenSparseCholeskyTemplate() {}
+ CompressedRowSparseMatrix::StorageType StorageType() const final {
+ return CompressedRowSparseMatrix::LOWER_TRIANGULAR;
+ }
+
+ LinearSolverTerminationType Factorize(
+ const Eigen::SparseMatrix<typename Solver::Scalar>& lhs,
+ std::string* message) {
+ if (!analyzed_) {
+ solver_.analyzePattern(lhs);
+
+ if (VLOG_IS_ON(2)) {
+ std::stringstream ss;
+ solver_.dumpMemory(ss);
+ VLOG(2) << "Symbolic Analysis\n" << ss.str();
+ }
+
+ if (solver_.info() != Eigen::Success) {
+ *message = "Eigen failure. Unable to find symbolic factorization.";
+ return LINEAR_SOLVER_FATAL_ERROR;
+ }
+
+ analyzed_ = true;
+ }
+
+ solver_.factorize(lhs);
+ if (solver_.info() != Eigen::Success) {
+ *message = "Eigen failure. Unable to find numeric factorization.";
+ return LINEAR_SOLVER_FAILURE;
+ }
+ return LINEAR_SOLVER_SUCCESS;
+ }
+
+ LinearSolverTerminationType Solve(const double* rhs_ptr,
+ double* solution_ptr,
+ std::string* message) {
+ CHECK(analyzed_) << "Solve called without a call to Factorize first.";
+
+ scalar_rhs_ = ConstVectorRef(rhs_ptr, solver_.cols())
+ .template cast<typename Solver::Scalar>();
+
+ // The two casts are needed if the Scalar in this class is not
+ // double. For code simplicity we are going to assume that Eigen
+ // is smart enough to figure out that casting a double Vector to a
+ // double Vector is a straight copy. If this turns into a
+ // performance bottleneck (unlikely), we can revisit this.
+ scalar_solution_ = solver_.solve(scalar_rhs_);
+ VectorRef(solution_ptr, solver_.cols()) =
+ scalar_solution_.template cast<double>();
+
+ if (solver_.info() != Eigen::Success) {
+ *message = "Eigen failure. Unable to do triangular solve.";
+ return LINEAR_SOLVER_FAILURE;
+ }
+ return LINEAR_SOLVER_SUCCESS;
+ }
+
+ LinearSolverTerminationType Factorize(CompressedRowSparseMatrix* lhs,
+ std::string* message) final {
+ CHECK_EQ(lhs->storage_type(), StorageType());
+
+ typename Solver::Scalar* values_ptr = NULL;
+ if (std::is_same<typename Solver::Scalar, double>::value) {
+ values_ptr =
+ reinterpret_cast<typename Solver::Scalar*>(lhs->mutable_values());
+ } else {
+ // In the case where the scalar used in this class is not
+ // double. In that case, make a copy of the values array in the
+ // CompressedRowSparseMatrix and cast it to Scalar along the way.
+ values_ = ConstVectorRef(lhs->values(), lhs->num_nonzeros())
+ .cast<typename Solver::Scalar>();
+ values_ptr = values_.data();
+ }
+
+ Eigen::MappedSparseMatrix<typename Solver::Scalar, Eigen::ColMajor>
+ eigen_lhs(lhs->num_rows(),
+ lhs->num_rows(),
+ lhs->num_nonzeros(),
+ lhs->mutable_rows(),
+ lhs->mutable_cols(),
+ values_ptr);
+ return Factorize(eigen_lhs, message);
+ }
+
+ private:
+ Eigen::Matrix<typename Solver::Scalar, Eigen::Dynamic, 1> values_,
+ scalar_rhs_, scalar_solution_;
+ bool analyzed_;
+ Solver solver_;
+};
+
+std::unique_ptr<SparseCholesky> EigenSparseCholesky::Create(
+ const OrderingType ordering_type) {
+ std::unique_ptr<SparseCholesky> sparse_cholesky;
+
+ typedef Eigen::SimplicialLDLT<Eigen::SparseMatrix<double>,
+ Eigen::Upper,
+ Eigen::AMDOrdering<int>>
+ WithAMDOrdering;
+ typedef Eigen::SimplicialLDLT<Eigen::SparseMatrix<double>,
+ Eigen::Upper,
+ Eigen::NaturalOrdering<int>>
+ WithNaturalOrdering;
+ if (ordering_type == AMD) {
+ sparse_cholesky.reset(new EigenSparseCholeskyTemplate<WithAMDOrdering>());
+ } else {
+ sparse_cholesky.reset(
+ new EigenSparseCholeskyTemplate<WithNaturalOrdering>());
+ }
+ return sparse_cholesky;
+}
+
+EigenSparseCholesky::~EigenSparseCholesky() {}
+
+std::unique_ptr<SparseCholesky> FloatEigenSparseCholesky::Create(
+ const OrderingType ordering_type) {
+ std::unique_ptr<SparseCholesky> sparse_cholesky;
+ typedef Eigen::SimplicialLDLT<Eigen::SparseMatrix<float>,
+ Eigen::Upper,
+ Eigen::AMDOrdering<int>>
+ WithAMDOrdering;
+ typedef Eigen::SimplicialLDLT<Eigen::SparseMatrix<float>,
+ Eigen::Upper,
+ Eigen::NaturalOrdering<int>>
+ WithNaturalOrdering;
+ if (ordering_type == AMD) {
+ sparse_cholesky.reset(new EigenSparseCholeskyTemplate<WithAMDOrdering>());
+ } else {
+ sparse_cholesky.reset(
+ new EigenSparseCholeskyTemplate<WithNaturalOrdering>());
+ }
+ return sparse_cholesky;
+}
+
+FloatEigenSparseCholesky::~FloatEigenSparseCholesky() {}
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_USE_EIGEN_SPARSE
diff --git a/extern/ceres/internal/ceres/eigensparse.h b/extern/ceres/internal/ceres/eigensparse.h
new file mode 100644
index 00000000000..2e6c6f01abb
--- /dev/null
+++ b/extern/ceres/internal/ceres/eigensparse.h
@@ -0,0 +1,90 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2017 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// A simple C++ interface to the Eigen's Sparse Cholesky routines.
+
+#ifndef CERES_INTERNAL_EIGENSPARSE_H_
+#define CERES_INTERNAL_EIGENSPARSE_H_
+
+// This include must come before any #ifndef check on Ceres compile options.
+#include "ceres/internal/port.h"
+
+#ifdef CERES_USE_EIGEN_SPARSE
+
+#include <memory>
+#include <string>
+
+#include "Eigen/SparseCore"
+#include "ceres/linear_solver.h"
+#include "ceres/sparse_cholesky.h"
+
+namespace ceres {
+namespace internal {
+
+class EigenSparseCholesky : public SparseCholesky {
+ public:
+ // Factory
+ static std::unique_ptr<SparseCholesky> Create(
+ const OrderingType ordering_type);
+
+ // SparseCholesky interface.
+ virtual ~EigenSparseCholesky();
+ virtual LinearSolverTerminationType Factorize(
+ CompressedRowSparseMatrix* lhs, std::string* message) = 0;
+ virtual CompressedRowSparseMatrix::StorageType StorageType() const = 0;
+ virtual LinearSolverTerminationType Solve(const double* rhs,
+ double* solution,
+ std::string* message) = 0;
+};
+
+// Even though the input is double precision linear system, this class
+// solves it by computing a single precision Cholesky factorization.
+class FloatEigenSparseCholesky : public SparseCholesky {
+ public:
+ // Factory
+ static std::unique_ptr<SparseCholesky> Create(
+ const OrderingType ordering_type);
+
+ // SparseCholesky interface.
+ virtual ~FloatEigenSparseCholesky();
+ virtual LinearSolverTerminationType Factorize(
+ CompressedRowSparseMatrix* lhs, std::string* message) = 0;
+ virtual CompressedRowSparseMatrix::StorageType StorageType() const = 0;
+ virtual LinearSolverTerminationType Solve(const double* rhs,
+ double* solution,
+ std::string* message) = 0;
+};
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_USE_EIGEN_SPARSE
+
+#endif // CERES_INTERNAL_EIGENSPARSE_H_
diff --git a/extern/ceres/internal/ceres/evaluator.cc b/extern/ceres/internal/ceres/evaluator.cc
index baba9afa11b..8387983553d 100644
--- a/extern/ceres/internal/ceres/evaluator.cc
+++ b/extern/ceres/internal/ceres/evaluator.cc
@@ -51,6 +51,8 @@ Evaluator::~Evaluator() {}
Evaluator* Evaluator::Create(const Evaluator::Options& options,
Program* program,
std::string* error) {
+ CHECK(options.context != NULL);
+
switch (options.linear_solver_type) {
case DENSE_QR:
case DENSE_NORMAL_CHOLESKY:
@@ -71,9 +73,9 @@ Evaluator* Evaluator::Create(const Evaluator::Options& options,
DynamicCompressedRowJacobianFinalizer>(
options, program);
} else {
- return new ProgramEvaluator<ScratchEvaluatePreparer,
- CompressedRowJacobianWriter>(options,
- program);
+ return new ProgramEvaluator<BlockEvaluatePreparer,
+ BlockJacobianWriter>(options,
+ program);
}
default:
diff --git a/extern/ceres/internal/ceres/evaluator.h b/extern/ceres/internal/ceres/evaluator.h
index fea307919d0..b820958ed77 100644
--- a/extern/ceres/internal/ceres/evaluator.h
+++ b/extern/ceres/internal/ceres/evaluator.h
@@ -36,6 +36,7 @@
#include <string>
#include <vector>
+#include "ceres/context_impl.h"
#include "ceres/execution_summary.h"
#include "ceres/internal/port.h"
#include "ceres/types.h"
@@ -43,6 +44,7 @@
namespace ceres {
struct CRSMatrix;
+class EvaluationCallback;
namespace internal {
@@ -58,47 +60,18 @@ class Evaluator {
virtual ~Evaluator();
struct Options {
- Options()
- : num_threads(1),
- num_eliminate_blocks(-1),
- linear_solver_type(DENSE_QR),
- dynamic_sparsity(false) {}
-
- int num_threads;
- int num_eliminate_blocks;
- LinearSolverType linear_solver_type;
- bool dynamic_sparsity;
+ int num_threads = 1;
+ int num_eliminate_blocks = -1;
+ LinearSolverType linear_solver_type = DENSE_QR;
+ bool dynamic_sparsity = false;
+ ContextImpl* context = nullptr;
+ EvaluationCallback* evaluation_callback = nullptr;
};
static Evaluator* Create(const Options& options,
Program* program,
std::string* error);
- // This is used for computing the cost, residual and Jacobian for
- // returning to the user. For actually solving the optimization
- // problem, the optimization algorithm uses the ProgramEvaluator
- // objects directly.
- //
- // The residual, gradients and jacobian pointers can be NULL, in
- // which case they will not be evaluated. cost cannot be NULL.
- //
- // The parallelism of the evaluator is controlled by num_threads; it
- // should be at least 1.
- //
- // Note: That this function does not take a parameter vector as
- // input. The parameter blocks are evaluated on the values contained
- // in the arrays pointed to by their user_state pointers.
- //
- // Also worth noting is that this function mutates program by
- // calling Program::SetParameterOffsetsAndIndex() on it so that an
- // evaluator object can be constructed.
- static bool Evaluate(Program* program,
- int num_threads,
- double* cost,
- std::vector<double>* residuals,
- std::vector<double>* gradient,
- CRSMatrix* jacobian);
-
// Build and return a sparse matrix for storing and working with the Jacobian
// of the objective function. The jacobian has dimensions
// NumEffectiveParameters() by NumParameters(), and is typically extremely
@@ -117,16 +90,14 @@ class Evaluator {
// Schur complement based methods.
virtual SparseMatrix* CreateJacobian() const = 0;
-
// Options struct to control Evaluator::Evaluate;
struct EvaluateOptions {
- EvaluateOptions()
- : apply_loss_function(true) {
- }
-
// If false, the loss function correction is not applied to the
// residual blocks.
- bool apply_loss_function;
+ bool apply_loss_function = true;
+
+ // If false, this evaluation point is the same as the last one.
+ bool new_evaluation_point = true;
};
// Evaluate the cost function for the given state. Returns the cost,
@@ -190,12 +161,8 @@ class Evaluator {
// that the base class implementation does not have to worry about
// life time issues. Further, these calls are not expected to be
// frequent or performance sensitive.
- virtual std::map<std::string, int> CallStatistics() const {
- return std::map<std::string, int>();
- }
-
- virtual std::map<std::string, double> TimeStatistics() const {
- return std::map<std::string, double>();
+ virtual std::map<std::string, CallStatistics> Statistics() const {
+ return std::map<std::string, CallStatistics>();
}
};
diff --git a/extern/ceres/internal/ceres/execution_summary.h b/extern/ceres/internal/ceres/execution_summary.h
index aa9929d8974..17fd882af03 100644
--- a/extern/ceres/internal/ceres/execution_summary.h
+++ b/extern/ceres/internal/ceres/execution_summary.h
@@ -32,47 +32,45 @@
#define CERES_INTERNAL_EXECUTION_SUMMARY_H_
#include <map>
+#include <mutex>
#include <string>
#include "ceres/internal/port.h"
#include "ceres/wall_time.h"
-#include "ceres/mutex.h"
namespace ceres {
namespace internal {
-// Struct used by various objects to report statistics and other
-// information about their execution. e.g., ExecutionSummary::times
-// can be used for reporting times associated with various activities.
+struct CallStatistics {
+ CallStatistics() : time(0.), calls(0) {}
+ double time;
+ int calls;
+};
+
+// Struct used by various objects to report statistics about their
+// execution.
class ExecutionSummary {
public:
void IncrementTimeBy(const std::string& name, const double value) {
- CeresMutexLock l(&times_mutex_);
- times_[name] += value;
+ std::lock_guard<std::mutex> l(mutex_);
+ CallStatistics& call_stats = statistics_[name];
+ call_stats.time += value;
+ ++call_stats.calls;
}
- void IncrementCall(const std::string& name) {
- CeresMutexLock l(&calls_mutex_);
- calls_[name] += 1;
+ const std::map<std::string, CallStatistics>& statistics() const {
+ return statistics_;
}
- const std::map<std::string, double>& times() const { return times_; }
- const std::map<std::string, int>& calls() const { return calls_; }
-
private:
- Mutex times_mutex_;
- std::map<std::string, double> times_;
-
- Mutex calls_mutex_;
- std::map<std::string, int> calls_;
+ std::mutex mutex_;
+ std::map<std::string, CallStatistics> statistics_;
};
class ScopedExecutionTimer {
public:
ScopedExecutionTimer(const std::string& name, ExecutionSummary* summary)
- : start_time_(WallTimeInSeconds()),
- name_(name),
- summary_(summary) {}
+ : start_time_(WallTimeInSeconds()), name_(name), summary_(summary) {}
~ScopedExecutionTimer() {
summary_->IncrementTimeBy(name_, WallTimeInSeconds() - start_time_);
diff --git a/extern/ceres/internal/ceres/float_cxsparse.cc b/extern/ceres/internal/ceres/float_cxsparse.cc
new file mode 100644
index 00000000000..6c688303444
--- /dev/null
+++ b/extern/ceres/internal/ceres/float_cxsparse.cc
@@ -0,0 +1,47 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2018 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#include "ceres/float_cxsparse.h"
+
+#if !defined(CERES_NO_CXSPARSE)
+
+namespace ceres {
+namespace internal {
+
+std::unique_ptr<SparseCholesky> FloatCXSparseCholesky::Create(
+ OrderingType ordering_type) {
+ LOG(FATAL) << "FloatCXSparseCholesky is not available.";
+ return std::unique_ptr<SparseCholesky>();
+}
+
+} // namespace internal
+} // namespace ceres
+
+#endif // !defined(CERES_NO_CXSPARSE)
diff --git a/extern/ceres/internal/ceres/float_cxsparse.h b/extern/ceres/internal/ceres/float_cxsparse.h
new file mode 100644
index 00000000000..57fc5e4c010
--- /dev/null
+++ b/extern/ceres/internal/ceres/float_cxsparse.h
@@ -0,0 +1,58 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2018 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#ifndef CERES_INTERNAL_FLOAT_CXSPARSE_H_
+#define CERES_INTERNAL_FLOAT_CXSPARSE_H_
+
+// This include must come before any #ifndef check on Ceres compile options.
+#include "ceres/internal/port.h"
+
+#if !defined(CERES_NO_CXSPARSE)
+
+#include <memory>
+#include "ceres/sparse_cholesky.h"
+
+namespace ceres {
+namespace internal {
+
+// Fake implementation of a single precision Sparse Cholesky using
+// CXSparse.
+class FloatCXSparseCholesky : public SparseCholesky {
+ public:
+ static std::unique_ptr<SparseCholesky> Create(
+ OrderingType ordering_type);
+};
+
+} // namespace internal
+} // namespace ceres
+
+#endif // !defined(CERES_NO_CXSPARSE)
+
+#endif // CERES_INTERNAL_FLOAT_CXSPARSE_H_
diff --git a/extern/ceres/internal/ceres/float_suitesparse.cc b/extern/ceres/internal/ceres/float_suitesparse.cc
new file mode 100644
index 00000000000..03604572b5c
--- /dev/null
+++ b/extern/ceres/internal/ceres/float_suitesparse.cc
@@ -0,0 +1,47 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2018 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#include "ceres/float_suitesparse.h"
+
+#if !defined(CERES_NO_SUITESPARSE)
+
+namespace ceres {
+namespace internal {
+
+std::unique_ptr<SparseCholesky> FloatSuiteSparseCholesky::Create(
+ OrderingType ordering_type) {
+ LOG(FATAL) << "FloatSuiteSparseCholesky is not available.";
+ return std::unique_ptr<SparseCholesky>();
+}
+
+} // namespace internal
+} // namespace ceres
+
+#endif // !defined(CERES_NO_SUITESPARSE)
diff --git a/extern/ceres/internal/ceres/float_suitesparse.h b/extern/ceres/internal/ceres/float_suitesparse.h
new file mode 100644
index 00000000000..ac4d4090922
--- /dev/null
+++ b/extern/ceres/internal/ceres/float_suitesparse.h
@@ -0,0 +1,58 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2018 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#ifndef CERES_INTERNAL_FLOAT_SUITESPARSE_H_
+#define CERES_INTERNAL_FLOAT_SUITESPARSE_H_
+
+// This include must come before any #ifndef check on Ceres compile options.
+#include "ceres/internal/port.h"
+
+#include <memory>
+#include "ceres/sparse_cholesky.h"
+
+#if !defined(CERES_NO_SUITESPARSE)
+
+namespace ceres {
+namespace internal {
+
+// Fake implementation of a single precision Sparse Cholesky using
+// SuiteSparse.
+class FloatSuiteSparseCholesky : public SparseCholesky {
+ public:
+ static std::unique_ptr<SparseCholesky> Create(
+ OrderingType ordering_type);
+};
+
+} // namespace internal
+} // namespace ceres
+
+#endif // !defined(CERES_NO_SUITESPARSE)
+
+#endif // CERES_INTERNAL_FLOAT_SUITESPARSE_H_
diff --git a/extern/ceres/internal/ceres/integral_types.h b/extern/ceres/internal/ceres/function_sample.cc
index 98a746f13ff..2fd3dbdf7c5 100644
--- a/extern/ceres/internal/ceres/integral_types.h
+++ b/extern/ceres/internal/ceres/function_sample.cc
@@ -26,66 +26,48 @@
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
-// Author: keir@google.com (Keir Mierle)
-//
-// Portable typedefs for various fixed-size integers. Uses template
-// metaprogramming instead of fragile compiler defines.
+// Author: sameeragarwal@google.com (Sameer Agarwal)
-#ifndef CERES_INTERNAL_INTEGRAL_TYPES_H_
-#define CERES_INTERNAL_INTEGRAL_TYPES_H_
+#include "ceres/function_sample.h"
+#include "ceres/stringprintf.h"
namespace ceres {
namespace internal {
-// Compile time ternary on types.
-template<bool kCondition, typename kTrueType, typename kFalseType>
-struct Ternary {
- typedef kTrueType type;
-};
-template<typename kTrueType, typename kFalseType>
-struct Ternary<false, kTrueType, kFalseType> {
- typedef kFalseType type;
-};
-
-#define CERES_INTSIZE(TYPE) \
- typename Ternary<sizeof(TYPE) * 8 == kBits, TYPE,
-
-template<int kBits>
-struct Integer {
- typedef
- CERES_INTSIZE(char)
- CERES_INTSIZE(short)
- CERES_INTSIZE(int)
- CERES_INTSIZE(long int)
- CERES_INTSIZE(long long)
- void>::type >::type >::type >::type >::type
- type;
-};
+FunctionSample::FunctionSample()
+ : x(0.0),
+ vector_x_is_valid(false),
+ value(0.0),
+ value_is_valid(false),
+ vector_gradient_is_valid(false),
+ gradient(0.0),
+ gradient_is_valid(false) {}
-template<int kBits>
-struct UnsignedInteger {
- typedef
- CERES_INTSIZE(unsigned char)
- CERES_INTSIZE(unsigned short)
- CERES_INTSIZE(unsigned int)
- CERES_INTSIZE(unsigned long int)
- CERES_INTSIZE(unsigned long long)
- void>::type >::type >::type >::type >::type
- type;
-};
+FunctionSample::FunctionSample(const double x, const double value)
+ : x(x),
+ vector_x_is_valid(false),
+ value(value),
+ value_is_valid(true),
+ vector_gradient_is_valid(false),
+ gradient(0.0),
+ gradient_is_valid(false) {}
-#undef CERES_INTSIZE
+FunctionSample::FunctionSample(const double x,
+ const double value,
+ const double gradient)
+ : x(x),
+ vector_x_is_valid(false),
+ value(value),
+ value_is_valid(true),
+ vector_gradient_is_valid(false),
+ gradient(gradient),
+ gradient_is_valid(true) {}
-typedef Integer< 8>::type int8;
-typedef Integer<32>::type int32;
-typedef Integer<64>::type int64;
-
-typedef UnsignedInteger< 8>::type uint8;
-typedef UnsignedInteger<16>::type uint16;
-typedef UnsignedInteger<32>::type uint32;
-typedef UnsignedInteger<64>::type uint64;
+std::string FunctionSample::ToDebugString() const {
+ return StringPrintf("[x: %.8e, value: %.8e, gradient: %.8e, "
+ "value_is_valid: %d, gradient_is_valid: %d]",
+ x, value, gradient, value_is_valid, gradient_is_valid);
+}
} // namespace internal
} // namespace ceres
-
-#endif // CERES_INTERNAL_INTEGRAL_TYPES_H_
diff --git a/extern/ceres/internal/ceres/function_sample.h b/extern/ceres/internal/ceres/function_sample.h
new file mode 100644
index 00000000000..df79aef944f
--- /dev/null
+++ b/extern/ceres/internal/ceres/function_sample.h
@@ -0,0 +1,94 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2017 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#ifndef CERES_INTERNAL_FUNCTION_SAMPLE_H_
+#define CERES_INTERNAL_FUNCTION_SAMPLE_H_
+
+#include <string>
+#include "ceres/internal/eigen.h"
+
+namespace ceres {
+namespace internal {
+
+// FunctionSample is used by the line search routines to store and
+// communicate the value and (optionally) the gradient of the function
+// being minimized.
+//
+// Since line search as the name implies happens along a certain
+// line/direction. FunctionSample contains the information in two
+// ways. Information in the ambient space and information along the
+// direction of search.
+struct FunctionSample {
+ FunctionSample();
+ FunctionSample(double x, double value);
+ FunctionSample(double x, double value, double gradient);
+
+ std::string ToDebugString() const;
+
+ // x is the location of the sample along the search direction.
+ double x;
+
+ // Let p be a point and d be the search direction then
+ //
+ // vector_x = p + x * d;
+ Vector vector_x;
+ // True if vector_x has been assigned a valid value.
+ bool vector_x_is_valid;
+
+ // value = f(vector_x)
+ double value;
+ // True of the evaluation was successful and value is a finite
+ // number.
+ bool value_is_valid;
+
+ // vector_gradient = Df(vector_position);
+ //
+ // D is the derivative operator.
+ Vector vector_gradient;
+ // True if the vector gradient was evaluated and the evaluation was
+ // successful (the value is a finite number).
+ bool vector_gradient_is_valid;
+
+ // gradient = d.transpose() * vector_gradient
+ //
+ // where d is the search direction.
+ double gradient;
+ // True if the evaluation of the gradient was sucessful and the
+ // value is a finite number.
+ bool gradient_is_valid;
+};
+
+
+
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_FUNCTION_SAMPLE_H_
diff --git a/extern/ceres/internal/ceres/generate_template_specializations.py b/extern/ceres/internal/ceres/generate_template_specializations.py
new file mode 100644
index 00000000000..5e91f8d2b6a
--- /dev/null
+++ b/extern/ceres/internal/ceres/generate_template_specializations.py
@@ -0,0 +1,246 @@
+# Ceres Solver - A fast non-linear least squares minimizer
+# Copyright 2015 Google Inc. All rights reserved.
+# http://ceres-solver.org/
+#
+# 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.
+#
+# Author: sameeragarwal@google.com (Sameer Agarwal)
+#
+# Script for explicitly generating template specialization of the
+# SchurEliminator class. It is a rather large class
+# and the number of explicit instantiations is also large. Explicitly
+# generating these instantiations in separate .cc files breaks the
+# compilation into separate compilation unit rather than one large cc
+# file which takes 2+GB of RAM to compile.
+#
+# This script creates three sets of files.
+#
+# 1. schur_eliminator_x_x_x.cc and partitioned_matrix_view_x_x_x.cc
+# where, the x indicates the template parameters and
+#
+# 2. schur_eliminator.cc & partitioned_matrix_view.cc
+#
+# that contains a factory function for instantiating these classes
+# based on runtime parameters.
+#
+# 3. schur_templates.cc
+#
+# that contains a function which can be queried to determine what
+# template specializations are available.
+#
+# The following list of tuples, specializations indicates the set of
+# specializations that is generated.
+SPECIALIZATIONS = [(2, 2, 2),
+ (2, 2, 3),
+ (2, 2, 4),
+ (2, 2, "Eigen::Dynamic"),
+ (2, 3, 3),
+ (2, 3, 4),
+ (2, 3, 6),
+ (2, 3, 9),
+ (2, 3, "Eigen::Dynamic"),
+ (2, 4, 3),
+ (2, 4, 4),
+ (2, 4, 6),
+ (2, 4, 8),
+ (2, 4, 9),
+ (2, 4, "Eigen::Dynamic"),
+ (2, "Eigen::Dynamic", "Eigen::Dynamic"),
+ (3, 3, 3),
+ (4, 4, 2),
+ (4, 4, 3),
+ (4, 4, 4),
+ (4, 4, "Eigen::Dynamic")]
+
+import schur_eliminator_template
+import partitioned_matrix_view_template
+import os
+import glob
+
+def SuffixForSize(size):
+ if size == "Eigen::Dynamic":
+ return "d"
+ return str(size)
+
+def SpecializationFilename(prefix, row_block_size, e_block_size, f_block_size):
+ return "_".join([prefix] + map(SuffixForSize, (row_block_size,
+ e_block_size,
+ f_block_size)))
+
+def GenerateFactoryConditional(row_block_size, e_block_size, f_block_size):
+ conditionals = []
+ if (row_block_size != "Eigen::Dynamic"):
+ conditionals.append("(options.row_block_size == %s)" % row_block_size)
+ if (e_block_size != "Eigen::Dynamic"):
+ conditionals.append("(options.e_block_size == %s)" % e_block_size)
+ if (f_block_size != "Eigen::Dynamic"):
+ conditionals.append("(options.f_block_size == %s)" % f_block_size)
+ if (len(conditionals) == 0):
+ return "%s"
+
+ if (len(conditionals) == 1):
+ return " if " + conditionals[0] + "{\n %s\n }\n"
+
+ return " if (" + " &&\n ".join(conditionals) + ") {\n %s\n }\n"
+
+def Specialize(name, data):
+ """
+ Generate specialization code and the conditionals to instantiate it.
+ """
+
+ # Specialization files
+ for row_block_size, e_block_size, f_block_size in SPECIALIZATIONS:
+ output = SpecializationFilename("generated/" + name,
+ row_block_size,
+ e_block_size,
+ f_block_size) + ".cc"
+
+ with open(output, "w") as f:
+ f.write(data["HEADER"])
+ f.write(data["SPECIALIZATION_FILE"] %
+ (row_block_size, e_block_size, f_block_size))
+
+ # Generate the _d_d_d specialization.
+ output = SpecializationFilename("generated/" + name,
+ "Eigen::Dynamic",
+ "Eigen::Dynamic",
+ "Eigen::Dynamic") + ".cc"
+ with open(output, "w") as f:
+ f.write(data["HEADER"])
+ f.write(data["DYNAMIC_FILE"] %
+ ("Eigen::Dynamic", "Eigen::Dynamic", "Eigen::Dynamic"))
+
+ # Factory
+ with open(name + ".cc", "w") as f:
+ f.write(data["HEADER"])
+ f.write(data["FACTORY_FILE_HEADER"])
+ for row_block_size, e_block_size, f_block_size in SPECIALIZATIONS:
+ factory_conditional = GenerateFactoryConditional(
+ row_block_size, e_block_size, f_block_size)
+ factory = data["FACTORY"] % (row_block_size, e_block_size, f_block_size)
+ f.write(factory_conditional % factory);
+ f.write(data["FACTORY_FOOTER"])
+
+QUERY_HEADER = """// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2017 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// What template specializations are available.
+//
+// ========================================
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+//=========================================
+//
+// This file is generated using generate_template_specializations.py.
+"""
+
+QUERY_FILE_HEADER = """
+#include "ceres/internal/eigen.h"
+#include "ceres/schur_templates.h"
+
+namespace ceres {
+namespace internal {
+
+void GetBestSchurTemplateSpecialization(int* row_block_size,
+ int* e_block_size,
+ int* f_block_size) {
+ LinearSolver::Options options;
+ options.row_block_size = *row_block_size;
+ options.e_block_size = *e_block_size;
+ options.f_block_size = *f_block_size;
+ *row_block_size = Eigen::Dynamic;
+ *e_block_size = Eigen::Dynamic;
+ *f_block_size = Eigen::Dynamic;
+#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
+"""
+
+QUERY_FOOTER = """
+#endif
+ return;
+}
+
+} // namespace internal
+} // namespace ceres
+"""
+
+QUERY_ACTION = """ *row_block_size = %s;
+ *e_block_size = %s;
+ *f_block_size = %s;
+ return;"""
+
+def GenerateQueryFile():
+ """
+ Generate file that allows querying for available template specializations.
+ """
+
+ with open("schur_templates.cc", "w") as f:
+ f.write(QUERY_HEADER)
+ f.write(QUERY_FILE_HEADER)
+ for row_block_size, e_block_size, f_block_size in SPECIALIZATIONS:
+ factory_conditional = GenerateFactoryConditional(
+ row_block_size, e_block_size, f_block_size)
+ action = QUERY_ACTION % (row_block_size, e_block_size, f_block_size)
+ f.write(factory_conditional % action)
+ f.write(QUERY_FOOTER)
+
+
+if __name__ == "__main__":
+ for f in glob.glob("generated/*"):
+ os.remove(f)
+
+ Specialize("schur_eliminator",
+ schur_eliminator_template.__dict__)
+ Specialize("partitioned_matrix_view",
+ partitioned_matrix_view_template.__dict__)
+ GenerateQueryFile()
diff --git a/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_2_2.cc b/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_2_2.cc
index 500115b9897..86ad17b4f71 100644
--- a/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_2_2.cc
+++ b/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_2_2.cc
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2017 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -37,8 +37,7 @@
// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
//=========================================
//
-// This file is generated using generate_partitioned_matrix_view_specializations.py.
-// Editing it manually is not recommended.
+// This file is generated using generate_template_specializations.py.
// This include must come before any #ifndef check on Ceres compile options.
#include "ceres/internal/port.h"
diff --git a/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_2_3.cc b/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_2_3.cc
index 1384cb619e3..33018d573a4 100644
--- a/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_2_3.cc
+++ b/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_2_3.cc
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2017 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -37,8 +37,7 @@
// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
//=========================================
//
-// This file is generated using generate_partitioned_matrix_view_specializations.py.
-// Editing it manually is not recommended.
+// This file is generated using generate_template_specializations.py.
// This include must come before any #ifndef check on Ceres compile options.
#include "ceres/internal/port.h"
diff --git a/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_2_4.cc b/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_2_4.cc
index 030035ec97b..a429a546e3d 100644
--- a/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_2_4.cc
+++ b/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_2_4.cc
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2017 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -37,8 +37,7 @@
// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
//=========================================
//
-// This file is generated using generate_partitioned_matrix_view_specializations.py.
-// Editing it manually is not recommended.
+// This file is generated using generate_template_specializations.py.
// This include must come before any #ifndef check on Ceres compile options.
#include "ceres/internal/port.h"
diff --git a/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_2_d.cc b/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_2_d.cc
index c9501b50170..f6f03ea6dcc 100644
--- a/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_2_d.cc
+++ b/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_2_d.cc
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2017 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -37,8 +37,7 @@
// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
//=========================================
//
-// This file is generated using generate_partitioned_matrix_view_specializations.py.
-// Editing it manually is not recommended.
+// This file is generated using generate_template_specializations.py.
// This include must come before any #ifndef check on Ceres compile options.
#include "ceres/internal/port.h"
diff --git a/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_3_3.cc b/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_3_3.cc
index c2639bff69e..0b73e1a2aa8 100644
--- a/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_3_3.cc
+++ b/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_3_3.cc
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2017 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -37,8 +37,7 @@
// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
//=========================================
//
-// This file is generated using generate_partitioned_matrix_view_specializations.py.
-// Editing it manually is not recommended.
+// This file is generated using generate_template_specializations.py.
// This include must come before any #ifndef check on Ceres compile options.
#include "ceres/internal/port.h"
diff --git a/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_3_4.cc b/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_3_4.cc
index 693e43959c1..bc4a86194eb 100644
--- a/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_3_4.cc
+++ b/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_3_4.cc
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2017 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -37,8 +37,7 @@
// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
//=========================================
//
-// This file is generated using generate_partitioned_matrix_view_specializations.py.
-// Editing it manually is not recommended.
+// This file is generated using generate_template_specializations.py.
// This include must come before any #ifndef check on Ceres compile options.
#include "ceres/internal/port.h"
diff --git a/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_3_6.cc b/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_3_6.cc
index 7b9368ffefd..fe8f7dd37af 100644
--- a/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_3_6.cc
+++ b/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_3_6.cc
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2017 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -37,8 +37,7 @@
// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
//=========================================
//
-// This file is generated using generate_partitioned_matrix_view_specializations.py.
-// Editing it manually is not recommended.
+// This file is generated using generate_template_specializations.py.
// This include must come before any #ifndef check on Ceres compile options.
#include "ceres/internal/port.h"
diff --git a/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_3_9.cc b/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_3_9.cc
index e72c5f6937a..ac493fcd0c0 100644
--- a/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_3_9.cc
+++ b/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_3_9.cc
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2017 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -37,8 +37,7 @@
// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
//=========================================
//
-// This file is generated using generate_partitioned_matrix_view_specializations.py.
-// Editing it manually is not recommended.
+// This file is generated using generate_template_specializations.py.
// This include must come before any #ifndef check on Ceres compile options.
#include "ceres/internal/port.h"
diff --git a/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_3_d.cc b/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_3_d.cc
index c1f410eb64c..e29efaf4832 100644
--- a/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_3_d.cc
+++ b/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_3_d.cc
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2017 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -37,8 +37,7 @@
// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
//=========================================
//
-// This file is generated using generate_partitioned_matrix_view_specializations.py.
-// Editing it manually is not recommended.
+// This file is generated using generate_template_specializations.py.
// This include must come before any #ifndef check on Ceres compile options.
#include "ceres/internal/port.h"
diff --git a/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_4_3.cc b/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_4_3.cc
index 7292c333d5d..e61e0a31314 100644
--- a/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_4_3.cc
+++ b/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_4_3.cc
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2017 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -37,8 +37,7 @@
// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
//=========================================
//
-// This file is generated using generate_partitioned_matrix_view_specializations.py.
-// Editing it manually is not recommended.
+// This file is generated using generate_template_specializations.py.
// This include must come before any #ifndef check on Ceres compile options.
#include "ceres/internal/port.h"
diff --git a/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_4_4.cc b/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_4_4.cc
index 891d65a8646..2e1170da01f 100644
--- a/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_4_4.cc
+++ b/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_4_4.cc
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2017 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -37,8 +37,7 @@
// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
//=========================================
//
-// This file is generated using generate_partitioned_matrix_view_specializations.py.
-// Editing it manually is not recommended.
+// This file is generated using generate_template_specializations.py.
// This include must come before any #ifndef check on Ceres compile options.
#include "ceres/internal/port.h"
diff --git a/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_4_6.cc b/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_4_6.cc
new file mode 100644
index 00000000000..4a5590d9751
--- /dev/null
+++ b/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_4_6.cc
@@ -0,0 +1,58 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2017 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Template specialization of PartitionedMatrixView.
+//
+// ========================================
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+//=========================================
+//
+// This file is generated using generate_template_specializations.py.
+
+// This include must come before any #ifndef check on Ceres compile options.
+#include "ceres/internal/port.h"
+
+#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
+
+#include "ceres/partitioned_matrix_view_impl.h"
+#include "ceres/internal/eigen.h"
+
+namespace ceres {
+namespace internal {
+
+template class PartitionedMatrixView<2, 4, 6>;
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_4_8.cc b/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_4_8.cc
index 395f6bd4c13..83015f1ecc5 100644
--- a/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_4_8.cc
+++ b/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_4_8.cc
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2017 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -37,8 +37,7 @@
// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
//=========================================
//
-// This file is generated using generate_partitioned_matrix_view_specializations.py.
-// Editing it manually is not recommended.
+// This file is generated using generate_template_specializations.py.
// This include must come before any #ifndef check on Ceres compile options.
#include "ceres/internal/port.h"
diff --git a/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_4_9.cc b/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_4_9.cc
index 88952b10e34..25671f913dd 100644
--- a/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_4_9.cc
+++ b/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_4_9.cc
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2017 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -37,8 +37,7 @@
// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
//=========================================
//
-// This file is generated using generate_partitioned_matrix_view_specializations.py.
-// Editing it manually is not recommended.
+// This file is generated using generate_template_specializations.py.
// This include must come before any #ifndef check on Ceres compile options.
#include "ceres/internal/port.h"
diff --git a/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_4_d.cc b/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_4_d.cc
index 7733e1993eb..d259802bd5a 100644
--- a/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_4_d.cc
+++ b/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_4_d.cc
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2017 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -37,8 +37,7 @@
// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
//=========================================
//
-// This file is generated using generate_partitioned_matrix_view_specializations.py.
-// Editing it manually is not recommended.
+// This file is generated using generate_template_specializations.py.
// This include must come before any #ifndef check on Ceres compile options.
#include "ceres/internal/port.h"
diff --git a/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_d_d.cc b/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_d_d.cc
index 117a0cdb8c1..c9567595acd 100644
--- a/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_d_d.cc
+++ b/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_d_d.cc
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2017 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -37,8 +37,7 @@
// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
//=========================================
//
-// This file is generated using generate_partitioned_matrix_view_specializations.py.
-// Editing it manually is not recommended.
+// This file is generated using generate_template_specializations.py.
// This include must come before any #ifndef check on Ceres compile options.
#include "ceres/internal/port.h"
diff --git a/extern/ceres/internal/ceres/generated/partitioned_matrix_view_3_3_3.cc b/extern/ceres/internal/ceres/generated/partitioned_matrix_view_3_3_3.cc
new file mode 100644
index 00000000000..d3b20be70e7
--- /dev/null
+++ b/extern/ceres/internal/ceres/generated/partitioned_matrix_view_3_3_3.cc
@@ -0,0 +1,58 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2017 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Template specialization of PartitionedMatrixView.
+//
+// ========================================
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+//=========================================
+//
+// This file is generated using generate_template_specializations.py.
+
+// This include must come before any #ifndef check on Ceres compile options.
+#include "ceres/internal/port.h"
+
+#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
+
+#include "ceres/partitioned_matrix_view_impl.h"
+#include "ceres/internal/eigen.h"
+
+namespace ceres {
+namespace internal {
+
+template class PartitionedMatrixView<3, 3, 3>;
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/extern/ceres/internal/ceres/generated/partitioned_matrix_view_4_4_2.cc b/extern/ceres/internal/ceres/generated/partitioned_matrix_view_4_4_2.cc
index a620bb70dba..f08049c9653 100644
--- a/extern/ceres/internal/ceres/generated/partitioned_matrix_view_4_4_2.cc
+++ b/extern/ceres/internal/ceres/generated/partitioned_matrix_view_4_4_2.cc
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2017 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -37,8 +37,7 @@
// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
//=========================================
//
-// This file is generated using generate_partitioned_matrix_view_specializations.py.
-// Editing it manually is not recommended.
+// This file is generated using generate_template_specializations.py.
// This include must come before any #ifndef check on Ceres compile options.
#include "ceres/internal/port.h"
diff --git a/extern/ceres/internal/ceres/generated/partitioned_matrix_view_4_4_3.cc b/extern/ceres/internal/ceres/generated/partitioned_matrix_view_4_4_3.cc
index 2978630832c..9342612022f 100644
--- a/extern/ceres/internal/ceres/generated/partitioned_matrix_view_4_4_3.cc
+++ b/extern/ceres/internal/ceres/generated/partitioned_matrix_view_4_4_3.cc
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2017 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -37,8 +37,7 @@
// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
//=========================================
//
-// This file is generated using generate_partitioned_matrix_view_specializations.py.
-// Editing it manually is not recommended.
+// This file is generated using generate_template_specializations.py.
// This include must come before any #ifndef check on Ceres compile options.
#include "ceres/internal/port.h"
diff --git a/extern/ceres/internal/ceres/generated/partitioned_matrix_view_4_4_4.cc b/extern/ceres/internal/ceres/generated/partitioned_matrix_view_4_4_4.cc
index bcd03b02e3a..8b273fa0da0 100644
--- a/extern/ceres/internal/ceres/generated/partitioned_matrix_view_4_4_4.cc
+++ b/extern/ceres/internal/ceres/generated/partitioned_matrix_view_4_4_4.cc
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2017 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -37,8 +37,7 @@
// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
//=========================================
//
-// This file is generated using generate_partitioned_matrix_view_specializations.py.
-// Editing it manually is not recommended.
+// This file is generated using generate_template_specializations.py.
// This include must come before any #ifndef check on Ceres compile options.
#include "ceres/internal/port.h"
diff --git a/extern/ceres/internal/ceres/generated/partitioned_matrix_view_4_4_d.cc b/extern/ceres/internal/ceres/generated/partitioned_matrix_view_4_4_d.cc
index 6b541ecf0d9..e8b45e49eca 100644
--- a/extern/ceres/internal/ceres/generated/partitioned_matrix_view_4_4_d.cc
+++ b/extern/ceres/internal/ceres/generated/partitioned_matrix_view_4_4_d.cc
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2017 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -37,8 +37,7 @@
// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
//=========================================
//
-// This file is generated using generate_partitioned_matrix_view_specializations.py.
-// Editing it manually is not recommended.
+// This file is generated using generate_template_specializations.py.
// This include must come before any #ifndef check on Ceres compile options.
#include "ceres/internal/port.h"
diff --git a/extern/ceres/internal/ceres/generated/partitioned_matrix_view_d_d_d.cc b/extern/ceres/internal/ceres/generated/partitioned_matrix_view_d_d_d.cc
index 85111e722c4..3545b869d5f 100644
--- a/extern/ceres/internal/ceres/generated/partitioned_matrix_view_d_d_d.cc
+++ b/extern/ceres/internal/ceres/generated/partitioned_matrix_view_d_d_d.cc
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2017 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -37,8 +37,7 @@
// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
//=========================================
//
-// This file is generated using generate_partitioned_matrix_view_specializations.py.
-// Editing it manually is not recommended.
+// This file is generated using generate_template_specializations.py.
#include "ceres/partitioned_matrix_view_impl.h"
diff --git a/extern/ceres/internal/ceres/generated/schur_eliminator_2_2_2.cc b/extern/ceres/internal/ceres/generated/schur_eliminator_2_2_2.cc
index ac07a3f229e..79fcf437981 100644
--- a/extern/ceres/internal/ceres/generated/schur_eliminator_2_2_2.cc
+++ b/extern/ceres/internal/ceres/generated/schur_eliminator_2_2_2.cc
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2017 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -37,8 +37,7 @@
// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
//=========================================
//
-// This file is generated using generate_eliminator_specialization.py.
-// Editing it manually is not recommended.
+// This file is generated using generate_template_specializations.py.
// This include must come before any #ifndef check on Ceres compile options.
#include "ceres/internal/port.h"
diff --git a/extern/ceres/internal/ceres/generated/schur_eliminator_2_2_3.cc b/extern/ceres/internal/ceres/generated/schur_eliminator_2_2_3.cc
index 0ec09553f9e..edd7fb649b4 100644
--- a/extern/ceres/internal/ceres/generated/schur_eliminator_2_2_3.cc
+++ b/extern/ceres/internal/ceres/generated/schur_eliminator_2_2_3.cc
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2017 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -37,8 +37,7 @@
// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
//=========================================
//
-// This file is generated using generate_eliminator_specialization.py.
-// Editing it manually is not recommended.
+// This file is generated using generate_template_specializations.py.
// This include must come before any #ifndef check on Ceres compile options.
#include "ceres/internal/port.h"
diff --git a/extern/ceres/internal/ceres/generated/schur_eliminator_2_2_4.cc b/extern/ceres/internal/ceres/generated/schur_eliminator_2_2_4.cc
index 74a42cc4a16..692267dba46 100644
--- a/extern/ceres/internal/ceres/generated/schur_eliminator_2_2_4.cc
+++ b/extern/ceres/internal/ceres/generated/schur_eliminator_2_2_4.cc
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2017 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -37,8 +37,7 @@
// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
//=========================================
//
-// This file is generated using generate_eliminator_specialization.py.
-// Editing it manually is not recommended.
+// This file is generated using generate_template_specializations.py.
// This include must come before any #ifndef check on Ceres compile options.
#include "ceres/internal/port.h"
diff --git a/extern/ceres/internal/ceres/generated/schur_eliminator_2_2_d.cc b/extern/ceres/internal/ceres/generated/schur_eliminator_2_2_d.cc
index 5ce757fda5d..33d9c6de270 100644
--- a/extern/ceres/internal/ceres/generated/schur_eliminator_2_2_d.cc
+++ b/extern/ceres/internal/ceres/generated/schur_eliminator_2_2_d.cc
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2017 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -37,8 +37,7 @@
// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
//=========================================
//
-// This file is generated using generate_eliminator_specialization.py.
-// Editing it manually is not recommended.
+// This file is generated using generate_template_specializations.py.
// This include must come before any #ifndef check on Ceres compile options.
#include "ceres/internal/port.h"
diff --git a/extern/ceres/internal/ceres/generated/schur_eliminator_2_3_3.cc b/extern/ceres/internal/ceres/generated/schur_eliminator_2_3_3.cc
index 2e7ae28b4ea..4a5e2fe30c0 100644
--- a/extern/ceres/internal/ceres/generated/schur_eliminator_2_3_3.cc
+++ b/extern/ceres/internal/ceres/generated/schur_eliminator_2_3_3.cc
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2017 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -37,8 +37,7 @@
// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
//=========================================
//
-// This file is generated using generate_eliminator_specialization.py.
-// Editing it manually is not recommended.
+// This file is generated using generate_template_specializations.py.
// This include must come before any #ifndef check on Ceres compile options.
#include "ceres/internal/port.h"
diff --git a/extern/ceres/internal/ceres/generated/schur_eliminator_2_3_4.cc b/extern/ceres/internal/ceres/generated/schur_eliminator_2_3_4.cc
index 443207070cf..7ee63d069aa 100644
--- a/extern/ceres/internal/ceres/generated/schur_eliminator_2_3_4.cc
+++ b/extern/ceres/internal/ceres/generated/schur_eliminator_2_3_4.cc
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2017 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -37,8 +37,7 @@
// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
//=========================================
//
-// This file is generated using generate_eliminator_specialization.py.
-// Editing it manually is not recommended.
+// This file is generated using generate_template_specializations.py.
// This include must come before any #ifndef check on Ceres compile options.
#include "ceres/internal/port.h"
diff --git a/extern/ceres/internal/ceres/generated/schur_eliminator_2_3_6.cc b/extern/ceres/internal/ceres/generated/schur_eliminator_2_3_6.cc
index ac2f358b383..108760ef1f8 100644
--- a/extern/ceres/internal/ceres/generated/schur_eliminator_2_3_6.cc
+++ b/extern/ceres/internal/ceres/generated/schur_eliminator_2_3_6.cc
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2017 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -37,8 +37,7 @@
// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
//=========================================
//
-// This file is generated using generate_eliminator_specialization.py.
-// Editing it manually is not recommended.
+// This file is generated using generate_template_specializations.py.
// This include must come before any #ifndef check on Ceres compile options.
#include "ceres/internal/port.h"
diff --git a/extern/ceres/internal/ceres/generated/schur_eliminator_2_3_9.cc b/extern/ceres/internal/ceres/generated/schur_eliminator_2_3_9.cc
index 930ab440fa5..4fea2fa4417 100644
--- a/extern/ceres/internal/ceres/generated/schur_eliminator_2_3_9.cc
+++ b/extern/ceres/internal/ceres/generated/schur_eliminator_2_3_9.cc
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2017 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -37,8 +37,7 @@
// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
//=========================================
//
-// This file is generated using generate_eliminator_specialization.py.
-// Editing it manually is not recommended.
+// This file is generated using generate_template_specializations.py.
// This include must come before any #ifndef check on Ceres compile options.
#include "ceres/internal/port.h"
diff --git a/extern/ceres/internal/ceres/generated/schur_eliminator_2_3_d.cc b/extern/ceres/internal/ceres/generated/schur_eliminator_2_3_d.cc
index 486c53d36f4..0d13c99e7ca 100644
--- a/extern/ceres/internal/ceres/generated/schur_eliminator_2_3_d.cc
+++ b/extern/ceres/internal/ceres/generated/schur_eliminator_2_3_d.cc
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2017 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -37,8 +37,7 @@
// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
//=========================================
//
-// This file is generated using generate_eliminator_specialization.py.
-// Editing it manually is not recommended.
+// This file is generated using generate_template_specializations.py.
// This include must come before any #ifndef check on Ceres compile options.
#include "ceres/internal/port.h"
diff --git a/extern/ceres/internal/ceres/generated/schur_eliminator_2_4_3.cc b/extern/ceres/internal/ceres/generated/schur_eliminator_2_4_3.cc
index 6f247a7b832..3827c653a63 100644
--- a/extern/ceres/internal/ceres/generated/schur_eliminator_2_4_3.cc
+++ b/extern/ceres/internal/ceres/generated/schur_eliminator_2_4_3.cc
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2017 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -37,8 +37,7 @@
// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
//=========================================
//
-// This file is generated using generate_eliminator_specialization.py.
-// Editing it manually is not recommended.
+// This file is generated using generate_template_specializations.py.
// This include must come before any #ifndef check on Ceres compile options.
#include "ceres/internal/port.h"
diff --git a/extern/ceres/internal/ceres/generated/schur_eliminator_2_4_4.cc b/extern/ceres/internal/ceres/generated/schur_eliminator_2_4_4.cc
index c44cd045263..47bdfab1f22 100644
--- a/extern/ceres/internal/ceres/generated/schur_eliminator_2_4_4.cc
+++ b/extern/ceres/internal/ceres/generated/schur_eliminator_2_4_4.cc
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2017 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -37,8 +37,7 @@
// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
//=========================================
//
-// This file is generated using generate_eliminator_specialization.py.
-// Editing it manually is not recommended.
+// This file is generated using generate_template_specializations.py.
// This include must come before any #ifndef check on Ceres compile options.
#include "ceres/internal/port.h"
diff --git a/extern/ceres/internal/ceres/generated/schur_eliminator_2_4_6.cc b/extern/ceres/internal/ceres/generated/schur_eliminator_2_4_6.cc
new file mode 100644
index 00000000000..3777be22707
--- /dev/null
+++ b/extern/ceres/internal/ceres/generated/schur_eliminator_2_4_6.cc
@@ -0,0 +1,58 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2017 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Template specialization of SchurEliminator.
+//
+// ========================================
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+//=========================================
+//
+// This file is generated using generate_template_specializations.py.
+
+// This include must come before any #ifndef check on Ceres compile options.
+#include "ceres/internal/port.h"
+
+#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
+
+#include "ceres/schur_eliminator_impl.h"
+#include "ceres/internal/eigen.h"
+
+namespace ceres {
+namespace internal {
+
+template class SchurEliminator<2, 4, 6>;
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/extern/ceres/internal/ceres/generated/schur_eliminator_2_4_8.cc b/extern/ceres/internal/ceres/generated/schur_eliminator_2_4_8.cc
index c9a0d5fc729..862c76a2a9c 100644
--- a/extern/ceres/internal/ceres/generated/schur_eliminator_2_4_8.cc
+++ b/extern/ceres/internal/ceres/generated/schur_eliminator_2_4_8.cc
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2017 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -37,8 +37,7 @@
// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
//=========================================
//
-// This file is generated using generate_eliminator_specialization.py.
-// Editing it manually is not recommended.
+// This file is generated using generate_template_specializations.py.
// This include must come before any #ifndef check on Ceres compile options.
#include "ceres/internal/port.h"
diff --git a/extern/ceres/internal/ceres/generated/schur_eliminator_2_4_9.cc b/extern/ceres/internal/ceres/generated/schur_eliminator_2_4_9.cc
index b0455b0bca0..5b5b7ccd415 100644
--- a/extern/ceres/internal/ceres/generated/schur_eliminator_2_4_9.cc
+++ b/extern/ceres/internal/ceres/generated/schur_eliminator_2_4_9.cc
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2017 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -37,8 +37,7 @@
// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
//=========================================
//
-// This file is generated using generate_eliminator_specialization.py.
-// Editing it manually is not recommended.
+// This file is generated using generate_template_specializations.py.
// This include must come before any #ifndef check on Ceres compile options.
#include "ceres/internal/port.h"
diff --git a/extern/ceres/internal/ceres/generated/schur_eliminator_2_4_d.cc b/extern/ceres/internal/ceres/generated/schur_eliminator_2_4_d.cc
index 3234380f23c..ce2d450b073 100644
--- a/extern/ceres/internal/ceres/generated/schur_eliminator_2_4_d.cc
+++ b/extern/ceres/internal/ceres/generated/schur_eliminator_2_4_d.cc
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2017 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -37,8 +37,7 @@
// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
//=========================================
//
-// This file is generated using generate_eliminator_specialization.py.
-// Editing it manually is not recommended.
+// This file is generated using generate_template_specializations.py.
// This include must come before any #ifndef check on Ceres compile options.
#include "ceres/internal/port.h"
diff --git a/extern/ceres/internal/ceres/generated/schur_eliminator_2_d_d.cc b/extern/ceres/internal/ceres/generated/schur_eliminator_2_d_d.cc
index 311f8556932..9b02bd9db5a 100644
--- a/extern/ceres/internal/ceres/generated/schur_eliminator_2_d_d.cc
+++ b/extern/ceres/internal/ceres/generated/schur_eliminator_2_d_d.cc
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2017 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -37,8 +37,7 @@
// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
//=========================================
//
-// This file is generated using generate_eliminator_specialization.py.
-// Editing it manually is not recommended.
+// This file is generated using generate_template_specializations.py.
// This include must come before any #ifndef check on Ceres compile options.
#include "ceres/internal/port.h"
diff --git a/extern/ceres/internal/ceres/generated/schur_eliminator_3_3_3.cc b/extern/ceres/internal/ceres/generated/schur_eliminator_3_3_3.cc
new file mode 100644
index 00000000000..1cbeadf518f
--- /dev/null
+++ b/extern/ceres/internal/ceres/generated/schur_eliminator_3_3_3.cc
@@ -0,0 +1,58 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2017 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Template specialization of SchurEliminator.
+//
+// ========================================
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+//=========================================
+//
+// This file is generated using generate_template_specializations.py.
+
+// This include must come before any #ifndef check on Ceres compile options.
+#include "ceres/internal/port.h"
+
+#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
+
+#include "ceres/schur_eliminator_impl.h"
+#include "ceres/internal/eigen.h"
+
+namespace ceres {
+namespace internal {
+
+template class SchurEliminator<3, 3, 3>;
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/extern/ceres/internal/ceres/generated/schur_eliminator_4_4_2.cc b/extern/ceres/internal/ceres/generated/schur_eliminator_4_4_2.cc
index bc40bd55296..10f709d7577 100644
--- a/extern/ceres/internal/ceres/generated/schur_eliminator_4_4_2.cc
+++ b/extern/ceres/internal/ceres/generated/schur_eliminator_4_4_2.cc
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2017 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -37,8 +37,7 @@
// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
//=========================================
//
-// This file is generated using generate_eliminator_specialization.py.
-// Editing it manually is not recommended.
+// This file is generated using generate_template_specializations.py.
// This include must come before any #ifndef check on Ceres compile options.
#include "ceres/internal/port.h"
diff --git a/extern/ceres/internal/ceres/generated/schur_eliminator_4_4_3.cc b/extern/ceres/internal/ceres/generated/schur_eliminator_4_4_3.cc
index cca88c802b0..bcbcc745519 100644
--- a/extern/ceres/internal/ceres/generated/schur_eliminator_4_4_3.cc
+++ b/extern/ceres/internal/ceres/generated/schur_eliminator_4_4_3.cc
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2017 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -37,8 +37,7 @@
// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
//=========================================
//
-// This file is generated using generate_eliminator_specialization.py.
-// Editing it manually is not recommended.
+// This file is generated using generate_template_specializations.py.
// This include must come before any #ifndef check on Ceres compile options.
#include "ceres/internal/port.h"
diff --git a/extern/ceres/internal/ceres/generated/schur_eliminator_4_4_4.cc b/extern/ceres/internal/ceres/generated/schur_eliminator_4_4_4.cc
index 33c94a907b9..44ecc87deba 100644
--- a/extern/ceres/internal/ceres/generated/schur_eliminator_4_4_4.cc
+++ b/extern/ceres/internal/ceres/generated/schur_eliminator_4_4_4.cc
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2017 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -37,8 +37,7 @@
// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
//=========================================
//
-// This file is generated using generate_eliminator_specialization.py.
-// Editing it manually is not recommended.
+// This file is generated using generate_template_specializations.py.
// This include must come before any #ifndef check on Ceres compile options.
#include "ceres/internal/port.h"
diff --git a/extern/ceres/internal/ceres/generated/schur_eliminator_4_4_d.cc b/extern/ceres/internal/ceres/generated/schur_eliminator_4_4_d.cc
index 1a1866f93a8..69c856304f0 100644
--- a/extern/ceres/internal/ceres/generated/schur_eliminator_4_4_d.cc
+++ b/extern/ceres/internal/ceres/generated/schur_eliminator_4_4_d.cc
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2017 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -37,8 +37,7 @@
// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
//=========================================
//
-// This file is generated using generate_eliminator_specialization.py.
-// Editing it manually is not recommended.
+// This file is generated using generate_template_specializations.py.
// This include must come before any #ifndef check on Ceres compile options.
#include "ceres/internal/port.h"
diff --git a/extern/ceres/internal/ceres/generated/schur_eliminator_d_d_d.cc b/extern/ceres/internal/ceres/generated/schur_eliminator_d_d_d.cc
index 6b18ef8c863..348708bb335 100644
--- a/extern/ceres/internal/ceres/generated/schur_eliminator_d_d_d.cc
+++ b/extern/ceres/internal/ceres/generated/schur_eliminator_d_d_d.cc
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2017 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -37,8 +37,7 @@
// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
//=========================================
//
-// This file is generated using generate_eliminator_specialization.py.
-// Editing it manually is not recommended.
+// This file is generated using generate_template_specializations.py.
#include "ceres/schur_eliminator_impl.h"
diff --git a/extern/ceres/internal/ceres/gradient_checker.cc b/extern/ceres/internal/ceres/gradient_checker.cc
index c16c141db09..ef56666970d 100644
--- a/extern/ceres/internal/ceres/gradient_checker.cc
+++ b/extern/ceres/internal/ceres/gradient_checker.cc
@@ -34,6 +34,7 @@
#include <algorithm>
#include <cmath>
+#include <cstdint>
#include <numeric>
#include <string>
#include <vector>
@@ -61,11 +62,11 @@ bool EvaluateCostFunction(
Vector* residuals,
std::vector<Matrix>* jacobians,
std::vector<Matrix>* local_jacobians) {
- CHECK_NOTNULL(residuals);
- CHECK_NOTNULL(jacobians);
- CHECK_NOTNULL(local_jacobians);
+ CHECK(residuals != nullptr);
+ CHECK(jacobians != nullptr);
+ CHECK(local_jacobians != nullptr);
- const vector<int32>& block_sizes = function->parameter_block_sizes();
+ const vector<int32_t>& block_sizes = function->parameter_block_sizes();
const int num_parameter_blocks = block_sizes.size();
// Allocate Jacobian matrices in local space.
@@ -110,7 +111,7 @@ bool EvaluateCostFunction(
Matrix global_J_local(global_size, local_size);
local_parameterizations.at(i)->ComputeJacobian(
parameters[i], global_J_local.data());
- local_jacobians->at(i) = jacobians->at(i) * global_J_local;
+ local_jacobians->at(i).noalias() = jacobians->at(i) * global_J_local;
}
}
return true;
@@ -122,20 +123,20 @@ GradientChecker::GradientChecker(
const vector<const LocalParameterization*>* local_parameterizations,
const NumericDiffOptions& options) :
function_(function) {
- CHECK_NOTNULL(function);
+ CHECK(function != nullptr);
if (local_parameterizations != NULL) {
local_parameterizations_ = *local_parameterizations;
} else {
local_parameterizations_.resize(function->parameter_block_sizes().size(),
NULL);
}
- DynamicNumericDiffCostFunction<CostFunction, CENTRAL>*
+ DynamicNumericDiffCostFunction<CostFunction, RIDDERS>*
finite_diff_cost_function =
- new DynamicNumericDiffCostFunction<CostFunction, CENTRAL>(
+ new DynamicNumericDiffCostFunction<CostFunction, RIDDERS>(
function, DO_NOT_TAKE_OWNERSHIP, options);
finite_diff_cost_function_.reset(finite_diff_cost_function);
- const vector<int32>& parameter_block_sizes =
+ const vector<int32_t>& parameter_block_sizes =
function->parameter_block_sizes();
const int num_parameter_blocks = parameter_block_sizes.size();
for (int i = 0; i < num_parameter_blocks; ++i) {
diff --git a/extern/ceres/internal/ceres/gradient_checking_cost_function.cc b/extern/ceres/internal/ceres/gradient_checking_cost_function.cc
index f2c73367891..13d6c58a6b7 100644
--- a/extern/ceres/internal/ceres/gradient_checking_cost_function.cc
+++ b/extern/ceres/internal/ceres/gradient_checking_cost_function.cc
@@ -33,13 +33,13 @@
#include <algorithm>
#include <cmath>
+#include <cstdint>
#include <numeric>
#include <string>
#include <vector>
#include "ceres/gradient_checker.h"
#include "ceres/internal/eigen.h"
-#include "ceres/internal/scoped_ptr.h"
#include "ceres/parameter_block.h"
#include "ceres/problem.h"
#include "ceres/problem_impl.h"
@@ -74,8 +74,8 @@ class GradientCheckingCostFunction : public CostFunction {
relative_precision_(relative_precision),
extra_info_(extra_info),
callback_(callback) {
- CHECK_NOTNULL(callback_);
- const vector<int32>& parameter_block_sizes =
+ CHECK(callback_ != nullptr);
+ const vector<int32_t>& parameter_block_sizes =
function->parameter_block_sizes();
*mutable_parameter_block_sizes() = parameter_block_sizes;
set_num_residuals(function->num_residuals());
@@ -83,9 +83,9 @@ class GradientCheckingCostFunction : public CostFunction {
virtual ~GradientCheckingCostFunction() { }
- virtual bool Evaluate(double const* const* parameters,
- double* residuals,
- double** jacobians) const {
+ bool Evaluate(double const* const* parameters,
+ double* residuals,
+ double** jacobians) const final {
if (!jacobians) {
// Nothing to check in this case; just forward.
return function_->Evaluate(parameters, residuals, NULL);
@@ -107,7 +107,7 @@ class GradientCheckingCostFunction : public CostFunction {
MatrixRef(residuals, num_residuals, 1) = results.residuals;
// Copy the original jacobian blocks into the jacobians array.
- const vector<int32>& block_sizes = function_->parameter_block_sizes();
+ const vector<int32_t>& block_sizes = function_->parameter_block_sizes();
for (int k = 0; k < block_sizes.size(); k++) {
if (jacobians[k] != NULL) {
MatrixRef(jacobians[k],
@@ -148,10 +148,9 @@ CallbackReturnType GradientCheckingIterationCallback::operator()(
}
void GradientCheckingIterationCallback::SetGradientErrorDetected(
std::string& error_log) {
- mutex_.Lock();
+ std::lock_guard<std::mutex> l(mutex_);
gradient_error_detected_ = true;
error_log_ += "\n" + error_log;
- mutex_.Unlock();
}
CostFunction* CreateGradientCheckingCostFunction(
@@ -176,7 +175,7 @@ ProblemImpl* CreateGradientCheckingProblemImpl(
double relative_step_size,
double relative_precision,
GradientCheckingIterationCallback* callback) {
- CHECK_NOTNULL(callback);
+ CHECK(callback != nullptr);
// We create new CostFunctions by wrapping the original CostFunction
// in a gradient checking CostFunction. So its okay for the
// ProblemImpl to take ownership of it and destroy it. The
@@ -189,6 +188,7 @@ ProblemImpl* CreateGradientCheckingProblemImpl(
DO_NOT_TAKE_OWNERSHIP;
gradient_checking_problem_options.local_parameterization_ownership =
DO_NOT_TAKE_OWNERSHIP;
+ gradient_checking_problem_options.context = problem_impl->context();
NumericDiffOptions numeric_diff_options;
numeric_diff_options.relative_step_size = relative_step_size;
@@ -212,6 +212,17 @@ ProblemImpl* CreateGradientCheckingProblemImpl(
gradient_checking_problem_impl->SetParameterBlockConstant(
parameter_block->mutable_user_state());
}
+
+ for (int i = 0; i < parameter_block->Size(); ++i) {
+ gradient_checking_problem_impl->SetParameterUpperBound(
+ parameter_block->mutable_user_state(),
+ i,
+ parameter_block->UpperBound(i));
+ gradient_checking_problem_impl->SetParameterLowerBound(
+ parameter_block->mutable_user_state(),
+ i,
+ parameter_block->LowerBound(i));
+ }
}
// For every ResidualBlock in problem_impl, create a new
@@ -255,7 +266,8 @@ ProblemImpl* CreateGradientCheckingProblemImpl(
gradient_checking_problem_impl->AddResidualBlock(
gradient_checking_cost_function,
const_cast<LossFunction*>(residual_block->loss_function()),
- parameter_blocks);
+ parameter_blocks.data(),
+ static_cast<int>(parameter_blocks.size()));
}
// Normally, when a problem is given to the solver, we guarantee
diff --git a/extern/ceres/internal/ceres/gradient_checking_cost_function.h b/extern/ceres/internal/ceres/gradient_checking_cost_function.h
index 497f8e2a594..e9a34f7eb9f 100644
--- a/extern/ceres/internal/ceres/gradient_checking_cost_function.h
+++ b/extern/ceres/internal/ceres/gradient_checking_cost_function.h
@@ -32,12 +32,12 @@
#ifndef CERES_INTERNAL_GRADIENT_CHECKING_COST_FUNCTION_H_
#define CERES_INTERNAL_GRADIENT_CHECKING_COST_FUNCTION_H_
+#include <mutex>
#include <string>
#include "ceres/cost_function.h"
#include "ceres/iteration_callback.h"
#include "ceres/local_parameterization.h"
-#include "ceres/mutex.h"
namespace ceres {
namespace internal {
@@ -52,7 +52,7 @@ class GradientCheckingIterationCallback : public IterationCallback {
// Will return SOLVER_CONTINUE until a gradient error has been detected,
// then return SOLVER_ABORT.
- virtual CallbackReturnType operator()(const IterationSummary& summary);
+ CallbackReturnType operator()(const IterationSummary& summary) final;
// Notify this that a gradient error has occurred (thread safe).
void SetGradientErrorDetected(std::string& error_log);
@@ -63,8 +63,7 @@ class GradientCheckingIterationCallback : public IterationCallback {
private:
bool gradient_error_detected_;
std::string error_log_;
- // Mutex protecting member variables.
- ceres::internal::Mutex mutex_;
+ std::mutex mutex_;
};
// Creates a CostFunction that checks the Jacobians that cost_function computes
diff --git a/extern/ceres/internal/ceres/gradient_problem_evaluator.h b/extern/ceres/internal/ceres/gradient_problem_evaluator.h
index 2c562544768..c5ad1d71607 100644
--- a/extern/ceres/internal/ceres/gradient_problem_evaluator.h
+++ b/extern/ceres/internal/ceres/gradient_problem_evaluator.h
@@ -48,43 +48,46 @@ class GradientProblemEvaluator : public Evaluator {
explicit GradientProblemEvaluator(const GradientProblem& problem)
: problem_(problem) {}
virtual ~GradientProblemEvaluator() {}
- virtual SparseMatrix* CreateJacobian() const { return NULL; }
- virtual bool Evaluate(const EvaluateOptions& evaluate_options,
- const double* state,
- double* cost,
- double* residuals,
- double* gradient,
- SparseMatrix* jacobian) {
+ SparseMatrix* CreateJacobian() const final { return nullptr; }
+ bool Evaluate(const EvaluateOptions& evaluate_options,
+ const double* state,
+ double* cost,
+ double* residuals,
+ double* gradient,
+ SparseMatrix* jacobian) final {
CHECK(jacobian == NULL);
ScopedExecutionTimer total_timer("Evaluator::Total", &execution_summary_);
+ // The reason we use Residual and Jacobian here even when we are
+ // only computing the cost and gradient has to do with the fact
+ // that the line search minimizer code is used by both the
+ // GradientProblemSolver and the main CeresSolver coder where the
+ // Evaluator evaluates the Jacobian, and these magic strings need
+ // to be consistent across the code base for the time accounting
+ // to work.
ScopedExecutionTimer call_type_timer(
- gradient == NULL ? "Evaluator::Cost" : "Evaluator::Gradient",
+ gradient == NULL ? "Evaluator::Residual" : "Evaluator::Jacobian",
&execution_summary_);
return problem_.Evaluate(state, cost, gradient);
}
- virtual bool Plus(const double* state,
- const double* delta,
- double* state_plus_delta) const {
+ bool Plus(const double* state,
+ const double* delta,
+ double* state_plus_delta) const final {
return problem_.Plus(state, delta, state_plus_delta);
}
- virtual int NumParameters() const {
+ int NumParameters() const final {
return problem_.NumParameters();
}
- virtual int NumEffectiveParameters() const {
+ int NumEffectiveParameters() const final {
return problem_.NumLocalParameters();
}
- virtual int NumResiduals() const { return 1; }
+ int NumResiduals() const final { return 1; }
- virtual std::map<std::string, int> CallStatistics() const {
- return execution_summary_.calls();
- }
-
- virtual std::map<std::string, double> TimeStatistics() const {
- return execution_summary_.times();
+ std::map<std::string, internal::CallStatistics> Statistics() const final {
+ return execution_summary_.statistics();
}
private:
diff --git a/extern/ceres/internal/ceres/gradient_problem_solver.cc b/extern/ceres/internal/ceres/gradient_problem_solver.cc
index 8709f8f3fbd..1639e30666c 100644
--- a/extern/ceres/internal/ceres/gradient_problem_solver.cc
+++ b/extern/ceres/internal/ceres/gradient_problem_solver.cc
@@ -30,6 +30,7 @@
#include "ceres/gradient_problem_solver.h"
+#include <memory>
#include "ceres/callbacks.h"
#include "ceres/gradient_problem.h"
#include "ceres/gradient_problem_evaluator.h"
@@ -72,6 +73,7 @@ Solver::Options GradientProblemSolverOptionsToSolverOptions(
COPY_OPTION(max_line_search_step_expansion);
COPY_OPTION(max_num_iterations);
COPY_OPTION(max_solver_time_in_seconds);
+ COPY_OPTION(parameter_tolerance);
COPY_OPTION(function_tolerance);
COPY_OPTION(gradient_tolerance);
COPY_OPTION(logging_type);
@@ -97,16 +99,18 @@ void GradientProblemSolver::Solve(const GradientProblemSolver::Options& options,
const GradientProblem& problem,
double* parameters_ptr,
GradientProblemSolver::Summary* summary) {
- using internal::scoped_ptr;
- using internal::WallTimeInSeconds;
- using internal::Minimizer;
+ using internal::CallStatistics;
using internal::GradientProblemEvaluator;
+ using internal::GradientProblemSolverStateUpdatingCallback;
using internal::LoggingCallback;
+ using internal::Minimizer;
using internal::SetSummaryFinalCost;
+ using internal::WallTimeInSeconds;
double start_time = WallTimeInSeconds();
- *CHECK_NOTNULL(summary) = Summary();
+ CHECK(summary != nullptr);
+ *summary = Summary();
summary->num_parameters = problem.NumParameters();
summary->num_local_parameters = problem.NumLocalParameters();
summary->line_search_direction_type = options.line_search_direction_type; // NOLINT
@@ -121,6 +125,10 @@ void GradientProblemSolver::Solve(const GradientProblemSolver::Options& options,
return;
}
+ VectorRef parameters(parameters_ptr, problem.NumParameters());
+ Vector solution(problem.NumParameters());
+ solution = parameters;
+
// TODO(sameeragarwal): This is a bit convoluted, we should be able
// to convert to minimizer options directly, but this will do for
// now.
@@ -128,7 +136,7 @@ void GradientProblemSolver::Solve(const GradientProblemSolver::Options& options,
Minimizer::Options(GradientProblemSolverOptionsToSolverOptions(options));
minimizer_options.evaluator.reset(new GradientProblemEvaluator(problem));
- scoped_ptr<IterationCallback> logging_callback;
+ std::unique_ptr<IterationCallback> logging_callback;
if (options.logging_type != SILENT) {
logging_callback.reset(
new LoggingCallback(LINE_SEARCH, options.minimizer_progress_to_stdout));
@@ -136,10 +144,16 @@ void GradientProblemSolver::Solve(const GradientProblemSolver::Options& options,
logging_callback.get());
}
- scoped_ptr<Minimizer> minimizer(Minimizer::Create(LINE_SEARCH));
- Vector solution(problem.NumParameters());
- VectorRef parameters(parameters_ptr, problem.NumParameters());
- solution = parameters;
+ std::unique_ptr<IterationCallback> state_updating_callback;
+ if (options.update_state_every_iteration) {
+ state_updating_callback.reset(
+ new GradientProblemSolverStateUpdatingCallback(
+ problem.NumParameters(), solution.data(), parameters_ptr));
+ minimizer_options.callbacks.insert(minimizer_options.callbacks.begin(),
+ state_updating_callback.get());
+ }
+
+ std::unique_ptr<Minimizer> minimizer(Minimizer::Create(LINE_SEARCH));
Solver::Summary solver_summary;
solver_summary.fixed_cost = 0.0;
@@ -162,34 +176,23 @@ void GradientProblemSolver::Solve(const GradientProblemSolver::Options& options,
SetSummaryFinalCost(summary);
}
- const std::map<string, double>& evaluator_time_statistics =
- minimizer_options.evaluator->TimeStatistics();
- summary->cost_evaluation_time_in_seconds =
- FindWithDefault(evaluator_time_statistics, "Evaluator::Residual", 0.0);
- summary->gradient_evaluation_time_in_seconds =
- FindWithDefault(evaluator_time_statistics, "Evaluator::Jacobian", 0.0);
+ const std::map<string, CallStatistics>& evaluator_statistics =
+ minimizer_options.evaluator->Statistics();
+ {
+ const CallStatistics& call_stats = FindWithDefault(
+ evaluator_statistics, "Evaluator::Residual", CallStatistics());
+ summary->cost_evaluation_time_in_seconds = call_stats.time;
+ summary->num_cost_evaluations = call_stats.calls;
+ }
- summary->total_time_in_seconds = WallTimeInSeconds() - start_time;
-}
+ {
+ const CallStatistics& call_stats = FindWithDefault(
+ evaluator_statistics, "Evaluator::Jacobian", CallStatistics());
+ summary->gradient_evaluation_time_in_seconds = call_stats.time;
+ summary->num_gradient_evaluations = call_stats.calls;
+ }
-// Invalid values for most fields, to ensure that we are not
-// accidentally reporting default values.
-GradientProblemSolver::Summary::Summary()
- : termination_type(FAILURE),
- message("ceres::GradientProblemSolve was not called."),
- initial_cost(-1.0),
- final_cost(-1.0),
- total_time_in_seconds(-1.0),
- cost_evaluation_time_in_seconds(-1.0),
- gradient_evaluation_time_in_seconds(-1.0),
- line_search_polynomial_minimization_time_in_seconds(-1.0),
- num_parameters(-1),
- num_local_parameters(-1),
- line_search_direction_type(LBFGS),
- line_search_type(ARMIJO),
- line_search_interpolation_type(BISECTION),
- nonlinear_conjugate_gradient_type(FLETCHER_REEVES),
- max_lbfgs_rank(-1) {
+ summary->total_time_in_seconds = WallTimeInSeconds() - start_time;
}
bool GradientProblemSolver::Summary::IsSolutionUsable() const {
@@ -256,15 +259,15 @@ string GradientProblemSolver::Summary::FullReport() const {
static_cast<int>(iterations.size()));
StringAppendF(&report, "\nTime (in seconds):\n");
-
- StringAppendF(&report, "\n Cost evaluation %23.4f\n",
- cost_evaluation_time_in_seconds);
- StringAppendF(&report, " Gradient evaluation %23.4f\n",
- gradient_evaluation_time_in_seconds);
- StringAppendF(&report, " Polynomial minimization %17.4f\n",
+ StringAppendF(&report, "\n Cost evaluation %23.6f (%d)\n",
+ cost_evaluation_time_in_seconds,
+ num_cost_evaluations);
+ StringAppendF(&report, " Gradient & cost evaluation %16.6f (%d)\n",
+ gradient_evaluation_time_in_seconds,
+ num_gradient_evaluations);
+ StringAppendF(&report, " Polynomial minimization %17.6f\n",
line_search_polynomial_minimization_time_in_seconds);
-
- StringAppendF(&report, "Total %25.4f\n\n",
+ StringAppendF(&report, "Total %25.6f\n\n",
total_time_in_seconds);
StringAppendF(&report, "Termination: %25s (%s)\n",
diff --git a/extern/ceres/internal/ceres/graph.h b/extern/ceres/internal/ceres/graph.h
index b96b67265cb..4e1fd81c1ea 100644
--- a/extern/ceres/internal/ceres/graph.h
+++ b/extern/ceres/internal/ceres/graph.h
@@ -32,11 +32,11 @@
#define CERES_INTERNAL_GRAPH_H_
#include <limits>
+#include <unordered_set>
+#include <unordered_map>
#include <utility>
-#include "ceres/integral_types.h"
#include "ceres/map_util.h"
-#include "ceres/collections_port.h"
-#include "ceres/internal/macros.h"
+#include "ceres/pair_hash.h"
#include "ceres/types.h"
#include "glog/logging.h"
@@ -53,7 +53,7 @@ class Graph {
// Add a vertex.
void AddVertex(const Vertex& vertex) {
if (vertices_.insert(vertex).second) {
- edges_[vertex] = HashSet<Vertex>();
+ edges_[vertex] = std::unordered_set<Vertex>();
}
}
@@ -63,10 +63,9 @@ class Graph {
}
vertices_.erase(vertex);
- const HashSet<Vertex>& sinks = edges_[vertex];
- for (typename HashSet<Vertex>::const_iterator it = sinks.begin();
- it != sinks.end(); ++it) {
- edges_[*it].erase(vertex);
+ const std::unordered_set<Vertex>& sinks = edges_[vertex];
+ for (const Vertex& s : sinks) {
+ edges_[s].erase(vertex);
}
edges_.erase(vertex);
@@ -90,19 +89,17 @@ class Graph {
// Calling Neighbors on a vertex not in the graph will result in
// undefined behaviour.
- const HashSet<Vertex>& Neighbors(const Vertex& vertex) const {
+ const std::unordered_set<Vertex>& Neighbors(const Vertex& vertex) const {
return FindOrDie(edges_, vertex);
}
- const HashSet<Vertex>& vertices() const {
+ const std::unordered_set<Vertex>& vertices() const {
return vertices_;
}
private:
- HashSet<Vertex> vertices_;
- HashMap<Vertex, HashSet<Vertex> > edges_;
-
- CERES_DISALLOW_COPY_AND_ASSIGN(Graph);
+ std::unordered_set<Vertex> vertices_;
+ std::unordered_map<Vertex, std::unordered_set<Vertex>> edges_;
};
// A weighted undirected graph templated over the vertex ids. Vertex
@@ -117,7 +114,7 @@ class WeightedGraph {
void AddVertex(const Vertex& vertex, double weight) {
if (vertices_.find(vertex) == vertices_.end()) {
vertices_.insert(vertex);
- edges_[vertex] = HashSet<Vertex>();
+ edges_[vertex] = std::unordered_set<Vertex>();
}
vertex_weights_[vertex] = weight;
}
@@ -135,15 +132,14 @@ class WeightedGraph {
vertices_.erase(vertex);
vertex_weights_.erase(vertex);
- const HashSet<Vertex>& sinks = edges_[vertex];
- for (typename HashSet<Vertex>::const_iterator it = sinks.begin();
- it != sinks.end(); ++it) {
- if (vertex < *it) {
- edge_weights_.erase(std::make_pair(vertex, *it));
+ const std::unordered_set<Vertex>& sinks = edges_[vertex];
+ for (const Vertex& s : sinks) {
+ if (vertex < s) {
+ edge_weights_.erase(std::make_pair(vertex, s));
} else {
- edge_weights_.erase(std::make_pair(*it, vertex));
+ edge_weights_.erase(std::make_pair(s, vertex));
}
- edges_[*it].erase(vertex);
+ edges_[s].erase(vertex);
}
edges_.erase(vertex);
@@ -198,11 +194,11 @@ class WeightedGraph {
// Calling Neighbors on a vertex not in the graph will result in
// undefined behaviour.
- const HashSet<Vertex>& Neighbors(const Vertex& vertex) const {
+ const std::unordered_set<Vertex>& Neighbors(const Vertex& vertex) const {
return FindOrDie(edges_, vertex);
}
- const HashSet<Vertex>& vertices() const {
+ const std::unordered_set<Vertex>& vertices() const {
return vertices_;
}
@@ -211,12 +207,11 @@ class WeightedGraph {
}
private:
- HashSet<Vertex> vertices_;
- HashMap<Vertex, double> vertex_weights_;
- HashMap<Vertex, HashSet<Vertex> > edges_;
- HashMap<std::pair<Vertex, Vertex>, double> edge_weights_;
-
- CERES_DISALLOW_COPY_AND_ASSIGN(WeightedGraph);
+ std::unordered_set<Vertex> vertices_;
+ std::unordered_map<Vertex, double> vertex_weights_;
+ std::unordered_map<Vertex, std::unordered_set<Vertex>> edges_;
+ std::unordered_map<std::pair<Vertex, Vertex>, double, pair_hash>
+ edge_weights_;
};
} // namespace internal
diff --git a/extern/ceres/internal/ceres/graph_algorithms.h b/extern/ceres/internal/ceres/graph_algorithms.h
index d1d3f52cd22..b0629313159 100644
--- a/extern/ceres/internal/ceres/graph_algorithms.h
+++ b/extern/ceres/internal/ceres/graph_algorithms.h
@@ -34,9 +34,10 @@
#define CERES_INTERNAL_GRAPH_ALGORITHMS_H_
#include <algorithm>
+#include <unordered_map>
+#include <unordered_set>
#include <vector>
#include <utility>
-#include "ceres/collections_port.h"
#include "ceres/graph.h"
#include "ceres/wall_time.h"
#include "glog/logging.h"
@@ -96,10 +97,10 @@ class VertexDegreeLessThan {
template <typename Vertex>
int IndependentSetOrdering(const Graph<Vertex>& graph,
std::vector<Vertex>* ordering) {
- const HashSet<Vertex>& vertices = graph.vertices();
+ const std::unordered_set<Vertex>& vertices = graph.vertices();
const int num_vertices = vertices.size();
- CHECK_NOTNULL(ordering);
+ CHECK(ordering != nullptr);
ordering->clear();
ordering->reserve(num_vertices);
@@ -109,34 +110,29 @@ int IndependentSetOrdering(const Graph<Vertex>& graph,
const char kBlack = 2;
// Mark all vertices white.
- HashMap<Vertex, char> vertex_color;
+ std::unordered_map<Vertex, char> vertex_color;
std::vector<Vertex> vertex_queue;
- for (typename HashSet<Vertex>::const_iterator it = vertices.begin();
- it != vertices.end();
- ++it) {
- vertex_color[*it] = kWhite;
- vertex_queue.push_back(*it);
+ for (const Vertex& vertex : vertices) {
+ vertex_color[vertex] = kWhite;
+ vertex_queue.push_back(vertex);
}
-
- std::sort(vertex_queue.begin(), vertex_queue.end(),
+ std::sort(vertex_queue.begin(),
+ vertex_queue.end(),
VertexTotalOrdering<Vertex>(graph));
// Iterate over vertex_queue. Pick the first white vertex, add it
// to the independent set. Mark it black and its neighbors grey.
- for (int i = 0; i < vertex_queue.size(); ++i) {
- const Vertex& vertex = vertex_queue[i];
+ for (const Vertex& vertex : vertex_queue) {
if (vertex_color[vertex] != kWhite) {
continue;
}
ordering->push_back(vertex);
vertex_color[vertex] = kBlack;
- const HashSet<Vertex>& neighbors = graph.Neighbors(vertex);
- for (typename HashSet<Vertex>::const_iterator it = neighbors.begin();
- it != neighbors.end();
- ++it) {
- vertex_color[*it] = kGrey;
+ const std::unordered_set<Vertex>& neighbors = graph.Neighbors(vertex);
+ for (const Vertex& neighbor : neighbors) {
+ vertex_color[neighbor] = kGrey;
}
}
@@ -145,10 +141,7 @@ int IndependentSetOrdering(const Graph<Vertex>& graph,
// Iterate over the vertices and add all the grey vertices to the
// ordering. At this stage there should only be black or grey
// vertices in the graph.
- for (typename std::vector<Vertex>::const_iterator it = vertex_queue.begin();
- it != vertex_queue.end();
- ++it) {
- const Vertex vertex = *it;
+ for (const Vertex& vertex : vertex_queue) {
DCHECK(vertex_color[vertex] != kWhite);
if (vertex_color[vertex] != kBlack) {
ordering->push_back(vertex);
@@ -172,8 +165,8 @@ int IndependentSetOrdering(const Graph<Vertex>& graph,
template <typename Vertex>
int StableIndependentSetOrdering(const Graph<Vertex>& graph,
std::vector<Vertex>* ordering) {
- CHECK_NOTNULL(ordering);
- const HashSet<Vertex>& vertices = graph.vertices();
+ CHECK(ordering != nullptr);
+ const std::unordered_set<Vertex>& vertices = graph.vertices();
const int num_vertices = vertices.size();
CHECK_EQ(vertices.size(), ordering->size());
@@ -188,11 +181,9 @@ int StableIndependentSetOrdering(const Graph<Vertex>& graph,
VertexDegreeLessThan<Vertex>(graph));
// Mark all vertices white.
- HashMap<Vertex, char> vertex_color;
- for (typename HashSet<Vertex>::const_iterator it = vertices.begin();
- it != vertices.end();
- ++it) {
- vertex_color[*it] = kWhite;
+ std::unordered_map<Vertex, char> vertex_color;
+ for (const Vertex& vertex : vertices) {
+ vertex_color[vertex] = kWhite;
}
ordering->clear();
@@ -207,11 +198,9 @@ int StableIndependentSetOrdering(const Graph<Vertex>& graph,
ordering->push_back(vertex);
vertex_color[vertex] = kBlack;
- const HashSet<Vertex>& neighbors = graph.Neighbors(vertex);
- for (typename HashSet<Vertex>::const_iterator it = neighbors.begin();
- it != neighbors.end();
- ++it) {
- vertex_color[*it] = kGrey;
+ const std::unordered_set<Vertex>& neighbors = graph.Neighbors(vertex);
+ for (const Vertex& neighbor : neighbors) {
+ vertex_color[neighbor] = kGrey;
}
}
@@ -220,10 +209,7 @@ int StableIndependentSetOrdering(const Graph<Vertex>& graph,
// Iterate over the vertices and add all the grey vertices to the
// ordering. At this stage there should only be black or grey
// vertices in the graph.
- for (typename std::vector<Vertex>::const_iterator it = vertex_queue.begin();
- it != vertex_queue.end();
- ++it) {
- const Vertex vertex = *it;
+ for (const Vertex& vertex : vertex_queue) {
DCHECK(vertex_color[vertex] != kWhite);
if (vertex_color[vertex] != kBlack) {
ordering->push_back(vertex);
@@ -242,8 +228,8 @@ int StableIndependentSetOrdering(const Graph<Vertex>& graph,
// is what gives this data structure its efficiency.
template <typename Vertex>
Vertex FindConnectedComponent(const Vertex& vertex,
- HashMap<Vertex, Vertex>* union_find) {
- typename HashMap<Vertex, Vertex>::iterator it = union_find->find(vertex);
+ std::unordered_map<Vertex, Vertex>* union_find) {
+ auto it = union_find->find(vertex);
DCHECK(it != union_find->end());
if (it->second != vertex) {
it->second = FindConnectedComponent(it->second, union_find);
@@ -274,30 +260,24 @@ template <typename Vertex>
WeightedGraph<Vertex>*
Degree2MaximumSpanningForest(const WeightedGraph<Vertex>& graph) {
// Array of edges sorted in decreasing order of their weights.
- std::vector<std::pair<double, std::pair<Vertex, Vertex> > > weighted_edges;
+ std::vector<std::pair<double, std::pair<Vertex, Vertex>>> weighted_edges;
WeightedGraph<Vertex>* forest = new WeightedGraph<Vertex>();
// Disjoint-set to keep track of the connected components in the
// maximum spanning tree.
- HashMap<Vertex, Vertex> disjoint_set;
+ std::unordered_map<Vertex, Vertex> disjoint_set;
// Sort of the edges in the graph in decreasing order of their
// weight. Also add the vertices of the graph to the Maximum
// Spanning Tree graph and set each vertex to be its own connected
// component in the disjoint_set structure.
- const HashSet<Vertex>& vertices = graph.vertices();
- for (typename HashSet<Vertex>::const_iterator it = vertices.begin();
- it != vertices.end();
- ++it) {
- const Vertex vertex1 = *it;
+ const std::unordered_set<Vertex>& vertices = graph.vertices();
+ for (const Vertex& vertex1 : vertices) {
forest->AddVertex(vertex1, graph.VertexWeight(vertex1));
disjoint_set[vertex1] = vertex1;
- const HashSet<Vertex>& neighbors = graph.Neighbors(vertex1);
- for (typename HashSet<Vertex>::const_iterator it2 = neighbors.begin();
- it2 != neighbors.end();
- ++it2) {
- const Vertex vertex2 = *it2;
+ const std::unordered_set<Vertex>& neighbors = graph.Neighbors(vertex1);
+ for (const Vertex& vertex2 : neighbors) {
if (vertex1 >= vertex2) {
continue;
}
diff --git a/extern/ceres/internal/ceres/implicit_schur_complement.cc b/extern/ceres/internal/ceres/implicit_schur_complement.cc
index d05f03817b7..bf680d1d952 100644
--- a/extern/ceres/internal/ceres/implicit_schur_complement.cc
+++ b/extern/ceres/internal/ceres/implicit_schur_complement.cc
@@ -34,7 +34,6 @@
#include "ceres/block_sparse_matrix.h"
#include "ceres/block_structure.h"
#include "ceres/internal/eigen.h"
-#include "ceres/internal/scoped_ptr.h"
#include "ceres/linear_solver.h"
#include "ceres/types.h"
#include "glog/logging.h"
diff --git a/extern/ceres/internal/ceres/implicit_schur_complement.h b/extern/ceres/internal/ceres/implicit_schur_complement.h
index 5d822ebaeef..f4ddf724910 100644
--- a/extern/ceres/internal/ceres/implicit_schur_complement.h
+++ b/extern/ceres/internal/ceres/implicit_schur_complement.h
@@ -34,11 +34,11 @@
#ifndef CERES_INTERNAL_IMPLICIT_SCHUR_COMPLEMENT_H_
#define CERES_INTERNAL_IMPLICIT_SCHUR_COMPLEMENT_H_
+#include <memory>
#include "ceres/linear_operator.h"
#include "ceres/linear_solver.h"
#include "ceres/partitioned_matrix_view.h"
#include "ceres/internal/eigen.h"
-#include "ceres/internal/scoped_ptr.h"
#include "ceres/types.h"
namespace ceres {
@@ -113,11 +113,11 @@ class ImplicitSchurComplement : public LinearOperator {
void Init(const BlockSparseMatrix& A, const double* D, const double* b);
// y += Sx, where S is the Schur complement.
- virtual void RightMultiply(const double* x, double* y) const;
+ void RightMultiply(const double* x, double* y) const final;
// The Schur complement is a symmetric positive definite matrix,
// thus the left and right multiply operators are the same.
- virtual void LeftMultiply(const double* x, double* y) const {
+ void LeftMultiply(const double* x, double* y) const final {
RightMultiply(x, y);
}
@@ -127,8 +127,8 @@ class ImplicitSchurComplement : public LinearOperator {
// complement.
void BackSubstitute(const double* x, double* y);
- virtual int num_rows() const { return A_->num_cols_f(); }
- virtual int num_cols() const { return A_->num_cols_f(); }
+ int num_rows() const final { return A_->num_cols_f(); }
+ int num_cols() const final { return A_->num_cols_f(); }
const Vector& rhs() const { return rhs_; }
const BlockSparseMatrix* block_diagonal_EtE_inverse() const {
@@ -145,12 +145,12 @@ class ImplicitSchurComplement : public LinearOperator {
const LinearSolver::Options& options_;
- scoped_ptr<PartitionedMatrixViewBase> A_;
+ std::unique_ptr<PartitionedMatrixViewBase> A_;
const double* D_;
const double* b_;
- scoped_ptr<BlockSparseMatrix> block_diagonal_EtE_inverse_;
- scoped_ptr<BlockSparseMatrix> block_diagonal_FtF_inverse_;
+ std::unique_ptr<BlockSparseMatrix> block_diagonal_EtE_inverse_;
+ std::unique_ptr<BlockSparseMatrix> block_diagonal_FtF_inverse_;
Vector rhs_;
diff --git a/extern/ceres/internal/ceres/inner_product_computer.cc b/extern/ceres/internal/ceres/inner_product_computer.cc
new file mode 100644
index 00000000000..2bf88365d99
--- /dev/null
+++ b/extern/ceres/internal/ceres/inner_product_computer.cc
@@ -0,0 +1,330 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2017 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#include "ceres/inner_product_computer.h"
+
+#include <algorithm>
+#include "ceres/small_blas.h"
+
+namespace ceres {
+namespace internal {
+
+
+// Create the CompressedRowSparseMatrix matrix that will contain the
+// inner product.
+//
+// storage_type controls whether the result matrix contains the upper
+// or the lower triangular part of the product.
+//
+// num_nonzeros is the number of non-zeros in the result matrix.
+CompressedRowSparseMatrix* InnerProductComputer::CreateResultMatrix(
+ const CompressedRowSparseMatrix::StorageType storage_type,
+ const int num_nonzeros) {
+ CompressedRowSparseMatrix* matrix =
+ new CompressedRowSparseMatrix(m_.num_cols(), m_.num_cols(), num_nonzeros);
+ matrix->set_storage_type(storage_type);
+
+ const CompressedRowBlockStructure* bs = m_.block_structure();
+ const std::vector<Block>& blocks = bs->cols;
+ matrix->mutable_row_blocks()->resize(blocks.size());
+ matrix->mutable_col_blocks()->resize(blocks.size());
+ for (int i = 0; i < blocks.size(); ++i) {
+ (*(matrix->mutable_row_blocks()))[i] = blocks[i].size;
+ (*(matrix->mutable_col_blocks()))[i] = blocks[i].size;
+ }
+
+ return matrix;
+}
+
+// Given the set of product terms in the inner product, return the
+// total number of non-zeros in the result and for each row block of
+// the result matrix, compute the number of non-zeros in any one row
+// of the row block.
+int InnerProductComputer::ComputeNonzeros(
+ const std::vector<InnerProductComputer::ProductTerm>& product_terms,
+ std::vector<int>* row_nnz) {
+ const CompressedRowBlockStructure* bs = m_.block_structure();
+ const std::vector<Block>& blocks = bs->cols;
+
+ row_nnz->resize(blocks.size());
+ std::fill(row_nnz->begin(), row_nnz->end(), 0);
+
+ // First product term.
+ (*row_nnz)[product_terms[0].row] = blocks[product_terms[0].col].size;
+ int num_nonzeros =
+ blocks[product_terms[0].row].size * blocks[product_terms[0].col].size;
+
+ // Remaining product terms.
+ for (int i = 1; i < product_terms.size(); ++i) {
+ const ProductTerm& previous = product_terms[i - 1];
+ const ProductTerm& current = product_terms[i];
+
+ // Each (row, col) block counts only once.
+ // This check depends on product sorted on (row, col).
+ if (current.row != previous.row || current.col != previous.col) {
+ (*row_nnz)[current.row] += blocks[current.col].size;
+ num_nonzeros += blocks[current.row].size * blocks[current.col].size;
+ }
+ }
+
+ return num_nonzeros;
+}
+
+InnerProductComputer::InnerProductComputer(const BlockSparseMatrix& m,
+ const int start_row_block,
+ const int end_row_block)
+ : m_(m), start_row_block_(start_row_block), end_row_block_(end_row_block) {}
+
+// Compute the sparsity structure of the product m.transpose() * m
+// and create a CompressedRowSparseMatrix corresponding to it.
+//
+// Also compute the "program" vector, which for every term in the
+// block outer product provides the information for the entry in the
+// values array of the result matrix where it should be accumulated.
+//
+// Since the entries of the program are the same for rows with the
+// same sparsity structure, the program only stores the result for one
+// row per row block. The Compute function reuses this information for
+// each row in the row block.
+//
+// product_storage_type controls the form of the output matrix. It
+// can be LOWER_TRIANGULAR or UPPER_TRIANGULAR.
+InnerProductComputer* InnerProductComputer::Create(
+ const BlockSparseMatrix& m,
+ CompressedRowSparseMatrix::StorageType product_storage_type) {
+ return InnerProductComputer::Create(
+ m, 0, m.block_structure()->rows.size(), product_storage_type);
+}
+
+InnerProductComputer* InnerProductComputer::Create(
+ const BlockSparseMatrix& m,
+ const int start_row_block,
+ const int end_row_block,
+ CompressedRowSparseMatrix::StorageType product_storage_type) {
+ CHECK(product_storage_type == CompressedRowSparseMatrix::LOWER_TRIANGULAR ||
+ product_storage_type == CompressedRowSparseMatrix::UPPER_TRIANGULAR);
+ CHECK_GT(m.num_nonzeros(), 0)
+ << "Congratulations, you found a bug in Ceres. Please report it.";
+ InnerProductComputer* inner_product_computer =
+ new InnerProductComputer(m, start_row_block, end_row_block);
+ inner_product_computer->Init(product_storage_type);
+ return inner_product_computer;
+}
+
+void InnerProductComputer::Init(
+ const CompressedRowSparseMatrix::StorageType product_storage_type) {
+ std::vector<InnerProductComputer::ProductTerm> product_terms;
+ const CompressedRowBlockStructure* bs = m_.block_structure();
+
+ // Give input matrix m in Block Sparse format
+ // (row_block, col_block)
+ // represent each block multiplication
+ // (row_block, col_block1)' X (row_block, col_block2)
+ // by its product term:
+ // (col_block1, col_block2, index)
+ for (int row_block = start_row_block_; row_block < end_row_block_;
+ ++row_block) {
+ const CompressedRow& row = bs->rows[row_block];
+ for (int c1 = 0; c1 < row.cells.size(); ++c1) {
+ const Cell& cell1 = row.cells[c1];
+ int c2_begin, c2_end;
+ if (product_storage_type == CompressedRowSparseMatrix::LOWER_TRIANGULAR) {
+ c2_begin = 0;
+ c2_end = c1 + 1;
+ } else {
+ c2_begin = c1;
+ c2_end = row.cells.size();
+ }
+
+ for (int c2 = c2_begin; c2 < c2_end; ++c2) {
+ const Cell& cell2 = row.cells[c2];
+ product_terms.push_back(InnerProductComputer::ProductTerm(
+ cell1.block_id, cell2.block_id, product_terms.size()));
+ }
+ }
+ }
+
+ std::sort(product_terms.begin(), product_terms.end());
+ ComputeOffsetsAndCreateResultMatrix(product_storage_type, product_terms);
+}
+
+void InnerProductComputer::ComputeOffsetsAndCreateResultMatrix(
+ const CompressedRowSparseMatrix::StorageType product_storage_type,
+ const std::vector<InnerProductComputer::ProductTerm>& product_terms) {
+ const std::vector<Block>& col_blocks = m_.block_structure()->cols;
+
+ std::vector<int> row_block_nnz;
+ const int num_nonzeros = ComputeNonzeros(product_terms, &row_block_nnz);
+
+ result_.reset(CreateResultMatrix(product_storage_type, num_nonzeros));
+
+ // Populate the row non-zero counts in the result matrix.
+ int* crsm_rows = result_->mutable_rows();
+ crsm_rows[0] = 0;
+ for (int i = 0; i < col_blocks.size(); ++i) {
+ for (int j = 0; j < col_blocks[i].size; ++j, ++crsm_rows) {
+ *(crsm_rows + 1) = *crsm_rows + row_block_nnz[i];
+ }
+ }
+
+ // The following macro FILL_CRSM_COL_BLOCK is key to understanding
+ // how this class works.
+ //
+ // It does two things.
+ //
+ // Sets the value for the current term in the result_offsets_ array
+ // and populates the cols array of the result matrix.
+ //
+ // row_block and col_block as the names imply, refer to the row and
+ // column blocks of the current term.
+ //
+ // row_nnz is the number of nonzeros in the result_matrix at the
+ // beginning of the first row of row_block.
+ //
+ // col_nnz is the number of nonzeros in the first row of the row
+ // block that occur before the current column block, i.e. this is
+ // sum of the sizes of all the column blocks in this row block that
+ // came before this column block.
+ //
+ // Given these two numbers and the total number of nonzeros in this
+ // row (nnz_in_row), we can now populate the cols array as follows:
+ //
+ // nnz + j * nnz_in_row is the beginning of the j^th row.
+ //
+ // nnz + j * nnz_in_row + col_nnz is the beginning of the column
+ // block in the j^th row.
+ //
+ // nnz + j * nnz_in_row + col_nnz + k is then the j^th row and the
+ // k^th column of the product block, whose value is
+ //
+ // col_blocks[col_block].position + k, which is the column number of
+ // the k^th column of the current column block.
+#define FILL_CRSM_COL_BLOCK \
+ const int row_block = current->row; \
+ const int col_block = current->col; \
+ const int nnz_in_row = row_block_nnz[row_block]; \
+ int* crsm_cols = result_->mutable_cols(); \
+ result_offsets_[current->index] = nnz + col_nnz; \
+ for (int j = 0; j < col_blocks[row_block].size; ++j) { \
+ for (int k = 0; k < col_blocks[col_block].size; ++k) { \
+ crsm_cols[nnz + j * nnz_in_row + col_nnz + k] = \
+ col_blocks[col_block].position + k; \
+ } \
+ }
+
+ result_offsets_.resize(product_terms.size());
+ int col_nnz = 0;
+ int nnz = 0;
+
+ // Process the first term.
+ const InnerProductComputer::ProductTerm* current = &product_terms[0];
+ FILL_CRSM_COL_BLOCK;
+
+ // Process the rest of the terms.
+ for (int i = 1; i < product_terms.size(); ++i) {
+ current = &product_terms[i];
+ const InnerProductComputer::ProductTerm* previous = &product_terms[i - 1];
+
+ // If the current term is the same as the previous term, then it
+ // stores its product at the same location as the previous term.
+ if (previous->row == current->row && previous->col == current->col) {
+ result_offsets_[current->index] = result_offsets_[previous->index];
+ continue;
+ }
+
+ if (previous->row == current->row) {
+ // if the current and previous terms are in the same row block,
+ // then they differ in the column block, in which case advance
+ // col_nnz by the column size of the prevous term.
+ col_nnz += col_blocks[previous->col].size;
+ } else {
+ // If we have moved to a new row-block , then col_nnz is zero,
+ // and nnz is set to the beginning of the row block.
+ col_nnz = 0;
+ nnz += row_block_nnz[previous->row] * col_blocks[previous->row].size;
+ }
+
+ FILL_CRSM_COL_BLOCK;
+ }
+}
+
+// Use the results_offsets_ array to numerically compute the product
+// m' * m and store it in result_.
+//
+// TODO(sameeragarwal): Multithreading support.
+void InnerProductComputer::Compute() {
+ const double* m_values = m_.values();
+ const CompressedRowBlockStructure* bs = m_.block_structure();
+
+ const CompressedRowSparseMatrix::StorageType storage_type =
+ result_->storage_type();
+ result_->SetZero();
+ double* values = result_->mutable_values();
+ const int* rows = result_->rows();
+ int cursor = 0;
+
+ // Iterate row blocks.
+ for (int r = start_row_block_; r < end_row_block_; ++r) {
+ const CompressedRow& m_row = bs->rows[r];
+ for (int c1 = 0; c1 < m_row.cells.size(); ++c1) {
+ const Cell& cell1 = m_row.cells[c1];
+ const int c1_size = bs->cols[cell1.block_id].size;
+ const int row_nnz = rows[bs->cols[cell1.block_id].position + 1] -
+ rows[bs->cols[cell1.block_id].position];
+
+ int c2_begin, c2_end;
+ if (storage_type == CompressedRowSparseMatrix::LOWER_TRIANGULAR) {
+ c2_begin = 0;
+ c2_end = c1 + 1;
+ } else {
+ c2_begin = c1;
+ c2_end = m_row.cells.size();
+ }
+
+ for (int c2 = c2_begin; c2 < c2_end; ++c2, ++cursor) {
+ const Cell& cell2 = m_row.cells[c2];
+ const int c2_size = bs->cols[cell2.block_id].size;
+ MatrixTransposeMatrixMultiply<Eigen::Dynamic, Eigen::Dynamic,
+ Eigen::Dynamic, Eigen::Dynamic, 1>(
+ m_values + cell1.position,
+ m_row.block.size, c1_size,
+ m_values + cell2.position,
+ m_row.block.size, c2_size,
+ values + result_offsets_[cursor],
+ 0, 0, c1_size, row_nnz);
+ }
+ }
+ }
+
+ CHECK_EQ(cursor, result_offsets_.size());
+}
+
+} // namespace internal
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/inner_product_computer.h b/extern/ceres/internal/ceres/inner_product_computer.h
new file mode 100644
index 00000000000..73073f8ad06
--- /dev/null
+++ b/extern/ceres/internal/ceres/inner_product_computer.h
@@ -0,0 +1,157 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2017 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#ifndef CERES_INTERNAL_INNER_PRODUCT_COMPUTER_H_
+#define CERES_INTERNAL_INNER_PRODUCT_COMPUTER_H_
+
+#include <memory>
+#include <vector>
+
+#include "ceres/block_sparse_matrix.h"
+#include "ceres/compressed_row_sparse_matrix.h"
+
+namespace ceres {
+namespace internal {
+
+// This class is used to repeatedly compute the inner product
+//
+// result = m' * m
+//
+// where the sparsity structure of m remains constant across calls.
+//
+// Upon creation, the class computes and caches information needed to
+// compute v, and then uses it to efficiently compute the product
+// every time InnerProductComputer::Compute is called.
+//
+// See sparse_normal_cholesky_solver.cc for example usage.
+//
+// Note that the result matrix is a block upper or lower-triangular
+// matrix, i.e., it will contain entries in the upper or lower
+// triangular part of the matrix corresponding to the block that occur
+// along its diagonal.
+//
+// This is not a problem as sparse linear algebra libraries can ignore
+// these entries with ease and the space used is minimal/linear in the
+// size of the matrices.
+class InnerProductComputer {
+ public:
+ // Factory
+ //
+ // m is the input matrix
+ //
+ // Since m' * m is a symmetric matrix, we only compute half of the
+ // matrix and the value of storage_type which must be
+ // UPPER_TRIANGULAR or LOWER_TRIANGULAR determines which half is
+ // computed.
+ //
+ // The user must ensure that the matrix m is valid for the life time
+ // of this object.
+ static InnerProductComputer* Create(
+ const BlockSparseMatrix& m,
+ CompressedRowSparseMatrix::StorageType storage_type);
+
+ // This factory method allows the user control over range of row
+ // blocks of m that should be used to compute the inner product.
+ //
+ // a = m(start_row_block : end_row_block, :);
+ // result = a' * a;
+ static InnerProductComputer* Create(
+ const BlockSparseMatrix& m,
+ int start_row_block,
+ int end_row_block,
+ CompressedRowSparseMatrix::StorageType storage_type);
+
+ // Update result_ to be numerically equal to m' * m.
+ void Compute();
+
+ // Accessors for the result containing the inner product.
+ //
+ // Compute must be called before accessing this result for
+ // the first time.
+ const CompressedRowSparseMatrix& result() const { return *result_; }
+ CompressedRowSparseMatrix* mutable_result() const { return result_.get(); }
+
+ private:
+ // A ProductTerm is a term in the block inner product of a matrix
+ // with itself.
+ struct ProductTerm {
+ ProductTerm(const int row, const int col, const int index)
+ : row(row), col(col), index(index) {}
+
+ bool operator<(const ProductTerm& right) const {
+ if (row == right.row) {
+ if (col == right.col) {
+ return index < right.index;
+ }
+ return col < right.col;
+ }
+ return row < right.row;
+ }
+
+ int row;
+ int col;
+ int index;
+ };
+
+ InnerProductComputer(const BlockSparseMatrix& m,
+ int start_row_block,
+ int end_row_block);
+
+ void Init(CompressedRowSparseMatrix::StorageType storage_type);
+
+ CompressedRowSparseMatrix* CreateResultMatrix(
+ const CompressedRowSparseMatrix::StorageType storage_type,
+ int num_nonzeros);
+
+ int ComputeNonzeros(const std::vector<ProductTerm>& product_terms,
+ std::vector<int>* row_block_nnz);
+
+ void ComputeOffsetsAndCreateResultMatrix(
+ const CompressedRowSparseMatrix::StorageType storage_type,
+ const std::vector<ProductTerm>& product_terms);
+
+ const BlockSparseMatrix& m_;
+ const int start_row_block_;
+ const int end_row_block_;
+ std::unique_ptr<CompressedRowSparseMatrix> result_;
+
+ // For each term in the inner product, result_offsets_ contains the
+ // location in the values array of the result_ matrix where it
+ // should be stored.
+ //
+ // This is the principal look up table that allows this class to
+ // compute the inner product fast.
+ std::vector<int> result_offsets_;
+};
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_INNER_PRODUCT_COMPUTER_H_
diff --git a/extern/ceres/internal/ceres/invert_psd_matrix.h b/extern/ceres/internal/ceres/invert_psd_matrix.h
new file mode 100644
index 00000000000..21d301a77ee
--- /dev/null
+++ b/extern/ceres/internal/ceres/invert_psd_matrix.h
@@ -0,0 +1,79 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2017 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#ifndef CERES_INTERNAL_INVERT_PSD_MATRIX_H_
+#define CERES_INTERNAL_INVERT_PSD_MATRIX_H_
+
+#include "ceres/internal/eigen.h"
+#include "glog/logging.h"
+#include "Eigen/Dense"
+
+namespace ceres {
+namespace internal {
+
+// Helper routine to compute the inverse or pseudo-inverse of a
+// symmetric positive semi-definite matrix.
+//
+// assume_full_rank controls whether a Cholesky factorization or an
+// Singular Value Decomposition is used to compute the inverse and the
+// pseudo-inverse respectively.
+//
+// The template parameter kSize can either be Eigen::Dynamic or a
+// positive integer equal to the number of rows of m.
+template <int kSize>
+typename EigenTypes<kSize, kSize>::Matrix InvertPSDMatrix(
+ const bool assume_full_rank,
+ const typename EigenTypes<kSize, kSize>::Matrix& m) {
+ using MType = typename EigenTypes<kSize, kSize>::Matrix;
+ const int size = m.rows();
+
+ // If the matrix can be assumed to be full rank, then if it is small
+ // (< 5) and fixed size, use Eigen's optimized inverse()
+ // implementation.
+ //
+ // https://eigen.tuxfamily.org/dox/group__TutorialLinearAlgebra.html#title3
+ if (assume_full_rank) {
+ if (kSize > 0 && kSize < 5) {
+ return m.inverse();
+ }
+ return m.template selfadjointView<Eigen::Upper>().llt().solve(
+ MType::Identity(size, size));
+ }
+
+ // For a thin SVD the number of columns of the matrix need to be dynamic.
+ using SVDMType = typename EigenTypes<kSize, Eigen::Dynamic>::Matrix;
+ Eigen::JacobiSVD<SVDMType> svd(m, Eigen::ComputeThinU | Eigen::ComputeThinV);
+ return svd.solve(MType::Identity(size, size));
+}
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_INVERT_PSD_MATRIX_H_
diff --git a/extern/ceres/internal/ceres/iterative_refiner.cc b/extern/ceres/internal/ceres/iterative_refiner.cc
new file mode 100644
index 00000000000..fb0e45bdcdd
--- /dev/null
+++ b/extern/ceres/internal/ceres/iterative_refiner.cc
@@ -0,0 +1,74 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2018 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#include <string>
+#include "ceres/iterative_refiner.h"
+
+#include "Eigen/Core"
+#include "ceres/sparse_cholesky.h"
+#include "ceres/sparse_matrix.h"
+
+namespace ceres {
+namespace internal {
+
+IterativeRefiner::IterativeRefiner(const int max_num_iterations)
+ : max_num_iterations_(max_num_iterations) {}
+
+IterativeRefiner::~IterativeRefiner() {}
+
+void IterativeRefiner::Allocate(int num_cols) {
+ residual_.resize(num_cols);
+ correction_.resize(num_cols);
+ lhs_x_solution_.resize(num_cols);
+}
+
+void IterativeRefiner::Refine(const SparseMatrix& lhs,
+ const double* rhs_ptr,
+ SparseCholesky* sparse_cholesky,
+ double* solution_ptr) {
+ const int num_cols = lhs.num_cols();
+ Allocate(num_cols);
+ ConstVectorRef rhs(rhs_ptr, num_cols);
+ VectorRef solution(solution_ptr, num_cols);
+ for (int i = 0; i < max_num_iterations_; ++i) {
+ // residual = rhs - lhs * solution
+ lhs_x_solution_.setZero();
+ lhs.RightMultiply(solution_ptr, lhs_x_solution_.data());
+ residual_ = rhs - lhs_x_solution_;
+ // solution += lhs^-1 residual
+ std::string ignored_message;
+ sparse_cholesky->Solve(
+ residual_.data(), correction_.data(), &ignored_message);
+ solution += correction_;
+ }
+};
+
+} // namespace internal
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/iterative_refiner.h b/extern/ceres/internal/ceres/iterative_refiner.h
new file mode 100644
index 00000000000..f969935ae46
--- /dev/null
+++ b/extern/ceres/internal/ceres/iterative_refiner.h
@@ -0,0 +1,93 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2018 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#ifndef CERES_INTERNAL_ITERATIVE_REFINER_H_
+#define CERES_INTERNAL_ITERATIVE_REFINER_H_
+
+// This include must come before any #ifndef check on Ceres compile options.
+#include "ceres/internal/port.h"
+#include "ceres/internal/eigen.h"
+
+namespace ceres {
+namespace internal {
+
+class SparseCholesky;
+class SparseMatrix;
+
+// Iterative refinement
+// (https://en.wikipedia.org/wiki/Iterative_refinement) is the process
+// of improving the solution to a linear system, by using the
+// following iteration.
+//
+// r_i = b - Ax_i
+// Ad_i = r_i
+// x_{i+1} = x_i + d_i
+//
+// IterativeRefiner implements this process for Symmetric Positive
+// Definite linear systems.
+//
+// The above iterative loop is run until max_num_iterations is reached.
+class IterativeRefiner {
+ public:
+ // max_num_iterations is the number of refinement iterations to
+ // perform.
+ IterativeRefiner(int max_num_iterations);
+
+ // Needed for mocking.
+ virtual ~IterativeRefiner();
+
+ // Given an initial estimate of the solution of lhs * x = rhs, use
+ // max_num_iterations rounds of iterative refinement to improve it.
+ //
+ // sparse_cholesky is assumed to contain an already computed
+ // factorization (or approximation thereof) of lhs.
+ //
+ // solution is expected to contain a approximation to the solution
+ // to lhs * x = rhs. It can be zero.
+ //
+ // This method is virtual to facilitate mocking.
+ virtual void Refine(const SparseMatrix& lhs,
+ const double* rhs,
+ SparseCholesky* sparse_cholesky,
+ double* solution);
+
+ private:
+ void Allocate(int num_cols);
+
+ int max_num_iterations_;
+ Vector residual_;
+ Vector correction_;
+ Vector lhs_x_solution_;
+};
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_ITERATIVE_REFINER_H_
diff --git a/extern/ceres/internal/ceres/iterative_schur_complement_solver.cc b/extern/ceres/internal/ceres/iterative_schur_complement_solver.cc
index 9d4e30d69d2..6076c38c71d 100644
--- a/extern/ceres/internal/ceres/iterative_schur_complement_solver.cc
+++ b/extern/ceres/internal/ceres/iterative_schur_complement_solver.cc
@@ -41,7 +41,6 @@
#include "ceres/detect_structure.h"
#include "ceres/implicit_schur_complement.h"
#include "ceres/internal/eigen.h"
-#include "ceres/internal/scoped_ptr.h"
#include "ceres/linear_solver.h"
#include "ceres/preconditioner.h"
#include "ceres/schur_jacobi_preconditioner.h"
@@ -59,8 +58,7 @@ IterativeSchurComplementSolver::IterativeSchurComplementSolver(
: options_(options) {
}
-IterativeSchurComplementSolver::~IterativeSchurComplementSolver() {
-}
+IterativeSchurComplementSolver::~IterativeSchurComplementSolver() {}
LinearSolver::Summary IterativeSchurComplementSolver::SolveImpl(
BlockSparseMatrix* A,
@@ -69,7 +67,7 @@ LinearSolver::Summary IterativeSchurComplementSolver::SolveImpl(
double* x) {
EventLogger event_logger("IterativeSchurComplementSolver::Solve");
- CHECK_NOTNULL(A->block_structure());
+ CHECK(A->block_structure() != nullptr);
const int num_eliminate_blocks = options_.elimination_groups[0];
// Initialize a ImplicitSchurComplement object.
if (schur_complement_ == NULL) {
@@ -86,29 +84,61 @@ LinearSolver::Summary IterativeSchurComplementSolver::SolveImpl(
A->block_structure()->cols.size() - num_eliminate_blocks;
if (num_schur_complement_blocks == 0) {
VLOG(2) << "No parameter blocks left in the schur complement.";
- LinearSolver::Summary cg_summary;
- cg_summary.num_iterations = 0;
- cg_summary.termination_type = LINEAR_SOLVER_SUCCESS;
+ LinearSolver::Summary summary;
+ summary.num_iterations = 0;
+ summary.termination_type = LINEAR_SOLVER_SUCCESS;
schur_complement_->BackSubstitute(NULL, x);
- return cg_summary;
+ return summary;
}
// Initialize the solution to the Schur complement system to zero.
reduced_linear_system_solution_.resize(schur_complement_->num_rows());
reduced_linear_system_solution_.setZero();
- // Instantiate a conjugate gradient solver that runs on the Schur
- // complement matrix with the block diagonal of the matrix F'F as
- // the preconditioner.
LinearSolver::Options cg_options;
cg_options.min_num_iterations = options_.min_num_iterations;
cg_options.max_num_iterations = options_.max_num_iterations;
ConjugateGradientsSolver cg_solver(cg_options);
- LinearSolver::PerSolveOptions cg_per_solve_options;
+ LinearSolver::PerSolveOptions cg_per_solve_options;
cg_per_solve_options.r_tolerance = per_solve_options.r_tolerance;
cg_per_solve_options.q_tolerance = per_solve_options.q_tolerance;
+ CreatePreconditioner(A);
+ if (preconditioner_.get() != NULL) {
+ if (!preconditioner_->Update(*A, per_solve_options.D)) {
+ LinearSolver::Summary summary;
+ summary.num_iterations = 0;
+ summary.termination_type = LINEAR_SOLVER_FAILURE;
+ summary.message = "Preconditioner update failed.";
+ return summary;
+ }
+
+ cg_per_solve_options.preconditioner = preconditioner_.get();
+ }
+
+ event_logger.AddEvent("Setup");
+ LinearSolver::Summary summary =
+ cg_solver.Solve(schur_complement_.get(),
+ schur_complement_->rhs().data(),
+ cg_per_solve_options,
+ reduced_linear_system_solution_.data());
+ if (summary.termination_type != LINEAR_SOLVER_FAILURE &&
+ summary.termination_type != LINEAR_SOLVER_FATAL_ERROR) {
+ schur_complement_->BackSubstitute(reduced_linear_system_solution_.data(),
+ x);
+ }
+ event_logger.AddEvent("Solve");
+ return summary;
+}
+
+void IterativeSchurComplementSolver::CreatePreconditioner(
+ BlockSparseMatrix* A) {
+ if (options_.preconditioner_type == IDENTITY ||
+ preconditioner_.get() != NULL) {
+ return;
+ }
+
Preconditioner::Options preconditioner_options;
preconditioner_options.type = options_.preconditioner_type;
preconditioner_options.visibility_clustering_type =
@@ -120,63 +150,27 @@ LinearSolver::Summary IterativeSchurComplementSolver::SolveImpl(
preconditioner_options.e_block_size = options_.e_block_size;
preconditioner_options.f_block_size = options_.f_block_size;
preconditioner_options.elimination_groups = options_.elimination_groups;
+ CHECK(options_.context != NULL);
+ preconditioner_options.context = options_.context;
switch (options_.preconditioner_type) {
- case IDENTITY:
- break;
case JACOBI:
- preconditioner_.reset(
- new SparseMatrixPreconditionerWrapper(
- schur_complement_->block_diagonal_FtF_inverse()));
+ preconditioner_.reset(new SparseMatrixPreconditionerWrapper(
+ schur_complement_->block_diagonal_FtF_inverse()));
break;
case SCHUR_JACOBI:
- if (preconditioner_.get() == NULL) {
- preconditioner_.reset(
- new SchurJacobiPreconditioner(*A->block_structure(),
- preconditioner_options));
- }
+ preconditioner_.reset(new SchurJacobiPreconditioner(
+ *A->block_structure(), preconditioner_options));
break;
case CLUSTER_JACOBI:
case CLUSTER_TRIDIAGONAL:
- if (preconditioner_.get() == NULL) {
- preconditioner_.reset(
- new VisibilityBasedPreconditioner(*A->block_structure(),
- preconditioner_options));
- }
+ preconditioner_.reset(new VisibilityBasedPreconditioner(
+ *A->block_structure(), preconditioner_options));
break;
default:
LOG(FATAL) << "Unknown Preconditioner Type";
}
-
- bool preconditioner_update_was_successful = true;
- if (preconditioner_.get() != NULL) {
- preconditioner_update_was_successful =
- preconditioner_->Update(*A, per_solve_options.D);
- cg_per_solve_options.preconditioner = preconditioner_.get();
- }
- event_logger.AddEvent("Setup");
-
- LinearSolver::Summary cg_summary;
- cg_summary.num_iterations = 0;
- cg_summary.termination_type = LINEAR_SOLVER_FAILURE;
-
- // TODO(sameeragarwal): Refactor preconditioners to return a more
- // sane message.
- cg_summary.message = "Preconditioner update failed.";
- if (preconditioner_update_was_successful) {
- cg_summary = cg_solver.Solve(schur_complement_.get(),
- schur_complement_->rhs().data(),
- cg_per_solve_options,
- reduced_linear_system_solution_.data());
- if (cg_summary.termination_type != LINEAR_SOLVER_FAILURE &&
- cg_summary.termination_type != LINEAR_SOLVER_FATAL_ERROR) {
- schur_complement_->BackSubstitute(
- reduced_linear_system_solution_.data(), x);
- }
- }
- event_logger.AddEvent("Solve");
- return cg_summary;
-}
+};
} // namespace internal
} // namespace ceres
diff --git a/extern/ceres/internal/ceres/iterative_schur_complement_solver.h b/extern/ceres/internal/ceres/iterative_schur_complement_solver.h
index e90d310de07..9aed94fcb1a 100644
--- a/extern/ceres/internal/ceres/iterative_schur_complement_solver.h
+++ b/extern/ceres/internal/ceres/iterative_schur_complement_solver.h
@@ -31,9 +31,9 @@
#ifndef CERES_INTERNAL_ITERATIVE_SCHUR_COMPLEMENT_SOLVER_H_
#define CERES_INTERNAL_ITERATIVE_SCHUR_COMPLEMENT_SOLVER_H_
+#include <memory>
#include "ceres/linear_solver.h"
#include "ceres/internal/eigen.h"
-#include "ceres/internal/scoped_ptr.h"
#include "ceres/types.h"
namespace ceres {
@@ -70,20 +70,24 @@ class Preconditioner;
class IterativeSchurComplementSolver : public BlockSparseMatrixSolver {
public:
explicit IterativeSchurComplementSolver(const LinearSolver::Options& options);
+ IterativeSchurComplementSolver(const IterativeSchurComplementSolver&) = delete;
+ void operator=(const IterativeSchurComplementSolver&) = delete;
+
virtual ~IterativeSchurComplementSolver();
private:
- virtual LinearSolver::Summary SolveImpl(
+ LinearSolver::Summary SolveImpl(
BlockSparseMatrix* A,
const double* b,
const LinearSolver::PerSolveOptions& options,
- double* x);
+ double* x) final;
+
+ void CreatePreconditioner(BlockSparseMatrix* A);
LinearSolver::Options options_;
- scoped_ptr<internal::ImplicitSchurComplement> schur_complement_;
- scoped_ptr<Preconditioner> preconditioner_;
+ std::unique_ptr<internal::ImplicitSchurComplement> schur_complement_;
+ std::unique_ptr<Preconditioner> preconditioner_;
Vector reduced_linear_system_solution_;
- CERES_DISALLOW_COPY_AND_ASSIGN(IterativeSchurComplementSolver);
};
} // namespace internal
diff --git a/extern/ceres/internal/ceres/lapack.cc b/extern/ceres/internal/ceres/lapack.cc
index 6fc23f4e658..37efbcd27d1 100644
--- a/extern/ceres/internal/ceres/lapack.cc
+++ b/extern/ceres/internal/ceres/lapack.cc
@@ -34,6 +34,7 @@
#include "ceres/linear_solver.h"
#include "glog/logging.h"
+#ifndef CERES_NO_LAPACK
// C interface to the LAPACK Cholesky factorization and triangular solve.
extern "C" void dpotrf_(char* uplo,
int* n,
@@ -61,7 +62,7 @@ extern "C" void dgels_(char* uplo,
double* work,
int* lwork,
int* info);
-
+#endif
namespace ceres {
namespace internal {
diff --git a/extern/ceres/internal/ceres/levenberg_marquardt_strategy.cc b/extern/ceres/internal/ceres/levenberg_marquardt_strategy.cc
index e9833805ef5..9eec631e6dd 100644
--- a/extern/ceres/internal/ceres/levenberg_marquardt_strategy.cc
+++ b/extern/ceres/internal/ceres/levenberg_marquardt_strategy.cc
@@ -30,7 +30,9 @@
#include "ceres/levenberg_marquardt_strategy.h"
+#include <algorithm>
#include <cmath>
+
#include "Eigen/Core"
#include "ceres/array_utils.h"
#include "ceres/internal/eigen.h"
@@ -53,7 +55,7 @@ LevenbergMarquardtStrategy::LevenbergMarquardtStrategy(
max_diagonal_(options.max_lm_diagonal),
decrease_factor_(2.0),
reuse_diagonal_(false) {
- CHECK_NOTNULL(linear_solver_);
+ CHECK(linear_solver_ != nullptr);
CHECK_GT(min_diagonal_, 0.0);
CHECK_LE(min_diagonal_, max_diagonal_);
CHECK_GT(max_radius_, 0.0);
@@ -67,9 +69,9 @@ TrustRegionStrategy::Summary LevenbergMarquardtStrategy::ComputeStep(
SparseMatrix* jacobian,
const double* residuals,
double* step) {
- CHECK_NOTNULL(jacobian);
- CHECK_NOTNULL(residuals);
- CHECK_NOTNULL(step);
+ CHECK(jacobian != nullptr);
+ CHECK(residuals != nullptr);
+ CHECK(step != nullptr);
const int num_parameters = jacobian->num_cols();
if (!reuse_diagonal_) {
@@ -98,7 +100,7 @@ TrustRegionStrategy::Summary LevenbergMarquardtStrategy::ComputeStep(
// Invalidate the output array lm_step, so that we can detect if
// the linear solver generated numerical garbage. This is known
// to happen for the DENSE_QR and then DENSE_SCHUR solver when
- // the Jacobin is severly rank deficient and mu is too small.
+ // the Jacobin is severely rank deficient and mu is too small.
InvalidateArray(num_parameters, step);
// Instead of solving Jx = -r, solve Jy = r.
diff --git a/extern/ceres/internal/ceres/levenberg_marquardt_strategy.h b/extern/ceres/internal/ceres/levenberg_marquardt_strategy.h
index c87a016c8f4..8fb37f32959 100644
--- a/extern/ceres/internal/ceres/levenberg_marquardt_strategy.h
+++ b/extern/ceres/internal/ceres/levenberg_marquardt_strategy.h
@@ -49,14 +49,14 @@ class LevenbergMarquardtStrategy : public TrustRegionStrategy {
virtual ~LevenbergMarquardtStrategy();
// TrustRegionStrategy interface
- virtual TrustRegionStrategy::Summary ComputeStep(
+ TrustRegionStrategy::Summary ComputeStep(
const TrustRegionStrategy::PerSolveOptions& per_solve_options,
SparseMatrix* jacobian,
const double* residuals,
- double* step);
- virtual void StepAccepted(double step_quality);
- virtual void StepRejected(double step_quality);
- virtual void StepIsInvalid() {
+ double* step) final;
+ void StepAccepted(double step_quality) final;
+ void StepRejected(double step_quality) final;
+ void StepIsInvalid() final {
// Treat the current step as a rejected step with no increase in
// solution quality. Since rejected steps lead to decrease in the
// size of the trust region, the next time ComputeStep is called,
@@ -64,7 +64,7 @@ class LevenbergMarquardtStrategy : public TrustRegionStrategy {
StepRejected(0.0);
}
- virtual double Radius() const;
+ double Radius() const final;
private:
LinearSolver* linear_solver_;
diff --git a/extern/ceres/internal/ceres/line_search.cc b/extern/ceres/internal/ceres/line_search.cc
index 9cdcb7b77e5..352c64f5057 100644
--- a/extern/ceres/internal/ceres/line_search.cc
+++ b/extern/ceres/internal/ceres/line_search.cc
@@ -30,17 +30,19 @@
#include "ceres/line_search.h"
+#include <algorithm>
+#include <cmath>
#include <iomanip>
#include <iostream> // NOLINT
-#include "glog/logging.h"
#include "ceres/evaluator.h"
+#include "ceres/function_sample.h"
#include "ceres/internal/eigen.h"
-#include "ceres/fpclassify.h"
#include "ceres/map_util.h"
#include "ceres/polynomial.h"
#include "ceres/stringprintf.h"
#include "ceres/wall_time.h"
+#include "glog/logging.h"
namespace ceres {
namespace internal {
@@ -53,30 +55,8 @@ using std::vector;
namespace {
// Precision used for floating point values in error message output.
const int kErrorMessageNumericPrecision = 8;
-
-FunctionSample ValueSample(const double x, const double value) {
- FunctionSample sample;
- sample.x = x;
- sample.value = value;
- sample.value_is_valid = true;
- return sample;
-}
-
-FunctionSample ValueAndGradientSample(const double x,
- const double value,
- const double gradient) {
- FunctionSample sample;
- sample.x = x;
- sample.value = value;
- sample.gradient = gradient;
- sample.value_is_valid = true;
- sample.gradient_is_valid = true;
- return sample;
-}
-
} // namespace
-
ostream& operator<<(ostream &os, const FunctionSample& sample);
// Convenience stream operator for pushing FunctionSamples into log messages.
@@ -112,9 +92,7 @@ LineSearchFunction::LineSearchFunction(Evaluator* evaluator)
: evaluator_(evaluator),
position_(evaluator->NumParameters()),
direction_(evaluator->NumEffectiveParameters()),
- evaluation_point_(evaluator->NumParameters()),
scaled_direction_(evaluator->NumEffectiveParameters()),
- gradient_(evaluator->NumEffectiveParameters()),
initial_evaluator_residual_time_in_seconds(0.0),
initial_evaluator_jacobian_time_in_seconds(0.0) {}
@@ -124,27 +102,48 @@ void LineSearchFunction::Init(const Vector& position,
direction_ = direction;
}
-bool LineSearchFunction::Evaluate(double x, double* f, double* g) {
- scaled_direction_ = x * direction_;
+void LineSearchFunction::Evaluate(const double x,
+ const bool evaluate_gradient,
+ FunctionSample* output) {
+ output->x = x;
+ output->vector_x_is_valid = false;
+ output->value_is_valid = false;
+ output->gradient_is_valid = false;
+ output->vector_gradient_is_valid = false;
+
+ scaled_direction_ = output->x * direction_;
+ output->vector_x.resize(position_.rows(), 1);
if (!evaluator_->Plus(position_.data(),
scaled_direction_.data(),
- evaluation_point_.data())) {
- return false;
+ output->vector_x.data())) {
+ return;
}
+ output->vector_x_is_valid = true;
- if (g == NULL) {
- return (evaluator_->Evaluate(evaluation_point_.data(),
- f, NULL, NULL, NULL) &&
- IsFinite(*f));
+ double* gradient = NULL;
+ if (evaluate_gradient) {
+ output->vector_gradient.resize(direction_.rows(), 1);
+ gradient = output->vector_gradient.data();
}
+ const bool eval_status = evaluator_->Evaluate(
+ output->vector_x.data(), &(output->value), NULL, gradient, NULL);
- if (!evaluator_->Evaluate(evaluation_point_.data(),
- f, NULL, gradient_.data(), NULL)) {
- return false;
+ if (!eval_status || !std::isfinite(output->value)) {
+ return;
+ }
+
+ output->value_is_valid = true;
+ if (!evaluate_gradient) {
+ return;
+ }
+
+ output->gradient = direction_.dot(output->vector_gradient);
+ if (!std::isfinite(output->gradient)) {
+ return;
}
- *g = direction_.dot(gradient_);
- return IsFinite(*f) && IsFinite(*g);
+ output->gradient_is_valid = true;
+ output->vector_gradient_is_valid = true;
}
double LineSearchFunction::DirectionInfinityNorm() const {
@@ -152,21 +151,28 @@ double LineSearchFunction::DirectionInfinityNorm() const {
}
void LineSearchFunction::ResetTimeStatistics() {
- const map<string, double> evaluator_time_statistics =
- evaluator_->TimeStatistics();
+ const map<string, CallStatistics> evaluator_statistics =
+ evaluator_->Statistics();
+
initial_evaluator_residual_time_in_seconds =
- FindWithDefault(evaluator_time_statistics, "Evaluator::Residual", 0.0);
+ FindWithDefault(
+ evaluator_statistics, "Evaluator::Residual", CallStatistics())
+ .time;
initial_evaluator_jacobian_time_in_seconds =
- FindWithDefault(evaluator_time_statistics, "Evaluator::Jacobian", 0.0);
+ FindWithDefault(
+ evaluator_statistics, "Evaluator::Jacobian", CallStatistics())
+ .time;
}
void LineSearchFunction::TimeStatistics(
double* cost_evaluation_time_in_seconds,
double* gradient_evaluation_time_in_seconds) const {
- const map<string, double> evaluator_time_statistics =
- evaluator_->TimeStatistics();
+ const map<string, CallStatistics> evaluator_time_statistics =
+ evaluator_->Statistics();
*cost_evaluation_time_in_seconds =
- FindWithDefault(evaluator_time_statistics, "Evaluator::Residual", 0.0) -
+ FindWithDefault(
+ evaluator_time_statistics, "Evaluator::Residual", CallStatistics())
+ .time -
initial_evaluator_residual_time_in_seconds;
// Strictly speaking this will slightly underestimate the time spent
// evaluating the gradient of the line search univariate cost function as it
@@ -175,7 +181,9 @@ void LineSearchFunction::TimeStatistics(
// allows direct subtraction of the timing information from the totals for
// the evaluator returned in the solver summary.
*gradient_evaluation_time_in_seconds =
- FindWithDefault(evaluator_time_statistics, "Evaluator::Jacobian", 0.0) -
+ FindWithDefault(
+ evaluator_time_statistics, "Evaluator::Jacobian", CallStatistics())
+ .time -
initial_evaluator_jacobian_time_in_seconds;
}
@@ -184,12 +192,12 @@ void LineSearch::Search(double step_size_estimate,
double initial_gradient,
Summary* summary) const {
const double start_time = WallTimeInSeconds();
- *CHECK_NOTNULL(summary) = LineSearch::Summary();
+ CHECK(summary != nullptr);
+ *summary = LineSearch::Summary();
summary->cost_evaluation_time_in_seconds = 0.0;
summary->gradient_evaluation_time_in_seconds = 0.0;
summary->polynomial_minimization_time_in_seconds = 0.0;
-
options().function->ResetTimeStatistics();
this->DoSearch(step_size_estimate, initial_cost, initial_gradient, summary);
options().function->
@@ -243,12 +251,12 @@ double LineSearch::InterpolatingPolynomialMinimizingStepSize(
if (interpolation_type == QUADRATIC) {
// Two point interpolation using function values and the
// gradient at the lower bound.
- samples.push_back(ValueSample(current.x, current.value));
+ samples.push_back(FunctionSample(current.x, current.value));
if (previous.value_is_valid) {
// Three point interpolation, using function values and the
// gradient at the lower bound.
- samples.push_back(ValueSample(previous.x, previous.value));
+ samples.push_back(FunctionSample(previous.x, previous.value));
}
} else if (interpolation_type == CUBIC) {
// Two point interpolation using the function values and the gradients.
@@ -286,34 +294,26 @@ void ArmijoLineSearch::DoSearch(const double step_size_estimate,
// Note initial_cost & initial_gradient are evaluated at step_size = 0,
// not step_size_estimate, which is our starting guess.
- const FunctionSample initial_position =
- ValueAndGradientSample(0.0, initial_cost, initial_gradient);
+ FunctionSample initial_position(0.0, initial_cost, initial_gradient);
+ initial_position.vector_x = function->position();
+ initial_position.vector_x_is_valid = true;
- FunctionSample previous = ValueAndGradientSample(0.0, 0.0, 0.0);
- previous.value_is_valid = false;
-
- FunctionSample current = ValueAndGradientSample(step_size_estimate, 0.0, 0.0);
- current.value_is_valid = false;
+ const double descent_direction_max_norm = function->DirectionInfinityNorm();
+ FunctionSample previous;
+ FunctionSample current;
// As the Armijo line search algorithm always uses the initial point, for
// which both the function value and derivative are known, when fitting a
// minimizing polynomial, we can fit up to a quadratic without requiring the
// gradient at the current query point.
- const bool interpolation_uses_gradient_at_current_sample =
- options().interpolation_type == CUBIC;
- const double descent_direction_max_norm = function->DirectionInfinityNorm();
+ const bool kEvaluateGradient = options().interpolation_type == CUBIC;
++summary->num_function_evaluations;
- if (interpolation_uses_gradient_at_current_sample) {
+ if (kEvaluateGradient) {
++summary->num_gradient_evaluations;
}
- current.value_is_valid =
- function->Evaluate(current.x,
- &current.value,
- interpolation_uses_gradient_at_current_sample
- ? &current.gradient : NULL);
- current.gradient_is_valid =
- interpolation_uses_gradient_at_current_sample && current.value_is_valid;
+
+ function->Evaluate(step_size_estimate, kEvaluateGradient, &current);
while (!current.value_is_valid ||
current.value > (initial_cost
+ options().sufficient_decrease
@@ -354,22 +354,16 @@ void ArmijoLineSearch::DoSearch(const double step_size_estimate,
}
previous = current;
- current.x = step_size;
++summary->num_function_evaluations;
- if (interpolation_uses_gradient_at_current_sample) {
+ if (kEvaluateGradient) {
++summary->num_gradient_evaluations;
}
- current.value_is_valid =
- function->Evaluate(current.x,
- &current.value,
- interpolation_uses_gradient_at_current_sample
- ? &current.gradient : NULL);
- current.gradient_is_valid =
- interpolation_uses_gradient_at_current_sample && current.value_is_valid;
+
+ function->Evaluate(step_size, kEvaluateGradient, &current);
}
- summary->optimal_step_size = current.x;
+ summary->optimal_point = current;
summary->success = true;
}
@@ -391,9 +385,9 @@ void WolfeLineSearch::DoSearch(const double step_size_estimate,
// Note initial_cost & initial_gradient are evaluated at step_size = 0,
// not step_size_estimate, which is our starting guess.
- const FunctionSample initial_position =
- ValueAndGradientSample(0.0, initial_cost, initial_gradient);
-
+ FunctionSample initial_position(0.0, initial_cost, initial_gradient);
+ initial_position.vector_x = options().function->position();
+ initial_position.vector_x_is_valid = true;
bool do_zoom_search = false;
// Important: The high/low in bracket_high & bracket_low refer to their
// _function_ values, not their step sizes i.e. it is _not_ required that
@@ -435,7 +429,7 @@ void WolfeLineSearch::DoSearch(const double step_size_estimate,
// produce a valid point when ArmijoLineSearch would succeed, we return the
// point with the lowest cost found thus far which satsifies the Armijo
// condition (but not the Wolfe conditions).
- summary->optimal_step_size = bracket_low.x;
+ summary->optimal_point = bracket_low;
summary->success = true;
return;
}
@@ -481,11 +475,13 @@ void WolfeLineSearch::DoSearch(const double step_size_estimate,
// satisfies the strong Wolfe curvature condition, that we return the point
// amongst those found thus far, which minimizes f() and satisfies the Armijo
// condition.
- solution =
- solution.value_is_valid && solution.value <= bracket_low.value
- ? solution : bracket_low;
- summary->optimal_step_size = solution.x;
+ if (!solution.value_is_valid || solution.value > bracket_low.value) {
+ summary->optimal_point = bracket_low;
+ } else {
+ summary->optimal_point = solution;
+ }
+
summary->success = true;
}
@@ -515,8 +511,7 @@ bool WolfeLineSearch::BracketingPhase(
LineSearchFunction* function = options().function;
FunctionSample previous = initial_position;
- FunctionSample current = ValueAndGradientSample(step_size_estimate, 0.0, 0.0);
- current.value_is_valid = false;
+ FunctionSample current;
const double descent_direction_max_norm =
function->DirectionInfinityNorm();
@@ -535,12 +530,8 @@ bool WolfeLineSearch::BracketingPhase(
// issues).
++summary->num_function_evaluations;
++summary->num_gradient_evaluations;
- current.value_is_valid =
- function->Evaluate(current.x,
- &current.value,
- &current.gradient);
- current.gradient_is_valid = current.value_is_valid;
-
+ const bool kEvaluateGradient = true;
+ function->Evaluate(step_size_estimate, kEvaluateGradient, &current);
while (true) {
++summary->num_iterations;
@@ -637,7 +628,18 @@ bool WolfeLineSearch::BracketingPhase(
// being a boundary of a bracket.
// If f(current) is valid, (but meets no criteria) expand the search by
- // increasing the step size.
+ // increasing the step size. If f(current) is invalid, contract the step
+ // size.
+ //
+ // In Nocedal & Wright [1] (p60), the step-size can only increase in the
+ // bracketing phase: step_size_{k+1} \in [step_size_k, step_size_k * factor].
+ // However this does not account for the function returning invalid values
+ // which we support, in which case we need to contract the step size whilst
+ // ensuring that we do not invert the bracket, i.e, we require that:
+ // step_size_{k-1} <= step_size_{k+1} < step_size_k.
+ const double min_step_size =
+ current.value_is_valid
+ ? current.x : previous.x;
const double max_step_size =
current.value_is_valid
? (current.x * options().max_step_expansion) : current.x;
@@ -656,7 +658,7 @@ bool WolfeLineSearch::BracketingPhase(
previous,
unused_previous,
current,
- previous.x,
+ min_step_size,
max_step_size);
summary->polynomial_minimization_time_in_seconds +=
(WallTimeInSeconds() - polynomial_minimization_start_time);
@@ -669,16 +671,14 @@ bool WolfeLineSearch::BracketingPhase(
return false;
}
+ // Only advance the lower boundary (in x) of the bracket if f(current)
+ // is valid such that we can support contracting the step size when
+ // f(current) is invalid without risking inverting the bracket in x, i.e.
+ // prevent previous.x > current.x.
previous = current.value_is_valid ? current : previous;
- current.x = step_size;
-
++summary->num_function_evaluations;
++summary->num_gradient_evaluations;
- current.value_is_valid =
- function->Evaluate(current.x,
- &current.value,
- &current.gradient);
- current.gradient_is_valid = current.value_is_valid;
+ function->Evaluate(step_size, kEvaluateGradient, &current);
}
// Ensure that even if a valid bracket was found, we will only mark a zoom
@@ -799,7 +799,7 @@ bool WolfeLineSearch::ZoomPhase(const FunctionSample& initial_position,
const FunctionSample unused_previous;
DCHECK(!unused_previous.value_is_valid);
const double polynomial_minimization_start_time = WallTimeInSeconds();
- solution->x =
+ const double step_size =
this->InterpolatingPolynomialMinimizingStepSize(
options().interpolation_type,
lower_bound_step,
@@ -823,12 +823,9 @@ bool WolfeLineSearch::ZoomPhase(const FunctionSample& initial_position,
// to numerical issues).
++summary->num_function_evaluations;
++summary->num_gradient_evaluations;
- solution->value_is_valid =
- function->Evaluate(solution->x,
- &solution->value,
- &solution->gradient);
- solution->gradient_is_valid = solution->value_is_valid;
- if (!solution->value_is_valid) {
+ const bool kEvaluateGradient = true;
+ function->Evaluate(step_size, kEvaluateGradient, solution);
+ if (!solution->value_is_valid || !solution->gradient_is_valid) {
summary->error =
StringPrintf("Line search failed: Wolfe Zoom phase found "
"step_size: %.5e, for which function is invalid, "
diff --git a/extern/ceres/internal/ceres/line_search.h b/extern/ceres/internal/ceres/line_search.h
index 6a21cbeac11..d59fd777367 100644
--- a/extern/ceres/internal/ceres/line_search.h
+++ b/extern/ceres/internal/ceres/line_search.h
@@ -35,6 +35,7 @@
#include <string>
#include <vector>
+#include "ceres/function_sample.h"
#include "ceres/internal/eigen.h"
#include "ceres/internal/port.h"
#include "ceres/types.h"
@@ -43,7 +44,6 @@ namespace ceres {
namespace internal {
class Evaluator;
-struct FunctionSample;
class LineSearchFunction;
// Line search is another name for a one dimensional optimization
@@ -51,7 +51,7 @@ class LineSearchFunction;
// dimensional optimization problems that arise as subproblems of
// general multidimensional optimization problems.
//
-// While finding the exact minimum of a one dimensionl function is
+// While finding the exact minimum of a one dimensional function is
// hard, instances of LineSearch find a point that satisfies a
// sufficient decrease condition. Depending on the particular
// condition used, we get a variety of different line search
@@ -61,21 +61,9 @@ class LineSearch {
struct Summary;
struct Options {
- Options()
- : interpolation_type(CUBIC),
- sufficient_decrease(1e-4),
- max_step_contraction(1e-3),
- min_step_contraction(0.9),
- min_step_size(1e-9),
- max_num_iterations(20),
- sufficient_curvature_decrease(0.9),
- max_step_expansion(10.0),
- is_silent(false),
- function(NULL) {}
-
// Degree of the polynomial used to approximate the objective
// function.
- LineSearchInterpolationType interpolation_type;
+ LineSearchInterpolationType interpolation_type = CUBIC;
// Armijo and Wolfe line search parameters.
@@ -88,7 +76,7 @@ class LineSearch {
// s.t.
//
// f(step_size) <= f(0) + sufficient_decrease * f'(0) * step_size
- double sufficient_decrease;
+ double sufficient_decrease = 1e-4;
// In each iteration of the Armijo / Wolfe line search,
//
@@ -98,7 +86,7 @@ class LineSearch {
//
// 0 < max_step_contraction < min_step_contraction < 1
//
- double max_step_contraction;
+ double max_step_contraction = 1e-3;
// In each iteration of the Armijo / Wolfe line search,
//
@@ -107,16 +95,16 @@ class LineSearch {
//
// 0 < max_step_contraction < min_step_contraction < 1
//
- double min_step_contraction;
+ double min_step_contraction = 0.9;
// If during the line search, the step_size falls below this
// value, it is truncated to zero.
- double min_step_size;
+ double min_step_size = 1e-9;
// Maximum number of trial step size iterations during each line search,
// if a step size satisfying the search conditions cannot be found within
// this number of trials, the line search will terminate.
- int max_num_iterations;
+ int max_num_iterations = 20;
// Wolfe-specific line search parameters.
@@ -131,7 +119,7 @@ class LineSearch {
//
// Where f() is the line search objective and f'() is the derivative
// of f w.r.t step_size (d f / d step_size).
- double sufficient_curvature_decrease;
+ double sufficient_curvature_decrease = 0.9;
// During the bracketing phase of the Wolfe search, the step size is
// increased until either a point satisfying the Wolfe conditions is
@@ -142,43 +130,32 @@ class LineSearch {
// new_step_size <= max_step_expansion * step_size.
//
// By definition for expansion, max_step_expansion > 1.0.
- double max_step_expansion;
+ double max_step_expansion = 10;
- bool is_silent;
+ bool is_silent = false;
// The one dimensional function that the line search algorithm
// minimizes.
- LineSearchFunction* function;
+ LineSearchFunction* function = nullptr;
};
// Result of the line search.
struct Summary {
- Summary()
- : success(false),
- optimal_step_size(0.0),
- num_function_evaluations(0),
- num_gradient_evaluations(0),
- num_iterations(0),
- cost_evaluation_time_in_seconds(-1.0),
- gradient_evaluation_time_in_seconds(-1.0),
- polynomial_minimization_time_in_seconds(-1.0),
- total_time_in_seconds(-1.0) {}
-
- bool success;
- double optimal_step_size;
- int num_function_evaluations;
- int num_gradient_evaluations;
- int num_iterations;
+ bool success = false;
+ FunctionSample optimal_point;
+ int num_function_evaluations = 0;
+ int num_gradient_evaluations = 0;
+ int num_iterations = 0;
// Cumulative time spent evaluating the value of the cost function across
// all iterations.
- double cost_evaluation_time_in_seconds;
+ double cost_evaluation_time_in_seconds = 0.0;
// Cumulative time spent evaluating the gradient of the cost function across
// all iterations.
- double gradient_evaluation_time_in_seconds;
+ double gradient_evaluation_time_in_seconds = 0.0;
// Cumulative time spent minimizing the interpolating polynomial to compute
// the next candidate step size across all iterations.
- double polynomial_minimization_time_in_seconds;
- double total_time_in_seconds;
+ double polynomial_minimization_time_in_seconds = 0.0;
+ double total_time_in_seconds = 0.0;
std::string error;
};
@@ -234,6 +211,7 @@ class LineSearchFunction {
public:
explicit LineSearchFunction(Evaluator* evaluator);
void Init(const Vector& position, const Vector& direction);
+
// Evaluate the line search objective
//
// f(x) = p(position + x * direction)
@@ -241,27 +219,29 @@ class LineSearchFunction {
// Where, p is the objective function of the general optimization
// problem.
//
- // g is the gradient f'(x) at x.
+ // evaluate_gradient controls whether the gradient will be evaluated
+ // or not.
//
- // f must not be null. The gradient is computed only if g is not null.
- bool Evaluate(double x, double* f, double* g);
+ // On return output->*_is_valid indicate indicate whether the
+ // corresponding fields have numerically valid values or not.
+ void Evaluate(double x, bool evaluate_gradient, FunctionSample* output);
+
double DirectionInfinityNorm() const;
+
// Resets to now, the start point for the results from TimeStatistics().
void ResetTimeStatistics();
void TimeStatistics(double* cost_evaluation_time_in_seconds,
double* gradient_evaluation_time_in_seconds) const;
+ const Vector& position() const { return position_; }
+ const Vector& direction() const { return direction_; }
private:
Evaluator* evaluator_;
Vector position_;
Vector direction_;
- // evaluation_point = Evaluator::Plus(position_, x * direction_);
- Vector evaluation_point_;
-
// scaled_direction = x * direction_;
Vector scaled_direction_;
- Vector gradient_;
// We may not exclusively own the evaluator (e.g. in the Trust Region
// minimizer), hence we need to save the initial evaluation durations for the
@@ -282,10 +262,10 @@ class ArmijoLineSearch : public LineSearch {
virtual ~ArmijoLineSearch() {}
private:
- virtual void DoSearch(double step_size_estimate,
- double initial_cost,
- double initial_gradient,
- Summary* summary) const;
+ void DoSearch(double step_size_estimate,
+ double initial_cost,
+ double initial_gradient,
+ Summary* summary) const final;
};
// Bracketing / Zoom Strong Wolfe condition line search. This implementation
@@ -315,10 +295,10 @@ class WolfeLineSearch : public LineSearch {
Summary* summary) const;
private:
- virtual void DoSearch(double step_size_estimate,
- double initial_cost,
- double initial_gradient,
- Summary* summary) const;
+ void DoSearch(double step_size_estimate,
+ double initial_cost,
+ double initial_gradient,
+ Summary* summary) const final;
};
} // namespace internal
diff --git a/extern/ceres/internal/ceres/line_search_minimizer.cc b/extern/ceres/internal/ceres/line_search_minimizer.cc
index fdde1ca9c86..931f56c960c 100644
--- a/extern/ceres/internal/ceres/line_search_minimizer.cc
+++ b/extern/ceres/internal/ceres/line_search_minimizer.cc
@@ -43,6 +43,7 @@
#include <algorithm>
#include <cstdlib>
#include <cmath>
+#include <memory>
#include <string>
#include <vector>
@@ -51,7 +52,6 @@
#include "ceres/evaluator.h"
#include "ceres/internal/eigen.h"
#include "ceres/internal/port.h"
-#include "ceres/internal/scoped_ptr.h"
#include "ceres/line_search.h"
#include "ceres/line_search_direction.h"
#include "ceres/stringprintf.h"
@@ -63,27 +63,14 @@ namespace ceres {
namespace internal {
namespace {
-// TODO(sameeragarwal): I think there is a small bug here, in that if
-// the evaluation fails, then the state can contain garbage. Look at
-// this more carefully.
-bool Evaluate(Evaluator* evaluator,
- const Vector& x,
- LineSearchMinimizer::State* state,
- std::string* message) {
- if (!evaluator->Evaluate(x.data(),
- &(state->cost),
- NULL,
- state->gradient.data(),
- NULL)) {
- *message = "Gradient evaluation failed.";
- return false;
- }
-
+bool EvaluateGradientNorms(Evaluator* evaluator,
+ const Vector& x,
+ LineSearchMinimizer::State* state,
+ std::string* message) {
Vector negative_gradient = -state->gradient;
Vector projected_gradient_step(x.size());
- if (!evaluator->Plus(x.data(),
- negative_gradient.data(),
- projected_gradient_step.data())) {
+ if (!evaluator->Plus(
+ x.data(), negative_gradient.data(), projected_gradient_step.data())) {
*message = "projected_gradient_step = Plus(x, -gradient) failed.";
return false;
}
@@ -103,7 +90,8 @@ void LineSearchMinimizer::Minimize(const Minimizer::Options& options,
double start_time = WallTimeInSeconds();
double iteration_start_time = start_time;
- Evaluator* evaluator = CHECK_NOTNULL(options.evaluator.get());
+ CHECK(options.evaluator != nullptr);
+ Evaluator* evaluator = options.evaluator.get();
const int num_parameters = evaluator->NumParameters();
const int num_effective_parameters = evaluator->NumEffectiveParameters();
@@ -116,9 +104,6 @@ void LineSearchMinimizer::Minimize(const Minimizer::Options& options,
State current_state(num_parameters, num_effective_parameters);
State previous_state(num_parameters, num_effective_parameters);
- Vector delta(num_effective_parameters);
- Vector x_plus_delta(num_parameters);
-
IterationSummary iteration_summary;
iteration_summary.iteration = 0;
iteration_summary.step_is_valid = false;
@@ -130,8 +115,19 @@ void LineSearchMinimizer::Minimize(const Minimizer::Options& options,
iteration_summary.linear_solver_iterations = 0;
iteration_summary.step_solver_time_in_seconds = 0;
- // Do initial cost and Jacobian evaluation.
- if (!Evaluate(evaluator, x, &current_state, &summary->message)) {
+ // Do initial cost and gradient evaluation.
+ if (!evaluator->Evaluate(x.data(),
+ &(current_state.cost),
+ nullptr,
+ current_state.gradient.data(),
+ nullptr)) {
+ summary->termination_type = FAILURE;
+ summary->message = "Initial cost and jacobian evaluation failed.";
+ LOG_IF(WARNING, is_not_silent) << "Terminating: " << summary->message;
+ return;
+ }
+
+ if (!EvaluateGradientNorms(evaluator, x, &current_state, &summary->message)) {
summary->termination_type = FAILURE;
summary->message = "Initial cost and jacobian evaluation failed. "
"More details: " + summary->message;
@@ -142,9 +138,8 @@ void LineSearchMinimizer::Minimize(const Minimizer::Options& options,
summary->initial_cost = current_state.cost + summary->fixed_cost;
iteration_summary.cost = current_state.cost + summary->fixed_cost;
- iteration_summary.gradient_max_norm = current_state.gradient_max_norm;
iteration_summary.gradient_norm = sqrt(current_state.gradient_squared_norm);
-
+ iteration_summary.gradient_max_norm = current_state.gradient_max_norm;
if (iteration_summary.gradient_max_norm <= options.gradient_tolerance) {
summary->message = StringPrintf("Gradient tolerance reached. "
"Gradient max norm: %e <= %e",
@@ -170,7 +165,7 @@ void LineSearchMinimizer::Minimize(const Minimizer::Options& options,
line_search_direction_options.max_lbfgs_rank = options.max_lbfgs_rank;
line_search_direction_options.use_approximate_eigenvalue_bfgs_scaling =
options.use_approximate_eigenvalue_bfgs_scaling;
- scoped_ptr<LineSearchDirection> line_search_direction(
+ std::unique_ptr<LineSearchDirection> line_search_direction(
LineSearchDirection::Create(line_search_direction_options));
LineSearchFunction line_search_function(evaluator);
@@ -194,11 +189,11 @@ void LineSearchMinimizer::Minimize(const Minimizer::Options& options,
line_search_options.is_silent = options.is_silent;
line_search_options.function = &line_search_function;
- scoped_ptr<LineSearch>
+ std::unique_ptr<LineSearch>
line_search(LineSearch::Create(options.line_search_type,
line_search_options,
&summary->message));
- if (line_search.get() == NULL) {
+ if (line_search.get() == nullptr) {
summary->termination_type = FAILURE;
LOG_IF(ERROR, is_not_silent) << "Terminating: " << summary->message;
return;
@@ -326,28 +321,37 @@ void LineSearchMinimizer::Minimize(const Minimizer::Options& options,
break;
}
- current_state.step_size = line_search_summary.optimal_step_size;
- delta = current_state.step_size * current_state.search_direction;
-
+ const FunctionSample& optimal_point = line_search_summary.optimal_point;
+ CHECK(optimal_point.vector_x_is_valid)
+ << "Congratulations, you found a bug in Ceres. Please report it.";
+ current_state.step_size = optimal_point.x;
previous_state = current_state;
iteration_summary.step_solver_time_in_seconds =
WallTimeInSeconds() - iteration_start_time;
- const double x_norm = x.norm();
-
- if (!evaluator->Plus(x.data(), delta.data(), x_plus_delta.data())) {
- summary->termination_type = FAILURE;
- summary->message =
- "x_plus_delta = Plus(x, delta) failed. This should not happen "
- "as the step was valid when it was selected by the line search.";
- LOG_IF(WARNING, is_not_silent) << "Terminating: " << summary->message;
- break;
+ if (optimal_point.vector_gradient_is_valid) {
+ current_state.cost = optimal_point.value;
+ current_state.gradient = optimal_point.vector_gradient;
+ } else {
+ Evaluator::EvaluateOptions evaluate_options;
+ evaluate_options.new_evaluation_point = false;
+ if (!evaluator->Evaluate(evaluate_options,
+ optimal_point.vector_x.data(),
+ &(current_state.cost),
+ nullptr,
+ current_state.gradient.data(),
+ nullptr)) {
+ summary->termination_type = FAILURE;
+ summary->message = "Cost and jacobian evaluation failed.";
+ LOG_IF(WARNING, is_not_silent) << "Terminating: " << summary->message;
+ return;
+ }
}
- if (!Evaluate(evaluator,
- x_plus_delta,
- &current_state,
- &summary->message)) {
+ if (!EvaluateGradientNorms(evaluator,
+ optimal_point.vector_x,
+ &current_state,
+ &summary->message)) {
summary->termination_type = FAILURE;
summary->message =
"Step failed to evaluate. This should not happen as the step was "
@@ -358,8 +362,9 @@ void LineSearchMinimizer::Minimize(const Minimizer::Options& options,
}
// Compute the norm of the step in the ambient space.
- iteration_summary.step_norm = (x_plus_delta - x).norm();
- x = x_plus_delta;
+ iteration_summary.step_norm = (optimal_point.vector_x - x).norm();
+ const double x_norm = x.norm();
+ x = optimal_point.vector_x;
iteration_summary.gradient_max_norm = current_state.gradient_max_norm;
iteration_summary.gradient_norm = sqrt(current_state.gradient_squared_norm);
@@ -380,6 +385,7 @@ void LineSearchMinimizer::Minimize(const Minimizer::Options& options,
iteration_summary.cumulative_time_in_seconds =
WallTimeInSeconds() - start_time
+ summary->preprocessor_time_in_seconds;
+ summary->iterations.push_back(iteration_summary);
// Iterations inside the line search algorithm are considered
// 'steps' in the broader context, to distinguish these inner
@@ -423,20 +429,18 @@ void LineSearchMinimizer::Minimize(const Minimizer::Options& options,
}
const double absolute_function_tolerance =
- options.function_tolerance * previous_state.cost;
- if (fabs(iteration_summary.cost_change) <= absolute_function_tolerance) {
- summary->message =
- StringPrintf("Function tolerance reached. "
- "|cost_change|/cost: %e <= %e",
- fabs(iteration_summary.cost_change) /
- previous_state.cost,
- options.function_tolerance);
+ options.function_tolerance * std::abs(previous_state.cost);
+ if (std::abs(iteration_summary.cost_change) <=
+ absolute_function_tolerance) {
+ summary->message = StringPrintf(
+ "Function tolerance reached. "
+ "|cost_change|/cost: %e <= %e",
+ std::abs(iteration_summary.cost_change) / previous_state.cost,
+ options.function_tolerance);
summary->termination_type = CONVERGENCE;
VLOG_IF(1, is_not_silent) << "Terminating: " << summary->message;
break;
}
-
- summary->iterations.push_back(iteration_summary);
}
}
diff --git a/extern/ceres/internal/ceres/line_search_minimizer.h b/extern/ceres/internal/ceres/line_search_minimizer.h
index 54b7202e0c3..191128a933b 100644
--- a/extern/ceres/internal/ceres/line_search_minimizer.h
+++ b/extern/ceres/internal/ceres/line_search_minimizer.h
@@ -66,9 +66,9 @@ class LineSearchMinimizer : public Minimizer {
};
~LineSearchMinimizer() {}
- virtual void Minimize(const Minimizer::Options& options,
- double* parameters,
- Solver::Summary* summary);
+ void Minimize(const Minimizer::Options& options,
+ double* parameters,
+ Solver::Summary* summary) final;
};
} // namespace internal
diff --git a/extern/ceres/internal/ceres/line_search_preprocessor.cc b/extern/ceres/internal/ceres/line_search_preprocessor.cc
index 831f5e8d079..5a21809e509 100644
--- a/extern/ceres/internal/ceres/line_search_preprocessor.cc
+++ b/extern/ceres/internal/ceres/line_search_preprocessor.cc
@@ -32,6 +32,8 @@
#include <numeric>
#include <string>
+#include "ceres/casts.h"
+#include "ceres/context_impl.h"
#include "ceres/evaluator.h"
#include "ceres/minimizer.h"
#include "ceres/problem_impl.h"
@@ -57,6 +59,9 @@ bool SetupEvaluator(PreprocessedProblem* pp) {
pp->evaluator_options.linear_solver_type = CGNR;
pp->evaluator_options.num_eliminate_blocks = 0;
pp->evaluator_options.num_threads = pp->options.num_threads;
+ pp->evaluator_options.context = pp->problem->context();
+ pp->evaluator_options.evaluation_callback =
+ pp->reduced_program->mutable_evaluation_callback();
pp->evaluator.reset(Evaluator::Create(pp->evaluator_options,
pp->reduced_program.get(),
&pp->error));
@@ -71,7 +76,7 @@ LineSearchPreprocessor::~LineSearchPreprocessor() {
bool LineSearchPreprocessor::Preprocess(const Solver::Options& options,
ProblemImpl* problem,
PreprocessedProblem* pp) {
- CHECK_NOTNULL(pp);
+ CHECK(pp != nullptr);
pp->options = options;
ChangeNumThreadsIfNeeded(&pp->options);
diff --git a/extern/ceres/internal/ceres/line_search_preprocessor.h b/extern/ceres/internal/ceres/line_search_preprocessor.h
index 132d83a0a9a..12ccb53e011 100644
--- a/extern/ceres/internal/ceres/line_search_preprocessor.h
+++ b/extern/ceres/internal/ceres/line_search_preprocessor.h
@@ -39,9 +39,9 @@ namespace internal {
class LineSearchPreprocessor : public Preprocessor {
public:
virtual ~LineSearchPreprocessor();
- virtual bool Preprocess(const Solver::Options& options,
- ProblemImpl* problem,
- PreprocessedProblem* preprocessed_problem);
+ bool Preprocess(const Solver::Options& options,
+ ProblemImpl* problem,
+ PreprocessedProblem* preprocessed_problem) final;
};
} // namespace internal
diff --git a/extern/ceres/internal/ceres/linear_least_squares_problems.cc b/extern/ceres/internal/ceres/linear_least_squares_problems.cc
index 0a69375f7b5..7c523d399e1 100644
--- a/extern/ceres/internal/ceres/linear_least_squares_problems.cc
+++ b/extern/ceres/internal/ceres/linear_least_squares_problems.cc
@@ -31,13 +31,14 @@
#include "ceres/linear_least_squares_problems.h"
#include <cstdio>
+#include <memory>
#include <string>
#include <vector>
+
#include "ceres/block_sparse_matrix.h"
#include "ceres/block_structure.h"
#include "ceres/casts.h"
#include "ceres/file.h"
-#include "ceres/internal/scoped_ptr.h"
#include "ceres/stringprintf.h"
#include "ceres/triplet_sparse_matrix.h"
#include "ceres/types.h"
@@ -297,7 +298,7 @@ LinearLeastSquaresProblem* LinearLeastSquaresProblem2() {
problem->num_eliminate_blocks = 2;
CompressedRowBlockStructure* bs = new CompressedRowBlockStructure;
- scoped_array<double> values(new double[num_rows * num_cols]);
+ std::unique_ptr<double[]> values(new double[num_rows * num_cols]);
for (int c = 0; c < num_cols; ++c) {
bs->cols.push_back(Block());
@@ -431,7 +432,7 @@ LinearLeastSquaresProblem* LinearLeastSquaresProblem3() {
problem->num_eliminate_blocks = 2;
CompressedRowBlockStructure* bs = new CompressedRowBlockStructure;
- scoped_array<double> values(new double[num_rows * num_cols]);
+ std::unique_ptr<double[]> values(new double[num_rows * num_cols]);
for (int c = 0; c < num_cols; ++c) {
bs->cols.push_back(Block());
@@ -538,7 +539,7 @@ LinearLeastSquaresProblem* LinearLeastSquaresProblem4() {
problem->num_eliminate_blocks = 1;
CompressedRowBlockStructure* bs = new CompressedRowBlockStructure;
- scoped_array<double> values(new double[num_rows * num_cols]);
+ std::unique_ptr<double[]> values(new double[num_rows * num_cols]);
// Column block structure
bs->cols.push_back(Block());
@@ -613,7 +614,7 @@ bool DumpLinearLeastSquaresProblemToConsole(const SparseMatrix* A,
const double* b,
const double* x,
int num_eliminate_blocks) {
- CHECK_NOTNULL(A);
+ CHECK(A != nullptr);
Matrix AA;
A->ToDenseMatrix(&AA);
LOG(INFO) << "A^T: \n" << AA.transpose();
@@ -636,10 +637,10 @@ bool DumpLinearLeastSquaresProblemToConsole(const SparseMatrix* A,
void WriteArrayToFileOrDie(const string& filename,
const double* x,
const int size) {
- CHECK_NOTNULL(x);
+ CHECK(x != nullptr);
VLOG(2) << "Writing array to: " << filename;
FILE* fptr = fopen(filename.c_str(), "w");
- CHECK_NOTNULL(fptr);
+ CHECK(fptr != nullptr);
for (int i = 0; i < size; ++i) {
fprintf(fptr, "%17f\n", x[i]);
}
@@ -652,7 +653,7 @@ bool DumpLinearLeastSquaresProblemToTextFile(const string& filename_base,
const double* b,
const double* x,
int num_eliminate_blocks) {
- CHECK_NOTNULL(A);
+ CHECK(A != nullptr);
LOG(INFO) << "writing to: " << filename_base << "*";
string matlab_script;
@@ -666,7 +667,7 @@ bool DumpLinearLeastSquaresProblemToTextFile(const string& filename_base,
{
string filename = filename_base + "_A.txt";
FILE* fptr = fopen(filename.c_str(), "w");
- CHECK_NOTNULL(fptr);
+ CHECK(fptr != nullptr);
A->ToTextFile(fptr);
fclose(fptr);
StringAppendF(&matlab_script,
diff --git a/extern/ceres/internal/ceres/linear_least_squares_problems.h b/extern/ceres/internal/ceres/linear_least_squares_problems.h
index 384efb59a2b..5dfcd34e109 100644
--- a/extern/ceres/internal/ceres/linear_least_squares_problems.h
+++ b/extern/ceres/internal/ceres/linear_least_squares_problems.h
@@ -31,11 +31,11 @@
#ifndef CERES_INTERNAL_LINEAR_LEAST_SQUARES_PROBLEMS_H_
#define CERES_INTERNAL_LINEAR_LEAST_SQUARES_PROBLEMS_H_
+#include <memory>
#include <string>
#include <vector>
#include "ceres/sparse_matrix.h"
#include "ceres/internal/port.h"
-#include "ceres/internal/scoped_ptr.h"
namespace ceres {
namespace internal {
@@ -44,21 +44,20 @@ namespace internal {
// ground truth solutions. To be used by various LinearSolver tests.
struct LinearLeastSquaresProblem {
LinearLeastSquaresProblem()
- : A(NULL), b(NULL), D(NULL), num_eliminate_blocks(0),
- x(NULL), x_D(NULL) {
+ : num_eliminate_blocks(0) {
}
- scoped_ptr<SparseMatrix> A;
- scoped_array<double> b;
- scoped_array<double> D;
+ std::unique_ptr<SparseMatrix> A;
+ std::unique_ptr<double[]> b;
+ std::unique_ptr<double[]> D;
// If using the schur eliminator then how many of the variable
// blocks are e_type blocks.
int num_eliminate_blocks;
// Solution to min_x |Ax - b|^2
- scoped_array<double> x;
+ std::unique_ptr<double[]> x;
// Solution to min_x |Ax - b|^2 + |Dx|^2
- scoped_array<double> x_D;
+ std::unique_ptr<double[]> x_D;
};
// Factories for linear least squares problem.
diff --git a/extern/ceres/internal/ceres/linear_solver.cc b/extern/ceres/internal/ceres/linear_solver.cc
index 38e4625f747..107af6afcc8 100644
--- a/extern/ceres/internal/ceres/linear_solver.cc
+++ b/extern/ceres/internal/ceres/linear_solver.cc
@@ -35,6 +35,7 @@
#include "ceres/dense_qr_solver.h"
#include "ceres/iterative_schur_complement_solver.h"
#include "ceres/schur_complement_solver.h"
+#include "ceres/dynamic_sparse_normal_cholesky_solver.h"
#include "ceres/sparse_normal_cholesky_solver.h"
#include "ceres/types.h"
#include "glog/logging.h"
@@ -70,23 +71,25 @@ LinearSolverType LinearSolver::LinearSolverForZeroEBlocks(
}
LinearSolver* LinearSolver::Create(const LinearSolver::Options& options) {
+ CHECK(options.context != NULL);
+
switch (options.type) {
case CGNR:
return new CgnrSolver(options);
case SPARSE_NORMAL_CHOLESKY:
-#if defined(CERES_NO_SUITESPARSE) && \
- defined(CERES_NO_CXSPARSE) && \
- !defined(CERES_USE_EIGEN_SPARSE)
+#if defined(CERES_NO_SPARSE)
return NULL;
#else
+ if (options.dynamic_sparsity) {
+ return new DynamicSparseNormalCholeskySolver(options);
+ }
+
return new SparseNormalCholeskySolver(options);
#endif
case SPARSE_SCHUR:
-#if defined(CERES_NO_SUITESPARSE) && \
- defined(CERES_NO_CXSPARSE) && \
- !defined(CERES_USE_EIGEN_SPARSE)
+#if defined(CERES_NO_SPARSE)
return NULL;
#else
return new SparseSchurComplementSolver(options);
diff --git a/extern/ceres/internal/ceres/linear_solver.h b/extern/ceres/internal/ceres/linear_solver.h
index fb9332ca6e3..cb624b372dd 100644
--- a/extern/ceres/internal/ceres/linear_solver.h
+++ b/extern/ceres/internal/ceres/linear_solver.h
@@ -41,6 +41,7 @@
#include "ceres/block_sparse_matrix.h"
#include "ceres/casts.h"
#include "ceres/compressed_row_sparse_matrix.h"
+#include "ceres/context_impl.h"
#include "ceres/dense_sparse_matrix.h"
#include "ceres/execution_summary.h"
#include "ceres/triplet_sparse_matrix.h"
@@ -69,6 +70,16 @@ enum LinearSolverTerminationType {
LINEAR_SOLVER_FATAL_ERROR
};
+// This enum controls the fill-reducing ordering a sparse linear
+// algebra library should use before computing a sparse factorization
+// (usually Cholesky).
+enum OrderingType {
+ NATURAL, // Do not re-order the matrix. This is useful when the
+ // matrix has been ordered using a fill-reducing ordering
+ // already.
+ AMD // Use the Approximate Minimum Degree algorithm to re-order
+ // the matrix.
+};
class LinearOperator;
@@ -91,42 +102,25 @@ class LinearOperator;
class LinearSolver {
public:
struct Options {
- Options()
- : type(SPARSE_NORMAL_CHOLESKY),
- preconditioner_type(JACOBI),
- visibility_clustering_type(CANONICAL_VIEWS),
- dense_linear_algebra_library_type(EIGEN),
- sparse_linear_algebra_library_type(SUITE_SPARSE),
- use_postordering(false),
- dynamic_sparsity(false),
- use_explicit_schur_complement(false),
- min_num_iterations(1),
- max_num_iterations(1),
- num_threads(1),
- residual_reset_period(10),
- row_block_size(Eigen::Dynamic),
- e_block_size(Eigen::Dynamic),
- f_block_size(Eigen::Dynamic) {
- }
-
- LinearSolverType type;
- PreconditionerType preconditioner_type;
- VisibilityClusteringType visibility_clustering_type;
- DenseLinearAlgebraLibraryType dense_linear_algebra_library_type;
- SparseLinearAlgebraLibraryType sparse_linear_algebra_library_type;
+ LinearSolverType type = SPARSE_NORMAL_CHOLESKY;
+ PreconditionerType preconditioner_type = JACOBI;
+ VisibilityClusteringType visibility_clustering_type = CANONICAL_VIEWS;
+ DenseLinearAlgebraLibraryType dense_linear_algebra_library_type = EIGEN;
+ SparseLinearAlgebraLibraryType sparse_linear_algebra_library_type =
+ SUITE_SPARSE;
// See solver.h for information about these flags.
- bool use_postordering;
- bool dynamic_sparsity;
- bool use_explicit_schur_complement;
+ bool use_postordering = false;
+ bool dynamic_sparsity = false;
+ bool use_explicit_schur_complement = false;
// Number of internal iterations that the solver uses. This
// parameter only makes sense for iterative solvers like CG.
- int min_num_iterations;
- int max_num_iterations;
+ int min_num_iterations = 1;
+ int max_num_iterations = 1;
// If possible, how many threads can the solver use.
- int num_threads;
+ int num_threads = 1;
// Hints about the order in which the parameter blocks should be
// eliminated by the linear solver.
@@ -151,7 +145,7 @@ class LinearSolver {
// inaccurate over time. Thus for non-zero values of this
// parameter, the solver can be told to recalculate the value of
// the residual using a |b - Ax| evaluation.
- int residual_reset_period;
+ int residual_reset_period = 10;
// If the block sizes in a BlockSparseMatrix are fixed, then in
// some cases the Schur complement based solvers can detect and
@@ -162,20 +156,18 @@ class LinearSolver {
//
// Please see schur_complement_solver.h and schur_eliminator.h for
// more details.
- int row_block_size;
- int e_block_size;
- int f_block_size;
+ int row_block_size = Eigen::Dynamic;
+ int e_block_size = Eigen::Dynamic;
+ int f_block_size = Eigen::Dynamic;
+
+ bool use_mixed_precision_solves = false;
+ int max_num_refinement_iterations = 0;
+ int subset_preconditioner_start_row_block = -1;
+ ContextImpl* context = nullptr;
};
// Options for the Solve method.
struct PerSolveOptions {
- PerSolveOptions()
- : D(NULL),
- preconditioner(NULL),
- r_tolerance(0.0),
- q_tolerance(0.0) {
- }
-
// This option only makes sense for unsymmetric linear solvers
// that can solve rectangular linear systems.
//
@@ -199,7 +191,7 @@ class LinearSolver {
// does not have full column rank, the results returned by the
// solver cannot be relied on. D, if it is not null is an array of
// size n. b is an array of size m and x is an array of size n.
- double * D;
+ double* D = nullptr;
// This option only makes sense for iterative solvers.
//
@@ -221,7 +213,7 @@ class LinearSolver {
//
// A null preconditioner is equivalent to an identity matrix being
// used a preconditioner.
- LinearOperator* preconditioner;
+ LinearOperator* preconditioner = nullptr;
// The following tolerance related options only makes sense for
@@ -233,7 +225,7 @@ class LinearSolver {
//
// This is the most commonly used termination criterion for
// iterative solvers.
- double r_tolerance;
+ double r_tolerance = 0.0;
// For PSD matrices A, let
//
@@ -257,22 +249,16 @@ class LinearSolver {
// Journal of Computational and Applied Mathematics,
// 124(1-2), 45-59, 2000.
//
- double q_tolerance;
+ double q_tolerance = 0.0;
};
// Summary of a call to the Solve method. We should move away from
// the true/false method for determining solver success. We should
// let the summary object do the talking.
struct Summary {
- Summary()
- : residual_norm(0.0),
- num_iterations(-1),
- termination_type(LINEAR_SOLVER_FAILURE) {
- }
-
- double residual_norm;
- int num_iterations;
- LinearSolverTerminationType termination_type;
+ double residual_norm = -1.0;
+ int num_iterations = -1;
+ LinearSolverTerminationType termination_type = LINEAR_SOLVER_FAILURE;
std::string message;
};
@@ -292,16 +278,12 @@ class LinearSolver {
const PerSolveOptions& per_solve_options,
double* x) = 0;
- // The following two methods return copies instead of references so
- // that the base class implementation does not have to worry about
- // life time issues. Further, these calls are not expected to be
- // frequent or performance sensitive.
- virtual std::map<std::string, int> CallStatistics() const {
- return std::map<std::string, int>();
- }
-
- virtual std::map<std::string, double> TimeStatistics() const {
- return std::map<std::string, double>();
+ // This method returns copies instead of references so that the base
+ // class implementation does not have to worry about life time
+ // issues. Further, this calls are not expected to be frequent or
+ // performance sensitive.
+ virtual std::map<std::string, CallStatistics> Statistics() const {
+ return std::map<std::string, CallStatistics>();
}
// Factory
@@ -325,18 +307,14 @@ class TypedLinearSolver : public LinearSolver {
const LinearSolver::PerSolveOptions& per_solve_options,
double* x) {
ScopedExecutionTimer total_time("LinearSolver::Solve", &execution_summary_);
- CHECK_NOTNULL(A);
- CHECK_NOTNULL(b);
- CHECK_NOTNULL(x);
+ CHECK(A != nullptr);
+ CHECK(b != nullptr);
+ CHECK(x != nullptr);
return SolveImpl(down_cast<MatrixType*>(A), b, per_solve_options, x);
}
- virtual std::map<std::string, int> CallStatistics() const {
- return execution_summary_.calls();
- }
-
- virtual std::map<std::string, double> TimeStatistics() const {
- return execution_summary_.times();
+ virtual std::map<std::string, CallStatistics> Statistics() const {
+ return execution_summary_.statistics();
}
private:
diff --git a/extern/ceres/internal/ceres/local_parameterization.cc b/extern/ceres/internal/ceres/local_parameterization.cc
index a6bf1f6ddcc..97fdbed3eda 100644
--- a/extern/ceres/internal/ceres/local_parameterization.cc
+++ b/extern/ceres/internal/ceres/local_parameterization.cc
@@ -31,10 +31,11 @@
#include "ceres/local_parameterization.h"
#include <algorithm>
+
#include "Eigen/Geometry"
-#include "ceres/householder_vector.h"
#include "ceres/internal/eigen.h"
#include "ceres/internal/fixed_array.h"
+#include "ceres/internal/householder_vector.h"
#include "ceres/rotation.h"
#include "glog/logging.h"
@@ -42,13 +43,16 @@ namespace ceres {
using std::vector;
-LocalParameterization::~LocalParameterization() {
-}
+LocalParameterization::~LocalParameterization() {}
bool LocalParameterization::MultiplyByJacobian(const double* x,
const int num_rows,
const double* global_matrix,
double* local_matrix) const {
+ if (LocalSize() == 0) {
+ return true;
+ }
+
Matrix jacobian(GlobalSize(), LocalSize());
if (!ComputeJacobian(x, jacobian.data())) {
return false;
@@ -74,7 +78,7 @@ bool IdentityParameterization::Plus(const double* x,
bool IdentityParameterization::ComputeJacobian(const double* x,
double* jacobian) const {
- MatrixRef(jacobian, size_, size_) = Matrix::Identity(size_, size_);
+ MatrixRef(jacobian, size_, size_).setIdentity();
return true;
}
@@ -82,9 +86,8 @@ bool IdentityParameterization::MultiplyByJacobian(const double* x,
const int num_cols,
const double* global_matrix,
double* local_matrix) const {
- std::copy(global_matrix,
- global_matrix + num_cols * GlobalSize(),
- local_matrix);
+ std::copy(
+ global_matrix, global_matrix + num_cols * GlobalSize(), local_matrix);
return true;
}
@@ -93,8 +96,8 @@ SubsetParameterization::SubsetParameterization(
: local_size_(size - constant_parameters.size()), constancy_mask_(size, 0) {
vector<int> constant = constant_parameters;
std::sort(constant.begin(), constant.end());
- CHECK_GE(constant.front(), 0)
- << "Indices indicating constant parameter must be greater than zero.";
+ CHECK_GE(constant.front(), 0) << "Indices indicating constant parameter must "
+ "be greater than equal to zero.";
CHECK_LT(constant.back(), size)
<< "Indices indicating constant parameter must be less than the size "
<< "of the parameter block.";
@@ -108,7 +111,8 @@ SubsetParameterization::SubsetParameterization(
bool SubsetParameterization::Plus(const double* x,
const double* delta,
double* x_plus_delta) const {
- for (int i = 0, j = 0; i < constancy_mask_.size(); ++i) {
+ const int global_size = GlobalSize();
+ for (int i = 0, j = 0; i < global_size; ++i) {
if (constancy_mask_[i]) {
x_plus_delta[i] = x[i];
} else {
@@ -124,9 +128,10 @@ bool SubsetParameterization::ComputeJacobian(const double* x,
return true;
}
- MatrixRef m(jacobian, constancy_mask_.size(), local_size_);
+ const int global_size = GlobalSize();
+ MatrixRef m(jacobian, global_size, local_size_);
m.setZero();
- for (int i = 0, j = 0; i < constancy_mask_.size(); ++i) {
+ for (int i = 0, j = 0; i < global_size; ++i) {
if (!constancy_mask_[i]) {
m(i, j++) = 1.0;
}
@@ -135,18 +140,19 @@ bool SubsetParameterization::ComputeJacobian(const double* x,
}
bool SubsetParameterization::MultiplyByJacobian(const double* x,
- const int num_rows,
- const double* global_matrix,
- double* local_matrix) const {
+ const int num_cols,
+ const double* global_matrix,
+ double* local_matrix) const {
if (local_size_ == 0) {
return true;
}
- for (int row = 0; row < num_rows; ++row) {
- for (int col = 0, j = 0; col < constancy_mask_.size(); ++col) {
- if (!constancy_mask_[col]) {
- local_matrix[row * LocalSize() + j++] =
- global_matrix[row * GlobalSize() + col];
+ const int global_size = GlobalSize();
+ for (int col = 0; col < num_cols; ++col) {
+ for (int i = 0, j = 0; i < global_size; ++i) {
+ if (!constancy_mask_[i]) {
+ local_matrix[col * local_size_ + j++] =
+ global_matrix[col * global_size + i];
}
}
}
@@ -176,10 +182,12 @@ bool QuaternionParameterization::Plus(const double* x,
bool QuaternionParameterization::ComputeJacobian(const double* x,
double* jacobian) const {
- jacobian[0] = -x[1]; jacobian[1] = -x[2]; jacobian[2] = -x[3]; // NOLINT
- jacobian[3] = x[0]; jacobian[4] = x[3]; jacobian[5] = -x[2]; // NOLINT
- jacobian[6] = -x[3]; jacobian[7] = x[0]; jacobian[8] = x[1]; // NOLINT
- jacobian[9] = x[2]; jacobian[10] = -x[1]; jacobian[11] = x[0]; // NOLINT
+ // clang-format off
+ jacobian[0] = -x[1]; jacobian[1] = -x[2]; jacobian[2] = -x[3];
+ jacobian[3] = x[0]; jacobian[4] = x[3]; jacobian[5] = -x[2];
+ jacobian[6] = -x[3]; jacobian[7] = x[0]; jacobian[8] = x[1];
+ jacobian[9] = x[2]; jacobian[10] = -x[1]; jacobian[11] = x[0];
+ // clang-format on
return true;
}
@@ -209,10 +217,12 @@ bool EigenQuaternionParameterization::Plus(const double* x_ptr,
bool EigenQuaternionParameterization::ComputeJacobian(const double* x,
double* jacobian) const {
- jacobian[0] = x[3]; jacobian[1] = x[2]; jacobian[2] = -x[1]; // NOLINT
- jacobian[3] = -x[2]; jacobian[4] = x[3]; jacobian[5] = x[0]; // NOLINT
- jacobian[6] = x[1]; jacobian[7] = -x[0]; jacobian[8] = x[3]; // NOLINT
- jacobian[9] = -x[0]; jacobian[10] = -x[1]; jacobian[11] = -x[2]; // NOLINT
+ // clang-format off
+ jacobian[0] = x[3]; jacobian[1] = x[2]; jacobian[2] = -x[1];
+ jacobian[3] = -x[2]; jacobian[4] = x[3]; jacobian[5] = x[0];
+ jacobian[6] = x[1]; jacobian[7] = -x[0]; jacobian[8] = x[3];
+ jacobian[9] = -x[0]; jacobian[10] = -x[1]; jacobian[11] = -x[2];
+ // clang-format on
return true;
}
@@ -241,21 +251,26 @@ bool HomogeneousVectorParameterization::Plus(const double* x_ptr,
// (2nd Edition) for a detailed description. Note there is a typo on Page
// 625, line 4 so check the book errata.
const double norm_delta_div_2 = 0.5 * norm_delta;
- const double sin_delta_by_delta = sin(norm_delta_div_2) /
- norm_delta_div_2;
+ const double sin_delta_by_delta =
+ std::sin(norm_delta_div_2) / norm_delta_div_2;
Vector y(size_);
y.head(size_ - 1) = 0.5 * sin_delta_by_delta * delta;
- y(size_ - 1) = cos(norm_delta_div_2);
+ y(size_ - 1) = std::cos(norm_delta_div_2);
Vector v(size_);
double beta;
- internal::ComputeHouseholderVector<double>(x, &v, &beta);
+
+ // NOTE: The explicit template arguments are needed here because
+ // ComputeHouseholderVector is templated and some versions of MSVC
+ // have trouble deducing the type of v automatically.
+ internal::ComputeHouseholderVector<ConstVectorRef, double, Eigen::Dynamic>(
+ x, &v, &beta);
// Apply the delta update to remain on the unit sphere. See section A6.9.3
// on page 625 of Hartley & Zisserman (2nd Edition) for a detailed
// description.
- x_plus_delta = x.norm() * (y - v * (beta * (v.transpose() * y)));
+ x_plus_delta = x.norm() * (y - v * (beta * (v.transpose() * y)));
return true;
}
@@ -267,7 +282,12 @@ bool HomogeneousVectorParameterization::ComputeJacobian(
Vector v(size_);
double beta;
- internal::ComputeHouseholderVector<double>(x, &v, &beta);
+
+ // NOTE: The explicit template arguments are needed here because
+ // ComputeHouseholderVector is templated and some versions of MSVC
+ // have trouble deducing the type of v automatically.
+ internal::ComputeHouseholderVector<ConstVectorRef, double, Eigen::Dynamic>(
+ x, &v, &beta);
// The Jacobian is equal to J = 0.5 * H.leftCols(size_ - 1) where H is the
// Householder matrix (H = I - beta * v * v').
@@ -280,65 +300,14 @@ bool HomogeneousVectorParameterization::ComputeJacobian(
return true;
}
-ProductParameterization::ProductParameterization(
- LocalParameterization* local_param1,
- LocalParameterization* local_param2) {
- local_params_.push_back(local_param1);
- local_params_.push_back(local_param2);
- Init();
-}
-
-ProductParameterization::ProductParameterization(
- LocalParameterization* local_param1,
- LocalParameterization* local_param2,
- LocalParameterization* local_param3) {
- local_params_.push_back(local_param1);
- local_params_.push_back(local_param2);
- local_params_.push_back(local_param3);
- Init();
-}
-
-ProductParameterization::ProductParameterization(
- LocalParameterization* local_param1,
- LocalParameterization* local_param2,
- LocalParameterization* local_param3,
- LocalParameterization* local_param4) {
- local_params_.push_back(local_param1);
- local_params_.push_back(local_param2);
- local_params_.push_back(local_param3);
- local_params_.push_back(local_param4);
- Init();
-}
-
-ProductParameterization::~ProductParameterization() {
- for (int i = 0; i < local_params_.size(); ++i) {
- delete local_params_[i];
- }
-}
-
-void ProductParameterization::Init() {
- global_size_ = 0;
- local_size_ = 0;
- buffer_size_ = 0;
- for (int i = 0; i < local_params_.size(); ++i) {
- const LocalParameterization* param = local_params_[i];
- buffer_size_ = std::max(buffer_size_,
- param->LocalSize() * param->GlobalSize());
- global_size_ += param->GlobalSize();
- local_size_ += param->LocalSize();
- }
-}
-
bool ProductParameterization::Plus(const double* x,
const double* delta,
double* x_plus_delta) const {
int x_cursor = 0;
int delta_cursor = 0;
- for (int i = 0; i < local_params_.size(); ++i) {
- const LocalParameterization* param = local_params_[i];
- if (!param->Plus(x + x_cursor,
- delta + delta_cursor,
- x_plus_delta + x_cursor)) {
+ for (const auto& param : local_params_) {
+ if (!param->Plus(
+ x + x_cursor, delta + delta_cursor, x_plus_delta + x_cursor)) {
return false;
}
delta_cursor += param->LocalSize();
@@ -356,16 +325,15 @@ bool ProductParameterization::ComputeJacobian(const double* x,
int x_cursor = 0;
int delta_cursor = 0;
- for (int i = 0; i < local_params_.size(); ++i) {
- const LocalParameterization* param = local_params_[i];
+ for (const auto& param : local_params_) {
const int local_size = param->LocalSize();
const int global_size = param->GlobalSize();
- if (!param->ComputeJacobian(x + x_cursor, buffer.get())) {
+ if (!param->ComputeJacobian(x + x_cursor, buffer.data())) {
return false;
}
- jacobian.block(x_cursor, delta_cursor, global_size, local_size)
- = MatrixRef(buffer.get(), global_size, local_size);
+ jacobian.block(x_cursor, delta_cursor, global_size, local_size) =
+ MatrixRef(buffer.data(), global_size, local_size);
delta_cursor += local_size;
x_cursor += global_size;
diff --git a/extern/ceres/internal/ceres/loss_function.cc b/extern/ceres/internal/ceres/loss_function.cc
index eb5026784dd..2c21a7377ca 100644
--- a/extern/ceres/internal/ceres/loss_function.cc
+++ b/extern/ceres/internal/ceres/loss_function.cc
@@ -32,6 +32,7 @@
#include "ceres/loss_function.h"
+#include <algorithm>
#include <cmath>
#include <cstddef>
#include <limits>
@@ -101,7 +102,9 @@ void TolerantLoss::Evaluate(double s, double rho[3]) const {
// large, it will overflow. Since numerically 1 + e^x == e^x when the
// x is greater than about ln(2^53) for doubles, beyond this threshold
// we substitute x for ln(1 + e^x) as a numerically equivalent approximation.
- static const double kLog2Pow53 = 36.7; // ln(MathLimits<double>::kEpsilon).
+
+ // ln(MathLimits<double>::kEpsilon).
+ static constexpr double kLog2Pow53 = 36.7;
if (x > kLog2Pow53) {
rho[0] = s - a_ - c_;
rho[1] = 1.0;
@@ -119,12 +122,12 @@ void TukeyLoss::Evaluate(double s, double* rho) const {
// Inlier region.
const double value = 1.0 - s / a_squared_;
const double value_sq = value * value;
- rho[0] = a_squared_ / 6.0 * (1.0 - value_sq * value);
- rho[1] = 0.5 * value_sq;
- rho[2] = -1.0 / a_squared_ * value;
+ rho[0] = a_squared_ / 3.0 * (1.0 - value_sq * value);
+ rho[1] = value_sq;
+ rho[2] = -2.0 / a_squared_ * value;
} else {
// Outlier region.
- rho[0] = a_squared_ / 6.0;
+ rho[0] = a_squared_ / 3.0;
rho[1] = 0.0;
rho[2] = 0.0;
}
@@ -132,10 +135,12 @@ void TukeyLoss::Evaluate(double s, double* rho) const {
ComposedLoss::ComposedLoss(const LossFunction* f, Ownership ownership_f,
const LossFunction* g, Ownership ownership_g)
- : f_(CHECK_NOTNULL(f)),
- g_(CHECK_NOTNULL(g)),
+ : f_(f),
+ g_(g),
ownership_f_(ownership_f),
ownership_g_(ownership_g) {
+ CHECK(f_ != nullptr);
+ CHECK(g_ != nullptr);
}
ComposedLoss::~ComposedLoss() {
diff --git a/extern/ceres/internal/ceres/low_rank_inverse_hessian.cc b/extern/ceres/internal/ceres/low_rank_inverse_hessian.cc
index 1c6c9925f1c..f3953c46006 100644
--- a/extern/ceres/internal/ceres/low_rank_inverse_hessian.cc
+++ b/extern/ceres/internal/ceres/low_rank_inverse_hessian.cc
@@ -175,12 +175,10 @@ void LowRankInverseHessian::RightMultiply(const double* x_ptr,
<< "approximation.";
}
- for (list<int>::const_iterator it = indices_.begin();
- it != indices_.end();
- ++it) {
- const double beta = delta_gradient_history_.col(*it).dot(search_direction) /
- delta_x_dot_delta_gradient_(*it);
- search_direction += delta_x_history_.col(*it) * (alpha(*it) - beta);
+ for (const int i : indices_) {
+ const double beta = delta_gradient_history_.col(i).dot(search_direction) /
+ delta_x_dot_delta_gradient_(i);
+ search_direction += delta_x_history_.col(i) * (alpha(i) - beta);
}
}
diff --git a/extern/ceres/internal/ceres/low_rank_inverse_hessian.h b/extern/ceres/internal/ceres/low_rank_inverse_hessian.h
index 2c768c2ca53..0028a988923 100644
--- a/extern/ceres/internal/ceres/low_rank_inverse_hessian.h
+++ b/extern/ceres/internal/ceres/low_rank_inverse_hessian.h
@@ -54,7 +54,7 @@ namespace internal {
// enhanced with scaling rule by Byrd, Nocedal and Schanbel.
//
// Nocedal, J. (1980). "Updating Quasi-Newton Matrices with Limited
-// Storage". Mathematics of Computation 35 (151): 773–782.
+// Storage". Mathematics of Computation 35 (151): 773-782.
//
// Byrd, R. H.; Nocedal, J.; Schnabel, R. B. (1994).
// "Representations of Quasi-Newton Matrices and their use in
@@ -84,12 +84,12 @@ class LowRankInverseHessian : public LinearOperator {
bool Update(const Vector& delta_x, const Vector& delta_gradient);
// LinearOperator interface
- virtual void RightMultiply(const double* x, double* y) const;
- virtual void LeftMultiply(const double* x, double* y) const {
+ void RightMultiply(const double* x, double* y) const final;
+ void LeftMultiply(const double* x, double* y) const final {
RightMultiply(x, y);
}
- virtual int num_rows() const { return num_parameters_; }
- virtual int num_cols() const { return num_parameters_; }
+ int num_rows() const final { return num_parameters_; }
+ int num_cols() const final { return num_parameters_; }
private:
const int num_parameters_;
diff --git a/extern/ceres/internal/ceres/minimizer.h b/extern/ceres/internal/ceres/minimizer.h
index b59372806e7..afdd60d2944 100644
--- a/extern/ceres/internal/ceres/minimizer.h
+++ b/extern/ceres/internal/ceres/minimizer.h
@@ -31,6 +31,7 @@
#ifndef CERES_INTERNAL_MINIMIZER_H_
#define CERES_INTERNAL_MINIMIZER_H_
+#include <memory>
#include <string>
#include <vector>
#include "ceres/internal/port.h"
@@ -167,19 +168,19 @@ class Minimizer {
// Object responsible for evaluating the cost, residuals and
// Jacobian matrix.
- shared_ptr<Evaluator> evaluator;
+ std::shared_ptr<Evaluator> evaluator;
// Object responsible for actually computing the trust region
// step, and sizing the trust region radius.
- shared_ptr<TrustRegionStrategy> trust_region_strategy;
+ std::shared_ptr<TrustRegionStrategy> trust_region_strategy;
// Object holding the Jacobian matrix. It is assumed that the
// sparsity structure of the matrix has already been initialized
// and will remain constant for the life time of the
// optimization.
- shared_ptr<SparseMatrix> jacobian;
+ std::shared_ptr<SparseMatrix> jacobian;
- shared_ptr<CoordinateDescentMinimizer> inner_iteration_minimizer;
+ std::shared_ptr<CoordinateDescentMinimizer> inner_iteration_minimizer;
};
static Minimizer* Create(MinimizerType minimizer_type);
diff --git a/extern/ceres/internal/ceres/mutex.h b/extern/ceres/internal/ceres/mutex.h
deleted file mode 100644
index 2ce97772755..00000000000
--- a/extern/ceres/internal/ceres/mutex.h
+++ /dev/null
@@ -1,329 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
-// http://ceres-solver.org/
-//
-// 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.
-//
-// Author: Craig Silverstein.
-//
-// A simple mutex wrapper, supporting locks and read-write locks.
-// You should assume the locks are *not* re-entrant.
-//
-// This class is meant to be internal-only and should be wrapped by an
-// internal namespace. Before you use this module, please give the
-// name of your internal namespace for this module. Or, if you want
-// to expose it, you'll want to move it to the Google namespace. We
-// cannot put this class in global namespace because there can be some
-// problems when we have multiple versions of Mutex in each shared object.
-//
-// NOTE: by default, we have #ifdef'ed out the TryLock() method.
-// This is for two reasons:
-// 1) TryLock() under Windows is a bit annoying (it requires a
-// #define to be defined very early).
-// 2) TryLock() is broken for NO_THREADS mode, at least in NDEBUG
-// mode.
-// If you need TryLock(), and either these two caveats are not a
-// problem for you, or you're willing to work around them, then
-// feel free to #define GMUTEX_TRYLOCK, or to remove the #ifdefs
-// in the code below.
-//
-// CYGWIN NOTE: Cygwin support for rwlock seems to be buggy:
-// http://www.cygwin.com/ml/cygwin/2008-12/msg00017.html
-// Because of that, we might as well use windows locks for
-// cygwin. They seem to be more reliable than the cygwin pthreads layer.
-//
-// TRICKY IMPLEMENTATION NOTE:
-// This class is designed to be safe to use during
-// dynamic-initialization -- that is, by global constructors that are
-// run before main() starts. The issue in this case is that
-// dynamic-initialization happens in an unpredictable order, and it
-// could be that someone else's dynamic initializer could call a
-// function that tries to acquire this mutex -- but that all happens
-// before this mutex's constructor has run. (This can happen even if
-// the mutex and the function that uses the mutex are in the same .cc
-// file.) Basically, because Mutex does non-trivial work in its
-// constructor, it's not, in the naive implementation, safe to use
-// before dynamic initialization has run on it.
-//
-// The solution used here is to pair the actual mutex primitive with a
-// bool that is set to true when the mutex is dynamically initialized.
-// (Before that it's false.) Then we modify all mutex routines to
-// look at the bool, and not try to lock/unlock until the bool makes
-// it to true (which happens after the Mutex constructor has run.)
-//
-// This works because before main() starts -- particularly, during
-// dynamic initialization -- there are no threads, so a) it's ok that
-// the mutex operations are a no-op, since we don't need locking then
-// anyway; and b) we can be quite confident our bool won't change
-// state between a call to Lock() and a call to Unlock() (that would
-// require a global constructor in one translation unit to call Lock()
-// and another global constructor in another translation unit to call
-// Unlock() later, which is pretty perverse).
-//
-// That said, it's tricky, and can conceivably fail; it's safest to
-// avoid trying to acquire a mutex in a global constructor, if you
-// can. One way it can fail is that a really smart compiler might
-// initialize the bool to true at static-initialization time (too
-// early) rather than at dynamic-initialization time. To discourage
-// that, we set is_safe_ to true in code (not the constructor
-// colon-initializer) and set it to true via a function that always
-// evaluates to true, but that the compiler can't know always
-// evaluates to true. This should be good enough.
-
-#ifndef CERES_INTERNAL_MUTEX_H_
-#define CERES_INTERNAL_MUTEX_H_
-
-#include "ceres/internal/port.h"
-
-#if defined(CERES_NO_THREADS)
- typedef int MutexType; // to keep a lock-count
-#elif defined(_WIN32) || defined(__CYGWIN32__) || defined(__CYGWIN64__)
-# define CERES_WIN32_LEAN_AND_MEAN // We only need minimal includes
-# ifdef CERES_GMUTEX_TRYLOCK
- // We need Windows NT or later for TryEnterCriticalSection(). If you
- // don't need that functionality, you can remove these _WIN32_WINNT
- // lines, and change TryLock() to assert(0) or something.
-# ifndef _WIN32_WINNT
-# define _WIN32_WINNT 0x0400
-# endif
-# endif
-// Unfortunately, windows.h defines a bunch of macros with common
-// names. Two in particular need avoiding: ERROR and min/max.
-// To avoid macro definition of ERROR.
-# define NOGDI
-// To avoid macro definition of min/max.
-# ifndef NOMINMAX
-# define NOMINMAX
-# endif
-# include <windows.h>
- typedef CRITICAL_SECTION MutexType;
-#elif defined(CERES_HAVE_PTHREAD) && defined(CERES_HAVE_RWLOCK)
- // Needed for pthread_rwlock_*. If it causes problems, you could take it
- // out, but then you'd have to unset CERES_HAVE_RWLOCK (at least on linux --
- // it *does* cause problems for FreeBSD, or MacOSX, but isn't needed for
- // locking there.)
-# if defined(__linux__) && !defined(_XOPEN_SOURCE)
-# define _XOPEN_SOURCE 500 // may be needed to get the rwlock calls
-# endif
-# include <pthread.h>
- typedef pthread_rwlock_t MutexType;
-#elif defined(CERES_HAVE_PTHREAD)
-# include <pthread.h>
- typedef pthread_mutex_t MutexType;
-#else
-# error Need to implement mutex.h for your architecture, or #define NO_THREADS
-#endif
-
-// We need to include these header files after defining _XOPEN_SOURCE
-// as they may define the _XOPEN_SOURCE macro.
-#include <assert.h>
-#include <stdlib.h> // for abort()
-
-namespace ceres {
-namespace internal {
-
-class Mutex {
- public:
- // Create a Mutex that is not held by anybody. This constructor is
- // typically used for Mutexes allocated on the heap or the stack.
- // See below for a recommendation for constructing global Mutex
- // objects.
- inline Mutex();
-
- // Destructor
- inline ~Mutex();
-
- inline void Lock(); // Block if needed until free then acquire exclusively
- inline void Unlock(); // Release a lock acquired via Lock()
-#ifdef CERES_GMUTEX_TRYLOCK
- inline bool TryLock(); // If free, Lock() and return true, else return false
-#endif
- // Note that on systems that don't support read-write locks, these may
- // be implemented as synonyms to Lock() and Unlock(). So you can use
- // these for efficiency, but don't use them anyplace where being able
- // to do shared reads is necessary to avoid deadlock.
- inline void ReaderLock(); // Block until free or shared then acquire a share
- inline void ReaderUnlock(); // Release a read share of this Mutex
- inline void WriterLock() { Lock(); } // Acquire an exclusive lock
- inline void WriterUnlock() { Unlock(); } // Release a lock from WriterLock()
-
- // TODO(hamaji): Do nothing, implement correctly.
- inline void AssertHeld() {}
-
- private:
- MutexType mutex_;
- // We want to make sure that the compiler sets is_safe_ to true only
- // when we tell it to, and never makes assumptions is_safe_ is
- // always true. volatile is the most reliable way to do that.
- volatile bool is_safe_;
-
- inline void SetIsSafe() { is_safe_ = true; }
-
- // Catch the error of writing Mutex when intending MutexLock.
- Mutex(Mutex* /*ignored*/) {}
- // Disallow "evil" constructors
- Mutex(const Mutex&);
- void operator=(const Mutex&);
-};
-
-// Now the implementation of Mutex for various systems
-#if defined(CERES_NO_THREADS)
-
-// When we don't have threads, we can be either reading or writing,
-// but not both. We can have lots of readers at once (in no-threads
-// mode, that's most likely to happen in recursive function calls),
-// but only one writer. We represent this by having mutex_ be -1 when
-// writing and a number > 0 when reading (and 0 when no lock is held).
-//
-// In debug mode, we assert these invariants, while in non-debug mode
-// we do nothing, for efficiency. That's why everything is in an
-// assert.
-
-Mutex::Mutex() : mutex_(0) { }
-Mutex::~Mutex() { assert(mutex_ == 0); }
-void Mutex::Lock() { assert(--mutex_ == -1); }
-void Mutex::Unlock() { assert(mutex_++ == -1); }
-#ifdef CERES_GMUTEX_TRYLOCK
-bool Mutex::TryLock() { if (mutex_) return false; Lock(); return true; }
-#endif
-void Mutex::ReaderLock() { assert(++mutex_ > 0); }
-void Mutex::ReaderUnlock() { assert(mutex_-- > 0); }
-
-#elif defined(_WIN32) || defined(__CYGWIN32__) || defined(__CYGWIN64__)
-
-Mutex::Mutex() { InitializeCriticalSection(&mutex_); SetIsSafe(); }
-Mutex::~Mutex() { DeleteCriticalSection(&mutex_); }
-void Mutex::Lock() { if (is_safe_) EnterCriticalSection(&mutex_); }
-void Mutex::Unlock() { if (is_safe_) LeaveCriticalSection(&mutex_); }
-#ifdef GMUTEX_TRYLOCK
-bool Mutex::TryLock() { return is_safe_ ?
- TryEnterCriticalSection(&mutex_) != 0 : true; }
-#endif
-void Mutex::ReaderLock() { Lock(); } // we don't have read-write locks
-void Mutex::ReaderUnlock() { Unlock(); }
-
-#elif defined(CERES_HAVE_PTHREAD) && defined(CERES_HAVE_RWLOCK)
-
-#define CERES_SAFE_PTHREAD(fncall) do { /* run fncall if is_safe_ is true */ \
- if (is_safe_ && fncall(&mutex_) != 0) abort(); \
-} while (0)
-
-Mutex::Mutex() {
- SetIsSafe();
- if (is_safe_ && pthread_rwlock_init(&mutex_, NULL) != 0) abort();
-}
-Mutex::~Mutex() { CERES_SAFE_PTHREAD(pthread_rwlock_destroy); }
-void Mutex::Lock() { CERES_SAFE_PTHREAD(pthread_rwlock_wrlock); }
-void Mutex::Unlock() { CERES_SAFE_PTHREAD(pthread_rwlock_unlock); }
-#ifdef CERES_GMUTEX_TRYLOCK
-bool Mutex::TryLock() { return is_safe_ ?
- pthread_rwlock_trywrlock(&mutex_) == 0 :
- true; }
-#endif
-void Mutex::ReaderLock() { CERES_SAFE_PTHREAD(pthread_rwlock_rdlock); }
-void Mutex::ReaderUnlock() { CERES_SAFE_PTHREAD(pthread_rwlock_unlock); }
-#undef CERES_SAFE_PTHREAD
-
-#elif defined(CERES_HAVE_PTHREAD)
-
-#define CERES_SAFE_PTHREAD(fncall) do { /* run fncall if is_safe_ is true */ \
- if (is_safe_ && fncall(&mutex_) != 0) abort(); \
-} while (0)
-
-Mutex::Mutex() {
- SetIsSafe();
- if (is_safe_ && pthread_mutex_init(&mutex_, NULL) != 0) abort();
-}
-Mutex::~Mutex() { CERES_SAFE_PTHREAD(pthread_mutex_destroy); }
-void Mutex::Lock() { CERES_SAFE_PTHREAD(pthread_mutex_lock); }
-void Mutex::Unlock() { CERES_SAFE_PTHREAD(pthread_mutex_unlock); }
-#ifdef CERES_GMUTEX_TRYLOCK
-bool Mutex::TryLock() { return is_safe_ ?
- pthread_mutex_trylock(&mutex_) == 0 : true; }
-#endif
-void Mutex::ReaderLock() { Lock(); }
-void Mutex::ReaderUnlock() { Unlock(); }
-#undef CERES_SAFE_PTHREAD
-
-#endif
-
-// --------------------------------------------------------------------------
-// Some helper classes
-
-// Note: The weird "Ceres" prefix for the class is a workaround for having two
-// similar mutex.h files included in the same translation unit. This is a
-// problem because macros do not respect C++ namespaces, and as a result, this
-// does not work well (e.g. inside Chrome). The offending macros are
-// "MutexLock(x) COMPILE_ASSERT(false)". To work around this, "Ceres" is
-// prefixed to the class names; this permits defining the classes.
-
-// CeresMutexLock(mu) acquires mu when constructed and releases it
-// when destroyed.
-class CeresMutexLock {
- public:
- explicit CeresMutexLock(Mutex *mu) : mu_(mu) { mu_->Lock(); }
- ~CeresMutexLock() { mu_->Unlock(); }
- private:
- Mutex * const mu_;
- // Disallow "evil" constructors
- CeresMutexLock(const CeresMutexLock&);
- void operator=(const CeresMutexLock&);
-};
-
-// CeresReaderMutexLock and CeresWriterMutexLock do the same, for rwlocks
-class CeresReaderMutexLock {
- public:
- explicit CeresReaderMutexLock(Mutex *mu) : mu_(mu) { mu_->ReaderLock(); }
- ~CeresReaderMutexLock() { mu_->ReaderUnlock(); }
- private:
- Mutex * const mu_;
- // Disallow "evil" constructors
- CeresReaderMutexLock(const CeresReaderMutexLock&);
- void operator=(const CeresReaderMutexLock&);
-};
-
-class CeresWriterMutexLock {
- public:
- explicit CeresWriterMutexLock(Mutex *mu) : mu_(mu) { mu_->WriterLock(); }
- ~CeresWriterMutexLock() { mu_->WriterUnlock(); }
- private:
- Mutex * const mu_;
- // Disallow "evil" constructors
- CeresWriterMutexLock(const CeresWriterMutexLock&);
- void operator=(const CeresWriterMutexLock&);
-};
-
-// Catch bug where variable name is omitted, e.g. MutexLock (&mu);
-#define CeresMutexLock(x) \
- COMPILE_ASSERT(0, ceres_mutex_lock_decl_missing_var_name)
-#define CeresReaderMutexLock(x) \
- COMPILE_ASSERT(0, ceres_rmutex_lock_decl_missing_var_name)
-#define CeresWriterMutexLock(x) \
- COMPILE_ASSERT(0, ceres_wmutex_lock_decl_missing_var_name)
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_INTERNAL_MUTEX_H_
diff --git a/extern/ceres/internal/ceres/normal_prior.cc b/extern/ceres/internal/ceres/normal_prior.cc
index b3666cd702f..a3d5d8ed772 100644
--- a/extern/ceres/internal/ceres/normal_prior.cc
+++ b/extern/ceres/internal/ceres/normal_prior.cc
@@ -33,7 +33,6 @@
#include <cstddef>
#include <vector>
#include "ceres/internal/eigen.h"
-#include "ceres/internal/scoped_ptr.h"
#include "ceres/types.h"
#include "glog/logging.h"
diff --git a/extern/ceres/internal/ceres/pair_hash.h b/extern/ceres/internal/ceres/pair_hash.h
new file mode 100644
index 00000000000..80453bae7db
--- /dev/null
+++ b/extern/ceres/internal/ceres/pair_hash.h
@@ -0,0 +1,112 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2018 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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.
+//
+// Author: keir@google.com (Keir Mierle)
+//
+// A hasher for std::pair<T, T>.
+
+#ifndef CERES_INTERNAL_PAIR_HASH_H_
+#define CERES_INTERNAL_PAIR_HASH_H_
+
+#include "ceres/internal/port.h"
+#include <cstdint>
+#include <utility>
+
+namespace ceres {
+namespace internal {
+
+#if defined(_WIN32) && !defined(__MINGW64__) && !defined(__MINGW32__)
+#define GG_LONGLONG(x) x##I64
+#define GG_ULONGLONG(x) x##UI64
+#else
+#define GG_LONGLONG(x) x##LL
+#define GG_ULONGLONG(x) x##ULL
+#endif
+
+// The hash function is due to Bob Jenkins (see
+// http://burtleburtle.net/bob/hash/index.html). Each mix takes 36 instructions,
+// in 18 cycles if you're lucky. On x86 architectures, this requires 45
+// instructions in 27 cycles, if you're lucky.
+//
+// 32bit version
+inline void hash_mix(uint32_t& a, uint32_t& b, uint32_t& c) {
+ a -= b; a -= c; a ^= (c>>13);
+ b -= c; b -= a; b ^= (a<<8);
+ c -= a; c -= b; c ^= (b>>13);
+ a -= b; a -= c; a ^= (c>>12);
+ b -= c; b -= a; b ^= (a<<16);
+ c -= a; c -= b; c ^= (b>>5);
+ a -= b; a -= c; a ^= (c>>3);
+ b -= c; b -= a; b ^= (a<<10);
+ c -= a; c -= b; c ^= (b>>15);
+}
+
+// 64bit version
+inline void hash_mix(uint64_t& a, uint64_t& b, uint64_t& c) {
+ a -= b; a -= c; a ^= (c>>43);
+ b -= c; b -= a; b ^= (a<<9);
+ c -= a; c -= b; c ^= (b>>8);
+ a -= b; a -= c; a ^= (c>>38);
+ b -= c; b -= a; b ^= (a<<23);
+ c -= a; c -= b; c ^= (b>>5);
+ a -= b; a -= c; a ^= (c>>35);
+ b -= c; b -= a; b ^= (a<<49);
+ c -= a; c -= b; c ^= (b>>11);
+}
+
+inline uint32_t Hash32NumWithSeed(uint32_t num, uint32_t c) {
+ // The golden ratio; an arbitrary value.
+ uint32_t b = 0x9e3779b9UL;
+ hash_mix(num, b, c);
+ return c;
+}
+
+inline uint64_t Hash64NumWithSeed(uint64_t num, uint64_t c) {
+ // More of the golden ratio.
+ uint64_t b = GG_ULONGLONG(0xe08c1d668b756f82);
+ hash_mix(num, b, c);
+ return c;
+}
+
+// Hasher for STL pairs. Requires hashers for both members to be defined.
+struct pair_hash {
+ public:
+ template <typename T>
+ std::size_t operator()(const std::pair<T, T>& p) const {
+ const std::size_t h1 = std::hash<T>()(p.first);
+ const std::size_t h2 = std::hash<T>()(p.second);
+ // The decision below is at compile time
+ return (sizeof(h1) <= sizeof(uint32_t)) ? Hash32NumWithSeed(h1, h2)
+ : Hash64NumWithSeed(h1, h2);
+ }
+};
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_PAIR_HASH_H_
diff --git a/extern/ceres/internal/ceres/parallel_for.h b/extern/ceres/internal/ceres/parallel_for.h
new file mode 100644
index 00000000000..2da2320c137
--- /dev/null
+++ b/extern/ceres/internal/ceres/parallel_for.h
@@ -0,0 +1,67 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2018 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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.
+//
+// Author: vitus@google.com (Michael Vitus)
+
+#ifndef CERES_INTERNAL_PARALLEL_FOR_
+#define CERES_INTERNAL_PARALLEL_FOR_
+
+#include <functional>
+
+#include "ceres/context_impl.h"
+
+namespace ceres {
+namespace internal {
+
+// Returns the maximum number of threads supported by the threading backend
+// Ceres was compiled with.
+int MaxNumThreadsAvailable();
+
+// Execute the function for every element in the range [start, end) with at most
+// num_threads. It will execute all the work on the calling thread if
+// num_threads is 1.
+void ParallelFor(ContextImpl* context,
+ int start,
+ int end,
+ int num_threads,
+ const std::function<void(int)>& function);
+
+// Execute the function for every element in the range [start, end) with at most
+// num_threads. It will execute all the work on the calling thread if
+// num_threads is 1. Each invocation of function() will be passed a thread_id
+// in [0, num_threads) that is guaranteed to be distinct from the value passed
+// to any concurrent execution of function().
+void ParallelFor(ContextImpl* context,
+ int start,
+ int end,
+ int num_threads,
+ const std::function<void(int thread_id, int i)>& function);
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_PARALLEL_FOR_H_
diff --git a/extern/ceres/internal/ceres/parallel_for_cxx.cc b/extern/ceres/internal/ceres/parallel_for_cxx.cc
new file mode 100644
index 00000000000..8e358f5900b
--- /dev/null
+++ b/extern/ceres/internal/ceres/parallel_for_cxx.cc
@@ -0,0 +1,247 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2018 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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.
+//
+// Author: vitus@google.com (Michael Vitus)
+
+// This include must come before any #ifndef check on Ceres compile options.
+#include "ceres/internal/port.h"
+
+#ifdef CERES_USE_CXX_THREADS
+
+#include "ceres/parallel_for.h"
+
+#include <cmath>
+#include <condition_variable>
+#include <memory>
+#include <mutex>
+
+#include "ceres/concurrent_queue.h"
+#include "ceres/scoped_thread_token.h"
+#include "ceres/thread_token_provider.h"
+#include "glog/logging.h"
+
+namespace ceres {
+namespace internal {
+namespace {
+// This class creates a thread safe barrier which will block until a
+// pre-specified number of threads call Finished. This allows us to block the
+// main thread until all the parallel threads are finished processing all the
+// work.
+class BlockUntilFinished {
+ public:
+ explicit BlockUntilFinished(int num_total)
+ : num_finished_(0), num_total_(num_total) {}
+
+ // Increment the number of jobs that have finished and signal the blocking
+ // thread if all jobs have finished.
+ void Finished() {
+ std::lock_guard<std::mutex> lock(mutex_);
+ ++num_finished_;
+ CHECK_LE(num_finished_, num_total_);
+ if (num_finished_ == num_total_) {
+ condition_.notify_one();
+ }
+ }
+
+ // Block until all threads have signaled they are finished.
+ void Block() {
+ std::unique_lock<std::mutex> lock(mutex_);
+ condition_.wait(lock, [&]() { return num_finished_ == num_total_; });
+ }
+
+ private:
+ std::mutex mutex_;
+ std::condition_variable condition_;
+ // The current number of jobs finished.
+ int num_finished_;
+ // The total number of jobs.
+ int num_total_;
+};
+
+// Shared state between the parallel tasks. Each thread will use this
+// information to get the next block of work to be performed.
+struct SharedState {
+ SharedState(int start, int end, int num_work_items)
+ : start(start),
+ end(end),
+ num_work_items(num_work_items),
+ i(0),
+ thread_token_provider(num_work_items),
+ block_until_finished(num_work_items) {}
+
+ // The start and end index of the for loop.
+ const int start;
+ const int end;
+ // The number of blocks that need to be processed.
+ const int num_work_items;
+
+ // The next block of work to be assigned to a worker. The parallel for loop
+ // range is split into num_work_items blocks of work, i.e. a single block of
+ // work is:
+ // for (int j = start + i; j < end; j += num_work_items) { ... }.
+ int i;
+ std::mutex mutex_i;
+
+ // Provides a unique thread ID among all active threads working on the same
+ // group of tasks. Thread-safe.
+ ThreadTokenProvider thread_token_provider;
+
+ // Used to signal when all the work has been completed. Thread safe.
+ BlockUntilFinished block_until_finished;
+};
+
+} // namespace
+
+int MaxNumThreadsAvailable() {
+ return ThreadPool::MaxNumThreadsAvailable();
+}
+
+// See ParallelFor (below) for more details.
+void ParallelFor(ContextImpl* context,
+ int start,
+ int end,
+ int num_threads,
+ const std::function<void(int)>& function) {
+ CHECK_GT(num_threads, 0);
+ CHECK(context != NULL);
+ if (end <= start) {
+ return;
+ }
+
+ // Fast path for when it is single threaded.
+ if (num_threads == 1) {
+ for (int i = start; i < end; ++i) {
+ function(i);
+ }
+ return;
+ }
+
+ ParallelFor(context, start, end, num_threads,
+ [&function](int /*thread_id*/, int i) { function(i); });
+}
+
+// This implementation uses a fixed size max worker pool with a shared task
+// queue. The problem of executing the function for the interval of [start, end)
+// is broken up into at most num_threads blocks and added to the thread pool. To
+// avoid deadlocks, the calling thread is allowed to steal work from the worker
+// pool. This is implemented via a shared state between the tasks. In order for
+// the calling thread or thread pool to get a block of work, it will query the
+// shared state for the next block of work to be done. If there is nothing left,
+// it will return. We will exit the ParallelFor call when all of the work has
+// been done, not when all of the tasks have been popped off the task queue.
+//
+// A unique thread ID among all active tasks will be acquired once for each
+// block of work. This avoids the significant performance penalty for acquiring
+// it on every iteration of the for loop. The thread ID is guaranteed to be in
+// [0, num_threads).
+//
+// A performance analysis has shown this implementation is onpar with OpenMP and
+// TBB.
+void ParallelFor(ContextImpl* context,
+ int start,
+ int end,
+ int num_threads,
+ const std::function<void(int thread_id, int i)>& function) {
+ CHECK_GT(num_threads, 0);
+ CHECK(context != NULL);
+ if (end <= start) {
+ return;
+ }
+
+ // Fast path for when it is single threaded.
+ if (num_threads == 1) {
+ // Even though we only have one thread, use the thread token provider to
+ // guarantee the exact same behavior when running with multiple threads.
+ ThreadTokenProvider thread_token_provider(num_threads);
+ const ScopedThreadToken scoped_thread_token(&thread_token_provider);
+ const int thread_id = scoped_thread_token.token();
+ for (int i = start; i < end; ++i) {
+ function(thread_id, i);
+ }
+ return;
+ }
+
+ // We use a std::shared_ptr because the main thread can finish all
+ // the work before the tasks have been popped off the queue. So the
+ // shared state needs to exist for the duration of all the tasks.
+ const int num_work_items = std::min((end - start), num_threads);
+ std::shared_ptr<SharedState> shared_state(
+ new SharedState(start, end, num_work_items));
+
+ // A function which tries to perform a chunk of work. This returns false if
+ // there is no work to be done.
+ auto task_function = [shared_state, &function]() {
+ int i = 0;
+ {
+ // Get the next available chunk of work to be performed. If there is no
+ // work, return false.
+ std::lock_guard<std::mutex> lock(shared_state->mutex_i);
+ if (shared_state->i >= shared_state->num_work_items) {
+ return false;
+ }
+ i = shared_state->i;
+ ++shared_state->i;
+ }
+
+ const ScopedThreadToken scoped_thread_token(
+ &shared_state->thread_token_provider);
+ const int thread_id = scoped_thread_token.token();
+
+ // Perform each task.
+ for (int j = shared_state->start + i;
+ j < shared_state->end;
+ j += shared_state->num_work_items) {
+ function(thread_id, j);
+ }
+ shared_state->block_until_finished.Finished();
+ return true;
+ };
+
+ // Add all the tasks to the thread pool.
+ for (int i = 0; i < num_work_items; ++i) {
+ // Note we are taking the task_function as value so the shared_state
+ // shared pointer is copied and the ref count is increased. This is to
+ // prevent it from being deleted when the main thread finishes all the
+ // work and exits before the threads finish.
+ context->thread_pool.AddTask([task_function]() { task_function(); });
+ }
+
+ // Try to do any available work on the main thread. This may steal work from
+ // the thread pool, but when there is no work left the thread pool tasks
+ // will be no-ops.
+ while (task_function()) {
+ }
+
+ // Wait until all tasks have finished.
+ shared_state->block_until_finished.Block();
+}
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_USE_CXX_THREADS
diff --git a/extern/ceres/internal/ceres/parallel_for_nothreads.cc b/extern/ceres/internal/ceres/parallel_for_nothreads.cc
new file mode 100644
index 00000000000..e8f450a714d
--- /dev/null
+++ b/extern/ceres/internal/ceres/parallel_for_nothreads.cc
@@ -0,0 +1,78 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2018 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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.
+//
+// Author: alexs.mac@gmail.com (Alex Stewart)
+
+// This include must come before any #ifndef check on Ceres compile options.
+#include "ceres/internal/port.h"
+
+#ifdef CERES_NO_THREADS
+
+#include "ceres/parallel_for.h"
+#include "glog/logging.h"
+
+namespace ceres {
+namespace internal {
+
+int MaxNumThreadsAvailable() { return 1; }
+
+void ParallelFor(ContextImpl* context,
+ int start,
+ int end,
+ int num_threads,
+ const std::function<void(int)>& function) {
+ CHECK_GT(num_threads, 0);
+ CHECK(context != NULL);
+ if (end <= start) {
+ return;
+ }
+ for (int i = start; i < end; ++i) {
+ function(i);
+ }
+}
+
+void ParallelFor(ContextImpl* context,
+ int start,
+ int end,
+ int num_threads,
+ const std::function<void(int thread_id, int i)>& function) {
+ CHECK_GT(num_threads, 0);
+ CHECK(context != NULL);
+ if (end <= start) {
+ return;
+ }
+ const int thread_id = 0;
+ for (int i = start; i < end; ++i) {
+ function(thread_id, i);
+ }
+}
+
+}
+}
+
+#endif // CERES_NO_THREADS
diff --git a/extern/ceres/internal/ceres/parallel_for_openmp.cc b/extern/ceres/internal/ceres/parallel_for_openmp.cc
new file mode 100644
index 00000000000..8afe3b11f8d
--- /dev/null
+++ b/extern/ceres/internal/ceres/parallel_for_openmp.cc
@@ -0,0 +1,88 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2018 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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.
+//
+// Author: vitus@google.com (Michael Vitus)
+
+// This include must come before any #ifndef check on Ceres compile options.
+#include "ceres/internal/port.h"
+
+#if defined(CERES_USE_OPENMP)
+
+#include "ceres/parallel_for.h"
+
+#include "ceres/scoped_thread_token.h"
+#include "ceres/thread_token_provider.h"
+#include "glog/logging.h"
+#include "omp.h"
+
+namespace ceres {
+namespace internal {
+
+int MaxNumThreadsAvailable() {
+ return omp_get_max_threads();
+}
+
+void ParallelFor(ContextImpl* context,
+ int start,
+ int end,
+ int num_threads,
+ const std::function<void(int)>& function) {
+ CHECK_GT(num_threads, 0);
+ CHECK(context != NULL);
+ if (end <= start) {
+ return;
+ }
+
+#ifdef CERES_USE_OPENMP
+#pragma omp parallel for num_threads(num_threads) \
+ schedule(dynamic) if (num_threads > 1)
+#endif // CERES_USE_OPENMP
+ for (int i = start; i < end; ++i) {
+ function(i);
+ }
+}
+
+void ParallelFor(ContextImpl* context,
+ int start,
+ int end,
+ int num_threads,
+ const std::function<void(int thread_id, int i)>& function) {
+ CHECK(context != NULL);
+
+ ThreadTokenProvider thread_token_provider(num_threads);
+ ParallelFor(context, start, end, num_threads, [&](int i) {
+ const ScopedThreadToken scoped_thread_token(&thread_token_provider);
+ const int thread_id = scoped_thread_token.token();
+ function(thread_id, i);
+ });
+}
+
+} // namespace internal
+} // namespace ceres
+
+#endif // defined(CERES_USE_OPENMP)
diff --git a/extern/ceres/internal/ceres/parallel_utils.cc b/extern/ceres/internal/ceres/parallel_utils.cc
new file mode 100644
index 00000000000..e1cb5f979ec
--- /dev/null
+++ b/extern/ceres/internal/ceres/parallel_utils.cc
@@ -0,0 +1,90 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2018 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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.
+//
+// Author: wjr@google.com (William Rucklidge)
+
+#include "ceres/parallel_utils.h"
+
+namespace ceres {
+namespace internal {
+
+void LinearIndexToUpperTriangularIndex(int k, int n, int* i, int* j) {
+ // This works by unfolding a rectangle into a triangle.
+ // Say n is even. 4 is a nice even number. The 10 i,j pairs that we
+ // want to produce are:
+ // 0,0 0,1 0,2 0,3
+ // 1,1 1,2 1,3
+ // 2,2 2,3
+ // 3,3
+ // This triangle can be folded into a 5x2 rectangle:
+ // 3,3 0,0 0,1 0,2 0,3
+ // 2,2 2,3 1,1 1,2 1,3
+
+ // If N is odd, say 5, then the 15 i,j pairs are:
+ // 0,0 0,1 0,2 0,3 0,4
+ // 1,1 1,2 1,3 1,4
+ // 2,2 2,3 2,3
+ // 3,3 3,4
+ // 4,4
+ // which folds to a 5x3 rectangle:
+ // 0,0 0,1 0,2 0,3 0,4
+ // 4,4 1,1 1,2 1,3 1,4
+ // 3,3 3,4 2,2 2,3 2,4
+
+ // All this function does is map the linear iteration position to a
+ // location in the rectangle and work out the appropriate (i, j) for that
+ // location.
+ if (n & 1) {
+ // Odd n. The tip of the triangle is on row 1.
+ int w = n; // Width of the rectangle to unfold
+ int i0 = k / w;
+ int j0 = k % w;
+ if (j0 >= i0) {
+ *i = i0;
+ *j = j0;
+ } else {
+ *i = n - i0;
+ *j = *i + j0;
+ }
+ } else {
+ // Even n. The tip of the triangle is on row 0, making it one wider.
+ int w = n + 1;
+ int i0 = k / w;
+ int j0 = k % w;
+ if (j0 > i0) {
+ *i = i0;
+ *j = j0 - 1;
+ } else {
+ *i = n - 1 - i0;
+ *j = *i + j0;
+ }
+ }
+}
+
+} // namespace internal
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/parallel_utils.h b/extern/ceres/internal/ceres/parallel_utils.h
new file mode 100644
index 00000000000..1291428228a
--- /dev/null
+++ b/extern/ceres/internal/ceres/parallel_utils.h
@@ -0,0 +1,67 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2018 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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.
+//
+// Author: wjr@google.com (William Rucklidge)
+
+#ifndef CERES_INTERNAL_PARALLEL_UTILS_H_
+#define CERES_INTERNAL_PARALLEL_UTILS_H_
+
+namespace ceres {
+namespace internal {
+
+// Converts a linear iteration order into a triangular iteration order.
+// Suppose you have nested loops that look like
+// for (int i = 0; i < n; i++) {
+// for (int j = i; j < n; j++) {
+// ... use i and j
+// }
+// }
+// Naively using ParallelFor to parallelise those loops might look like
+// ParallelFor(..., 0, n * n, num_threads,
+// [](int thread_id, int k) {
+// int i = k / n, j = k % n;
+// if (j < i) return;
+// ...
+// });
+// but these empty work items can lead to very unbalanced threading. Instead,
+// do this:
+// int actual_work_items = (n * (n + 1)) / 2;
+// ParallelFor(..., 0, actual_work_items, num_threads,
+// [](int thread_id, int k) {
+// int i, j;
+// UnfoldIteration(k, n, &i, &j);
+// ...
+// });
+// which in each iteration will produce i and j satisfying
+// 0 <= i <= j < n
+void LinearIndexToUpperTriangularIndex(int k, int n, int* i, int* j);
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_PARALLEL_UTILS_H_
diff --git a/extern/ceres/internal/ceres/parameter_block.h b/extern/ceres/internal/ceres/parameter_block.h
index 8e21553c668..88943dfbcff 100644
--- a/extern/ceres/internal/ceres/parameter_block.h
+++ b/extern/ceres/internal/ceres/parameter_block.h
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2019 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -32,15 +32,16 @@
#define CERES_INTERNAL_PARAMETER_BLOCK_H_
#include <algorithm>
+#include <cstdint>
#include <cstdlib>
#include <limits>
+#include <memory>
#include <string>
+#include <unordered_set>
+
#include "ceres/array_utils.h"
-#include "ceres/collections_port.h"
-#include "ceres/integral_types.h"
#include "ceres/internal/eigen.h"
#include "ceres/internal/port.h"
-#include "ceres/internal/scoped_ptr.h"
#include "ceres/local_parameterization.h"
#include "ceres/stringprintf.h"
#include "glog/logging.h"
@@ -62,29 +63,28 @@ class ResidualBlock;
// responsible for the proper disposal of the local parameterization.
class ParameterBlock {
public:
- // TODO(keir): Decide what data structure is best here. Should this be a set?
- // Probably not, because sets are memory inefficient. However, if it's a
- // vector, you can get into pathological linear performance when removing a
- // residual block from a problem where all the residual blocks depend on one
- // parameter; for example, shared focal length in a bundle adjustment
- // problem. It might be worth making a custom structure that is just an array
- // when it is small, but transitions to a hash set when it has more elements.
- //
- // For now, use a hash set.
- typedef HashSet<ResidualBlock*> ResidualBlockSet;
+ typedef std::unordered_set<ResidualBlock*> ResidualBlockSet;
// Create a parameter block with the user state, size, and index specified.
// The size is the size of the parameter block and the index is the position
// of the parameter block inside a Program (if any).
- ParameterBlock(double* user_state, int size, int index) {
- Init(user_state, size, index, NULL);
- }
+ ParameterBlock(double* user_state, int size, int index)
+ : user_state_(user_state),
+ size_(size),
+ state_(user_state),
+ index_(index) {}
ParameterBlock(double* user_state,
int size,
int index,
- LocalParameterization* local_parameterization) {
- Init(user_state, size, index, local_parameterization);
+ LocalParameterization* local_parameterization)
+ : user_state_(user_state),
+ size_(size),
+ state_(user_state),
+ index_(index) {
+ if (local_parameterization != nullptr) {
+ SetParameterization(local_parameterization);
+ }
}
// The size of the parameter block.
@@ -92,12 +92,10 @@ class ParameterBlock {
// Manipulate the parameter state.
bool SetState(const double* x) {
- CHECK(x != NULL)
- << "Tried to set the state of constant parameter "
- << "with user location " << user_state_;
- CHECK(!is_constant_)
- << "Tried to set the state of constant parameter "
- << "with user location " << user_state_;
+ CHECK(x != nullptr) << "Tried to set the state of constant parameter "
+ << "with user location " << user_state_;
+ CHECK(!IsConstant()) << "Tried to set the state of constant parameter "
+ << "with user location " << user_state_;
state_ = x;
return UpdateLocalParameterizationJacobian();
@@ -106,9 +104,9 @@ class ParameterBlock {
// Copy the current parameter state out to x. This is "GetState()" rather than
// simply "state()" since it is actively copying the data into the passed
// pointer.
- void GetState(double *x) const {
+ void GetState(double* x) const {
if (x != state_) {
- memcpy(x, state_, sizeof(*state_) * size_);
+ std::copy(state_, state_ + size_, x);
}
}
@@ -116,7 +114,7 @@ class ParameterBlock {
const double* state() const { return state_; }
const double* user_state() const { return user_state_; }
double* mutable_user_state() { return user_state_; }
- LocalParameterization* local_parameterization() const {
+ const LocalParameterization* local_parameterization() const {
return local_parameterization_;
}
LocalParameterization* mutable_local_parameterization() {
@@ -124,9 +122,22 @@ class ParameterBlock {
}
// Set this parameter block to vary or not.
- void SetConstant() { is_constant_ = true; }
- void SetVarying() { is_constant_ = false; }
- bool IsConstant() const { return is_constant_; }
+ void SetConstant() { is_set_constant_ = true; }
+ void SetVarying() { is_set_constant_ = false; }
+ bool IsConstant() const { return (is_set_constant_ || LocalSize() == 0); }
+
+ double UpperBound(int index) const {
+ return (upper_bounds_ ? upper_bounds_[index]
+ : std::numeric_limits<double>::max());
+ }
+
+ double LowerBound(int index) const {
+ return (lower_bounds_ ? lower_bounds_[index]
+ : -std::numeric_limits<double>::max());
+ }
+
+ bool IsUpperBounded() const { return (upper_bounds_ == nullptr); }
+ bool IsLowerBounded() const { return (lower_bounds_ == nullptr); }
// This parameter block's index in an array.
int index() const { return index_; }
@@ -142,7 +153,7 @@ class ParameterBlock {
// Methods relating to the parameter block's parameterization.
- // The local to global jacobian. Returns NULL if there is no local
+ // The local to global jacobian. Returns nullptr if there is no local
// parameterization for this parameter block. The returned matrix is row-major
// and has Size() rows and LocalSize() columns.
const double* LocalParameterizationJacobian() const {
@@ -150,27 +161,24 @@ class ParameterBlock {
}
int LocalSize() const {
- return (local_parameterization_ == NULL)
- ? size_
- : local_parameterization_->LocalSize();
+ return (local_parameterization_ == nullptr)
+ ? size_
+ : local_parameterization_->LocalSize();
}
- // Set the parameterization. The parameterization can be set exactly once;
- // multiple calls to set the parameterization to different values will crash.
- // It is an error to pass NULL for the parameterization. The parameter block
- // does not take ownership of the parameterization.
+ // Set the parameterization. The parameter block does not take
+ // ownership of the parameterization.
void SetParameterization(LocalParameterization* new_parameterization) {
- CHECK(new_parameterization != NULL) << "NULL parameterization invalid.";
// Nothing to do if the new parameterization is the same as the
// old parameterization.
if (new_parameterization == local_parameterization_) {
return;
}
- CHECK(local_parameterization_ == NULL)
- << "Can't re-set the local parameterization; it leads to "
- << "ambiguous ownership. Current local parameterization is: "
- << local_parameterization_;
+ if (new_parameterization == nullptr) {
+ local_parameterization_ = nullptr;
+ return;
+ }
CHECK(new_parameterization->GlobalSize() == size_)
<< "Invalid parameterization for parameter block. The parameter block "
@@ -178,9 +186,9 @@ class ParameterBlock {
<< "size of " << new_parameterization->GlobalSize() << ". Did you "
<< "accidentally use the wrong parameter block or parameterization?";
- CHECK_GT(new_parameterization->LocalSize(), 0)
- << "Invalid parameterization. Parameterizations must have a positive "
- << "dimensional tangent space.";
+ CHECK_GE(new_parameterization->LocalSize(), 0)
+ << "Invalid parameterization. Parameterizations must have a "
+ << "non-negative dimensional tangent space.";
local_parameterization_ = new_parameterization;
local_parameterization_jacobian_.reset(
@@ -194,7 +202,11 @@ class ParameterBlock {
void SetUpperBound(int index, double upper_bound) {
CHECK_LT(index, size_);
- if (upper_bounds_.get() == NULL) {
+ if (upper_bound >= std::numeric_limits<double>::max() && !upper_bounds_) {
+ return;
+ }
+
+ if (!upper_bounds_) {
upper_bounds_.reset(new double[size_]);
std::fill(upper_bounds_.get(),
upper_bounds_.get() + size_,
@@ -207,7 +219,11 @@ class ParameterBlock {
void SetLowerBound(int index, double lower_bound) {
CHECK_LT(index, size_);
- if (lower_bounds_.get() == NULL) {
+ if (lower_bound <= -std::numeric_limits<double>::max() && !lower_bounds_) {
+ return;
+ }
+
+ if (!lower_bounds_) {
lower_bounds_.reset(new double[size_]);
std::fill(lower_bounds_.get(),
lower_bounds_.get() + size_,
@@ -220,24 +236,24 @@ class ParameterBlock {
// Generalization of the addition operation. This is the same as
// LocalParameterization::Plus() followed by projection onto the
// hyper cube implied by the bounds constraints.
- bool Plus(const double *x, const double* delta, double* x_plus_delta) {
- if (local_parameterization_ != NULL) {
+ bool Plus(const double* x, const double* delta, double* x_plus_delta) {
+ if (local_parameterization_ != nullptr) {
if (!local_parameterization_->Plus(x, delta, x_plus_delta)) {
return false;
}
} else {
- VectorRef(x_plus_delta, size_) = ConstVectorRef(x, size_) +
- ConstVectorRef(delta, size_);
+ VectorRef(x_plus_delta, size_) =
+ ConstVectorRef(x, size_) + ConstVectorRef(delta, size_);
}
// Project onto the box constraints.
- if (lower_bounds_.get() != NULL) {
+ if (lower_bounds_.get() != nullptr) {
for (int i = 0; i < size_; ++i) {
x_plus_delta[i] = std::max(x_plus_delta[i], lower_bounds_[i]);
}
}
- if (upper_bounds_.get() != NULL) {
+ if (upper_bounds_.get() != nullptr) {
for (int i = 0; i < size_; ++i) {
x_plus_delta[i] = std::min(x_plus_delta[i], upper_bounds_[i]);
}
@@ -247,35 +263,36 @@ class ParameterBlock {
}
std::string ToString() const {
- return StringPrintf("{ this=%p, user_state=%p, state=%p, size=%d, "
- "constant=%d, index=%d, state_offset=%d, "
- "delta_offset=%d }",
- this,
- user_state_,
- state_,
- size_,
- is_constant_,
- index_,
- state_offset_,
- delta_offset_);
+ return StringPrintf(
+ "{ this=%p, user_state=%p, state=%p, size=%d, "
+ "constant=%d, index=%d, state_offset=%d, "
+ "delta_offset=%d }",
+ this,
+ user_state_,
+ state_,
+ size_,
+ is_set_constant_,
+ index_,
+ state_offset_,
+ delta_offset_);
}
void EnableResidualBlockDependencies() {
- CHECK(residual_blocks_.get() == NULL)
+ CHECK(residual_blocks_.get() == nullptr)
<< "Ceres bug: There is already a residual block collection "
<< "for parameter block: " << ToString();
residual_blocks_.reset(new ResidualBlockSet);
}
void AddResidualBlock(ResidualBlock* residual_block) {
- CHECK(residual_blocks_.get() != NULL)
+ CHECK(residual_blocks_.get() != nullptr)
<< "Ceres bug: The residual block collection is null for parameter "
<< "block: " << ToString();
residual_blocks_->insert(residual_block);
}
void RemoveResidualBlock(ResidualBlock* residual_block) {
- CHECK(residual_blocks_.get() != NULL)
+ CHECK(residual_blocks_.get() != nullptr)
<< "Ceres bug: The residual block collection is null for parameter "
<< "block: " << ToString();
CHECK(residual_blocks_->find(residual_block) != residual_blocks_->end())
@@ -285,12 +302,10 @@ class ParameterBlock {
// This is only intended for iterating; perhaps this should only expose
// .begin() and .end().
- ResidualBlockSet* mutable_residual_blocks() {
- return residual_blocks_.get();
- }
+ ResidualBlockSet* mutable_residual_blocks() { return residual_blocks_.get(); }
double LowerBoundForParameter(int index) const {
- if (lower_bounds_.get() == NULL) {
+ if (lower_bounds_.get() == nullptr) {
return -std::numeric_limits<double>::max();
} else {
return lower_bounds_[index];
@@ -298,7 +313,7 @@ class ParameterBlock {
}
double UpperBoundForParameter(int index) const {
- if (upper_bounds_.get() == NULL) {
+ if (upper_bounds_.get() == nullptr) {
return std::numeric_limits<double>::max();
} else {
return upper_bounds_[index];
@@ -306,27 +321,8 @@ class ParameterBlock {
}
private:
- void Init(double* user_state,
- int size,
- int index,
- LocalParameterization* local_parameterization) {
- user_state_ = user_state;
- size_ = size;
- index_ = index;
- is_constant_ = false;
- state_ = user_state_;
-
- local_parameterization_ = NULL;
- if (local_parameterization != NULL) {
- SetParameterization(local_parameterization);
- }
-
- state_offset_ = -1;
- delta_offset_ = -1;
- }
-
bool UpdateLocalParameterizationJacobian() {
- if (local_parameterization_ == NULL) {
+ if (local_parameterization_ == nullptr) {
return true;
}
@@ -335,13 +331,12 @@ class ParameterBlock {
// at that time.
const int jacobian_size = Size() * LocalSize();
- InvalidateArray(jacobian_size,
- local_parameterization_jacobian_.get());
+ InvalidateArray(jacobian_size, local_parameterization_jacobian_.get());
if (!local_parameterization_->ComputeJacobian(
- state_,
- local_parameterization_jacobian_.get())) {
+ state_, local_parameterization_jacobian_.get())) {
LOG(WARNING) << "Local parameterization Jacobian computation failed"
- "for x: " << ConstVectorRef(state_, Size()).transpose();
+ "for x: "
+ << ConstVectorRef(state_, Size()).transpose();
return false;
}
@@ -358,30 +353,30 @@ class ParameterBlock {
return true;
}
- double* user_state_;
- int size_;
- bool is_constant_;
- LocalParameterization* local_parameterization_;
+ double* user_state_ = nullptr;
+ int size_ = -1;
+ bool is_set_constant_ = false;
+ LocalParameterization* local_parameterization_ = nullptr;
// The "state" of the parameter. These fields are only needed while the
// solver is running. While at first glance using mutable is a bad idea, this
// ends up simplifying the internals of Ceres enough to justify the potential
// pitfalls of using "mutable."
- mutable const double* state_;
- mutable scoped_array<double> local_parameterization_jacobian_;
+ mutable const double* state_ = nullptr;
+ mutable std::unique_ptr<double[]> local_parameterization_jacobian_;
// The index of the parameter. This is used by various other parts of Ceres to
// permit switching from a ParameterBlock* to an index in another array.
- int32 index_;
+ int index_ = -1;
// The offset of this parameter block inside a larger state vector.
- int32 state_offset_;
+ int state_offset_ = -1;
// The offset of this parameter block inside a larger delta vector.
- int32 delta_offset_;
+ int delta_offset_ = -1;
// If non-null, contains the residual blocks this parameter block is in.
- scoped_ptr<ResidualBlockSet> residual_blocks_;
+ std::unique_ptr<ResidualBlockSet> residual_blocks_;
// Upper and lower bounds for the parameter block. SetUpperBound
// and SetLowerBound lazily initialize the upper_bounds_ and
@@ -394,8 +389,8 @@ class ParameterBlock {
// std::numeric_limits<double>::max() and
// -std::numeric_limits<double>::max() respectively which correspond
// to the parameter block being unconstrained.
- scoped_array<double> upper_bounds_;
- scoped_array<double> lower_bounds_;
+ std::unique_ptr<double[]> upper_bounds_;
+ std::unique_ptr<double[]> lower_bounds_;
// Necessary so ProblemImpl can clean up the parameterizations.
friend class ProblemImpl;
diff --git a/extern/ceres/internal/ceres/parameter_block_ordering.cc b/extern/ceres/internal/ceres/parameter_block_ordering.cc
index efba339977c..ef521c0e11b 100644
--- a/extern/ceres/internal/ceres/parameter_block_ordering.cc
+++ b/extern/ceres/internal/ceres/parameter_block_ordering.cc
@@ -30,9 +30,11 @@
#include "ceres/parameter_block_ordering.h"
+#include <memory>
+#include <unordered_set>
+
#include "ceres/graph.h"
#include "ceres/graph_algorithms.h"
-#include "ceres/internal/scoped_ptr.h"
#include "ceres/map_util.h"
#include "ceres/parameter_block.h"
#include "ceres/program.h"
@@ -49,13 +51,14 @@ using std::vector;
int ComputeStableSchurOrdering(const Program& program,
vector<ParameterBlock*>* ordering) {
- CHECK_NOTNULL(ordering)->clear();
+ CHECK(ordering != nullptr);
+ ordering->clear();
EventLogger event_logger("ComputeStableSchurOrdering");
- scoped_ptr<Graph< ParameterBlock*> > graph(CreateHessianGraph(program));
+ std::unique_ptr<Graph< ParameterBlock*> > graph(CreateHessianGraph(program));
event_logger.AddEvent("CreateHessianGraph");
const vector<ParameterBlock*>& parameter_blocks = program.parameter_blocks();
- const HashSet<ParameterBlock*>& vertices = graph->vertices();
+ const std::unordered_set<ParameterBlock*>& vertices = graph->vertices();
for (int i = 0; i < parameter_blocks.size(); ++i) {
if (vertices.count(parameter_blocks[i]) > 0) {
ordering->push_back(parameter_blocks[i]);
@@ -80,9 +83,10 @@ int ComputeStableSchurOrdering(const Program& program,
int ComputeSchurOrdering(const Program& program,
vector<ParameterBlock*>* ordering) {
- CHECK_NOTNULL(ordering)->clear();
+ CHECK(ordering != nullptr);
+ ordering->clear();
- scoped_ptr<Graph< ParameterBlock*> > graph(CreateHessianGraph(program));
+ std::unique_ptr<Graph< ParameterBlock*> > graph(CreateHessianGraph(program));
int independent_set_size = IndependentSetOrdering(*graph, ordering);
const vector<ParameterBlock*>& parameter_blocks = program.parameter_blocks();
@@ -99,9 +103,10 @@ int ComputeSchurOrdering(const Program& program,
void ComputeRecursiveIndependentSetOrdering(const Program& program,
ParameterBlockOrdering* ordering) {
- CHECK_NOTNULL(ordering)->Clear();
+ CHECK(ordering != nullptr);
+ ordering->Clear();
const vector<ParameterBlock*> parameter_blocks = program.parameter_blocks();
- scoped_ptr<Graph< ParameterBlock*> > graph(CreateHessianGraph(program));
+ std::unique_ptr<Graph< ParameterBlock*> > graph(CreateHessianGraph(program));
int num_covered = 0;
int round = 0;
@@ -120,7 +125,8 @@ void ComputeRecursiveIndependentSetOrdering(const Program& program,
}
Graph<ParameterBlock*>* CreateHessianGraph(const Program& program) {
- Graph<ParameterBlock*>* graph = CHECK_NOTNULL(new Graph<ParameterBlock*>);
+ Graph<ParameterBlock*>* graph = new Graph<ParameterBlock*>;
+ CHECK(graph != nullptr);
const vector<ParameterBlock*>& parameter_blocks = program.parameter_blocks();
for (int i = 0; i < parameter_blocks.size(); ++i) {
ParameterBlock* parameter_block = parameter_blocks[i];
@@ -155,17 +161,16 @@ Graph<ParameterBlock*>* CreateHessianGraph(const Program& program) {
void OrderingToGroupSizes(const ParameterBlockOrdering* ordering,
vector<int>* group_sizes) {
- CHECK_NOTNULL(group_sizes)->clear();
+ CHECK(group_sizes != nullptr);
+ group_sizes->clear();
if (ordering == NULL) {
return;
}
- const map<int, set<double*> >& group_to_elements =
+ const map<int, set<double*>>& group_to_elements =
ordering->group_to_elements();
- for (map<int, set<double*> >::const_iterator it = group_to_elements.begin();
- it != group_to_elements.end();
- ++it) {
- group_sizes->push_back(it->second.size());
+ for (const auto& g_t_e : group_to_elements) {
+ group_sizes->push_back(g_t_e.second.size());
}
}
diff --git a/extern/ceres/internal/ceres/partitioned_matrix_view.cc b/extern/ceres/internal/ceres/partitioned_matrix_view.cc
index 8054964e039..d7a998d68a3 100644
--- a/extern/ceres/internal/ceres/partitioned_matrix_view.cc
+++ b/extern/ceres/internal/ceres/partitioned_matrix_view.cc
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2017 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -37,8 +37,7 @@
// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
//=========================================
//
-// This file is generated using generate_partitioned_matrix_view_specializations.py.
-// Editing it manually is not recommended.
+// This file is generated using generate_template_specializations.py.
#include "ceres/linear_solver.h"
#include "ceres/partitioned_matrix_view.h"
@@ -51,126 +50,105 @@ PartitionedMatrixViewBase*
PartitionedMatrixViewBase::Create(const LinearSolver::Options& options,
const BlockSparseMatrix& matrix) {
#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
- if ((options.row_block_size == 2) &&
- (options.e_block_size == 2) &&
- (options.f_block_size == 2)) {
- return new PartitionedMatrixView<2, 2, 2>(
- matrix, options.elimination_groups[0]);
- }
- if ((options.row_block_size == 2) &&
- (options.e_block_size == 2) &&
- (options.f_block_size == 3)) {
- return new PartitionedMatrixView<2, 2, 3>(
- matrix, options.elimination_groups[0]);
- }
- if ((options.row_block_size == 2) &&
- (options.e_block_size == 2) &&
- (options.f_block_size == 4)) {
- return new PartitionedMatrixView<2, 2, 4>(
- matrix, options.elimination_groups[0]);
- }
- if ((options.row_block_size == 2) &&
- (options.e_block_size == 2) &&
- (options.f_block_size == Eigen::Dynamic)) {
- return new PartitionedMatrixView<2, 2, Eigen::Dynamic>(
- matrix, options.elimination_groups[0]);
- }
- if ((options.row_block_size == 2) &&
- (options.e_block_size == 3) &&
- (options.f_block_size == 3)) {
- return new PartitionedMatrixView<2, 3, 3>(
- matrix, options.elimination_groups[0]);
- }
- if ((options.row_block_size == 2) &&
- (options.e_block_size == 3) &&
- (options.f_block_size == 4)) {
- return new PartitionedMatrixView<2, 3, 4>(
- matrix, options.elimination_groups[0]);
- }
- if ((options.row_block_size == 2) &&
- (options.e_block_size == 3) &&
- (options.f_block_size == 6)) {
- return new PartitionedMatrixView<2, 3, 6>(
- matrix, options.elimination_groups[0]);
- }
- if ((options.row_block_size == 2) &&
- (options.e_block_size == 3) &&
- (options.f_block_size == 9)) {
- return new PartitionedMatrixView<2, 3, 9>(
- matrix, options.elimination_groups[0]);
- }
- if ((options.row_block_size == 2) &&
- (options.e_block_size == 3) &&
- (options.f_block_size == Eigen::Dynamic)) {
- return new PartitionedMatrixView<2, 3, Eigen::Dynamic>(
- matrix, options.elimination_groups[0]);
- }
- if ((options.row_block_size == 2) &&
- (options.e_block_size == 4) &&
- (options.f_block_size == 3)) {
- return new PartitionedMatrixView<2, 4, 3>(
- matrix, options.elimination_groups[0]);
- }
- if ((options.row_block_size == 2) &&
- (options.e_block_size == 4) &&
- (options.f_block_size == 4)) {
- return new PartitionedMatrixView<2, 4, 4>(
- matrix, options.elimination_groups[0]);
- }
- if ((options.row_block_size == 2) &&
- (options.e_block_size == 4) &&
- (options.f_block_size == 8)) {
- return new PartitionedMatrixView<2, 4, 8>(
- matrix, options.elimination_groups[0]);
- }
- if ((options.row_block_size == 2) &&
- (options.e_block_size == 4) &&
- (options.f_block_size == 9)) {
- return new PartitionedMatrixView<2, 4, 9>(
- matrix, options.elimination_groups[0]);
- }
- if ((options.row_block_size == 2) &&
- (options.e_block_size == 4) &&
- (options.f_block_size == Eigen::Dynamic)) {
- return new PartitionedMatrixView<2, 4, Eigen::Dynamic>(
- matrix, options.elimination_groups[0]);
- }
- if ((options.row_block_size == 2) &&
- (options.e_block_size == Eigen::Dynamic) &&
- (options.f_block_size == Eigen::Dynamic)) {
- return new PartitionedMatrixView<2, Eigen::Dynamic, Eigen::Dynamic>(
- matrix, options.elimination_groups[0]);
- }
- if ((options.row_block_size == 4) &&
- (options.e_block_size == 4) &&
- (options.f_block_size == 2)) {
- return new PartitionedMatrixView<4, 4, 2>(
- matrix, options.elimination_groups[0]);
- }
- if ((options.row_block_size == 4) &&
- (options.e_block_size == 4) &&
- (options.f_block_size == 3)) {
- return new PartitionedMatrixView<4, 4, 3>(
- matrix, options.elimination_groups[0]);
- }
- if ((options.row_block_size == 4) &&
- (options.e_block_size == 4) &&
- (options.f_block_size == 4)) {
- return new PartitionedMatrixView<4, 4, 4>(
- matrix, options.elimination_groups[0]);
- }
- if ((options.row_block_size == 4) &&
- (options.e_block_size == 4) &&
- (options.f_block_size == Eigen::Dynamic)) {
- return new PartitionedMatrixView<4, 4, Eigen::Dynamic>(
- matrix, options.elimination_groups[0]);
- }
- if ((options.row_block_size == Eigen::Dynamic) &&
- (options.e_block_size == Eigen::Dynamic) &&
- (options.f_block_size == Eigen::Dynamic)) {
- return new PartitionedMatrixView<Eigen::Dynamic, Eigen::Dynamic, Eigen::Dynamic>(
- matrix, options.elimination_groups[0]);
- }
+ if ((options.row_block_size == 2) &&
+ (options.e_block_size == 2) &&
+ (options.f_block_size == 2)) {
+ return new PartitionedMatrixView<2, 2, 2>(matrix, options.elimination_groups[0]);
+ }
+ if ((options.row_block_size == 2) &&
+ (options.e_block_size == 2) &&
+ (options.f_block_size == 3)) {
+ return new PartitionedMatrixView<2, 2, 3>(matrix, options.elimination_groups[0]);
+ }
+ if ((options.row_block_size == 2) &&
+ (options.e_block_size == 2) &&
+ (options.f_block_size == 4)) {
+ return new PartitionedMatrixView<2, 2, 4>(matrix, options.elimination_groups[0]);
+ }
+ if ((options.row_block_size == 2) &&
+ (options.e_block_size == 2)) {
+ return new PartitionedMatrixView<2, 2, Eigen::Dynamic>(matrix, options.elimination_groups[0]);
+ }
+ if ((options.row_block_size == 2) &&
+ (options.e_block_size == 3) &&
+ (options.f_block_size == 3)) {
+ return new PartitionedMatrixView<2, 3, 3>(matrix, options.elimination_groups[0]);
+ }
+ if ((options.row_block_size == 2) &&
+ (options.e_block_size == 3) &&
+ (options.f_block_size == 4)) {
+ return new PartitionedMatrixView<2, 3, 4>(matrix, options.elimination_groups[0]);
+ }
+ if ((options.row_block_size == 2) &&
+ (options.e_block_size == 3) &&
+ (options.f_block_size == 6)) {
+ return new PartitionedMatrixView<2, 3, 6>(matrix, options.elimination_groups[0]);
+ }
+ if ((options.row_block_size == 2) &&
+ (options.e_block_size == 3) &&
+ (options.f_block_size == 9)) {
+ return new PartitionedMatrixView<2, 3, 9>(matrix, options.elimination_groups[0]);
+ }
+ if ((options.row_block_size == 2) &&
+ (options.e_block_size == 3)) {
+ return new PartitionedMatrixView<2, 3, Eigen::Dynamic>(matrix, options.elimination_groups[0]);
+ }
+ if ((options.row_block_size == 2) &&
+ (options.e_block_size == 4) &&
+ (options.f_block_size == 3)) {
+ return new PartitionedMatrixView<2, 4, 3>(matrix, options.elimination_groups[0]);
+ }
+ if ((options.row_block_size == 2) &&
+ (options.e_block_size == 4) &&
+ (options.f_block_size == 4)) {
+ return new PartitionedMatrixView<2, 4, 4>(matrix, options.elimination_groups[0]);
+ }
+ if ((options.row_block_size == 2) &&
+ (options.e_block_size == 4) &&
+ (options.f_block_size == 6)) {
+ return new PartitionedMatrixView<2, 4, 6>(matrix, options.elimination_groups[0]);
+ }
+ if ((options.row_block_size == 2) &&
+ (options.e_block_size == 4) &&
+ (options.f_block_size == 8)) {
+ return new PartitionedMatrixView<2, 4, 8>(matrix, options.elimination_groups[0]);
+ }
+ if ((options.row_block_size == 2) &&
+ (options.e_block_size == 4) &&
+ (options.f_block_size == 9)) {
+ return new PartitionedMatrixView<2, 4, 9>(matrix, options.elimination_groups[0]);
+ }
+ if ((options.row_block_size == 2) &&
+ (options.e_block_size == 4)) {
+ return new PartitionedMatrixView<2, 4, Eigen::Dynamic>(matrix, options.elimination_groups[0]);
+ }
+ if (options.row_block_size == 2){
+ return new PartitionedMatrixView<2, Eigen::Dynamic, Eigen::Dynamic>(matrix, options.elimination_groups[0]);
+ }
+ if ((options.row_block_size == 3) &&
+ (options.e_block_size == 3) &&
+ (options.f_block_size == 3)) {
+ return new PartitionedMatrixView<3, 3, 3>(matrix, options.elimination_groups[0]);
+ }
+ if ((options.row_block_size == 4) &&
+ (options.e_block_size == 4) &&
+ (options.f_block_size == 2)) {
+ return new PartitionedMatrixView<4, 4, 2>(matrix, options.elimination_groups[0]);
+ }
+ if ((options.row_block_size == 4) &&
+ (options.e_block_size == 4) &&
+ (options.f_block_size == 3)) {
+ return new PartitionedMatrixView<4, 4, 3>(matrix, options.elimination_groups[0]);
+ }
+ if ((options.row_block_size == 4) &&
+ (options.e_block_size == 4) &&
+ (options.f_block_size == 4)) {
+ return new PartitionedMatrixView<4, 4, 4>(matrix, options.elimination_groups[0]);
+ }
+ if ((options.row_block_size == 4) &&
+ (options.e_block_size == 4)) {
+ return new PartitionedMatrixView<4, 4, Eigen::Dynamic>(matrix, options.elimination_groups[0]);
+ }
#endif
VLOG(1) << "Template specializations not found for <"
diff --git a/extern/ceres/internal/ceres/partitioned_matrix_view.h b/extern/ceres/internal/ceres/partitioned_matrix_view.h
index 6e75060a47e..3853ea10dd6 100644
--- a/extern/ceres/internal/ceres/partitioned_matrix_view.h
+++ b/extern/ceres/internal/ceres/partitioned_matrix_view.h
@@ -119,20 +119,20 @@ class PartitionedMatrixView : public PartitionedMatrixViewBase {
PartitionedMatrixView(const BlockSparseMatrix& matrix, int num_col_blocks_e);
virtual ~PartitionedMatrixView();
- virtual void LeftMultiplyE(const double* x, double* y) const;
- virtual void LeftMultiplyF(const double* x, double* y) const;
- virtual void RightMultiplyE(const double* x, double* y) const;
- virtual void RightMultiplyF(const double* x, double* y) const;
- virtual BlockSparseMatrix* CreateBlockDiagonalEtE() const;
- virtual BlockSparseMatrix* CreateBlockDiagonalFtF() const;
- virtual void UpdateBlockDiagonalEtE(BlockSparseMatrix* block_diagonal) const;
- virtual void UpdateBlockDiagonalFtF(BlockSparseMatrix* block_diagonal) const;
- virtual int num_col_blocks_e() const { return num_col_blocks_e_; }
- virtual int num_col_blocks_f() const { return num_col_blocks_f_; }
- virtual int num_cols_e() const { return num_cols_e_; }
- virtual int num_cols_f() const { return num_cols_f_; }
- virtual int num_rows() const { return matrix_.num_rows(); }
- virtual int num_cols() const { return matrix_.num_cols(); }
+ void LeftMultiplyE(const double* x, double* y) const final;
+ void LeftMultiplyF(const double* x, double* y) const final;
+ void RightMultiplyE(const double* x, double* y) const final;
+ void RightMultiplyF(const double* x, double* y) const final;
+ BlockSparseMatrix* CreateBlockDiagonalEtE() const final;
+ BlockSparseMatrix* CreateBlockDiagonalFtF() const final;
+ void UpdateBlockDiagonalEtE(BlockSparseMatrix* block_diagonal) const final;
+ void UpdateBlockDiagonalFtF(BlockSparseMatrix* block_diagonal) const final;
+ int num_col_blocks_e() const final { return num_col_blocks_e_; }
+ int num_col_blocks_f() const final { return num_col_blocks_f_; }
+ int num_cols_e() const final { return num_cols_e_; }
+ int num_cols_f() const final { return num_cols_f_; }
+ int num_rows() const final { return matrix_.num_rows(); }
+ int num_cols() const final { return matrix_.num_cols(); }
private:
BlockSparseMatrix* CreateBlockDiagonalMatrixLayout(int start_col_block,
diff --git a/extern/ceres/internal/ceres/partitioned_matrix_view_impl.h b/extern/ceres/internal/ceres/partitioned_matrix_view_impl.h
index 86fb278fa27..f3f548c7a80 100644
--- a/extern/ceres/internal/ceres/partitioned_matrix_view_impl.h
+++ b/extern/ceres/internal/ceres/partitioned_matrix_view_impl.h
@@ -50,7 +50,7 @@ PartitionedMatrixView(
: matrix_(matrix),
num_col_blocks_e_(num_col_blocks_e) {
const CompressedRowBlockStructure* bs = matrix_.block_structure();
- CHECK_NOTNULL(bs);
+ CHECK(bs != nullptr);
num_col_blocks_f_ = bs->cols.size() - num_col_blocks_e_;
diff --git a/extern/ceres/internal/ceres/generate_partitioned_matrix_view_specializations.py b/extern/ceres/internal/ceres/partitioned_matrix_view_template.py
index c4ac3cf2332..7894523cdea 100644
--- a/extern/ceres/internal/ceres/generate_partitioned_matrix_view_specializations.py
+++ b/extern/ceres/internal/ceres/partitioned_matrix_view_template.py
@@ -46,29 +46,8 @@
# The list of tuples, specializations indicates the set of
# specializations that is generated.
-# Set of template specializations to generate
-SPECIALIZATIONS = [(2, 2, 2),
- (2, 2, 3),
- (2, 2, 4),
- (2, 2, "Eigen::Dynamic"),
- (2, 3, 3),
- (2, 3, 4),
- (2, 3, 6),
- (2, 3, 9),
- (2, 3, "Eigen::Dynamic"),
- (2, 4, 3),
- (2, 4, 4),
- (2, 4, 8),
- (2, 4, 9),
- (2, 4, "Eigen::Dynamic"),
- (2, "Eigen::Dynamic", "Eigen::Dynamic"),
- (4, 4, 2),
- (4, 4, 3),
- (4, 4, 4),
- (4, 4, "Eigen::Dynamic"),
- ("Eigen::Dynamic", "Eigen::Dynamic", "Eigen::Dynamic")]
HEADER = """// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2017 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -106,8 +85,7 @@ HEADER = """// Ceres Solver - A fast non-linear least squares minimizer
// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
//=========================================
//
-// This file is generated using generate_partitioned_matrix_view_specializations.py.
-// Editing it manually is not recommended.
+// This file is generated using generate_template_specializations.py.
"""
DYNAMIC_FILE = """
@@ -157,14 +135,7 @@ PartitionedMatrixViewBase::Create(const LinearSolver::Options& options,
const BlockSparseMatrix& matrix) {
#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
"""
-
-FACTORY_CONDITIONAL = """ if ((options.row_block_size == %s) &&
- (options.e_block_size == %s) &&
- (options.f_block_size == %s)) {
- return new PartitionedMatrixView<%s, %s, %s>(
- matrix, options.elimination_groups[0]);
- }
-"""
+FACTORY = """ return new PartitionedMatrixView<%s, %s, %s>(matrix, options.elimination_groups[0]);"""
FACTORY_FOOTER = """
#endif
@@ -179,54 +150,3 @@ FACTORY_FOOTER = """
} // namespace internal
} // namespace ceres
"""
-
-
-def SuffixForSize(size):
- if size == "Eigen::Dynamic":
- return "d"
- return str(size)
-
-
-def SpecializationFilename(prefix, row_block_size, e_block_size, f_block_size):
- return "_".join([prefix] + map(SuffixForSize, (row_block_size,
- e_block_size,
- f_block_size)))
-
-
-def Specialize():
- """
- Generate specialization code and the conditionals to instantiate it.
- """
- f = open("partitioned_matrix_view.cc", "w")
- f.write(HEADER)
- f.write(FACTORY_FILE_HEADER)
-
- for row_block_size, e_block_size, f_block_size in SPECIALIZATIONS:
- output = SpecializationFilename("generated/partitioned_matrix_view",
- row_block_size,
- e_block_size,
- f_block_size) + ".cc"
- fptr = open(output, "w")
- fptr.write(HEADER)
-
- template = SPECIALIZATION_FILE
- if (row_block_size == "Eigen::Dynamic" and
- e_block_size == "Eigen::Dynamic" and
- f_block_size == "Eigen::Dynamic"):
- template = DYNAMIC_FILE
-
- fptr.write(template % (row_block_size, e_block_size, f_block_size))
- fptr.close()
-
- f.write(FACTORY_CONDITIONAL % (row_block_size,
- e_block_size,
- f_block_size,
- row_block_size,
- e_block_size,
- f_block_size))
- f.write(FACTORY_FOOTER)
- f.close()
-
-
-if __name__ == "__main__":
- Specialize()
diff --git a/extern/ceres/internal/ceres/polynomial.cc b/extern/ceres/internal/ceres/polynomial.cc
index 13bf8edeee6..20812f4de81 100644
--- a/extern/ceres/internal/ceres/polynomial.cc
+++ b/extern/ceres/internal/ceres/polynomial.cc
@@ -36,14 +36,13 @@
#include <vector>
#include "Eigen/Dense"
+#include "ceres/function_sample.h"
#include "ceres/internal/port.h"
-#include "ceres/stringprintf.h"
#include "glog/logging.h"
namespace ceres {
namespace internal {
-using std::string;
using std::vector;
namespace {
@@ -53,7 +52,7 @@ namespace {
// In: Numerische Mathematik, Volume 13, Number 4 (1969), 293-304,
// Springer Berlin / Heidelberg. DOI: 10.1007/BF02165404
void BalanceCompanionMatrix(Matrix* companion_matrix_ptr) {
- CHECK_NOTNULL(companion_matrix_ptr);
+ CHECK(companion_matrix_ptr != nullptr);
Matrix& companion_matrix = *companion_matrix_ptr;
Matrix companion_matrix_offdiagonal = companion_matrix;
companion_matrix_offdiagonal.diagonal().setZero();
@@ -105,7 +104,7 @@ void BalanceCompanionMatrix(Matrix* companion_matrix_ptr) {
void BuildCompanionMatrix(const Vector& polynomial,
Matrix* companion_matrix_ptr) {
- CHECK_NOTNULL(companion_matrix_ptr);
+ CHECK(companion_matrix_ptr != nullptr);
Matrix& companion_matrix = *companion_matrix_ptr;
const int degree = polynomial.size() - 1;
@@ -327,12 +326,6 @@ void MinimizePolynomial(const Vector& polynomial,
}
}
-string FunctionSample::ToDebugString() const {
- return StringPrintf("[x: %.8e, value: %.8e, gradient: %.8e, "
- "value_is_valid: %d, gradient_is_valid: %d]",
- x, value, gradient, value_is_valid, gradient_is_valid);
-}
-
Vector FindInterpolatingPolynomial(const vector<FunctionSample>& samples) {
const int num_samples = samples.size();
int num_constraints = 0;
@@ -370,7 +363,10 @@ Vector FindInterpolatingPolynomial(const vector<FunctionSample>& samples) {
}
}
- return lhs.fullPivLu().solve(rhs);
+ // TODO(sameeragarwal): This is a hack.
+ // https://github.com/ceres-solver/ceres-solver/issues/248
+ Eigen::FullPivLU<Matrix> lu(lhs);
+ return lu.setThreshold(0.0).solve(rhs);
}
void MinimizeInterpolatingPolynomial(const vector<FunctionSample>& samples,
diff --git a/extern/ceres/internal/ceres/polynomial.h b/extern/ceres/internal/ceres/polynomial.h
index 09a64c577f5..3e09bae3d0f 100644
--- a/extern/ceres/internal/ceres/polynomial.h
+++ b/extern/ceres/internal/ceres/polynomial.h
@@ -32,7 +32,6 @@
#ifndef CERES_INTERNAL_POLYNOMIAL_SOLVER_H_
#define CERES_INTERNAL_POLYNOMIAL_SOLVER_H_
-#include <string>
#include <vector>
#include "ceres/internal/eigen.h"
#include "ceres/internal/port.h"
@@ -40,6 +39,8 @@
namespace ceres {
namespace internal {
+struct FunctionSample;
+
// All polynomials are assumed to be the form
//
// sum_{i=0}^N polynomial(i) x^{N-i}.
@@ -84,27 +85,6 @@ void MinimizePolynomial(const Vector& polynomial,
double* optimal_x,
double* optimal_value);
-// Structure for storing sample values of a function.
-//
-// Clients can use this struct to communicate the value of the
-// function and or its gradient at a given point x.
-struct FunctionSample {
- FunctionSample()
- : x(0.0),
- value(0.0),
- value_is_valid(false),
- gradient(0.0),
- gradient_is_valid(false) {
- }
- std::string ToDebugString() const;
-
- double x;
- double value; // value = f(x)
- bool value_is_valid;
- double gradient; // gradient = f'(x)
- bool gradient_is_valid;
-};
-
// Given a set of function value and/or gradient samples, find a
// polynomial whose value and gradients are exactly equal to the ones
// in samples.
diff --git a/extern/ceres/internal/ceres/preconditioner.cc b/extern/ceres/internal/ceres/preconditioner.cc
index 82621dae50c..f98374e0cf8 100644
--- a/extern/ceres/internal/ceres/preconditioner.cc
+++ b/extern/ceres/internal/ceres/preconditioner.cc
@@ -49,7 +49,8 @@ PreconditionerType Preconditioner::PreconditionerForZeroEBlocks(
SparseMatrixPreconditionerWrapper::SparseMatrixPreconditionerWrapper(
const SparseMatrix* matrix)
- : matrix_(CHECK_NOTNULL(matrix)) {
+ : matrix_(matrix) {
+ CHECK(matrix != nullptr);
}
SparseMatrixPreconditionerWrapper::~SparseMatrixPreconditionerWrapper() {
diff --git a/extern/ceres/internal/ceres/preconditioner.h b/extern/ceres/internal/ceres/preconditioner.h
index a248eae060d..3e46ed83db2 100644
--- a/extern/ceres/internal/ceres/preconditioner.h
+++ b/extern/ceres/internal/ceres/preconditioner.h
@@ -34,6 +34,7 @@
#include <vector>
#include "ceres/casts.h"
#include "ceres/compressed_row_sparse_matrix.h"
+#include "ceres/context_impl.h"
#include "ceres/linear_operator.h"
#include "ceres/sparse_matrix.h"
#include "ceres/types.h"
@@ -47,22 +48,27 @@ class SparseMatrix;
class Preconditioner : public LinearOperator {
public:
struct Options {
- Options()
- : type(JACOBI),
- visibility_clustering_type(CANONICAL_VIEWS),
- sparse_linear_algebra_library_type(SUITE_SPARSE),
- num_threads(1),
- row_block_size(Eigen::Dynamic),
- e_block_size(Eigen::Dynamic),
- f_block_size(Eigen::Dynamic) {
- }
-
- PreconditionerType type;
- VisibilityClusteringType visibility_clustering_type;
- SparseLinearAlgebraLibraryType sparse_linear_algebra_library_type;
+ PreconditionerType type = JACOBI;
+ VisibilityClusteringType visibility_clustering_type = CANONICAL_VIEWS;
+ SparseLinearAlgebraLibraryType sparse_linear_algebra_library_type = SUITE_SPARSE;
+
+ // When using the subset preconditioner, all row blocks starting
+ // from this row block are used to construct the preconditioner.
+ //
+ // i.e., the Jacobian matrix A is horizontally partitioned as
+ //
+ // A = [P]
+ // [Q]
+ //
+ // where P has subset_preconditioner_start_row_block row blocks,
+ // and the preconditioner is the inverse of the matrix Q'Q.
+ int subset_preconditioner_start_row_block = -1;
+
+ // See solver.h for information about these flags.
+ bool use_postordering = false;
// If possible, how many threads the preconditioner can use.
- int num_threads;
+ int num_threads = 1;
// Hints about the order in which the parameter blocks should be
// eliminated by the linear solver.
@@ -91,9 +97,11 @@ class Preconditioner : public LinearOperator {
//
// Please see schur_complement_solver.h and schur_eliminator.h for
// more details.
- int row_block_size;
- int e_block_size;
- int f_block_size;
+ int row_block_size = Eigen::Dynamic;
+ int e_block_size = Eigen::Dynamic;
+ int f_block_size = Eigen::Dynamic;
+
+ ContextImpl* context = nullptr;
};
// If the optimization problem is such that there are no remaining
@@ -123,13 +131,13 @@ class Preconditioner : public LinearOperator {
// LeftMultiply and num_cols are just calls to RightMultiply and
// num_rows respectively. Update() must be called before
// RightMultiply can be called.
- virtual void RightMultiply(const double* x, double* y) const = 0;
- virtual void LeftMultiply(const double* x, double* y) const {
+ void RightMultiply(const double* x, double* y) const override = 0;
+ void LeftMultiply(const double* x, double* y) const override {
return RightMultiply(x, y);
}
- virtual int num_rows() const = 0;
- virtual int num_cols() const {
+ int num_rows() const override = 0;
+ int num_cols() const override {
return num_rows();
}
};
@@ -141,7 +149,7 @@ template <typename MatrixType>
class TypedPreconditioner : public Preconditioner {
public:
virtual ~TypedPreconditioner() {}
- virtual bool Update(const LinearOperator& A, const double* D) {
+ bool Update(const LinearOperator& A, const double* D) final {
return UpdateImpl(*down_cast<const MatrixType*>(&A), D);
}
@@ -149,7 +157,7 @@ class TypedPreconditioner : public Preconditioner {
virtual bool UpdateImpl(const MatrixType& A, const double* D) = 0;
};
-// Preconditioners that depend on acccess to the low level structure
+// Preconditioners that depend on access to the low level structure
// of a SparseMatrix.
typedef TypedPreconditioner<SparseMatrix> SparseMatrixPreconditioner; // NOLINT
typedef TypedPreconditioner<BlockSparseMatrix> BlockSparseMatrixPreconditioner; // NOLINT
diff --git a/extern/ceres/internal/ceres/preprocessor.cc b/extern/ceres/internal/ceres/preprocessor.cc
index 4aba6a39ce8..02219147d75 100644
--- a/extern/ceres/internal/ceres/preprocessor.cc
+++ b/extern/ceres/internal/ceres/preprocessor.cc
@@ -31,6 +31,7 @@
#include "ceres/callbacks.h"
#include "ceres/gradient_checking_cost_function.h"
#include "ceres/line_search_preprocessor.h"
+#include "ceres/parallel_for.h"
#include "ceres/preprocessor.h"
#include "ceres/problem_impl.h"
#include "ceres/solver.h"
@@ -56,25 +57,15 @@ Preprocessor::~Preprocessor() {
}
void ChangeNumThreadsIfNeeded(Solver::Options* options) {
-#ifndef CERES_USE_OPENMP
- if (options->num_threads > 1) {
+ const int num_threads_available = MaxNumThreadsAvailable();
+ if (options->num_threads > num_threads_available) {
LOG(WARNING)
- << "OpenMP support is not compiled into this binary; "
- << "only options.num_threads = 1 is supported. Switching "
- << "to single threaded mode.";
- options->num_threads = 1;
+ << "Specified options.num_threads: " << options->num_threads
+ << " exceeds maximum available from the threading model Ceres "
+ << "was compiled with: " << num_threads_available
+ << ". Bounding to maximum number available.";
+ options->num_threads = num_threads_available;
}
-
- // Only the Trust Region solver currently uses a linear solver.
- if (options->minimizer_type == TRUST_REGION &&
- options->num_linear_solver_threads > 1) {
- LOG(WARNING)
- << "OpenMP support is not compiled into this binary; "
- << "only options.num_linear_solver_threads=1 is supported. Switching "
- << "to single threaded mode.";
- options->num_linear_solver_threads = 1;
- }
-#endif // CERES_USE_OPENMP
}
void SetupCommonMinimizerOptions(PreprocessedProblem* pp) {
diff --git a/extern/ceres/internal/ceres/preprocessor.h b/extern/ceres/internal/ceres/preprocessor.h
index ff53d6f0d3f..99bd6c0c5dd 100644
--- a/extern/ceres/internal/ceres/preprocessor.h
+++ b/extern/ceres/internal/ceres/preprocessor.h
@@ -31,6 +31,7 @@
#ifndef CERES_INTERNAL_PREPROCESSOR_H_
#define CERES_INTERNAL_PREPROCESSOR_H_
+#include <memory>
#include <string>
#include <vector>
@@ -38,7 +39,6 @@
#include "ceres/evaluator.h"
#include "ceres/internal/eigen.h"
#include "ceres/internal/port.h"
-#include "ceres/internal/scoped_ptr.h"
#include "ceres/iteration_callback.h"
#include "ceres/linear_solver.h"
#include "ceres/minimizer.h"
@@ -91,14 +91,14 @@ struct PreprocessedProblem {
Minimizer::Options minimizer_options;
ProblemImpl* problem;
- scoped_ptr<ProblemImpl> gradient_checking_problem;
- scoped_ptr<Program> reduced_program;
- scoped_ptr<LinearSolver> linear_solver;
- scoped_ptr<IterationCallback> logging_callback;
- scoped_ptr<IterationCallback> state_updating_callback;
+ std::unique_ptr<ProblemImpl> gradient_checking_problem;
+ std::unique_ptr<Program> reduced_program;
+ std::unique_ptr<LinearSolver> linear_solver;
+ std::unique_ptr<IterationCallback> logging_callback;
+ std::unique_ptr<IterationCallback> state_updating_callback;
- shared_ptr<Evaluator> evaluator;
- shared_ptr<CoordinateDescentMinimizer> inner_iteration_minimizer;
+ std::shared_ptr<Evaluator> evaluator;
+ std::shared_ptr<CoordinateDescentMinimizer> inner_iteration_minimizer;
std::vector<double*> removed_parameter_blocks;
Vector reduced_parameters;
@@ -107,8 +107,9 @@ struct PreprocessedProblem {
// Common functions used by various preprocessors.
-// If OpenMP support is not available and user has requested more than
-// one thread, then set the *_num_threads options as needed to 1.
+// If the user has specified a num_threads > the maximum number of threads
+// available from the compiled threading model, bound the number of threads
+// to the maximum.
void ChangeNumThreadsIfNeeded(Solver::Options* options);
// Extract the effective parameter vector from the preprocessed
diff --git a/extern/ceres/internal/ceres/problem.cc b/extern/ceres/internal/ceres/problem.cc
index 730ce642036..767fe977296 100644
--- a/extern/ceres/internal/ceres/problem.cc
+++ b/extern/ceres/internal/ceres/problem.cc
@@ -32,6 +32,7 @@
#include "ceres/problem.h"
#include <vector>
+
#include "ceres/crs_matrix.h"
#include "ceres/problem_impl.h"
@@ -39,166 +40,90 @@ namespace ceres {
using std::vector;
-Problem::Problem() : problem_impl_(new internal::ProblemImpl) {}
+Problem::Problem() : impl_(new internal::ProblemImpl) {}
Problem::Problem(const Problem::Options& options)
- : problem_impl_(new internal::ProblemImpl(options)) {}
+ : impl_(new internal::ProblemImpl(options)) {}
+// Not inline defaulted in declaration due to use of std::unique_ptr.
+Problem::Problem(Problem&&) = default;
+Problem& Problem::operator=(Problem&&) = default;
Problem::~Problem() {}
ResidualBlockId Problem::AddResidualBlock(
CostFunction* cost_function,
LossFunction* loss_function,
const vector<double*>& parameter_blocks) {
- return problem_impl_->AddResidualBlock(cost_function,
- loss_function,
- parameter_blocks);
-}
-
-ResidualBlockId Problem::AddResidualBlock(
- CostFunction* cost_function,
- LossFunction* loss_function,
- double* x0) {
- return problem_impl_->AddResidualBlock(cost_function,
- loss_function,
- x0);
-}
-
-ResidualBlockId Problem::AddResidualBlock(
- CostFunction* cost_function,
- LossFunction* loss_function,
- double* x0, double* x1) {
- return problem_impl_->AddResidualBlock(cost_function,
- loss_function,
- x0, x1);
-}
-
-ResidualBlockId Problem::AddResidualBlock(
- CostFunction* cost_function,
- LossFunction* loss_function,
- double* x0, double* x1, double* x2) {
- return problem_impl_->AddResidualBlock(cost_function,
- loss_function,
- x0, x1, x2);
-}
-
-ResidualBlockId Problem::AddResidualBlock(
- CostFunction* cost_function,
- LossFunction* loss_function,
- double* x0, double* x1, double* x2, double* x3) {
- return problem_impl_->AddResidualBlock(cost_function,
- loss_function,
- x0, x1, x2, x3);
-}
-
-ResidualBlockId Problem::AddResidualBlock(
- CostFunction* cost_function,
- LossFunction* loss_function,
- double* x0, double* x1, double* x2, double* x3, double* x4) {
- return problem_impl_->AddResidualBlock(cost_function,
- loss_function,
- x0, x1, x2, x3, x4);
-}
-
-ResidualBlockId Problem::AddResidualBlock(
- CostFunction* cost_function,
- LossFunction* loss_function,
- double* x0, double* x1, double* x2, double* x3, double* x4, double* x5) {
- return problem_impl_->AddResidualBlock(cost_function,
- loss_function,
- x0, x1, x2, x3, x4, x5);
-}
-
-ResidualBlockId Problem::AddResidualBlock(
- CostFunction* cost_function,
- LossFunction* loss_function,
- double* x0, double* x1, double* x2, double* x3, double* x4, double* x5,
- double* x6) {
- return problem_impl_->AddResidualBlock(cost_function,
- loss_function,
- x0, x1, x2, x3, x4, x5, x6);
+ return impl_->AddResidualBlock(cost_function,
+ loss_function,
+ parameter_blocks.data(),
+ static_cast<int>(parameter_blocks.size()));
}
-ResidualBlockId Problem::AddResidualBlock(
- CostFunction* cost_function,
- LossFunction* loss_function,
- double* x0, double* x1, double* x2, double* x3, double* x4, double* x5,
- double* x6, double* x7) {
- return problem_impl_->AddResidualBlock(cost_function,
- loss_function,
- x0, x1, x2, x3, x4, x5, x6, x7);
-}
-
-ResidualBlockId Problem::AddResidualBlock(
- CostFunction* cost_function,
- LossFunction* loss_function,
- double* x0, double* x1, double* x2, double* x3, double* x4, double* x5,
- double* x6, double* x7, double* x8) {
- return problem_impl_->AddResidualBlock(cost_function,
- loss_function,
- x0, x1, x2, x3, x4, x5, x6, x7, x8);
-}
-
-ResidualBlockId Problem::AddResidualBlock(
- CostFunction* cost_function,
- LossFunction* loss_function,
- double* x0, double* x1, double* x2, double* x3, double* x4, double* x5,
- double* x6, double* x7, double* x8, double* x9) {
- return problem_impl_->AddResidualBlock(
- cost_function,
- loss_function,
- x0, x1, x2, x3, x4, x5, x6, x7, x8, x9);
+ResidualBlockId Problem::AddResidualBlock(CostFunction* cost_function,
+ LossFunction* loss_function,
+ double* const* const parameter_blocks,
+ int num_parameter_blocks) {
+ return impl_->AddResidualBlock(
+ cost_function, loss_function, parameter_blocks, num_parameter_blocks);
}
void Problem::AddParameterBlock(double* values, int size) {
- problem_impl_->AddParameterBlock(values, size);
+ impl_->AddParameterBlock(values, size);
}
void Problem::AddParameterBlock(double* values,
int size,
LocalParameterization* local_parameterization) {
- problem_impl_->AddParameterBlock(values, size, local_parameterization);
+ impl_->AddParameterBlock(values, size, local_parameterization);
}
void Problem::RemoveResidualBlock(ResidualBlockId residual_block) {
- problem_impl_->RemoveResidualBlock(residual_block);
+ impl_->RemoveResidualBlock(residual_block);
}
-void Problem::RemoveParameterBlock(double* values) {
- problem_impl_->RemoveParameterBlock(values);
+void Problem::RemoveParameterBlock(const double* values) {
+ impl_->RemoveParameterBlock(values);
}
-void Problem::SetParameterBlockConstant(double* values) {
- problem_impl_->SetParameterBlockConstant(values);
+void Problem::SetParameterBlockConstant(const double* values) {
+ impl_->SetParameterBlockConstant(values);
}
void Problem::SetParameterBlockVariable(double* values) {
- problem_impl_->SetParameterBlockVariable(values);
+ impl_->SetParameterBlockVariable(values);
}
-bool Problem::IsParameterBlockConstant(double* values) const {
- return problem_impl_->IsParameterBlockConstant(values);
+bool Problem::IsParameterBlockConstant(const double* values) const {
+ return impl_->IsParameterBlockConstant(values);
}
void Problem::SetParameterization(
- double* values,
- LocalParameterization* local_parameterization) {
- problem_impl_->SetParameterization(values, local_parameterization);
+ double* values, LocalParameterization* local_parameterization) {
+ impl_->SetParameterization(values, local_parameterization);
}
const LocalParameterization* Problem::GetParameterization(
- double* values) const {
- return problem_impl_->GetParameterization(values);
+ const double* values) const {
+ return impl_->GetParameterization(values);
}
void Problem::SetParameterLowerBound(double* values,
int index,
double lower_bound) {
- problem_impl_->SetParameterLowerBound(values, index, lower_bound);
+ impl_->SetParameterLowerBound(values, index, lower_bound);
}
void Problem::SetParameterUpperBound(double* values,
int index,
double upper_bound) {
- problem_impl_->SetParameterUpperBound(values, index, upper_bound);
+ impl_->SetParameterUpperBound(values, index, upper_bound);
+}
+
+double Problem::GetParameterUpperBound(const double* values, int index) const {
+ return impl_->GetParameterUpperBound(values, index);
+}
+
+double Problem::GetParameterLowerBound(const double* values, int index) const {
+ return impl_->GetParameterLowerBound(values, index);
}
bool Problem::Evaluate(const EvaluateOptions& evaluate_options,
@@ -206,72 +131,66 @@ bool Problem::Evaluate(const EvaluateOptions& evaluate_options,
vector<double>* residuals,
vector<double>* gradient,
CRSMatrix* jacobian) {
- return problem_impl_->Evaluate(evaluate_options,
- cost,
- residuals,
- gradient,
- jacobian);
+ return impl_->Evaluate(evaluate_options, cost, residuals, gradient, jacobian);
}
-int Problem::NumParameterBlocks() const {
- return problem_impl_->NumParameterBlocks();
+bool Problem::EvaluateResidualBlock(ResidualBlockId residual_block_id,
+ bool apply_loss_function,
+ double* cost,
+ double* residuals,
+ double** jacobians) const {
+ return impl_->EvaluateResidualBlock(
+ residual_block_id, apply_loss_function, cost, residuals, jacobians);
}
-int Problem::NumParameters() const {
- return problem_impl_->NumParameters();
-}
+int Problem::NumParameterBlocks() const { return impl_->NumParameterBlocks(); }
-int Problem::NumResidualBlocks() const {
- return problem_impl_->NumResidualBlocks();
-}
+int Problem::NumParameters() const { return impl_->NumParameters(); }
-int Problem::NumResiduals() const {
- return problem_impl_->NumResiduals();
-}
+int Problem::NumResidualBlocks() const { return impl_->NumResidualBlocks(); }
+
+int Problem::NumResiduals() const { return impl_->NumResiduals(); }
int Problem::ParameterBlockSize(const double* parameter_block) const {
- return problem_impl_->ParameterBlockSize(parameter_block);
+ return impl_->ParameterBlockSize(parameter_block);
}
int Problem::ParameterBlockLocalSize(const double* parameter_block) const {
- return problem_impl_->ParameterBlockLocalSize(parameter_block);
+ return impl_->ParameterBlockLocalSize(parameter_block);
}
bool Problem::HasParameterBlock(const double* values) const {
- return problem_impl_->HasParameterBlock(values);
+ return impl_->HasParameterBlock(values);
}
void Problem::GetParameterBlocks(vector<double*>* parameter_blocks) const {
- problem_impl_->GetParameterBlocks(parameter_blocks);
+ impl_->GetParameterBlocks(parameter_blocks);
}
void Problem::GetResidualBlocks(
vector<ResidualBlockId>* residual_blocks) const {
- problem_impl_->GetResidualBlocks(residual_blocks);
+ impl_->GetResidualBlocks(residual_blocks);
}
void Problem::GetParameterBlocksForResidualBlock(
const ResidualBlockId residual_block,
vector<double*>* parameter_blocks) const {
- problem_impl_->GetParameterBlocksForResidualBlock(residual_block,
- parameter_blocks);
+ impl_->GetParameterBlocksForResidualBlock(residual_block, parameter_blocks);
}
const CostFunction* Problem::GetCostFunctionForResidualBlock(
const ResidualBlockId residual_block) const {
- return problem_impl_->GetCostFunctionForResidualBlock(residual_block);
+ return impl_->GetCostFunctionForResidualBlock(residual_block);
}
const LossFunction* Problem::GetLossFunctionForResidualBlock(
const ResidualBlockId residual_block) const {
- return problem_impl_->GetLossFunctionForResidualBlock(residual_block);
+ return impl_->GetLossFunctionForResidualBlock(residual_block);
}
void Problem::GetResidualBlocksForParameterBlock(
- const double* values,
- vector<ResidualBlockId>* residual_blocks) const {
- problem_impl_->GetResidualBlocksForParameterBlock(values,
- residual_blocks);
+ const double* values, vector<ResidualBlockId>* residual_blocks) const {
+ impl_->GetResidualBlocksForParameterBlock(values, residual_blocks);
}
} // namespace ceres
diff --git a/extern/ceres/internal/ceres/problem_impl.cc b/extern/ceres/internal/ceres/problem_impl.cc
index 4abea8b33ee..6cc4d336c6a 100644
--- a/extern/ceres/internal/ceres/problem_impl.cc
+++ b/extern/ceres/internal/ceres/problem_impl.cc
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2019 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -33,21 +33,31 @@
#include <algorithm>
#include <cstddef>
+#include <cstdint>
#include <iterator>
+#include <memory>
#include <set>
#include <string>
#include <utility>
#include <vector>
+
#include "ceres/casts.h"
+#include "ceres/compressed_row_jacobian_writer.h"
#include "ceres/compressed_row_sparse_matrix.h"
+#include "ceres/context_impl.h"
#include "ceres/cost_function.h"
#include "ceres/crs_matrix.h"
+#include "ceres/evaluation_callback.h"
#include "ceres/evaluator.h"
+#include "ceres/internal/fixed_array.h"
+#include "ceres/internal/port.h"
#include "ceres/loss_function.h"
#include "ceres/map_util.h"
#include "ceres/parameter_block.h"
#include "ceres/program.h"
+#include "ceres/program_evaluator.h"
#include "ceres/residual_block.h"
+#include "ceres/scratch_evaluate_preparer.h"
#include "ceres/stl_util.h"
#include "ceres/stringprintf.h"
#include "glog/logging.h"
@@ -58,36 +68,66 @@ namespace internal {
using std::map;
using std::string;
using std::vector;
-typedef std::map<double*, internal::ParameterBlock*> ParameterMap;
namespace {
// Returns true if two regions of memory, a and b, with sizes size_a and size_b
// respectively, overlap.
-bool RegionsAlias(const double* a, int size_a,
- const double* b, int size_b) {
- return (a < b) ? b < (a + size_a)
- : a < (b + size_b);
+bool RegionsAlias(const double* a, int size_a, const double* b, int size_b) {
+ return (a < b) ? b < (a + size_a) : a < (b + size_b);
}
void CheckForNoAliasing(double* existing_block,
int existing_block_size,
double* new_block,
int new_block_size) {
- CHECK(!RegionsAlias(existing_block, existing_block_size,
- new_block, new_block_size))
+ CHECK(!RegionsAlias(
+ existing_block, existing_block_size, new_block, new_block_size))
<< "Aliasing detected between existing parameter block at memory "
- << "location " << existing_block
- << " and has size " << existing_block_size << " with new parameter "
+ << "location " << existing_block << " and has size "
+ << existing_block_size << " with new parameter "
<< "block that has memory address " << new_block << " and would have "
<< "size " << new_block_size << ".";
}
+template <typename KeyType>
+void DecrementValueOrDeleteKey(const KeyType key,
+ std::map<KeyType, int>* container) {
+ auto it = container->find(key);
+ if (it->second == 1) {
+ delete key;
+ container->erase(it);
+ } else {
+ --it->second;
+ }
+}
+
+template <typename ForwardIterator>
+void STLDeleteContainerPairFirstPointers(ForwardIterator begin,
+ ForwardIterator end) {
+ while (begin != end) {
+ delete begin->first;
+ ++begin;
+ }
+}
+
+void InitializeContext(Context* context,
+ ContextImpl** context_impl,
+ bool* context_impl_owned) {
+ if (context == nullptr) {
+ *context_impl_owned = true;
+ *context_impl = new ContextImpl;
+ } else {
+ *context_impl_owned = false;
+ *context_impl = down_cast<ContextImpl*>(context);
+ }
+}
+
} // namespace
ParameterBlock* ProblemImpl::InternalAddParameterBlock(double* values,
int size) {
- CHECK(values != NULL) << "Null pointer passed to AddParameterBlock "
- << "for a parameter with size " << size;
+ CHECK(values != nullptr) << "Null pointer passed to AddParameterBlock "
+ << "for a parameter with size " << size;
// Ignore the request if there is a block for the given pointer already.
ParameterMap::iterator it = parameter_block_map_.find(values);
@@ -97,8 +137,7 @@ ParameterBlock* ProblemImpl::InternalAddParameterBlock(double* values,
CHECK(size == existing_size)
<< "Tried adding a parameter block with the same double pointer, "
<< values << ", twice, but with different block sizes. Original "
- << "size was " << existing_size << " but new size is "
- << size;
+ << "size was " << existing_size << " but new size is " << size;
}
return it->second;
}
@@ -113,18 +152,13 @@ ParameterBlock* ProblemImpl::InternalAddParameterBlock(double* values,
if (lb != parameter_block_map_.begin()) {
ParameterMap::iterator previous = lb;
--previous;
- CheckForNoAliasing(previous->first,
- previous->second->Size(),
- values,
- size);
+ CheckForNoAliasing(
+ previous->first, previous->second->Size(), values, size);
}
// If lb is not off the end, check lb for aliasing.
if (lb != parameter_block_map_.end()) {
- CheckForNoAliasing(lb->first,
- lb->second->Size(),
- values,
- size);
+ CheckForNoAliasing(lb->first, lb->second->Size(), values, size);
}
}
}
@@ -145,7 +179,7 @@ ParameterBlock* ProblemImpl::InternalAddParameterBlock(double* values,
}
void ProblemImpl::InternalRemoveResidualBlock(ResidualBlock* residual_block) {
- CHECK_NOTNULL(residual_block);
+ CHECK(residual_block != nullptr);
// Perform no check on the validity of residual_block, that is handled in
// the public method: RemoveResidualBlock().
@@ -154,8 +188,8 @@ void ProblemImpl::InternalRemoveResidualBlock(ResidualBlock* residual_block) {
const int num_parameter_blocks_for_residual =
residual_block->NumParameterBlocks();
for (int i = 0; i < num_parameter_blocks_for_residual; ++i) {
- residual_block->parameter_blocks()[i]
- ->RemoveResidualBlock(residual_block);
+ residual_block->parameter_blocks()[i]->RemoveResidualBlock(
+ residual_block);
}
ResidualBlockSet::iterator it = residual_block_set_.find(residual_block);
@@ -173,16 +207,19 @@ void ProblemImpl::DeleteBlock(ResidualBlock* residual_block) {
// The const casts here are legit, since ResidualBlock holds these
// pointers as const pointers but we have ownership of them and
// have the right to destroy them when the destructor is called.
- if (options_.cost_function_ownership == TAKE_OWNERSHIP &&
- residual_block->cost_function() != NULL) {
- cost_functions_to_delete_.push_back(
- const_cast<CostFunction*>(residual_block->cost_function()));
+ CostFunction* cost_function =
+ const_cast<CostFunction*>(residual_block->cost_function());
+ if (options_.cost_function_ownership == TAKE_OWNERSHIP) {
+ DecrementValueOrDeleteKey(cost_function, &cost_function_ref_count_);
}
+
+ LossFunction* loss_function =
+ const_cast<LossFunction*>(residual_block->loss_function());
if (options_.loss_function_ownership == TAKE_OWNERSHIP &&
- residual_block->loss_function() != NULL) {
- loss_functions_to_delete_.push_back(
- const_cast<LossFunction*>(residual_block->loss_function()));
+ loss_function != nullptr) {
+ DecrementValueOrDeleteKey(loss_function, &loss_function_ref_count_);
}
+
delete residual_block;
}
@@ -193,7 +230,7 @@ void ProblemImpl::DeleteBlock(ResidualBlock* residual_block) {
// without doing a full scan.
void ProblemImpl::DeleteBlock(ParameterBlock* parameter_block) {
if (options_.local_parameterization_ownership == TAKE_OWNERSHIP &&
- parameter_block->local_parameterization() != NULL) {
+ parameter_block->local_parameterization() != nullptr) {
local_parameterizations_to_delete_.push_back(
parameter_block->mutable_local_parameterization());
}
@@ -201,18 +238,29 @@ void ProblemImpl::DeleteBlock(ParameterBlock* parameter_block) {
delete parameter_block;
}
-ProblemImpl::ProblemImpl() : program_(new internal::Program) {}
+ProblemImpl::ProblemImpl()
+ : options_(Problem::Options()), program_(new internal::Program) {
+ InitializeContext(options_.context, &context_impl_, &context_impl_owned_);
+}
+
ProblemImpl::ProblemImpl(const Problem::Options& options)
- : options_(options),
- program_(new internal::Program) {}
+ : options_(options), program_(new internal::Program) {
+ program_->evaluation_callback_ = options.evaluation_callback;
+ InitializeContext(options_.context, &context_impl_, &context_impl_owned_);
+}
ProblemImpl::~ProblemImpl() {
- // Collect the unique cost/loss functions and delete the residuals.
- const int num_residual_blocks = program_->residual_blocks_.size();
- cost_functions_to_delete_.reserve(num_residual_blocks);
- loss_functions_to_delete_.reserve(num_residual_blocks);
- for (int i = 0; i < program_->residual_blocks_.size(); ++i) {
- DeleteBlock(program_->residual_blocks_[i]);
+ STLDeleteContainerPointers(program_->residual_blocks_.begin(),
+ program_->residual_blocks_.end());
+
+ if (options_.cost_function_ownership == TAKE_OWNERSHIP) {
+ STLDeleteContainerPairFirstPointers(cost_function_ref_count_.begin(),
+ cost_function_ref_count_.end());
+ }
+
+ if (options_.loss_function_ownership == TAKE_OWNERSHIP) {
+ STLDeleteContainerPairFirstPointers(loss_function_ref_count_.begin(),
+ loss_function_ref_count_.end());
}
// Collect the unique parameterizations and delete the parameters.
@@ -220,57 +268,57 @@ ProblemImpl::~ProblemImpl() {
DeleteBlock(program_->parameter_blocks_[i]);
}
- // Delete the owned cost/loss functions and parameterizations.
+ // Delete the owned parameterizations.
STLDeleteUniqueContainerPointers(local_parameterizations_to_delete_.begin(),
local_parameterizations_to_delete_.end());
- STLDeleteUniqueContainerPointers(cost_functions_to_delete_.begin(),
- cost_functions_to_delete_.end());
- STLDeleteUniqueContainerPointers(loss_functions_to_delete_.begin(),
- loss_functions_to_delete_.end());
+
+ if (context_impl_owned_) {
+ delete context_impl_;
+ }
}
-ResidualBlock* ProblemImpl::AddResidualBlock(
+ResidualBlockId ProblemImpl::AddResidualBlock(
CostFunction* cost_function,
LossFunction* loss_function,
- const vector<double*>& parameter_blocks) {
- CHECK_NOTNULL(cost_function);
- CHECK_EQ(parameter_blocks.size(),
- cost_function->parameter_block_sizes().size());
+ double* const* const parameter_blocks,
+ int num_parameter_blocks) {
+ CHECK(cost_function != nullptr);
+ CHECK_EQ(num_parameter_blocks, cost_function->parameter_block_sizes().size());
// Check the sizes match.
- const vector<int32>& parameter_block_sizes =
+ const vector<int32_t>& parameter_block_sizes =
cost_function->parameter_block_sizes();
if (!options_.disable_all_safety_checks) {
- CHECK_EQ(parameter_block_sizes.size(), parameter_blocks.size())
+ CHECK_EQ(parameter_block_sizes.size(), num_parameter_blocks)
<< "Number of blocks input is different than the number of blocks "
<< "that the cost function expects.";
// Check for duplicate parameter blocks.
- vector<double*> sorted_parameter_blocks(parameter_blocks);
+ vector<double*> sorted_parameter_blocks(
+ parameter_blocks, parameter_blocks + num_parameter_blocks);
sort(sorted_parameter_blocks.begin(), sorted_parameter_blocks.end());
const bool has_duplicate_items =
(std::adjacent_find(sorted_parameter_blocks.begin(),
- sorted_parameter_blocks.end())
- != sorted_parameter_blocks.end());
+ sorted_parameter_blocks.end()) !=
+ sorted_parameter_blocks.end());
if (has_duplicate_items) {
string blocks;
- for (int i = 0; i < parameter_blocks.size(); ++i) {
+ for (int i = 0; i < num_parameter_blocks; ++i) {
blocks += StringPrintf(" %p ", parameter_blocks[i]);
}
LOG(FATAL) << "Duplicate parameter blocks in a residual parameter "
- << "are not allowed. Parameter block pointers: ["
- << blocks << "]";
+ << "are not allowed. Parameter block pointers: [" << blocks
+ << "]";
}
}
// Add parameter blocks and convert the double*'s to parameter blocks.
- vector<ParameterBlock*> parameter_block_ptrs(parameter_blocks.size());
- for (int i = 0; i < parameter_blocks.size(); ++i) {
- parameter_block_ptrs[i] =
- InternalAddParameterBlock(parameter_blocks[i],
- parameter_block_sizes[i]);
+ vector<ParameterBlock*> parameter_block_ptrs(num_parameter_blocks);
+ for (int i = 0; i < num_parameter_blocks; ++i) {
+ parameter_block_ptrs[i] = InternalAddParameterBlock(
+ parameter_blocks[i], parameter_block_sizes[i]);
}
if (!options_.disable_all_safety_checks) {
@@ -279,8 +327,8 @@ ResidualBlock* ProblemImpl::AddResidualBlock(
for (int i = 0; i < parameter_block_ptrs.size(); ++i) {
CHECK_EQ(cost_function->parameter_block_sizes()[i],
parameter_block_ptrs[i]->Size())
- << "The cost function expects parameter block " << i
- << " of size " << cost_function->parameter_block_sizes()[i]
+ << "The cost function expects parameter block " << i << " of size "
+ << cost_function->parameter_block_sizes()[i]
<< " but was given a block of size "
<< parameter_block_ptrs[i]->Size();
}
@@ -294,7 +342,7 @@ ResidualBlock* ProblemImpl::AddResidualBlock(
// Add dependencies on the residual to the parameter blocks.
if (options_.enable_fast_removal) {
- for (int i = 0; i < parameter_blocks.size(); ++i) {
+ for (int i = 0; i < num_parameter_blocks; ++i) {
parameter_block_ptrs[i]->AddResidualBlock(new_residual_block);
}
}
@@ -305,148 +353,19 @@ ResidualBlock* ProblemImpl::AddResidualBlock(
residual_block_set_.insert(new_residual_block);
}
- return new_residual_block;
-}
-
-// Unfortunately, macros don't help much to reduce this code, and var args don't
-// work because of the ambiguous case that there is no loss function.
-ResidualBlock* ProblemImpl::AddResidualBlock(
- CostFunction* cost_function,
- LossFunction* loss_function,
- double* x0) {
- vector<double*> residual_parameters;
- residual_parameters.push_back(x0);
- return AddResidualBlock(cost_function, loss_function, residual_parameters);
-}
-
-ResidualBlock* ProblemImpl::AddResidualBlock(
- CostFunction* cost_function,
- LossFunction* loss_function,
- double* x0, double* x1) {
- vector<double*> residual_parameters;
- residual_parameters.push_back(x0);
- residual_parameters.push_back(x1);
- return AddResidualBlock(cost_function, loss_function, residual_parameters);
-}
-
-ResidualBlock* ProblemImpl::AddResidualBlock(
- CostFunction* cost_function,
- LossFunction* loss_function,
- double* x0, double* x1, double* x2) {
- vector<double*> residual_parameters;
- residual_parameters.push_back(x0);
- residual_parameters.push_back(x1);
- residual_parameters.push_back(x2);
- return AddResidualBlock(cost_function, loss_function, residual_parameters);
-}
-
-ResidualBlock* ProblemImpl::AddResidualBlock(
- CostFunction* cost_function,
- LossFunction* loss_function,
- double* x0, double* x1, double* x2, double* x3) {
- vector<double*> residual_parameters;
- residual_parameters.push_back(x0);
- residual_parameters.push_back(x1);
- residual_parameters.push_back(x2);
- residual_parameters.push_back(x3);
- return AddResidualBlock(cost_function, loss_function, residual_parameters);
-}
+ if (options_.cost_function_ownership == TAKE_OWNERSHIP) {
+ // Increment the reference count, creating an entry in the table if
+ // needed. Note: C++ maps guarantee that new entries have default
+ // constructed values; this implies integers are zero initialized.
+ ++cost_function_ref_count_[cost_function];
+ }
-ResidualBlock* ProblemImpl::AddResidualBlock(
- CostFunction* cost_function,
- LossFunction* loss_function,
- double* x0, double* x1, double* x2, double* x3, double* x4) {
- vector<double*> residual_parameters;
- residual_parameters.push_back(x0);
- residual_parameters.push_back(x1);
- residual_parameters.push_back(x2);
- residual_parameters.push_back(x3);
- residual_parameters.push_back(x4);
- return AddResidualBlock(cost_function, loss_function, residual_parameters);
-}
+ if (options_.loss_function_ownership == TAKE_OWNERSHIP &&
+ loss_function != nullptr) {
+ ++loss_function_ref_count_[loss_function];
+ }
-ResidualBlock* ProblemImpl::AddResidualBlock(
- CostFunction* cost_function,
- LossFunction* loss_function,
- double* x0, double* x1, double* x2, double* x3, double* x4, double* x5) {
- vector<double*> residual_parameters;
- residual_parameters.push_back(x0);
- residual_parameters.push_back(x1);
- residual_parameters.push_back(x2);
- residual_parameters.push_back(x3);
- residual_parameters.push_back(x4);
- residual_parameters.push_back(x5);
- return AddResidualBlock(cost_function, loss_function, residual_parameters);
-}
-
-ResidualBlock* ProblemImpl::AddResidualBlock(
- CostFunction* cost_function,
- LossFunction* loss_function,
- double* x0, double* x1, double* x2, double* x3, double* x4, double* x5,
- double* x6) {
- vector<double*> residual_parameters;
- residual_parameters.push_back(x0);
- residual_parameters.push_back(x1);
- residual_parameters.push_back(x2);
- residual_parameters.push_back(x3);
- residual_parameters.push_back(x4);
- residual_parameters.push_back(x5);
- residual_parameters.push_back(x6);
- return AddResidualBlock(cost_function, loss_function, residual_parameters);
-}
-
-ResidualBlock* ProblemImpl::AddResidualBlock(
- CostFunction* cost_function,
- LossFunction* loss_function,
- double* x0, double* x1, double* x2, double* x3, double* x4, double* x5,
- double* x6, double* x7) {
- vector<double*> residual_parameters;
- residual_parameters.push_back(x0);
- residual_parameters.push_back(x1);
- residual_parameters.push_back(x2);
- residual_parameters.push_back(x3);
- residual_parameters.push_back(x4);
- residual_parameters.push_back(x5);
- residual_parameters.push_back(x6);
- residual_parameters.push_back(x7);
- return AddResidualBlock(cost_function, loss_function, residual_parameters);
-}
-
-ResidualBlock* ProblemImpl::AddResidualBlock(
- CostFunction* cost_function,
- LossFunction* loss_function,
- double* x0, double* x1, double* x2, double* x3, double* x4, double* x5,
- double* x6, double* x7, double* x8) {
- vector<double*> residual_parameters;
- residual_parameters.push_back(x0);
- residual_parameters.push_back(x1);
- residual_parameters.push_back(x2);
- residual_parameters.push_back(x3);
- residual_parameters.push_back(x4);
- residual_parameters.push_back(x5);
- residual_parameters.push_back(x6);
- residual_parameters.push_back(x7);
- residual_parameters.push_back(x8);
- return AddResidualBlock(cost_function, loss_function, residual_parameters);
-}
-
-ResidualBlock* ProblemImpl::AddResidualBlock(
- CostFunction* cost_function,
- LossFunction* loss_function,
- double* x0, double* x1, double* x2, double* x3, double* x4, double* x5,
- double* x6, double* x7, double* x8, double* x9) {
- vector<double*> residual_parameters;
- residual_parameters.push_back(x0);
- residual_parameters.push_back(x1);
- residual_parameters.push_back(x2);
- residual_parameters.push_back(x3);
- residual_parameters.push_back(x4);
- residual_parameters.push_back(x5);
- residual_parameters.push_back(x6);
- residual_parameters.push_back(x7);
- residual_parameters.push_back(x8);
- residual_parameters.push_back(x9);
- return AddResidualBlock(cost_function, loss_function, residual_parameters);
+ return new_residual_block;
}
void ProblemImpl::AddParameterBlock(double* values, int size) {
@@ -454,12 +373,9 @@ void ProblemImpl::AddParameterBlock(double* values, int size) {
}
void ProblemImpl::AddParameterBlock(
- double* values,
- int size,
- LocalParameterization* local_parameterization) {
- ParameterBlock* parameter_block =
- InternalAddParameterBlock(values, size);
- if (local_parameterization != NULL) {
+ double* values, int size, LocalParameterization* local_parameterization) {
+ ParameterBlock* parameter_block = InternalAddParameterBlock(values, size);
+ if (local_parameterization != nullptr) {
parameter_block->SetParameterization(local_parameterization);
}
}
@@ -468,13 +384,12 @@ void ProblemImpl::AddParameterBlock(
// This is done in constant time by moving an element from the end of the
// vector over the element to remove, then popping the last element. It
// destroys the ordering in the interest of speed.
-template<typename Block>
+template <typename Block>
void ProblemImpl::DeleteBlockInVector(vector<Block*>* mutable_blocks,
Block* block_to_remove) {
CHECK_EQ((*mutable_blocks)[block_to_remove->index()], block_to_remove)
<< "You found a Ceres bug! \n"
- << "Block requested: "
- << block_to_remove->ToString() << "\n"
+ << "Block requested: " << block_to_remove->ToString() << "\n"
<< "Block present: "
<< (*mutable_blocks)[block_to_remove->index()]->ToString();
@@ -493,24 +408,23 @@ void ProblemImpl::DeleteBlockInVector(vector<Block*>* mutable_blocks,
}
void ProblemImpl::RemoveResidualBlock(ResidualBlock* residual_block) {
- CHECK_NOTNULL(residual_block);
+ CHECK(residual_block != nullptr);
// Verify that residual_block identifies a residual in the current problem.
- const string residual_not_found_message =
- StringPrintf("Residual block to remove: %p not found. This usually means "
- "one of three things have happened:\n"
- " 1) residual_block is uninitialised and points to a random "
- "area in memory.\n"
- " 2) residual_block represented a residual that was added to"
- " the problem, but referred to a parameter block which has "
- "since been removed, which removes all residuals which "
- "depend on that parameter block, and was thus removed.\n"
- " 3) residual_block referred to a residual that has already "
- "been removed from the problem (by the user).",
- residual_block);
+ const string residual_not_found_message = StringPrintf(
+ "Residual block to remove: %p not found. This usually means "
+ "one of three things have happened:\n"
+ " 1) residual_block is uninitialised and points to a random "
+ "area in memory.\n"
+ " 2) residual_block represented a residual that was added to"
+ " the problem, but referred to a parameter block which has "
+ "since been removed, which removes all residuals which "
+ "depend on that parameter block, and was thus removed.\n"
+ " 3) residual_block referred to a residual that has already "
+ "been removed from the problem (by the user).",
+ residual_block);
if (options_.enable_fast_removal) {
- CHECK(residual_block_set_.find(residual_block) !=
- residual_block_set_.end())
+ CHECK(residual_block_set_.find(residual_block) != residual_block_set_.end())
<< residual_not_found_message;
} else {
// Perform a full search over all current residuals.
@@ -523,10 +437,10 @@ void ProblemImpl::RemoveResidualBlock(ResidualBlock* residual_block) {
InternalRemoveResidualBlock(residual_block);
}
-void ProblemImpl::RemoveParameterBlock(double* values) {
- ParameterBlock* parameter_block =
- FindWithDefault(parameter_block_map_, values, NULL);
- if (parameter_block == NULL) {
+void ProblemImpl::RemoveParameterBlock(const double* values) {
+ ParameterBlock* parameter_block = FindWithDefault(
+ parameter_block_map_, const_cast<double*>(values), nullptr);
+ if (parameter_block == nullptr) {
LOG(FATAL) << "Parameter block not found: " << values
<< ". You must add the parameter block to the problem before "
<< "it can be removed.";
@@ -561,10 +475,10 @@ void ProblemImpl::RemoveParameterBlock(double* values) {
DeleteBlockInVector(program_->mutable_parameter_blocks(), parameter_block);
}
-void ProblemImpl::SetParameterBlockConstant(double* values) {
- ParameterBlock* parameter_block =
- FindWithDefault(parameter_block_map_, values, NULL);
- if (parameter_block == NULL) {
+void ProblemImpl::SetParameterBlockConstant(const double* values) {
+ ParameterBlock* parameter_block = FindWithDefault(
+ parameter_block_map_, const_cast<double*>(values), nullptr);
+ if (parameter_block == nullptr) {
LOG(FATAL) << "Parameter block not found: " << values
<< ". You must add the parameter block to the problem before "
<< "it can be set constant.";
@@ -573,20 +487,19 @@ void ProblemImpl::SetParameterBlockConstant(double* values) {
parameter_block->SetConstant();
}
-bool ProblemImpl::IsParameterBlockConstant(double* values) const {
- const ParameterBlock* parameter_block =
- FindWithDefault(parameter_block_map_, values, NULL);
- CHECK(parameter_block != NULL)
- << "Parameter block not found: " << values << ". You must add the "
- << "parameter block to the problem before it can be queried.";
-
+bool ProblemImpl::IsParameterBlockConstant(const double* values) const {
+ const ParameterBlock* parameter_block = FindWithDefault(
+ parameter_block_map_, const_cast<double*>(values), nullptr);
+ CHECK(parameter_block != nullptr)
+ << "Parameter block not found: " << values << ". You must add the "
+ << "parameter block to the problem before it can be queried.";
return parameter_block->IsConstant();
}
void ProblemImpl::SetParameterBlockVariable(double* values) {
ParameterBlock* parameter_block =
- FindWithDefault(parameter_block_map_, values, NULL);
- if (parameter_block == NULL) {
+ FindWithDefault(parameter_block_map_, values, nullptr);
+ if (parameter_block == nullptr) {
LOG(FATAL) << "Parameter block not found: " << values
<< ". You must add the parameter block to the problem before "
<< "it can be set varying.";
@@ -596,24 +509,32 @@ void ProblemImpl::SetParameterBlockVariable(double* values) {
}
void ProblemImpl::SetParameterization(
- double* values,
- LocalParameterization* local_parameterization) {
+ double* values, LocalParameterization* local_parameterization) {
ParameterBlock* parameter_block =
- FindWithDefault(parameter_block_map_, values, NULL);
- if (parameter_block == NULL) {
+ FindWithDefault(parameter_block_map_, values, nullptr);
+ if (parameter_block == nullptr) {
LOG(FATAL) << "Parameter block not found: " << values
<< ". You must add the parameter block to the problem before "
<< "you can set its local parameterization.";
}
+ // If the parameter block already has a local parameterization and
+ // we are to take ownership of local parameterizations, then add it
+ // to local_parameterizations_to_delete_ for eventual deletion.
+ if (parameter_block->local_parameterization_ &&
+ options_.local_parameterization_ownership == TAKE_OWNERSHIP) {
+ local_parameterizations_to_delete_.push_back(
+ parameter_block->local_parameterization_);
+ }
+
parameter_block->SetParameterization(local_parameterization);
}
const LocalParameterization* ProblemImpl::GetParameterization(
- double* values) const {
- ParameterBlock* parameter_block =
- FindWithDefault(parameter_block_map_, values, NULL);
- if (parameter_block == NULL) {
+ const double* values) const {
+ ParameterBlock* parameter_block = FindWithDefault(
+ parameter_block_map_, const_cast<double*>(values), nullptr);
+ if (parameter_block == nullptr) {
LOG(FATAL) << "Parameter block not found: " << values
<< ". You must add the parameter block to the problem before "
<< "you can get its local parameterization.";
@@ -626,8 +547,8 @@ void ProblemImpl::SetParameterLowerBound(double* values,
int index,
double lower_bound) {
ParameterBlock* parameter_block =
- FindWithDefault(parameter_block_map_, values, NULL);
- if (parameter_block == NULL) {
+ FindWithDefault(parameter_block_map_, values, nullptr);
+ if (parameter_block == nullptr) {
LOG(FATAL) << "Parameter block not found: " << values
<< ". You must add the parameter block to the problem before "
<< "you can set a lower bound on one of its components.";
@@ -640,8 +561,8 @@ void ProblemImpl::SetParameterUpperBound(double* values,
int index,
double upper_bound) {
ParameterBlock* parameter_block =
- FindWithDefault(parameter_block_map_, values, NULL);
- if (parameter_block == NULL) {
+ FindWithDefault(parameter_block_map_, values, nullptr);
+ if (parameter_block == nullptr) {
LOG(FATAL) << "Parameter block not found: " << values
<< ". You must add the parameter block to the problem before "
<< "you can set an upper bound on one of its components.";
@@ -649,15 +570,37 @@ void ProblemImpl::SetParameterUpperBound(double* values,
parameter_block->SetUpperBound(index, upper_bound);
}
+double ProblemImpl::GetParameterLowerBound(const double* values,
+ int index) const {
+ ParameterBlock* parameter_block = FindWithDefault(
+ parameter_block_map_, const_cast<double*>(values), nullptr);
+ if (parameter_block == nullptr) {
+ LOG(FATAL) << "Parameter block not found: " << values
+ << ". You must add the parameter block to the problem before "
+ << "you can get the lower bound on one of its components.";
+ }
+ return parameter_block->LowerBound(index);
+}
+
+double ProblemImpl::GetParameterUpperBound(const double* values,
+ int index) const {
+ ParameterBlock* parameter_block = FindWithDefault(
+ parameter_block_map_, const_cast<double*>(values), nullptr);
+ if (parameter_block == nullptr) {
+ LOG(FATAL) << "Parameter block not found: " << values
+ << ". You must add the parameter block to the problem before "
+ << "you can set an upper bound on one of its components.";
+ }
+ return parameter_block->UpperBound(index);
+}
+
bool ProblemImpl::Evaluate(const Problem::EvaluateOptions& evaluate_options,
double* cost,
vector<double>* residuals,
vector<double>* gradient,
CRSMatrix* jacobian) {
- if (cost == NULL &&
- residuals == NULL &&
- gradient == NULL &&
- jacobian == NULL) {
+ if (cost == nullptr && residuals == nullptr && gradient == nullptr &&
+ jacobian == nullptr) {
LOG(INFO) << "Nothing to do.";
return true;
}
@@ -667,7 +610,8 @@ bool ProblemImpl::Evaluate(const Problem::EvaluateOptions& evaluate_options,
Program program;
*program.mutable_residual_blocks() =
((evaluate_options.residual_blocks.size() > 0)
- ? evaluate_options.residual_blocks : program_->residual_blocks());
+ ? evaluate_options.residual_blocks
+ : program_->residual_blocks());
const vector<double*>& parameter_block_ptrs =
evaluate_options.parameter_blocks;
@@ -688,10 +632,9 @@ bool ProblemImpl::Evaluate(const Problem::EvaluateOptions& evaluate_options,
// 1. Convert double* into ParameterBlock*
parameter_blocks.resize(parameter_block_ptrs.size());
for (int i = 0; i < parameter_block_ptrs.size(); ++i) {
- parameter_blocks[i] = FindWithDefault(parameter_block_map_,
- parameter_block_ptrs[i],
- NULL);
- if (parameter_blocks[i] == NULL) {
+ parameter_blocks[i] = FindWithDefault(
+ parameter_block_map_, parameter_block_ptrs[i], nullptr);
+ if (parameter_blocks[i] == nullptr) {
LOG(FATAL) << "No known parameter block for "
<< "Problem::Evaluate::Options.parameter_blocks[" << i << "]"
<< " = " << parameter_block_ptrs[i];
@@ -742,45 +685,36 @@ bool ProblemImpl::Evaluate(const Problem::EvaluateOptions& evaluate_options,
// the Evaluator decides the storage for the Jacobian based on the
// type of linear solver being used.
evaluator_options.linear_solver_type = SPARSE_NORMAL_CHOLESKY;
-#ifndef CERES_USE_OPENMP
+#ifdef CERES_NO_THREADS
LOG_IF(WARNING, evaluate_options.num_threads > 1)
- << "OpenMP support is not compiled into this binary; "
+ << "No threading support is compiled into this binary; "
<< "only evaluate_options.num_threads = 1 is supported. Switching "
<< "to single threaded mode.";
evaluator_options.num_threads = 1;
#else
evaluator_options.num_threads = evaluate_options.num_threads;
-#endif // CERES_USE_OPENMP
-
- string error;
- scoped_ptr<Evaluator> evaluator(
- Evaluator::Create(evaluator_options, &program, &error));
- if (evaluator.get() == NULL) {
- LOG(ERROR) << "Unable to create an Evaluator object. "
- << "Error: " << error
- << "This is a Ceres bug; please contact the developers!";
-
- // Make the parameter blocks that were temporarily marked
- // constant, variable again.
- for (int i = 0; i < variable_parameter_blocks.size(); ++i) {
- variable_parameter_blocks[i]->SetVarying();
- }
-
- program_->SetParameterBlockStatePtrsToUserStatePtrs();
- program_->SetParameterOffsetsAndIndex();
- return false;
- }
-
- if (residuals !=NULL) {
+#endif // CERES_NO_THREADS
+
+ // The main thread also does work so we only need to launch num_threads - 1.
+ context_impl_->EnsureMinimumThreads(evaluator_options.num_threads - 1);
+ evaluator_options.context = context_impl_;
+ evaluator_options.evaluation_callback =
+ program_->mutable_evaluation_callback();
+ std::unique_ptr<Evaluator> evaluator(
+ new ProgramEvaluator<ScratchEvaluatePreparer,
+ CompressedRowJacobianWriter>(evaluator_options,
+ &program));
+
+ if (residuals != nullptr) {
residuals->resize(evaluator->NumResiduals());
}
- if (gradient != NULL) {
+ if (gradient != nullptr) {
gradient->resize(evaluator->NumEffectiveParameters());
}
- scoped_ptr<CompressedRowSparseMatrix> tmp_jacobian;
- if (jacobian != NULL) {
+ std::unique_ptr<CompressedRowSparseMatrix> tmp_jacobian;
+ if (jacobian != nullptr) {
tmp_jacobian.reset(
down_cast<CompressedRowSparseMatrix*>(evaluator->CreateJacobian()));
}
@@ -804,12 +738,13 @@ bool ProblemImpl::Evaluate(const Problem::EvaluateOptions& evaluate_options,
Evaluator::EvaluateOptions evaluator_evaluate_options;
evaluator_evaluate_options.apply_loss_function =
evaluate_options.apply_loss_function;
- bool status = evaluator->Evaluate(evaluator_evaluate_options,
- parameters.data(),
- &tmp_cost,
- residuals != NULL ? &(*residuals)[0] : NULL,
- gradient != NULL ? &(*gradient)[0] : NULL,
- tmp_jacobian.get());
+ bool status =
+ evaluator->Evaluate(evaluator_evaluate_options,
+ parameters.data(),
+ &tmp_cost,
+ residuals != nullptr ? &(*residuals)[0] : nullptr,
+ gradient != nullptr ? &(*gradient)[0] : nullptr,
+ tmp_jacobian.get());
// Make the parameter blocks that were temporarily marked constant,
// variable again.
@@ -818,10 +753,10 @@ bool ProblemImpl::Evaluate(const Problem::EvaluateOptions& evaluate_options,
}
if (status) {
- if (cost != NULL) {
+ if (cost != nullptr) {
*cost = tmp_cost;
}
- if (jacobian != NULL) {
+ if (jacobian != nullptr) {
tmp_jacobian->ToCRSMatrix(jacobian);
}
}
@@ -831,26 +766,53 @@ bool ProblemImpl::Evaluate(const Problem::EvaluateOptions& evaluate_options,
return status;
}
+bool ProblemImpl::EvaluateResidualBlock(ResidualBlock* residual_block,
+ bool apply_loss_function,
+ double* cost,
+ double* residuals,
+ double** jacobians) const {
+ ParameterBlock* const* parameter_blocks = residual_block->parameter_blocks();
+ const int num_parameter_blocks = residual_block->NumParameterBlocks();
+ for (int i = 0; i < num_parameter_blocks; ++i) {
+ ParameterBlock* parameter_block = parameter_blocks[i];
+ if (parameter_block->IsConstant()) {
+ if (jacobians != nullptr && jacobians[i] != nullptr) {
+ LOG(ERROR) << "Jacobian requested for parameter block : " << i
+ << ". But the parameter block is marked constant.";
+ return false;
+ }
+ } else {
+ CHECK(parameter_block->SetState(parameter_block->user_state()))
+ << "Congratulations, you found a Ceres bug! Please report this error "
+ << "to the developers.";
+ }
+ }
+
+ double dummy_cost = 0.0;
+ FixedArray<double> scratch(residual_block->NumScratchDoublesForEvaluate());
+ return residual_block->Evaluate(apply_loss_function,
+ cost ? cost : &dummy_cost,
+ residuals,
+ jacobians,
+ scratch.data());
+}
+
int ProblemImpl::NumParameterBlocks() const {
return program_->NumParameterBlocks();
}
-int ProblemImpl::NumParameters() const {
- return program_->NumParameters();
-}
+int ProblemImpl::NumParameters() const { return program_->NumParameters(); }
int ProblemImpl::NumResidualBlocks() const {
return program_->NumResidualBlocks();
}
-int ProblemImpl::NumResiduals() const {
- return program_->NumResiduals();
-}
+int ProblemImpl::NumResiduals() const { return program_->NumResiduals(); }
int ProblemImpl::ParameterBlockSize(const double* values) const {
- ParameterBlock* parameter_block =
- FindWithDefault(parameter_block_map_, const_cast<double*>(values), NULL);
- if (parameter_block == NULL) {
+ ParameterBlock* parameter_block = FindWithDefault(
+ parameter_block_map_, const_cast<double*>(values), nullptr);
+ if (parameter_block == nullptr) {
LOG(FATAL) << "Parameter block not found: " << values
<< ". You must add the parameter block to the problem before "
<< "you can get its size.";
@@ -860,9 +822,9 @@ int ProblemImpl::ParameterBlockSize(const double* values) const {
}
int ProblemImpl::ParameterBlockLocalSize(const double* values) const {
- ParameterBlock* parameter_block =
- FindWithDefault(parameter_block_map_, const_cast<double*>(values), NULL);
- if (parameter_block == NULL) {
+ ParameterBlock* parameter_block = FindWithDefault(
+ parameter_block_map_, const_cast<double*>(values), nullptr);
+ if (parameter_block == nullptr) {
LOG(FATAL) << "Parameter block not found: " << values
<< ". You must add the parameter block to the problem before "
<< "you can get its local size.";
@@ -877,18 +839,17 @@ bool ProblemImpl::HasParameterBlock(const double* parameter_block) const {
}
void ProblemImpl::GetParameterBlocks(vector<double*>* parameter_blocks) const {
- CHECK_NOTNULL(parameter_blocks);
+ CHECK(parameter_blocks != nullptr);
parameter_blocks->resize(0);
- for (ParameterMap::const_iterator it = parameter_block_map_.begin();
- it != parameter_block_map_.end();
- ++it) {
- parameter_blocks->push_back(it->first);
+ parameter_blocks->reserve(parameter_block_map_.size());
+ for (const auto& entry : parameter_block_map_) {
+ parameter_blocks->push_back(entry.first);
}
}
void ProblemImpl::GetResidualBlocks(
vector<ResidualBlockId>* residual_blocks) const {
- CHECK_NOTNULL(residual_blocks);
+ CHECK(residual_blocks != nullptr);
*residual_blocks = program().residual_blocks();
}
@@ -896,7 +857,8 @@ void ProblemImpl::GetParameterBlocksForResidualBlock(
const ResidualBlockId residual_block,
vector<double*>* parameter_blocks) const {
int num_parameter_blocks = residual_block->NumParameterBlocks();
- CHECK_NOTNULL(parameter_blocks)->resize(num_parameter_blocks);
+ CHECK(parameter_blocks != nullptr);
+ parameter_blocks->resize(num_parameter_blocks);
for (int i = 0; i < num_parameter_blocks; ++i) {
(*parameter_blocks)[i] =
residual_block->parameter_blocks()[i]->mutable_user_state();
@@ -914,11 +876,10 @@ const LossFunction* ProblemImpl::GetLossFunctionForResidualBlock(
}
void ProblemImpl::GetResidualBlocksForParameterBlock(
- const double* values,
- vector<ResidualBlockId>* residual_blocks) const {
- ParameterBlock* parameter_block =
- FindWithDefault(parameter_block_map_, const_cast<double*>(values), NULL);
- if (parameter_block == NULL) {
+ const double* values, vector<ResidualBlockId>* residual_blocks) const {
+ ParameterBlock* parameter_block = FindWithDefault(
+ parameter_block_map_, const_cast<double*>(values), nullptr);
+ if (parameter_block == nullptr) {
LOG(FATAL) << "Parameter block not found: " << values
<< ". You must add the parameter block to the problem before "
<< "you can get the residual blocks that depend on it.";
@@ -927,8 +888,8 @@ void ProblemImpl::GetResidualBlocksForParameterBlock(
if (options_.enable_fast_removal) {
// In this case the residual blocks that depend on the parameter block are
// stored in the parameter block already, so just copy them out.
- CHECK_NOTNULL(residual_blocks)->resize(
- parameter_block->mutable_residual_blocks()->size());
+ CHECK(residual_blocks != nullptr);
+ residual_blocks->resize(parameter_block->mutable_residual_blocks()->size());
std::copy(parameter_block->mutable_residual_blocks()->begin(),
parameter_block->mutable_residual_blocks()->end(),
residual_blocks->begin());
@@ -936,11 +897,11 @@ void ProblemImpl::GetResidualBlocksForParameterBlock(
}
// Find residual blocks that depend on the parameter block.
- CHECK_NOTNULL(residual_blocks)->clear();
+ CHECK(residual_blocks != nullptr);
+ residual_blocks->clear();
const int num_residual_blocks = NumResidualBlocks();
for (int i = 0; i < num_residual_blocks; ++i) {
- ResidualBlock* residual_block =
- (*(program_->mutable_residual_blocks()))[i];
+ ResidualBlock* residual_block = (*(program_->mutable_residual_blocks()))[i];
const int num_parameter_blocks = residual_block->NumParameterBlocks();
for (int j = 0; j < num_parameter_blocks; ++j) {
if (residual_block->parameter_blocks()[j] == parameter_block) {
diff --git a/extern/ceres/internal/ceres/problem_impl.h b/extern/ceres/internal/ceres/problem_impl.h
index a4689c362f6..8bbe7238d27 100644
--- a/extern/ceres/internal/ceres/problem_impl.h
+++ b/extern/ceres/internal/ceres/problem_impl.h
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2019 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -39,19 +39,21 @@
#ifndef CERES_PUBLIC_PROBLEM_IMPL_H_
#define CERES_PUBLIC_PROBLEM_IMPL_H_
+#include <array>
#include <map>
+#include <memory>
+#include <unordered_set>
#include <vector>
-#include "ceres/internal/macros.h"
+#include "ceres/context_impl.h"
#include "ceres/internal/port.h"
-#include "ceres/internal/scoped_ptr.h"
-#include "ceres/collections_port.h"
#include "ceres/problem.h"
#include "ceres/types.h"
namespace ceres {
class CostFunction;
+class EvaluationCallback;
class LossFunction;
class LocalParameterization;
struct CRSMatrix;
@@ -64,78 +66,55 @@ class ResidualBlock;
class ProblemImpl {
public:
typedef std::map<double*, ParameterBlock*> ParameterMap;
- typedef HashSet<ResidualBlock*> ResidualBlockSet;
+ typedef std::unordered_set<ResidualBlock*> ResidualBlockSet;
+ typedef std::map<CostFunction*, int> CostFunctionRefCount;
+ typedef std::map<LossFunction*, int> LossFunctionRefCount;
ProblemImpl();
explicit ProblemImpl(const Problem::Options& options);
+ ProblemImpl(const ProblemImpl&) = delete;
+ void operator=(const ProblemImpl&) = delete;
~ProblemImpl();
// See the public problem.h file for description of these methods.
- ResidualBlockId AddResidualBlock(
- CostFunction* cost_function,
- LossFunction* loss_function,
- const std::vector<double*>& parameter_blocks);
ResidualBlockId AddResidualBlock(CostFunction* cost_function,
LossFunction* loss_function,
- double* x0);
- ResidualBlockId AddResidualBlock(CostFunction* cost_function,
- LossFunction* loss_function,
- double* x0, double* x1);
- ResidualBlockId AddResidualBlock(CostFunction* cost_function,
- LossFunction* loss_function,
- double* x0, double* x1, double* x2);
- ResidualBlockId AddResidualBlock(CostFunction* cost_function,
- LossFunction* loss_function,
- double* x0, double* x1, double* x2,
- double* x3);
- ResidualBlockId AddResidualBlock(CostFunction* cost_function,
- LossFunction* loss_function,
- double* x0, double* x1, double* x2,
- double* x3, double* x4);
- ResidualBlockId AddResidualBlock(CostFunction* cost_function,
- LossFunction* loss_function,
- double* x0, double* x1, double* x2,
- double* x3, double* x4, double* x5);
- ResidualBlockId AddResidualBlock(CostFunction* cost_function,
- LossFunction* loss_function,
- double* x0, double* x1, double* x2,
- double* x3, double* x4, double* x5,
- double* x6);
- ResidualBlockId AddResidualBlock(CostFunction* cost_function,
- LossFunction* loss_function,
- double* x0, double* x1, double* x2,
- double* x3, double* x4, double* x5,
- double* x6, double* x7);
- ResidualBlockId AddResidualBlock(CostFunction* cost_function,
- LossFunction* loss_function,
- double* x0, double* x1, double* x2,
- double* x3, double* x4, double* x5,
- double* x6, double* x7, double* x8);
+ double* const* const parameter_blocks,
+ int num_parameter_blocks);
+
+ template <typename... Ts>
ResidualBlockId AddResidualBlock(CostFunction* cost_function,
LossFunction* loss_function,
- double* x0, double* x1, double* x2,
- double* x3, double* x4, double* x5,
- double* x6, double* x7, double* x8,
- double* x9);
+ double* x0,
+ Ts*... xs) {
+ const std::array<double*, sizeof...(Ts) + 1> parameter_blocks{{x0, xs...}};
+ return AddResidualBlock(cost_function,
+ loss_function,
+ parameter_blocks.data(),
+ static_cast<int>(parameter_blocks.size()));
+ }
+
void AddParameterBlock(double* values, int size);
void AddParameterBlock(double* values,
int size,
LocalParameterization* local_parameterization);
void RemoveResidualBlock(ResidualBlock* residual_block);
- void RemoveParameterBlock(double* values);
+ void RemoveParameterBlock(const double* values);
- void SetParameterBlockConstant(double* values);
+ void SetParameterBlockConstant(const double* values);
void SetParameterBlockVariable(double* values);
- bool IsParameterBlockConstant(double* values) const;
+ bool IsParameterBlockConstant(const double* values) const;
void SetParameterization(double* values,
LocalParameterization* local_parameterization);
- const LocalParameterization* GetParameterization(double* values) const;
+ const LocalParameterization* GetParameterization(const double* values) const;
void SetParameterLowerBound(double* values, int index, double lower_bound);
void SetParameterUpperBound(double* values, int index, double upper_bound);
+ double GetParameterLowerBound(const double* values, int index) const;
+ double GetParameterUpperBound(const double* values, int index) const;
bool Evaluate(const Problem::EvaluateOptions& options,
double* cost,
@@ -143,6 +122,12 @@ class ProblemImpl {
std::vector<double>* gradient,
CRSMatrix* jacobian);
+ bool EvaluateResidualBlock(ResidualBlock* residual_block,
+ bool apply_loss_function,
+ double* cost,
+ double* residuals,
+ double** jacobians) const;
+
int NumParameterBlocks() const;
int NumParameters() const;
int NumResidualBlocks() const;
@@ -179,20 +164,16 @@ class ProblemImpl {
return residual_block_set_;
}
+ ContextImpl* context() { return context_impl_; }
+
private:
ParameterBlock* InternalAddParameterBlock(double* values, int size);
void InternalRemoveResidualBlock(ResidualBlock* residual_block);
- bool InternalEvaluate(Program* program,
- double* cost,
- std::vector<double>* residuals,
- std::vector<double>* gradient,
- CRSMatrix* jacobian);
-
// Delete the arguments in question. These differ from the Remove* functions
// in that they do not clean up references to the block to delete; they
// merely delete them.
- template<typename Block>
+ template <typename Block>
void DeleteBlockInVector(std::vector<Block*>* mutable_blocks,
Block* block_to_remove);
void DeleteBlock(ResidualBlock* residual_block);
@@ -200,26 +181,32 @@ class ProblemImpl {
const Problem::Options options_;
+ bool context_impl_owned_;
+ ContextImpl* context_impl_;
+
// The mapping from user pointers to parameter blocks.
- std::map<double*, ParameterBlock*> parameter_block_map_;
+ ParameterMap parameter_block_map_;
// Iff enable_fast_removal is enabled, contains the current residual blocks.
ResidualBlockSet residual_block_set_;
// The actual parameter and residual blocks.
- internal::scoped_ptr<internal::Program> program_;
+ std::unique_ptr<internal::Program> program_;
- // When removing residual and parameter blocks, cost/loss functions and
- // parameterizations have ambiguous ownership. Instead of scanning the entire
- // problem to see if the cost/loss/parameterization is shared with other
- // residual or parameter blocks, buffer them until destruction.
+ // When removing parameter blocks, parameterizations have ambiguous
+ // ownership. Instead of scanning the entire problem to see if the
+ // parameterization is shared with other parameter blocks, buffer
+ // them until destruction.
//
// TODO(keir): See if it makes sense to use sets instead.
- std::vector<CostFunction*> cost_functions_to_delete_;
- std::vector<LossFunction*> loss_functions_to_delete_;
std::vector<LocalParameterization*> local_parameterizations_to_delete_;
- CERES_DISALLOW_COPY_AND_ASSIGN(ProblemImpl);
+ // For each cost function and loss function in the problem, a count
+ // of the number of residual blocks that refer to them. When the
+ // count goes to zero and the problem owns these objects, they are
+ // destroyed.
+ CostFunctionRefCount cost_function_ref_count_;
+ LossFunctionRefCount loss_function_ref_count_;
};
} // namespace internal
diff --git a/extern/ceres/internal/ceres/program.cc b/extern/ceres/internal/ceres/program.cc
index 8e97f072113..f1ded2e5d5a 100644
--- a/extern/ceres/internal/ceres/program.cc
+++ b/extern/ceres/internal/ceres/program.cc
@@ -30,8 +30,11 @@
#include "ceres/program.h"
+#include <algorithm>
#include <map>
+#include <memory>
#include <vector>
+
#include "ceres/array_utils.h"
#include "ceres/casts.h"
#include "ceres/compressed_row_sparse_matrix.h"
@@ -59,8 +62,8 @@ Program::Program() {}
Program::Program(const Program& program)
: parameter_blocks_(program.parameter_blocks_),
- residual_blocks_(program.residual_blocks_) {
-}
+ residual_blocks_(program.residual_blocks_),
+ evaluation_callback_(program.evaluation_callback_) {}
const vector<ParameterBlock*>& Program::parameter_blocks() const {
return parameter_blocks_;
@@ -78,7 +81,11 @@ vector<ResidualBlock*>* Program::mutable_residual_blocks() {
return &residual_blocks_;
}
-bool Program::StateVectorToParameterBlocks(const double *state) {
+EvaluationCallback* Program::mutable_evaluation_callback() {
+ return evaluation_callback_;
+}
+
+bool Program::StateVectorToParameterBlocks(const double* state) {
for (int i = 0; i < parameter_blocks_.size(); ++i) {
if (!parameter_blocks_[i]->IsConstant() &&
!parameter_blocks_[i]->SetState(state)) {
@@ -89,7 +96,7 @@ bool Program::StateVectorToParameterBlocks(const double *state) {
return true;
}
-void Program::ParameterBlocksToStateVector(double *state) const {
+void Program::ParameterBlocksToStateVector(double* state) const {
for (int i = 0; i < parameter_blocks_.size(); ++i) {
parameter_blocks_[i]->GetState(state);
state += parameter_blocks_[i]->Size();
@@ -178,7 +185,7 @@ bool Program::IsValid() const {
}
bool Program::ParameterBlocksAreFinite(string* message) const {
- CHECK_NOTNULL(message);
+ CHECK(message != nullptr);
for (int i = 0; i < parameter_blocks_.size(); ++i) {
const ParameterBlock* parameter_block = parameter_blocks_[i];
const double* array = parameter_block->user_state();
@@ -189,7 +196,9 @@ bool Program::ParameterBlocksAreFinite(string* message) const {
"ParameterBlock: %p with size %d has at least one invalid value.\n"
"First invalid value is at index: %d.\n"
"Parameter block values: ",
- array, size, invalid_index);
+ array,
+ size,
+ invalid_index);
AppendArrayToString(size, array, message);
return false;
}
@@ -217,7 +226,7 @@ bool Program::IsBoundsConstrained() const {
}
bool Program::IsFeasible(string* message) const {
- CHECK_NOTNULL(message);
+ CHECK(message != nullptr);
for (int i = 0; i < parameter_blocks_.size(); ++i) {
const ParameterBlock* parameter_block = parameter_blocks_[i];
const double* parameters = parameter_block->user_state();
@@ -236,7 +245,12 @@ bool Program::IsFeasible(string* message) const {
"\nFirst infeasible value is at index: %d."
"\nLower bound: %e, value: %e, upper bound: %e"
"\nParameter block values: ",
- parameters, size, j, lower_bound, parameters[j], upper_bound);
+ parameters,
+ size,
+ j,
+ lower_bound,
+ parameters[j],
+ upper_bound);
AppendArrayToString(size, parameters, message);
return false;
}
@@ -255,7 +269,11 @@ bool Program::IsFeasible(string* message) const {
"\nFirst infeasible bound is at index: %d."
"\nLower bound: %e, upper bound: %e"
"\nParameter block values: ",
- parameters, size, j, lower_bound, upper_bound);
+ parameters,
+ size,
+ j,
+ lower_bound,
+ upper_bound);
AppendArrayToString(size, parameters, message);
return false;
}
@@ -270,15 +288,14 @@ Program* Program::CreateReducedProgram(
vector<double*>* removed_parameter_blocks,
double* fixed_cost,
string* error) const {
- CHECK_NOTNULL(removed_parameter_blocks);
- CHECK_NOTNULL(fixed_cost);
- CHECK_NOTNULL(error);
-
- scoped_ptr<Program> reduced_program(new Program(*this));
- if (!reduced_program->RemoveFixedBlocks(removed_parameter_blocks,
- fixed_cost,
- error)) {
- return NULL;
+ CHECK(removed_parameter_blocks != nullptr);
+ CHECK(fixed_cost != nullptr);
+ CHECK(error != nullptr);
+
+ std::unique_ptr<Program> reduced_program(new Program(*this));
+ if (!reduced_program->RemoveFixedBlocks(
+ removed_parameter_blocks, fixed_cost, error)) {
+ return nullptr;
}
reduced_program->SetParameterOffsetsAndIndex();
@@ -288,15 +305,17 @@ Program* Program::CreateReducedProgram(
bool Program::RemoveFixedBlocks(vector<double*>* removed_parameter_blocks,
double* fixed_cost,
string* error) {
- CHECK_NOTNULL(removed_parameter_blocks);
- CHECK_NOTNULL(fixed_cost);
- CHECK_NOTNULL(error);
+ CHECK(removed_parameter_blocks != nullptr);
+ CHECK(fixed_cost != nullptr);
+ CHECK(error != nullptr);
- scoped_array<double> residual_block_evaluate_scratch;
+ std::unique_ptr<double[]> residual_block_evaluate_scratch;
residual_block_evaluate_scratch.reset(
new double[MaxScratchDoublesNeededForEvaluate()]);
*fixed_cost = 0.0;
+ bool need_to_call_prepare_for_evaluation = evaluation_callback_ != nullptr;
+
// Mark all the parameters as unused. Abuse the index member of the
// parameter blocks for the marking.
for (int i = 0; i < parameter_blocks_.size(); ++i) {
@@ -326,18 +345,45 @@ bool Program::RemoveFixedBlocks(vector<double*>* removed_parameter_blocks,
continue;
}
+ // This is an exceedingly rare case, where the user has residual
+ // blocks which are effectively constant but they are also
+ // performance sensitive enough to add an EvaluationCallback.
+ //
+ // In this case before we evaluate the cost of the constant
+ // residual blocks, we must call
+ // EvaluationCallback::PrepareForEvaluation(). Because this call
+ // can be costly, we only call this if we actually encounter a
+ // residual block with all constant parameter blocks.
+ //
+ // It is worth nothing that there is a minor inefficiency here,
+ // that the iteration 0 of TrustRegionMinimizer will also cause
+ // PrepareForEvaluation to be called on the same point, but with
+ // evaluate_jacobians = true. We could try and optimize this here,
+ // but given the rarity of this case, the additional complexity
+ // and long range dependency is not worth it.
+ if (need_to_call_prepare_for_evaluation) {
+ constexpr bool kNewPoint = true;
+ constexpr bool kDoNotEvaluateJacobians = false;
+ evaluation_callback_->PrepareForEvaluation(kDoNotEvaluateJacobians,
+ kNewPoint);
+ need_to_call_prepare_for_evaluation = false;
+ }
+
// The residual is constant and will be removed, so its cost is
// added to the variable fixed_cost.
double cost = 0.0;
if (!residual_block->Evaluate(true,
&cost,
- NULL,
- NULL,
+ nullptr,
+ nullptr,
residual_block_evaluate_scratch.get())) {
- *error = StringPrintf("Evaluation of the residual %d failed during "
- "removal of fixed residual blocks.", i);
+ *error = StringPrintf(
+ "Evaluation of the residual %d failed during "
+ "removal of fixed residual blocks.",
+ i);
return false;
}
+
*fixed_cost += cost;
}
residual_blocks_.resize(num_active_residual_blocks);
@@ -356,11 +402,9 @@ bool Program::RemoveFixedBlocks(vector<double*>* removed_parameter_blocks,
}
parameter_blocks_.resize(num_active_parameter_blocks);
- if (!(((NumResidualBlocks() == 0) &&
- (NumParameterBlocks() == 0)) ||
- ((NumResidualBlocks() != 0) &&
- (NumParameterBlocks() != 0)))) {
- *error = "Congratulations, you found a bug in Ceres. Please report it.";
+ if (!(((NumResidualBlocks() == 0) && (NumParameterBlocks() == 0)) ||
+ ((NumResidualBlocks() != 0) && (NumParameterBlocks() != 0)))) {
+ *error = "Congratulations, you found a bug in Ceres. Please report it.";
return false;
}
@@ -373,15 +417,13 @@ bool Program::IsParameterBlockSetIndependent(
// blocks in the same residual block are part of
// parameter_block_ptrs as that would violate the assumption that it
// is an independent set in the Hessian matrix.
- for (vector<ResidualBlock*>::const_iterator it = residual_blocks_.begin();
- it != residual_blocks_.end();
- ++it) {
- ParameterBlock* const* parameter_blocks = (*it)->parameter_blocks();
- const int num_parameter_blocks = (*it)->NumParameterBlocks();
+ for (const ResidualBlock* residual_block : residual_blocks_) {
+ ParameterBlock* const* parameter_blocks =
+ residual_block->parameter_blocks();
+ const int num_parameter_blocks = residual_block->NumParameterBlocks();
int count = 0;
for (int i = 0; i < num_parameter_blocks; ++i) {
- count += independent_set.count(
- parameter_blocks[i]->mutable_user_state());
+ count += independent_set.count(parameter_blocks[i]->mutable_user_state());
}
if (count > 1) {
return false;
@@ -390,18 +432,20 @@ bool Program::IsParameterBlockSetIndependent(
return true;
}
-TripletSparseMatrix* Program::CreateJacobianBlockSparsityTranspose() const {
+std::unique_ptr<TripletSparseMatrix>
+Program::CreateJacobianBlockSparsityTranspose(int start_residual_block) const {
// Matrix to store the block sparsity structure of the Jacobian.
- TripletSparseMatrix* tsm =
- new TripletSparseMatrix(NumParameterBlocks(),
- NumResidualBlocks(),
- 10 * NumResidualBlocks());
+ const int num_rows = NumParameterBlocks();
+ const int num_cols = NumResidualBlocks() - start_residual_block;
+
+ std::unique_ptr<TripletSparseMatrix> tsm(
+ new TripletSparseMatrix(num_rows, num_cols, 10 * num_cols));
int num_nonzeros = 0;
int* rows = tsm->mutable_rows();
int* cols = tsm->mutable_cols();
double* values = tsm->mutable_values();
- for (int c = 0; c < residual_blocks_.size(); ++c) {
+ for (int c = start_residual_block; c < residual_blocks_.size(); ++c) {
const ResidualBlock* residual_block = residual_blocks_[c];
const int num_parameter_blocks = residual_block->NumParameterBlocks();
ParameterBlock* const* parameter_blocks =
@@ -423,7 +467,7 @@ TripletSparseMatrix* Program::CreateJacobianBlockSparsityTranspose() const {
const int r = parameter_blocks[j]->index();
rows[num_nonzeros] = r;
- cols[num_nonzeros] = c;
+ cols[num_nonzeros] = c - start_residual_block;
values[num_nonzeros] = 1.0;
++num_nonzeros;
}
@@ -433,13 +477,9 @@ TripletSparseMatrix* Program::CreateJacobianBlockSparsityTranspose() const {
return tsm;
}
-int Program::NumResidualBlocks() const {
- return residual_blocks_.size();
-}
+int Program::NumResidualBlocks() const { return residual_blocks_.size(); }
-int Program::NumParameterBlocks() const {
- return parameter_blocks_.size();
-}
+int Program::NumParameterBlocks() const { return parameter_blocks_.size(); }
int Program::NumResiduals() const {
int num_residuals = 0;
@@ -465,6 +505,9 @@ int Program::NumEffectiveParameters() const {
return num_parameters;
}
+// TODO(sameeragarwal): The following methods should just be updated
+// incrementally and the values cached, rather than the linear
+// complexity we have right now on every call.
int Program::MaxScratchDoublesNeededForEvaluate() const {
// Compute the scratch space needed for evaluate.
int max_scratch_bytes_for_evaluate = 0;
@@ -494,8 +537,8 @@ int Program::MaxDerivativesPerResidualBlock() const {
int Program::MaxParametersPerResidualBlock() const {
int max_parameters = 0;
for (int i = 0; i < residual_blocks_.size(); ++i) {
- max_parameters = max(max_parameters,
- residual_blocks_[i]->NumParameterBlocks());
+ max_parameters =
+ max(max_parameters, residual_blocks_[i]->NumParameterBlocks());
}
return max_parameters;
}
@@ -514,8 +557,8 @@ string Program::ToString() const {
ret += StringPrintf("Number of parameters: %d\n", NumParameters());
ret += "Parameters:\n";
for (int i = 0; i < parameter_blocks_.size(); ++i) {
- ret += StringPrintf("%d: %s\n",
- i, parameter_blocks_[i]->ToString().c_str());
+ ret +=
+ StringPrintf("%d: %s\n", i, parameter_blocks_[i]->ToString().c_str());
}
return ret;
}
diff --git a/extern/ceres/internal/ceres/program.h b/extern/ceres/internal/ceres/program.h
index 38c958fe34a..797129980e3 100644
--- a/extern/ceres/internal/ceres/program.h
+++ b/extern/ceres/internal/ceres/program.h
@@ -31,10 +31,13 @@
#ifndef CERES_INTERNAL_PROGRAM_H_
#define CERES_INTERNAL_PROGRAM_H_
+#include <memory>
#include <set>
#include <string>
#include <vector>
+
#include "ceres/internal/port.h"
+#include "ceres/evaluation_callback.h"
namespace ceres {
namespace internal {
@@ -64,6 +67,7 @@ class Program {
const std::vector<ResidualBlock*>& residual_blocks() const;
std::vector<ParameterBlock*>* mutable_parameter_blocks();
std::vector<ResidualBlock*>* mutable_residual_blocks();
+ EvaluationCallback* mutable_evaluation_callback();
// Serialize to/from the program and update states.
//
@@ -71,8 +75,8 @@ class Program {
// computation of the Jacobian of its local parameterization. If
// this computation fails for some reason, then this method returns
// false and the state of the parameter blocks cannot be trusted.
- bool StateVectorToParameterBlocks(const double *state);
- void ParameterBlocksToStateVector(double *state) const;
+ bool StateVectorToParameterBlocks(const double* state);
+ void ParameterBlocksToStateVector(double* state) const;
// Copy internal state to the user's parameters.
void CopyParameterBlockStateToUserState();
@@ -127,8 +131,10 @@ class Program {
// structure corresponding to the block sparsity of the transpose of
// the Jacobian matrix.
//
- // Caller owns the result.
- TripletSparseMatrix* CreateJacobianBlockSparsityTranspose() const;
+ // start_residual_block which allows the user to ignore the first
+ // start_residual_block residuals.
+ std::unique_ptr<TripletSparseMatrix> CreateJacobianBlockSparsityTranspose(
+ int start_residual_block = 0) const;
// Create a copy of this program and removes constant parameter
// blocks and residual blocks with no varying parameter blocks while
@@ -182,6 +188,7 @@ class Program {
// The Program does not own the ParameterBlock or ResidualBlock objects.
std::vector<ParameterBlock*> parameter_blocks_;
std::vector<ResidualBlock*> residual_blocks_;
+ EvaluationCallback* evaluation_callback_ = nullptr;
friend class ProblemImpl;
};
diff --git a/extern/ceres/internal/ceres/program_evaluator.h b/extern/ceres/internal/ceres/program_evaluator.h
index 74a812adeef..97ee590fbab 100644
--- a/extern/ceres/internal/ceres/program_evaluator.h
+++ b/extern/ceres/internal/ceres/program_evaluator.h
@@ -43,7 +43,7 @@
// residual jacobians are written directly into their final position in the
// block sparse matrix by the user's CostFunction; there is no copying.
//
-// The evaluation is threaded with OpenMP.
+// The evaluation is threaded with OpenMP or C++ threads.
//
// The EvaluatePreparer and JacobianWriter interfaces are as follows:
//
@@ -82,16 +82,16 @@
// This include must come before any #ifndef check on Ceres compile options.
#include "ceres/internal/port.h"
-#ifdef CERES_USE_OPENMP
-#include <omp.h>
-#endif
-
+#include <atomic>
#include <map>
+#include <memory>
#include <string>
#include <vector>
+
+#include "ceres/evaluation_callback.h"
#include "ceres/execution_summary.h"
#include "ceres/internal/eigen.h"
-#include "ceres/internal/scoped_ptr.h"
+#include "ceres/parallel_for.h"
#include "ceres/parameter_block.h"
#include "ceres/program.h"
#include "ceres/residual_block.h"
@@ -104,34 +104,33 @@ struct NullJacobianFinalizer {
void operator()(SparseMatrix* jacobian, int num_parameters) {}
};
-template<typename EvaluatePreparer,
- typename JacobianWriter,
- typename JacobianFinalizer = NullJacobianFinalizer>
+template <typename EvaluatePreparer,
+ typename JacobianWriter,
+ typename JacobianFinalizer = NullJacobianFinalizer>
class ProgramEvaluator : public Evaluator {
public:
- ProgramEvaluator(const Evaluator::Options &options, Program* program)
+ ProgramEvaluator(const Evaluator::Options& options, Program* program)
: options_(options),
program_(program),
jacobian_writer_(options, program),
evaluate_preparers_(
jacobian_writer_.CreateEvaluatePreparers(options.num_threads)) {
-#ifndef CERES_USE_OPENMP
+#ifdef CERES_NO_THREADS
if (options_.num_threads > 1) {
- LOG(WARNING)
- << "OpenMP support is not compiled into this binary; "
- << "only options.num_threads = 1 is supported. Switching "
- << "to single threaded mode.";
+ LOG(WARNING) << "No threading support is compiled into this binary; "
+ << "only options.num_threads = 1 is supported. Switching "
+ << "to single threaded mode.";
options_.num_threads = 1;
}
-#endif
+#endif // CERES_NO_THREADS
BuildResidualLayout(*program, &residual_layout_);
- evaluate_scratch_.reset(CreateEvaluatorScratch(*program,
- options.num_threads));
+ evaluate_scratch_.reset(
+ CreateEvaluatorScratch(*program, options.num_threads));
}
// Implementation of Evaluator interface.
- SparseMatrix* CreateJacobian() const {
+ SparseMatrix* CreateJacobian() const final {
return jacobian_writer_.CreateJacobian();
}
@@ -140,133 +139,133 @@ class ProgramEvaluator : public Evaluator {
double* cost,
double* residuals,
double* gradient,
- SparseMatrix* jacobian) {
+ SparseMatrix* jacobian) final {
ScopedExecutionTimer total_timer("Evaluator::Total", &execution_summary_);
- ScopedExecutionTimer call_type_timer(gradient == NULL && jacobian == NULL
- ? "Evaluator::Residual"
- : "Evaluator::Jacobian",
- &execution_summary_);
+ ScopedExecutionTimer call_type_timer(
+ gradient == nullptr && jacobian == nullptr ? "Evaluator::Residual"
+ : "Evaluator::Jacobian",
+ &execution_summary_);
// The parameters are stateful, so set the state before evaluating.
if (!program_->StateVectorToParameterBlocks(state)) {
return false;
}
- if (residuals != NULL) {
+ // Notify the user about a new evaluation point if they are interested.
+ if (options_.evaluation_callback != nullptr) {
+ program_->CopyParameterBlockStateToUserState();
+ options_.evaluation_callback->PrepareForEvaluation(
+ /*jacobians=*/(gradient != nullptr || jacobian != nullptr),
+ evaluate_options.new_evaluation_point);
+ }
+
+ if (residuals != nullptr) {
VectorRef(residuals, program_->NumResiduals()).setZero();
}
- if (jacobian != NULL) {
+ if (jacobian != nullptr) {
jacobian->SetZero();
}
// Each thread gets it's own cost and evaluate scratch space.
for (int i = 0; i < options_.num_threads; ++i) {
evaluate_scratch_[i].cost = 0.0;
- if (gradient != NULL) {
+ if (gradient != nullptr) {
VectorRef(evaluate_scratch_[i].gradient.get(),
- program_->NumEffectiveParameters()).setZero();
+ program_->NumEffectiveParameters())
+ .setZero();
}
}
- // This bool is used to disable the loop if an error is encountered
- // without breaking out of it. The remaining loop iterations are still run,
- // but with an empty body, and so will finish quickly.
- bool abort = false;
- int num_residual_blocks = program_->NumResidualBlocks();
-#pragma omp parallel for num_threads(options_.num_threads)
- for (int i = 0; i < num_residual_blocks; ++i) {
-// Disable the loop instead of breaking, as required by OpenMP.
-#pragma omp flush(abort)
- if (abort) {
- continue;
- }
+ const int num_residual_blocks = program_->NumResidualBlocks();
+ // This bool is used to disable the loop if an error is encountered without
+ // breaking out of it. The remaining loop iterations are still run, but with
+ // an empty body, and so will finish quickly.
+ std::atomic_bool abort(false);
+ ParallelFor(
+ options_.context,
+ 0,
+ num_residual_blocks,
+ options_.num_threads,
+ [&](int thread_id, int i) {
+ if (abort) {
+ return;
+ }
-#ifdef CERES_USE_OPENMP
- int thread_id = omp_get_thread_num();
-#else
- int thread_id = 0;
-#endif
- EvaluatePreparer* preparer = &evaluate_preparers_[thread_id];
- EvaluateScratch* scratch = &evaluate_scratch_[thread_id];
-
- // Prepare block residuals if requested.
- const ResidualBlock* residual_block = program_->residual_blocks()[i];
- double* block_residuals = NULL;
- if (residuals != NULL) {
- block_residuals = residuals + residual_layout_[i];
- } else if (gradient != NULL) {
- block_residuals = scratch->residual_block_residuals.get();
- }
+ EvaluatePreparer* preparer = &evaluate_preparers_[thread_id];
+ EvaluateScratch* scratch = &evaluate_scratch_[thread_id];
- // Prepare block jacobians if requested.
- double** block_jacobians = NULL;
- if (jacobian != NULL || gradient != NULL) {
- preparer->Prepare(residual_block,
- i,
- jacobian,
- scratch->jacobian_block_ptrs.get());
- block_jacobians = scratch->jacobian_block_ptrs.get();
- }
+ // Prepare block residuals if requested.
+ const ResidualBlock* residual_block = program_->residual_blocks()[i];
+ double* block_residuals = nullptr;
+ if (residuals != nullptr) {
+ block_residuals = residuals + residual_layout_[i];
+ } else if (gradient != nullptr) {
+ block_residuals = scratch->residual_block_residuals.get();
+ }
- // Evaluate the cost, residuals, and jacobians.
- double block_cost;
- if (!residual_block->Evaluate(
- evaluate_options.apply_loss_function,
- &block_cost,
- block_residuals,
- block_jacobians,
- scratch->residual_block_evaluate_scratch.get())) {
- abort = true;
-// This ensures that the OpenMP threads have a consistent view of 'abort'. Do
-// the flush inside the failure case so that there is usually only one
-// synchronization point per loop iteration instead of two.
-#pragma omp flush(abort)
- continue;
- }
+ // Prepare block jacobians if requested.
+ double** block_jacobians = nullptr;
+ if (jacobian != nullptr || gradient != nullptr) {
+ preparer->Prepare(residual_block,
+ i,
+ jacobian,
+ scratch->jacobian_block_ptrs.get());
+ block_jacobians = scratch->jacobian_block_ptrs.get();
+ }
- scratch->cost += block_cost;
+ // Evaluate the cost, residuals, and jacobians.
+ double block_cost;
+ if (!residual_block->Evaluate(
+ evaluate_options.apply_loss_function,
+ &block_cost,
+ block_residuals,
+ block_jacobians,
+ scratch->residual_block_evaluate_scratch.get())) {
+ abort = true;
+ return;
+ }
- // Store the jacobians, if they were requested.
- if (jacobian != NULL) {
- jacobian_writer_.Write(i,
- residual_layout_[i],
- block_jacobians,
- jacobian);
- }
+ scratch->cost += block_cost;
- // Compute and store the gradient, if it was requested.
- if (gradient != NULL) {
- int num_residuals = residual_block->NumResiduals();
- int num_parameter_blocks = residual_block->NumParameterBlocks();
- for (int j = 0; j < num_parameter_blocks; ++j) {
- const ParameterBlock* parameter_block =
- residual_block->parameter_blocks()[j];
- if (parameter_block->IsConstant()) {
- continue;
+ // Store the jacobians, if they were requested.
+ if (jacobian != nullptr) {
+ jacobian_writer_.Write(
+ i, residual_layout_[i], block_jacobians, jacobian);
}
- MatrixTransposeVectorMultiply<Eigen::Dynamic, Eigen::Dynamic, 1>(
- block_jacobians[j],
- num_residuals,
- parameter_block->LocalSize(),
- block_residuals,
- scratch->gradient.get() + parameter_block->delta_offset());
- }
- }
- }
+ // Compute and store the gradient, if it was requested.
+ if (gradient != nullptr) {
+ int num_residuals = residual_block->NumResiduals();
+ int num_parameter_blocks = residual_block->NumParameterBlocks();
+ for (int j = 0; j < num_parameter_blocks; ++j) {
+ const ParameterBlock* parameter_block =
+ residual_block->parameter_blocks()[j];
+ if (parameter_block->IsConstant()) {
+ continue;
+ }
+
+ MatrixTransposeVectorMultiply<Eigen::Dynamic, Eigen::Dynamic, 1>(
+ block_jacobians[j],
+ num_residuals,
+ parameter_block->LocalSize(),
+ block_residuals,
+ scratch->gradient.get() + parameter_block->delta_offset());
+ }
+ }
+ });
if (!abort) {
const int num_parameters = program_->NumEffectiveParameters();
// Sum the cost and gradient (if requested) from each thread.
(*cost) = 0.0;
- if (gradient != NULL) {
+ if (gradient != nullptr) {
VectorRef(gradient, num_parameters).setZero();
}
for (int i = 0; i < options_.num_threads; ++i) {
(*cost) += evaluate_scratch_[i].cost;
- if (gradient != NULL) {
+ if (gradient != nullptr) {
VectorRef(gradient, num_parameters) +=
VectorRef(evaluate_scratch_[i].gradient.get(), num_parameters);
}
@@ -276,7 +275,7 @@ class ProgramEvaluator : public Evaluator {
// `num_parameters` is passed to the finalizer so that additional
// storage can be reserved for additional diagonal elements if
// necessary.
- if (jacobian != NULL) {
+ if (jacobian != nullptr) {
JacobianFinalizer f;
f(jacobian, num_parameters);
}
@@ -286,27 +285,19 @@ class ProgramEvaluator : public Evaluator {
bool Plus(const double* state,
const double* delta,
- double* state_plus_delta) const {
+ double* state_plus_delta) const final {
return program_->Plus(state, delta, state_plus_delta);
}
- int NumParameters() const {
- return program_->NumParameters();
- }
- int NumEffectiveParameters() const {
+ int NumParameters() const final { return program_->NumParameters(); }
+ int NumEffectiveParameters() const final {
return program_->NumEffectiveParameters();
}
- int NumResiduals() const {
- return program_->NumResiduals();
- }
-
- virtual std::map<std::string, int> CallStatistics() const {
- return execution_summary_.calls();
- }
+ int NumResiduals() const final { return program_->NumResiduals(); }
- virtual std::map<std::string, double> TimeStatistics() const {
- return execution_summary_.times();
+ std::map<std::string, CallStatistics> Statistics() const final {
+ return execution_summary_.statistics();
}
private:
@@ -322,17 +313,16 @@ class ProgramEvaluator : public Evaluator {
VectorRef(gradient.get(), num_parameters).setZero();
residual_block_residuals.reset(
new double[max_residuals_per_residual_block]);
- jacobian_block_ptrs.reset(
- new double*[max_parameters_per_residual_block]);
+ jacobian_block_ptrs.reset(new double*[max_parameters_per_residual_block]);
}
double cost;
- scoped_array<double> residual_block_evaluate_scratch;
+ std::unique_ptr<double[]> residual_block_evaluate_scratch;
// The gradient in the local parameterization.
- scoped_array<double> gradient;
+ std::unique_ptr<double[]> gradient;
// Enough space to store the residual for the largest residual block.
- scoped_array<double> residual_block_residuals;
- scoped_array<double*> jacobian_block_ptrs;
+ std::unique_ptr<double[]> residual_block_residuals;
+ std::unique_ptr<double*[]> jacobian_block_ptrs;
};
static void BuildResidualLayout(const Program& program,
@@ -372,8 +362,8 @@ class ProgramEvaluator : public Evaluator {
Evaluator::Options options_;
Program* program_;
JacobianWriter jacobian_writer_;
- scoped_array<EvaluatePreparer> evaluate_preparers_;
- scoped_array<EvaluateScratch> evaluate_scratch_;
+ std::unique_ptr<EvaluatePreparer[]> evaluate_preparers_;
+ std::unique_ptr<EvaluateScratch[]> evaluate_scratch_;
std::vector<int> residual_layout_;
::ceres::internal::ExecutionSummary execution_summary_;
};
diff --git a/extern/ceres/internal/ceres/random.h b/extern/ceres/internal/ceres/random.h
index 2a025600609..87d9d77d90d 100644
--- a/extern/ceres/internal/ceres/random.h
+++ b/extern/ceres/internal/ceres/random.h
@@ -43,7 +43,11 @@ inline void SetRandomState(int state) {
}
inline int Uniform(int n) {
- return rand() % n;
+ if (n) {
+ return rand() % n;
+ } else {
+ return 0;
+ }
}
inline double RandDouble() {
diff --git a/extern/ceres/internal/ceres/reorder_program.cc b/extern/ceres/internal/ceres/reorder_program.cc
index a7c37107591..aa6032a9e9e 100644
--- a/extern/ceres/internal/ceres/reorder_program.cc
+++ b/extern/ceres/internal/ceres/reorder_program.cc
@@ -31,6 +31,7 @@
#include "ceres/reorder_program.h"
#include <algorithm>
+#include <memory>
#include <numeric>
#include <vector>
@@ -84,7 +85,7 @@ static int MinParameterBlock(const ResidualBlock* residual_block,
return min_parameter_block_position;
}
-#if EIGEN_VERSION_AT_LEAST(3, 2, 2) && defined(CERES_USE_EIGEN_SPARSE)
+#if defined(CERES_USE_EIGEN_SPARSE)
Eigen::SparseMatrix<int> CreateBlockJacobian(
const TripletSparseMatrix& block_jacobian_transpose) {
typedef Eigen::SparseMatrix<int> SparseMatrix;
@@ -178,7 +179,6 @@ void OrderingForSparseNormalCholeskyUsingCXSparse(
}
-#if EIGEN_VERSION_AT_LEAST(3, 2, 2)
void OrderingForSparseNormalCholeskyUsingEigenSparse(
const TripletSparseMatrix& tsm_block_jacobian_transpose,
int* ordering) {
@@ -211,7 +211,6 @@ void OrderingForSparseNormalCholeskyUsingEigenSparse(
}
#endif // CERES_USE_EIGEN_SPARSE
}
-#endif
} // namespace
@@ -233,24 +232,19 @@ bool ApplyOrdering(const ProblemImpl::ParameterMap& parameter_map,
program->mutable_parameter_blocks();
parameter_blocks->clear();
- const map<int, set<double*> >& groups = ordering.group_to_elements();
- for (map<int, set<double*> >::const_iterator group_it = groups.begin();
- group_it != groups.end();
- ++group_it) {
- const set<double*>& group = group_it->second;
- for (set<double*>::const_iterator parameter_block_ptr_it = group.begin();
- parameter_block_ptr_it != group.end();
- ++parameter_block_ptr_it) {
- ProblemImpl::ParameterMap::const_iterator parameter_block_it =
- parameter_map.find(*parameter_block_ptr_it);
- if (parameter_block_it == parameter_map.end()) {
+ const map<int, set<double*>>& groups = ordering.group_to_elements();
+ for (const auto& p : groups) {
+ const set<double*>& group = p.second;
+ for (double* parameter_block_ptr : group) {
+ auto it = parameter_map.find(parameter_block_ptr);
+ if (it == parameter_map.end()) {
*error = StringPrintf("User specified ordering contains a pointer "
"to a double that is not a parameter block in "
"the problem. The invalid double is in group: %d",
- group_it->first);
+ p.first);
return false;
}
- parameter_blocks->push_back(parameter_block_it->second);
+ parameter_blocks->push_back(it->second);
}
}
return true;
@@ -339,7 +333,7 @@ bool LexicographicallyOrderResidualBlocks(
// Pre-order the columns corresponding to the schur complement if
// possible.
-void MaybeReorderSchurComplementColumnsUsingSuiteSparse(
+static void MaybeReorderSchurComplementColumnsUsingSuiteSparse(
const ParameterBlockOrdering& parameter_block_ordering,
Program* program) {
#ifndef CERES_NO_SUITESPARSE
@@ -364,7 +358,7 @@ void MaybeReorderSchurComplementColumnsUsingSuiteSparse(
MapValuesToContiguousRange(constraints.size(), &constraints[0]);
// Compute a block sparse presentation of J'.
- scoped_ptr<TripletSparseMatrix> tsm_block_jacobian_transpose(
+ std::unique_ptr<TripletSparseMatrix> tsm_block_jacobian_transpose(
program->CreateJacobianBlockSparsityTranspose());
cholmod_sparse* block_jacobian_transpose =
@@ -385,15 +379,12 @@ void MaybeReorderSchurComplementColumnsUsingSuiteSparse(
#endif
}
-void MaybeReorderSchurComplementColumnsUsingEigen(
+static void MaybeReorderSchurComplementColumnsUsingEigen(
const int size_of_first_elimination_group,
const ProblemImpl::ParameterMap& parameter_map,
Program* program) {
-#if !EIGEN_VERSION_AT_LEAST(3, 2, 2) || !defined(CERES_USE_EIGEN_SPARSE)
- return;
-#else
-
- scoped_ptr<TripletSparseMatrix> tsm_block_jacobian_transpose(
+#if defined(CERES_USE_EIGEN_SPARSE)
+ std::unique_ptr<TripletSparseMatrix> tsm_block_jacobian_transpose(
program->CreateJacobianBlockSparsityTranspose());
typedef Eigen::SparseMatrix<int> SparseMatrix;
@@ -531,18 +522,14 @@ bool ReorderProgramForSchurTypeLinearSolver(
// Schur type solvers also require that their residual blocks be
// lexicographically ordered.
- if (!LexicographicallyOrderResidualBlocks(size_of_first_elimination_group,
- program,
- error)) {
- return false;
- }
-
- return true;
+ return LexicographicallyOrderResidualBlocks(
+ size_of_first_elimination_group, program, error);
}
-bool ReorderProgramForSparseNormalCholesky(
+bool ReorderProgramForSparseCholesky(
const SparseLinearAlgebraLibraryType sparse_linear_algebra_library_type,
const ParameterBlockOrdering& parameter_block_ordering,
+ int start_row_block,
Program* program,
string* error) {
if (parameter_block_ordering.NumElements() != program->NumParameterBlocks()) {
@@ -555,8 +542,8 @@ bool ReorderProgramForSparseNormalCholesky(
}
// Compute a block sparse presentation of J'.
- scoped_ptr<TripletSparseMatrix> tsm_block_jacobian_transpose(
- program->CreateJacobianBlockSparsityTranspose());
+ std::unique_ptr<TripletSparseMatrix> tsm_block_jacobian_transpose(
+ program->CreateJacobianBlockSparsityTranspose(start_row_block));
vector<int> ordering(program->NumParameterBlocks(), 0);
vector<ParameterBlock*>& parameter_blocks =
@@ -572,19 +559,19 @@ bool ReorderProgramForSparseNormalCholesky(
OrderingForSparseNormalCholeskyUsingCXSparse(
*tsm_block_jacobian_transpose,
&ordering[0]);
+ } else if (sparse_linear_algebra_library_type == ACCELERATE_SPARSE) {
+ // Accelerate does not provide a function to perform reordering without
+ // performing a full symbolic factorisation. As such, we have nothing
+ // to gain from trying to reorder the problem here, as it will happen
+ // in AppleAccelerateCholesky::Factorize() (once) and reordering here
+ // would involve performing two symbolic factorisations instead of one
+ // which would have a negative overall impact on performance.
+ return true;
+
} else if (sparse_linear_algebra_library_type == EIGEN_SPARSE) {
-#if EIGEN_VERSION_AT_LEAST(3, 2, 2)
- OrderingForSparseNormalCholeskyUsingEigenSparse(
+ OrderingForSparseNormalCholeskyUsingEigenSparse(
*tsm_block_jacobian_transpose,
&ordering[0]);
-#else
- // For Eigen versions less than 3.2.2, there is nothing to do as
- // older versions of Eigen do not expose a method for doing
- // symbolic analysis on pre-ordered matrices, so a block
- // pre-ordering is a bit pointless.
-
- return true;
-#endif
}
// Apply ordering.
@@ -597,5 +584,17 @@ bool ReorderProgramForSparseNormalCholesky(
return true;
}
+int ReorderResidualBlocksByPartition(
+ const std::unordered_set<ResidualBlockId>& bottom_residual_blocks,
+ Program* program) {
+ auto residual_blocks = program->mutable_residual_blocks();
+ auto it = std::partition(
+ residual_blocks->begin(), residual_blocks->end(),
+ [&bottom_residual_blocks](ResidualBlock* r) {
+ return bottom_residual_blocks.count(r) == 0;
+ });
+ return it - residual_blocks->begin();
+}
+
} // namespace internal
} // namespace ceres
diff --git a/extern/ceres/internal/ceres/reorder_program.h b/extern/ceres/internal/ceres/reorder_program.h
index 36e5d1637a9..88cbee3af21 100644
--- a/extern/ceres/internal/ceres/reorder_program.h
+++ b/extern/ceres/internal/ceres/reorder_program.h
@@ -89,12 +89,27 @@ bool ReorderProgramForSchurTypeLinearSolver(
// fill-reducing ordering is available in the sparse linear algebra
// library (SuiteSparse version >= 4.2.0) then the fill reducing
// ordering will take it into account, otherwise it will be ignored.
-bool ReorderProgramForSparseNormalCholesky(
+bool ReorderProgramForSparseCholesky(
SparseLinearAlgebraLibraryType sparse_linear_algebra_library_type,
const ParameterBlockOrdering& parameter_block_ordering,
+ int start_row_block,
Program* program,
std::string* error);
+// Reorder the residual blocks in the program so that all the residual
+// blocks in bottom_residual_blocks are at the bottom. The return
+// value is the number of residual blocks in the program in "top" part
+// of the Program, i.e., the ones not included in
+// bottom_residual_blocks.
+//
+// This number can be different from program->NumResidualBlocks() -
+// bottom_residual_blocks.size() because we allow
+// bottom_residual_blocks to contain residual blocks not present in
+// the Program.
+int ReorderResidualBlocksByPartition(
+ const std::unordered_set<ResidualBlockId>& bottom_residual_blocks,
+ Program* program);
+
} // namespace internal
} // namespace ceres
diff --git a/extern/ceres/internal/ceres/residual_block.cc b/extern/ceres/internal/ceres/residual_block.cc
index 9a123cf132e..0bf30bcf446 100644
--- a/extern/ceres/internal/ceres/residual_block.cc
+++ b/extern/ceres/internal/ceres/residual_block.cc
@@ -35,13 +35,13 @@
#include <cstddef>
#include <vector>
#include "ceres/corrector.h"
-#include "ceres/parameter_block.h"
-#include "ceres/residual_block_utils.h"
#include "ceres/cost_function.h"
#include "ceres/internal/eigen.h"
#include "ceres/internal/fixed_array.h"
#include "ceres/local_parameterization.h"
#include "ceres/loss_function.h"
+#include "ceres/parameter_block.h"
+#include "ceres/residual_block_utils.h"
#include "ceres/small_blas.h"
using Eigen::Dynamic;
@@ -50,16 +50,14 @@ namespace ceres {
namespace internal {
ResidualBlock::ResidualBlock(
- const CostFunction* cost_function,
- const LossFunction* loss_function,
- const std::vector<ParameterBlock*>& parameter_blocks,
- int index)
+ const CostFunction* cost_function, const LossFunction* loss_function,
+ const std::vector<ParameterBlock*>& parameter_blocks, int index)
: cost_function_(cost_function),
loss_function_(loss_function),
parameter_blocks_(
- new ParameterBlock* [
- cost_function->parameter_block_sizes().size()]),
+ new ParameterBlock*[cost_function->parameter_block_sizes().size()]),
index_(index) {
+ CHECK(cost_function_ != nullptr);
std::copy(parameter_blocks.begin(),
parameter_blocks.end(),
parameter_blocks_.get());
@@ -82,11 +80,11 @@ bool ResidualBlock::Evaluate(const bool apply_loss_function,
// Put pointers into the scratch space into global_jacobians as appropriate.
FixedArray<double*, 8> global_jacobians(num_parameter_blocks);
- if (jacobians != NULL) {
+ if (jacobians != nullptr) {
for (int i = 0; i < num_parameter_blocks; ++i) {
const ParameterBlock* parameter_block = parameter_blocks_[i];
- if (jacobians[i] != NULL &&
- parameter_block->LocalParameterizationJacobian() != NULL) {
+ if (jacobians[i] != nullptr &&
+ parameter_block->LocalParameterizationJacobian() != nullptr) {
global_jacobians[i] = scratch;
scratch += num_residuals * parameter_block->Size();
} else {
@@ -96,7 +94,7 @@ bool ResidualBlock::Evaluate(const bool apply_loss_function,
}
// If the caller didn't request residuals, use the scratch space for them.
- bool outputting_residuals = (residuals != NULL);
+ bool outputting_residuals = (residuals != nullptr);
if (!outputting_residuals) {
residuals = scratch;
}
@@ -104,16 +102,17 @@ bool ResidualBlock::Evaluate(const bool apply_loss_function,
// Invalidate the evaluation buffers so that we can check them after
// the CostFunction::Evaluate call, to see if all the return values
// that were required were written to and that they are finite.
- double** eval_jacobians = (jacobians != NULL) ? global_jacobians.get() : NULL;
+ double** eval_jacobians =
+ (jacobians != nullptr) ? global_jacobians.data() : nullptr;
InvalidateEvaluation(*this, cost, residuals, eval_jacobians);
- if (!cost_function_->Evaluate(parameters.get(), residuals, eval_jacobians)) {
+ if (!cost_function_->Evaluate(parameters.data(), residuals, eval_jacobians)) {
return false;
}
if (!IsEvaluationValid(*this,
- parameters.get(),
+ parameters.data(),
cost,
residuals,
eval_jacobians)) {
@@ -124,7 +123,7 @@ bool ResidualBlock::Evaluate(const bool apply_loss_function,
"residual and jacobians that were requested or there was a non-finite value (nan/infinite)\n" // NOLINT
"generated during the or jacobian computation. \n\n" +
EvaluationToString(*this,
- parameters.get(),
+ parameters.data(),
cost,
residuals,
eval_jacobians);
@@ -135,13 +134,13 @@ bool ResidualBlock::Evaluate(const bool apply_loss_function,
double squared_norm = VectorRef(residuals, num_residuals).squaredNorm();
// Update the jacobians with the local parameterizations.
- if (jacobians != NULL) {
+ if (jacobians != nullptr) {
for (int i = 0; i < num_parameter_blocks; ++i) {
- if (jacobians[i] != NULL) {
+ if (jacobians[i] != nullptr) {
const ParameterBlock* parameter_block = parameter_blocks_[i];
// Apply local reparameterization to the jacobians.
- if (parameter_block->LocalParameterizationJacobian() != NULL) {
+ if (parameter_block->LocalParameterizationJacobian() != nullptr) {
// jacobians[i] = global_jacobians[i] * global_to_local_jacobian.
MatrixMatrixMultiply<Dynamic, Dynamic, Dynamic, Dynamic, 0>(
global_jacobians[i],
@@ -156,7 +155,7 @@ bool ResidualBlock::Evaluate(const bool apply_loss_function,
}
}
- if (loss_function_ == NULL || !apply_loss_function) {
+ if (loss_function_ == nullptr || !apply_loss_function) {
*cost = 0.5 * squared_norm;
return true;
}
@@ -167,16 +166,16 @@ bool ResidualBlock::Evaluate(const bool apply_loss_function,
// No jacobians and not outputting residuals? All done. Doing an early exit
// here avoids constructing the "Corrector" object below in a common case.
- if (jacobians == NULL && !outputting_residuals) {
+ if (jacobians == nullptr && !outputting_residuals) {
return true;
}
// Correct for the effects of the loss function. The jacobians need to be
// corrected before the residuals, since they use the uncorrected residuals.
Corrector correct(squared_norm, rho);
- if (jacobians != NULL) {
+ if (jacobians != nullptr) {
for (int i = 0; i < num_parameter_blocks; ++i) {
- if (jacobians[i] != NULL) {
+ if (jacobians[i] != nullptr) {
const ParameterBlock* parameter_block = parameter_blocks_[i];
// Correct the jacobians for the loss function.
@@ -206,8 +205,7 @@ int ResidualBlock::NumScratchDoublesForEvaluate() const {
int scratch_doubles = 1;
for (int i = 0; i < num_parameters; ++i) {
const ParameterBlock* parameter_block = parameter_blocks_[i];
- if (!parameter_block->IsConstant() &&
- parameter_block->LocalParameterizationJacobian() != NULL) {
+ if (parameter_block->LocalParameterizationJacobian() != nullptr) {
scratch_doubles += parameter_block->Size();
}
}
diff --git a/extern/ceres/internal/ceres/residual_block.h b/extern/ceres/internal/ceres/residual_block.h
index a32f1c36cd3..a2e4425b911 100644
--- a/extern/ceres/internal/ceres/residual_block.h
+++ b/extern/ceres/internal/ceres/residual_block.h
@@ -34,12 +34,13 @@
#ifndef CERES_INTERNAL_RESIDUAL_BLOCK_H_
#define CERES_INTERNAL_RESIDUAL_BLOCK_H_
+#include <cstdint>
+#include <memory>
#include <string>
#include <vector>
#include "ceres/cost_function.h"
#include "ceres/internal/port.h"
-#include "ceres/internal/scoped_ptr.h"
#include "ceres/stringprintf.h"
#include "ceres/types.h"
@@ -81,12 +82,14 @@ class ResidualBlock {
// computed. If jacobians[i] is NULL, then the jacobian for that parameter is
// not computed.
//
+ // cost must not be null.
+ //
// Evaluate needs scratch space which must be supplied by the caller via
// scratch. The array should have at least NumScratchDoublesForEvaluate()
// space available.
//
// The return value indicates the success or failure. If the function returns
- // false, the caller should expect the the output memory locations to have
+ // false, the caller should expect the output memory locations to have
// been modified.
//
// The returned cost and jacobians have had robustification and local
@@ -134,12 +137,12 @@ class ResidualBlock {
private:
const CostFunction* cost_function_;
const LossFunction* loss_function_;
- scoped_array<ParameterBlock*> parameter_blocks_;
+ std::unique_ptr<ParameterBlock*[]> parameter_blocks_;
// The index of the residual, typically in a Program. This is only to permit
// switching from a ResidualBlock* to an index in the Program's array, needed
// to do efficient removals.
- int32 index_;
+ int32_t index_;
};
} // namespace internal
diff --git a/extern/ceres/internal/ceres/residual_block_utils.cc b/extern/ceres/internal/ceres/residual_block_utils.cc
index dd2bd73a6ac..35e928bbcc1 100644
--- a/extern/ceres/internal/ceres/residual_block_utils.cc
+++ b/extern/ceres/internal/ceres/residual_block_utils.cc
@@ -68,8 +68,8 @@ string EvaluationToString(const ResidualBlock& block,
double* cost,
double* residuals,
double** jacobians) {
- CHECK_NOTNULL(cost);
- CHECK_NOTNULL(residuals);
+ CHECK(cost != nullptr);
+ CHECK(residuals != nullptr);
const int num_parameter_blocks = block.NumParameterBlocks();
const int num_residuals = block.NumResiduals();
diff --git a/extern/ceres/internal/ceres/schur_complement_solver.cc b/extern/ceres/internal/ceres/schur_complement_solver.cc
index 65449832c4c..0083300b036 100644
--- a/extern/ceres/internal/ceres/schur_complement_solver.cc
+++ b/extern/ceres/internal/ceres/schur_complement_solver.cc
@@ -28,33 +28,30 @@
//
// Author: sameeragarwal@google.com (Sameer Agarwal)
-#include "ceres/internal/port.h"
+#include "ceres/schur_complement_solver.h"
#include <algorithm>
#include <ctime>
+#include <memory>
#include <set>
-#include <sstream>
#include <vector>
+#include "Eigen/Dense"
+#include "Eigen/SparseCore"
#include "ceres/block_random_access_dense_matrix.h"
#include "ceres/block_random_access_matrix.h"
#include "ceres/block_random_access_sparse_matrix.h"
#include "ceres/block_sparse_matrix.h"
#include "ceres/block_structure.h"
#include "ceres/conjugate_gradients_solver.h"
-#include "ceres/cxsparse.h"
#include "ceres/detect_structure.h"
#include "ceres/internal/eigen.h"
-#include "ceres/internal/scoped_ptr.h"
#include "ceres/lapack.h"
#include "ceres/linear_solver.h"
-#include "ceres/schur_complement_solver.h"
-#include "ceres/suitesparse.h"
+#include "ceres/sparse_cholesky.h"
#include "ceres/triplet_sparse_matrix.h"
#include "ceres/types.h"
#include "ceres/wall_time.h"
-#include "Eigen/Dense"
-#include "Eigen/SparseCore"
namespace ceres {
namespace internal {
@@ -70,23 +67,22 @@ class BlockRandomAccessSparseMatrixAdapter : public LinearOperator {
public:
explicit BlockRandomAccessSparseMatrixAdapter(
const BlockRandomAccessSparseMatrix& m)
- : m_(m) {
- }
+ : m_(m) {}
virtual ~BlockRandomAccessSparseMatrixAdapter() {}
// y = y + Ax;
- virtual void RightMultiply(const double* x, double* y) const {
+ void RightMultiply(const double* x, double* y) const final {
m_.SymmetricRightMultiply(x, y);
}
// y = y + A'x;
- virtual void LeftMultiply(const double* x, double* y) const {
+ void LeftMultiply(const double* x, double* y) const final {
m_.SymmetricRightMultiply(x, y);
}
- virtual int num_rows() const { return m_.num_rows(); }
- virtual int num_cols() const { return m_.num_rows(); }
+ int num_rows() const final { return m_.num_rows(); }
+ int num_cols() const final { return m_.num_rows(); }
private:
const BlockRandomAccessSparseMatrix& m_;
@@ -96,29 +92,28 @@ class BlockRandomAccessDiagonalMatrixAdapter : public LinearOperator {
public:
explicit BlockRandomAccessDiagonalMatrixAdapter(
const BlockRandomAccessDiagonalMatrix& m)
- : m_(m) {
- }
+ : m_(m) {}
virtual ~BlockRandomAccessDiagonalMatrixAdapter() {}
// y = y + Ax;
- virtual void RightMultiply(const double* x, double* y) const {
+ void RightMultiply(const double* x, double* y) const final {
m_.RightMultiply(x, y);
}
// y = y + A'x;
- virtual void LeftMultiply(const double* x, double* y) const {
+ void LeftMultiply(const double* x, double* y) const final {
m_.RightMultiply(x, y);
}
- virtual int num_rows() const { return m_.num_rows(); }
- virtual int num_cols() const { return m_.num_rows(); }
+ int num_rows() const final { return m_.num_rows(); }
+ int num_cols() const final { return m_.num_rows(); }
private:
const BlockRandomAccessDiagonalMatrix& m_;
};
-} // namespace
+} // namespace
LinearSolver::Summary SchurComplementSolver::SolveImpl(
BlockSparseMatrix* A,
@@ -127,20 +122,45 @@ LinearSolver::Summary SchurComplementSolver::SolveImpl(
double* x) {
EventLogger event_logger("SchurComplementSolver::Solve");
+ const CompressedRowBlockStructure* bs = A->block_structure();
if (eliminator_.get() == NULL) {
- InitStorage(A->block_structure());
- DetectStructure(*A->block_structure(),
- options_.elimination_groups[0],
+ const int num_eliminate_blocks = options_.elimination_groups[0];
+ const int num_f_blocks = bs->cols.size() - num_eliminate_blocks;
+
+ InitStorage(bs);
+ DetectStructure(*bs,
+ num_eliminate_blocks,
&options_.row_block_size,
&options_.e_block_size,
&options_.f_block_size);
- eliminator_.reset(CHECK_NOTNULL(SchurEliminatorBase::Create(options_)));
- eliminator_->Init(options_.elimination_groups[0], A->block_structure());
- };
+
+ // For the special case of the static structure <2,3,6> with
+ // exactly one f block use the SchurEliminatorForOneFBlock.
+ //
+ // TODO(sameeragarwal): A more scalable template specialization
+ // mechanism that does not cause binary bloat.
+ if (options_.row_block_size == 2 &&
+ options_.e_block_size == 3 &&
+ options_.f_block_size == 6 &&
+ num_f_blocks == 1) {
+ eliminator_.reset(new SchurEliminatorForOneFBlock<2, 3, 6>);
+ } else {
+ eliminator_.reset(SchurEliminatorBase::Create(options_));
+ }
+
+ CHECK(eliminator_);
+ const bool kFullRankETE = true;
+ eliminator_->Init(num_eliminate_blocks, kFullRankETE, bs);
+ }
+
std::fill(x, x + A->num_cols(), 0.0);
event_logger.AddEvent("Setup");
- eliminator_->Eliminate(A, b, per_solve_options.D, lhs_.get(), rhs_.get());
+ eliminator_->Eliminate(BlockSparseMatrixData(*A),
+ b,
+ per_solve_options.D,
+ lhs_.get(),
+ rhs_.get());
event_logger.AddEvent("Eliminate");
double* reduced_solution = x + A->num_cols() - lhs_->num_cols();
@@ -149,7 +169,8 @@ LinearSolver::Summary SchurComplementSolver::SolveImpl(
event_logger.AddEvent("ReducedSolve");
if (summary.termination_type == LINEAR_SOLVER_SUCCESS) {
- eliminator_->BackSubstitute(A, b, per_solve_options.D, reduced_solution, x);
+ eliminator_->BackSubstitute(
+ BlockSparseMatrixData(*A), b, per_solve_options.D, reduced_solution, x);
event_logger.AddEvent("BackSubstitute");
}
@@ -164,9 +185,7 @@ void DenseSchurComplementSolver::InitStorage(
const int num_col_blocks = bs->cols.size();
vector<int> blocks(num_col_blocks - num_eliminate_blocks, 0);
- for (int i = num_eliminate_blocks, j = 0;
- i < num_col_blocks;
- ++i, ++j) {
+ for (int i = num_eliminate_blocks, j = 0; i < num_col_blocks; ++i, ++j) {
blocks[j] = bs->cols[i].size;
}
@@ -177,10 +196,8 @@ void DenseSchurComplementSolver::InitStorage(
// Solve the system Sx = r, assuming that the matrix S is stored in a
// BlockRandomAccessDenseMatrix. The linear system is solved using
// Eigen's Cholesky factorization.
-LinearSolver::Summary
-DenseSchurComplementSolver::SolveReducedLinearSystem(
- const LinearSolver::PerSolveOptions& per_solve_options,
- double* solution) {
+LinearSolver::Summary DenseSchurComplementSolver::SolveReducedLinearSystem(
+ const LinearSolver::PerSolveOptions& per_solve_options, double* solution) {
LinearSolver::Summary summary;
summary.num_iterations = 0;
summary.termination_type = LINEAR_SOLVER_SUCCESS;
@@ -201,8 +218,8 @@ DenseSchurComplementSolver::SolveReducedLinearSystem(
if (options().dense_linear_algebra_library_type == EIGEN) {
Eigen::LLT<Matrix, Eigen::Upper> llt =
ConstMatrixRef(m->values(), num_rows, num_rows)
- .selfadjointView<Eigen::Upper>()
- .llt();
+ .selfadjointView<Eigen::Upper>()
+ .llt();
if (llt.info() != Eigen::Success) {
summary.termination_type = LINEAR_SOLVER_FAILURE;
summary.message =
@@ -213,11 +230,8 @@ DenseSchurComplementSolver::SolveReducedLinearSystem(
VectorRef(solution, num_rows) = llt.solve(ConstVectorRef(rhs(), num_rows));
} else {
VectorRef(solution, num_rows) = ConstVectorRef(rhs(), num_rows);
- summary.termination_type =
- LAPACK::SolveInPlaceUsingCholesky(num_rows,
- m->values(),
- solution,
- &summary.message);
+ summary.termination_type = LAPACK::SolveInPlaceUsingCholesky(
+ num_rows, m->values(), solution, &summary.message);
}
return summary;
@@ -225,23 +239,14 @@ DenseSchurComplementSolver::SolveReducedLinearSystem(
SparseSchurComplementSolver::SparseSchurComplementSolver(
const LinearSolver::Options& options)
- : SchurComplementSolver(options),
- factor_(NULL),
- cxsparse_factor_(NULL) {
-}
-
-SparseSchurComplementSolver::~SparseSchurComplementSolver() {
- if (factor_ != NULL) {
- ss_.Free(factor_);
- factor_ = NULL;
- }
-
- if (cxsparse_factor_ != NULL) {
- cxsparse_.Free(cxsparse_factor_);
- cxsparse_factor_ = NULL;
+ : SchurComplementSolver(options) {
+ if (options.type != ITERATIVE_SCHUR) {
+ sparse_cholesky_ = SparseCholesky::Create(options);
}
}
+SparseSchurComplementSolver::~SparseSchurComplementSolver() {}
+
// Determine the non-zero blocks in the Schur Complement matrix, and
// initialize a BlockRandomAccessSparseMatrix object.
void SparseSchurComplementSolver::InitStorage(
@@ -255,7 +260,7 @@ void SparseSchurComplementSolver::InitStorage(
blocks_[i - num_eliminate_blocks] = bs->cols[i].size;
}
- set<pair<int, int> > block_pairs;
+ set<pair<int, int>> block_pairs;
for (int i = 0; i < blocks_.size(); ++i) {
block_pairs.insert(make_pair(i, i));
}
@@ -293,7 +298,7 @@ void SparseSchurComplementSolver::InitStorage(
}
}
- // Remaing rows do not contribute to the chunks and directly go
+ // Remaining rows do not contribute to the chunks and directly go
// into the schur complement via an outer product.
for (; r < num_row_blocks; ++r) {
const CompressedRow& row = bs->rows[r];
@@ -313,296 +318,49 @@ void SparseSchurComplementSolver::InitStorage(
set_rhs(new double[lhs()->num_rows()]);
}
-LinearSolver::Summary
-SparseSchurComplementSolver::SolveReducedLinearSystem(
- const LinearSolver::PerSolveOptions& per_solve_options,
- double* solution) {
+LinearSolver::Summary SparseSchurComplementSolver::SolveReducedLinearSystem(
+ const LinearSolver::PerSolveOptions& per_solve_options, double* solution) {
if (options().type == ITERATIVE_SCHUR) {
- CHECK(options().use_explicit_schur_complement);
return SolveReducedLinearSystemUsingConjugateGradients(per_solve_options,
solution);
}
- switch (options().sparse_linear_algebra_library_type) {
- case SUITE_SPARSE:
- return SolveReducedLinearSystemUsingSuiteSparse(per_solve_options,
- solution);
- case CX_SPARSE:
- return SolveReducedLinearSystemUsingCXSparse(per_solve_options,
- solution);
- case EIGEN_SPARSE:
- return SolveReducedLinearSystemUsingEigen(per_solve_options,
- solution);
- default:
- LOG(FATAL) << "Unknown sparse linear algebra library : "
- << options().sparse_linear_algebra_library_type;
- }
-
- return LinearSolver::Summary();
-}
-
-// Solve the system Sx = r, assuming that the matrix S is stored in a
-// BlockRandomAccessSparseMatrix. The linear system is solved using
-// CHOLMOD's sparse cholesky factorization routines.
-LinearSolver::Summary
-SparseSchurComplementSolver::SolveReducedLinearSystemUsingSuiteSparse(
- const LinearSolver::PerSolveOptions& per_solve_options,
- double* solution) {
-#ifdef CERES_NO_SUITESPARSE
-
- LinearSolver::Summary summary;
- summary.num_iterations = 0;
- summary.termination_type = LINEAR_SOLVER_FATAL_ERROR;
- summary.message = "Ceres was not built with SuiteSparse support. "
- "Therefore, SPARSE_SCHUR cannot be used with SUITE_SPARSE";
- return summary;
-
-#else
-
LinearSolver::Summary summary;
summary.num_iterations = 0;
summary.termination_type = LINEAR_SOLVER_SUCCESS;
summary.message = "Success.";
- TripletSparseMatrix* tsm =
- const_cast<TripletSparseMatrix*>(
- down_cast<const BlockRandomAccessSparseMatrix*>(lhs())->matrix());
- const int num_rows = tsm->num_rows();
-
- // The case where there are no f blocks, and the system is block
- // diagonal.
- if (num_rows == 0) {
+ const TripletSparseMatrix* tsm =
+ down_cast<const BlockRandomAccessSparseMatrix*>(lhs())->matrix();
+ if (tsm->num_rows() == 0) {
return summary;
}
- summary.num_iterations = 1;
- cholmod_sparse* cholmod_lhs = NULL;
- if (options().use_postordering) {
- // If we are going to do a full symbolic analysis of the schur
- // complement matrix from scratch and not rely on the
- // pre-ordering, then the fastest path in cholmod_factorize is the
- // one corresponding to upper triangular matrices.
-
- // Create a upper triangular symmetric matrix.
- cholmod_lhs = ss_.CreateSparseMatrix(tsm);
- cholmod_lhs->stype = 1;
-
- if (factor_ == NULL) {
- factor_ = ss_.BlockAnalyzeCholesky(cholmod_lhs,
- blocks_,
- blocks_,
- &summary.message);
- }
+ std::unique_ptr<CompressedRowSparseMatrix> lhs;
+ const CompressedRowSparseMatrix::StorageType storage_type =
+ sparse_cholesky_->StorageType();
+ if (storage_type == CompressedRowSparseMatrix::UPPER_TRIANGULAR) {
+ lhs.reset(CompressedRowSparseMatrix::FromTripletSparseMatrix(*tsm));
+ lhs->set_storage_type(CompressedRowSparseMatrix::UPPER_TRIANGULAR);
} else {
- // If we are going to use the natural ordering (i.e. rely on the
- // pre-ordering computed by solver_impl.cc), then the fastest
- // path in cholmod_factorize is the one corresponding to lower
- // triangular matrices.
-
- // Create a upper triangular symmetric matrix.
- cholmod_lhs = ss_.CreateSparseMatrixTranspose(tsm);
- cholmod_lhs->stype = -1;
-
- if (factor_ == NULL) {
- factor_ = ss_.AnalyzeCholeskyWithNaturalOrdering(cholmod_lhs,
- &summary.message);
- }
- }
-
- if (factor_ == NULL) {
- ss_.Free(cholmod_lhs);
- summary.termination_type = LINEAR_SOLVER_FATAL_ERROR;
- // No need to set message as it has already been set by the
- // symbolic analysis routines above.
- return summary;
+ lhs.reset(
+ CompressedRowSparseMatrix::FromTripletSparseMatrixTransposed(*tsm));
+ lhs->set_storage_type(CompressedRowSparseMatrix::LOWER_TRIANGULAR);
}
- summary.termination_type =
- ss_.Cholesky(cholmod_lhs, factor_, &summary.message);
-
- ss_.Free(cholmod_lhs);
-
- if (summary.termination_type != LINEAR_SOLVER_SUCCESS) {
- // No need to set message as it has already been set by the
- // numeric factorization routine above.
- return summary;
- }
-
- cholmod_dense* cholmod_rhs =
- ss_.CreateDenseVector(const_cast<double*>(rhs()), num_rows, num_rows);
- cholmod_dense* cholmod_solution = ss_.Solve(factor_,
- cholmod_rhs,
- &summary.message);
- ss_.Free(cholmod_rhs);
-
- if (cholmod_solution == NULL) {
- summary.message =
- "SuiteSparse failure. Unable to perform triangular solve.";
- summary.termination_type = LINEAR_SOLVER_FAILURE;
- return summary;
- }
-
- VectorRef(solution, num_rows)
- = VectorRef(static_cast<double*>(cholmod_solution->x), num_rows);
- ss_.Free(cholmod_solution);
- return summary;
-#endif // CERES_NO_SUITESPARSE
-}
-
-// Solve the system Sx = r, assuming that the matrix S is stored in a
-// BlockRandomAccessSparseMatrix. The linear system is solved using
-// CXSparse's sparse cholesky factorization routines.
-LinearSolver::Summary
-SparseSchurComplementSolver::SolveReducedLinearSystemUsingCXSparse(
- const LinearSolver::PerSolveOptions& per_solve_options,
- double* solution) {
-#ifdef CERES_NO_CXSPARSE
-
- LinearSolver::Summary summary;
- summary.num_iterations = 0;
- summary.termination_type = LINEAR_SOLVER_FATAL_ERROR;
- summary.message = "Ceres was not built with CXSparse support. "
- "Therefore, SPARSE_SCHUR cannot be used with CX_SPARSE";
- return summary;
-
-#else
-
- LinearSolver::Summary summary;
- summary.num_iterations = 0;
- summary.termination_type = LINEAR_SOLVER_SUCCESS;
- summary.message = "Success.";
-
- // Extract the TripletSparseMatrix that is used for actually storing S.
- TripletSparseMatrix* tsm =
- const_cast<TripletSparseMatrix*>(
- down_cast<const BlockRandomAccessSparseMatrix*>(lhs())->matrix());
- const int num_rows = tsm->num_rows();
-
- // The case where there are no f blocks, and the system is block
- // diagonal.
- if (num_rows == 0) {
- return summary;
- }
-
- cs_di* lhs = CHECK_NOTNULL(cxsparse_.CreateSparseMatrix(tsm));
- VectorRef(solution, num_rows) = ConstVectorRef(rhs(), num_rows);
-
- // Compute symbolic factorization if not available.
- if (cxsparse_factor_ == NULL) {
- cxsparse_factor_ = cxsparse_.BlockAnalyzeCholesky(lhs, blocks_, blocks_);
- }
-
- if (cxsparse_factor_ == NULL) {
- summary.termination_type = LINEAR_SOLVER_FATAL_ERROR;
- summary.message =
- "CXSparse failure. Unable to find symbolic factorization.";
- } else if (!cxsparse_.SolveCholesky(lhs, cxsparse_factor_, solution)) {
- summary.termination_type = LINEAR_SOLVER_FAILURE;
- summary.message = "CXSparse::SolveCholesky failed.";
- }
-
- cxsparse_.Free(lhs);
- return summary;
-#endif // CERES_NO_CXPARSE
-}
-
-// Solve the system Sx = r, assuming that the matrix S is stored in a
-// BlockRandomAccessSparseMatrix. The linear system is solved using
-// Eigen's sparse cholesky factorization routines.
-LinearSolver::Summary
-SparseSchurComplementSolver::SolveReducedLinearSystemUsingEigen(
- const LinearSolver::PerSolveOptions& per_solve_options,
- double* solution) {
-#ifndef CERES_USE_EIGEN_SPARSE
-
- LinearSolver::Summary summary;
- summary.num_iterations = 0;
- summary.termination_type = LINEAR_SOLVER_FATAL_ERROR;
- summary.message =
- "SPARSE_SCHUR cannot be used with EIGEN_SPARSE. "
- "Ceres was not built with support for "
- "Eigen's SimplicialLDLT decomposition. "
- "This requires enabling building with -DEIGENSPARSE=ON.";
- return summary;
-
-#else
- EventLogger event_logger("SchurComplementSolver::EigenSolve");
- LinearSolver::Summary summary;
- summary.num_iterations = 0;
- summary.termination_type = LINEAR_SOLVER_SUCCESS;
- summary.message = "Success.";
-
- // Extract the TripletSparseMatrix that is used for actually storing S.
- TripletSparseMatrix* tsm =
- const_cast<TripletSparseMatrix*>(
- down_cast<const BlockRandomAccessSparseMatrix*>(lhs())->matrix());
- const int num_rows = tsm->num_rows();
-
- // The case where there are no f blocks, and the system is block
- // diagonal.
- if (num_rows == 0) {
- return summary;
- }
-
- // This is an upper triangular matrix.
- CompressedRowSparseMatrix crsm(*tsm);
- // Map this to a column major, lower triangular matrix.
- Eigen::MappedSparseMatrix<double, Eigen::ColMajor> eigen_lhs(
- crsm.num_rows(),
- crsm.num_rows(),
- crsm.num_nonzeros(),
- crsm.mutable_rows(),
- crsm.mutable_cols(),
- crsm.mutable_values());
- event_logger.AddEvent("ToCompressedRowSparseMatrix");
-
- // Compute symbolic factorization if one does not exist.
- if (simplicial_ldlt_.get() == NULL) {
- simplicial_ldlt_.reset(new SimplicialLDLT);
- // This ordering is quite bad. The scalar ordering produced by the
- // AMD algorithm is quite bad and can be an order of magnitude
- // worse than the one computed using the block version of the
- // algorithm.
- simplicial_ldlt_->analyzePattern(eigen_lhs);
- if (VLOG_IS_ON(2)) {
- std::stringstream ss;
- simplicial_ldlt_->dumpMemory(ss);
- VLOG(2) << "Symbolic Analysis\n"
- << ss.str();
- }
- event_logger.AddEvent("Analysis");
- if (simplicial_ldlt_->info() != Eigen::Success) {
- summary.termination_type = LINEAR_SOLVER_FATAL_ERROR;
- summary.message =
- "Eigen failure. Unable to find symbolic factorization.";
- return summary;
- }
- }
-
- simplicial_ldlt_->factorize(eigen_lhs);
- event_logger.AddEvent("Factorize");
- if (simplicial_ldlt_->info() != Eigen::Success) {
- summary.termination_type = LINEAR_SOLVER_FAILURE;
- summary.message = "Eigen failure. Unable to find numeric factoriztion.";
- return summary;
- }
-
- VectorRef(solution, num_rows) =
- simplicial_ldlt_->solve(ConstVectorRef(rhs(), num_rows));
- event_logger.AddEvent("Solve");
- if (simplicial_ldlt_->info() != Eigen::Success) {
- summary.termination_type = LINEAR_SOLVER_FAILURE;
- summary.message = "Eigen failure. Unable to do triangular solve.";
- }
+ *lhs->mutable_col_blocks() = blocks_;
+ *lhs->mutable_row_blocks() = blocks_;
+ summary.num_iterations = 1;
+ summary.termination_type = sparse_cholesky_->FactorAndSolve(
+ lhs.get(), rhs(), solution, &summary.message);
return summary;
-#endif // CERES_USE_EIGEN_SPARSE
}
LinearSolver::Summary
SparseSchurComplementSolver::SolveReducedLinearSystemUsingConjugateGradients(
- const LinearSolver::PerSolveOptions& per_solve_options,
- double* solution) {
+ const LinearSolver::PerSolveOptions& per_solve_options, double* solution) {
+ CHECK(options().use_explicit_schur_complement);
const int num_rows = lhs()->num_rows();
// The case where there are no f blocks, and the system is block
// diagonal.
@@ -621,27 +379,24 @@ SparseSchurComplementSolver::SolveReducedLinearSystemUsingConjugateGradients(
preconditioner_.reset(new BlockRandomAccessDiagonalMatrix(blocks_));
}
- BlockRandomAccessSparseMatrix* sc =
- down_cast<BlockRandomAccessSparseMatrix*>(
- const_cast<BlockRandomAccessMatrix*>(lhs()));
+ BlockRandomAccessSparseMatrix* sc = down_cast<BlockRandomAccessSparseMatrix*>(
+ const_cast<BlockRandomAccessMatrix*>(lhs()));
// Extract block diagonal from the Schur complement to construct the
// schur_jacobi preconditioner.
- for (int i = 0; i < blocks_.size(); ++i) {
+ for (int i = 0; i < blocks_.size(); ++i) {
const int block_size = blocks_[i];
int sc_r, sc_c, sc_row_stride, sc_col_stride;
CellInfo* sc_cell_info =
- CHECK_NOTNULL(sc->GetCell(i, i,
- &sc_r, &sc_c,
- &sc_row_stride, &sc_col_stride));
+ sc->GetCell(i, i, &sc_r, &sc_c, &sc_row_stride, &sc_col_stride);
+ CHECK(sc_cell_info != nullptr);
MatrixRef sc_m(sc_cell_info->values, sc_row_stride, sc_col_stride);
int pre_r, pre_c, pre_row_stride, pre_col_stride;
- CellInfo* pre_cell_info = CHECK_NOTNULL(
- preconditioner_->GetCell(i, i,
- &pre_r, &pre_c,
- &pre_row_stride, &pre_col_stride));
+ CellInfo* pre_cell_info = preconditioner_->GetCell(
+ i, i, &pre_r, &pre_c, &pre_row_stride, &pre_col_stride);
+ CHECK(pre_cell_info != nullptr);
MatrixRef pre_m(pre_cell_info->values, pre_row_stride, pre_col_stride);
pre_m.block(pre_r, pre_c, block_size, block_size) =
@@ -651,12 +406,11 @@ SparseSchurComplementSolver::SolveReducedLinearSystemUsingConjugateGradients(
VectorRef(solution, num_rows).setZero();
- scoped_ptr<LinearOperator> lhs_adapter(
+ std::unique_ptr<LinearOperator> lhs_adapter(
new BlockRandomAccessSparseMatrixAdapter(*sc));
- scoped_ptr<LinearOperator> preconditioner_adapter(
+ std::unique_ptr<LinearOperator> preconditioner_adapter(
new BlockRandomAccessDiagonalMatrixAdapter(*preconditioner_));
-
LinearSolver::Options cg_options;
cg_options.min_num_iterations = options().min_num_iterations;
cg_options.max_num_iterations = options().max_num_iterations;
@@ -667,10 +421,8 @@ SparseSchurComplementSolver::SolveReducedLinearSystemUsingConjugateGradients(
cg_per_solve_options.q_tolerance = per_solve_options.q_tolerance;
cg_per_solve_options.preconditioner = preconditioner_adapter.get();
- return cg_solver.Solve(lhs_adapter.get(),
- rhs(),
- cg_per_solve_options,
- solution);
+ return cg_solver.Solve(
+ lhs_adapter.get(), rhs(), cg_per_solve_options, solution);
}
} // namespace internal
diff --git a/extern/ceres/internal/ceres/schur_complement_solver.h b/extern/ceres/internal/ceres/schur_complement_solver.h
index 714dafc5b0c..87f04785794 100644
--- a/extern/ceres/internal/ceres/schur_complement_solver.h
+++ b/extern/ceres/internal/ceres/schur_complement_solver.h
@@ -31,22 +31,19 @@
#ifndef CERES_INTERNAL_SCHUR_COMPLEMENT_SOLVER_H_
#define CERES_INTERNAL_SCHUR_COMPLEMENT_SOLVER_H_
+#include <memory>
#include <set>
#include <utility>
#include <vector>
-#include "ceres/internal/port.h"
-
+#include "ceres/block_random_access_diagonal_matrix.h"
#include "ceres/block_random_access_matrix.h"
#include "ceres/block_sparse_matrix.h"
#include "ceres/block_structure.h"
-#include "ceres/cxsparse.h"
+#include "ceres/internal/port.h"
#include "ceres/linear_solver.h"
#include "ceres/schur_eliminator.h"
-#include "ceres/suitesparse.h"
-#include "ceres/internal/scoped_ptr.h"
#include "ceres/types.h"
-#include "ceres/block_random_access_diagonal_matrix.h"
#ifdef CERES_USE_EIGEN_SPARSE
#include "Eigen/SparseCholesky"
@@ -57,6 +54,7 @@ namespace ceres {
namespace internal {
class BlockSparseMatrix;
+class SparseCholesky;
// Base class for Schur complement based linear least squares
// solvers. It assumes that the input linear system Ax = b can be
@@ -96,33 +94,37 @@ class BlockSparseMatrix;
// be used for problems with upto a few hundred cameras.
//
// SparseSchurComplementSolver: For problems where the Schur
-// complement matrix is large and sparse. It requires that
-// CHOLMOD/SuiteSparse be installed, as it uses CHOLMOD to find a
-// sparse Cholesky factorization of the Schur complement. This solver
-// can be used for solving structure from motion problems with tens of
-// thousands of cameras, though depending on the exact sparsity
-// structure, it maybe better to use an iterative solver.
+// complement matrix is large and sparse. It requires that Ceres be
+// build with at least one sparse linear algebra library, as it
+// computes a sparse Cholesky factorization of the Schur complement.
+//
+// This solver can be used for solving structure from motion problems
+// with tens of thousands of cameras, though depending on the exact
+// sparsity structure, it maybe better to use an iterative solver.
//
// The two solvers can be instantiated by calling
// LinearSolver::CreateLinearSolver with LinearSolver::Options::type
// set to DENSE_SCHUR and SPARSE_SCHUR
-// respectively. LinearSolver::Options::elimination_groups[0] should be
-// at least 1.
+// respectively. LinearSolver::Options::elimination_groups[0] should
+// be at least 1.
class SchurComplementSolver : public BlockSparseMatrixSolver {
public:
explicit SchurComplementSolver(const LinearSolver::Options& options)
: options_(options) {
CHECK_GT(options.elimination_groups.size(), 1);
CHECK_GT(options.elimination_groups[0], 0);
+ CHECK(options.context != NULL);
}
+ SchurComplementSolver(const SchurComplementSolver&) = delete;
+ void operator=(const SchurComplementSolver&) = delete;
// LinearSolver methods
virtual ~SchurComplementSolver() {}
- virtual LinearSolver::Summary SolveImpl(
+ LinearSolver::Summary SolveImpl(
BlockSparseMatrix* A,
const double* b,
const LinearSolver::PerSolveOptions& per_solve_options,
- double* x);
+ double* x) override;
protected:
const LinearSolver::Options& options() const { return options_; }
@@ -140,11 +142,9 @@ class SchurComplementSolver : public BlockSparseMatrixSolver {
LinearSolver::Options options_;
- scoped_ptr<SchurEliminatorBase> eliminator_;
- scoped_ptr<BlockRandomAccessMatrix> lhs_;
- scoped_array<double> rhs_;
-
- CERES_DISALLOW_COPY_AND_ASSIGN(SchurComplementSolver);
+ std::unique_ptr<SchurEliminatorBase> eliminator_;
+ std::unique_ptr<BlockRandomAccessMatrix> lhs_;
+ std::unique_ptr<double[]> rhs_;
};
// Dense Cholesky factorization based solver.
@@ -152,72 +152,40 @@ class DenseSchurComplementSolver : public SchurComplementSolver {
public:
explicit DenseSchurComplementSolver(const LinearSolver::Options& options)
: SchurComplementSolver(options) {}
+ DenseSchurComplementSolver(const DenseSchurComplementSolver&) = delete;
+ void operator=(const DenseSchurComplementSolver&) = delete;
+
virtual ~DenseSchurComplementSolver() {}
private:
- virtual void InitStorage(const CompressedRowBlockStructure* bs);
- virtual LinearSolver::Summary SolveReducedLinearSystem(
+ void InitStorage(const CompressedRowBlockStructure* bs) final;
+ LinearSolver::Summary SolveReducedLinearSystem(
const LinearSolver::PerSolveOptions& per_solve_options,
- double* solution);
-
- CERES_DISALLOW_COPY_AND_ASSIGN(DenseSchurComplementSolver);
+ double* solution) final;
};
// Sparse Cholesky factorization based solver.
class SparseSchurComplementSolver : public SchurComplementSolver {
public:
explicit SparseSchurComplementSolver(const LinearSolver::Options& options);
+ SparseSchurComplementSolver(const SparseSchurComplementSolver&) = delete;
+ void operator=(const SparseSchurComplementSolver&) = delete;
+
virtual ~SparseSchurComplementSolver();
private:
- virtual void InitStorage(const CompressedRowBlockStructure* bs);
- virtual LinearSolver::Summary SolveReducedLinearSystem(
- const LinearSolver::PerSolveOptions& per_solve_options,
- double* solution);
- LinearSolver::Summary SolveReducedLinearSystemUsingSuiteSparse(
+ void InitStorage(const CompressedRowBlockStructure* bs) final;
+ LinearSolver::Summary SolveReducedLinearSystem(
const LinearSolver::PerSolveOptions& per_solve_options,
- double* solution);
- LinearSolver::Summary SolveReducedLinearSystemUsingCXSparse(
- const LinearSolver::PerSolveOptions& per_solve_options,
- double* solution);
- LinearSolver::Summary SolveReducedLinearSystemUsingEigen(
- const LinearSolver::PerSolveOptions& per_solve_options,
- double* solution);
+ double* solution) final;
LinearSolver::Summary SolveReducedLinearSystemUsingConjugateGradients(
const LinearSolver::PerSolveOptions& per_solve_options,
double* solution);
// Size of the blocks in the Schur complement.
std::vector<int> blocks_;
-
- SuiteSparse ss_;
- // Symbolic factorization of the reduced linear system. Precomputed
- // once and reused in subsequent calls.
- cholmod_factor* factor_;
-
- CXSparse cxsparse_;
- // Cached factorization
- cs_dis* cxsparse_factor_;
-
-#ifdef CERES_USE_EIGEN_SPARSE
-
- // The preprocessor gymnastics here are dealing with the fact that
- // before version 3.2.2, Eigen did not support a third template
- // parameter to specify the ordering.
-#if EIGEN_VERSION_AT_LEAST(3,2,2)
- typedef Eigen::SimplicialLDLT<Eigen::SparseMatrix<double>, Eigen::Lower,
- Eigen::NaturalOrdering<int> >
- SimplicialLDLT;
-#else
- typedef Eigen::SimplicialLDLT<Eigen::SparseMatrix<double>, Eigen::Lower>
- SimplicialLDLT;
-#endif
-
- scoped_ptr<SimplicialLDLT> simplicial_ldlt_;
-#endif
-
- scoped_ptr<BlockRandomAccessDiagonalMatrix> preconditioner_;
- CERES_DISALLOW_COPY_AND_ASSIGN(SparseSchurComplementSolver);
+ std::unique_ptr<SparseCholesky> sparse_cholesky_;
+ std::unique_ptr<BlockRandomAccessDiagonalMatrix> preconditioner_;
};
} // namespace internal
diff --git a/extern/ceres/internal/ceres/schur_eliminator.cc b/extern/ceres/internal/ceres/schur_eliminator.cc
index ec0e2a020e5..bc8ced4bc7c 100644
--- a/extern/ceres/internal/ceres/schur_eliminator.cc
+++ b/extern/ceres/internal/ceres/schur_eliminator.cc
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2017 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -37,8 +37,7 @@
// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
//=========================================
//
-// This file is generated using generate_eliminator_specialization.py.
-// Editing it manually is not recommended.
+// This file is generated using generate_template_specializations.py.
#include "ceres/linear_solver.h"
#include "ceres/schur_eliminator.h"
@@ -50,106 +49,105 @@ namespace internal {
SchurEliminatorBase*
SchurEliminatorBase::Create(const LinearSolver::Options& options) {
#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
- if ((options.row_block_size == 2) &&
- (options.e_block_size == 2) &&
- (options.f_block_size == 2)) {
- return new SchurEliminator<2, 2, 2>(options);
- }
- if ((options.row_block_size == 2) &&
- (options.e_block_size == 2) &&
- (options.f_block_size == 3)) {
- return new SchurEliminator<2, 2, 3>(options);
- }
- if ((options.row_block_size == 2) &&
- (options.e_block_size == 2) &&
- (options.f_block_size == 4)) {
- return new SchurEliminator<2, 2, 4>(options);
- }
- if ((options.row_block_size == 2) &&
- (options.e_block_size == 2) &&
- (options.f_block_size == Eigen::Dynamic)) {
- return new SchurEliminator<2, 2, Eigen::Dynamic>(options);
- }
- if ((options.row_block_size == 2) &&
- (options.e_block_size == 3) &&
- (options.f_block_size == 3)) {
- return new SchurEliminator<2, 3, 3>(options);
- }
- if ((options.row_block_size == 2) &&
- (options.e_block_size == 3) &&
- (options.f_block_size == 4)) {
- return new SchurEliminator<2, 3, 4>(options);
- }
- if ((options.row_block_size == 2) &&
- (options.e_block_size == 3) &&
- (options.f_block_size == 6)) {
- return new SchurEliminator<2, 3, 6>(options);
- }
- if ((options.row_block_size == 2) &&
- (options.e_block_size == 3) &&
- (options.f_block_size == 9)) {
- return new SchurEliminator<2, 3, 9>(options);
- }
- if ((options.row_block_size == 2) &&
- (options.e_block_size == 3) &&
- (options.f_block_size == Eigen::Dynamic)) {
- return new SchurEliminator<2, 3, Eigen::Dynamic>(options);
- }
- if ((options.row_block_size == 2) &&
- (options.e_block_size == 4) &&
- (options.f_block_size == 3)) {
- return new SchurEliminator<2, 4, 3>(options);
- }
- if ((options.row_block_size == 2) &&
- (options.e_block_size == 4) &&
- (options.f_block_size == 4)) {
- return new SchurEliminator<2, 4, 4>(options);
- }
- if ((options.row_block_size == 2) &&
- (options.e_block_size == 4) &&
- (options.f_block_size == 8)) {
- return new SchurEliminator<2, 4, 8>(options);
- }
- if ((options.row_block_size == 2) &&
- (options.e_block_size == 4) &&
- (options.f_block_size == 9)) {
- return new SchurEliminator<2, 4, 9>(options);
- }
- if ((options.row_block_size == 2) &&
- (options.e_block_size == 4) &&
- (options.f_block_size == Eigen::Dynamic)) {
- return new SchurEliminator<2, 4, Eigen::Dynamic>(options);
- }
- if ((options.row_block_size == 2) &&
- (options.e_block_size == Eigen::Dynamic) &&
- (options.f_block_size == Eigen::Dynamic)) {
- return new SchurEliminator<2, Eigen::Dynamic, Eigen::Dynamic>(options);
- }
- if ((options.row_block_size == 4) &&
- (options.e_block_size == 4) &&
- (options.f_block_size == 2)) {
- return new SchurEliminator<4, 4, 2>(options);
- }
- if ((options.row_block_size == 4) &&
- (options.e_block_size == 4) &&
- (options.f_block_size == 3)) {
- return new SchurEliminator<4, 4, 3>(options);
- }
- if ((options.row_block_size == 4) &&
- (options.e_block_size == 4) &&
- (options.f_block_size == 4)) {
- return new SchurEliminator<4, 4, 4>(options);
- }
- if ((options.row_block_size == 4) &&
- (options.e_block_size == 4) &&
- (options.f_block_size == Eigen::Dynamic)) {
- return new SchurEliminator<4, 4, Eigen::Dynamic>(options);
- }
- if ((options.row_block_size == Eigen::Dynamic) &&
- (options.e_block_size == Eigen::Dynamic) &&
- (options.f_block_size == Eigen::Dynamic)) {
- return new SchurEliminator<Eigen::Dynamic, Eigen::Dynamic, Eigen::Dynamic>(options);
- }
+ if ((options.row_block_size == 2) &&
+ (options.e_block_size == 2) &&
+ (options.f_block_size == 2)) {
+ return new SchurEliminator<2, 2, 2>(options);
+ }
+ if ((options.row_block_size == 2) &&
+ (options.e_block_size == 2) &&
+ (options.f_block_size == 3)) {
+ return new SchurEliminator<2, 2, 3>(options);
+ }
+ if ((options.row_block_size == 2) &&
+ (options.e_block_size == 2) &&
+ (options.f_block_size == 4)) {
+ return new SchurEliminator<2, 2, 4>(options);
+ }
+ if ((options.row_block_size == 2) &&
+ (options.e_block_size == 2)) {
+ return new SchurEliminator<2, 2, Eigen::Dynamic>(options);
+ }
+ if ((options.row_block_size == 2) &&
+ (options.e_block_size == 3) &&
+ (options.f_block_size == 3)) {
+ return new SchurEliminator<2, 3, 3>(options);
+ }
+ if ((options.row_block_size == 2) &&
+ (options.e_block_size == 3) &&
+ (options.f_block_size == 4)) {
+ return new SchurEliminator<2, 3, 4>(options);
+ }
+ if ((options.row_block_size == 2) &&
+ (options.e_block_size == 3) &&
+ (options.f_block_size == 6)) {
+ return new SchurEliminator<2, 3, 6>(options);
+ }
+ if ((options.row_block_size == 2) &&
+ (options.e_block_size == 3) &&
+ (options.f_block_size == 9)) {
+ return new SchurEliminator<2, 3, 9>(options);
+ }
+ if ((options.row_block_size == 2) &&
+ (options.e_block_size == 3)) {
+ return new SchurEliminator<2, 3, Eigen::Dynamic>(options);
+ }
+ if ((options.row_block_size == 2) &&
+ (options.e_block_size == 4) &&
+ (options.f_block_size == 3)) {
+ return new SchurEliminator<2, 4, 3>(options);
+ }
+ if ((options.row_block_size == 2) &&
+ (options.e_block_size == 4) &&
+ (options.f_block_size == 4)) {
+ return new SchurEliminator<2, 4, 4>(options);
+ }
+ if ((options.row_block_size == 2) &&
+ (options.e_block_size == 4) &&
+ (options.f_block_size == 6)) {
+ return new SchurEliminator<2, 4, 6>(options);
+ }
+ if ((options.row_block_size == 2) &&
+ (options.e_block_size == 4) &&
+ (options.f_block_size == 8)) {
+ return new SchurEliminator<2, 4, 8>(options);
+ }
+ if ((options.row_block_size == 2) &&
+ (options.e_block_size == 4) &&
+ (options.f_block_size == 9)) {
+ return new SchurEliminator<2, 4, 9>(options);
+ }
+ if ((options.row_block_size == 2) &&
+ (options.e_block_size == 4)) {
+ return new SchurEliminator<2, 4, Eigen::Dynamic>(options);
+ }
+ if (options.row_block_size == 2){
+ return new SchurEliminator<2, Eigen::Dynamic, Eigen::Dynamic>(options);
+ }
+ if ((options.row_block_size == 3) &&
+ (options.e_block_size == 3) &&
+ (options.f_block_size == 3)) {
+ return new SchurEliminator<3, 3, 3>(options);
+ }
+ if ((options.row_block_size == 4) &&
+ (options.e_block_size == 4) &&
+ (options.f_block_size == 2)) {
+ return new SchurEliminator<4, 4, 2>(options);
+ }
+ if ((options.row_block_size == 4) &&
+ (options.e_block_size == 4) &&
+ (options.f_block_size == 3)) {
+ return new SchurEliminator<4, 4, 3>(options);
+ }
+ if ((options.row_block_size == 4) &&
+ (options.e_block_size == 4) &&
+ (options.f_block_size == 4)) {
+ return new SchurEliminator<4, 4, 4>(options);
+ }
+ if ((options.row_block_size == 4) &&
+ (options.e_block_size == 4)) {
+ return new SchurEliminator<4, 4, Eigen::Dynamic>(options);
+ }
#endif
VLOG(1) << "Template specializations not found for <"
diff --git a/extern/ceres/internal/ceres/schur_eliminator.h b/extern/ceres/internal/ceres/schur_eliminator.h
index 761b58adc7f..66fcb4d58e8 100644
--- a/extern/ceres/internal/ceres/schur_eliminator.h
+++ b/extern/ceres/internal/ceres/schur_eliminator.h
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2019 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -32,14 +32,17 @@
#define CERES_INTERNAL_SCHUR_ELIMINATOR_H_
#include <map>
+#include <memory>
+#include <mutex>
#include <vector>
-#include "ceres/mutex.h"
+
+#include "Eigen/Dense"
#include "ceres/block_random_access_matrix.h"
#include "ceres/block_sparse_matrix.h"
#include "ceres/block_structure.h"
-#include "ceres/linear_solver.h"
#include "ceres/internal/eigen.h"
-#include "ceres/internal/scoped_ptr.h"
+#include "ceres/internal/port.h"
+#include "ceres/linear_solver.h"
namespace ceres {
namespace internal {
@@ -50,7 +53,7 @@ namespace internal {
//
// E y + F z = b
//
-// Where x = [y;z] is a partition of the variables. The paritioning
+// Where x = [y;z] is a partition of the variables. The partitioning
// of the variables is such that, E'E is a block diagonal matrix. Or
// in other words, the parameter blocks in E form an independent set
// of the of the graph implied by the block matrix A'A. Then, this
@@ -147,7 +150,7 @@ namespace internal {
// Where the sum is over chunks and E_k'E_k is dense matrix of size y1
// x y1.
//
-// Advanced usage. Uptil now it has been assumed that the user would
+// Advanced usage. Until now it has been assumed that the user would
// be interested in all of the Schur Complement S. However, it is also
// possible to use this eliminator to obtain an arbitrary submatrix of
// the full Schur complement. When the eliminator is generating the
@@ -171,7 +174,14 @@ class SchurEliminatorBase {
// CompressedRowBlockStructure object passed to this method is the
// same one (or is equivalent to) the one associated with the
// BlockSparseMatrix objects below.
+ //
+ // assume_full_rank_ete controls how the eliminator inverts with the
+ // diagonal blocks corresponding to e blocks in A'A. If
+ // assume_full_rank_ete is true, then a Cholesky factorization is
+ // used to compute the inverse, otherwise a singular value
+ // decomposition is used to compute the pseudo inverse.
virtual void Init(int num_eliminate_blocks,
+ bool assume_full_rank_ete,
const CompressedRowBlockStructure* bs) = 0;
// Compute the Schur complement system from the augmented linear
@@ -185,7 +195,7 @@ class SchurEliminatorBase {
//
// Since the Schur complement is a symmetric matrix, only the upper
// triangular part of the Schur complement is computed.
- virtual void Eliminate(const BlockSparseMatrix* A,
+ virtual void Eliminate(const BlockSparseMatrixData& A,
const double* b,
const double* D,
BlockRandomAccessMatrix* lhs,
@@ -194,7 +204,7 @@ class SchurEliminatorBase {
// Given values for the variables z in the F block of A, solve for
// the optimal values of the variables y corresponding to the E
// block in A.
- virtual void BackSubstitute(const BlockSparseMatrix* A,
+ virtual void BackSubstitute(const BlockSparseMatrixData& A,
const double* b,
const double* D,
const double* z,
@@ -210,32 +220,31 @@ class SchurEliminatorBase {
// parameters as template arguments so that they are visible to the
// compiler and can be used for compile time optimization of the low
// level linear algebra routines.
-//
-// This implementation is mulithreaded using OpenMP. The level of
-// parallelism is controlled by LinearSolver::Options::num_threads.
template <int kRowBlockSize = Eigen::Dynamic,
int kEBlockSize = Eigen::Dynamic,
- int kFBlockSize = Eigen::Dynamic >
+ int kFBlockSize = Eigen::Dynamic>
class SchurEliminator : public SchurEliminatorBase {
public:
explicit SchurEliminator(const LinearSolver::Options& options)
- : num_threads_(options.num_threads) {
+ : num_threads_(options.num_threads), context_(options.context) {
+ CHECK(context_ != nullptr);
}
// SchurEliminatorBase Interface
virtual ~SchurEliminator();
- virtual void Init(int num_eliminate_blocks,
- const CompressedRowBlockStructure* bs);
- virtual void Eliminate(const BlockSparseMatrix* A,
- const double* b,
- const double* D,
- BlockRandomAccessMatrix* lhs,
- double* rhs);
- virtual void BackSubstitute(const BlockSparseMatrix* A,
- const double* b,
- const double* D,
- const double* z,
- double* y);
+ void Init(int num_eliminate_blocks,
+ bool assume_full_rank_ete,
+ const CompressedRowBlockStructure* bs) final;
+ void Eliminate(const BlockSparseMatrixData& A,
+ const double* b,
+ const double* D,
+ BlockRandomAccessMatrix* lhs,
+ double* rhs) final;
+ void BackSubstitute(const BlockSparseMatrixData& A,
+ const double* b,
+ const double* D,
+ const double* z,
+ double* y) final;
private:
// Chunk objects store combinatorial information needed to
@@ -273,7 +282,7 @@ class SchurEliminator : public SchurEliminatorBase {
void ChunkDiagonalBlockAndGradient(
const Chunk& chunk,
- const BlockSparseMatrix* A,
+ const BlockSparseMatrixData& A,
const double* b,
int row_block_counter,
typename EigenTypes<kEBlockSize, kEBlockSize>::Matrix* eet,
@@ -282,33 +291,36 @@ class SchurEliminator : public SchurEliminatorBase {
BlockRandomAccessMatrix* lhs);
void UpdateRhs(const Chunk& chunk,
- const BlockSparseMatrix* A,
+ const BlockSparseMatrixData& A,
const double* b,
int row_block_counter,
const double* inverse_ete_g,
double* rhs);
- void ChunkOuterProduct(const CompressedRowBlockStructure* bs,
+ void ChunkOuterProduct(int thread_id,
+ const CompressedRowBlockStructure* bs,
const Matrix& inverse_eet,
const double* buffer,
const BufferLayoutType& buffer_layout,
BlockRandomAccessMatrix* lhs);
- void EBlockRowOuterProduct(const BlockSparseMatrix* A,
+ void EBlockRowOuterProduct(const BlockSparseMatrixData& A,
int row_block_index,
BlockRandomAccessMatrix* lhs);
+ void NoEBlockRowsUpdate(const BlockSparseMatrixData& A,
+ const double* b,
+ int row_block_counter,
+ BlockRandomAccessMatrix* lhs,
+ double* rhs);
- void NoEBlockRowsUpdate(const BlockSparseMatrix* A,
- const double* b,
- int row_block_counter,
- BlockRandomAccessMatrix* lhs,
- double* rhs);
-
- void NoEBlockRowOuterProduct(const BlockSparseMatrix* A,
+ void NoEBlockRowOuterProduct(const BlockSparseMatrixData& A,
int row_block_index,
BlockRandomAccessMatrix* lhs);
+ int num_threads_;
+ ContextImpl* context_;
int num_eliminate_blocks_;
+ bool assume_full_rank_ete_;
// Block layout of the columns of the reduced linear system. Since
// the f blocks can be of varying size, this vector stores the
@@ -330,7 +342,7 @@ class SchurEliminator : public SchurEliminatorBase {
//
// [thread_id * buffer_size_ , (thread_id + 1) * buffer_size_]
//
- scoped_array<double> buffer_;
+ std::unique_ptr<double[]> buffer_;
// Buffer to store per thread matrix matrix products used by
// ChunkOuterProduct. Like buffer_ it is of size num_threads *
@@ -338,15 +350,275 @@ class SchurEliminator : public SchurEliminatorBase {
//
// [thread_id * buffer_size_ , (thread_id + 1) * buffer_size_ -1]
//
- scoped_array<double> chunk_outer_product_buffer_;
+ std::unique_ptr<double[]> chunk_outer_product_buffer_;
int buffer_size_;
- int num_threads_;
int uneliminated_row_begins_;
// Locks for the blocks in the right hand side of the reduced linear
// system.
- std::vector<Mutex*> rhs_locks_;
+ std::vector<std::mutex*> rhs_locks_;
+};
+
+// SchurEliminatorForOneFBlock specializes the SchurEliminatorBase interface for
+// the case where there is exactly one f-block and all three parameters
+// kRowBlockSize, kEBlockSize and KFBlockSize are known at compile time. This is
+// the case for some two view bundle adjustment problems which have very
+// stringent latency requirements.
+//
+// Under these assumptions, we can simplify the more general algorithm
+// implemented by SchurEliminatorImpl significantly. Two of the major
+// contributors to the increased performance are:
+//
+// 1. Simpler loop structure and less use of dynamic memory. Almost everything
+// is on the stack and benefits from aligned memory as well as fixed sized
+// vectorization. We are also able to reason about temporaries and control
+// their lifetimes better.
+// 2. Use of inverse() over llt().solve(Identity).
+template <int kRowBlockSize = Eigen::Dynamic,
+ int kEBlockSize = Eigen::Dynamic,
+ int kFBlockSize = Eigen::Dynamic>
+class SchurEliminatorForOneFBlock : public SchurEliminatorBase {
+ public:
+ virtual ~SchurEliminatorForOneFBlock() {}
+ void Init(int num_eliminate_blocks,
+ bool assume_full_rank_ete,
+ const CompressedRowBlockStructure* bs) override {
+ CHECK_GT(num_eliminate_blocks, 0)
+ << "SchurComplementSolver cannot be initialized with "
+ << "num_eliminate_blocks = 0.";
+ CHECK_EQ(bs->cols.size() - num_eliminate_blocks, 1);
+
+ num_eliminate_blocks_ = num_eliminate_blocks;
+ const int num_row_blocks = bs->rows.size();
+ chunks_.clear();
+ int r = 0;
+ // Iterate over the row blocks of A, and detect the chunks. The
+ // matrix should already have been ordered so that all rows
+ // containing the same y block are vertically contiguous.
+ while (r < num_row_blocks) {
+ const int e_block_id = bs->rows[r].cells.front().block_id;
+ if (e_block_id >= num_eliminate_blocks_) {
+ break;
+ }
+
+ chunks_.push_back(Chunk());
+ Chunk& chunk = chunks_.back();
+ chunk.num_rows = 0;
+ chunk.start = r;
+ // Add to the chunk until the first block in the row is
+ // different than the one in the first row for the chunk.
+ while (r + chunk.num_rows < num_row_blocks) {
+ const CompressedRow& row = bs->rows[r + chunk.num_rows];
+ if (row.cells.front().block_id != e_block_id) {
+ break;
+ }
+ ++chunk.num_rows;
+ }
+ r += chunk.num_rows;
+ }
+
+ const Chunk& last_chunk = chunks_.back();
+ uneliminated_row_begins_ = last_chunk.start + last_chunk.num_rows;
+ e_t_e_inverse_matrices_.resize(kEBlockSize * kEBlockSize * chunks_.size());
+ std::fill(
+ e_t_e_inverse_matrices_.begin(), e_t_e_inverse_matrices_.end(), 0.0);
+ }
+
+ void Eliminate(const BlockSparseMatrixData& A,
+ const double* b,
+ const double* D,
+ BlockRandomAccessMatrix* lhs_bram,
+ double* rhs_ptr) override {
+ // Since there is only one f-block, we can call GetCell once, and cache its
+ // output.
+ int r, c, row_stride, col_stride;
+ CellInfo* cell_info =
+ lhs_bram->GetCell(0, 0, &r, &c, &row_stride, &col_stride);
+ typename EigenTypes<kFBlockSize, kFBlockSize>::MatrixRef lhs(
+ cell_info->values, kFBlockSize, kFBlockSize);
+ typename EigenTypes<kFBlockSize>::VectorRef rhs(rhs_ptr, kFBlockSize);
+
+ lhs.setZero();
+ rhs.setZero();
+
+ const CompressedRowBlockStructure* bs = A.block_structure();
+ const double* values = A.values();
+
+ // Add the diagonal to the schur complement.
+ if (D != nullptr) {
+ typename EigenTypes<kFBlockSize>::ConstVectorRef diag(
+ D + bs->cols[num_eliminate_blocks_].position, kFBlockSize);
+ lhs.diagonal() = diag.array().square().matrix();
+ }
+
+ Eigen::Matrix<double, kEBlockSize, kFBlockSize> tmp;
+ Eigen::Matrix<double, kEBlockSize, 1> tmp2;
+
+ // The following loop works on a block matrix which looks as follows
+ // (number of rows can be anything):
+ //
+ // [e_1 | f_1] = [b1]
+ // [e_2 | f_2] = [b2]
+ // [e_3 | f_3] = [b3]
+ // [e_4 | f_4] = [b4]
+ //
+ // and computes the following
+ //
+ // e_t_e = sum_i e_i^T * e_i
+ // e_t_e_inverse = inverse(e_t_e)
+ // e_t_f = sum_i e_i^T f_i
+ // e_t_b = sum_i e_i^T b_i
+ // f_t_b = sum_i f_i^T b_i
+ //
+ // lhs += sum_i f_i^T * f_i - e_t_f^T * e_t_e_inverse * e_t_f
+ // rhs += f_t_b - e_t_f^T * e_t_e_inverse * e_t_b
+ for (int i = 0; i < chunks_.size(); ++i) {
+ const Chunk& chunk = chunks_[i];
+ const int e_block_id = bs->rows[chunk.start].cells.front().block_id;
+
+ // Naming covention, e_t_e = e_block.transpose() * e_block;
+ Eigen::Matrix<double, kEBlockSize, kEBlockSize> e_t_e;
+ Eigen::Matrix<double, kEBlockSize, kFBlockSize> e_t_f;
+ Eigen::Matrix<double, kEBlockSize, 1> e_t_b;
+ Eigen::Matrix<double, kFBlockSize, 1> f_t_b;
+
+ // Add the square of the diagonal to e_t_e.
+ if (D != NULL) {
+ const typename EigenTypes<kEBlockSize>::ConstVectorRef diag(
+ D + bs->cols[e_block_id].position, kEBlockSize);
+ e_t_e = diag.array().square().matrix().asDiagonal();
+ } else {
+ e_t_e.setZero();
+ }
+ e_t_f.setZero();
+ e_t_b.setZero();
+ f_t_b.setZero();
+
+ for (int j = 0; j < chunk.num_rows; ++j) {
+ const int row_id = chunk.start + j;
+ const auto& row = bs->rows[row_id];
+ const typename EigenTypes<kRowBlockSize, kEBlockSize>::ConstMatrixRef
+ e_block(values + row.cells[0].position, kRowBlockSize, kEBlockSize);
+ const typename EigenTypes<kRowBlockSize>::ConstVectorRef b_block(
+ b + row.block.position, kRowBlockSize);
+
+ e_t_e.noalias() += e_block.transpose() * e_block;
+ e_t_b.noalias() += e_block.transpose() * b_block;
+
+ if (row.cells.size() == 1) {
+ // There is no f block, so there is nothing more to do.
+ continue;
+ }
+
+ const typename EigenTypes<kRowBlockSize, kFBlockSize>::ConstMatrixRef
+ f_block(values + row.cells[1].position, kRowBlockSize, kFBlockSize);
+ e_t_f.noalias() += e_block.transpose() * f_block;
+ lhs.noalias() += f_block.transpose() * f_block;
+ f_t_b.noalias() += f_block.transpose() * b_block;
+ }
+
+ // BackSubstitute computes the same inverse, and this is the key workload
+ // there, so caching these inverses makes BackSubstitute essentially free.
+ typename EigenTypes<kEBlockSize, kEBlockSize>::MatrixRef e_t_e_inverse(
+ &e_t_e_inverse_matrices_[kEBlockSize * kEBlockSize * i],
+ kEBlockSize,
+ kEBlockSize);
+
+ // e_t_e is a symmetric positive definite matrix, so the standard way to
+ // compute its inverse is via the Cholesky factorization by calling
+ // e_t_e.llt().solve(Identity()). However, the inverse() method even
+ // though it is not optimized for symmetric matrices is significantly
+ // faster for small fixed size (up to 4x4) matrices.
+ //
+ // https://eigen.tuxfamily.org/dox/group__TutorialLinearAlgebra.html#title3
+ e_t_e_inverse.noalias() = e_t_e.inverse();
+
+ // The use of these two pre-allocated tmp vectors saves temporaries in the
+ // expressions for lhs and rhs updates below and has a significant impact
+ // on the performance of this method.
+ tmp.noalias() = e_t_e_inverse * e_t_f;
+ tmp2.noalias() = e_t_e_inverse * e_t_b;
+
+ lhs.noalias() -= e_t_f.transpose() * tmp;
+ rhs.noalias() += f_t_b - e_t_f.transpose() * tmp2;
+ }
+
+ // The rows without any e-blocks can have arbitrary size but only contain
+ // the f-block.
+ //
+ // lhs += f_i^T f_i
+ // rhs += f_i^T b_i
+ for (int row_id = uneliminated_row_begins_; row_id < bs->rows.size();
+ ++row_id) {
+ const auto& row = bs->rows[row_id];
+ const auto& cell = row.cells[0];
+ const typename EigenTypes<Eigen::Dynamic, kFBlockSize>::ConstMatrixRef
+ f_block(values + cell.position, row.block.size, kFBlockSize);
+ const typename EigenTypes<Eigen::Dynamic>::ConstVectorRef b_block(
+ b + row.block.position, row.block.size);
+ lhs.noalias() += f_block.transpose() * f_block;
+ rhs.noalias() += f_block.transpose() * b_block;
+ }
+ }
+
+ // This implementation of BackSubstitute depends on Eliminate being called
+ // before this. SchurComplementSolver always does this.
+ //
+ // y_i = e_t_e_inverse * sum_i e_i^T * (b_i - f_i * z);
+ void BackSubstitute(const BlockSparseMatrixData& A,
+ const double* b,
+ const double* D,
+ const double* z_ptr,
+ double* y) override {
+ typename EigenTypes<kFBlockSize>::ConstVectorRef z(z_ptr, kFBlockSize);
+ const CompressedRowBlockStructure* bs = A.block_structure();
+ const double* values = A.values();
+ Eigen::Matrix<double, kEBlockSize, 1> tmp;
+ for (int i = 0; i < chunks_.size(); ++i) {
+ const Chunk& chunk = chunks_[i];
+ const int e_block_id = bs->rows[chunk.start].cells.front().block_id;
+ tmp.setZero();
+ for (int j = 0; j < chunk.num_rows; ++j) {
+ const int row_id = chunk.start + j;
+ const auto& row = bs->rows[row_id];
+ const typename EigenTypes<kRowBlockSize, kEBlockSize>::ConstMatrixRef
+ e_block(values + row.cells[0].position, kRowBlockSize, kEBlockSize);
+ const typename EigenTypes<kRowBlockSize>::ConstVectorRef b_block(
+ b + row.block.position, kRowBlockSize);
+
+ if (row.cells.size() == 1) {
+ // There is no f block.
+ tmp += e_block.transpose() * b_block;
+ } else {
+ typename EigenTypes<kRowBlockSize, kFBlockSize>::ConstMatrixRef
+ f_block(
+ values + row.cells[1].position, kRowBlockSize, kFBlockSize);
+ tmp += e_block.transpose() * (b_block - f_block * z);
+ }
+ }
+
+ typename EigenTypes<kEBlockSize, kEBlockSize>::MatrixRef e_t_e_inverse(
+ &e_t_e_inverse_matrices_[kEBlockSize * kEBlockSize * i],
+ kEBlockSize,
+ kEBlockSize);
+
+ typename EigenTypes<kEBlockSize>::VectorRef y_block(
+ y + bs->cols[e_block_id].position, kEBlockSize);
+ y_block.noalias() = e_t_e_inverse * tmp;
+ }
+ }
+
+ private:
+ struct Chunk {
+ int start = 0;
+ int num_rows = 0;
+ };
+
+ std::vector<Chunk> chunks_;
+ int num_eliminate_blocks_;
+ int uneliminated_row_begins_;
+ std::vector<double> e_t_e_inverse_matrices_;
};
} // namespace internal
diff --git a/extern/ceres/internal/ceres/schur_eliminator_impl.h b/extern/ceres/internal/ceres/schur_eliminator_impl.h
index f2535880f15..bd0881eec1e 100644
--- a/extern/ceres/internal/ceres/schur_eliminator_impl.h
+++ b/extern/ceres/internal/ceres/schur_eliminator_impl.h
@@ -48,23 +48,23 @@
// This include must come before any #ifndef check on Ceres compile options.
#include "ceres/internal/port.h"
-#ifdef CERES_USE_OPENMP
-#include <omp.h>
-#endif
-
#include <algorithm>
#include <map>
+
+#include "Eigen/Dense"
#include "ceres/block_random_access_matrix.h"
#include "ceres/block_sparse_matrix.h"
#include "ceres/block_structure.h"
#include "ceres/internal/eigen.h"
#include "ceres/internal/fixed_array.h"
-#include "ceres/internal/scoped_ptr.h"
+#include "ceres/invert_psd_matrix.h"
#include "ceres/map_util.h"
+#include "ceres/parallel_for.h"
#include "ceres/schur_eliminator.h"
+#include "ceres/scoped_thread_token.h"
#include "ceres/small_blas.h"
#include "ceres/stl_util.h"
-#include "Eigen/Dense"
+#include "ceres/thread_token_provider.h"
#include "glog/logging.h"
namespace ceres {
@@ -76,14 +76,16 @@ SchurEliminator<kRowBlockSize, kEBlockSize, kFBlockSize>::~SchurEliminator() {
}
template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
-void
-SchurEliminator<kRowBlockSize, kEBlockSize, kFBlockSize>::
-Init(int num_eliminate_blocks, const CompressedRowBlockStructure* bs) {
+void SchurEliminator<kRowBlockSize, kEBlockSize, kFBlockSize>::Init(
+ int num_eliminate_blocks,
+ bool assume_full_rank_ete,
+ const CompressedRowBlockStructure* bs) {
CHECK_GT(num_eliminate_blocks, 0)
<< "SchurComplementSolver cannot be initialized with "
<< "num_eliminate_blocks = 0.";
num_eliminate_blocks_ = num_eliminate_blocks;
+ assume_full_rank_ete_ = assume_full_rank_ete;
const int num_col_blocks = bs->cols.size();
const int num_row_blocks = bs->rows.size();
@@ -102,6 +104,13 @@ Init(int num_eliminate_blocks, const CompressedRowBlockStructure* bs) {
lhs_num_rows += bs->cols[i].size;
}
+ // TODO(sameeragarwal): Now that we may have subset block structure,
+ // we need to make sure that we account for the fact that somep
+ // point blocks only have a "diagonal" row and nothing more.
+ //
+ // This likely requires a slightly different algorithm, which works
+ // off of the number of elimination blocks.
+
int r = 0;
// Iterate over the row blocks of A, and detect the chunks. The
// matrix should already have been ordered so that all rows
@@ -143,15 +152,12 @@ Init(int num_eliminate_blocks, const CompressedRowBlockStructure* bs) {
++chunk.size;
}
- CHECK_GT(chunk.size, 0);
+ CHECK_GT(chunk.size, 0); // This check will need to be resolved.
r += chunk.size;
}
const Chunk& chunk = chunks_.back();
uneliminated_row_begins_ = chunk.start + chunk.size;
- if (num_threads_ > 1) {
- random_shuffle(chunks_.begin(), chunks_.end());
- }
buffer_.reset(new double[buffer_size_ * num_threads_]);
@@ -163,46 +169,51 @@ Init(int num_eliminate_blocks, const CompressedRowBlockStructure* bs) {
STLDeleteElements(&rhs_locks_);
rhs_locks_.resize(num_col_blocks - num_eliminate_blocks_);
for (int i = 0; i < num_col_blocks - num_eliminate_blocks_; ++i) {
- rhs_locks_[i] = new Mutex;
+ rhs_locks_[i] = new std::mutex;
}
}
template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
void
SchurEliminator<kRowBlockSize, kEBlockSize, kFBlockSize>::
-Eliminate(const BlockSparseMatrix* A,
+Eliminate(const BlockSparseMatrixData& A,
const double* b,
const double* D,
BlockRandomAccessMatrix* lhs,
double* rhs) {
if (lhs->num_rows() > 0) {
lhs->SetZero();
- VectorRef(rhs, lhs->num_rows()).setZero();
+ if (rhs) {
+ VectorRef(rhs, lhs->num_rows()).setZero();
+ }
}
- const CompressedRowBlockStructure* bs = A->block_structure();
+ const CompressedRowBlockStructure* bs = A.block_structure();
const int num_col_blocks = bs->cols.size();
// Add the diagonal to the schur complement.
if (D != NULL) {
-#pragma omp parallel for num_threads(num_threads_) schedule(dynamic)
- for (int i = num_eliminate_blocks_; i < num_col_blocks; ++i) {
- const int block_id = i - num_eliminate_blocks_;
- int r, c, row_stride, col_stride;
- CellInfo* cell_info = lhs->GetCell(block_id, block_id,
- &r, &c,
- &row_stride, &col_stride);
- if (cell_info != NULL) {
- const int block_size = bs->cols[i].size;
- typename EigenTypes<Eigen::Dynamic>::ConstVectorRef
- diag(D + bs->cols[i].position, block_size);
-
- CeresMutexLock l(&cell_info->m);
- MatrixRef m(cell_info->values, row_stride, col_stride);
- m.block(r, c, block_size, block_size).diagonal()
- += diag.array().square().matrix();
- }
- }
+ ParallelFor(
+ context_,
+ num_eliminate_blocks_,
+ num_col_blocks,
+ num_threads_,
+ [&](int i) {
+ const int block_id = i - num_eliminate_blocks_;
+ int r, c, row_stride, col_stride;
+ CellInfo* cell_info = lhs->GetCell(block_id, block_id, &r, &c,
+ &row_stride, &col_stride);
+ if (cell_info != NULL) {
+ const int block_size = bs->cols[i].size;
+ typename EigenTypes<Eigen::Dynamic>::ConstVectorRef diag(
+ D + bs->cols[i].position, block_size);
+
+ std::lock_guard<std::mutex> l(cell_info->m);
+ MatrixRef m(cell_info->values, row_stride, col_stride);
+ m.block(r, c, block_size, block_size).diagonal() +=
+ diag.array().square().matrix();
+ }
+ });
}
// Eliminate y blocks one chunk at a time. For each chunk, compute
@@ -218,79 +229,78 @@ Eliminate(const BlockSparseMatrix* A,
// z blocks that share a row block/residual term with the y
// block. EliminateRowOuterProduct does the corresponding operation
// for the lhs of the reduced linear system.
-#pragma omp parallel for num_threads(num_threads_) schedule(dynamic)
- for (int i = 0; i < chunks_.size(); ++i) {
-#ifdef CERES_USE_OPENMP
- int thread_id = omp_get_thread_num();
-#else
- int thread_id = 0;
-#endif
- double* buffer = buffer_.get() + thread_id * buffer_size_;
- const Chunk& chunk = chunks_[i];
- const int e_block_id = bs->rows[chunk.start].cells.front().block_id;
- const int e_block_size = bs->cols[e_block_id].size;
-
- VectorRef(buffer, buffer_size_).setZero();
-
- typename EigenTypes<kEBlockSize, kEBlockSize>::Matrix
- ete(e_block_size, e_block_size);
+ ParallelFor(
+ context_,
+ 0,
+ int(chunks_.size()),
+ num_threads_,
+ [&](int thread_id, int i) {
+ double* buffer = buffer_.get() + thread_id * buffer_size_;
+ const Chunk& chunk = chunks_[i];
+ const int e_block_id = bs->rows[chunk.start].cells.front().block_id;
+ const int e_block_size = bs->cols[e_block_id].size;
+
+ VectorRef(buffer, buffer_size_).setZero();
+
+ typename EigenTypes<kEBlockSize, kEBlockSize>::Matrix
+ ete(e_block_size, e_block_size);
+
+ if (D != NULL) {
+ const typename EigenTypes<kEBlockSize>::ConstVectorRef
+ diag(D + bs->cols[e_block_id].position, e_block_size);
+ ete = diag.array().square().matrix().asDiagonal();
+ } else {
+ ete.setZero();
+ }
- if (D != NULL) {
- const typename EigenTypes<kEBlockSize>::ConstVectorRef
- diag(D + bs->cols[e_block_id].position, e_block_size);
- ete = diag.array().square().matrix().asDiagonal();
- } else {
- ete.setZero();
- }
+ FixedArray<double, 8> g(e_block_size);
+ typename EigenTypes<kEBlockSize>::VectorRef gref(g.data(),
+ e_block_size);
+ gref.setZero();
+
+ // We are going to be computing
+ //
+ // S += F'F - F'E(E'E)^{-1}E'F
+ //
+ // for each Chunk. The computation is broken down into a number of
+ // function calls as below.
+
+ // Compute the outer product of the e_blocks with themselves (ete
+ // = E'E). Compute the product of the e_blocks with the
+ // corresponding f_blocks (buffer = E'F), the gradient of the terms
+ // in this chunk (g) and add the outer product of the f_blocks to
+ // Schur complement (S += F'F).
+ ChunkDiagonalBlockAndGradient(
+ chunk, A, b, chunk.start, &ete, g.data(), buffer, lhs);
+
+ // Normally one wouldn't compute the inverse explicitly, but
+ // e_block_size will typically be a small number like 3, in
+ // which case its much faster to compute the inverse once and
+ // use it to multiply other matrices/vectors instead of doing a
+ // Solve call over and over again.
+ typename EigenTypes<kEBlockSize, kEBlockSize>::Matrix inverse_ete =
+ InvertPSDMatrix<kEBlockSize>(assume_full_rank_ete_, ete);
+
+ // For the current chunk compute and update the rhs of the reduced
+ // linear system.
+ //
+ // rhs = F'b - F'E(E'E)^(-1) E'b
+
+ if (rhs) {
+ FixedArray<double, 8> inverse_ete_g(e_block_size);
+ MatrixVectorMultiply<kEBlockSize, kEBlockSize, 0>(
+ inverse_ete.data(),
+ e_block_size,
+ e_block_size,
+ g.data(),
+ inverse_ete_g.data());
+ UpdateRhs(chunk, A, b, chunk.start, inverse_ete_g.data(), rhs);
+ }
- FixedArray<double, 8> g(e_block_size);
- typename EigenTypes<kEBlockSize>::VectorRef gref(g.get(), e_block_size);
- gref.setZero();
-
- // We are going to be computing
- //
- // S += F'F - F'E(E'E)^{-1}E'F
- //
- // for each Chunk. The computation is broken down into a number of
- // function calls as below.
-
- // Compute the outer product of the e_blocks with themselves (ete
- // = E'E). Compute the product of the e_blocks with the
- // corresonding f_blocks (buffer = E'F), the gradient of the terms
- // in this chunk (g) and add the outer product of the f_blocks to
- // Schur complement (S += F'F).
- ChunkDiagonalBlockAndGradient(
- chunk, A, b, chunk.start, &ete, g.get(), buffer, lhs);
-
- // Normally one wouldn't compute the inverse explicitly, but
- // e_block_size will typically be a small number like 3, in
- // which case its much faster to compute the inverse once and
- // use it to multiply other matrices/vectors instead of doing a
- // Solve call over and over again.
- typename EigenTypes<kEBlockSize, kEBlockSize>::Matrix inverse_ete =
- ete
- .template selfadjointView<Eigen::Upper>()
- .llt()
- .solve(Matrix::Identity(e_block_size, e_block_size));
-
- // For the current chunk compute and update the rhs of the reduced
- // linear system.
- //
- // rhs = F'b - F'E(E'E)^(-1) E'b
-
- FixedArray<double, 8> inverse_ete_g(e_block_size);
- MatrixVectorMultiply<kEBlockSize, kEBlockSize, 0>(
- inverse_ete.data(),
- e_block_size,
- e_block_size,
- g.get(),
- inverse_ete_g.get());
-
- UpdateRhs(chunk, A, b, chunk.start, inverse_ete_g.get(), rhs);
-
- // S -= F'E(E'E)^{-1}E'F
- ChunkOuterProduct(bs, inverse_ete, buffer, chunk.buffer_layout, lhs);
- }
+ // S -= F'E(E'E)^{-1}E'F
+ ChunkOuterProduct(
+ thread_id, bs, inverse_ete, buffer, chunk.buffer_layout, lhs);
+ });
// For rows with no e_blocks, the schur complement update reduces to
// S += F'F.
@@ -300,19 +310,25 @@ Eliminate(const BlockSparseMatrix* A,
template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
void
SchurEliminator<kRowBlockSize, kEBlockSize, kFBlockSize>::
-BackSubstitute(const BlockSparseMatrix* A,
+BackSubstitute(const BlockSparseMatrixData& A,
const double* b,
const double* D,
const double* z,
double* y) {
- const CompressedRowBlockStructure* bs = A->block_structure();
-#pragma omp parallel for num_threads(num_threads_) schedule(dynamic)
- for (int i = 0; i < chunks_.size(); ++i) {
+ const CompressedRowBlockStructure* bs = A.block_structure();
+ const double* values = A.values();
+
+ ParallelFor(
+ context_,
+ 0,
+ int(chunks_.size()),
+ num_threads_,
+ [&](int i) {
const Chunk& chunk = chunks_[i];
const int e_block_id = bs->rows[chunk.start].cells.front().block_id;
const int e_block_size = bs->cols[e_block_id].size;
- double* y_ptr = y + bs->cols[e_block_id].position;
+ double* y_ptr = y + bs->cols[e_block_id].position;
typename EigenTypes<kEBlockSize>::VectorRef y_block(y_ptr, e_block_size);
typename EigenTypes<kEBlockSize, kEBlockSize>::Matrix
@@ -325,7 +341,6 @@ BackSubstitute(const BlockSparseMatrix* A,
ete.setZero();
}
- const double* values = A->values();
for (int j = 0; j < chunk.size; ++j) {
const CompressedRow& row = bs->rows[chunk.start + j];
const Cell& e_cell = row.cells.front();
@@ -333,9 +348,9 @@ BackSubstitute(const BlockSparseMatrix* A,
FixedArray<double, 8> sj(row.block.size);
- typename EigenTypes<kRowBlockSize>::VectorRef(sj.get(), row.block.size) =
- typename EigenTypes<kRowBlockSize>::ConstVectorRef
- (b + bs->rows[chunk.start + j].block.position, row.block.size);
+ typename EigenTypes<kRowBlockSize>::VectorRef(sj.data(), row.block.size) =
+ typename EigenTypes<kRowBlockSize>::ConstVectorRef(
+ b + bs->rows[chunk.start + j].block.position, row.block.size);
for (int c = 1; c < row.cells.size(); ++c) {
const int f_block_id = row.cells[c].block_id;
@@ -345,23 +360,24 @@ BackSubstitute(const BlockSparseMatrix* A,
MatrixVectorMultiply<kRowBlockSize, kFBlockSize, -1>(
values + row.cells[c].position, row.block.size, f_block_size,
z + lhs_row_layout_[r_block],
- sj.get());
+ sj.data());
}
MatrixTransposeVectorMultiply<kRowBlockSize, kEBlockSize, 1>(
values + e_cell.position, row.block.size, e_block_size,
- sj.get(),
+ sj.data(),
y_ptr);
MatrixTransposeMatrixMultiply
<kRowBlockSize, kEBlockSize, kRowBlockSize, kEBlockSize, 1>(
- values + e_cell.position, row.block.size, e_block_size,
- values + e_cell.position, row.block.size, e_block_size,
- ete.data(), 0, 0, e_block_size, e_block_size);
+ values + e_cell.position, row.block.size, e_block_size,
+ values + e_cell.position, row.block.size, e_block_size,
+ ete.data(), 0, 0, e_block_size, e_block_size);
}
- ete.llt().solveInPlace(y_block);
- }
+ y_block =
+ InvertPSDMatrix<kEBlockSize>(assume_full_rank_ete_, ete) * y_block;
+ });
}
// Update the rhs of the reduced linear system. Compute
@@ -371,17 +387,17 @@ template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
void
SchurEliminator<kRowBlockSize, kEBlockSize, kFBlockSize>::
UpdateRhs(const Chunk& chunk,
- const BlockSparseMatrix* A,
+ const BlockSparseMatrixData& A,
const double* b,
int row_block_counter,
const double* inverse_ete_g,
double* rhs) {
- const CompressedRowBlockStructure* bs = A->block_structure();
+ const CompressedRowBlockStructure* bs = A.block_structure();
+ const double* values = A.values();
+
const int e_block_id = bs->rows[chunk.start].cells.front().block_id;
const int e_block_size = bs->cols[e_block_id].size;
-
int b_pos = bs->rows[row_block_counter].block.position;
- const double* values = A->values();
for (int j = 0; j < chunk.size; ++j) {
const CompressedRow& row = bs->rows[row_block_counter + j];
const Cell& e_cell = row.cells.front();
@@ -398,7 +414,7 @@ UpdateRhs(const Chunk& chunk,
const int block_id = row.cells[c].block_id;
const int block_size = bs->cols[block_id].size;
const int block = block_id - num_eliminate_blocks_;
- CeresMutexLock l(rhs_locks_[block]);
+ std::lock_guard<std::mutex> l(*rhs_locks_[block]);
MatrixTransposeVectorMultiply<kRowBlockSize, kFBlockSize, 1>(
values + row.cells[c].position,
row.block.size, block_size,
@@ -432,14 +448,15 @@ void
SchurEliminator<kRowBlockSize, kEBlockSize, kFBlockSize>::
ChunkDiagonalBlockAndGradient(
const Chunk& chunk,
- const BlockSparseMatrix* A,
+ const BlockSparseMatrixData& A,
const double* b,
int row_block_counter,
typename EigenTypes<kEBlockSize, kEBlockSize>::Matrix* ete,
double* g,
double* buffer,
BlockRandomAccessMatrix* lhs) {
- const CompressedRowBlockStructure* bs = A->block_structure();
+ const CompressedRowBlockStructure* bs = A.block_structure();
+ const double* values = A.values();
int b_pos = bs->rows[row_block_counter].block.position;
const int e_block_size = ete->rows();
@@ -448,7 +465,6 @@ ChunkDiagonalBlockAndGradient(
// contribution of its F blocks to the Schur complement, the
// contribution of its E block to the matrix EE' (ete), and the
// corresponding block in the gradient vector.
- const double* values = A->values();
for (int j = 0; j < chunk.size; ++j) {
const CompressedRow& row = bs->rows[row_block_counter + j];
@@ -464,12 +480,13 @@ ChunkDiagonalBlockAndGradient(
values + e_cell.position, row.block.size, e_block_size,
ete->data(), 0, 0, e_block_size, e_block_size);
- // g += E_i' b_i
- MatrixTransposeVectorMultiply<kRowBlockSize, kEBlockSize, 1>(
- values + e_cell.position, row.block.size, e_block_size,
- b + b_pos,
- g);
-
+ if (b) {
+ // g += E_i' b_i
+ MatrixTransposeVectorMultiply<kRowBlockSize, kEBlockSize, 1>(
+ values + e_cell.position, row.block.size, e_block_size,
+ b + b_pos,
+ g);
+ }
// buffer = E'F. This computation is done by iterating over the
// f_blocks for each row in the chunk.
@@ -495,7 +512,8 @@ ChunkDiagonalBlockAndGradient(
template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
void
SchurEliminator<kRowBlockSize, kEBlockSize, kFBlockSize>::
-ChunkOuterProduct(const CompressedRowBlockStructure* bs,
+ChunkOuterProduct(int thread_id,
+ const CompressedRowBlockStructure* bs,
const Matrix& inverse_ete,
const double* buffer,
const BufferLayoutType& buffer_layout,
@@ -507,11 +525,6 @@ ChunkOuterProduct(const CompressedRowBlockStructure* bs,
const int e_block_size = inverse_ete.rows();
BufferLayoutType::const_iterator it1 = buffer_layout.begin();
-#ifdef CERES_USE_OPENMP
- int thread_id = omp_get_thread_num();
-#else
- int thread_id = 0;
-#endif
double* b1_transpose_inverse_ete =
chunk_outer_product_buffer_.get() + thread_id * buffer_size_;
@@ -535,7 +548,7 @@ ChunkOuterProduct(const CompressedRowBlockStructure* bs,
&row_stride, &col_stride);
if (cell_info != NULL) {
const int block2_size = bs->cols[it2->first].size;
- CeresMutexLock l(&cell_info->m);
+ std::lock_guard<std::mutex> l(cell_info->m);
MatrixMatrixMultiply
<kFBlockSize, kEBlockSize, kEBlockSize, kFBlockSize, -1>(
b1_transpose_inverse_ete, block1_size, e_block_size,
@@ -552,14 +565,18 @@ ChunkOuterProduct(const CompressedRowBlockStructure* bs,
template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
void
SchurEliminator<kRowBlockSize, kEBlockSize, kFBlockSize>::
-NoEBlockRowsUpdate(const BlockSparseMatrix* A,
+NoEBlockRowsUpdate(const BlockSparseMatrixData& A,
const double* b,
int row_block_counter,
BlockRandomAccessMatrix* lhs,
double* rhs) {
- const CompressedRowBlockStructure* bs = A->block_structure();
- const double* values = A->values();
+ const CompressedRowBlockStructure* bs = A.block_structure();
+ const double* values = A.values();
for (; row_block_counter < bs->rows.size(); ++row_block_counter) {
+ NoEBlockRowOuterProduct(A, row_block_counter, lhs);
+ if (!rhs) {
+ continue;
+ }
const CompressedRow& row = bs->rows[row_block_counter];
for (int c = 0; c < row.cells.size(); ++c) {
const int block_id = row.cells[c].block_id;
@@ -570,7 +587,6 @@ NoEBlockRowsUpdate(const BlockSparseMatrix* A,
b + row.block.position,
rhs + lhs_row_layout_[block]);
}
- NoEBlockRowOuterProduct(A, row_block_counter, lhs);
}
}
@@ -582,7 +598,7 @@ NoEBlockRowsUpdate(const BlockSparseMatrix* A,
// one difference. It does not use any of the template
// parameters. This is because the algorithm used for detecting the
// static structure of the matrix A only pays attention to rows with
-// e_blocks. This is becase rows without e_blocks are rare and
+// e_blocks. This is because rows without e_blocks are rare and
// typically arise from regularization terms in the original
// optimization problem, and have a very different structure than the
// rows with e_blocks. Including them in the static structure
@@ -592,12 +608,13 @@ NoEBlockRowsUpdate(const BlockSparseMatrix* A,
template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
void
SchurEliminator<kRowBlockSize, kEBlockSize, kFBlockSize>::
-NoEBlockRowOuterProduct(const BlockSparseMatrix* A,
+NoEBlockRowOuterProduct(const BlockSparseMatrixData& A,
int row_block_index,
BlockRandomAccessMatrix* lhs) {
- const CompressedRowBlockStructure* bs = A->block_structure();
+ const CompressedRowBlockStructure* bs = A.block_structure();
+ const double* values = A.values();
+
const CompressedRow& row = bs->rows[row_block_index];
- const double* values = A->values();
for (int i = 0; i < row.cells.size(); ++i) {
const int block1 = row.cells[i].block_id - num_eliminate_blocks_;
DCHECK_GE(block1, 0);
@@ -608,7 +625,7 @@ NoEBlockRowOuterProduct(const BlockSparseMatrix* A,
&r, &c,
&row_stride, &col_stride);
if (cell_info != NULL) {
- CeresMutexLock l(&cell_info->m);
+ std::lock_guard<std::mutex> l(cell_info->m);
// This multiply currently ignores the fact that this is a
// symmetric outer product.
MatrixTransposeMatrixMultiply
@@ -628,7 +645,7 @@ NoEBlockRowOuterProduct(const BlockSparseMatrix* A,
&row_stride, &col_stride);
if (cell_info != NULL) {
const int block2_size = bs->cols[row.cells[j].block_id].size;
- CeresMutexLock l(&cell_info->m);
+ std::lock_guard<std::mutex> l(cell_info->m);
MatrixTransposeMatrixMultiply
<Eigen::Dynamic, Eigen::Dynamic, Eigen::Dynamic, Eigen::Dynamic, 1>(
values + row.cells[i].position, row.block.size, block1_size,
@@ -639,18 +656,19 @@ NoEBlockRowOuterProduct(const BlockSparseMatrix* A,
}
}
-// For a row with an e_block, compute the contribition S += F'F. This
+// For a row with an e_block, compute the contribution S += F'F. This
// function has the same structure as NoEBlockRowOuterProduct, except
// that this function uses the template parameters.
template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
void
SchurEliminator<kRowBlockSize, kEBlockSize, kFBlockSize>::
-EBlockRowOuterProduct(const BlockSparseMatrix* A,
+EBlockRowOuterProduct(const BlockSparseMatrixData& A,
int row_block_index,
BlockRandomAccessMatrix* lhs) {
- const CompressedRowBlockStructure* bs = A->block_structure();
+ const CompressedRowBlockStructure* bs = A.block_structure();
+ const double* values = A.values();
+
const CompressedRow& row = bs->rows[row_block_index];
- const double* values = A->values();
for (int i = 1; i < row.cells.size(); ++i) {
const int block1 = row.cells[i].block_id - num_eliminate_blocks_;
DCHECK_GE(block1, 0);
@@ -661,7 +679,7 @@ EBlockRowOuterProduct(const BlockSparseMatrix* A,
&r, &c,
&row_stride, &col_stride);
if (cell_info != NULL) {
- CeresMutexLock l(&cell_info->m);
+ std::lock_guard<std::mutex> l(cell_info->m);
// block += b1.transpose() * b1;
MatrixTransposeMatrixMultiply
<kRowBlockSize, kFBlockSize, kRowBlockSize, kFBlockSize, 1>(
@@ -681,7 +699,7 @@ EBlockRowOuterProduct(const BlockSparseMatrix* A,
&row_stride, &col_stride);
if (cell_info != NULL) {
// block += b1.transpose() * b2;
- CeresMutexLock l(&cell_info->m);
+ std::lock_guard<std::mutex> l(cell_info->m);
MatrixTransposeMatrixMultiply
<kRowBlockSize, kFBlockSize, kRowBlockSize, kFBlockSize, 1>(
values + row.cells[i].position, row.block.size, block1_size,
diff --git a/extern/ceres/internal/ceres/generate_eliminator_specialization.py b/extern/ceres/internal/ceres/schur_eliminator_template.py
index e89e7a48c98..2f38cf5ad8f 100644
--- a/extern/ceres/internal/ceres/generate_eliminator_specialization.py
+++ b/extern/ceres/internal/ceres/schur_eliminator_template.py
@@ -1,5 +1,5 @@
# Ceres Solver - A fast non-linear least squares minimizer
-# Copyright 2015 Google Inc. All rights reserved.
+# Copyright 2017 Google Inc. All rights reserved.
# http://ceres-solver.org/
#
# Redistribution and use in source and binary forms, with or without
@@ -49,28 +49,9 @@
# specializations that is generated.
# Set of template specializations to generate
-SPECIALIZATIONS = [(2, 2, 2),
- (2, 2, 3),
- (2, 2, 4),
- (2, 2, "Eigen::Dynamic"),
- (2, 3, 3),
- (2, 3, 4),
- (2, 3, 6),
- (2, 3, 9),
- (2, 3, "Eigen::Dynamic"),
- (2, 4, 3),
- (2, 4, 4),
- (2, 4, 8),
- (2, 4, 9),
- (2, 4, "Eigen::Dynamic"),
- (2, "Eigen::Dynamic", "Eigen::Dynamic"),
- (4, 4, 2),
- (4, 4, 3),
- (4, 4, 4),
- (4, 4, "Eigen::Dynamic"),
- ("Eigen::Dynamic", "Eigen::Dynamic", "Eigen::Dynamic")]
+
HEADER = """// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2017 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -108,8 +89,7 @@ HEADER = """// Ceres Solver - A fast non-linear least squares minimizer
// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
//=========================================
//
-// This file is generated using generate_eliminator_specialization.py.
-// Editing it manually is not recommended.
+// This file is generated using generate_template_specializations.py.
"""
DYNAMIC_FILE = """
@@ -159,12 +139,7 @@ SchurEliminatorBase::Create(const LinearSolver::Options& options) {
#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
"""
-FACTORY_CONDITIONAL = """ if ((options.row_block_size == %s) &&
- (options.e_block_size == %s) &&
- (options.f_block_size == %s)) {
- return new SchurEliminator<%s, %s, %s>(options);
- }
-"""
+FACTORY = """ return new SchurEliminator<%s, %s, %s>(options);"""
FACTORY_FOOTER = """
#endif
@@ -178,54 +153,3 @@ FACTORY_FOOTER = """
} // namespace internal
} // namespace ceres
"""
-
-
-def SuffixForSize(size):
- if size == "Eigen::Dynamic":
- return "d"
- return str(size)
-
-
-def SpecializationFilename(prefix, row_block_size, e_block_size, f_block_size):
- return "_".join([prefix] + map(SuffixForSize, (row_block_size,
- e_block_size,
- f_block_size)))
-
-
-def Specialize():
- """
- Generate specialization code and the conditionals to instantiate it.
- """
- f = open("schur_eliminator.cc", "w")
- f.write(HEADER)
- f.write(FACTORY_FILE_HEADER)
-
- for row_block_size, e_block_size, f_block_size in SPECIALIZATIONS:
- output = SpecializationFilename("generated/schur_eliminator",
- row_block_size,
- e_block_size,
- f_block_size) + ".cc"
- fptr = open(output, "w")
- fptr.write(HEADER)
-
- template = SPECIALIZATION_FILE
- if (row_block_size == "Eigen::Dynamic" and
- e_block_size == "Eigen::Dynamic" and
- f_block_size == "Eigen::Dynamic"):
- template = DYNAMIC_FILE
-
- fptr.write(template % (row_block_size, e_block_size, f_block_size))
- fptr.close()
-
- f.write(FACTORY_CONDITIONAL % (row_block_size,
- e_block_size,
- f_block_size,
- row_block_size,
- e_block_size,
- f_block_size))
- f.write(FACTORY_FOOTER)
- f.close()
-
-
-if __name__ == "__main__":
- Specialize()
diff --git a/extern/ceres/internal/ceres/schur_jacobi_preconditioner.cc b/extern/ceres/internal/ceres/schur_jacobi_preconditioner.cc
index 3e6cc90f63c..89d770b405a 100644
--- a/extern/ceres/internal/ceres/schur_jacobi_preconditioner.cc
+++ b/extern/ceres/internal/ceres/schur_jacobi_preconditioner.cc
@@ -32,10 +32,9 @@
#include <utility>
#include <vector>
+
#include "ceres/block_random_access_diagonal_matrix.h"
#include "ceres/block_sparse_matrix.h"
-#include "ceres/collections_port.h"
-#include "ceres/internal/scoped_ptr.h"
#include "ceres/linear_solver.h"
#include "ceres/schur_eliminator.h"
#include "glog/logging.h"
@@ -50,9 +49,9 @@ SchurJacobiPreconditioner::SchurJacobiPreconditioner(
CHECK_GT(options_.elimination_groups.size(), 1);
CHECK_GT(options_.elimination_groups[0], 0);
const int num_blocks = bs.cols.size() - options_.elimination_groups[0];
- CHECK_GT(num_blocks, 0)
- << "Jacobian should have atleast 1 f_block for "
- << "SCHUR_JACOBI preconditioner.";
+ CHECK_GT(num_blocks, 0) << "Jacobian should have at least 1 f_block for "
+ << "SCHUR_JACOBI preconditioner.";
+ CHECK(options_.context != NULL);
std::vector<int> blocks(num_blocks);
for (int i = 0; i < num_blocks; ++i) {
@@ -63,8 +62,7 @@ SchurJacobiPreconditioner::SchurJacobiPreconditioner(
InitEliminator(bs);
}
-SchurJacobiPreconditioner::~SchurJacobiPreconditioner() {
-}
+SchurJacobiPreconditioner::~SchurJacobiPreconditioner() {}
// Initialize the SchurEliminator.
void SchurJacobiPreconditioner::InitEliminator(
@@ -75,8 +73,11 @@ void SchurJacobiPreconditioner::InitEliminator(
eliminator_options.e_block_size = options_.e_block_size;
eliminator_options.f_block_size = options_.f_block_size;
eliminator_options.row_block_size = options_.row_block_size;
+ eliminator_options.context = options_.context;
eliminator_.reset(SchurEliminatorBase::Create(eliminator_options));
- eliminator_->Init(eliminator_options.elimination_groups[0], &bs);
+ const bool kFullRankETE = true;
+ eliminator_->Init(
+ eliminator_options.elimination_groups[0], kFullRankETE, &bs);
}
// Update the values of the preconditioner matrix and factorize it.
@@ -85,19 +86,9 @@ bool SchurJacobiPreconditioner::UpdateImpl(const BlockSparseMatrix& A,
const int num_rows = m_->num_rows();
CHECK_GT(num_rows, 0);
- // We need a dummy rhs vector and a dummy b vector since the Schur
- // eliminator combines the computation of the reduced camera matrix
- // with the computation of the right hand side of that linear
- // system.
- //
- // TODO(sameeragarwal): Perhaps its worth refactoring the
- // SchurEliminator::Eliminate function to allow NULL for the rhs. As
- // of now it does not seem to be worth the effort.
- Vector rhs = Vector::Zero(m_->num_rows());
- Vector b = Vector::Zero(A.num_rows());
-
// Compute a subset of the entries of the Schur complement.
- eliminator_->Eliminate(&A, b.data(), D, m_.get(), rhs.data());
+ eliminator_->Eliminate(
+ BlockSparseMatrixData(A), nullptr, D, m_.get(), nullptr);
m_->Invert();
return true;
}
@@ -107,9 +98,7 @@ void SchurJacobiPreconditioner::RightMultiply(const double* x,
m_->RightMultiply(x, y);
}
-int SchurJacobiPreconditioner::num_rows() const {
- return m_->num_rows();
-}
+int SchurJacobiPreconditioner::num_rows() const { return m_->num_rows(); }
} // namespace internal
} // namespace ceres
diff --git a/extern/ceres/internal/ceres/schur_jacobi_preconditioner.h b/extern/ceres/internal/ceres/schur_jacobi_preconditioner.h
index 5398f3ff35d..372b790b82f 100644
--- a/extern/ceres/internal/ceres/schur_jacobi_preconditioner.h
+++ b/extern/ceres/internal/ceres/schur_jacobi_preconditioner.h
@@ -38,12 +38,11 @@
#ifndef CERES_INTERNAL_SCHUR_JACOBI_PRECONDITIONER_H_
#define CERES_INTERNAL_SCHUR_JACOBI_PRECONDITIONER_H_
+#include <memory>
#include <set>
-#include <vector>
#include <utility>
-#include "ceres/collections_port.h"
-#include "ceres/internal/macros.h"
-#include "ceres/internal/scoped_ptr.h"
+#include <vector>
+
#include "ceres/preconditioner.h"
namespace ceres {
@@ -83,21 +82,23 @@ class SchurJacobiPreconditioner : public BlockSparseMatrixPreconditioner {
// based solvers. Please see schur_eliminator.h for more details.
SchurJacobiPreconditioner(const CompressedRowBlockStructure& bs,
const Preconditioner::Options& options);
+ SchurJacobiPreconditioner(const SchurJacobiPreconditioner&) = delete;
+ void operator=(const SchurJacobiPreconditioner&) = delete;
+
virtual ~SchurJacobiPreconditioner();
// Preconditioner interface.
- virtual void RightMultiply(const double* x, double* y) const;
- virtual int num_rows() const;
+ void RightMultiply(const double* x, double* y) const final;
+ int num_rows() const final;
private:
void InitEliminator(const CompressedRowBlockStructure& bs);
- virtual bool UpdateImpl(const BlockSparseMatrix& A, const double* D);
+ bool UpdateImpl(const BlockSparseMatrix& A, const double* D) final;
Preconditioner::Options options_;
- scoped_ptr<SchurEliminatorBase> eliminator_;
+ std::unique_ptr<SchurEliminatorBase> eliminator_;
// Preconditioner matrix.
- scoped_ptr<BlockRandomAccessDiagonalMatrix> m_;
- CERES_DISALLOW_COPY_AND_ASSIGN(SchurJacobiPreconditioner);
+ std::unique_ptr<BlockRandomAccessDiagonalMatrix> m_;
};
} // namespace internal
diff --git a/extern/ceres/internal/ceres/schur_templates.cc b/extern/ceres/internal/ceres/schur_templates.cc
new file mode 100644
index 00000000000..01528619b1b
--- /dev/null
+++ b/extern/ceres/internal/ceres/schur_templates.cc
@@ -0,0 +1,227 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2017 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// What template specializations are available.
+//
+// ========================================
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+//=========================================
+//
+// This file is generated using generate_template_specializations.py.
+
+#include "ceres/internal/eigen.h"
+#include "ceres/schur_templates.h"
+
+namespace ceres {
+namespace internal {
+
+void GetBestSchurTemplateSpecialization(int* row_block_size,
+ int* e_block_size,
+ int* f_block_size) {
+ LinearSolver::Options options;
+ options.row_block_size = *row_block_size;
+ options.e_block_size = *e_block_size;
+ options.f_block_size = *f_block_size;
+ *row_block_size = Eigen::Dynamic;
+ *e_block_size = Eigen::Dynamic;
+ *f_block_size = Eigen::Dynamic;
+#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
+ if ((options.row_block_size == 2) &&
+ (options.e_block_size == 2) &&
+ (options.f_block_size == 2)) {
+ *row_block_size = 2;
+ *e_block_size = 2;
+ *f_block_size = 2;
+ return;
+ }
+ if ((options.row_block_size == 2) &&
+ (options.e_block_size == 2) &&
+ (options.f_block_size == 3)) {
+ *row_block_size = 2;
+ *e_block_size = 2;
+ *f_block_size = 3;
+ return;
+ }
+ if ((options.row_block_size == 2) &&
+ (options.e_block_size == 2) &&
+ (options.f_block_size == 4)) {
+ *row_block_size = 2;
+ *e_block_size = 2;
+ *f_block_size = 4;
+ return;
+ }
+ if ((options.row_block_size == 2) &&
+ (options.e_block_size == 2)) {
+ *row_block_size = 2;
+ *e_block_size = 2;
+ *f_block_size = Eigen::Dynamic;
+ return;
+ }
+ if ((options.row_block_size == 2) &&
+ (options.e_block_size == 3) &&
+ (options.f_block_size == 3)) {
+ *row_block_size = 2;
+ *e_block_size = 3;
+ *f_block_size = 3;
+ return;
+ }
+ if ((options.row_block_size == 2) &&
+ (options.e_block_size == 3) &&
+ (options.f_block_size == 4)) {
+ *row_block_size = 2;
+ *e_block_size = 3;
+ *f_block_size = 4;
+ return;
+ }
+ if ((options.row_block_size == 2) &&
+ (options.e_block_size == 3) &&
+ (options.f_block_size == 6)) {
+ *row_block_size = 2;
+ *e_block_size = 3;
+ *f_block_size = 6;
+ return;
+ }
+ if ((options.row_block_size == 2) &&
+ (options.e_block_size == 3) &&
+ (options.f_block_size == 9)) {
+ *row_block_size = 2;
+ *e_block_size = 3;
+ *f_block_size = 9;
+ return;
+ }
+ if ((options.row_block_size == 2) &&
+ (options.e_block_size == 3)) {
+ *row_block_size = 2;
+ *e_block_size = 3;
+ *f_block_size = Eigen::Dynamic;
+ return;
+ }
+ if ((options.row_block_size == 2) &&
+ (options.e_block_size == 4) &&
+ (options.f_block_size == 3)) {
+ *row_block_size = 2;
+ *e_block_size = 4;
+ *f_block_size = 3;
+ return;
+ }
+ if ((options.row_block_size == 2) &&
+ (options.e_block_size == 4) &&
+ (options.f_block_size == 4)) {
+ *row_block_size = 2;
+ *e_block_size = 4;
+ *f_block_size = 4;
+ return;
+ }
+ if ((options.row_block_size == 2) &&
+ (options.e_block_size == 4) &&
+ (options.f_block_size == 6)) {
+ *row_block_size = 2;
+ *e_block_size = 4;
+ *f_block_size = 6;
+ return;
+ }
+ if ((options.row_block_size == 2) &&
+ (options.e_block_size == 4) &&
+ (options.f_block_size == 8)) {
+ *row_block_size = 2;
+ *e_block_size = 4;
+ *f_block_size = 8;
+ return;
+ }
+ if ((options.row_block_size == 2) &&
+ (options.e_block_size == 4) &&
+ (options.f_block_size == 9)) {
+ *row_block_size = 2;
+ *e_block_size = 4;
+ *f_block_size = 9;
+ return;
+ }
+ if ((options.row_block_size == 2) &&
+ (options.e_block_size == 4)) {
+ *row_block_size = 2;
+ *e_block_size = 4;
+ *f_block_size = Eigen::Dynamic;
+ return;
+ }
+ if (options.row_block_size == 2){
+ *row_block_size = 2;
+ *e_block_size = Eigen::Dynamic;
+ *f_block_size = Eigen::Dynamic;
+ return;
+ }
+ if ((options.row_block_size == 3) &&
+ (options.e_block_size == 3) &&
+ (options.f_block_size == 3)) {
+ *row_block_size = 3;
+ *e_block_size = 3;
+ *f_block_size = 3;
+ return;
+ }
+ if ((options.row_block_size == 4) &&
+ (options.e_block_size == 4) &&
+ (options.f_block_size == 2)) {
+ *row_block_size = 4;
+ *e_block_size = 4;
+ *f_block_size = 2;
+ return;
+ }
+ if ((options.row_block_size == 4) &&
+ (options.e_block_size == 4) &&
+ (options.f_block_size == 3)) {
+ *row_block_size = 4;
+ *e_block_size = 4;
+ *f_block_size = 3;
+ return;
+ }
+ if ((options.row_block_size == 4) &&
+ (options.e_block_size == 4) &&
+ (options.f_block_size == 4)) {
+ *row_block_size = 4;
+ *e_block_size = 4;
+ *f_block_size = 4;
+ return;
+ }
+ if ((options.row_block_size == 4) &&
+ (options.e_block_size == 4)) {
+ *row_block_size = 4;
+ *e_block_size = 4;
+ *f_block_size = Eigen::Dynamic;
+ return;
+ }
+
+#endif
+ return;
+}
+
+} // namespace internal
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/schur_templates.h b/extern/ceres/internal/ceres/schur_templates.h
new file mode 100644
index 00000000000..90aee0a1afc
--- /dev/null
+++ b/extern/ceres/internal/ceres/schur_templates.h
@@ -0,0 +1,46 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2017 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+
+#ifndef CERES_INTERNAL_SCHUR_TEMPLATES_H_
+#define CERES_INTERNAL_SCHUR_TEMPLATES_H_
+
+#include "ceres/linear_solver.h"
+
+namespace ceres {
+namespace internal {
+
+void GetBestSchurTemplateSpecialization(int* row_block_size,
+ int* e_block_size,
+ int* f_block_size);
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_SCHUR_TEMPLATES_H_
diff --git a/extern/ceres/internal/ceres/scoped_thread_token.h b/extern/ceres/internal/ceres/scoped_thread_token.h
new file mode 100644
index 00000000000..c167397cce9
--- /dev/null
+++ b/extern/ceres/internal/ceres/scoped_thread_token.h
@@ -0,0 +1,61 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2017 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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.
+//
+// Author: yp@photonscore.de (Yury Prokazov)
+
+#ifndef CERES_INTERNAL_SCOPED_THREAD_TOKEN_H_
+#define CERES_INTERNAL_SCOPED_THREAD_TOKEN_H_
+
+#include "ceres/thread_token_provider.h"
+
+namespace ceres {
+namespace internal {
+
+// Helper class for ThreadTokenProvider. This object acquires a token in its
+// constructor and puts that token back with destruction.
+class ScopedThreadToken {
+ public:
+ ScopedThreadToken(ThreadTokenProvider* provider)
+ : provider_(provider), token_(provider->Acquire()) {}
+
+ ~ScopedThreadToken() { provider_->Release(token_); }
+
+ int token() const { return token_; }
+
+ private:
+ ThreadTokenProvider* provider_;
+ int token_;
+
+ ScopedThreadToken(ScopedThreadToken&);
+ ScopedThreadToken& operator=(ScopedThreadToken&);
+};
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_SCOPED_THREAD_TOKEN_H_
diff --git a/extern/ceres/internal/ceres/scratch_evaluate_preparer.h b/extern/ceres/internal/ceres/scratch_evaluate_preparer.h
index fa9ebd0e50e..c8d9b937b47 100644
--- a/extern/ceres/internal/ceres/scratch_evaluate_preparer.h
+++ b/extern/ceres/internal/ceres/scratch_evaluate_preparer.h
@@ -35,7 +35,7 @@
#ifndef CERES_INTERNAL_SCRATCH_EVALUATE_PREPARER_H_
#define CERES_INTERNAL_SCRATCH_EVALUATE_PREPARER_H_
-#include "ceres/internal/scoped_ptr.h"
+#include <memory>
namespace ceres {
namespace internal {
@@ -60,7 +60,7 @@ class ScratchEvaluatePreparer {
private:
// Scratch space for the jacobians; each jacobian is packed one after another.
// There is enough scratch to hold all the jacobians for the largest residual.
- scoped_array<double> jacobian_scratch_;
+ std::unique_ptr<double[]> jacobian_scratch_;
};
} // namespace internal
diff --git a/extern/ceres/internal/ceres/single_linkage_clustering.cc b/extern/ceres/internal/ceres/single_linkage_clustering.cc
new file mode 100644
index 00000000000..394492cdf23
--- /dev/null
+++ b/extern/ceres/internal/ceres/single_linkage_clustering.cc
@@ -0,0 +1,94 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#include "ceres/single_linkage_clustering.h"
+
+#include <unordered_set>
+#include <unordered_map>
+#include "ceres/graph.h"
+#include "ceres/graph_algorithms.h"
+
+namespace ceres {
+namespace internal {
+
+int ComputeSingleLinkageClustering(
+ const SingleLinkageClusteringOptions& options,
+ const WeightedGraph<int>& graph,
+ std::unordered_map<int, int>* membership) {
+ CHECK(membership != nullptr);
+ membership->clear();
+
+ // Initially each vertex is in its own cluster.
+ const std::unordered_set<int>& vertices = graph.vertices();
+ for (const int v : vertices) {
+ (*membership)[v] = v;
+ }
+
+ for (const int vertex1 : vertices) {
+ const std::unordered_set<int>& neighbors = graph.Neighbors(vertex1);
+ for (const int vertex2 : neighbors) {
+ // Since the graph is undirected, only pay attention to one side
+ // of the edge and ignore weak edges.
+ if ((vertex1 > vertex2) ||
+ (graph.EdgeWeight(vertex1, vertex2) < options.min_similarity)) {
+ continue;
+ }
+
+ // Use a union-find algorithm to keep track of the clusters.
+ const int c1 = FindConnectedComponent(vertex1, membership);
+ const int c2 = FindConnectedComponent(vertex2, membership);
+
+ if (c1 == c2) {
+ continue;
+ }
+
+ if (c1 < c2) {
+ (*membership)[c2] = c1;
+ } else {
+ (*membership)[c1] = c2;
+ }
+ }
+ }
+
+ // Make sure that every vertex is connected directly to the vertex
+ // identifying the cluster.
+ int num_clusters = 0;
+ for (auto& m : *membership) {
+ m.second = FindConnectedComponent(m.first, membership);
+ if (m.first == m.second) {
+ ++num_clusters;
+ }
+ }
+
+ return num_clusters;
+}
+
+} // namespace internal
+} // namespace ceres
diff --git a/extern/ceres/include/ceres/fpclassify.h b/extern/ceres/internal/ceres/single_linkage_clustering.h
index bc2dc90026c..ccd6f8ea37d 100644
--- a/extern/ceres/include/ceres/fpclassify.h
+++ b/extern/ceres/internal/ceres/single_linkage_clustering.h
@@ -26,45 +26,39 @@
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
-// Author: keir@google.com (Keir Mierle)
-//
-// Portable floating point classification. The names are picked such that they
-// do not collide with macros. For example, "isnan" in C99 is a macro and hence
-// does not respect namespaces.
-//
-// TODO(keir): Finish porting!
+// Author: sameeragarwal@google.com (Sameer Agarwal)
-#ifndef CERES_PUBLIC_FPCLASSIFY_H_
-#define CERES_PUBLIC_FPCLASSIFY_H_
+#ifndef CERES_INTERNAL_SINGLE_LINKAGE_CLUSTERING_H_
+#define CERES_INTERNAL_SINGLE_LINKAGE_CLUSTERING_H_
-#if defined(_MSC_VER)
-#include <float.h>
-#endif
-
-#include <limits>
+#include <unordered_map>
+#include "ceres/graph.h"
namespace ceres {
+namespace internal {
-#if defined(_MSC_VER)
-
-inline bool IsFinite (double x) { return _finite(x) != 0; }
-inline bool IsInfinite(double x) { return _finite(x) == 0 && _isnan(x) == 0; }
-inline bool IsNaN (double x) { return _isnan(x) != 0; }
-inline bool IsNormal (double x) { // NOLINT
- const int classification = _fpclass(x);
- return (classification == _FPCLASS_NN || classification == _FPCLASS_PN);
-}
+struct SingleLinkageClusteringOptions {
+ // Graph edges with edge weight less than min_similarity are ignored
+ // during the clustering process.
+ double min_similarity = 0.99;
+};
-# else
-
-// These definitions are for the normal Unix suspects.
-inline bool IsFinite (double x) { return std::isfinite(x); }
-inline bool IsInfinite(double x) { return std::isinf(x); }
-inline bool IsNaN (double x) { return std::isnan(x); }
-inline bool IsNormal (double x) { return std::isnormal(x); }
-
-#endif
+// Compute a partitioning of the vertices of the graph using the
+// single linkage clustering algorithm. Edges with weight less than
+// SingleLinkageClusteringOptions::min_similarity will be ignored.
+//
+// membership upon return will contain a mapping from the vertices of
+// the graph to an integer indicating the identity of the cluster that
+// it belongs to.
+//
+// The return value of this function is the number of clusters
+// identified by the algorithm.
+int ComputeSingleLinkageClustering(
+ const SingleLinkageClusteringOptions& options,
+ const WeightedGraph<int>& graph,
+ std::unordered_map<int, int>* membership);
+} // namespace internal
} // namespace ceres
-#endif // CERES_PUBLIC_FPCLASSIFY_H_
+#endif // CERES_INTERNAL_SINGLE_LINKAGE_CLUSTERING_H_
diff --git a/extern/ceres/internal/ceres/small_blas.h b/extern/ceres/internal/ceres/small_blas.h
index 264ac53047d..81c58722d5b 100644
--- a/extern/ceres/internal/ceres/small_blas.h
+++ b/extern/ceres/internal/ceres/small_blas.h
@@ -38,6 +38,7 @@
#include "ceres/internal/port.h"
#include "ceres/internal/eigen.h"
#include "glog/logging.h"
+#include "small_blas_generic.h"
namespace ceres {
namespace internal {
@@ -89,6 +90,26 @@ namespace internal {
B, num_row_b, num_col_b, \
C, start_row_c, start_col_c, row_stride_c, col_stride_c);
+#define CERES_GEMM_STORE_SINGLE(p, index, value) \
+ if (kOperation > 0) { \
+ p[index] += value; \
+ } else if (kOperation < 0) { \
+ p[index] -= value; \
+ } else { \
+ p[index] = value; \
+ }
+
+#define CERES_GEMM_STORE_PAIR(p, index, v1, v2) \
+ if (kOperation > 0) { \
+ p[index] += v1; \
+ p[index + 1] += v2; \
+ } else if (kOperation < 0) { \
+ p[index] -= v1; \
+ p[index + 1] -= v2; \
+ } else { \
+ p[index] = v1; \
+ p[index + 1] = v2; \
+ }
// For the matrix-matrix functions below, there are three variants for
// each functionality. Foo, FooNaive and FooEigen. Foo is the one to
@@ -160,24 +181,64 @@ CERES_GEMM_BEGIN(MatrixMatrixMultiplyNaive) {
const int NUM_COL_C = NUM_COL_B;
DCHECK_LE(start_row_c + NUM_ROW_C, row_stride_c);
DCHECK_LE(start_col_c + NUM_COL_C, col_stride_c);
+ const int span = 4;
+
+ // Calculate the remainder part first.
- for (int row = 0; row < NUM_ROW_C; ++row) {
- for (int col = 0; col < NUM_COL_C; ++col) {
+ // Process the last odd column if present.
+ if (NUM_COL_C & 1) {
+ int col = NUM_COL_C - 1;
+ const double* pa = &A[0];
+ for (int row = 0; row < NUM_ROW_C; ++row, pa += NUM_COL_A) {
+ const double* pb = &B[col];
double tmp = 0.0;
- for (int k = 0; k < NUM_COL_A; ++k) {
- tmp += A[row * NUM_COL_A + k] * B[k * NUM_COL_B + col];
+ for (int k = 0; k < NUM_COL_A; ++k, pb += NUM_COL_B) {
+ tmp += pa[k] * pb[0];
}
const int index = (row + start_row_c) * col_stride_c + start_col_c + col;
- if (kOperation > 0) {
- C[index] += tmp;
- } else if (kOperation < 0) {
- C[index] -= tmp;
- } else {
- C[index] = tmp;
+ CERES_GEMM_STORE_SINGLE(C, index, tmp);
+ }
+
+ // Return directly for efficiency of extremely small matrix multiply.
+ if (NUM_COL_C == 1) {
+ return;
+ }
+ }
+
+ // Process the couple columns in remainder if present.
+ if (NUM_COL_C & 2) {
+ int col = NUM_COL_C & (int)(~(span - 1)) ;
+ const double* pa = &A[0];
+ for (int row = 0; row < NUM_ROW_C; ++row, pa += NUM_COL_A) {
+ const double* pb = &B[col];
+ double tmp1 = 0.0, tmp2 = 0.0;
+ for (int k = 0; k < NUM_COL_A; ++k, pb += NUM_COL_B) {
+ double av = pa[k];
+ tmp1 += av * pb[0];
+ tmp2 += av * pb[1];
}
+
+ const int index = (row + start_row_c) * col_stride_c + start_col_c + col;
+ CERES_GEMM_STORE_PAIR(C, index, tmp1, tmp2);
+ }
+
+ // Return directly for efficiency of extremely small matrix multiply.
+ if (NUM_COL_C < span) {
+ return;
}
}
+
+ // Calculate the main part with multiples of 4.
+ int col_m = NUM_COL_C & (int)(~(span - 1));
+ for (int col = 0; col < col_m; col += span) {
+ for (int row = 0; row < NUM_ROW_C; ++row) {
+ const int index = (row + start_row_c) * col_stride_c + start_col_c + col;
+ MMM_mat1x4(NUM_COL_A, &A[row * NUM_COL_A],
+ &B[col], NUM_COL_B, &C[index], kOperation);
+ }
+ }
+
}
CERES_GEMM_BEGIN(MatrixMatrixMultiply) {
@@ -220,24 +281,68 @@ CERES_GEMM_BEGIN(MatrixTransposeMatrixMultiplyNaive) {
const int NUM_COL_C = NUM_COL_B;
DCHECK_LE(start_row_c + NUM_ROW_C, row_stride_c);
DCHECK_LE(start_col_c + NUM_COL_C, col_stride_c);
+ const int span = 4;
- for (int row = 0; row < NUM_ROW_C; ++row) {
- for (int col = 0; col < NUM_COL_C; ++col) {
+ // Process the remainder part first.
+
+ // Process the last odd column if present.
+ if (NUM_COL_C & 1) {
+ int col = NUM_COL_C - 1;
+ for (int row = 0; row < NUM_ROW_C; ++row) {
+ const double* pa = &A[row];
+ const double* pb = &B[col];
double tmp = 0.0;
for (int k = 0; k < NUM_ROW_A; ++k) {
- tmp += A[k * NUM_COL_A + row] * B[k * NUM_COL_B + col];
+ tmp += pa[0] * pb[0];
+ pa += NUM_COL_A;
+ pb += NUM_COL_B;
}
const int index = (row + start_row_c) * col_stride_c + start_col_c + col;
- if (kOperation > 0) {
- C[index]+= tmp;
- } else if (kOperation < 0) {
- C[index]-= tmp;
- } else {
- C[index]= tmp;
+ CERES_GEMM_STORE_SINGLE(C, index, tmp);
+ }
+
+ // Return directly for efficiency of extremely small matrix multiply.
+ if (NUM_COL_C == 1) {
+ return;
+ }
+ }
+
+ // Process the couple columns in remainder if present.
+ if (NUM_COL_C & 2) {
+ int col = NUM_COL_C & (int)(~(span - 1)) ;
+ for (int row = 0; row < NUM_ROW_C; ++row) {
+ const double* pa = &A[row];
+ const double* pb = &B[col];
+ double tmp1 = 0.0, tmp2 = 0.0;
+ for (int k = 0; k < NUM_ROW_A; ++k) {
+ double av = *pa;
+ tmp1 += av * pb[0];
+ tmp2 += av * pb[1];
+ pa += NUM_COL_A;
+ pb += NUM_COL_B;
}
+
+ const int index = (row + start_row_c) * col_stride_c + start_col_c + col;
+ CERES_GEMM_STORE_PAIR(C, index, tmp1, tmp2);
+ }
+
+ // Return directly for efficiency of extremely small matrix multiply.
+ if (NUM_COL_C < span) {
+ return;
}
}
+
+ // Process the main part with multiples of 4.
+ int col_m = NUM_COL_C & (int)(~(span - 1));
+ for (int col = 0; col < col_m; col += span) {
+ for (int row = 0; row < NUM_ROW_C; ++row) {
+ const int index = (row + start_row_c) * col_stride_c + start_col_c + col;
+ MTM_mat1x4(NUM_ROW_A, &A[row], NUM_COL_A,
+ &B[col], NUM_COL_B, &C[index], kOperation);
+ }
+ }
+
}
CERES_GEMM_BEGIN(MatrixTransposeMatrixMultiply) {
@@ -301,21 +406,54 @@ inline void MatrixVectorMultiply(const double* A,
const int NUM_ROW_A = (kRowA != Eigen::Dynamic ? kRowA : num_row_a);
const int NUM_COL_A = (kColA != Eigen::Dynamic ? kColA : num_col_a);
+ const int span = 4;
- for (int row = 0; row < NUM_ROW_A; ++row) {
+ // Calculate the remainder part first.
+
+ // Process the last odd row if present.
+ if (NUM_ROW_A & 1) {
+ int row = NUM_ROW_A - 1;
+ const double* pa = &A[row * NUM_COL_A];
+ const double* pb = &b[0];
double tmp = 0.0;
for (int col = 0; col < NUM_COL_A; ++col) {
- tmp += A[row * NUM_COL_A + col] * b[col];
+ tmp += (*pa++) * (*pb++);
+ }
+ CERES_GEMM_STORE_SINGLE(c, row, tmp);
+
+ // Return directly for efficiency of extremely small matrix multiply.
+ if (NUM_ROW_A == 1) {
+ return;
+ }
+ }
+
+ // Process the couple rows in remainder if present.
+ if (NUM_ROW_A & 2) {
+ int row = NUM_ROW_A & (int)(~(span - 1));
+ const double* pa1 = &A[row * NUM_COL_A];
+ const double* pa2 = pa1 + NUM_COL_A;
+ const double* pb = &b[0];
+ double tmp1 = 0.0, tmp2 = 0.0;
+ for (int col = 0; col < NUM_COL_A; ++col) {
+ double bv = *pb++;
+ tmp1 += *(pa1++) * bv;
+ tmp2 += *(pa2++) * bv;
}
+ CERES_GEMM_STORE_PAIR(c, row, tmp1, tmp2);
- if (kOperation > 0) {
- c[row] += tmp;
- } else if (kOperation < 0) {
- c[row] -= tmp;
- } else {
- c[row] = tmp;
+ // Return directly for efficiency of extremely small matrix multiply.
+ if (NUM_ROW_A < span) {
+ return;
}
}
+
+ // Calculate the main part with multiples of 4.
+ int row_m = NUM_ROW_A & (int)(~(span - 1));
+ for (int row = 0; row < row_m; row += span) {
+ MVM_mat4x1(NUM_COL_A, &A[row * NUM_COL_A], NUM_COL_A,
+ &b[0], &c[row], kOperation);
+ }
+
#endif // CERES_NO_CUSTOM_BLAS
}
@@ -352,21 +490,55 @@ inline void MatrixTransposeVectorMultiply(const double* A,
const int NUM_ROW_A = (kRowA != Eigen::Dynamic ? kRowA : num_row_a);
const int NUM_COL_A = (kColA != Eigen::Dynamic ? kColA : num_col_a);
+ const int span = 4;
+
+ // Calculate the remainder part first.
- for (int row = 0; row < NUM_COL_A; ++row) {
+ // Process the last odd column if present.
+ if (NUM_COL_A & 1) {
+ int row = NUM_COL_A - 1;
+ const double* pa = &A[row];
+ const double* pb = &b[0];
double tmp = 0.0;
for (int col = 0; col < NUM_ROW_A; ++col) {
- tmp += A[col * NUM_COL_A + row] * b[col];
+ tmp += *pa * (*pb++);
+ pa += NUM_COL_A;
}
+ CERES_GEMM_STORE_SINGLE(c, row, tmp);
- if (kOperation > 0) {
- c[row] += tmp;
- } else if (kOperation < 0) {
- c[row] -= tmp;
- } else {
- c[row] = tmp;
+ // Return directly for efficiency of extremely small matrix multiply.
+ if (NUM_COL_A == 1) {
+ return;
}
}
+
+ // Process the couple columns in remainder if present.
+ if (NUM_COL_A & 2) {
+ int row = NUM_COL_A & (int)(~(span - 1));
+ const double* pa = &A[row];
+ const double* pb = &b[0];
+ double tmp1 = 0.0, tmp2 = 0.0;
+ for (int col = 0; col < NUM_ROW_A; ++col) {
+ double bv = *pb++;
+ tmp1 += *(pa ) * bv;
+ tmp2 += *(pa + 1) * bv;
+ pa += NUM_COL_A;
+ }
+ CERES_GEMM_STORE_PAIR(c, row, tmp1, tmp2);
+
+ // Return directly for efficiency of extremely small matrix multiply.
+ if (NUM_COL_A < span) {
+ return;
+ }
+ }
+
+ // Calculate the main part with multiples of 4.
+ int row_m = NUM_COL_A & (int)(~(span - 1));
+ for (int row = 0; row < row_m; row += span) {
+ MTV_mat4x1(NUM_ROW_A, &A[row], NUM_COL_A,
+ &b[0], &c[row], kOperation);
+ }
+
#endif // CERES_NO_CUSTOM_BLAS
}
@@ -374,6 +546,8 @@ inline void MatrixTransposeVectorMultiply(const double* A,
#undef CERES_GEMM_EIGEN_HEADER
#undef CERES_GEMM_NAIVE_HEADER
#undef CERES_CALL_GEMM
+#undef CERES_GEMM_STORE_SINGLE
+#undef CERES_GEMM_STORE_PAIR
} // namespace internal
} // namespace ceres
diff --git a/extern/ceres/internal/ceres/small_blas_generic.h b/extern/ceres/internal/ceres/small_blas_generic.h
new file mode 100644
index 00000000000..978c5d56a84
--- /dev/null
+++ b/extern/ceres/internal/ceres/small_blas_generic.h
@@ -0,0 +1,315 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2018 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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.
+//
+// Author: yangfan34@lenovo.com (Lenovo Research Device+ Lab - Shanghai)
+//
+// Optimization for simple blas functions used in the Schur Eliminator.
+// These are fairly basic implementations which already yield a significant
+// speedup in the eliminator performance.
+
+#ifndef CERES_INTERNAL_SMALL_BLAS_GENERIC_H_
+#define CERES_INTERNAL_SMALL_BLAS_GENERIC_H_
+
+namespace ceres {
+namespace internal {
+
+// The following macros are used to share code
+#define CERES_GEMM_OPT_NAIVE_HEADER \
+ double c0 = 0.0; \
+ double c1 = 0.0; \
+ double c2 = 0.0; \
+ double c3 = 0.0; \
+ const double* pa = a; \
+ const double* pb = b; \
+ const int span = 4; \
+ int col_r = col_a & (span - 1); \
+ int col_m = col_a - col_r;
+
+#define CERES_GEMM_OPT_STORE_MAT1X4 \
+ if (kOperation > 0) { \
+ *c++ += c0; \
+ *c++ += c1; \
+ *c++ += c2; \
+ *c++ += c3; \
+ } else if (kOperation < 0) { \
+ *c++ -= c0; \
+ *c++ -= c1; \
+ *c++ -= c2; \
+ *c++ -= c3; \
+ } else { \
+ *c++ = c0; \
+ *c++ = c1; \
+ *c++ = c2; \
+ *c++ = c3; \
+ }
+
+// Matrix-Matrix Multiplication
+// Figure out 1x4 of Matrix C in one batch
+//
+// c op a * B;
+// where op can be +=, -=, or =, indicated by kOperation.
+//
+// Matrix C Matrix A Matrix B
+//
+// C0, C1, C2, C3 op A0, A1, A2, A3, ... * B0, B1, B2, B3
+// B4, B5, B6, B7
+// B8, B9, Ba, Bb
+// Bc, Bd, Be, Bf
+// . , . , . , .
+// . , . , . , .
+// . , . , . , .
+//
+// unroll for loops
+// utilize the data resided in cache
+// NOTE: col_a means the columns of A
+static inline void MMM_mat1x4(const int col_a,
+ const double* a,
+ const double* b,
+ const int col_stride_b,
+ double* c,
+ const int kOperation) {
+ CERES_GEMM_OPT_NAIVE_HEADER
+ double av = 0.0;
+ int bi = 0;
+
+#define CERES_GEMM_OPT_MMM_MAT1X4_MUL \
+ av = pa[k]; \
+ pb = b + bi; \
+ c0 += av * *pb++; \
+ c1 += av * *pb++; \
+ c2 += av * *pb++; \
+ c3 += av * *pb++; \
+ bi += col_stride_b; \
+ k++;
+
+ for (int k = 0; k < col_m;) {
+ CERES_GEMM_OPT_MMM_MAT1X4_MUL
+ CERES_GEMM_OPT_MMM_MAT1X4_MUL
+ CERES_GEMM_OPT_MMM_MAT1X4_MUL
+ CERES_GEMM_OPT_MMM_MAT1X4_MUL
+ }
+
+ for (int k = col_m; k < col_a;) {
+ CERES_GEMM_OPT_MMM_MAT1X4_MUL
+ }
+
+ CERES_GEMM_OPT_STORE_MAT1X4
+
+#undef CERES_GEMM_OPT_MMM_MAT1X4_MUL
+}
+
+// Matrix Transpose-Matrix multiplication
+// Figure out 1x4 of Matrix C in one batch
+//
+// c op a' * B;
+// where op can be +=, -=, or = indicated by kOperation.
+//
+// Matrix A
+//
+// A0
+// A1
+// A2
+// A3
+// .
+// .
+// .
+//
+// Matrix C Matrix A' Matrix B
+//
+// C0, C1, C2, C3 op A0, A1, A2, A3, ... * B0, B1, B2, B3
+// B4, B5, B6, B7
+// B8, B9, Ba, Bb
+// Bc, Bd, Be, Bf
+// . , . , . , .
+// . , . , . , .
+// . , . , . , .
+//
+// unroll for loops
+// utilize the data resided in cache
+// NOTE: col_a means the columns of A'
+static inline void MTM_mat1x4(const int col_a,
+ const double* a,
+ const int col_stride_a,
+ const double* b,
+ const int col_stride_b,
+ double* c,
+ const int kOperation) {
+ CERES_GEMM_OPT_NAIVE_HEADER
+ double av = 0.0;
+ int ai = 0;
+ int bi = 0;
+
+#define CERES_GEMM_OPT_MTM_MAT1X4_MUL \
+ av = pa[ai]; \
+ pb = b + bi; \
+ c0 += av * *pb++; \
+ c1 += av * *pb++; \
+ c2 += av * *pb++; \
+ c3 += av * *pb++; \
+ ai += col_stride_a; \
+ bi += col_stride_b;
+
+ for (int k = 0; k < col_m; k += span) {
+ CERES_GEMM_OPT_MTM_MAT1X4_MUL
+ CERES_GEMM_OPT_MTM_MAT1X4_MUL
+ CERES_GEMM_OPT_MTM_MAT1X4_MUL
+ CERES_GEMM_OPT_MTM_MAT1X4_MUL
+ }
+
+ for (int k = col_m; k < col_a; k++) {
+ CERES_GEMM_OPT_MTM_MAT1X4_MUL
+ }
+
+ CERES_GEMM_OPT_STORE_MAT1X4
+
+#undef CERES_GEMM_OPT_MTM_MAT1X4_MUL
+}
+
+// Matrix-Vector Multiplication
+// Figure out 4x1 of vector c in one batch
+//
+// c op A * b;
+// where op can be +=, -=, or =, indicated by kOperation.
+//
+// Vector c Matrix A Vector b
+//
+// C0 op A0, A1, A2, A3, ... * B0
+// C1 A4, A5, A6, A7, ... B1
+// C2 A8, A9, Aa, Ab, ... B2
+// C3 Ac, Ad, Ae, Af, ... B3
+// .
+// .
+// .
+//
+// unroll for loops
+// utilize the data resided in cache
+// NOTE: col_a means the columns of A
+static inline void MVM_mat4x1(const int col_a,
+ const double* a,
+ const int col_stride_a,
+ const double* b,
+ double* c,
+ const int kOperation) {
+ CERES_GEMM_OPT_NAIVE_HEADER
+ double bv = 0.0;
+
+#define CERES_GEMM_OPT_MVM_MAT4X1_MUL \
+ bv = *pb; \
+ c0 += *(pa ) * bv; \
+ c1 += *(pa + col_stride_a ) * bv; \
+ c2 += *(pa + col_stride_a * 2) * bv; \
+ c3 += *(pa + col_stride_a * 3) * bv; \
+ pa++; \
+ pb++;
+
+ for (int k = 0; k < col_m; k += span) {
+ CERES_GEMM_OPT_MVM_MAT4X1_MUL
+ CERES_GEMM_OPT_MVM_MAT4X1_MUL
+ CERES_GEMM_OPT_MVM_MAT4X1_MUL
+ CERES_GEMM_OPT_MVM_MAT4X1_MUL
+ }
+
+ for (int k = col_m; k < col_a; k++) {
+ CERES_GEMM_OPT_MVM_MAT4X1_MUL
+ }
+
+ CERES_GEMM_OPT_STORE_MAT1X4
+
+#undef CERES_GEMM_OPT_MVM_MAT4X1_MUL
+}
+
+// Matrix Transpose-Vector multiplication
+// Figure out 4x1 of vector c in one batch
+//
+// c op A' * b;
+// where op can be +=, -=, or =, indicated by kOperation.
+//
+// Matrix A
+//
+// A0, A4, A8, Ac
+// A1, A5, A9, Ad
+// A2, A6, Aa, Ae
+// A3, A7, Ab, Af
+// . , . , . , .
+// . , . , . , .
+// . , . , . , .
+//
+// Vector c Matrix A' Vector b
+//
+// C0 op A0, A1, A2, A3, ... * B0
+// C1 A4, A5, A6, A7, ... B1
+// C2 A8, A9, Aa, Ab, ... B2
+// C3 Ac, Ad, Ae, Af, ... B3
+// .
+// .
+// .
+//
+// unroll for loops
+// utilize the data resided in cache
+// NOTE: col_a means the columns of A'
+static inline void MTV_mat4x1(const int col_a,
+ const double* a,
+ const int col_stride_a,
+ const double* b,
+ double* c,
+ const int kOperation) {
+ CERES_GEMM_OPT_NAIVE_HEADER
+ double bv = 0.0;
+
+#define CERES_GEMM_OPT_MTV_MAT4X1_MUL \
+ bv = *pb; \
+ c0 += *(pa ) * bv; \
+ c1 += *(pa + 1) * bv; \
+ c2 += *(pa + 2) * bv; \
+ c3 += *(pa + 3) * bv; \
+ pa += col_stride_a; \
+ pb++;
+
+ for (int k = 0; k < col_m; k += span) {
+ CERES_GEMM_OPT_MTV_MAT4X1_MUL
+ CERES_GEMM_OPT_MTV_MAT4X1_MUL
+ CERES_GEMM_OPT_MTV_MAT4X1_MUL
+ CERES_GEMM_OPT_MTV_MAT4X1_MUL
+ }
+
+ for (int k = col_m; k < col_a; k++) {
+ CERES_GEMM_OPT_MTV_MAT4X1_MUL
+ }
+
+ CERES_GEMM_OPT_STORE_MAT1X4
+
+#undef CERES_GEMM_OPT_MTV_MAT4X1_MUL
+}
+
+#undef CERES_GEMM_OPT_NAIVE_HEADER
+#undef CERES_GEMM_OPT_STORE_MAT1X4
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_SMALL_BLAS_GENERIC_H_
diff --git a/extern/ceres/internal/ceres/solver.cc b/extern/ceres/internal/ceres/solver.cc
index 8411350986a..861d8d30485 100644
--- a/extern/ceres/internal/ceres/solver.cc
+++ b/extern/ceres/internal/ceres/solver.cc
@@ -32,8 +32,14 @@
#include "ceres/solver.h"
#include <algorithm>
-#include <sstream> // NOLINT
+#include <memory>
+#include <sstream> // NOLINT
#include <vector>
+
+#include "ceres/casts.h"
+#include "ceres/context.h"
+#include "ceres/context_impl.h"
+#include "ceres/detect_structure.h"
#include "ceres/gradient_checking_cost_function.h"
#include "ceres/internal/port.h"
#include "ceres/parameter_block_ordering.h"
@@ -41,6 +47,7 @@
#include "ceres/problem.h"
#include "ceres/problem_impl.h"
#include "ceres/program.h"
+#include "ceres/schur_templates.h"
#include "ceres/solver_utils.h"
#include "ceres/stringprintf.h"
#include "ceres/types.h"
@@ -52,6 +59,8 @@ namespace {
using std::map;
using std::string;
using std::vector;
+using internal::StringAppendF;
+using internal::StringPrintf;
#define OPTION_OP(x, y, OP) \
if (!(options.x OP y)) { \
@@ -91,7 +100,6 @@ bool CommonOptionsAreValid(const Solver::Options& options, string* error) {
OPTION_GE(gradient_tolerance, 0.0);
OPTION_GE(parameter_tolerance, 0.0);
OPTION_GT(num_threads, 0);
- OPTION_GT(num_linear_solver_threads, 0);
if (options.check_gradients) {
OPTION_GT(gradient_check_relative_precision, 0.0);
OPTION_GT(gradient_check_numeric_derivative_relative_step_size, 0.0);
@@ -132,101 +140,51 @@ bool TrustRegionOptionsAreValid(const Solver::Options& options, string* error) {
return false;
}
- if (options.preconditioner_type == CLUSTER_JACOBI &&
- options.sparse_linear_algebra_library_type != SUITE_SPARSE) {
- *error = "CLUSTER_JACOBI requires "
- "Solver::Options::sparse_linear_algebra_library_type to be "
- "SUITE_SPARSE";
- return false;
- }
-
- if (options.preconditioner_type == CLUSTER_TRIDIAGONAL &&
- options.sparse_linear_algebra_library_type != SUITE_SPARSE) {
- *error = "CLUSTER_TRIDIAGONAL requires "
- "Solver::Options::sparse_linear_algebra_library_type to be "
- "SUITE_SPARSE";
- return false;
- }
-
-#ifdef CERES_NO_LAPACK
- if (options.dense_linear_algebra_library_type == LAPACK) {
- if (options.linear_solver_type == DENSE_NORMAL_CHOLESKY) {
- *error = "Can't use DENSE_NORMAL_CHOLESKY with LAPACK because "
- "LAPACK was not enabled when Ceres was built.";
- return false;
- } else if (options.linear_solver_type == DENSE_QR) {
- *error = "Can't use DENSE_QR with LAPACK because "
- "LAPACK was not enabled when Ceres was built.";
- return false;
- } else if (options.linear_solver_type == DENSE_SCHUR) {
- *error = "Can't use DENSE_SCHUR with LAPACK because "
- "LAPACK was not enabled when Ceres was built.";
- return false;
- }
- }
-#endif
-
-#ifdef CERES_NO_SUITESPARSE
- if (options.sparse_linear_algebra_library_type == SUITE_SPARSE) {
- if (options.linear_solver_type == SPARSE_NORMAL_CHOLESKY) {
- *error = "Can't use SPARSE_NORMAL_CHOLESKY with SUITESPARSE because "
- "SuiteSparse was not enabled when Ceres was built.";
- return false;
- } else if (options.linear_solver_type == SPARSE_SCHUR) {
- *error = "Can't use SPARSE_SCHUR with SUITESPARSE because "
- "SuiteSparse was not enabled when Ceres was built.";
- return false;
- } else if (options.preconditioner_type == CLUSTER_JACOBI) {
- *error = "CLUSTER_JACOBI preconditioner not supported. "
- "SuiteSparse was not enabled when Ceres was built.";
- return false;
- } else if (options.preconditioner_type == CLUSTER_TRIDIAGONAL) {
- *error = "CLUSTER_TRIDIAGONAL preconditioner not supported. "
- "SuiteSparse was not enabled when Ceres was built.";
+ if (options.dense_linear_algebra_library_type == LAPACK &&
+ !IsDenseLinearAlgebraLibraryTypeAvailable(LAPACK) &&
+ (options.linear_solver_type == DENSE_NORMAL_CHOLESKY ||
+ options.linear_solver_type == DENSE_QR ||
+ options.linear_solver_type == DENSE_SCHUR)) {
+ *error = StringPrintf(
+ "Can't use %s with "
+ "Solver::Options::dense_linear_algebra_library_type = LAPACK "
+ "because LAPACK was not enabled when Ceres was built.",
+ LinearSolverTypeToString(options.linear_solver_type));
return false;
- }
}
-#endif
-#ifdef CERES_NO_CXSPARSE
- if (options.sparse_linear_algebra_library_type == CX_SPARSE) {
- if (options.linear_solver_type == SPARSE_NORMAL_CHOLESKY) {
- *error = "Can't use SPARSE_NORMAL_CHOLESKY with CX_SPARSE because "
- "CXSparse was not enabled when Ceres was built.";
- return false;
- } else if (options.linear_solver_type == SPARSE_SCHUR) {
- *error = "Can't use SPARSE_SCHUR with CX_SPARSE because "
- "CXSparse was not enabled when Ceres was built.";
- return false;
+ {
+ const char* sparse_linear_algebra_library_name =
+ SparseLinearAlgebraLibraryTypeToString(
+ options.sparse_linear_algebra_library_type);
+ const char* name = nullptr;
+ if (options.linear_solver_type == SPARSE_NORMAL_CHOLESKY ||
+ options.linear_solver_type == SPARSE_SCHUR) {
+ name = LinearSolverTypeToString(options.linear_solver_type);
+ } else if ((options.linear_solver_type == ITERATIVE_SCHUR &&
+ (options.preconditioner_type == CLUSTER_JACOBI ||
+ options.preconditioner_type == CLUSTER_TRIDIAGONAL)) ||
+ (options.linear_solver_type == CGNR &&
+ options.preconditioner_type == SUBSET)) {
+ name = PreconditionerTypeToString(options.preconditioner_type);
}
- }
-#endif
-#ifndef CERES_USE_EIGEN_SPARSE
- if (options.sparse_linear_algebra_library_type == EIGEN_SPARSE) {
- if (options.linear_solver_type == SPARSE_NORMAL_CHOLESKY) {
- *error = "Can't use SPARSE_NORMAL_CHOLESKY with EIGEN_SPARSE because "
- "Eigen's sparse linear algebra was not enabled when Ceres was "
- "built.";
- return false;
- } else if (options.linear_solver_type == SPARSE_SCHUR) {
- *error = "Can't use SPARSE_SCHUR with EIGEN_SPARSE because "
- "Eigen's sparse linear algebra was not enabled when Ceres was "
- "built.";
- return false;
- }
- }
-#endif
-
- if (options.sparse_linear_algebra_library_type == NO_SPARSE) {
- if (options.linear_solver_type == SPARSE_NORMAL_CHOLESKY) {
- *error = "Can't use SPARSE_NORMAL_CHOLESKY as "
- "sparse_linear_algebra_library_type is NO_SPARSE.";
- return false;
- } else if (options.linear_solver_type == SPARSE_SCHUR) {
- *error = "Can't use SPARSE_SCHUR as "
- "sparse_linear_algebra_library_type is NO_SPARSE.";
- return false;
+ if (name) {
+ if (options.sparse_linear_algebra_library_type == NO_SPARSE) {
+ *error = StringPrintf(
+ "Can't use %s with "
+ "Solver::Options::sparse_linear_algebra_library_type = %s.",
+ name, sparse_linear_algebra_library_name);
+ return false;
+ } else if (!IsSparseLinearAlgebraLibraryTypeAvailable(
+ options.sparse_linear_algebra_library_type)) {
+ *error = StringPrintf(
+ "Can't use %s with "
+ "Solver::Options::sparse_linear_algebra_library_type = %s, "
+ "because support was not enabled when Ceres Solver was built.",
+ name, sparse_linear_algebra_library_name);
+ return false;
+ }
}
}
@@ -240,16 +198,32 @@ bool TrustRegionOptionsAreValid(const Solver::Options& options, string* error) {
}
}
- if (options.trust_region_minimizer_iterations_to_dump.size() > 0 &&
+ if (!options.trust_region_minimizer_iterations_to_dump.empty() &&
options.trust_region_problem_dump_format_type != CONSOLE &&
options.trust_region_problem_dump_directory.empty()) {
*error = "Solver::Options::trust_region_problem_dump_directory is empty.";
return false;
}
- if (options.dynamic_sparsity &&
- options.linear_solver_type != SPARSE_NORMAL_CHOLESKY) {
- *error = "Dynamic sparsity is only supported with SPARSE_NORMAL_CHOLESKY.";
+ if (options.dynamic_sparsity) {
+ if (options.linear_solver_type != SPARSE_NORMAL_CHOLESKY) {
+ *error = "Dynamic sparsity is only supported with SPARSE_NORMAL_CHOLESKY.";
+ return false;
+ }
+ if (options.sparse_linear_algebra_library_type == ACCELERATE_SPARSE) {
+ *error = "ACCELERATE_SPARSE is not currently supported with dynamic "
+ "sparsity.";
+ return false;
+ }
+ }
+
+ if (options.linear_solver_type == CGNR &&
+ options.preconditioner_type == SUBSET &&
+ options.residual_blocks_for_subset_preconditioner.empty()) {
+ *error =
+ "When using SUBSET preconditioner, "
+ "Solver::Options::residual_blocks_for_subset_preconditioner cannot be "
+ "empty";
return false;
}
@@ -264,7 +238,8 @@ bool LineSearchOptionsAreValid(const Solver::Options& options, string* error) {
OPTION_LT_OPTION(max_line_search_step_contraction,
min_line_search_step_contraction);
OPTION_LE(min_line_search_step_contraction, 1.0);
- OPTION_GT(max_num_line_search_step_size_iterations, 0);
+ OPTION_GE(max_num_line_search_step_size_iterations,
+ (options.minimizer_type == ceres::TRUST_REGION ? 0 : 1));
OPTION_GT(line_search_sufficient_function_decrease, 0.0);
OPTION_LT_OPTION(line_search_sufficient_function_decrease,
line_search_sufficient_curvature_decrease);
@@ -310,13 +285,13 @@ bool LineSearchOptionsAreValid(const Solver::Options& options, string* error) {
#undef OPTION_LT_OPTION
void StringifyOrdering(const vector<int>& ordering, string* report) {
- if (ordering.size() == 0) {
+ if (ordering.empty()) {
internal::StringAppendF(report, "AUTOMATIC");
return;
}
for (int i = 0; i < ordering.size() - 1; ++i) {
- internal::StringAppendF(report, "%d, ", ordering[i]);
+ internal::StringAppendF(report, "%d,", ordering[i]);
}
internal::StringAppendF(report, "%d", ordering.back());
}
@@ -364,7 +339,6 @@ void PreSolveSummarize(const Solver::Options& options,
summary->max_lbfgs_rank = options.max_lbfgs_rank;
summary->minimizer_type = options.minimizer_type;
summary->nonlinear_conjugate_gradient_type = options.nonlinear_conjugate_gradient_type; // NOLINT
- summary->num_linear_solver_threads_given = options.num_linear_solver_threads; // NOLINT
summary->num_threads_given = options.num_threads;
summary->preconditioner_type_given = options.preconditioner_type;
summary->sparse_linear_algebra_library_type = options.sparse_linear_algebra_library_type; // NOLINT
@@ -380,10 +354,9 @@ void PostSolveSummarize(const internal::PreprocessedProblem& pp,
&(summary->inner_iteration_ordering_used));
summary->inner_iterations_used = pp.inner_iteration_minimizer.get() != NULL; // NOLINT
- summary->linear_solver_type_used = pp.options.linear_solver_type;
- summary->num_linear_solver_threads_used = pp.options.num_linear_solver_threads; // NOLINT
+ summary->linear_solver_type_used = pp.linear_solver_options.type;
summary->num_threads_used = pp.options.num_threads;
- summary->preconditioner_type_used = pp.options.preconditioner_type; // NOLINT
+ summary->preconditioner_type_used = pp.options.preconditioner_type;
internal::SetSummaryFinalCost(summary);
@@ -391,36 +364,47 @@ void PostSolveSummarize(const internal::PreprocessedProblem& pp,
SummarizeReducedProgram(*pp.reduced_program, summary);
}
+ using internal::CallStatistics;
+
// It is possible that no evaluator was created. This would be the
// case if the preprocessor failed, or if the reduced problem did
// not contain any parameter blocks. Thus, only extract the
// evaluator statistics if one exists.
if (pp.evaluator.get() != NULL) {
- const map<string, double>& evaluator_time_statistics =
- pp.evaluator->TimeStatistics();
- summary->residual_evaluation_time_in_seconds =
- FindWithDefault(evaluator_time_statistics, "Evaluator::Residual", 0.0);
- summary->jacobian_evaluation_time_in_seconds =
- FindWithDefault(evaluator_time_statistics, "Evaluator::Jacobian", 0.0);
+ const map<string, CallStatistics>& evaluator_statistics =
+ pp.evaluator->Statistics();
+ {
+ const CallStatistics& call_stats = FindWithDefault(
+ evaluator_statistics, "Evaluator::Residual", CallStatistics());
+
+ summary->residual_evaluation_time_in_seconds = call_stats.time;
+ summary->num_residual_evaluations = call_stats.calls;
+ }
+ {
+ const CallStatistics& call_stats = FindWithDefault(
+ evaluator_statistics, "Evaluator::Jacobian", CallStatistics());
+
+ summary->jacobian_evaluation_time_in_seconds = call_stats.time;
+ summary->num_jacobian_evaluations = call_stats.calls;
+ }
}
// Again, like the evaluator, there may or may not be a linear
// solver from which we can extract run time statistics. In
// particular the line search solver does not use a linear solver.
if (pp.linear_solver.get() != NULL) {
- const map<string, double>& linear_solver_time_statistics =
- pp.linear_solver->TimeStatistics();
- summary->linear_solver_time_in_seconds =
- FindWithDefault(linear_solver_time_statistics,
- "LinearSolver::Solve",
- 0.0);
+ const map<string, CallStatistics>& linear_solver_statistics =
+ pp.linear_solver->Statistics();
+ const CallStatistics& call_stats = FindWithDefault(
+ linear_solver_statistics, "LinearSolver::Solve", CallStatistics());
+ summary->num_linear_solves = call_stats.calls;
+ summary->linear_solver_time_in_seconds = call_stats.time;
}
}
void Minimize(internal::PreprocessedProblem* pp,
Solver::Summary* summary) {
using internal::Program;
- using internal::scoped_ptr;
using internal::Minimizer;
Program* program = pp->reduced_program.get();
@@ -434,16 +418,36 @@ void Minimize(internal::PreprocessedProblem* pp,
return;
}
- scoped_ptr<Minimizer> minimizer(
+ const Vector original_reduced_parameters = pp->reduced_parameters;
+ std::unique_ptr<Minimizer> minimizer(
Minimizer::Create(pp->options.minimizer_type));
minimizer->Minimize(pp->minimizer_options,
pp->reduced_parameters.data(),
summary);
- if (summary->IsSolutionUsable()) {
- program->StateVectorToParameterBlocks(pp->reduced_parameters.data());
- program->CopyParameterBlockStateToUserState();
- }
+ program->StateVectorToParameterBlocks(
+ summary->IsSolutionUsable()
+ ? pp->reduced_parameters.data()
+ : original_reduced_parameters.data());
+ program->CopyParameterBlockStateToUserState();
+}
+
+std::string SchurStructureToString(const int row_block_size,
+ const int e_block_size,
+ const int f_block_size) {
+ const std::string row =
+ (row_block_size == Eigen::Dynamic)
+ ? "d" : internal::StringPrintf("%d", row_block_size);
+
+ const std::string e =
+ (e_block_size == Eigen::Dynamic)
+ ? "d" : internal::StringPrintf("%d", e_block_size);
+
+ const std::string f =
+ (f_block_size == Eigen::Dynamic)
+ ? "d" : internal::StringPrintf("%d", f_block_size);
+
+ return internal::StringPrintf("%s,%s,%s", row.c_str(), e.c_str(), f.c_str());
}
} // namespace
@@ -475,11 +479,10 @@ void Solver::Solve(const Solver::Options& options,
using internal::Preprocessor;
using internal::ProblemImpl;
using internal::Program;
- using internal::scoped_ptr;
using internal::WallTimeInSeconds;
- CHECK_NOTNULL(problem);
- CHECK_NOTNULL(summary);
+ CHECK(problem != nullptr);
+ CHECK(summary != nullptr);
double start_time = WallTimeInSeconds();
*summary = Summary();
@@ -488,18 +491,14 @@ void Solver::Solve(const Solver::Options& options,
return;
}
- ProblemImpl* problem_impl = problem->problem_impl_.get();
+ ProblemImpl* problem_impl = problem->impl_.get();
Program* program = problem_impl->mutable_program();
PreSolveSummarize(options, problem_impl, summary);
- // Make sure that all the parameter blocks states are set to the
- // values provided by the user.
- program->SetParameterBlockStatePtrsToUserStatePtrs();
-
// If gradient_checking is enabled, wrap all cost functions in a
// gradient checker and install a callback that terminates if any gradient
// error is detected.
- scoped_ptr<internal::ProblemImpl> gradient_checking_problem;
+ std::unique_ptr<internal::ProblemImpl> gradient_checking_problem;
internal::GradientCheckingIterationCallback gradient_checking_callback;
Solver::Options modified_options = options;
if (options.check_gradients) {
@@ -514,10 +513,46 @@ void Solver::Solve(const Solver::Options& options,
program = problem_impl->mutable_program();
}
- scoped_ptr<Preprocessor> preprocessor(
+ // Make sure that all the parameter blocks states are set to the
+ // values provided by the user.
+ program->SetParameterBlockStatePtrsToUserStatePtrs();
+
+ // The main thread also does work so we only need to launch num_threads - 1.
+ problem_impl->context()->EnsureMinimumThreads(options.num_threads - 1);
+
+ std::unique_ptr<Preprocessor> preprocessor(
Preprocessor::Create(modified_options.minimizer_type));
PreprocessedProblem pp;
+
const bool status = preprocessor->Preprocess(modified_options, problem_impl, &pp);
+
+ // We check the linear_solver_options.type rather than
+ // modified_options.linear_solver_type because, depending on the
+ // lack of a Schur structure, the preprocessor may change the linear
+ // solver type.
+ if (IsSchurType(pp.linear_solver_options.type)) {
+ // TODO(sameeragarwal): We can likely eliminate the duplicate call
+ // to DetectStructure here and inside the linear solver, by
+ // calling this in the preprocessor.
+ int row_block_size;
+ int e_block_size;
+ int f_block_size;
+ DetectStructure(*static_cast<internal::BlockSparseMatrix*>(
+ pp.minimizer_options.jacobian.get())
+ ->block_structure(),
+ pp.linear_solver_options.elimination_groups[0],
+ &row_block_size,
+ &e_block_size,
+ &f_block_size);
+ summary->schur_structure_given =
+ SchurStructureToString(row_block_size, e_block_size, f_block_size);
+ internal::GetBestSchurTemplateSpecialization(&row_block_size,
+ &e_block_size,
+ &f_block_size);
+ summary->schur_structure_used =
+ SchurStructureToString(row_block_size, e_block_size, f_block_size);
+ }
+
summary->fixed_cost = pp.fixed_cost;
summary->preprocessor_time_in_seconds = WallTimeInSeconds() - start_time;
@@ -531,7 +566,7 @@ void Solver::Solve(const Solver::Options& options,
}
const double postprocessor_start_time = WallTimeInSeconds();
- problem_impl = problem->problem_impl_.get();
+ problem_impl = problem->impl_.get();
program = problem_impl->mutable_program();
// On exit, ensure that the parameter blocks again point at the user
// provided values and the parameter blocks are numbered according
@@ -559,66 +594,6 @@ void Solve(const Solver::Options& options,
solver.Solve(options, problem, summary);
}
-Solver::Summary::Summary()
- // Invalid values for most fields, to ensure that we are not
- // accidentally reporting default values.
- : minimizer_type(TRUST_REGION),
- termination_type(FAILURE),
- message("ceres::Solve was not called."),
- initial_cost(-1.0),
- final_cost(-1.0),
- fixed_cost(-1.0),
- num_successful_steps(-1),
- num_unsuccessful_steps(-1),
- num_inner_iteration_steps(-1),
- num_line_search_steps(-1),
- preprocessor_time_in_seconds(-1.0),
- minimizer_time_in_seconds(-1.0),
- postprocessor_time_in_seconds(-1.0),
- total_time_in_seconds(-1.0),
- linear_solver_time_in_seconds(-1.0),
- residual_evaluation_time_in_seconds(-1.0),
- jacobian_evaluation_time_in_seconds(-1.0),
- inner_iteration_time_in_seconds(-1.0),
- line_search_cost_evaluation_time_in_seconds(-1.0),
- line_search_gradient_evaluation_time_in_seconds(-1.0),
- line_search_polynomial_minimization_time_in_seconds(-1.0),
- line_search_total_time_in_seconds(-1.0),
- num_parameter_blocks(-1),
- num_parameters(-1),
- num_effective_parameters(-1),
- num_residual_blocks(-1),
- num_residuals(-1),
- num_parameter_blocks_reduced(-1),
- num_parameters_reduced(-1),
- num_effective_parameters_reduced(-1),
- num_residual_blocks_reduced(-1),
- num_residuals_reduced(-1),
- is_constrained(false),
- num_threads_given(-1),
- num_threads_used(-1),
- num_linear_solver_threads_given(-1),
- num_linear_solver_threads_used(-1),
- linear_solver_type_given(SPARSE_NORMAL_CHOLESKY),
- linear_solver_type_used(SPARSE_NORMAL_CHOLESKY),
- inner_iterations_given(false),
- inner_iterations_used(false),
- preconditioner_type_given(IDENTITY),
- preconditioner_type_used(IDENTITY),
- visibility_clustering_type(CANONICAL_VIEWS),
- trust_region_strategy_type(LEVENBERG_MARQUARDT),
- dense_linear_algebra_library_type(EIGEN),
- sparse_linear_algebra_library_type(SUITE_SPARSE),
- line_search_direction_type(LBFGS),
- line_search_type(ARMIJO),
- line_search_interpolation_type(BISECTION),
- nonlinear_conjugate_gradient_type(FLETCHER_REEVES),
- max_lbfgs_rank(-1) {
-}
-
-using internal::StringAppendF;
-using internal::StringPrintf;
-
string Solver::Summary::BriefReport() const {
return StringPrintf("Ceres Solver Report: "
"Iterations: %d, "
@@ -647,7 +622,7 @@ string Solver::Summary::FullReport() const {
}
StringAppendF(&report, "Residual blocks % 25d% 25d\n",
num_residual_blocks, num_residual_blocks_reduced);
- StringAppendF(&report, "Residual % 25d% 25d\n",
+ StringAppendF(&report, "Residuals % 25d% 25d\n",
num_residuals, num_residuals_reduced);
if (minimizer_type == TRUST_REGION) {
@@ -708,9 +683,6 @@ string Solver::Summary::FullReport() const {
}
StringAppendF(&report, "Threads % 25d% 25d\n",
num_threads_given, num_threads_used);
- StringAppendF(&report, "Linear solver threads % 23d% 25d\n",
- num_linear_solver_threads_given,
- num_linear_solver_threads_used);
string given;
StringifyOrdering(linear_solver_ordering_given, &given);
@@ -720,6 +692,12 @@ string Solver::Summary::FullReport() const {
"Linear solver ordering %22s %24s\n",
given.c_str(),
used.c_str());
+ if (IsSchurType(linear_solver_type_used)) {
+ StringAppendF(&report,
+ "Schur structure %22s %24s\n",
+ schur_structure_given.c_str(),
+ schur_structure_used.c_str());
+ }
if (inner_iterations_given) {
StringAppendF(&report,
@@ -808,44 +786,44 @@ string Solver::Summary::FullReport() const {
}
StringAppendF(&report, "\nTime (in seconds):\n");
- StringAppendF(&report, "Preprocessor %25.4f\n",
+ StringAppendF(&report, "Preprocessor %25.6f\n",
preprocessor_time_in_seconds);
- StringAppendF(&report, "\n Residual evaluation %23.4f\n",
- residual_evaluation_time_in_seconds);
+ StringAppendF(&report, "\n Residual only evaluation %18.6f (%d)\n",
+ residual_evaluation_time_in_seconds, num_residual_evaluations);
if (line_search_used) {
- StringAppendF(&report, " Line search cost evaluation %10.4f\n",
+ StringAppendF(&report, " Line search cost evaluation %10.6f\n",
line_search_cost_evaluation_time_in_seconds);
}
- StringAppendF(&report, " Jacobian evaluation %23.4f\n",
- jacobian_evaluation_time_in_seconds);
+ StringAppendF(&report, " Jacobian & residual evaluation %12.6f (%d)\n",
+ jacobian_evaluation_time_in_seconds, num_jacobian_evaluations);
if (line_search_used) {
- StringAppendF(&report, " Line search gradient evaluation %6.4f\n",
+ StringAppendF(&report, " Line search gradient evaluation %6.6f\n",
line_search_gradient_evaluation_time_in_seconds);
}
if (minimizer_type == TRUST_REGION) {
- StringAppendF(&report, " Linear solver %23.4f\n",
- linear_solver_time_in_seconds);
+ StringAppendF(&report, " Linear solver %23.6f (%d)\n",
+ linear_solver_time_in_seconds, num_linear_solves);
}
if (inner_iterations_used) {
- StringAppendF(&report, " Inner iterations %23.4f\n",
+ StringAppendF(&report, " Inner iterations %23.6f\n",
inner_iteration_time_in_seconds);
}
if (line_search_used) {
- StringAppendF(&report, " Line search polynomial minimization %.4f\n",
+ StringAppendF(&report, " Line search polynomial minimization %.6f\n",
line_search_polynomial_minimization_time_in_seconds);
}
- StringAppendF(&report, "Minimizer %25.4f\n\n",
+ StringAppendF(&report, "Minimizer %25.6f\n\n",
minimizer_time_in_seconds);
- StringAppendF(&report, "Postprocessor %24.4f\n",
+ StringAppendF(&report, "Postprocessor %24.6f\n",
postprocessor_time_in_seconds);
- StringAppendF(&report, "Total %25.4f\n\n",
+ StringAppendF(&report, "Total %25.6f\n\n",
total_time_in_seconds);
StringAppendF(&report, "Termination: %25s (%s)\n",
diff --git a/extern/ceres/internal/ceres/solver_utils.cc b/extern/ceres/internal/ceres/solver_utils.cc
index 7f4ff7eb940..177a928e090 100644
--- a/extern/ceres/internal/ceres/solver_utils.cc
+++ b/extern/ceres/internal/ceres/solver_utils.cc
@@ -30,6 +30,8 @@
#include <string>
+#include "ceres/internal/config.h"
+
#include "Eigen/Core"
#include "ceres/internal/port.h"
#include "ceres/solver_utils.h"
@@ -61,6 +63,10 @@ std::string VersionString() {
value += "-cxsparse-(" + std::string(CERES_CXSPARSE_VERSION) + ")";
#endif
+#ifndef CERES_NO_ACCELERATE_SPARSE
+ value += "-acceleratesparse";
+#endif
+
#ifdef CERES_USE_EIGEN_SPARSE
value += "-eigensparse";
#endif
diff --git a/extern/ceres/internal/ceres/sparse_cholesky.cc b/extern/ceres/internal/ceres/sparse_cholesky.cc
new file mode 100644
index 00000000000..d9d2100d3f9
--- /dev/null
+++ b/extern/ceres/internal/ceres/sparse_cholesky.cc
@@ -0,0 +1,163 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2017 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#include "ceres/sparse_cholesky.h"
+
+#include "ceres/accelerate_sparse.h"
+#include "ceres/cxsparse.h"
+#include "ceres/eigensparse.h"
+#include "ceres/float_cxsparse.h"
+#include "ceres/float_suitesparse.h"
+#include "ceres/iterative_refiner.h"
+#include "ceres/suitesparse.h"
+
+namespace ceres {
+namespace internal {
+
+std::unique_ptr<SparseCholesky> SparseCholesky::Create(
+ const LinearSolver::Options& options) {
+ const OrderingType ordering_type = options.use_postordering ? AMD : NATURAL;
+ std::unique_ptr<SparseCholesky> sparse_cholesky;
+
+ switch (options.sparse_linear_algebra_library_type) {
+ case SUITE_SPARSE:
+#ifndef CERES_NO_SUITESPARSE
+ if (options.use_mixed_precision_solves) {
+ sparse_cholesky = FloatSuiteSparseCholesky::Create(ordering_type);
+ } else {
+ sparse_cholesky = SuiteSparseCholesky::Create(ordering_type);
+ }
+ break;
+#else
+ (void)ordering_type;
+ LOG(FATAL) << "Ceres was compiled without support for SuiteSparse.";
+#endif
+
+ case EIGEN_SPARSE:
+#ifdef CERES_USE_EIGEN_SPARSE
+ if (options.use_mixed_precision_solves) {
+ sparse_cholesky = FloatEigenSparseCholesky::Create(ordering_type);
+ } else {
+ sparse_cholesky = EigenSparseCholesky::Create(ordering_type);
+ }
+ break;
+#else
+ LOG(FATAL) << "Ceres was compiled without support for "
+ << "Eigen's sparse Cholesky factorization routines.";
+#endif
+
+ case CX_SPARSE:
+#ifndef CERES_NO_CXSPARSE
+ if (options.use_mixed_precision_solves) {
+ sparse_cholesky = FloatCXSparseCholesky::Create(ordering_type);
+ } else {
+ sparse_cholesky = CXSparseCholesky::Create(ordering_type);
+ }
+ break;
+#else
+ LOG(FATAL) << "Ceres was compiled without support for CXSparse.";
+#endif
+
+ case ACCELERATE_SPARSE:
+#ifndef CERES_NO_ACCELERATE_SPARSE
+ if (options.use_mixed_precision_solves) {
+ sparse_cholesky = AppleAccelerateCholesky<float>::Create(ordering_type);
+ } else {
+ sparse_cholesky = AppleAccelerateCholesky<double>::Create(ordering_type);
+ }
+ break;
+#else
+ LOG(FATAL) << "Ceres was compiled without support for Apple's Accelerate "
+ << "framework solvers.";
+#endif
+
+ default:
+ LOG(FATAL) << "Unknown sparse linear algebra library type : "
+ << SparseLinearAlgebraLibraryTypeToString(
+ options.sparse_linear_algebra_library_type);
+ }
+
+ if (options.max_num_refinement_iterations > 0) {
+ std::unique_ptr<IterativeRefiner> refiner(
+ new IterativeRefiner(options.max_num_refinement_iterations));
+ sparse_cholesky = std::unique_ptr<SparseCholesky>(new RefinedSparseCholesky(
+ std::move(sparse_cholesky), std::move(refiner)));
+ }
+ return sparse_cholesky;
+}
+
+SparseCholesky::~SparseCholesky() {}
+
+LinearSolverTerminationType SparseCholesky::FactorAndSolve(
+ CompressedRowSparseMatrix* lhs,
+ const double* rhs,
+ double* solution,
+ std::string* message) {
+ LinearSolverTerminationType termination_type = Factorize(lhs, message);
+ if (termination_type == LINEAR_SOLVER_SUCCESS) {
+ termination_type = Solve(rhs, solution, message);
+ }
+ return termination_type;
+}
+
+RefinedSparseCholesky::RefinedSparseCholesky(
+ std::unique_ptr<SparseCholesky> sparse_cholesky,
+ std::unique_ptr<IterativeRefiner> iterative_refiner)
+ : sparse_cholesky_(std::move(sparse_cholesky)),
+ iterative_refiner_(std::move(iterative_refiner)) {}
+
+RefinedSparseCholesky::~RefinedSparseCholesky() {}
+
+CompressedRowSparseMatrix::StorageType RefinedSparseCholesky::StorageType()
+ const {
+ return sparse_cholesky_->StorageType();
+}
+
+LinearSolverTerminationType RefinedSparseCholesky::Factorize(
+ CompressedRowSparseMatrix* lhs, std::string* message) {
+ lhs_ = lhs;
+ return sparse_cholesky_->Factorize(lhs, message);
+}
+
+LinearSolverTerminationType RefinedSparseCholesky::Solve(const double* rhs,
+ double* solution,
+ std::string* message) {
+ CHECK(lhs_ != nullptr);
+ auto termination_type = sparse_cholesky_->Solve(rhs, solution, message);
+ if (termination_type != LINEAR_SOLVER_SUCCESS) {
+ return termination_type;
+ }
+
+ iterative_refiner_->Refine(*lhs_, rhs, sparse_cholesky_.get(), solution);
+ return LINEAR_SOLVER_SUCCESS;
+}
+
+} // namespace internal
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/sparse_cholesky.h b/extern/ceres/internal/ceres/sparse_cholesky.h
new file mode 100644
index 00000000000..bbe42370505
--- /dev/null
+++ b/extern/ceres/internal/ceres/sparse_cholesky.h
@@ -0,0 +1,138 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2017 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#ifndef CERES_INTERNAL_SPARSE_CHOLESKY_H_
+#define CERES_INTERNAL_SPARSE_CHOLESKY_H_
+
+// This include must come before any #ifndef check on Ceres compile options.
+#include "ceres/internal/port.h"
+
+#include <memory>
+#include "ceres/linear_solver.h"
+#include "glog/logging.h"
+
+namespace ceres {
+namespace internal {
+
+// An interface that abstracts away the internal details of various
+// sparse linear algebra libraries and offers a simple API for solving
+// symmetric positive definite linear systems using a sparse Cholesky
+// factorization.
+//
+// Instances of SparseCholesky are expected to cache the symbolic
+// factorization of the linear system. They do this on the first call
+// to Factorize or FactorAndSolve. Subsequent calls to Factorize and
+// FactorAndSolve are expected to have the same sparsity structure.
+//
+// Example usage:
+//
+// std::unique_ptr<SparseCholesky>
+// sparse_cholesky(SparseCholesky::Create(SUITE_SPARSE, AMD));
+//
+// CompressedRowSparseMatrix lhs = ...;
+// std::string message;
+// CHECK_EQ(sparse_cholesky->Factorize(&lhs, &message), LINEAR_SOLVER_SUCCESS);
+// Vector rhs = ...;
+// Vector solution = ...;
+// CHECK_EQ(sparse_cholesky->Solve(rhs.data(), solution.data(), &message),
+// LINEAR_SOLVER_SUCCESS);
+
+class SparseCholesky {
+ public:
+ static std::unique_ptr<SparseCholesky> Create(
+ const LinearSolver::Options& options);
+
+ virtual ~SparseCholesky();
+
+ // Due to the symmetry of the linear system, sparse linear algebra
+ // libraries only use one half of the input matrix. Whether it is
+ // the upper or the lower triangular part of the matrix depends on
+ // the library and the re-ordering strategy being used. This
+ // function tells the user the storage type expected of the input
+ // matrix for the sparse linear algebra library and reordering
+ // strategy used.
+ virtual CompressedRowSparseMatrix::StorageType StorageType() const = 0;
+
+ // Computes the numeric factorization of the given matrix. If this
+ // is the first call to Factorize, first the symbolic factorization
+ // will be computed and cached and the numeric factorization will be
+ // computed based on that.
+ //
+ // Subsequent calls to Factorize will use that symbolic
+ // factorization assuming that the sparsity of the matrix has
+ // remained constant.
+ virtual LinearSolverTerminationType Factorize(
+ CompressedRowSparseMatrix* lhs, std::string* message) = 0;
+
+ // Computes the solution to the equation
+ //
+ // lhs * solution = rhs
+ virtual LinearSolverTerminationType Solve(const double* rhs,
+ double* solution,
+ std::string* message) = 0;
+
+ // Convenience method which combines a call to Factorize and
+ // Solve. Solve is only called if Factorize returns
+ // LINEAR_SOLVER_SUCCESS.
+ virtual LinearSolverTerminationType FactorAndSolve(
+ CompressedRowSparseMatrix* lhs,
+ const double* rhs,
+ double* solution,
+ std::string* message);
+
+};
+
+class IterativeRefiner;
+
+// Computes an initial solution using the given instance of
+// SparseCholesky, and then refines it using the IterativeRefiner.
+class RefinedSparseCholesky : public SparseCholesky {
+ public:
+ RefinedSparseCholesky(std::unique_ptr<SparseCholesky> sparse_cholesky,
+ std::unique_ptr<IterativeRefiner> iterative_refiner);
+ virtual ~RefinedSparseCholesky();
+
+ virtual CompressedRowSparseMatrix::StorageType StorageType() const;
+ virtual LinearSolverTerminationType Factorize(
+ CompressedRowSparseMatrix* lhs, std::string* message);
+ virtual LinearSolverTerminationType Solve(const double* rhs,
+ double* solution,
+ std::string* message);
+
+ private:
+ std::unique_ptr<SparseCholesky> sparse_cholesky_;
+ std::unique_ptr<IterativeRefiner> iterative_refiner_;
+ CompressedRowSparseMatrix* lhs_ = nullptr;
+};
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_SPARSE_CHOLESKY_H_
diff --git a/extern/ceres/internal/ceres/sparse_matrix.h b/extern/ceres/internal/ceres/sparse_matrix.h
index b3af1d06440..074d847807e 100644
--- a/extern/ceres/internal/ceres/sparse_matrix.h
+++ b/extern/ceres/internal/ceres/sparse_matrix.h
@@ -90,7 +90,7 @@ class SparseMatrix : public LinearOperator {
virtual void ToTextFile(FILE* file) const = 0;
// Accessors for the values array that stores the entries of the
- // sparse matrix. The exact interpreptation of the values of this
+ // sparse matrix. The exact interpretation of the values of this
// array depends on the particular kind of SparseMatrix being
// accessed.
virtual double* mutable_values() = 0;
diff --git a/extern/ceres/internal/ceres/sparse_normal_cholesky_solver.cc b/extern/ceres/internal/ceres/sparse_normal_cholesky_solver.cc
index a4c2c766ddc..0f2e589d041 100644
--- a/extern/ceres/internal/ceres/sparse_normal_cholesky_solver.cc
+++ b/extern/ceres/internal/ceres/sparse_normal_cholesky_solver.cc
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2017 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -33,461 +33,82 @@
#include <algorithm>
#include <cstring>
#include <ctime>
-#include <sstream>
+#include <memory>
-#include "ceres/compressed_row_sparse_matrix.h"
-#include "ceres/cxsparse.h"
+#include "ceres/block_sparse_matrix.h"
+#include "ceres/inner_product_computer.h"
#include "ceres/internal/eigen.h"
-#include "ceres/internal/scoped_ptr.h"
+#include "ceres/iterative_refiner.h"
#include "ceres/linear_solver.h"
-#include "ceres/suitesparse.h"
+#include "ceres/sparse_cholesky.h"
#include "ceres/triplet_sparse_matrix.h"
#include "ceres/types.h"
#include "ceres/wall_time.h"
-#include "Eigen/SparseCore"
-
-#ifdef CERES_USE_EIGEN_SPARSE
-#include "Eigen/SparseCholesky"
-#endif
namespace ceres {
namespace internal {
-namespace {
-
-#ifdef CERES_USE_EIGEN_SPARSE
-// A templated factorized and solve function, which allows us to use
-// the same code independent of whether a AMD or a Natural ordering is
-// used.
-template <typename SimplicialCholeskySolver, typename SparseMatrixType>
-LinearSolver::Summary SimplicialLDLTSolve(
- const SparseMatrixType& lhs,
- const bool do_symbolic_analysis,
- SimplicialCholeskySolver* solver,
- double* rhs_and_solution,
- EventLogger* event_logger) {
- LinearSolver::Summary summary;
- summary.num_iterations = 1;
- summary.termination_type = LINEAR_SOLVER_SUCCESS;
- summary.message = "Success.";
-
- if (do_symbolic_analysis) {
- solver->analyzePattern(lhs);
- if (VLOG_IS_ON(2)) {
- std::stringstream ss;
- solver->dumpMemory(ss);
- VLOG(2) << "Symbolic Analysis\n"
- << ss.str();
- }
- event_logger->AddEvent("Analyze");
- if (solver->info() != Eigen::Success) {
- summary.termination_type = LINEAR_SOLVER_FATAL_ERROR;
- summary.message =
- "Eigen failure. Unable to find symbolic factorization.";
- return summary;
- }
- }
-
- solver->factorize(lhs);
- event_logger->AddEvent("Factorize");
- if (solver->info() != Eigen::Success) {
- summary.termination_type = LINEAR_SOLVER_FAILURE;
- summary.message = "Eigen failure. Unable to find numeric factorization.";
- return summary;
- }
-
- const Vector rhs = VectorRef(rhs_and_solution, lhs.cols());
-
- VectorRef(rhs_and_solution, lhs.cols()) = solver->solve(rhs);
- event_logger->AddEvent("Solve");
- if (solver->info() != Eigen::Success) {
- summary.termination_type = LINEAR_SOLVER_FAILURE;
- summary.message = "Eigen failure. Unable to do triangular solve.";
- return summary;
- }
-
- return summary;
-}
-
-#endif // CERES_USE_EIGEN_SPARSE
-
-#ifndef CERES_NO_CXSPARSE
-LinearSolver::Summary ComputeNormalEquationsAndSolveUsingCXSparse(
- CompressedRowSparseMatrix* A,
- double * rhs_and_solution,
- EventLogger* event_logger) {
- LinearSolver::Summary summary;
- summary.num_iterations = 1;
- summary.termination_type = LINEAR_SOLVER_SUCCESS;
- summary.message = "Success.";
-
- CXSparse cxsparse;
-
- // Wrap the augmented Jacobian in a compressed sparse column matrix.
- cs_di a_transpose = cxsparse.CreateSparseMatrixTransposeView(A);
-
- // Compute the normal equations. J'J delta = J'f and solve them
- // using a sparse Cholesky factorization. Notice that when compared
- // to SuiteSparse we have to explicitly compute the transpose of Jt,
- // and then the normal equations before they can be
- // factorized. CHOLMOD/SuiteSparse on the other hand can just work
- // off of Jt to compute the Cholesky factorization of the normal
- // equations.
- cs_di* a = cxsparse.TransposeMatrix(&a_transpose);
- cs_di* lhs = cxsparse.MatrixMatrixMultiply(&a_transpose, a);
- cxsparse.Free(a);
- event_logger->AddEvent("NormalEquations");
-
- cs_dis* factor = cxsparse.AnalyzeCholesky(lhs);
- event_logger->AddEvent("Analysis");
-
- if (factor == NULL) {
- summary.termination_type = LINEAR_SOLVER_FATAL_ERROR;
- summary.message = "CXSparse::AnalyzeCholesky failed.";
- } else if (!cxsparse.SolveCholesky(lhs, factor, rhs_and_solution)) {
- summary.termination_type = LINEAR_SOLVER_FAILURE;
- summary.message = "CXSparse::SolveCholesky failed.";
- }
- event_logger->AddEvent("Solve");
-
- cxsparse.Free(lhs);
- cxsparse.Free(factor);
- event_logger->AddEvent("TearDown");
- return summary;
-}
-
-#endif // CERES_NO_CXSPARSE
-
-} // namespace
SparseNormalCholeskySolver::SparseNormalCholeskySolver(
const LinearSolver::Options& options)
- : factor_(NULL),
- cxsparse_factor_(NULL),
- options_(options) {
+ : options_(options) {
+ sparse_cholesky_ = SparseCholesky::Create(options);
}
-void SparseNormalCholeskySolver::FreeFactorization() {
- if (factor_ != NULL) {
- ss_.Free(factor_);
- factor_ = NULL;
- }
-
- if (cxsparse_factor_ != NULL) {
- cxsparse_.Free(cxsparse_factor_);
- cxsparse_factor_ = NULL;
- }
-}
-
-SparseNormalCholeskySolver::~SparseNormalCholeskySolver() {
- FreeFactorization();
-}
+SparseNormalCholeskySolver::~SparseNormalCholeskySolver() {}
LinearSolver::Summary SparseNormalCholeskySolver::SolveImpl(
- CompressedRowSparseMatrix* A,
+ BlockSparseMatrix* A,
const double* b,
const LinearSolver::PerSolveOptions& per_solve_options,
- double * x) {
-
- const int num_cols = A->num_cols();
- VectorRef(x, num_cols).setZero();
- A->LeftMultiply(b, x);
-
- if (per_solve_options.D != NULL) {
- // Temporarily append a diagonal block to the A matrix, but undo
- // it before returning the matrix to the user.
- scoped_ptr<CompressedRowSparseMatrix> regularizer;
- if (A->col_blocks().size() > 0) {
- regularizer.reset(CompressedRowSparseMatrix::CreateBlockDiagonalMatrix(
- per_solve_options.D, A->col_blocks()));
- } else {
- regularizer.reset(new CompressedRowSparseMatrix(
- per_solve_options.D, num_cols));
- }
- A->AppendRows(*regularizer);
- }
-
- LinearSolver::Summary summary;
- switch (options_.sparse_linear_algebra_library_type) {
- case SUITE_SPARSE:
- summary = SolveImplUsingSuiteSparse(A, x);
- break;
- case CX_SPARSE:
- summary = SolveImplUsingCXSparse(A, x);
- break;
- case EIGEN_SPARSE:
- summary = SolveImplUsingEigen(A, x);
- break;
- default:
- LOG(FATAL) << "Unknown sparse linear algebra library : "
- << options_.sparse_linear_algebra_library_type;
- }
-
- if (per_solve_options.D != NULL) {
- A->DeleteRows(num_cols);
- }
-
- return summary;
-}
-
-LinearSolver::Summary SparseNormalCholeskySolver::SolveImplUsingEigen(
- CompressedRowSparseMatrix* A,
- double * rhs_and_solution) {
-#ifndef CERES_USE_EIGEN_SPARSE
-
- LinearSolver::Summary summary;
- summary.num_iterations = 0;
- summary.termination_type = LINEAR_SOLVER_FATAL_ERROR;
- summary.message =
- "SPARSE_NORMAL_CHOLESKY cannot be used with EIGEN_SPARSE "
- "because Ceres was not built with support for "
- "Eigen's SimplicialLDLT decomposition. "
- "This requires enabling building with -DEIGENSPARSE=ON.";
- return summary;
-
-#else
-
- EventLogger event_logger("SparseNormalCholeskySolver::Eigen::Solve");
- // Compute the normal equations. J'J delta = J'f and solve them
- // using a sparse Cholesky factorization. Notice that when compared
- // to SuiteSparse we have to explicitly compute the normal equations
- // before they can be factorized. CHOLMOD/SuiteSparse on the other
- // hand can just work off of Jt to compute the Cholesky
- // factorization of the normal equations.
-
- if (options_.dynamic_sparsity) {
- // In the case where the problem has dynamic sparsity, it is not
- // worth using the ComputeOuterProduct routine, as the setup cost
- // is not amortized over multiple calls to Solve.
- Eigen::MappedSparseMatrix<double, Eigen::RowMajor> a(
- A->num_rows(),
- A->num_cols(),
- A->num_nonzeros(),
- A->mutable_rows(),
- A->mutable_cols(),
- A->mutable_values());
-
- Eigen::SparseMatrix<double> lhs = a.transpose() * a;
- Eigen::SimplicialLDLT<Eigen::SparseMatrix<double> > solver;
- return SimplicialLDLTSolve(lhs,
- true,
- &solver,
- rhs_and_solution,
- &event_logger);
- }
-
- if (outer_product_.get() == NULL) {
- outer_product_.reset(
- CompressedRowSparseMatrix::CreateOuterProductMatrixAndProgram(
- *A, &pattern_));
- }
-
- CompressedRowSparseMatrix::ComputeOuterProduct(
- *A, pattern_, outer_product_.get());
-
- // Map to an upper triangular column major matrix.
- //
- // outer_product_ is a compressed row sparse matrix and in lower
- // triangular form, when mapped to a compressed column sparse
- // matrix, it becomes an upper triangular matrix.
- Eigen::MappedSparseMatrix<double, Eigen::ColMajor> lhs(
- outer_product_->num_rows(),
- outer_product_->num_rows(),
- outer_product_->num_nonzeros(),
- outer_product_->mutable_rows(),
- outer_product_->mutable_cols(),
- outer_product_->mutable_values());
-
- bool do_symbolic_analysis = false;
-
- // If using post ordering or an old version of Eigen, we cannot
- // depend on a preordered jacobian, so we work with a SimplicialLDLT
- // decomposition with AMD ordering.
- if (options_.use_postordering ||
- !EIGEN_VERSION_AT_LEAST(3, 2, 2)) {
- if (amd_ldlt_.get() == NULL) {
- amd_ldlt_.reset(new SimplicialLDLTWithAMDOrdering);
- do_symbolic_analysis = true;
- }
-
- return SimplicialLDLTSolve(lhs,
- do_symbolic_analysis,
- amd_ldlt_.get(),
- rhs_and_solution,
- &event_logger);
- }
-
-#if EIGEN_VERSION_AT_LEAST(3,2,2)
- // The common case
- if (natural_ldlt_.get() == NULL) {
- natural_ldlt_.reset(new SimplicialLDLTWithNaturalOrdering);
- do_symbolic_analysis = true;
- }
-
- return SimplicialLDLTSolve(lhs,
- do_symbolic_analysis,
- natural_ldlt_.get(),
- rhs_and_solution,
- &event_logger);
-#endif
-
-#endif // EIGEN_USE_EIGEN_SPARSE
-}
-
-LinearSolver::Summary SparseNormalCholeskySolver::SolveImplUsingCXSparse(
- CompressedRowSparseMatrix* A,
- double * rhs_and_solution) {
-#ifdef CERES_NO_CXSPARSE
-
- LinearSolver::Summary summary;
- summary.num_iterations = 0;
- summary.termination_type = LINEAR_SOLVER_FATAL_ERROR;
- summary.message =
- "SPARSE_NORMAL_CHOLESKY cannot be used with CX_SPARSE "
- "because Ceres was not built with support for CXSparse. "
- "This requires enabling building with -DCXSPARSE=ON.";
-
- return summary;
-
-#else
-
- EventLogger event_logger("SparseNormalCholeskySolver::CXSparse::Solve");
- if (options_.dynamic_sparsity) {
- return ComputeNormalEquationsAndSolveUsingCXSparse(A,
- rhs_and_solution,
- &event_logger);
- }
-
+ double* x) {
+ EventLogger event_logger("SparseNormalCholeskySolver::Solve");
LinearSolver::Summary summary;
summary.num_iterations = 1;
summary.termination_type = LINEAR_SOLVER_SUCCESS;
summary.message = "Success.";
- // Compute the normal equations. J'J delta = J'f and solve them
- // using a sparse Cholesky factorization. Notice that when compared
- // to SuiteSparse we have to explicitly compute the normal equations
- // before they can be factorized. CHOLMOD/SuiteSparse on the other
- // hand can just work off of Jt to compute the Cholesky
- // factorization of the normal equations.
- if (outer_product_.get() == NULL) {
- outer_product_.reset(
- CompressedRowSparseMatrix::CreateOuterProductMatrixAndProgram(
- *A, &pattern_));
- }
-
- CompressedRowSparseMatrix::ComputeOuterProduct(
- *A, pattern_, outer_product_.get());
- cs_di lhs =
- cxsparse_.CreateSparseMatrixTransposeView(outer_product_.get());
-
- event_logger.AddEvent("Setup");
-
- // Compute symbolic factorization if not available.
- if (cxsparse_factor_ == NULL) {
- if (options_.use_postordering) {
- cxsparse_factor_ = cxsparse_.BlockAnalyzeCholesky(&lhs,
- A->col_blocks(),
- A->col_blocks());
- } else {
- cxsparse_factor_ = cxsparse_.AnalyzeCholeskyWithNaturalOrdering(&lhs);
- }
- }
- event_logger.AddEvent("Analysis");
-
- if (cxsparse_factor_ == NULL) {
- summary.termination_type = LINEAR_SOLVER_FATAL_ERROR;
- summary.message =
- "CXSparse failure. Unable to find symbolic factorization.";
- } else if (!cxsparse_.SolveCholesky(&lhs,
- cxsparse_factor_,
- rhs_and_solution)) {
- summary.termination_type = LINEAR_SOLVER_FAILURE;
- summary.message = "CXSparse::SolveCholesky failed.";
- }
- event_logger.AddEvent("Solve");
-
- return summary;
-#endif
-}
-
-LinearSolver::Summary SparseNormalCholeskySolver::SolveImplUsingSuiteSparse(
- CompressedRowSparseMatrix* A,
- double * rhs_and_solution) {
-#ifdef CERES_NO_SUITESPARSE
-
- LinearSolver::Summary summary;
- summary.num_iterations = 0;
- summary.termination_type = LINEAR_SOLVER_FATAL_ERROR;
- summary.message =
- "SPARSE_NORMAL_CHOLESKY cannot be used with SUITE_SPARSE "
- "because Ceres was not built with support for SuiteSparse. "
- "This requires enabling building with -DSUITESPARSE=ON.";
- return summary;
-
-#else
-
- EventLogger event_logger("SparseNormalCholeskySolver::SuiteSparse::Solve");
- LinearSolver::Summary summary;
- summary.termination_type = LINEAR_SOLVER_SUCCESS;
- summary.num_iterations = 1;
- summary.message = "Success.";
-
const int num_cols = A->num_cols();
- cholmod_sparse lhs = ss_.CreateSparseMatrixTransposeView(A);
- event_logger.AddEvent("Setup");
-
- if (options_.dynamic_sparsity) {
- FreeFactorization();
- }
+ VectorRef xref(x, num_cols);
+ xref.setZero();
+ rhs_.resize(num_cols);
+ rhs_.setZero();
+ A->LeftMultiply(b, rhs_.data());
+ event_logger.AddEvent("Compute RHS");
- if (factor_ == NULL) {
- if (options_.use_postordering) {
- factor_ = ss_.BlockAnalyzeCholesky(&lhs,
- A->col_blocks(),
- A->row_blocks(),
- &summary.message);
- } else {
- if (options_.dynamic_sparsity) {
- factor_ = ss_.AnalyzeCholesky(&lhs, &summary.message);
- } else {
- factor_ = ss_.AnalyzeCholeskyWithNaturalOrdering(&lhs,
- &summary.message);
- }
- }
+ if (per_solve_options.D != NULL) {
+ // Temporarily append a diagonal block to the A matrix, but undo
+ // it before returning the matrix to the user.
+ std::unique_ptr<BlockSparseMatrix> regularizer;
+ regularizer.reset(BlockSparseMatrix::CreateDiagonalMatrix(
+ per_solve_options.D, A->block_structure()->cols));
+ event_logger.AddEvent("Diagonal");
+ A->AppendRows(*regularizer);
+ event_logger.AddEvent("Append");
}
- event_logger.AddEvent("Analysis");
+ event_logger.AddEvent("Append Rows");
- if (factor_ == NULL) {
- summary.termination_type = LINEAR_SOLVER_FATAL_ERROR;
- // No need to set message as it has already been set by the
- // symbolic analysis routines above.
- return summary;
- }
+ if (inner_product_computer_.get() == NULL) {
+ inner_product_computer_.reset(
+ InnerProductComputer::Create(*A, sparse_cholesky_->StorageType()));
- summary.termination_type = ss_.Cholesky(&lhs, factor_, &summary.message);
- if (summary.termination_type != LINEAR_SOLVER_SUCCESS) {
- return summary;
+ event_logger.AddEvent("InnerProductComputer::Create");
}
- cholmod_dense* rhs = ss_.CreateDenseVector(rhs_and_solution,
- num_cols,
- num_cols);
- cholmod_dense* solution = ss_.Solve(factor_, rhs, &summary.message);
- event_logger.AddEvent("Solve");
+ inner_product_computer_->Compute();
+ event_logger.AddEvent("InnerProductComputer::Compute");
- ss_.Free(rhs);
- if (solution != NULL) {
- memcpy(rhs_and_solution, solution->x, num_cols * sizeof(*rhs_and_solution));
- ss_.Free(solution);
- } else {
- // No need to set message as it has already been set by the
- // numeric factorization routine above.
- summary.termination_type = LINEAR_SOLVER_FAILURE;
+ if (per_solve_options.D != NULL) {
+ A->DeleteRowBlocks(A->block_structure()->cols.size());
}
- event_logger.AddEvent("Teardown");
+ summary.termination_type = sparse_cholesky_->FactorAndSolve(
+ inner_product_computer_->mutable_result(),
+ rhs_.data(),
+ x,
+ &summary.message);
+ event_logger.AddEvent("SparseCholesky::FactorAndSolve");
return summary;
-#endif
}
-} // namespace internal
-} // namespace ceres
+} // namespace internal
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/sparse_normal_cholesky_solver.h b/extern/ceres/internal/ceres/sparse_normal_cholesky_solver.h
index 2a93bc56d29..cbff2bdb3f6 100644
--- a/extern/ceres/internal/ceres/sparse_normal_cholesky_solver.h
+++ b/extern/ceres/internal/ceres/sparse_normal_cholesky_solver.h
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2017 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -34,91 +34,40 @@
#ifndef CERES_INTERNAL_SPARSE_NORMAL_CHOLESKY_SOLVER_H_
#define CERES_INTERNAL_SPARSE_NORMAL_CHOLESKY_SOLVER_H_
-#include <vector>
-
// This include must come before any #ifndef check on Ceres compile options.
#include "ceres/internal/port.h"
-#include "ceres/internal/macros.h"
+#include <vector>
#include "ceres/linear_solver.h"
-#include "ceres/suitesparse.h"
-#include "ceres/cxsparse.h"
-
-#ifdef CERES_USE_EIGEN_SPARSE
-#include "Eigen/SparseCholesky"
-#endif
namespace ceres {
namespace internal {
class CompressedRowSparseMatrix;
+class InnerProductComputer;
+class SparseCholesky;
-// Solves the normal equations (A'A + D'D) x = A'b, using the CHOLMOD sparse
-// cholesky solver.
-class SparseNormalCholeskySolver : public CompressedRowSparseMatrixSolver {
+// Solves the normal equations (A'A + D'D) x = A'b, using the sparse
+// linear algebra library of the user's choice.
+class SparseNormalCholeskySolver : public BlockSparseMatrixSolver {
public:
explicit SparseNormalCholeskySolver(const LinearSolver::Options& options);
+ SparseNormalCholeskySolver(const SparseNormalCholeskySolver&) = delete;
+ void operator=(const SparseNormalCholeskySolver&) = delete;
+
virtual ~SparseNormalCholeskySolver();
private:
- virtual LinearSolver::Summary SolveImpl(
- CompressedRowSparseMatrix* A,
+ LinearSolver::Summary SolveImpl(
+ BlockSparseMatrix* A,
const double* b,
const LinearSolver::PerSolveOptions& options,
- double* x);
-
- LinearSolver::Summary SolveImplUsingSuiteSparse(
- CompressedRowSparseMatrix* A,
- double* rhs_and_solution);
-
-
- LinearSolver::Summary SolveImplUsingCXSparse(
- CompressedRowSparseMatrix* A,
- double* rhs_and_solution);
-
- LinearSolver::Summary SolveImplUsingEigen(
- CompressedRowSparseMatrix* A,
- double* rhs_and_solution);
-
- void FreeFactorization();
-
- SuiteSparse ss_;
- // Cached factorization
- cholmod_factor* factor_;
-
- CXSparse cxsparse_;
- // Cached factorization
- cs_dis* cxsparse_factor_;
-
-#ifdef CERES_USE_EIGEN_SPARSE
-
- // The preprocessor gymnastics here are dealing with the fact that
- // before version 3.2.2, Eigen did not support a third template
- // parameter to specify the ordering.
-#if EIGEN_VERSION_AT_LEAST(3,2,2)
- typedef Eigen::SimplicialLDLT<Eigen::SparseMatrix<double>, Eigen::Upper,
- Eigen::NaturalOrdering<int> >
- SimplicialLDLTWithNaturalOrdering;
- scoped_ptr<SimplicialLDLTWithNaturalOrdering> natural_ldlt_;
-
- typedef Eigen::SimplicialLDLT<Eigen::SparseMatrix<double>, Eigen::Upper,
- Eigen::AMDOrdering<int> >
- SimplicialLDLTWithAMDOrdering;
- scoped_ptr<SimplicialLDLTWithAMDOrdering> amd_ldlt_;
-
-#else
- typedef Eigen::SimplicialLDLT<Eigen::SparseMatrix<double>, Eigen::Upper>
- SimplicialLDLTWithAMDOrdering;
-
- scoped_ptr<SimplicialLDLTWithAMDOrdering> amd_ldlt_;
-#endif
-
-#endif
+ double* x) final;
- scoped_ptr<CompressedRowSparseMatrix> outer_product_;
- std::vector<int> pattern_;
const LinearSolver::Options options_;
- CERES_DISALLOW_COPY_AND_ASSIGN(SparseNormalCholeskySolver);
+ Vector rhs_;
+ std::unique_ptr<SparseCholesky> sparse_cholesky_;
+ std::unique_ptr<InnerProductComputer> inner_product_computer_;
};
} // namespace internal
diff --git a/extern/ceres/internal/ceres/split.cc b/extern/ceres/internal/ceres/split.cc
index 296c09a6440..3a09e866839 100644
--- a/extern/ceres/internal/ceres/split.cc
+++ b/extern/ceres/internal/ceres/split.cc
@@ -115,7 +115,7 @@ void SplitStringUsing(const string& full,
const char* delim,
vector<string>* result) {
result->reserve(result->size() + CalculateReserveForVector(full, delim));
- std::back_insert_iterator<vector<string> > it(*result);
+ std::back_insert_iterator<vector<string>> it(*result);
SplitStringToIteratorUsing(full, delim, it);
}
diff --git a/extern/ceres/internal/ceres/stringprintf.cc b/extern/ceres/internal/ceres/stringprintf.cc
index b3b7474d8f8..7a21f0e2118 100644
--- a/extern/ceres/internal/ceres/stringprintf.cc
+++ b/extern/ceres/internal/ceres/stringprintf.cc
@@ -43,28 +43,6 @@ namespace internal {
using std::string;
-// va_copy() was defined in the C99 standard. However, it did not appear in the
-// C++ standard until C++11. This means that if Ceres is being compiled with a
-// strict pre-C++11 standard (e.g. -std=c++03), va_copy() will NOT be defined,
-// as we are using the C++ compiler (it would however be defined if we were
-// using the C compiler). Note however that both GCC & Clang will in fact
-// define va_copy() when compiling for C++ if the C++ standard is not explicitly
-// specified (i.e. no -std=c++<XX> arg), even though it should not strictly be
-// defined unless -std=c++11 (or greater) was passed.
-#if !defined(va_copy)
-#if defined (__GNUC__)
-// On GCC/Clang, if va_copy() is not defined (C++ standard < C++11 explicitly
-// specified), use the internal __va_copy() version, which should be present
-// in even very old GCC versions.
-#define va_copy(d, s) __va_copy(d, s)
-#else
-// Some older versions of MSVC do not have va_copy(), in which case define it.
-// Although this is required for older MSVC versions, it should also work for
-// other non-GCC/Clang compilers which also do not defined va_copy().
-#define va_copy(d, s) ((d) = (s))
-#endif // defined (__GNUC__)
-#endif // !defined(va_copy)
-
void StringAppendV(string* dst, const char* format, va_list ap) {
// First try with a small fixed size buffer
char space[1024];
diff --git a/extern/ceres/internal/ceres/subset_preconditioner.cc b/extern/ceres/internal/ceres/subset_preconditioner.cc
new file mode 100644
index 00000000000..7c24ae9f288
--- /dev/null
+++ b/extern/ceres/internal/ceres/subset_preconditioner.cc
@@ -0,0 +1,117 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2017 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#include "ceres/subset_preconditioner.h"
+
+#include <memory>
+#include <string>
+#include "ceres/compressed_row_sparse_matrix.h"
+#include "ceres/inner_product_computer.h"
+#include "ceres/linear_solver.h"
+#include "ceres/sparse_cholesky.h"
+#include "ceres/types.h"
+
+namespace ceres {
+namespace internal {
+
+SubsetPreconditioner::SubsetPreconditioner(
+ const Preconditioner::Options& options, const BlockSparseMatrix& A)
+ : options_(options), num_cols_(A.num_cols()) {
+ CHECK_GE(options_.subset_preconditioner_start_row_block, 0)
+ << "Congratulations, you found a bug in Ceres. Please report it.";
+
+ LinearSolver::Options sparse_cholesky_options;
+ sparse_cholesky_options.sparse_linear_algebra_library_type =
+ options_.sparse_linear_algebra_library_type;
+ sparse_cholesky_options.use_postordering =
+ options_.use_postordering;
+ sparse_cholesky_ = SparseCholesky::Create(sparse_cholesky_options);
+}
+
+SubsetPreconditioner::~SubsetPreconditioner() {}
+
+void SubsetPreconditioner::RightMultiply(const double* x, double* y) const {
+ CHECK(x != nullptr);
+ CHECK(y != nullptr);
+ std::string message;
+ sparse_cholesky_->Solve(x, y, &message);
+}
+
+bool SubsetPreconditioner::UpdateImpl(const BlockSparseMatrix& A,
+ const double* D) {
+ BlockSparseMatrix* m = const_cast<BlockSparseMatrix*>(&A);
+ const CompressedRowBlockStructure* bs = m->block_structure();
+
+ // A = [P]
+ // [Q]
+
+ // Now add D to A if needed.
+ if (D != NULL) {
+ // A = [P]
+ // [Q]
+ // [D]
+ std::unique_ptr<BlockSparseMatrix> regularizer(
+ BlockSparseMatrix::CreateDiagonalMatrix(D, bs->cols));
+ m->AppendRows(*regularizer);
+ }
+
+ if (inner_product_computer_.get() == NULL) {
+ inner_product_computer_.reset(InnerProductComputer::Create(
+ *m,
+ options_.subset_preconditioner_start_row_block,
+ bs->rows.size(),
+ sparse_cholesky_->StorageType()));
+ }
+
+ // Compute inner_product = [Q'*Q + D'*D]
+ inner_product_computer_->Compute();
+
+ // Unappend D if needed.
+ if (D != NULL) {
+ // A = [P]
+ // [Q]
+ m->DeleteRowBlocks(bs->cols.size());
+ }
+
+ std::string message;
+ // Compute L. s.t., LL' = Q'*Q + D'*D
+ const LinearSolverTerminationType termination_type =
+ sparse_cholesky_->Factorize(inner_product_computer_->mutable_result(),
+ &message);
+ if (termination_type != LINEAR_SOLVER_SUCCESS) {
+ LOG(ERROR) << "Preconditioner factorization failed: " << message;
+ return false;
+ }
+
+ return true;
+}
+
+} // namespace internal
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/subset_preconditioner.h b/extern/ceres/internal/ceres/subset_preconditioner.h
new file mode 100644
index 00000000000..6f3c9ecd052
--- /dev/null
+++ b/extern/ceres/internal/ceres/subset_preconditioner.h
@@ -0,0 +1,91 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2017 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#ifndef CERES_INTERNAL_SUBSET_PRECONDITIONER_H_
+#define CERES_INTERNAL_SUBSET_PRECONDITIONER_H_
+
+#include <memory>
+#include "ceres/preconditioner.h"
+
+namespace ceres {
+namespace internal {
+
+class BlockSparseMatrix;
+class SparseCholesky;
+class InnerProductComputer;
+
+// Subset preconditioning, uses a subset of the rows of the Jacobian
+// to construct a preconditioner for the normal equations.
+//
+// To keep the interface simple, we assume that the matrix A has
+// already been re-ordered that the user wishes to some subset of the
+// bottom row blocks of the matrix as the preconditioner. This is
+// controlled by
+// Preconditioner::Options::subset_preconditioner_start_row_block.
+//
+// When using the subset preconditioner, all row blocks starting
+// from this row block are used to construct the preconditioner.
+//
+// More precisely the matrix A is horizontally partitioned as
+//
+// A = [P]
+// [Q]
+//
+// where P has subset_preconditioner_start_row_block row blocks,
+// and the preconditioner is the inverse of the matrix Q'Q.
+//
+// Obviously, the smaller this number, the more accurate and
+// computationally expensive this preconditioner will be.
+//
+// See the tests for example usage.
+class SubsetPreconditioner : public BlockSparseMatrixPreconditioner {
+ public:
+ SubsetPreconditioner(const Preconditioner::Options& options,
+ const BlockSparseMatrix& A);
+ virtual ~SubsetPreconditioner();
+
+ // Preconditioner interface
+ void RightMultiply(const double* x, double* y) const final;
+ int num_rows() const final { return num_cols_; }
+ int num_cols() const final { return num_cols_; }
+
+ private:
+ bool UpdateImpl(const BlockSparseMatrix& A, const double* D) final;
+
+ const Preconditioner::Options options_;
+ const int num_cols_;
+ std::unique_ptr<SparseCholesky> sparse_cholesky_;
+ std::unique_ptr<InnerProductComputer> inner_product_computer_;
+};
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_SUBSET_PRECONDITIONER_H_
diff --git a/extern/ceres/internal/ceres/suitesparse.cc b/extern/ceres/internal/ceres/suitesparse.cc
new file mode 100644
index 00000000000..190d1755add
--- /dev/null
+++ b/extern/ceres/internal/ceres/suitesparse.cc
@@ -0,0 +1,430 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+// This include must come before any #ifndef check on Ceres compile options.
+#include "ceres/internal/port.h"
+
+#ifndef CERES_NO_SUITESPARSE
+#include "ceres/suitesparse.h"
+
+#include <vector>
+
+#include "ceres/compressed_col_sparse_matrix_utils.h"
+#include "ceres/compressed_row_sparse_matrix.h"
+#include "ceres/linear_solver.h"
+#include "ceres/triplet_sparse_matrix.h"
+#include "cholmod.h"
+
+namespace ceres {
+namespace internal {
+
+using std::string;
+using std::vector;
+
+SuiteSparse::SuiteSparse() { cholmod_start(&cc_); }
+
+SuiteSparse::~SuiteSparse() { cholmod_finish(&cc_); }
+
+cholmod_sparse* SuiteSparse::CreateSparseMatrix(TripletSparseMatrix* A) {
+ cholmod_triplet triplet;
+
+ triplet.nrow = A->num_rows();
+ triplet.ncol = A->num_cols();
+ triplet.nzmax = A->max_num_nonzeros();
+ triplet.nnz = A->num_nonzeros();
+ triplet.i = reinterpret_cast<void*>(A->mutable_rows());
+ triplet.j = reinterpret_cast<void*>(A->mutable_cols());
+ triplet.x = reinterpret_cast<void*>(A->mutable_values());
+ triplet.stype = 0; // Matrix is not symmetric.
+ triplet.itype = CHOLMOD_INT;
+ triplet.xtype = CHOLMOD_REAL;
+ triplet.dtype = CHOLMOD_DOUBLE;
+
+ return cholmod_triplet_to_sparse(&triplet, triplet.nnz, &cc_);
+}
+
+cholmod_sparse* SuiteSparse::CreateSparseMatrixTranspose(
+ TripletSparseMatrix* A) {
+ cholmod_triplet triplet;
+
+ triplet.ncol = A->num_rows(); // swap row and columns
+ triplet.nrow = A->num_cols();
+ triplet.nzmax = A->max_num_nonzeros();
+ triplet.nnz = A->num_nonzeros();
+
+ // swap rows and columns
+ triplet.j = reinterpret_cast<void*>(A->mutable_rows());
+ triplet.i = reinterpret_cast<void*>(A->mutable_cols());
+ triplet.x = reinterpret_cast<void*>(A->mutable_values());
+ triplet.stype = 0; // Matrix is not symmetric.
+ triplet.itype = CHOLMOD_INT;
+ triplet.xtype = CHOLMOD_REAL;
+ triplet.dtype = CHOLMOD_DOUBLE;
+
+ return cholmod_triplet_to_sparse(&triplet, triplet.nnz, &cc_);
+}
+
+cholmod_sparse SuiteSparse::CreateSparseMatrixTransposeView(
+ CompressedRowSparseMatrix* A) {
+ cholmod_sparse m;
+ m.nrow = A->num_cols();
+ m.ncol = A->num_rows();
+ m.nzmax = A->num_nonzeros();
+ m.nz = nullptr;
+ m.p = reinterpret_cast<void*>(A->mutable_rows());
+ m.i = reinterpret_cast<void*>(A->mutable_cols());
+ m.x = reinterpret_cast<void*>(A->mutable_values());
+ m.z = nullptr;
+
+ if (A->storage_type() == CompressedRowSparseMatrix::LOWER_TRIANGULAR) {
+ m.stype = 1;
+ } else if (A->storage_type() == CompressedRowSparseMatrix::UPPER_TRIANGULAR) {
+ m.stype = -1;
+ } else {
+ m.stype = 0;
+ }
+
+ m.itype = CHOLMOD_INT;
+ m.xtype = CHOLMOD_REAL;
+ m.dtype = CHOLMOD_DOUBLE;
+ m.sorted = 1;
+ m.packed = 1;
+
+ return m;
+}
+
+cholmod_dense SuiteSparse::CreateDenseVectorView(const double* x, int size) {
+ cholmod_dense v;
+ v.nrow = size;
+ v.ncol = 1;
+ v.nzmax = size;
+ v.d = size;
+ v.x = const_cast<void*>(reinterpret_cast<const void*>(x));
+ v.xtype = CHOLMOD_REAL;
+ v.dtype = CHOLMOD_DOUBLE;
+ return v;
+}
+
+cholmod_dense* SuiteSparse::CreateDenseVector(const double* x,
+ int in_size,
+ int out_size) {
+ CHECK_LE(in_size, out_size);
+ cholmod_dense* v = cholmod_zeros(out_size, 1, CHOLMOD_REAL, &cc_);
+ if (x != nullptr) {
+ memcpy(v->x, x, in_size * sizeof(*x));
+ }
+ return v;
+}
+
+cholmod_factor* SuiteSparse::AnalyzeCholesky(cholmod_sparse* A,
+ string* message) {
+ // Cholmod can try multiple re-ordering strategies to find a fill
+ // reducing ordering. Here we just tell it use AMD with automatic
+ // matrix dependence choice of supernodal versus simplicial
+ // factorization.
+ cc_.nmethods = 1;
+ cc_.method[0].ordering = CHOLMOD_AMD;
+ cc_.supernodal = CHOLMOD_AUTO;
+
+ cholmod_factor* factor = cholmod_analyze(A, &cc_);
+ if (VLOG_IS_ON(2)) {
+ cholmod_print_common(const_cast<char*>("Symbolic Analysis"), &cc_);
+ }
+
+ if (cc_.status != CHOLMOD_OK) {
+ *message =
+ StringPrintf("cholmod_analyze failed. error code: %d", cc_.status);
+ return nullptr;
+ }
+
+ CHECK(factor != nullptr);
+ return factor;
+}
+
+cholmod_factor* SuiteSparse::BlockAnalyzeCholesky(cholmod_sparse* A,
+ const vector<int>& row_blocks,
+ const vector<int>& col_blocks,
+ string* message) {
+ vector<int> ordering;
+ if (!BlockAMDOrdering(A, row_blocks, col_blocks, &ordering)) {
+ return nullptr;
+ }
+ return AnalyzeCholeskyWithUserOrdering(A, ordering, message);
+}
+
+cholmod_factor* SuiteSparse::AnalyzeCholeskyWithUserOrdering(
+ cholmod_sparse* A, const vector<int>& ordering, string* message) {
+ CHECK_EQ(ordering.size(), A->nrow);
+
+ cc_.nmethods = 1;
+ cc_.method[0].ordering = CHOLMOD_GIVEN;
+
+ cholmod_factor* factor =
+ cholmod_analyze_p(A, const_cast<int*>(&ordering[0]), nullptr, 0, &cc_);
+ if (VLOG_IS_ON(2)) {
+ cholmod_print_common(const_cast<char*>("Symbolic Analysis"), &cc_);
+ }
+ if (cc_.status != CHOLMOD_OK) {
+ *message =
+ StringPrintf("cholmod_analyze failed. error code: %d", cc_.status);
+ return nullptr;
+ }
+
+ CHECK(factor != nullptr);
+ return factor;
+}
+
+cholmod_factor* SuiteSparse::AnalyzeCholeskyWithNaturalOrdering(
+ cholmod_sparse* A, string* message) {
+ cc_.nmethods = 1;
+ cc_.method[0].ordering = CHOLMOD_NATURAL;
+ cc_.postorder = 0;
+
+ cholmod_factor* factor = cholmod_analyze(A, &cc_);
+ if (VLOG_IS_ON(2)) {
+ cholmod_print_common(const_cast<char*>("Symbolic Analysis"), &cc_);
+ }
+ if (cc_.status != CHOLMOD_OK) {
+ *message =
+ StringPrintf("cholmod_analyze failed. error code: %d", cc_.status);
+ return nullptr;
+ }
+
+ CHECK(factor != nullptr);
+ return factor;
+}
+
+bool SuiteSparse::BlockAMDOrdering(const cholmod_sparse* A,
+ const vector<int>& row_blocks,
+ const vector<int>& col_blocks,
+ vector<int>* ordering) {
+ const int num_row_blocks = row_blocks.size();
+ const int num_col_blocks = col_blocks.size();
+
+ // Arrays storing the compressed column structure of the matrix
+ // incoding the block sparsity of A.
+ vector<int> block_cols;
+ vector<int> block_rows;
+
+ CompressedColumnScalarMatrixToBlockMatrix(reinterpret_cast<const int*>(A->i),
+ reinterpret_cast<const int*>(A->p),
+ row_blocks,
+ col_blocks,
+ &block_rows,
+ &block_cols);
+ cholmod_sparse_struct block_matrix;
+ block_matrix.nrow = num_row_blocks;
+ block_matrix.ncol = num_col_blocks;
+ block_matrix.nzmax = block_rows.size();
+ block_matrix.p = reinterpret_cast<void*>(&block_cols[0]);
+ block_matrix.i = reinterpret_cast<void*>(&block_rows[0]);
+ block_matrix.x = nullptr;
+ block_matrix.stype = A->stype;
+ block_matrix.itype = CHOLMOD_INT;
+ block_matrix.xtype = CHOLMOD_PATTERN;
+ block_matrix.dtype = CHOLMOD_DOUBLE;
+ block_matrix.sorted = 1;
+ block_matrix.packed = 1;
+
+ vector<int> block_ordering(num_row_blocks);
+ if (!cholmod_amd(&block_matrix, nullptr, 0, &block_ordering[0], &cc_)) {
+ return false;
+ }
+
+ BlockOrderingToScalarOrdering(row_blocks, block_ordering, ordering);
+ return true;
+}
+
+LinearSolverTerminationType SuiteSparse::Cholesky(cholmod_sparse* A,
+ cholmod_factor* L,
+ string* message) {
+ CHECK(A != nullptr);
+ CHECK(L != nullptr);
+
+ // Save the current print level and silence CHOLMOD, otherwise
+ // CHOLMOD is prone to dumping stuff to stderr, which can be
+ // distracting when the error (matrix is indefinite) is not a fatal
+ // failure.
+ const int old_print_level = cc_.print;
+ cc_.print = 0;
+
+ cc_.quick_return_if_not_posdef = 1;
+ int cholmod_status = cholmod_factorize(A, L, &cc_);
+ cc_.print = old_print_level;
+
+ switch (cc_.status) {
+ case CHOLMOD_NOT_INSTALLED:
+ *message = "CHOLMOD failure: Method not installed.";
+ return LINEAR_SOLVER_FATAL_ERROR;
+ case CHOLMOD_OUT_OF_MEMORY:
+ *message = "CHOLMOD failure: Out of memory.";
+ return LINEAR_SOLVER_FATAL_ERROR;
+ case CHOLMOD_TOO_LARGE:
+ *message = "CHOLMOD failure: Integer overflow occurred.";
+ return LINEAR_SOLVER_FATAL_ERROR;
+ case CHOLMOD_INVALID:
+ *message = "CHOLMOD failure: Invalid input.";
+ return LINEAR_SOLVER_FATAL_ERROR;
+ case CHOLMOD_NOT_POSDEF:
+ *message = "CHOLMOD warning: Matrix not positive definite.";
+ return LINEAR_SOLVER_FAILURE;
+ case CHOLMOD_DSMALL:
+ *message =
+ "CHOLMOD warning: D for LDL' or diag(L) or "
+ "LL' has tiny absolute value.";
+ return LINEAR_SOLVER_FAILURE;
+ case CHOLMOD_OK:
+ if (cholmod_status != 0) {
+ return LINEAR_SOLVER_SUCCESS;
+ }
+
+ *message =
+ "CHOLMOD failure: cholmod_factorize returned false "
+ "but cholmod_common::status is CHOLMOD_OK."
+ "Please report this to ceres-solver@googlegroups.com.";
+ return LINEAR_SOLVER_FATAL_ERROR;
+ default:
+ *message = StringPrintf(
+ "Unknown cholmod return code: %d. "
+ "Please report this to ceres-solver@googlegroups.com.",
+ cc_.status);
+ return LINEAR_SOLVER_FATAL_ERROR;
+ }
+
+ return LINEAR_SOLVER_FATAL_ERROR;
+}
+
+cholmod_dense* SuiteSparse::Solve(cholmod_factor* L,
+ cholmod_dense* b,
+ string* message) {
+ if (cc_.status != CHOLMOD_OK) {
+ *message = "cholmod_solve failed. CHOLMOD status is not CHOLMOD_OK";
+ return nullptr;
+ }
+
+ return cholmod_solve(CHOLMOD_A, L, b, &cc_);
+}
+
+bool SuiteSparse::ApproximateMinimumDegreeOrdering(cholmod_sparse* matrix,
+ int* ordering) {
+ return cholmod_amd(matrix, nullptr, 0, ordering, &cc_);
+}
+
+bool SuiteSparse::ConstrainedApproximateMinimumDegreeOrdering(
+ cholmod_sparse* matrix, int* constraints, int* ordering) {
+#ifndef CERES_NO_CAMD
+ return cholmod_camd(matrix, nullptr, 0, constraints, ordering, &cc_);
+#else
+ LOG(FATAL) << "Congratulations you have found a bug in Ceres."
+ << "Ceres Solver was compiled with SuiteSparse "
+ << "version 4.1.0 or less. Calling this function "
+ << "in that case is a bug. Please contact the"
+ << "the Ceres Solver developers.";
+ return false;
+#endif
+}
+
+std::unique_ptr<SparseCholesky> SuiteSparseCholesky::Create(
+ const OrderingType ordering_type) {
+ return std::unique_ptr<SparseCholesky>(new SuiteSparseCholesky(ordering_type));
+}
+
+SuiteSparseCholesky::SuiteSparseCholesky(const OrderingType ordering_type)
+ : ordering_type_(ordering_type), factor_(nullptr) {}
+
+SuiteSparseCholesky::~SuiteSparseCholesky() {
+ if (factor_ != nullptr) {
+ ss_.Free(factor_);
+ }
+}
+
+LinearSolverTerminationType SuiteSparseCholesky::Factorize(
+ CompressedRowSparseMatrix* lhs, string* message) {
+ if (lhs == nullptr) {
+ *message = "Failure: Input lhs is NULL.";
+ return LINEAR_SOLVER_FATAL_ERROR;
+ }
+
+ cholmod_sparse cholmod_lhs = ss_.CreateSparseMatrixTransposeView(lhs);
+
+ if (factor_ == nullptr) {
+ if (ordering_type_ == NATURAL) {
+ factor_ = ss_.AnalyzeCholeskyWithNaturalOrdering(&cholmod_lhs, message);
+ } else {
+ if (!lhs->col_blocks().empty() && !(lhs->row_blocks().empty())) {
+ factor_ = ss_.BlockAnalyzeCholesky(
+ &cholmod_lhs, lhs->col_blocks(), lhs->row_blocks(), message);
+ } else {
+ factor_ = ss_.AnalyzeCholesky(&cholmod_lhs, message);
+ }
+ }
+
+ if (factor_ == nullptr) {
+ return LINEAR_SOLVER_FATAL_ERROR;
+ }
+ }
+
+ return ss_.Cholesky(&cholmod_lhs, factor_, message);
+}
+
+CompressedRowSparseMatrix::StorageType SuiteSparseCholesky::StorageType()
+ const {
+ return ((ordering_type_ == NATURAL)
+ ? CompressedRowSparseMatrix::UPPER_TRIANGULAR
+ : CompressedRowSparseMatrix::LOWER_TRIANGULAR);
+}
+
+LinearSolverTerminationType SuiteSparseCholesky::Solve(const double* rhs,
+ double* solution,
+ string* message) {
+ // Error checking
+ if (factor_ == nullptr) {
+ *message = "Solve called without a call to Factorize first.";
+ return LINEAR_SOLVER_FATAL_ERROR;
+ }
+
+ const int num_cols = factor_->n;
+ cholmod_dense cholmod_rhs = ss_.CreateDenseVectorView(rhs, num_cols);
+ cholmod_dense* cholmod_dense_solution =
+ ss_.Solve(factor_, &cholmod_rhs, message);
+
+ if (cholmod_dense_solution == nullptr) {
+ return LINEAR_SOLVER_FAILURE;
+ }
+
+ memcpy(solution, cholmod_dense_solution->x, num_cols * sizeof(*solution));
+ ss_.Free(cholmod_dense_solution);
+ return LINEAR_SOLVER_SUCCESS;
+}
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_NO_SUITESPARSE
diff --git a/extern/ceres/internal/ceres/suitesparse.h b/extern/ceres/internal/ceres/suitesparse.h
index 380d76e003a..b77b296a66e 100644
--- a/extern/ceres/internal/ceres/suitesparse.h
+++ b/extern/ceres/internal/ceres/suitesparse.h
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2017 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -41,11 +41,11 @@
#include <cstring>
#include <string>
#include <vector>
-
+#include "SuiteSparseQR.hpp"
#include "ceres/linear_solver.h"
+#include "ceres/sparse_cholesky.h"
#include "cholmod.h"
#include "glog/logging.h"
-#include "SuiteSparseQR.hpp"
// Before SuiteSparse version 4.2.0, cholmod_camd was only enabled
// if SuiteSparse was compiled with Metis support. This makes
@@ -99,6 +99,11 @@ class SuiteSparse {
// use the SuiteSparse machinery to allocate memory.
cholmod_sparse CreateSparseMatrixTransposeView(CompressedRowSparseMatrix* A);
+ // Create a cholmod_dense vector around the contents of the array x.
+ // This is a shallow object, which refers to the contents of x and
+ // does not use the SuiteSparse machinery to allocate memory.
+ cholmod_dense CreateDenseVectorView(const double* x, int size);
+
// Given a vector x, build a cholmod_dense vector of size out_size
// with the first in_size entries copied from x. If x is NULL, then
// an all zeros vector is returned. Caller owns the result.
@@ -197,12 +202,12 @@ class SuiteSparse {
// doing sparse direct factorization of these matrices the
// fill-reducing ordering algorithms (in particular AMD) can either
// be run on the block or the scalar form of these matrices. The two
- // SuiteSparse::AnalyzeCholesky methods allows the the client to
+ // SuiteSparse::AnalyzeCholesky methods allows the client to
// compute the symbolic factorization of a matrix by either using
// AMD on the matrix or a user provided ordering of the rows.
//
// But since the underlying matrices are block oriented, it is worth
- // running AMD on just the block structre of these matrices and then
+ // running AMD on just the block structure of these matrices and then
// lifting these block orderings to a full scalar ordering. This
// preserves the block structure of the permuted matrix, and exposes
// more of the super-nodal structure of the matrix to the numerical
@@ -278,6 +283,27 @@ class SuiteSparse {
cholmod_common cc_;
};
+class SuiteSparseCholesky : public SparseCholesky {
+ public:
+ static std::unique_ptr<SparseCholesky> Create(
+ OrderingType ordering_type);
+
+ // SparseCholesky interface.
+ virtual ~SuiteSparseCholesky();
+ CompressedRowSparseMatrix::StorageType StorageType() const final;
+ LinearSolverTerminationType Factorize(
+ CompressedRowSparseMatrix* lhs, std::string* message) final;
+ LinearSolverTerminationType Solve(const double* rhs,
+ double* solution,
+ std::string* message) final;
+ private:
+ SuiteSparseCholesky(const OrderingType ordering_type);
+
+ const OrderingType ordering_type_;
+ SuiteSparse ss_;
+ cholmod_factor* factor_;
+};
+
} // namespace internal
} // namespace ceres
@@ -285,6 +311,9 @@ class SuiteSparse {
typedef void cholmod_factor;
+namespace ceres {
+namespace internal {
+
class SuiteSparse {
public:
// Defining this static function even when SuiteSparse is not
@@ -292,7 +321,7 @@ class SuiteSparse {
// without checking for the absence of the CERES_NO_CAMD symbol.
//
// This is safer because the symbol maybe missing due to a user
- // accidently not including suitesparse.h in their code when
+ // accidentally not including suitesparse.h in their code when
// checking for the symbol.
static bool IsConstrainedApproximateMinimumDegreeOrderingAvailable() {
return false;
@@ -301,6 +330,9 @@ class SuiteSparse {
void Free(void* arg) {}
};
+} // namespace internal
+} // namespace ceres
+
#endif // CERES_NO_SUITESPARSE
#endif // CERES_INTERNAL_SUITESPARSE_H_
diff --git a/extern/ceres/internal/ceres/thread_pool.cc b/extern/ceres/internal/ceres/thread_pool.cc
new file mode 100644
index 00000000000..5a52c9d06a6
--- /dev/null
+++ b/extern/ceres/internal/ceres/thread_pool.cc
@@ -0,0 +1,116 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2018 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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.
+//
+// Author: vitus@google.com (Michael Vitus)
+
+// This include must come before any #ifndef check on Ceres compile options.
+#include "ceres/internal/port.h"
+
+#ifdef CERES_USE_CXX_THREADS
+
+#include "ceres/thread_pool.h"
+
+#include <cmath>
+#include <limits>
+
+namespace ceres {
+namespace internal {
+namespace {
+
+// Constrain the total number of threads to the amount the hardware can support.
+int GetNumAllowedThreads(int requested_num_threads) {
+ return std::min(requested_num_threads, ThreadPool::MaxNumThreadsAvailable());
+}
+
+} // namespace
+
+int ThreadPool::MaxNumThreadsAvailable() {
+ const int num_hardware_threads = std::thread::hardware_concurrency();
+ // hardware_concurrency() can return 0 if the value is not well defined or not
+ // computable.
+ return num_hardware_threads == 0
+ ? std::numeric_limits<int>::max()
+ : num_hardware_threads;
+}
+
+ThreadPool::ThreadPool() { }
+
+ThreadPool::ThreadPool(int num_threads) {
+ Resize(num_threads);
+}
+
+ThreadPool::~ThreadPool() {
+ std::lock_guard<std::mutex> lock(thread_pool_mutex_);
+ // Signal the thread workers to stop and wait for them to finish all scheduled
+ // tasks.
+ Stop();
+ for (std::thread& thread : thread_pool_) {
+ thread.join();
+ }
+}
+
+void ThreadPool::Resize(int num_threads) {
+ std::lock_guard<std::mutex> lock(thread_pool_mutex_);
+
+ const int num_current_threads = thread_pool_.size();
+ if (num_current_threads >= num_threads) {
+ return;
+ }
+
+ const int create_num_threads =
+ GetNumAllowedThreads(num_threads) - num_current_threads;
+
+ for (int i = 0; i < create_num_threads; ++i) {
+ thread_pool_.push_back(std::thread(&ThreadPool::ThreadMainLoop, this));
+ }
+}
+
+void ThreadPool::AddTask(const std::function<void()>& func) {
+ task_queue_.Push(func);
+}
+
+int ThreadPool::Size() {
+ std::lock_guard<std::mutex> lock(thread_pool_mutex_);
+ return thread_pool_.size();
+}
+
+void ThreadPool::ThreadMainLoop() {
+ std::function<void()> task;
+ while (task_queue_.Wait(&task)) {
+ task();
+ }
+}
+
+void ThreadPool::Stop() {
+ task_queue_.StopWaiters();
+}
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_USE_CXX_THREADS
diff --git a/extern/ceres/internal/ceres/thread_pool.h b/extern/ceres/internal/ceres/thread_pool.h
new file mode 100644
index 00000000000..1ebb52eb6b4
--- /dev/null
+++ b/extern/ceres/internal/ceres/thread_pool.h
@@ -0,0 +1,120 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2018 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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.
+//
+// Author: vitus@google.com (Michael Vitus)
+
+#ifndef CERES_INTERNAL_THREAD_POOL_H_
+#define CERES_INTERNAL_THREAD_POOL_H_
+
+#include <functional>
+#include <mutex>
+#include <thread>
+#include <vector>
+
+#include "ceres/concurrent_queue.h"
+
+namespace ceres {
+namespace internal {
+
+// A thread-safe thread pool with an unbounded task queue and a resizable number
+// of workers. The size of the thread pool can be increased but never decreased
+// in order to support the largest number of threads requested. The ThreadPool
+// has three states:
+//
+// (1) The thread pool size is zero. Tasks may be added to the thread pool via
+// AddTask but they will not be executed until the thread pool is resized.
+//
+// (2) The thread pool size is greater than zero. Tasks may be added to the
+// thread pool and will be executed as soon as a worker is available. The
+// thread pool may be resized while the thread pool is running.
+//
+// (3) The thread pool is destructing. The thread pool will signal all the
+// workers to stop. The workers will finish all of the tasks that have already
+// been added to the thread pool.
+//
+class ThreadPool {
+ public:
+ // Returns the maximum number of hardware threads.
+ static int MaxNumThreadsAvailable();
+
+ // Default constructor with no active threads. We allow instantiating a
+ // thread pool with no threads to support the use case of single threaded
+ // Ceres where everything will be executed on the main thread. For single
+ // threaded execution this has two benefits: avoid any overhead as threads
+ // are expensive to create, and no unused threads shown in the debugger.
+ ThreadPool();
+
+ // Instantiates a thread pool with min(MaxNumThreadsAvailable, num_threads)
+ // number of threads.
+ explicit ThreadPool(int num_threads);
+
+ // Signals the workers to stop and waits for them to finish any tasks that
+ // have been scheduled.
+ ~ThreadPool();
+
+ // Resizes the thread pool if it is currently less than the requested number
+ // of threads. The thread pool will be resized to min(MaxNumThreadsAvailable,
+ // num_threads) number of threads. Resize does not support reducing the
+ // thread pool size. If a smaller number of threads is requested, the thread
+ // pool remains the same size. The thread pool is reused within Ceres with
+ // different number of threads, and we need to ensure we can support the
+ // largest number of threads requested. It is safe to resize the thread pool
+ // while the workers are executing tasks, and the resizing is guaranteed to
+ // complete upon return.
+ void Resize(int num_threads);
+
+ // Adds a task to the queue and wakes up a blocked thread. If the thread pool
+ // size is greater than zero, then the task will be executed by a currently
+ // idle thread or when a thread becomes available. If the thread pool has no
+ // threads, then the task will never be executed and the user should use
+ // Resize() to create a non-empty thread pool.
+ void AddTask(const std::function<void()>& func);
+
+ // Returns the current size of the thread pool.
+ int Size();
+
+ private:
+ // Main loop for the threads which blocks on the task queue until work becomes
+ // available. It will return if and only if Stop has been called.
+ void ThreadMainLoop();
+
+ // Signal all the threads to stop. It does not block until the threads are
+ // finished.
+ void Stop();
+
+ // The queue that stores the units of work available for the thread pool. The
+ // task queue maintains its own thread safety.
+ ConcurrentQueue<std::function<void()>> task_queue_;
+ std::vector<std::thread> thread_pool_;
+ std::mutex thread_pool_mutex_;
+};
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_THREAD_POOL_H_
diff --git a/extern/ceres/internal/ceres/thread_token_provider.cc b/extern/ceres/internal/ceres/thread_token_provider.cc
new file mode 100644
index 00000000000..b04cf844488
--- /dev/null
+++ b/extern/ceres/internal/ceres/thread_token_provider.cc
@@ -0,0 +1,76 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2017 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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.
+//
+// Author: yp@photonscore.de (Yury Prokazov)
+
+#include "ceres/thread_token_provider.h"
+
+#ifdef CERES_USE_OPENMP
+#include <omp.h>
+#endif
+
+namespace ceres {
+namespace internal {
+
+ThreadTokenProvider::ThreadTokenProvider(int num_threads) {
+ (void)num_threads;
+#ifdef CERES_USE_CXX_THREADS
+ for (int i = 0; i < num_threads; i++) {
+ pool_.Push(i);
+ }
+#endif
+
+}
+
+int ThreadTokenProvider::Acquire() {
+#ifdef CERES_USE_OPENMP
+ return omp_get_thread_num();
+#endif
+
+#ifdef CERES_NO_THREADS
+ return 0;
+#endif
+
+#ifdef CERES_USE_CXX_THREADS
+ int thread_id;
+ CHECK(pool_.Wait(&thread_id));
+ return thread_id;
+#endif
+
+}
+
+void ThreadTokenProvider::Release(int thread_id) {
+ (void)thread_id;
+#ifdef CERES_USE_CXX_THREADS
+ pool_.Push(thread_id);
+#endif
+
+}
+
+} // namespace internal
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/thread_token_provider.h b/extern/ceres/internal/ceres/thread_token_provider.h
new file mode 100644
index 00000000000..06dc0438572
--- /dev/null
+++ b/extern/ceres/internal/ceres/thread_token_provider.h
@@ -0,0 +1,97 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2017 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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.
+//
+// Author: yp@photonscore.de (Yury Prokazov)
+
+#ifndef CERES_INTERNAL_THREAD_TOKEN_PROVIDER_H_
+#define CERES_INTERNAL_THREAD_TOKEN_PROVIDER_H_
+
+#include "ceres/internal/config.h"
+#include "ceres/internal/port.h"
+
+#ifdef CERES_USE_CXX_THREADS
+#include "ceres/concurrent_queue.h"
+#endif
+
+namespace ceres {
+namespace internal {
+
+// Helper for C++ thread number identification that is similar to
+// omp_get_thread_num() behaviour. This is necessary to support C++
+// threading with a sequential thread id. This is used to access preallocated
+// resources in the parallelized code parts. The sequence of tokens varies from
+// 0 to num_threads - 1 that can be acquired to identify the thread in a thread
+// pool.
+//
+// If CERES_NO_THREADS is defined, Acquire() always returns 0 and Release()
+// takes no action.
+//
+// If CERES_USE_OPENMP, omp_get_thread_num() is used to Acquire() with no action
+// in Release()
+//
+//
+// Example usage pseudocode:
+//
+// ThreadTokenProvider ttp(N); // allocate N tokens
+// Spawn N threads {
+// int token = ttp.Acquire(); // get unique token
+// ...
+// ... use token to access resources bound to the thread
+// ...
+// ttp.Release(token); // return token to the pool
+// }
+//
+class ThreadTokenProvider {
+ public:
+ ThreadTokenProvider(int num_threads);
+
+ // Returns the first token from the queue. The acquired value must be
+ // given back by Release().
+ int Acquire();
+
+ // Makes previously acquired token available for other threads.
+ void Release(int thread_id);
+
+ private:
+#ifdef CERES_USE_CXX_THREADS
+ // This queue initially holds a sequence from 0..num_threads-1. Every
+ // Acquire() call the first number is removed from here. When the token is not
+ // needed anymore it shall be given back with corresponding Release()
+ // call. This concurrent queue is more expensive than TBB's version, so you
+ // should not acquire the thread ID on every for loop iteration.
+ ConcurrentQueue<int> pool_;
+#endif
+
+ ThreadTokenProvider(ThreadTokenProvider&);
+ ThreadTokenProvider& operator=(ThreadTokenProvider&);
+};
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_THREAD_TOKEN_PROVIDER_H_
diff --git a/extern/ceres/internal/ceres/triplet_sparse_matrix.cc b/extern/ceres/internal/ceres/triplet_sparse_matrix.cc
index 8df405ca115..54b588ba466 100644
--- a/extern/ceres/internal/ceres/triplet_sparse_matrix.cc
+++ b/extern/ceres/internal/ceres/triplet_sparse_matrix.cc
@@ -32,9 +32,10 @@
#include <algorithm>
#include <cstddef>
+
#include "ceres/internal/eigen.h"
#include "ceres/internal/port.h"
-#include "ceres/internal/scoped_ptr.h"
+#include "ceres/random.h"
#include "ceres/types.h"
#include "glog/logging.h"
@@ -45,10 +46,8 @@ TripletSparseMatrix::TripletSparseMatrix()
: num_rows_(0),
num_cols_(0),
max_num_nonzeros_(0),
- num_nonzeros_(0),
- rows_(NULL),
- cols_(NULL),
- values_(NULL) {}
+ num_nonzeros_(0) {}
+
TripletSparseMatrix::~TripletSparseMatrix() {}
@@ -58,10 +57,7 @@ TripletSparseMatrix::TripletSparseMatrix(int num_rows,
: num_rows_(num_rows),
num_cols_(num_cols),
max_num_nonzeros_(max_num_nonzeros),
- num_nonzeros_(0),
- rows_(NULL),
- cols_(NULL),
- values_(NULL) {
+ num_nonzeros_(0) {
// All the sizes should at least be zero
CHECK_GE(num_rows, 0);
CHECK_GE(num_cols, 0);
@@ -69,21 +65,41 @@ TripletSparseMatrix::TripletSparseMatrix(int num_rows,
AllocateMemory();
}
+TripletSparseMatrix::TripletSparseMatrix(const int num_rows,
+ const int num_cols,
+ const std::vector<int>& rows,
+ const std::vector<int>& cols,
+ const std::vector<double>& values)
+ : num_rows_(num_rows),
+ num_cols_(num_cols),
+ max_num_nonzeros_(values.size()),
+ num_nonzeros_(values.size()) {
+ // All the sizes should at least be zero
+ CHECK_GE(num_rows, 0);
+ CHECK_GE(num_cols, 0);
+ CHECK_EQ(rows.size(), cols.size());
+ CHECK_EQ(rows.size(), values.size());
+ AllocateMemory();
+ std::copy(rows.begin(), rows.end(), rows_.get());
+ std::copy(cols.begin(), cols.end(), cols_.get());
+ std::copy(values.begin(), values.end(), values_.get());
+}
+
TripletSparseMatrix::TripletSparseMatrix(const TripletSparseMatrix& orig)
: SparseMatrix(),
num_rows_(orig.num_rows_),
num_cols_(orig.num_cols_),
max_num_nonzeros_(orig.max_num_nonzeros_),
- num_nonzeros_(orig.num_nonzeros_),
- rows_(NULL),
- cols_(NULL),
- values_(NULL) {
+ num_nonzeros_(orig.num_nonzeros_) {
AllocateMemory();
CopyData(orig);
}
TripletSparseMatrix& TripletSparseMatrix::operator=(
const TripletSparseMatrix& rhs) {
+ if (this == &rhs) {
+ return *this;
+ }
num_rows_ = rhs.num_rows_;
num_cols_ = rhs.num_cols_;
num_nonzeros_ = rhs.num_nonzeros_;
@@ -165,7 +181,7 @@ void TripletSparseMatrix::LeftMultiply(const double* x, double* y) const {
}
void TripletSparseMatrix::SquaredColumnNorm(double* x) const {
- CHECK_NOTNULL(x);
+ CHECK(x != nullptr);
VectorRef(x, num_cols_).setZero();
for (int i = 0; i < num_nonzeros_; ++i) {
x[cols_[i]] += values_[i] * values_[i];
@@ -173,7 +189,7 @@ void TripletSparseMatrix::SquaredColumnNorm(double* x) const {
}
void TripletSparseMatrix::ScaleColumns(const double* scale) {
- CHECK_NOTNULL(scale);
+ CHECK(scale != nullptr);
for (int i = 0; i < num_nonzeros_; ++i) {
values_[i] = values_[i] * scale[cols_[i]];
}
@@ -254,11 +270,40 @@ TripletSparseMatrix* TripletSparseMatrix::CreateSparseDiagonalMatrix(
}
void TripletSparseMatrix::ToTextFile(FILE* file) const {
- CHECK_NOTNULL(file);
+ CHECK(file != nullptr);
for (int i = 0; i < num_nonzeros_; ++i) {
fprintf(file, "% 10d % 10d %17f\n", rows_[i], cols_[i], values_[i]);
}
}
+TripletSparseMatrix* TripletSparseMatrix::CreateRandomMatrix(
+ const TripletSparseMatrix::RandomMatrixOptions& options) {
+ CHECK_GT(options.num_rows, 0);
+ CHECK_GT(options.num_cols, 0);
+ CHECK_GT(options.density, 0.0);
+ CHECK_LE(options.density, 1.0);
+
+ std::vector<int> rows;
+ std::vector<int> cols;
+ std::vector<double> values;
+ while (rows.empty()) {
+ rows.clear();
+ cols.clear();
+ values.clear();
+ for (int r = 0; r < options.num_rows; ++r) {
+ for (int c = 0; c < options.num_cols; ++c) {
+ if (RandDouble() <= options.density) {
+ rows.push_back(r);
+ cols.push_back(c);
+ values.push_back(RandNormal());
+ }
+ }
+ }
+ }
+
+ return new TripletSparseMatrix(
+ options.num_rows, options.num_cols, rows, cols, values);
+}
+
} // namespace internal
} // namespace ceres
diff --git a/extern/ceres/internal/ceres/triplet_sparse_matrix.h b/extern/ceres/internal/ceres/triplet_sparse_matrix.h
index f3f5370df6f..2ee0fa992b5 100644
--- a/extern/ceres/internal/ceres/triplet_sparse_matrix.h
+++ b/extern/ceres/internal/ceres/triplet_sparse_matrix.h
@@ -31,9 +31,10 @@
#ifndef CERES_INTERNAL_TRIPLET_SPARSE_MATRIX_H_
#define CERES_INTERNAL_TRIPLET_SPARSE_MATRIX_H_
+#include <memory>
+#include <vector>
#include "ceres/sparse_matrix.h"
#include "ceres/internal/eigen.h"
-#include "ceres/internal/scoped_ptr.h"
#include "ceres/types.h"
namespace ceres {
@@ -47,26 +48,32 @@ class TripletSparseMatrix : public SparseMatrix {
public:
TripletSparseMatrix();
TripletSparseMatrix(int num_rows, int num_cols, int max_num_nonzeros);
+ TripletSparseMatrix(int num_rows,
+ int num_cols,
+ const std::vector<int>& rows,
+ const std::vector<int>& cols,
+ const std::vector<double>& values);
+
explicit TripletSparseMatrix(const TripletSparseMatrix& orig);
TripletSparseMatrix& operator=(const TripletSparseMatrix& rhs);
- ~TripletSparseMatrix();
+ virtual ~TripletSparseMatrix();
// Implementation of the SparseMatrix interface.
- virtual void SetZero();
- virtual void RightMultiply(const double* x, double* y) const;
- virtual void LeftMultiply(const double* x, double* y) const;
- virtual void SquaredColumnNorm(double* x) const;
- virtual void ScaleColumns(const double* scale);
- virtual void ToDenseMatrix(Matrix* dense_matrix) const;
- virtual void ToTextFile(FILE* file) const;
- virtual int num_rows() const { return num_rows_; }
- virtual int num_cols() const { return num_cols_; }
- virtual int num_nonzeros() const { return num_nonzeros_; }
- virtual const double* values() const { return values_.get(); }
- virtual double* mutable_values() { return values_.get(); }
- virtual void set_num_nonzeros(int num_nonzeros);
+ void SetZero() final;
+ void RightMultiply(const double* x, double* y) const final;
+ void LeftMultiply(const double* x, double* y) const final;
+ void SquaredColumnNorm(double* x) const final;
+ void ScaleColumns(const double* scale) final;
+ void ToDenseMatrix(Matrix* dense_matrix) const final;
+ void ToTextFile(FILE* file) const final;
+ int num_rows() const final { return num_rows_; }
+ int num_cols() const final { return num_cols_; }
+ int num_nonzeros() const final { return num_nonzeros_; }
+ const double* values() const final { return values_.get(); }
+ double* mutable_values() final { return values_.get(); }
+ void set_num_nonzeros(int num_nonzeros);
// Increase max_num_nonzeros and correspondingly increase the size
// of rows_, cols_ and values_. If new_max_num_nonzeros is smaller
@@ -105,6 +112,25 @@ class TripletSparseMatrix : public SparseMatrix {
static TripletSparseMatrix* CreateSparseDiagonalMatrix(const double* values,
int num_rows);
+ // Options struct to control the generation of random
+ // TripletSparseMatrix objects.
+ struct RandomMatrixOptions {
+ int num_rows;
+ int num_cols;
+ // 0 < density <= 1 is the probability of an entry being
+ // structurally non-zero. A given random matrix will not have
+ // precisely this density.
+ double density;
+ };
+
+ // Create a random CompressedRowSparseMatrix whose entries are
+ // normally distributed and whose structure is determined by
+ // RandomMatrixOptions.
+ //
+ // Caller owns the result.
+ static TripletSparseMatrix* CreateRandomMatrix(
+ const TripletSparseMatrix::RandomMatrixOptions& options);
+
private:
void AllocateMemory();
void CopyData(const TripletSparseMatrix& orig);
@@ -118,9 +144,9 @@ class TripletSparseMatrix : public SparseMatrix {
// stored at the location (rows_[i], cols_[i]). If the there are
// multiple entries with the same (rows_[i], cols_[i]), the values_
// entries corresponding to them are summed up.
- scoped_array<int> rows_;
- scoped_array<int> cols_;
- scoped_array<double> values_;
+ std::unique_ptr<int[]> rows_;
+ std::unique_ptr<int[]> cols_;
+ std::unique_ptr<double[]> values_;
};
} // namespace internal
diff --git a/extern/ceres/internal/ceres/trust_region_minimizer.cc b/extern/ceres/internal/ceres/trust_region_minimizer.cc
index d809906ab54..7065977ad77 100644
--- a/extern/ceres/internal/ceres/trust_region_minimizer.cc
+++ b/extern/ceres/internal/ceres/trust_region_minimizer.cc
@@ -35,6 +35,7 @@
#include <cstdlib>
#include <cstring>
#include <limits>
+#include <memory>
#include <string>
#include <vector>
@@ -92,7 +93,8 @@ void TrustRegionMinimizer::Minimize(const Minimizer::Options& options,
continue;
}
- if (options_.is_constrained) {
+ if (options_.is_constrained &&
+ options_.max_num_line_search_step_size_iterations > 0) {
// Use a projected line search to enforce the bounds constraints
// and improve the quality of the step.
DoLineSearch(x_, gradient_, x_cost_, &delta_);
@@ -135,13 +137,16 @@ void TrustRegionMinimizer::Init(const Minimizer::Options& options,
solver_summary_->num_unsuccessful_steps = 0;
solver_summary_->is_constrained = options.is_constrained;
- evaluator_ = CHECK_NOTNULL(options_.evaluator.get());
- jacobian_ = CHECK_NOTNULL(options_.jacobian.get());
- strategy_ = CHECK_NOTNULL(options_.trust_region_strategy.get());
+ CHECK(options_.evaluator != nullptr);
+ CHECK(options_.jacobian != nullptr);
+ CHECK(options_.trust_region_strategy != nullptr);
+ evaluator_ = options_.evaluator.get();
+ jacobian_ = options_.jacobian.get();
+ strategy_ = options_.trust_region_strategy.get();
is_not_silent_ = !options.is_silent;
inner_iterations_are_enabled_ =
- options.inner_iteration_minimizer.get() != NULL;
+ options.inner_iteration_minimizer.get() != nullptr;
inner_iterations_were_useful_ = false;
num_parameters_ = evaluator_->NumParameters();
@@ -201,7 +206,7 @@ bool TrustRegionMinimizer::IterationZero() {
x_norm_ = x_.norm();
}
- if (!EvaluateGradientAndJacobian()) {
+ if (!EvaluateGradientAndJacobian(/*new_evaluation_point=*/true)) {
return false;
}
@@ -223,8 +228,12 @@ bool TrustRegionMinimizer::IterationZero() {
// Returns true if all computations could be performed
// successfully. Any failures are considered fatal and the
// Solver::Summary is updated to indicate this.
-bool TrustRegionMinimizer::EvaluateGradientAndJacobian() {
- if (!evaluator_->Evaluate(x_.data(),
+bool TrustRegionMinimizer::EvaluateGradientAndJacobian(
+ bool new_evaluation_point) {
+ Evaluator::EvaluateOptions evaluate_options;
+ evaluate_options.new_evaluation_point = new_evaluation_point;
+ if (!evaluator_->Evaluate(evaluate_options,
+ x_.data(),
&x_cost_,
residuals_.data(),
gradient_.data(),
@@ -482,8 +491,11 @@ void TrustRegionMinimizer::DoInnerIterationsIfNeeded() {
options_.inner_iteration_minimizer->Minimize(
options_, inner_iteration_x_.data(), &inner_iteration_summary);
double inner_iteration_cost;
- if (!evaluator_->Evaluate(
- inner_iteration_x_.data(), &inner_iteration_cost, NULL, NULL, NULL)) {
+ if (!evaluator_->Evaluate(inner_iteration_x_.data(),
+ &inner_iteration_cost,
+ nullptr,
+ nullptr,
+ nullptr)) {
VLOG_IF(2, is_not_silent_) << "Inner iteration failed.";
return;
}
@@ -569,8 +581,8 @@ void TrustRegionMinimizer::DoLineSearch(const Vector& x,
line_search_options.function = &line_search_function;
std::string message;
- scoped_ptr<LineSearch> line_search(CHECK_NOTNULL(
- LineSearch::Create(ceres::ARMIJO, line_search_options, &message)));
+ std::unique_ptr<LineSearch> line_search(
+ LineSearch::Create(ceres::ARMIJO, line_search_options, &message));
LineSearch::Summary line_search_summary;
line_search_function.Init(x, *delta);
line_search->Search(1.0, cost, gradient.dot(*delta), &line_search_summary);
@@ -586,7 +598,7 @@ void TrustRegionMinimizer::DoLineSearch(const Vector& x,
line_search_summary.total_time_in_seconds;
if (line_search_summary.success) {
- *delta *= line_search_summary.optimal_step_size;
+ *delta *= line_search_summary.optimal_point.x;
}
}
@@ -601,10 +613,11 @@ bool TrustRegionMinimizer::MaxSolverTimeReached() {
return false;
}
- solver_summary_->message = StringPrintf("Maximum solver time reached. "
- "Total solver time: %e >= %e.",
- total_solver_time,
- options_.max_solver_time_in_seconds);
+ solver_summary_->message = StringPrintf(
+ "Maximum solver time reached. "
+ "Total solver time: %e >= %e.",
+ total_solver_time,
+ options_.max_solver_time_in_seconds);
solver_summary_->termination_type = NO_CONVERGENCE;
VLOG_IF(1, is_not_silent_) << "Terminating: " << solver_summary_->message;
return true;
@@ -618,10 +631,10 @@ bool TrustRegionMinimizer::MaxSolverIterationsReached() {
return false;
}
- solver_summary_->message =
- StringPrintf("Maximum number of iterations reached. "
- "Number of iterations: %d.",
- iteration_summary_.iteration);
+ solver_summary_->message = StringPrintf(
+ "Maximum number of iterations reached. "
+ "Number of iterations: %d.",
+ iteration_summary_.iteration);
solver_summary_->termination_type = NO_CONVERGENCE;
VLOG_IF(1, is_not_silent_) << "Terminating: " << solver_summary_->message;
@@ -653,11 +666,11 @@ bool TrustRegionMinimizer::MinTrustRegionRadiusReached() {
return false;
}
- solver_summary_->message =
- StringPrintf("Minimum trust region radius reached. "
- "Trust region radius: %e <= %e",
- iteration_summary_.trust_region_radius,
- options_.min_trust_region_radius);
+ solver_summary_->message = StringPrintf(
+ "Minimum trust region radius reached. "
+ "Trust region radius: %e <= %e",
+ iteration_summary_.trust_region_radius,
+ options_.min_trust_region_radius);
solver_summary_->termination_type = CONVERGENCE;
VLOG_IF(1, is_not_silent_) << "Terminating: " << solver_summary_->message;
return true;
@@ -725,7 +738,7 @@ void TrustRegionMinimizer::ComputeCandidatePointAndEvaluateCost() {
}
if (!evaluator_->Evaluate(
- candidate_x_.data(), &candidate_cost_, NULL, NULL, NULL)) {
+ candidate_x_.data(), &candidate_cost_, nullptr, nullptr, nullptr)) {
LOG_IF(WARNING, is_not_silent_)
<< "Step failed to evaluate. "
<< "Treating it as a step with infinite cost";
@@ -746,7 +759,7 @@ bool TrustRegionMinimizer::IsStepSuccessful() {
// small.
//
// This can cause the trust region loop to reject this step. To
- // get around this, we expicitly check if the inner iterations
+ // get around this, we explicitly check if the inner iterations
// led to a net decrease in the objective function value. If
// they did, we accept the step even if the trust region ratio
// is small.
@@ -768,7 +781,9 @@ bool TrustRegionMinimizer::HandleSuccessfulStep() {
x_ = candidate_x_;
x_norm_ = x_.norm();
- if (!EvaluateGradientAndJacobian()) {
+ // Since the step was successful, this point has already had the residual
+ // evaluated (but not the jacobian). So indicate that to the evaluator.
+ if (!EvaluateGradientAndJacobian(/*new_evaluation_point=*/false)) {
return false;
}
diff --git a/extern/ceres/internal/ceres/trust_region_minimizer.h b/extern/ceres/internal/ceres/trust_region_minimizer.h
index 43141da58a1..b5c41225ddc 100644
--- a/extern/ceres/internal/ceres/trust_region_minimizer.h
+++ b/extern/ceres/internal/ceres/trust_region_minimizer.h
@@ -31,8 +31,8 @@
#ifndef CERES_INTERNAL_TRUST_REGION_MINIMIZER_H_
#define CERES_INTERNAL_TRUST_REGION_MINIMIZER_H_
+#include <memory>
#include "ceres/internal/eigen.h"
-#include "ceres/internal/scoped_ptr.h"
#include "ceres/minimizer.h"
#include "ceres/solver.h"
#include "ceres/sparse_matrix.h"
@@ -51,9 +51,9 @@ class TrustRegionMinimizer : public Minimizer {
~TrustRegionMinimizer();
// This method is not thread safe.
- virtual void Minimize(const Minimizer::Options& options,
- double* parameters,
- Solver::Summary* solver_summary);
+ void Minimize(const Minimizer::Options& options,
+ double* parameters,
+ Solver::Summary* solver_summary) override;
private:
void Init(const Minimizer::Options& options,
@@ -63,7 +63,7 @@ class TrustRegionMinimizer : public Minimizer {
bool FinalizeIterationAndCheckIfMinimizerCanContinue();
bool ComputeTrustRegionStep();
- bool EvaluateGradientAndJacobian();
+ bool EvaluateGradientAndJacobian(bool new_evaluation_point);
void ComputeCandidatePointAndEvaluateCost();
void DoLineSearch(const Vector& x,
@@ -94,7 +94,7 @@ class TrustRegionMinimizer : public Minimizer {
SparseMatrix* jacobian_;
TrustRegionStrategy* strategy_;
- scoped_ptr<TrustRegionStepEvaluator> step_evaluator_;
+ std::unique_ptr<TrustRegionStepEvaluator> step_evaluator_;
bool is_not_silent_;
bool inner_iterations_are_enabled_;
diff --git a/extern/ceres/internal/ceres/trust_region_preprocessor.cc b/extern/ceres/internal/ceres/trust_region_preprocessor.cc
index 4020e4ca115..b8c6b49d1ca 100644
--- a/extern/ceres/internal/ceres/trust_region_preprocessor.cc
+++ b/extern/ceres/internal/ceres/trust_region_preprocessor.cc
@@ -32,7 +32,9 @@
#include <numeric>
#include <string>
+
#include "ceres/callbacks.h"
+#include "ceres/context_impl.h"
#include "ceres/evaluator.h"
#include "ceres/linear_solver.h"
#include "ceres/minimizer.h"
@@ -56,8 +58,7 @@ namespace {
ParameterBlockOrdering* CreateDefaultLinearSolverOrdering(
const Program& program) {
ParameterBlockOrdering* ordering = new ParameterBlockOrdering;
- const vector<ParameterBlock*>& parameter_blocks =
- program.parameter_blocks();
+ const vector<ParameterBlock*>& parameter_blocks = program.parameter_blocks();
for (int i = 0; i < parameter_blocks.size(); ++i) {
ordering->AddElementToGroup(
const_cast<double*>(parameter_blocks[i]->user_state()), 0);
@@ -68,8 +69,7 @@ ParameterBlockOrdering* CreateDefaultLinearSolverOrdering(
// Check if all the user supplied values in the parameter blocks are
// sane or not, and if the program is feasible or not.
bool IsProgramValid(const Program& program, std::string* error) {
- return (program.ParameterBlocksAreFinite(error) &&
- program.IsFeasible(error));
+ return (program.ParameterBlocksAreFinite(error) && program.IsFeasible(error));
}
void AlternateLinearSolverAndPreconditionerForSchurTypeLinearSolver(
@@ -81,36 +81,33 @@ void AlternateLinearSolverAndPreconditionerForSchurTypeLinearSolver(
const LinearSolverType linear_solver_type_given = options->linear_solver_type;
const PreconditionerType preconditioner_type_given =
options->preconditioner_type;
- options->linear_solver_type = LinearSolver::LinearSolverForZeroEBlocks(
- linear_solver_type_given);
+ options->linear_solver_type =
+ LinearSolver::LinearSolverForZeroEBlocks(linear_solver_type_given);
std::string message;
if (linear_solver_type_given == ITERATIVE_SCHUR) {
- options->preconditioner_type = Preconditioner::PreconditionerForZeroEBlocks(
- preconditioner_type_given);
+ options->preconditioner_type =
+ Preconditioner::PreconditionerForZeroEBlocks(preconditioner_type_given);
message =
- StringPrintf(
- "No E blocks. Switching from %s(%s) to %s(%s).",
- LinearSolverTypeToString(linear_solver_type_given),
- PreconditionerTypeToString(preconditioner_type_given),
- LinearSolverTypeToString(options->linear_solver_type),
- PreconditionerTypeToString(options->preconditioner_type));
+ StringPrintf("No E blocks. Switching from %s(%s) to %s(%s).",
+ LinearSolverTypeToString(linear_solver_type_given),
+ PreconditionerTypeToString(preconditioner_type_given),
+ LinearSolverTypeToString(options->linear_solver_type),
+ PreconditionerTypeToString(options->preconditioner_type));
} else {
message =
- StringPrintf(
- "No E blocks. Switching from %s to %s.",
- LinearSolverTypeToString(linear_solver_type_given),
- LinearSolverTypeToString(options->linear_solver_type));
+ StringPrintf("No E blocks. Switching from %s to %s.",
+ LinearSolverTypeToString(linear_solver_type_given),
+ LinearSolverTypeToString(options->linear_solver_type));
}
VLOG_IF(1, options->logging_type != SILENT) << message;
}
-// For Schur type and SPARSE_NORMAL_CHOLESKY linear solvers, reorder
-// the program to reduce fill-in and increase cache coherency.
+// Reorder the program to reduce fill-in and increase cache coherency.
bool ReorderProgram(PreprocessedProblem* pp) {
- Solver::Options& options = pp->options;
+ const Solver::Options& options = pp->options;
if (IsSchurType(options.linear_solver_type)) {
return ReorderProgramForSchurTypeLinearSolver(
options.linear_solver_type,
@@ -123,9 +120,25 @@ bool ReorderProgram(PreprocessedProblem* pp) {
if (options.linear_solver_type == SPARSE_NORMAL_CHOLESKY &&
!options.dynamic_sparsity) {
- return ReorderProgramForSparseNormalCholesky(
+ return ReorderProgramForSparseCholesky(
options.sparse_linear_algebra_library_type,
*options.linear_solver_ordering,
+ 0, /* use all the rows of the jacobian */
+ pp->reduced_program.get(),
+ &pp->error);
+ }
+
+ if (options.linear_solver_type == CGNR &&
+ options.preconditioner_type == SUBSET) {
+ pp->linear_solver_options.subset_preconditioner_start_row_block =
+ ReorderResidualBlocksByPartition(
+ options.residual_blocks_for_subset_preconditioner,
+ pp->reduced_program.get());
+
+ return ReorderProgramForSparseCholesky(
+ options.sparse_linear_algebra_library_type,
+ *options.linear_solver_ordering,
+ pp->linear_solver_options.subset_preconditioner_start_row_block,
pp->reduced_program.get(),
&pp->error);
}
@@ -139,7 +152,9 @@ bool ReorderProgram(PreprocessedProblem* pp) {
// too.
bool SetupLinearSolver(PreprocessedProblem* pp) {
Solver::Options& options = pp->options;
- if (options.linear_solver_ordering.get() == NULL) {
+ pp->linear_solver_options = LinearSolver::Options();
+
+ if (!options.linear_solver_ordering) {
// If the user has not supplied a linear solver ordering, then we
// assume that they are giving all the freedom to us in choosing
// the best possible ordering. This intent can be indicated by
@@ -163,8 +178,7 @@ bool SetupLinearSolver(PreprocessedProblem* pp) {
ordering->Remove(pp->removed_parameter_blocks);
if (IsSchurType(options.linear_solver_type) &&
min_group_id != ordering->MinNonZeroGroup()) {
- AlternateLinearSolverAndPreconditionerForSchurTypeLinearSolver(
- &options);
+ AlternateLinearSolverAndPreconditionerForSchurTypeLinearSolver(&options);
}
}
@@ -175,7 +189,6 @@ bool SetupLinearSolver(PreprocessedProblem* pp) {
}
// Configure the linear solver.
- pp->linear_solver_options = LinearSolver::Options();
pp->linear_solver_options.min_num_iterations =
options.min_linear_solver_iterations;
pp->linear_solver_options.max_num_iterations =
@@ -191,33 +204,50 @@ bool SetupLinearSolver(PreprocessedProblem* pp) {
pp->linear_solver_options.use_explicit_schur_complement =
options.use_explicit_schur_complement;
pp->linear_solver_options.dynamic_sparsity = options.dynamic_sparsity;
- pp->linear_solver_options.num_threads = options.num_linear_solver_threads;
-
- // Ignore user's postordering preferences and force it to be true if
- // cholmod_camd is not available. This ensures that the linear
- // solver does not assume that a fill-reducing pre-ordering has been
- // done.
+ pp->linear_solver_options.use_mixed_precision_solves =
+ options.use_mixed_precision_solves;
+ pp->linear_solver_options.max_num_refinement_iterations =
+ options.max_num_refinement_iterations;
+ pp->linear_solver_options.num_threads = options.num_threads;
pp->linear_solver_options.use_postordering = options.use_postordering;
- if (options.linear_solver_type == SPARSE_SCHUR &&
- options.sparse_linear_algebra_library_type == SUITE_SPARSE &&
- !SuiteSparse::IsConstrainedApproximateMinimumDegreeOrderingAvailable()) {
- pp->linear_solver_options.use_postordering = true;
- }
-
- OrderingToGroupSizes(options.linear_solver_ordering.get(),
- &pp->linear_solver_options.elimination_groups);
+ pp->linear_solver_options.context = pp->problem->context();
+
+ if (IsSchurType(pp->linear_solver_options.type)) {
+ OrderingToGroupSizes(options.linear_solver_ordering.get(),
+ &pp->linear_solver_options.elimination_groups);
+
+ // Schur type solvers expect at least two elimination groups. If
+ // there is only one elimination group, then it is guaranteed that
+ // this group only contains e_blocks. Thus we add a dummy
+ // elimination group with zero blocks in it.
+ if (pp->linear_solver_options.elimination_groups.size() == 1) {
+ pp->linear_solver_options.elimination_groups.push_back(0);
+ }
- // Schur type solvers expect at least two elimination groups. If
- // there is only one elimination group, then it is guaranteed that
- // this group only contains e_blocks. Thus we add a dummy
- // elimination group with zero blocks in it.
- if (IsSchurType(pp->linear_solver_options.type) &&
- pp->linear_solver_options.elimination_groups.size() == 1) {
- pp->linear_solver_options.elimination_groups.push_back(0);
+ if (options.linear_solver_type == SPARSE_SCHUR) {
+ // When using SPARSE_SCHUR, we ignore the user's postordering
+ // preferences in certain cases.
+ //
+ // 1. SUITE_SPARSE is the sparse linear algebra library requested
+ // but cholmod_camd is not available.
+ // 2. CX_SPARSE is the sparse linear algebra library requested.
+ //
+ // This ensures that the linear solver does not assume that a
+ // fill-reducing pre-ordering has been done.
+ //
+ // TODO(sameeragarwal): Implement the reordering of parameter
+ // blocks for CX_SPARSE.
+ if ((options.sparse_linear_algebra_library_type == SUITE_SPARSE &&
+ !SuiteSparse::
+ IsConstrainedApproximateMinimumDegreeOrderingAvailable()) ||
+ (options.sparse_linear_algebra_library_type == CX_SPARSE)) {
+ pp->linear_solver_options.use_postordering = true;
+ }
+ }
}
pp->linear_solver.reset(LinearSolver::Create(pp->linear_solver_options));
- return (pp->linear_solver.get() != NULL);
+ return (pp->linear_solver != nullptr);
}
// Configure and create the evaluator.
@@ -228,19 +258,20 @@ bool SetupEvaluator(PreprocessedProblem* pp) {
pp->evaluator_options.num_eliminate_blocks = 0;
if (IsSchurType(options.linear_solver_type)) {
pp->evaluator_options.num_eliminate_blocks =
- options
- .linear_solver_ordering
- ->group_to_elements().begin()
- ->second.size();
+ options.linear_solver_ordering->group_to_elements()
+ .begin()
+ ->second.size();
}
pp->evaluator_options.num_threads = options.num_threads;
pp->evaluator_options.dynamic_sparsity = options.dynamic_sparsity;
- pp->evaluator.reset(Evaluator::Create(pp->evaluator_options,
- pp->reduced_program.get(),
- &pp->error));
+ pp->evaluator_options.context = pp->problem->context();
+ pp->evaluator_options.evaluation_callback =
+ pp->reduced_program->mutable_evaluation_callback();
+ pp->evaluator.reset(Evaluator::Create(
+ pp->evaluator_options, pp->reduced_program.get(), &pp->error));
- return (pp->evaluator.get() != NULL);
+ return (pp->evaluator != nullptr);
}
// If the user requested inner iterations, then find an inner
@@ -252,6 +283,11 @@ bool SetupInnerIterationMinimizer(PreprocessedProblem* pp) {
return true;
}
+ if (pp->reduced_program->mutable_evaluation_callback()) {
+ pp->error = "Inner iterations cannot be used with EvaluationCallbacks";
+ return false;
+ }
+
// With just one parameter block, the outer iteration of the trust
// region method and inner iterations are doing exactly the same
// thing, and thus inner iterations are not needed.
@@ -261,7 +297,7 @@ bool SetupInnerIterationMinimizer(PreprocessedProblem* pp) {
return true;
}
- if (options.inner_iteration_ordering.get() != NULL) {
+ if (options.inner_iteration_ordering != nullptr) {
// If the user supplied an ordering, then remove the set of
// inactive parameter blocks from it
options.inner_iteration_ordering->Remove(pp->removed_parameter_blocks);
@@ -283,7 +319,8 @@ bool SetupInnerIterationMinimizer(PreprocessedProblem* pp) {
CoordinateDescentMinimizer::CreateOrdering(*pp->reduced_program));
}
- pp->inner_iteration_minimizer.reset(new CoordinateDescentMinimizer);
+ pp->inner_iteration_minimizer.reset(
+ new CoordinateDescentMinimizer(pp->problem->context()));
return pp->inner_iteration_minimizer->Init(*pp->reduced_program,
pp->problem->parameter_map(),
*options.inner_iteration_ordering,
@@ -303,8 +340,7 @@ void SetupMinimizerOptions(PreprocessedProblem* pp) {
TrustRegionStrategy::Options strategy_options;
strategy_options.linear_solver = pp->linear_solver.get();
- strategy_options.initial_radius =
- options.initial_trust_region_radius;
+ strategy_options.initial_radius = options.initial_trust_region_radius;
strategy_options.max_radius = options.max_trust_region_radius;
strategy_options.min_lm_diagonal = options.min_lm_diagonal;
strategy_options.max_lm_diagonal = options.max_lm_diagonal;
@@ -312,18 +348,18 @@ void SetupMinimizerOptions(PreprocessedProblem* pp) {
options.trust_region_strategy_type;
strategy_options.dogleg_type = options.dogleg_type;
pp->minimizer_options.trust_region_strategy.reset(
- CHECK_NOTNULL(TrustRegionStrategy::Create(strategy_options)));
+ TrustRegionStrategy::Create(strategy_options));
+ CHECK(pp->minimizer_options.trust_region_strategy != nullptr);
}
} // namespace
-TrustRegionPreprocessor::~TrustRegionPreprocessor() {
-}
+TrustRegionPreprocessor::~TrustRegionPreprocessor() {}
bool TrustRegionPreprocessor::Preprocess(const Solver::Options& options,
ProblemImpl* problem,
PreprocessedProblem* pp) {
- CHECK_NOTNULL(pp);
+ CHECK(pp != nullptr);
pp->options = options;
ChangeNumThreadsIfNeeded(&pp->options);
@@ -333,10 +369,8 @@ bool TrustRegionPreprocessor::Preprocess(const Solver::Options& options,
return false;
}
- pp->reduced_program.reset(
- program->CreateReducedProgram(&pp->removed_parameter_blocks,
- &pp->fixed_cost,
- &pp->error));
+ pp->reduced_program.reset(program->CreateReducedProgram(
+ &pp->removed_parameter_blocks, &pp->fixed_cost, &pp->error));
if (pp->reduced_program.get() == NULL) {
return false;
@@ -348,8 +382,7 @@ bool TrustRegionPreprocessor::Preprocess(const Solver::Options& options,
return true;
}
- if (!SetupLinearSolver(pp) ||
- !SetupEvaluator(pp) ||
+ if (!SetupLinearSolver(pp) || !SetupEvaluator(pp) ||
!SetupInnerIterationMinimizer(pp)) {
return false;
}
diff --git a/extern/ceres/internal/ceres/trust_region_preprocessor.h b/extern/ceres/internal/ceres/trust_region_preprocessor.h
index a6631ab3d40..9597905ae9a 100644
--- a/extern/ceres/internal/ceres/trust_region_preprocessor.h
+++ b/extern/ceres/internal/ceres/trust_region_preprocessor.h
@@ -39,9 +39,9 @@ namespace internal {
class TrustRegionPreprocessor : public Preprocessor {
public:
virtual ~TrustRegionPreprocessor();
- virtual bool Preprocess(const Solver::Options& options,
- ProblemImpl* problem,
- PreprocessedProblem* preprocessed_problem);
+ bool Preprocess(const Solver::Options& options,
+ ProblemImpl* problem,
+ PreprocessedProblem* preprocessed_problem) override;
};
} // namespace internal
diff --git a/extern/ceres/internal/ceres/trust_region_step_evaluator.cc b/extern/ceres/internal/ceres/trust_region_step_evaluator.cc
index c9167e623ef..33b0c41ead6 100644
--- a/extern/ceres/internal/ceres/trust_region_step_evaluator.cc
+++ b/extern/ceres/internal/ceres/trust_region_step_evaluator.cc
@@ -29,6 +29,7 @@
// Author: sameeragarwal@google.com (Sameer Agarwal)
#include <algorithm>
+#include <limits>
#include "ceres/trust_region_step_evaluator.h"
#include "glog/logging.h"
@@ -51,6 +52,15 @@ TrustRegionStepEvaluator::TrustRegionStepEvaluator(
double TrustRegionStepEvaluator::StepQuality(
const double cost,
const double model_cost_change) const {
+ // If the function evaluation for this step was a failure, in which
+ // case the TrustRegionMinimizer would have set the cost to
+ // std::numeric_limits<double>::max(). In this case, the division by
+ // model_cost_change can result in an overflow. To prevent that from
+ // happening, we will deal with this case explicitly.
+ if (cost >= std::numeric_limits<double>::max()) {
+ return std::numeric_limits<double>::lowest();
+ }
+
const double relative_decrease = (current_cost_ - cost) / model_cost_change;
const double historical_relative_decrease =
(reference_cost_ - cost) /
diff --git a/extern/ceres/internal/ceres/trust_region_step_evaluator.h b/extern/ceres/internal/ceres/trust_region_step_evaluator.h
index 06df102a308..03c00362dac 100644
--- a/extern/ceres/internal/ceres/trust_region_step_evaluator.h
+++ b/extern/ceres/internal/ceres/trust_region_step_evaluator.h
@@ -56,7 +56,7 @@ namespace internal {
// The parameter max_consecutive_nonmonotonic_steps controls the
// window size used by the step selection algorithm to accept
// non-monotonic steps. Setting this parameter to zero, recovers the
-// classic montonic descent algorithm.
+// classic monotonic descent algorithm.
//
// Based on algorithm 10.1.2 (page 357) of "Trust Region
// Methods" by Conn Gould & Toint, or equations 33-40 of
@@ -82,7 +82,7 @@ class TrustRegionStepEvaluator {
// max_consecutive_nonmonotonic_steps controls the window size used
// by the step selection algorithm to accept non-monotonic
// steps. Setting this parameter to zero, recovers the classic
- // montonic descent algorithm.
+ // monotonic descent algorithm.
TrustRegionStepEvaluator(double initial_cost,
int max_consecutive_nonmonotonic_steps);
diff --git a/extern/ceres/internal/ceres/trust_region_strategy.h b/extern/ceres/internal/ceres/trust_region_strategy.h
index 36e8e981cc0..5751691e5ec 100644
--- a/extern/ceres/internal/ceres/trust_region_strategy.h
+++ b/extern/ceres/internal/ceres/trust_region_strategy.h
@@ -56,43 +56,34 @@ class SparseMatrix;
class TrustRegionStrategy {
public:
struct Options {
- Options()
- : trust_region_strategy_type(LEVENBERG_MARQUARDT),
- initial_radius(1e4),
- max_radius(1e32),
- min_lm_diagonal(1e-6),
- max_lm_diagonal(1e32),
- dogleg_type(TRADITIONAL_DOGLEG) {
- }
-
- TrustRegionStrategyType trust_region_strategy_type;
+ TrustRegionStrategyType trust_region_strategy_type = LEVENBERG_MARQUARDT;
// Linear solver used for actually solving the trust region step.
- LinearSolver* linear_solver;
- double initial_radius;
- double max_radius;
+ LinearSolver* linear_solver = nullptr;
+ double initial_radius = 1e4;
+ double max_radius = 1e32;
// Minimum and maximum values of the diagonal damping matrix used
// by LevenbergMarquardtStrategy. The DoglegStrategy also uses
// these bounds to construct a regularizing diagonal to ensure
// that the Gauss-Newton step computation is of full rank.
- double min_lm_diagonal;
- double max_lm_diagonal;
+ double min_lm_diagonal = 1e-6;
+ double max_lm_diagonal = 1e32;
// Further specify which dogleg method to use
- DoglegType dogleg_type;
+ DoglegType dogleg_type = TRADITIONAL_DOGLEG;
};
+ // Factory.
+ static TrustRegionStrategy* Create(const Options& options);
+
+ virtual ~TrustRegionStrategy();
+
// Per solve options.
struct PerSolveOptions {
- PerSolveOptions()
- : eta(0),
- dump_format_type(TEXTFILE) {
- }
-
// Forcing sequence for inexact solves.
- double eta;
+ double eta = 1e-1;
- DumpFormatType dump_format_type;
+ DumpFormatType dump_format_type = TEXTFILE;
// If non-empty and dump_format_type is not CONSOLE, the trust
// regions strategy will write the linear system to file(s) with
@@ -103,12 +94,6 @@ class TrustRegionStrategy {
};
struct Summary {
- Summary()
- : residual_norm(0.0),
- num_iterations(-1),
- termination_type(LINEAR_SOLVER_FAILURE) {
- }
-
// If the trust region problem is,
//
// 1/2 x'Ax + b'x + c,
@@ -116,19 +101,17 @@ class TrustRegionStrategy {
// then
//
// residual_norm = |Ax -b|
- double residual_norm;
+ double residual_norm = -1;
// Number of iterations used by the linear solver. If a linear
// solver was not called (e.g., DogLegStrategy after an
// unsuccessful step), then this would be zero.
- int num_iterations;
+ int num_iterations = -1;
// Status of the linear solver used to solve the Newton system.
- LinearSolverTerminationType termination_type;
+ LinearSolverTerminationType termination_type = LINEAR_SOLVER_FAILURE;
};
- virtual ~TrustRegionStrategy();
-
// Use the current radius to solve for the trust region step.
virtual Summary ComputeStep(const PerSolveOptions& per_solve_options,
SparseMatrix* jacobian,
@@ -153,9 +136,6 @@ class TrustRegionStrategy {
// Current trust region radius.
virtual double Radius() const = 0;
-
- // Factory.
- static TrustRegionStrategy* Create(const Options& options);
};
} // namespace internal
diff --git a/extern/ceres/internal/ceres/types.cc b/extern/ceres/internal/ceres/types.cc
index f86fb78eb8c..93c4cfcb027 100644
--- a/extern/ceres/internal/ceres/types.cc
+++ b/extern/ceres/internal/ceres/types.cc
@@ -78,6 +78,7 @@ const char* PreconditionerTypeToString(PreconditionerType type) {
CASESTR(SCHUR_JACOBI);
CASESTR(CLUSTER_JACOBI);
CASESTR(CLUSTER_TRIDIAGONAL);
+ CASESTR(SUBSET);
default:
return "UNKNOWN";
}
@@ -90,6 +91,7 @@ bool StringToPreconditionerType(string value, PreconditionerType* type) {
STRENUM(SCHUR_JACOBI);
STRENUM(CLUSTER_JACOBI);
STRENUM(CLUSTER_TRIDIAGONAL);
+ STRENUM(SUBSET);
return false;
}
@@ -99,6 +101,7 @@ const char* SparseLinearAlgebraLibraryTypeToString(
CASESTR(SUITE_SPARSE);
CASESTR(CX_SPARSE);
CASESTR(EIGEN_SPARSE);
+ CASESTR(ACCELERATE_SPARSE);
CASESTR(NO_SPARSE);
default:
return "UNKNOWN";
@@ -112,6 +115,7 @@ bool StringToSparseLinearAlgebraLibraryType(
STRENUM(SUITE_SPARSE);
STRENUM(CX_SPARSE);
STRENUM(EIGEN_SPARSE);
+ STRENUM(ACCELERATE_SPARSE);
STRENUM(NO_SPARSE);
return false;
}
@@ -267,8 +271,7 @@ const char* CovarianceAlgorithmTypeToString(
CovarianceAlgorithmType type) {
switch (type) {
CASESTR(DENSE_SVD);
- CASESTR(EIGEN_SPARSE_QR);
- CASESTR(SUITE_SPARSE_QR);
+ CASESTR(SPARSE_QR);
default:
return "UNKNOWN";
}
@@ -279,8 +282,7 @@ bool StringToCovarianceAlgorithmType(
CovarianceAlgorithmType* type) {
UpperCase(&value);
STRENUM(DENSE_SVD);
- STRENUM(EIGEN_SPARSE_QR);
- STRENUM(SUITE_SPARSE_QR);
+ STRENUM(SPARSE_QR);
return false;
}
@@ -336,6 +338,39 @@ const char* TerminationTypeToString(TerminationType type) {
}
}
+const char* LoggingTypeToString(LoggingType type) {
+ switch (type) {
+ CASESTR(SILENT);
+ CASESTR(PER_MINIMIZER_ITERATION);
+ default:
+ return "UNKNOWN";
+ }
+}
+
+bool StringtoLoggingType(std::string value, LoggingType* type) {
+ UpperCase(&value);
+ STRENUM(SILENT);
+ STRENUM(PER_MINIMIZER_ITERATION);
+ return false;
+}
+
+
+const char* DumpFormatTypeToString(DumpFormatType type) {
+ switch (type) {
+ CASESTR(CONSOLE);
+ CASESTR(TEXTFILE);
+ default:
+ return "UNKNOWN";
+ }
+}
+
+bool StringtoDumpFormatType(std::string value, DumpFormatType* type) {
+ UpperCase(&value);
+ STRENUM(CONSOLE);
+ STRENUM(TEXTFILE);
+ return false;
+}
+
#undef CASESTR
#undef STRENUM
@@ -363,6 +398,14 @@ bool IsSparseLinearAlgebraLibraryTypeAvailable(
#endif
}
+ if (type == ACCELERATE_SPARSE) {
+#ifdef CERES_NO_ACCELERATE_SPARSE
+ return false;
+#else
+ return true;
+#endif
+ }
+
if (type == EIGEN_SPARSE) {
#ifdef CERES_USE_EIGEN_SPARSE
return true;
diff --git a/extern/ceres/internal/ceres/visibility.cc b/extern/ceres/internal/ceres/visibility.cc
new file mode 100644
index 00000000000..0981eeddcbf
--- /dev/null
+++ b/extern/ceres/internal/ceres/visibility.cc
@@ -0,0 +1,152 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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.
+//
+// Author: kushalav@google.com (Avanish Kushal)
+
+#include "ceres/visibility.h"
+
+#include <cmath>
+#include <ctime>
+#include <algorithm>
+#include <set>
+#include <vector>
+#include <unordered_map>
+#include <utility>
+#include "ceres/block_structure.h"
+#include "ceres/graph.h"
+#include "ceres/pair_hash.h"
+#include "glog/logging.h"
+
+namespace ceres {
+namespace internal {
+
+using std::make_pair;
+using std::max;
+using std::pair;
+using std::set;
+using std::vector;
+
+void ComputeVisibility(const CompressedRowBlockStructure& block_structure,
+ const int num_eliminate_blocks,
+ vector<set<int>>* visibility) {
+ CHECK(visibility != nullptr);
+
+ // Clear the visibility vector and resize it to hold a
+ // vector for each camera.
+ visibility->resize(0);
+ visibility->resize(block_structure.cols.size() - num_eliminate_blocks);
+
+ for (int i = 0; i < block_structure.rows.size(); ++i) {
+ const vector<Cell>& cells = block_structure.rows[i].cells;
+ int block_id = cells[0].block_id;
+ // If the first block is not an e_block, then skip this row block.
+ if (block_id >= num_eliminate_blocks) {
+ continue;
+ }
+
+ for (int j = 1; j < cells.size(); ++j) {
+ int camera_block_id = cells[j].block_id - num_eliminate_blocks;
+ DCHECK_GE(camera_block_id, 0);
+ DCHECK_LT(camera_block_id, visibility->size());
+ (*visibility)[camera_block_id].insert(block_id);
+ }
+ }
+}
+
+WeightedGraph<int>* CreateSchurComplementGraph(
+ const vector<set<int>>& visibility) {
+ const time_t start_time = time(NULL);
+ // Compute the number of e_blocks/point blocks. Since the visibility
+ // set for each e_block/camera contains the set of e_blocks/points
+ // visible to it, we find the maximum across all visibility sets.
+ int num_points = 0;
+ for (int i = 0; i < visibility.size(); i++) {
+ if (visibility[i].size() > 0) {
+ num_points = max(num_points, (*visibility[i].rbegin()) + 1);
+ }
+ }
+
+ // Invert the visibility. The input is a camera->point mapping,
+ // which tells us which points are visible in which
+ // cameras. However, to compute the sparsity structure of the Schur
+ // Complement efficiently, its better to have the point->camera
+ // mapping.
+ vector<set<int>> inverse_visibility(num_points);
+ for (int i = 0; i < visibility.size(); i++) {
+ const set<int>& visibility_set = visibility[i];
+ for (const int v : visibility_set) {
+ inverse_visibility[v].insert(i);
+ }
+ }
+
+ // Map from camera pairs to number of points visible to both cameras
+ // in the pair.
+ std::unordered_map<pair<int, int>, int, pair_hash> camera_pairs;
+
+ // Count the number of points visible to each camera/f_block pair.
+ for (const auto& inverse_visibility_set : inverse_visibility) {
+ for (set<int>::const_iterator camera1 = inverse_visibility_set.begin();
+ camera1 != inverse_visibility_set.end();
+ ++camera1) {
+ set<int>::const_iterator camera2 = camera1;
+ for (++camera2; camera2 != inverse_visibility_set.end(); ++camera2) {
+ ++(camera_pairs[make_pair(*camera1, *camera2)]);
+ }
+ }
+ }
+
+ WeightedGraph<int>* graph = new WeightedGraph<int>;
+
+ // Add vertices and initialize the pairs for self edges so that self
+ // edges are guaranteed. This is needed for the Canonical views
+ // algorithm to work correctly.
+ static constexpr double kSelfEdgeWeight = 1.0;
+ for (int i = 0; i < visibility.size(); ++i) {
+ graph->AddVertex(i);
+ graph->AddEdge(i, i, kSelfEdgeWeight);
+ }
+
+ // Add an edge for each camera pair.
+ for (const auto& camera_pair_count : camera_pairs) {
+ const int camera1 = camera_pair_count.first.first;
+ const int camera2 = camera_pair_count.first.second;
+ const int count = camera_pair_count.second;
+ DCHECK_NE(camera1, camera2);
+ // Static cast necessary for Windows.
+ const double weight = static_cast<double>(count) /
+ (sqrt(static_cast<double>(
+ visibility[camera1].size() * visibility[camera2].size())));
+ graph->AddEdge(camera1, camera2, weight);
+ }
+
+ VLOG(2) << "Schur complement graph time: " << (time(NULL) - start_time);
+ return graph;
+}
+
+} // namespace internal
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/visibility.h b/extern/ceres/internal/ceres/visibility.h
new file mode 100644
index 00000000000..115d45f7cf6
--- /dev/null
+++ b/extern/ceres/internal/ceres/visibility.h
@@ -0,0 +1,78 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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.
+//
+// Author: kushalav@google.com (Avanish Kushal)
+// sameeragarwal@google.com (Sameer Agarwal)
+//
+// Functions to manipulate visibility information from the block
+// structure of sparse matrices.
+
+#ifndef CERES_INTERNAL_VISIBILITY_H_
+#define CERES_INTERNAL_VISIBILITY_H_
+
+#include <set>
+#include <vector>
+#include "ceres/graph.h"
+
+namespace ceres {
+namespace internal {
+
+struct CompressedRowBlockStructure;
+
+// Given a compressed row block structure, computes the set of
+// e_blocks "visible" to each f_block. If an e_block co-occurs with an
+// f_block in a residual block, it is visible to the f_block. The
+// first num_eliminate_blocks columns blocks are e_blocks and the rest
+// f_blocks.
+//
+// In a structure from motion problem, e_blocks correspond to 3D
+// points and f_blocks correspond to cameras.
+void ComputeVisibility(const CompressedRowBlockStructure& block_structure,
+ int num_eliminate_blocks,
+ std::vector<std::set<int>>* visibility);
+
+// Given f_block visibility as computed by the ComputeVisibility
+// function above, construct and return a graph whose vertices are
+// f_blocks and an edge connects two vertices if they have at least one
+// e_block in common. The weight of this edge is normalized dot
+// product between the visibility vectors of the two
+// vertices/f_blocks.
+//
+// This graph reflects the sparsity structure of reduced camera
+// matrix/Schur complement matrix obtained by eliminating the e_blocks
+// from the normal equations.
+//
+// Caller acquires ownership of the returned WeightedGraph pointer
+// (heap-allocated).
+WeightedGraph<int>* CreateSchurComplementGraph(
+ const std::vector<std::set<int>>& visibility);
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_VISIBILITY_H_
diff --git a/extern/ceres/internal/ceres/visibility_based_preconditioner.cc b/extern/ceres/internal/ceres/visibility_based_preconditioner.cc
new file mode 100644
index 00000000000..3372e82d1e1
--- /dev/null
+++ b/extern/ceres/internal/ceres/visibility_based_preconditioner.cc
@@ -0,0 +1,585 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#include "ceres/visibility_based_preconditioner.h"
+
+#include <algorithm>
+#include <functional>
+#include <iterator>
+#include <memory>
+#include <set>
+#include <utility>
+#include <vector>
+
+#include "Eigen/Dense"
+#include "ceres/block_random_access_sparse_matrix.h"
+#include "ceres/block_sparse_matrix.h"
+#include "ceres/canonical_views_clustering.h"
+#include "ceres/graph.h"
+#include "ceres/graph_algorithms.h"
+#include "ceres/linear_solver.h"
+#include "ceres/schur_eliminator.h"
+#include "ceres/single_linkage_clustering.h"
+#include "ceres/visibility.h"
+#include "glog/logging.h"
+
+namespace ceres {
+namespace internal {
+
+using std::make_pair;
+using std::pair;
+using std::set;
+using std::swap;
+using std::vector;
+
+// TODO(sameeragarwal): Currently these are magic weights for the
+// preconditioner construction. Move these higher up into the Options
+// struct and provide some guidelines for choosing them.
+//
+// This will require some more work on the clustering algorithm and
+// possibly some more refactoring of the code.
+static constexpr double kCanonicalViewsSizePenaltyWeight = 3.0;
+static constexpr double kCanonicalViewsSimilarityPenaltyWeight = 0.0;
+static constexpr double kSingleLinkageMinSimilarity = 0.9;
+
+VisibilityBasedPreconditioner::VisibilityBasedPreconditioner(
+ const CompressedRowBlockStructure& bs,
+ const Preconditioner::Options& options)
+ : options_(options), num_blocks_(0), num_clusters_(0) {
+ CHECK_GT(options_.elimination_groups.size(), 1);
+ CHECK_GT(options_.elimination_groups[0], 0);
+ CHECK(options_.type == CLUSTER_JACOBI || options_.type == CLUSTER_TRIDIAGONAL)
+ << "Unknown preconditioner type: " << options_.type;
+ num_blocks_ = bs.cols.size() - options_.elimination_groups[0];
+ CHECK_GT(num_blocks_, 0) << "Jacobian should have at least 1 f_block for "
+ << "visibility based preconditioning.";
+ CHECK(options_.context != NULL);
+
+ // Vector of camera block sizes
+ block_size_.resize(num_blocks_);
+ for (int i = 0; i < num_blocks_; ++i) {
+ block_size_[i] = bs.cols[i + options_.elimination_groups[0]].size;
+ }
+
+ const time_t start_time = time(NULL);
+ switch (options_.type) {
+ case CLUSTER_JACOBI:
+ ComputeClusterJacobiSparsity(bs);
+ break;
+ case CLUSTER_TRIDIAGONAL:
+ ComputeClusterTridiagonalSparsity(bs);
+ break;
+ default:
+ LOG(FATAL) << "Unknown preconditioner type";
+ }
+ const time_t structure_time = time(NULL);
+ InitStorage(bs);
+ const time_t storage_time = time(NULL);
+ InitEliminator(bs);
+ const time_t eliminator_time = time(NULL);
+
+ LinearSolver::Options sparse_cholesky_options;
+ sparse_cholesky_options.sparse_linear_algebra_library_type =
+ options_.sparse_linear_algebra_library_type;
+
+ // The preconditioner's sparsity is not available in the
+ // preprocessor, so the columns of the Jacobian have not been
+ // reordered to minimize fill in when computing its sparse Cholesky
+ // factorization. So we must tell the SparseCholesky object to
+ // perform approximate minimum-degree reordering, which is done by
+ // setting use_postordering to true.
+ sparse_cholesky_options.use_postordering = true;
+ sparse_cholesky_ = SparseCholesky::Create(sparse_cholesky_options);
+
+ const time_t init_time = time(NULL);
+ VLOG(2) << "init time: " << init_time - start_time
+ << " structure time: " << structure_time - start_time
+ << " storage time:" << storage_time - structure_time
+ << " eliminator time: " << eliminator_time - storage_time;
+}
+
+VisibilityBasedPreconditioner::~VisibilityBasedPreconditioner() {}
+
+// Determine the sparsity structure of the CLUSTER_JACOBI
+// preconditioner. It clusters cameras using their scene
+// visibility. The clusters form the diagonal blocks of the
+// preconditioner matrix.
+void VisibilityBasedPreconditioner::ComputeClusterJacobiSparsity(
+ const CompressedRowBlockStructure& bs) {
+ vector<set<int>> visibility;
+ ComputeVisibility(bs, options_.elimination_groups[0], &visibility);
+ CHECK_EQ(num_blocks_, visibility.size());
+ ClusterCameras(visibility);
+ cluster_pairs_.clear();
+ for (int i = 0; i < num_clusters_; ++i) {
+ cluster_pairs_.insert(make_pair(i, i));
+ }
+}
+
+// Determine the sparsity structure of the CLUSTER_TRIDIAGONAL
+// preconditioner. It clusters cameras using using the scene
+// visibility and then finds the strongly interacting pairs of
+// clusters by constructing another graph with the clusters as
+// vertices and approximating it with a degree-2 maximum spanning
+// forest. The set of edges in this forest are the cluster pairs.
+void VisibilityBasedPreconditioner::ComputeClusterTridiagonalSparsity(
+ const CompressedRowBlockStructure& bs) {
+ vector<set<int>> visibility;
+ ComputeVisibility(bs, options_.elimination_groups[0], &visibility);
+ CHECK_EQ(num_blocks_, visibility.size());
+ ClusterCameras(visibility);
+
+ // Construct a weighted graph on the set of clusters, where the
+ // edges are the number of 3D points/e_blocks visible in both the
+ // clusters at the ends of the edge. Return an approximate degree-2
+ // maximum spanning forest of this graph.
+ vector<set<int>> cluster_visibility;
+ ComputeClusterVisibility(visibility, &cluster_visibility);
+ std::unique_ptr<WeightedGraph<int>> cluster_graph(
+ CreateClusterGraph(cluster_visibility));
+ CHECK(cluster_graph != nullptr);
+ std::unique_ptr<WeightedGraph<int>> forest(
+ Degree2MaximumSpanningForest(*cluster_graph));
+ CHECK(forest != nullptr);
+ ForestToClusterPairs(*forest, &cluster_pairs_);
+}
+
+// Allocate storage for the preconditioner matrix.
+void VisibilityBasedPreconditioner::InitStorage(
+ const CompressedRowBlockStructure& bs) {
+ ComputeBlockPairsInPreconditioner(bs);
+ m_.reset(new BlockRandomAccessSparseMatrix(block_size_, block_pairs_));
+}
+
+// Call the canonical views algorithm and cluster the cameras based on
+// their visibility sets. The visibility set of a camera is the set of
+// e_blocks/3D points in the scene that are seen by it.
+//
+// The cluster_membership_ vector is updated to indicate cluster
+// memberships for each camera block.
+void VisibilityBasedPreconditioner::ClusterCameras(
+ const vector<set<int>>& visibility) {
+ std::unique_ptr<WeightedGraph<int>> schur_complement_graph(
+ CreateSchurComplementGraph(visibility));
+ CHECK(schur_complement_graph != nullptr);
+
+ std::unordered_map<int, int> membership;
+
+ if (options_.visibility_clustering_type == CANONICAL_VIEWS) {
+ vector<int> centers;
+ CanonicalViewsClusteringOptions clustering_options;
+ clustering_options.size_penalty_weight = kCanonicalViewsSizePenaltyWeight;
+ clustering_options.similarity_penalty_weight =
+ kCanonicalViewsSimilarityPenaltyWeight;
+ ComputeCanonicalViewsClustering(
+ clustering_options, *schur_complement_graph, &centers, &membership);
+ num_clusters_ = centers.size();
+ } else if (options_.visibility_clustering_type == SINGLE_LINKAGE) {
+ SingleLinkageClusteringOptions clustering_options;
+ clustering_options.min_similarity = kSingleLinkageMinSimilarity;
+ num_clusters_ = ComputeSingleLinkageClustering(
+ clustering_options, *schur_complement_graph, &membership);
+ } else {
+ LOG(FATAL) << "Unknown visibility clustering algorithm.";
+ }
+
+ CHECK_GT(num_clusters_, 0);
+ VLOG(2) << "num_clusters: " << num_clusters_;
+ FlattenMembershipMap(membership, &cluster_membership_);
+}
+
+// Compute the block sparsity structure of the Schur complement
+// matrix. For each pair of cameras contributing a non-zero cell to
+// the schur complement, determine if that cell is present in the
+// preconditioner or not.
+//
+// A pair of cameras contribute a cell to the preconditioner if they
+// are part of the same cluster or if the two clusters that they
+// belong have an edge connecting them in the degree-2 maximum
+// spanning forest.
+//
+// For example, a camera pair (i,j) where i belongs to cluster1 and
+// j belongs to cluster2 (assume that cluster1 < cluster2).
+//
+// The cell corresponding to (i,j) is present in the preconditioner
+// if cluster1 == cluster2 or the pair (cluster1, cluster2) were
+// connected by an edge in the degree-2 maximum spanning forest.
+//
+// Since we have already expanded the forest into a set of camera
+// pairs/edges, including self edges, the check can be reduced to
+// checking membership of (cluster1, cluster2) in cluster_pairs_.
+void VisibilityBasedPreconditioner::ComputeBlockPairsInPreconditioner(
+ const CompressedRowBlockStructure& bs) {
+ block_pairs_.clear();
+ for (int i = 0; i < num_blocks_; ++i) {
+ block_pairs_.insert(make_pair(i, i));
+ }
+
+ int r = 0;
+ const int num_row_blocks = bs.rows.size();
+ const int num_eliminate_blocks = options_.elimination_groups[0];
+
+ // Iterate over each row of the matrix. The block structure of the
+ // matrix is assumed to be sorted in order of the e_blocks/point
+ // blocks. Thus all row blocks containing an e_block/point occur
+ // contiguously. Further, if present, an e_block is always the first
+ // parameter block in each row block. These structural assumptions
+ // are common to all Schur complement based solvers in Ceres.
+ //
+ // For each e_block/point block we identify the set of cameras
+ // seeing it. The cross product of this set with itself is the set
+ // of non-zero cells contributed by this e_block.
+ //
+ // The time complexity of this is O(nm^2) where, n is the number of
+ // 3d points and m is the maximum number of cameras seeing any
+ // point, which for most scenes is a fairly small number.
+ while (r < num_row_blocks) {
+ int e_block_id = bs.rows[r].cells.front().block_id;
+ if (e_block_id >= num_eliminate_blocks) {
+ // Skip the rows whose first block is an f_block.
+ break;
+ }
+
+ set<int> f_blocks;
+ for (; r < num_row_blocks; ++r) {
+ const CompressedRow& row = bs.rows[r];
+ if (row.cells.front().block_id != e_block_id) {
+ break;
+ }
+
+ // Iterate over the blocks in the row, ignoring the first block
+ // since it is the one to be eliminated and adding the rest to
+ // the list of f_blocks associated with this e_block.
+ for (int c = 1; c < row.cells.size(); ++c) {
+ const Cell& cell = row.cells[c];
+ const int f_block_id = cell.block_id - num_eliminate_blocks;
+ CHECK_GE(f_block_id, 0);
+ f_blocks.insert(f_block_id);
+ }
+ }
+
+ for (set<int>::const_iterator block1 = f_blocks.begin();
+ block1 != f_blocks.end();
+ ++block1) {
+ set<int>::const_iterator block2 = block1;
+ ++block2;
+ for (; block2 != f_blocks.end(); ++block2) {
+ if (IsBlockPairInPreconditioner(*block1, *block2)) {
+ block_pairs_.insert(make_pair(*block1, *block2));
+ }
+ }
+ }
+ }
+
+ // The remaining rows which do not contain any e_blocks.
+ for (; r < num_row_blocks; ++r) {
+ const CompressedRow& row = bs.rows[r];
+ CHECK_GE(row.cells.front().block_id, num_eliminate_blocks);
+ for (int i = 0; i < row.cells.size(); ++i) {
+ const int block1 = row.cells[i].block_id - num_eliminate_blocks;
+ for (int j = 0; j < row.cells.size(); ++j) {
+ const int block2 = row.cells[j].block_id - num_eliminate_blocks;
+ if (block1 <= block2) {
+ if (IsBlockPairInPreconditioner(block1, block2)) {
+ block_pairs_.insert(make_pair(block1, block2));
+ }
+ }
+ }
+ }
+ }
+
+ VLOG(1) << "Block pair stats: " << block_pairs_.size();
+}
+
+// Initialize the SchurEliminator.
+void VisibilityBasedPreconditioner::InitEliminator(
+ const CompressedRowBlockStructure& bs) {
+ LinearSolver::Options eliminator_options;
+ eliminator_options.elimination_groups = options_.elimination_groups;
+ eliminator_options.num_threads = options_.num_threads;
+ eliminator_options.e_block_size = options_.e_block_size;
+ eliminator_options.f_block_size = options_.f_block_size;
+ eliminator_options.row_block_size = options_.row_block_size;
+ eliminator_options.context = options_.context;
+ eliminator_.reset(SchurEliminatorBase::Create(eliminator_options));
+ const bool kFullRankETE = true;
+ eliminator_->Init(
+ eliminator_options.elimination_groups[0], kFullRankETE, &bs);
+}
+
+// Update the values of the preconditioner matrix and factorize it.
+bool VisibilityBasedPreconditioner::UpdateImpl(const BlockSparseMatrix& A,
+ const double* D) {
+ const time_t start_time = time(NULL);
+ const int num_rows = m_->num_rows();
+ CHECK_GT(num_rows, 0);
+
+ // Compute a subset of the entries of the Schur complement.
+ eliminator_->Eliminate(
+ BlockSparseMatrixData(A), nullptr, D, m_.get(), nullptr);
+
+ // Try factorizing the matrix. For CLUSTER_JACOBI, this should
+ // always succeed modulo some numerical/conditioning problems. For
+ // CLUSTER_TRIDIAGONAL, in general the preconditioner matrix as
+ // constructed is not positive definite. However, we will go ahead
+ // and try factorizing it. If it works, great, otherwise we scale
+ // all the cells in the preconditioner corresponding to the edges in
+ // the degree-2 forest and that guarantees positive
+ // definiteness. The proof of this fact can be found in Lemma 1 in
+ // "Visibility Based Preconditioning for Bundle Adjustment".
+ //
+ // Doing the factorization like this saves us matrix mass when
+ // scaling is not needed, which is quite often in our experience.
+ LinearSolverTerminationType status = Factorize();
+
+ if (status == LINEAR_SOLVER_FATAL_ERROR) {
+ return false;
+ }
+
+ // The scaling only affects the tri-diagonal case, since
+ // ScaleOffDiagonalBlocks only pays attention to the cells that
+ // belong to the edges of the degree-2 forest. In the CLUSTER_JACOBI
+ // case, the preconditioner is guaranteed to be positive
+ // semidefinite.
+ if (status == LINEAR_SOLVER_FAILURE && options_.type == CLUSTER_TRIDIAGONAL) {
+ VLOG(1) << "Unscaled factorization failed. Retrying with off-diagonal "
+ << "scaling";
+ ScaleOffDiagonalCells();
+ status = Factorize();
+ }
+
+ VLOG(2) << "Compute time: " << time(NULL) - start_time;
+ return (status == LINEAR_SOLVER_SUCCESS);
+}
+
+// Consider the preconditioner matrix as meta-block matrix, whose
+// blocks correspond to the clusters. Then cluster pairs corresponding
+// to edges in the degree-2 forest are off diagonal entries of this
+// matrix. Scaling these off-diagonal entries by 1/2 forces this
+// matrix to be positive definite.
+void VisibilityBasedPreconditioner::ScaleOffDiagonalCells() {
+ for (const auto& block_pair : block_pairs_) {
+ const int block1 = block_pair.first;
+ const int block2 = block_pair.second;
+ if (!IsBlockPairOffDiagonal(block1, block2)) {
+ continue;
+ }
+
+ int r, c, row_stride, col_stride;
+ CellInfo* cell_info =
+ m_->GetCell(block1, block2, &r, &c, &row_stride, &col_stride);
+ CHECK(cell_info != NULL)
+ << "Cell missing for block pair (" << block1 << "," << block2 << ")"
+ << " cluster pair (" << cluster_membership_[block1] << " "
+ << cluster_membership_[block2] << ")";
+
+ // Ah the magic of tri-diagonal matrices and diagonal
+ // dominance. See Lemma 1 in "Visibility Based Preconditioning
+ // For Bundle Adjustment".
+ MatrixRef m(cell_info->values, row_stride, col_stride);
+ m.block(r, c, block_size_[block1], block_size_[block2]) *= 0.5;
+ }
+}
+
+// Compute the sparse Cholesky factorization of the preconditioner
+// matrix.
+LinearSolverTerminationType VisibilityBasedPreconditioner::Factorize() {
+ // Extract the TripletSparseMatrix that is used for actually storing
+ // S and convert it into a CompressedRowSparseMatrix.
+ const TripletSparseMatrix* tsm =
+ down_cast<BlockRandomAccessSparseMatrix*>(m_.get())->mutable_matrix();
+
+ std::unique_ptr<CompressedRowSparseMatrix> lhs;
+ const CompressedRowSparseMatrix::StorageType storage_type =
+ sparse_cholesky_->StorageType();
+ if (storage_type == CompressedRowSparseMatrix::UPPER_TRIANGULAR) {
+ lhs.reset(CompressedRowSparseMatrix::FromTripletSparseMatrix(*tsm));
+ lhs->set_storage_type(CompressedRowSparseMatrix::UPPER_TRIANGULAR);
+ } else {
+ lhs.reset(
+ CompressedRowSparseMatrix::FromTripletSparseMatrixTransposed(*tsm));
+ lhs->set_storage_type(CompressedRowSparseMatrix::LOWER_TRIANGULAR);
+ }
+
+ std::string message;
+ return sparse_cholesky_->Factorize(lhs.get(), &message);
+}
+
+void VisibilityBasedPreconditioner::RightMultiply(const double* x,
+ double* y) const {
+ CHECK(x != nullptr);
+ CHECK(y != nullptr);
+ CHECK(sparse_cholesky_ != nullptr);
+ std::string message;
+ sparse_cholesky_->Solve(x, y, &message);
+}
+
+int VisibilityBasedPreconditioner::num_rows() const { return m_->num_rows(); }
+
+// Classify camera/f_block pairs as in and out of the preconditioner,
+// based on whether the cluster pair that they belong to is in the
+// preconditioner or not.
+bool VisibilityBasedPreconditioner::IsBlockPairInPreconditioner(
+ const int block1, const int block2) const {
+ int cluster1 = cluster_membership_[block1];
+ int cluster2 = cluster_membership_[block2];
+ if (cluster1 > cluster2) {
+ swap(cluster1, cluster2);
+ }
+ return (cluster_pairs_.count(make_pair(cluster1, cluster2)) > 0);
+}
+
+bool VisibilityBasedPreconditioner::IsBlockPairOffDiagonal(
+ const int block1, const int block2) const {
+ return (cluster_membership_[block1] != cluster_membership_[block2]);
+}
+
+// Convert a graph into a list of edges that includes self edges for
+// each vertex.
+void VisibilityBasedPreconditioner::ForestToClusterPairs(
+ const WeightedGraph<int>& forest,
+ std::unordered_set<pair<int, int>, pair_hash>* cluster_pairs) const {
+ CHECK(cluster_pairs != nullptr);
+ cluster_pairs->clear();
+ const std::unordered_set<int>& vertices = forest.vertices();
+ CHECK_EQ(vertices.size(), num_clusters_);
+
+ // Add all the cluster pairs corresponding to the edges in the
+ // forest.
+ for (const int cluster1 : vertices) {
+ cluster_pairs->insert(make_pair(cluster1, cluster1));
+ const std::unordered_set<int>& neighbors = forest.Neighbors(cluster1);
+ for (const int cluster2 : neighbors) {
+ if (cluster1 < cluster2) {
+ cluster_pairs->insert(make_pair(cluster1, cluster2));
+ }
+ }
+ }
+}
+
+// The visibility set of a cluster is the union of the visibility sets
+// of all its cameras. In other words, the set of points visible to
+// any camera in the cluster.
+void VisibilityBasedPreconditioner::ComputeClusterVisibility(
+ const vector<set<int>>& visibility,
+ vector<set<int>>* cluster_visibility) const {
+ CHECK(cluster_visibility != nullptr);
+ cluster_visibility->resize(0);
+ cluster_visibility->resize(num_clusters_);
+ for (int i = 0; i < num_blocks_; ++i) {
+ const int cluster_id = cluster_membership_[i];
+ (*cluster_visibility)[cluster_id].insert(visibility[i].begin(),
+ visibility[i].end());
+ }
+}
+
+// Construct a graph whose vertices are the clusters, and the edge
+// weights are the number of 3D points visible to cameras in both the
+// vertices.
+WeightedGraph<int>* VisibilityBasedPreconditioner::CreateClusterGraph(
+ const vector<set<int>>& cluster_visibility) const {
+ WeightedGraph<int>* cluster_graph = new WeightedGraph<int>;
+
+ for (int i = 0; i < num_clusters_; ++i) {
+ cluster_graph->AddVertex(i);
+ }
+
+ for (int i = 0; i < num_clusters_; ++i) {
+ const set<int>& cluster_i = cluster_visibility[i];
+ for (int j = i + 1; j < num_clusters_; ++j) {
+ vector<int> intersection;
+ const set<int>& cluster_j = cluster_visibility[j];
+ set_intersection(cluster_i.begin(),
+ cluster_i.end(),
+ cluster_j.begin(),
+ cluster_j.end(),
+ back_inserter(intersection));
+
+ if (intersection.size() > 0) {
+ // Clusters interact strongly when they share a large number
+ // of 3D points. The degree-2 maximum spanning forest
+ // algorithm, iterates on the edges in decreasing order of
+ // their weight, which is the number of points shared by the
+ // two cameras that it connects.
+ cluster_graph->AddEdge(i, j, intersection.size());
+ }
+ }
+ }
+ return cluster_graph;
+}
+
+// Canonical views clustering returns a std::unordered_map from vertices to
+// cluster ids. Convert this into a flat array for quick lookup. It is
+// possible that some of the vertices may not be associated with any
+// cluster. In that case, randomly assign them to one of the clusters.
+//
+// The cluster ids can be non-contiguous integers. So as we flatten
+// the membership_map, we also map the cluster ids to a contiguous set
+// of integers so that the cluster ids are in [0, num_clusters_).
+void VisibilityBasedPreconditioner::FlattenMembershipMap(
+ const std::unordered_map<int, int>& membership_map,
+ vector<int>* membership_vector) const {
+ CHECK(membership_vector != nullptr);
+ membership_vector->resize(0);
+ membership_vector->resize(num_blocks_, -1);
+
+ std::unordered_map<int, int> cluster_id_to_index;
+ // Iterate over the cluster membership map and update the
+ // cluster_membership_ vector assigning arbitrary cluster ids to
+ // the few cameras that have not been clustered.
+ for (const auto& m : membership_map) {
+ const int camera_id = m.first;
+ int cluster_id = m.second;
+
+ // If the view was not clustered, randomly assign it to one of the
+ // clusters. This preserves the mathematical correctness of the
+ // preconditioner. If there are too many views which are not
+ // clustered, it may lead to some quality degradation though.
+ //
+ // TODO(sameeragarwal): Check if a large number of views have not
+ // been clustered and deal with it?
+ if (cluster_id == -1) {
+ cluster_id = camera_id % num_clusters_;
+ }
+
+ const int index = FindWithDefault(
+ cluster_id_to_index, cluster_id, cluster_id_to_index.size());
+
+ if (index == cluster_id_to_index.size()) {
+ cluster_id_to_index[cluster_id] = index;
+ }
+
+ CHECK_LT(index, num_clusters_);
+ membership_vector->at(camera_id) = index;
+ }
+}
+
+} // namespace internal
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/visibility_based_preconditioner.h b/extern/ceres/internal/ceres/visibility_based_preconditioner.h
index a627c13523c..aa582d5e7ef 100644
--- a/extern/ceres/internal/ceres/visibility_based_preconditioner.h
+++ b/extern/ceres/internal/ceres/visibility_based_preconditioner.h
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2017 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -48,16 +48,18 @@
#ifndef CERES_INTERNAL_VISIBILITY_BASED_PRECONDITIONER_H_
#define CERES_INTERNAL_VISIBILITY_BASED_PRECONDITIONER_H_
+#include <memory>
#include <set>
-#include <vector>
+#include <unordered_map>
+#include <unordered_set>
#include <utility>
-#include "ceres/collections_port.h"
+#include <vector>
+
#include "ceres/graph.h"
-#include "ceres/internal/macros.h"
-#include "ceres/internal/scoped_ptr.h"
#include "ceres/linear_solver.h"
+#include "ceres/pair_hash.h"
#include "ceres/preconditioner.h"
-#include "ceres/suitesparse.h"
+#include "ceres/sparse_cholesky.h"
namespace ceres {
namespace internal {
@@ -122,8 +124,6 @@ class SchurEliminatorBase;
// *A.block_structure(), options);
// preconditioner.Update(A, NULL);
// preconditioner.RightMultiply(x, y);
-//
-#ifndef CERES_NO_SUITESPARSE
class VisibilityBasedPreconditioner : public BlockSparseMatrixPreconditioner {
public:
// Initialize the symbolic structure of the preconditioner. bs is
@@ -134,16 +134,19 @@ class VisibilityBasedPreconditioner : public BlockSparseMatrixPreconditioner {
// based solvers. Please see schur_eliminator.h for more details.
VisibilityBasedPreconditioner(const CompressedRowBlockStructure& bs,
const Preconditioner::Options& options);
+ VisibilityBasedPreconditioner(const VisibilityBasedPreconditioner&) = delete;
+ void operator=(const VisibilityBasedPreconditioner&) = delete;
+
virtual ~VisibilityBasedPreconditioner();
// Preconditioner interface
- virtual void RightMultiply(const double* x, double* y) const;
- virtual int num_rows() const;
+ void RightMultiply(const double* x, double* y) const final;
+ int num_rows() const final;
friend class VisibilityBasedPreconditionerTest;
private:
- virtual bool UpdateImpl(const BlockSparseMatrix& A, const double* D);
+ bool UpdateImpl(const BlockSparseMatrix& A, const double* D) final;
void ComputeClusterJacobiSparsity(const CompressedRowBlockStructure& bs);
void ComputeClusterTridiagonalSparsity(const CompressedRowBlockStructure& bs);
void InitStorage(const CompressedRowBlockStructure& bs);
@@ -151,16 +154,16 @@ class VisibilityBasedPreconditioner : public BlockSparseMatrixPreconditioner {
LinearSolverTerminationType Factorize();
void ScaleOffDiagonalCells();
- void ClusterCameras(const std::vector<std::set<int> >& visibility);
- void FlattenMembershipMap(const HashMap<int, int>& membership_map,
+ void ClusterCameras(const std::vector<std::set<int>>& visibility);
+ void FlattenMembershipMap(const std::unordered_map<int, int>& membership_map,
std::vector<int>* membership_vector) const;
void ComputeClusterVisibility(
- const std::vector<std::set<int> >& visibility,
- std::vector<std::set<int> >* cluster_visibility) const;
+ const std::vector<std::set<int>>& visibility,
+ std::vector<std::set<int>>* cluster_visibility) const;
WeightedGraph<int>* CreateClusterGraph(
- const std::vector<std::set<int> >& visibility) const;
+ const std::vector<std::set<int>>& visibility) const;
void ForestToClusterPairs(const WeightedGraph<int>& forest,
- HashSet<std::pair<int, int> >* cluster_pairs) const;
+ std::unordered_set<std::pair<int, int>, pair_hash>* cluster_pairs) const;
void ComputeBlockPairsInPreconditioner(const CompressedRowBlockStructure& bs);
bool IsBlockPairInPreconditioner(int block1, int block2) const;
bool IsBlockPairOffDiagonal(int block1, int block2) const;
@@ -180,52 +183,17 @@ class VisibilityBasedPreconditioner : public BlockSparseMatrixPreconditioner {
// Non-zero camera pairs from the schur complement matrix that are
// present in the preconditioner, sorted by row (first element of
// each pair), then column (second).
- std::set<std::pair<int, int> > block_pairs_;
+ std::set<std::pair<int, int>> block_pairs_;
// Set of cluster pairs (including self pairs (i,i)) in the
// preconditioner.
- HashSet<std::pair<int, int> > cluster_pairs_;
- scoped_ptr<SchurEliminatorBase> eliminator_;
+ std::unordered_set<std::pair<int, int>, pair_hash> cluster_pairs_;
+ std::unique_ptr<SchurEliminatorBase> eliminator_;
// Preconditioner matrix.
- scoped_ptr<BlockRandomAccessSparseMatrix> m_;
-
- // RightMultiply is a const method for LinearOperators. It is
- // implemented using CHOLMOD's sparse triangular matrix solve
- // function. This however requires non-const access to the
- // SuiteSparse context object, even though it does not result in any
- // of the state of the preconditioner being modified.
- SuiteSparse ss_;
-
- // Symbolic and numeric factorization of the preconditioner.
- cholmod_factor* factor_;
-
- // Temporary vector used by RightMultiply.
- cholmod_dense* tmp_rhs_;
- CERES_DISALLOW_COPY_AND_ASSIGN(VisibilityBasedPreconditioner);
-};
-#else // SuiteSparse
-// If SuiteSparse is not compiled in, the preconditioner is not
-// available.
-class VisibilityBasedPreconditioner : public BlockSparseMatrixPreconditioner {
- public:
- VisibilityBasedPreconditioner(const CompressedRowBlockStructure& bs,
- const Preconditioner::Options& options) {
- LOG(FATAL) << "Visibility based preconditioning is not available. Please "
- "build Ceres with SuiteSparse.";
- }
- virtual ~VisibilityBasedPreconditioner() {}
- virtual void RightMultiply(const double* x, double* y) const {}
- virtual void LeftMultiply(const double* x, double* y) const {}
- virtual int num_rows() const { return -1; }
- virtual int num_cols() const { return -1; }
-
- private:
- bool UpdateImpl(const BlockSparseMatrix& A, const double* D) {
- return false;
- }
+ std::unique_ptr<BlockRandomAccessSparseMatrix> m_;
+ std::unique_ptr<SparseCholesky> sparse_cholesky_;
};
-#endif // CERES_NO_SUITESPARSE
} // namespace internal
} // namespace ceres
diff --git a/extern/ceres/internal/ceres/wall_time.cc b/extern/ceres/internal/ceres/wall_time.cc
index c353973cc3e..716392741e9 100644
--- a/extern/ceres/internal/ceres/wall_time.cc
+++ b/extern/ceres/internal/ceres/wall_time.cc
@@ -50,7 +50,12 @@ double WallTimeInSeconds() {
return omp_get_wtime();
#else
#ifdef _WIN32
- return static_cast<double>(std::time(NULL));
+ LARGE_INTEGER count;
+ LARGE_INTEGER frequency;
+ QueryPerformanceCounter(&count);
+ QueryPerformanceFrequency(&frequency);
+ return static_cast<double>(count.QuadPart) /
+ static_cast<double>(frequency.QuadPart);
#else
timeval time_val;
gettimeofday(&time_val, NULL);
@@ -59,20 +64,24 @@ double WallTimeInSeconds() {
#endif
}
-EventLogger::EventLogger(const std::string& logger_name)
- : start_time_(WallTimeInSeconds()),
- last_event_time_(start_time_),
- events_("") {
- StringAppendF(&events_,
- "\n%s\n Delta Cumulative\n",
- logger_name.c_str());
+EventLogger::EventLogger(const std::string& logger_name) {
+ if (!VLOG_IS_ON(3)) {
+ return;
+ }
+
+ start_time_ = WallTimeInSeconds();
+ last_event_time_ = start_time_;
+ events_ = StringPrintf(
+ "\n%s\n Delta Cumulative\n",
+ logger_name.c_str());
}
EventLogger::~EventLogger() {
- if (VLOG_IS_ON(3)) {
- AddEvent("Total");
- VLOG(2) << "\n" << events_ << "\n";
+ if (!VLOG_IS_ON(3)) {
+ return;
}
+ AddEvent("Total");
+ VLOG(3) << "\n" << events_ << "\n";
}
void EventLogger::AddEvent(const std::string& event_name) {
diff --git a/extern/ceres/internal/ceres/wall_time.h b/extern/ceres/internal/ceres/wall_time.h
index 966aa67cab6..ed0610f27da 100644
--- a/extern/ceres/internal/ceres/wall_time.h
+++ b/extern/ceres/internal/ceres/wall_time.h
@@ -77,7 +77,7 @@ class EventLogger {
void AddEvent(const std::string& event_name);
private:
- const double start_time_;
+ double start_time_;
double last_event_time_;
std::string events_;
};
diff --git a/extern/ceres/patches/series b/extern/ceres/patches/series
index e69de29bb2d..7fa3673acac 100644
--- a/extern/ceres/patches/series
+++ b/extern/ceres/patches/series
@@ -0,0 +1,2 @@
+unused_parameter.patch
+unused_variable.patch
diff --git a/extern/ceres/patches/unused_parameter.patch b/extern/ceres/patches/unused_parameter.patch
new file mode 100644
index 00000000000..14969d6a19f
--- /dev/null
+++ b/extern/ceres/patches/unused_parameter.patch
@@ -0,0 +1,13 @@
+diff --git a/extern/ceres/include/ceres/internal/autodiff.h b/extern/ceres/include/ceres/internal/autodiff.h
+index 71b7bae4757..cb7b1aca5b9 100644
+--- a/include/ceres/internal/autodiff.h
++++ b/include/ceres/internal/autodiff.h
+@@ -198,7 +198,7 @@ struct Make1stOrderPerturbation {
+ template <int N, int Offset, typename T, typename JetT>
+ struct Make1stOrderPerturbation<N, N, Offset, T, JetT> {
+ public:
+- static void Apply(const T* src, JetT* dst) {}
++ static void Apply(const T* /*src*/, JetT* /*dst*/) {}
+ };
+
+ // Calls Make1stOrderPerturbation for every parameter block.
diff --git a/extern/ceres/patches/unused_variable.patch b/extern/ceres/patches/unused_variable.patch
new file mode 100644
index 00000000000..24a4f392962
--- /dev/null
+++ b/extern/ceres/patches/unused_variable.patch
@@ -0,0 +1,12 @@
+diff --git a/extern/ceres/internal/ceres/sparse_cholesky.cc b/extern/ceres/internal/ceres/sparse_cholesky.cc
+index 0639ea90664..d9d2100d3f9 100644
+--- a/internal/ceres/sparse_cholesky.cc
++++ b/internal/ceres/sparse_cholesky.cc
+@@ -56,6 +56,7 @@ std::unique_ptr<SparseCholesky> SparseCholesky::Create(
+ }
+ break;
+ #else
++ (void)ordering_type;
+ LOG(FATAL) << "Ceres was compiled without support for SuiteSparse.";
+ #endif
+
diff --git a/extern/draco/CMakeLists.txt b/extern/draco/CMakeLists.txt
index a3f9a8b9561..6961fa8a769 100644
--- a/extern/draco/CMakeLists.txt
+++ b/extern/draco/CMakeLists.txt
@@ -18,8 +18,6 @@
# All rights reserved.
# ***** END GPL LICENSE BLOCK *****
-set(CMAKE_CXX_STANDARD 14)
-
# Build Draco library.
add_subdirectory(dracoenc)
diff --git a/extern/glog/AUTHORS b/extern/glog/AUTHORS
index 8e654101b7c..e5111cea7dd 100644
--- a/extern/glog/AUTHORS
+++ b/extern/glog/AUTHORS
@@ -10,6 +10,7 @@
Abhishek Dasgupta <abhi2743@gmail.com>
Abhishek Parmar <abhishek@orng.net>
+Andrew Schwartzmeyer <andrew@schwartzmeyer.com>
Andy Ying <andy@trailofbits.com>
Brian Silverman <bsilver16384@gmail.com>
Google Inc.
@@ -17,6 +18,8 @@ Guillaume Dumont <dumont.guillaume@gmail.com>
Michael Tanner <michael@tannertaxpro.com>
MiniLight <MiniLightAR@Gmail.com>
romange <romange@users.noreply.github.com>
+Roman Perepelitsa <roman.perepelitsa@gmail.com>
Sergiu Deitsch <sergiu.deitsch@gmail.com>
tbennun <tbennun@gmail.com>
Teddy Reed <teddy@prosauce.org>
+Zhongming Qu <qzmfranklin@gmail.com>
diff --git a/extern/glog/CMakeLists.txt b/extern/glog/CMakeLists.txt
index bfe715d3463..2a9736425a8 100644
--- a/extern/glog/CMakeLists.txt
+++ b/extern/glog/CMakeLists.txt
@@ -27,11 +27,16 @@ set(INC_SYS
)
set(SRC
+ src/demangle.cc
src/logging.cc
src/raw_logging.cc
+ src/signalhandler.cc
+ src/symbolize.cc
src/utilities.cc
src/vlog_is_on.cc
+ src/demangle.h
+ src/symbolize.h
src/utilities.h
src/config.h
@@ -51,6 +56,7 @@ set(SRC
src/stacktrace_powerpc-inl.h
src/stacktrace_x86_64-inl.h
src/stacktrace_x86-inl.h
+ src/stacktrace_windows-inl.h
)
set(LIB
@@ -87,13 +93,6 @@ else()
include
)
list(APPEND SRC
- src/demangle.cc
- src/signalhandler.cc
- src/symbolize.cc
-
- src/demangle.h
- src/symbolize.h
-
include/glog/logging.h
include/glog/log_severity.h
include/glog/raw_logging.h
diff --git a/extern/glog/ChangeLog b/extern/glog/ChangeLog
index d1b42484416..f8e43f8b39d 100644
--- a/extern/glog/ChangeLog
+++ b/extern/glog/ChangeLog
@@ -1,3 +1,18 @@
+2019-01-22 Google Inc. <opensource@google.com>
+
+ * google-glog: version 0.4.0.
+ * See git log for the details.
+
+2017-05-09 Google Inc. <opensource@google.com>
+
+ * google-glog: version 0.3.5
+ * See git log for the details.
+
+2015-03-09 Google Inc. <opensource@google.com>
+
+ * google-glog: version 0.3.4
+ * See git log for the details.
+
2013-02-01 Google Inc. <opensource@google.com>
* google-glog: version 0.3.3
diff --git a/extern/glog/README.blender b/extern/glog/README.blender
index 38d5ff05c86..62cd065ef0f 100644
--- a/extern/glog/README.blender
+++ b/extern/glog/README.blender
@@ -1,7 +1,7 @@
Project: Google Logging
URL: https://github.com/google/glog
License: New BSD
-Upstream version: 0.3.5, a6a166db069
+Upstream version: 0.4.0, 96a2f23dca4
Local modifications:
* Added per-platform config.h files so no configuration-time
checks for functions and so are needed.
diff --git a/extern/glog/include/glog/logging.h b/extern/glog/include/glog/logging.h
index 8238ca9610f..7254b8dd62c 100644
--- a/extern/glog/include/glog/logging.h
+++ b/extern/glog/include/glog/logging.h
@@ -431,9 +431,15 @@ DECLARE_bool(stop_logging_if_full_disk);
#define LOG_TO_STRING_FATAL(message) google::NullStreamFatal()
#endif
+#if defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON)
+#define DCHECK_IS_ON() 0
+#else
+#define DCHECK_IS_ON() 1
+#endif
+
// For DFATAL, we want to use LogMessage (as opposed to
// LogMessageFatal), to be consistent with the original behavior.
-#ifdef NDEBUG
+#if !DCHECK_IS_ON()
#define COMPACT_GOOGLE_LOG_DFATAL COMPACT_GOOGLE_LOG_ERROR
#elif GOOGLE_STRIP_LOG <= 3
#define COMPACT_GOOGLE_LOG_DFATAL google::LogMessage( \
@@ -562,8 +568,10 @@ class LogSink; // defined below
LOG_TO_STRING_##severity(static_cast<std::vector<std::string>*>(outvec)).stream()
#define LOG_IF(severity, condition) \
+ static_cast<void>(0), \
!(condition) ? (void) 0 : google::LogMessageVoidify() & LOG(severity)
#define SYSLOG_IF(severity, condition) \
+ static_cast<void>(0), \
!(condition) ? (void) 0 : google::LogMessageVoidify() & SYSLOG(severity)
#define LOG_ASSERT(condition) \
@@ -572,7 +580,7 @@ class LogSink; // defined below
SYSLOG_IF(FATAL, !(condition)) << "Assert failed: " #condition
// CHECK dies with a fatal error if condition is not true. It is *not*
-// controlled by NDEBUG, so the check will be executed regardless of
+// controlled by DCHECK_IS_ON(), so the check will be executed regardless of
// compilation mode. Therefore, it is safe to do things like:
// CHECK(fp->Write(x) == 4)
#define CHECK(condition) \
@@ -644,7 +652,7 @@ void MakeCheckOpValueString(std::ostream* os, const unsigned char& v);
// Build the error message string. Specify no inlining for code size.
template <typename T1, typename T2>
std::string* MakeCheckOpString(const T1& v1, const T2& v2, const char* exprtext)
- __attribute__ ((noinline));
+ __attribute__((noinline));
namespace base {
namespace internal {
@@ -722,7 +730,7 @@ DEFINE_CHECK_OP_IMPL(Check_GT, > )
#if defined(STATIC_ANALYSIS)
// Only for static analysis tool to know that it is equivalent to assert
#define CHECK_OP_LOG(name, op, val1, val2, log) CHECK((val1) op (val2))
-#elif !defined(NDEBUG)
+#elif DCHECK_IS_ON()
// In debug mode, avoid constructing CheckOpStrings if possible,
// to reduce the overhead of CHECK statments by 2x.
// Real DCHECK-heavy tests have seen 1.5x speedups.
@@ -751,7 +759,7 @@ typedef std::string _Check_string;
google::GetReferenceableValue(val2), \
#val1 " " #op " " #val2)) \
log(__FILE__, __LINE__, _result).stream()
-#endif // STATIC_ANALYSIS, !NDEBUG
+#endif // STATIC_ANALYSIS, DCHECK_IS_ON()
#if GOOGLE_STRIP_LOG <= 3
#define CHECK_OP(name, op, val1, val2) \
@@ -853,6 +861,7 @@ DECLARE_CHECK_STROP_IMPL(strcasecmp, false)
&google::LogMessage::SendToLog)
#define PLOG_IF(severity, condition) \
+ static_cast<void>(0), \
!(condition) ? (void) 0 : google::LogMessageVoidify() & PLOG(severity)
// A CHECK() macro that postpends errno if the condition is false. E.g.
@@ -925,16 +934,11 @@ struct CompileAssert {
struct CrashReason;
// Returns true if FailureSignalHandler is installed.
-bool IsFailureSignalHandlerInstalled();
+// Needs to be exported since it's used by the signalhandler_unittest.
+GOOGLE_GLOG_DLL_DECL bool IsFailureSignalHandlerInstalled();
} // namespace glog_internal_namespace_
-#define GOOGLE_GLOG_COMPILE_ASSERT(expr, msg) \
- typedef google::glog_internal_namespace_::CompileAssert<(bool(expr))> msg[bool(expr) ? 1 : -1]
-
#define LOG_EVERY_N(severity, n) \
- GOOGLE_GLOG_COMPILE_ASSERT(google::GLOG_ ## severity < \
- google::NUM_SEVERITIES, \
- INVALID_REQUESTED_LOG_SEVERITY); \
SOME_KIND_OF_LOG_EVERY_N(severity, (n), google::LogMessage::SendToLog)
#define SYSLOG_EVERY_N(severity, n) \
@@ -976,7 +980,7 @@ const LogSeverity GLOG_0 = GLOG_ERROR;
// Plus some debug-logging macros that get compiled to nothing for production
-#ifndef NDEBUG
+#if DCHECK_IS_ON()
#define DLOG(severity) LOG(severity)
#define DVLOG(verboselevel) VLOG(verboselevel)
@@ -986,7 +990,7 @@ const LogSeverity GLOG_0 = GLOG_ERROR;
LOG_IF_EVERY_N(severity, condition, n)
#define DLOG_ASSERT(condition) LOG_ASSERT(condition)
-// debug-only checking. not executed in NDEBUG mode.
+// debug-only checking. executed if DCHECK_IS_ON().
#define DCHECK(condition) CHECK(condition)
#define DCHECK_EQ(val1, val2) CHECK_EQ(val1, val2)
#define DCHECK_NE(val1, val2) CHECK_NE(val1, val2)
@@ -1000,25 +1004,31 @@ const LogSeverity GLOG_0 = GLOG_ERROR;
#define DCHECK_STRNE(str1, str2) CHECK_STRNE(str1, str2)
#define DCHECK_STRCASENE(str1, str2) CHECK_STRCASENE(str1, str2)
-#else // NDEBUG
+#else // !DCHECK_IS_ON()
-#define DLOG(severity) \
+#define DLOG(severity) \
+ static_cast<void>(0), \
true ? (void) 0 : google::LogMessageVoidify() & LOG(severity)
-#define DVLOG(verboselevel) \
- (true || !VLOG_IS_ON(verboselevel)) ?\
- (void) 0 : google::LogMessageVoidify() & LOG(INFO)
+#define DVLOG(verboselevel) \
+ static_cast<void>(0), \
+ (true || !VLOG_IS_ON(verboselevel)) ? \
+ (void) 0 : google::LogMessageVoidify() & LOG(INFO)
#define DLOG_IF(severity, condition) \
+ static_cast<void>(0), \
(true || !(condition)) ? (void) 0 : google::LogMessageVoidify() & LOG(severity)
#define DLOG_EVERY_N(severity, n) \
+ static_cast<void>(0), \
true ? (void) 0 : google::LogMessageVoidify() & LOG(severity)
#define DLOG_IF_EVERY_N(severity, condition, n) \
+ static_cast<void>(0), \
(true || !(condition))? (void) 0 : google::LogMessageVoidify() & LOG(severity)
#define DLOG_ASSERT(condition) \
+ static_cast<void>(0), \
true ? (void) 0 : LOG_ASSERT(condition)
// MSVC warning C4127: conditional expression is constant
@@ -1081,7 +1091,7 @@ const LogSeverity GLOG_0 = GLOG_ERROR;
while (false) \
GLOG_MSVC_POP_WARNING() CHECK_STRCASENE(str1, str2)
-#endif // NDEBUG
+#endif // DCHECK_IS_ON()
// Log only in verbose mode.
@@ -1103,10 +1113,11 @@ namespace base_logging {
// buffer to allow for a '\n' and '\0'.
class GOOGLE_GLOG_DLL_DECL LogStreamBuf : public std::streambuf {
public:
- // REQUIREMENTS: "len" must be >= 2 to account for the '\n' and '\n'.
+ // REQUIREMENTS: "len" must be >= 2 to account for the '\n' and '\0'.
LogStreamBuf(char *buf, int len) {
setp(buf, buf + len - 2);
}
+
// This effectively ignores overflow.
virtual int_type overflow(int_type ch) {
return ch;
@@ -1145,13 +1156,9 @@ public:
// 2005 if you are deriving from a type in the Standard C++ Library"
// http://msdn.microsoft.com/en-us/library/3tdb471s(VS.80).aspx
// Let's just ignore the warning.
-#ifdef _MSC_VER
-# pragma warning(disable: 4275)
-#endif
+GLOG_MSVC_PUSH_DISABLE_WARNING(4275)
class GOOGLE_GLOG_DLL_DECL LogStream : public std::ostream {
-#ifdef _MSC_VER
-# pragma warning(default: 4275)
-#endif
+GLOG_MSVC_POP_WARNING()
public:
LogStream(char *buf, int len, int ctr)
: std::ostream(NULL),
@@ -1240,7 +1247,7 @@ public:
void SendToSyslogAndLog(); // Actually dispatch to syslog and the logs
// Call abort() or similar to perform LOG(FATAL) crash.
- static void __attribute__ ((noreturn)) Fail();
+ static void __attribute__((noreturn)) Fail();
std::ostream& stream();
@@ -1288,7 +1295,7 @@ class GOOGLE_GLOG_DLL_DECL LogMessageFatal : public LogMessage {
public:
LogMessageFatal(const char* file, int line);
LogMessageFatal(const char* file, int line, const CheckOpString& result);
- __attribute__ ((noreturn)) ~LogMessageFatal();
+ __attribute__((noreturn)) ~LogMessageFatal();
};
// A non-macro interface to the log facility; (useful
@@ -1303,6 +1310,35 @@ inline void LogAtLevel(int const severity, std::string const &msg) {
// LOG macros, 2. this macro can be used as C++ stream.
#define LOG_AT_LEVEL(severity) google::LogMessage(__FILE__, __LINE__, severity).stream()
+// Check if it's compiled in C++11 mode.
+//
+// GXX_EXPERIMENTAL_CXX0X is defined by gcc and clang up to at least
+// gcc-4.7 and clang-3.1 (2011-12-13). __cplusplus was defined to 1
+// in gcc before 4.7 (Crosstool 16) and clang before 3.1, but is
+// defined according to the language version in effect thereafter.
+// Microsoft Visual Studio 14 (2015) sets __cplusplus==199711 despite
+// reasonably good C++11 support, so we set LANG_CXX for it and
+// newer versions (_MSC_VER >= 1900).
+#if (defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L || \
+ (defined(_MSC_VER) && _MSC_VER >= 1900))
+// Helper for CHECK_NOTNULL().
+//
+// In C++11, all cases can be handled by a single function. Since the value
+// category of the argument is preserved (also for rvalue references),
+// member initializer lists like the one below will compile correctly:
+//
+// Foo()
+// : x_(CHECK_NOTNULL(MethodReturningUniquePtr())) {}
+template <typename T>
+T CheckNotNull(const char* file, int line, const char* names, T&& t) {
+ if (t == nullptr) {
+ LogMessageFatal(file, line, new std::string(names));
+ }
+ return std::forward<T>(t);
+}
+
+#else
+
// A small helper for CHECK_NOTNULL().
template <typename T>
T* CheckNotNull(const char *file, int line, const char *names, T* t) {
@@ -1311,6 +1347,7 @@ T* CheckNotNull(const char *file, int line, const char *names, T* t) {
}
return t;
}
+#endif
// Allow folks to put a counter in the LOG_EVERY_X()'ed messages. This
// only works if ostream is a LogStream. If the ostream is not a
@@ -1592,7 +1629,7 @@ class GOOGLE_GLOG_DLL_DECL NullStreamFatal : public NullStream {
NullStreamFatal() { }
NullStreamFatal(const char* file, int line, const CheckOpString& result) :
NullStream(file, line, result) { }
- __attribute__ ((noreturn)) ~NullStreamFatal() throw () { _exit(1); }
+ __attribute__((noreturn)) ~NullStreamFatal() throw () { _exit(1); }
};
// Install a signal handler that will dump signal information and a stack
diff --git a/extern/glog/include/glog/raw_logging.h b/extern/glog/include/glog/raw_logging.h
index 65278f62803..cf3f27d9516 100644
--- a/extern/glog/include/glog/raw_logging.h
+++ b/extern/glog/include/glog/raw_logging.h
@@ -173,12 +173,7 @@ GOOGLE_GLOG_DLL_DECL void RawLog__(LogSeverity severity,
const char* file,
int line,
const char* format, ...)
- __attribute__((__format__ (__printf__, 4, 5)));
-
-// Hack to propagate time information into this module so that
-// this module does not have to directly call localtime_r(),
-// which could allocate memory.
-GOOGLE_GLOG_DLL_DECL void RawLog__SetLastTime(const struct tm& t, int usecs);
+ ;
}
diff --git a/extern/glog/src/config.h b/extern/glog/src/config.h
index 2703b7ba9dd..e4cde736d65 100644
--- a/extern/glog/src/config.h
+++ b/extern/glog/src/config.h
@@ -1,7 +1,3 @@
-/* src/config.h. Generated from config.h.in by configure. */
-/* src/config.h.in. Generated from configure.ac by autoheader. */
-
-/* Namespace for Google classes */
#if defined(__APPLE__)
#include "config_mac.h"
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
diff --git a/extern/glog/src/config_mac.h b/extern/glog/src/config_mac.h
index 4f008b5f67c..57cc64a0a74 100644
--- a/extern/glog/src/config_mac.h
+++ b/extern/glog/src/config_mac.h
@@ -5,7 +5,7 @@
#define GOOGLE_NAMESPACE google
/* Define if you have the `dladdr' function */
-/* #undef HAVE_DLADDR */
+#define HAVE_DLADDR
/* Define if you have the `snprintf' function */
#define HAVE_SNPRINTF
@@ -65,7 +65,7 @@
#define HAVE_PWRITE
/* define if the compiler implements pthread_rwlock_* */
-/* #undef HAVE_RWLOCK */
+#define HAVE_RWLOCK
/* Define if you have the 'sigaction' function */
#define HAVE_SIGACTION
@@ -104,7 +104,7 @@
#define HAVE_SYS_TYPES_H 1
/* Define to 1 if you have the <sys/ucontext.h> header file. */
-#define HAVE_SYS_UCONTEXT_H 1
+/* #undef HAVE_SYS_UCONTEXT_H */
/* Define to 1 if you have the <sys/utsname.h> header file. */
#define HAVE_SYS_UTSNAME_H
diff --git a/extern/glog/src/demangle.cc b/extern/glog/src/demangle.cc
index e858181a68f..9369f9a65c2 100644
--- a/extern/glog/src/demangle.cc
+++ b/extern/glog/src/demangle.cc
@@ -30,15 +30,22 @@
// Author: Satoru Takabayashi
//
// For reference check out:
-// http://www.codesourcery.com/public/cxx-abi/abi.html#mangling
+// http://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling
//
// Note that we only have partial C++0x support yet.
#include <stdio.h> // for NULL
+#include "utilities.h"
#include "demangle.h"
+#if defined(OS_WINDOWS)
+#include <dbghelp.h>
+#pragma comment(lib, "dbghelp")
+#endif
+
_START_GOOGLE_NAMESPACE_
+#if !defined(OS_WINDOWS)
typedef struct {
const char *abbrev;
const char *real_name;
@@ -416,6 +423,8 @@ static bool ParseNumber(State *state, int *number_out);
static bool ParseFloatNumber(State *state);
static bool ParseSeqId(State *state);
static bool ParseIdentifier(State *state, int length);
+static bool ParseAbiTags(State *state);
+static bool ParseAbiTag(State *state);
static bool ParseOperatorName(State *state);
static bool ParseSpecialName(State *state);
static bool ParseCallOffset(State *state);
@@ -587,13 +596,13 @@ static bool ParsePrefix(State *state) {
// <unqualified-name> ::= <operator-name>
// ::= <ctor-dtor-name>
-// ::= <source-name>
-// ::= <local-source-name>
+// ::= <source-name> [<abi-tags>]
+// ::= <local-source-name> [<abi-tags>]
static bool ParseUnqualifiedName(State *state) {
return (ParseOperatorName(state) ||
ParseCtorDtorName(state) ||
- ParseSourceName(state) ||
- ParseLocalSourceName(state));
+ (ParseSourceName(state) && Optional(ParseAbiTags(state))) ||
+ (ParseLocalSourceName(state) && Optional(ParseAbiTags(state))));
}
// <source-name> ::= <positive length number> <identifier>
@@ -696,6 +705,23 @@ static bool ParseIdentifier(State *state, int length) {
return true;
}
+// <abi-tags> ::= <abi-tag> [<abi-tags>]
+static bool ParseAbiTags(State *state) {
+ State copy = *state;
+ DisableAppend(state);
+ if (OneOrMore(ParseAbiTag, state)) {
+ RestoreAppend(state, copy.append);
+ return true;
+ }
+ *state = copy;
+ return false;
+}
+
+// <abi-tag> ::= B <source-name>
+static bool ParseAbiTag(State *state) {
+ return ParseOneCharToken(state, 'B') && ParseSourceName(state);
+}
+
// <operator-name> ::= nw, and other two letters cases
// ::= cv <type> # (cast)
// ::= v <digit> <source-name> # vendor extended operator
@@ -1090,10 +1116,11 @@ static bool ParseTemplateArgs(State *state) {
// <template-arg> ::= <type>
// ::= <expr-primary>
// ::= I <template-arg>* E # argument pack
+// ::= J <template-arg>* E # argument pack
// ::= X <expression> E
static bool ParseTemplateArg(State *state) {
State copy = *state;
- if (ParseOneCharToken(state, 'I') &&
+ if ((ParseOneCharToken(state, 'I') || ParseOneCharToken(state, 'J')) &&
ZeroOrMore(ParseTemplateArg, state) &&
ParseOneCharToken(state, 'E')) {
return true;
@@ -1293,12 +1320,37 @@ static bool ParseTopLevelMangledName(State *state) {
}
return false;
}
+#endif
// The demangler entry point.
bool Demangle(const char *mangled, char *out, int out_size) {
+#if defined(OS_WINDOWS)
+ // When built with incremental linking, the Windows debugger
+ // library provides a more complicated `Symbol->Name` with the
+ // Incremental Linking Table offset, which looks like
+ // `@ILT+1105(?func@Foo@@SAXH@Z)`. However, the demangler expects
+ // only the mangled symbol, `?func@Foo@@SAXH@Z`. Fortunately, the
+ // mangled symbol is guaranteed not to have parentheses,
+ // so we search for `(` and extract up to `)`.
+ //
+ // Since we may be in a signal handler here, we cannot use `std::string`.
+ char buffer[1024]; // Big enough for a sane symbol.
+ const char *lparen = strchr(mangled, '(');
+ if (lparen) {
+ // Extract the string `(?...)`
+ const char *rparen = strchr(lparen, ')');
+ size_t length = rparen - lparen - 1;
+ strncpy(buffer, lparen + 1, length);
+ buffer[length] = '\0';
+ mangled = buffer;
+ } // Else the symbol wasn't inside a set of parentheses
+ // We use the ANSI version to ensure the string type is always `char *`.
+ return UnDecorateSymbolName(mangled, out, out_size, UNDNAME_COMPLETE);
+#else
State state;
InitState(&state, mangled, out, out_size);
return ParseTopLevelMangledName(&state) && !state.overflowed;
+#endif
}
_END_GOOGLE_NAMESPACE_
diff --git a/extern/glog/src/logging.cc b/extern/glog/src/logging.cc
index 3e8f48e814d..0c86cf62296 100644
--- a/extern/glog/src/logging.cc
+++ b/extern/glog/src/logging.cc
@@ -114,11 +114,6 @@ GLOG_DEFINE_bool(drop_log_memory, true, "Drop in-memory buffers of log contents.
"Logs can grow very quickly and they are rarely read before they "
"need to be evicted from memory. Instead, drop them from memory "
"as soon as they are flushed to disk.");
-_START_GOOGLE_NAMESPACE_
-namespace logging {
-static const int64 kPageSize = getpagesize();
-}
-_END_GOOGLE_NAMESPACE_
#endif
// By default, errors (including fatal errors) get logged to stderr as
@@ -188,7 +183,7 @@ GLOG_DEFINE_string(log_backtrace_at, "",
#ifndef HAVE_PREAD
#if defined(OS_WINDOWS)
-#include <BaseTsd.h>
+#include <basetsd.h>
#define ssize_t SSIZE_T
#endif
static ssize_t pread(int fd, void* buf, size_t count, off_t offset) {
@@ -304,7 +299,7 @@ static GLogColor SeverityToColor(LogSeverity severity) {
#ifdef OS_WINDOWS
// Returns the character attribute for the given color.
-WORD GetColorAttribute(GLogColor color) {
+static WORD GetColorAttribute(GLogColor color) {
switch (color) {
case COLOR_RED: return FOREGROUND_RED;
case COLOR_GREEN: return FOREGROUND_GREEN;
@@ -316,7 +311,7 @@ WORD GetColorAttribute(GLogColor color) {
#else
// Returns the ANSI color code for the given color.
-const char* GetAnsiColorCode(GLogColor color) {
+static const char* GetAnsiColorCode(GLogColor color) {
switch (color) {
case COLOR_RED: return "1";
case COLOR_GREEN: return "2";
@@ -441,6 +436,7 @@ class LogFileObject : public base::Logger {
FILE* file_;
LogSeverity severity_;
uint32 bytes_since_flush_;
+ uint32 dropped_mem_length_;
uint32 file_length_;
unsigned int rollover_attempt_;
int64 next_flush_time_; // cycle count at which to flush log
@@ -842,6 +838,7 @@ LogFileObject::LogFileObject(LogSeverity severity,
file_(NULL),
severity_(severity),
bytes_since_flush_(0),
+ dropped_mem_length_(0),
file_length_(0),
rollover_attempt_(kRolloverAttemptFrequency-1),
next_flush_time_(0) {
@@ -979,7 +976,7 @@ void LogFileObject::Write(bool force_flush,
PidHasChanged()) {
if (file_ != NULL) fclose(file_);
file_ = NULL;
- file_length_ = bytes_since_flush_ = 0;
+ file_length_ = bytes_since_flush_ = dropped_mem_length_ = 0;
rollover_attempt_ = kRolloverAttemptFrequency-1;
}
@@ -1119,11 +1116,17 @@ void LogFileObject::Write(bool force_flush,
(CycleClock_Now() >= next_flush_time_) ) {
FlushUnlocked();
#ifdef OS_LINUX
- if (FLAGS_drop_log_memory) {
- if (file_length_ >= logging::kPageSize) {
- // don't evict the most recent page
- uint32 len = file_length_ & ~(logging::kPageSize - 1);
- posix_fadvise(fileno(file_), 0, len, POSIX_FADV_DONTNEED);
+ // Only consider files >= 3MiB
+ if (FLAGS_drop_log_memory && file_length_ >= (3 << 20)) {
+ // Don't evict the most recent 1-2MiB so as not to impact a tailer
+ // of the log file and to avoid page rounding issue on linux < 4.7
+ uint32 total_drop_length = (file_length_ & ~((1 << 20) - 1)) - (1 << 20);
+ uint32 this_drop_length = total_drop_length - dropped_mem_length_;
+ if (this_drop_length >= (2 << 20)) {
+ // Only advise when >= 2MiB to drop
+ posix_fadvise(fileno(file_), dropped_mem_length_, this_drop_length,
+ POSIX_FADV_DONTNEED);
+ dropped_mem_length_ = total_drop_length;
}
}
#endif
@@ -1145,6 +1148,22 @@ static bool fatal_msg_exclusive = true;
static LogMessage::LogMessageData fatal_msg_data_exclusive;
static LogMessage::LogMessageData fatal_msg_data_shared;
+#ifdef GLOG_THREAD_LOCAL_STORAGE
+// Static thread-local log data space to use, because typically at most one
+// LogMessageData object exists (in this case glog makes zero heap memory
+// allocations).
+static GLOG_THREAD_LOCAL_STORAGE bool thread_data_available = true;
+
+#ifdef HAVE_ALIGNED_STORAGE
+static GLOG_THREAD_LOCAL_STORAGE
+ std::aligned_storage<sizeof(LogMessage::LogMessageData),
+ alignof(LogMessage::LogMessageData)>::type thread_msg_data;
+#else
+static GLOG_THREAD_LOCAL_STORAGE
+ char thread_msg_data[sizeof(void*) + sizeof(LogMessage::LogMessageData)];
+#endif // HAVE_ALIGNED_STORAGE
+#endif // defined(GLOG_THREAD_LOCAL_STORAGE)
+
LogMessage::LogMessageData::LogMessageData()
: stream_(message_text_, LogMessage::kMaxLogMessageLen, 0) {
}
@@ -1201,8 +1220,28 @@ void LogMessage::Init(const char* file,
void (LogMessage::*send_method)()) {
allocated_ = NULL;
if (severity != GLOG_FATAL || !exit_on_dfatal) {
+#ifdef GLOG_THREAD_LOCAL_STORAGE
+ // No need for locking, because this is thread local.
+ if (thread_data_available) {
+ thread_data_available = false;
+#ifdef HAVE_ALIGNED_STORAGE
+ data_ = new (&thread_msg_data) LogMessageData;
+#else
+ const uintptr_t kAlign = sizeof(void*) - 1;
+
+ char* align_ptr =
+ reinterpret_cast<char*>(reinterpret_cast<uintptr_t>(thread_msg_data + kAlign) & ~kAlign);
+ data_ = new (align_ptr) LogMessageData;
+ assert(reinterpret_cast<uintptr_t>(align_ptr) % sizeof(void*) == 0);
+#endif
+ } else {
+ allocated_ = new LogMessageData();
+ data_ = allocated_;
+ }
+#else // !defined(GLOG_THREAD_LOCAL_STORAGE)
allocated_ = new LogMessageData();
data_ = allocated_;
+#endif // defined(GLOG_THREAD_LOCAL_STORAGE)
data_->first_fatal_ = false;
} else {
MutexLock l(&fatal_msg_lock);
@@ -1227,7 +1266,6 @@ void LogMessage::Init(const char* file,
data_->timestamp_ = static_cast<time_t>(now);
localtime_r(&data_->timestamp_, &data_->tm_time_);
int usecs = static_cast<int>((now - data_->timestamp_) * 1000000);
- RawLog__SetLastTime(data_->tm_time_, usecs);
data_->num_chars_to_log_ = 0;
data_->num_chars_to_syslog_ = 0;
@@ -1271,7 +1309,17 @@ void LogMessage::Init(const char* file,
LogMessage::~LogMessage() {
Flush();
+#ifdef GLOG_THREAD_LOCAL_STORAGE
+ if (data_ == static_cast<void*>(&thread_msg_data)) {
+ data_->~LogMessageData();
+ thread_data_available = true;
+ }
+ else {
+ delete allocated_;
+ }
+#else // !defined(GLOG_THREAD_LOCAL_STORAGE)
delete allocated_;
+#endif // defined(GLOG_THREAD_LOCAL_STORAGE)
}
int LogMessage::preserved_errno() const {
@@ -1466,16 +1514,13 @@ void LogMessage::RecordCrashReason(
# define ATTRIBUTE_NORETURN
#endif
+#if defined(OS_WINDOWS)
+__declspec(noreturn)
+#endif
static void logging_fail() ATTRIBUTE_NORETURN;
static void logging_fail() {
-#if defined(_DEBUG) && defined(_MSC_VER)
- // When debugging on windows, avoid the obnoxious dialog and make
- // it possible to continue past a LOG(FATAL) in the debugger
- __debugbreak();
-#else
abort();
-#endif
}
typedef void (*logging_fail_func_t)() ATTRIBUTE_NORETURN;
@@ -1681,6 +1726,7 @@ void LogToStderr() {
namespace base {
namespace internal {
+bool GetExitOnDFatal();
bool GetExitOnDFatal() {
MutexLock l(&log_mutex);
return exit_on_dfatal;
@@ -1696,6 +1742,7 @@ bool GetExitOnDFatal() {
// and the stack trace is not recorded. The LOG(FATAL) *will* still
// exit the program. Since this function is used only in testing,
// these differences are acceptable.
+void SetExitOnDFatal(bool value);
void SetExitOnDFatal(bool value) {
MutexLock l(&log_mutex);
exit_on_dfatal = value;
@@ -1704,6 +1751,42 @@ void SetExitOnDFatal(bool value) {
} // namespace internal
} // namespace base
+// Shell-escaping as we need to shell out ot /bin/mail.
+static const char kDontNeedShellEscapeChars[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz"
+ "0123456789+-_.=/:,@";
+
+static string ShellEscape(const string& src) {
+ string result;
+ if (!src.empty() && // empty string needs quotes
+ src.find_first_not_of(kDontNeedShellEscapeChars) == string::npos) {
+ // only contains chars that don't need quotes; it's fine
+ result.assign(src);
+ } else if (src.find_first_of('\'') == string::npos) {
+ // no single quotes; just wrap it in single quotes
+ result.assign("'");
+ result.append(src);
+ result.append("'");
+ } else {
+ // needs double quote escaping
+ result.assign("\"");
+ for (size_t i = 0; i < src.size(); ++i) {
+ switch (src[i]) {
+ case '\\':
+ case '$':
+ case '"':
+ case '`':
+ result.append("\\");
+ }
+ result.append(src, i, 1);
+ }
+ result.append("\"");
+ }
+ return result;
+}
+
+
// use_logging controls whether the logging functions LOG/VLOG are used
// to log errors. It should be set to false when the caller holds the
// log_mutex.
@@ -1719,7 +1802,10 @@ static bool SendEmailInternal(const char*dest, const char *subject,
}
string cmd =
- FLAGS_logmailer + " -s\"" + subject + "\" " + dest;
+ FLAGS_logmailer + " -s" +
+ ShellEscape(subject) + " " + ShellEscape(dest);
+ VLOG(4) << "Mailing command: " << cmd;
+
FILE* pipe = popen(cmd.c_str(), "w");
if (pipe != NULL) {
// Add the body if we have one
diff --git a/extern/glog/src/raw_logging.cc b/extern/glog/src/raw_logging.cc
index 7a7409bbf34..3bbfda31868 100644
--- a/extern/glog/src/raw_logging.cc
+++ b/extern/glog/src/raw_logging.cc
@@ -68,17 +68,6 @@
_START_GOOGLE_NAMESPACE_
-// Data for RawLog__ below. We simply pick up the latest
-// time data created by a normal log message to avoid calling
-// localtime_r which can allocate memory.
-static struct ::tm last_tm_time_for_raw_log;
-static int last_usecs_for_raw_log;
-
-void RawLog__SetLastTime(const struct ::tm& t, int usecs) {
- memcpy(&last_tm_time_for_raw_log, &t, sizeof(last_tm_time_for_raw_log));
- last_usecs_for_raw_log = usecs;
-}
-
// CAVEAT: vsnprintf called from *DoRawLog below has some (exotic) code paths
// that invoke malloc() and getenv() that might acquire some locks.
// If this becomes a problem we should reimplement a subset of vsnprintf
@@ -120,16 +109,13 @@ void RawLog__(LogSeverity severity, const char* file, int line,
return; // this stderr log message is suppressed
}
// can't call localtime_r here: it can allocate
- struct ::tm& t = last_tm_time_for_raw_log;
char buffer[kLogBufSize];
char* buf = buffer;
int size = sizeof(buffer);
// NOTE: this format should match the specification in base/logging.h
- DoRawLog(&buf, &size, "%c%02d%02d %02d:%02d:%02d.%06d %5u %s:%d] RAW: ",
+ DoRawLog(&buf, &size, "%c0000 00:00:00.000000 %5u %s:%d] RAW: ",
LogSeverityNames[severity][0],
- 1 + t.tm_mon, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec,
- last_usecs_for_raw_log,
static_cast<unsigned int>(GetTID()),
const_basename(const_cast<char *>(file)), line);
diff --git a/extern/glog/src/signalhandler.cc b/extern/glog/src/signalhandler.cc
index a7aef8b99d2..961ee965196 100644
--- a/extern/glog/src/signalhandler.cc
+++ b/extern/glog/src/signalhandler.cc
@@ -48,9 +48,6 @@
_START_GOOGLE_NAMESPACE_
-// TOOD(hamaji): Use signal instead of sigaction?
-#ifdef HAVE_SIGACTION
-
namespace {
// We'll install the failure signal handler for these signals. We could
@@ -66,10 +63,14 @@ const struct {
{ SIGILL, "SIGILL" },
{ SIGFPE, "SIGFPE" },
{ SIGABRT, "SIGABRT" },
+#if !defined(OS_WINDOWS)
{ SIGBUS, "SIGBUS" },
+#endif
{ SIGTERM, "SIGTERM" },
};
+static bool kFailureSignalHandlerInstalled = false;
+
// Returns the program counter from signal context, NULL if unknown.
void* GetPC(void* ucontext_in_void) {
#if (defined(HAVE_UCONTEXT_H) || defined(HAVE_SYS_UCONTEXT_H)) && defined(PC_FROM_UCONTEXT)
@@ -92,7 +93,7 @@ class MinimalFormatter {
}
// Returns the number of bytes written in the buffer.
- int num_bytes_written() const { return cursor_ - buffer_; }
+ int num_bytes_written() const { return (int) (cursor_ - buffer_); }
// Appends string from "str" and updates the internal cursor.
void AppendString(const char* str) {
@@ -168,6 +169,9 @@ void DumpTimeInfo() {
g_failure_writer(buf, formatter.num_bytes_written());
}
+// TOOD(hamaji): Use signal instead of sigaction?
+#ifdef HAVE_SIGACTION
+
// Dumps information about the signal to STDERR.
void DumpSignalInfo(int signal_number, siginfo_t *siginfo) {
// Get the signal name.
@@ -213,6 +217,8 @@ void DumpSignalInfo(int signal_number, siginfo_t *siginfo) {
g_failure_writer(buf, formatter.num_bytes_written());
}
+#endif // HAVE_SIGACTION
+
// Dumps information about the stack frame to STDERR.
void DumpStackFrameInfo(const char* prefix, void* pc) {
// Get the symbol name.
@@ -240,12 +246,17 @@ void DumpStackFrameInfo(const char* prefix, void* pc) {
// Invoke the default signal handler.
void InvokeDefaultSignalHandler(int signal_number) {
+#ifdef HAVE_SIGACTION
struct sigaction sig_action;
memset(&sig_action, 0, sizeof(sig_action));
sigemptyset(&sig_action.sa_mask);
sig_action.sa_handler = SIG_DFL;
sigaction(signal_number, &sig_action, NULL);
kill(getpid(), signal_number);
+#elif defined(OS_WINDOWS)
+ signal(signal_number, SIG_DFL);
+ raise(signal_number);
+#endif
}
// This variable is used for protecting FailureSignalHandler() from
@@ -256,9 +267,14 @@ static pthread_t* g_entered_thread_id_pointer = NULL;
// Dumps signal and stack frame information, and invokes the default
// signal handler once our job is done.
+#if defined(OS_WINDOWS)
+void FailureSignalHandler(int signal_number)
+#else
void FailureSignalHandler(int signal_number,
siginfo_t *signal_info,
- void *ucontext) {
+ void *ucontext)
+#endif
+{
// First check if we've already entered the function. We use an atomic
// compare and swap operation for platforms that support it. For other
// platforms, we use a naive method that could lead to a subtle race.
@@ -298,16 +314,20 @@ void FailureSignalHandler(int signal_number,
// First dump time info.
DumpTimeInfo();
+#if !defined(OS_WINDOWS)
// Get the program counter from ucontext.
void *pc = GetPC(ucontext);
DumpStackFrameInfo("PC: ", pc);
+#endif
#ifdef HAVE_STACKTRACE
// Get the stack traces.
void *stack[32];
// +1 to exclude this function.
const int depth = GetStackTrace(stack, ARRAYSIZE(stack), 1);
+# ifdef HAVE_SIGACTION
DumpSignalInfo(signal_number, signal_info);
+# endif
// Dump the stack traces.
for (int i = 0; i < depth; ++i) {
DumpStackFrameInfo(" ", stack[i]);
@@ -333,18 +353,19 @@ void FailureSignalHandler(int signal_number,
} // namespace
-#endif // HAVE_SIGACTION
-
namespace glog_internal_namespace_ {
bool IsFailureSignalHandlerInstalled() {
#ifdef HAVE_SIGACTION
+ // TODO(andschwa): Return kFailureSignalHandlerInstalled?
struct sigaction sig_action;
memset(&sig_action, 0, sizeof(sig_action));
sigemptyset(&sig_action.sa_mask);
sigaction(SIGABRT, NULL, &sig_action);
if (sig_action.sa_sigaction == &FailureSignalHandler)
return true;
+#elif defined(OS_WINDOWS)
+ return kFailureSignalHandlerInstalled;
#endif // HAVE_SIGACTION
return false;
}
@@ -363,11 +384,18 @@ void InstallFailureSignalHandler() {
for (size_t i = 0; i < ARRAYSIZE(kFailureSignals); ++i) {
CHECK_ERR(sigaction(kFailureSignals[i].number, &sig_action, NULL));
}
+ kFailureSignalHandlerInstalled = true;
+#elif defined(OS_WINDOWS)
+ for (size_t i = 0; i < ARRAYSIZE(kFailureSignals); ++i) {
+ CHECK_NE(signal(kFailureSignals[i].number, &FailureSignalHandler),
+ SIG_ERR);
+ }
+ kFailureSignalHandlerInstalled = true;
#endif // HAVE_SIGACTION
}
void InstallFailureWriter(void (*writer)(const char* data, int size)) {
-#ifdef HAVE_SIGACTION
+#if defined(HAVE_SIGACTION) || defined(OS_WINDOWS)
g_failure_writer = writer;
#endif // HAVE_SIGACTION
}
diff --git a/extern/glog/src/stacktrace.h b/extern/glog/src/stacktrace.h
index 8c3e8fe8f8d..cb64b33a688 100644
--- a/extern/glog/src/stacktrace.h
+++ b/extern/glog/src/stacktrace.h
@@ -34,6 +34,7 @@
#define BASE_STACKTRACE_H_
#include "config.h"
+#include "glog/logging.h"
_START_GOOGLE_NAMESPACE_
@@ -53,7 +54,7 @@ _START_GOOGLE_NAMESPACE_
// .... ...
//
// "result" must not be NULL.
-extern int GetStackTrace(void** result, int max_depth, int skip_count);
+GOOGLE_GLOG_DLL_DECL int GetStackTrace(void** result, int max_depth, int skip_count);
_END_GOOGLE_NAMESPACE_
diff --git a/extern/glog/src/stacktrace_windows-inl.h b/extern/glog/src/stacktrace_windows-inl.h
new file mode 100644
index 00000000000..726318879d8
--- /dev/null
+++ b/extern/glog/src/stacktrace_windows-inl.h
@@ -0,0 +1,50 @@
+// Copyright (c) 2000 - 2007, 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.
+//
+// Author: Andrew Schwartzmeyer
+//
+// Windows implementation - just use CaptureStackBackTrace
+
+#include "config.h"
+#include "port.h"
+#include "stacktrace.h"
+#include <DbgHelp.h>
+
+_START_GOOGLE_NAMESPACE_
+
+int GetStackTrace(void** result, int max_depth, int skip_count) {
+ if (max_depth > 64) {
+ max_depth = 64;
+ }
+ skip_count++; // we want to skip the current frame as well
+ // This API is thread-safe (moreover it walks only the current thread).
+ return CaptureStackBackTrace(skip_count, max_depth, result, NULL);
+}
+
+_END_GOOGLE_NAMESPACE_
diff --git a/extern/glog/src/stacktrace_x86-inl.h b/extern/glog/src/stacktrace_x86-inl.h
index cfd31f783e3..3b8d5a8282d 100644
--- a/extern/glog/src/stacktrace_x86-inl.h
+++ b/extern/glog/src/stacktrace_x86-inl.h
@@ -93,16 +93,23 @@ static void **NextStackFrame(void **old_sp) {
// If you change this function, also change GetStackFrames below.
int GetStackTrace(void** result, int max_depth, int skip_count) {
void **sp;
-#ifdef __i386__
+
+#ifdef __GNUC__
+#if __GNUC__ * 100 + __GNUC_MINOR__ >= 402
+#define USE_BUILTIN_FRAME_ADDRESS
+#endif
+#endif
+
+#ifdef USE_BUILTIN_FRAME_ADDRESS
+ sp = reinterpret_cast<void**>(__builtin_frame_address(0));
+#elif defined(__i386__)
// Stack frame format:
// sp[0] pointer to previous frame
// sp[1] caller address
// sp[2] first argument
// ...
sp = (void **)&result - 2;
-#endif
-
-#ifdef __x86_64__
+#elif defined(__x86_64__)
// __builtin_frame_address(0) can return the wrong address on gcc-4.1.0-k8
unsigned long rbp;
// Move the value of the register %rbp into the local variable rbp.
diff --git a/extern/glog/src/symbolize.cc b/extern/glog/src/symbolize.cc
index f83c309738e..1ffc6079a2a 100644
--- a/extern/glog/src/symbolize.cc
+++ b/extern/glog/src/symbolize.cc
@@ -56,6 +56,9 @@
#if defined(HAVE_SYMBOLIZE)
+#include <string.h>
+
+#include <algorithm>
#include <limits>
#include "symbolize.h"
@@ -134,17 +137,20 @@ _END_GOOGLE_NAMESPACE_
_START_GOOGLE_NAMESPACE_
-// Read up to "count" bytes from file descriptor "fd" into the buffer
-// starting at "buf" while handling short reads and EINTR. On
-// success, return the number of bytes read. Otherwise, return -1.
-static ssize_t ReadPersistent(const int fd, void *buf, const size_t count) {
+// Read up to "count" bytes from "offset" in the file pointed by file
+// descriptor "fd" into the buffer starting at "buf" while handling short reads
+// and EINTR. On success, return the number of bytes read. Otherwise, return
+// -1.
+static ssize_t ReadFromOffset(const int fd, void *buf, const size_t count,
+ const off_t offset) {
SAFE_ASSERT(fd >= 0);
SAFE_ASSERT(count <= std::numeric_limits<ssize_t>::max());
char *buf0 = reinterpret_cast<char *>(buf);
ssize_t num_bytes = 0;
while (num_bytes < count) {
ssize_t len;
- NO_INTR(len = read(fd, buf0 + num_bytes, count - num_bytes));
+ NO_INTR(len = pread(fd, buf0 + num_bytes, count - num_bytes,
+ offset + num_bytes));
if (len < 0) { // There was an error other than EINTR.
return -1;
}
@@ -157,18 +163,6 @@ static ssize_t ReadPersistent(const int fd, void *buf, const size_t count) {
return num_bytes;
}
-// Read up to "count" bytes from "offset" in the file pointed by file
-// descriptor "fd" into the buffer starting at "buf". On success,
-// return the number of bytes read. Otherwise, return -1.
-static ssize_t ReadFromOffset(const int fd, void *buf,
- const size_t count, const off_t offset) {
- off_t off = lseek(fd, offset, SEEK_SET);
- if (off == (off_t)-1) {
- return -1;
- }
- return ReadPersistent(fd, buf, count);
-}
-
// Try reading exactly "count" bytes from "offset" bytes in a file
// pointed by "fd" into the buffer starting at "buf" while handling
// short reads and EINTR. On success, return true. Otherwise, return
@@ -207,6 +201,9 @@ GetSectionHeaderByType(const int fd, ElfW(Half) sh_num, const off_t sh_offset,
(sizeof(buf) > num_bytes_left) ? num_bytes_left : sizeof(buf);
const ssize_t len = ReadFromOffset(fd, buf, num_bytes_to_read,
sh_offset + i * sizeof(buf[0]));
+ if (len == -1) {
+ return false;
+ }
SAFE_ASSERT(len % sizeof(buf[0]) == 0);
const ssize_t num_headers_in_buf = len / sizeof(buf[0]);
SAFE_ASSERT(num_headers_in_buf <= sizeof(buf) / sizeof(buf[0]));
@@ -296,10 +293,12 @@ FindSymbol(uint64_t pc, const int fd, char *out, int out_size,
// Read at most NUM_SYMBOLS symbols at once to save read() calls.
ElfW(Sym) buf[NUM_SYMBOLS];
- const ssize_t len = ReadFromOffset(fd, &buf, sizeof(buf), offset);
+ int num_symbols_to_read = std::min(NUM_SYMBOLS, num_symbols - i);
+ const ssize_t len =
+ ReadFromOffset(fd, &buf, sizeof(buf[0]) * num_symbols_to_read, offset);
SAFE_ASSERT(len % sizeof(buf[0]) == 0);
const ssize_t num_symbols_in_buf = len / sizeof(buf[0]);
- SAFE_ASSERT(num_symbols_in_buf <= sizeof(buf)/sizeof(buf[0]));
+ SAFE_ASSERT(num_symbols_in_buf <= num_symbols_to_read);
for (int j = 0; j < num_symbols_in_buf; ++j) {
const ElfW(Sym)& symbol = buf[j];
uint64_t start_address = symbol.st_value;
@@ -325,41 +324,17 @@ FindSymbol(uint64_t pc, const int fd, char *out, int out_size,
// both regular and dynamic symbol tables if necessary. On success,
// write the symbol name to "out" and return true. Otherwise, return
// false.
-static bool GetSymbolFromObjectFile(const int fd, uint64_t pc,
- char *out, int out_size,
- uint64_t map_base_address) {
+static bool GetSymbolFromObjectFile(const int fd,
+ uint64_t pc,
+ char* out,
+ int out_size,
+ uint64_t base_address) {
// Read the ELF header.
ElfW(Ehdr) elf_header;
if (!ReadFromOffsetExact(fd, &elf_header, sizeof(elf_header), 0)) {
return false;
}
- uint64_t symbol_offset = 0;
- if (elf_header.e_type == ET_DYN) { // DSO needs offset adjustment.
- ElfW(Phdr) phdr;
- // We need to find the PT_LOAD segment corresponding to the read-execute
- // file mapping in order to correctly perform the offset adjustment.
- for (unsigned i = 0; i != elf_header.e_phnum; ++i) {
- if (!ReadFromOffsetExact(fd, &phdr, sizeof(phdr),
- elf_header.e_phoff + i * sizeof(phdr)))
- return false;
- if (phdr.p_type == PT_LOAD &&
- (phdr.p_flags & (PF_R | PF_X)) == (PF_R | PF_X)) {
- // Find the mapped address corresponding to virtual address zero. We do
- // this by first adding p_offset. This gives us the mapped address of
- // the start of the segment, or in other words the mapped address
- // corresponding to the virtual address of the segment. (Note that this
- // is distinct from the start address, as p_offset is not guaranteed to
- // be page aligned.) We then subtract p_vaddr, which takes us to virtual
- // address zero.
- symbol_offset = map_base_address + phdr.p_offset - phdr.p_vaddr;
- break;
- }
- }
- if (symbol_offset == 0)
- return false;
- }
-
ElfW(Shdr) symtab, strtab;
// Consult a regular symbol table first.
@@ -369,8 +344,7 @@ static bool GetSymbolFromObjectFile(const int fd, uint64_t pc,
symtab.sh_link * sizeof(symtab))) {
return false;
}
- if (FindSymbol(pc, fd, out, out_size, symbol_offset,
- &strtab, &symtab)) {
+ if (FindSymbol(pc, fd, out, out_size, base_address, &strtab, &symtab)) {
return true; // Found the symbol in a regular symbol table.
}
}
@@ -382,8 +356,7 @@ static bool GetSymbolFromObjectFile(const int fd, uint64_t pc,
symtab.sh_link * sizeof(symtab))) {
return false;
}
- if (FindSymbol(pc, fd, out, out_size, symbol_offset,
- &strtab, &symtab)) {
+ if (FindSymbol(pc, fd, out, out_size, base_address, &strtab, &symtab)) {
return true; // Found the symbol in a dynamic symbol table.
}
}
@@ -416,9 +389,14 @@ struct FileDescriptor {
// and snprintf().
class LineReader {
public:
- explicit LineReader(int fd, char *buf, int buf_len) : fd_(fd),
- buf_(buf), buf_len_(buf_len), bol_(buf), eol_(buf), eod_(buf) {
- }
+ explicit LineReader(int fd, char *buf, int buf_len, off_t offset)
+ : fd_(fd),
+ buf_(buf),
+ buf_len_(buf_len),
+ offset_(offset),
+ bol_(buf),
+ eol_(buf),
+ eod_(buf) {}
// Read '\n'-terminated line from file. On success, modify "bol"
// and "eol", then return true. Otherwise, return false.
@@ -427,10 +405,11 @@ class LineReader {
// dropped. It's an intentional behavior to make the code simple.
bool ReadLine(const char **bol, const char **eol) {
if (BufferIsEmpty()) { // First time.
- const ssize_t num_bytes = ReadPersistent(fd_, buf_, buf_len_);
+ const ssize_t num_bytes = ReadFromOffset(fd_, buf_, buf_len_, offset_);
if (num_bytes <= 0) { // EOF or error.
return false;
}
+ offset_ += num_bytes;
eod_ = buf_ + num_bytes;
bol_ = buf_;
} else {
@@ -443,11 +422,12 @@ class LineReader {
// Read text from file and append it.
char * const append_pos = buf_ + incomplete_line_length;
const int capacity_left = buf_len_ - incomplete_line_length;
- const ssize_t num_bytes = ReadPersistent(fd_, append_pos,
- capacity_left);
+ const ssize_t num_bytes =
+ ReadFromOffset(fd_, append_pos, capacity_left, offset_);
if (num_bytes <= 0) { // EOF or error.
return false;
}
+ offset_ += num_bytes;
eod_ = append_pos + num_bytes;
bol_ = buf_;
}
@@ -492,6 +472,7 @@ class LineReader {
const int fd_;
char * const buf_;
const int buf_len_;
+ off_t offset_;
char *bol_;
char *eol_;
const char *eod_; // End of data in "buf_".
@@ -532,7 +513,6 @@ OpenObjectFileContainingPcAndGetStartAddress(uint64_t pc,
int out_file_name_size) {
int object_fd;
- // Open /proc/self/maps.
int maps_fd;
NO_INTR(maps_fd = open("/proc/self/maps", O_RDONLY));
FileDescriptor wrapped_maps_fd(maps_fd);
@@ -540,11 +520,18 @@ OpenObjectFileContainingPcAndGetStartAddress(uint64_t pc,
return -1;
}
+ int mem_fd;
+ NO_INTR(mem_fd = open("/proc/self/mem", O_RDONLY));
+ FileDescriptor wrapped_mem_fd(mem_fd);
+ if (wrapped_mem_fd.get() < 0) {
+ return -1;
+ }
+
// Iterate over maps and look for the map containing the pc. Then
// look into the symbol tables inside.
char buf[1024]; // Big enough for line of sane /proc/self/maps
int num_maps = 0;
- LineReader reader(wrapped_maps_fd.get(), buf, sizeof(buf));
+ LineReader reader(wrapped_maps_fd.get(), buf, sizeof(buf), 0);
while (true) {
num_maps++;
const char *cursor;
@@ -575,11 +562,6 @@ OpenObjectFileContainingPcAndGetStartAddress(uint64_t pc,
}
++cursor; // Skip ' '.
- // Check start and end addresses.
- if (!(start_address <= pc && pc < end_address)) {
- continue; // We skip this map. PC isn't in this map.
- }
-
// Read flags. Skip flags until we encounter a space or eol.
const char * const flags_start = cursor;
while (cursor < eol && *cursor != ' ') {
@@ -590,6 +572,49 @@ OpenObjectFileContainingPcAndGetStartAddress(uint64_t pc,
return -1; // Malformed line.
}
+ // Determine the base address by reading ELF headers in process memory.
+ ElfW(Ehdr) ehdr;
+ // Skip non-readable maps.
+ if (flags_start[0] == 'r' &&
+ ReadFromOffsetExact(mem_fd, &ehdr, sizeof(ElfW(Ehdr)), start_address) &&
+ memcmp(ehdr.e_ident, ELFMAG, SELFMAG) == 0) {
+ switch (ehdr.e_type) {
+ case ET_EXEC:
+ base_address = 0;
+ break;
+ case ET_DYN:
+ // Find the segment containing file offset 0. This will correspond
+ // to the ELF header that we just read. Normally this will have
+ // virtual address 0, but this is not guaranteed. We must subtract
+ // the virtual address from the address where the ELF header was
+ // mapped to get the base address.
+ //
+ // If we fail to find a segment for file offset 0, use the address
+ // of the ELF header as the base address.
+ base_address = start_address;
+ for (unsigned i = 0; i != ehdr.e_phnum; ++i) {
+ ElfW(Phdr) phdr;
+ if (ReadFromOffsetExact(
+ mem_fd, &phdr, sizeof(phdr),
+ start_address + ehdr.e_phoff + i * sizeof(phdr)) &&
+ phdr.p_type == PT_LOAD && phdr.p_offset == 0) {
+ base_address = start_address - phdr.p_vaddr;
+ break;
+ }
+ }
+ break;
+ default:
+ // ET_REL or ET_CORE. These aren't directly executable, so they don't
+ // affect the base address.
+ break;
+ }
+ }
+
+ // Check start and end addresses.
+ if (!(start_address <= pc && pc < end_address)) {
+ continue; // We skip this map. PC isn't in this map.
+ }
+
// Check flags. We are only interested in "r*x" maps.
if (flags_start[0] != 'r' || flags_start[2] != 'x') {
continue; // We skip this map.
@@ -604,19 +629,6 @@ OpenObjectFileContainingPcAndGetStartAddress(uint64_t pc,
}
++cursor; // Skip ' '.
- // Don't subtract 'start_address' from the first entry:
- // * If a binary is compiled w/o -pie, then the first entry in
- // process maps is likely the binary itself (all dynamic libs
- // are mapped higher in address space). For such a binary,
- // instruction offset in binary coincides with the actual
- // instruction address in virtual memory (as code section
- // is mapped to a fixed memory range).
- // * If a binary is compiled with -pie, all the modules are
- // mapped high at address space (in particular, higher than
- // shadow memory of the tool), so the module can't be the
- // first entry.
- base_address = ((num_maps == 1) ? 0U : start_address) - file_offset;
-
// Skip to file name. "cursor" now points to dev. We need to
// skip at least two spaces for dev and inode.
int num_spaces = 0;
@@ -655,7 +667,7 @@ OpenObjectFileContainingPcAndGetStartAddress(uint64_t pc,
// bytes. Output will be truncated as needed, and a NUL character is always
// appended.
// NOTE: code from sandbox/linux/seccomp-bpf/demo.cc.
-char *itoa_r(intptr_t i, char *buf, size_t sz, int base, size_t padding) {
+static char *itoa_r(intptr_t i, char *buf, size_t sz, int base, size_t padding) {
// Make sure we can write at least one NUL byte.
size_t n = 1;
if (n > sz)
@@ -672,7 +684,8 @@ char *itoa_r(intptr_t i, char *buf, size_t sz, int base, size_t padding) {
// Handle negative numbers (only for base 10).
if (i < 0 && base == 10) {
- j = -i;
+ // This does "j = -i" while avoiding integer overflow.
+ j = static_cast<uintptr_t>(-(i + 1)) + 1;
// Make sure we can write the '-' character.
if (++n > sz) {
@@ -717,7 +730,7 @@ char *itoa_r(intptr_t i, char *buf, size_t sz, int base, size_t padding) {
// Safely appends string |source| to string |dest|. Never writes past the
// buffer size |dest_size| and guarantees that |dest| is null-terminated.
-void SafeAppendString(const char* source, char* dest, int dest_size) {
+static void SafeAppendString(const char* source, char* dest, int dest_size) {
int dest_string_length = strlen(dest);
SAFE_ASSERT(dest_string_length < dest_size);
dest += dest_string_length;
@@ -730,7 +743,7 @@ void SafeAppendString(const char* source, char* dest, int dest_size) {
// Converts a 64-bit value into a hex string, and safely appends it to |dest|.
// Never writes past the buffer size |dest_size| and guarantees that |dest| is
// null-terminated.
-void SafeAppendHexNumber(uint64_t value, char* dest, int dest_size) {
+static void SafeAppendHexNumber(uint64_t value, char* dest, int dest_size) {
// 64-bit numbers in hex can have up to 16 digits.
char buf[17] = {'\0'};
SafeAppendString(itoa_r(value, buf, sizeof(buf), 16, 0), dest, dest_size);
@@ -768,8 +781,13 @@ static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(void *pc, char *out,
out_size - 1);
}
+#if defined(PRINT_UNSYMBOLIZED_STACK_TRACES)
+ {
+ FileDescriptor wrapped_object_fd(object_fd);
+#else
// Check whether a file name was returned.
if (object_fd < 0) {
+#endif
if (out[1]) {
// The object file containing PC was determined successfully however the
// object file was not opened successfully. This is still considered
@@ -793,7 +811,7 @@ static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(void *pc, char *out,
// Run the call back if it's installed.
// Note: relocation (and much of the rest of this code) will be
// wrong for prelinked shared libraries and PIE executables.
- uint64 relocation = (elf_type == ET_DYN) ? start_address : 0;
+ uint64_t relocation = (elf_type == ET_DYN) ? start_address : 0;
int num_bytes_written = g_symbolize_callback(wrapped_object_fd.get(),
pc, out, out_size,
relocation);
@@ -837,6 +855,71 @@ static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(void *pc, char *out,
_END_GOOGLE_NAMESPACE_
+#elif defined(OS_WINDOWS) || defined(OS_CYGWIN)
+
+#include <windows.h>
+#include <dbghelp.h>
+
+#ifdef _MSC_VER
+#pragma comment(lib, "dbghelp")
+#endif
+
+_START_GOOGLE_NAMESPACE_
+
+class SymInitializer {
+public:
+ HANDLE process;
+ bool ready;
+ SymInitializer() : process(NULL), ready(false) {
+ // Initialize the symbol handler.
+ // https://msdn.microsoft.com/en-us/library/windows/desktop/ms680344(v=vs.85).aspx
+ process = GetCurrentProcess();
+ // Defer symbol loading.
+ // We do not request undecorated symbols with SYMOPT_UNDNAME
+ // because the mangling library calls UnDecorateSymbolName.
+ SymSetOptions(SYMOPT_DEFERRED_LOADS);
+ if (SymInitialize(process, NULL, true)) {
+ ready = true;
+ }
+ }
+ ~SymInitializer() {
+ SymCleanup(process);
+ // We do not need to close `HANDLE process` because it's a "pseudo handle."
+ }
+private:
+ SymInitializer(const SymInitializer&);
+ SymInitializer& operator=(const SymInitializer&);
+};
+
+static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(void *pc, char *out,
+ int out_size) {
+ const static SymInitializer symInitializer;
+ if (!symInitializer.ready) {
+ return false;
+ }
+ // Resolve symbol information from address.
+ // https://msdn.microsoft.com/en-us/library/windows/desktop/ms680578(v=vs.85).aspx
+ char buf[sizeof(SYMBOL_INFO) + MAX_SYM_NAME];
+ SYMBOL_INFO *symbol = reinterpret_cast<SYMBOL_INFO *>(buf);
+ symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
+ symbol->MaxNameLen = MAX_SYM_NAME;
+ // We use the ANSI version to ensure the string type is always `char *`.
+ // This could break if a symbol has Unicode in it.
+ BOOL ret = SymFromAddr(symInitializer.process,
+ reinterpret_cast<DWORD64>(pc), 0, symbol);
+ if (ret == 1 && static_cast<int>(symbol->NameLen) < out_size) {
+ // `NameLen` does not include the null terminating character.
+ strncpy(out, symbol->Name, static_cast<size_t>(symbol->NameLen) + 1);
+ out[static_cast<size_t>(symbol->NameLen)] = '\0';
+ // Symbolization succeeded. Now we try to demangle the symbol.
+ DemangleInplace(out, out_size);
+ return true;
+ }
+ return false;
+}
+
+_END_GOOGLE_NAMESPACE_
+
#else
# error BUG: HAVE_SYMBOLIZE was wrongly set
#endif
diff --git a/extern/glog/src/symbolize.h b/extern/glog/src/symbolize.h
index f617184249c..c6f9ec4360e 100644
--- a/extern/glog/src/symbolize.h
+++ b/extern/glog/src/symbolize.h
@@ -116,8 +116,11 @@ _START_GOOGLE_NAMESPACE_
// counter "pc". The callback function should write output to "out"
// and return the size of the output written. On error, the callback
// function should return -1.
-typedef int (*SymbolizeCallback)(int fd, void *pc, char *out, size_t out_size,
- uint64 relocation);
+typedef int (*SymbolizeCallback)(int fd,
+ void* pc,
+ char* out,
+ size_t out_size,
+ uint64_t relocation);
void InstallSymbolizeCallback(SymbolizeCallback callback);
// Installs a callback function, which will be called instead of
@@ -131,9 +134,9 @@ void InstallSymbolizeCallback(SymbolizeCallback callback);
// returns -1. |out_file_name_size| is the size of the file name buffer
// (including the null-terminator).
typedef int (*SymbolizeOpenObjectFileCallback)(uint64_t pc,
- uint64_t &start_address,
- uint64_t &base_address,
- char *out_file_name,
+ uint64_t& start_address,
+ uint64_t& base_address,
+ char* out_file_name,
int out_file_name_size);
void InstallSymbolizeOpenObjectFileCallback(
SymbolizeOpenObjectFileCallback callback);
@@ -148,7 +151,7 @@ _START_GOOGLE_NAMESPACE_
// symbol name to "out". The symbol name is demangled if possible
// (supports symbols generated by GCC 3.x or newer). Otherwise,
// returns false.
-bool Symbolize(void *pc, char *out, int out_size);
+GOOGLE_GLOG_DLL_DECL bool Symbolize(void *pc, char *out, int out_size);
_END_GOOGLE_NAMESPACE_
diff --git a/extern/glog/src/utilities.cc b/extern/glog/src/utilities.cc
index 5c88e58d3c0..25c4b760f1c 100644
--- a/extern/glog/src/utilities.cc
+++ b/extern/glog/src/utilities.cc
@@ -47,6 +47,12 @@
#ifdef HAVE_SYSLOG_H
# include <syslog.h>
#endif
+#ifdef HAVE_UNISTD_H
+# include <unistd.h> // For geteuid.
+#endif
+#ifdef HAVE_PWD_H
+# include <pwd.h>
+#endif
#include "base/googleinit.h"
@@ -84,7 +90,7 @@ static void DebugWriteToStderr(const char* data, void *) {
}
}
-void DebugWriteToString(const char* data, void *arg) {
+static void DebugWriteToString(const char* data, void *arg) {
reinterpret_cast<string*>(arg)->append(data);
}
@@ -137,17 +143,19 @@ static void DumpStackTraceAndExit() {
DumpStackTrace(1, DebugWriteToStderr, NULL);
// TOOD(hamaji): Use signal instead of sigaction?
-#ifdef HAVE_SIGACTION
if (IsFailureSignalHandlerInstalled()) {
// Set the default signal handler for SIGABRT, to avoid invoking our
// own signal handler installed by InstallFailureSignalHandler().
+#ifdef HAVE_SIGACTION
struct sigaction sig_action;
memset(&sig_action, 0, sizeof(sig_action));
sigemptyset(&sig_action.sa_mask);
sig_action.sa_handler = SIG_DFL;
sigaction(SIGABRT, &sig_action, NULL);
- }
+#elif defined(OS_WINDOWS)
+ signal(SIGABRT, SIG_DFL);
#endif // HAVE_SIGACTION
+ }
abort();
}
@@ -266,7 +274,7 @@ pid_t GetTID() {
// If gettid() could not be used, we use one of the following.
#if defined OS_LINUX
return getpid(); // Linux: getpid returns thread ID when gettid is absent
-#elif defined OS_WINDOWS || defined OS_CYGWIN
+#elif defined OS_WINDOWS && !defined OS_CYGWIN
return GetCurrentThreadId();
#else
// If none of the techniques above worked, we use pthread_self().
@@ -297,8 +305,24 @@ static void MyUserNameInitializer() {
if (user != NULL) {
g_my_user_name = user;
} else {
- g_my_user_name = "invalid-user";
+#if defined(HAVE_PWD_H) && defined(HAVE_UNISTD_H)
+ struct passwd pwd;
+ struct passwd* result = NULL;
+ char buffer[1024] = {'\0'};
+ uid_t uid = geteuid();
+ int pwuid_res = getpwuid_r(uid, &pwd, buffer, sizeof(buffer), &result);
+ if (pwuid_res == 0) {
+ g_my_user_name = pwd.pw_name;
+ } else {
+ snprintf(buffer, sizeof(buffer), "uid%d", uid);
+ g_my_user_name = buffer;
+ }
+#endif
+ if (g_my_user_name.empty()) {
+ g_my_user_name = "invalid-user";
+ }
}
+
}
REGISTER_MODULE_INITIALIZER(utilities, MyUserNameInitializer());
@@ -349,4 +373,12 @@ _END_GOOGLE_NAMESPACE_
// Make an implementation of stacktrace compiled.
#ifdef STACKTRACE_H
# include STACKTRACE_H
+# if 0
+// For include scanners which can't handle macro expansions.
+# include "stacktrace_libunwind-inl.h"
+# include "stacktrace_x86-inl.h"
+# include "stacktrace_x86_64-inl.h"
+# include "stacktrace_powerpc-inl.h"
+# include "stacktrace_generic-inl.h"
+# endif
#endif
diff --git a/extern/glog/src/utilities.h b/extern/glog/src/utilities.h
index 5f79968ef55..ca21cfb3884 100644
--- a/extern/glog/src/utilities.h
+++ b/extern/glog/src/utilities.h
@@ -39,7 +39,9 @@
#elif defined(__CYGWIN__) || defined(__CYGWIN32__)
# define OS_CYGWIN
#elif defined(linux) || defined(__linux) || defined(__linux__)
-# define OS_LINUX
+# ifndef OS_LINUX
+# define OS_LINUX
+# endif
#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)
# define OS_MACOSX
#elif defined(__FreeBSD__)
@@ -97,6 +99,8 @@
// malloc() from the unwinder. This is a problem because we're
// trying to use the unwinder to instrument malloc().
//
+// 4) The Windows API CaptureStackTrace.
+//
// Note: if you add a new implementation here, make sure it works
// correctly when GetStackTrace() is called with max_depth == 0.
// Some code may do that.
@@ -110,6 +114,8 @@
# define STACKTRACE_H "stacktrace_x86_64-inl.h"
# elif (defined(__ppc__) || defined(__PPC__)) && __GNUC__ >= 2
# define STACKTRACE_H "stacktrace_powerpc-inl.h"
+# elif defined(OS_WINDOWS)
+# define STACKTRACE_H "stacktrace_windows-inl.h"
# endif
#endif
@@ -121,13 +127,18 @@
# define HAVE_STACKTRACE
#endif
+#ifndef HAVE_SYMBOLIZE
// defined by gcc
#if defined(__ELF__) && defined(OS_LINUX)
# define HAVE_SYMBOLIZE
#elif defined(OS_MACOSX) && defined(HAVE_DLADDR)
// Use dladdr to symbolize.
# define HAVE_SYMBOLIZE
+#elif defined(OS_WINDOWS)
+// Use DbgHelp to symbolize
+# define HAVE_SYMBOLIZE
#endif
+#endif // !defined(HAVE_SYMBOLIZE)
#ifndef ARRAYSIZE
// There is a better way, but this is good enough for our purpose.
@@ -141,6 +152,9 @@ namespace glog_internal_namespace_ {
#ifdef HAVE___ATTRIBUTE__
# define ATTRIBUTE_NOINLINE __attribute__ ((noinline))
# define HAVE_ATTRIBUTE_NOINLINE
+#elif defined(OS_WINDOWS)
+# define ATTRIBUTE_NOINLINE __declspec(noinline)
+# define HAVE_ATTRIBUTE_NOINLINE
#else
# define ATTRIBUTE_NOINLINE
#endif
diff --git a/extern/glog/src/vlog_is_on.cc b/extern/glog/src/vlog_is_on.cc
index 4c95583b683..e8fdbae7dcb 100644
--- a/extern/glog/src/vlog_is_on.cc
+++ b/extern/glog/src/vlog_is_on.cc
@@ -62,6 +62,12 @@ _START_GOOGLE_NAMESPACE_
namespace glog_internal_namespace_ {
+// Used by logging_unittests.cc so can't make it static here.
+GOOGLE_GLOG_DLL_DECL bool SafeFNMatch_(const char* pattern,
+ size_t patt_len,
+ const char* str,
+ size_t str_len);
+
// Implementation of fnmatch that does not need 0-termination
// of arguments and does not allocate any memory,
// but we only support "*" and "?" wildcards, not the "[...]" patterns.
diff --git a/extern/glog/src/windows/glog/logging.h b/extern/glog/src/windows/glog/logging.h
index f521a2b9424..3681fa3fcc4 100644
--- a/extern/glog/src/windows/glog/logging.h
+++ b/extern/glog/src/windows/glog/logging.h
@@ -572,8 +572,10 @@ class LogSink; // defined below
LOG_TO_STRING_##severity(static_cast<std::vector<std::string>*>(outvec)).stream()
#define LOG_IF(severity, condition) \
+ static_cast<void>(0), \
!(condition) ? (void) 0 : google::LogMessageVoidify() & LOG(severity)
#define SYSLOG_IF(severity, condition) \
+ static_cast<void>(0), \
!(condition) ? (void) 0 : google::LogMessageVoidify() & SYSLOG(severity)
#define LOG_ASSERT(condition) \
@@ -863,6 +865,7 @@ DECLARE_CHECK_STROP_IMPL(strcasecmp, false)
&google::LogMessage::SendToLog)
#define PLOG_IF(severity, condition) \
+ static_cast<void>(0), \
!(condition) ? (void) 0 : google::LogMessageVoidify() & PLOG(severity)
// A CHECK() macro that postpends errno if the condition is false. E.g.
@@ -935,16 +938,11 @@ struct CompileAssert {
struct CrashReason;
// Returns true if FailureSignalHandler is installed.
-bool IsFailureSignalHandlerInstalled();
+// Needs to be exported since it's used by the signalhandler_unittest.
+GOOGLE_GLOG_DLL_DECL bool IsFailureSignalHandlerInstalled();
} // namespace glog_internal_namespace_
-#define GOOGLE_GLOG_COMPILE_ASSERT(expr, msg) \
- typedef google::glog_internal_namespace_::CompileAssert<(bool(expr))> msg[bool(expr) ? 1 : -1]
-
#define LOG_EVERY_N(severity, n) \
- GOOGLE_GLOG_COMPILE_ASSERT(google::GLOG_ ## severity < \
- google::NUM_SEVERITIES, \
- INVALID_REQUESTED_LOG_SEVERITY); \
SOME_KIND_OF_LOG_EVERY_N(severity, (n), google::LogMessage::SendToLog)
#define SYSLOG_EVERY_N(severity, n) \
@@ -1012,23 +1010,29 @@ const LogSeverity GLOG_0 = GLOG_ERROR;
#else // !DCHECK_IS_ON()
-#define DLOG(severity) \
+#define DLOG(severity) \
+ static_cast<void>(0), \
true ? (void) 0 : google::LogMessageVoidify() & LOG(severity)
-#define DVLOG(verboselevel) \
- (true || !VLOG_IS_ON(verboselevel)) ?\
+#define DVLOG(verboselevel) \
+ static_cast<void>(0), \
+ (true || !VLOG_IS_ON(verboselevel)) ? \
(void) 0 : google::LogMessageVoidify() & LOG(INFO)
#define DLOG_IF(severity, condition) \
+ static_cast<void>(0), \
(true || !(condition)) ? (void) 0 : google::LogMessageVoidify() & LOG(severity)
#define DLOG_EVERY_N(severity, n) \
+ static_cast<void>(0), \
true ? (void) 0 : google::LogMessageVoidify() & LOG(severity)
#define DLOG_IF_EVERY_N(severity, condition, n) \
+ static_cast<void>(0), \
(true || !(condition))? (void) 0 : google::LogMessageVoidify() & LOG(severity)
#define DLOG_ASSERT(condition) \
+ static_cast<void>(0), \
true ? (void) 0 : LOG_ASSERT(condition)
// MSVC warning C4127: conditional expression is constant
@@ -1113,10 +1117,11 @@ namespace base_logging {
// buffer to allow for a '\n' and '\0'.
class GOOGLE_GLOG_DLL_DECL LogStreamBuf : public std::streambuf {
public:
- // REQUIREMENTS: "len" must be >= 2 to account for the '\n' and '\n'.
+ // REQUIREMENTS: "len" must be >= 2 to account for the '\n' and '\0'.
LogStreamBuf(char *buf, int len) {
setp(buf, buf + len - 2);
}
+
// This effectively ignores overflow.
virtual int_type overflow(int_type ch) {
return ch;
@@ -1155,13 +1160,9 @@ public:
// 2005 if you are deriving from a type in the Standard C++ Library"
// http://msdn.microsoft.com/en-us/library/3tdb471s(VS.80).aspx
// Let's just ignore the warning.
-#ifdef _MSC_VER
-# pragma warning(disable: 4275)
-#endif
+GLOG_MSVC_PUSH_DISABLE_WARNING(4275)
class GOOGLE_GLOG_DLL_DECL LogStream : public std::ostream {
-#ifdef _MSC_VER
-# pragma warning(default: 4275)
-#endif
+GLOG_MSVC_POP_WARNING()
public:
LogStream(char *buf, int len, int ctr)
: std::ostream(NULL),
diff --git a/extern/glog/src/windows/glog/raw_logging.h b/extern/glog/src/windows/glog/raw_logging.h
index 4757a719db7..e0e6d6f1a25 100644
--- a/extern/glog/src/windows/glog/raw_logging.h
+++ b/extern/glog/src/windows/glog/raw_logging.h
@@ -179,11 +179,6 @@ GOOGLE_GLOG_DLL_DECL void RawLog__(LogSeverity severity,
const char* format, ...)
;
-// Hack to propagate time information into this module so that
-// this module does not have to directly call localtime_r(),
-// which could allocate memory.
-GOOGLE_GLOG_DLL_DECL void RawLog__SetLastTime(const struct tm& t, int usecs);
-
}
#endif // BASE_RAW_LOGGING_H_
diff --git a/extern/glog/src/windows/port.cc b/extern/glog/src/windows/port.cc
index d9943254ee5..19bda367c62 100644
--- a/extern/glog/src/windows/port.cc
+++ b/extern/glog/src/windows/port.cc
@@ -38,15 +38,8 @@
#include "config.h"
#include <stdarg.h> // for va_list, va_start, va_end
-#include <string.h> // for strstr()
-#include <assert.h>
-#include <string>
-#include <vector>
#include "port.h"
-using std::string;
-using std::vector;
-
// These call the windows _vsnprintf, but always NUL-terminate.
int safe_vsnprintf(char *str, size_t size, const char *format, va_list ap) {
if (size == 0) // not even room for a \0?
@@ -55,6 +48,12 @@ int safe_vsnprintf(char *str, size_t size, const char *format, va_list ap) {
return _vsnprintf(str, size-1, format, ap);
}
+#ifndef HAVE_LOCALTIME_R
+struct tm* localtime_r(const time_t* timep, struct tm* result) {
+ localtime_s(result, timep);
+ return result;
+}
+#endif // not HAVE_LOCALTIME_R
#ifndef HAVE_SNPRINTF
int snprintf(char *str, size_t size, const char *format, ...) {
va_list ap;
diff --git a/extern/glog/src/windows/port.h b/extern/glog/src/windows/port.h
index 819846151b9..7b4b9c8545b 100644
--- a/extern/glog/src/windows/port.h
+++ b/extern/glog/src/windows/port.h
@@ -70,8 +70,11 @@
* 4715: for some reason VC++ stopped realizing you can't return after abort()
* 4800: we know we're casting ints/char*'s to bools, and we're ok with that
* 4996: Yes, we're ok using "unsafe" functions like fopen() and strerror()
+ * 4312: Converting uint32_t to a pointer when testing %p
+ * 4267: also subtracting two size_t to int
+ * 4722: Destructor never returns due to abort()
*/
-#pragma warning(disable:4244 4251 4355 4715 4800 4996)
+#pragma warning(disable:4244 4251 4355 4715 4800 4996 4267 4312 4722)
/* file I/O */
#define PATH_MAX 1024
@@ -86,6 +89,11 @@
#define pclose _pclose
#define R_OK 04 /* read-only (for access()) */
#define S_ISDIR(m) (((m) & _S_IFMT) == _S_IFDIR)
+
+#define O_WRONLY _O_WRONLY
+#define O_CREAT _O_CREAT
+#define O_EXCL _O_EXCL
+
#ifndef __MINGW32__
enum { STDIN_FILENO = 0, STDOUT_FILENO = 1, STDERR_FILENO = 2 };
#endif
@@ -136,19 +144,20 @@ typedef int pid_t;
#endif // _MSC_VER
// ----------------------------------- THREADS
-#ifndef __MINGW32__
+#if defined(HAVE_PTHREAD)
+# include <pthread.h>
+#else // no PTHREAD
typedef DWORD pthread_t;
typedef DWORD pthread_key_t;
typedef LONG pthread_once_t;
enum { PTHREAD_ONCE_INIT = 0 }; // important that this be 0! for SpinLock
#define pthread_self GetCurrentThreadId
#define pthread_equal(pthread_t_1, pthread_t_2) ((pthread_t_1)==(pthread_t_2))
+#endif // HAVE_PTHREAD
-inline struct tm* localtime_r(const time_t* timep, struct tm* result) {
- localtime_s(result, timep);
- return result;
-}
-#endif
+#ifndef HAVE_LOCALTIME_R
+extern GOOGLE_GLOG_DLL_DECL struct tm* localtime_r(const time_t* timep, struct tm* result);
+#endif // not HAVE_LOCALTIME_R
inline char* strerror_r(int errnum, char* buf, size_t buflen) {
strerror_s(buf, buflen, errnum);
diff --git a/extern/glog/src/windows/preprocess.sh b/extern/glog/src/windows/preprocess.sh
index 5398988e7ea..c35e92913b6 100755
--- a/extern/glog/src/windows/preprocess.sh
+++ b/extern/glog/src/windows/preprocess.sh
@@ -95,7 +95,7 @@ DLLDEF_DEFINES="\
-e "s!@ac_cv_have_libgflags@!0!g" \
-e "s!@ac_cv_have___builtin_expect@!0!g" \
-e "s!@ac_cv_cxx_using_operator@!1!g" \
- -e "s!@ac_cv___attribute___noreturn@!!g" \
+ -e "s!@ac_cv___attribute___noreturn@!__declspec(noreturn)!g" \
-e "s!@ac_cv___attribute___noinline@!!g" \
-e "s!@ac_cv___attribute___printf_4_5@!!g" \
-e "s!@ac_google_attribute@!${HAVE___ATTRIBUTE__:-0}!g" \
diff --git a/extern/gmock/CHANGES b/extern/gmock/CHANGES
deleted file mode 100644
index d6f2f760e34..00000000000
--- a/extern/gmock/CHANGES
+++ /dev/null
@@ -1,126 +0,0 @@
-Changes for 1.7.0:
-
-* All new improvements in Google Test 1.7.0.
-* New feature: matchers DoubleNear(), FloatNear(),
- NanSensitiveDoubleNear(), NanSensitiveFloatNear(),
- UnorderedElementsAre(), UnorderedElementsAreArray(), WhenSorted(),
- WhenSortedBy(), IsEmpty(), and SizeIs().
-* Improvement: Google Mock can now be built as a DLL.
-* Improvement: when compiled by a C++11 compiler, matchers AllOf()
- and AnyOf() can accept an arbitrary number of matchers.
-* Improvement: when compiled by a C++11 compiler, matchers
- ElementsAreArray() can accept an initializer list.
-* Improvement: when exceptions are enabled, a mock method with no
- default action now throws instead crashing the test.
-* Improvement: added class testing::StringMatchResultListener to aid
- definition of composite matchers.
-* Improvement: function return types used in MOCK_METHOD*() macros can
- now contain unprotected commas.
-* Improvement (potentially breaking): EXPECT_THAT() and ASSERT_THAT()
- are now more strict in ensuring that the value type and the matcher
- type are compatible, catching potential bugs in tests.
-* Improvement: Pointee() now works on an optional<T>.
-* Improvement: the ElementsAreArray() matcher can now take a vector or
- iterator range as input, and makes a copy of its input elements
- before the conversion to a Matcher.
-* Improvement: the Google Mock Generator can now generate mocks for
- some class templates.
-* Bug fix: mock object destruction triggerred by another mock object's
- destruction no longer hangs.
-* Improvement: Google Mock Doctor works better with newer Clang and
- GCC now.
-* Compatibility fixes.
-* Bug/warning fixes.
-
-Changes for 1.6.0:
-
-* Compilation is much faster and uses much less memory, especially
- when the constructor and destructor of a mock class are moved out of
- the class body.
-* New matchers: Pointwise(), Each().
-* New actions: ReturnPointee() and ReturnRefOfCopy().
-* CMake support.
-* Project files for Visual Studio 2010.
-* AllOf() and AnyOf() can handle up-to 10 arguments now.
-* Google Mock doctor understands Clang error messages now.
-* SetArgPointee<> now accepts string literals.
-* gmock_gen.py handles storage specifier macros and template return
- types now.
-* Compatibility fixes.
-* Bug fixes and implementation clean-ups.
-* Potentially incompatible changes: disables the harmful 'make install'
- command in autotools.
-
-Potentially breaking changes:
-
-* The description string for MATCHER*() changes from Python-style
- interpolation to an ordinary C++ string expression.
-* SetArgumentPointee is deprecated in favor of SetArgPointee.
-* Some non-essential project files for Visual Studio 2005 are removed.
-
-Changes for 1.5.0:
-
- * New feature: Google Mock can be safely used in multi-threaded tests
- on platforms having pthreads.
- * New feature: function for printing a value of arbitrary type.
- * New feature: function ExplainMatchResult() for easy definition of
- composite matchers.
- * The new matcher API lets user-defined matchers generate custom
- explanations more directly and efficiently.
- * Better failure messages all around.
- * NotNull() and IsNull() now work with smart pointers.
- * Field() and Property() now work when the matcher argument is a pointer
- passed by reference.
- * Regular expression matchers on all platforms.
- * Added GCC 4.0 support for Google Mock Doctor.
- * Added gmock_all_test.cc for compiling most Google Mock tests
- in a single file.
- * Significantly cleaned up compiler warnings.
- * Bug fixes, better test coverage, and implementation clean-ups.
-
- Potentially breaking changes:
-
- * Custom matchers defined using MatcherInterface or MakePolymorphicMatcher()
- need to be updated after upgrading to Google Mock 1.5.0; matchers defined
- using MATCHER or MATCHER_P* aren't affected.
- * Dropped support for 'make install'.
-
-Changes for 1.4.0 (we skipped 1.2.* and 1.3.* to match the version of
-Google Test):
-
- * Works in more environments: Symbian and minGW, Visual C++ 7.1.
- * Lighter weight: comes with our own implementation of TR1 tuple (no
- more dependency on Boost!).
- * New feature: --gmock_catch_leaked_mocks for detecting leaked mocks.
- * New feature: ACTION_TEMPLATE for defining templatized actions.
- * New feature: the .After() clause for specifying expectation order.
- * New feature: the .With() clause for for specifying inter-argument
- constraints.
- * New feature: actions ReturnArg<k>(), ReturnNew<T>(...), and
- DeleteArg<k>().
- * New feature: matchers Key(), Pair(), Args<...>(), AllArgs(), IsNull(),
- and Contains().
- * New feature: utility class MockFunction<F>, useful for checkpoints, etc.
- * New feature: functions Value(x, m) and SafeMatcherCast<T>(m).
- * New feature: copying a mock object is rejected at compile time.
- * New feature: a script for fusing all Google Mock and Google Test
- source files for easy deployment.
- * Improved the Google Mock doctor to diagnose more diseases.
- * Improved the Google Mock generator script.
- * Compatibility fixes for Mac OS X and gcc.
- * Bug fixes and implementation clean-ups.
-
-Changes for 1.1.0:
-
- * New feature: ability to use Google Mock with any testing framework.
- * New feature: macros for easily defining new matchers
- * New feature: macros for easily defining new actions.
- * New feature: more container matchers.
- * New feature: actions for accessing function arguments and throwing
- exceptions.
- * Improved the Google Mock doctor script for diagnosing compiler errors.
- * Bug fixes and implementation clean-ups.
-
-Changes for 1.0.0:
-
- * Initial Open Source release of Google Mock
diff --git a/extern/gmock/CMakeLists.txt b/extern/gmock/CMakeLists.txt
index 73e524d80cd..faa133265d3 100644
--- a/extern/gmock/CMakeLists.txt
+++ b/extern/gmock/CMakeLists.txt
@@ -29,33 +29,34 @@ set(INC_SYS
set(SRC
# src/gmock-all.cc
+ # src/gmock_main.cc
- src/gmock-cardinalities.cc
src/gmock.cc
+ src/gmock-cardinalities.cc
src/gmock-internal-utils.cc
- src/gmock_main.cc
src/gmock-matchers.cc
src/gmock-spec-builders.cc
)
set(SRC_HEADERS
+ include/gmock/gmock.h
include/gmock/gmock-actions.h
include/gmock/gmock-cardinalities.h
+ include/gmock/gmock-function-mocker.h
include/gmock/gmock-generated-actions.h
include/gmock/gmock-generated-function-mockers.h
include/gmock/gmock-generated-matchers.h
- include/gmock/gmock-generated-nice-strict.h
- include/gmock/gmock.h
include/gmock/gmock-matchers.h
include/gmock/gmock-more-actions.h
include/gmock/gmock-more-matchers.h
+ include/gmock/gmock-nice-strict.h
include/gmock/gmock-spec-builders.h
include/gmock/internal/custom/gmock-generated-actions.h
include/gmock/internal/custom/gmock-matchers.h
include/gmock/internal/custom/gmock-port.h
- include/gmock/internal/gmock-generated-internal-utils.h
include/gmock/internal/gmock-internal-utils.h
include/gmock/internal/gmock-port.h
+ include/gmock/internal/gmock-pp.h
)
include_directories(${INC})
diff --git a/extern/gmock/README.blender b/extern/gmock/README.blender
index 6165bd6f717..3f9d80362d8 100644
--- a/extern/gmock/README.blender
+++ b/extern/gmock/README.blender
@@ -1,7 +1,5 @@
Project: Google C++ Testing Framework
URL: https://github.com/google/googletest
License: New BSD
-Upstream version: 1.8.0 (ec44c6c1675)
-Local modifications:
-
-None.
+Upstream version: 1.10.0 (703bd9caab5)
+Local modifications: None
diff --git a/extern/gmock/README.md b/extern/gmock/README.md
index 332beab3881..183fdb81d9b 100644
--- a/extern/gmock/README.md
+++ b/extern/gmock/README.md
@@ -1,333 +1,44 @@
-## Google Mock ##
+# Googletest Mocking (gMock) Framework
-The Google C++ mocking framework.
+### Overview
-### Overview ###
-
-Google's framework for writing and using C++ mock classes.
-It can help you derive better designs of your system and write better tests.
+Google's framework for writing and using C++ mock classes. It can help you
+derive better designs of your system and write better tests.
It is inspired by:
- * [jMock](http://www.jmock.org/),
- * [EasyMock](http://www.easymock.org/), and
- * [Hamcrest](http://code.google.com/p/hamcrest/),
+* [jMock](http://www.jmock.org/),
+* [EasyMock](http://www.easymock.org/), and
+* [Hamcrest](http://code.google.com/p/hamcrest/),
and designed with C++'s specifics in mind.
-Google mock:
-
- * lets you create mock classes trivially using simple macros.
- * supports a rich set of matchers and actions.
- * handles unordered, partially ordered, or completely ordered expectations.
- * is extensible by users.
-
-We hope you find it useful!
-
-### Features ###
-
- * Provides a declarative syntax for defining mocks.
- * Can easily define partial (hybrid) mocks, which are a cross of real
- and mock objects.
- * Handles functions of arbitrary types and overloaded functions.
- * Comes with a rich set of matchers for validating function arguments.
- * Uses an intuitive syntax for controlling the behavior of a mock.
- * Does automatic verification of expectations (no record-and-replay needed).
- * Allows arbitrary (partial) ordering constraints on
- function calls to be expressed,.
- * Lets a user extend it by defining new matchers and actions.
- * Does not use exceptions.
- * Is easy to learn and use.
-
-Please see the project page above for more information as well as the
-mailing list for questions, discussions, and development. There is
-also an IRC channel on OFTC (irc.oftc.net) #gtest available. Please
-join us!
-
-Please note that code under [scripts/generator](scripts/generator/) is
-from [cppclean](http://code.google.com/p/cppclean/) and released under
-the Apache License, which is different from Google Mock's license.
-
-## Getting Started ##
-
-If you are new to the project, we suggest that you read the user
-documentation in the following order:
-
- * Learn the [basics](../googletest/docs/Primer.md) of
- Google Test, if you choose to use Google Mock with it (recommended).
- * Read [Google Mock for Dummies](docs/ForDummies.md).
- * Read the instructions below on how to build Google Mock.
-
-You can also watch Zhanyong's [talk](http://www.youtube.com/watch?v=sYpCyLI47rM) on Google Mock's usage and implementation.
-
-Once you understand the basics, check out the rest of the docs:
-
- * [CheatSheet](docs/CheatSheet.md) - all the commonly used stuff
- at a glance.
- * [CookBook](docs/CookBook.md) - recipes for getting things done,
- including advanced techniques.
-
-If you need help, please check the
-[KnownIssues](docs/KnownIssues.md) and
-[FrequentlyAskedQuestions](docs/FrequentlyAskedQuestions.md) before
-posting a question on the
-[discussion group](http://groups.google.com/group/googlemock).
-
-
-### Using Google Mock Without Google Test ###
-
-Google Mock is not a testing framework itself. Instead, it needs a
-testing framework for writing tests. Google Mock works seamlessly
-with [Google Test](http://code.google.com/p/googletest/), but
-you can also use it with [any C++ testing framework](googlemock/ForDummies.md#Using_Google_Mock_with_Any_Testing_Framework).
-
-### Requirements for End Users ###
-
-Google Mock is implemented on top of [Google Test](
-http://github.com/google/googletest/), and depends on it.
-You must use the bundled version of Google Test when using Google Mock.
-
-You can also easily configure Google Mock to work with another testing
-framework, although it will still need Google Test. Please read
-["Using_Google_Mock_with_Any_Testing_Framework"](
- docs/ForDummies.md#Using_Google_Mock_with_Any_Testing_Framework)
-for instructions.
-
-Google Mock depends on advanced C++ features and thus requires a more
-modern compiler. The following are needed to use Google Mock:
-
-#### Linux Requirements ####
-
- * GNU-compatible Make or "gmake"
- * POSIX-standard shell
- * POSIX(-2) Regular Expressions (regex.h)
- * C++98-standard-compliant compiler (e.g. GCC 3.4 or newer)
-
-#### Windows Requirements ####
-
- * Microsoft Visual C++ 8.0 SP1 or newer
-
-#### Mac OS X Requirements ####
-
- * Mac OS X 10.4 Tiger or newer
- * Developer Tools Installed
-
-### Requirements for Contributors ###
-
-We welcome patches. If you plan to contribute a patch, you need to
-build Google Mock and its tests, which has further requirements:
-
- * Automake version 1.9 or newer
- * Autoconf version 2.59 or newer
- * Libtool / Libtoolize
- * Python version 2.3 or newer (for running some of the tests and
- re-generating certain source files from templates)
-
-### Building Google Mock ###
-
-#### Preparing to Build (Unix only) ####
-
-If you are using a Unix system and plan to use the GNU Autotools build
-system to build Google Mock (described below), you'll need to
-configure it now.
-
-To prepare the Autotools build system:
-
- cd googlemock
- autoreconf -fvi
-
-To build Google Mock and your tests that use it, you need to tell your
-build system where to find its headers and source files. The exact
-way to do it depends on which build system you use, and is usually
-straightforward.
-
-This section shows how you can integrate Google Mock into your
-existing build system.
-
-Suppose you put Google Mock in directory `${GMOCK_DIR}` and Google Test
-in `${GTEST_DIR}` (the latter is `${GMOCK_DIR}/gtest` by default). To
-build Google Mock, create a library build target (or a project as
-called by Visual Studio and Xcode) to compile
-
- ${GTEST_DIR}/src/gtest-all.cc and ${GMOCK_DIR}/src/gmock-all.cc
-
-with
-
- ${GTEST_DIR}/include and ${GMOCK_DIR}/include
-
-in the system header search path, and
-
- ${GTEST_DIR} and ${GMOCK_DIR}
-
-in the normal header search path. Assuming a Linux-like system and gcc,
-something like the following will do:
-
- g++ -isystem ${GTEST_DIR}/include -I${GTEST_DIR} \
- -isystem ${GMOCK_DIR}/include -I${GMOCK_DIR} \
- -pthread -c ${GTEST_DIR}/src/gtest-all.cc
- g++ -isystem ${GTEST_DIR}/include -I${GTEST_DIR} \
- -isystem ${GMOCK_DIR}/include -I${GMOCK_DIR} \
- -pthread -c ${GMOCK_DIR}/src/gmock-all.cc
- ar -rv libgmock.a gtest-all.o gmock-all.o
-
-(We need -pthread as Google Test and Google Mock use threads.)
-
-Next, you should compile your test source file with
-${GTEST\_DIR}/include and ${GMOCK\_DIR}/include in the header search
-path, and link it with gmock and any other necessary libraries:
-
- g++ -isystem ${GTEST_DIR}/include -isystem ${GMOCK_DIR}/include \
- -pthread path/to/your_test.cc libgmock.a -o your_test
-
-As an example, the make/ directory contains a Makefile that you can
-use to build Google Mock on systems where GNU make is available
-(e.g. Linux, Mac OS X, and Cygwin). It doesn't try to build Google
-Mock's own tests. Instead, it just builds the Google Mock library and
-a sample test. You can use it as a starting point for your own build
-script.
-
-If the default settings are correct for your environment, the
-following commands should succeed:
-
- cd ${GMOCK_DIR}/make
- make
- ./gmock_test
-
-If you see errors, try to tweak the contents of
-[make/Makefile](make/Makefile) to make them go away.
-
-### Windows ###
-
-The msvc/2005 directory contains VC++ 2005 projects and the msvc/2010
-directory contains VC++ 2010 projects for building Google Mock and
-selected tests.
-
-Change to the appropriate directory and run "msbuild gmock.sln" to
-build the library and tests (or open the gmock.sln in the MSVC IDE).
-If you want to create your own project to use with Google Mock, you'll
-have to configure it to use the `gmock_config` propety sheet. For that:
-
- * Open the Property Manager window (View | Other Windows | Property Manager)
- * Right-click on your project and select "Add Existing Property Sheet..."
- * Navigate to `gmock_config.vsprops` or `gmock_config.props` and select it.
- * In Project Properties | Configuration Properties | General | Additional
- Include Directories, type <path to Google Mock>/include.
-
-### Tweaking Google Mock ###
-
-Google Mock can be used in diverse environments. The default
-configuration may not work (or may not work well) out of the box in
-some environments. However, you can easily tweak Google Mock by
-defining control macros on the compiler command line. Generally,
-these macros are named like `GTEST_XYZ` and you define them to either 1
-or 0 to enable or disable a certain feature.
-
-We list the most frequently used macros below. For a complete list,
-see file [${GTEST\_DIR}/include/gtest/internal/gtest-port.h](
-../googletest/include/gtest/internal/gtest-port.h).
-
-### Choosing a TR1 Tuple Library ###
-
-Google Mock uses the C++ Technical Report 1 (TR1) tuple library
-heavily. Unfortunately TR1 tuple is not yet widely available with all
-compilers. The good news is that Google Test 1.4.0+ implements a
-subset of TR1 tuple that's enough for Google Mock's need. Google Mock
-will automatically use that implementation when the compiler doesn't
-provide TR1 tuple.
-
-Usually you don't need to care about which tuple library Google Test
-and Google Mock use. However, if your project already uses TR1 tuple,
-you need to tell Google Test and Google Mock to use the same TR1 tuple
-library the rest of your project uses, or the two tuple
-implementations will clash. To do that, add
-
- -DGTEST_USE_OWN_TR1_TUPLE=0
-
-to the compiler flags while compiling Google Test, Google Mock, and
-your tests. If you want to force Google Test and Google Mock to use
-their own tuple library, just add
-
- -DGTEST_USE_OWN_TR1_TUPLE=1
-
-to the compiler flags instead.
-
-If you want to use Boost's TR1 tuple library with Google Mock, please
-refer to the Boost website (http://www.boost.org/) for how to obtain
-it and set it up.
-
-### As a Shared Library (DLL) ###
-
-Google Mock is compact, so most users can build and link it as a static
-library for the simplicity. Google Mock can be used as a DLL, but the
-same DLL must contain Google Test as well. See
-[Google Test's README][gtest_readme]
-for instructions on how to set up necessary compiler settings.
-
-### Tweaking Google Mock ###
-
-Most of Google Test's control macros apply to Google Mock as well.
-Please see [Google Test's README][gtest_readme] for how to tweak them.
-
-### Upgrading from an Earlier Version ###
-
-We strive to keep Google Mock releases backward compatible.
-Sometimes, though, we have to make some breaking changes for the
-users' long-term benefits. This section describes what you'll need to
-do if you are upgrading from an earlier version of Google Mock.
-
-#### Upgrading from 1.1.0 or Earlier ####
-
-You may need to explicitly enable or disable Google Test's own TR1
-tuple library. See the instructions in section "[Choosing a TR1 Tuple
-Library](../googletest/#choosing-a-tr1-tuple-library)".
-
-#### Upgrading from 1.4.0 or Earlier ####
-
-On platforms where the pthread library is available, Google Test and
-Google Mock use it in order to be thread-safe. For this to work, you
-may need to tweak your compiler and/or linker flags. Please see the
-"[Multi-threaded Tests](../googletest#multi-threaded-tests
-)" section in file Google Test's README for what you may need to do.
-
-If you have custom matchers defined using `MatcherInterface` or
-`MakePolymorphicMatcher()`, you'll need to update their definitions to
-use the new matcher API (
-[monomorphic](http://code.google.com/p/googlemock/wiki/CookBook#Writing_New_Monomorphic_Matchers),
-[polymorphic](http://code.google.com/p/googlemock/wiki/CookBook#Writing_New_Polymorphic_Matchers)).
-Matchers defined using `MATCHER()` or `MATCHER_P*()` aren't affected.
-
-### Developing Google Mock ###
-
-This section discusses how to make your own changes to Google Mock.
-
-#### Testing Google Mock Itself ####
-
-To make sure your changes work as intended and don't break existing
-functionality, you'll want to compile and run Google Test's own tests.
-For that you'll need Autotools. First, make sure you have followed
-the instructions above to configure Google Mock.
-Then, create a build output directory and enter it. Next,
-
- ${GMOCK_DIR}/configure # try --help for more info
-
-Once you have successfully configured Google Mock, the build steps are
-standard for GNU-style OSS packages.
-
- make # Standard makefile following GNU conventions
- make check # Builds and runs all tests - all should pass.
-
-Note that when building your project against Google Mock, you are building
-against Google Test as well. There is no need to configure Google Test
-separately.
-
-#### Contributing a Patch ####
-
-We welcome patches.
-Please read the [Developer's Guide](docs/DevGuide.md)
-for how you can contribute. In particular, make sure you have signed
-the Contributor License Agreement, or we won't be able to accept the
-patch.
-
-Happy testing!
-
-[gtest_readme]: ../googletest/README.md "googletest"
+gMock:
+
+- provides a declarative syntax for defining mocks,
+- can define partial (hybrid) mocks, which are a cross of real and mock
+ objects,
+- handles functions of arbitrary types and overloaded functions,
+- comes with a rich set of matchers for validating function arguments,
+- uses an intuitive syntax for controlling the behavior of a mock,
+- does automatic verification of expectations (no record-and-replay needed),
+- allows arbitrary (partial) ordering constraints on function calls to be
+ expressed,
+- lets a user extend it by defining new matchers and actions.
+- does not use exceptions, and
+- is easy to learn and use.
+
+Details and examples can be found here:
+
+* [gMock for Dummies](docs/for_dummies.md)
+* [Legacy gMock FAQ](docs/gmock_faq.md)
+* [gMock Cookbook](docs/cook_book.md)
+* [gMock Cheat Sheet](docs/cheat_sheet.md)
+
+Please note that code under scripts/generator/ is from the [cppclean
+project](http://code.google.com/p/cppclean/) and under the Apache
+License, which is different from Google Mock's license.
+
+Google Mock is a part of
+[Google Test C++ testing framework](http://github.com/google/googletest/) and a
+subject to the same requirements.
diff --git a/extern/gmock/include/gmock/gmock-actions.h b/extern/gmock/include/gmock/gmock-actions.h
index b3f654af348..f12d39be06a 100644
--- a/extern/gmock/include/gmock/gmock-actions.h
+++ b/extern/gmock/include/gmock/gmock-actions.h
@@ -26,13 +26,14 @@
// 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.
-//
-// Author: wan@google.com (Zhanyong Wan)
+
// Google Mock - a framework for writing C++ mock classes.
//
// This file implements some commonly used actions.
+// GOOGLETEST_CM0002 DO NOT DELETE
+
#ifndef GMOCK_INCLUDE_GMOCK_GMOCK_ACTIONS_H_
#define GMOCK_INCLUDE_GMOCK_GMOCK_ACTIONS_H_
@@ -41,13 +42,18 @@
#endif
#include <algorithm>
+#include <functional>
+#include <memory>
#include <string>
+#include <type_traits>
+#include <utility>
#include "gmock/internal/gmock-internal-utils.h"
#include "gmock/internal/gmock-port.h"
-#if GTEST_HAS_STD_TYPE_TRAITS_ // Defined by gtest-port.h via gmock-port.h.
-#include <type_traits>
+#ifdef _MSC_VER
+# pragma warning(push)
+# pragma warning(disable:4100)
#endif
namespace testing {
@@ -63,9 +69,6 @@ namespace testing {
namespace internal {
-template <typename F1, typename F2>
-class ActionAdaptor;
-
// BuiltInDefaultValueGetter<T, true>::Get() returns a
// default-constructed T value. BuiltInDefaultValueGetter<T,
// false>::Get() crashes with an error.
@@ -96,8 +99,8 @@ struct BuiltInDefaultValueGetter<T, false> {
template <typename T>
class BuiltInDefaultValue {
public:
-#if GTEST_HAS_STD_TYPE_TRAITS_
- // This function returns true iff type T has a built-in default value.
+ // This function returns true if and only if type T has a built-in default
+ // value.
static bool Exists() {
return ::std::is_default_constructible<T>::value;
}
@@ -106,18 +109,6 @@ class BuiltInDefaultValue {
return BuiltInDefaultValueGetter<
T, ::std::is_default_constructible<T>::value>::Get();
}
-
-#else // GTEST_HAS_STD_TYPE_TRAITS_
- // This function returns true iff type T has a built-in default value.
- static bool Exists() {
- return false;
- }
-
- static T Get() {
- return BuiltInDefaultValueGetter<T, false>::Get();
- }
-
-#endif // GTEST_HAS_STD_TYPE_TRAITS_
};
// This partial specialization says that we use the same built-in
@@ -135,7 +126,7 @@ template <typename T>
class BuiltInDefaultValue<T*> {
public:
static bool Exists() { return true; }
- static T* Get() { return NULL; }
+ static T* Get() { return nullptr; }
};
// The following specializations define the default values for
@@ -149,9 +140,6 @@ class BuiltInDefaultValue<T*> {
}
GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(void, ); // NOLINT
-#if GTEST_HAS_GLOBAL_STRING
-GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(::string, "");
-#endif // GTEST_HAS_GLOBAL_STRING
GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(::std::string, "");
GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(bool, false);
GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(unsigned char, '\0');
@@ -218,11 +206,11 @@ class DefaultValue {
// Unsets the default value for type T.
static void Clear() {
delete producer_;
- producer_ = NULL;
+ producer_ = nullptr;
}
- // Returns true iff the user has set the default value for type T.
- static bool IsSet() { return producer_ != NULL; }
+ // Returns true if and only if the user has set the default value for type T.
+ static bool IsSet() { return producer_ != nullptr; }
// Returns true if T has a default return value set by the user or there
// exists a built-in default value.
@@ -234,8 +222,8 @@ class DefaultValue {
// otherwise returns the built-in default value. Requires that Exists()
// is true, which ensures that the return value is well-defined.
static T Get() {
- return producer_ == NULL ?
- internal::BuiltInDefaultValue<T>::Get() : producer_->Produce();
+ return producer_ == nullptr ? internal::BuiltInDefaultValue<T>::Get()
+ : producer_->Produce();
}
private:
@@ -248,7 +236,7 @@ class DefaultValue {
class FixedValueProducer : public ValueProducer {
public:
explicit FixedValueProducer(T value) : value_(value) {}
- virtual T Produce() { return value_; }
+ T Produce() override { return value_; }
private:
const T value_;
@@ -259,7 +247,7 @@ class DefaultValue {
public:
explicit FactoryValueProducer(FactoryFunction factory)
: factory_(factory) {}
- virtual T Produce() { return factory_(); }
+ T Produce() override { return factory_(); }
private:
const FactoryFunction factory_;
@@ -280,12 +268,10 @@ class DefaultValue<T&> {
}
// Unsets the default value for type T&.
- static void Clear() {
- address_ = NULL;
- }
+ static void Clear() { address_ = nullptr; }
- // Returns true iff the user has set the default value for type T&.
- static bool IsSet() { return address_ != NULL; }
+ // Returns true if and only if the user has set the default value for type T&.
+ static bool IsSet() { return address_ != nullptr; }
// Returns true if T has a default return value set by the user or there
// exists a built-in default value.
@@ -297,8 +283,8 @@ class DefaultValue<T&> {
// otherwise returns the built-in default value if there is one;
// otherwise aborts the process.
static T& Get() {
- return address_ == NULL ?
- internal::BuiltInDefaultValue<T&>::Get() : *address_;
+ return address_ == nullptr ? internal::BuiltInDefaultValue<T&>::Get()
+ : *address_;
}
private:
@@ -316,11 +302,11 @@ class DefaultValue<void> {
// Points to the user-set default value for type T.
template <typename T>
-typename DefaultValue<T>::ValueProducer* DefaultValue<T>::producer_ = NULL;
+typename DefaultValue<T>::ValueProducer* DefaultValue<T>::producer_ = nullptr;
// Points to the user-set default value for type T&.
template <typename T>
-T* DefaultValue<T&>::address_ = NULL;
+T* DefaultValue<T&>::address_ = nullptr;
// Implement this interface to define an action for function type F.
template <typename F>
@@ -345,38 +331,53 @@ class ActionInterface {
// An Action<F> is a copyable and IMMUTABLE (except by assignment)
// object that represents an action to be taken when a mock function
// of type F is called. The implementation of Action<T> is just a
-// linked_ptr to const ActionInterface<T>, so copying is fairly cheap.
-// Don't inherit from Action!
-//
+// std::shared_ptr to const ActionInterface<T>. Don't inherit from Action!
// You can view an object implementing ActionInterface<F> as a
// concrete action (including its current state), and an Action<F>
// object as a handle to it.
template <typename F>
class Action {
+ // Adapter class to allow constructing Action from a legacy ActionInterface.
+ // New code should create Actions from functors instead.
+ struct ActionAdapter {
+ // Adapter must be copyable to satisfy std::function requirements.
+ ::std::shared_ptr<ActionInterface<F>> impl_;
+
+ template <typename... Args>
+ typename internal::Function<F>::Result operator()(Args&&... args) {
+ return impl_->Perform(
+ ::std::forward_as_tuple(::std::forward<Args>(args)...));
+ }
+ };
+
public:
typedef typename internal::Function<F>::Result Result;
typedef typename internal::Function<F>::ArgumentTuple ArgumentTuple;
// Constructs a null Action. Needed for storing Action objects in
// STL containers.
- Action() : impl_(NULL) {}
+ Action() {}
- // Constructs an Action from its implementation. A NULL impl is
- // used to represent the "do-default" action.
- explicit Action(ActionInterface<F>* impl) : impl_(impl) {}
+ // Construct an Action from a specified callable.
+ // This cannot take std::function directly, because then Action would not be
+ // directly constructible from lambda (it would require two conversions).
+ template <typename G,
+ typename = typename ::std::enable_if<
+ ::std::is_constructible<::std::function<F>, G>::value>::type>
+ Action(G&& fun) : fun_(::std::forward<G>(fun)) {} // NOLINT
- // Copy constructor.
- Action(const Action& action) : impl_(action.impl_) {}
+ // Constructs an Action from its implementation.
+ explicit Action(ActionInterface<F>* impl)
+ : fun_(ActionAdapter{::std::shared_ptr<ActionInterface<F>>(impl)}) {}
// This constructor allows us to turn an Action<Func> object into an
// Action<F>, as long as F's arguments can be implicitly converted
- // to Func's and Func's return type can be implicitly converted to
- // F's.
+ // to Func's and Func's return type can be implicitly converted to F's.
template <typename Func>
- explicit Action(const Action<Func>& action);
+ explicit Action(const Action<Func>& action) : fun_(action.fun_) {}
- // Returns true iff this is the DoDefault() action.
- bool IsDoDefault() const { return impl_.get() == NULL; }
+ // Returns true if and only if this is the DoDefault() action.
+ bool IsDoDefault() const { return fun_ == nullptr; }
// Performs the action. Note that this method is const even though
// the corresponding method in ActionInterface is not. The reason
@@ -384,22 +385,19 @@ class Action {
// another concrete action, not that the concrete action it binds to
// cannot change state. (Think of the difference between a const
// pointer and a pointer to const.)
- Result Perform(const ArgumentTuple& args) const {
- internal::Assert(
- !IsDoDefault(), __FILE__, __LINE__,
- "You are using DoDefault() inside a composite action like "
- "DoAll() or WithArgs(). This is not supported for technical "
- "reasons. Please instead spell out the default action, or "
- "assign the default action to an Action variable and use "
- "the variable in various places.");
- return impl_->Perform(args);
+ Result Perform(ArgumentTuple args) const {
+ if (IsDoDefault()) {
+ internal::IllegalDoDefault(__FILE__, __LINE__);
+ }
+ return internal::Apply(fun_, ::std::move(args));
}
private:
- template <typename F1, typename F2>
- friend class internal::ActionAdaptor;
+ template <typename G>
+ friend class Action;
- internal::linked_ptr<ActionInterface<F> > impl_;
+ // fun_ is an empty function if and only if this is the DoDefault() action.
+ ::std::function<F> fun_;
};
// The PolymorphicAction class template makes it easy to implement a
@@ -414,7 +412,7 @@ class Action {
// template <typename Result, typename ArgumentTuple>
// Result Perform(const ArgumentTuple& args) const {
// // Processes the arguments and returns a result, using
-// // tr1::get<N>(args) to get the N-th (0-based) argument in the tuple.
+// // std::get<N>(args) to get the N-th (0-based) argument in the tuple.
// }
// ...
// };
@@ -442,7 +440,7 @@ class PolymorphicAction {
explicit MonomorphicImpl(const Impl& impl) : impl_(impl) {}
- virtual Result Perform(const ArgumentTuple& args) {
+ Result Perform(const ArgumentTuple& args) override {
return impl_.template Perform<Result>(args);
}
@@ -478,31 +476,11 @@ inline PolymorphicAction<Impl> MakePolymorphicAction(const Impl& impl) {
namespace internal {
-// Allows an Action<F2> object to pose as an Action<F1>, as long as F2
-// and F1 are compatible.
-template <typename F1, typename F2>
-class ActionAdaptor : public ActionInterface<F1> {
- public:
- typedef typename internal::Function<F1>::Result Result;
- typedef typename internal::Function<F1>::ArgumentTuple ArgumentTuple;
-
- explicit ActionAdaptor(const Action<F2>& from) : impl_(from.impl_) {}
-
- virtual Result Perform(const ArgumentTuple& args) {
- return impl_->Perform(args);
- }
-
- private:
- const internal::linked_ptr<ActionInterface<F2> > impl_;
-
- GTEST_DISALLOW_ASSIGN_(ActionAdaptor);
-};
-
// Helper struct to specialize ReturnAction to execute a move instead of a copy
// on return. Useful for move-only types, but could be used on any type.
template <typename T>
struct ByMoveWrapper {
- explicit ByMoveWrapper(T value) : payload(internal::move(value)) {}
+ explicit ByMoveWrapper(T value) : payload(std::move(value)) {}
T payload;
};
@@ -530,18 +508,21 @@ struct ByMoveWrapper {
// statement, and conversion of the result of Return to Action<T(U)> is a
// good place for that.
//
+// The real life example of the above scenario happens when an invocation
+// of gtl::Container() is passed into Return.
+//
template <typename R>
class ReturnAction {
public:
// Constructs a ReturnAction object from the value to be returned.
// 'value' is passed by value instead of by const reference in order
// to allow Return("string literal") to compile.
- explicit ReturnAction(R value) : value_(new R(internal::move(value))) {}
+ explicit ReturnAction(R value) : value_(new R(std::move(value))) {}
// This template type conversion operator allows Return(x) to be
// used in ANY function that returns x's type.
template <typename F>
- operator Action<F>() const {
+ operator Action<F>() const { // NOLINT
// Assert statement belongs here because this is the best place to verify
// conditions on F. It produces the clearest error messages
// in most compilers.
@@ -552,8 +533,10 @@ class ReturnAction {
// in the Impl class. But both definitions must be the same.
typedef typename Function<F>::Result Result;
GTEST_COMPILE_ASSERT_(
- !is_reference<Result>::value,
+ !std::is_reference<Result>::value,
use_ReturnRef_instead_of_Return_to_return_a_reference);
+ static_assert(!std::is_void<Result>::value,
+ "Can't use Return() on an action expected to return `void`.");
return Action<F>(new Impl<R, F>(value_));
}
@@ -572,14 +555,14 @@ class ReturnAction {
// Result to call. ImplicitCast_ forces the compiler to convert R to
// Result without considering explicit constructors, thus resolving the
// ambiguity. value_ is then initialized using its copy constructor.
- explicit Impl(const linked_ptr<R>& value)
+ explicit Impl(const std::shared_ptr<R>& value)
: value_before_cast_(*value),
value_(ImplicitCast_<Result>(value_before_cast_)) {}
- virtual Result Perform(const ArgumentTuple&) { return value_; }
+ Result Perform(const ArgumentTuple&) override { return value_; }
private:
- GTEST_COMPILE_ASSERT_(!is_reference<Result>::value,
+ GTEST_COMPILE_ASSERT_(!std::is_reference<Result>::value,
Result_cannot_be_a_reference_type);
// We save the value before casting just in case it is being cast to a
// wrapper type.
@@ -597,24 +580,24 @@ class ReturnAction {
typedef typename Function<F>::Result Result;
typedef typename Function<F>::ArgumentTuple ArgumentTuple;
- explicit Impl(const linked_ptr<R>& wrapper)
+ explicit Impl(const std::shared_ptr<R>& wrapper)
: performed_(false), wrapper_(wrapper) {}
- virtual Result Perform(const ArgumentTuple&) {
+ Result Perform(const ArgumentTuple&) override {
GTEST_CHECK_(!performed_)
<< "A ByMove() action should only be performed once.";
performed_ = true;
- return internal::move(wrapper_->payload);
+ return std::move(wrapper_->payload);
}
private:
bool performed_;
- const linked_ptr<R> wrapper_;
+ const std::shared_ptr<R> wrapper_;
GTEST_DISALLOW_ASSIGN_(Impl);
};
- const linked_ptr<R> value_;
+ const std::shared_ptr<R> value_;
GTEST_DISALLOW_ASSIGN_(ReturnAction);
};
@@ -627,13 +610,7 @@ class ReturnNullAction {
// pointer type on compile time.
template <typename Result, typename ArgumentTuple>
static Result Perform(const ArgumentTuple&) {
-#if GTEST_LANG_CXX11
return nullptr;
-#else
- GTEST_COMPILE_ASSERT_(internal::is_pointer<Result>::value,
- ReturnNull_can_be_used_to_return_a_pointer_only);
- return NULL;
-#endif // GTEST_LANG_CXX11
}
};
@@ -643,7 +620,7 @@ class ReturnVoidAction {
// Allows Return() to be used in any void-returning function.
template <typename Result, typename ArgumentTuple>
static void Perform(const ArgumentTuple&) {
- CompileAssertTypesEqual<void, Result>();
+ static_assert(std::is_void<Result>::value, "Result should be void.");
}
};
@@ -664,7 +641,7 @@ class ReturnRefAction {
// Asserts that the function return type is a reference. This
// catches the user error of using ReturnRef(x) when Return(x)
// should be used, and generates some helpful error message.
- GTEST_COMPILE_ASSERT_(internal::is_reference<Result>::value,
+ GTEST_COMPILE_ASSERT_(std::is_reference<Result>::value,
use_Return_instead_of_ReturnRef_to_return_a_value);
return Action<F>(new Impl<F>(ref_));
}
@@ -679,9 +656,7 @@ class ReturnRefAction {
explicit Impl(T& ref) : ref_(ref) {} // NOLINT
- virtual Result Perform(const ArgumentTuple&) {
- return ref_;
- }
+ Result Perform(const ArgumentTuple&) override { return ref_; }
private:
T& ref_;
@@ -713,7 +688,7 @@ class ReturnRefOfCopyAction {
// catches the user error of using ReturnRefOfCopy(x) when Return(x)
// should be used, and generates some helpful error message.
GTEST_COMPILE_ASSERT_(
- internal::is_reference<Result>::value,
+ std::is_reference<Result>::value,
use_Return_instead_of_ReturnRefOfCopy_to_return_a_value);
return Action<F>(new Impl<F>(value_));
}
@@ -728,9 +703,7 @@ class ReturnRefOfCopyAction {
explicit Impl(const T& value) : value_(value) {} // NOLINT
- virtual Result Perform(const ArgumentTuple&) {
- return value_;
- }
+ Result Perform(const ArgumentTuple&) override { return value_; }
private:
T value_;
@@ -749,7 +722,7 @@ class DoDefaultAction {
// This template type conversion operator allows DoDefault() to be
// used in any function.
template <typename F>
- operator Action<F>() const { return Action<F>(NULL); }
+ operator Action<F>() const { return Action<F>(); } // NOLINT
};
// Implements the Assign action to set a given pointer referent to a
@@ -797,92 +770,58 @@ class SetErrnoAndReturnAction {
#endif // !GTEST_OS_WINDOWS_MOBILE
// Implements the SetArgumentPointee<N>(x) action for any function
-// whose N-th argument (0-based) is a pointer to x's type. The
-// template parameter kIsProto is true iff type A is ProtocolMessage,
-// proto2::Message, or a sub-class of those.
-template <size_t N, typename A, bool kIsProto>
-class SetArgumentPointeeAction {
- public:
- // Constructs an action that sets the variable pointed to by the
- // N-th function argument to 'value'.
- explicit SetArgumentPointeeAction(const A& value) : value_(value) {}
-
- template <typename Result, typename ArgumentTuple>
- void Perform(const ArgumentTuple& args) const {
- CompileAssertTypesEqual<void, Result>();
- *::testing::get<N>(args) = value_;
+// whose N-th argument (0-based) is a pointer to x's type.
+template <size_t N, typename A, typename = void>
+struct SetArgumentPointeeAction {
+ A value;
+
+ template <typename... Args>
+ void operator()(const Args&... args) const {
+ *::std::get<N>(std::tie(args...)) = value;
}
-
- private:
- const A value_;
-
- GTEST_DISALLOW_ASSIGN_(SetArgumentPointeeAction);
};
-template <size_t N, typename Proto>
-class SetArgumentPointeeAction<N, Proto, true> {
- public:
- // Constructs an action that sets the variable pointed to by the
- // N-th function argument to 'proto'. Both ProtocolMessage and
- // proto2::Message have the CopyFrom() method, so the same
- // implementation works for both.
- explicit SetArgumentPointeeAction(const Proto& proto) : proto_(new Proto) {
- proto_->CopyFrom(proto);
- }
-
- template <typename Result, typename ArgumentTuple>
- void Perform(const ArgumentTuple& args) const {
- CompileAssertTypesEqual<void, Result>();
- ::testing::get<N>(args)->CopyFrom(*proto_);
+// Implements the Invoke(object_ptr, &Class::Method) action.
+template <class Class, typename MethodPtr>
+struct InvokeMethodAction {
+ Class* const obj_ptr;
+ const MethodPtr method_ptr;
+
+ template <typename... Args>
+ auto operator()(Args&&... args) const
+ -> decltype((obj_ptr->*method_ptr)(std::forward<Args>(args)...)) {
+ return (obj_ptr->*method_ptr)(std::forward<Args>(args)...);
}
-
- private:
- const internal::linked_ptr<Proto> proto_;
-
- GTEST_DISALLOW_ASSIGN_(SetArgumentPointeeAction);
};
// Implements the InvokeWithoutArgs(f) action. The template argument
// FunctionImpl is the implementation type of f, which can be either a
// function pointer or a functor. InvokeWithoutArgs(f) can be used as an
-// Action<F> as long as f's type is compatible with F (i.e. f can be
-// assigned to a tr1::function<F>).
+// Action<F> as long as f's type is compatible with F.
template <typename FunctionImpl>
-class InvokeWithoutArgsAction {
- public:
- // The c'tor makes a copy of function_impl (either a function
- // pointer or a functor).
- explicit InvokeWithoutArgsAction(FunctionImpl function_impl)
- : function_impl_(function_impl) {}
+struct InvokeWithoutArgsAction {
+ FunctionImpl function_impl;
// Allows InvokeWithoutArgs(f) to be used as any action whose type is
// compatible with f.
- template <typename Result, typename ArgumentTuple>
- Result Perform(const ArgumentTuple&) { return function_impl_(); }
-
- private:
- FunctionImpl function_impl_;
-
- GTEST_DISALLOW_ASSIGN_(InvokeWithoutArgsAction);
+ template <typename... Args>
+ auto operator()(const Args&...) -> decltype(function_impl()) {
+ return function_impl();
+ }
};
// Implements the InvokeWithoutArgs(object_ptr, &Class::Method) action.
template <class Class, typename MethodPtr>
-class InvokeMethodWithoutArgsAction {
- public:
- InvokeMethodWithoutArgsAction(Class* obj_ptr, MethodPtr method_ptr)
- : obj_ptr_(obj_ptr), method_ptr_(method_ptr) {}
+struct InvokeMethodWithoutArgsAction {
+ Class* const obj_ptr;
+ const MethodPtr method_ptr;
- template <typename Result, typename ArgumentTuple>
- Result Perform(const ArgumentTuple&) const {
- return (obj_ptr_->*method_ptr_)();
- }
+ using ReturnType = typename std::result_of<MethodPtr(Class*)>::type;
- private:
- Class* const obj_ptr_;
- const MethodPtr method_ptr_;
-
- GTEST_DISALLOW_ASSIGN_(InvokeMethodWithoutArgsAction);
+ template <typename... Args>
+ ReturnType operator()(const Args&...) const {
+ return (obj_ptr->*method_ptr)();
+ }
};
// Implements the IgnoreResult(action) action.
@@ -904,7 +843,7 @@ class IgnoreResultAction {
typedef typename internal::Function<F>::Result Result;
// Asserts at compile time that F returns void.
- CompileAssertTypesEqual<void, Result>();
+ static_assert(std::is_void<Result>::value, "Result type should be void.");
return Action<F>(new Impl<F>(action_));
}
@@ -918,7 +857,7 @@ class IgnoreResultAction {
explicit Impl(const A& action) : action_(action) {}
- virtual void Perform(const ArgumentTuple& args) {
+ void Perform(const ArgumentTuple& args) override {
// Performs the action and ignores its result.
action_.Perform(args);
}
@@ -939,76 +878,51 @@ class IgnoreResultAction {
GTEST_DISALLOW_ASSIGN_(IgnoreResultAction);
};
-// A ReferenceWrapper<T> object represents a reference to type T,
-// which can be either const or not. It can be explicitly converted
-// from, and implicitly converted to, a T&. Unlike a reference,
-// ReferenceWrapper<T> can be copied and can survive template type
-// inference. This is used to support by-reference arguments in the
-// InvokeArgument<N>(...) action. The idea was from "reference
-// wrappers" in tr1, which we don't have in our source tree yet.
-template <typename T>
-class ReferenceWrapper {
- public:
- // Constructs a ReferenceWrapper<T> object from a T&.
- explicit ReferenceWrapper(T& l_value) : pointer_(&l_value) {} // NOLINT
-
- // Allows a ReferenceWrapper<T> object to be implicitly converted to
- // a T&.
- operator T&() const { return *pointer_; }
- private:
- T* pointer_;
+template <typename InnerAction, size_t... I>
+struct WithArgsAction {
+ InnerAction action;
+
+ // The inner action could be anything convertible to Action<X>.
+ // We use the conversion operator to detect the signature of the inner Action.
+ template <typename R, typename... Args>
+ operator Action<R(Args...)>() const { // NOLINT
+ Action<R(typename std::tuple_element<I, std::tuple<Args...>>::type...)>
+ converted(action);
+
+ return [converted](Args... args) -> R {
+ return converted.Perform(std::forward_as_tuple(
+ std::get<I>(std::forward_as_tuple(std::forward<Args>(args)...))...));
+ };
+ }
};
-// Allows the expression ByRef(x) to be printed as a reference to x.
-template <typename T>
-void PrintTo(const ReferenceWrapper<T>& ref, ::std::ostream* os) {
- T& value = ref;
- UniversalPrinter<T&>::Print(value, os);
-}
+template <typename... Actions>
+struct DoAllAction {
+ private:
+ template <typename... Args, size_t... I>
+ std::vector<Action<void(Args...)>> Convert(IndexSequence<I...>) const {
+ return {std::get<I>(actions)...};
+ }
-// Does two actions sequentially. Used for implementing the DoAll(a1,
-// a2, ...) action.
-template <typename Action1, typename Action2>
-class DoBothAction {
public:
- DoBothAction(Action1 action1, Action2 action2)
- : action1_(action1), action2_(action2) {}
-
- // This template type conversion operator allows DoAll(a1, ..., a_n)
- // to be used in ANY function of compatible type.
- template <typename F>
- operator Action<F>() const {
- return Action<F>(new Impl<F>(action1_, action2_));
+ std::tuple<Actions...> actions;
+
+ template <typename R, typename... Args>
+ operator Action<R(Args...)>() const { // NOLINT
+ struct Op {
+ std::vector<Action<void(Args...)>> converted;
+ Action<R(Args...)> last;
+ R operator()(Args... args) const {
+ auto tuple_args = std::forward_as_tuple(std::forward<Args>(args)...);
+ for (auto& a : converted) {
+ a.Perform(tuple_args);
+ }
+ return last.Perform(tuple_args);
+ }
+ };
+ return Op{Convert<Args...>(MakeIndexSequence<sizeof...(Actions) - 1>()),
+ std::get<sizeof...(Actions) - 1>(actions)};
}
-
- private:
- // Implements the DoAll(...) action for a particular function type F.
- template <typename F>
- class Impl : public ActionInterface<F> {
- public:
- typedef typename Function<F>::Result Result;
- typedef typename Function<F>::ArgumentTuple ArgumentTuple;
- typedef typename Function<F>::MakeResultVoid VoidResult;
-
- Impl(const Action<VoidResult>& action1, const Action<F>& action2)
- : action1_(action1), action2_(action2) {}
-
- virtual Result Perform(const ArgumentTuple& args) {
- action1_.Perform(args);
- return action2_.Perform(args);
- }
-
- private:
- const Action<VoidResult> action1_;
- const Action<F> action2_;
-
- GTEST_DISALLOW_ASSIGN_(Impl);
- };
-
- Action1 action1_;
- Action2 action2_;
-
- GTEST_DISALLOW_ASSIGN_(DoBothAction);
};
} // namespace internal
@@ -1029,9 +943,9 @@ class DoBothAction {
// return sqrt(x*x + y*y);
// }
// ...
-// EXEPCT_CALL(mock, Foo("abc", _, _))
+// EXPECT_CALL(mock, Foo("abc", _, _))
// .WillOnce(Invoke(DistanceToOriginWithLabel));
-// EXEPCT_CALL(mock, Bar(5, _, _))
+// EXPECT_CALL(mock, Bar(5, _, _))
// .WillOnce(Invoke(DistanceToOriginWithIndex));
//
// you could write
@@ -1041,25 +955,55 @@ class DoBothAction {
// return sqrt(x*x + y*y);
// }
// ...
-// EXEPCT_CALL(mock, Foo("abc", _, _)).WillOnce(Invoke(DistanceToOrigin));
-// EXEPCT_CALL(mock, Bar(5, _, _)).WillOnce(Invoke(DistanceToOrigin));
+// EXPECT_CALL(mock, Foo("abc", _, _)).WillOnce(Invoke(DistanceToOrigin));
+// EXPECT_CALL(mock, Bar(5, _, _)).WillOnce(Invoke(DistanceToOrigin));
typedef internal::IgnoredValue Unused;
-// This constructor allows us to turn an Action<From> object into an
-// Action<To>, as long as To's arguments can be implicitly converted
-// to From's and From's return type cann be implicitly converted to
-// To's.
-template <typename To>
-template <typename From>
-Action<To>::Action(const Action<From>& from)
- : impl_(new internal::ActionAdaptor<To, From>(from)) {}
+// Creates an action that does actions a1, a2, ..., sequentially in
+// each invocation.
+template <typename... Action>
+internal::DoAllAction<typename std::decay<Action>::type...> DoAll(
+ Action&&... action) {
+ return {std::forward_as_tuple(std::forward<Action>(action)...)};
+}
+
+// WithArg<k>(an_action) creates an action that passes the k-th
+// (0-based) argument of the mock function to an_action and performs
+// it. It adapts an action accepting one argument to one that accepts
+// multiple arguments. For convenience, we also provide
+// WithArgs<k>(an_action) (defined below) as a synonym.
+template <size_t k, typename InnerAction>
+internal::WithArgsAction<typename std::decay<InnerAction>::type, k>
+WithArg(InnerAction&& action) {
+ return {std::forward<InnerAction>(action)};
+}
+
+// WithArgs<N1, N2, ..., Nk>(an_action) creates an action that passes
+// the selected arguments of the mock function to an_action and
+// performs it. It serves as an adaptor between actions with
+// different argument lists.
+template <size_t k, size_t... ks, typename InnerAction>
+internal::WithArgsAction<typename std::decay<InnerAction>::type, k, ks...>
+WithArgs(InnerAction&& action) {
+ return {std::forward<InnerAction>(action)};
+}
+
+// WithoutArgs(inner_action) can be used in a mock function with a
+// non-empty argument list to perform inner_action, which takes no
+// argument. In other words, it adapts an action accepting no
+// argument to one that accepts (and ignores) arguments.
+template <typename InnerAction>
+internal::WithArgsAction<typename std::decay<InnerAction>::type>
+WithoutArgs(InnerAction&& action) {
+ return {std::forward<InnerAction>(action)};
+}
// Creates an action that returns 'value'. 'value' is passed by value
// instead of const reference - otherwise Return("string literal")
// will trigger a compiler error about using array as initializer.
template <typename R>
internal::ReturnAction<R> Return(R value) {
- return internal::ReturnAction<R>(internal::move(value));
+ return internal::ReturnAction<R>(std::move(value));
}
// Creates an action that returns NULL.
@@ -1092,7 +1036,7 @@ inline internal::ReturnRefOfCopyAction<R> ReturnRefOfCopy(const R& x) {
// invariant.
template <typename R>
internal::ByMoveWrapper<R> ByMove(R x) {
- return internal::ByMoveWrapper<R>(internal::move(x));
+ return internal::ByMoveWrapper<R>(std::move(x));
}
// Creates an action that does the default action for the give mock function.
@@ -1103,43 +1047,14 @@ inline internal::DoDefaultAction DoDefault() {
// Creates an action that sets the variable pointed by the N-th
// (0-based) function argument to 'value'.
template <size_t N, typename T>
-PolymorphicAction<
- internal::SetArgumentPointeeAction<
- N, T, internal::IsAProtocolMessage<T>::value> >
-SetArgPointee(const T& x) {
- return MakePolymorphicAction(internal::SetArgumentPointeeAction<
- N, T, internal::IsAProtocolMessage<T>::value>(x));
-}
-
-#if !((GTEST_GCC_VER_ && GTEST_GCC_VER_ < 40000) || GTEST_OS_SYMBIAN)
-// This overload allows SetArgPointee() to accept a string literal.
-// GCC prior to the version 4.0 and Symbian C++ compiler cannot distinguish
-// this overload from the templated version and emit a compile error.
-template <size_t N>
-PolymorphicAction<
- internal::SetArgumentPointeeAction<N, const char*, false> >
-SetArgPointee(const char* p) {
- return MakePolymorphicAction(internal::SetArgumentPointeeAction<
- N, const char*, false>(p));
-}
-
-template <size_t N>
-PolymorphicAction<
- internal::SetArgumentPointeeAction<N, const wchar_t*, false> >
-SetArgPointee(const wchar_t* p) {
- return MakePolymorphicAction(internal::SetArgumentPointeeAction<
- N, const wchar_t*, false>(p));
+internal::SetArgumentPointeeAction<N, T> SetArgPointee(T x) {
+ return {std::move(x)};
}
-#endif
// The following version is DEPRECATED.
template <size_t N, typename T>
-PolymorphicAction<
- internal::SetArgumentPointeeAction<
- N, T, internal::IsAProtocolMessage<T>::value> >
-SetArgumentPointee(const T& x) {
- return MakePolymorphicAction(internal::SetArgumentPointeeAction<
- N, T, internal::IsAProtocolMessage<T>::value>(x));
+internal::SetArgumentPointeeAction<N, T> SetArgumentPointee(T x) {
+ return {std::move(x)};
}
// Creates an action that sets a pointer referent to a given value.
@@ -1160,24 +1075,38 @@ SetErrnoAndReturn(int errval, T result) {
#endif // !GTEST_OS_WINDOWS_MOBILE
-// Various overloads for InvokeWithoutArgs().
+// Various overloads for Invoke().
+
+// Legacy function.
+// Actions can now be implicitly constructed from callables. No need to create
+// wrapper objects.
+// This function exists for backwards compatibility.
+template <typename FunctionImpl>
+typename std::decay<FunctionImpl>::type Invoke(FunctionImpl&& function_impl) {
+ return std::forward<FunctionImpl>(function_impl);
+}
+
+// Creates an action that invokes the given method on the given object
+// with the mock function's arguments.
+template <class Class, typename MethodPtr>
+internal::InvokeMethodAction<Class, MethodPtr> Invoke(Class* obj_ptr,
+ MethodPtr method_ptr) {
+ return {obj_ptr, method_ptr};
+}
// Creates an action that invokes 'function_impl' with no argument.
template <typename FunctionImpl>
-PolymorphicAction<internal::InvokeWithoutArgsAction<FunctionImpl> >
+internal::InvokeWithoutArgsAction<typename std::decay<FunctionImpl>::type>
InvokeWithoutArgs(FunctionImpl function_impl) {
- return MakePolymorphicAction(
- internal::InvokeWithoutArgsAction<FunctionImpl>(function_impl));
+ return {std::move(function_impl)};
}
// Creates an action that invokes the given method on the given object
// with no argument.
template <class Class, typename MethodPtr>
-PolymorphicAction<internal::InvokeMethodWithoutArgsAction<Class, MethodPtr> >
-InvokeWithoutArgs(Class* obj_ptr, MethodPtr method_ptr) {
- return MakePolymorphicAction(
- internal::InvokeMethodWithoutArgsAction<Class, MethodPtr>(
- obj_ptr, method_ptr));
+internal::InvokeMethodWithoutArgsAction<Class, MethodPtr> InvokeWithoutArgs(
+ Class* obj_ptr, MethodPtr method_ptr) {
+ return {obj_ptr, method_ptr};
}
// Creates an action that performs an_action and throws away its
@@ -1195,11 +1124,19 @@ inline internal::IgnoreResultAction<A> IgnoreResult(const A& an_action) {
// where Base is a base class of Derived, just write:
//
// ByRef<const Base>(derived)
+//
+// N.B. ByRef is redundant with std::ref, std::cref and std::reference_wrapper.
+// However, it may still be used for consistency with ByMove().
template <typename T>
-inline internal::ReferenceWrapper<T> ByRef(T& l_value) { // NOLINT
- return internal::ReferenceWrapper<T>(l_value);
+inline ::std::reference_wrapper<T> ByRef(T& l_value) { // NOLINT
+ return ::std::reference_wrapper<T>(l_value);
}
} // namespace testing
+#ifdef _MSC_VER
+# pragma warning(pop)
+#endif
+
+
#endif // GMOCK_INCLUDE_GMOCK_GMOCK_ACTIONS_H_
diff --git a/extern/gmock/include/gmock/gmock-cardinalities.h b/extern/gmock/include/gmock/gmock-cardinalities.h
index fc315f92ab5..46e01e102d5 100644
--- a/extern/gmock/include/gmock/gmock-cardinalities.h
+++ b/extern/gmock/include/gmock/gmock-cardinalities.h
@@ -26,8 +26,7 @@
// 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.
-//
-// Author: wan@google.com (Zhanyong Wan)
+
// Google Mock - a framework for writing C++ mock classes.
//
@@ -35,14 +34,20 @@
// cardinalities can be defined by the user implementing the
// CardinalityInterface interface if necessary.
+// GOOGLETEST_CM0002 DO NOT DELETE
+
#ifndef GMOCK_INCLUDE_GMOCK_GMOCK_CARDINALITIES_H_
#define GMOCK_INCLUDE_GMOCK_GMOCK_CARDINALITIES_H_
#include <limits.h>
+#include <memory>
#include <ostream> // NOLINT
#include "gmock/internal/gmock-port.h"
#include "gtest/gtest.h"
+GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \
+/* class A needs to have dll-interface to be used by clients of class B */)
+
namespace testing {
// To implement a cardinality Foo, define:
@@ -65,10 +70,12 @@ class CardinalityInterface {
virtual int ConservativeLowerBound() const { return 0; }
virtual int ConservativeUpperBound() const { return INT_MAX; }
- // Returns true iff call_count calls will satisfy this cardinality.
+ // Returns true if and only if call_count calls will satisfy this
+ // cardinality.
virtual bool IsSatisfiedByCallCount(int call_count) const = 0;
- // Returns true iff call_count calls will saturate this cardinality.
+ // Returns true if and only if call_count calls will saturate this
+ // cardinality.
virtual bool IsSaturatedByCallCount(int call_count) const = 0;
// Describes self to an ostream.
@@ -77,9 +84,8 @@ class CardinalityInterface {
// A Cardinality is a copyable and IMMUTABLE (except by assignment)
// object that specifies how many times a mock function is expected to
-// be called. The implementation of Cardinality is just a linked_ptr
-// to const CardinalityInterface, so copying is fairly cheap.
-// Don't inherit from Cardinality!
+// be called. The implementation of Cardinality is just a std::shared_ptr
+// to const CardinalityInterface. Don't inherit from Cardinality!
class GTEST_API_ Cardinality {
public:
// Constructs a null cardinality. Needed for storing Cardinality
@@ -94,17 +100,19 @@ class GTEST_API_ Cardinality {
int ConservativeLowerBound() const { return impl_->ConservativeLowerBound(); }
int ConservativeUpperBound() const { return impl_->ConservativeUpperBound(); }
- // Returns true iff call_count calls will satisfy this cardinality.
+ // Returns true if and only if call_count calls will satisfy this
+ // cardinality.
bool IsSatisfiedByCallCount(int call_count) const {
return impl_->IsSatisfiedByCallCount(call_count);
}
- // Returns true iff call_count calls will saturate this cardinality.
+ // Returns true if and only if call_count calls will saturate this
+ // cardinality.
bool IsSaturatedByCallCount(int call_count) const {
return impl_->IsSaturatedByCallCount(call_count);
}
- // Returns true iff call_count calls will over-saturate this
+ // Returns true if and only if call_count calls will over-saturate this
// cardinality, i.e. exceed the maximum number of allowed calls.
bool IsOverSaturatedByCallCount(int call_count) const {
return impl_->IsSaturatedByCallCount(call_count) &&
@@ -119,7 +127,7 @@ class GTEST_API_ Cardinality {
::std::ostream* os);
private:
- internal::linked_ptr<const CardinalityInterface> impl_;
+ std::shared_ptr<const CardinalityInterface> impl_;
};
// Creates a cardinality that allows at least n calls.
@@ -144,4 +152,6 @@ inline Cardinality MakeCardinality(const CardinalityInterface* c) {
} // namespace testing
+GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251
+
#endif // GMOCK_INCLUDE_GMOCK_GMOCK_CARDINALITIES_H_
diff --git a/extern/gmock/include/gmock/gmock-function-mocker.h b/extern/gmock/include/gmock/gmock-function-mocker.h
new file mode 100644
index 00000000000..cc1535c806b
--- /dev/null
+++ b/extern/gmock/include/gmock/gmock-function-mocker.h
@@ -0,0 +1,253 @@
+// Copyright 2007, 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.
+
+// Google Mock - a framework for writing C++ mock classes.
+//
+// This file implements MOCK_METHOD.
+
+// GOOGLETEST_CM0002 DO NOT DELETE
+
+#ifndef THIRD_PARTY_GOOGLETEST_GOOGLEMOCK_INCLUDE_GMOCK_INTERNAL_GMOCK_FUNCTION_MOCKER_H_ // NOLINT
+#define THIRD_PARTY_GOOGLETEST_GOOGLEMOCK_INCLUDE_GMOCK_INTERNAL_GMOCK_FUNCTION_MOCKER_H_ // NOLINT
+
+#include "gmock/gmock-generated-function-mockers.h" // NOLINT
+#include "gmock/internal/gmock-pp.h"
+
+#define MOCK_METHOD(...) \
+ GMOCK_PP_VARIADIC_CALL(GMOCK_INTERNAL_MOCK_METHOD_ARG_, __VA_ARGS__)
+
+#define GMOCK_INTERNAL_MOCK_METHOD_ARG_1(...) \
+ GMOCK_INTERNAL_WRONG_ARITY(__VA_ARGS__)
+
+#define GMOCK_INTERNAL_MOCK_METHOD_ARG_2(...) \
+ GMOCK_INTERNAL_WRONG_ARITY(__VA_ARGS__)
+
+#define GMOCK_INTERNAL_MOCK_METHOD_ARG_3(_Ret, _MethodName, _Args) \
+ GMOCK_INTERNAL_MOCK_METHOD_ARG_4(_Ret, _MethodName, _Args, ())
+
+#define GMOCK_INTERNAL_MOCK_METHOD_ARG_4(_Ret, _MethodName, _Args, _Spec) \
+ GMOCK_INTERNAL_ASSERT_PARENTHESIS(_Args); \
+ GMOCK_INTERNAL_ASSERT_PARENTHESIS(_Spec); \
+ GMOCK_INTERNAL_ASSERT_VALID_SIGNATURE( \
+ GMOCK_PP_NARG0 _Args, GMOCK_INTERNAL_SIGNATURE(_Ret, _Args)); \
+ GMOCK_INTERNAL_ASSERT_VALID_SPEC(_Spec) \
+ GMOCK_INTERNAL_MOCK_METHOD_IMPL( \
+ GMOCK_PP_NARG0 _Args, _MethodName, GMOCK_INTERNAL_HAS_CONST(_Spec), \
+ GMOCK_INTERNAL_HAS_OVERRIDE(_Spec), GMOCK_INTERNAL_HAS_FINAL(_Spec), \
+ GMOCK_INTERNAL_HAS_NOEXCEPT(_Spec), GMOCK_INTERNAL_GET_CALLTYPE(_Spec), \
+ (GMOCK_INTERNAL_SIGNATURE(_Ret, _Args)))
+
+#define GMOCK_INTERNAL_MOCK_METHOD_ARG_5(...) \
+ GMOCK_INTERNAL_WRONG_ARITY(__VA_ARGS__)
+
+#define GMOCK_INTERNAL_MOCK_METHOD_ARG_6(...) \
+ GMOCK_INTERNAL_WRONG_ARITY(__VA_ARGS__)
+
+#define GMOCK_INTERNAL_MOCK_METHOD_ARG_7(...) \
+ GMOCK_INTERNAL_WRONG_ARITY(__VA_ARGS__)
+
+#define GMOCK_INTERNAL_WRONG_ARITY(...) \
+ static_assert( \
+ false, \
+ "MOCK_METHOD must be called with 3 or 4 arguments. _Ret, " \
+ "_MethodName, _Args and optionally _Spec. _Args and _Spec must be " \
+ "enclosed in parentheses. If _Ret is a type with unprotected commas, " \
+ "it must also be enclosed in parentheses.")
+
+#define GMOCK_INTERNAL_ASSERT_PARENTHESIS(_Tuple) \
+ static_assert( \
+ GMOCK_PP_IS_ENCLOSED_PARENS(_Tuple), \
+ GMOCK_PP_STRINGIZE(_Tuple) " should be enclosed in parentheses.")
+
+#define GMOCK_INTERNAL_ASSERT_VALID_SIGNATURE(_N, ...) \
+ static_assert( \
+ std::is_function<__VA_ARGS__>::value, \
+ "Signature must be a function type, maybe return type contains " \
+ "unprotected comma."); \
+ static_assert( \
+ ::testing::tuple_size<typename ::testing::internal::Function< \
+ __VA_ARGS__>::ArgumentTuple>::value == _N, \
+ "This method does not take " GMOCK_PP_STRINGIZE( \
+ _N) " arguments. Parenthesize all types with unproctected commas.")
+
+#define GMOCK_INTERNAL_ASSERT_VALID_SPEC(_Spec) \
+ GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_ASSERT_VALID_SPEC_ELEMENT, ~, _Spec)
+
+#define GMOCK_INTERNAL_MOCK_METHOD_IMPL(_N, _MethodName, _Constness, \
+ _Override, _Final, _Noexcept, \
+ _CallType, _Signature) \
+ typename ::testing::internal::Function<GMOCK_PP_REMOVE_PARENS( \
+ _Signature)>::Result \
+ GMOCK_INTERNAL_EXPAND(_CallType) \
+ _MethodName(GMOCK_PP_REPEAT(GMOCK_INTERNAL_PARAMETER, _Signature, _N)) \
+ GMOCK_PP_IF(_Constness, const, ) GMOCK_PP_IF(_Noexcept, noexcept, ) \
+ GMOCK_PP_IF(_Override, override, ) \
+ GMOCK_PP_IF(_Final, final, ) { \
+ GMOCK_MOCKER_(_N, _Constness, _MethodName) \
+ .SetOwnerAndName(this, #_MethodName); \
+ return GMOCK_MOCKER_(_N, _Constness, _MethodName) \
+ .Invoke(GMOCK_PP_REPEAT(GMOCK_INTERNAL_FORWARD_ARG, _Signature, _N)); \
+ } \
+ ::testing::MockSpec<GMOCK_PP_REMOVE_PARENS(_Signature)> gmock_##_MethodName( \
+ GMOCK_PP_REPEAT(GMOCK_INTERNAL_MATCHER_PARAMETER, _Signature, _N)) \
+ GMOCK_PP_IF(_Constness, const, ) { \
+ GMOCK_MOCKER_(_N, _Constness, _MethodName).RegisterOwner(this); \
+ return GMOCK_MOCKER_(_N, _Constness, _MethodName) \
+ .With(GMOCK_PP_REPEAT(GMOCK_INTERNAL_MATCHER_ARGUMENT, , _N)); \
+ } \
+ ::testing::MockSpec<GMOCK_PP_REMOVE_PARENS(_Signature)> gmock_##_MethodName( \
+ const ::testing::internal::WithoutMatchers&, \
+ GMOCK_PP_IF(_Constness, const, )::testing::internal::Function< \
+ GMOCK_PP_REMOVE_PARENS(_Signature)>*) \
+ const GMOCK_PP_IF(_Noexcept, noexcept, ) { \
+ return GMOCK_PP_CAT(::testing::internal::AdjustConstness_, \
+ GMOCK_PP_IF(_Constness, const, ))(this) \
+ ->gmock_##_MethodName(GMOCK_PP_REPEAT( \
+ GMOCK_INTERNAL_A_MATCHER_ARGUMENT, _Signature, _N)); \
+ } \
+ mutable ::testing::FunctionMocker<GMOCK_PP_REMOVE_PARENS(_Signature)> \
+ GMOCK_MOCKER_(_N, _Constness, _MethodName)
+
+#define GMOCK_INTERNAL_EXPAND(...) __VA_ARGS__
+
+// Five Valid modifiers.
+#define GMOCK_INTERNAL_HAS_CONST(_Tuple) \
+ GMOCK_PP_HAS_COMMA(GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_DETECT_CONST, ~, _Tuple))
+
+#define GMOCK_INTERNAL_HAS_OVERRIDE(_Tuple) \
+ GMOCK_PP_HAS_COMMA( \
+ GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_DETECT_OVERRIDE, ~, _Tuple))
+
+#define GMOCK_INTERNAL_HAS_FINAL(_Tuple) \
+ GMOCK_PP_HAS_COMMA(GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_DETECT_FINAL, ~, _Tuple))
+
+#define GMOCK_INTERNAL_HAS_NOEXCEPT(_Tuple) \
+ GMOCK_PP_HAS_COMMA( \
+ GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_DETECT_NOEXCEPT, ~, _Tuple))
+
+#define GMOCK_INTERNAL_GET_CALLTYPE(_Tuple) \
+ GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_GET_CALLTYPE_IMPL, ~, _Tuple)
+
+#define GMOCK_INTERNAL_ASSERT_VALID_SPEC_ELEMENT(_i, _, _elem) \
+ static_assert( \
+ (GMOCK_PP_HAS_COMMA(GMOCK_INTERNAL_DETECT_CONST(_i, _, _elem)) + \
+ GMOCK_PP_HAS_COMMA(GMOCK_INTERNAL_DETECT_OVERRIDE(_i, _, _elem)) + \
+ GMOCK_PP_HAS_COMMA(GMOCK_INTERNAL_DETECT_FINAL(_i, _, _elem)) + \
+ GMOCK_PP_HAS_COMMA(GMOCK_INTERNAL_DETECT_NOEXCEPT(_i, _, _elem)) + \
+ GMOCK_INTERNAL_IS_CALLTYPE(_elem)) == 1, \
+ GMOCK_PP_STRINGIZE( \
+ _elem) " cannot be recognized as a valid specification modifier.");
+
+// Modifiers implementation.
+#define GMOCK_INTERNAL_DETECT_CONST(_i, _, _elem) \
+ GMOCK_PP_CAT(GMOCK_INTERNAL_DETECT_CONST_I_, _elem)
+
+#define GMOCK_INTERNAL_DETECT_CONST_I_const ,
+
+#define GMOCK_INTERNAL_DETECT_OVERRIDE(_i, _, _elem) \
+ GMOCK_PP_CAT(GMOCK_INTERNAL_DETECT_OVERRIDE_I_, _elem)
+
+#define GMOCK_INTERNAL_DETECT_OVERRIDE_I_override ,
+
+#define GMOCK_INTERNAL_DETECT_FINAL(_i, _, _elem) \
+ GMOCK_PP_CAT(GMOCK_INTERNAL_DETECT_FINAL_I_, _elem)
+
+#define GMOCK_INTERNAL_DETECT_FINAL_I_final ,
+
+// TODO(iserna): Maybe noexcept should accept an argument here as well.
+#define GMOCK_INTERNAL_DETECT_NOEXCEPT(_i, _, _elem) \
+ GMOCK_PP_CAT(GMOCK_INTERNAL_DETECT_NOEXCEPT_I_, _elem)
+
+#define GMOCK_INTERNAL_DETECT_NOEXCEPT_I_noexcept ,
+
+#define GMOCK_INTERNAL_GET_CALLTYPE_IMPL(_i, _, _elem) \
+ GMOCK_PP_IF(GMOCK_INTERNAL_IS_CALLTYPE(_elem), \
+ GMOCK_INTERNAL_GET_VALUE_CALLTYPE, GMOCK_PP_EMPTY) \
+ (_elem)
+
+// TODO(iserna): GMOCK_INTERNAL_IS_CALLTYPE and
+// GMOCK_INTERNAL_GET_VALUE_CALLTYPE needed more expansions to work on windows
+// maybe they can be simplified somehow.
+#define GMOCK_INTERNAL_IS_CALLTYPE(_arg) \
+ GMOCK_INTERNAL_IS_CALLTYPE_I( \
+ GMOCK_PP_CAT(GMOCK_INTERNAL_IS_CALLTYPE_HELPER_, _arg))
+#define GMOCK_INTERNAL_IS_CALLTYPE_I(_arg) GMOCK_PP_IS_ENCLOSED_PARENS(_arg)
+
+#define GMOCK_INTERNAL_GET_VALUE_CALLTYPE(_arg) \
+ GMOCK_INTERNAL_GET_VALUE_CALLTYPE_I( \
+ GMOCK_PP_CAT(GMOCK_INTERNAL_IS_CALLTYPE_HELPER_, _arg))
+#define GMOCK_INTERNAL_GET_VALUE_CALLTYPE_I(_arg) \
+ GMOCK_PP_CAT(GMOCK_PP_IDENTITY, _arg)
+
+#define GMOCK_INTERNAL_IS_CALLTYPE_HELPER_Calltype
+
+#define GMOCK_INTERNAL_SIGNATURE(_Ret, _Args) \
+ GMOCK_PP_IF(GMOCK_PP_IS_BEGIN_PARENS(_Ret), GMOCK_PP_REMOVE_PARENS, \
+ GMOCK_PP_IDENTITY) \
+ (_Ret)(GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_GET_TYPE, _, _Args))
+
+#define GMOCK_INTERNAL_GET_TYPE(_i, _, _elem) \
+ GMOCK_PP_COMMA_IF(_i) \
+ GMOCK_PP_IF(GMOCK_PP_IS_BEGIN_PARENS(_elem), GMOCK_PP_REMOVE_PARENS, \
+ GMOCK_PP_IDENTITY) \
+ (_elem)
+
+#define GMOCK_INTERNAL_PARAMETER(_i, _Signature, _) \
+ GMOCK_PP_COMMA_IF(_i) \
+ GMOCK_INTERNAL_ARG_O(typename, GMOCK_PP_INC(_i), \
+ GMOCK_PP_REMOVE_PARENS(_Signature)) \
+ gmock_a##_i
+
+#define GMOCK_INTERNAL_FORWARD_ARG(_i, _Signature, _) \
+ GMOCK_PP_COMMA_IF(_i) \
+ ::std::forward<GMOCK_INTERNAL_ARG_O(typename, GMOCK_PP_INC(_i), \
+ GMOCK_PP_REMOVE_PARENS(_Signature))>( \
+ gmock_a##_i)
+
+#define GMOCK_INTERNAL_MATCHER_PARAMETER(_i, _Signature, _) \
+ GMOCK_PP_COMMA_IF(_i) \
+ GMOCK_INTERNAL_MATCHER_O(typename, GMOCK_PP_INC(_i), \
+ GMOCK_PP_REMOVE_PARENS(_Signature)) \
+ gmock_a##_i
+
+#define GMOCK_INTERNAL_MATCHER_ARGUMENT(_i, _1, _2) \
+ GMOCK_PP_COMMA_IF(_i) \
+ gmock_a##_i
+
+#define GMOCK_INTERNAL_A_MATCHER_ARGUMENT(_i, _Signature, _) \
+ GMOCK_PP_COMMA_IF(_i) \
+ ::testing::A<GMOCK_INTERNAL_ARG_O(typename, GMOCK_PP_INC(_i), \
+ GMOCK_PP_REMOVE_PARENS(_Signature))>()
+
+#define GMOCK_INTERNAL_ARG_O(_tn, _i, ...) GMOCK_ARG_(_tn, _i, __VA_ARGS__)
+
+#define GMOCK_INTERNAL_MATCHER_O(_tn, _i, ...) \
+ GMOCK_MATCHER_(_tn, _i, __VA_ARGS__)
+
+#endif // THIRD_PARTY_GOOGLETEST_GOOGLEMOCK_INCLUDE_GMOCK_INTERNAL_GMOCK_FUNCTION_MOCKER_H_
diff --git a/extern/gmock/include/gmock/gmock-generated-actions.h b/extern/gmock/include/gmock/gmock-generated-actions.h
index b5a889c0c3a..981af78ff9a 100644
--- a/extern/gmock/include/gmock/gmock-generated-actions.h
+++ b/extern/gmock/include/gmock/gmock-generated-actions.h
@@ -1,4 +1,6 @@
-// This file was GENERATED by a script. DO NOT EDIT BY HAND!!!
+// This file was GENERATED by command:
+// pump.py gmock-generated-actions.h.pump
+// DO NOT EDIT BY HAND!!!
// Copyright 2007, Google Inc.
// All rights reserved.
@@ -28,469 +30,26 @@
// 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.
-//
-// Author: wan@google.com (Zhanyong Wan)
+
// Google Mock - a framework for writing C++ mock classes.
//
// This file implements some commonly used variadic actions.
+// GOOGLETEST_CM0002 DO NOT DELETE
+
#ifndef GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_ACTIONS_H_
#define GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_ACTIONS_H_
+#include <memory>
+#include <utility>
+
#include "gmock/gmock-actions.h"
#include "gmock/internal/gmock-port.h"
namespace testing {
namespace internal {
-// InvokeHelper<F> knows how to unpack an N-tuple and invoke an N-ary
-// function or method with the unpacked values, where F is a function
-// type that takes N arguments.
-template <typename Result, typename ArgumentTuple>
-class InvokeHelper;
-
-template <typename R>
-class InvokeHelper<R, ::testing::tuple<> > {
- public:
- template <typename Function>
- static R Invoke(Function function, const ::testing::tuple<>&) {
- return function();
- }
-
- template <class Class, typename MethodPtr>
- static R InvokeMethod(Class* obj_ptr,
- MethodPtr method_ptr,
- const ::testing::tuple<>&) {
- return (obj_ptr->*method_ptr)();
- }
-};
-
-template <typename R, typename A1>
-class InvokeHelper<R, ::testing::tuple<A1> > {
- public:
- template <typename Function>
- static R Invoke(Function function, const ::testing::tuple<A1>& args) {
- return function(get<0>(args));
- }
-
- template <class Class, typename MethodPtr>
- static R InvokeMethod(Class* obj_ptr,
- MethodPtr method_ptr,
- const ::testing::tuple<A1>& args) {
- return (obj_ptr->*method_ptr)(get<0>(args));
- }
-};
-
-template <typename R, typename A1, typename A2>
-class InvokeHelper<R, ::testing::tuple<A1, A2> > {
- public:
- template <typename Function>
- static R Invoke(Function function, const ::testing::tuple<A1, A2>& args) {
- return function(get<0>(args), get<1>(args));
- }
-
- template <class Class, typename MethodPtr>
- static R InvokeMethod(Class* obj_ptr,
- MethodPtr method_ptr,
- const ::testing::tuple<A1, A2>& args) {
- return (obj_ptr->*method_ptr)(get<0>(args), get<1>(args));
- }
-};
-
-template <typename R, typename A1, typename A2, typename A3>
-class InvokeHelper<R, ::testing::tuple<A1, A2, A3> > {
- public:
- template <typename Function>
- static R Invoke(Function function, const ::testing::tuple<A1, A2, A3>& args) {
- return function(get<0>(args), get<1>(args), get<2>(args));
- }
-
- template <class Class, typename MethodPtr>
- static R InvokeMethod(Class* obj_ptr,
- MethodPtr method_ptr,
- const ::testing::tuple<A1, A2, A3>& args) {
- return (obj_ptr->*method_ptr)(get<0>(args), get<1>(args),
- get<2>(args));
- }
-};
-
-template <typename R, typename A1, typename A2, typename A3, typename A4>
-class InvokeHelper<R, ::testing::tuple<A1, A2, A3, A4> > {
- public:
- template <typename Function>
- static R Invoke(Function function, const ::testing::tuple<A1, A2, A3,
- A4>& args) {
- return function(get<0>(args), get<1>(args), get<2>(args),
- get<3>(args));
- }
-
- template <class Class, typename MethodPtr>
- static R InvokeMethod(Class* obj_ptr,
- MethodPtr method_ptr,
- const ::testing::tuple<A1, A2, A3, A4>& args) {
- return (obj_ptr->*method_ptr)(get<0>(args), get<1>(args),
- get<2>(args), get<3>(args));
- }
-};
-
-template <typename R, typename A1, typename A2, typename A3, typename A4,
- typename A5>
-class InvokeHelper<R, ::testing::tuple<A1, A2, A3, A4, A5> > {
- public:
- template <typename Function>
- static R Invoke(Function function, const ::testing::tuple<A1, A2, A3, A4,
- A5>& args) {
- return function(get<0>(args), get<1>(args), get<2>(args),
- get<3>(args), get<4>(args));
- }
-
- template <class Class, typename MethodPtr>
- static R InvokeMethod(Class* obj_ptr,
- MethodPtr method_ptr,
- const ::testing::tuple<A1, A2, A3, A4, A5>& args) {
- return (obj_ptr->*method_ptr)(get<0>(args), get<1>(args),
- get<2>(args), get<3>(args), get<4>(args));
- }
-};
-
-template <typename R, typename A1, typename A2, typename A3, typename A4,
- typename A5, typename A6>
-class InvokeHelper<R, ::testing::tuple<A1, A2, A3, A4, A5, A6> > {
- public:
- template <typename Function>
- static R Invoke(Function function, const ::testing::tuple<A1, A2, A3, A4, A5,
- A6>& args) {
- return function(get<0>(args), get<1>(args), get<2>(args),
- get<3>(args), get<4>(args), get<5>(args));
- }
-
- template <class Class, typename MethodPtr>
- static R InvokeMethod(Class* obj_ptr,
- MethodPtr method_ptr,
- const ::testing::tuple<A1, A2, A3, A4, A5, A6>& args) {
- return (obj_ptr->*method_ptr)(get<0>(args), get<1>(args),
- get<2>(args), get<3>(args), get<4>(args), get<5>(args));
- }
-};
-
-template <typename R, typename A1, typename A2, typename A3, typename A4,
- typename A5, typename A6, typename A7>
-class InvokeHelper<R, ::testing::tuple<A1, A2, A3, A4, A5, A6, A7> > {
- public:
- template <typename Function>
- static R Invoke(Function function, const ::testing::tuple<A1, A2, A3, A4, A5,
- A6, A7>& args) {
- return function(get<0>(args), get<1>(args), get<2>(args),
- get<3>(args), get<4>(args), get<5>(args), get<6>(args));
- }
-
- template <class Class, typename MethodPtr>
- static R InvokeMethod(Class* obj_ptr,
- MethodPtr method_ptr,
- const ::testing::tuple<A1, A2, A3, A4, A5, A6,
- A7>& args) {
- return (obj_ptr->*method_ptr)(get<0>(args), get<1>(args),
- get<2>(args), get<3>(args), get<4>(args), get<5>(args),
- get<6>(args));
- }
-};
-
-template <typename R, typename A1, typename A2, typename A3, typename A4,
- typename A5, typename A6, typename A7, typename A8>
-class InvokeHelper<R, ::testing::tuple<A1, A2, A3, A4, A5, A6, A7, A8> > {
- public:
- template <typename Function>
- static R Invoke(Function function, const ::testing::tuple<A1, A2, A3, A4, A5,
- A6, A7, A8>& args) {
- return function(get<0>(args), get<1>(args), get<2>(args),
- get<3>(args), get<4>(args), get<5>(args), get<6>(args),
- get<7>(args));
- }
-
- template <class Class, typename MethodPtr>
- static R InvokeMethod(Class* obj_ptr,
- MethodPtr method_ptr,
- const ::testing::tuple<A1, A2, A3, A4, A5, A6, A7,
- A8>& args) {
- return (obj_ptr->*method_ptr)(get<0>(args), get<1>(args),
- get<2>(args), get<3>(args), get<4>(args), get<5>(args),
- get<6>(args), get<7>(args));
- }
-};
-
-template <typename R, typename A1, typename A2, typename A3, typename A4,
- typename A5, typename A6, typename A7, typename A8, typename A9>
-class InvokeHelper<R, ::testing::tuple<A1, A2, A3, A4, A5, A6, A7, A8, A9> > {
- public:
- template <typename Function>
- static R Invoke(Function function, const ::testing::tuple<A1, A2, A3, A4, A5,
- A6, A7, A8, A9>& args) {
- return function(get<0>(args), get<1>(args), get<2>(args),
- get<3>(args), get<4>(args), get<5>(args), get<6>(args),
- get<7>(args), get<8>(args));
- }
-
- template <class Class, typename MethodPtr>
- static R InvokeMethod(Class* obj_ptr,
- MethodPtr method_ptr,
- const ::testing::tuple<A1, A2, A3, A4, A5, A6, A7, A8,
- A9>& args) {
- return (obj_ptr->*method_ptr)(get<0>(args), get<1>(args),
- get<2>(args), get<3>(args), get<4>(args), get<5>(args),
- get<6>(args), get<7>(args), get<8>(args));
- }
-};
-
-template <typename R, typename A1, typename A2, typename A3, typename A4,
- typename A5, typename A6, typename A7, typename A8, typename A9,
- typename A10>
-class InvokeHelper<R, ::testing::tuple<A1, A2, A3, A4, A5, A6, A7, A8, A9,
- A10> > {
- public:
- template <typename Function>
- static R Invoke(Function function, const ::testing::tuple<A1, A2, A3, A4, A5,
- A6, A7, A8, A9, A10>& args) {
- return function(get<0>(args), get<1>(args), get<2>(args),
- get<3>(args), get<4>(args), get<5>(args), get<6>(args),
- get<7>(args), get<8>(args), get<9>(args));
- }
-
- template <class Class, typename MethodPtr>
- static R InvokeMethod(Class* obj_ptr,
- MethodPtr method_ptr,
- const ::testing::tuple<A1, A2, A3, A4, A5, A6, A7, A8,
- A9, A10>& args) {
- return (obj_ptr->*method_ptr)(get<0>(args), get<1>(args),
- get<2>(args), get<3>(args), get<4>(args), get<5>(args),
- get<6>(args), get<7>(args), get<8>(args), get<9>(args));
- }
-};
-
-// An INTERNAL macro for extracting the type of a tuple field. It's
-// subject to change without notice - DO NOT USE IN USER CODE!
-#define GMOCK_FIELD_(Tuple, N) \
- typename ::testing::tuple_element<N, Tuple>::type
-
-// SelectArgs<Result, ArgumentTuple, k1, k2, ..., k_n>::type is the
-// type of an n-ary function whose i-th (1-based) argument type is the
-// k{i}-th (0-based) field of ArgumentTuple, which must be a tuple
-// type, and whose return type is Result. For example,
-// SelectArgs<int, ::testing::tuple<bool, char, double, long>, 0, 3>::type
-// is int(bool, long).
-//
-// SelectArgs<Result, ArgumentTuple, k1, k2, ..., k_n>::Select(args)
-// returns the selected fields (k1, k2, ..., k_n) of args as a tuple.
-// For example,
-// SelectArgs<int, tuple<bool, char, double>, 2, 0>::Select(
-// ::testing::make_tuple(true, 'a', 2.5))
-// returns tuple (2.5, true).
-//
-// The numbers in list k1, k2, ..., k_n must be >= 0, where n can be
-// in the range [0, 10]. Duplicates are allowed and they don't have
-// to be in an ascending or descending order.
-
-template <typename Result, typename ArgumentTuple, int k1, int k2, int k3,
- int k4, int k5, int k6, int k7, int k8, int k9, int k10>
-class SelectArgs {
- public:
- typedef Result type(GMOCK_FIELD_(ArgumentTuple, k1),
- GMOCK_FIELD_(ArgumentTuple, k2), GMOCK_FIELD_(ArgumentTuple, k3),
- GMOCK_FIELD_(ArgumentTuple, k4), GMOCK_FIELD_(ArgumentTuple, k5),
- GMOCK_FIELD_(ArgumentTuple, k6), GMOCK_FIELD_(ArgumentTuple, k7),
- GMOCK_FIELD_(ArgumentTuple, k8), GMOCK_FIELD_(ArgumentTuple, k9),
- GMOCK_FIELD_(ArgumentTuple, k10));
- typedef typename Function<type>::ArgumentTuple SelectedArgs;
- static SelectedArgs Select(const ArgumentTuple& args) {
- return SelectedArgs(get<k1>(args), get<k2>(args), get<k3>(args),
- get<k4>(args), get<k5>(args), get<k6>(args), get<k7>(args),
- get<k8>(args), get<k9>(args), get<k10>(args));
- }
-};
-
-template <typename Result, typename ArgumentTuple>
-class SelectArgs<Result, ArgumentTuple,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1> {
- public:
- typedef Result type();
- typedef typename Function<type>::ArgumentTuple SelectedArgs;
- static SelectedArgs Select(const ArgumentTuple& /* args */) {
- return SelectedArgs();
- }
-};
-
-template <typename Result, typename ArgumentTuple, int k1>
-class SelectArgs<Result, ArgumentTuple,
- k1, -1, -1, -1, -1, -1, -1, -1, -1, -1> {
- public:
- typedef Result type(GMOCK_FIELD_(ArgumentTuple, k1));
- typedef typename Function<type>::ArgumentTuple SelectedArgs;
- static SelectedArgs Select(const ArgumentTuple& args) {
- return SelectedArgs(get<k1>(args));
- }
-};
-
-template <typename Result, typename ArgumentTuple, int k1, int k2>
-class SelectArgs<Result, ArgumentTuple,
- k1, k2, -1, -1, -1, -1, -1, -1, -1, -1> {
- public:
- typedef Result type(GMOCK_FIELD_(ArgumentTuple, k1),
- GMOCK_FIELD_(ArgumentTuple, k2));
- typedef typename Function<type>::ArgumentTuple SelectedArgs;
- static SelectedArgs Select(const ArgumentTuple& args) {
- return SelectedArgs(get<k1>(args), get<k2>(args));
- }
-};
-
-template <typename Result, typename ArgumentTuple, int k1, int k2, int k3>
-class SelectArgs<Result, ArgumentTuple,
- k1, k2, k3, -1, -1, -1, -1, -1, -1, -1> {
- public:
- typedef Result type(GMOCK_FIELD_(ArgumentTuple, k1),
- GMOCK_FIELD_(ArgumentTuple, k2), GMOCK_FIELD_(ArgumentTuple, k3));
- typedef typename Function<type>::ArgumentTuple SelectedArgs;
- static SelectedArgs Select(const ArgumentTuple& args) {
- return SelectedArgs(get<k1>(args), get<k2>(args), get<k3>(args));
- }
-};
-
-template <typename Result, typename ArgumentTuple, int k1, int k2, int k3,
- int k4>
-class SelectArgs<Result, ArgumentTuple,
- k1, k2, k3, k4, -1, -1, -1, -1, -1, -1> {
- public:
- typedef Result type(GMOCK_FIELD_(ArgumentTuple, k1),
- GMOCK_FIELD_(ArgumentTuple, k2), GMOCK_FIELD_(ArgumentTuple, k3),
- GMOCK_FIELD_(ArgumentTuple, k4));
- typedef typename Function<type>::ArgumentTuple SelectedArgs;
- static SelectedArgs Select(const ArgumentTuple& args) {
- return SelectedArgs(get<k1>(args), get<k2>(args), get<k3>(args),
- get<k4>(args));
- }
-};
-
-template <typename Result, typename ArgumentTuple, int k1, int k2, int k3,
- int k4, int k5>
-class SelectArgs<Result, ArgumentTuple,
- k1, k2, k3, k4, k5, -1, -1, -1, -1, -1> {
- public:
- typedef Result type(GMOCK_FIELD_(ArgumentTuple, k1),
- GMOCK_FIELD_(ArgumentTuple, k2), GMOCK_FIELD_(ArgumentTuple, k3),
- GMOCK_FIELD_(ArgumentTuple, k4), GMOCK_FIELD_(ArgumentTuple, k5));
- typedef typename Function<type>::ArgumentTuple SelectedArgs;
- static SelectedArgs Select(const ArgumentTuple& args) {
- return SelectedArgs(get<k1>(args), get<k2>(args), get<k3>(args),
- get<k4>(args), get<k5>(args));
- }
-};
-
-template <typename Result, typename ArgumentTuple, int k1, int k2, int k3,
- int k4, int k5, int k6>
-class SelectArgs<Result, ArgumentTuple,
- k1, k2, k3, k4, k5, k6, -1, -1, -1, -1> {
- public:
- typedef Result type(GMOCK_FIELD_(ArgumentTuple, k1),
- GMOCK_FIELD_(ArgumentTuple, k2), GMOCK_FIELD_(ArgumentTuple, k3),
- GMOCK_FIELD_(ArgumentTuple, k4), GMOCK_FIELD_(ArgumentTuple, k5),
- GMOCK_FIELD_(ArgumentTuple, k6));
- typedef typename Function<type>::ArgumentTuple SelectedArgs;
- static SelectedArgs Select(const ArgumentTuple& args) {
- return SelectedArgs(get<k1>(args), get<k2>(args), get<k3>(args),
- get<k4>(args), get<k5>(args), get<k6>(args));
- }
-};
-
-template <typename Result, typename ArgumentTuple, int k1, int k2, int k3,
- int k4, int k5, int k6, int k7>
-class SelectArgs<Result, ArgumentTuple,
- k1, k2, k3, k4, k5, k6, k7, -1, -1, -1> {
- public:
- typedef Result type(GMOCK_FIELD_(ArgumentTuple, k1),
- GMOCK_FIELD_(ArgumentTuple, k2), GMOCK_FIELD_(ArgumentTuple, k3),
- GMOCK_FIELD_(ArgumentTuple, k4), GMOCK_FIELD_(ArgumentTuple, k5),
- GMOCK_FIELD_(ArgumentTuple, k6), GMOCK_FIELD_(ArgumentTuple, k7));
- typedef typename Function<type>::ArgumentTuple SelectedArgs;
- static SelectedArgs Select(const ArgumentTuple& args) {
- return SelectedArgs(get<k1>(args), get<k2>(args), get<k3>(args),
- get<k4>(args), get<k5>(args), get<k6>(args), get<k7>(args));
- }
-};
-
-template <typename Result, typename ArgumentTuple, int k1, int k2, int k3,
- int k4, int k5, int k6, int k7, int k8>
-class SelectArgs<Result, ArgumentTuple,
- k1, k2, k3, k4, k5, k6, k7, k8, -1, -1> {
- public:
- typedef Result type(GMOCK_FIELD_(ArgumentTuple, k1),
- GMOCK_FIELD_(ArgumentTuple, k2), GMOCK_FIELD_(ArgumentTuple, k3),
- GMOCK_FIELD_(ArgumentTuple, k4), GMOCK_FIELD_(ArgumentTuple, k5),
- GMOCK_FIELD_(ArgumentTuple, k6), GMOCK_FIELD_(ArgumentTuple, k7),
- GMOCK_FIELD_(ArgumentTuple, k8));
- typedef typename Function<type>::ArgumentTuple SelectedArgs;
- static SelectedArgs Select(const ArgumentTuple& args) {
- return SelectedArgs(get<k1>(args), get<k2>(args), get<k3>(args),
- get<k4>(args), get<k5>(args), get<k6>(args), get<k7>(args),
- get<k8>(args));
- }
-};
-
-template <typename Result, typename ArgumentTuple, int k1, int k2, int k3,
- int k4, int k5, int k6, int k7, int k8, int k9>
-class SelectArgs<Result, ArgumentTuple,
- k1, k2, k3, k4, k5, k6, k7, k8, k9, -1> {
- public:
- typedef Result type(GMOCK_FIELD_(ArgumentTuple, k1),
- GMOCK_FIELD_(ArgumentTuple, k2), GMOCK_FIELD_(ArgumentTuple, k3),
- GMOCK_FIELD_(ArgumentTuple, k4), GMOCK_FIELD_(ArgumentTuple, k5),
- GMOCK_FIELD_(ArgumentTuple, k6), GMOCK_FIELD_(ArgumentTuple, k7),
- GMOCK_FIELD_(ArgumentTuple, k8), GMOCK_FIELD_(ArgumentTuple, k9));
- typedef typename Function<type>::ArgumentTuple SelectedArgs;
- static SelectedArgs Select(const ArgumentTuple& args) {
- return SelectedArgs(get<k1>(args), get<k2>(args), get<k3>(args),
- get<k4>(args), get<k5>(args), get<k6>(args), get<k7>(args),
- get<k8>(args), get<k9>(args));
- }
-};
-
-#undef GMOCK_FIELD_
-
-// Implements the WithArgs action.
-template <typename InnerAction, int k1 = -1, int k2 = -1, int k3 = -1,
- int k4 = -1, int k5 = -1, int k6 = -1, int k7 = -1, int k8 = -1,
- int k9 = -1, int k10 = -1>
-class WithArgsAction {
- public:
- explicit WithArgsAction(const InnerAction& action) : action_(action) {}
-
- template <typename F>
- operator Action<F>() const { return MakeAction(new Impl<F>(action_)); }
-
- private:
- template <typename F>
- class Impl : public ActionInterface<F> {
- public:
- typedef typename Function<F>::Result Result;
- typedef typename Function<F>::ArgumentTuple ArgumentTuple;
-
- explicit Impl(const InnerAction& action) : action_(action) {}
-
- virtual Result Perform(const ArgumentTuple& args) {
- return action_.Perform(SelectArgs<Result, ArgumentTuple, k1, k2, k3, k4,
- k5, k6, k7, k8, k9, k10>::Select(args));
- }
-
- private:
- typedef typename SelectArgs<Result, ArgumentTuple,
- k1, k2, k3, k4, k5, k6, k7, k8, k9, k10>::type InnerFunctionType;
-
- Action<InnerFunctionType> action_;
- };
-
- const InnerAction action_;
-
- GTEST_DISALLOW_ASSIGN_(WithArgsAction);
-};
-
// A macro from the ACTION* family (defined later in this file)
// defines an action that can be used in a mock function. Typically,
// these actions only care about a subset of the arguments of the mock
@@ -511,7 +70,7 @@ struct ExcessiveArg {};
template <typename Result, class Impl>
class ActionHelper {
public:
- static Result Perform(Impl* impl, const ::testing::tuple<>& args) {
+ static Result Perform(Impl* impl, const ::std::tuple<>& args) {
return impl->template gmock_PerformImpl<>(args, ExcessiveArg(),
ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(),
ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(),
@@ -519,266 +78,100 @@ class ActionHelper {
}
template <typename A0>
- static Result Perform(Impl* impl, const ::testing::tuple<A0>& args) {
- return impl->template gmock_PerformImpl<A0>(args, get<0>(args),
+ static Result Perform(Impl* impl, const ::std::tuple<A0>& args) {
+ return impl->template gmock_PerformImpl<A0>(args, std::get<0>(args),
ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(),
ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(),
ExcessiveArg());
}
template <typename A0, typename A1>
- static Result Perform(Impl* impl, const ::testing::tuple<A0, A1>& args) {
- return impl->template gmock_PerformImpl<A0, A1>(args, get<0>(args),
- get<1>(args), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(),
+ static Result Perform(Impl* impl, const ::std::tuple<A0, A1>& args) {
+ return impl->template gmock_PerformImpl<A0, A1>(args, std::get<0>(args),
+ std::get<1>(args), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(),
ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(),
ExcessiveArg());
}
template <typename A0, typename A1, typename A2>
- static Result Perform(Impl* impl, const ::testing::tuple<A0, A1, A2>& args) {
- return impl->template gmock_PerformImpl<A0, A1, A2>(args, get<0>(args),
- get<1>(args), get<2>(args), ExcessiveArg(), ExcessiveArg(),
+ static Result Perform(Impl* impl, const ::std::tuple<A0, A1, A2>& args) {
+ return impl->template gmock_PerformImpl<A0, A1, A2>(args,
+ std::get<0>(args), std::get<1>(args), std::get<2>(args),
ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(),
- ExcessiveArg());
+ ExcessiveArg(), ExcessiveArg(), ExcessiveArg());
}
template <typename A0, typename A1, typename A2, typename A3>
- static Result Perform(Impl* impl, const ::testing::tuple<A0, A1, A2,
- A3>& args) {
- return impl->template gmock_PerformImpl<A0, A1, A2, A3>(args, get<0>(args),
- get<1>(args), get<2>(args), get<3>(args), ExcessiveArg(),
- ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(),
- ExcessiveArg());
+ static Result Perform(Impl* impl, const ::std::tuple<A0, A1, A2, A3>& args) {
+ return impl->template gmock_PerformImpl<A0, A1, A2, A3>(args,
+ std::get<0>(args), std::get<1>(args), std::get<2>(args),
+ std::get<3>(args), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(),
+ ExcessiveArg(), ExcessiveArg(), ExcessiveArg());
}
template <typename A0, typename A1, typename A2, typename A3, typename A4>
- static Result Perform(Impl* impl, const ::testing::tuple<A0, A1, A2, A3,
+ static Result Perform(Impl* impl, const ::std::tuple<A0, A1, A2, A3,
A4>& args) {
return impl->template gmock_PerformImpl<A0, A1, A2, A3, A4>(args,
- get<0>(args), get<1>(args), get<2>(args), get<3>(args), get<4>(args),
- ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(),
- ExcessiveArg());
+ std::get<0>(args), std::get<1>(args), std::get<2>(args),
+ std::get<3>(args), std::get<4>(args), ExcessiveArg(), ExcessiveArg(),
+ ExcessiveArg(), ExcessiveArg(), ExcessiveArg());
}
template <typename A0, typename A1, typename A2, typename A3, typename A4,
typename A5>
- static Result Perform(Impl* impl, const ::testing::tuple<A0, A1, A2, A3, A4,
+ static Result Perform(Impl* impl, const ::std::tuple<A0, A1, A2, A3, A4,
A5>& args) {
return impl->template gmock_PerformImpl<A0, A1, A2, A3, A4, A5>(args,
- get<0>(args), get<1>(args), get<2>(args), get<3>(args), get<4>(args),
- get<5>(args), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(),
- ExcessiveArg());
+ std::get<0>(args), std::get<1>(args), std::get<2>(args),
+ std::get<3>(args), std::get<4>(args), std::get<5>(args),
+ ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg());
}
template <typename A0, typename A1, typename A2, typename A3, typename A4,
typename A5, typename A6>
- static Result Perform(Impl* impl, const ::testing::tuple<A0, A1, A2, A3, A4,
- A5, A6>& args) {
+ static Result Perform(Impl* impl, const ::std::tuple<A0, A1, A2, A3, A4, A5,
+ A6>& args) {
return impl->template gmock_PerformImpl<A0, A1, A2, A3, A4, A5, A6>(args,
- get<0>(args), get<1>(args), get<2>(args), get<3>(args), get<4>(args),
- get<5>(args), get<6>(args), ExcessiveArg(), ExcessiveArg(),
- ExcessiveArg());
+ std::get<0>(args), std::get<1>(args), std::get<2>(args),
+ std::get<3>(args), std::get<4>(args), std::get<5>(args),
+ std::get<6>(args), ExcessiveArg(), ExcessiveArg(), ExcessiveArg());
}
template <typename A0, typename A1, typename A2, typename A3, typename A4,
typename A5, typename A6, typename A7>
- static Result Perform(Impl* impl, const ::testing::tuple<A0, A1, A2, A3, A4,
- A5, A6, A7>& args) {
+ static Result Perform(Impl* impl, const ::std::tuple<A0, A1, A2, A3, A4, A5,
+ A6, A7>& args) {
return impl->template gmock_PerformImpl<A0, A1, A2, A3, A4, A5, A6,
- A7>(args, get<0>(args), get<1>(args), get<2>(args), get<3>(args),
- get<4>(args), get<5>(args), get<6>(args), get<7>(args), ExcessiveArg(),
- ExcessiveArg());
+ A7>(args, std::get<0>(args), std::get<1>(args), std::get<2>(args),
+ std::get<3>(args), std::get<4>(args), std::get<5>(args),
+ std::get<6>(args), std::get<7>(args), ExcessiveArg(), ExcessiveArg());
}
template <typename A0, typename A1, typename A2, typename A3, typename A4,
typename A5, typename A6, typename A7, typename A8>
- static Result Perform(Impl* impl, const ::testing::tuple<A0, A1, A2, A3, A4,
- A5, A6, A7, A8>& args) {
+ static Result Perform(Impl* impl, const ::std::tuple<A0, A1, A2, A3, A4, A5,
+ A6, A7, A8>& args) {
return impl->template gmock_PerformImpl<A0, A1, A2, A3, A4, A5, A6, A7,
- A8>(args, get<0>(args), get<1>(args), get<2>(args), get<3>(args),
- get<4>(args), get<5>(args), get<6>(args), get<7>(args), get<8>(args),
+ A8>(args, std::get<0>(args), std::get<1>(args), std::get<2>(args),
+ std::get<3>(args), std::get<4>(args), std::get<5>(args),
+ std::get<6>(args), std::get<7>(args), std::get<8>(args),
ExcessiveArg());
}
template <typename A0, typename A1, typename A2, typename A3, typename A4,
typename A5, typename A6, typename A7, typename A8, typename A9>
- static Result Perform(Impl* impl, const ::testing::tuple<A0, A1, A2, A3, A4,
- A5, A6, A7, A8, A9>& args) {
+ static Result Perform(Impl* impl, const ::std::tuple<A0, A1, A2, A3, A4, A5,
+ A6, A7, A8, A9>& args) {
return impl->template gmock_PerformImpl<A0, A1, A2, A3, A4, A5, A6, A7, A8,
- A9>(args, get<0>(args), get<1>(args), get<2>(args), get<3>(args),
- get<4>(args), get<5>(args), get<6>(args), get<7>(args), get<8>(args),
- get<9>(args));
+ A9>(args, std::get<0>(args), std::get<1>(args), std::get<2>(args),
+ std::get<3>(args), std::get<4>(args), std::get<5>(args),
+ std::get<6>(args), std::get<7>(args), std::get<8>(args),
+ std::get<9>(args));
}
};
} // namespace internal
-
-// Various overloads for Invoke().
-
-// WithArgs<N1, N2, ..., Nk>(an_action) creates an action that passes
-// the selected arguments of the mock function to an_action and
-// performs it. It serves as an adaptor between actions with
-// different argument lists. C++ doesn't support default arguments for
-// function templates, so we have to overload it.
-template <int k1, typename InnerAction>
-inline internal::WithArgsAction<InnerAction, k1>
-WithArgs(const InnerAction& action) {
- return internal::WithArgsAction<InnerAction, k1>(action);
-}
-
-template <int k1, int k2, typename InnerAction>
-inline internal::WithArgsAction<InnerAction, k1, k2>
-WithArgs(const InnerAction& action) {
- return internal::WithArgsAction<InnerAction, k1, k2>(action);
-}
-
-template <int k1, int k2, int k3, typename InnerAction>
-inline internal::WithArgsAction<InnerAction, k1, k2, k3>
-WithArgs(const InnerAction& action) {
- return internal::WithArgsAction<InnerAction, k1, k2, k3>(action);
-}
-
-template <int k1, int k2, int k3, int k4, typename InnerAction>
-inline internal::WithArgsAction<InnerAction, k1, k2, k3, k4>
-WithArgs(const InnerAction& action) {
- return internal::WithArgsAction<InnerAction, k1, k2, k3, k4>(action);
-}
-
-template <int k1, int k2, int k3, int k4, int k5, typename InnerAction>
-inline internal::WithArgsAction<InnerAction, k1, k2, k3, k4, k5>
-WithArgs(const InnerAction& action) {
- return internal::WithArgsAction<InnerAction, k1, k2, k3, k4, k5>(action);
-}
-
-template <int k1, int k2, int k3, int k4, int k5, int k6, typename InnerAction>
-inline internal::WithArgsAction<InnerAction, k1, k2, k3, k4, k5, k6>
-WithArgs(const InnerAction& action) {
- return internal::WithArgsAction<InnerAction, k1, k2, k3, k4, k5, k6>(action);
-}
-
-template <int k1, int k2, int k3, int k4, int k5, int k6, int k7,
- typename InnerAction>
-inline internal::WithArgsAction<InnerAction, k1, k2, k3, k4, k5, k6, k7>
-WithArgs(const InnerAction& action) {
- return internal::WithArgsAction<InnerAction, k1, k2, k3, k4, k5, k6,
- k7>(action);
-}
-
-template <int k1, int k2, int k3, int k4, int k5, int k6, int k7, int k8,
- typename InnerAction>
-inline internal::WithArgsAction<InnerAction, k1, k2, k3, k4, k5, k6, k7, k8>
-WithArgs(const InnerAction& action) {
- return internal::WithArgsAction<InnerAction, k1, k2, k3, k4, k5, k6, k7,
- k8>(action);
-}
-
-template <int k1, int k2, int k3, int k4, int k5, int k6, int k7, int k8,
- int k9, typename InnerAction>
-inline internal::WithArgsAction<InnerAction, k1, k2, k3, k4, k5, k6, k7, k8, k9>
-WithArgs(const InnerAction& action) {
- return internal::WithArgsAction<InnerAction, k1, k2, k3, k4, k5, k6, k7, k8,
- k9>(action);
-}
-
-template <int k1, int k2, int k3, int k4, int k5, int k6, int k7, int k8,
- int k9, int k10, typename InnerAction>
-inline internal::WithArgsAction<InnerAction, k1, k2, k3, k4, k5, k6, k7, k8,
- k9, k10>
-WithArgs(const InnerAction& action) {
- return internal::WithArgsAction<InnerAction, k1, k2, k3, k4, k5, k6, k7, k8,
- k9, k10>(action);
-}
-
-// Creates an action that does actions a1, a2, ..., sequentially in
-// each invocation.
-template <typename Action1, typename Action2>
-inline internal::DoBothAction<Action1, Action2>
-DoAll(Action1 a1, Action2 a2) {
- return internal::DoBothAction<Action1, Action2>(a1, a2);
-}
-
-template <typename Action1, typename Action2, typename Action3>
-inline internal::DoBothAction<Action1, internal::DoBothAction<Action2,
- Action3> >
-DoAll(Action1 a1, Action2 a2, Action3 a3) {
- return DoAll(a1, DoAll(a2, a3));
-}
-
-template <typename Action1, typename Action2, typename Action3,
- typename Action4>
-inline internal::DoBothAction<Action1, internal::DoBothAction<Action2,
- internal::DoBothAction<Action3, Action4> > >
-DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4) {
- return DoAll(a1, DoAll(a2, a3, a4));
-}
-
-template <typename Action1, typename Action2, typename Action3,
- typename Action4, typename Action5>
-inline internal::DoBothAction<Action1, internal::DoBothAction<Action2,
- internal::DoBothAction<Action3, internal::DoBothAction<Action4,
- Action5> > > >
-DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5) {
- return DoAll(a1, DoAll(a2, a3, a4, a5));
-}
-
-template <typename Action1, typename Action2, typename Action3,
- typename Action4, typename Action5, typename Action6>
-inline internal::DoBothAction<Action1, internal::DoBothAction<Action2,
- internal::DoBothAction<Action3, internal::DoBothAction<Action4,
- internal::DoBothAction<Action5, Action6> > > > >
-DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6) {
- return DoAll(a1, DoAll(a2, a3, a4, a5, a6));
-}
-
-template <typename Action1, typename Action2, typename Action3,
- typename Action4, typename Action5, typename Action6, typename Action7>
-inline internal::DoBothAction<Action1, internal::DoBothAction<Action2,
- internal::DoBothAction<Action3, internal::DoBothAction<Action4,
- internal::DoBothAction<Action5, internal::DoBothAction<Action6,
- Action7> > > > > >
-DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6,
- Action7 a7) {
- return DoAll(a1, DoAll(a2, a3, a4, a5, a6, a7));
-}
-
-template <typename Action1, typename Action2, typename Action3,
- typename Action4, typename Action5, typename Action6, typename Action7,
- typename Action8>
-inline internal::DoBothAction<Action1, internal::DoBothAction<Action2,
- internal::DoBothAction<Action3, internal::DoBothAction<Action4,
- internal::DoBothAction<Action5, internal::DoBothAction<Action6,
- internal::DoBothAction<Action7, Action8> > > > > > >
-DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6,
- Action7 a7, Action8 a8) {
- return DoAll(a1, DoAll(a2, a3, a4, a5, a6, a7, a8));
-}
-
-template <typename Action1, typename Action2, typename Action3,
- typename Action4, typename Action5, typename Action6, typename Action7,
- typename Action8, typename Action9>
-inline internal::DoBothAction<Action1, internal::DoBothAction<Action2,
- internal::DoBothAction<Action3, internal::DoBothAction<Action4,
- internal::DoBothAction<Action5, internal::DoBothAction<Action6,
- internal::DoBothAction<Action7, internal::DoBothAction<Action8,
- Action9> > > > > > > >
-DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6,
- Action7 a7, Action8 a8, Action9 a9) {
- return DoAll(a1, DoAll(a2, a3, a4, a5, a6, a7, a8, a9));
-}
-
-template <typename Action1, typename Action2, typename Action3,
- typename Action4, typename Action5, typename Action6, typename Action7,
- typename Action8, typename Action9, typename Action10>
-inline internal::DoBothAction<Action1, internal::DoBothAction<Action2,
- internal::DoBothAction<Action3, internal::DoBothAction<Action4,
- internal::DoBothAction<Action5, internal::DoBothAction<Action6,
- internal::DoBothAction<Action7, internal::DoBothAction<Action8,
- internal::DoBothAction<Action9, Action10> > > > > > > > >
-DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6,
- Action7 a7, Action8 a8, Action9 a9, Action10 a10) {
- return DoAll(a1, DoAll(a2, a3, a4, a5, a6, a7, a8, a9, a10));
-}
-
} // namespace testing
// The ACTION* family of macros can be used in a namespace scope to
@@ -866,30 +259,29 @@ DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6,
//
// CAVEAT:
//
-// ACTION*() can only be used in a namespace scope. The reason is
-// that C++ doesn't yet allow function-local types to be used to
-// instantiate templates. The up-coming C++0x standard will fix this.
-// Once that's done, we'll consider supporting using ACTION*() inside
-// a function.
+// ACTION*() can only be used in a namespace scope as templates cannot be
+// declared inside of a local class.
+// Users can, however, define any local functors (e.g. a lambda) that
+// can be used as actions.
//
// MORE INFORMATION:
//
-// To learn more about using these macros, please search for 'ACTION'
-// on http://code.google.com/p/googlemock/wiki/CookBook.
+// To learn more about using these macros, please search for 'ACTION' on
+// https://github.com/google/googletest/blob/master/googlemock/docs/cook_book.md
// An internal macro needed for implementing ACTION*().
#define GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_\
const args_type& args GTEST_ATTRIBUTE_UNUSED_, \
- arg0_type arg0 GTEST_ATTRIBUTE_UNUSED_, \
- arg1_type arg1 GTEST_ATTRIBUTE_UNUSED_, \
- arg2_type arg2 GTEST_ATTRIBUTE_UNUSED_, \
- arg3_type arg3 GTEST_ATTRIBUTE_UNUSED_, \
- arg4_type arg4 GTEST_ATTRIBUTE_UNUSED_, \
- arg5_type arg5 GTEST_ATTRIBUTE_UNUSED_, \
- arg6_type arg6 GTEST_ATTRIBUTE_UNUSED_, \
- arg7_type arg7 GTEST_ATTRIBUTE_UNUSED_, \
- arg8_type arg8 GTEST_ATTRIBUTE_UNUSED_, \
- arg9_type arg9 GTEST_ATTRIBUTE_UNUSED_
+ const arg0_type& arg0 GTEST_ATTRIBUTE_UNUSED_, \
+ const arg1_type& arg1 GTEST_ATTRIBUTE_UNUSED_, \
+ const arg2_type& arg2 GTEST_ATTRIBUTE_UNUSED_, \
+ const arg3_type& arg3 GTEST_ATTRIBUTE_UNUSED_, \
+ const arg4_type& arg4 GTEST_ATTRIBUTE_UNUSED_, \
+ const arg5_type& arg5 GTEST_ATTRIBUTE_UNUSED_, \
+ const arg6_type& arg6 GTEST_ATTRIBUTE_UNUSED_, \
+ const arg7_type& arg7 GTEST_ATTRIBUTE_UNUSED_, \
+ const arg8_type& arg8 GTEST_ATTRIBUTE_UNUSED_, \
+ const arg9_type& arg9 GTEST_ATTRIBUTE_UNUSED_
// Sometimes you want to give an action explicit template parameters
// that cannot be inferred from its value parameters. ACTION() and
@@ -915,7 +307,7 @@ DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6,
// ACTION_TEMPLATE(DuplicateArg,
// HAS_2_TEMPLATE_PARAMS(int, k, typename, T),
// AND_1_VALUE_PARAMS(output)) {
-// *output = T(::testing::get<k>(args));
+// *output = T(::std::get<k>(args));
// }
// ...
// int n;
@@ -1073,52 +465,67 @@ DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6,
#define GMOCK_INTERNAL_INIT_AND_0_VALUE_PARAMS()\
()
#define GMOCK_INTERNAL_INIT_AND_1_VALUE_PARAMS(p0)\
- (p0##_type gmock_p0) : p0(gmock_p0)
+ (p0##_type gmock_p0) : p0(::std::move(gmock_p0))
#define GMOCK_INTERNAL_INIT_AND_2_VALUE_PARAMS(p0, p1)\
- (p0##_type gmock_p0, p1##_type gmock_p1) : p0(gmock_p0), p1(gmock_p1)
+ (p0##_type gmock_p0, p1##_type gmock_p1) : p0(::std::move(gmock_p0)), \
+ p1(::std::move(gmock_p1))
#define GMOCK_INTERNAL_INIT_AND_3_VALUE_PARAMS(p0, p1, p2)\
(p0##_type gmock_p0, p1##_type gmock_p1, \
- p2##_type gmock_p2) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2)
+ p2##_type gmock_p2) : p0(::std::move(gmock_p0)), \
+ p1(::std::move(gmock_p1)), p2(::std::move(gmock_p2))
#define GMOCK_INTERNAL_INIT_AND_4_VALUE_PARAMS(p0, p1, p2, p3)\
(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \
- p3##_type gmock_p3) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \
- p3(gmock_p3)
+ p3##_type gmock_p3) : p0(::std::move(gmock_p0)), \
+ p1(::std::move(gmock_p1)), p2(::std::move(gmock_p2)), \
+ p3(::std::move(gmock_p3))
#define GMOCK_INTERNAL_INIT_AND_5_VALUE_PARAMS(p0, p1, p2, p3, p4)\
(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \
- p3##_type gmock_p3, p4##_type gmock_p4) : p0(gmock_p0), p1(gmock_p1), \
- p2(gmock_p2), p3(gmock_p3), p4(gmock_p4)
+ p3##_type gmock_p3, p4##_type gmock_p4) : p0(::std::move(gmock_p0)), \
+ p1(::std::move(gmock_p1)), p2(::std::move(gmock_p2)), \
+ p3(::std::move(gmock_p3)), p4(::std::move(gmock_p4))
#define GMOCK_INTERNAL_INIT_AND_6_VALUE_PARAMS(p0, p1, p2, p3, p4, p5)\
(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \
p3##_type gmock_p3, p4##_type gmock_p4, \
- p5##_type gmock_p5) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \
- p3(gmock_p3), p4(gmock_p4), p5(gmock_p5)
+ p5##_type gmock_p5) : p0(::std::move(gmock_p0)), \
+ p1(::std::move(gmock_p1)), p2(::std::move(gmock_p2)), \
+ p3(::std::move(gmock_p3)), p4(::std::move(gmock_p4)), \
+ p5(::std::move(gmock_p5))
#define GMOCK_INTERNAL_INIT_AND_7_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6)\
(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \
p3##_type gmock_p3, p4##_type gmock_p4, p5##_type gmock_p5, \
- p6##_type gmock_p6) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \
- p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), p6(gmock_p6)
+ p6##_type gmock_p6) : p0(::std::move(gmock_p0)), \
+ p1(::std::move(gmock_p1)), p2(::std::move(gmock_p2)), \
+ p3(::std::move(gmock_p3)), p4(::std::move(gmock_p4)), \
+ p5(::std::move(gmock_p5)), p6(::std::move(gmock_p6))
#define GMOCK_INTERNAL_INIT_AND_8_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, p7)\
(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \
p3##_type gmock_p3, p4##_type gmock_p4, p5##_type gmock_p5, \
- p6##_type gmock_p6, p7##_type gmock_p7) : p0(gmock_p0), p1(gmock_p1), \
- p2(gmock_p2), p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), \
- p7(gmock_p7)
+ p6##_type gmock_p6, p7##_type gmock_p7) : p0(::std::move(gmock_p0)), \
+ p1(::std::move(gmock_p1)), p2(::std::move(gmock_p2)), \
+ p3(::std::move(gmock_p3)), p4(::std::move(gmock_p4)), \
+ p5(::std::move(gmock_p5)), p6(::std::move(gmock_p6)), \
+ p7(::std::move(gmock_p7))
#define GMOCK_INTERNAL_INIT_AND_9_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, \
p7, p8)\
(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \
p3##_type gmock_p3, p4##_type gmock_p4, p5##_type gmock_p5, \
p6##_type gmock_p6, p7##_type gmock_p7, \
- p8##_type gmock_p8) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \
- p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), p7(gmock_p7), \
- p8(gmock_p8)
+ p8##_type gmock_p8) : p0(::std::move(gmock_p0)), \
+ p1(::std::move(gmock_p1)), p2(::std::move(gmock_p2)), \
+ p3(::std::move(gmock_p3)), p4(::std::move(gmock_p4)), \
+ p5(::std::move(gmock_p5)), p6(::std::move(gmock_p6)), \
+ p7(::std::move(gmock_p7)), p8(::std::move(gmock_p8))
#define GMOCK_INTERNAL_INIT_AND_10_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, \
p7, p8, p9)\
(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \
p3##_type gmock_p3, p4##_type gmock_p4, p5##_type gmock_p5, \
p6##_type gmock_p6, p7##_type gmock_p7, p8##_type gmock_p8, \
- p9##_type gmock_p9) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \
- p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), p7(gmock_p7), \
- p8(gmock_p8), p9(gmock_p9)
+ p9##_type gmock_p9) : p0(::std::move(gmock_p0)), \
+ p1(::std::move(gmock_p1)), p2(::std::move(gmock_p2)), \
+ p3(::std::move(gmock_p3)), p4(::std::move(gmock_p4)), \
+ p5(::std::move(gmock_p5)), p6(::std::move(gmock_p6)), \
+ p7(::std::move(gmock_p7)), p8(::std::move(gmock_p8)), \
+ p9(::std::move(gmock_p9))
// Declares the fields for storing the value parameters.
#define GMOCK_INTERNAL_DEFN_AND_0_VALUE_PARAMS()
@@ -1264,10 +671,12 @@ DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6,
typename arg3_type, typename arg4_type, typename arg5_type, \
typename arg6_type, typename arg7_type, typename arg8_type, \
typename arg9_type>\
- return_type gmock_PerformImpl(const args_type& args, arg0_type arg0, \
- arg1_type arg1, arg2_type arg2, arg3_type arg3, arg4_type arg4, \
- arg5_type arg5, arg6_type arg6, arg7_type arg7, arg8_type arg8, \
- arg9_type arg9) const;\
+ return_type gmock_PerformImpl(const args_type& args, \
+ const arg0_type& arg0, const arg1_type& arg1, \
+ const arg2_type& arg2, const arg3_type& arg3, \
+ const arg4_type& arg4, const arg5_type& arg5, \
+ const arg6_type& arg6, const arg7_type& arg7, \
+ const arg8_type& arg8, const arg9_type& arg9) const;\
GMOCK_INTERNAL_DEFN_##value_params\
private:\
GTEST_DISALLOW_ASSIGN_(gmock_Impl);\
@@ -1325,10 +734,12 @@ DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6,
typename arg3_type, typename arg4_type, typename arg5_type, \
typename arg6_type, typename arg7_type, typename arg8_type, \
typename arg9_type>\
- return_type gmock_PerformImpl(const args_type& args, arg0_type arg0, \
- arg1_type arg1, arg2_type arg2, arg3_type arg3, arg4_type arg4, \
- arg5_type arg5, arg6_type arg6, arg7_type arg7, arg8_type arg8, \
- arg9_type arg9) const;\
+ return_type gmock_PerformImpl(const args_type& args, \
+ const arg0_type& arg0, const arg1_type& arg1, \
+ const arg2_type& arg2, const arg3_type& arg3, \
+ const arg4_type& arg4, const arg5_type& arg5, \
+ const arg6_type& arg6, const arg7_type& arg7, \
+ const arg8_type& arg8, const arg9_type& arg9) const;\
private:\
GTEST_DISALLOW_ASSIGN_(gmock_Impl);\
};\
@@ -1354,7 +765,8 @@ DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6,
template <typename p0##_type>\
class name##ActionP {\
public:\
- explicit name##ActionP(p0##_type gmock_p0) : p0(gmock_p0) {}\
+ explicit name##ActionP(p0##_type gmock_p0) : \
+ p0(::std::forward<p0##_type>(gmock_p0)) {}\
template <typename F>\
class gmock_Impl : public ::testing::ActionInterface<F> {\
public:\
@@ -1362,7 +774,8 @@ DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6,
typedef typename ::testing::internal::Function<F>::Result return_type;\
typedef typename ::testing::internal::Function<F>::ArgumentTuple\
args_type;\
- explicit gmock_Impl(p0##_type gmock_p0) : p0(gmock_p0) {}\
+ explicit gmock_Impl(p0##_type gmock_p0) : \
+ p0(::std::forward<p0##_type>(gmock_p0)) {}\
virtual return_type Perform(const args_type& args) {\
return ::testing::internal::ActionHelper<return_type, gmock_Impl>::\
Perform(this, args);\
@@ -1371,10 +784,12 @@ DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6,
typename arg3_type, typename arg4_type, typename arg5_type, \
typename arg6_type, typename arg7_type, typename arg8_type, \
typename arg9_type>\
- return_type gmock_PerformImpl(const args_type& args, arg0_type arg0, \
- arg1_type arg1, arg2_type arg2, arg3_type arg3, arg4_type arg4, \
- arg5_type arg5, arg6_type arg6, arg7_type arg7, arg8_type arg8, \
- arg9_type arg9) const;\
+ return_type gmock_PerformImpl(const args_type& args, \
+ const arg0_type& arg0, const arg1_type& arg1, \
+ const arg2_type& arg2, const arg3_type& arg3, \
+ const arg4_type& arg4, const arg5_type& arg5, \
+ const arg6_type& arg6, const arg7_type& arg7, \
+ const arg8_type& arg8, const arg9_type& arg9) const;\
p0##_type p0;\
private:\
GTEST_DISALLOW_ASSIGN_(gmock_Impl);\
@@ -1404,8 +819,9 @@ DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6,
template <typename p0##_type, typename p1##_type>\
class name##ActionP2 {\
public:\
- name##ActionP2(p0##_type gmock_p0, p1##_type gmock_p1) : p0(gmock_p0), \
- p1(gmock_p1) {}\
+ name##ActionP2(p0##_type gmock_p0, \
+ p1##_type gmock_p1) : p0(::std::forward<p0##_type>(gmock_p0)), \
+ p1(::std::forward<p1##_type>(gmock_p1)) {}\
template <typename F>\
class gmock_Impl : public ::testing::ActionInterface<F> {\
public:\
@@ -1413,8 +829,9 @@ DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6,
typedef typename ::testing::internal::Function<F>::Result return_type;\
typedef typename ::testing::internal::Function<F>::ArgumentTuple\
args_type;\
- gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1) : p0(gmock_p0), \
- p1(gmock_p1) {}\
+ gmock_Impl(p0##_type gmock_p0, \
+ p1##_type gmock_p1) : p0(::std::forward<p0##_type>(gmock_p0)), \
+ p1(::std::forward<p1##_type>(gmock_p1)) {}\
virtual return_type Perform(const args_type& args) {\
return ::testing::internal::ActionHelper<return_type, gmock_Impl>::\
Perform(this, args);\
@@ -1423,10 +840,12 @@ DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6,
typename arg3_type, typename arg4_type, typename arg5_type, \
typename arg6_type, typename arg7_type, typename arg8_type, \
typename arg9_type>\
- return_type gmock_PerformImpl(const args_type& args, arg0_type arg0, \
- arg1_type arg1, arg2_type arg2, arg3_type arg3, arg4_type arg4, \
- arg5_type arg5, arg6_type arg6, arg7_type arg7, arg8_type arg8, \
- arg9_type arg9) const;\
+ return_type gmock_PerformImpl(const args_type& args, \
+ const arg0_type& arg0, const arg1_type& arg1, \
+ const arg2_type& arg2, const arg3_type& arg3, \
+ const arg4_type& arg4, const arg5_type& arg5, \
+ const arg6_type& arg6, const arg7_type& arg7, \
+ const arg8_type& arg8, const arg9_type& arg9) const;\
p0##_type p0;\
p1##_type p1;\
private:\
@@ -1460,7 +879,9 @@ DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6,
class name##ActionP3 {\
public:\
name##ActionP3(p0##_type gmock_p0, p1##_type gmock_p1, \
- p2##_type gmock_p2) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2) {}\
+ p2##_type gmock_p2) : p0(::std::forward<p0##_type>(gmock_p0)), \
+ p1(::std::forward<p1##_type>(gmock_p1)), \
+ p2(::std::forward<p2##_type>(gmock_p2)) {}\
template <typename F>\
class gmock_Impl : public ::testing::ActionInterface<F> {\
public:\
@@ -1469,7 +890,9 @@ DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6,
typedef typename ::testing::internal::Function<F>::ArgumentTuple\
args_type;\
gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, \
- p2##_type gmock_p2) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2) {}\
+ p2##_type gmock_p2) : p0(::std::forward<p0##_type>(gmock_p0)), \
+ p1(::std::forward<p1##_type>(gmock_p1)), \
+ p2(::std::forward<p2##_type>(gmock_p2)) {}\
virtual return_type Perform(const args_type& args) {\
return ::testing::internal::ActionHelper<return_type, gmock_Impl>::\
Perform(this, args);\
@@ -1478,10 +901,12 @@ DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6,
typename arg3_type, typename arg4_type, typename arg5_type, \
typename arg6_type, typename arg7_type, typename arg8_type, \
typename arg9_type>\
- return_type gmock_PerformImpl(const args_type& args, arg0_type arg0, \
- arg1_type arg1, arg2_type arg2, arg3_type arg3, arg4_type arg4, \
- arg5_type arg5, arg6_type arg6, arg7_type arg7, arg8_type arg8, \
- arg9_type arg9) const;\
+ return_type gmock_PerformImpl(const args_type& args, \
+ const arg0_type& arg0, const arg1_type& arg1, \
+ const arg2_type& arg2, const arg3_type& arg3, \
+ const arg4_type& arg4, const arg5_type& arg5, \
+ const arg6_type& arg6, const arg7_type& arg7, \
+ const arg8_type& arg8, const arg9_type& arg9) const;\
p0##_type p0;\
p1##_type p1;\
p2##_type p2;\
@@ -1519,8 +944,11 @@ DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6,
class name##ActionP4 {\
public:\
name##ActionP4(p0##_type gmock_p0, p1##_type gmock_p1, \
- p2##_type gmock_p2, p3##_type gmock_p3) : p0(gmock_p0), p1(gmock_p1), \
- p2(gmock_p2), p3(gmock_p3) {}\
+ p2##_type gmock_p2, \
+ p3##_type gmock_p3) : p0(::std::forward<p0##_type>(gmock_p0)), \
+ p1(::std::forward<p1##_type>(gmock_p1)), \
+ p2(::std::forward<p2##_type>(gmock_p2)), \
+ p3(::std::forward<p3##_type>(gmock_p3)) {}\
template <typename F>\
class gmock_Impl : public ::testing::ActionInterface<F> {\
public:\
@@ -1529,8 +957,10 @@ DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6,
typedef typename ::testing::internal::Function<F>::ArgumentTuple\
args_type;\
gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \
- p3##_type gmock_p3) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \
- p3(gmock_p3) {}\
+ p3##_type gmock_p3) : p0(::std::forward<p0##_type>(gmock_p0)), \
+ p1(::std::forward<p1##_type>(gmock_p1)), \
+ p2(::std::forward<p2##_type>(gmock_p2)), \
+ p3(::std::forward<p3##_type>(gmock_p3)) {}\
virtual return_type Perform(const args_type& args) {\
return ::testing::internal::ActionHelper<return_type, gmock_Impl>::\
Perform(this, args);\
@@ -1539,10 +969,12 @@ DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6,
typename arg3_type, typename arg4_type, typename arg5_type, \
typename arg6_type, typename arg7_type, typename arg8_type, \
typename arg9_type>\
- return_type gmock_PerformImpl(const args_type& args, arg0_type arg0, \
- arg1_type arg1, arg2_type arg2, arg3_type arg3, arg4_type arg4, \
- arg5_type arg5, arg6_type arg6, arg7_type arg7, arg8_type arg8, \
- arg9_type arg9) const;\
+ return_type gmock_PerformImpl(const args_type& args, \
+ const arg0_type& arg0, const arg1_type& arg1, \
+ const arg2_type& arg2, const arg3_type& arg3, \
+ const arg4_type& arg4, const arg5_type& arg5, \
+ const arg6_type& arg6, const arg7_type& arg7, \
+ const arg8_type& arg8, const arg9_type& arg9) const;\
p0##_type p0;\
p1##_type p1;\
p2##_type p2;\
@@ -1587,8 +1019,11 @@ DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6,
public:\
name##ActionP5(p0##_type gmock_p0, p1##_type gmock_p1, \
p2##_type gmock_p2, p3##_type gmock_p3, \
- p4##_type gmock_p4) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \
- p3(gmock_p3), p4(gmock_p4) {}\
+ p4##_type gmock_p4) : p0(::std::forward<p0##_type>(gmock_p0)), \
+ p1(::std::forward<p1##_type>(gmock_p1)), \
+ p2(::std::forward<p2##_type>(gmock_p2)), \
+ p3(::std::forward<p3##_type>(gmock_p3)), \
+ p4(::std::forward<p4##_type>(gmock_p4)) {}\
template <typename F>\
class gmock_Impl : public ::testing::ActionInterface<F> {\
public:\
@@ -1597,8 +1032,12 @@ DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6,
typedef typename ::testing::internal::Function<F>::ArgumentTuple\
args_type;\
gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \
- p3##_type gmock_p3, p4##_type gmock_p4) : p0(gmock_p0), \
- p1(gmock_p1), p2(gmock_p2), p3(gmock_p3), p4(gmock_p4) {}\
+ p3##_type gmock_p3, \
+ p4##_type gmock_p4) : p0(::std::forward<p0##_type>(gmock_p0)), \
+ p1(::std::forward<p1##_type>(gmock_p1)), \
+ p2(::std::forward<p2##_type>(gmock_p2)), \
+ p3(::std::forward<p3##_type>(gmock_p3)), \
+ p4(::std::forward<p4##_type>(gmock_p4)) {}\
virtual return_type Perform(const args_type& args) {\
return ::testing::internal::ActionHelper<return_type, gmock_Impl>::\
Perform(this, args);\
@@ -1607,10 +1046,12 @@ DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6,
typename arg3_type, typename arg4_type, typename arg5_type, \
typename arg6_type, typename arg7_type, typename arg8_type, \
typename arg9_type>\
- return_type gmock_PerformImpl(const args_type& args, arg0_type arg0, \
- arg1_type arg1, arg2_type arg2, arg3_type arg3, arg4_type arg4, \
- arg5_type arg5, arg6_type arg6, arg7_type arg7, arg8_type arg8, \
- arg9_type arg9) const;\
+ return_type gmock_PerformImpl(const args_type& args, \
+ const arg0_type& arg0, const arg1_type& arg1, \
+ const arg2_type& arg2, const arg3_type& arg3, \
+ const arg4_type& arg4, const arg5_type& arg5, \
+ const arg6_type& arg6, const arg7_type& arg7, \
+ const arg8_type& arg8, const arg9_type& arg9) const;\
p0##_type p0;\
p1##_type p1;\
p2##_type p2;\
@@ -1657,8 +1098,12 @@ DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6,
public:\
name##ActionP6(p0##_type gmock_p0, p1##_type gmock_p1, \
p2##_type gmock_p2, p3##_type gmock_p3, p4##_type gmock_p4, \
- p5##_type gmock_p5) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \
- p3(gmock_p3), p4(gmock_p4), p5(gmock_p5) {}\
+ p5##_type gmock_p5) : p0(::std::forward<p0##_type>(gmock_p0)), \
+ p1(::std::forward<p1##_type>(gmock_p1)), \
+ p2(::std::forward<p2##_type>(gmock_p2)), \
+ p3(::std::forward<p3##_type>(gmock_p3)), \
+ p4(::std::forward<p4##_type>(gmock_p4)), \
+ p5(::std::forward<p5##_type>(gmock_p5)) {}\
template <typename F>\
class gmock_Impl : public ::testing::ActionInterface<F> {\
public:\
@@ -1668,8 +1113,12 @@ DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6,
args_type;\
gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \
p3##_type gmock_p3, p4##_type gmock_p4, \
- p5##_type gmock_p5) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \
- p3(gmock_p3), p4(gmock_p4), p5(gmock_p5) {}\
+ p5##_type gmock_p5) : p0(::std::forward<p0##_type>(gmock_p0)), \
+ p1(::std::forward<p1##_type>(gmock_p1)), \
+ p2(::std::forward<p2##_type>(gmock_p2)), \
+ p3(::std::forward<p3##_type>(gmock_p3)), \
+ p4(::std::forward<p4##_type>(gmock_p4)), \
+ p5(::std::forward<p5##_type>(gmock_p5)) {}\
virtual return_type Perform(const args_type& args) {\
return ::testing::internal::ActionHelper<return_type, gmock_Impl>::\
Perform(this, args);\
@@ -1678,10 +1127,12 @@ DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6,
typename arg3_type, typename arg4_type, typename arg5_type, \
typename arg6_type, typename arg7_type, typename arg8_type, \
typename arg9_type>\
- return_type gmock_PerformImpl(const args_type& args, arg0_type arg0, \
- arg1_type arg1, arg2_type arg2, arg3_type arg3, arg4_type arg4, \
- arg5_type arg5, arg6_type arg6, arg7_type arg7, arg8_type arg8, \
- arg9_type arg9) const;\
+ return_type gmock_PerformImpl(const args_type& args, \
+ const arg0_type& arg0, const arg1_type& arg1, \
+ const arg2_type& arg2, const arg3_type& arg3, \
+ const arg4_type& arg4, const arg5_type& arg5, \
+ const arg6_type& arg6, const arg7_type& arg7, \
+ const arg8_type& arg8, const arg9_type& arg9) const;\
p0##_type p0;\
p1##_type p1;\
p2##_type p2;\
@@ -1731,9 +1182,14 @@ DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6,
public:\
name##ActionP7(p0##_type gmock_p0, p1##_type gmock_p1, \
p2##_type gmock_p2, p3##_type gmock_p3, p4##_type gmock_p4, \
- p5##_type gmock_p5, p6##_type gmock_p6) : p0(gmock_p0), p1(gmock_p1), \
- p2(gmock_p2), p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), \
- p6(gmock_p6) {}\
+ p5##_type gmock_p5, \
+ p6##_type gmock_p6) : p0(::std::forward<p0##_type>(gmock_p0)), \
+ p1(::std::forward<p1##_type>(gmock_p1)), \
+ p2(::std::forward<p2##_type>(gmock_p2)), \
+ p3(::std::forward<p3##_type>(gmock_p3)), \
+ p4(::std::forward<p4##_type>(gmock_p4)), \
+ p5(::std::forward<p5##_type>(gmock_p5)), \
+ p6(::std::forward<p6##_type>(gmock_p6)) {}\
template <typename F>\
class gmock_Impl : public ::testing::ActionInterface<F> {\
public:\
@@ -1743,8 +1199,13 @@ DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6,
args_type;\
gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \
p3##_type gmock_p3, p4##_type gmock_p4, p5##_type gmock_p5, \
- p6##_type gmock_p6) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \
- p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), p6(gmock_p6) {}\
+ p6##_type gmock_p6) : p0(::std::forward<p0##_type>(gmock_p0)), \
+ p1(::std::forward<p1##_type>(gmock_p1)), \
+ p2(::std::forward<p2##_type>(gmock_p2)), \
+ p3(::std::forward<p3##_type>(gmock_p3)), \
+ p4(::std::forward<p4##_type>(gmock_p4)), \
+ p5(::std::forward<p5##_type>(gmock_p5)), \
+ p6(::std::forward<p6##_type>(gmock_p6)) {}\
virtual return_type Perform(const args_type& args) {\
return ::testing::internal::ActionHelper<return_type, gmock_Impl>::\
Perform(this, args);\
@@ -1753,10 +1214,12 @@ DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6,
typename arg3_type, typename arg4_type, typename arg5_type, \
typename arg6_type, typename arg7_type, typename arg8_type, \
typename arg9_type>\
- return_type gmock_PerformImpl(const args_type& args, arg0_type arg0, \
- arg1_type arg1, arg2_type arg2, arg3_type arg3, arg4_type arg4, \
- arg5_type arg5, arg6_type arg6, arg7_type arg7, arg8_type arg8, \
- arg9_type arg9) const;\
+ return_type gmock_PerformImpl(const args_type& args, \
+ const arg0_type& arg0, const arg1_type& arg1, \
+ const arg2_type& arg2, const arg3_type& arg3, \
+ const arg4_type& arg4, const arg5_type& arg5, \
+ const arg6_type& arg6, const arg7_type& arg7, \
+ const arg8_type& arg8, const arg9_type& arg9) const;\
p0##_type p0;\
p1##_type p1;\
p2##_type p2;\
@@ -1813,9 +1276,14 @@ DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6,
name##ActionP8(p0##_type gmock_p0, p1##_type gmock_p1, \
p2##_type gmock_p2, p3##_type gmock_p3, p4##_type gmock_p4, \
p5##_type gmock_p5, p6##_type gmock_p6, \
- p7##_type gmock_p7) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \
- p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), \
- p7(gmock_p7) {}\
+ p7##_type gmock_p7) : p0(::std::forward<p0##_type>(gmock_p0)), \
+ p1(::std::forward<p1##_type>(gmock_p1)), \
+ p2(::std::forward<p2##_type>(gmock_p2)), \
+ p3(::std::forward<p3##_type>(gmock_p3)), \
+ p4(::std::forward<p4##_type>(gmock_p4)), \
+ p5(::std::forward<p5##_type>(gmock_p5)), \
+ p6(::std::forward<p6##_type>(gmock_p6)), \
+ p7(::std::forward<p7##_type>(gmock_p7)) {}\
template <typename F>\
class gmock_Impl : public ::testing::ActionInterface<F> {\
public:\
@@ -1825,9 +1293,15 @@ DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6,
args_type;\
gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \
p3##_type gmock_p3, p4##_type gmock_p4, p5##_type gmock_p5, \
- p6##_type gmock_p6, p7##_type gmock_p7) : p0(gmock_p0), \
- p1(gmock_p1), p2(gmock_p2), p3(gmock_p3), p4(gmock_p4), \
- p5(gmock_p5), p6(gmock_p6), p7(gmock_p7) {}\
+ p6##_type gmock_p6, \
+ p7##_type gmock_p7) : p0(::std::forward<p0##_type>(gmock_p0)), \
+ p1(::std::forward<p1##_type>(gmock_p1)), \
+ p2(::std::forward<p2##_type>(gmock_p2)), \
+ p3(::std::forward<p3##_type>(gmock_p3)), \
+ p4(::std::forward<p4##_type>(gmock_p4)), \
+ p5(::std::forward<p5##_type>(gmock_p5)), \
+ p6(::std::forward<p6##_type>(gmock_p6)), \
+ p7(::std::forward<p7##_type>(gmock_p7)) {}\
virtual return_type Perform(const args_type& args) {\
return ::testing::internal::ActionHelper<return_type, gmock_Impl>::\
Perform(this, args);\
@@ -1836,10 +1310,12 @@ DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6,
typename arg3_type, typename arg4_type, typename arg5_type, \
typename arg6_type, typename arg7_type, typename arg8_type, \
typename arg9_type>\
- return_type gmock_PerformImpl(const args_type& args, arg0_type arg0, \
- arg1_type arg1, arg2_type arg2, arg3_type arg3, arg4_type arg4, \
- arg5_type arg5, arg6_type arg6, arg7_type arg7, arg8_type arg8, \
- arg9_type arg9) const;\
+ return_type gmock_PerformImpl(const args_type& args, \
+ const arg0_type& arg0, const arg1_type& arg1, \
+ const arg2_type& arg2, const arg3_type& arg3, \
+ const arg4_type& arg4, const arg5_type& arg5, \
+ const arg6_type& arg6, const arg7_type& arg7, \
+ const arg8_type& arg8, const arg9_type& arg9) const;\
p0##_type p0;\
p1##_type p1;\
p2##_type p2;\
@@ -1900,9 +1376,15 @@ DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6,
name##ActionP9(p0##_type gmock_p0, p1##_type gmock_p1, \
p2##_type gmock_p2, p3##_type gmock_p3, p4##_type gmock_p4, \
p5##_type gmock_p5, p6##_type gmock_p6, p7##_type gmock_p7, \
- p8##_type gmock_p8) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \
- p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), p7(gmock_p7), \
- p8(gmock_p8) {}\
+ p8##_type gmock_p8) : p0(::std::forward<p0##_type>(gmock_p0)), \
+ p1(::std::forward<p1##_type>(gmock_p1)), \
+ p2(::std::forward<p2##_type>(gmock_p2)), \
+ p3(::std::forward<p3##_type>(gmock_p3)), \
+ p4(::std::forward<p4##_type>(gmock_p4)), \
+ p5(::std::forward<p5##_type>(gmock_p5)), \
+ p6(::std::forward<p6##_type>(gmock_p6)), \
+ p7(::std::forward<p7##_type>(gmock_p7)), \
+ p8(::std::forward<p8##_type>(gmock_p8)) {}\
template <typename F>\
class gmock_Impl : public ::testing::ActionInterface<F> {\
public:\
@@ -1913,9 +1395,15 @@ DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6,
gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \
p3##_type gmock_p3, p4##_type gmock_p4, p5##_type gmock_p5, \
p6##_type gmock_p6, p7##_type gmock_p7, \
- p8##_type gmock_p8) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \
- p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), \
- p7(gmock_p7), p8(gmock_p8) {}\
+ p8##_type gmock_p8) : p0(::std::forward<p0##_type>(gmock_p0)), \
+ p1(::std::forward<p1##_type>(gmock_p1)), \
+ p2(::std::forward<p2##_type>(gmock_p2)), \
+ p3(::std::forward<p3##_type>(gmock_p3)), \
+ p4(::std::forward<p4##_type>(gmock_p4)), \
+ p5(::std::forward<p5##_type>(gmock_p5)), \
+ p6(::std::forward<p6##_type>(gmock_p6)), \
+ p7(::std::forward<p7##_type>(gmock_p7)), \
+ p8(::std::forward<p8##_type>(gmock_p8)) {}\
virtual return_type Perform(const args_type& args) {\
return ::testing::internal::ActionHelper<return_type, gmock_Impl>::\
Perform(this, args);\
@@ -1924,10 +1412,12 @@ DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6,
typename arg3_type, typename arg4_type, typename arg5_type, \
typename arg6_type, typename arg7_type, typename arg8_type, \
typename arg9_type>\
- return_type gmock_PerformImpl(const args_type& args, arg0_type arg0, \
- arg1_type arg1, arg2_type arg2, arg3_type arg3, arg4_type arg4, \
- arg5_type arg5, arg6_type arg6, arg7_type arg7, arg8_type arg8, \
- arg9_type arg9) const;\
+ return_type gmock_PerformImpl(const args_type& args, \
+ const arg0_type& arg0, const arg1_type& arg1, \
+ const arg2_type& arg2, const arg3_type& arg3, \
+ const arg4_type& arg4, const arg5_type& arg5, \
+ const arg6_type& arg6, const arg7_type& arg7, \
+ const arg8_type& arg8, const arg9_type& arg9) const;\
p0##_type p0;\
p1##_type p1;\
p2##_type p2;\
@@ -1992,9 +1482,17 @@ DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6,
name##ActionP10(p0##_type gmock_p0, p1##_type gmock_p1, \
p2##_type gmock_p2, p3##_type gmock_p3, p4##_type gmock_p4, \
p5##_type gmock_p5, p6##_type gmock_p6, p7##_type gmock_p7, \
- p8##_type gmock_p8, p9##_type gmock_p9) : p0(gmock_p0), p1(gmock_p1), \
- p2(gmock_p2), p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), \
- p7(gmock_p7), p8(gmock_p8), p9(gmock_p9) {}\
+ p8##_type gmock_p8, \
+ p9##_type gmock_p9) : p0(::std::forward<p0##_type>(gmock_p0)), \
+ p1(::std::forward<p1##_type>(gmock_p1)), \
+ p2(::std::forward<p2##_type>(gmock_p2)), \
+ p3(::std::forward<p3##_type>(gmock_p3)), \
+ p4(::std::forward<p4##_type>(gmock_p4)), \
+ p5(::std::forward<p5##_type>(gmock_p5)), \
+ p6(::std::forward<p6##_type>(gmock_p6)), \
+ p7(::std::forward<p7##_type>(gmock_p7)), \
+ p8(::std::forward<p8##_type>(gmock_p8)), \
+ p9(::std::forward<p9##_type>(gmock_p9)) {}\
template <typename F>\
class gmock_Impl : public ::testing::ActionInterface<F> {\
public:\
@@ -2005,9 +1503,16 @@ DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6,
gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \
p3##_type gmock_p3, p4##_type gmock_p4, p5##_type gmock_p5, \
p6##_type gmock_p6, p7##_type gmock_p7, p8##_type gmock_p8, \
- p9##_type gmock_p9) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \
- p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), \
- p7(gmock_p7), p8(gmock_p8), p9(gmock_p9) {}\
+ p9##_type gmock_p9) : p0(::std::forward<p0##_type>(gmock_p0)), \
+ p1(::std::forward<p1##_type>(gmock_p1)), \
+ p2(::std::forward<p2##_type>(gmock_p2)), \
+ p3(::std::forward<p3##_type>(gmock_p3)), \
+ p4(::std::forward<p4##_type>(gmock_p4)), \
+ p5(::std::forward<p5##_type>(gmock_p5)), \
+ p6(::std::forward<p6##_type>(gmock_p6)), \
+ p7(::std::forward<p7##_type>(gmock_p7)), \
+ p8(::std::forward<p8##_type>(gmock_p8)), \
+ p9(::std::forward<p9##_type>(gmock_p9)) {}\
virtual return_type Perform(const args_type& args) {\
return ::testing::internal::ActionHelper<return_type, gmock_Impl>::\
Perform(this, args);\
@@ -2016,10 +1521,12 @@ DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6,
typename arg3_type, typename arg4_type, typename arg5_type, \
typename arg6_type, typename arg7_type, typename arg8_type, \
typename arg9_type>\
- return_type gmock_PerformImpl(const args_type& args, arg0_type arg0, \
- arg1_type arg1, arg2_type arg2, arg3_type arg3, arg4_type arg4, \
- arg5_type arg5, arg6_type arg6, arg7_type arg7, arg8_type arg8, \
- arg9_type arg9) const;\
+ return_type gmock_PerformImpl(const args_type& args, \
+ const arg0_type& arg0, const arg1_type& arg1, \
+ const arg2_type& arg2, const arg3_type& arg3, \
+ const arg4_type& arg4, const arg5_type& arg5, \
+ const arg6_type& arg6, const arg7_type& arg7, \
+ const arg8_type& arg8, const arg9_type& arg9) const;\
p0##_type p0;\
p1##_type p1;\
p2##_type p2;\
@@ -2199,7 +1706,7 @@ ACTION_TEMPLATE(InvokeArgument,
using internal::invoke_argument::InvokeArgumentAdl;
return InvokeArgumentAdl<return_type>(
internal::invoke_argument::AdlTag(),
- ::testing::get<k>(args));
+ ::std::get<k>(args));
}
ACTION_TEMPLATE(InvokeArgument,
@@ -2208,7 +1715,7 @@ ACTION_TEMPLATE(InvokeArgument,
using internal::invoke_argument::InvokeArgumentAdl;
return InvokeArgumentAdl<return_type>(
internal::invoke_argument::AdlTag(),
- ::testing::get<k>(args), p0);
+ ::std::get<k>(args), p0);
}
ACTION_TEMPLATE(InvokeArgument,
@@ -2217,7 +1724,7 @@ ACTION_TEMPLATE(InvokeArgument,
using internal::invoke_argument::InvokeArgumentAdl;
return InvokeArgumentAdl<return_type>(
internal::invoke_argument::AdlTag(),
- ::testing::get<k>(args), p0, p1);
+ ::std::get<k>(args), p0, p1);
}
ACTION_TEMPLATE(InvokeArgument,
@@ -2226,7 +1733,7 @@ ACTION_TEMPLATE(InvokeArgument,
using internal::invoke_argument::InvokeArgumentAdl;
return InvokeArgumentAdl<return_type>(
internal::invoke_argument::AdlTag(),
- ::testing::get<k>(args), p0, p1, p2);
+ ::std::get<k>(args), p0, p1, p2);
}
ACTION_TEMPLATE(InvokeArgument,
@@ -2235,7 +1742,7 @@ ACTION_TEMPLATE(InvokeArgument,
using internal::invoke_argument::InvokeArgumentAdl;
return InvokeArgumentAdl<return_type>(
internal::invoke_argument::AdlTag(),
- ::testing::get<k>(args), p0, p1, p2, p3);
+ ::std::get<k>(args), p0, p1, p2, p3);
}
ACTION_TEMPLATE(InvokeArgument,
@@ -2244,7 +1751,7 @@ ACTION_TEMPLATE(InvokeArgument,
using internal::invoke_argument::InvokeArgumentAdl;
return InvokeArgumentAdl<return_type>(
internal::invoke_argument::AdlTag(),
- ::testing::get<k>(args), p0, p1, p2, p3, p4);
+ ::std::get<k>(args), p0, p1, p2, p3, p4);
}
ACTION_TEMPLATE(InvokeArgument,
@@ -2253,7 +1760,7 @@ ACTION_TEMPLATE(InvokeArgument,
using internal::invoke_argument::InvokeArgumentAdl;
return InvokeArgumentAdl<return_type>(
internal::invoke_argument::AdlTag(),
- ::testing::get<k>(args), p0, p1, p2, p3, p4, p5);
+ ::std::get<k>(args), p0, p1, p2, p3, p4, p5);
}
ACTION_TEMPLATE(InvokeArgument,
@@ -2262,7 +1769,7 @@ ACTION_TEMPLATE(InvokeArgument,
using internal::invoke_argument::InvokeArgumentAdl;
return InvokeArgumentAdl<return_type>(
internal::invoke_argument::AdlTag(),
- ::testing::get<k>(args), p0, p1, p2, p3, p4, p5, p6);
+ ::std::get<k>(args), p0, p1, p2, p3, p4, p5, p6);
}
ACTION_TEMPLATE(InvokeArgument,
@@ -2271,7 +1778,7 @@ ACTION_TEMPLATE(InvokeArgument,
using internal::invoke_argument::InvokeArgumentAdl;
return InvokeArgumentAdl<return_type>(
internal::invoke_argument::AdlTag(),
- ::testing::get<k>(args), p0, p1, p2, p3, p4, p5, p6, p7);
+ ::std::get<k>(args), p0, p1, p2, p3, p4, p5, p6, p7);
}
ACTION_TEMPLATE(InvokeArgument,
@@ -2280,7 +1787,7 @@ ACTION_TEMPLATE(InvokeArgument,
using internal::invoke_argument::InvokeArgumentAdl;
return InvokeArgumentAdl<return_type>(
internal::invoke_argument::AdlTag(),
- ::testing::get<k>(args), p0, p1, p2, p3, p4, p5, p6, p7, p8);
+ ::std::get<k>(args), p0, p1, p2, p3, p4, p5, p6, p7, p8);
}
ACTION_TEMPLATE(InvokeArgument,
@@ -2289,7 +1796,7 @@ ACTION_TEMPLATE(InvokeArgument,
using internal::invoke_argument::InvokeArgumentAdl;
return InvokeArgumentAdl<return_type>(
internal::invoke_argument::AdlTag(),
- ::testing::get<k>(args), p0, p1, p2, p3, p4, p5, p6, p7, p8, p9);
+ ::std::get<k>(args), p0, p1, p2, p3, p4, p5, p6, p7, p8, p9);
}
// Various overloads for ReturnNew<T>().
@@ -2369,7 +1876,7 @@ ACTION_TEMPLATE(ReturnNew,
} // namespace testing
-// Include any custom actions added by the local installation.
+// Include any custom callback actions added by the local installation.
// We must include this header at the end to make sure it can use the
// declarations from this file.
#include "gmock/internal/custom/gmock-generated-actions.h"
diff --git a/extern/gmock/include/gmock/gmock-generated-function-mockers.h b/extern/gmock/include/gmock/gmock-generated-function-mockers.h
index 4fa5ca94849..cd9578178c0 100644
--- a/extern/gmock/include/gmock/gmock-generated-function-mockers.h
+++ b/extern/gmock/include/gmock/gmock-generated-function-mockers.h
@@ -30,295 +30,76 @@
// 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.
-//
-// Author: wan@google.com (Zhanyong Wan)
+
// Google Mock - a framework for writing C++ mock classes.
//
// This file implements function mockers of various arities.
+// GOOGLETEST_CM0002 DO NOT DELETE
+
#ifndef GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_FUNCTION_MOCKERS_H_
#define GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_FUNCTION_MOCKERS_H_
+#include <functional>
+#include <utility>
+
#include "gmock/gmock-spec-builders.h"
#include "gmock/internal/gmock-internal-utils.h"
-#if GTEST_HAS_STD_FUNCTION_
-# include <functional>
-#endif
-
namespace testing {
namespace internal {
-
-template <typename F>
-class FunctionMockerBase;
-
-// Note: class FunctionMocker really belongs to the ::testing
-// namespace. However if we define it in ::testing, MSVC will
-// complain when classes in ::testing::internal declare it as a
-// friend class template. To workaround this compiler bug, we define
-// FunctionMocker in ::testing::internal and import it into ::testing.
-template <typename F>
-class FunctionMocker;
-
-template <typename R>
-class FunctionMocker<R()> : public
- internal::FunctionMockerBase<R()> {
- public:
- typedef R F();
- typedef typename internal::Function<F>::ArgumentTuple ArgumentTuple;
-
- MockSpec<F>& With() {
- return this->current_spec();
- }
-
- R Invoke() {
- // Even though gcc and MSVC don't enforce it, 'this->' is required
- // by the C++ standard [14.6.4] here, as the base class type is
- // dependent on the template argument (and thus shouldn't be
- // looked into when resolving InvokeWith).
- return this->InvokeWith(ArgumentTuple());
- }
-};
-
-template <typename R, typename A1>
-class FunctionMocker<R(A1)> : public
- internal::FunctionMockerBase<R(A1)> {
- public:
- typedef R F(A1);
- typedef typename internal::Function<F>::ArgumentTuple ArgumentTuple;
-
- MockSpec<F>& With(const Matcher<A1>& m1) {
- this->current_spec().SetMatchers(::testing::make_tuple(m1));
- return this->current_spec();
- }
-
- R Invoke(A1 a1) {
- // Even though gcc and MSVC don't enforce it, 'this->' is required
- // by the C++ standard [14.6.4] here, as the base class type is
- // dependent on the template argument (and thus shouldn't be
- // looked into when resolving InvokeWith).
- return this->InvokeWith(ArgumentTuple(a1));
- }
-};
-
-template <typename R, typename A1, typename A2>
-class FunctionMocker<R(A1, A2)> : public
- internal::FunctionMockerBase<R(A1, A2)> {
- public:
- typedef R F(A1, A2);
- typedef typename internal::Function<F>::ArgumentTuple ArgumentTuple;
-
- MockSpec<F>& With(const Matcher<A1>& m1, const Matcher<A2>& m2) {
- this->current_spec().SetMatchers(::testing::make_tuple(m1, m2));
- return this->current_spec();
- }
-
- R Invoke(A1 a1, A2 a2) {
- // Even though gcc and MSVC don't enforce it, 'this->' is required
- // by the C++ standard [14.6.4] here, as the base class type is
- // dependent on the template argument (and thus shouldn't be
- // looked into when resolving InvokeWith).
- return this->InvokeWith(ArgumentTuple(a1, a2));
- }
-};
-
-template <typename R, typename A1, typename A2, typename A3>
-class FunctionMocker<R(A1, A2, A3)> : public
- internal::FunctionMockerBase<R(A1, A2, A3)> {
- public:
- typedef R F(A1, A2, A3);
- typedef typename internal::Function<F>::ArgumentTuple ArgumentTuple;
-
- MockSpec<F>& With(const Matcher<A1>& m1, const Matcher<A2>& m2,
- const Matcher<A3>& m3) {
- this->current_spec().SetMatchers(::testing::make_tuple(m1, m2, m3));
- return this->current_spec();
- }
-
- R Invoke(A1 a1, A2 a2, A3 a3) {
- // Even though gcc and MSVC don't enforce it, 'this->' is required
- // by the C++ standard [14.6.4] here, as the base class type is
- // dependent on the template argument (and thus shouldn't be
- // looked into when resolving InvokeWith).
- return this->InvokeWith(ArgumentTuple(a1, a2, a3));
- }
-};
-
-template <typename R, typename A1, typename A2, typename A3, typename A4>
-class FunctionMocker<R(A1, A2, A3, A4)> : public
- internal::FunctionMockerBase<R(A1, A2, A3, A4)> {
- public:
- typedef R F(A1, A2, A3, A4);
- typedef typename internal::Function<F>::ArgumentTuple ArgumentTuple;
-
- MockSpec<F>& With(const Matcher<A1>& m1, const Matcher<A2>& m2,
- const Matcher<A3>& m3, const Matcher<A4>& m4) {
- this->current_spec().SetMatchers(::testing::make_tuple(m1, m2, m3, m4));
- return this->current_spec();
- }
-
- R Invoke(A1 a1, A2 a2, A3 a3, A4 a4) {
- // Even though gcc and MSVC don't enforce it, 'this->' is required
- // by the C++ standard [14.6.4] here, as the base class type is
- // dependent on the template argument (and thus shouldn't be
- // looked into when resolving InvokeWith).
- return this->InvokeWith(ArgumentTuple(a1, a2, a3, a4));
- }
-};
-
-template <typename R, typename A1, typename A2, typename A3, typename A4,
- typename A5>
-class FunctionMocker<R(A1, A2, A3, A4, A5)> : public
- internal::FunctionMockerBase<R(A1, A2, A3, A4, A5)> {
- public:
- typedef R F(A1, A2, A3, A4, A5);
- typedef typename internal::Function<F>::ArgumentTuple ArgumentTuple;
-
- MockSpec<F>& With(const Matcher<A1>& m1, const Matcher<A2>& m2,
- const Matcher<A3>& m3, const Matcher<A4>& m4, const Matcher<A5>& m5) {
- this->current_spec().SetMatchers(::testing::make_tuple(m1, m2, m3, m4, m5));
- return this->current_spec();
- }
-
- R Invoke(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) {
- // Even though gcc and MSVC don't enforce it, 'this->' is required
- // by the C++ standard [14.6.4] here, as the base class type is
- // dependent on the template argument (and thus shouldn't be
- // looked into when resolving InvokeWith).
- return this->InvokeWith(ArgumentTuple(a1, a2, a3, a4, a5));
- }
-};
-
-template <typename R, typename A1, typename A2, typename A3, typename A4,
- typename A5, typename A6>
-class FunctionMocker<R(A1, A2, A3, A4, A5, A6)> : public
- internal::FunctionMockerBase<R(A1, A2, A3, A4, A5, A6)> {
- public:
- typedef R F(A1, A2, A3, A4, A5, A6);
- typedef typename internal::Function<F>::ArgumentTuple ArgumentTuple;
-
- MockSpec<F>& With(const Matcher<A1>& m1, const Matcher<A2>& m2,
- const Matcher<A3>& m3, const Matcher<A4>& m4, const Matcher<A5>& m5,
- const Matcher<A6>& m6) {
- this->current_spec().SetMatchers(::testing::make_tuple(m1, m2, m3, m4, m5,
- m6));
- return this->current_spec();
- }
-
- R Invoke(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6) {
- // Even though gcc and MSVC don't enforce it, 'this->' is required
- // by the C++ standard [14.6.4] here, as the base class type is
- // dependent on the template argument (and thus shouldn't be
- // looked into when resolving InvokeWith).
- return this->InvokeWith(ArgumentTuple(a1, a2, a3, a4, a5, a6));
- }
-};
-
-template <typename R, typename A1, typename A2, typename A3, typename A4,
- typename A5, typename A6, typename A7>
-class FunctionMocker<R(A1, A2, A3, A4, A5, A6, A7)> : public
- internal::FunctionMockerBase<R(A1, A2, A3, A4, A5, A6, A7)> {
- public:
- typedef R F(A1, A2, A3, A4, A5, A6, A7);
- typedef typename internal::Function<F>::ArgumentTuple ArgumentTuple;
-
- MockSpec<F>& With(const Matcher<A1>& m1, const Matcher<A2>& m2,
- const Matcher<A3>& m3, const Matcher<A4>& m4, const Matcher<A5>& m5,
- const Matcher<A6>& m6, const Matcher<A7>& m7) {
- this->current_spec().SetMatchers(::testing::make_tuple(m1, m2, m3, m4, m5,
- m6, m7));
- return this->current_spec();
- }
-
- R Invoke(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7) {
- // Even though gcc and MSVC don't enforce it, 'this->' is required
- // by the C++ standard [14.6.4] here, as the base class type is
- // dependent on the template argument (and thus shouldn't be
- // looked into when resolving InvokeWith).
- return this->InvokeWith(ArgumentTuple(a1, a2, a3, a4, a5, a6, a7));
- }
-};
-
-template <typename R, typename A1, typename A2, typename A3, typename A4,
- typename A5, typename A6, typename A7, typename A8>
-class FunctionMocker<R(A1, A2, A3, A4, A5, A6, A7, A8)> : public
- internal::FunctionMockerBase<R(A1, A2, A3, A4, A5, A6, A7, A8)> {
- public:
- typedef R F(A1, A2, A3, A4, A5, A6, A7, A8);
- typedef typename internal::Function<F>::ArgumentTuple ArgumentTuple;
-
- MockSpec<F>& With(const Matcher<A1>& m1, const Matcher<A2>& m2,
- const Matcher<A3>& m3, const Matcher<A4>& m4, const Matcher<A5>& m5,
- const Matcher<A6>& m6, const Matcher<A7>& m7, const Matcher<A8>& m8) {
- this->current_spec().SetMatchers(::testing::make_tuple(m1, m2, m3, m4, m5,
- m6, m7, m8));
- return this->current_spec();
- }
-
- R Invoke(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8) {
- // Even though gcc and MSVC don't enforce it, 'this->' is required
- // by the C++ standard [14.6.4] here, as the base class type is
- // dependent on the template argument (and thus shouldn't be
- // looked into when resolving InvokeWith).
- return this->InvokeWith(ArgumentTuple(a1, a2, a3, a4, a5, a6, a7, a8));
- }
-};
-
-template <typename R, typename A1, typename A2, typename A3, typename A4,
- typename A5, typename A6, typename A7, typename A8, typename A9>
-class FunctionMocker<R(A1, A2, A3, A4, A5, A6, A7, A8, A9)> : public
- internal::FunctionMockerBase<R(A1, A2, A3, A4, A5, A6, A7, A8, A9)> {
- public:
- typedef R F(A1, A2, A3, A4, A5, A6, A7, A8, A9);
- typedef typename internal::Function<F>::ArgumentTuple ArgumentTuple;
-
- MockSpec<F>& With(const Matcher<A1>& m1, const Matcher<A2>& m2,
- const Matcher<A3>& m3, const Matcher<A4>& m4, const Matcher<A5>& m5,
- const Matcher<A6>& m6, const Matcher<A7>& m7, const Matcher<A8>& m8,
- const Matcher<A9>& m9) {
- this->current_spec().SetMatchers(::testing::make_tuple(m1, m2, m3, m4, m5,
- m6, m7, m8, m9));
- return this->current_spec();
- }
-
- R Invoke(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9) {
- // Even though gcc and MSVC don't enforce it, 'this->' is required
- // by the C++ standard [14.6.4] here, as the base class type is
- // dependent on the template argument (and thus shouldn't be
- // looked into when resolving InvokeWith).
- return this->InvokeWith(ArgumentTuple(a1, a2, a3, a4, a5, a6, a7, a8, a9));
- }
-};
-
-template <typename R, typename A1, typename A2, typename A3, typename A4,
- typename A5, typename A6, typename A7, typename A8, typename A9,
- typename A10>
-class FunctionMocker<R(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10)> : public
- internal::FunctionMockerBase<R(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10)> {
- public:
- typedef R F(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10);
- typedef typename internal::Function<F>::ArgumentTuple ArgumentTuple;
-
- MockSpec<F>& With(const Matcher<A1>& m1, const Matcher<A2>& m2,
- const Matcher<A3>& m3, const Matcher<A4>& m4, const Matcher<A5>& m5,
- const Matcher<A6>& m6, const Matcher<A7>& m7, const Matcher<A8>& m8,
- const Matcher<A9>& m9, const Matcher<A10>& m10) {
- this->current_spec().SetMatchers(::testing::make_tuple(m1, m2, m3, m4, m5,
- m6, m7, m8, m9, m10));
- return this->current_spec();
- }
-
- R Invoke(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9,
- A10 a10) {
- // Even though gcc and MSVC don't enforce it, 'this->' is required
- // by the C++ standard [14.6.4] here, as the base class type is
- // dependent on the template argument (and thus shouldn't be
- // looked into when resolving InvokeWith).
- return this->InvokeWith(ArgumentTuple(a1, a2, a3, a4, a5, a6, a7, a8, a9,
- a10));
- }
-};
+// Removes the given pointer; this is a helper for the expectation setter method
+// for parameterless matchers.
+//
+// We want to make sure that the user cannot set a parameterless expectation on
+// overloaded methods, including methods which are overloaded on const. Example:
+//
+// class MockClass {
+// MOCK_METHOD0(GetName, string&());
+// MOCK_CONST_METHOD0(GetName, const string&());
+// };
+//
+// TEST() {
+// // This should be an error, as it's not clear which overload is expected.
+// EXPECT_CALL(mock, GetName).WillOnce(ReturnRef(value));
+// }
+//
+// Here are the generated expectation-setter methods:
+//
+// class MockClass {
+// // Overload 1
+// MockSpec<string&()> gmock_GetName() { ... }
+// // Overload 2. Declared const so that the compiler will generate an
+// // error when trying to resolve between this and overload 4 in
+// // 'gmock_GetName(WithoutMatchers(), nullptr)'.
+// MockSpec<string&()> gmock_GetName(
+// const WithoutMatchers&, const Function<string&()>*) const {
+// // Removes const from this, calls overload 1
+// return AdjustConstness_(this)->gmock_GetName();
+// }
+//
+// // Overload 3
+// const string& gmock_GetName() const { ... }
+// // Overload 4
+// MockSpec<const string&()> gmock_GetName(
+// const WithoutMatchers&, const Function<const string&()>*) const {
+// // Does not remove const, calls overload 3
+// return AdjustConstness_const(this)->gmock_GetName();
+// }
+// }
+//
+template <typename MockType>
+const MockType* AdjustConstness_const(const MockType* mock) {
+ return mock;
+}
+
+// Removes const from and returns the given pointer; this is a helper for the
+// expectation setter method for parameterless matchers.
+template <typename MockType>
+MockType* AdjustConstness_(const MockType* mock) {
+ return const_cast<MockType*>(mock);
+}
} // namespace internal
@@ -340,7 +121,7 @@ using internal::FunctionMocker;
// The type of argument N of the given function type.
// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!!
#define GMOCK_ARG_(tn, N, ...) \
- tn ::testing::internal::Function<__VA_ARGS__>::Argument##N
+ tn ::testing::internal::Function<__VA_ARGS__>::template Arg<N-1>::type
// The matcher type for argument N of the given function type.
// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!!
@@ -354,78 +135,101 @@ using internal::FunctionMocker;
// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!!
#define GMOCK_METHOD0_(tn, constness, ct, Method, ...) \
+ static_assert(0 == \
+ ::testing::internal::Function<__VA_ARGS__>::ArgumentCount, \
+ "MOCK_METHOD<N> must match argument count.");\
GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \
) constness { \
- GTEST_COMPILE_ASSERT_((::testing::tuple_size< \
- tn ::testing::internal::Function<__VA_ARGS__>::ArgumentTuple>::value \
- == 0), \
- this_method_does_not_take_0_arguments); \
GMOCK_MOCKER_(0, constness, Method).SetOwnerAndName(this, #Method); \
return GMOCK_MOCKER_(0, constness, Method).Invoke(); \
} \
- ::testing::MockSpec<__VA_ARGS__>& \
+ ::testing::MockSpec<__VA_ARGS__> \
gmock_##Method() constness { \
GMOCK_MOCKER_(0, constness, Method).RegisterOwner(this); \
return GMOCK_MOCKER_(0, constness, Method).With(); \
} \
+ ::testing::MockSpec<__VA_ARGS__> gmock_##Method( \
+ const ::testing::internal::WithoutMatchers&, \
+ constness ::testing::internal::Function<__VA_ARGS__>* ) const { \
+ return ::testing::internal::AdjustConstness_##constness(this)-> \
+ gmock_##Method(); \
+ } \
mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_(0, constness, \
Method)
// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!!
#define GMOCK_METHOD1_(tn, constness, ct, Method, ...) \
+ static_assert(1 == \
+ ::testing::internal::Function<__VA_ARGS__>::ArgumentCount, \
+ "MOCK_METHOD<N> must match argument count.");\
GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \
GMOCK_ARG_(tn, 1, __VA_ARGS__) gmock_a1) constness { \
- GTEST_COMPILE_ASSERT_((::testing::tuple_size< \
- tn ::testing::internal::Function<__VA_ARGS__>::ArgumentTuple>::value \
- == 1), \
- this_method_does_not_take_1_argument); \
GMOCK_MOCKER_(1, constness, Method).SetOwnerAndName(this, #Method); \
- return GMOCK_MOCKER_(1, constness, Method).Invoke(gmock_a1); \
+ return GMOCK_MOCKER_(1, constness, \
+ Method).Invoke(::std::forward<GMOCK_ARG_(tn, 1, \
+ __VA_ARGS__)>(gmock_a1)); \
} \
- ::testing::MockSpec<__VA_ARGS__>& \
+ ::testing::MockSpec<__VA_ARGS__> \
gmock_##Method(GMOCK_MATCHER_(tn, 1, __VA_ARGS__) gmock_a1) constness { \
GMOCK_MOCKER_(1, constness, Method).RegisterOwner(this); \
return GMOCK_MOCKER_(1, constness, Method).With(gmock_a1); \
} \
+ ::testing::MockSpec<__VA_ARGS__> gmock_##Method( \
+ const ::testing::internal::WithoutMatchers&, \
+ constness ::testing::internal::Function<__VA_ARGS__>* ) const { \
+ return ::testing::internal::AdjustConstness_##constness(this)-> \
+ gmock_##Method(::testing::A<GMOCK_ARG_(tn, 1, __VA_ARGS__)>()); \
+ } \
mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_(1, constness, \
Method)
// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!!
#define GMOCK_METHOD2_(tn, constness, ct, Method, ...) \
+ static_assert(2 == \
+ ::testing::internal::Function<__VA_ARGS__>::ArgumentCount, \
+ "MOCK_METHOD<N> must match argument count.");\
GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \
- GMOCK_ARG_(tn, 1, __VA_ARGS__) gmock_a1, \
- GMOCK_ARG_(tn, 2, __VA_ARGS__) gmock_a2) constness { \
- GTEST_COMPILE_ASSERT_((::testing::tuple_size< \
- tn ::testing::internal::Function<__VA_ARGS__>::ArgumentTuple>::value \
- == 2), \
- this_method_does_not_take_2_arguments); \
+ GMOCK_ARG_(tn, 1, __VA_ARGS__) gmock_a1, GMOCK_ARG_(tn, 2, \
+ __VA_ARGS__) gmock_a2) constness { \
GMOCK_MOCKER_(2, constness, Method).SetOwnerAndName(this, #Method); \
- return GMOCK_MOCKER_(2, constness, Method).Invoke(gmock_a1, gmock_a2); \
+ return GMOCK_MOCKER_(2, constness, \
+ Method).Invoke(::std::forward<GMOCK_ARG_(tn, 1, \
+ __VA_ARGS__)>(gmock_a1), \
+ ::std::forward<GMOCK_ARG_(tn, 2, __VA_ARGS__)>(gmock_a2)); \
} \
- ::testing::MockSpec<__VA_ARGS__>& \
+ ::testing::MockSpec<__VA_ARGS__> \
gmock_##Method(GMOCK_MATCHER_(tn, 1, __VA_ARGS__) gmock_a1, \
GMOCK_MATCHER_(tn, 2, __VA_ARGS__) gmock_a2) constness { \
GMOCK_MOCKER_(2, constness, Method).RegisterOwner(this); \
return GMOCK_MOCKER_(2, constness, Method).With(gmock_a1, gmock_a2); \
} \
+ ::testing::MockSpec<__VA_ARGS__> gmock_##Method( \
+ const ::testing::internal::WithoutMatchers&, \
+ constness ::testing::internal::Function<__VA_ARGS__>* ) const { \
+ return ::testing::internal::AdjustConstness_##constness(this)-> \
+ gmock_##Method(::testing::A<GMOCK_ARG_(tn, 1, __VA_ARGS__)>(), \
+ ::testing::A<GMOCK_ARG_(tn, 2, __VA_ARGS__)>()); \
+ } \
mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_(2, constness, \
Method)
// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!!
#define GMOCK_METHOD3_(tn, constness, ct, Method, ...) \
+ static_assert(3 == \
+ ::testing::internal::Function<__VA_ARGS__>::ArgumentCount, \
+ "MOCK_METHOD<N> must match argument count.");\
GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \
- GMOCK_ARG_(tn, 1, __VA_ARGS__) gmock_a1, \
- GMOCK_ARG_(tn, 2, __VA_ARGS__) gmock_a2, \
- GMOCK_ARG_(tn, 3, __VA_ARGS__) gmock_a3) constness { \
- GTEST_COMPILE_ASSERT_((::testing::tuple_size< \
- tn ::testing::internal::Function<__VA_ARGS__>::ArgumentTuple>::value \
- == 3), \
- this_method_does_not_take_3_arguments); \
+ GMOCK_ARG_(tn, 1, __VA_ARGS__) gmock_a1, GMOCK_ARG_(tn, 2, \
+ __VA_ARGS__) gmock_a2, GMOCK_ARG_(tn, 3, \
+ __VA_ARGS__) gmock_a3) constness { \
GMOCK_MOCKER_(3, constness, Method).SetOwnerAndName(this, #Method); \
- return GMOCK_MOCKER_(3, constness, Method).Invoke(gmock_a1, gmock_a2, \
- gmock_a3); \
+ return GMOCK_MOCKER_(3, constness, \
+ Method).Invoke(::std::forward<GMOCK_ARG_(tn, 1, \
+ __VA_ARGS__)>(gmock_a1), \
+ ::std::forward<GMOCK_ARG_(tn, 2, __VA_ARGS__)>(gmock_a2), \
+ ::std::forward<GMOCK_ARG_(tn, 3, __VA_ARGS__)>(gmock_a3)); \
} \
- ::testing::MockSpec<__VA_ARGS__>& \
+ ::testing::MockSpec<__VA_ARGS__> \
gmock_##Method(GMOCK_MATCHER_(tn, 1, __VA_ARGS__) gmock_a1, \
GMOCK_MATCHER_(tn, 2, __VA_ARGS__) gmock_a2, \
GMOCK_MATCHER_(tn, 3, __VA_ARGS__) gmock_a3) constness { \
@@ -433,25 +237,35 @@ using internal::FunctionMocker;
return GMOCK_MOCKER_(3, constness, Method).With(gmock_a1, gmock_a2, \
gmock_a3); \
} \
+ ::testing::MockSpec<__VA_ARGS__> gmock_##Method( \
+ const ::testing::internal::WithoutMatchers&, \
+ constness ::testing::internal::Function<__VA_ARGS__>* ) const { \
+ return ::testing::internal::AdjustConstness_##constness(this)-> \
+ gmock_##Method(::testing::A<GMOCK_ARG_(tn, 1, __VA_ARGS__)>(), \
+ ::testing::A<GMOCK_ARG_(tn, 2, __VA_ARGS__)>(), \
+ ::testing::A<GMOCK_ARG_(tn, 3, __VA_ARGS__)>()); \
+ } \
mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_(3, constness, \
Method)
// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!!
#define GMOCK_METHOD4_(tn, constness, ct, Method, ...) \
+ static_assert(4 == \
+ ::testing::internal::Function<__VA_ARGS__>::ArgumentCount, \
+ "MOCK_METHOD<N> must match argument count.");\
GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \
- GMOCK_ARG_(tn, 1, __VA_ARGS__) gmock_a1, \
- GMOCK_ARG_(tn, 2, __VA_ARGS__) gmock_a2, \
- GMOCK_ARG_(tn, 3, __VA_ARGS__) gmock_a3, \
- GMOCK_ARG_(tn, 4, __VA_ARGS__) gmock_a4) constness { \
- GTEST_COMPILE_ASSERT_((::testing::tuple_size< \
- tn ::testing::internal::Function<__VA_ARGS__>::ArgumentTuple>::value \
- == 4), \
- this_method_does_not_take_4_arguments); \
+ GMOCK_ARG_(tn, 1, __VA_ARGS__) gmock_a1, GMOCK_ARG_(tn, 2, \
+ __VA_ARGS__) gmock_a2, GMOCK_ARG_(tn, 3, __VA_ARGS__) gmock_a3, \
+ GMOCK_ARG_(tn, 4, __VA_ARGS__) gmock_a4) constness { \
GMOCK_MOCKER_(4, constness, Method).SetOwnerAndName(this, #Method); \
- return GMOCK_MOCKER_(4, constness, Method).Invoke(gmock_a1, gmock_a2, \
- gmock_a3, gmock_a4); \
+ return GMOCK_MOCKER_(4, constness, \
+ Method).Invoke(::std::forward<GMOCK_ARG_(tn, 1, \
+ __VA_ARGS__)>(gmock_a1), \
+ ::std::forward<GMOCK_ARG_(tn, 2, __VA_ARGS__)>(gmock_a2), \
+ ::std::forward<GMOCK_ARG_(tn, 3, __VA_ARGS__)>(gmock_a3), \
+ ::std::forward<GMOCK_ARG_(tn, 4, __VA_ARGS__)>(gmock_a4)); \
} \
- ::testing::MockSpec<__VA_ARGS__>& \
+ ::testing::MockSpec<__VA_ARGS__> \
gmock_##Method(GMOCK_MATCHER_(tn, 1, __VA_ARGS__) gmock_a1, \
GMOCK_MATCHER_(tn, 2, __VA_ARGS__) gmock_a2, \
GMOCK_MATCHER_(tn, 3, __VA_ARGS__) gmock_a3, \
@@ -460,26 +274,38 @@ using internal::FunctionMocker;
return GMOCK_MOCKER_(4, constness, Method).With(gmock_a1, gmock_a2, \
gmock_a3, gmock_a4); \
} \
+ ::testing::MockSpec<__VA_ARGS__> gmock_##Method( \
+ const ::testing::internal::WithoutMatchers&, \
+ constness ::testing::internal::Function<__VA_ARGS__>* ) const { \
+ return ::testing::internal::AdjustConstness_##constness(this)-> \
+ gmock_##Method(::testing::A<GMOCK_ARG_(tn, 1, __VA_ARGS__)>(), \
+ ::testing::A<GMOCK_ARG_(tn, 2, __VA_ARGS__)>(), \
+ ::testing::A<GMOCK_ARG_(tn, 3, __VA_ARGS__)>(), \
+ ::testing::A<GMOCK_ARG_(tn, 4, __VA_ARGS__)>()); \
+ } \
mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_(4, constness, \
Method)
// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!!
#define GMOCK_METHOD5_(tn, constness, ct, Method, ...) \
+ static_assert(5 == \
+ ::testing::internal::Function<__VA_ARGS__>::ArgumentCount, \
+ "MOCK_METHOD<N> must match argument count.");\
GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \
- GMOCK_ARG_(tn, 1, __VA_ARGS__) gmock_a1, \
- GMOCK_ARG_(tn, 2, __VA_ARGS__) gmock_a2, \
- GMOCK_ARG_(tn, 3, __VA_ARGS__) gmock_a3, \
- GMOCK_ARG_(tn, 4, __VA_ARGS__) gmock_a4, \
- GMOCK_ARG_(tn, 5, __VA_ARGS__) gmock_a5) constness { \
- GTEST_COMPILE_ASSERT_((::testing::tuple_size< \
- tn ::testing::internal::Function<__VA_ARGS__>::ArgumentTuple>::value \
- == 5), \
- this_method_does_not_take_5_arguments); \
+ GMOCK_ARG_(tn, 1, __VA_ARGS__) gmock_a1, GMOCK_ARG_(tn, 2, \
+ __VA_ARGS__) gmock_a2, GMOCK_ARG_(tn, 3, __VA_ARGS__) gmock_a3, \
+ GMOCK_ARG_(tn, 4, __VA_ARGS__) gmock_a4, GMOCK_ARG_(tn, 5, \
+ __VA_ARGS__) gmock_a5) constness { \
GMOCK_MOCKER_(5, constness, Method).SetOwnerAndName(this, #Method); \
- return GMOCK_MOCKER_(5, constness, Method).Invoke(gmock_a1, gmock_a2, \
- gmock_a3, gmock_a4, gmock_a5); \
+ return GMOCK_MOCKER_(5, constness, \
+ Method).Invoke(::std::forward<GMOCK_ARG_(tn, 1, \
+ __VA_ARGS__)>(gmock_a1), \
+ ::std::forward<GMOCK_ARG_(tn, 2, __VA_ARGS__)>(gmock_a2), \
+ ::std::forward<GMOCK_ARG_(tn, 3, __VA_ARGS__)>(gmock_a3), \
+ ::std::forward<GMOCK_ARG_(tn, 4, __VA_ARGS__)>(gmock_a4), \
+ ::std::forward<GMOCK_ARG_(tn, 5, __VA_ARGS__)>(gmock_a5)); \
} \
- ::testing::MockSpec<__VA_ARGS__>& \
+ ::testing::MockSpec<__VA_ARGS__> \
gmock_##Method(GMOCK_MATCHER_(tn, 1, __VA_ARGS__) gmock_a1, \
GMOCK_MATCHER_(tn, 2, __VA_ARGS__) gmock_a2, \
GMOCK_MATCHER_(tn, 3, __VA_ARGS__) gmock_a3, \
@@ -489,27 +315,41 @@ using internal::FunctionMocker;
return GMOCK_MOCKER_(5, constness, Method).With(gmock_a1, gmock_a2, \
gmock_a3, gmock_a4, gmock_a5); \
} \
+ ::testing::MockSpec<__VA_ARGS__> gmock_##Method( \
+ const ::testing::internal::WithoutMatchers&, \
+ constness ::testing::internal::Function<__VA_ARGS__>* ) const { \
+ return ::testing::internal::AdjustConstness_##constness(this)-> \
+ gmock_##Method(::testing::A<GMOCK_ARG_(tn, 1, __VA_ARGS__)>(), \
+ ::testing::A<GMOCK_ARG_(tn, 2, __VA_ARGS__)>(), \
+ ::testing::A<GMOCK_ARG_(tn, 3, __VA_ARGS__)>(), \
+ ::testing::A<GMOCK_ARG_(tn, 4, __VA_ARGS__)>(), \
+ ::testing::A<GMOCK_ARG_(tn, 5, __VA_ARGS__)>()); \
+ } \
mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_(5, constness, \
Method)
// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!!
#define GMOCK_METHOD6_(tn, constness, ct, Method, ...) \
+ static_assert(6 == \
+ ::testing::internal::Function<__VA_ARGS__>::ArgumentCount, \
+ "MOCK_METHOD<N> must match argument count.");\
GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \
- GMOCK_ARG_(tn, 1, __VA_ARGS__) gmock_a1, \
- GMOCK_ARG_(tn, 2, __VA_ARGS__) gmock_a2, \
- GMOCK_ARG_(tn, 3, __VA_ARGS__) gmock_a3, \
- GMOCK_ARG_(tn, 4, __VA_ARGS__) gmock_a4, \
- GMOCK_ARG_(tn, 5, __VA_ARGS__) gmock_a5, \
- GMOCK_ARG_(tn, 6, __VA_ARGS__) gmock_a6) constness { \
- GTEST_COMPILE_ASSERT_((::testing::tuple_size< \
- tn ::testing::internal::Function<__VA_ARGS__>::ArgumentTuple>::value \
- == 6), \
- this_method_does_not_take_6_arguments); \
+ GMOCK_ARG_(tn, 1, __VA_ARGS__) gmock_a1, GMOCK_ARG_(tn, 2, \
+ __VA_ARGS__) gmock_a2, GMOCK_ARG_(tn, 3, __VA_ARGS__) gmock_a3, \
+ GMOCK_ARG_(tn, 4, __VA_ARGS__) gmock_a4, GMOCK_ARG_(tn, 5, \
+ __VA_ARGS__) gmock_a5, GMOCK_ARG_(tn, 6, \
+ __VA_ARGS__) gmock_a6) constness { \
GMOCK_MOCKER_(6, constness, Method).SetOwnerAndName(this, #Method); \
- return GMOCK_MOCKER_(6, constness, Method).Invoke(gmock_a1, gmock_a2, \
- gmock_a3, gmock_a4, gmock_a5, gmock_a6); \
+ return GMOCK_MOCKER_(6, constness, \
+ Method).Invoke(::std::forward<GMOCK_ARG_(tn, 1, \
+ __VA_ARGS__)>(gmock_a1), \
+ ::std::forward<GMOCK_ARG_(tn, 2, __VA_ARGS__)>(gmock_a2), \
+ ::std::forward<GMOCK_ARG_(tn, 3, __VA_ARGS__)>(gmock_a3), \
+ ::std::forward<GMOCK_ARG_(tn, 4, __VA_ARGS__)>(gmock_a4), \
+ ::std::forward<GMOCK_ARG_(tn, 5, __VA_ARGS__)>(gmock_a5), \
+ ::std::forward<GMOCK_ARG_(tn, 6, __VA_ARGS__)>(gmock_a6)); \
} \
- ::testing::MockSpec<__VA_ARGS__>& \
+ ::testing::MockSpec<__VA_ARGS__> \
gmock_##Method(GMOCK_MATCHER_(tn, 1, __VA_ARGS__) gmock_a1, \
GMOCK_MATCHER_(tn, 2, __VA_ARGS__) gmock_a2, \
GMOCK_MATCHER_(tn, 3, __VA_ARGS__) gmock_a3, \
@@ -520,28 +360,43 @@ using internal::FunctionMocker;
return GMOCK_MOCKER_(6, constness, Method).With(gmock_a1, gmock_a2, \
gmock_a3, gmock_a4, gmock_a5, gmock_a6); \
} \
+ ::testing::MockSpec<__VA_ARGS__> gmock_##Method( \
+ const ::testing::internal::WithoutMatchers&, \
+ constness ::testing::internal::Function<__VA_ARGS__>* ) const { \
+ return ::testing::internal::AdjustConstness_##constness(this)-> \
+ gmock_##Method(::testing::A<GMOCK_ARG_(tn, 1, __VA_ARGS__)>(), \
+ ::testing::A<GMOCK_ARG_(tn, 2, __VA_ARGS__)>(), \
+ ::testing::A<GMOCK_ARG_(tn, 3, __VA_ARGS__)>(), \
+ ::testing::A<GMOCK_ARG_(tn, 4, __VA_ARGS__)>(), \
+ ::testing::A<GMOCK_ARG_(tn, 5, __VA_ARGS__)>(), \
+ ::testing::A<GMOCK_ARG_(tn, 6, __VA_ARGS__)>()); \
+ } \
mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_(6, constness, \
Method)
// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!!
#define GMOCK_METHOD7_(tn, constness, ct, Method, ...) \
+ static_assert(7 == \
+ ::testing::internal::Function<__VA_ARGS__>::ArgumentCount, \
+ "MOCK_METHOD<N> must match argument count.");\
GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \
- GMOCK_ARG_(tn, 1, __VA_ARGS__) gmock_a1, \
- GMOCK_ARG_(tn, 2, __VA_ARGS__) gmock_a2, \
- GMOCK_ARG_(tn, 3, __VA_ARGS__) gmock_a3, \
- GMOCK_ARG_(tn, 4, __VA_ARGS__) gmock_a4, \
- GMOCK_ARG_(tn, 5, __VA_ARGS__) gmock_a5, \
- GMOCK_ARG_(tn, 6, __VA_ARGS__) gmock_a6, \
- GMOCK_ARG_(tn, 7, __VA_ARGS__) gmock_a7) constness { \
- GTEST_COMPILE_ASSERT_((::testing::tuple_size< \
- tn ::testing::internal::Function<__VA_ARGS__>::ArgumentTuple>::value \
- == 7), \
- this_method_does_not_take_7_arguments); \
+ GMOCK_ARG_(tn, 1, __VA_ARGS__) gmock_a1, GMOCK_ARG_(tn, 2, \
+ __VA_ARGS__) gmock_a2, GMOCK_ARG_(tn, 3, __VA_ARGS__) gmock_a3, \
+ GMOCK_ARG_(tn, 4, __VA_ARGS__) gmock_a4, GMOCK_ARG_(tn, 5, \
+ __VA_ARGS__) gmock_a5, GMOCK_ARG_(tn, 6, __VA_ARGS__) gmock_a6, \
+ GMOCK_ARG_(tn, 7, __VA_ARGS__) gmock_a7) constness { \
GMOCK_MOCKER_(7, constness, Method).SetOwnerAndName(this, #Method); \
- return GMOCK_MOCKER_(7, constness, Method).Invoke(gmock_a1, gmock_a2, \
- gmock_a3, gmock_a4, gmock_a5, gmock_a6, gmock_a7); \
+ return GMOCK_MOCKER_(7, constness, \
+ Method).Invoke(::std::forward<GMOCK_ARG_(tn, 1, \
+ __VA_ARGS__)>(gmock_a1), \
+ ::std::forward<GMOCK_ARG_(tn, 2, __VA_ARGS__)>(gmock_a2), \
+ ::std::forward<GMOCK_ARG_(tn, 3, __VA_ARGS__)>(gmock_a3), \
+ ::std::forward<GMOCK_ARG_(tn, 4, __VA_ARGS__)>(gmock_a4), \
+ ::std::forward<GMOCK_ARG_(tn, 5, __VA_ARGS__)>(gmock_a5), \
+ ::std::forward<GMOCK_ARG_(tn, 6, __VA_ARGS__)>(gmock_a6), \
+ ::std::forward<GMOCK_ARG_(tn, 7, __VA_ARGS__)>(gmock_a7)); \
} \
- ::testing::MockSpec<__VA_ARGS__>& \
+ ::testing::MockSpec<__VA_ARGS__> \
gmock_##Method(GMOCK_MATCHER_(tn, 1, __VA_ARGS__) gmock_a1, \
GMOCK_MATCHER_(tn, 2, __VA_ARGS__) gmock_a2, \
GMOCK_MATCHER_(tn, 3, __VA_ARGS__) gmock_a3, \
@@ -553,29 +408,46 @@ using internal::FunctionMocker;
return GMOCK_MOCKER_(7, constness, Method).With(gmock_a1, gmock_a2, \
gmock_a3, gmock_a4, gmock_a5, gmock_a6, gmock_a7); \
} \
+ ::testing::MockSpec<__VA_ARGS__> gmock_##Method( \
+ const ::testing::internal::WithoutMatchers&, \
+ constness ::testing::internal::Function<__VA_ARGS__>* ) const { \
+ return ::testing::internal::AdjustConstness_##constness(this)-> \
+ gmock_##Method(::testing::A<GMOCK_ARG_(tn, 1, __VA_ARGS__)>(), \
+ ::testing::A<GMOCK_ARG_(tn, 2, __VA_ARGS__)>(), \
+ ::testing::A<GMOCK_ARG_(tn, 3, __VA_ARGS__)>(), \
+ ::testing::A<GMOCK_ARG_(tn, 4, __VA_ARGS__)>(), \
+ ::testing::A<GMOCK_ARG_(tn, 5, __VA_ARGS__)>(), \
+ ::testing::A<GMOCK_ARG_(tn, 6, __VA_ARGS__)>(), \
+ ::testing::A<GMOCK_ARG_(tn, 7, __VA_ARGS__)>()); \
+ } \
mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_(7, constness, \
Method)
// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!!
#define GMOCK_METHOD8_(tn, constness, ct, Method, ...) \
+ static_assert(8 == \
+ ::testing::internal::Function<__VA_ARGS__>::ArgumentCount, \
+ "MOCK_METHOD<N> must match argument count.");\
GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \
- GMOCK_ARG_(tn, 1, __VA_ARGS__) gmock_a1, \
- GMOCK_ARG_(tn, 2, __VA_ARGS__) gmock_a2, \
- GMOCK_ARG_(tn, 3, __VA_ARGS__) gmock_a3, \
- GMOCK_ARG_(tn, 4, __VA_ARGS__) gmock_a4, \
- GMOCK_ARG_(tn, 5, __VA_ARGS__) gmock_a5, \
- GMOCK_ARG_(tn, 6, __VA_ARGS__) gmock_a6, \
- GMOCK_ARG_(tn, 7, __VA_ARGS__) gmock_a7, \
- GMOCK_ARG_(tn, 8, __VA_ARGS__) gmock_a8) constness { \
- GTEST_COMPILE_ASSERT_((::testing::tuple_size< \
- tn ::testing::internal::Function<__VA_ARGS__>::ArgumentTuple>::value \
- == 8), \
- this_method_does_not_take_8_arguments); \
+ GMOCK_ARG_(tn, 1, __VA_ARGS__) gmock_a1, GMOCK_ARG_(tn, 2, \
+ __VA_ARGS__) gmock_a2, GMOCK_ARG_(tn, 3, __VA_ARGS__) gmock_a3, \
+ GMOCK_ARG_(tn, 4, __VA_ARGS__) gmock_a4, GMOCK_ARG_(tn, 5, \
+ __VA_ARGS__) gmock_a5, GMOCK_ARG_(tn, 6, __VA_ARGS__) gmock_a6, \
+ GMOCK_ARG_(tn, 7, __VA_ARGS__) gmock_a7, GMOCK_ARG_(tn, 8, \
+ __VA_ARGS__) gmock_a8) constness { \
GMOCK_MOCKER_(8, constness, Method).SetOwnerAndName(this, #Method); \
- return GMOCK_MOCKER_(8, constness, Method).Invoke(gmock_a1, gmock_a2, \
- gmock_a3, gmock_a4, gmock_a5, gmock_a6, gmock_a7, gmock_a8); \
+ return GMOCK_MOCKER_(8, constness, \
+ Method).Invoke(::std::forward<GMOCK_ARG_(tn, 1, \
+ __VA_ARGS__)>(gmock_a1), \
+ ::std::forward<GMOCK_ARG_(tn, 2, __VA_ARGS__)>(gmock_a2), \
+ ::std::forward<GMOCK_ARG_(tn, 3, __VA_ARGS__)>(gmock_a3), \
+ ::std::forward<GMOCK_ARG_(tn, 4, __VA_ARGS__)>(gmock_a4), \
+ ::std::forward<GMOCK_ARG_(tn, 5, __VA_ARGS__)>(gmock_a5), \
+ ::std::forward<GMOCK_ARG_(tn, 6, __VA_ARGS__)>(gmock_a6), \
+ ::std::forward<GMOCK_ARG_(tn, 7, __VA_ARGS__)>(gmock_a7), \
+ ::std::forward<GMOCK_ARG_(tn, 8, __VA_ARGS__)>(gmock_a8)); \
} \
- ::testing::MockSpec<__VA_ARGS__>& \
+ ::testing::MockSpec<__VA_ARGS__> \
gmock_##Method(GMOCK_MATCHER_(tn, 1, __VA_ARGS__) gmock_a1, \
GMOCK_MATCHER_(tn, 2, __VA_ARGS__) gmock_a2, \
GMOCK_MATCHER_(tn, 3, __VA_ARGS__) gmock_a3, \
@@ -588,31 +460,49 @@ using internal::FunctionMocker;
return GMOCK_MOCKER_(8, constness, Method).With(gmock_a1, gmock_a2, \
gmock_a3, gmock_a4, gmock_a5, gmock_a6, gmock_a7, gmock_a8); \
} \
+ ::testing::MockSpec<__VA_ARGS__> gmock_##Method( \
+ const ::testing::internal::WithoutMatchers&, \
+ constness ::testing::internal::Function<__VA_ARGS__>* ) const { \
+ return ::testing::internal::AdjustConstness_##constness(this)-> \
+ gmock_##Method(::testing::A<GMOCK_ARG_(tn, 1, __VA_ARGS__)>(), \
+ ::testing::A<GMOCK_ARG_(tn, 2, __VA_ARGS__)>(), \
+ ::testing::A<GMOCK_ARG_(tn, 3, __VA_ARGS__)>(), \
+ ::testing::A<GMOCK_ARG_(tn, 4, __VA_ARGS__)>(), \
+ ::testing::A<GMOCK_ARG_(tn, 5, __VA_ARGS__)>(), \
+ ::testing::A<GMOCK_ARG_(tn, 6, __VA_ARGS__)>(), \
+ ::testing::A<GMOCK_ARG_(tn, 7, __VA_ARGS__)>(), \
+ ::testing::A<GMOCK_ARG_(tn, 8, __VA_ARGS__)>()); \
+ } \
mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_(8, constness, \
Method)
// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!!
#define GMOCK_METHOD9_(tn, constness, ct, Method, ...) \
+ static_assert(9 == \
+ ::testing::internal::Function<__VA_ARGS__>::ArgumentCount, \
+ "MOCK_METHOD<N> must match argument count.");\
GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \
- GMOCK_ARG_(tn, 1, __VA_ARGS__) gmock_a1, \
- GMOCK_ARG_(tn, 2, __VA_ARGS__) gmock_a2, \
- GMOCK_ARG_(tn, 3, __VA_ARGS__) gmock_a3, \
- GMOCK_ARG_(tn, 4, __VA_ARGS__) gmock_a4, \
- GMOCK_ARG_(tn, 5, __VA_ARGS__) gmock_a5, \
- GMOCK_ARG_(tn, 6, __VA_ARGS__) gmock_a6, \
- GMOCK_ARG_(tn, 7, __VA_ARGS__) gmock_a7, \
- GMOCK_ARG_(tn, 8, __VA_ARGS__) gmock_a8, \
- GMOCK_ARG_(tn, 9, __VA_ARGS__) gmock_a9) constness { \
- GTEST_COMPILE_ASSERT_((::testing::tuple_size< \
- tn ::testing::internal::Function<__VA_ARGS__>::ArgumentTuple>::value \
- == 9), \
- this_method_does_not_take_9_arguments); \
+ GMOCK_ARG_(tn, 1, __VA_ARGS__) gmock_a1, GMOCK_ARG_(tn, 2, \
+ __VA_ARGS__) gmock_a2, GMOCK_ARG_(tn, 3, __VA_ARGS__) gmock_a3, \
+ GMOCK_ARG_(tn, 4, __VA_ARGS__) gmock_a4, GMOCK_ARG_(tn, 5, \
+ __VA_ARGS__) gmock_a5, GMOCK_ARG_(tn, 6, __VA_ARGS__) gmock_a6, \
+ GMOCK_ARG_(tn, 7, __VA_ARGS__) gmock_a7, GMOCK_ARG_(tn, 8, \
+ __VA_ARGS__) gmock_a8, GMOCK_ARG_(tn, 9, \
+ __VA_ARGS__) gmock_a9) constness { \
GMOCK_MOCKER_(9, constness, Method).SetOwnerAndName(this, #Method); \
- return GMOCK_MOCKER_(9, constness, Method).Invoke(gmock_a1, gmock_a2, \
- gmock_a3, gmock_a4, gmock_a5, gmock_a6, gmock_a7, gmock_a8, \
- gmock_a9); \
+ return GMOCK_MOCKER_(9, constness, \
+ Method).Invoke(::std::forward<GMOCK_ARG_(tn, 1, \
+ __VA_ARGS__)>(gmock_a1), \
+ ::std::forward<GMOCK_ARG_(tn, 2, __VA_ARGS__)>(gmock_a2), \
+ ::std::forward<GMOCK_ARG_(tn, 3, __VA_ARGS__)>(gmock_a3), \
+ ::std::forward<GMOCK_ARG_(tn, 4, __VA_ARGS__)>(gmock_a4), \
+ ::std::forward<GMOCK_ARG_(tn, 5, __VA_ARGS__)>(gmock_a5), \
+ ::std::forward<GMOCK_ARG_(tn, 6, __VA_ARGS__)>(gmock_a6), \
+ ::std::forward<GMOCK_ARG_(tn, 7, __VA_ARGS__)>(gmock_a7), \
+ ::std::forward<GMOCK_ARG_(tn, 8, __VA_ARGS__)>(gmock_a8), \
+ ::std::forward<GMOCK_ARG_(tn, 9, __VA_ARGS__)>(gmock_a9)); \
} \
- ::testing::MockSpec<__VA_ARGS__>& \
+ ::testing::MockSpec<__VA_ARGS__> \
gmock_##Method(GMOCK_MATCHER_(tn, 1, __VA_ARGS__) gmock_a1, \
GMOCK_MATCHER_(tn, 2, __VA_ARGS__) gmock_a2, \
GMOCK_MATCHER_(tn, 3, __VA_ARGS__) gmock_a3, \
@@ -627,32 +517,51 @@ using internal::FunctionMocker;
gmock_a3, gmock_a4, gmock_a5, gmock_a6, gmock_a7, gmock_a8, \
gmock_a9); \
} \
+ ::testing::MockSpec<__VA_ARGS__> gmock_##Method( \
+ const ::testing::internal::WithoutMatchers&, \
+ constness ::testing::internal::Function<__VA_ARGS__>* ) const { \
+ return ::testing::internal::AdjustConstness_##constness(this)-> \
+ gmock_##Method(::testing::A<GMOCK_ARG_(tn, 1, __VA_ARGS__)>(), \
+ ::testing::A<GMOCK_ARG_(tn, 2, __VA_ARGS__)>(), \
+ ::testing::A<GMOCK_ARG_(tn, 3, __VA_ARGS__)>(), \
+ ::testing::A<GMOCK_ARG_(tn, 4, __VA_ARGS__)>(), \
+ ::testing::A<GMOCK_ARG_(tn, 5, __VA_ARGS__)>(), \
+ ::testing::A<GMOCK_ARG_(tn, 6, __VA_ARGS__)>(), \
+ ::testing::A<GMOCK_ARG_(tn, 7, __VA_ARGS__)>(), \
+ ::testing::A<GMOCK_ARG_(tn, 8, __VA_ARGS__)>(), \
+ ::testing::A<GMOCK_ARG_(tn, 9, __VA_ARGS__)>()); \
+ } \
mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_(9, constness, \
Method)
// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!!
#define GMOCK_METHOD10_(tn, constness, ct, Method, ...) \
+ static_assert(10 == \
+ ::testing::internal::Function<__VA_ARGS__>::ArgumentCount, \
+ "MOCK_METHOD<N> must match argument count.");\
GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \
- GMOCK_ARG_(tn, 1, __VA_ARGS__) gmock_a1, \
- GMOCK_ARG_(tn, 2, __VA_ARGS__) gmock_a2, \
- GMOCK_ARG_(tn, 3, __VA_ARGS__) gmock_a3, \
- GMOCK_ARG_(tn, 4, __VA_ARGS__) gmock_a4, \
- GMOCK_ARG_(tn, 5, __VA_ARGS__) gmock_a5, \
- GMOCK_ARG_(tn, 6, __VA_ARGS__) gmock_a6, \
- GMOCK_ARG_(tn, 7, __VA_ARGS__) gmock_a7, \
- GMOCK_ARG_(tn, 8, __VA_ARGS__) gmock_a8, \
- GMOCK_ARG_(tn, 9, __VA_ARGS__) gmock_a9, \
- GMOCK_ARG_(tn, 10, __VA_ARGS__) gmock_a10) constness { \
- GTEST_COMPILE_ASSERT_((::testing::tuple_size< \
- tn ::testing::internal::Function<__VA_ARGS__>::ArgumentTuple>::value \
- == 10), \
- this_method_does_not_take_10_arguments); \
+ GMOCK_ARG_(tn, 1, __VA_ARGS__) gmock_a1, GMOCK_ARG_(tn, 2, \
+ __VA_ARGS__) gmock_a2, GMOCK_ARG_(tn, 3, __VA_ARGS__) gmock_a3, \
+ GMOCK_ARG_(tn, 4, __VA_ARGS__) gmock_a4, GMOCK_ARG_(tn, 5, \
+ __VA_ARGS__) gmock_a5, GMOCK_ARG_(tn, 6, __VA_ARGS__) gmock_a6, \
+ GMOCK_ARG_(tn, 7, __VA_ARGS__) gmock_a7, GMOCK_ARG_(tn, 8, \
+ __VA_ARGS__) gmock_a8, GMOCK_ARG_(tn, 9, __VA_ARGS__) gmock_a9, \
+ GMOCK_ARG_(tn, 10, __VA_ARGS__) gmock_a10) constness { \
GMOCK_MOCKER_(10, constness, Method).SetOwnerAndName(this, #Method); \
- return GMOCK_MOCKER_(10, constness, Method).Invoke(gmock_a1, gmock_a2, \
- gmock_a3, gmock_a4, gmock_a5, gmock_a6, gmock_a7, gmock_a8, gmock_a9, \
- gmock_a10); \
+ return GMOCK_MOCKER_(10, constness, \
+ Method).Invoke(::std::forward<GMOCK_ARG_(tn, 1, \
+ __VA_ARGS__)>(gmock_a1), \
+ ::std::forward<GMOCK_ARG_(tn, 2, __VA_ARGS__)>(gmock_a2), \
+ ::std::forward<GMOCK_ARG_(tn, 3, __VA_ARGS__)>(gmock_a3), \
+ ::std::forward<GMOCK_ARG_(tn, 4, __VA_ARGS__)>(gmock_a4), \
+ ::std::forward<GMOCK_ARG_(tn, 5, __VA_ARGS__)>(gmock_a5), \
+ ::std::forward<GMOCK_ARG_(tn, 6, __VA_ARGS__)>(gmock_a6), \
+ ::std::forward<GMOCK_ARG_(tn, 7, __VA_ARGS__)>(gmock_a7), \
+ ::std::forward<GMOCK_ARG_(tn, 8, __VA_ARGS__)>(gmock_a8), \
+ ::std::forward<GMOCK_ARG_(tn, 9, __VA_ARGS__)>(gmock_a9), \
+ ::std::forward<GMOCK_ARG_(tn, 10, __VA_ARGS__)>(gmock_a10)); \
} \
- ::testing::MockSpec<__VA_ARGS__>& \
+ ::testing::MockSpec<__VA_ARGS__> \
gmock_##Method(GMOCK_MATCHER_(tn, 1, __VA_ARGS__) gmock_a1, \
GMOCK_MATCHER_(tn, 2, __VA_ARGS__) gmock_a2, \
GMOCK_MATCHER_(tn, 3, __VA_ARGS__) gmock_a3, \
@@ -669,6 +578,21 @@ using internal::FunctionMocker;
gmock_a3, gmock_a4, gmock_a5, gmock_a6, gmock_a7, gmock_a8, gmock_a9, \
gmock_a10); \
} \
+ ::testing::MockSpec<__VA_ARGS__> gmock_##Method( \
+ const ::testing::internal::WithoutMatchers&, \
+ constness ::testing::internal::Function<__VA_ARGS__>* ) const { \
+ return ::testing::internal::AdjustConstness_##constness(this)-> \
+ gmock_##Method(::testing::A<GMOCK_ARG_(tn, 1, __VA_ARGS__)>(), \
+ ::testing::A<GMOCK_ARG_(tn, 2, __VA_ARGS__)>(), \
+ ::testing::A<GMOCK_ARG_(tn, 3, __VA_ARGS__)>(), \
+ ::testing::A<GMOCK_ARG_(tn, 4, __VA_ARGS__)>(), \
+ ::testing::A<GMOCK_ARG_(tn, 5, __VA_ARGS__)>(), \
+ ::testing::A<GMOCK_ARG_(tn, 6, __VA_ARGS__)>(), \
+ ::testing::A<GMOCK_ARG_(tn, 7, __VA_ARGS__)>(), \
+ ::testing::A<GMOCK_ARG_(tn, 8, __VA_ARGS__)>(), \
+ ::testing::A<GMOCK_ARG_(tn, 9, __VA_ARGS__)>(), \
+ ::testing::A<GMOCK_ARG_(tn, 10, __VA_ARGS__)>()); \
+ } \
mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_(10, constness, \
Method)
@@ -823,273 +747,6 @@ using internal::FunctionMocker;
#define MOCK_CONST_METHOD10_T_WITH_CALLTYPE(ct, m, ...) \
GMOCK_METHOD10_(typename, const, ct, m, __VA_ARGS__)
-// A MockFunction<F> class has one mock method whose type is F. It is
-// useful when you just want your test code to emit some messages and
-// have Google Mock verify the right messages are sent (and perhaps at
-// the right times). For example, if you are exercising code:
-//
-// Foo(1);
-// Foo(2);
-// Foo(3);
-//
-// and want to verify that Foo(1) and Foo(3) both invoke
-// mock.Bar("a"), but Foo(2) doesn't invoke anything, you can write:
-//
-// TEST(FooTest, InvokesBarCorrectly) {
-// MyMock mock;
-// MockFunction<void(string check_point_name)> check;
-// {
-// InSequence s;
-//
-// EXPECT_CALL(mock, Bar("a"));
-// EXPECT_CALL(check, Call("1"));
-// EXPECT_CALL(check, Call("2"));
-// EXPECT_CALL(mock, Bar("a"));
-// }
-// Foo(1);
-// check.Call("1");
-// Foo(2);
-// check.Call("2");
-// Foo(3);
-// }
-//
-// The expectation spec says that the first Bar("a") must happen
-// before check point "1", the second Bar("a") must happen after check
-// point "2", and nothing should happen between the two check
-// points. The explicit check points make it easy to tell which
-// Bar("a") is called by which call to Foo().
-//
-// MockFunction<F> can also be used to exercise code that accepts
-// std::function<F> callbacks. To do so, use AsStdFunction() method
-// to create std::function proxy forwarding to original object's Call.
-// Example:
-//
-// TEST(FooTest, RunsCallbackWithBarArgument) {
-// MockFunction<int(string)> callback;
-// EXPECT_CALL(callback, Call("bar")).WillOnce(Return(1));
-// Foo(callback.AsStdFunction());
-// }
-template <typename F>
-class MockFunction;
-
-template <typename R>
-class MockFunction<R()> {
- public:
- MockFunction() {}
-
- MOCK_METHOD0_T(Call, R());
-
-#if GTEST_HAS_STD_FUNCTION_
- std::function<R()> AsStdFunction() {
- return [this]() -> R {
- return this->Call();
- };
- }
-#endif // GTEST_HAS_STD_FUNCTION_
-
- private:
- GTEST_DISALLOW_COPY_AND_ASSIGN_(MockFunction);
-};
-
-template <typename R, typename A0>
-class MockFunction<R(A0)> {
- public:
- MockFunction() {}
-
- MOCK_METHOD1_T(Call, R(A0));
-
-#if GTEST_HAS_STD_FUNCTION_
- std::function<R(A0)> AsStdFunction() {
- return [this](A0 a0) -> R {
- return this->Call(a0);
- };
- }
-#endif // GTEST_HAS_STD_FUNCTION_
-
- private:
- GTEST_DISALLOW_COPY_AND_ASSIGN_(MockFunction);
-};
-
-template <typename R, typename A0, typename A1>
-class MockFunction<R(A0, A1)> {
- public:
- MockFunction() {}
-
- MOCK_METHOD2_T(Call, R(A0, A1));
-
-#if GTEST_HAS_STD_FUNCTION_
- std::function<R(A0, A1)> AsStdFunction() {
- return [this](A0 a0, A1 a1) -> R {
- return this->Call(a0, a1);
- };
- }
-#endif // GTEST_HAS_STD_FUNCTION_
-
- private:
- GTEST_DISALLOW_COPY_AND_ASSIGN_(MockFunction);
-};
-
-template <typename R, typename A0, typename A1, typename A2>
-class MockFunction<R(A0, A1, A2)> {
- public:
- MockFunction() {}
-
- MOCK_METHOD3_T(Call, R(A0, A1, A2));
-
-#if GTEST_HAS_STD_FUNCTION_
- std::function<R(A0, A1, A2)> AsStdFunction() {
- return [this](A0 a0, A1 a1, A2 a2) -> R {
- return this->Call(a0, a1, a2);
- };
- }
-#endif // GTEST_HAS_STD_FUNCTION_
-
- private:
- GTEST_DISALLOW_COPY_AND_ASSIGN_(MockFunction);
-};
-
-template <typename R, typename A0, typename A1, typename A2, typename A3>
-class MockFunction<R(A0, A1, A2, A3)> {
- public:
- MockFunction() {}
-
- MOCK_METHOD4_T(Call, R(A0, A1, A2, A3));
-
-#if GTEST_HAS_STD_FUNCTION_
- std::function<R(A0, A1, A2, A3)> AsStdFunction() {
- return [this](A0 a0, A1 a1, A2 a2, A3 a3) -> R {
- return this->Call(a0, a1, a2, a3);
- };
- }
-#endif // GTEST_HAS_STD_FUNCTION_
-
- private:
- GTEST_DISALLOW_COPY_AND_ASSIGN_(MockFunction);
-};
-
-template <typename R, typename A0, typename A1, typename A2, typename A3,
- typename A4>
-class MockFunction<R(A0, A1, A2, A3, A4)> {
- public:
- MockFunction() {}
-
- MOCK_METHOD5_T(Call, R(A0, A1, A2, A3, A4));
-
-#if GTEST_HAS_STD_FUNCTION_
- std::function<R(A0, A1, A2, A3, A4)> AsStdFunction() {
- return [this](A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) -> R {
- return this->Call(a0, a1, a2, a3, a4);
- };
- }
-#endif // GTEST_HAS_STD_FUNCTION_
-
- private:
- GTEST_DISALLOW_COPY_AND_ASSIGN_(MockFunction);
-};
-
-template <typename R, typename A0, typename A1, typename A2, typename A3,
- typename A4, typename A5>
-class MockFunction<R(A0, A1, A2, A3, A4, A5)> {
- public:
- MockFunction() {}
-
- MOCK_METHOD6_T(Call, R(A0, A1, A2, A3, A4, A5));
-
-#if GTEST_HAS_STD_FUNCTION_
- std::function<R(A0, A1, A2, A3, A4, A5)> AsStdFunction() {
- return [this](A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) -> R {
- return this->Call(a0, a1, a2, a3, a4, a5);
- };
- }
-#endif // GTEST_HAS_STD_FUNCTION_
-
- private:
- GTEST_DISALLOW_COPY_AND_ASSIGN_(MockFunction);
-};
-
-template <typename R, typename A0, typename A1, typename A2, typename A3,
- typename A4, typename A5, typename A6>
-class MockFunction<R(A0, A1, A2, A3, A4, A5, A6)> {
- public:
- MockFunction() {}
-
- MOCK_METHOD7_T(Call, R(A0, A1, A2, A3, A4, A5, A6));
-
-#if GTEST_HAS_STD_FUNCTION_
- std::function<R(A0, A1, A2, A3, A4, A5, A6)> AsStdFunction() {
- return [this](A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6) -> R {
- return this->Call(a0, a1, a2, a3, a4, a5, a6);
- };
- }
-#endif // GTEST_HAS_STD_FUNCTION_
-
- private:
- GTEST_DISALLOW_COPY_AND_ASSIGN_(MockFunction);
-};
-
-template <typename R, typename A0, typename A1, typename A2, typename A3,
- typename A4, typename A5, typename A6, typename A7>
-class MockFunction<R(A0, A1, A2, A3, A4, A5, A6, A7)> {
- public:
- MockFunction() {}
-
- MOCK_METHOD8_T(Call, R(A0, A1, A2, A3, A4, A5, A6, A7));
-
-#if GTEST_HAS_STD_FUNCTION_
- std::function<R(A0, A1, A2, A3, A4, A5, A6, A7)> AsStdFunction() {
- return [this](A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7) -> R {
- return this->Call(a0, a1, a2, a3, a4, a5, a6, a7);
- };
- }
-#endif // GTEST_HAS_STD_FUNCTION_
-
- private:
- GTEST_DISALLOW_COPY_AND_ASSIGN_(MockFunction);
-};
-
-template <typename R, typename A0, typename A1, typename A2, typename A3,
- typename A4, typename A5, typename A6, typename A7, typename A8>
-class MockFunction<R(A0, A1, A2, A3, A4, A5, A6, A7, A8)> {
- public:
- MockFunction() {}
-
- MOCK_METHOD9_T(Call, R(A0, A1, A2, A3, A4, A5, A6, A7, A8));
-
-#if GTEST_HAS_STD_FUNCTION_
- std::function<R(A0, A1, A2, A3, A4, A5, A6, A7, A8)> AsStdFunction() {
- return [this](A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7,
- A8 a8) -> R {
- return this->Call(a0, a1, a2, a3, a4, a5, a6, a7, a8);
- };
- }
-#endif // GTEST_HAS_STD_FUNCTION_
-
- private:
- GTEST_DISALLOW_COPY_AND_ASSIGN_(MockFunction);
-};
-
-template <typename R, typename A0, typename A1, typename A2, typename A3,
- typename A4, typename A5, typename A6, typename A7, typename A8,
- typename A9>
-class MockFunction<R(A0, A1, A2, A3, A4, A5, A6, A7, A8, A9)> {
- public:
- MockFunction() {}
-
- MOCK_METHOD10_T(Call, R(A0, A1, A2, A3, A4, A5, A6, A7, A8, A9));
-
-#if GTEST_HAS_STD_FUNCTION_
- std::function<R(A0, A1, A2, A3, A4, A5, A6, A7, A8, A9)> AsStdFunction() {
- return [this](A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7,
- A8 a8, A9 a9) -> R {
- return this->Call(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
- };
- }
-#endif // GTEST_HAS_STD_FUNCTION_
-
- private:
- GTEST_DISALLOW_COPY_AND_ASSIGN_(MockFunction);
-};
-
} // namespace testing
#endif // GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_FUNCTION_MOCKERS_H_
diff --git a/extern/gmock/include/gmock/gmock-generated-matchers.h b/extern/gmock/include/gmock/gmock-generated-matchers.h
index 57056fd91d2..690a57f1c9f 100644
--- a/extern/gmock/include/gmock/gmock-generated-matchers.h
+++ b/extern/gmock/include/gmock/gmock-generated-matchers.h
@@ -35,1134 +35,18 @@
//
// This file implements some commonly used variadic matchers.
+// GOOGLETEST_CM0002 DO NOT DELETE
+
#ifndef GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_MATCHERS_H_
#define GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_MATCHERS_H_
#include <iterator>
#include <sstream>
#include <string>
+#include <utility>
#include <vector>
#include "gmock/gmock-matchers.h"
-namespace testing {
-namespace internal {
-
-// The type of the i-th (0-based) field of Tuple.
-#define GMOCK_FIELD_TYPE_(Tuple, i) \
- typename ::testing::tuple_element<i, Tuple>::type
-
-// TupleFields<Tuple, k0, ..., kn> is for selecting fields from a
-// tuple of type Tuple. It has two members:
-//
-// type: a tuple type whose i-th field is the ki-th field of Tuple.
-// GetSelectedFields(t): returns fields k0, ..., and kn of t as a tuple.
-//
-// For example, in class TupleFields<tuple<bool, char, int>, 2, 0>, we have:
-//
-// type is tuple<int, bool>, and
-// GetSelectedFields(make_tuple(true, 'a', 42)) is (42, true).
-
-template <class Tuple, int k0 = -1, int k1 = -1, int k2 = -1, int k3 = -1,
- int k4 = -1, int k5 = -1, int k6 = -1, int k7 = -1, int k8 = -1,
- int k9 = -1>
-class TupleFields;
-
-// This generic version is used when there are 10 selectors.
-template <class Tuple, int k0, int k1, int k2, int k3, int k4, int k5, int k6,
- int k7, int k8, int k9>
-class TupleFields {
- public:
- typedef ::testing::tuple<GMOCK_FIELD_TYPE_(Tuple, k0),
- GMOCK_FIELD_TYPE_(Tuple, k1), GMOCK_FIELD_TYPE_(Tuple, k2),
- GMOCK_FIELD_TYPE_(Tuple, k3), GMOCK_FIELD_TYPE_(Tuple, k4),
- GMOCK_FIELD_TYPE_(Tuple, k5), GMOCK_FIELD_TYPE_(Tuple, k6),
- GMOCK_FIELD_TYPE_(Tuple, k7), GMOCK_FIELD_TYPE_(Tuple, k8),
- GMOCK_FIELD_TYPE_(Tuple, k9)> type;
- static type GetSelectedFields(const Tuple& t) {
- return type(get<k0>(t), get<k1>(t), get<k2>(t), get<k3>(t), get<k4>(t),
- get<k5>(t), get<k6>(t), get<k7>(t), get<k8>(t), get<k9>(t));
- }
-};
-
-// The following specialization is used for 0 ~ 9 selectors.
-
-template <class Tuple>
-class TupleFields<Tuple, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1> {
- public:
- typedef ::testing::tuple<> type;
- static type GetSelectedFields(const Tuple& /* t */) {
- return type();
- }
-};
-
-template <class Tuple, int k0>
-class TupleFields<Tuple, k0, -1, -1, -1, -1, -1, -1, -1, -1, -1> {
- public:
- typedef ::testing::tuple<GMOCK_FIELD_TYPE_(Tuple, k0)> type;
- static type GetSelectedFields(const Tuple& t) {
- return type(get<k0>(t));
- }
-};
-
-template <class Tuple, int k0, int k1>
-class TupleFields<Tuple, k0, k1, -1, -1, -1, -1, -1, -1, -1, -1> {
- public:
- typedef ::testing::tuple<GMOCK_FIELD_TYPE_(Tuple, k0),
- GMOCK_FIELD_TYPE_(Tuple, k1)> type;
- static type GetSelectedFields(const Tuple& t) {
- return type(get<k0>(t), get<k1>(t));
- }
-};
-
-template <class Tuple, int k0, int k1, int k2>
-class TupleFields<Tuple, k0, k1, k2, -1, -1, -1, -1, -1, -1, -1> {
- public:
- typedef ::testing::tuple<GMOCK_FIELD_TYPE_(Tuple, k0),
- GMOCK_FIELD_TYPE_(Tuple, k1), GMOCK_FIELD_TYPE_(Tuple, k2)> type;
- static type GetSelectedFields(const Tuple& t) {
- return type(get<k0>(t), get<k1>(t), get<k2>(t));
- }
-};
-
-template <class Tuple, int k0, int k1, int k2, int k3>
-class TupleFields<Tuple, k0, k1, k2, k3, -1, -1, -1, -1, -1, -1> {
- public:
- typedef ::testing::tuple<GMOCK_FIELD_TYPE_(Tuple, k0),
- GMOCK_FIELD_TYPE_(Tuple, k1), GMOCK_FIELD_TYPE_(Tuple, k2),
- GMOCK_FIELD_TYPE_(Tuple, k3)> type;
- static type GetSelectedFields(const Tuple& t) {
- return type(get<k0>(t), get<k1>(t), get<k2>(t), get<k3>(t));
- }
-};
-
-template <class Tuple, int k0, int k1, int k2, int k3, int k4>
-class TupleFields<Tuple, k0, k1, k2, k3, k4, -1, -1, -1, -1, -1> {
- public:
- typedef ::testing::tuple<GMOCK_FIELD_TYPE_(Tuple, k0),
- GMOCK_FIELD_TYPE_(Tuple, k1), GMOCK_FIELD_TYPE_(Tuple, k2),
- GMOCK_FIELD_TYPE_(Tuple, k3), GMOCK_FIELD_TYPE_(Tuple, k4)> type;
- static type GetSelectedFields(const Tuple& t) {
- return type(get<k0>(t), get<k1>(t), get<k2>(t), get<k3>(t), get<k4>(t));
- }
-};
-
-template <class Tuple, int k0, int k1, int k2, int k3, int k4, int k5>
-class TupleFields<Tuple, k0, k1, k2, k3, k4, k5, -1, -1, -1, -1> {
- public:
- typedef ::testing::tuple<GMOCK_FIELD_TYPE_(Tuple, k0),
- GMOCK_FIELD_TYPE_(Tuple, k1), GMOCK_FIELD_TYPE_(Tuple, k2),
- GMOCK_FIELD_TYPE_(Tuple, k3), GMOCK_FIELD_TYPE_(Tuple, k4),
- GMOCK_FIELD_TYPE_(Tuple, k5)> type;
- static type GetSelectedFields(const Tuple& t) {
- return type(get<k0>(t), get<k1>(t), get<k2>(t), get<k3>(t), get<k4>(t),
- get<k5>(t));
- }
-};
-
-template <class Tuple, int k0, int k1, int k2, int k3, int k4, int k5, int k6>
-class TupleFields<Tuple, k0, k1, k2, k3, k4, k5, k6, -1, -1, -1> {
- public:
- typedef ::testing::tuple<GMOCK_FIELD_TYPE_(Tuple, k0),
- GMOCK_FIELD_TYPE_(Tuple, k1), GMOCK_FIELD_TYPE_(Tuple, k2),
- GMOCK_FIELD_TYPE_(Tuple, k3), GMOCK_FIELD_TYPE_(Tuple, k4),
- GMOCK_FIELD_TYPE_(Tuple, k5), GMOCK_FIELD_TYPE_(Tuple, k6)> type;
- static type GetSelectedFields(const Tuple& t) {
- return type(get<k0>(t), get<k1>(t), get<k2>(t), get<k3>(t), get<k4>(t),
- get<k5>(t), get<k6>(t));
- }
-};
-
-template <class Tuple, int k0, int k1, int k2, int k3, int k4, int k5, int k6,
- int k7>
-class TupleFields<Tuple, k0, k1, k2, k3, k4, k5, k6, k7, -1, -1> {
- public:
- typedef ::testing::tuple<GMOCK_FIELD_TYPE_(Tuple, k0),
- GMOCK_FIELD_TYPE_(Tuple, k1), GMOCK_FIELD_TYPE_(Tuple, k2),
- GMOCK_FIELD_TYPE_(Tuple, k3), GMOCK_FIELD_TYPE_(Tuple, k4),
- GMOCK_FIELD_TYPE_(Tuple, k5), GMOCK_FIELD_TYPE_(Tuple, k6),
- GMOCK_FIELD_TYPE_(Tuple, k7)> type;
- static type GetSelectedFields(const Tuple& t) {
- return type(get<k0>(t), get<k1>(t), get<k2>(t), get<k3>(t), get<k4>(t),
- get<k5>(t), get<k6>(t), get<k7>(t));
- }
-};
-
-template <class Tuple, int k0, int k1, int k2, int k3, int k4, int k5, int k6,
- int k7, int k8>
-class TupleFields<Tuple, k0, k1, k2, k3, k4, k5, k6, k7, k8, -1> {
- public:
- typedef ::testing::tuple<GMOCK_FIELD_TYPE_(Tuple, k0),
- GMOCK_FIELD_TYPE_(Tuple, k1), GMOCK_FIELD_TYPE_(Tuple, k2),
- GMOCK_FIELD_TYPE_(Tuple, k3), GMOCK_FIELD_TYPE_(Tuple, k4),
- GMOCK_FIELD_TYPE_(Tuple, k5), GMOCK_FIELD_TYPE_(Tuple, k6),
- GMOCK_FIELD_TYPE_(Tuple, k7), GMOCK_FIELD_TYPE_(Tuple, k8)> type;
- static type GetSelectedFields(const Tuple& t) {
- return type(get<k0>(t), get<k1>(t), get<k2>(t), get<k3>(t), get<k4>(t),
- get<k5>(t), get<k6>(t), get<k7>(t), get<k8>(t));
- }
-};
-
-#undef GMOCK_FIELD_TYPE_
-
-// Implements the Args() matcher.
-template <class ArgsTuple, int k0 = -1, int k1 = -1, int k2 = -1, int k3 = -1,
- int k4 = -1, int k5 = -1, int k6 = -1, int k7 = -1, int k8 = -1,
- int k9 = -1>
-class ArgsMatcherImpl : public MatcherInterface<ArgsTuple> {
- public:
- // ArgsTuple may have top-level const or reference modifiers.
- typedef GTEST_REMOVE_REFERENCE_AND_CONST_(ArgsTuple) RawArgsTuple;
- typedef typename internal::TupleFields<RawArgsTuple, k0, k1, k2, k3, k4, k5,
- k6, k7, k8, k9>::type SelectedArgs;
- typedef Matcher<const SelectedArgs&> MonomorphicInnerMatcher;
-
- template <typename InnerMatcher>
- explicit ArgsMatcherImpl(const InnerMatcher& inner_matcher)
- : inner_matcher_(SafeMatcherCast<const SelectedArgs&>(inner_matcher)) {}
-
- virtual bool MatchAndExplain(ArgsTuple args,
- MatchResultListener* listener) const {
- const SelectedArgs& selected_args = GetSelectedArgs(args);
- if (!listener->IsInterested())
- return inner_matcher_.Matches(selected_args);
-
- PrintIndices(listener->stream());
- *listener << "are " << PrintToString(selected_args);
-
- StringMatchResultListener inner_listener;
- const bool match = inner_matcher_.MatchAndExplain(selected_args,
- &inner_listener);
- PrintIfNotEmpty(inner_listener.str(), listener->stream());
- return match;
- }
-
- virtual void DescribeTo(::std::ostream* os) const {
- *os << "are a tuple ";
- PrintIndices(os);
- inner_matcher_.DescribeTo(os);
- }
-
- virtual void DescribeNegationTo(::std::ostream* os) const {
- *os << "are a tuple ";
- PrintIndices(os);
- inner_matcher_.DescribeNegationTo(os);
- }
-
- private:
- static SelectedArgs GetSelectedArgs(ArgsTuple args) {
- return TupleFields<RawArgsTuple, k0, k1, k2, k3, k4, k5, k6, k7, k8,
- k9>::GetSelectedFields(args);
- }
-
- // Prints the indices of the selected fields.
- static void PrintIndices(::std::ostream* os) {
- *os << "whose fields (";
- const int indices[10] = { k0, k1, k2, k3, k4, k5, k6, k7, k8, k9 };
- for (int i = 0; i < 10; i++) {
- if (indices[i] < 0)
- break;
-
- if (i >= 1)
- *os << ", ";
-
- *os << "#" << indices[i];
- }
- *os << ") ";
- }
-
- const MonomorphicInnerMatcher inner_matcher_;
-
- GTEST_DISALLOW_ASSIGN_(ArgsMatcherImpl);
-};
-
-template <class InnerMatcher, int k0 = -1, int k1 = -1, int k2 = -1,
- int k3 = -1, int k4 = -1, int k5 = -1, int k6 = -1, int k7 = -1,
- int k8 = -1, int k9 = -1>
-class ArgsMatcher {
- public:
- explicit ArgsMatcher(const InnerMatcher& inner_matcher)
- : inner_matcher_(inner_matcher) {}
-
- template <typename ArgsTuple>
- operator Matcher<ArgsTuple>() const {
- return MakeMatcher(new ArgsMatcherImpl<ArgsTuple, k0, k1, k2, k3, k4, k5,
- k6, k7, k8, k9>(inner_matcher_));
- }
-
- private:
- const InnerMatcher inner_matcher_;
-
- GTEST_DISALLOW_ASSIGN_(ArgsMatcher);
-};
-
-// A set of metafunctions for computing the result type of AllOf.
-// AllOf(m1, ..., mN) returns
-// AllOfResultN<decltype(m1), ..., decltype(mN)>::type.
-
-// Although AllOf isn't defined for one argument, AllOfResult1 is defined
-// to simplify the implementation.
-template <typename M1>
-struct AllOfResult1 {
- typedef M1 type;
-};
-
-template <typename M1, typename M2>
-struct AllOfResult2 {
- typedef BothOfMatcher<
- typename AllOfResult1<M1>::type,
- typename AllOfResult1<M2>::type
- > type;
-};
-
-template <typename M1, typename M2, typename M3>
-struct AllOfResult3 {
- typedef BothOfMatcher<
- typename AllOfResult1<M1>::type,
- typename AllOfResult2<M2, M3>::type
- > type;
-};
-
-template <typename M1, typename M2, typename M3, typename M4>
-struct AllOfResult4 {
- typedef BothOfMatcher<
- typename AllOfResult2<M1, M2>::type,
- typename AllOfResult2<M3, M4>::type
- > type;
-};
-
-template <typename M1, typename M2, typename M3, typename M4, typename M5>
-struct AllOfResult5 {
- typedef BothOfMatcher<
- typename AllOfResult2<M1, M2>::type,
- typename AllOfResult3<M3, M4, M5>::type
- > type;
-};
-
-template <typename M1, typename M2, typename M3, typename M4, typename M5,
- typename M6>
-struct AllOfResult6 {
- typedef BothOfMatcher<
- typename AllOfResult3<M1, M2, M3>::type,
- typename AllOfResult3<M4, M5, M6>::type
- > type;
-};
-
-template <typename M1, typename M2, typename M3, typename M4, typename M5,
- typename M6, typename M7>
-struct AllOfResult7 {
- typedef BothOfMatcher<
- typename AllOfResult3<M1, M2, M3>::type,
- typename AllOfResult4<M4, M5, M6, M7>::type
- > type;
-};
-
-template <typename M1, typename M2, typename M3, typename M4, typename M5,
- typename M6, typename M7, typename M8>
-struct AllOfResult8 {
- typedef BothOfMatcher<
- typename AllOfResult4<M1, M2, M3, M4>::type,
- typename AllOfResult4<M5, M6, M7, M8>::type
- > type;
-};
-
-template <typename M1, typename M2, typename M3, typename M4, typename M5,
- typename M6, typename M7, typename M8, typename M9>
-struct AllOfResult9 {
- typedef BothOfMatcher<
- typename AllOfResult4<M1, M2, M3, M4>::type,
- typename AllOfResult5<M5, M6, M7, M8, M9>::type
- > type;
-};
-
-template <typename M1, typename M2, typename M3, typename M4, typename M5,
- typename M6, typename M7, typename M8, typename M9, typename M10>
-struct AllOfResult10 {
- typedef BothOfMatcher<
- typename AllOfResult5<M1, M2, M3, M4, M5>::type,
- typename AllOfResult5<M6, M7, M8, M9, M10>::type
- > type;
-};
-
-// A set of metafunctions for computing the result type of AnyOf.
-// AnyOf(m1, ..., mN) returns
-// AnyOfResultN<decltype(m1), ..., decltype(mN)>::type.
-
-// Although AnyOf isn't defined for one argument, AnyOfResult1 is defined
-// to simplify the implementation.
-template <typename M1>
-struct AnyOfResult1 {
- typedef M1 type;
-};
-
-template <typename M1, typename M2>
-struct AnyOfResult2 {
- typedef EitherOfMatcher<
- typename AnyOfResult1<M1>::type,
- typename AnyOfResult1<M2>::type
- > type;
-};
-
-template <typename M1, typename M2, typename M3>
-struct AnyOfResult3 {
- typedef EitherOfMatcher<
- typename AnyOfResult1<M1>::type,
- typename AnyOfResult2<M2, M3>::type
- > type;
-};
-
-template <typename M1, typename M2, typename M3, typename M4>
-struct AnyOfResult4 {
- typedef EitherOfMatcher<
- typename AnyOfResult2<M1, M2>::type,
- typename AnyOfResult2<M3, M4>::type
- > type;
-};
-
-template <typename M1, typename M2, typename M3, typename M4, typename M5>
-struct AnyOfResult5 {
- typedef EitherOfMatcher<
- typename AnyOfResult2<M1, M2>::type,
- typename AnyOfResult3<M3, M4, M5>::type
- > type;
-};
-
-template <typename M1, typename M2, typename M3, typename M4, typename M5,
- typename M6>
-struct AnyOfResult6 {
- typedef EitherOfMatcher<
- typename AnyOfResult3<M1, M2, M3>::type,
- typename AnyOfResult3<M4, M5, M6>::type
- > type;
-};
-
-template <typename M1, typename M2, typename M3, typename M4, typename M5,
- typename M6, typename M7>
-struct AnyOfResult7 {
- typedef EitherOfMatcher<
- typename AnyOfResult3<M1, M2, M3>::type,
- typename AnyOfResult4<M4, M5, M6, M7>::type
- > type;
-};
-
-template <typename M1, typename M2, typename M3, typename M4, typename M5,
- typename M6, typename M7, typename M8>
-struct AnyOfResult8 {
- typedef EitherOfMatcher<
- typename AnyOfResult4<M1, M2, M3, M4>::type,
- typename AnyOfResult4<M5, M6, M7, M8>::type
- > type;
-};
-
-template <typename M1, typename M2, typename M3, typename M4, typename M5,
- typename M6, typename M7, typename M8, typename M9>
-struct AnyOfResult9 {
- typedef EitherOfMatcher<
- typename AnyOfResult4<M1, M2, M3, M4>::type,
- typename AnyOfResult5<M5, M6, M7, M8, M9>::type
- > type;
-};
-
-template <typename M1, typename M2, typename M3, typename M4, typename M5,
- typename M6, typename M7, typename M8, typename M9, typename M10>
-struct AnyOfResult10 {
- typedef EitherOfMatcher<
- typename AnyOfResult5<M1, M2, M3, M4, M5>::type,
- typename AnyOfResult5<M6, M7, M8, M9, M10>::type
- > type;
-};
-
-} // namespace internal
-
-// Args<N1, N2, ..., Nk>(a_matcher) matches a tuple if the selected
-// fields of it matches a_matcher. C++ doesn't support default
-// arguments for function templates, so we have to overload it.
-template <typename InnerMatcher>
-inline internal::ArgsMatcher<InnerMatcher>
-Args(const InnerMatcher& matcher) {
- return internal::ArgsMatcher<InnerMatcher>(matcher);
-}
-
-template <int k1, typename InnerMatcher>
-inline internal::ArgsMatcher<InnerMatcher, k1>
-Args(const InnerMatcher& matcher) {
- return internal::ArgsMatcher<InnerMatcher, k1>(matcher);
-}
-
-template <int k1, int k2, typename InnerMatcher>
-inline internal::ArgsMatcher<InnerMatcher, k1, k2>
-Args(const InnerMatcher& matcher) {
- return internal::ArgsMatcher<InnerMatcher, k1, k2>(matcher);
-}
-
-template <int k1, int k2, int k3, typename InnerMatcher>
-inline internal::ArgsMatcher<InnerMatcher, k1, k2, k3>
-Args(const InnerMatcher& matcher) {
- return internal::ArgsMatcher<InnerMatcher, k1, k2, k3>(matcher);
-}
-
-template <int k1, int k2, int k3, int k4, typename InnerMatcher>
-inline internal::ArgsMatcher<InnerMatcher, k1, k2, k3, k4>
-Args(const InnerMatcher& matcher) {
- return internal::ArgsMatcher<InnerMatcher, k1, k2, k3, k4>(matcher);
-}
-
-template <int k1, int k2, int k3, int k4, int k5, typename InnerMatcher>
-inline internal::ArgsMatcher<InnerMatcher, k1, k2, k3, k4, k5>
-Args(const InnerMatcher& matcher) {
- return internal::ArgsMatcher<InnerMatcher, k1, k2, k3, k4, k5>(matcher);
-}
-
-template <int k1, int k2, int k3, int k4, int k5, int k6, typename InnerMatcher>
-inline internal::ArgsMatcher<InnerMatcher, k1, k2, k3, k4, k5, k6>
-Args(const InnerMatcher& matcher) {
- return internal::ArgsMatcher<InnerMatcher, k1, k2, k3, k4, k5, k6>(matcher);
-}
-
-template <int k1, int k2, int k3, int k4, int k5, int k6, int k7,
- typename InnerMatcher>
-inline internal::ArgsMatcher<InnerMatcher, k1, k2, k3, k4, k5, k6, k7>
-Args(const InnerMatcher& matcher) {
- return internal::ArgsMatcher<InnerMatcher, k1, k2, k3, k4, k5, k6,
- k7>(matcher);
-}
-
-template <int k1, int k2, int k3, int k4, int k5, int k6, int k7, int k8,
- typename InnerMatcher>
-inline internal::ArgsMatcher<InnerMatcher, k1, k2, k3, k4, k5, k6, k7, k8>
-Args(const InnerMatcher& matcher) {
- return internal::ArgsMatcher<InnerMatcher, k1, k2, k3, k4, k5, k6, k7,
- k8>(matcher);
-}
-
-template <int k1, int k2, int k3, int k4, int k5, int k6, int k7, int k8,
- int k9, typename InnerMatcher>
-inline internal::ArgsMatcher<InnerMatcher, k1, k2, k3, k4, k5, k6, k7, k8, k9>
-Args(const InnerMatcher& matcher) {
- return internal::ArgsMatcher<InnerMatcher, k1, k2, k3, k4, k5, k6, k7, k8,
- k9>(matcher);
-}
-
-template <int k1, int k2, int k3, int k4, int k5, int k6, int k7, int k8,
- int k9, int k10, typename InnerMatcher>
-inline internal::ArgsMatcher<InnerMatcher, k1, k2, k3, k4, k5, k6, k7, k8, k9,
- k10>
-Args(const InnerMatcher& matcher) {
- return internal::ArgsMatcher<InnerMatcher, k1, k2, k3, k4, k5, k6, k7, k8,
- k9, k10>(matcher);
-}
-
-// ElementsAre(e_1, e_2, ... e_n) matches an STL-style container with
-// n elements, where the i-th element in the container must
-// match the i-th argument in the list. Each argument of
-// ElementsAre() can be either a value or a matcher. We support up to
-// 10 arguments.
-//
-// The use of DecayArray in the implementation allows ElementsAre()
-// to accept string literals, whose type is const char[N], but we
-// want to treat them as const char*.
-//
-// NOTE: Since ElementsAre() cares about the order of the elements, it
-// must not be used with containers whose elements's order is
-// undefined (e.g. hash_map).
-
-inline internal::ElementsAreMatcher<
- ::testing::tuple<> >
-ElementsAre() {
- typedef ::testing::tuple<> Args;
- return internal::ElementsAreMatcher<Args>(Args());
-}
-
-template <typename T1>
-inline internal::ElementsAreMatcher<
- ::testing::tuple<
- typename internal::DecayArray<T1>::type> >
-ElementsAre(const T1& e1) {
- typedef ::testing::tuple<
- typename internal::DecayArray<T1>::type> Args;
- return internal::ElementsAreMatcher<Args>(Args(e1));
-}
-
-template <typename T1, typename T2>
-inline internal::ElementsAreMatcher<
- ::testing::tuple<
- typename internal::DecayArray<T1>::type,
- typename internal::DecayArray<T2>::type> >
-ElementsAre(const T1& e1, const T2& e2) {
- typedef ::testing::tuple<
- typename internal::DecayArray<T1>::type,
- typename internal::DecayArray<T2>::type> Args;
- return internal::ElementsAreMatcher<Args>(Args(e1, e2));
-}
-
-template <typename T1, typename T2, typename T3>
-inline internal::ElementsAreMatcher<
- ::testing::tuple<
- typename internal::DecayArray<T1>::type,
- typename internal::DecayArray<T2>::type,
- typename internal::DecayArray<T3>::type> >
-ElementsAre(const T1& e1, const T2& e2, const T3& e3) {
- typedef ::testing::tuple<
- typename internal::DecayArray<T1>::type,
- typename internal::DecayArray<T2>::type,
- typename internal::DecayArray<T3>::type> Args;
- return internal::ElementsAreMatcher<Args>(Args(e1, e2, e3));
-}
-
-template <typename T1, typename T2, typename T3, typename T4>
-inline internal::ElementsAreMatcher<
- ::testing::tuple<
- typename internal::DecayArray<T1>::type,
- typename internal::DecayArray<T2>::type,
- typename internal::DecayArray<T3>::type,
- typename internal::DecayArray<T4>::type> >
-ElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4) {
- typedef ::testing::tuple<
- typename internal::DecayArray<T1>::type,
- typename internal::DecayArray<T2>::type,
- typename internal::DecayArray<T3>::type,
- typename internal::DecayArray<T4>::type> Args;
- return internal::ElementsAreMatcher<Args>(Args(e1, e2, e3, e4));
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5>
-inline internal::ElementsAreMatcher<
- ::testing::tuple<
- typename internal::DecayArray<T1>::type,
- typename internal::DecayArray<T2>::type,
- typename internal::DecayArray<T3>::type,
- typename internal::DecayArray<T4>::type,
- typename internal::DecayArray<T5>::type> >
-ElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4,
- const T5& e5) {
- typedef ::testing::tuple<
- typename internal::DecayArray<T1>::type,
- typename internal::DecayArray<T2>::type,
- typename internal::DecayArray<T3>::type,
- typename internal::DecayArray<T4>::type,
- typename internal::DecayArray<T5>::type> Args;
- return internal::ElementsAreMatcher<Args>(Args(e1, e2, e3, e4, e5));
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6>
-inline internal::ElementsAreMatcher<
- ::testing::tuple<
- typename internal::DecayArray<T1>::type,
- typename internal::DecayArray<T2>::type,
- typename internal::DecayArray<T3>::type,
- typename internal::DecayArray<T4>::type,
- typename internal::DecayArray<T5>::type,
- typename internal::DecayArray<T6>::type> >
-ElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4,
- const T5& e5, const T6& e6) {
- typedef ::testing::tuple<
- typename internal::DecayArray<T1>::type,
- typename internal::DecayArray<T2>::type,
- typename internal::DecayArray<T3>::type,
- typename internal::DecayArray<T4>::type,
- typename internal::DecayArray<T5>::type,
- typename internal::DecayArray<T6>::type> Args;
- return internal::ElementsAreMatcher<Args>(Args(e1, e2, e3, e4, e5, e6));
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7>
-inline internal::ElementsAreMatcher<
- ::testing::tuple<
- typename internal::DecayArray<T1>::type,
- typename internal::DecayArray<T2>::type,
- typename internal::DecayArray<T3>::type,
- typename internal::DecayArray<T4>::type,
- typename internal::DecayArray<T5>::type,
- typename internal::DecayArray<T6>::type,
- typename internal::DecayArray<T7>::type> >
-ElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4,
- const T5& e5, const T6& e6, const T7& e7) {
- typedef ::testing::tuple<
- typename internal::DecayArray<T1>::type,
- typename internal::DecayArray<T2>::type,
- typename internal::DecayArray<T3>::type,
- typename internal::DecayArray<T4>::type,
- typename internal::DecayArray<T5>::type,
- typename internal::DecayArray<T6>::type,
- typename internal::DecayArray<T7>::type> Args;
- return internal::ElementsAreMatcher<Args>(Args(e1, e2, e3, e4, e5, e6, e7));
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8>
-inline internal::ElementsAreMatcher<
- ::testing::tuple<
- typename internal::DecayArray<T1>::type,
- typename internal::DecayArray<T2>::type,
- typename internal::DecayArray<T3>::type,
- typename internal::DecayArray<T4>::type,
- typename internal::DecayArray<T5>::type,
- typename internal::DecayArray<T6>::type,
- typename internal::DecayArray<T7>::type,
- typename internal::DecayArray<T8>::type> >
-ElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4,
- const T5& e5, const T6& e6, const T7& e7, const T8& e8) {
- typedef ::testing::tuple<
- typename internal::DecayArray<T1>::type,
- typename internal::DecayArray<T2>::type,
- typename internal::DecayArray<T3>::type,
- typename internal::DecayArray<T4>::type,
- typename internal::DecayArray<T5>::type,
- typename internal::DecayArray<T6>::type,
- typename internal::DecayArray<T7>::type,
- typename internal::DecayArray<T8>::type> Args;
- return internal::ElementsAreMatcher<Args>(Args(e1, e2, e3, e4, e5, e6, e7,
- e8));
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9>
-inline internal::ElementsAreMatcher<
- ::testing::tuple<
- typename internal::DecayArray<T1>::type,
- typename internal::DecayArray<T2>::type,
- typename internal::DecayArray<T3>::type,
- typename internal::DecayArray<T4>::type,
- typename internal::DecayArray<T5>::type,
- typename internal::DecayArray<T6>::type,
- typename internal::DecayArray<T7>::type,
- typename internal::DecayArray<T8>::type,
- typename internal::DecayArray<T9>::type> >
-ElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4,
- const T5& e5, const T6& e6, const T7& e7, const T8& e8, const T9& e9) {
- typedef ::testing::tuple<
- typename internal::DecayArray<T1>::type,
- typename internal::DecayArray<T2>::type,
- typename internal::DecayArray<T3>::type,
- typename internal::DecayArray<T4>::type,
- typename internal::DecayArray<T5>::type,
- typename internal::DecayArray<T6>::type,
- typename internal::DecayArray<T7>::type,
- typename internal::DecayArray<T8>::type,
- typename internal::DecayArray<T9>::type> Args;
- return internal::ElementsAreMatcher<Args>(Args(e1, e2, e3, e4, e5, e6, e7,
- e8, e9));
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10>
-inline internal::ElementsAreMatcher<
- ::testing::tuple<
- typename internal::DecayArray<T1>::type,
- typename internal::DecayArray<T2>::type,
- typename internal::DecayArray<T3>::type,
- typename internal::DecayArray<T4>::type,
- typename internal::DecayArray<T5>::type,
- typename internal::DecayArray<T6>::type,
- typename internal::DecayArray<T7>::type,
- typename internal::DecayArray<T8>::type,
- typename internal::DecayArray<T9>::type,
- typename internal::DecayArray<T10>::type> >
-ElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4,
- const T5& e5, const T6& e6, const T7& e7, const T8& e8, const T9& e9,
- const T10& e10) {
- typedef ::testing::tuple<
- typename internal::DecayArray<T1>::type,
- typename internal::DecayArray<T2>::type,
- typename internal::DecayArray<T3>::type,
- typename internal::DecayArray<T4>::type,
- typename internal::DecayArray<T5>::type,
- typename internal::DecayArray<T6>::type,
- typename internal::DecayArray<T7>::type,
- typename internal::DecayArray<T8>::type,
- typename internal::DecayArray<T9>::type,
- typename internal::DecayArray<T10>::type> Args;
- return internal::ElementsAreMatcher<Args>(Args(e1, e2, e3, e4, e5, e6, e7,
- e8, e9, e10));
-}
-
-// UnorderedElementsAre(e_1, e_2, ..., e_n) is an ElementsAre extension
-// that matches n elements in any order. We support up to n=10 arguments.
-
-inline internal::UnorderedElementsAreMatcher<
- ::testing::tuple<> >
-UnorderedElementsAre() {
- typedef ::testing::tuple<> Args;
- return internal::UnorderedElementsAreMatcher<Args>(Args());
-}
-
-template <typename T1>
-inline internal::UnorderedElementsAreMatcher<
- ::testing::tuple<
- typename internal::DecayArray<T1>::type> >
-UnorderedElementsAre(const T1& e1) {
- typedef ::testing::tuple<
- typename internal::DecayArray<T1>::type> Args;
- return internal::UnorderedElementsAreMatcher<Args>(Args(e1));
-}
-
-template <typename T1, typename T2>
-inline internal::UnorderedElementsAreMatcher<
- ::testing::tuple<
- typename internal::DecayArray<T1>::type,
- typename internal::DecayArray<T2>::type> >
-UnorderedElementsAre(const T1& e1, const T2& e2) {
- typedef ::testing::tuple<
- typename internal::DecayArray<T1>::type,
- typename internal::DecayArray<T2>::type> Args;
- return internal::UnorderedElementsAreMatcher<Args>(Args(e1, e2));
-}
-
-template <typename T1, typename T2, typename T3>
-inline internal::UnorderedElementsAreMatcher<
- ::testing::tuple<
- typename internal::DecayArray<T1>::type,
- typename internal::DecayArray<T2>::type,
- typename internal::DecayArray<T3>::type> >
-UnorderedElementsAre(const T1& e1, const T2& e2, const T3& e3) {
- typedef ::testing::tuple<
- typename internal::DecayArray<T1>::type,
- typename internal::DecayArray<T2>::type,
- typename internal::DecayArray<T3>::type> Args;
- return internal::UnorderedElementsAreMatcher<Args>(Args(e1, e2, e3));
-}
-
-template <typename T1, typename T2, typename T3, typename T4>
-inline internal::UnorderedElementsAreMatcher<
- ::testing::tuple<
- typename internal::DecayArray<T1>::type,
- typename internal::DecayArray<T2>::type,
- typename internal::DecayArray<T3>::type,
- typename internal::DecayArray<T4>::type> >
-UnorderedElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4) {
- typedef ::testing::tuple<
- typename internal::DecayArray<T1>::type,
- typename internal::DecayArray<T2>::type,
- typename internal::DecayArray<T3>::type,
- typename internal::DecayArray<T4>::type> Args;
- return internal::UnorderedElementsAreMatcher<Args>(Args(e1, e2, e3, e4));
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5>
-inline internal::UnorderedElementsAreMatcher<
- ::testing::tuple<
- typename internal::DecayArray<T1>::type,
- typename internal::DecayArray<T2>::type,
- typename internal::DecayArray<T3>::type,
- typename internal::DecayArray<T4>::type,
- typename internal::DecayArray<T5>::type> >
-UnorderedElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4,
- const T5& e5) {
- typedef ::testing::tuple<
- typename internal::DecayArray<T1>::type,
- typename internal::DecayArray<T2>::type,
- typename internal::DecayArray<T3>::type,
- typename internal::DecayArray<T4>::type,
- typename internal::DecayArray<T5>::type> Args;
- return internal::UnorderedElementsAreMatcher<Args>(Args(e1, e2, e3, e4, e5));
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6>
-inline internal::UnorderedElementsAreMatcher<
- ::testing::tuple<
- typename internal::DecayArray<T1>::type,
- typename internal::DecayArray<T2>::type,
- typename internal::DecayArray<T3>::type,
- typename internal::DecayArray<T4>::type,
- typename internal::DecayArray<T5>::type,
- typename internal::DecayArray<T6>::type> >
-UnorderedElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4,
- const T5& e5, const T6& e6) {
- typedef ::testing::tuple<
- typename internal::DecayArray<T1>::type,
- typename internal::DecayArray<T2>::type,
- typename internal::DecayArray<T3>::type,
- typename internal::DecayArray<T4>::type,
- typename internal::DecayArray<T5>::type,
- typename internal::DecayArray<T6>::type> Args;
- return internal::UnorderedElementsAreMatcher<Args>(Args(e1, e2, e3, e4, e5,
- e6));
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7>
-inline internal::UnorderedElementsAreMatcher<
- ::testing::tuple<
- typename internal::DecayArray<T1>::type,
- typename internal::DecayArray<T2>::type,
- typename internal::DecayArray<T3>::type,
- typename internal::DecayArray<T4>::type,
- typename internal::DecayArray<T5>::type,
- typename internal::DecayArray<T6>::type,
- typename internal::DecayArray<T7>::type> >
-UnorderedElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4,
- const T5& e5, const T6& e6, const T7& e7) {
- typedef ::testing::tuple<
- typename internal::DecayArray<T1>::type,
- typename internal::DecayArray<T2>::type,
- typename internal::DecayArray<T3>::type,
- typename internal::DecayArray<T4>::type,
- typename internal::DecayArray<T5>::type,
- typename internal::DecayArray<T6>::type,
- typename internal::DecayArray<T7>::type> Args;
- return internal::UnorderedElementsAreMatcher<Args>(Args(e1, e2, e3, e4, e5,
- e6, e7));
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8>
-inline internal::UnorderedElementsAreMatcher<
- ::testing::tuple<
- typename internal::DecayArray<T1>::type,
- typename internal::DecayArray<T2>::type,
- typename internal::DecayArray<T3>::type,
- typename internal::DecayArray<T4>::type,
- typename internal::DecayArray<T5>::type,
- typename internal::DecayArray<T6>::type,
- typename internal::DecayArray<T7>::type,
- typename internal::DecayArray<T8>::type> >
-UnorderedElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4,
- const T5& e5, const T6& e6, const T7& e7, const T8& e8) {
- typedef ::testing::tuple<
- typename internal::DecayArray<T1>::type,
- typename internal::DecayArray<T2>::type,
- typename internal::DecayArray<T3>::type,
- typename internal::DecayArray<T4>::type,
- typename internal::DecayArray<T5>::type,
- typename internal::DecayArray<T6>::type,
- typename internal::DecayArray<T7>::type,
- typename internal::DecayArray<T8>::type> Args;
- return internal::UnorderedElementsAreMatcher<Args>(Args(e1, e2, e3, e4, e5,
- e6, e7, e8));
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9>
-inline internal::UnorderedElementsAreMatcher<
- ::testing::tuple<
- typename internal::DecayArray<T1>::type,
- typename internal::DecayArray<T2>::type,
- typename internal::DecayArray<T3>::type,
- typename internal::DecayArray<T4>::type,
- typename internal::DecayArray<T5>::type,
- typename internal::DecayArray<T6>::type,
- typename internal::DecayArray<T7>::type,
- typename internal::DecayArray<T8>::type,
- typename internal::DecayArray<T9>::type> >
-UnorderedElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4,
- const T5& e5, const T6& e6, const T7& e7, const T8& e8, const T9& e9) {
- typedef ::testing::tuple<
- typename internal::DecayArray<T1>::type,
- typename internal::DecayArray<T2>::type,
- typename internal::DecayArray<T3>::type,
- typename internal::DecayArray<T4>::type,
- typename internal::DecayArray<T5>::type,
- typename internal::DecayArray<T6>::type,
- typename internal::DecayArray<T7>::type,
- typename internal::DecayArray<T8>::type,
- typename internal::DecayArray<T9>::type> Args;
- return internal::UnorderedElementsAreMatcher<Args>(Args(e1, e2, e3, e4, e5,
- e6, e7, e8, e9));
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10>
-inline internal::UnorderedElementsAreMatcher<
- ::testing::tuple<
- typename internal::DecayArray<T1>::type,
- typename internal::DecayArray<T2>::type,
- typename internal::DecayArray<T3>::type,
- typename internal::DecayArray<T4>::type,
- typename internal::DecayArray<T5>::type,
- typename internal::DecayArray<T6>::type,
- typename internal::DecayArray<T7>::type,
- typename internal::DecayArray<T8>::type,
- typename internal::DecayArray<T9>::type,
- typename internal::DecayArray<T10>::type> >
-UnorderedElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4,
- const T5& e5, const T6& e6, const T7& e7, const T8& e8, const T9& e9,
- const T10& e10) {
- typedef ::testing::tuple<
- typename internal::DecayArray<T1>::type,
- typename internal::DecayArray<T2>::type,
- typename internal::DecayArray<T3>::type,
- typename internal::DecayArray<T4>::type,
- typename internal::DecayArray<T5>::type,
- typename internal::DecayArray<T6>::type,
- typename internal::DecayArray<T7>::type,
- typename internal::DecayArray<T8>::type,
- typename internal::DecayArray<T9>::type,
- typename internal::DecayArray<T10>::type> Args;
- return internal::UnorderedElementsAreMatcher<Args>(Args(e1, e2, e3, e4, e5,
- e6, e7, e8, e9, e10));
-}
-
-// AllOf(m1, m2, ..., mk) matches any value that matches all of the given
-// sub-matchers. AllOf is called fully qualified to prevent ADL from firing.
-
-template <typename M1, typename M2>
-inline typename internal::AllOfResult2<M1, M2>::type
-AllOf(M1 m1, M2 m2) {
- return typename internal::AllOfResult2<M1, M2>::type(
- m1,
- m2);
-}
-
-template <typename M1, typename M2, typename M3>
-inline typename internal::AllOfResult3<M1, M2, M3>::type
-AllOf(M1 m1, M2 m2, M3 m3) {
- return typename internal::AllOfResult3<M1, M2, M3>::type(
- m1,
- ::testing::AllOf(m2, m3));
-}
-
-template <typename M1, typename M2, typename M3, typename M4>
-inline typename internal::AllOfResult4<M1, M2, M3, M4>::type
-AllOf(M1 m1, M2 m2, M3 m3, M4 m4) {
- return typename internal::AllOfResult4<M1, M2, M3, M4>::type(
- ::testing::AllOf(m1, m2),
- ::testing::AllOf(m3, m4));
-}
-
-template <typename M1, typename M2, typename M3, typename M4, typename M5>
-inline typename internal::AllOfResult5<M1, M2, M3, M4, M5>::type
-AllOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5) {
- return typename internal::AllOfResult5<M1, M2, M3, M4, M5>::type(
- ::testing::AllOf(m1, m2),
- ::testing::AllOf(m3, m4, m5));
-}
-
-template <typename M1, typename M2, typename M3, typename M4, typename M5,
- typename M6>
-inline typename internal::AllOfResult6<M1, M2, M3, M4, M5, M6>::type
-AllOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5, M6 m6) {
- return typename internal::AllOfResult6<M1, M2, M3, M4, M5, M6>::type(
- ::testing::AllOf(m1, m2, m3),
- ::testing::AllOf(m4, m5, m6));
-}
-
-template <typename M1, typename M2, typename M3, typename M4, typename M5,
- typename M6, typename M7>
-inline typename internal::AllOfResult7<M1, M2, M3, M4, M5, M6, M7>::type
-AllOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5, M6 m6, M7 m7) {
- return typename internal::AllOfResult7<M1, M2, M3, M4, M5, M6, M7>::type(
- ::testing::AllOf(m1, m2, m3),
- ::testing::AllOf(m4, m5, m6, m7));
-}
-
-template <typename M1, typename M2, typename M3, typename M4, typename M5,
- typename M6, typename M7, typename M8>
-inline typename internal::AllOfResult8<M1, M2, M3, M4, M5, M6, M7, M8>::type
-AllOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5, M6 m6, M7 m7, M8 m8) {
- return typename internal::AllOfResult8<M1, M2, M3, M4, M5, M6, M7, M8>::type(
- ::testing::AllOf(m1, m2, m3, m4),
- ::testing::AllOf(m5, m6, m7, m8));
-}
-
-template <typename M1, typename M2, typename M3, typename M4, typename M5,
- typename M6, typename M7, typename M8, typename M9>
-inline typename internal::AllOfResult9<M1, M2, M3, M4, M5, M6, M7, M8, M9>::type
-AllOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5, M6 m6, M7 m7, M8 m8, M9 m9) {
- return typename internal::AllOfResult9<M1, M2, M3, M4, M5, M6, M7, M8,
- M9>::type(
- ::testing::AllOf(m1, m2, m3, m4),
- ::testing::AllOf(m5, m6, m7, m8, m9));
-}
-
-template <typename M1, typename M2, typename M3, typename M4, typename M5,
- typename M6, typename M7, typename M8, typename M9, typename M10>
-inline typename internal::AllOfResult10<M1, M2, M3, M4, M5, M6, M7, M8, M9,
- M10>::type
-AllOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5, M6 m6, M7 m7, M8 m8, M9 m9, M10 m10) {
- return typename internal::AllOfResult10<M1, M2, M3, M4, M5, M6, M7, M8, M9,
- M10>::type(
- ::testing::AllOf(m1, m2, m3, m4, m5),
- ::testing::AllOf(m6, m7, m8, m9, m10));
-}
-
-// AnyOf(m1, m2, ..., mk) matches any value that matches any of the given
-// sub-matchers. AnyOf is called fully qualified to prevent ADL from firing.
-
-template <typename M1, typename M2>
-inline typename internal::AnyOfResult2<M1, M2>::type
-AnyOf(M1 m1, M2 m2) {
- return typename internal::AnyOfResult2<M1, M2>::type(
- m1,
- m2);
-}
-
-template <typename M1, typename M2, typename M3>
-inline typename internal::AnyOfResult3<M1, M2, M3>::type
-AnyOf(M1 m1, M2 m2, M3 m3) {
- return typename internal::AnyOfResult3<M1, M2, M3>::type(
- m1,
- ::testing::AnyOf(m2, m3));
-}
-
-template <typename M1, typename M2, typename M3, typename M4>
-inline typename internal::AnyOfResult4<M1, M2, M3, M4>::type
-AnyOf(M1 m1, M2 m2, M3 m3, M4 m4) {
- return typename internal::AnyOfResult4<M1, M2, M3, M4>::type(
- ::testing::AnyOf(m1, m2),
- ::testing::AnyOf(m3, m4));
-}
-
-template <typename M1, typename M2, typename M3, typename M4, typename M5>
-inline typename internal::AnyOfResult5<M1, M2, M3, M4, M5>::type
-AnyOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5) {
- return typename internal::AnyOfResult5<M1, M2, M3, M4, M5>::type(
- ::testing::AnyOf(m1, m2),
- ::testing::AnyOf(m3, m4, m5));
-}
-
-template <typename M1, typename M2, typename M3, typename M4, typename M5,
- typename M6>
-inline typename internal::AnyOfResult6<M1, M2, M3, M4, M5, M6>::type
-AnyOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5, M6 m6) {
- return typename internal::AnyOfResult6<M1, M2, M3, M4, M5, M6>::type(
- ::testing::AnyOf(m1, m2, m3),
- ::testing::AnyOf(m4, m5, m6));
-}
-
-template <typename M1, typename M2, typename M3, typename M4, typename M5,
- typename M6, typename M7>
-inline typename internal::AnyOfResult7<M1, M2, M3, M4, M5, M6, M7>::type
-AnyOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5, M6 m6, M7 m7) {
- return typename internal::AnyOfResult7<M1, M2, M3, M4, M5, M6, M7>::type(
- ::testing::AnyOf(m1, m2, m3),
- ::testing::AnyOf(m4, m5, m6, m7));
-}
-
-template <typename M1, typename M2, typename M3, typename M4, typename M5,
- typename M6, typename M7, typename M8>
-inline typename internal::AnyOfResult8<M1, M2, M3, M4, M5, M6, M7, M8>::type
-AnyOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5, M6 m6, M7 m7, M8 m8) {
- return typename internal::AnyOfResult8<M1, M2, M3, M4, M5, M6, M7, M8>::type(
- ::testing::AnyOf(m1, m2, m3, m4),
- ::testing::AnyOf(m5, m6, m7, m8));
-}
-
-template <typename M1, typename M2, typename M3, typename M4, typename M5,
- typename M6, typename M7, typename M8, typename M9>
-inline typename internal::AnyOfResult9<M1, M2, M3, M4, M5, M6, M7, M8, M9>::type
-AnyOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5, M6 m6, M7 m7, M8 m8, M9 m9) {
- return typename internal::AnyOfResult9<M1, M2, M3, M4, M5, M6, M7, M8,
- M9>::type(
- ::testing::AnyOf(m1, m2, m3, m4),
- ::testing::AnyOf(m5, m6, m7, m8, m9));
-}
-
-template <typename M1, typename M2, typename M3, typename M4, typename M5,
- typename M6, typename M7, typename M8, typename M9, typename M10>
-inline typename internal::AnyOfResult10<M1, M2, M3, M4, M5, M6, M7, M8, M9,
- M10>::type
-AnyOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5, M6 m6, M7 m7, M8 m8, M9 m9, M10 m10) {
- return typename internal::AnyOfResult10<M1, M2, M3, M4, M5, M6, M7, M8, M9,
- M10>::type(
- ::testing::AnyOf(m1, m2, m3, m4, m5),
- ::testing::AnyOf(m6, m7, m8, m9, m10));
-}
-
-} // namespace testing
-
-
// The MATCHER* family of macros can be used in a namespace scope to
// define custom matchers easily.
//
@@ -1268,7 +152,7 @@ AnyOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5, M6 m6, M7 m7, M8 m8, M9 m9, M10 m10) {
// using testing::PrintToString;
//
// MATCHER_P2(InClosedRange, low, hi,
-// string(negation ? "is not" : "is") + " in range [" +
+// std::string(negation ? "is not" : "is") + " in range [" +
// PrintToString(low) + ", " + PrintToString(hi) + "]") {
// return low <= arg && arg <= hi;
// }
@@ -1366,28 +250,28 @@ AnyOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5, M6 m6, M7 m7, M8 m8, M9 m9, M10 m10) {
// overloading matchers based on parameter types (as opposed to just
// based on the number of parameters).
//
-// MATCHER*() can only be used in a namespace scope. The reason is
-// that C++ doesn't yet allow function-local types to be used to
-// instantiate templates. The up-coming C++0x standard will fix this.
-// Once that's done, we'll consider supporting using MATCHER*() inside
-// a function.
+// MATCHER*() can only be used in a namespace scope as templates cannot be
+// declared inside of a local class.
//
// More Information
// ================
//
// To learn more about using these macros, please search for 'MATCHER'
-// on http://code.google.com/p/googlemock/wiki/CookBook.
+// on
+// https://github.com/google/googletest/blob/master/googlemock/docs/cook_book.md
#define MATCHER(name, description)\
class name##Matcher {\
public:\
template <typename arg_type>\
- class gmock_Impl : public ::testing::MatcherInterface<arg_type> {\
+ class gmock_Impl : public ::testing::MatcherInterface<\
+ GTEST_REFERENCE_TO_CONST_(arg_type)> {\
public:\
gmock_Impl()\
{}\
virtual bool MatchAndExplain(\
- arg_type arg, ::testing::MatchResultListener* result_listener) const;\
+ GTEST_REFERENCE_TO_CONST_(arg_type) arg,\
+ ::testing::MatchResultListener* result_listener) const;\
virtual void DescribeTo(::std::ostream* gmock_os) const {\
*gmock_os << FormatDescription(false);\
}\
@@ -1395,16 +279,16 @@ AnyOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5, M6 m6, M7 m7, M8 m8, M9 m9, M10 m10) {
*gmock_os << FormatDescription(true);\
}\
private:\
- ::testing::internal::string FormatDescription(bool negation) const {\
- const ::testing::internal::string gmock_description = (description);\
- if (!gmock_description.empty())\
+ ::std::string FormatDescription(bool negation) const {\
+ ::std::string gmock_description = (description);\
+ if (!gmock_description.empty()) {\
return gmock_description;\
+ }\
return ::testing::internal::FormatMatcherDescription(\
negation, #name, \
::testing::internal::UniversalTersePrintTupleFieldsToStrings(\
- ::testing::tuple<>()));\
+ ::std::tuple<>()));\
}\
- GTEST_DISALLOW_ASSIGN_(gmock_Impl);\
};\
template <typename arg_type>\
operator ::testing::Matcher<arg_type>() const {\
@@ -1414,14 +298,13 @@ AnyOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5, M6 m6, M7 m7, M8 m8, M9 m9, M10 m10) {
name##Matcher() {\
}\
private:\
- GTEST_DISALLOW_ASSIGN_(name##Matcher);\
};\
inline name##Matcher name() {\
return name##Matcher();\
}\
template <typename arg_type>\
bool name##Matcher::gmock_Impl<arg_type>::MatchAndExplain(\
- arg_type arg, \
+ GTEST_REFERENCE_TO_CONST_(arg_type) arg,\
::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\
const
@@ -1430,41 +313,42 @@ AnyOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5, M6 m6, M7 m7, M8 m8, M9 m9, M10 m10) {
class name##MatcherP {\
public:\
template <typename arg_type>\
- class gmock_Impl : public ::testing::MatcherInterface<arg_type> {\
+ class gmock_Impl : public ::testing::MatcherInterface<\
+ GTEST_REFERENCE_TO_CONST_(arg_type)> {\
public:\
explicit gmock_Impl(p0##_type gmock_p0)\
- : p0(gmock_p0) {}\
+ : p0(::std::move(gmock_p0)) {}\
virtual bool MatchAndExplain(\
- arg_type arg, ::testing::MatchResultListener* result_listener) const;\
+ GTEST_REFERENCE_TO_CONST_(arg_type) arg,\
+ ::testing::MatchResultListener* result_listener) const;\
virtual void DescribeTo(::std::ostream* gmock_os) const {\
*gmock_os << FormatDescription(false);\
}\
virtual void DescribeNegationTo(::std::ostream* gmock_os) const {\
*gmock_os << FormatDescription(true);\
}\
- p0##_type p0;\
+ p0##_type const p0;\
private:\
- ::testing::internal::string FormatDescription(bool negation) const {\
- const ::testing::internal::string gmock_description = (description);\
- if (!gmock_description.empty())\
+ ::std::string FormatDescription(bool negation) const {\
+ ::std::string gmock_description = (description);\
+ if (!gmock_description.empty()) {\
return gmock_description;\
+ }\
return ::testing::internal::FormatMatcherDescription(\
negation, #name, \
::testing::internal::UniversalTersePrintTupleFieldsToStrings(\
- ::testing::tuple<p0##_type>(p0)));\
+ ::std::tuple<p0##_type>(p0)));\
}\
- GTEST_DISALLOW_ASSIGN_(gmock_Impl);\
};\
template <typename arg_type>\
operator ::testing::Matcher<arg_type>() const {\
return ::testing::Matcher<arg_type>(\
new gmock_Impl<arg_type>(p0));\
}\
- explicit name##MatcherP(p0##_type gmock_p0) : p0(gmock_p0) {\
+ explicit name##MatcherP(p0##_type gmock_p0) : p0(::std::move(gmock_p0)) {\
}\
- p0##_type p0;\
+ p0##_type const p0;\
private:\
- GTEST_DISALLOW_ASSIGN_(name##MatcherP);\
};\
template <typename p0##_type>\
inline name##MatcherP<p0##_type> name(p0##_type p0) {\
@@ -1473,7 +357,7 @@ AnyOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5, M6 m6, M7 m7, M8 m8, M9 m9, M10 m10) {
template <typename p0##_type>\
template <typename arg_type>\
bool name##MatcherP<p0##_type>::gmock_Impl<arg_type>::MatchAndExplain(\
- arg_type arg, \
+ GTEST_REFERENCE_TO_CONST_(arg_type) arg,\
::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\
const
@@ -1482,44 +366,46 @@ AnyOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5, M6 m6, M7 m7, M8 m8, M9 m9, M10 m10) {
class name##MatcherP2 {\
public:\
template <typename arg_type>\
- class gmock_Impl : public ::testing::MatcherInterface<arg_type> {\
+ class gmock_Impl : public ::testing::MatcherInterface<\
+ GTEST_REFERENCE_TO_CONST_(arg_type)> {\
public:\
gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1)\
- : p0(gmock_p0), p1(gmock_p1) {}\
+ : p0(::std::move(gmock_p0)), p1(::std::move(gmock_p1)) {}\
virtual bool MatchAndExplain(\
- arg_type arg, ::testing::MatchResultListener* result_listener) const;\
+ GTEST_REFERENCE_TO_CONST_(arg_type) arg,\
+ ::testing::MatchResultListener* result_listener) const;\
virtual void DescribeTo(::std::ostream* gmock_os) const {\
*gmock_os << FormatDescription(false);\
}\
virtual void DescribeNegationTo(::std::ostream* gmock_os) const {\
*gmock_os << FormatDescription(true);\
}\
- p0##_type p0;\
- p1##_type p1;\
+ p0##_type const p0;\
+ p1##_type const p1;\
private:\
- ::testing::internal::string FormatDescription(bool negation) const {\
- const ::testing::internal::string gmock_description = (description);\
- if (!gmock_description.empty())\
+ ::std::string FormatDescription(bool negation) const {\
+ ::std::string gmock_description = (description);\
+ if (!gmock_description.empty()) {\
return gmock_description;\
+ }\
return ::testing::internal::FormatMatcherDescription(\
negation, #name, \
::testing::internal::UniversalTersePrintTupleFieldsToStrings(\
- ::testing::tuple<p0##_type, p1##_type>(p0, p1)));\
+ ::std::tuple<p0##_type, p1##_type>(p0, p1)));\
}\
- GTEST_DISALLOW_ASSIGN_(gmock_Impl);\
};\
template <typename arg_type>\
operator ::testing::Matcher<arg_type>() const {\
return ::testing::Matcher<arg_type>(\
new gmock_Impl<arg_type>(p0, p1));\
}\
- name##MatcherP2(p0##_type gmock_p0, p1##_type gmock_p1) : p0(gmock_p0), \
- p1(gmock_p1) {\
+ name##MatcherP2(p0##_type gmock_p0, \
+ p1##_type gmock_p1) : p0(::std::move(gmock_p0)), \
+ p1(::std::move(gmock_p1)) {\
}\
- p0##_type p0;\
- p1##_type p1;\
+ p0##_type const p0;\
+ p1##_type const p1;\
private:\
- GTEST_DISALLOW_ASSIGN_(name##MatcherP2);\
};\
template <typename p0##_type, typename p1##_type>\
inline name##MatcherP2<p0##_type, p1##_type> name(p0##_type p0, \
@@ -1530,7 +416,7 @@ AnyOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5, M6 m6, M7 m7, M8 m8, M9 m9, M10 m10) {
template <typename arg_type>\
bool name##MatcherP2<p0##_type, \
p1##_type>::gmock_Impl<arg_type>::MatchAndExplain(\
- arg_type arg, \
+ GTEST_REFERENCE_TO_CONST_(arg_type) arg,\
::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\
const
@@ -1539,33 +425,35 @@ AnyOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5, M6 m6, M7 m7, M8 m8, M9 m9, M10 m10) {
class name##MatcherP3 {\
public:\
template <typename arg_type>\
- class gmock_Impl : public ::testing::MatcherInterface<arg_type> {\
+ class gmock_Impl : public ::testing::MatcherInterface<\
+ GTEST_REFERENCE_TO_CONST_(arg_type)> {\
public:\
gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2)\
- : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2) {}\
+ : p0(::std::move(gmock_p0)), p1(::std::move(gmock_p1)), \
+ p2(::std::move(gmock_p2)) {}\
virtual bool MatchAndExplain(\
- arg_type arg, ::testing::MatchResultListener* result_listener) const;\
+ GTEST_REFERENCE_TO_CONST_(arg_type) arg,\
+ ::testing::MatchResultListener* result_listener) const;\
virtual void DescribeTo(::std::ostream* gmock_os) const {\
*gmock_os << FormatDescription(false);\
}\
virtual void DescribeNegationTo(::std::ostream* gmock_os) const {\
*gmock_os << FormatDescription(true);\
}\
- p0##_type p0;\
- p1##_type p1;\
- p2##_type p2;\
+ p0##_type const p0;\
+ p1##_type const p1;\
+ p2##_type const p2;\
private:\
- ::testing::internal::string FormatDescription(bool negation) const {\
- const ::testing::internal::string gmock_description = (description);\
- if (!gmock_description.empty())\
+ ::std::string FormatDescription(bool negation) const {\
+ ::std::string gmock_description = (description);\
+ if (!gmock_description.empty()) {\
return gmock_description;\
+ }\
return ::testing::internal::FormatMatcherDescription(\
negation, #name, \
::testing::internal::UniversalTersePrintTupleFieldsToStrings(\
- ::testing::tuple<p0##_type, p1##_type, p2##_type>(p0, p1, \
- p2)));\
+ ::std::tuple<p0##_type, p1##_type, p2##_type>(p0, p1, p2)));\
}\
- GTEST_DISALLOW_ASSIGN_(gmock_Impl);\
};\
template <typename arg_type>\
operator ::testing::Matcher<arg_type>() const {\
@@ -1573,13 +461,13 @@ AnyOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5, M6 m6, M7 m7, M8 m8, M9 m9, M10 m10) {
new gmock_Impl<arg_type>(p0, p1, p2));\
}\
name##MatcherP3(p0##_type gmock_p0, p1##_type gmock_p1, \
- p2##_type gmock_p2) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2) {\
+ p2##_type gmock_p2) : p0(::std::move(gmock_p0)), \
+ p1(::std::move(gmock_p1)), p2(::std::move(gmock_p2)) {\
}\
- p0##_type p0;\
- p1##_type p1;\
- p2##_type p2;\
+ p0##_type const p0;\
+ p1##_type const p1;\
+ p2##_type const p2;\
private:\
- GTEST_DISALLOW_ASSIGN_(name##MatcherP3);\
};\
template <typename p0##_type, typename p1##_type, typename p2##_type>\
inline name##MatcherP3<p0##_type, p1##_type, p2##_type> name(p0##_type p0, \
@@ -1590,7 +478,7 @@ AnyOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5, M6 m6, M7 m7, M8 m8, M9 m9, M10 m10) {
template <typename arg_type>\
bool name##MatcherP3<p0##_type, p1##_type, \
p2##_type>::gmock_Impl<arg_type>::MatchAndExplain(\
- arg_type arg, \
+ GTEST_REFERENCE_TO_CONST_(arg_type) arg,\
::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\
const
@@ -1600,35 +488,38 @@ AnyOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5, M6 m6, M7 m7, M8 m8, M9 m9, M10 m10) {
class name##MatcherP4 {\
public:\
template <typename arg_type>\
- class gmock_Impl : public ::testing::MatcherInterface<arg_type> {\
+ class gmock_Impl : public ::testing::MatcherInterface<\
+ GTEST_REFERENCE_TO_CONST_(arg_type)> {\
public:\
gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \
p3##_type gmock_p3)\
- : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), p3(gmock_p3) {}\
+ : p0(::std::move(gmock_p0)), p1(::std::move(gmock_p1)), \
+ p2(::std::move(gmock_p2)), p3(::std::move(gmock_p3)) {}\
virtual bool MatchAndExplain(\
- arg_type arg, ::testing::MatchResultListener* result_listener) const;\
+ GTEST_REFERENCE_TO_CONST_(arg_type) arg,\
+ ::testing::MatchResultListener* result_listener) const;\
virtual void DescribeTo(::std::ostream* gmock_os) const {\
*gmock_os << FormatDescription(false);\
}\
virtual void DescribeNegationTo(::std::ostream* gmock_os) const {\
*gmock_os << FormatDescription(true);\
}\
- p0##_type p0;\
- p1##_type p1;\
- p2##_type p2;\
- p3##_type p3;\
+ p0##_type const p0;\
+ p1##_type const p1;\
+ p2##_type const p2;\
+ p3##_type const p3;\
private:\
- ::testing::internal::string FormatDescription(bool negation) const {\
- const ::testing::internal::string gmock_description = (description);\
- if (!gmock_description.empty())\
+ ::std::string FormatDescription(bool negation) const {\
+ ::std::string gmock_description = (description);\
+ if (!gmock_description.empty()) {\
return gmock_description;\
+ }\
return ::testing::internal::FormatMatcherDescription(\
negation, #name, \
::testing::internal::UniversalTersePrintTupleFieldsToStrings(\
- ::testing::tuple<p0##_type, p1##_type, p2##_type, \
- p3##_type>(p0, p1, p2, p3)));\
+ ::std::tuple<p0##_type, p1##_type, p2##_type, p3##_type>(p0, \
+ p1, p2, p3)));\
}\
- GTEST_DISALLOW_ASSIGN_(gmock_Impl);\
};\
template <typename arg_type>\
operator ::testing::Matcher<arg_type>() const {\
@@ -1636,15 +527,15 @@ AnyOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5, M6 m6, M7 m7, M8 m8, M9 m9, M10 m10) {
new gmock_Impl<arg_type>(p0, p1, p2, p3));\
}\
name##MatcherP4(p0##_type gmock_p0, p1##_type gmock_p1, \
- p2##_type gmock_p2, p3##_type gmock_p3) : p0(gmock_p0), p1(gmock_p1), \
- p2(gmock_p2), p3(gmock_p3) {\
+ p2##_type gmock_p2, p3##_type gmock_p3) : p0(::std::move(gmock_p0)), \
+ p1(::std::move(gmock_p1)), p2(::std::move(gmock_p2)), \
+ p3(::std::move(gmock_p3)) {\
}\
- p0##_type p0;\
- p1##_type p1;\
- p2##_type p2;\
- p3##_type p3;\
+ p0##_type const p0;\
+ p1##_type const p1;\
+ p2##_type const p2;\
+ p3##_type const p3;\
private:\
- GTEST_DISALLOW_ASSIGN_(name##MatcherP4);\
};\
template <typename p0##_type, typename p1##_type, typename p2##_type, \
typename p3##_type>\
@@ -1659,7 +550,7 @@ AnyOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5, M6 m6, M7 m7, M8 m8, M9 m9, M10 m10) {
template <typename arg_type>\
bool name##MatcherP4<p0##_type, p1##_type, p2##_type, \
p3##_type>::gmock_Impl<arg_type>::MatchAndExplain(\
- arg_type arg, \
+ GTEST_REFERENCE_TO_CONST_(arg_type) arg,\
::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\
const
@@ -1669,37 +560,40 @@ AnyOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5, M6 m6, M7 m7, M8 m8, M9 m9, M10 m10) {
class name##MatcherP5 {\
public:\
template <typename arg_type>\
- class gmock_Impl : public ::testing::MatcherInterface<arg_type> {\
+ class gmock_Impl : public ::testing::MatcherInterface<\
+ GTEST_REFERENCE_TO_CONST_(arg_type)> {\
public:\
gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \
p3##_type gmock_p3, p4##_type gmock_p4)\
- : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), p3(gmock_p3), \
- p4(gmock_p4) {}\
+ : p0(::std::move(gmock_p0)), p1(::std::move(gmock_p1)), \
+ p2(::std::move(gmock_p2)), p3(::std::move(gmock_p3)), \
+ p4(::std::move(gmock_p4)) {}\
virtual bool MatchAndExplain(\
- arg_type arg, ::testing::MatchResultListener* result_listener) const;\
+ GTEST_REFERENCE_TO_CONST_(arg_type) arg,\
+ ::testing::MatchResultListener* result_listener) const;\
virtual void DescribeTo(::std::ostream* gmock_os) const {\
*gmock_os << FormatDescription(false);\
}\
virtual void DescribeNegationTo(::std::ostream* gmock_os) const {\
*gmock_os << FormatDescription(true);\
}\
- p0##_type p0;\
- p1##_type p1;\
- p2##_type p2;\
- p3##_type p3;\
- p4##_type p4;\
+ p0##_type const p0;\
+ p1##_type const p1;\
+ p2##_type const p2;\
+ p3##_type const p3;\
+ p4##_type const p4;\
private:\
- ::testing::internal::string FormatDescription(bool negation) const {\
- const ::testing::internal::string gmock_description = (description);\
- if (!gmock_description.empty())\
+ ::std::string FormatDescription(bool negation) const {\
+ ::std::string gmock_description = (description);\
+ if (!gmock_description.empty()) {\
return gmock_description;\
+ }\
return ::testing::internal::FormatMatcherDescription(\
negation, #name, \
::testing::internal::UniversalTersePrintTupleFieldsToStrings(\
- ::testing::tuple<p0##_type, p1##_type, p2##_type, p3##_type, \
+ ::std::tuple<p0##_type, p1##_type, p2##_type, p3##_type, \
p4##_type>(p0, p1, p2, p3, p4)));\
}\
- GTEST_DISALLOW_ASSIGN_(gmock_Impl);\
};\
template <typename arg_type>\
operator ::testing::Matcher<arg_type>() const {\
@@ -1708,16 +602,16 @@ AnyOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5, M6 m6, M7 m7, M8 m8, M9 m9, M10 m10) {
}\
name##MatcherP5(p0##_type gmock_p0, p1##_type gmock_p1, \
p2##_type gmock_p2, p3##_type gmock_p3, \
- p4##_type gmock_p4) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \
- p3(gmock_p3), p4(gmock_p4) {\
+ p4##_type gmock_p4) : p0(::std::move(gmock_p0)), \
+ p1(::std::move(gmock_p1)), p2(::std::move(gmock_p2)), \
+ p3(::std::move(gmock_p3)), p4(::std::move(gmock_p4)) {\
}\
- p0##_type p0;\
- p1##_type p1;\
- p2##_type p2;\
- p3##_type p3;\
- p4##_type p4;\
+ p0##_type const p0;\
+ p1##_type const p1;\
+ p2##_type const p2;\
+ p3##_type const p3;\
+ p4##_type const p4;\
private:\
- GTEST_DISALLOW_ASSIGN_(name##MatcherP5);\
};\
template <typename p0##_type, typename p1##_type, typename p2##_type, \
typename p3##_type, typename p4##_type>\
@@ -1732,7 +626,7 @@ AnyOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5, M6 m6, M7 m7, M8 m8, M9 m9, M10 m10) {
template <typename arg_type>\
bool name##MatcherP5<p0##_type, p1##_type, p2##_type, p3##_type, \
p4##_type>::gmock_Impl<arg_type>::MatchAndExplain(\
- arg_type arg, \
+ GTEST_REFERENCE_TO_CONST_(arg_type) arg,\
::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\
const
@@ -1742,38 +636,41 @@ AnyOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5, M6 m6, M7 m7, M8 m8, M9 m9, M10 m10) {
class name##MatcherP6 {\
public:\
template <typename arg_type>\
- class gmock_Impl : public ::testing::MatcherInterface<arg_type> {\
+ class gmock_Impl : public ::testing::MatcherInterface<\
+ GTEST_REFERENCE_TO_CONST_(arg_type)> {\
public:\
gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \
p3##_type gmock_p3, p4##_type gmock_p4, p5##_type gmock_p5)\
- : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), p3(gmock_p3), \
- p4(gmock_p4), p5(gmock_p5) {}\
+ : p0(::std::move(gmock_p0)), p1(::std::move(gmock_p1)), \
+ p2(::std::move(gmock_p2)), p3(::std::move(gmock_p3)), \
+ p4(::std::move(gmock_p4)), p5(::std::move(gmock_p5)) {}\
virtual bool MatchAndExplain(\
- arg_type arg, ::testing::MatchResultListener* result_listener) const;\
+ GTEST_REFERENCE_TO_CONST_(arg_type) arg,\
+ ::testing::MatchResultListener* result_listener) const;\
virtual void DescribeTo(::std::ostream* gmock_os) const {\
*gmock_os << FormatDescription(false);\
}\
virtual void DescribeNegationTo(::std::ostream* gmock_os) const {\
*gmock_os << FormatDescription(true);\
}\
- p0##_type p0;\
- p1##_type p1;\
- p2##_type p2;\
- p3##_type p3;\
- p4##_type p4;\
- p5##_type p5;\
+ p0##_type const p0;\
+ p1##_type const p1;\
+ p2##_type const p2;\
+ p3##_type const p3;\
+ p4##_type const p4;\
+ p5##_type const p5;\
private:\
- ::testing::internal::string FormatDescription(bool negation) const {\
- const ::testing::internal::string gmock_description = (description);\
- if (!gmock_description.empty())\
+ ::std::string FormatDescription(bool negation) const {\
+ ::std::string gmock_description = (description);\
+ if (!gmock_description.empty()) {\
return gmock_description;\
+ }\
return ::testing::internal::FormatMatcherDescription(\
negation, #name, \
::testing::internal::UniversalTersePrintTupleFieldsToStrings(\
- ::testing::tuple<p0##_type, p1##_type, p2##_type, p3##_type, \
+ ::std::tuple<p0##_type, p1##_type, p2##_type, p3##_type, \
p4##_type, p5##_type>(p0, p1, p2, p3, p4, p5)));\
}\
- GTEST_DISALLOW_ASSIGN_(gmock_Impl);\
};\
template <typename arg_type>\
operator ::testing::Matcher<arg_type>() const {\
@@ -1782,17 +679,18 @@ AnyOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5, M6 m6, M7 m7, M8 m8, M9 m9, M10 m10) {
}\
name##MatcherP6(p0##_type gmock_p0, p1##_type gmock_p1, \
p2##_type gmock_p2, p3##_type gmock_p3, p4##_type gmock_p4, \
- p5##_type gmock_p5) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \
- p3(gmock_p3), p4(gmock_p4), p5(gmock_p5) {\
+ p5##_type gmock_p5) : p0(::std::move(gmock_p0)), \
+ p1(::std::move(gmock_p1)), p2(::std::move(gmock_p2)), \
+ p3(::std::move(gmock_p3)), p4(::std::move(gmock_p4)), \
+ p5(::std::move(gmock_p5)) {\
}\
- p0##_type p0;\
- p1##_type p1;\
- p2##_type p2;\
- p3##_type p3;\
- p4##_type p4;\
- p5##_type p5;\
+ p0##_type const p0;\
+ p1##_type const p1;\
+ p2##_type const p2;\
+ p3##_type const p3;\
+ p4##_type const p4;\
+ p5##_type const p5;\
private:\
- GTEST_DISALLOW_ASSIGN_(name##MatcherP6);\
};\
template <typename p0##_type, typename p1##_type, typename p2##_type, \
typename p3##_type, typename p4##_type, typename p5##_type>\
@@ -1807,7 +705,7 @@ AnyOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5, M6 m6, M7 m7, M8 m8, M9 m9, M10 m10) {
template <typename arg_type>\
bool name##MatcherP6<p0##_type, p1##_type, p2##_type, p3##_type, p4##_type, \
p5##_type>::gmock_Impl<arg_type>::MatchAndExplain(\
- arg_type arg, \
+ GTEST_REFERENCE_TO_CONST_(arg_type) arg,\
::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\
const
@@ -1818,41 +716,45 @@ AnyOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5, M6 m6, M7 m7, M8 m8, M9 m9, M10 m10) {
class name##MatcherP7 {\
public:\
template <typename arg_type>\
- class gmock_Impl : public ::testing::MatcherInterface<arg_type> {\
+ class gmock_Impl : public ::testing::MatcherInterface<\
+ GTEST_REFERENCE_TO_CONST_(arg_type)> {\
public:\
gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \
p3##_type gmock_p3, p4##_type gmock_p4, p5##_type gmock_p5, \
p6##_type gmock_p6)\
- : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), p3(gmock_p3), \
- p4(gmock_p4), p5(gmock_p5), p6(gmock_p6) {}\
+ : p0(::std::move(gmock_p0)), p1(::std::move(gmock_p1)), \
+ p2(::std::move(gmock_p2)), p3(::std::move(gmock_p3)), \
+ p4(::std::move(gmock_p4)), p5(::std::move(gmock_p5)), \
+ p6(::std::move(gmock_p6)) {}\
virtual bool MatchAndExplain(\
- arg_type arg, ::testing::MatchResultListener* result_listener) const;\
+ GTEST_REFERENCE_TO_CONST_(arg_type) arg,\
+ ::testing::MatchResultListener* result_listener) const;\
virtual void DescribeTo(::std::ostream* gmock_os) const {\
*gmock_os << FormatDescription(false);\
}\
virtual void DescribeNegationTo(::std::ostream* gmock_os) const {\
*gmock_os << FormatDescription(true);\
}\
- p0##_type p0;\
- p1##_type p1;\
- p2##_type p2;\
- p3##_type p3;\
- p4##_type p4;\
- p5##_type p5;\
- p6##_type p6;\
+ p0##_type const p0;\
+ p1##_type const p1;\
+ p2##_type const p2;\
+ p3##_type const p3;\
+ p4##_type const p4;\
+ p5##_type const p5;\
+ p6##_type const p6;\
private:\
- ::testing::internal::string FormatDescription(bool negation) const {\
- const ::testing::internal::string gmock_description = (description);\
- if (!gmock_description.empty())\
+ ::std::string FormatDescription(bool negation) const {\
+ ::std::string gmock_description = (description);\
+ if (!gmock_description.empty()) {\
return gmock_description;\
+ }\
return ::testing::internal::FormatMatcherDescription(\
negation, #name, \
::testing::internal::UniversalTersePrintTupleFieldsToStrings(\
- ::testing::tuple<p0##_type, p1##_type, p2##_type, p3##_type, \
+ ::std::tuple<p0##_type, p1##_type, p2##_type, p3##_type, \
p4##_type, p5##_type, p6##_type>(p0, p1, p2, p3, p4, p5, \
p6)));\
}\
- GTEST_DISALLOW_ASSIGN_(gmock_Impl);\
};\
template <typename arg_type>\
operator ::testing::Matcher<arg_type>() const {\
@@ -1861,19 +763,19 @@ AnyOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5, M6 m6, M7 m7, M8 m8, M9 m9, M10 m10) {
}\
name##MatcherP7(p0##_type gmock_p0, p1##_type gmock_p1, \
p2##_type gmock_p2, p3##_type gmock_p3, p4##_type gmock_p4, \
- p5##_type gmock_p5, p6##_type gmock_p6) : p0(gmock_p0), p1(gmock_p1), \
- p2(gmock_p2), p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), \
- p6(gmock_p6) {\
+ p5##_type gmock_p5, p6##_type gmock_p6) : p0(::std::move(gmock_p0)), \
+ p1(::std::move(gmock_p1)), p2(::std::move(gmock_p2)), \
+ p3(::std::move(gmock_p3)), p4(::std::move(gmock_p4)), \
+ p5(::std::move(gmock_p5)), p6(::std::move(gmock_p6)) {\
}\
- p0##_type p0;\
- p1##_type p1;\
- p2##_type p2;\
- p3##_type p3;\
- p4##_type p4;\
- p5##_type p5;\
- p6##_type p6;\
+ p0##_type const p0;\
+ p1##_type const p1;\
+ p2##_type const p2;\
+ p3##_type const p3;\
+ p4##_type const p4;\
+ p5##_type const p5;\
+ p6##_type const p6;\
private:\
- GTEST_DISALLOW_ASSIGN_(name##MatcherP7);\
};\
template <typename p0##_type, typename p1##_type, typename p2##_type, \
typename p3##_type, typename p4##_type, typename p5##_type, \
@@ -1891,7 +793,7 @@ AnyOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5, M6 m6, M7 m7, M8 m8, M9 m9, M10 m10) {
template <typename arg_type>\
bool name##MatcherP7<p0##_type, p1##_type, p2##_type, p3##_type, p4##_type, \
p5##_type, p6##_type>::gmock_Impl<arg_type>::MatchAndExplain(\
- arg_type arg, \
+ GTEST_REFERENCE_TO_CONST_(arg_type) arg,\
::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\
const
@@ -1902,42 +804,46 @@ AnyOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5, M6 m6, M7 m7, M8 m8, M9 m9, M10 m10) {
class name##MatcherP8 {\
public:\
template <typename arg_type>\
- class gmock_Impl : public ::testing::MatcherInterface<arg_type> {\
+ class gmock_Impl : public ::testing::MatcherInterface<\
+ GTEST_REFERENCE_TO_CONST_(arg_type)> {\
public:\
gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \
p3##_type gmock_p3, p4##_type gmock_p4, p5##_type gmock_p5, \
p6##_type gmock_p6, p7##_type gmock_p7)\
- : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), p3(gmock_p3), \
- p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), p7(gmock_p7) {}\
+ : p0(::std::move(gmock_p0)), p1(::std::move(gmock_p1)), \
+ p2(::std::move(gmock_p2)), p3(::std::move(gmock_p3)), \
+ p4(::std::move(gmock_p4)), p5(::std::move(gmock_p5)), \
+ p6(::std::move(gmock_p6)), p7(::std::move(gmock_p7)) {}\
virtual bool MatchAndExplain(\
- arg_type arg, ::testing::MatchResultListener* result_listener) const;\
+ GTEST_REFERENCE_TO_CONST_(arg_type) arg,\
+ ::testing::MatchResultListener* result_listener) const;\
virtual void DescribeTo(::std::ostream* gmock_os) const {\
*gmock_os << FormatDescription(false);\
}\
virtual void DescribeNegationTo(::std::ostream* gmock_os) const {\
*gmock_os << FormatDescription(true);\
}\
- p0##_type p0;\
- p1##_type p1;\
- p2##_type p2;\
- p3##_type p3;\
- p4##_type p4;\
- p5##_type p5;\
- p6##_type p6;\
- p7##_type p7;\
+ p0##_type const p0;\
+ p1##_type const p1;\
+ p2##_type const p2;\
+ p3##_type const p3;\
+ p4##_type const p4;\
+ p5##_type const p5;\
+ p6##_type const p6;\
+ p7##_type const p7;\
private:\
- ::testing::internal::string FormatDescription(bool negation) const {\
- const ::testing::internal::string gmock_description = (description);\
- if (!gmock_description.empty())\
+ ::std::string FormatDescription(bool negation) const {\
+ ::std::string gmock_description = (description);\
+ if (!gmock_description.empty()) {\
return gmock_description;\
+ }\
return ::testing::internal::FormatMatcherDescription(\
negation, #name, \
::testing::internal::UniversalTersePrintTupleFieldsToStrings(\
- ::testing::tuple<p0##_type, p1##_type, p2##_type, p3##_type, \
+ ::std::tuple<p0##_type, p1##_type, p2##_type, p3##_type, \
p4##_type, p5##_type, p6##_type, p7##_type>(p0, p1, p2, \
p3, p4, p5, p6, p7)));\
}\
- GTEST_DISALLOW_ASSIGN_(gmock_Impl);\
};\
template <typename arg_type>\
operator ::testing::Matcher<arg_type>() const {\
@@ -1947,20 +853,21 @@ AnyOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5, M6 m6, M7 m7, M8 m8, M9 m9, M10 m10) {
name##MatcherP8(p0##_type gmock_p0, p1##_type gmock_p1, \
p2##_type gmock_p2, p3##_type gmock_p3, p4##_type gmock_p4, \
p5##_type gmock_p5, p6##_type gmock_p6, \
- p7##_type gmock_p7) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \
- p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), \
- p7(gmock_p7) {\
+ p7##_type gmock_p7) : p0(::std::move(gmock_p0)), \
+ p1(::std::move(gmock_p1)), p2(::std::move(gmock_p2)), \
+ p3(::std::move(gmock_p3)), p4(::std::move(gmock_p4)), \
+ p5(::std::move(gmock_p5)), p6(::std::move(gmock_p6)), \
+ p7(::std::move(gmock_p7)) {\
}\
- p0##_type p0;\
- p1##_type p1;\
- p2##_type p2;\
- p3##_type p3;\
- p4##_type p4;\
- p5##_type p5;\
- p6##_type p6;\
- p7##_type p7;\
+ p0##_type const p0;\
+ p1##_type const p1;\
+ p2##_type const p2;\
+ p3##_type const p3;\
+ p4##_type const p4;\
+ p5##_type const p5;\
+ p6##_type const p6;\
+ p7##_type const p7;\
private:\
- GTEST_DISALLOW_ASSIGN_(name##MatcherP8);\
};\
template <typename p0##_type, typename p1##_type, typename p2##_type, \
typename p3##_type, typename p4##_type, typename p5##_type, \
@@ -1980,7 +887,7 @@ AnyOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5, M6 m6, M7 m7, M8 m8, M9 m9, M10 m10) {
bool name##MatcherP8<p0##_type, p1##_type, p2##_type, p3##_type, p4##_type, \
p5##_type, p6##_type, \
p7##_type>::gmock_Impl<arg_type>::MatchAndExplain(\
- arg_type arg, \
+ GTEST_REFERENCE_TO_CONST_(arg_type) arg,\
::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\
const
@@ -1991,44 +898,48 @@ AnyOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5, M6 m6, M7 m7, M8 m8, M9 m9, M10 m10) {
class name##MatcherP9 {\
public:\
template <typename arg_type>\
- class gmock_Impl : public ::testing::MatcherInterface<arg_type> {\
+ class gmock_Impl : public ::testing::MatcherInterface<\
+ GTEST_REFERENCE_TO_CONST_(arg_type)> {\
public:\
gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \
p3##_type gmock_p3, p4##_type gmock_p4, p5##_type gmock_p5, \
p6##_type gmock_p6, p7##_type gmock_p7, p8##_type gmock_p8)\
- : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), p3(gmock_p3), \
- p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), p7(gmock_p7), \
- p8(gmock_p8) {}\
+ : p0(::std::move(gmock_p0)), p1(::std::move(gmock_p1)), \
+ p2(::std::move(gmock_p2)), p3(::std::move(gmock_p3)), \
+ p4(::std::move(gmock_p4)), p5(::std::move(gmock_p5)), \
+ p6(::std::move(gmock_p6)), p7(::std::move(gmock_p7)), \
+ p8(::std::move(gmock_p8)) {}\
virtual bool MatchAndExplain(\
- arg_type arg, ::testing::MatchResultListener* result_listener) const;\
+ GTEST_REFERENCE_TO_CONST_(arg_type) arg,\
+ ::testing::MatchResultListener* result_listener) const;\
virtual void DescribeTo(::std::ostream* gmock_os) const {\
*gmock_os << FormatDescription(false);\
}\
virtual void DescribeNegationTo(::std::ostream* gmock_os) const {\
*gmock_os << FormatDescription(true);\
}\
- p0##_type p0;\
- p1##_type p1;\
- p2##_type p2;\
- p3##_type p3;\
- p4##_type p4;\
- p5##_type p5;\
- p6##_type p6;\
- p7##_type p7;\
- p8##_type p8;\
+ p0##_type const p0;\
+ p1##_type const p1;\
+ p2##_type const p2;\
+ p3##_type const p3;\
+ p4##_type const p4;\
+ p5##_type const p5;\
+ p6##_type const p6;\
+ p7##_type const p7;\
+ p8##_type const p8;\
private:\
- ::testing::internal::string FormatDescription(bool negation) const {\
- const ::testing::internal::string gmock_description = (description);\
- if (!gmock_description.empty())\
+ ::std::string FormatDescription(bool negation) const {\
+ ::std::string gmock_description = (description);\
+ if (!gmock_description.empty()) {\
return gmock_description;\
+ }\
return ::testing::internal::FormatMatcherDescription(\
negation, #name, \
::testing::internal::UniversalTersePrintTupleFieldsToStrings(\
- ::testing::tuple<p0##_type, p1##_type, p2##_type, p3##_type, \
+ ::std::tuple<p0##_type, p1##_type, p2##_type, p3##_type, \
p4##_type, p5##_type, p6##_type, p7##_type, \
p8##_type>(p0, p1, p2, p3, p4, p5, p6, p7, p8)));\
}\
- GTEST_DISALLOW_ASSIGN_(gmock_Impl);\
};\
template <typename arg_type>\
operator ::testing::Matcher<arg_type>() const {\
@@ -2038,21 +949,22 @@ AnyOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5, M6 m6, M7 m7, M8 m8, M9 m9, M10 m10) {
name##MatcherP9(p0##_type gmock_p0, p1##_type gmock_p1, \
p2##_type gmock_p2, p3##_type gmock_p3, p4##_type gmock_p4, \
p5##_type gmock_p5, p6##_type gmock_p6, p7##_type gmock_p7, \
- p8##_type gmock_p8) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \
- p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), p7(gmock_p7), \
- p8(gmock_p8) {\
+ p8##_type gmock_p8) : p0(::std::move(gmock_p0)), \
+ p1(::std::move(gmock_p1)), p2(::std::move(gmock_p2)), \
+ p3(::std::move(gmock_p3)), p4(::std::move(gmock_p4)), \
+ p5(::std::move(gmock_p5)), p6(::std::move(gmock_p6)), \
+ p7(::std::move(gmock_p7)), p8(::std::move(gmock_p8)) {\
}\
- p0##_type p0;\
- p1##_type p1;\
- p2##_type p2;\
- p3##_type p3;\
- p4##_type p4;\
- p5##_type p5;\
- p6##_type p6;\
- p7##_type p7;\
- p8##_type p8;\
+ p0##_type const p0;\
+ p1##_type const p1;\
+ p2##_type const p2;\
+ p3##_type const p3;\
+ p4##_type const p4;\
+ p5##_type const p5;\
+ p6##_type const p6;\
+ p7##_type const p7;\
+ p8##_type const p8;\
private:\
- GTEST_DISALLOW_ASSIGN_(name##MatcherP9);\
};\
template <typename p0##_type, typename p1##_type, typename p2##_type, \
typename p3##_type, typename p4##_type, typename p5##_type, \
@@ -2073,7 +985,7 @@ AnyOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5, M6 m6, M7 m7, M8 m8, M9 m9, M10 m10) {
bool name##MatcherP9<p0##_type, p1##_type, p2##_type, p3##_type, p4##_type, \
p5##_type, p6##_type, p7##_type, \
p8##_type>::gmock_Impl<arg_type>::MatchAndExplain(\
- arg_type arg, \
+ GTEST_REFERENCE_TO_CONST_(arg_type) arg,\
::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\
const
@@ -2085,46 +997,50 @@ AnyOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5, M6 m6, M7 m7, M8 m8, M9 m9, M10 m10) {
class name##MatcherP10 {\
public:\
template <typename arg_type>\
- class gmock_Impl : public ::testing::MatcherInterface<arg_type> {\
+ class gmock_Impl : public ::testing::MatcherInterface<\
+ GTEST_REFERENCE_TO_CONST_(arg_type)> {\
public:\
gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \
p3##_type gmock_p3, p4##_type gmock_p4, p5##_type gmock_p5, \
p6##_type gmock_p6, p7##_type gmock_p7, p8##_type gmock_p8, \
p9##_type gmock_p9)\
- : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), p3(gmock_p3), \
- p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), p7(gmock_p7), \
- p8(gmock_p8), p9(gmock_p9) {}\
+ : p0(::std::move(gmock_p0)), p1(::std::move(gmock_p1)), \
+ p2(::std::move(gmock_p2)), p3(::std::move(gmock_p3)), \
+ p4(::std::move(gmock_p4)), p5(::std::move(gmock_p5)), \
+ p6(::std::move(gmock_p6)), p7(::std::move(gmock_p7)), \
+ p8(::std::move(gmock_p8)), p9(::std::move(gmock_p9)) {}\
virtual bool MatchAndExplain(\
- arg_type arg, ::testing::MatchResultListener* result_listener) const;\
+ GTEST_REFERENCE_TO_CONST_(arg_type) arg,\
+ ::testing::MatchResultListener* result_listener) const;\
virtual void DescribeTo(::std::ostream* gmock_os) const {\
*gmock_os << FormatDescription(false);\
}\
virtual void DescribeNegationTo(::std::ostream* gmock_os) const {\
*gmock_os << FormatDescription(true);\
}\
- p0##_type p0;\
- p1##_type p1;\
- p2##_type p2;\
- p3##_type p3;\
- p4##_type p4;\
- p5##_type p5;\
- p6##_type p6;\
- p7##_type p7;\
- p8##_type p8;\
- p9##_type p9;\
+ p0##_type const p0;\
+ p1##_type const p1;\
+ p2##_type const p2;\
+ p3##_type const p3;\
+ p4##_type const p4;\
+ p5##_type const p5;\
+ p6##_type const p6;\
+ p7##_type const p7;\
+ p8##_type const p8;\
+ p9##_type const p9;\
private:\
- ::testing::internal::string FormatDescription(bool negation) const {\
- const ::testing::internal::string gmock_description = (description);\
- if (!gmock_description.empty())\
+ ::std::string FormatDescription(bool negation) const {\
+ ::std::string gmock_description = (description);\
+ if (!gmock_description.empty()) {\
return gmock_description;\
+ }\
return ::testing::internal::FormatMatcherDescription(\
negation, #name, \
::testing::internal::UniversalTersePrintTupleFieldsToStrings(\
- ::testing::tuple<p0##_type, p1##_type, p2##_type, p3##_type, \
+ ::std::tuple<p0##_type, p1##_type, p2##_type, p3##_type, \
p4##_type, p5##_type, p6##_type, p7##_type, p8##_type, \
p9##_type>(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9)));\
}\
- GTEST_DISALLOW_ASSIGN_(gmock_Impl);\
};\
template <typename arg_type>\
operator ::testing::Matcher<arg_type>() const {\
@@ -2134,22 +1050,24 @@ AnyOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5, M6 m6, M7 m7, M8 m8, M9 m9, M10 m10) {
name##MatcherP10(p0##_type gmock_p0, p1##_type gmock_p1, \
p2##_type gmock_p2, p3##_type gmock_p3, p4##_type gmock_p4, \
p5##_type gmock_p5, p6##_type gmock_p6, p7##_type gmock_p7, \
- p8##_type gmock_p8, p9##_type gmock_p9) : p0(gmock_p0), p1(gmock_p1), \
- p2(gmock_p2), p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), \
- p7(gmock_p7), p8(gmock_p8), p9(gmock_p9) {\
+ p8##_type gmock_p8, p9##_type gmock_p9) : p0(::std::move(gmock_p0)), \
+ p1(::std::move(gmock_p1)), p2(::std::move(gmock_p2)), \
+ p3(::std::move(gmock_p3)), p4(::std::move(gmock_p4)), \
+ p5(::std::move(gmock_p5)), p6(::std::move(gmock_p6)), \
+ p7(::std::move(gmock_p7)), p8(::std::move(gmock_p8)), \
+ p9(::std::move(gmock_p9)) {\
}\
- p0##_type p0;\
- p1##_type p1;\
- p2##_type p2;\
- p3##_type p3;\
- p4##_type p4;\
- p5##_type p5;\
- p6##_type p6;\
- p7##_type p7;\
- p8##_type p8;\
- p9##_type p9;\
+ p0##_type const p0;\
+ p1##_type const p1;\
+ p2##_type const p2;\
+ p3##_type const p3;\
+ p4##_type const p4;\
+ p5##_type const p5;\
+ p6##_type const p6;\
+ p7##_type const p7;\
+ p8##_type const p8;\
+ p9##_type const p9;\
private:\
- GTEST_DISALLOW_ASSIGN_(name##MatcherP10);\
};\
template <typename p0##_type, typename p1##_type, typename p2##_type, \
typename p3##_type, typename p4##_type, typename p5##_type, \
@@ -2172,7 +1090,7 @@ AnyOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5, M6 m6, M7 m7, M8 m8, M9 m9, M10 m10) {
bool name##MatcherP10<p0##_type, p1##_type, p2##_type, p3##_type, \
p4##_type, p5##_type, p6##_type, p7##_type, p8##_type, \
p9##_type>::gmock_Impl<arg_type>::MatchAndExplain(\
- arg_type arg, \
+ GTEST_REFERENCE_TO_CONST_(arg_type) arg,\
::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\
const
diff --git a/extern/gmock/include/gmock/gmock-generated-nice-strict.h b/extern/gmock/include/gmock/gmock-generated-nice-strict.h
deleted file mode 100644
index 4095f4d5bc7..00000000000
--- a/extern/gmock/include/gmock/gmock-generated-nice-strict.h
+++ /dev/null
@@ -1,397 +0,0 @@
-// This file was GENERATED by command:
-// pump.py gmock-generated-nice-strict.h.pump
-// DO NOT EDIT BY HAND!!!
-
-// Copyright 2008, 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.
-//
-// Author: wan@google.com (Zhanyong Wan)
-
-// Implements class templates NiceMock, NaggyMock, and StrictMock.
-//
-// Given a mock class MockFoo that is created using Google Mock,
-// NiceMock<MockFoo> is a subclass of MockFoo that allows
-// uninteresting calls (i.e. calls to mock methods that have no
-// EXPECT_CALL specs), NaggyMock<MockFoo> is a subclass of MockFoo
-// that prints a warning when an uninteresting call occurs, and
-// StrictMock<MockFoo> is a subclass of MockFoo that treats all
-// uninteresting calls as errors.
-//
-// Currently a mock is naggy by default, so MockFoo and
-// NaggyMock<MockFoo> behave like the same. However, we will soon
-// switch the default behavior of mocks to be nice, as that in general
-// leads to more maintainable tests. When that happens, MockFoo will
-// stop behaving like NaggyMock<MockFoo> and start behaving like
-// NiceMock<MockFoo>.
-//
-// NiceMock, NaggyMock, and StrictMock "inherit" the constructors of
-// their respective base class, with up-to 10 arguments. Therefore
-// you can write NiceMock<MockFoo>(5, "a") to construct a nice mock
-// where MockFoo has a constructor that accepts (int, const char*),
-// for example.
-//
-// A known limitation is that NiceMock<MockFoo>, NaggyMock<MockFoo>,
-// and StrictMock<MockFoo> only works for mock methods defined using
-// the MOCK_METHOD* family of macros DIRECTLY in the MockFoo class.
-// If a mock method is defined in a base class of MockFoo, the "nice"
-// or "strict" modifier may not affect it, depending on the compiler.
-// In particular, nesting NiceMock, NaggyMock, and StrictMock is NOT
-// supported.
-//
-// Another known limitation is that the constructors of the base mock
-// cannot have arguments passed by non-const reference, which are
-// banned by the Google C++ style guide anyway.
-
-#ifndef GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_NICE_STRICT_H_
-#define GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_NICE_STRICT_H_
-
-#include "gmock/gmock-spec-builders.h"
-#include "gmock/internal/gmock-port.h"
-
-namespace testing {
-
-template <class MockClass>
-class NiceMock : public MockClass {
- public:
- // We don't factor out the constructor body to a common method, as
- // we have to avoid a possible clash with members of MockClass.
- NiceMock() {
- ::testing::Mock::AllowUninterestingCalls(
- internal::ImplicitCast_<MockClass*>(this));
- }
-
- // C++ doesn't (yet) allow inheritance of constructors, so we have
- // to define it for each arity.
- template <typename A1>
- explicit NiceMock(const A1& a1) : MockClass(a1) {
- ::testing::Mock::AllowUninterestingCalls(
- internal::ImplicitCast_<MockClass*>(this));
- }
- template <typename A1, typename A2>
- NiceMock(const A1& a1, const A2& a2) : MockClass(a1, a2) {
- ::testing::Mock::AllowUninterestingCalls(
- internal::ImplicitCast_<MockClass*>(this));
- }
-
- template <typename A1, typename A2, typename A3>
- NiceMock(const A1& a1, const A2& a2, const A3& a3) : MockClass(a1, a2, a3) {
- ::testing::Mock::AllowUninterestingCalls(
- internal::ImplicitCast_<MockClass*>(this));
- }
-
- template <typename A1, typename A2, typename A3, typename A4>
- NiceMock(const A1& a1, const A2& a2, const A3& a3,
- const A4& a4) : MockClass(a1, a2, a3, a4) {
- ::testing::Mock::AllowUninterestingCalls(
- internal::ImplicitCast_<MockClass*>(this));
- }
-
- template <typename A1, typename A2, typename A3, typename A4, typename A5>
- NiceMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4,
- const A5& a5) : MockClass(a1, a2, a3, a4, a5) {
- ::testing::Mock::AllowUninterestingCalls(
- internal::ImplicitCast_<MockClass*>(this));
- }
-
- template <typename A1, typename A2, typename A3, typename A4, typename A5,
- typename A6>
- NiceMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4,
- const A5& a5, const A6& a6) : MockClass(a1, a2, a3, a4, a5, a6) {
- ::testing::Mock::AllowUninterestingCalls(
- internal::ImplicitCast_<MockClass*>(this));
- }
-
- template <typename A1, typename A2, typename A3, typename A4, typename A5,
- typename A6, typename A7>
- NiceMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4,
- const A5& a5, const A6& a6, const A7& a7) : MockClass(a1, a2, a3, a4, a5,
- a6, a7) {
- ::testing::Mock::AllowUninterestingCalls(
- internal::ImplicitCast_<MockClass*>(this));
- }
-
- template <typename A1, typename A2, typename A3, typename A4, typename A5,
- typename A6, typename A7, typename A8>
- NiceMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4,
- const A5& a5, const A6& a6, const A7& a7, const A8& a8) : MockClass(a1,
- a2, a3, a4, a5, a6, a7, a8) {
- ::testing::Mock::AllowUninterestingCalls(
- internal::ImplicitCast_<MockClass*>(this));
- }
-
- template <typename A1, typename A2, typename A3, typename A4, typename A5,
- typename A6, typename A7, typename A8, typename A9>
- NiceMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4,
- const A5& a5, const A6& a6, const A7& a7, const A8& a8,
- const A9& a9) : MockClass(a1, a2, a3, a4, a5, a6, a7, a8, a9) {
- ::testing::Mock::AllowUninterestingCalls(
- internal::ImplicitCast_<MockClass*>(this));
- }
-
- template <typename A1, typename A2, typename A3, typename A4, typename A5,
- typename A6, typename A7, typename A8, typename A9, typename A10>
- NiceMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4,
- const A5& a5, const A6& a6, const A7& a7, const A8& a8, const A9& a9,
- const A10& a10) : MockClass(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) {
- ::testing::Mock::AllowUninterestingCalls(
- internal::ImplicitCast_<MockClass*>(this));
- }
-
- virtual ~NiceMock() {
- ::testing::Mock::UnregisterCallReaction(
- internal::ImplicitCast_<MockClass*>(this));
- }
-
- private:
- GTEST_DISALLOW_COPY_AND_ASSIGN_(NiceMock);
-};
-
-template <class MockClass>
-class NaggyMock : public MockClass {
- public:
- // We don't factor out the constructor body to a common method, as
- // we have to avoid a possible clash with members of MockClass.
- NaggyMock() {
- ::testing::Mock::WarnUninterestingCalls(
- internal::ImplicitCast_<MockClass*>(this));
- }
-
- // C++ doesn't (yet) allow inheritance of constructors, so we have
- // to define it for each arity.
- template <typename A1>
- explicit NaggyMock(const A1& a1) : MockClass(a1) {
- ::testing::Mock::WarnUninterestingCalls(
- internal::ImplicitCast_<MockClass*>(this));
- }
- template <typename A1, typename A2>
- NaggyMock(const A1& a1, const A2& a2) : MockClass(a1, a2) {
- ::testing::Mock::WarnUninterestingCalls(
- internal::ImplicitCast_<MockClass*>(this));
- }
-
- template <typename A1, typename A2, typename A3>
- NaggyMock(const A1& a1, const A2& a2, const A3& a3) : MockClass(a1, a2, a3) {
- ::testing::Mock::WarnUninterestingCalls(
- internal::ImplicitCast_<MockClass*>(this));
- }
-
- template <typename A1, typename A2, typename A3, typename A4>
- NaggyMock(const A1& a1, const A2& a2, const A3& a3,
- const A4& a4) : MockClass(a1, a2, a3, a4) {
- ::testing::Mock::WarnUninterestingCalls(
- internal::ImplicitCast_<MockClass*>(this));
- }
-
- template <typename A1, typename A2, typename A3, typename A4, typename A5>
- NaggyMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4,
- const A5& a5) : MockClass(a1, a2, a3, a4, a5) {
- ::testing::Mock::WarnUninterestingCalls(
- internal::ImplicitCast_<MockClass*>(this));
- }
-
- template <typename A1, typename A2, typename A3, typename A4, typename A5,
- typename A6>
- NaggyMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4,
- const A5& a5, const A6& a6) : MockClass(a1, a2, a3, a4, a5, a6) {
- ::testing::Mock::WarnUninterestingCalls(
- internal::ImplicitCast_<MockClass*>(this));
- }
-
- template <typename A1, typename A2, typename A3, typename A4, typename A5,
- typename A6, typename A7>
- NaggyMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4,
- const A5& a5, const A6& a6, const A7& a7) : MockClass(a1, a2, a3, a4, a5,
- a6, a7) {
- ::testing::Mock::WarnUninterestingCalls(
- internal::ImplicitCast_<MockClass*>(this));
- }
-
- template <typename A1, typename A2, typename A3, typename A4, typename A5,
- typename A6, typename A7, typename A8>
- NaggyMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4,
- const A5& a5, const A6& a6, const A7& a7, const A8& a8) : MockClass(a1,
- a2, a3, a4, a5, a6, a7, a8) {
- ::testing::Mock::WarnUninterestingCalls(
- internal::ImplicitCast_<MockClass*>(this));
- }
-
- template <typename A1, typename A2, typename A3, typename A4, typename A5,
- typename A6, typename A7, typename A8, typename A9>
- NaggyMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4,
- const A5& a5, const A6& a6, const A7& a7, const A8& a8,
- const A9& a9) : MockClass(a1, a2, a3, a4, a5, a6, a7, a8, a9) {
- ::testing::Mock::WarnUninterestingCalls(
- internal::ImplicitCast_<MockClass*>(this));
- }
-
- template <typename A1, typename A2, typename A3, typename A4, typename A5,
- typename A6, typename A7, typename A8, typename A9, typename A10>
- NaggyMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4,
- const A5& a5, const A6& a6, const A7& a7, const A8& a8, const A9& a9,
- const A10& a10) : MockClass(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) {
- ::testing::Mock::WarnUninterestingCalls(
- internal::ImplicitCast_<MockClass*>(this));
- }
-
- virtual ~NaggyMock() {
- ::testing::Mock::UnregisterCallReaction(
- internal::ImplicitCast_<MockClass*>(this));
- }
-
- private:
- GTEST_DISALLOW_COPY_AND_ASSIGN_(NaggyMock);
-};
-
-template <class MockClass>
-class StrictMock : public MockClass {
- public:
- // We don't factor out the constructor body to a common method, as
- // we have to avoid a possible clash with members of MockClass.
- StrictMock() {
- ::testing::Mock::FailUninterestingCalls(
- internal::ImplicitCast_<MockClass*>(this));
- }
-
- // C++ doesn't (yet) allow inheritance of constructors, so we have
- // to define it for each arity.
- template <typename A1>
- explicit StrictMock(const A1& a1) : MockClass(a1) {
- ::testing::Mock::FailUninterestingCalls(
- internal::ImplicitCast_<MockClass*>(this));
- }
- template <typename A1, typename A2>
- StrictMock(const A1& a1, const A2& a2) : MockClass(a1, a2) {
- ::testing::Mock::FailUninterestingCalls(
- internal::ImplicitCast_<MockClass*>(this));
- }
-
- template <typename A1, typename A2, typename A3>
- StrictMock(const A1& a1, const A2& a2, const A3& a3) : MockClass(a1, a2, a3) {
- ::testing::Mock::FailUninterestingCalls(
- internal::ImplicitCast_<MockClass*>(this));
- }
-
- template <typename A1, typename A2, typename A3, typename A4>
- StrictMock(const A1& a1, const A2& a2, const A3& a3,
- const A4& a4) : MockClass(a1, a2, a3, a4) {
- ::testing::Mock::FailUninterestingCalls(
- internal::ImplicitCast_<MockClass*>(this));
- }
-
- template <typename A1, typename A2, typename A3, typename A4, typename A5>
- StrictMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4,
- const A5& a5) : MockClass(a1, a2, a3, a4, a5) {
- ::testing::Mock::FailUninterestingCalls(
- internal::ImplicitCast_<MockClass*>(this));
- }
-
- template <typename A1, typename A2, typename A3, typename A4, typename A5,
- typename A6>
- StrictMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4,
- const A5& a5, const A6& a6) : MockClass(a1, a2, a3, a4, a5, a6) {
- ::testing::Mock::FailUninterestingCalls(
- internal::ImplicitCast_<MockClass*>(this));
- }
-
- template <typename A1, typename A2, typename A3, typename A4, typename A5,
- typename A6, typename A7>
- StrictMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4,
- const A5& a5, const A6& a6, const A7& a7) : MockClass(a1, a2, a3, a4, a5,
- a6, a7) {
- ::testing::Mock::FailUninterestingCalls(
- internal::ImplicitCast_<MockClass*>(this));
- }
-
- template <typename A1, typename A2, typename A3, typename A4, typename A5,
- typename A6, typename A7, typename A8>
- StrictMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4,
- const A5& a5, const A6& a6, const A7& a7, const A8& a8) : MockClass(a1,
- a2, a3, a4, a5, a6, a7, a8) {
- ::testing::Mock::FailUninterestingCalls(
- internal::ImplicitCast_<MockClass*>(this));
- }
-
- template <typename A1, typename A2, typename A3, typename A4, typename A5,
- typename A6, typename A7, typename A8, typename A9>
- StrictMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4,
- const A5& a5, const A6& a6, const A7& a7, const A8& a8,
- const A9& a9) : MockClass(a1, a2, a3, a4, a5, a6, a7, a8, a9) {
- ::testing::Mock::FailUninterestingCalls(
- internal::ImplicitCast_<MockClass*>(this));
- }
-
- template <typename A1, typename A2, typename A3, typename A4, typename A5,
- typename A6, typename A7, typename A8, typename A9, typename A10>
- StrictMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4,
- const A5& a5, const A6& a6, const A7& a7, const A8& a8, const A9& a9,
- const A10& a10) : MockClass(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) {
- ::testing::Mock::FailUninterestingCalls(
- internal::ImplicitCast_<MockClass*>(this));
- }
-
- virtual ~StrictMock() {
- ::testing::Mock::UnregisterCallReaction(
- internal::ImplicitCast_<MockClass*>(this));
- }
-
- private:
- GTEST_DISALLOW_COPY_AND_ASSIGN_(StrictMock);
-};
-
-// The following specializations catch some (relatively more common)
-// user errors of nesting nice and strict mocks. They do NOT catch
-// all possible errors.
-
-// These specializations are declared but not defined, as NiceMock,
-// NaggyMock, and StrictMock cannot be nested.
-
-template <typename MockClass>
-class NiceMock<NiceMock<MockClass> >;
-template <typename MockClass>
-class NiceMock<NaggyMock<MockClass> >;
-template <typename MockClass>
-class NiceMock<StrictMock<MockClass> >;
-
-template <typename MockClass>
-class NaggyMock<NiceMock<MockClass> >;
-template <typename MockClass>
-class NaggyMock<NaggyMock<MockClass> >;
-template <typename MockClass>
-class NaggyMock<StrictMock<MockClass> >;
-
-template <typename MockClass>
-class StrictMock<NiceMock<MockClass> >;
-template <typename MockClass>
-class StrictMock<NaggyMock<MockClass> >;
-template <typename MockClass>
-class StrictMock<StrictMock<MockClass> >;
-
-} // namespace testing
-
-#endif // GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_NICE_STRICT_H_
diff --git a/extern/gmock/include/gmock/gmock-matchers.h b/extern/gmock/include/gmock/gmock-matchers.h
index 33b37a7a5d6..28e188bb813 100644
--- a/extern/gmock/include/gmock/gmock-matchers.h
+++ b/extern/gmock/include/gmock/gmock-matchers.h
@@ -26,36 +26,50 @@
// 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.
-//
-// Author: wan@google.com (Zhanyong Wan)
+
// Google Mock - a framework for writing C++ mock classes.
//
// This file implements some commonly used argument matchers. More
// matchers can be defined by the user implementing the
// MatcherInterface<T> interface if necessary.
+//
+// See googletest/include/gtest/gtest-matchers.h for the definition of class
+// Matcher, class MatcherInterface, and others.
+
+// GOOGLETEST_CM0002 DO NOT DELETE
#ifndef GMOCK_INCLUDE_GMOCK_GMOCK_MATCHERS_H_
#define GMOCK_INCLUDE_GMOCK_GMOCK_MATCHERS_H_
#include <math.h>
#include <algorithm>
+#include <initializer_list>
#include <iterator>
#include <limits>
+#include <memory>
#include <ostream> // NOLINT
#include <sstream>
#include <string>
+#include <type_traits>
#include <utility>
#include <vector>
-
#include "gmock/internal/gmock-internal-utils.h"
#include "gmock/internal/gmock-port.h"
#include "gtest/gtest.h"
-#if GTEST_HAS_STD_INITIALIZER_LIST_
-# include <initializer_list> // NOLINT -- must be after gtest.h
+// MSVC warning C5046 is new as of VS2017 version 15.8.
+#if defined(_MSC_VER) && _MSC_VER >= 1915
+#define GMOCK_MAYBE_5046_ 5046
+#else
+#define GMOCK_MAYBE_5046_
#endif
+GTEST_DISABLE_MSC_WARNINGS_PUSH_(
+ 4251 GMOCK_MAYBE_5046_ /* class A needs to have dll-interface to be used by
+ clients of class B */
+ /* Symbol involving type with internal linkage not defined */)
+
namespace testing {
// To implement a matcher Foo for type T, define:
@@ -70,123 +84,13 @@ namespace testing {
// ownership management as Matcher objects can now be copied like
// plain values.
-// MatchResultListener is an abstract class. Its << operator can be
-// used by a matcher to explain why a value matches or doesn't match.
-//
-// TODO(wan@google.com): add method
-// bool InterestedInWhy(bool result) const;
-// to indicate whether the listener is interested in why the match
-// result is 'result'.
-class MatchResultListener {
- public:
- // Creates a listener object with the given underlying ostream. The
- // listener does not own the ostream, and does not dereference it
- // in the constructor or destructor.
- explicit MatchResultListener(::std::ostream* os) : stream_(os) {}
- virtual ~MatchResultListener() = 0; // Makes this class abstract.
-
- // Streams x to the underlying ostream; does nothing if the ostream
- // is NULL.
- template <typename T>
- MatchResultListener& operator<<(const T& x) {
- if (stream_ != NULL)
- *stream_ << x;
- return *this;
- }
-
- // Returns the underlying ostream.
- ::std::ostream* stream() { return stream_; }
-
- // Returns true iff the listener is interested in an explanation of
- // the match result. A matcher's MatchAndExplain() method can use
- // this information to avoid generating the explanation when no one
- // intends to hear it.
- bool IsInterested() const { return stream_ != NULL; }
-
- private:
- ::std::ostream* const stream_;
-
- GTEST_DISALLOW_COPY_AND_ASSIGN_(MatchResultListener);
-};
-
-inline MatchResultListener::~MatchResultListener() {
-}
-
-// An instance of a subclass of this knows how to describe itself as a
-// matcher.
-class MatcherDescriberInterface {
- public:
- virtual ~MatcherDescriberInterface() {}
-
- // Describes this matcher to an ostream. The function should print
- // a verb phrase that describes the property a value matching this
- // matcher should have. The subject of the verb phrase is the value
- // being matched. For example, the DescribeTo() method of the Gt(7)
- // matcher prints "is greater than 7".
- virtual void DescribeTo(::std::ostream* os) const = 0;
-
- // Describes the negation of this matcher to an ostream. For
- // example, if the description of this matcher is "is greater than
- // 7", the negated description could be "is not greater than 7".
- // You are not required to override this when implementing
- // MatcherInterface, but it is highly advised so that your matcher
- // can produce good error messages.
- virtual void DescribeNegationTo(::std::ostream* os) const {
- *os << "not (";
- DescribeTo(os);
- *os << ")";
- }
-};
-
-// The implementation of a matcher.
-template <typename T>
-class MatcherInterface : public MatcherDescriberInterface {
- public:
- // Returns true iff the matcher matches x; also explains the match
- // result to 'listener' if necessary (see the next paragraph), in
- // the form of a non-restrictive relative clause ("which ...",
- // "whose ...", etc) that describes x. For example, the
- // MatchAndExplain() method of the Pointee(...) matcher should
- // generate an explanation like "which points to ...".
- //
- // Implementations of MatchAndExplain() should add an explanation of
- // the match result *if and only if* they can provide additional
- // information that's not already present (or not obvious) in the
- // print-out of x and the matcher's description. Whether the match
- // succeeds is not a factor in deciding whether an explanation is
- // needed, as sometimes the caller needs to print a failure message
- // when the match succeeds (e.g. when the matcher is used inside
- // Not()).
- //
- // For example, a "has at least 10 elements" matcher should explain
- // what the actual element count is, regardless of the match result,
- // as it is useful information to the reader; on the other hand, an
- // "is empty" matcher probably only needs to explain what the actual
- // size is when the match fails, as it's redundant to say that the
- // size is 0 when the value is already known to be empty.
- //
- // You should override this method when defining a new matcher.
- //
- // It's the responsibility of the caller (Google Mock) to guarantee
- // that 'listener' is not NULL. This helps to simplify a matcher's
- // implementation when it doesn't care about the performance, as it
- // can talk to 'listener' without checking its validity first.
- // However, in order to implement dummy listeners efficiently,
- // listener->stream() may be NULL.
- virtual bool MatchAndExplain(T x, MatchResultListener* listener) const = 0;
-
- // Inherits these methods from MatcherDescriberInterface:
- // virtual void DescribeTo(::std::ostream* os) const = 0;
- // virtual void DescribeNegationTo(::std::ostream* os) const;
-};
-
// A match result listener that stores the explanation in a string.
class StringMatchResultListener : public MatchResultListener {
public:
StringMatchResultListener() : MatchResultListener(&ss_) {}
// Returns the explanation accumulated so far.
- internal::string str() const { return ss_.str(); }
+ std::string str() const { return ss_.str(); }
// Clears the explanation accumulated so far.
void Clear() { ss_.str(""); }
@@ -197,306 +101,6 @@ class StringMatchResultListener : public MatchResultListener {
GTEST_DISALLOW_COPY_AND_ASSIGN_(StringMatchResultListener);
};
-namespace internal {
-
-struct AnyEq {
- template <typename A, typename B>
- bool operator()(const A& a, const B& b) const { return a == b; }
-};
-struct AnyNe {
- template <typename A, typename B>
- bool operator()(const A& a, const B& b) const { return a != b; }
-};
-struct AnyLt {
- template <typename A, typename B>
- bool operator()(const A& a, const B& b) const { return a < b; }
-};
-struct AnyGt {
- template <typename A, typename B>
- bool operator()(const A& a, const B& b) const { return a > b; }
-};
-struct AnyLe {
- template <typename A, typename B>
- bool operator()(const A& a, const B& b) const { return a <= b; }
-};
-struct AnyGe {
- template <typename A, typename B>
- bool operator()(const A& a, const B& b) const { return a >= b; }
-};
-
-// A match result listener that ignores the explanation.
-class DummyMatchResultListener : public MatchResultListener {
- public:
- DummyMatchResultListener() : MatchResultListener(NULL) {}
-
- private:
- GTEST_DISALLOW_COPY_AND_ASSIGN_(DummyMatchResultListener);
-};
-
-// A match result listener that forwards the explanation to a given
-// ostream. The difference between this and MatchResultListener is
-// that the former is concrete.
-class StreamMatchResultListener : public MatchResultListener {
- public:
- explicit StreamMatchResultListener(::std::ostream* os)
- : MatchResultListener(os) {}
-
- private:
- GTEST_DISALLOW_COPY_AND_ASSIGN_(StreamMatchResultListener);
-};
-
-// An internal class for implementing Matcher<T>, which will derive
-// from it. We put functionalities common to all Matcher<T>
-// specializations here to avoid code duplication.
-template <typename T>
-class MatcherBase {
- public:
- // Returns true iff the matcher matches x; also explains the match
- // result to 'listener'.
- bool MatchAndExplain(T x, MatchResultListener* listener) const {
- return impl_->MatchAndExplain(x, listener);
- }
-
- // Returns true iff this matcher matches x.
- bool Matches(T x) const {
- DummyMatchResultListener dummy;
- return MatchAndExplain(x, &dummy);
- }
-
- // Describes this matcher to an ostream.
- void DescribeTo(::std::ostream* os) const { impl_->DescribeTo(os); }
-
- // Describes the negation of this matcher to an ostream.
- void DescribeNegationTo(::std::ostream* os) const {
- impl_->DescribeNegationTo(os);
- }
-
- // Explains why x matches, or doesn't match, the matcher.
- void ExplainMatchResultTo(T x, ::std::ostream* os) const {
- StreamMatchResultListener listener(os);
- MatchAndExplain(x, &listener);
- }
-
- // Returns the describer for this matcher object; retains ownership
- // of the describer, which is only guaranteed to be alive when
- // this matcher object is alive.
- const MatcherDescriberInterface* GetDescriber() const {
- return impl_.get();
- }
-
- protected:
- MatcherBase() {}
-
- // Constructs a matcher from its implementation.
- explicit MatcherBase(const MatcherInterface<T>* impl)
- : impl_(impl) {}
-
- virtual ~MatcherBase() {}
-
- private:
- // shared_ptr (util/gtl/shared_ptr.h) and linked_ptr have similar
- // interfaces. The former dynamically allocates a chunk of memory
- // to hold the reference count, while the latter tracks all
- // references using a circular linked list without allocating
- // memory. It has been observed that linked_ptr performs better in
- // typical scenarios. However, shared_ptr can out-perform
- // linked_ptr when there are many more uses of the copy constructor
- // than the default constructor.
- //
- // If performance becomes a problem, we should see if using
- // shared_ptr helps.
- ::testing::internal::linked_ptr<const MatcherInterface<T> > impl_;
-};
-
-} // namespace internal
-
-// A Matcher<T> is a copyable and IMMUTABLE (except by assignment)
-// object that can check whether a value of type T matches. The
-// implementation of Matcher<T> is just a linked_ptr to const
-// MatcherInterface<T>, so copying is fairly cheap. Don't inherit
-// from Matcher!
-template <typename T>
-class Matcher : public internal::MatcherBase<T> {
- public:
- // Constructs a null matcher. Needed for storing Matcher objects in STL
- // containers. A default-constructed matcher is not yet initialized. You
- // cannot use it until a valid value has been assigned to it.
- explicit Matcher() {} // NOLINT
-
- // Constructs a matcher from its implementation.
- explicit Matcher(const MatcherInterface<T>* impl)
- : internal::MatcherBase<T>(impl) {}
-
- // Implicit constructor here allows people to write
- // EXPECT_CALL(foo, Bar(5)) instead of EXPECT_CALL(foo, Bar(Eq(5))) sometimes
- Matcher(T value); // NOLINT
-};
-
-// The following two specializations allow the user to write str
-// instead of Eq(str) and "foo" instead of Eq("foo") when a string
-// matcher is expected.
-template <>
-class GTEST_API_ Matcher<const internal::string&>
- : public internal::MatcherBase<const internal::string&> {
- public:
- Matcher() {}
-
- explicit Matcher(const MatcherInterface<const internal::string&>* impl)
- : internal::MatcherBase<const internal::string&>(impl) {}
-
- // Allows the user to write str instead of Eq(str) sometimes, where
- // str is a string object.
- Matcher(const internal::string& s); // NOLINT
-
- // Allows the user to write "foo" instead of Eq("foo") sometimes.
- Matcher(const char* s); // NOLINT
-};
-
-template <>
-class GTEST_API_ Matcher<internal::string>
- : public internal::MatcherBase<internal::string> {
- public:
- Matcher() {}
-
- explicit Matcher(const MatcherInterface<internal::string>* impl)
- : internal::MatcherBase<internal::string>(impl) {}
-
- // Allows the user to write str instead of Eq(str) sometimes, where
- // str is a string object.
- Matcher(const internal::string& s); // NOLINT
-
- // Allows the user to write "foo" instead of Eq("foo") sometimes.
- Matcher(const char* s); // NOLINT
-};
-
-#if GTEST_HAS_STRING_PIECE_
-// The following two specializations allow the user to write str
-// instead of Eq(str) and "foo" instead of Eq("foo") when a StringPiece
-// matcher is expected.
-template <>
-class GTEST_API_ Matcher<const StringPiece&>
- : public internal::MatcherBase<const StringPiece&> {
- public:
- Matcher() {}
-
- explicit Matcher(const MatcherInterface<const StringPiece&>* impl)
- : internal::MatcherBase<const StringPiece&>(impl) {}
-
- // Allows the user to write str instead of Eq(str) sometimes, where
- // str is a string object.
- Matcher(const internal::string& s); // NOLINT
-
- // Allows the user to write "foo" instead of Eq("foo") sometimes.
- Matcher(const char* s); // NOLINT
-
- // Allows the user to pass StringPieces directly.
- Matcher(StringPiece s); // NOLINT
-};
-
-template <>
-class GTEST_API_ Matcher<StringPiece>
- : public internal::MatcherBase<StringPiece> {
- public:
- Matcher() {}
-
- explicit Matcher(const MatcherInterface<StringPiece>* impl)
- : internal::MatcherBase<StringPiece>(impl) {}
-
- // Allows the user to write str instead of Eq(str) sometimes, where
- // str is a string object.
- Matcher(const internal::string& s); // NOLINT
-
- // Allows the user to write "foo" instead of Eq("foo") sometimes.
- Matcher(const char* s); // NOLINT
-
- // Allows the user to pass StringPieces directly.
- Matcher(StringPiece s); // NOLINT
-};
-#endif // GTEST_HAS_STRING_PIECE_
-
-// The PolymorphicMatcher class template makes it easy to implement a
-// polymorphic matcher (i.e. a matcher that can match values of more
-// than one type, e.g. Eq(n) and NotNull()).
-//
-// To define a polymorphic matcher, a user should provide an Impl
-// class that has a DescribeTo() method and a DescribeNegationTo()
-// method, and define a member function (or member function template)
-//
-// bool MatchAndExplain(const Value& value,
-// MatchResultListener* listener) const;
-//
-// See the definition of NotNull() for a complete example.
-template <class Impl>
-class PolymorphicMatcher {
- public:
- explicit PolymorphicMatcher(const Impl& an_impl) : impl_(an_impl) {}
-
- // Returns a mutable reference to the underlying matcher
- // implementation object.
- Impl& mutable_impl() { return impl_; }
-
- // Returns an immutable reference to the underlying matcher
- // implementation object.
- const Impl& impl() const { return impl_; }
-
- template <typename T>
- operator Matcher<T>() const {
- return Matcher<T>(new MonomorphicImpl<T>(impl_));
- }
-
- private:
- template <typename T>
- class MonomorphicImpl : public MatcherInterface<T> {
- public:
- explicit MonomorphicImpl(const Impl& impl) : impl_(impl) {}
-
- virtual void DescribeTo(::std::ostream* os) const {
- impl_.DescribeTo(os);
- }
-
- virtual void DescribeNegationTo(::std::ostream* os) const {
- impl_.DescribeNegationTo(os);
- }
-
- virtual bool MatchAndExplain(T x, MatchResultListener* listener) const {
- return impl_.MatchAndExplain(x, listener);
- }
-
- private:
- const Impl impl_;
-
- GTEST_DISALLOW_ASSIGN_(MonomorphicImpl);
- };
-
- Impl impl_;
-
- GTEST_DISALLOW_ASSIGN_(PolymorphicMatcher);
-};
-
-// Creates a matcher from its implementation. This is easier to use
-// than the Matcher<T> constructor as it doesn't require you to
-// explicitly write the template argument, e.g.
-//
-// MakeMatcher(foo);
-// vs
-// Matcher<const string&>(foo);
-template <typename T>
-inline Matcher<T> MakeMatcher(const MatcherInterface<T>* impl) {
- return Matcher<T>(impl);
-}
-
-// Creates a polymorphic matcher from its implementation. This is
-// easier to use than the PolymorphicMatcher<Impl> constructor as it
-// doesn't require you to explicitly write the template argument, e.g.
-//
-// MakePolymorphicMatcher(foo);
-// vs
-// PolymorphicMatcher<TypeOfFoo>(foo);
-template <class Impl>
-inline PolymorphicMatcher<Impl> MakePolymorphicMatcher(const Impl& impl) {
- return PolymorphicMatcher<Impl>(impl);
-}
-
// Anything inside the 'internal' namespace IS INTERNAL IMPLEMENTATION
// and MUST NOT BE USED IN USER CODE!!!
namespace internal {
@@ -515,7 +119,7 @@ template <typename T, typename M>
class MatcherCastImpl {
public:
static Matcher<T> Cast(const M& polymorphic_matcher_or_value) {
- // M can be a polymorhic matcher, in which case we want to use
+ // M can be a polymorphic matcher, in which case we want to use
// its conversion operator to create Matcher<T>. Or it can be a value
// that should be passed to the Matcher<T>'s constructor.
//
@@ -528,24 +132,18 @@ class MatcherCastImpl {
// polymorphic_matcher_or_value to Matcher<T> because it won't trigger
// a user-defined conversion from M to T if one exists (assuming M is
// a value).
- return CastImpl(
- polymorphic_matcher_or_value,
- BooleanConstant<
- internal::ImplicitlyConvertible<M, Matcher<T> >::value>());
+ return CastImpl(polymorphic_matcher_or_value,
+ std::is_convertible<M, Matcher<T>>{},
+ std::is_convertible<M, T>{});
}
private:
- static Matcher<T> CastImpl(const M& value, BooleanConstant<false>) {
- // M can't be implicitly converted to Matcher<T>, so M isn't a polymorphic
- // matcher. It must be a value then. Use direct initialization to create
- // a matcher.
- return Matcher<T>(ImplicitCast_<T>(value));
- }
-
+ template <bool Ignore>
static Matcher<T> CastImpl(const M& polymorphic_matcher_or_value,
- BooleanConstant<true>) {
+ std::true_type /* convertible_to_matcher */,
+ bool_constant<Ignore>) {
// M is implicitly convertible to Matcher<T>, which means that either
- // M is a polymorhpic matcher or Matcher<T> has an implicit constructor
+ // M is a polymorphic matcher or Matcher<T> has an implicit constructor
// from M. In both cases using the implicit conversion will produce a
// matcher.
//
@@ -554,6 +152,29 @@ class MatcherCastImpl {
// (first to create T from M and then to create Matcher<T> from T).
return polymorphic_matcher_or_value;
}
+
+ // M can't be implicitly converted to Matcher<T>, so M isn't a polymorphic
+ // matcher. It's a value of a type implicitly convertible to T. Use direct
+ // initialization to create a matcher.
+ static Matcher<T> CastImpl(const M& value,
+ std::false_type /* convertible_to_matcher */,
+ std::true_type /* convertible_to_T */) {
+ return Matcher<T>(ImplicitCast_<T>(value));
+ }
+
+ // M can't be implicitly converted to either Matcher<T> or T. Attempt to use
+ // polymorphic matcher Eq(value) in this case.
+ //
+ // Note that we first attempt to perform an implicit cast on the value and
+ // only fall back to the polymorphic Eq() matcher afterwards because the
+ // latter calls bool operator==(const Lhs& lhs, const Rhs& rhs) in the end
+ // which might be undefined even when Rhs is implicitly convertible to Lhs
+ // (e.g. std::pair<const int, int> vs. std::pair<int, int>).
+ //
+ // We don't define this method inline as we need the declaration of Eq().
+ static Matcher<T> CastImpl(const M& value,
+ std::false_type /* convertible_to_matcher */,
+ std::false_type /* convertible_to_T */);
};
// This more specialized version is used when MatcherCast()'s argument
@@ -573,15 +194,29 @@ class MatcherCastImpl<T, Matcher<U> > {
: source_matcher_(source_matcher) {}
// We delegate the matching logic to the source matcher.
- virtual bool MatchAndExplain(T x, MatchResultListener* listener) const {
+ bool MatchAndExplain(T x, MatchResultListener* listener) const override {
+ using FromType = typename std::remove_cv<typename std::remove_pointer<
+ typename std::remove_reference<T>::type>::type>::type;
+ using ToType = typename std::remove_cv<typename std::remove_pointer<
+ typename std::remove_reference<U>::type>::type>::type;
+ // Do not allow implicitly converting base*/& to derived*/&.
+ static_assert(
+ // Do not trigger if only one of them is a pointer. That implies a
+ // regular conversion and not a down_cast.
+ (std::is_pointer<typename std::remove_reference<T>::type>::value !=
+ std::is_pointer<typename std::remove_reference<U>::type>::value) ||
+ std::is_same<FromType, ToType>::value ||
+ !std::is_base_of<FromType, ToType>::value,
+ "Can't implicitly convert from <base> to <derived>");
+
return source_matcher_.MatchAndExplain(static_cast<U>(x), listener);
}
- virtual void DescribeTo(::std::ostream* os) const {
+ void DescribeTo(::std::ostream* os) const override {
source_matcher_.DescribeTo(os);
}
- virtual void DescribeNegationTo(::std::ostream* os) const {
+ void DescribeNegationTo(::std::ostream* os) const override {
source_matcher_.DescribeNegationTo(os);
}
@@ -613,11 +248,8 @@ inline Matcher<T> MatcherCast(const M& matcher) {
// Implements SafeMatcherCast().
//
-// We use an intermediate class to do the actual safe casting as Nokia's
-// Symbian compiler cannot decide between
-// template <T, M> ... (M) and
-// template <T, U> ... (const Matcher<U>&)
-// for function templates but can for member function templates.
+// FIXME: The intermediate SafeMatcherCastImpl class was introduced as a
+// workaround for a compiler bug, and can now be removed.
template <typename T>
class SafeMatcherCastImpl {
public:
@@ -640,13 +272,13 @@ class SafeMatcherCastImpl {
template <typename U>
static inline Matcher<T> Cast(const Matcher<U>& matcher) {
// Enforce that T can be implicitly converted to U.
- GTEST_COMPILE_ASSERT_((internal::ImplicitlyConvertible<T, U>::value),
- T_must_be_implicitly_convertible_to_U);
+ GTEST_COMPILE_ASSERT_((std::is_convertible<T, U>::value),
+ "T must be implicitly convertible to U");
// Enforce that we are not converting a non-reference type T to a reference
// type U.
GTEST_COMPILE_ASSERT_(
- internal::is_reference<T>::value || !internal::is_reference<U>::value,
- cannot_convert_non_referentce_arg_to_reference);
+ std::is_reference<T>::value || !std::is_reference<U>::value,
+ cannot_convert_non_reference_arg_to_reference);
// In case both T and U are arithmetic types, enforce that the
// conversion is not lossy.
typedef GTEST_REMOVE_REFERENCE_AND_CONST_(T) RawT;
@@ -675,9 +307,9 @@ Matcher<T> A();
namespace internal {
// If the explanation is not empty, prints it to the ostream.
-inline void PrintIfNotEmpty(const internal::string& explanation,
+inline void PrintIfNotEmpty(const std::string& explanation,
::std::ostream* os) {
- if (explanation != "" && os != NULL) {
+ if (explanation != "" && os != nullptr) {
*os << ", " << explanation;
}
}
@@ -685,11 +317,11 @@ inline void PrintIfNotEmpty(const internal::string& explanation,
// Returns true if the given type name is easy to read by a human.
// This is used to decide whether printing the type of a value might
// be helpful.
-inline bool IsReadableTypeName(const string& type_name) {
+inline bool IsReadableTypeName(const std::string& type_name) {
// We consider a type name readable if it's short or doesn't contain
// a template or function type.
return (type_name.length() <= 20 ||
- type_name.find_first_of("<(") == string::npos);
+ type_name.find_first_of("<(") == std::string::npos);
}
// Matches the value against the given matcher, prints the value and explains
@@ -711,7 +343,7 @@ bool MatchPrintAndExplain(Value& value, const Matcher<T>& matcher,
UniversalPrint(value, listener->stream());
#if GTEST_HAS_RTTI
- const string& type_name = GetTypeName<Value>();
+ const std::string& type_name = GetTypeName<Value>();
if (IsReadableTypeName(type_name))
*listener->stream() << " (of type " << type_name << ")";
#endif
@@ -726,13 +358,13 @@ template <size_t N>
class TuplePrefix {
public:
// TuplePrefix<N>::Matches(matcher_tuple, value_tuple) returns true
- // iff the first N fields of matcher_tuple matches the first N
- // fields of value_tuple, respectively.
+ // if and only if the first N fields of matcher_tuple matches
+ // the first N fields of value_tuple, respectively.
template <typename MatcherTuple, typename ValueTuple>
static bool Matches(const MatcherTuple& matcher_tuple,
const ValueTuple& value_tuple) {
- return TuplePrefix<N - 1>::Matches(matcher_tuple, value_tuple)
- && get<N - 1>(matcher_tuple).Matches(get<N - 1>(value_tuple));
+ return TuplePrefix<N - 1>::Matches(matcher_tuple, value_tuple) &&
+ std::get<N - 1>(matcher_tuple).Matches(std::get<N - 1>(value_tuple));
}
// TuplePrefix<N>::ExplainMatchFailuresTo(matchers, values, os)
@@ -748,16 +380,14 @@ class TuplePrefix {
// Then describes the failure (if any) in the (N - 1)-th (0-based)
// field.
- typename tuple_element<N - 1, MatcherTuple>::type matcher =
- get<N - 1>(matchers);
- typedef typename tuple_element<N - 1, ValueTuple>::type Value;
- Value value = get<N - 1>(values);
+ typename std::tuple_element<N - 1, MatcherTuple>::type matcher =
+ std::get<N - 1>(matchers);
+ typedef typename std::tuple_element<N - 1, ValueTuple>::type Value;
+ const Value& value = std::get<N - 1>(values);
StringMatchResultListener listener;
if (!matcher.MatchAndExplain(value, &listener)) {
- // TODO(wan): include in the message the name of the parameter
- // as used in MOCK_METHOD*() when possible.
*os << " Expected arg #" << N - 1 << ": ";
- get<N - 1>(matchers).DescribeTo(os);
+ std::get<N - 1>(matchers).DescribeTo(os);
*os << "\n Actual: ";
// We remove the reference in type Value to prevent the
// universal printer from printing the address of value, which
@@ -787,8 +417,8 @@ class TuplePrefix<0> {
::std::ostream* /* os */) {}
};
-// TupleMatches(matcher_tuple, value_tuple) returns true iff all
-// matchers in matcher_tuple match the corresponding fields in
+// TupleMatches(matcher_tuple, value_tuple) returns true if and only if
+// all matchers in matcher_tuple match the corresponding fields in
// value_tuple. It is a compiler error if matcher_tuple and
// value_tuple have different number of fields or incompatible field
// types.
@@ -797,11 +427,11 @@ bool TupleMatches(const MatcherTuple& matcher_tuple,
const ValueTuple& value_tuple) {
// Makes sure that matcher_tuple and value_tuple have the same
// number of fields.
- GTEST_COMPILE_ASSERT_(tuple_size<MatcherTuple>::value ==
- tuple_size<ValueTuple>::value,
+ GTEST_COMPILE_ASSERT_(std::tuple_size<MatcherTuple>::value ==
+ std::tuple_size<ValueTuple>::value,
matcher_and_value_have_different_numbers_of_fields);
- return TuplePrefix<tuple_size<ValueTuple>::value>::
- Matches(matcher_tuple, value_tuple);
+ return TuplePrefix<std::tuple_size<ValueTuple>::value>::Matches(matcher_tuple,
+ value_tuple);
}
// Describes failures in matching matchers against values. If there
@@ -810,7 +440,7 @@ template <typename MatcherTuple, typename ValueTuple>
void ExplainMatchFailureTupleTo(const MatcherTuple& matchers,
const ValueTuple& values,
::std::ostream* os) {
- TuplePrefix<tuple_size<MatcherTuple>::value>::ExplainMatchFailuresTo(
+ TuplePrefix<std::tuple_size<MatcherTuple>::value>::ExplainMatchFailuresTo(
matchers, values, os);
}
@@ -821,7 +451,7 @@ void ExplainMatchFailureTupleTo(const MatcherTuple& matchers,
template <typename Tuple, typename Func, typename OutIter>
class TransformTupleValuesHelper {
private:
- typedef ::testing::tuple_size<Tuple> TupleSize;
+ typedef ::std::tuple_size<Tuple> TupleSize;
public:
// For each member of tuple 't', taken in order, evaluates '*out++ = f(t)'.
@@ -834,7 +464,7 @@ class TransformTupleValuesHelper {
template <typename Tup, size_t kRemainingSize>
struct IterateOverTuple {
OutIter operator() (Func f, const Tup& t, OutIter out) const {
- *out++ = f(::testing::get<TupleSize::value - kRemainingSize>(t));
+ *out++ = f(::std::get<TupleSize::value - kRemainingSize>(t));
return IterateOverTuple<Tup, kRemainingSize - 1>()(f, t, out);
}
};
@@ -856,12 +486,14 @@ OutIter TransformTupleValues(Func f, const Tuple& t, OutIter out) {
// Implements A<T>().
template <typename T>
-class AnyMatcherImpl : public MatcherInterface<T> {
+class AnyMatcherImpl : public MatcherInterface<const T&> {
public:
- virtual bool MatchAndExplain(
- T /* x */, MatchResultListener* /* listener */) const { return true; }
- virtual void DescribeTo(::std::ostream* os) const { *os << "is anything"; }
- virtual void DescribeNegationTo(::std::ostream* os) const {
+ bool MatchAndExplain(const T& /* x */,
+ MatchResultListener* /* listener */) const override {
+ return true;
+ }
+ void DescribeTo(::std::ostream* os) const override { *os << "is anything"; }
+ void DescribeNegationTo(::std::ostream* os) const override {
// This is mostly for completeness' safe, as it's not very useful
// to write Not(A<bool>()). However we cannot completely rule out
// such a possibility, and it doesn't hurt to be prepared.
@@ -879,99 +511,6 @@ class AnythingMatcher {
operator Matcher<T>() const { return A<T>(); }
};
-// Implements a matcher that compares a given value with a
-// pre-supplied value using one of the ==, <=, <, etc, operators. The
-// two values being compared don't have to have the same type.
-//
-// The matcher defined here is polymorphic (for example, Eq(5) can be
-// used to match an int, a short, a double, etc). Therefore we use
-// a template type conversion operator in the implementation.
-//
-// The following template definition assumes that the Rhs parameter is
-// a "bare" type (i.e. neither 'const T' nor 'T&').
-template <typename D, typename Rhs, typename Op>
-class ComparisonBase {
- public:
- explicit ComparisonBase(const Rhs& rhs) : rhs_(rhs) {}
- template <typename Lhs>
- operator Matcher<Lhs>() const {
- return MakeMatcher(new Impl<Lhs>(rhs_));
- }
-
- private:
- template <typename Lhs>
- class Impl : public MatcherInterface<Lhs> {
- public:
- explicit Impl(const Rhs& rhs) : rhs_(rhs) {}
- virtual bool MatchAndExplain(
- Lhs lhs, MatchResultListener* /* listener */) const {
- return Op()(lhs, rhs_);
- }
- virtual void DescribeTo(::std::ostream* os) const {
- *os << D::Desc() << " ";
- UniversalPrint(rhs_, os);
- }
- virtual void DescribeNegationTo(::std::ostream* os) const {
- *os << D::NegatedDesc() << " ";
- UniversalPrint(rhs_, os);
- }
- private:
- Rhs rhs_;
- GTEST_DISALLOW_ASSIGN_(Impl);
- };
- Rhs rhs_;
- GTEST_DISALLOW_ASSIGN_(ComparisonBase);
-};
-
-template <typename Rhs>
-class EqMatcher : public ComparisonBase<EqMatcher<Rhs>, Rhs, AnyEq> {
- public:
- explicit EqMatcher(const Rhs& rhs)
- : ComparisonBase<EqMatcher<Rhs>, Rhs, AnyEq>(rhs) { }
- static const char* Desc() { return "is equal to"; }
- static const char* NegatedDesc() { return "isn't equal to"; }
-};
-template <typename Rhs>
-class NeMatcher : public ComparisonBase<NeMatcher<Rhs>, Rhs, AnyNe> {
- public:
- explicit NeMatcher(const Rhs& rhs)
- : ComparisonBase<NeMatcher<Rhs>, Rhs, AnyNe>(rhs) { }
- static const char* Desc() { return "isn't equal to"; }
- static const char* NegatedDesc() { return "is equal to"; }
-};
-template <typename Rhs>
-class LtMatcher : public ComparisonBase<LtMatcher<Rhs>, Rhs, AnyLt> {
- public:
- explicit LtMatcher(const Rhs& rhs)
- : ComparisonBase<LtMatcher<Rhs>, Rhs, AnyLt>(rhs) { }
- static const char* Desc() { return "is <"; }
- static const char* NegatedDesc() { return "isn't <"; }
-};
-template <typename Rhs>
-class GtMatcher : public ComparisonBase<GtMatcher<Rhs>, Rhs, AnyGt> {
- public:
- explicit GtMatcher(const Rhs& rhs)
- : ComparisonBase<GtMatcher<Rhs>, Rhs, AnyGt>(rhs) { }
- static const char* Desc() { return "is >"; }
- static const char* NegatedDesc() { return "isn't >"; }
-};
-template <typename Rhs>
-class LeMatcher : public ComparisonBase<LeMatcher<Rhs>, Rhs, AnyLe> {
- public:
- explicit LeMatcher(const Rhs& rhs)
- : ComparisonBase<LeMatcher<Rhs>, Rhs, AnyLe>(rhs) { }
- static const char* Desc() { return "is <="; }
- static const char* NegatedDesc() { return "isn't <="; }
-};
-template <typename Rhs>
-class GeMatcher : public ComparisonBase<GeMatcher<Rhs>, Rhs, AnyGe> {
- public:
- explicit GeMatcher(const Rhs& rhs)
- : ComparisonBase<GeMatcher<Rhs>, Rhs, AnyGe>(rhs) { }
- static const char* Desc() { return "is >="; }
- static const char* NegatedDesc() { return "isn't >="; }
-};
-
// Implements the polymorphic IsNull() matcher, which matches any raw or smart
// pointer that is NULL.
class IsNullMatcher {
@@ -979,11 +518,7 @@ class IsNullMatcher {
template <typename Pointer>
bool MatchAndExplain(const Pointer& p,
MatchResultListener* /* listener */) const {
-#if GTEST_LANG_CXX11
return p == nullptr;
-#else // GTEST_LANG_CXX11
- return GetRawPointer(p) == NULL;
-#endif // GTEST_LANG_CXX11
}
void DescribeTo(::std::ostream* os) const { *os << "is NULL"; }
@@ -999,11 +534,7 @@ class NotNullMatcher {
template <typename Pointer>
bool MatchAndExplain(const Pointer& p,
MatchResultListener* /* listener */) const {
-#if GTEST_LANG_CXX11
return p != nullptr;
-#else // GTEST_LANG_CXX11
- return GetRawPointer(p) != NULL;
-#endif // GTEST_LANG_CXX11
}
void DescribeTo(::std::ostream* os) const { *os << "isn't NULL"; }
@@ -1059,18 +590,18 @@ class RefMatcher<T&> {
// MatchAndExplain() takes a Super& (as opposed to const Super&)
// in order to match the interface MatcherInterface<Super&>.
- virtual bool MatchAndExplain(
- Super& x, MatchResultListener* listener) const {
+ bool MatchAndExplain(Super& x,
+ MatchResultListener* listener) const override {
*listener << "which is located @" << static_cast<const void*>(&x);
return &x == &object_;
}
- virtual void DescribeTo(::std::ostream* os) const {
+ void DescribeTo(::std::ostream* os) const override {
*os << "references the variable ";
UniversalPrinter<Super&>::Print(object_, os);
}
- virtual void DescribeNegationTo(::std::ostream* os) const {
+ void DescribeNegationTo(::std::ostream* os) const override {
*os << "does not reference the variable ";
UniversalPrinter<Super&>::Print(object_, os);
}
@@ -1129,6 +660,16 @@ class StrEqualityMatcher {
bool case_sensitive)
: string_(str), expect_eq_(expect_eq), case_sensitive_(case_sensitive) {}
+#if GTEST_HAS_ABSL
+ bool MatchAndExplain(const absl::string_view& s,
+ MatchResultListener* listener) const {
+ // This should fail to compile if absl::string_view is used with wide
+ // strings.
+ const StringType& str = std::string(s);
+ return MatchAndExplain(str, listener);
+ }
+#endif // GTEST_HAS_ABSL
+
// Accepts pointer types, particularly:
// const char*
// char*
@@ -1136,7 +677,7 @@ class StrEqualityMatcher {
// wchar_t*
template <typename CharType>
bool MatchAndExplain(CharType* s, MatchResultListener* listener) const {
- if (s == NULL) {
+ if (s == nullptr) {
return !expect_eq_;
}
return MatchAndExplain(StringType(s), listener);
@@ -1145,7 +686,7 @@ class StrEqualityMatcher {
// Matches anything that can convert to StringType.
//
// This is a template, not just a plain function with const StringType&,
- // because StringPiece has some interfering non-explicit constructors.
+ // because absl::string_view has some interfering non-explicit constructors.
template <typename MatcheeStringType>
bool MatchAndExplain(const MatcheeStringType& s,
MatchResultListener* /* listener */) const {
@@ -1189,6 +730,16 @@ class HasSubstrMatcher {
explicit HasSubstrMatcher(const StringType& substring)
: substring_(substring) {}
+#if GTEST_HAS_ABSL
+ bool MatchAndExplain(const absl::string_view& s,
+ MatchResultListener* listener) const {
+ // This should fail to compile if absl::string_view is used with wide
+ // strings.
+ const StringType& str = std::string(s);
+ return MatchAndExplain(str, listener);
+ }
+#endif // GTEST_HAS_ABSL
+
// Accepts pointer types, particularly:
// const char*
// char*
@@ -1196,13 +747,13 @@ class HasSubstrMatcher {
// wchar_t*
template <typename CharType>
bool MatchAndExplain(CharType* s, MatchResultListener* listener) const {
- return s != NULL && MatchAndExplain(StringType(s), listener);
+ return s != nullptr && MatchAndExplain(StringType(s), listener);
}
// Matches anything that can convert to StringType.
//
// This is a template, not just a plain function with const StringType&,
- // because StringPiece has some interfering non-explicit constructors.
+ // because absl::string_view has some interfering non-explicit constructors.
template <typename MatcheeStringType>
bool MatchAndExplain(const MatcheeStringType& s,
MatchResultListener* /* listener */) const {
@@ -1236,6 +787,16 @@ class StartsWithMatcher {
explicit StartsWithMatcher(const StringType& prefix) : prefix_(prefix) {
}
+#if GTEST_HAS_ABSL
+ bool MatchAndExplain(const absl::string_view& s,
+ MatchResultListener* listener) const {
+ // This should fail to compile if absl::string_view is used with wide
+ // strings.
+ const StringType& str = std::string(s);
+ return MatchAndExplain(str, listener);
+ }
+#endif // GTEST_HAS_ABSL
+
// Accepts pointer types, particularly:
// const char*
// char*
@@ -1243,13 +804,13 @@ class StartsWithMatcher {
// wchar_t*
template <typename CharType>
bool MatchAndExplain(CharType* s, MatchResultListener* listener) const {
- return s != NULL && MatchAndExplain(StringType(s), listener);
+ return s != nullptr && MatchAndExplain(StringType(s), listener);
}
// Matches anything that can convert to StringType.
//
// This is a template, not just a plain function with const StringType&,
- // because StringPiece has some interfering non-explicit constructors.
+ // because absl::string_view has some interfering non-explicit constructors.
template <typename MatcheeStringType>
bool MatchAndExplain(const MatcheeStringType& s,
MatchResultListener* /* listener */) const {
@@ -1282,6 +843,16 @@ class EndsWithMatcher {
public:
explicit EndsWithMatcher(const StringType& suffix) : suffix_(suffix) {}
+#if GTEST_HAS_ABSL
+ bool MatchAndExplain(const absl::string_view& s,
+ MatchResultListener* listener) const {
+ // This should fail to compile if absl::string_view is used with wide
+ // strings.
+ const StringType& str = std::string(s);
+ return MatchAndExplain(str, listener);
+ }
+#endif // GTEST_HAS_ABSL
+
// Accepts pointer types, particularly:
// const char*
// char*
@@ -1289,13 +860,13 @@ class EndsWithMatcher {
// wchar_t*
template <typename CharType>
bool MatchAndExplain(CharType* s, MatchResultListener* listener) const {
- return s != NULL && MatchAndExplain(StringType(s), listener);
+ return s != nullptr && MatchAndExplain(StringType(s), listener);
}
// Matches anything that can convert to StringType.
//
// This is a template, not just a plain function with const StringType&,
- // because StringPiece has some interfering non-explicit constructors.
+ // because absl::string_view has some interfering non-explicit constructors.
template <typename MatcheeStringType>
bool MatchAndExplain(const MatcheeStringType& s,
MatchResultListener* /* listener */) const {
@@ -1320,73 +891,24 @@ class EndsWithMatcher {
GTEST_DISALLOW_ASSIGN_(EndsWithMatcher);
};
-// Implements polymorphic matchers MatchesRegex(regex) and
-// ContainsRegex(regex), which can be used as a Matcher<T> as long as
-// T can be converted to a string.
-class MatchesRegexMatcher {
- public:
- MatchesRegexMatcher(const RE* regex, bool full_match)
- : regex_(regex), full_match_(full_match) {}
-
- // Accepts pointer types, particularly:
- // const char*
- // char*
- // const wchar_t*
- // wchar_t*
- template <typename CharType>
- bool MatchAndExplain(CharType* s, MatchResultListener* listener) const {
- return s != NULL && MatchAndExplain(internal::string(s), listener);
- }
-
- // Matches anything that can convert to internal::string.
- //
- // This is a template, not just a plain function with const internal::string&,
- // because StringPiece has some interfering non-explicit constructors.
- template <class MatcheeStringType>
- bool MatchAndExplain(const MatcheeStringType& s,
- MatchResultListener* /* listener */) const {
- const internal::string& s2(s);
- return full_match_ ? RE::FullMatch(s2, *regex_) :
- RE::PartialMatch(s2, *regex_);
- }
-
- void DescribeTo(::std::ostream* os) const {
- *os << (full_match_ ? "matches" : "contains")
- << " regular expression ";
- UniversalPrinter<internal::string>::Print(regex_->pattern(), os);
- }
-
- void DescribeNegationTo(::std::ostream* os) const {
- *os << "doesn't " << (full_match_ ? "match" : "contain")
- << " regular expression ";
- UniversalPrinter<internal::string>::Print(regex_->pattern(), os);
- }
-
- private:
- const internal::linked_ptr<const RE> regex_;
- const bool full_match_;
-
- GTEST_DISALLOW_ASSIGN_(MatchesRegexMatcher);
-};
-
// Implements a matcher that compares the two fields of a 2-tuple
// using one of the ==, <=, <, etc, operators. The two fields being
// compared don't have to have the same type.
//
// The matcher defined here is polymorphic (for example, Eq() can be
-// used to match a tuple<int, short>, a tuple<const long&, double>,
+// used to match a std::tuple<int, short>, a std::tuple<const long&, double>,
// etc). Therefore we use a template type conversion operator in the
// implementation.
template <typename D, typename Op>
class PairMatchBase {
public:
template <typename T1, typename T2>
- operator Matcher< ::testing::tuple<T1, T2> >() const {
- return MakeMatcher(new Impl< ::testing::tuple<T1, T2> >);
+ operator Matcher<::std::tuple<T1, T2>>() const {
+ return Matcher<::std::tuple<T1, T2>>(new Impl<const ::std::tuple<T1, T2>&>);
}
template <typename T1, typename T2>
- operator Matcher<const ::testing::tuple<T1, T2>&>() const {
- return MakeMatcher(new Impl<const ::testing::tuple<T1, T2>&>);
+ operator Matcher<const ::std::tuple<T1, T2>&>() const {
+ return MakeMatcher(new Impl<const ::std::tuple<T1, T2>&>);
}
private:
@@ -1397,15 +919,14 @@ class PairMatchBase {
template <typename Tuple>
class Impl : public MatcherInterface<Tuple> {
public:
- virtual bool MatchAndExplain(
- Tuple args,
- MatchResultListener* /* listener */) const {
- return Op()(::testing::get<0>(args), ::testing::get<1>(args));
+ bool MatchAndExplain(Tuple args,
+ MatchResultListener* /* listener */) const override {
+ return Op()(::std::get<0>(args), ::std::get<1>(args));
}
- virtual void DescribeTo(::std::ostream* os) const {
+ void DescribeTo(::std::ostream* os) const override {
*os << "are " << GetDesc;
}
- virtual void DescribeNegationTo(::std::ostream* os) const {
+ void DescribeNegationTo(::std::ostream* os) const override {
*os << "aren't " << GetDesc;
}
};
@@ -1441,20 +962,21 @@ class Ge2Matcher : public PairMatchBase<Ge2Matcher, AnyGe> {
// will prevent different instantiations of NotMatcher from sharing
// the same NotMatcherImpl<T> class.
template <typename T>
-class NotMatcherImpl : public MatcherInterface<T> {
+class NotMatcherImpl : public MatcherInterface<const T&> {
public:
explicit NotMatcherImpl(const Matcher<T>& matcher)
: matcher_(matcher) {}
- virtual bool MatchAndExplain(T x, MatchResultListener* listener) const {
+ bool MatchAndExplain(const T& x,
+ MatchResultListener* listener) const override {
return !matcher_.MatchAndExplain(x, listener);
}
- virtual void DescribeTo(::std::ostream* os) const {
+ void DescribeTo(::std::ostream* os) const override {
matcher_.DescribeNegationTo(os);
}
- virtual void DescribeNegationTo(::std::ostream* os) const {
+ void DescribeNegationTo(::std::ostream* os) const override {
matcher_.DescribeTo(os);
}
@@ -1489,115 +1011,62 @@ class NotMatcher {
// that will prevent different instantiations of BothOfMatcher from
// sharing the same BothOfMatcherImpl<T> class.
template <typename T>
-class BothOfMatcherImpl : public MatcherInterface<T> {
+class AllOfMatcherImpl : public MatcherInterface<const T&> {
public:
- BothOfMatcherImpl(const Matcher<T>& matcher1, const Matcher<T>& matcher2)
- : matcher1_(matcher1), matcher2_(matcher2) {}
+ explicit AllOfMatcherImpl(std::vector<Matcher<T> > matchers)
+ : matchers_(std::move(matchers)) {}
- virtual void DescribeTo(::std::ostream* os) const {
+ void DescribeTo(::std::ostream* os) const override {
*os << "(";
- matcher1_.DescribeTo(os);
- *os << ") and (";
- matcher2_.DescribeTo(os);
+ for (size_t i = 0; i < matchers_.size(); ++i) {
+ if (i != 0) *os << ") and (";
+ matchers_[i].DescribeTo(os);
+ }
*os << ")";
}
- virtual void DescribeNegationTo(::std::ostream* os) const {
+ void DescribeNegationTo(::std::ostream* os) const override {
*os << "(";
- matcher1_.DescribeNegationTo(os);
- *os << ") or (";
- matcher2_.DescribeNegationTo(os);
+ for (size_t i = 0; i < matchers_.size(); ++i) {
+ if (i != 0) *os << ") or (";
+ matchers_[i].DescribeNegationTo(os);
+ }
*os << ")";
}
- virtual bool MatchAndExplain(T x, MatchResultListener* listener) const {
+ bool MatchAndExplain(const T& x,
+ MatchResultListener* listener) const override {
// If either matcher1_ or matcher2_ doesn't match x, we only need
// to explain why one of them fails.
- StringMatchResultListener listener1;
- if (!matcher1_.MatchAndExplain(x, &listener1)) {
- *listener << listener1.str();
- return false;
- }
+ std::string all_match_result;
- StringMatchResultListener listener2;
- if (!matcher2_.MatchAndExplain(x, &listener2)) {
- *listener << listener2.str();
- return false;
+ for (size_t i = 0; i < matchers_.size(); ++i) {
+ StringMatchResultListener slistener;
+ if (matchers_[i].MatchAndExplain(x, &slistener)) {
+ if (all_match_result.empty()) {
+ all_match_result = slistener.str();
+ } else {
+ std::string result = slistener.str();
+ if (!result.empty()) {
+ all_match_result += ", and ";
+ all_match_result += result;
+ }
+ }
+ } else {
+ *listener << slistener.str();
+ return false;
+ }
}
// Otherwise we need to explain why *both* of them match.
- const internal::string s1 = listener1.str();
- const internal::string s2 = listener2.str();
-
- if (s1 == "") {
- *listener << s2;
- } else {
- *listener << s1;
- if (s2 != "") {
- *listener << ", and " << s2;
- }
- }
+ *listener << all_match_result;
return true;
}
private:
- const Matcher<T> matcher1_;
- const Matcher<T> matcher2_;
+ const std::vector<Matcher<T> > matchers_;
- GTEST_DISALLOW_ASSIGN_(BothOfMatcherImpl);
-};
-
-#if GTEST_LANG_CXX11
-// MatcherList provides mechanisms for storing a variable number of matchers in
-// a list structure (ListType) and creating a combining matcher from such a
-// list.
-// The template is defined recursively using the following template paramters:
-// * kSize is the length of the MatcherList.
-// * Head is the type of the first matcher of the list.
-// * Tail denotes the types of the remaining matchers of the list.
-template <int kSize, typename Head, typename... Tail>
-struct MatcherList {
- typedef MatcherList<kSize - 1, Tail...> MatcherListTail;
- typedef ::std::pair<Head, typename MatcherListTail::ListType> ListType;
-
- // BuildList stores variadic type values in a nested pair structure.
- // Example:
- // MatcherList<3, int, string, float>::BuildList(5, "foo", 2.0) will return
- // the corresponding result of type pair<int, pair<string, float>>.
- static ListType BuildList(const Head& matcher, const Tail&... tail) {
- return ListType(matcher, MatcherListTail::BuildList(tail...));
- }
-
- // CreateMatcher<T> creates a Matcher<T> from a given list of matchers (built
- // by BuildList()). CombiningMatcher<T> is used to combine the matchers of the
- // list. CombiningMatcher<T> must implement MatcherInterface<T> and have a
- // constructor taking two Matcher<T>s as input.
- template <typename T, template <typename /* T */> class CombiningMatcher>
- static Matcher<T> CreateMatcher(const ListType& matchers) {
- return Matcher<T>(new CombiningMatcher<T>(
- SafeMatcherCast<T>(matchers.first),
- MatcherListTail::template CreateMatcher<T, CombiningMatcher>(
- matchers.second)));
- }
-};
-
-// The following defines the base case for the recursive definition of
-// MatcherList.
-template <typename Matcher1, typename Matcher2>
-struct MatcherList<2, Matcher1, Matcher2> {
- typedef ::std::pair<Matcher1, Matcher2> ListType;
-
- static ListType BuildList(const Matcher1& matcher1,
- const Matcher2& matcher2) {
- return ::std::pair<Matcher1, Matcher2>(matcher1, matcher2);
- }
-
- template <typename T, template <typename /* T */> class CombiningMatcher>
- static Matcher<T> CreateMatcher(const ListType& matchers) {
- return Matcher<T>(new CombiningMatcher<T>(
- SafeMatcherCast<T>(matchers.first),
- SafeMatcherCast<T>(matchers.second)));
- }
+ GTEST_DISALLOW_ASSIGN_(AllOfMatcherImpl);
};
// VariadicMatcher is used for the variadic implementation of
@@ -1608,149 +1077,139 @@ template <template <typename T> class CombiningMatcher, typename... Args>
class VariadicMatcher {
public:
VariadicMatcher(const Args&... matchers) // NOLINT
- : matchers_(MatcherListType::BuildList(matchers...)) {}
+ : matchers_(matchers...) {
+ static_assert(sizeof...(Args) > 0, "Must have at least one matcher.");
+ }
// This template type conversion operator allows an
// VariadicMatcher<Matcher1, Matcher2...> object to match any type that
// all of the provided matchers (Matcher1, Matcher2, ...) can match.
template <typename T>
operator Matcher<T>() const {
- return MatcherListType::template CreateMatcher<T, CombiningMatcher>(
- matchers_);
+ std::vector<Matcher<T> > values;
+ CreateVariadicMatcher<T>(&values, std::integral_constant<size_t, 0>());
+ return Matcher<T>(new CombiningMatcher<T>(std::move(values)));
}
private:
- typedef MatcherList<sizeof...(Args), Args...> MatcherListType;
+ template <typename T, size_t I>
+ void CreateVariadicMatcher(std::vector<Matcher<T> >* values,
+ std::integral_constant<size_t, I>) const {
+ values->push_back(SafeMatcherCast<T>(std::get<I>(matchers_)));
+ CreateVariadicMatcher<T>(values, std::integral_constant<size_t, I + 1>());
+ }
- const typename MatcherListType::ListType matchers_;
+ template <typename T>
+ void CreateVariadicMatcher(
+ std::vector<Matcher<T> >*,
+ std::integral_constant<size_t, sizeof...(Args)>) const {}
+
+ std::tuple<Args...> matchers_;
GTEST_DISALLOW_ASSIGN_(VariadicMatcher);
};
template <typename... Args>
-using AllOfMatcher = VariadicMatcher<BothOfMatcherImpl, Args...>;
-
-#endif // GTEST_LANG_CXX11
-
-// Used for implementing the AllOf(m_1, ..., m_n) matcher, which
-// matches a value that matches all of the matchers m_1, ..., and m_n.
-template <typename Matcher1, typename Matcher2>
-class BothOfMatcher {
- public:
- BothOfMatcher(Matcher1 matcher1, Matcher2 matcher2)
- : matcher1_(matcher1), matcher2_(matcher2) {}
-
- // This template type conversion operator allows a
- // BothOfMatcher<Matcher1, Matcher2> object to match any type that
- // both Matcher1 and Matcher2 can match.
- template <typename T>
- operator Matcher<T>() const {
- return Matcher<T>(new BothOfMatcherImpl<T>(SafeMatcherCast<T>(matcher1_),
- SafeMatcherCast<T>(matcher2_)));
- }
-
- private:
- Matcher1 matcher1_;
- Matcher2 matcher2_;
-
- GTEST_DISALLOW_ASSIGN_(BothOfMatcher);
-};
+using AllOfMatcher = VariadicMatcher<AllOfMatcherImpl, Args...>;
// Implements the AnyOf(m1, m2) matcher for a particular argument type
// T. We do not nest it inside the AnyOfMatcher class template, as
// that will prevent different instantiations of AnyOfMatcher from
// sharing the same EitherOfMatcherImpl<T> class.
template <typename T>
-class EitherOfMatcherImpl : public MatcherInterface<T> {
+class AnyOfMatcherImpl : public MatcherInterface<const T&> {
public:
- EitherOfMatcherImpl(const Matcher<T>& matcher1, const Matcher<T>& matcher2)
- : matcher1_(matcher1), matcher2_(matcher2) {}
+ explicit AnyOfMatcherImpl(std::vector<Matcher<T> > matchers)
+ : matchers_(std::move(matchers)) {}
- virtual void DescribeTo(::std::ostream* os) const {
+ void DescribeTo(::std::ostream* os) const override {
*os << "(";
- matcher1_.DescribeTo(os);
- *os << ") or (";
- matcher2_.DescribeTo(os);
+ for (size_t i = 0; i < matchers_.size(); ++i) {
+ if (i != 0) *os << ") or (";
+ matchers_[i].DescribeTo(os);
+ }
*os << ")";
}
- virtual void DescribeNegationTo(::std::ostream* os) const {
+ void DescribeNegationTo(::std::ostream* os) const override {
*os << "(";
- matcher1_.DescribeNegationTo(os);
- *os << ") and (";
- matcher2_.DescribeNegationTo(os);
+ for (size_t i = 0; i < matchers_.size(); ++i) {
+ if (i != 0) *os << ") and (";
+ matchers_[i].DescribeNegationTo(os);
+ }
*os << ")";
}
- virtual bool MatchAndExplain(T x, MatchResultListener* listener) const {
+ bool MatchAndExplain(const T& x,
+ MatchResultListener* listener) const override {
+ std::string no_match_result;
+
// If either matcher1_ or matcher2_ matches x, we just need to
// explain why *one* of them matches.
- StringMatchResultListener listener1;
- if (matcher1_.MatchAndExplain(x, &listener1)) {
- *listener << listener1.str();
- return true;
- }
-
- StringMatchResultListener listener2;
- if (matcher2_.MatchAndExplain(x, &listener2)) {
- *listener << listener2.str();
- return true;
+ for (size_t i = 0; i < matchers_.size(); ++i) {
+ StringMatchResultListener slistener;
+ if (matchers_[i].MatchAndExplain(x, &slistener)) {
+ *listener << slistener.str();
+ return true;
+ } else {
+ if (no_match_result.empty()) {
+ no_match_result = slistener.str();
+ } else {
+ std::string result = slistener.str();
+ if (!result.empty()) {
+ no_match_result += ", and ";
+ no_match_result += result;
+ }
+ }
+ }
}
// Otherwise we need to explain why *both* of them fail.
- const internal::string s1 = listener1.str();
- const internal::string s2 = listener2.str();
-
- if (s1 == "") {
- *listener << s2;
- } else {
- *listener << s1;
- if (s2 != "") {
- *listener << ", and " << s2;
- }
- }
+ *listener << no_match_result;
return false;
}
private:
- const Matcher<T> matcher1_;
- const Matcher<T> matcher2_;
+ const std::vector<Matcher<T> > matchers_;
- GTEST_DISALLOW_ASSIGN_(EitherOfMatcherImpl);
+ GTEST_DISALLOW_ASSIGN_(AnyOfMatcherImpl);
};
-#if GTEST_LANG_CXX11
// AnyOfMatcher is used for the variadic implementation of AnyOf(m_1, m_2, ...).
template <typename... Args>
-using AnyOfMatcher = VariadicMatcher<EitherOfMatcherImpl, Args...>;
-
-#endif // GTEST_LANG_CXX11
+using AnyOfMatcher = VariadicMatcher<AnyOfMatcherImpl, Args...>;
-// Used for implementing the AnyOf(m_1, ..., m_n) matcher, which
-// matches a value that matches at least one of the matchers m_1, ...,
-// and m_n.
-template <typename Matcher1, typename Matcher2>
-class EitherOfMatcher {
+// Wrapper for implementation of Any/AllOfArray().
+template <template <class> class MatcherImpl, typename T>
+class SomeOfArrayMatcher {
public:
- EitherOfMatcher(Matcher1 matcher1, Matcher2 matcher2)
- : matcher1_(matcher1), matcher2_(matcher2) {}
+ // Constructs the matcher from a sequence of element values or
+ // element matchers.
+ template <typename Iter>
+ SomeOfArrayMatcher(Iter first, Iter last) : matchers_(first, last) {}
- // This template type conversion operator allows a
- // EitherOfMatcher<Matcher1, Matcher2> object to match any type that
- // both Matcher1 and Matcher2 can match.
- template <typename T>
- operator Matcher<T>() const {
- return Matcher<T>(new EitherOfMatcherImpl<T>(
- SafeMatcherCast<T>(matcher1_), SafeMatcherCast<T>(matcher2_)));
+ template <typename U>
+ operator Matcher<U>() const { // NOLINT
+ using RawU = typename std::decay<U>::type;
+ std::vector<Matcher<RawU>> matchers;
+ for (const auto& matcher : matchers_) {
+ matchers.push_back(MatcherCast<RawU>(matcher));
+ }
+ return Matcher<U>(new MatcherImpl<RawU>(std::move(matchers)));
}
private:
- Matcher1 matcher1_;
- Matcher2 matcher2_;
+ const ::std::vector<T> matchers_;
- GTEST_DISALLOW_ASSIGN_(EitherOfMatcher);
+ GTEST_DISALLOW_ASSIGN_(SomeOfArrayMatcher);
};
+template <typename T>
+using AllOfArrayMatcher = SomeOfArrayMatcher<AllOfMatcherImpl, T>;
+
+template <typename T>
+using AnyOfArrayMatcher = SomeOfArrayMatcher<AnyOfMatcherImpl, T>;
+
// Used for implementing Truly(pred), which turns a predicate into a
// matcher.
template <typename Predicate>
@@ -1833,7 +1292,7 @@ class MatcherAsPredicate {
template <typename M>
class PredicateFormatterFromMatcher {
public:
- explicit PredicateFormatterFromMatcher(M m) : matcher_(internal::move(m)) {}
+ explicit PredicateFormatterFromMatcher(M m) : matcher_(std::move(m)) {}
// This template () operator allows a PredicateFormatterFromMatcher
// object to act as a predicate-formatter suitable for using with
@@ -1852,14 +1311,24 @@ class PredicateFormatterFromMatcher {
// We don't write MatcherCast<const T&> either, as that allows
// potentially unsafe downcasting of the matcher argument.
const Matcher<const T&> matcher = SafeMatcherCast<const T&>(matcher_);
- StringMatchResultListener listener;
- if (MatchPrintAndExplain(x, matcher, &listener))
+
+ // The expected path here is that the matcher should match (i.e. that most
+ // tests pass) so optimize for this case.
+ if (matcher.Matches(x)) {
return AssertionSuccess();
+ }
::std::stringstream ss;
ss << "Value of: " << value_text << "\n"
<< "Expected: ";
matcher.DescribeTo(&ss);
+
+ // Rerun the matcher to "PrintAndExain" the failure.
+ StringMatchResultListener listener;
+ if (MatchPrintAndExplain(x, matcher, &listener)) {
+ ss << "\n The matcher failed on the initial attempt; but passed when "
+ "rerun to generate the explanation.";
+ }
ss << "\n Actual: " << listener.str();
return AssertionFailure() << ss.str();
}
@@ -1877,7 +1346,7 @@ class PredicateFormatterFromMatcher {
template <typename M>
inline PredicateFormatterFromMatcher<M>
MakePredicateFormatterFromMatcher(M matcher) {
- return PredicateFormatterFromMatcher<M>(internal::move(matcher));
+ return PredicateFormatterFromMatcher<M>(std::move(matcher));
}
// Implements the polymorphic floating point equality matcher, which matches
@@ -1918,8 +1387,8 @@ class FloatingEqMatcher {
nan_eq_nan_(nan_eq_nan),
max_abs_error_(max_abs_error) {}
- virtual bool MatchAndExplain(T value,
- MatchResultListener* listener) const {
+ bool MatchAndExplain(T value,
+ MatchResultListener* listener) const override {
const FloatingPoint<FloatType> actual(value), expected(expected_);
// Compares NaNs first, if nan_eq_nan_ is true.
@@ -1953,7 +1422,7 @@ class FloatingEqMatcher {
}
}
- virtual void DescribeTo(::std::ostream* os) const {
+ void DescribeTo(::std::ostream* os) const override {
// os->precision() returns the previously set precision, which we
// store to restore the ostream to its original configuration
// after outputting.
@@ -1974,7 +1443,7 @@ class FloatingEqMatcher {
os->precision(old_precision);
}
- virtual void DescribeNegationTo(::std::ostream* os) const {
+ void DescribeNegationTo(::std::ostream* os) const override {
// As before, get original precision.
const ::std::streamsize old_precision = os->precision(
::std::numeric_limits<FloatType>::digits10 + 2);
@@ -2037,6 +1506,82 @@ class FloatingEqMatcher {
GTEST_DISALLOW_ASSIGN_(FloatingEqMatcher);
};
+// A 2-tuple ("binary") wrapper around FloatingEqMatcher:
+// FloatingEq2Matcher() matches (x, y) by matching FloatingEqMatcher(x, false)
+// against y, and FloatingEq2Matcher(e) matches FloatingEqMatcher(x, false, e)
+// against y. The former implements "Eq", the latter "Near". At present, there
+// is no version that compares NaNs as equal.
+template <typename FloatType>
+class FloatingEq2Matcher {
+ public:
+ FloatingEq2Matcher() { Init(-1, false); }
+
+ explicit FloatingEq2Matcher(bool nan_eq_nan) { Init(-1, nan_eq_nan); }
+
+ explicit FloatingEq2Matcher(FloatType max_abs_error) {
+ Init(max_abs_error, false);
+ }
+
+ FloatingEq2Matcher(FloatType max_abs_error, bool nan_eq_nan) {
+ Init(max_abs_error, nan_eq_nan);
+ }
+
+ template <typename T1, typename T2>
+ operator Matcher<::std::tuple<T1, T2>>() const {
+ return MakeMatcher(
+ new Impl<::std::tuple<T1, T2>>(max_abs_error_, nan_eq_nan_));
+ }
+ template <typename T1, typename T2>
+ operator Matcher<const ::std::tuple<T1, T2>&>() const {
+ return MakeMatcher(
+ new Impl<const ::std::tuple<T1, T2>&>(max_abs_error_, nan_eq_nan_));
+ }
+
+ private:
+ static ::std::ostream& GetDesc(::std::ostream& os) { // NOLINT
+ return os << "an almost-equal pair";
+ }
+
+ template <typename Tuple>
+ class Impl : public MatcherInterface<Tuple> {
+ public:
+ Impl(FloatType max_abs_error, bool nan_eq_nan) :
+ max_abs_error_(max_abs_error),
+ nan_eq_nan_(nan_eq_nan) {}
+
+ bool MatchAndExplain(Tuple args,
+ MatchResultListener* listener) const override {
+ if (max_abs_error_ == -1) {
+ FloatingEqMatcher<FloatType> fm(::std::get<0>(args), nan_eq_nan_);
+ return static_cast<Matcher<FloatType>>(fm).MatchAndExplain(
+ ::std::get<1>(args), listener);
+ } else {
+ FloatingEqMatcher<FloatType> fm(::std::get<0>(args), nan_eq_nan_,
+ max_abs_error_);
+ return static_cast<Matcher<FloatType>>(fm).MatchAndExplain(
+ ::std::get<1>(args), listener);
+ }
+ }
+ void DescribeTo(::std::ostream* os) const override {
+ *os << "are " << GetDesc;
+ }
+ void DescribeNegationTo(::std::ostream* os) const override {
+ *os << "aren't " << GetDesc;
+ }
+
+ private:
+ FloatType max_abs_error_;
+ const bool nan_eq_nan_;
+ };
+
+ void Init(FloatType max_abs_error_val, bool nan_eq_nan_val) {
+ max_abs_error_ = max_abs_error_val;
+ nan_eq_nan_ = nan_eq_nan_val;
+ }
+ FloatType max_abs_error_;
+ bool nan_eq_nan_;
+};
+
// Implements the Pointee(m) matcher for matching a pointer whose
// pointee matches matcher m. The pointer can be either raw or smart.
template <typename InnerMatcher>
@@ -2054,7 +1599,7 @@ class PointeeMatcher {
// enough for implementing the DescribeTo() method of Pointee().
template <typename Pointer>
operator Matcher<Pointer>() const {
- return MakeMatcher(new Impl<Pointer>(matcher_));
+ return Matcher<Pointer>(new Impl<const Pointer&>(matcher_));
}
private:
@@ -2062,26 +1607,25 @@ class PointeeMatcher {
template <typename Pointer>
class Impl : public MatcherInterface<Pointer> {
public:
- typedef typename PointeeOf<GTEST_REMOVE_CONST_( // NOLINT
- GTEST_REMOVE_REFERENCE_(Pointer))>::type Pointee;
+ typedef typename PointeeOf<typename std::remove_const<
+ typename std::remove_reference<Pointer>::type>::type>::type Pointee;
explicit Impl(const InnerMatcher& matcher)
: matcher_(MatcherCast<const Pointee&>(matcher)) {}
- virtual void DescribeTo(::std::ostream* os) const {
+ void DescribeTo(::std::ostream* os) const override {
*os << "points to a value that ";
matcher_.DescribeTo(os);
}
- virtual void DescribeNegationTo(::std::ostream* os) const {
+ void DescribeNegationTo(::std::ostream* os) const override {
*os << "does not point to a value that ";
matcher_.DescribeTo(os);
}
- virtual bool MatchAndExplain(Pointer pointer,
- MatchResultListener* listener) const {
- if (GetRawPointer(pointer) == NULL)
- return false;
+ bool MatchAndExplain(Pointer pointer,
+ MatchResultListener* listener) const override {
+ if (GetRawPointer(pointer) == nullptr) return false;
*listener << "which points to ";
return MatchPrintAndExplain(*pointer, matcher_, listener);
@@ -2098,6 +1642,7 @@ class PointeeMatcher {
GTEST_DISALLOW_ASSIGN_(PointeeMatcher);
};
+#if GTEST_HAS_RTTI
// Implements the WhenDynamicCastTo<T>(m) matcher that matches a pointer or
// reference that matches inner_matcher when dynamic_cast<T> is applied.
// The result of dynamic_cast<To> is forwarded to the inner matcher.
@@ -2123,12 +1668,8 @@ class WhenDynamicCastToMatcherBase {
protected:
const Matcher<To> matcher_;
- static string GetToName() {
-#if GTEST_HAS_RTTI
+ static std::string GetToName() {
return GetTypeName<To>();
-#else // GTEST_HAS_RTTI
- return "the target type";
-#endif // GTEST_HAS_RTTI
}
private:
@@ -2149,7 +1690,6 @@ class WhenDynamicCastToMatcher : public WhenDynamicCastToMatcherBase<To> {
template <typename From>
bool MatchAndExplain(From from, MatchResultListener* listener) const {
- // TODO(sbenza): Add more detail on failures. ie did the dyn_cast fail?
To to = dynamic_cast<To>(from);
return MatchPrintAndExplain(to, this->matcher_, listener);
}
@@ -2167,13 +1707,14 @@ class WhenDynamicCastToMatcher<To&> : public WhenDynamicCastToMatcherBase<To&> {
bool MatchAndExplain(From& from, MatchResultListener* listener) const {
// We don't want an std::bad_cast here, so do the cast with pointers.
To* to = dynamic_cast<To*>(&from);
- if (to == NULL) {
+ if (to == nullptr) {
*listener << "which cannot be dynamic_cast to " << this->GetToName();
return false;
}
return MatchPrintAndExplain(*to, this->matcher_, listener);
}
};
+#endif // GTEST_HAS_RTTI
// Implements the Field() matcher for matching a field (i.e. member
// variable) of an object.
@@ -2182,137 +1723,144 @@ class FieldMatcher {
public:
FieldMatcher(FieldType Class::*field,
const Matcher<const FieldType&>& matcher)
- : field_(field), matcher_(matcher) {}
+ : field_(field), matcher_(matcher), whose_field_("whose given field ") {}
+
+ FieldMatcher(const std::string& field_name, FieldType Class::*field,
+ const Matcher<const FieldType&>& matcher)
+ : field_(field),
+ matcher_(matcher),
+ whose_field_("whose field `" + field_name + "` ") {}
void DescribeTo(::std::ostream* os) const {
- *os << "is an object whose given field ";
+ *os << "is an object " << whose_field_;
matcher_.DescribeTo(os);
}
void DescribeNegationTo(::std::ostream* os) const {
- *os << "is an object whose given field ";
+ *os << "is an object " << whose_field_;
matcher_.DescribeNegationTo(os);
}
template <typename T>
bool MatchAndExplain(const T& value, MatchResultListener* listener) const {
+ // FIXME: The dispatch on std::is_pointer was introduced as a workaround for
+ // a compiler bug, and can now be removed.
return MatchAndExplainImpl(
- typename ::testing::internal::
- is_pointer<GTEST_REMOVE_CONST_(T)>::type(),
+ typename std::is_pointer<typename std::remove_const<T>::type>::type(),
value, listener);
}
private:
- // The first argument of MatchAndExplainImpl() is needed to help
- // Symbian's C++ compiler choose which overload to use. Its type is
- // true_type iff the Field() matcher is used to match a pointer.
- bool MatchAndExplainImpl(false_type /* is_not_pointer */, const Class& obj,
+ bool MatchAndExplainImpl(std::false_type /* is_not_pointer */,
+ const Class& obj,
MatchResultListener* listener) const {
- *listener << "whose given field is ";
+ *listener << whose_field_ << "is ";
return MatchPrintAndExplain(obj.*field_, matcher_, listener);
}
- bool MatchAndExplainImpl(true_type /* is_pointer */, const Class* p,
+ bool MatchAndExplainImpl(std::true_type /* is_pointer */, const Class* p,
MatchResultListener* listener) const {
- if (p == NULL)
- return false;
+ if (p == nullptr) return false;
*listener << "which points to an object ";
// Since *p has a field, it must be a class/struct/union type and
// thus cannot be a pointer. Therefore we pass false_type() as
// the first argument.
- return MatchAndExplainImpl(false_type(), *p, listener);
+ return MatchAndExplainImpl(std::false_type(), *p, listener);
}
const FieldType Class::*field_;
const Matcher<const FieldType&> matcher_;
+ // Contains either "whose given field " if the name of the field is unknown
+ // or "whose field `name_of_field` " if the name is known.
+ const std::string whose_field_;
+
GTEST_DISALLOW_ASSIGN_(FieldMatcher);
};
// Implements the Property() matcher for matching a property
// (i.e. return value of a getter method) of an object.
-template <typename Class, typename PropertyType>
+//
+// Property is a const-qualified member function of Class returning
+// PropertyType.
+template <typename Class, typename PropertyType, typename Property>
class PropertyMatcher {
public:
- // The property may have a reference type, so 'const PropertyType&'
- // may cause double references and fail to compile. That's why we
- // need GTEST_REFERENCE_TO_CONST, which works regardless of
- // PropertyType being a reference or not.
- typedef GTEST_REFERENCE_TO_CONST_(PropertyType) RefToConstProperty;
+ typedef const PropertyType& RefToConstProperty;
- PropertyMatcher(PropertyType (Class::*property)() const,
+ PropertyMatcher(Property property, const Matcher<RefToConstProperty>& matcher)
+ : property_(property),
+ matcher_(matcher),
+ whose_property_("whose given property ") {}
+
+ PropertyMatcher(const std::string& property_name, Property property,
const Matcher<RefToConstProperty>& matcher)
- : property_(property), matcher_(matcher) {}
+ : property_(property),
+ matcher_(matcher),
+ whose_property_("whose property `" + property_name + "` ") {}
void DescribeTo(::std::ostream* os) const {
- *os << "is an object whose given property ";
+ *os << "is an object " << whose_property_;
matcher_.DescribeTo(os);
}
void DescribeNegationTo(::std::ostream* os) const {
- *os << "is an object whose given property ";
+ *os << "is an object " << whose_property_;
matcher_.DescribeNegationTo(os);
}
template <typename T>
bool MatchAndExplain(const T&value, MatchResultListener* listener) const {
return MatchAndExplainImpl(
- typename ::testing::internal::
- is_pointer<GTEST_REMOVE_CONST_(T)>::type(),
+ typename std::is_pointer<typename std::remove_const<T>::type>::type(),
value, listener);
}
private:
- // The first argument of MatchAndExplainImpl() is needed to help
- // Symbian's C++ compiler choose which overload to use. Its type is
- // true_type iff the Property() matcher is used to match a pointer.
- bool MatchAndExplainImpl(false_type /* is_not_pointer */, const Class& obj,
+ bool MatchAndExplainImpl(std::false_type /* is_not_pointer */,
+ const Class& obj,
MatchResultListener* listener) const {
- *listener << "whose given property is ";
+ *listener << whose_property_ << "is ";
// Cannot pass the return value (for example, int) to MatchPrintAndExplain,
// which takes a non-const reference as argument.
-#if defined(_PREFAST_ ) && _MSC_VER == 1800
- // Workaround bug in VC++ 2013's /analyze parser.
- // https://connect.microsoft.com/VisualStudio/feedback/details/1106363/internal-compiler-error-with-analyze-due-to-failure-to-infer-move
- posix::Abort(); // To make sure it is never run.
- return false;
-#else
RefToConstProperty result = (obj.*property_)();
return MatchPrintAndExplain(result, matcher_, listener);
-#endif
}
- bool MatchAndExplainImpl(true_type /* is_pointer */, const Class* p,
+ bool MatchAndExplainImpl(std::true_type /* is_pointer */, const Class* p,
MatchResultListener* listener) const {
- if (p == NULL)
- return false;
+ if (p == nullptr) return false;
*listener << "which points to an object ";
// Since *p has a property method, it must be a class/struct/union
// type and thus cannot be a pointer. Therefore we pass
// false_type() as the first argument.
- return MatchAndExplainImpl(false_type(), *p, listener);
+ return MatchAndExplainImpl(std::false_type(), *p, listener);
}
- PropertyType (Class::*property_)() const;
+ Property property_;
const Matcher<RefToConstProperty> matcher_;
+ // Contains either "whose given property " if the name of the property is
+ // unknown or "whose property `name_of_property` " if the name is known.
+ const std::string whose_property_;
+
GTEST_DISALLOW_ASSIGN_(PropertyMatcher);
};
// Type traits specifying various features of different functors for ResultOf.
// The default template specifies features for functor objects.
-// Functor classes have to typedef argument_type and result_type
-// to be compatible with ResultOf.
template <typename Functor>
struct CallableTraits {
- typedef typename Functor::result_type ResultType;
typedef Functor StorageType;
static void CheckIsValid(Functor /* functor */) {}
+
template <typename T>
- static ResultType Invoke(Functor f, T arg) { return f(arg); }
+ static auto Invoke(Functor f, const T& arg) -> decltype(f(arg)) {
+ return f(arg);
+ }
};
// Specialization for function pointers.
@@ -2322,7 +1870,7 @@ struct CallableTraits<ResType(*)(ArgType)> {
typedef ResType(*StorageType)(ArgType);
static void CheckIsValid(ResType(*f)(ArgType)) {
- GTEST_CHECK_(f != NULL)
+ GTEST_CHECK_(f != nullptr)
<< "NULL function pointer is passed into ResultOf().";
}
template <typename T>
@@ -2333,19 +1881,17 @@ struct CallableTraits<ResType(*)(ArgType)> {
// Implements the ResultOf() matcher for matching a return value of a
// unary function of an object.
-template <typename Callable>
+template <typename Callable, typename InnerMatcher>
class ResultOfMatcher {
public:
- typedef typename CallableTraits<Callable>::ResultType ResultType;
-
- ResultOfMatcher(Callable callable, const Matcher<ResultType>& matcher)
- : callable_(callable), matcher_(matcher) {
+ ResultOfMatcher(Callable callable, InnerMatcher matcher)
+ : callable_(std::move(callable)), matcher_(std::move(matcher)) {
CallableTraits<Callable>::CheckIsValid(callable_);
}
template <typename T>
operator Matcher<T>() const {
- return Matcher<T>(new Impl<T>(callable_, matcher_));
+ return Matcher<T>(new Impl<const T&>(callable_, matcher_));
}
private:
@@ -2353,24 +1899,30 @@ class ResultOfMatcher {
template <typename T>
class Impl : public MatcherInterface<T> {
+ using ResultType = decltype(CallableTraits<Callable>::template Invoke<T>(
+ std::declval<CallableStorageType>(), std::declval<T>()));
+
public:
- Impl(CallableStorageType callable, const Matcher<ResultType>& matcher)
- : callable_(callable), matcher_(matcher) {}
+ template <typename M>
+ Impl(const CallableStorageType& callable, const M& matcher)
+ : callable_(callable), matcher_(MatcherCast<ResultType>(matcher)) {}
- virtual void DescribeTo(::std::ostream* os) const {
+ void DescribeTo(::std::ostream* os) const override {
*os << "is mapped by the given callable to a value that ";
matcher_.DescribeTo(os);
}
- virtual void DescribeNegationTo(::std::ostream* os) const {
+ void DescribeNegationTo(::std::ostream* os) const override {
*os << "is mapped by the given callable to a value that ";
matcher_.DescribeNegationTo(os);
}
- virtual bool MatchAndExplain(T obj, MatchResultListener* listener) const {
+ bool MatchAndExplain(T obj, MatchResultListener* listener) const override {
*listener << "which is mapped by the given callable to ";
- // Cannot pass the return value (for example, int) to
- // MatchPrintAndExplain, which takes a non-const reference as argument.
+ // Cannot pass the return value directly to MatchPrintAndExplain, which
+ // takes a non-const reference as argument.
+ // Also, specifying template argument explicitly is needed because T could
+ // be a non-const reference (e.g. Matcher<Uncopyable&>).
ResultType result =
CallableTraits<Callable>::template Invoke<T>(callable_, obj);
return MatchPrintAndExplain(result, matcher_, listener);
@@ -2378,9 +1930,9 @@ class ResultOfMatcher {
private:
// Functors often define operator() as non-const method even though
- // they are actualy stateless. But we need to use them even when
+ // they are actually stateless. But we need to use them even when
// 'this' is a const pointer. It's the user's responsibility not to
- // use stateful callables with ResultOf(), which does't guarantee
+ // use stateful callables with ResultOf(), which doesn't guarantee
// how many times the callable will be invoked.
mutable CallableStorageType callable_;
const Matcher<ResultType> matcher_;
@@ -2389,7 +1941,7 @@ class ResultOfMatcher {
}; // class Impl
const CallableStorageType callable_;
- const Matcher<ResultType> matcher_;
+ const InnerMatcher matcher_;
GTEST_DISALLOW_ASSIGN_(ResultOfMatcher);
};
@@ -2404,29 +1956,27 @@ class SizeIsMatcher {
template <typename Container>
operator Matcher<Container>() const {
- return MakeMatcher(new Impl<Container>(size_matcher_));
+ return Matcher<Container>(new Impl<const Container&>(size_matcher_));
}
template <typename Container>
class Impl : public MatcherInterface<Container> {
public:
- typedef internal::StlContainerView<
- GTEST_REMOVE_REFERENCE_AND_CONST_(Container)> ContainerView;
- typedef typename ContainerView::type::size_type SizeType;
+ using SizeType = decltype(std::declval<Container>().size());
explicit Impl(const SizeMatcher& size_matcher)
: size_matcher_(MatcherCast<SizeType>(size_matcher)) {}
- virtual void DescribeTo(::std::ostream* os) const {
+ void DescribeTo(::std::ostream* os) const override {
*os << "size ";
size_matcher_.DescribeTo(os);
}
- virtual void DescribeNegationTo(::std::ostream* os) const {
+ void DescribeNegationTo(::std::ostream* os) const override {
*os << "size ";
size_matcher_.DescribeNegationTo(os);
}
- virtual bool MatchAndExplain(Container container,
- MatchResultListener* listener) const {
+ bool MatchAndExplain(Container container,
+ MatchResultListener* listener) const override {
SizeType size = container.size();
StringMatchResultListener size_listener;
const bool result = size_matcher_.MatchAndExplain(size, &size_listener);
@@ -2456,7 +2006,7 @@ class BeginEndDistanceIsMatcher {
template <typename Container>
operator Matcher<Container>() const {
- return MakeMatcher(new Impl<Container>(distance_matcher_));
+ return Matcher<Container>(new Impl<const Container&>(distance_matcher_));
}
template <typename Container>
@@ -2470,24 +2020,20 @@ class BeginEndDistanceIsMatcher {
explicit Impl(const DistanceMatcher& distance_matcher)
: distance_matcher_(MatcherCast<DistanceType>(distance_matcher)) {}
- virtual void DescribeTo(::std::ostream* os) const {
+ void DescribeTo(::std::ostream* os) const override {
*os << "distance between begin() and end() ";
distance_matcher_.DescribeTo(os);
}
- virtual void DescribeNegationTo(::std::ostream* os) const {
+ void DescribeNegationTo(::std::ostream* os) const override {
*os << "distance between begin() and end() ";
distance_matcher_.DescribeNegationTo(os);
}
- virtual bool MatchAndExplain(Container container,
- MatchResultListener* listener) const {
-#if GTEST_HAS_STD_BEGIN_AND_END_
+ bool MatchAndExplain(Container container,
+ MatchResultListener* listener) const override {
using std::begin;
using std::end;
DistanceType distance = std::distance(begin(container), end(container));
-#else
- DistanceType distance = std::distance(container.begin(), container.end());
-#endif
StringMatchResultListener distance_listener;
const bool result =
distance_matcher_.MatchAndExplain(distance, &distance_listener);
@@ -2524,15 +2070,15 @@ class ContainerEqMatcher {
typedef typename View::type StlContainer;
typedef typename View::const_reference StlContainerReference;
+ static_assert(!std::is_const<Container>::value,
+ "Container type must not be const");
+ static_assert(!std::is_reference<Container>::value,
+ "Container type must not be a reference");
+
// We make a copy of expected in case the elements in it are modified
// after this matcher is created.
explicit ContainerEqMatcher(const Container& expected)
- : expected_(View::Copy(expected)) {
- // Makes sure the user doesn't instantiate this class template
- // with a const or reference type.
- (void)testing::StaticAssertTypeEq<Container,
- GTEST_REMOVE_REFERENCE_AND_CONST_(Container)>();
- }
+ : expected_(View::Copy(expected)) {}
void DescribeTo(::std::ostream* os) const {
*os << "equals ";
@@ -2546,9 +2092,8 @@ class ContainerEqMatcher {
template <typename LhsContainer>
bool MatchAndExplain(const LhsContainer& lhs,
MatchResultListener* listener) const {
- // GTEST_REMOVE_CONST_() is needed to work around an MSVC 8.0 bug
- // that causes LhsContainer to be a const type sometimes.
- typedef internal::StlContainerView<GTEST_REMOVE_CONST_(LhsContainer)>
+ typedef internal::StlContainerView<
+ typename std::remove_const<LhsContainer>::type>
LhsView;
typedef typename LhsView::type LhsStlContainer;
StlContainerReference lhs_stl_container = LhsView::ConstReference(lhs);
@@ -2556,7 +2101,7 @@ class ContainerEqMatcher {
return true;
::std::ostream* const os = listener->stream();
- if (os != NULL) {
+ if (os != nullptr) {
// Something is different. Check for extra values first.
bool printed_header = false;
for (typename LhsStlContainer::const_iterator it =
@@ -2636,18 +2181,18 @@ class WhenSortedByMatcher {
Impl(const Comparator& comparator, const ContainerMatcher& matcher)
: comparator_(comparator), matcher_(matcher) {}
- virtual void DescribeTo(::std::ostream* os) const {
+ void DescribeTo(::std::ostream* os) const override {
*os << "(when sorted) ";
matcher_.DescribeTo(os);
}
- virtual void DescribeNegationTo(::std::ostream* os) const {
+ void DescribeNegationTo(::std::ostream* os) const override {
*os << "(when sorted) ";
matcher_.DescribeNegationTo(os);
}
- virtual bool MatchAndExplain(LhsContainer lhs,
- MatchResultListener* listener) const {
+ bool MatchAndExplain(LhsContainer lhs,
+ MatchResultListener* listener) const override {
LhsStlContainerReference lhs_stl_container = LhsView::ConstReference(lhs);
::std::vector<LhsValue> sorted_container(lhs_stl_container.begin(),
lhs_stl_container.end());
@@ -2686,29 +2231,38 @@ class WhenSortedByMatcher {
};
// Implements Pointwise(tuple_matcher, rhs_container). tuple_matcher
-// must be able to be safely cast to Matcher<tuple<const T1&, const
+// must be able to be safely cast to Matcher<std::tuple<const T1&, const
// T2&> >, where T1 and T2 are the types of elements in the LHS
// container and the RHS container respectively.
template <typename TupleMatcher, typename RhsContainer>
class PointwiseMatcher {
+ GTEST_COMPILE_ASSERT_(
+ !IsHashTable<GTEST_REMOVE_REFERENCE_AND_CONST_(RhsContainer)>::value,
+ use_UnorderedPointwise_with_hash_tables);
+
public:
typedef internal::StlContainerView<RhsContainer> RhsView;
typedef typename RhsView::type RhsStlContainer;
typedef typename RhsStlContainer::value_type RhsValue;
+ static_assert(!std::is_const<RhsContainer>::value,
+ "RhsContainer type must not be const");
+ static_assert(!std::is_reference<RhsContainer>::value,
+ "RhsContainer type must not be a reference");
+
// Like ContainerEq, we make a copy of rhs in case the elements in
// it are modified after this matcher is created.
PointwiseMatcher(const TupleMatcher& tuple_matcher, const RhsContainer& rhs)
- : tuple_matcher_(tuple_matcher), rhs_(RhsView::Copy(rhs)) {
- // Makes sure the user doesn't instantiate this class template
- // with a const or reference type.
- (void)testing::StaticAssertTypeEq<RhsContainer,
- GTEST_REMOVE_REFERENCE_AND_CONST_(RhsContainer)>();
- }
+ : tuple_matcher_(tuple_matcher), rhs_(RhsView::Copy(rhs)) {}
template <typename LhsContainer>
operator Matcher<LhsContainer>() const {
- return MakeMatcher(new Impl<LhsContainer>(tuple_matcher_, rhs_));
+ GTEST_COMPILE_ASSERT_(
+ !IsHashTable<GTEST_REMOVE_REFERENCE_AND_CONST_(LhsContainer)>::value,
+ use_UnorderedPointwise_with_hash_tables);
+
+ return Matcher<LhsContainer>(
+ new Impl<const LhsContainer&>(tuple_matcher_, rhs_));
}
template <typename LhsContainer>
@@ -2723,21 +2277,21 @@ class PointwiseMatcher {
// reference, as they may be expensive to copy. We must use tuple
// instead of pair here, as a pair cannot hold references (C++ 98,
// 20.2.2 [lib.pairs]).
- typedef ::testing::tuple<const LhsValue&, const RhsValue&> InnerMatcherArg;
+ typedef ::std::tuple<const LhsValue&, const RhsValue&> InnerMatcherArg;
Impl(const TupleMatcher& tuple_matcher, const RhsStlContainer& rhs)
// mono_tuple_matcher_ holds a monomorphic version of the tuple matcher.
: mono_tuple_matcher_(SafeMatcherCast<InnerMatcherArg>(tuple_matcher)),
rhs_(rhs) {}
- virtual void DescribeTo(::std::ostream* os) const {
+ void DescribeTo(::std::ostream* os) const override {
*os << "contains " << rhs_.size()
<< " values, where each value and its corresponding value in ";
UniversalPrinter<RhsStlContainer>::Print(rhs_, os);
*os << " ";
mono_tuple_matcher_.DescribeTo(os);
}
- virtual void DescribeNegationTo(::std::ostream* os) const {
+ void DescribeNegationTo(::std::ostream* os) const override {
*os << "doesn't contain exactly " << rhs_.size()
<< " values, or contains a value x at some index i"
<< " where x and the i-th value of ";
@@ -2746,8 +2300,8 @@ class PointwiseMatcher {
mono_tuple_matcher_.DescribeNegationTo(os);
}
- virtual bool MatchAndExplain(LhsContainer lhs,
- MatchResultListener* listener) const {
+ bool MatchAndExplain(LhsContainer lhs,
+ MatchResultListener* listener) const override {
LhsStlContainerReference lhs_stl_container = LhsView::ConstReference(lhs);
const size_t actual_size = lhs_stl_container.size();
if (actual_size != rhs_.size()) {
@@ -2758,12 +2312,15 @@ class PointwiseMatcher {
typename LhsStlContainer::const_iterator left = lhs_stl_container.begin();
typename RhsStlContainer::const_iterator right = rhs_.begin();
for (size_t i = 0; i != actual_size; ++i, ++left, ++right) {
- const InnerMatcherArg value_pair(*left, *right);
-
if (listener->IsInterested()) {
StringMatchResultListener inner_listener;
+ // Create InnerMatcherArg as a temporarily object to avoid it outlives
+ // *left and *right. Dereference or the conversion to `const T&` may
+ // return temp objects, e.g for vector<bool>.
if (!mono_tuple_matcher_.MatchAndExplain(
- value_pair, &inner_listener)) {
+ InnerMatcherArg(ImplicitCast_<const LhsValue&>(*left),
+ ImplicitCast_<const RhsValue&>(*right)),
+ &inner_listener)) {
*listener << "where the value pair (";
UniversalPrint(*left, listener->stream());
*listener << ", ";
@@ -2773,7 +2330,9 @@ class PointwiseMatcher {
return false;
}
} else {
- if (!mono_tuple_matcher_.Matches(value_pair))
+ if (!mono_tuple_matcher_.Matches(
+ InnerMatcherArg(ImplicitCast_<const LhsValue&>(*left),
+ ImplicitCast_<const RhsValue&>(*right))))
return false;
}
}
@@ -2849,18 +2408,18 @@ class ContainsMatcherImpl : public QuantifierMatcherImpl<Container> {
: QuantifierMatcherImpl<Container>(inner_matcher) {}
// Describes what this matcher does.
- virtual void DescribeTo(::std::ostream* os) const {
+ void DescribeTo(::std::ostream* os) const override {
*os << "contains at least one element that ";
this->inner_matcher_.DescribeTo(os);
}
- virtual void DescribeNegationTo(::std::ostream* os) const {
+ void DescribeNegationTo(::std::ostream* os) const override {
*os << "doesn't contain any element that ";
this->inner_matcher_.DescribeTo(os);
}
- virtual bool MatchAndExplain(Container container,
- MatchResultListener* listener) const {
+ bool MatchAndExplain(Container container,
+ MatchResultListener* listener) const override {
return this->MatchAndExplainImpl(false, container, listener);
}
@@ -2878,18 +2437,18 @@ class EachMatcherImpl : public QuantifierMatcherImpl<Container> {
: QuantifierMatcherImpl<Container>(inner_matcher) {}
// Describes what this matcher does.
- virtual void DescribeTo(::std::ostream* os) const {
+ void DescribeTo(::std::ostream* os) const override {
*os << "only contains elements that ";
this->inner_matcher_.DescribeTo(os);
}
- virtual void DescribeNegationTo(::std::ostream* os) const {
+ void DescribeNegationTo(::std::ostream* os) const override {
*os << "contains some element that ";
this->inner_matcher_.DescribeNegationTo(os);
}
- virtual bool MatchAndExplain(Container container,
- MatchResultListener* listener) const {
+ bool MatchAndExplain(Container container,
+ MatchResultListener* listener) const override {
return this->MatchAndExplainImpl(true, container, listener);
}
@@ -2905,7 +2464,8 @@ class ContainsMatcher {
template <typename Container>
operator Matcher<Container>() const {
- return MakeMatcher(new ContainsMatcherImpl<Container>(inner_matcher_));
+ return Matcher<Container>(
+ new ContainsMatcherImpl<const Container&>(inner_matcher_));
}
private:
@@ -2922,7 +2482,8 @@ class EachMatcher {
template <typename Container>
operator Matcher<Container>() const {
- return MakeMatcher(new EachMatcherImpl<Container>(inner_matcher_));
+ return Matcher<Container>(
+ new EachMatcherImpl<const Container&>(inner_matcher_));
}
private:
@@ -2931,6 +2492,30 @@ class EachMatcher {
GTEST_DISALLOW_ASSIGN_(EachMatcher);
};
+struct Rank1 {};
+struct Rank0 : Rank1 {};
+
+namespace pair_getters {
+using std::get;
+template <typename T>
+auto First(T& x, Rank1) -> decltype(get<0>(x)) { // NOLINT
+ return get<0>(x);
+}
+template <typename T>
+auto First(T& x, Rank0) -> decltype((x.first)) { // NOLINT
+ return x.first;
+}
+
+template <typename T>
+auto Second(T& x, Rank1) -> decltype(get<1>(x)) { // NOLINT
+ return get<1>(x);
+}
+template <typename T>
+auto Second(T& x, Rank0) -> decltype((x.second)) { // NOLINT
+ return x.second;
+}
+} // namespace pair_getters
+
// Implements Key(inner_matcher) for the given argument pair type.
// Key(inner_matcher) matches an std::pair whose 'first' field matches
// inner_matcher. For example, Contains(Key(Ge(5))) can be used to match an
@@ -2947,13 +2532,14 @@ class KeyMatcherImpl : public MatcherInterface<PairType> {
testing::SafeMatcherCast<const KeyType&>(inner_matcher)) {
}
- // Returns true iff 'key_value.first' (the key) matches the inner matcher.
- virtual bool MatchAndExplain(PairType key_value,
- MatchResultListener* listener) const {
+ // Returns true if and only if 'key_value.first' (the key) matches the inner
+ // matcher.
+ bool MatchAndExplain(PairType key_value,
+ MatchResultListener* listener) const override {
StringMatchResultListener inner_listener;
- const bool match = inner_matcher_.MatchAndExplain(key_value.first,
- &inner_listener);
- const internal::string explanation = inner_listener.str();
+ const bool match = inner_matcher_.MatchAndExplain(
+ pair_getters::First(key_value, Rank0()), &inner_listener);
+ const std::string explanation = inner_listener.str();
if (explanation != "") {
*listener << "whose first field is a value " << explanation;
}
@@ -2961,13 +2547,13 @@ class KeyMatcherImpl : public MatcherInterface<PairType> {
}
// Describes what this matcher does.
- virtual void DescribeTo(::std::ostream* os) const {
+ void DescribeTo(::std::ostream* os) const override {
*os << "has a key that ";
inner_matcher_.DescribeTo(os);
}
// Describes what the negation of this matcher does.
- virtual void DescribeNegationTo(::std::ostream* os) const {
+ void DescribeNegationTo(::std::ostream* os) const override {
*os << "doesn't have a key that ";
inner_matcher_.DescribeTo(os);
}
@@ -2986,7 +2572,8 @@ class KeyMatcher {
template <typename PairType>
operator Matcher<PairType>() const {
- return MakeMatcher(new KeyMatcherImpl<PairType>(matcher_for_key_));
+ return Matcher<PairType>(
+ new KeyMatcherImpl<const PairType&>(matcher_for_key_));
}
private:
@@ -3013,7 +2600,7 @@ class PairMatcherImpl : public MatcherInterface<PairType> {
}
// Describes what this matcher does.
- virtual void DescribeTo(::std::ostream* os) const {
+ void DescribeTo(::std::ostream* os) const override {
*os << "has a first field that ";
first_matcher_.DescribeTo(os);
*os << ", and has a second field that ";
@@ -3021,32 +2608,32 @@ class PairMatcherImpl : public MatcherInterface<PairType> {
}
// Describes what the negation of this matcher does.
- virtual void DescribeNegationTo(::std::ostream* os) const {
+ void DescribeNegationTo(::std::ostream* os) const override {
*os << "has a first field that ";
first_matcher_.DescribeNegationTo(os);
*os << ", or has a second field that ";
second_matcher_.DescribeNegationTo(os);
}
- // Returns true iff 'a_pair.first' matches first_matcher and 'a_pair.second'
- // matches second_matcher.
- virtual bool MatchAndExplain(PairType a_pair,
- MatchResultListener* listener) const {
+ // Returns true if and only if 'a_pair.first' matches first_matcher and
+ // 'a_pair.second' matches second_matcher.
+ bool MatchAndExplain(PairType a_pair,
+ MatchResultListener* listener) const override {
if (!listener->IsInterested()) {
// If the listener is not interested, we don't need to construct the
// explanation.
- return first_matcher_.Matches(a_pair.first) &&
- second_matcher_.Matches(a_pair.second);
+ return first_matcher_.Matches(pair_getters::First(a_pair, Rank0())) &&
+ second_matcher_.Matches(pair_getters::Second(a_pair, Rank0()));
}
StringMatchResultListener first_inner_listener;
- if (!first_matcher_.MatchAndExplain(a_pair.first,
+ if (!first_matcher_.MatchAndExplain(pair_getters::First(a_pair, Rank0()),
&first_inner_listener)) {
*listener << "whose first field does not match";
PrintIfNotEmpty(first_inner_listener.str(), listener->stream());
return false;
}
StringMatchResultListener second_inner_listener;
- if (!second_matcher_.MatchAndExplain(a_pair.second,
+ if (!second_matcher_.MatchAndExplain(pair_getters::Second(a_pair, Rank0()),
&second_inner_listener)) {
*listener << "whose second field does not match";
PrintIfNotEmpty(second_inner_listener.str(), listener->stream());
@@ -3058,8 +2645,8 @@ class PairMatcherImpl : public MatcherInterface<PairType> {
}
private:
- void ExplainSuccess(const internal::string& first_explanation,
- const internal::string& second_explanation,
+ void ExplainSuccess(const std::string& first_explanation,
+ const std::string& second_explanation,
MatchResultListener* listener) const {
*listener << "whose both fields match";
if (first_explanation != "") {
@@ -3091,9 +2678,8 @@ class PairMatcher {
template <typename PairType>
operator Matcher<PairType> () const {
- return MakeMatcher(
- new PairMatcherImpl<PairType>(
- first_matcher_, second_matcher_));
+ return Matcher<PairType>(
+ new PairMatcherImpl<const PairType&>(first_matcher_, second_matcher_));
}
private:
@@ -3123,7 +2709,7 @@ class ElementsAreMatcherImpl : public MatcherInterface<Container> {
}
// Describes what this matcher does.
- virtual void DescribeTo(::std::ostream* os) const {
+ void DescribeTo(::std::ostream* os) const override {
if (count() == 0) {
*os << "is empty";
} else if (count() == 1) {
@@ -3142,7 +2728,7 @@ class ElementsAreMatcherImpl : public MatcherInterface<Container> {
}
// Describes what the negation of this matcher does.
- virtual void DescribeNegationTo(::std::ostream* os) const {
+ void DescribeNegationTo(::std::ostream* os) const override {
if (count() == 0) {
*os << "isn't empty";
return;
@@ -3158,15 +2744,15 @@ class ElementsAreMatcherImpl : public MatcherInterface<Container> {
}
}
- virtual bool MatchAndExplain(Container container,
- MatchResultListener* listener) const {
+ bool MatchAndExplain(Container container,
+ MatchResultListener* listener) const override {
// To work with stream-like "containers", we must only walk
// through the elements in one pass.
const bool listener_interested = listener->IsInterested();
// explanations[i] is the explanation of the element at index i.
- ::std::vector<internal::string> explanations(count());
+ ::std::vector<std::string> explanations(count());
StlContainerReference stl_container = View::ConstReference(container);
typename StlContainer::const_iterator it = stl_container.begin();
size_t exam_pos = 0;
@@ -3225,7 +2811,7 @@ class ElementsAreMatcherImpl : public MatcherInterface<Container> {
if (listener_interested) {
bool reason_printed = false;
for (size_t i = 0; i != count(); ++i) {
- const internal::string& s = explanations[i];
+ const std::string& s = explanations[i];
if (!s.empty()) {
if (reason_printed) {
*listener << ",\nand ";
@@ -3278,7 +2864,7 @@ class GTEST_API_ MatchMatrix {
void Randomize();
- string DebugString() const;
+ std::string DebugString() const;
private:
size_t SpaceIndex(size_t ilhs, size_t irhs) const {
@@ -3302,14 +2888,23 @@ typedef ::std::vector<ElementMatcherPair> ElementMatcherPairs;
GTEST_API_ ElementMatcherPairs
FindMaxBipartiteMatching(const MatchMatrix& g);
-GTEST_API_ bool FindPairing(const MatchMatrix& matrix,
- MatchResultListener* listener);
+struct UnorderedMatcherRequire {
+ enum Flags {
+ Superset = 1 << 0,
+ Subset = 1 << 1,
+ ExactMatch = Superset | Subset,
+ };
+};
// Untyped base class for implementing UnorderedElementsAre. By
// putting logic that's not specific to the element type here, we
// reduce binary bloat and increase compilation speed.
class GTEST_API_ UnorderedElementsAreMatcherImplBase {
protected:
+ explicit UnorderedElementsAreMatcherImplBase(
+ UnorderedMatcherRequire::Flags matcher_flags)
+ : match_flags_(matcher_flags) {}
+
// A vector of matcher describers, one for each element matcher.
// Does not own the describers (and thus can be used only when the
// element matchers are alive).
@@ -3321,10 +2916,12 @@ class GTEST_API_ UnorderedElementsAreMatcherImplBase {
// Describes the negation of this UnorderedElementsAre matcher.
void DescribeNegationToImpl(::std::ostream* os) const;
- bool VerifyAllElementsAndMatchersAreMatched(
- const ::std::vector<string>& element_printouts,
- const MatchMatrix& matrix,
- MatchResultListener* listener) const;
+ bool VerifyMatchMatrix(const ::std::vector<std::string>& element_printouts,
+ const MatchMatrix& matrix,
+ MatchResultListener* listener) const;
+
+ bool FindPairing(const MatchMatrix& matrix,
+ MatchResultListener* listener) const;
MatcherDescriberVec& matcher_describers() {
return matcher_describers_;
@@ -3334,13 +2931,17 @@ class GTEST_API_ UnorderedElementsAreMatcherImplBase {
return Message() << n << " element" << (n == 1 ? "" : "s");
}
+ UnorderedMatcherRequire::Flags match_flags() const { return match_flags_; }
+
private:
+ UnorderedMatcherRequire::Flags match_flags_;
MatcherDescriberVec matcher_describers_;
GTEST_DISALLOW_ASSIGN_(UnorderedElementsAreMatcherImplBase);
};
-// Implements unordered ElementsAre and unordered ElementsAreArray.
+// Implements UnorderedElementsAre, UnorderedElementsAreArray, IsSubsetOf, and
+// IsSupersetOf.
template <typename Container>
class UnorderedElementsAreMatcherImpl
: public MatcherInterface<Container>,
@@ -3353,10 +2954,10 @@ class UnorderedElementsAreMatcherImpl
typedef typename StlContainer::const_iterator StlContainerConstIterator;
typedef typename StlContainer::value_type Element;
- // Constructs the matcher from a sequence of element values or
- // element matchers.
template <typename InputIter>
- UnorderedElementsAreMatcherImpl(InputIter first, InputIter last) {
+ UnorderedElementsAreMatcherImpl(UnorderedMatcherRequire::Flags matcher_flags,
+ InputIter first, InputIter last)
+ : UnorderedElementsAreMatcherImplBase(matcher_flags) {
for (; first != last; ++first) {
matchers_.push_back(MatcherCast<const Element&>(*first));
matcher_describers().push_back(matchers_.back().GetDescriber());
@@ -3364,50 +2965,48 @@ class UnorderedElementsAreMatcherImpl
}
// Describes what this matcher does.
- virtual void DescribeTo(::std::ostream* os) const {
+ void DescribeTo(::std::ostream* os) const override {
return UnorderedElementsAreMatcherImplBase::DescribeToImpl(os);
}
// Describes what the negation of this matcher does.
- virtual void DescribeNegationTo(::std::ostream* os) const {
+ void DescribeNegationTo(::std::ostream* os) const override {
return UnorderedElementsAreMatcherImplBase::DescribeNegationToImpl(os);
}
- virtual bool MatchAndExplain(Container container,
- MatchResultListener* listener) const {
+ bool MatchAndExplain(Container container,
+ MatchResultListener* listener) const override {
StlContainerReference stl_container = View::ConstReference(container);
- ::std::vector<string> element_printouts;
- MatchMatrix matrix = AnalyzeElements(stl_container.begin(),
- stl_container.end(),
- &element_printouts,
- listener);
-
- const size_t actual_count = matrix.LhsSize();
- if (actual_count == 0 && matchers_.empty()) {
+ ::std::vector<std::string> element_printouts;
+ MatchMatrix matrix =
+ AnalyzeElements(stl_container.begin(), stl_container.end(),
+ &element_printouts, listener);
+
+ if (matrix.LhsSize() == 0 && matrix.RhsSize() == 0) {
return true;
}
- if (actual_count != matchers_.size()) {
- // The element count doesn't match. If the container is empty,
- // there's no need to explain anything as Google Mock already
- // prints the empty container. Otherwise we just need to show
- // how many elements there actually are.
- if (actual_count != 0 && listener->IsInterested()) {
- *listener << "which has " << Elements(actual_count);
+
+ if (match_flags() == UnorderedMatcherRequire::ExactMatch) {
+ if (matrix.LhsSize() != matrix.RhsSize()) {
+ // The element count doesn't match. If the container is empty,
+ // there's no need to explain anything as Google Mock already
+ // prints the empty container. Otherwise we just need to show
+ // how many elements there actually are.
+ if (matrix.LhsSize() != 0 && listener->IsInterested()) {
+ *listener << "which has " << Elements(matrix.LhsSize());
+ }
+ return false;
}
- return false;
}
- return VerifyAllElementsAndMatchersAreMatched(element_printouts,
- matrix, listener) &&
+ return VerifyMatchMatrix(element_printouts, matrix, listener) &&
FindPairing(matrix, listener);
}
private:
- typedef ::std::vector<Matcher<const Element&> > MatcherVec;
-
template <typename ElementIter>
MatchMatrix AnalyzeElements(ElementIter elem_first, ElementIter elem_last,
- ::std::vector<string>* element_printouts,
+ ::std::vector<std::string>* element_printouts,
MatchResultListener* listener) const {
element_printouts->clear();
::std::vector<char> did_match;
@@ -3431,7 +3030,7 @@ class UnorderedElementsAreMatcherImpl
return matrix;
}
- MatcherVec matchers_;
+ ::std::vector<Matcher<const Element&> > matchers_;
GTEST_DISALLOW_ASSIGN_(UnorderedElementsAreMatcherImpl);
};
@@ -3460,11 +3059,13 @@ class UnorderedElementsAreMatcher {
typedef typename View::value_type Element;
typedef ::std::vector<Matcher<const Element&> > MatcherVec;
MatcherVec matchers;
- matchers.reserve(::testing::tuple_size<MatcherTuple>::value);
+ matchers.reserve(::std::tuple_size<MatcherTuple>::value);
TransformTupleValues(CastAndAppendTransform<const Element&>(), matchers_,
::std::back_inserter(matchers));
- return MakeMatcher(new UnorderedElementsAreMatcherImpl<Container>(
- matchers.begin(), matchers.end()));
+ return Matcher<Container>(
+ new UnorderedElementsAreMatcherImpl<const Container&>(
+ UnorderedMatcherRequire::ExactMatch, matchers.begin(),
+ matchers.end()));
}
private:
@@ -3480,16 +3081,21 @@ class ElementsAreMatcher {
template <typename Container>
operator Matcher<Container>() const {
+ GTEST_COMPILE_ASSERT_(
+ !IsHashTable<GTEST_REMOVE_REFERENCE_AND_CONST_(Container)>::value ||
+ ::std::tuple_size<MatcherTuple>::value < 2,
+ use_UnorderedElementsAre_with_hash_tables);
+
typedef GTEST_REMOVE_REFERENCE_AND_CONST_(Container) RawContainer;
typedef typename internal::StlContainerView<RawContainer>::type View;
typedef typename View::value_type Element;
typedef ::std::vector<Matcher<const Element&> > MatcherVec;
MatcherVec matchers;
- matchers.reserve(::testing::tuple_size<MatcherTuple>::value);
+ matchers.reserve(::std::tuple_size<MatcherTuple>::value);
TransformTupleValues(CastAndAppendTransform<const Element&>(), matchers_,
::std::back_inserter(matchers));
- return MakeMatcher(new ElementsAreMatcherImpl<Container>(
- matchers.begin(), matchers.end()));
+ return Matcher<Container>(new ElementsAreMatcherImpl<const Container&>(
+ matchers.begin(), matchers.end()));
}
private:
@@ -3497,24 +3103,24 @@ class ElementsAreMatcher {
GTEST_DISALLOW_ASSIGN_(ElementsAreMatcher);
};
-// Implements UnorderedElementsAreArray().
+// Implements UnorderedElementsAreArray(), IsSubsetOf(), and IsSupersetOf().
template <typename T>
class UnorderedElementsAreArrayMatcher {
public:
- UnorderedElementsAreArrayMatcher() {}
-
template <typename Iter>
- UnorderedElementsAreArrayMatcher(Iter first, Iter last)
- : matchers_(first, last) {}
+ UnorderedElementsAreArrayMatcher(UnorderedMatcherRequire::Flags match_flags,
+ Iter first, Iter last)
+ : match_flags_(match_flags), matchers_(first, last) {}
template <typename Container>
operator Matcher<Container>() const {
- return MakeMatcher(
- new UnorderedElementsAreMatcherImpl<Container>(matchers_.begin(),
- matchers_.end()));
+ return Matcher<Container>(
+ new UnorderedElementsAreMatcherImpl<const Container&>(
+ match_flags_, matchers_.begin(), matchers_.end()));
}
private:
+ UnorderedMatcherRequire::Flags match_flags_;
::std::vector<T> matchers_;
GTEST_DISALLOW_ASSIGN_(UnorderedElementsAreArrayMatcher);
@@ -3529,7 +3135,11 @@ class ElementsAreArrayMatcher {
template <typename Container>
operator Matcher<Container>() const {
- return MakeMatcher(new ElementsAreMatcherImpl<Container>(
+ GTEST_COMPILE_ASSERT_(
+ !IsHashTable<GTEST_REMOVE_REFERENCE_AND_CONST_(Container)>::value,
+ use_UnorderedElementsAreArray_with_hash_tables);
+
+ return Matcher<Container>(new ElementsAreMatcherImpl<const Container&>(
matchers_.begin(), matchers_.end()));
}
@@ -3541,8 +3151,8 @@ class ElementsAreArrayMatcher {
// Given a 2-tuple matcher tm of type Tuple2Matcher and a value second
// of type Second, BoundSecondMatcher<Tuple2Matcher, Second>(tm,
-// second) is a polymorphic matcher that matches a value x iff tm
-// matches tuple (x, second). Useful for implementing
+// second) is a polymorphic matcher that matches a value x if and only if
+// tm matches tuple (x, second). Useful for implementing
// UnorderedPointwise() in terms of UnorderedElementsAreArray().
//
// BoundSecondMatcher is copyable and assignable, as we need to put
@@ -3575,20 +3185,20 @@ class BoundSecondMatcher {
template <typename T>
class Impl : public MatcherInterface<T> {
public:
- typedef ::testing::tuple<T, Second> ArgTuple;
+ typedef ::std::tuple<T, Second> ArgTuple;
Impl(const Tuple2Matcher& tm, const Second& second)
: mono_tuple2_matcher_(SafeMatcherCast<const ArgTuple&>(tm)),
second_value_(second) {}
- virtual void DescribeTo(::std::ostream* os) const {
+ void DescribeTo(::std::ostream* os) const override {
*os << "and ";
UniversalPrint(second_value_, os);
*os << " ";
mono_tuple2_matcher_.DescribeTo(os);
}
- virtual bool MatchAndExplain(T x, MatchResultListener* listener) const {
+ bool MatchAndExplain(T x, MatchResultListener* listener) const override {
return mono_tuple2_matcher_.MatchAndExplain(ArgTuple(x, second_value_),
listener);
}
@@ -3606,8 +3216,8 @@ class BoundSecondMatcher {
// Given a 2-tuple matcher tm and a value second,
// MatcherBindSecond(tm, second) returns a matcher that matches a
-// value x iff tm matches tuple (x, second). Useful for implementing
-// UnorderedPointwise() in terms of UnorderedElementsAreArray().
+// value x if and only if tm matches tuple (x, second). Useful for
+// implementing UnorderedPointwise() in terms of UnorderedElementsAreArray().
template <typename Tuple2Matcher, typename Second>
BoundSecondMatcher<Tuple2Matcher, Second> MatcherBindSecond(
const Tuple2Matcher& tm, const Second& second) {
@@ -3619,13 +3229,264 @@ BoundSecondMatcher<Tuple2Matcher, Second> MatcherBindSecond(
// 'negation' is false; otherwise returns the description of the
// negation of the matcher. 'param_values' contains a list of strings
// that are the print-out of the matcher's parameters.
-GTEST_API_ string FormatMatcherDescription(bool negation,
- const char* matcher_name,
- const Strings& param_values);
+GTEST_API_ std::string FormatMatcherDescription(bool negation,
+ const char* matcher_name,
+ const Strings& param_values);
+
+// Implements a matcher that checks the value of a optional<> type variable.
+template <typename ValueMatcher>
+class OptionalMatcher {
+ public:
+ explicit OptionalMatcher(const ValueMatcher& value_matcher)
+ : value_matcher_(value_matcher) {}
+
+ template <typename Optional>
+ operator Matcher<Optional>() const {
+ return Matcher<Optional>(new Impl<const Optional&>(value_matcher_));
+ }
+
+ template <typename Optional>
+ class Impl : public MatcherInterface<Optional> {
+ public:
+ typedef GTEST_REMOVE_REFERENCE_AND_CONST_(Optional) OptionalView;
+ typedef typename OptionalView::value_type ValueType;
+ explicit Impl(const ValueMatcher& value_matcher)
+ : value_matcher_(MatcherCast<ValueType>(value_matcher)) {}
+
+ void DescribeTo(::std::ostream* os) const override {
+ *os << "value ";
+ value_matcher_.DescribeTo(os);
+ }
+
+ void DescribeNegationTo(::std::ostream* os) const override {
+ *os << "value ";
+ value_matcher_.DescribeNegationTo(os);
+ }
+
+ bool MatchAndExplain(Optional optional,
+ MatchResultListener* listener) const override {
+ if (!optional) {
+ *listener << "which is not engaged";
+ return false;
+ }
+ const ValueType& value = *optional;
+ StringMatchResultListener value_listener;
+ const bool match = value_matcher_.MatchAndExplain(value, &value_listener);
+ *listener << "whose value " << PrintToString(value)
+ << (match ? " matches" : " doesn't match");
+ PrintIfNotEmpty(value_listener.str(), listener->stream());
+ return match;
+ }
+
+ private:
+ const Matcher<ValueType> value_matcher_;
+ GTEST_DISALLOW_ASSIGN_(Impl);
+ };
+
+ private:
+ const ValueMatcher value_matcher_;
+ GTEST_DISALLOW_ASSIGN_(OptionalMatcher);
+};
+
+namespace variant_matcher {
+// Overloads to allow VariantMatcher to do proper ADL lookup.
+template <typename T>
+void holds_alternative() {}
+template <typename T>
+void get() {}
+
+// Implements a matcher that checks the value of a variant<> type variable.
+template <typename T>
+class VariantMatcher {
+ public:
+ explicit VariantMatcher(::testing::Matcher<const T&> matcher)
+ : matcher_(std::move(matcher)) {}
+
+ template <typename Variant>
+ bool MatchAndExplain(const Variant& value,
+ ::testing::MatchResultListener* listener) const {
+ using std::get;
+ if (!listener->IsInterested()) {
+ return holds_alternative<T>(value) && matcher_.Matches(get<T>(value));
+ }
+
+ if (!holds_alternative<T>(value)) {
+ *listener << "whose value is not of type '" << GetTypeName() << "'";
+ return false;
+ }
+
+ const T& elem = get<T>(value);
+ StringMatchResultListener elem_listener;
+ const bool match = matcher_.MatchAndExplain(elem, &elem_listener);
+ *listener << "whose value " << PrintToString(elem)
+ << (match ? " matches" : " doesn't match");
+ PrintIfNotEmpty(elem_listener.str(), listener->stream());
+ return match;
+ }
+
+ void DescribeTo(std::ostream* os) const {
+ *os << "is a variant<> with value of type '" << GetTypeName()
+ << "' and the value ";
+ matcher_.DescribeTo(os);
+ }
+
+ void DescribeNegationTo(std::ostream* os) const {
+ *os << "is a variant<> with value of type other than '" << GetTypeName()
+ << "' or the value ";
+ matcher_.DescribeNegationTo(os);
+ }
+
+ private:
+ static std::string GetTypeName() {
+#if GTEST_HAS_RTTI
+ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(
+ return internal::GetTypeName<T>());
+#endif
+ return "the element type";
+ }
+
+ const ::testing::Matcher<const T&> matcher_;
+};
+
+} // namespace variant_matcher
+
+namespace any_cast_matcher {
+
+// Overloads to allow AnyCastMatcher to do proper ADL lookup.
+template <typename T>
+void any_cast() {}
+
+// Implements a matcher that any_casts the value.
+template <typename T>
+class AnyCastMatcher {
+ public:
+ explicit AnyCastMatcher(const ::testing::Matcher<const T&>& matcher)
+ : matcher_(matcher) {}
+
+ template <typename AnyType>
+ bool MatchAndExplain(const AnyType& value,
+ ::testing::MatchResultListener* listener) const {
+ if (!listener->IsInterested()) {
+ const T* ptr = any_cast<T>(&value);
+ return ptr != nullptr && matcher_.Matches(*ptr);
+ }
+
+ const T* elem = any_cast<T>(&value);
+ if (elem == nullptr) {
+ *listener << "whose value is not of type '" << GetTypeName() << "'";
+ return false;
+ }
+
+ StringMatchResultListener elem_listener;
+ const bool match = matcher_.MatchAndExplain(*elem, &elem_listener);
+ *listener << "whose value " << PrintToString(*elem)
+ << (match ? " matches" : " doesn't match");
+ PrintIfNotEmpty(elem_listener.str(), listener->stream());
+ return match;
+ }
+
+ void DescribeTo(std::ostream* os) const {
+ *os << "is an 'any' type with value of type '" << GetTypeName()
+ << "' and the value ";
+ matcher_.DescribeTo(os);
+ }
+
+ void DescribeNegationTo(std::ostream* os) const {
+ *os << "is an 'any' type with value of type other than '" << GetTypeName()
+ << "' or the value ";
+ matcher_.DescribeNegationTo(os);
+ }
+
+ private:
+ static std::string GetTypeName() {
+#if GTEST_HAS_RTTI
+ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(
+ return internal::GetTypeName<T>());
+#endif
+ return "the element type";
+ }
+
+ const ::testing::Matcher<const T&> matcher_;
+};
+
+} // namespace any_cast_matcher
+
+// Implements the Args() matcher.
+template <class ArgsTuple, size_t... k>
+class ArgsMatcherImpl : public MatcherInterface<ArgsTuple> {
+ public:
+ using RawArgsTuple = typename std::decay<ArgsTuple>::type;
+ using SelectedArgs =
+ std::tuple<typename std::tuple_element<k, RawArgsTuple>::type...>;
+ using MonomorphicInnerMatcher = Matcher<const SelectedArgs&>;
+
+ template <typename InnerMatcher>
+ explicit ArgsMatcherImpl(const InnerMatcher& inner_matcher)
+ : inner_matcher_(SafeMatcherCast<const SelectedArgs&>(inner_matcher)) {}
+
+ bool MatchAndExplain(ArgsTuple args,
+ MatchResultListener* listener) const override {
+ // Workaround spurious C4100 on MSVC<=15.7 when k is empty.
+ (void)args;
+ const SelectedArgs& selected_args =
+ std::forward_as_tuple(std::get<k>(args)...);
+ if (!listener->IsInterested()) return inner_matcher_.Matches(selected_args);
+
+ PrintIndices(listener->stream());
+ *listener << "are " << PrintToString(selected_args);
+
+ StringMatchResultListener inner_listener;
+ const bool match =
+ inner_matcher_.MatchAndExplain(selected_args, &inner_listener);
+ PrintIfNotEmpty(inner_listener.str(), listener->stream());
+ return match;
+ }
+
+ void DescribeTo(::std::ostream* os) const override {
+ *os << "are a tuple ";
+ PrintIndices(os);
+ inner_matcher_.DescribeTo(os);
+ }
+
+ void DescribeNegationTo(::std::ostream* os) const override {
+ *os << "are a tuple ";
+ PrintIndices(os);
+ inner_matcher_.DescribeNegationTo(os);
+ }
+
+ private:
+ // Prints the indices of the selected fields.
+ static void PrintIndices(::std::ostream* os) {
+ *os << "whose fields (";
+ const char* sep = "";
+ // Workaround spurious C4189 on MSVC<=15.7 when k is empty.
+ (void)sep;
+ const char* dummy[] = {"", (*os << sep << "#" << k, sep = ", ")...};
+ (void)dummy;
+ *os << ") ";
+ }
+
+ MonomorphicInnerMatcher inner_matcher_;
+};
+
+template <class InnerMatcher, size_t... k>
+class ArgsMatcher {
+ public:
+ explicit ArgsMatcher(InnerMatcher inner_matcher)
+ : inner_matcher_(std::move(inner_matcher)) {}
+
+ template <typename ArgsTuple>
+ operator Matcher<ArgsTuple>() const { // NOLINT
+ return MakeMatcher(new ArgsMatcherImpl<ArgsTuple, k...>(inner_matcher_));
+ }
+
+ private:
+ InnerMatcher inner_matcher_;
+};
} // namespace internal
-// ElementsAreArray(first, last)
+// ElementsAreArray(iterator_first, iterator_last)
// ElementsAreArray(pointer, count)
// ElementsAreArray(array)
// ElementsAreArray(container)
@@ -3666,28 +3527,32 @@ ElementsAreArray(const Container& container) {
return ElementsAreArray(container.begin(), container.end());
}
-#if GTEST_HAS_STD_INITIALIZER_LIST_
template <typename T>
inline internal::ElementsAreArrayMatcher<T>
ElementsAreArray(::std::initializer_list<T> xs) {
return ElementsAreArray(xs.begin(), xs.end());
}
-#endif
-// UnorderedElementsAreArray(first, last)
+// UnorderedElementsAreArray(iterator_first, iterator_last)
// UnorderedElementsAreArray(pointer, count)
// UnorderedElementsAreArray(array)
// UnorderedElementsAreArray(container)
// UnorderedElementsAreArray({ e1, e2, ..., en })
//
-// The UnorderedElementsAreArray() functions are like
-// ElementsAreArray(...), but allow matching the elements in any order.
+// UnorderedElementsAreArray() verifies that a bijective mapping onto a
+// collection of matchers exists.
+//
+// The matchers can be specified as an array, a pointer and count, a container,
+// an initializer list, or an STL iterator range. In each of these cases, the
+// underlying matchers can be either values or matchers.
+
template <typename Iter>
inline internal::UnorderedElementsAreArrayMatcher<
typename ::std::iterator_traits<Iter>::value_type>
UnorderedElementsAreArray(Iter first, Iter last) {
typedef typename ::std::iterator_traits<Iter>::value_type T;
- return internal::UnorderedElementsAreArrayMatcher<T>(first, last);
+ return internal::UnorderedElementsAreArrayMatcher<T>(
+ internal::UnorderedMatcherRequire::ExactMatch, first, last);
}
template <typename T>
@@ -3709,13 +3574,11 @@ UnorderedElementsAreArray(const Container& container) {
return UnorderedElementsAreArray(container.begin(), container.end());
}
-#if GTEST_HAS_STD_INITIALIZER_LIST_
template <typename T>
inline internal::UnorderedElementsAreArrayMatcher<T>
UnorderedElementsAreArray(::std::initializer_list<T> xs) {
return UnorderedElementsAreArray(xs.begin(), xs.end());
}
-#endif
// _ is a matcher that matches anything of any type.
//
@@ -3729,66 +3592,19 @@ UnorderedElementsAreArray(::std::initializer_list<T> xs) {
const internal::AnythingMatcher _ = {};
// Creates a matcher that matches any value of the given type T.
template <typename T>
-inline Matcher<T> A() { return MakeMatcher(new internal::AnyMatcherImpl<T>()); }
+inline Matcher<T> A() {
+ return Matcher<T>(new internal::AnyMatcherImpl<T>());
+}
// Creates a matcher that matches any value of the given type T.
template <typename T>
inline Matcher<T> An() { return A<T>(); }
-// Creates a polymorphic matcher that matches anything equal to x.
-// Note: if the parameter of Eq() were declared as const T&, Eq("foo")
-// wouldn't compile.
-template <typename T>
-inline internal::EqMatcher<T> Eq(T x) { return internal::EqMatcher<T>(x); }
-
-// Constructs a Matcher<T> from a 'value' of type T. The constructed
-// matcher matches any value that's equal to 'value'.
-template <typename T>
-Matcher<T>::Matcher(T value) { *this = Eq(value); }
-
-// Creates a monomorphic matcher that matches anything with type Lhs
-// and equal to rhs. A user may need to use this instead of Eq(...)
-// in order to resolve an overloading ambiguity.
-//
-// TypedEq<T>(x) is just a convenient short-hand for Matcher<T>(Eq(x))
-// or Matcher<T>(x), but more readable than the latter.
-//
-// We could define similar monomorphic matchers for other comparison
-// operations (e.g. TypedLt, TypedGe, and etc), but decided not to do
-// it yet as those are used much less than Eq() in practice. A user
-// can always write Matcher<T>(Lt(5)) to be explicit about the type,
-// for example.
-template <typename Lhs, typename Rhs>
-inline Matcher<Lhs> TypedEq(const Rhs& rhs) { return Eq(rhs); }
-
-// Creates a polymorphic matcher that matches anything >= x.
-template <typename Rhs>
-inline internal::GeMatcher<Rhs> Ge(Rhs x) {
- return internal::GeMatcher<Rhs>(x);
-}
-
-// Creates a polymorphic matcher that matches anything > x.
-template <typename Rhs>
-inline internal::GtMatcher<Rhs> Gt(Rhs x) {
- return internal::GtMatcher<Rhs>(x);
-}
-
-// Creates a polymorphic matcher that matches anything <= x.
-template <typename Rhs>
-inline internal::LeMatcher<Rhs> Le(Rhs x) {
- return internal::LeMatcher<Rhs>(x);
-}
-
-// Creates a polymorphic matcher that matches anything < x.
-template <typename Rhs>
-inline internal::LtMatcher<Rhs> Lt(Rhs x) {
- return internal::LtMatcher<Rhs>(x);
-}
-
-// Creates a polymorphic matcher that matches anything != x.
-template <typename Rhs>
-inline internal::NeMatcher<Rhs> Ne(Rhs x) {
- return internal::NeMatcher<Rhs>(x);
+template <typename T, typename M>
+Matcher<T> internal::MatcherCastImpl<T, M>::CastImpl(
+ const M& value, std::false_type /* convertible_to_matcher */,
+ std::false_type /* convertible_to_T */) {
+ return Eq(value);
}
// Creates a polymorphic matcher that matches any NULL pointer.
@@ -3874,6 +3690,7 @@ inline internal::PointeeMatcher<InnerMatcher> Pointee(
return internal::PointeeMatcher<InnerMatcher>(inner_matcher);
}
+#if GTEST_HAS_RTTI
// Creates a matcher that matches a pointer or reference that matches
// inner_matcher when dynamic_cast<To> is applied.
// The result of dynamic_cast<To> is forwarded to the inner matcher.
@@ -3886,11 +3703,12 @@ WhenDynamicCastTo(const Matcher<To>& inner_matcher) {
return MakePolymorphicMatcher(
internal::WhenDynamicCastToMatcher<To>(inner_matcher));
}
+#endif // GTEST_HAS_RTTI
// Creates a matcher that matches an object whose given field matches
// 'matcher'. For example,
// Field(&Foo::number, Ge(5))
-// matches a Foo object x iff x.number >= 5.
+// matches a Foo object x if and only if x.number >= 5.
template <typename Class, typename FieldType, typename FieldMatcher>
inline PolymorphicMatcher<
internal::FieldMatcher<Class, FieldType> > Field(
@@ -3904,178 +3722,194 @@ inline PolymorphicMatcher<
// to compile where bar is an int32 and m is a matcher for int64.
}
+// Same as Field() but also takes the name of the field to provide better error
+// messages.
+template <typename Class, typename FieldType, typename FieldMatcher>
+inline PolymorphicMatcher<internal::FieldMatcher<Class, FieldType> > Field(
+ const std::string& field_name, FieldType Class::*field,
+ const FieldMatcher& matcher) {
+ return MakePolymorphicMatcher(internal::FieldMatcher<Class, FieldType>(
+ field_name, field, MatcherCast<const FieldType&>(matcher)));
+}
+
// Creates a matcher that matches an object whose given property
// matches 'matcher'. For example,
// Property(&Foo::str, StartsWith("hi"))
-// matches a Foo object x iff x.str() starts with "hi".
+// matches a Foo object x if and only if x.str() starts with "hi".
template <typename Class, typename PropertyType, typename PropertyMatcher>
-inline PolymorphicMatcher<
- internal::PropertyMatcher<Class, PropertyType> > Property(
- PropertyType (Class::*property)() const, const PropertyMatcher& matcher) {
+inline PolymorphicMatcher<internal::PropertyMatcher<
+ Class, PropertyType, PropertyType (Class::*)() const> >
+Property(PropertyType (Class::*property)() const,
+ const PropertyMatcher& matcher) {
return MakePolymorphicMatcher(
- internal::PropertyMatcher<Class, PropertyType>(
- property,
- MatcherCast<GTEST_REFERENCE_TO_CONST_(PropertyType)>(matcher)));
+ internal::PropertyMatcher<Class, PropertyType,
+ PropertyType (Class::*)() const>(
+ property, MatcherCast<const PropertyType&>(matcher)));
// The call to MatcherCast() is required for supporting inner
// matchers of compatible types. For example, it allows
// Property(&Foo::bar, m)
// to compile where bar() returns an int32 and m is a matcher for int64.
}
-// Creates a matcher that matches an object iff the result of applying
-// a callable to x matches 'matcher'.
-// For example,
+// Same as Property() above, but also takes the name of the property to provide
+// better error messages.
+template <typename Class, typename PropertyType, typename PropertyMatcher>
+inline PolymorphicMatcher<internal::PropertyMatcher<
+ Class, PropertyType, PropertyType (Class::*)() const> >
+Property(const std::string& property_name,
+ PropertyType (Class::*property)() const,
+ const PropertyMatcher& matcher) {
+ return MakePolymorphicMatcher(
+ internal::PropertyMatcher<Class, PropertyType,
+ PropertyType (Class::*)() const>(
+ property_name, property, MatcherCast<const PropertyType&>(matcher)));
+}
+
+// The same as above but for reference-qualified member functions.
+template <typename Class, typename PropertyType, typename PropertyMatcher>
+inline PolymorphicMatcher<internal::PropertyMatcher<
+ Class, PropertyType, PropertyType (Class::*)() const &> >
+Property(PropertyType (Class::*property)() const &,
+ const PropertyMatcher& matcher) {
+ return MakePolymorphicMatcher(
+ internal::PropertyMatcher<Class, PropertyType,
+ PropertyType (Class::*)() const&>(
+ property, MatcherCast<const PropertyType&>(matcher)));
+}
+
+// Three-argument form for reference-qualified member functions.
+template <typename Class, typename PropertyType, typename PropertyMatcher>
+inline PolymorphicMatcher<internal::PropertyMatcher<
+ Class, PropertyType, PropertyType (Class::*)() const &> >
+Property(const std::string& property_name,
+ PropertyType (Class::*property)() const &,
+ const PropertyMatcher& matcher) {
+ return MakePolymorphicMatcher(
+ internal::PropertyMatcher<Class, PropertyType,
+ PropertyType (Class::*)() const&>(
+ property_name, property, MatcherCast<const PropertyType&>(matcher)));
+}
+
+// Creates a matcher that matches an object if and only if the result of
+// applying a callable to x matches 'matcher'. For example,
// ResultOf(f, StartsWith("hi"))
-// matches a Foo object x iff f(x) starts with "hi".
-// callable parameter can be a function, function pointer, or a functor.
-// Callable has to satisfy the following conditions:
-// * It is required to keep no state affecting the results of
-// the calls on it and make no assumptions about how many calls
-// will be made. Any state it keeps must be protected from the
-// concurrent access.
-// * If it is a function object, it has to define type result_type.
-// We recommend deriving your functor classes from std::unary_function.
-template <typename Callable, typename ResultOfMatcher>
-internal::ResultOfMatcher<Callable> ResultOf(
- Callable callable, const ResultOfMatcher& matcher) {
- return internal::ResultOfMatcher<Callable>(
- callable,
- MatcherCast<typename internal::CallableTraits<Callable>::ResultType>(
- matcher));
- // The call to MatcherCast() is required for supporting inner
- // matchers of compatible types. For example, it allows
- // ResultOf(Function, m)
- // to compile where Function() returns an int32 and m is a matcher for int64.
+// matches a Foo object x if and only if f(x) starts with "hi".
+// `callable` parameter can be a function, function pointer, or a functor. It is
+// required to keep no state affecting the results of the calls on it and make
+// no assumptions about how many calls will be made. Any state it keeps must be
+// protected from the concurrent access.
+template <typename Callable, typename InnerMatcher>
+internal::ResultOfMatcher<Callable, InnerMatcher> ResultOf(
+ Callable callable, InnerMatcher matcher) {
+ return internal::ResultOfMatcher<Callable, InnerMatcher>(
+ std::move(callable), std::move(matcher));
}
// String matchers.
// Matches a string equal to str.
-inline PolymorphicMatcher<internal::StrEqualityMatcher<internal::string> >
- StrEq(const internal::string& str) {
- return MakePolymorphicMatcher(internal::StrEqualityMatcher<internal::string>(
- str, true, true));
+inline PolymorphicMatcher<internal::StrEqualityMatcher<std::string> > StrEq(
+ const std::string& str) {
+ return MakePolymorphicMatcher(
+ internal::StrEqualityMatcher<std::string>(str, true, true));
}
// Matches a string not equal to str.
-inline PolymorphicMatcher<internal::StrEqualityMatcher<internal::string> >
- StrNe(const internal::string& str) {
- return MakePolymorphicMatcher(internal::StrEqualityMatcher<internal::string>(
- str, false, true));
+inline PolymorphicMatcher<internal::StrEqualityMatcher<std::string> > StrNe(
+ const std::string& str) {
+ return MakePolymorphicMatcher(
+ internal::StrEqualityMatcher<std::string>(str, false, true));
}
// Matches a string equal to str, ignoring case.
-inline PolymorphicMatcher<internal::StrEqualityMatcher<internal::string> >
- StrCaseEq(const internal::string& str) {
- return MakePolymorphicMatcher(internal::StrEqualityMatcher<internal::string>(
- str, true, false));
+inline PolymorphicMatcher<internal::StrEqualityMatcher<std::string> > StrCaseEq(
+ const std::string& str) {
+ return MakePolymorphicMatcher(
+ internal::StrEqualityMatcher<std::string>(str, true, false));
}
// Matches a string not equal to str, ignoring case.
-inline PolymorphicMatcher<internal::StrEqualityMatcher<internal::string> >
- StrCaseNe(const internal::string& str) {
- return MakePolymorphicMatcher(internal::StrEqualityMatcher<internal::string>(
- str, false, false));
+inline PolymorphicMatcher<internal::StrEqualityMatcher<std::string> > StrCaseNe(
+ const std::string& str) {
+ return MakePolymorphicMatcher(
+ internal::StrEqualityMatcher<std::string>(str, false, false));
}
// Creates a matcher that matches any string, std::string, or C string
// that contains the given substring.
-inline PolymorphicMatcher<internal::HasSubstrMatcher<internal::string> >
- HasSubstr(const internal::string& substring) {
- return MakePolymorphicMatcher(internal::HasSubstrMatcher<internal::string>(
- substring));
+inline PolymorphicMatcher<internal::HasSubstrMatcher<std::string> > HasSubstr(
+ const std::string& substring) {
+ return MakePolymorphicMatcher(
+ internal::HasSubstrMatcher<std::string>(substring));
}
// Matches a string that starts with 'prefix' (case-sensitive).
-inline PolymorphicMatcher<internal::StartsWithMatcher<internal::string> >
- StartsWith(const internal::string& prefix) {
- return MakePolymorphicMatcher(internal::StartsWithMatcher<internal::string>(
- prefix));
+inline PolymorphicMatcher<internal::StartsWithMatcher<std::string> > StartsWith(
+ const std::string& prefix) {
+ return MakePolymorphicMatcher(
+ internal::StartsWithMatcher<std::string>(prefix));
}
// Matches a string that ends with 'suffix' (case-sensitive).
-inline PolymorphicMatcher<internal::EndsWithMatcher<internal::string> >
- EndsWith(const internal::string& suffix) {
- return MakePolymorphicMatcher(internal::EndsWithMatcher<internal::string>(
- suffix));
-}
-
-// Matches a string that fully matches regular expression 'regex'.
-// The matcher takes ownership of 'regex'.
-inline PolymorphicMatcher<internal::MatchesRegexMatcher> MatchesRegex(
- const internal::RE* regex) {
- return MakePolymorphicMatcher(internal::MatchesRegexMatcher(regex, true));
-}
-inline PolymorphicMatcher<internal::MatchesRegexMatcher> MatchesRegex(
- const internal::string& regex) {
- return MatchesRegex(new internal::RE(regex));
+inline PolymorphicMatcher<internal::EndsWithMatcher<std::string> > EndsWith(
+ const std::string& suffix) {
+ return MakePolymorphicMatcher(internal::EndsWithMatcher<std::string>(suffix));
}
-// Matches a string that contains regular expression 'regex'.
-// The matcher takes ownership of 'regex'.
-inline PolymorphicMatcher<internal::MatchesRegexMatcher> ContainsRegex(
- const internal::RE* regex) {
- return MakePolymorphicMatcher(internal::MatchesRegexMatcher(regex, false));
-}
-inline PolymorphicMatcher<internal::MatchesRegexMatcher> ContainsRegex(
- const internal::string& regex) {
- return ContainsRegex(new internal::RE(regex));
-}
-
-#if GTEST_HAS_GLOBAL_WSTRING || GTEST_HAS_STD_WSTRING
+#if GTEST_HAS_STD_WSTRING
// Wide string matchers.
// Matches a string equal to str.
-inline PolymorphicMatcher<internal::StrEqualityMatcher<internal::wstring> >
- StrEq(const internal::wstring& str) {
- return MakePolymorphicMatcher(internal::StrEqualityMatcher<internal::wstring>(
- str, true, true));
+inline PolymorphicMatcher<internal::StrEqualityMatcher<std::wstring> > StrEq(
+ const std::wstring& str) {
+ return MakePolymorphicMatcher(
+ internal::StrEqualityMatcher<std::wstring>(str, true, true));
}
// Matches a string not equal to str.
-inline PolymorphicMatcher<internal::StrEqualityMatcher<internal::wstring> >
- StrNe(const internal::wstring& str) {
- return MakePolymorphicMatcher(internal::StrEqualityMatcher<internal::wstring>(
- str, false, true));
+inline PolymorphicMatcher<internal::StrEqualityMatcher<std::wstring> > StrNe(
+ const std::wstring& str) {
+ return MakePolymorphicMatcher(
+ internal::StrEqualityMatcher<std::wstring>(str, false, true));
}
// Matches a string equal to str, ignoring case.
-inline PolymorphicMatcher<internal::StrEqualityMatcher<internal::wstring> >
- StrCaseEq(const internal::wstring& str) {
- return MakePolymorphicMatcher(internal::StrEqualityMatcher<internal::wstring>(
- str, true, false));
+inline PolymorphicMatcher<internal::StrEqualityMatcher<std::wstring> >
+StrCaseEq(const std::wstring& str) {
+ return MakePolymorphicMatcher(
+ internal::StrEqualityMatcher<std::wstring>(str, true, false));
}
// Matches a string not equal to str, ignoring case.
-inline PolymorphicMatcher<internal::StrEqualityMatcher<internal::wstring> >
- StrCaseNe(const internal::wstring& str) {
- return MakePolymorphicMatcher(internal::StrEqualityMatcher<internal::wstring>(
- str, false, false));
+inline PolymorphicMatcher<internal::StrEqualityMatcher<std::wstring> >
+StrCaseNe(const std::wstring& str) {
+ return MakePolymorphicMatcher(
+ internal::StrEqualityMatcher<std::wstring>(str, false, false));
}
-// Creates a matcher that matches any wstring, std::wstring, or C wide string
+// Creates a matcher that matches any ::wstring, std::wstring, or C wide string
// that contains the given substring.
-inline PolymorphicMatcher<internal::HasSubstrMatcher<internal::wstring> >
- HasSubstr(const internal::wstring& substring) {
- return MakePolymorphicMatcher(internal::HasSubstrMatcher<internal::wstring>(
- substring));
+inline PolymorphicMatcher<internal::HasSubstrMatcher<std::wstring> > HasSubstr(
+ const std::wstring& substring) {
+ return MakePolymorphicMatcher(
+ internal::HasSubstrMatcher<std::wstring>(substring));
}
// Matches a string that starts with 'prefix' (case-sensitive).
-inline PolymorphicMatcher<internal::StartsWithMatcher<internal::wstring> >
- StartsWith(const internal::wstring& prefix) {
- return MakePolymorphicMatcher(internal::StartsWithMatcher<internal::wstring>(
- prefix));
+inline PolymorphicMatcher<internal::StartsWithMatcher<std::wstring> >
+StartsWith(const std::wstring& prefix) {
+ return MakePolymorphicMatcher(
+ internal::StartsWithMatcher<std::wstring>(prefix));
}
// Matches a string that ends with 'suffix' (case-sensitive).
-inline PolymorphicMatcher<internal::EndsWithMatcher<internal::wstring> >
- EndsWith(const internal::wstring& suffix) {
- return MakePolymorphicMatcher(internal::EndsWithMatcher<internal::wstring>(
- suffix));
+inline PolymorphicMatcher<internal::EndsWithMatcher<std::wstring> > EndsWith(
+ const std::wstring& suffix) {
+ return MakePolymorphicMatcher(
+ internal::EndsWithMatcher<std::wstring>(suffix));
}
-#endif // GTEST_HAS_GLOBAL_WSTRING || GTEST_HAS_STD_WSTRING
+#endif // GTEST_HAS_STD_WSTRING
// Creates a polymorphic matcher that matches a 2-tuple where the
// first field == the second field.
@@ -4101,6 +3935,58 @@ inline internal::Lt2Matcher Lt() { return internal::Lt2Matcher(); }
// first field != the second field.
inline internal::Ne2Matcher Ne() { return internal::Ne2Matcher(); }
+// Creates a polymorphic matcher that matches a 2-tuple where
+// FloatEq(first field) matches the second field.
+inline internal::FloatingEq2Matcher<float> FloatEq() {
+ return internal::FloatingEq2Matcher<float>();
+}
+
+// Creates a polymorphic matcher that matches a 2-tuple where
+// DoubleEq(first field) matches the second field.
+inline internal::FloatingEq2Matcher<double> DoubleEq() {
+ return internal::FloatingEq2Matcher<double>();
+}
+
+// Creates a polymorphic matcher that matches a 2-tuple where
+// FloatEq(first field) matches the second field with NaN equality.
+inline internal::FloatingEq2Matcher<float> NanSensitiveFloatEq() {
+ return internal::FloatingEq2Matcher<float>(true);
+}
+
+// Creates a polymorphic matcher that matches a 2-tuple where
+// DoubleEq(first field) matches the second field with NaN equality.
+inline internal::FloatingEq2Matcher<double> NanSensitiveDoubleEq() {
+ return internal::FloatingEq2Matcher<double>(true);
+}
+
+// Creates a polymorphic matcher that matches a 2-tuple where
+// FloatNear(first field, max_abs_error) matches the second field.
+inline internal::FloatingEq2Matcher<float> FloatNear(float max_abs_error) {
+ return internal::FloatingEq2Matcher<float>(max_abs_error);
+}
+
+// Creates a polymorphic matcher that matches a 2-tuple where
+// DoubleNear(first field, max_abs_error) matches the second field.
+inline internal::FloatingEq2Matcher<double> DoubleNear(double max_abs_error) {
+ return internal::FloatingEq2Matcher<double>(max_abs_error);
+}
+
+// Creates a polymorphic matcher that matches a 2-tuple where
+// FloatNear(first field, max_abs_error) matches the second field with NaN
+// equality.
+inline internal::FloatingEq2Matcher<float> NanSensitiveFloatNear(
+ float max_abs_error) {
+ return internal::FloatingEq2Matcher<float>(max_abs_error, true);
+}
+
+// Creates a polymorphic matcher that matches a 2-tuple where
+// DoubleNear(first field, max_abs_error) matches the second field with NaN
+// equality.
+inline internal::FloatingEq2Matcher<double> NanSensitiveDoubleNear(
+ double max_abs_error) {
+ return internal::FloatingEq2Matcher<double>(max_abs_error, true);
+}
+
// Creates a matcher that matches any value of type T that m doesn't
// match.
template <typename InnerMatcher>
@@ -4145,12 +4031,12 @@ BeginEndDistanceIs(const DistanceMatcher& distance_matcher) {
// values that are included in one container but not the other. (Duplicate
// values and order differences are not explained.)
template <typename Container>
-inline PolymorphicMatcher<internal::ContainerEqMatcher< // NOLINT
- GTEST_REMOVE_CONST_(Container)> >
- ContainerEq(const Container& rhs) {
+inline PolymorphicMatcher<internal::ContainerEqMatcher<
+ typename std::remove_const<Container>::type>>
+ContainerEq(const Container& rhs) {
// This following line is for working around a bug in MSVC 8.0,
// which causes Container to be a const type sometimes.
- typedef GTEST_REMOVE_CONST_(Container) RawContainer;
+ typedef typename std::remove_const<Container>::type RawContainer;
return MakePolymorphicMatcher(
internal::ContainerEqMatcher<RawContainer>(rhs));
}
@@ -4178,22 +4064,21 @@ WhenSorted(const ContainerMatcher& container_matcher) {
// Matches an STL-style container or a native array that contains the
// same number of elements as in rhs, where its i-th element and rhs's
// i-th element (as a pair) satisfy the given pair matcher, for all i.
-// TupleMatcher must be able to be safely cast to Matcher<tuple<const
+// TupleMatcher must be able to be safely cast to Matcher<std::tuple<const
// T1&, const T2&> >, where T1 and T2 are the types of elements in the
// LHS container and the RHS container respectively.
template <typename TupleMatcher, typename Container>
inline internal::PointwiseMatcher<TupleMatcher,
- GTEST_REMOVE_CONST_(Container)>
+ typename std::remove_const<Container>::type>
Pointwise(const TupleMatcher& tuple_matcher, const Container& rhs) {
// This following line is for working around a bug in MSVC 8.0,
// which causes Container to be a const type sometimes (e.g. when
// rhs is a const int[])..
- typedef GTEST_REMOVE_CONST_(Container) RawContainer;
+ typedef typename std::remove_const<Container>::type RawContainer;
return internal::PointwiseMatcher<TupleMatcher, RawContainer>(
tuple_matcher, rhs);
}
-#if GTEST_HAS_STD_INITIALIZER_LIST_
// Supports the Pointwise(m, {a, b, c}) syntax.
template <typename TupleMatcher, typename T>
@@ -4202,14 +4087,13 @@ inline internal::PointwiseMatcher<TupleMatcher, std::vector<T> > Pointwise(
return Pointwise(tuple_matcher, std::vector<T>(rhs));
}
-#endif // GTEST_HAS_STD_INITIALIZER_LIST_
// UnorderedPointwise(pair_matcher, rhs) matches an STL-style
// container or a native array that contains the same number of
// elements as in rhs, where in some permutation of the container, its
// i-th element and rhs's i-th element (as a pair) satisfy the given
// pair matcher, for all i. Tuple2Matcher must be able to be safely
-// cast to Matcher<tuple<const T1&, const T2&> >, where T1 and T2 are
+// cast to Matcher<std::tuple<const T1&, const T2&> >, where T1 and T2 are
// the types of elements in the LHS container and the RHS container
// respectively.
//
@@ -4218,14 +4102,15 @@ inline internal::PointwiseMatcher<TupleMatcher, std::vector<T> > Pointwise(
template <typename Tuple2Matcher, typename RhsContainer>
inline internal::UnorderedElementsAreArrayMatcher<
typename internal::BoundSecondMatcher<
- Tuple2Matcher, typename internal::StlContainerView<GTEST_REMOVE_CONST_(
- RhsContainer)>::type::value_type> >
+ Tuple2Matcher,
+ typename internal::StlContainerView<
+ typename std::remove_const<RhsContainer>::type>::type::value_type>>
UnorderedPointwise(const Tuple2Matcher& tuple2_matcher,
const RhsContainer& rhs_container) {
// This following line is for working around a bug in MSVC 8.0,
// which causes RhsContainer to be a const type sometimes (e.g. when
// rhs_container is a const int[]).
- typedef GTEST_REMOVE_CONST_(RhsContainer) RawRhsContainer;
+ typedef typename std::remove_const<RhsContainer>::type RawRhsContainer;
// RhsView allows the same code to handle RhsContainer being a
// STL-style container and it being a native C-style array.
@@ -4247,7 +4132,6 @@ UnorderedPointwise(const Tuple2Matcher& tuple2_matcher,
return UnorderedElementsAreArray(matchers);
}
-#if GTEST_HAS_STD_INITIALIZER_LIST_
// Supports the UnorderedPointwise(m, {a, b, c}) syntax.
template <typename Tuple2Matcher, typename T>
@@ -4258,7 +4142,6 @@ UnorderedPointwise(const Tuple2Matcher& tuple2_matcher,
return UnorderedPointwise(tuple2_matcher, std::vector<T>(rhs));
}
-#endif // GTEST_HAS_STD_INITIALIZER_LIST_
// Matches an STL-style container or a native array that contains at
// least one element matching the given value or matcher.
@@ -4283,6 +4166,124 @@ inline internal::ContainsMatcher<M> Contains(M matcher) {
return internal::ContainsMatcher<M>(matcher);
}
+// IsSupersetOf(iterator_first, iterator_last)
+// IsSupersetOf(pointer, count)
+// IsSupersetOf(array)
+// IsSupersetOf(container)
+// IsSupersetOf({e1, e2, ..., en})
+//
+// IsSupersetOf() verifies that a surjective partial mapping onto a collection
+// of matchers exists. In other words, a container matches
+// IsSupersetOf({e1, ..., en}) if and only if there is a permutation
+// {y1, ..., yn} of some of the container's elements where y1 matches e1,
+// ..., and yn matches en. Obviously, the size of the container must be >= n
+// in order to have a match. Examples:
+//
+// - {1, 2, 3} matches IsSupersetOf({Ge(3), Ne(0)}), as 3 matches Ge(3) and
+// 1 matches Ne(0).
+// - {1, 2} doesn't match IsSupersetOf({Eq(1), Lt(2)}), even though 1 matches
+// both Eq(1) and Lt(2). The reason is that different matchers must be used
+// for elements in different slots of the container.
+// - {1, 1, 2} matches IsSupersetOf({Eq(1), Lt(2)}), as (the first) 1 matches
+// Eq(1) and (the second) 1 matches Lt(2).
+// - {1, 2, 3} matches IsSupersetOf(Gt(1), Gt(1)), as 2 matches (the first)
+// Gt(1) and 3 matches (the second) Gt(1).
+//
+// The matchers can be specified as an array, a pointer and count, a container,
+// an initializer list, or an STL iterator range. In each of these cases, the
+// underlying matchers can be either values or matchers.
+
+template <typename Iter>
+inline internal::UnorderedElementsAreArrayMatcher<
+ typename ::std::iterator_traits<Iter>::value_type>
+IsSupersetOf(Iter first, Iter last) {
+ typedef typename ::std::iterator_traits<Iter>::value_type T;
+ return internal::UnorderedElementsAreArrayMatcher<T>(
+ internal::UnorderedMatcherRequire::Superset, first, last);
+}
+
+template <typename T>
+inline internal::UnorderedElementsAreArrayMatcher<T> IsSupersetOf(
+ const T* pointer, size_t count) {
+ return IsSupersetOf(pointer, pointer + count);
+}
+
+template <typename T, size_t N>
+inline internal::UnorderedElementsAreArrayMatcher<T> IsSupersetOf(
+ const T (&array)[N]) {
+ return IsSupersetOf(array, N);
+}
+
+template <typename Container>
+inline internal::UnorderedElementsAreArrayMatcher<
+ typename Container::value_type>
+IsSupersetOf(const Container& container) {
+ return IsSupersetOf(container.begin(), container.end());
+}
+
+template <typename T>
+inline internal::UnorderedElementsAreArrayMatcher<T> IsSupersetOf(
+ ::std::initializer_list<T> xs) {
+ return IsSupersetOf(xs.begin(), xs.end());
+}
+
+// IsSubsetOf(iterator_first, iterator_last)
+// IsSubsetOf(pointer, count)
+// IsSubsetOf(array)
+// IsSubsetOf(container)
+// IsSubsetOf({e1, e2, ..., en})
+//
+// IsSubsetOf() verifies that an injective mapping onto a collection of matchers
+// exists. In other words, a container matches IsSubsetOf({e1, ..., en}) if and
+// only if there is a subset of matchers {m1, ..., mk} which would match the
+// container using UnorderedElementsAre. Obviously, the size of the container
+// must be <= n in order to have a match. Examples:
+//
+// - {1} matches IsSubsetOf({Gt(0), Lt(0)}), as 1 matches Gt(0).
+// - {1, -1} matches IsSubsetOf({Lt(0), Gt(0)}), as 1 matches Gt(0) and -1
+// matches Lt(0).
+// - {1, 2} doesn't matches IsSubsetOf({Gt(0), Lt(0)}), even though 1 and 2 both
+// match Gt(0). The reason is that different matchers must be used for
+// elements in different slots of the container.
+//
+// The matchers can be specified as an array, a pointer and count, a container,
+// an initializer list, or an STL iterator range. In each of these cases, the
+// underlying matchers can be either values or matchers.
+
+template <typename Iter>
+inline internal::UnorderedElementsAreArrayMatcher<
+ typename ::std::iterator_traits<Iter>::value_type>
+IsSubsetOf(Iter first, Iter last) {
+ typedef typename ::std::iterator_traits<Iter>::value_type T;
+ return internal::UnorderedElementsAreArrayMatcher<T>(
+ internal::UnorderedMatcherRequire::Subset, first, last);
+}
+
+template <typename T>
+inline internal::UnorderedElementsAreArrayMatcher<T> IsSubsetOf(
+ const T* pointer, size_t count) {
+ return IsSubsetOf(pointer, pointer + count);
+}
+
+template <typename T, size_t N>
+inline internal::UnorderedElementsAreArrayMatcher<T> IsSubsetOf(
+ const T (&array)[N]) {
+ return IsSubsetOf(array, N);
+}
+
+template <typename Container>
+inline internal::UnorderedElementsAreArrayMatcher<
+ typename Container::value_type>
+IsSubsetOf(const Container& container) {
+ return IsSubsetOf(container.begin(), container.end());
+}
+
+template <typename T>
+inline internal::UnorderedElementsAreArrayMatcher<T> IsSubsetOf(
+ ::std::initializer_list<T> xs) {
+ return IsSubsetOf(xs.begin(), xs.end());
+}
+
// Matches an STL-style container or a native array that contains only
// elements matching the given value or matcher.
//
@@ -4342,7 +4343,7 @@ inline internal::MatcherAsPredicate<M> Matches(M matcher) {
return internal::MatcherAsPredicate<M>(matcher);
}
-// Returns true iff the value matches the matcher.
+// Returns true if and only if the value matches the matcher.
template <typename T, typename M>
inline bool Value(const T& value, M matcher) {
return testing::Matches(matcher)(value);
@@ -4356,20 +4357,152 @@ inline bool ExplainMatchResult(
return SafeMatcherCast<const T&>(matcher).MatchAndExplain(value, listener);
}
-#if GTEST_LANG_CXX11
-// Define variadic matcher versions. They are overloaded in
-// gmock-generated-matchers.h for the cases supported by pre C++11 compilers.
+// Returns a string representation of the given matcher. Useful for description
+// strings of matchers defined using MATCHER_P* macros that accept matchers as
+// their arguments. For example:
+//
+// MATCHER_P(XAndYThat, matcher,
+// "X that " + DescribeMatcher<int>(matcher, negation) +
+// " and Y that " + DescribeMatcher<double>(matcher, negation)) {
+// return ExplainMatchResult(matcher, arg.x(), result_listener) &&
+// ExplainMatchResult(matcher, arg.y(), result_listener);
+// }
+template <typename T, typename M>
+std::string DescribeMatcher(const M& matcher, bool negation = false) {
+ ::std::stringstream ss;
+ Matcher<T> monomorphic_matcher = SafeMatcherCast<T>(matcher);
+ if (negation) {
+ monomorphic_matcher.DescribeNegationTo(&ss);
+ } else {
+ monomorphic_matcher.DescribeTo(&ss);
+ }
+ return ss.str();
+}
+
+template <typename... Args>
+internal::ElementsAreMatcher<
+ std::tuple<typename std::decay<const Args&>::type...>>
+ElementsAre(const Args&... matchers) {
+ return internal::ElementsAreMatcher<
+ std::tuple<typename std::decay<const Args&>::type...>>(
+ std::make_tuple(matchers...));
+}
+
template <typename... Args>
-inline internal::AllOfMatcher<Args...> AllOf(const Args&... matchers) {
- return internal::AllOfMatcher<Args...>(matchers...);
+internal::UnorderedElementsAreMatcher<
+ std::tuple<typename std::decay<const Args&>::type...>>
+UnorderedElementsAre(const Args&... matchers) {
+ return internal::UnorderedElementsAreMatcher<
+ std::tuple<typename std::decay<const Args&>::type...>>(
+ std::make_tuple(matchers...));
}
+// Define variadic matcher versions.
template <typename... Args>
-inline internal::AnyOfMatcher<Args...> AnyOf(const Args&... matchers) {
- return internal::AnyOfMatcher<Args...>(matchers...);
+internal::AllOfMatcher<typename std::decay<const Args&>::type...> AllOf(
+ const Args&... matchers) {
+ return internal::AllOfMatcher<typename std::decay<const Args&>::type...>(
+ matchers...);
}
-#endif // GTEST_LANG_CXX11
+template <typename... Args>
+internal::AnyOfMatcher<typename std::decay<const Args&>::type...> AnyOf(
+ const Args&... matchers) {
+ return internal::AnyOfMatcher<typename std::decay<const Args&>::type...>(
+ matchers...);
+}
+
+// AnyOfArray(array)
+// AnyOfArray(pointer, count)
+// AnyOfArray(container)
+// AnyOfArray({ e1, e2, ..., en })
+// AnyOfArray(iterator_first, iterator_last)
+//
+// AnyOfArray() verifies whether a given value matches any member of a
+// collection of matchers.
+//
+// AllOfArray(array)
+// AllOfArray(pointer, count)
+// AllOfArray(container)
+// AllOfArray({ e1, e2, ..., en })
+// AllOfArray(iterator_first, iterator_last)
+//
+// AllOfArray() verifies whether a given value matches all members of a
+// collection of matchers.
+//
+// The matchers can be specified as an array, a pointer and count, a container,
+// an initializer list, or an STL iterator range. In each of these cases, the
+// underlying matchers can be either values or matchers.
+
+template <typename Iter>
+inline internal::AnyOfArrayMatcher<
+ typename ::std::iterator_traits<Iter>::value_type>
+AnyOfArray(Iter first, Iter last) {
+ return internal::AnyOfArrayMatcher<
+ typename ::std::iterator_traits<Iter>::value_type>(first, last);
+}
+
+template <typename Iter>
+inline internal::AllOfArrayMatcher<
+ typename ::std::iterator_traits<Iter>::value_type>
+AllOfArray(Iter first, Iter last) {
+ return internal::AllOfArrayMatcher<
+ typename ::std::iterator_traits<Iter>::value_type>(first, last);
+}
+
+template <typename T>
+inline internal::AnyOfArrayMatcher<T> AnyOfArray(const T* ptr, size_t count) {
+ return AnyOfArray(ptr, ptr + count);
+}
+
+template <typename T>
+inline internal::AllOfArrayMatcher<T> AllOfArray(const T* ptr, size_t count) {
+ return AllOfArray(ptr, ptr + count);
+}
+
+template <typename T, size_t N>
+inline internal::AnyOfArrayMatcher<T> AnyOfArray(const T (&array)[N]) {
+ return AnyOfArray(array, N);
+}
+
+template <typename T, size_t N>
+inline internal::AllOfArrayMatcher<T> AllOfArray(const T (&array)[N]) {
+ return AllOfArray(array, N);
+}
+
+template <typename Container>
+inline internal::AnyOfArrayMatcher<typename Container::value_type> AnyOfArray(
+ const Container& container) {
+ return AnyOfArray(container.begin(), container.end());
+}
+
+template <typename Container>
+inline internal::AllOfArrayMatcher<typename Container::value_type> AllOfArray(
+ const Container& container) {
+ return AllOfArray(container.begin(), container.end());
+}
+
+template <typename T>
+inline internal::AnyOfArrayMatcher<T> AnyOfArray(
+ ::std::initializer_list<T> xs) {
+ return AnyOfArray(xs.begin(), xs.end());
+}
+
+template <typename T>
+inline internal::AllOfArrayMatcher<T> AllOfArray(
+ ::std::initializer_list<T> xs) {
+ return AllOfArray(xs.begin(), xs.end());
+}
+
+// Args<N1, N2, ..., Nk>(a_matcher) matches a tuple if the selected
+// fields of it matches a_matcher. C++ doesn't support default
+// arguments for function templates, so we have to overload it.
+template <size_t... k, typename InnerMatcher>
+internal::ArgsMatcher<typename std::decay<InnerMatcher>::type, k...> Args(
+ InnerMatcher&& matcher) {
+ return internal::ArgsMatcher<typename std::decay<InnerMatcher>::type, k...>(
+ std::forward<InnerMatcher>(matcher));
+}
// AllArgs(m) is a synonym of m. This is useful in
//
@@ -4381,10 +4514,43 @@ inline internal::AnyOfMatcher<Args...> AnyOf(const Args&... matchers) {
template <typename InnerMatcher>
inline InnerMatcher AllArgs(const InnerMatcher& matcher) { return matcher; }
+// Returns a matcher that matches the value of an optional<> type variable.
+// The matcher implementation only uses '!arg' and requires that the optional<>
+// type has a 'value_type' member type and that '*arg' is of type 'value_type'
+// and is printable using 'PrintToString'. It is compatible with
+// std::optional/std::experimental::optional.
+// Note that to compare an optional type variable against nullopt you should
+// use Eq(nullopt) and not Optional(Eq(nullopt)). The latter implies that the
+// optional value contains an optional itself.
+template <typename ValueMatcher>
+inline internal::OptionalMatcher<ValueMatcher> Optional(
+ const ValueMatcher& value_matcher) {
+ return internal::OptionalMatcher<ValueMatcher>(value_matcher);
+}
+
+// Returns a matcher that matches the value of a absl::any type variable.
+template <typename T>
+PolymorphicMatcher<internal::any_cast_matcher::AnyCastMatcher<T> > AnyWith(
+ const Matcher<const T&>& matcher) {
+ return MakePolymorphicMatcher(
+ internal::any_cast_matcher::AnyCastMatcher<T>(matcher));
+}
+
+// Returns a matcher that matches the value of a variant<> type variable.
+// The matcher implementation uses ADL to find the holds_alternative and get
+// functions.
+// It is compatible with std::variant.
+template <typename T>
+PolymorphicMatcher<internal::variant_matcher::VariantMatcher<T> > VariantWith(
+ const Matcher<const T&>& matcher) {
+ return MakePolymorphicMatcher(
+ internal::variant_matcher::VariantMatcher<T>(matcher));
+}
+
// These macros allow using matchers to check values in Google Test
// tests. ASSERT_THAT(value, matcher) and EXPECT_THAT(value, matcher)
-// succeed iff the value matches the matcher. If the assertion fails,
-// the value and the description of the matcher will be printed.
+// succeed if and only if the value matches the matcher. If the assertion
+// fails, the value and the description of the matcher will be printed.
#define ASSERT_THAT(value, matcher) ASSERT_PRED_FORMAT1(\
::testing::internal::MakePredicateFormatterFromMatcher(matcher), value)
#define EXPECT_THAT(value, matcher) EXPECT_PRED_FORMAT1(\
@@ -4392,8 +4558,11 @@ inline InnerMatcher AllArgs(const InnerMatcher& matcher) { return matcher; }
} // namespace testing
+GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 5046
+
// Include any custom callback matchers added by the local installation.
// We must include this header at the end to make sure it can use the
// declarations from this file.
#include "gmock/internal/custom/gmock-matchers.h"
+
#endif // GMOCK_INCLUDE_GMOCK_GMOCK_MATCHERS_H_
diff --git a/extern/gmock/include/gmock/gmock-more-actions.h b/extern/gmock/include/gmock/gmock-more-actions.h
index 3d387b6b7d7..d42484aef2b 100644
--- a/extern/gmock/include/gmock/gmock-more-actions.h
+++ b/extern/gmock/include/gmock/gmock-more-actions.h
@@ -26,70 +26,25 @@
// 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.
-//
-// Author: wan@google.com (Zhanyong Wan)
+
// Google Mock - a framework for writing C++ mock classes.
//
// This file implements some actions that depend on gmock-generated-actions.h.
+// GOOGLETEST_CM0002 DO NOT DELETE
+
#ifndef GMOCK_INCLUDE_GMOCK_GMOCK_MORE_ACTIONS_H_
#define GMOCK_INCLUDE_GMOCK_GMOCK_MORE_ACTIONS_H_
#include <algorithm>
+#include <type_traits>
#include "gmock/gmock-generated-actions.h"
namespace testing {
namespace internal {
-// Implements the Invoke(f) action. The template argument
-// FunctionImpl is the implementation type of f, which can be either a
-// function pointer or a functor. Invoke(f) can be used as an
-// Action<F> as long as f's type is compatible with F (i.e. f can be
-// assigned to a tr1::function<F>).
-template <typename FunctionImpl>
-class InvokeAction {
- public:
- // The c'tor makes a copy of function_impl (either a function
- // pointer or a functor).
- explicit InvokeAction(FunctionImpl function_impl)
- : function_impl_(function_impl) {}
-
- template <typename Result, typename ArgumentTuple>
- Result Perform(const ArgumentTuple& args) {
- return InvokeHelper<Result, ArgumentTuple>::Invoke(function_impl_, args);
- }
-
- private:
- FunctionImpl function_impl_;
-
- GTEST_DISALLOW_ASSIGN_(InvokeAction);
-};
-
-// Implements the Invoke(object_ptr, &Class::Method) action.
-template <class Class, typename MethodPtr>
-class InvokeMethodAction {
- public:
- InvokeMethodAction(Class* obj_ptr, MethodPtr method_ptr)
- : method_ptr_(method_ptr), obj_ptr_(obj_ptr) {}
-
- template <typename Result, typename ArgumentTuple>
- Result Perform(const ArgumentTuple& args) const {
- return InvokeHelper<Result, ArgumentTuple>::InvokeMethod(
- obj_ptr_, method_ptr_, args);
- }
-
- private:
- // The order of these members matters. Reversing the order can trigger
- // warning C4121 in MSVC (see
- // http://computer-programming-forum.com/7-vc.net/6fbc30265f860ad1.htm ).
- const MethodPtr method_ptr_;
- Class* const obj_ptr_;
-
- GTEST_DISALLOW_ASSIGN_(InvokeMethodAction);
-};
-
// An internal replacement for std::copy which mimics its behavior. This is
// necessary because Visual Studio deprecates ::std::copy, issuing warning 4996.
// However Visual Studio 2010 and later do not honor #pragmas which disable that
@@ -108,45 +63,6 @@ inline OutputIterator CopyElements(InputIterator first,
// Various overloads for Invoke().
-// Creates an action that invokes 'function_impl' with the mock
-// function's arguments.
-template <typename FunctionImpl>
-PolymorphicAction<internal::InvokeAction<FunctionImpl> > Invoke(
- FunctionImpl function_impl) {
- return MakePolymorphicAction(
- internal::InvokeAction<FunctionImpl>(function_impl));
-}
-
-// Creates an action that invokes the given method on the given object
-// with the mock function's arguments.
-template <class Class, typename MethodPtr>
-PolymorphicAction<internal::InvokeMethodAction<Class, MethodPtr> > Invoke(
- Class* obj_ptr, MethodPtr method_ptr) {
- return MakePolymorphicAction(
- internal::InvokeMethodAction<Class, MethodPtr>(obj_ptr, method_ptr));
-}
-
-// WithoutArgs(inner_action) can be used in a mock function with a
-// non-empty argument list to perform inner_action, which takes no
-// argument. In other words, it adapts an action accepting no
-// argument to one that accepts (and ignores) arguments.
-template <typename InnerAction>
-inline internal::WithArgsAction<InnerAction>
-WithoutArgs(const InnerAction& action) {
- return internal::WithArgsAction<InnerAction>(action);
-}
-
-// WithArg<k>(an_action) creates an action that passes the k-th
-// (0-based) argument of the mock function to an_action and performs
-// it. It adapts an action accepting one argument to one that accepts
-// multiple arguments. For convenience, we also provide
-// WithArgs<k>(an_action) (defined below) as a synonym.
-template <int k, typename InnerAction>
-inline internal::WithArgsAction<InnerAction, k>
-WithArg(const InnerAction& action) {
- return internal::WithArgsAction<InnerAction, k>(action);
-}
-
// The ACTION*() macros trigger warning C4100 (unreferenced formal
// parameter) in MSVC with -W4. Unfortunately they cannot be fixed in
// the macro definition, as the warnings are generated when the macro
@@ -161,7 +77,7 @@ WithArg(const InnerAction& action) {
ACTION_TEMPLATE(ReturnArg,
HAS_1_TEMPLATE_PARAMS(int, k),
AND_0_VALUE_PARAMS()) {
- return ::testing::get<k>(args);
+ return ::std::get<k>(args);
}
// Action SaveArg<k>(pointer) saves the k-th (0-based) argument of the
@@ -169,7 +85,7 @@ ACTION_TEMPLATE(ReturnArg,
ACTION_TEMPLATE(SaveArg,
HAS_1_TEMPLATE_PARAMS(int, k),
AND_1_VALUE_PARAMS(pointer)) {
- *pointer = ::testing::get<k>(args);
+ *pointer = ::std::get<k>(args);
}
// Action SaveArgPointee<k>(pointer) saves the value pointed to
@@ -177,7 +93,7 @@ ACTION_TEMPLATE(SaveArg,
ACTION_TEMPLATE(SaveArgPointee,
HAS_1_TEMPLATE_PARAMS(int, k),
AND_1_VALUE_PARAMS(pointer)) {
- *pointer = *::testing::get<k>(args);
+ *pointer = *::std::get<k>(args);
}
// Action SetArgReferee<k>(value) assigns 'value' to the variable
@@ -185,13 +101,13 @@ ACTION_TEMPLATE(SaveArgPointee,
ACTION_TEMPLATE(SetArgReferee,
HAS_1_TEMPLATE_PARAMS(int, k),
AND_1_VALUE_PARAMS(value)) {
- typedef typename ::testing::tuple_element<k, args_type>::type argk_type;
+ typedef typename ::std::tuple_element<k, args_type>::type argk_type;
// Ensures that argument #k is a reference. If you get a compiler
// error on the next line, you are using SetArgReferee<k>(value) in
// a mock function whose k-th (0-based) argument is not a reference.
- GTEST_COMPILE_ASSERT_(internal::is_reference<argk_type>::value,
+ GTEST_COMPILE_ASSERT_(std::is_reference<argk_type>::value,
SetArgReferee_must_be_used_with_a_reference_argument);
- ::testing::get<k>(args) = value;
+ ::std::get<k>(args) = value;
}
// Action SetArrayArgument<k>(first, last) copies the elements in
@@ -204,9 +120,9 @@ ACTION_TEMPLATE(SetArrayArgument,
AND_2_VALUE_PARAMS(first, last)) {
// Visual Studio deprecates ::std::copy, so we use our own copy in that case.
#ifdef _MSC_VER
- internal::CopyElements(first, last, ::testing::get<k>(args));
+ internal::CopyElements(first, last, ::std::get<k>(args));
#else
- ::std::copy(first, last, ::testing::get<k>(args));
+ ::std::copy(first, last, ::std::get<k>(args));
#endif
}
@@ -215,7 +131,7 @@ ACTION_TEMPLATE(SetArrayArgument,
ACTION_TEMPLATE(DeleteArg,
HAS_1_TEMPLATE_PARAMS(int, k),
AND_0_VALUE_PARAMS()) {
- delete ::testing::get<k>(args);
+ delete ::std::get<k>(args);
}
// This action returns the value pointed to by 'pointer'.
diff --git a/extern/gmock/include/gmock/gmock-more-matchers.h b/extern/gmock/include/gmock/gmock-more-matchers.h
index 3db899f4297..1c9a399a341 100644
--- a/extern/gmock/include/gmock/gmock-more-matchers.h
+++ b/extern/gmock/include/gmock/gmock-more-matchers.h
@@ -26,8 +26,7 @@
// 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.
-//
-// Author: marcus.boerger@google.com (Marcus Boerger)
+
// Google Mock - a framework for writing C++ mock classes.
//
@@ -36,13 +35,27 @@
// Note that tests are implemented in gmock-matchers_test.cc rather than
// gmock-more-matchers-test.cc.
-#ifndef GMOCK_GMOCK_MORE_MATCHERS_H_
-#define GMOCK_GMOCK_MORE_MATCHERS_H_
+// GOOGLETEST_CM0002 DO NOT DELETE
+
+#ifndef GMOCK_INCLUDE_GMOCK_MORE_MATCHERS_H_
+#define GMOCK_INCLUDE_GMOCK_MORE_MATCHERS_H_
#include "gmock/gmock-generated-matchers.h"
namespace testing {
+// Silence C4100 (unreferenced formal
+// parameter) for MSVC
+#ifdef _MSC_VER
+# pragma warning(push)
+# pragma warning(disable:4100)
+#if (_MSC_VER == 1900)
+// and silence C4800 (C4800: 'int *const ': forcing value
+// to bool 'true' or 'false') for MSVC 14
+# pragma warning(disable:4800)
+ #endif
+#endif
+
// Defines a matcher that matches an empty container. The container must
// support both size() and empty(), which all STL-like containers provide.
MATCHER(IsEmpty, negation ? "isn't empty" : "is empty") {
@@ -53,6 +66,27 @@ MATCHER(IsEmpty, negation ? "isn't empty" : "is empty") {
return false;
}
+// Define a matcher that matches a value that evaluates in boolean
+// context to true. Useful for types that define "explicit operator
+// bool" operators and so can't be compared for equality with true
+// and false.
+MATCHER(IsTrue, negation ? "is false" : "is true") {
+ return static_cast<bool>(arg);
+}
+
+// Define a matcher that matches a value that evaluates in boolean
+// context to false. Useful for types that define "explicit operator
+// bool" operators and so can't be compared for equality with true
+// and false.
+MATCHER(IsFalse, negation ? "is true" : "is false") {
+ return !static_cast<bool>(arg);
+}
+
+#ifdef _MSC_VER
+# pragma warning(pop)
+#endif
+
+
} // namespace testing
-#endif // GMOCK_GMOCK_MORE_MATCHERS_H_
+#endif // GMOCK_INCLUDE_GMOCK_MORE_MATCHERS_H_
diff --git a/extern/gmock/include/gmock/gmock-nice-strict.h b/extern/gmock/include/gmock/gmock-nice-strict.h
new file mode 100644
index 00000000000..5495a9805b5
--- /dev/null
+++ b/extern/gmock/include/gmock/gmock-nice-strict.h
@@ -0,0 +1,215 @@
+// Copyright 2008, 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.
+
+
+// Implements class templates NiceMock, NaggyMock, and StrictMock.
+//
+// Given a mock class MockFoo that is created using Google Mock,
+// NiceMock<MockFoo> is a subclass of MockFoo that allows
+// uninteresting calls (i.e. calls to mock methods that have no
+// EXPECT_CALL specs), NaggyMock<MockFoo> is a subclass of MockFoo
+// that prints a warning when an uninteresting call occurs, and
+// StrictMock<MockFoo> is a subclass of MockFoo that treats all
+// uninteresting calls as errors.
+//
+// Currently a mock is naggy by default, so MockFoo and
+// NaggyMock<MockFoo> behave like the same. However, we will soon
+// switch the default behavior of mocks to be nice, as that in general
+// leads to more maintainable tests. When that happens, MockFoo will
+// stop behaving like NaggyMock<MockFoo> and start behaving like
+// NiceMock<MockFoo>.
+//
+// NiceMock, NaggyMock, and StrictMock "inherit" the constructors of
+// their respective base class. Therefore you can write
+// NiceMock<MockFoo>(5, "a") to construct a nice mock where MockFoo
+// has a constructor that accepts (int, const char*), for example.
+//
+// A known limitation is that NiceMock<MockFoo>, NaggyMock<MockFoo>,
+// and StrictMock<MockFoo> only works for mock methods defined using
+// the MOCK_METHOD* family of macros DIRECTLY in the MockFoo class.
+// If a mock method is defined in a base class of MockFoo, the "nice"
+// or "strict" modifier may not affect it, depending on the compiler.
+// In particular, nesting NiceMock, NaggyMock, and StrictMock is NOT
+// supported.
+
+// GOOGLETEST_CM0002 DO NOT DELETE
+
+#ifndef GMOCK_INCLUDE_GMOCK_GMOCK_NICE_STRICT_H_
+#define GMOCK_INCLUDE_GMOCK_GMOCK_NICE_STRICT_H_
+
+#include "gmock/gmock-spec-builders.h"
+#include "gmock/internal/gmock-port.h"
+
+namespace testing {
+
+template <class MockClass>
+class NiceMock : public MockClass {
+ public:
+ NiceMock() : MockClass() {
+ ::testing::Mock::AllowUninterestingCalls(
+ internal::ImplicitCast_<MockClass*>(this));
+ }
+
+ // Ideally, we would inherit base class's constructors through a using
+ // declaration, which would preserve their visibility. However, many existing
+ // tests rely on the fact that current implementation reexports protected
+ // constructors as public. These tests would need to be cleaned up first.
+
+ // Single argument constructor is special-cased so that it can be
+ // made explicit.
+ template <typename A>
+ explicit NiceMock(A&& arg) : MockClass(std::forward<A>(arg)) {
+ ::testing::Mock::AllowUninterestingCalls(
+ internal::ImplicitCast_<MockClass*>(this));
+ }
+
+ template <typename A1, typename A2, typename... An>
+ NiceMock(A1&& arg1, A2&& arg2, An&&... args)
+ : MockClass(std::forward<A1>(arg1), std::forward<A2>(arg2),
+ std::forward<An>(args)...) {
+ ::testing::Mock::AllowUninterestingCalls(
+ internal::ImplicitCast_<MockClass*>(this));
+ }
+
+ ~NiceMock() { // NOLINT
+ ::testing::Mock::UnregisterCallReaction(
+ internal::ImplicitCast_<MockClass*>(this));
+ }
+
+ private:
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(NiceMock);
+};
+
+template <class MockClass>
+class NaggyMock : public MockClass {
+ public:
+ NaggyMock() : MockClass() {
+ ::testing::Mock::WarnUninterestingCalls(
+ internal::ImplicitCast_<MockClass*>(this));
+ }
+
+ // Ideally, we would inherit base class's constructors through a using
+ // declaration, which would preserve their visibility. However, many existing
+ // tests rely on the fact that current implementation reexports protected
+ // constructors as public. These tests would need to be cleaned up first.
+
+ // Single argument constructor is special-cased so that it can be
+ // made explicit.
+ template <typename A>
+ explicit NaggyMock(A&& arg) : MockClass(std::forward<A>(arg)) {
+ ::testing::Mock::WarnUninterestingCalls(
+ internal::ImplicitCast_<MockClass*>(this));
+ }
+
+ template <typename A1, typename A2, typename... An>
+ NaggyMock(A1&& arg1, A2&& arg2, An&&... args)
+ : MockClass(std::forward<A1>(arg1), std::forward<A2>(arg2),
+ std::forward<An>(args)...) {
+ ::testing::Mock::WarnUninterestingCalls(
+ internal::ImplicitCast_<MockClass*>(this));
+ }
+
+ ~NaggyMock() { // NOLINT
+ ::testing::Mock::UnregisterCallReaction(
+ internal::ImplicitCast_<MockClass*>(this));
+ }
+
+ private:
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(NaggyMock);
+};
+
+template <class MockClass>
+class StrictMock : public MockClass {
+ public:
+ StrictMock() : MockClass() {
+ ::testing::Mock::FailUninterestingCalls(
+ internal::ImplicitCast_<MockClass*>(this));
+ }
+
+ // Ideally, we would inherit base class's constructors through a using
+ // declaration, which would preserve their visibility. However, many existing
+ // tests rely on the fact that current implementation reexports protected
+ // constructors as public. These tests would need to be cleaned up first.
+
+ // Single argument constructor is special-cased so that it can be
+ // made explicit.
+ template <typename A>
+ explicit StrictMock(A&& arg) : MockClass(std::forward<A>(arg)) {
+ ::testing::Mock::FailUninterestingCalls(
+ internal::ImplicitCast_<MockClass*>(this));
+ }
+
+ template <typename A1, typename A2, typename... An>
+ StrictMock(A1&& arg1, A2&& arg2, An&&... args)
+ : MockClass(std::forward<A1>(arg1), std::forward<A2>(arg2),
+ std::forward<An>(args)...) {
+ ::testing::Mock::FailUninterestingCalls(
+ internal::ImplicitCast_<MockClass*>(this));
+ }
+
+ ~StrictMock() { // NOLINT
+ ::testing::Mock::UnregisterCallReaction(
+ internal::ImplicitCast_<MockClass*>(this));
+ }
+
+ private:
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(StrictMock);
+};
+
+// The following specializations catch some (relatively more common)
+// user errors of nesting nice and strict mocks. They do NOT catch
+// all possible errors.
+
+// These specializations are declared but not defined, as NiceMock,
+// NaggyMock, and StrictMock cannot be nested.
+
+template <typename MockClass>
+class NiceMock<NiceMock<MockClass> >;
+template <typename MockClass>
+class NiceMock<NaggyMock<MockClass> >;
+template <typename MockClass>
+class NiceMock<StrictMock<MockClass> >;
+
+template <typename MockClass>
+class NaggyMock<NiceMock<MockClass> >;
+template <typename MockClass>
+class NaggyMock<NaggyMock<MockClass> >;
+template <typename MockClass>
+class NaggyMock<StrictMock<MockClass> >;
+
+template <typename MockClass>
+class StrictMock<NiceMock<MockClass> >;
+template <typename MockClass>
+class StrictMock<NaggyMock<MockClass> >;
+template <typename MockClass>
+class StrictMock<StrictMock<MockClass> >;
+
+} // namespace testing
+
+#endif // GMOCK_INCLUDE_GMOCK_GMOCK_NICE_STRICT_H_
diff --git a/extern/gmock/include/gmock/gmock-spec-builders.h b/extern/gmock/include/gmock/gmock-spec-builders.h
index fed7de66bc4..80c13b55492 100644
--- a/extern/gmock/include/gmock/gmock-spec-builders.h
+++ b/extern/gmock/include/gmock/gmock-spec-builders.h
@@ -26,8 +26,7 @@
// 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.
-//
-// Author: wan@google.com (Zhanyong Wan)
+
// Google Mock - a framework for writing C++ mock classes.
//
@@ -57,19 +56,20 @@
// where all clauses are optional, and .InSequence()/.After()/
// .WillOnce() can appear any number of times.
+// GOOGLETEST_CM0002 DO NOT DELETE
+
#ifndef GMOCK_INCLUDE_GMOCK_GMOCK_SPEC_BUILDERS_H_
#define GMOCK_INCLUDE_GMOCK_GMOCK_SPEC_BUILDERS_H_
+#include <functional>
#include <map>
+#include <memory>
#include <set>
#include <sstream>
#include <string>
+#include <type_traits>
+#include <utility>
#include <vector>
-
-#if GTEST_HAS_EXCEPTIONS
-# include <stdexcept> // NOLINT
-#endif
-
#include "gmock/gmock-actions.h"
#include "gmock/gmock-cardinalities.h"
#include "gmock/gmock-matchers.h"
@@ -77,6 +77,13 @@
#include "gmock/internal/gmock-port.h"
#include "gtest/gtest.h"
+#if GTEST_HAS_EXCEPTIONS
+# include <stdexcept> // NOLINT
+#endif
+
+GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \
+/* class A needs to have dll-interface to be used by clients of class B */)
+
namespace testing {
// An abstract handle of an expectation.
@@ -101,9 +108,6 @@ template <typename F> class TypedExpectation;
// Helper class for testing the Expectation class template.
class ExpectationTester;
-// Base class for function mockers.
-template <typename F> class FunctionMockerBase;
-
// Protects the mock object registry (in class Mock), all function
// mockers, and all expectations.
//
@@ -120,9 +124,9 @@ GTEST_API_ GTEST_DECLARE_STATIC_MUTEX_(g_gmock_mutex);
// Untyped base class for ActionResultHolder<R>.
class UntypedActionResultHolderBase;
-// Abstract base class of FunctionMockerBase. This is the
+// Abstract base class of FunctionMocker. This is the
// type-agnostic part of the function mocker interface. Its pure
-// virtual methods are implemented by FunctionMockerBase.
+// virtual methods are implemented by FunctionMocker.
class GTEST_API_ UntypedFunctionMockerBase {
public:
UntypedFunctionMockerBase();
@@ -148,15 +152,13 @@ class GTEST_API_ UntypedFunctionMockerBase {
// action fails.
// L = *
virtual UntypedActionResultHolderBase* UntypedPerformDefaultAction(
- const void* untyped_args,
- const string& call_description) const = 0;
+ void* untyped_args, const std::string& call_description) const = 0;
// Performs the given action with the given arguments and returns
// the action's result.
// L = *
virtual UntypedActionResultHolderBase* UntypedPerformAction(
- const void* untyped_action,
- const void* untyped_args) const = 0;
+ const void* untyped_action, void* untyped_args) const = 0;
// Writes a message that the call is uninteresting (i.e. neither
// explicitly expected nor explicitly unexpected) to the given
@@ -186,7 +188,6 @@ class GTEST_API_ UntypedFunctionMockerBase {
// this information in the global mock registry. Will be called
// whenever an EXPECT_CALL() or ON_CALL() is executed on this mock
// method.
- // TODO(wan@google.com): rename to SetAndRegisterOwner().
void RegisterOwner(const void* mock_obj)
GTEST_LOCK_EXCLUDED_(g_gmock_mutex);
@@ -211,15 +212,13 @@ class GTEST_API_ UntypedFunctionMockerBase {
// arguments. This function can be safely called from multiple
// threads concurrently. The caller is responsible for deleting the
// result.
- UntypedActionResultHolderBase* UntypedInvokeWith(
- const void* untyped_args)
- GTEST_LOCK_EXCLUDED_(g_gmock_mutex);
+ UntypedActionResultHolderBase* UntypedInvokeWith(void* untyped_args)
+ GTEST_LOCK_EXCLUDED_(g_gmock_mutex);
protected:
typedef std::vector<const void*> UntypedOnCallSpecs;
- typedef std::vector<internal::linked_ptr<ExpectationBase> >
- UntypedExpectations;
+ using UntypedExpectations = std::vector<std::shared_ptr<ExpectationBase>>;
// Returns an Expectation object that references and co-owns exp,
// which must be an expectation on this mock function.
@@ -238,6 +237,14 @@ class GTEST_API_ UntypedFunctionMockerBase {
UntypedOnCallSpecs untyped_on_call_specs_;
// All expectations for this function mocker.
+ //
+ // It's undefined behavior to interleave expectations (EXPECT_CALLs
+ // or ON_CALLs) and mock function calls. Also, the order of
+ // expectations is important. Therefore it's a logic race condition
+ // to read/write untyped_expectations_ concurrently. In order for
+ // tools like tsan to catch concurrent read/write accesses to
+ // untyped_expectations, we deliberately leave accesses to it
+ // unprotected.
UntypedExpectations untyped_expectations_;
}; // class UntypedFunctionMockerBase
@@ -263,12 +270,14 @@ class UntypedOnCallSpecBase {
};
// Asserts that the ON_CALL() statement has a certain property.
- void AssertSpecProperty(bool property, const string& failure_message) const {
+ void AssertSpecProperty(bool property,
+ const std::string& failure_message) const {
Assert(property, file_, line_, failure_message);
}
// Expects that the ON_CALL() statement has a certain property.
- void ExpectSpecProperty(bool property, const string& failure_message) const {
+ void ExpectSpecProperty(bool property,
+ const std::string& failure_message) const {
Expect(property, file_, line_, failure_message);
}
@@ -294,11 +303,9 @@ class OnCallSpec : public UntypedOnCallSpecBase {
: UntypedOnCallSpecBase(a_file, a_line),
matchers_(matchers),
// By default, extra_matcher_ should match anything. However,
- // we cannot initialize it with _ as that triggers a compiler
- // bug in Symbian's C++ compiler (cannot decide between two
- // overloaded constructors of Matcher<const ArgumentTuple&>).
- extra_matcher_(A<const ArgumentTuple&>()) {
- }
+ // we cannot initialize it with _ as that causes ambiguity between
+ // Matcher's copy and move constructor for some argument types.
+ extra_matcher_(A<const ArgumentTuple&>()) {}
// Implements the .With() clause.
OnCallSpec& With(const Matcher<const ArgumentTuple&>& m) {
@@ -325,7 +332,7 @@ class OnCallSpec : public UntypedOnCallSpecBase {
return *this;
}
- // Returns true iff the given arguments match the matchers.
+ // Returns true if and only if the given arguments match the matchers.
bool Matches(const ArgumentTuple& args) const {
return TupleMatches(matchers_, args) && extra_matcher_.Matches(args);
}
@@ -362,7 +369,6 @@ enum CallReaction {
kAllow,
kWarn,
kFail,
- kDefault = kWarn // By default, warn about uninteresting calls.
};
} // namespace internal
@@ -384,18 +390,28 @@ class GTEST_API_ Mock {
GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex);
// Verifies all expectations on the given mock object and clears its
- // default actions and expectations. Returns true iff the
+ // default actions and expectations. Returns true if and only if the
// verification was successful.
static bool VerifyAndClear(void* mock_obj)
GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex);
+ // Returns whether the mock was created as a naggy mock (default)
+ static bool IsNaggy(void* mock_obj)
+ GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex);
+ // Returns whether the mock was created as a nice mock
+ static bool IsNice(void* mock_obj)
+ GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex);
+ // Returns whether the mock was created as a strict mock
+ static bool IsStrict(void* mock_obj)
+ GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex);
+
private:
friend class internal::UntypedFunctionMockerBase;
// Needed for a function mocker to register itself (so that we know
// how to clear a mock object).
template <typename F>
- friend class internal::FunctionMockerBase;
+ friend class internal::FunctionMocker;
template <typename M>
friend class NiceMock;
@@ -458,7 +474,7 @@ class GTEST_API_ Mock {
// Unregisters a mock method; removes the owning mock object from
// the registry when the last mock method associated with it has
// been unregistered. This is called only in the destructor of
- // FunctionMockerBase.
+ // FunctionMocker.
static void UnregisterLocked(internal::UntypedFunctionMockerBase* mocker)
GTEST_EXCLUSIVE_LOCK_REQUIRED_(internal::g_gmock_mutex);
}; // class Mock
@@ -478,12 +494,7 @@ class GTEST_API_ Mock {
// - Constness is shallow: a const Expectation object itself cannot
// be modified, but the mutable methods of the ExpectationBase
// object it references can be called via expectation_base().
-// - The constructors and destructor are defined out-of-line because
-// the Symbian WINSCW compiler wants to otherwise instantiate them
-// when it sees this class definition, at which point it doesn't have
-// ExpectationBase available yet, leading to incorrect destruction
-// in the linked_ptr (or compilation errors if using a checking
-// linked_ptr).
+
class GTEST_API_ Expectation {
public:
// Constructs a null object that doesn't reference any expectation.
@@ -505,7 +516,8 @@ class GTEST_API_ Expectation {
// The compiler-generated copy ctor and operator= work exactly as
// intended, so we don't need to define our own.
- // Returns true iff rhs references the same expectation as this object does.
+ // Returns true if and only if rhs references the same expectation as this
+ // object does.
bool operator==(const Expectation& rhs) const {
return expectation_base_ == rhs.expectation_base_;
}
@@ -519,7 +531,7 @@ class GTEST_API_ Expectation {
friend class ::testing::internal::UntypedFunctionMockerBase;
template <typename F>
- friend class ::testing::internal::FunctionMockerBase;
+ friend class ::testing::internal::FunctionMocker;
template <typename F>
friend class ::testing::internal::TypedExpectation;
@@ -535,16 +547,15 @@ class GTEST_API_ Expectation {
typedef ::std::set<Expectation, Less> Set;
Expectation(
- const internal::linked_ptr<internal::ExpectationBase>& expectation_base);
+ const std::shared_ptr<internal::ExpectationBase>& expectation_base);
// Returns the expectation this object references.
- const internal::linked_ptr<internal::ExpectationBase>&
- expectation_base() const {
+ const std::shared_ptr<internal::ExpectationBase>& expectation_base() const {
return expectation_base_;
}
- // A linked_ptr that co-owns the expectation this handle references.
- internal::linked_ptr<internal::ExpectationBase> expectation_base_;
+ // A shared_ptr that co-owns the expectation this handle references.
+ std::shared_ptr<internal::ExpectationBase> expectation_base_;
};
// A set of expectation handles. Useful in the .After() clause of
@@ -588,8 +599,8 @@ class ExpectationSet {
// The compiler-generator ctor and operator= works exactly as
// intended, so we don't need to define our own.
- // Returns true iff rhs contains the same set of Expectation objects
- // as this does.
+ // Returns true if and only if rhs contains the same set of Expectation
+ // objects as this does.
bool operator==(const ExpectationSet& rhs) const {
return expectations_ == rhs.expectations_;
}
@@ -626,11 +637,8 @@ class GTEST_API_ Sequence {
void AddExpectation(const Expectation& expectation) const;
private:
- // The last expectation in this sequence. We use a linked_ptr here
- // because Sequence objects are copyable and we want the copies to
- // be aliases. The linked_ptr allows the copies to co-own and share
- // the same Expectation object.
- internal::linked_ptr<Expectation> last_expectation_;
+ // The last expectation in this sequence.
+ std::shared_ptr<Expectation> last_expectation_;
}; // class Sequence
// An object of this type causes all EXPECT_CALL() statements
@@ -690,7 +698,7 @@ GTEST_API_ extern ThreadLocal<Sequence*> g_gmock_implicit_sequence;
class GTEST_API_ ExpectationBase {
public:
// source_text is the EXPECT_CALL(...) source that created this Expectation.
- ExpectationBase(const char* file, int line, const string& source_text);
+ ExpectationBase(const char* file, int line, const std::string& source_text);
virtual ~ExpectationBase();
@@ -738,12 +746,14 @@ class GTEST_API_ ExpectationBase {
virtual Expectation GetHandle() = 0;
// Asserts that the EXPECT_CALL() statement has the given property.
- void AssertSpecProperty(bool property, const string& failure_message) const {
+ void AssertSpecProperty(bool property,
+ const std::string& failure_message) const {
Assert(property, file_, line_, failure_message);
}
// Expects that the EXPECT_CALL() statement has the given property.
- void ExpectSpecProperty(bool property, const string& failure_message) const {
+ void ExpectSpecProperty(bool property,
+ const std::string& failure_message) const {
Expect(property, file_, line_, failure_message);
}
@@ -751,8 +761,8 @@ class GTEST_API_ ExpectationBase {
// by the subclasses to implement the .Times() clause.
void SpecifyCardinality(const Cardinality& cardinality);
- // Returns true iff the user specified the cardinality explicitly
- // using a .Times().
+ // Returns true if and only if the user specified the cardinality
+ // explicitly using a .Times().
bool cardinality_specified() const { return cardinality_specified_; }
// Sets the cardinality of this expectation spec.
@@ -768,7 +778,7 @@ class GTEST_API_ ExpectationBase {
void RetireAllPreRequisites()
GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex);
- // Returns true iff this expectation is retired.
+ // Returns true if and only if this expectation is retired.
bool is_retired() const
GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex) {
g_gmock_mutex.AssertHeld();
@@ -782,28 +792,29 @@ class GTEST_API_ ExpectationBase {
retired_ = true;
}
- // Returns true iff this expectation is satisfied.
+ // Returns true if and only if this expectation is satisfied.
bool IsSatisfied() const
GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex) {
g_gmock_mutex.AssertHeld();
return cardinality().IsSatisfiedByCallCount(call_count_);
}
- // Returns true iff this expectation is saturated.
+ // Returns true if and only if this expectation is saturated.
bool IsSaturated() const
GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex) {
g_gmock_mutex.AssertHeld();
return cardinality().IsSaturatedByCallCount(call_count_);
}
- // Returns true iff this expectation is over-saturated.
+ // Returns true if and only if this expectation is over-saturated.
bool IsOverSaturated() const
GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex) {
g_gmock_mutex.AssertHeld();
return cardinality().IsOverSaturatedByCallCount(call_count_);
}
- // Returns true iff all pre-requisites of this expectation are satisfied.
+ // Returns true if and only if all pre-requisites of this expectation are
+ // satisfied.
bool AllPrerequisitesAreSatisfied() const
GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex);
@@ -845,13 +856,13 @@ class GTEST_API_ ExpectationBase {
// an EXPECT_CALL() statement finishes.
const char* file_; // The file that contains the expectation.
int line_; // The line number of the expectation.
- const string source_text_; // The EXPECT_CALL(...) source text.
- // True iff the cardinality is specified explicitly.
+ const std::string source_text_; // The EXPECT_CALL(...) source text.
+ // True if and only if the cardinality is specified explicitly.
bool cardinality_specified_;
Cardinality cardinality_; // The cardinality of the expectation.
// The immediate pre-requisites (i.e. expectations that must be
// satisfied before this expectation can be matched) of this
- // expectation. We use linked_ptr in the set because we want an
+ // expectation. We use std::shared_ptr in the set because we want an
// Expectation object to be co-owned by its FunctionMocker and its
// successors. This allows multiple mock objects to be deleted at
// different times.
@@ -860,7 +871,7 @@ class GTEST_API_ ExpectationBase {
// This group of fields are the current state of the expectation,
// and can change as the mock function is called.
int call_count_; // How many times this expectation has been invoked.
- bool retired_; // True iff this expectation has retired.
+ bool retired_; // True if and only if this expectation has retired.
UntypedActions untyped_actions_;
bool extra_matcher_specified_;
bool repeated_action_specified_; // True if a WillRepeatedly() was specified.
@@ -880,20 +891,19 @@ class TypedExpectation : public ExpectationBase {
typedef typename Function<F>::ArgumentMatcherTuple ArgumentMatcherTuple;
typedef typename Function<F>::Result Result;
- TypedExpectation(FunctionMockerBase<F>* owner,
- const char* a_file, int a_line, const string& a_source_text,
+ TypedExpectation(FunctionMocker<F>* owner, const char* a_file, int a_line,
+ const std::string& a_source_text,
const ArgumentMatcherTuple& m)
: ExpectationBase(a_file, a_line, a_source_text),
owner_(owner),
matchers_(m),
// By default, extra_matcher_ should match anything. However,
- // we cannot initialize it with _ as that triggers a compiler
- // bug in Symbian's C++ compiler (cannot decide between two
- // overloaded constructors of Matcher<const ArgumentTuple&>).
+ // we cannot initialize it with _ as that causes ambiguity between
+ // Matcher's copy and move constructor for some argument types.
extra_matcher_(A<const ArgumentTuple&>()),
repeated_action_(DoDefault()) {}
- virtual ~TypedExpectation() {
+ ~TypedExpectation() override {
// Check the validity of the action count if it hasn't been done
// yet (for example, if the expectation was never used).
CheckActionCountIfNotDone();
@@ -1059,7 +1069,7 @@ class TypedExpectation : public ExpectationBase {
// If this mock method has an extra matcher (i.e. .With(matcher)),
// describes it to the ostream.
- virtual void MaybeDescribeExtraMatcherTo(::std::ostream* os) {
+ void MaybeDescribeExtraMatcherTo(::std::ostream* os) override {
if (extra_matcher_specified_) {
*os << " Expected args: ";
extra_matcher_.DescribeTo(os);
@@ -1069,26 +1079,25 @@ class TypedExpectation : public ExpectationBase {
private:
template <typename Function>
- friend class FunctionMockerBase;
+ friend class FunctionMocker;
// Returns an Expectation object that references and co-owns this
// expectation.
- virtual Expectation GetHandle() {
- return owner_->GetHandleOf(this);
- }
+ Expectation GetHandle() override { return owner_->GetHandleOf(this); }
// The following methods will be called only after the EXPECT_CALL()
// statement finishes and when the current thread holds
// g_gmock_mutex.
- // Returns true iff this expectation matches the given arguments.
+ // Returns true if and only if this expectation matches the given arguments.
bool Matches(const ArgumentTuple& args) const
GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex) {
g_gmock_mutex.AssertHeld();
return TupleMatches(matchers_, args) && extra_matcher_.Matches(args);
}
- // Returns true iff this expectation should handle the given arguments.
+ // Returns true if and only if this expectation should handle the given
+ // arguments.
bool ShouldHandleArguments(const ArgumentTuple& args) const
GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex) {
g_gmock_mutex.AssertHeld();
@@ -1148,10 +1157,9 @@ class TypedExpectation : public ExpectationBase {
}
// Returns the action that should be taken for the current invocation.
- const Action<F>& GetCurrentAction(
- const FunctionMockerBase<F>* mocker,
- const ArgumentTuple& args) const
- GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex) {
+ const Action<F>& GetCurrentAction(const FunctionMocker<F>* mocker,
+ const ArgumentTuple& args) const
+ GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex) {
g_gmock_mutex.AssertHeld();
const int count = call_count();
Assert(count >= 1, __FILE__, __LINE__,
@@ -1173,9 +1181,10 @@ class TypedExpectation : public ExpectationBase {
Log(kWarning, ss.str(), 1);
}
- return count <= action_count ?
- *static_cast<const Action<F>*>(untyped_actions_[count - 1]) :
- repeated_action();
+ return count <= action_count
+ ? *static_cast<const Action<F>*>(
+ untyped_actions_[static_cast<size_t>(count - 1)])
+ : repeated_action();
}
// Given the arguments of a mock function call, if the call will
@@ -1185,12 +1194,11 @@ class TypedExpectation : public ExpectationBase {
// Mock does it to 'why'. This method is not const as it calls
// IncrementCallCount(). A return value of NULL means the default
// action.
- const Action<F>* GetActionForArguments(
- const FunctionMockerBase<F>* mocker,
- const ArgumentTuple& args,
- ::std::ostream* what,
- ::std::ostream* why)
- GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex) {
+ const Action<F>* GetActionForArguments(const FunctionMocker<F>* mocker,
+ const ArgumentTuple& args,
+ ::std::ostream* what,
+ ::std::ostream* why)
+ GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex) {
g_gmock_mutex.AssertHeld();
if (IsSaturated()) {
// We have an excessive call.
@@ -1199,10 +1207,7 @@ class TypedExpectation : public ExpectationBase {
mocker->DescribeDefaultActionTo(args, what);
DescribeCallCountTo(why);
- // TODO(wan@google.com): allow the user to control whether
- // unexpected calls should fail immediately or continue using a
- // flag --gmock_unexpected_calls_are_fatal.
- return NULL;
+ return nullptr;
}
IncrementCallCount();
@@ -1219,7 +1224,7 @@ class TypedExpectation : public ExpectationBase {
// All the fields below won't change once the EXPECT_CALL()
// statement finishes.
- FunctionMockerBase<F>* const owner_;
+ FunctionMocker<F>* const owner_;
ArgumentMatcherTuple matchers_;
Matcher<const ArgumentTuple&> extra_matcher_;
Action<F> repeated_action_;
@@ -1240,7 +1245,7 @@ class TypedExpectation : public ExpectationBase {
// Logs a message including file and line number information.
GTEST_API_ void LogWithLocation(testing::internal::LogSeverity severity,
const char* file, int line,
- const string& message);
+ const std::string& message);
template <typename F>
class MockSpec {
@@ -1251,15 +1256,16 @@ class MockSpec {
// Constructs a MockSpec object, given the function mocker object
// that the spec is associated with.
- explicit MockSpec(internal::FunctionMockerBase<F>* function_mocker)
- : function_mocker_(function_mocker) {}
+ MockSpec(internal::FunctionMocker<F>* function_mocker,
+ const ArgumentMatcherTuple& matchers)
+ : function_mocker_(function_mocker), matchers_(matchers) {}
// Adds a new default action spec to the function mocker and returns
// the newly created spec.
internal::OnCallSpec<F>& InternalDefaultActionSetAt(
const char* file, int line, const char* obj, const char* call) {
LogWithLocation(internal::kInfo, file, line,
- string("ON_CALL(") + obj + ", " + call + ") invoked");
+ std::string("ON_CALL(") + obj + ", " + call + ") invoked");
return function_mocker_->AddNewOnCallSpec(file, line, matchers_);
}
@@ -1267,22 +1273,26 @@ class MockSpec {
// the newly created spec.
internal::TypedExpectation<F>& InternalExpectedAt(
const char* file, int line, const char* obj, const char* call) {
- const string source_text(string("EXPECT_CALL(") + obj + ", " + call + ")");
+ const std::string source_text(std::string("EXPECT_CALL(") + obj + ", " +
+ call + ")");
LogWithLocation(internal::kInfo, file, line, source_text + " invoked");
return function_mocker_->AddNewExpectation(
file, line, source_text, matchers_);
}
+ // This operator overload is used to swallow the superfluous parameter list
+ // introduced by the ON/EXPECT_CALL macros. See the macro comments for more
+ // explanation.
+ MockSpec<F>& operator()(const internal::WithoutMatchers&, void* const) {
+ return *this;
+ }
+
private:
template <typename Function>
friend class internal::FunctionMocker;
- void SetMatchers(const ArgumentMatcherTuple& matchers) {
- matchers_ = matchers;
- }
-
// The function mocker that owns this spec.
- internal::FunctionMockerBase<F>* const function_mocker_;
+ internal::FunctionMocker<F>* const function_mocker_;
// The argument matchers specified in the spec.
ArgumentMatcherTuple matchers_;
@@ -1303,18 +1313,18 @@ class ReferenceOrValueWrapper {
public:
// Constructs a wrapper from the given value/reference.
explicit ReferenceOrValueWrapper(T value)
- : value_(::testing::internal::move(value)) {
+ : value_(std::move(value)) {
}
// Unwraps and returns the underlying value/reference, exactly as
// originally passed. The behavior of calling this more than once on
// the same object is unspecified.
- T Unwrap() { return ::testing::internal::move(value_); }
+ T Unwrap() { return std::move(value_); }
// Provides nondestructive access to the underlying value/reference.
// Always returns a const reference (more precisely,
- // const RemoveReference<T>&). The behavior of calling this after
- // calling Unwrap on the same object is unspecified.
+ // const std::add_lvalue_reference<T>::type). The behavior of calling this
+ // after calling Unwrap on the same object is unspecified.
const T& Peek() const {
return value_;
}
@@ -1344,11 +1354,7 @@ class ReferenceOrValueWrapper<T&> {
// we need to temporarily disable the warning. We have to do it for
// the entire class to suppress the warning, even though it's about
// the constructor only.
-
-#ifdef _MSC_VER
-# pragma warning(push) // Saves the current warning state.
-# pragma warning(disable:4355) // Temporarily disables warning 4355.
-#endif // _MSV_VER
+GTEST_DISABLE_MSC_WARNINGS_PUSH_(4355)
// C++ treats the void type specially. For example, you cannot define
// a void-typed variable or pass a void value to a function.
@@ -1377,7 +1383,7 @@ class ActionResultHolder : public UntypedActionResultHolderBase {
}
// Prints the held value as an action's result to os.
- virtual void PrintAsActionResult(::std::ostream* os) const {
+ void PrintAsActionResult(::std::ostream* os) const override {
*os << "\n Returns: ";
// T may be a reference type, so we don't use UniversalPrint().
UniversalPrinter<T>::Print(result_.Peek(), os);
@@ -1387,27 +1393,27 @@ class ActionResultHolder : public UntypedActionResultHolderBase {
// result in a new-ed ActionResultHolder.
template <typename F>
static ActionResultHolder* PerformDefaultAction(
- const FunctionMockerBase<F>* func_mocker,
- const typename Function<F>::ArgumentTuple& args,
- const string& call_description) {
- return new ActionResultHolder(Wrapper(
- func_mocker->PerformDefaultAction(args, call_description)));
+ const FunctionMocker<F>* func_mocker,
+ typename Function<F>::ArgumentTuple&& args,
+ const std::string& call_description) {
+ return new ActionResultHolder(Wrapper(func_mocker->PerformDefaultAction(
+ std::move(args), call_description)));
}
// Performs the given action and returns the result in a new-ed
// ActionResultHolder.
template <typename F>
- static ActionResultHolder*
- PerformAction(const Action<F>& action,
- const typename Function<F>::ArgumentTuple& args) {
- return new ActionResultHolder(Wrapper(action.Perform(args)));
+ static ActionResultHolder* PerformAction(
+ const Action<F>& action, typename Function<F>::ArgumentTuple&& args) {
+ return new ActionResultHolder(
+ Wrapper(action.Perform(std::move(args))));
}
private:
typedef ReferenceOrValueWrapper<T> Wrapper;
explicit ActionResultHolder(Wrapper result)
- : result_(::testing::internal::move(result)) {
+ : result_(std::move(result)) {
}
Wrapper result_;
@@ -1421,16 +1427,16 @@ class ActionResultHolder<void> : public UntypedActionResultHolderBase {
public:
void Unwrap() { }
- virtual void PrintAsActionResult(::std::ostream* /* os */) const {}
+ void PrintAsActionResult(::std::ostream* /* os */) const override {}
// Performs the given mock function's default action and returns ownership
// of an empty ActionResultHolder*.
template <typename F>
static ActionResultHolder* PerformDefaultAction(
- const FunctionMockerBase<F>* func_mocker,
- const typename Function<F>::ArgumentTuple& args,
- const string& call_description) {
- func_mocker->PerformDefaultAction(args, call_description);
+ const FunctionMocker<F>* func_mocker,
+ typename Function<F>::ArgumentTuple&& args,
+ const std::string& call_description) {
+ func_mocker->PerformDefaultAction(std::move(args), call_description);
return new ActionResultHolder;
}
@@ -1438,9 +1444,8 @@ class ActionResultHolder<void> : public UntypedActionResultHolderBase {
// ActionResultHolder*.
template <typename F>
static ActionResultHolder* PerformAction(
- const Action<F>& action,
- const typename Function<F>::ArgumentTuple& args) {
- action.Perform(args);
+ const Action<F>& action, typename Function<F>::ArgumentTuple&& args) {
+ action.Perform(std::move(args));
return new ActionResultHolder;
}
@@ -1449,23 +1454,39 @@ class ActionResultHolder<void> : public UntypedActionResultHolderBase {
GTEST_DISALLOW_COPY_AND_ASSIGN_(ActionResultHolder);
};
-// The base of the function mocker class for the given function type.
-// We put the methods in this class instead of its child to avoid code
-// bloat.
template <typename F>
-class FunctionMockerBase : public UntypedFunctionMockerBase {
+class FunctionMocker;
+
+template <typename R, typename... Args>
+class FunctionMocker<R(Args...)> final : public UntypedFunctionMockerBase {
+ using F = R(Args...);
+
public:
- typedef typename Function<F>::Result Result;
- typedef typename Function<F>::ArgumentTuple ArgumentTuple;
- typedef typename Function<F>::ArgumentMatcherTuple ArgumentMatcherTuple;
+ using Result = R;
+ using ArgumentTuple = std::tuple<Args...>;
+ using ArgumentMatcherTuple = std::tuple<Matcher<Args>...>;
+
+ FunctionMocker() {}
- FunctionMockerBase() : current_spec_(this) {}
+ // There is no generally useful and implementable semantics of
+ // copying a mock object, so copying a mock is usually a user error.
+ // Thus we disallow copying function mockers. If the user really
+ // wants to copy a mock object, they should implement their own copy
+ // operation, for example:
+ //
+ // class MockFoo : public Foo {
+ // public:
+ // // Defines a copy constructor explicitly.
+ // MockFoo(const MockFoo& src) {}
+ // ...
+ // };
+ FunctionMocker(const FunctionMocker&) = delete;
+ FunctionMocker& operator=(const FunctionMocker&) = delete;
// The destructor verifies that all expectations on this mock
// function have been satisfied. If not, it will report Google Test
// non-fatal failures for the violations.
- virtual ~FunctionMockerBase()
- GTEST_LOCK_EXCLUDED_(g_gmock_mutex) {
+ ~FunctionMocker() override GTEST_LOCK_EXCLUDED_(g_gmock_mutex) {
MutexLock l(&g_gmock_mutex);
VerifyAndClearExpectationsLocked();
Mock::UnregisterLocked(this);
@@ -1485,7 +1506,7 @@ class FunctionMockerBase : public UntypedFunctionMockerBase {
return spec;
}
- return NULL;
+ return nullptr;
}
// Performs the default action of this mock function on the given
@@ -1495,14 +1516,15 @@ class FunctionMockerBase : public UntypedFunctionMockerBase {
// mutable state of this object, and thus can be called concurrently
// without locking.
// L = *
- Result PerformDefaultAction(const ArgumentTuple& args,
- const string& call_description) const {
+ Result PerformDefaultAction(ArgumentTuple&& args,
+ const std::string& call_description) const {
const OnCallSpec<F>* const spec =
this->FindOnCallSpec(args);
- if (spec != NULL) {
- return spec->GetAction().Perform(args);
+ if (spec != nullptr) {
+ return spec->GetAction().Perform(std::move(args));
}
- const string message = call_description +
+ const std::string message =
+ call_description +
"\n The mock function has no default action "
"set, and its return type has no default value set.";
#if GTEST_HAS_EXCEPTIONS
@@ -1520,31 +1542,30 @@ class FunctionMockerBase : public UntypedFunctionMockerBase {
// the error message to describe the call in the case the default
// action fails. The caller is responsible for deleting the result.
// L = *
- virtual UntypedActionResultHolderBase* UntypedPerformDefaultAction(
- const void* untyped_args, // must point to an ArgumentTuple
- const string& call_description) const {
- const ArgumentTuple& args =
- *static_cast<const ArgumentTuple*>(untyped_args);
- return ResultHolder::PerformDefaultAction(this, args, call_description);
+ UntypedActionResultHolderBase* UntypedPerformDefaultAction(
+ void* untyped_args, // must point to an ArgumentTuple
+ const std::string& call_description) const override {
+ ArgumentTuple* args = static_cast<ArgumentTuple*>(untyped_args);
+ return ResultHolder::PerformDefaultAction(this, std::move(*args),
+ call_description);
}
// Performs the given action with the given arguments and returns
// the action's result. The caller is responsible for deleting the
// result.
// L = *
- virtual UntypedActionResultHolderBase* UntypedPerformAction(
- const void* untyped_action, const void* untyped_args) const {
+ UntypedActionResultHolderBase* UntypedPerformAction(
+ const void* untyped_action, void* untyped_args) const override {
// Make a copy of the action before performing it, in case the
// action deletes the mock object (and thus deletes itself).
const Action<F> action = *static_cast<const Action<F>*>(untyped_action);
- const ArgumentTuple& args =
- *static_cast<const ArgumentTuple*>(untyped_args);
- return ResultHolder::PerformAction(action, args);
+ ArgumentTuple* args = static_cast<ArgumentTuple*>(untyped_args);
+ return ResultHolder::PerformAction(action, std::move(*args));
}
// Implements UntypedFunctionMockerBase::ClearDefaultActionsLocked():
// clears the ON_CALL()s set on this mock function.
- virtual void ClearDefaultActionsLocked()
+ void ClearDefaultActionsLocked() override
GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex) {
g_gmock_mutex.AssertHeld();
@@ -1570,22 +1591,26 @@ class FunctionMockerBase : public UntypedFunctionMockerBase {
g_gmock_mutex.Lock();
}
- protected:
- template <typename Function>
- friend class MockSpec;
-
- typedef ActionResultHolder<Result> ResultHolder;
-
// Returns the result of invoking this mock function with the given
// arguments. This function can be safely called from multiple
// threads concurrently.
- Result InvokeWith(const ArgumentTuple& args)
- GTEST_LOCK_EXCLUDED_(g_gmock_mutex) {
- scoped_ptr<ResultHolder> holder(
- DownCast_<ResultHolder*>(this->UntypedInvokeWith(&args)));
+ Result Invoke(Args... args) GTEST_LOCK_EXCLUDED_(g_gmock_mutex) {
+ ArgumentTuple tuple(std::forward<Args>(args)...);
+ std::unique_ptr<ResultHolder> holder(DownCast_<ResultHolder*>(
+ this->UntypedInvokeWith(static_cast<void*>(&tuple))));
return holder->Unwrap();
}
+ MockSpec<F> With(Matcher<Args>... m) {
+ return MockSpec<F>(this, ::std::make_tuple(std::move(m)...));
+ }
+
+ protected:
+ template <typename Function>
+ friend class MockSpec;
+
+ typedef ActionResultHolder<Result> ResultHolder;
+
// Adds and returns a default action spec for this mock function.
OnCallSpec<F>& AddNewOnCallSpec(
const char* file, int line,
@@ -1598,31 +1623,27 @@ class FunctionMockerBase : public UntypedFunctionMockerBase {
}
// Adds and returns an expectation spec for this mock function.
- TypedExpectation<F>& AddNewExpectation(
- const char* file,
- int line,
- const string& source_text,
- const ArgumentMatcherTuple& m)
- GTEST_LOCK_EXCLUDED_(g_gmock_mutex) {
+ TypedExpectation<F>& AddNewExpectation(const char* file, int line,
+ const std::string& source_text,
+ const ArgumentMatcherTuple& m)
+ GTEST_LOCK_EXCLUDED_(g_gmock_mutex) {
Mock::RegisterUseByOnCallOrExpectCall(MockObject(), file, line);
TypedExpectation<F>* const expectation =
new TypedExpectation<F>(this, file, line, source_text, m);
- const linked_ptr<ExpectationBase> untyped_expectation(expectation);
+ const std::shared_ptr<ExpectationBase> untyped_expectation(expectation);
+ // See the definition of untyped_expectations_ for why access to
+ // it is unprotected here.
untyped_expectations_.push_back(untyped_expectation);
// Adds this expectation into the implicit sequence if there is one.
Sequence* const implicit_sequence = g_gmock_implicit_sequence.get();
- if (implicit_sequence != NULL) {
+ if (implicit_sequence != nullptr) {
implicit_sequence->AddExpectation(Expectation(untyped_expectation));
}
return *expectation;
}
- // The current spec (either default action spec or expectation spec)
- // being described on this function mocker.
- MockSpec<F>& current_spec() { return current_spec_; }
-
private:
template <typename Func> friend class TypedExpectation;
@@ -1635,10 +1656,9 @@ class FunctionMockerBase : public UntypedFunctionMockerBase {
::std::ostream* os) const {
const OnCallSpec<F>* const spec = FindOnCallSpec(args);
- if (spec == NULL) {
- *os << (internal::type_equals<Result, void>::value ?
- "returning directly.\n" :
- "returning default value.\n");
+ if (spec == nullptr) {
+ *os << (std::is_void<Result>::value ? "returning directly.\n"
+ : "returning default value.\n");
} else {
*os << "taking default action specified at:\n"
<< FormatFileLocation(spec->file(), spec->line()) << "\n";
@@ -1648,10 +1668,9 @@ class FunctionMockerBase : public UntypedFunctionMockerBase {
// Writes a message that the call is uninteresting (i.e. neither
// explicitly expected nor explicitly unexpected) to the given
// ostream.
- virtual void UntypedDescribeUninterestingCall(
- const void* untyped_args,
- ::std::ostream* os) const
- GTEST_LOCK_EXCLUDED_(g_gmock_mutex) {
+ void UntypedDescribeUninterestingCall(const void* untyped_args,
+ ::std::ostream* os) const override
+ GTEST_LOCK_EXCLUDED_(g_gmock_mutex) {
const ArgumentTuple& args =
*static_cast<const ArgumentTuple*>(untyped_args);
*os << "Uninteresting mock function call - ";
@@ -1676,18 +1695,17 @@ class FunctionMockerBase : public UntypedFunctionMockerBase {
// section. The reason is that we have no control on what the
// action does (it can invoke an arbitrary user function or even a
// mock function) and excessive locking could cause a dead lock.
- virtual const ExpectationBase* UntypedFindMatchingExpectation(
- const void* untyped_args,
- const void** untyped_action, bool* is_excessive,
- ::std::ostream* what, ::std::ostream* why)
- GTEST_LOCK_EXCLUDED_(g_gmock_mutex) {
+ const ExpectationBase* UntypedFindMatchingExpectation(
+ const void* untyped_args, const void** untyped_action, bool* is_excessive,
+ ::std::ostream* what, ::std::ostream* why) override
+ GTEST_LOCK_EXCLUDED_(g_gmock_mutex) {
const ArgumentTuple& args =
*static_cast<const ArgumentTuple*>(untyped_args);
MutexLock l(&g_gmock_mutex);
TypedExpectation<F>* exp = this->FindMatchingExpectationLocked(args);
- if (exp == NULL) { // A match wasn't found.
+ if (exp == nullptr) { // A match wasn't found.
this->FormatUnexpectedCallMessageLocked(args, what, why);
- return NULL;
+ return nullptr;
}
// This line must be done before calling GetActionForArguments(),
@@ -1695,15 +1713,15 @@ class FunctionMockerBase : public UntypedFunctionMockerBase {
// its saturation status.
*is_excessive = exp->IsSaturated();
const Action<F>* action = exp->GetActionForArguments(this, args, what, why);
- if (action != NULL && action->IsDoDefault())
- action = NULL; // Normalize "do default" to NULL.
+ if (action != nullptr && action->IsDoDefault())
+ action = nullptr; // Normalize "do default" to NULL.
*untyped_action = action;
return exp;
}
// Prints the given function arguments to the ostream.
- virtual void UntypedPrintArgs(const void* untyped_args,
- ::std::ostream* os) const {
+ void UntypedPrintArgs(const void* untyped_args,
+ ::std::ostream* os) const override {
const ArgumentTuple& args =
*static_cast<const ArgumentTuple*>(untyped_args);
UniversalPrint(args, os);
@@ -1715,6 +1733,8 @@ class FunctionMockerBase : public UntypedFunctionMockerBase {
const ArgumentTuple& args) const
GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex) {
g_gmock_mutex.AssertHeld();
+ // See the definition of untyped_expectations_ for why access to
+ // it is unprotected here.
for (typename UntypedExpectations::const_reverse_iterator it =
untyped_expectations_.rbegin();
it != untyped_expectations_.rend(); ++it) {
@@ -1724,7 +1744,7 @@ class FunctionMockerBase : public UntypedFunctionMockerBase {
return exp;
}
}
- return NULL;
+ return nullptr;
}
// Returns a message that the arguments don't match any expectation.
@@ -1746,12 +1766,12 @@ class FunctionMockerBase : public UntypedFunctionMockerBase {
::std::ostream* why) const
GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex) {
g_gmock_mutex.AssertHeld();
- const int count = static_cast<int>(untyped_expectations_.size());
+ const size_t count = untyped_expectations_.size();
*why << "Google Mock tried the following " << count << " "
<< (count == 1 ? "expectation, but it didn't match" :
"expectations, but none matched")
<< ":\n";
- for (int i = 0; i < count; i++) {
+ for (size_t i = 0; i < count; i++) {
TypedExpectation<F>* const expectation =
static_cast<TypedExpectation<F>*>(untyped_expectations_[i].get());
*why << "\n";
@@ -1764,41 +1784,97 @@ class FunctionMockerBase : public UntypedFunctionMockerBase {
expectation->DescribeCallCountTo(why);
}
}
+}; // class FunctionMocker
- // The current spec (either default action spec or expectation spec)
- // being described on this function mocker.
- MockSpec<F> current_spec_;
+GTEST_DISABLE_MSC_WARNINGS_POP_() // 4355
- // There is no generally useful and implementable semantics of
- // copying a mock object, so copying a mock is usually a user error.
- // Thus we disallow copying function mockers. If the user really
- // wants to copy a mock object, he should implement his own copy
- // operation, for example:
- //
- // class MockFoo : public Foo {
- // public:
- // // Defines a copy constructor explicitly.
- // MockFoo(const MockFoo& src) {}
- // ...
- // };
- GTEST_DISALLOW_COPY_AND_ASSIGN_(FunctionMockerBase);
-}; // class FunctionMockerBase
+// Reports an uninteresting call (whose description is in msg) in the
+// manner specified by 'reaction'.
+void ReportUninterestingCall(CallReaction reaction, const std::string& msg);
-#ifdef _MSC_VER
-# pragma warning(pop) // Restores the warning state.
-#endif // _MSV_VER
+} // namespace internal
-// Implements methods of FunctionMockerBase.
+// A MockFunction<F> class has one mock method whose type is F. It is
+// useful when you just want your test code to emit some messages and
+// have Google Mock verify the right messages are sent (and perhaps at
+// the right times). For example, if you are exercising code:
+//
+// Foo(1);
+// Foo(2);
+// Foo(3);
+//
+// and want to verify that Foo(1) and Foo(3) both invoke
+// mock.Bar("a"), but Foo(2) doesn't invoke anything, you can write:
+//
+// TEST(FooTest, InvokesBarCorrectly) {
+// MyMock mock;
+// MockFunction<void(string check_point_name)> check;
+// {
+// InSequence s;
+//
+// EXPECT_CALL(mock, Bar("a"));
+// EXPECT_CALL(check, Call("1"));
+// EXPECT_CALL(check, Call("2"));
+// EXPECT_CALL(mock, Bar("a"));
+// }
+// Foo(1);
+// check.Call("1");
+// Foo(2);
+// check.Call("2");
+// Foo(3);
+// }
+//
+// The expectation spec says that the first Bar("a") must happen
+// before check point "1", the second Bar("a") must happen after check
+// point "2", and nothing should happen between the two check
+// points. The explicit check points make it easy to tell which
+// Bar("a") is called by which call to Foo().
+//
+// MockFunction<F> can also be used to exercise code that accepts
+// std::function<F> callbacks. To do so, use AsStdFunction() method
+// to create std::function proxy forwarding to original object's Call.
+// Example:
+//
+// TEST(FooTest, RunsCallbackWithBarArgument) {
+// MockFunction<int(string)> callback;
+// EXPECT_CALL(callback, Call("bar")).WillOnce(Return(1));
+// Foo(callback.AsStdFunction());
+// }
+template <typename F>
+class MockFunction;
-// Verifies that all expectations on this mock function have been
-// satisfied. Reports one or more Google Test non-fatal failures and
-// returns false if not.
+template <typename R, typename... Args>
+class MockFunction<R(Args...)> {
+ public:
+ MockFunction() {}
+ MockFunction(const MockFunction&) = delete;
+ MockFunction& operator=(const MockFunction&) = delete;
-// Reports an uninteresting call (whose description is in msg) in the
-// manner specified by 'reaction'.
-void ReportUninterestingCall(CallReaction reaction, const string& msg);
+ std::function<R(Args...)> AsStdFunction() {
+ return [this](Args... args) -> R {
+ return this->Call(std::forward<Args>(args)...);
+ };
+ }
-} // namespace internal
+ // Implementation detail: the expansion of the MOCK_METHOD macro.
+ R Call(Args... args) {
+ mock_.SetOwnerAndName(this, "Call");
+ return mock_.Invoke(std::forward<Args>(args)...);
+ }
+
+ internal::MockSpec<R(Args...)> gmock_Call(Matcher<Args>... m) {
+ mock_.RegisterOwner(this);
+ return mock_.With(std::move(m)...);
+ }
+
+ internal::MockSpec<R(Args...)> gmock_Call(const internal::WithoutMatchers&,
+ R (*)(Args...)) {
+ return this->gmock_Call(::testing::A<Args>()...);
+ }
+
+ private:
+ internal::FunctionMocker<R(Args...)> mock_;
+};
// The style guide prohibits "using" statements in a namespace scope
// inside a header file. However, the MockSpec class template is
@@ -1831,17 +1907,79 @@ inline Expectation::Expectation(internal::ExpectationBase& exp) // NOLINT
} // namespace testing
-// A separate macro is required to avoid compile errors when the name
-// of the method used in call is a result of macro expansion.
-// See CompilesWithMethodNameExpandedFromMacro tests in
-// internal/gmock-spec-builders_test.cc for more details.
-#define GMOCK_ON_CALL_IMPL_(obj, call) \
- ((obj).gmock_##call).InternalDefaultActionSetAt(__FILE__, __LINE__, \
- #obj, #call)
-#define ON_CALL(obj, call) GMOCK_ON_CALL_IMPL_(obj, call)
-
-#define GMOCK_EXPECT_CALL_IMPL_(obj, call) \
- ((obj).gmock_##call).InternalExpectedAt(__FILE__, __LINE__, #obj, #call)
-#define EXPECT_CALL(obj, call) GMOCK_EXPECT_CALL_IMPL_(obj, call)
+GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251
+
+// Implementation for ON_CALL and EXPECT_CALL macros. A separate macro is
+// required to avoid compile errors when the name of the method used in call is
+// a result of macro expansion. See CompilesWithMethodNameExpandedFromMacro
+// tests in internal/gmock-spec-builders_test.cc for more details.
+//
+// This macro supports statements both with and without parameter matchers. If
+// the parameter list is omitted, gMock will accept any parameters, which allows
+// tests to be written that don't need to encode the number of method
+// parameter. This technique may only be used for non-overloaded methods.
+//
+// // These are the same:
+// ON_CALL(mock, NoArgsMethod()).WillByDefault(...);
+// ON_CALL(mock, NoArgsMethod).WillByDefault(...);
+//
+// // As are these:
+// ON_CALL(mock, TwoArgsMethod(_, _)).WillByDefault(...);
+// ON_CALL(mock, TwoArgsMethod).WillByDefault(...);
+//
+// // Can also specify args if you want, of course:
+// ON_CALL(mock, TwoArgsMethod(_, 45)).WillByDefault(...);
+//
+// // Overloads work as long as you specify parameters:
+// ON_CALL(mock, OverloadedMethod(_)).WillByDefault(...);
+// ON_CALL(mock, OverloadedMethod(_, _)).WillByDefault(...);
+//
+// // Oops! Which overload did you want?
+// ON_CALL(mock, OverloadedMethod).WillByDefault(...);
+// => ERROR: call to member function 'gmock_OverloadedMethod' is ambiguous
+//
+// How this works: The mock class uses two overloads of the gmock_Method
+// expectation setter method plus an operator() overload on the MockSpec object.
+// In the matcher list form, the macro expands to:
+//
+// // This statement:
+// ON_CALL(mock, TwoArgsMethod(_, 45))...
+//
+// // ...expands to:
+// mock.gmock_TwoArgsMethod(_, 45)(WithoutMatchers(), nullptr)...
+// |-------------v---------------||------------v-------------|
+// invokes first overload swallowed by operator()
+//
+// // ...which is essentially:
+// mock.gmock_TwoArgsMethod(_, 45)...
+//
+// Whereas the form without a matcher list:
+//
+// // This statement:
+// ON_CALL(mock, TwoArgsMethod)...
+//
+// // ...expands to:
+// mock.gmock_TwoArgsMethod(WithoutMatchers(), nullptr)...
+// |-----------------------v--------------------------|
+// invokes second overload
+//
+// // ...which is essentially:
+// mock.gmock_TwoArgsMethod(_, _)...
+//
+// The WithoutMatchers() argument is used to disambiguate overloads and to
+// block the caller from accidentally invoking the second overload directly. The
+// second argument is an internal type derived from the method signature. The
+// failure to disambiguate two overloads of this method in the ON_CALL statement
+// is how we block callers from setting expectations on overloaded methods.
+#define GMOCK_ON_CALL_IMPL_(mock_expr, Setter, call) \
+ ((mock_expr).gmock_##call)(::testing::internal::GetWithoutMatchers(), \
+ nullptr) \
+ .Setter(__FILE__, __LINE__, #mock_expr, #call)
+
+#define ON_CALL(obj, call) \
+ GMOCK_ON_CALL_IMPL_(obj, InternalDefaultActionSetAt, call)
+
+#define EXPECT_CALL(obj, call) \
+ GMOCK_ON_CALL_IMPL_(obj, InternalExpectedAt, call)
#endif // GMOCK_INCLUDE_GMOCK_GMOCK_SPEC_BUILDERS_H_
diff --git a/extern/gmock/include/gmock/gmock.h b/extern/gmock/include/gmock/gmock.h
index 6735c71bf8a..99c3d7871d0 100644
--- a/extern/gmock/include/gmock/gmock.h
+++ b/extern/gmock/include/gmock/gmock.h
@@ -26,26 +26,27 @@
// 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.
-//
-// Author: wan@google.com (Zhanyong Wan)
+
// Google Mock - a framework for writing C++ mock classes.
//
// This is the main header file a user should include.
+// GOOGLETEST_CM0002 DO NOT DELETE
+
#ifndef GMOCK_INCLUDE_GMOCK_GMOCK_H_
#define GMOCK_INCLUDE_GMOCK_GMOCK_H_
// This file implements the following syntax:
//
-// ON_CALL(mock_object.Method(...))
+// ON_CALL(mock_object, Method(...))
// .With(...) ?
// .WillByDefault(...);
//
// where With() is optional and WillByDefault() must appear exactly
// once.
//
-// EXPECT_CALL(mock_object.Method(...))
+// EXPECT_CALL(mock_object, Method(...))
// .With(...) ?
// .Times(...) ?
// .InSequence(...) *
@@ -57,13 +58,14 @@
#include "gmock/gmock-actions.h"
#include "gmock/gmock-cardinalities.h"
+#include "gmock/gmock-function-mocker.h"
#include "gmock/gmock-generated-actions.h"
#include "gmock/gmock-generated-function-mockers.h"
-#include "gmock/gmock-generated-nice-strict.h"
#include "gmock/gmock-generated-matchers.h"
#include "gmock/gmock-matchers.h"
#include "gmock/gmock-more-actions.h"
#include "gmock/gmock-more-matchers.h"
+#include "gmock/gmock-nice-strict.h"
#include "gmock/internal/gmock-internal-utils.h"
namespace testing {
@@ -71,6 +73,7 @@ namespace testing {
// Declares Google Mock flags that we want a user to use programmatically.
GMOCK_DECLARE_bool_(catch_leaked_mocks);
GMOCK_DECLARE_string_(verbose);
+GMOCK_DECLARE_int32_(default_mock_behavior);
// Initializes Google Mock. This must be called before running the
// tests. In particular, it parses the command line for the flags
@@ -89,6 +92,10 @@ GTEST_API_ void InitGoogleMock(int* argc, char** argv);
// UNICODE mode.
GTEST_API_ void InitGoogleMock(int* argc, wchar_t** argv);
+// This overloaded version can be used on Arduino/embedded platforms where
+// there is no argc/argv.
+GTEST_API_ void InitGoogleMock();
+
} // namespace testing
#endif // GMOCK_INCLUDE_GMOCK_GMOCK_H_
diff --git a/extern/gmock/include/gmock/internal/custom/README.md b/extern/gmock/include/gmock/internal/custom/README.md
new file mode 100644
index 00000000000..f6c93f616d6
--- /dev/null
+++ b/extern/gmock/include/gmock/internal/custom/README.md
@@ -0,0 +1,16 @@
+# Customization Points
+
+The custom directory is an injection point for custom user configurations.
+
+## Header `gmock-port.h`
+
+The following macros can be defined:
+
+### Flag related macros:
+
+* `GMOCK_DECLARE_bool_(name)`
+* `GMOCK_DECLARE_int32_(name)`
+* `GMOCK_DECLARE_string_(name)`
+* `GMOCK_DEFINE_bool_(name, default_val, doc)`
+* `GMOCK_DEFINE_int32_(name, default_val, doc)`
+* `GMOCK_DEFINE_string_(name, default_val, doc)`
diff --git a/extern/gmock/include/gmock/internal/custom/gmock-generated-actions.h b/extern/gmock/include/gmock/internal/custom/gmock-generated-actions.h
index 7dc3b1ad541..92d910cf06d 100644
--- a/extern/gmock/include/gmock/internal/custom/gmock-generated-actions.h
+++ b/extern/gmock/include/gmock/internal/custom/gmock-generated-actions.h
@@ -2,6 +2,8 @@
// pump.py gmock-generated-actions.h.pump
// DO NOT EDIT BY HAND!!!
+// GOOGLETEST_CM0002 DO NOT DELETE
+
#ifndef GMOCK_INCLUDE_GMOCK_INTERNAL_CUSTOM_GMOCK_GENERATED_ACTIONS_H_
#define GMOCK_INCLUDE_GMOCK_INTERNAL_CUSTOM_GMOCK_GENERATED_ACTIONS_H_
diff --git a/extern/gmock/include/gmock/internal/custom/gmock-matchers.h b/extern/gmock/include/gmock/internal/custom/gmock-matchers.h
index f2efef91dbe..14aafaabe6b 100644
--- a/extern/gmock/include/gmock/internal/custom/gmock-matchers.h
+++ b/extern/gmock/include/gmock/internal/custom/gmock-matchers.h
@@ -27,13 +27,10 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
-// ============================================================
-// An installation-specific extension point for gmock-matchers.h.
-// ============================================================
+// Injection point for custom user configurations. See README for details
//
-// Adds google3 callback support to CallableTraits.
-//
-#ifndef GMOCK_INCLUDE_GMOCK_INTERNAL_CUSTOM_CALLBACK_MATCHERS_H_
-#define GMOCK_INCLUDE_GMOCK_INTERNAL_CUSTOM_CALLBACK_MATCHERS_H_
+// GOOGLETEST_CM0002 DO NOT DELETE
-#endif // GMOCK_INCLUDE_GMOCK_INTERNAL_CUSTOM_CALLBACK_MATCHERS_H_
+#ifndef GMOCK_INCLUDE_GMOCK_INTERNAL_CUSTOM_GMOCK_MATCHERS_H_
+#define GMOCK_INCLUDE_GMOCK_INTERNAL_CUSTOM_GMOCK_MATCHERS_H_
+#endif // GMOCK_INCLUDE_GMOCK_INTERNAL_CUSTOM_GMOCK_MATCHERS_H_
diff --git a/extern/gmock/include/gmock/internal/custom/gmock-port.h b/extern/gmock/include/gmock/internal/custom/gmock-port.h
index 9ce8bfe06bf..0030fe91118 100644
--- a/extern/gmock/include/gmock/internal/custom/gmock-port.h
+++ b/extern/gmock/include/gmock/internal/custom/gmock-port.h
@@ -27,19 +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.
//
-// Injection point for custom user configurations.
-// The following macros can be defined:
-//
-// Flag related macros:
-// GMOCK_DECLARE_bool_(name)
-// GMOCK_DECLARE_int32_(name)
-// GMOCK_DECLARE_string_(name)
-// GMOCK_DEFINE_bool_(name, default_val, doc)
-// GMOCK_DEFINE_int32_(name, default_val, doc)
-// GMOCK_DEFINE_string_(name, default_val, doc)
+// Injection point for custom user configurations. See README for details
//
// ** Custom implementation starts here **
+// GOOGLETEST_CM0002 DO NOT DELETE
+
#ifndef GMOCK_INCLUDE_GMOCK_INTERNAL_CUSTOM_GMOCK_PORT_H_
#define GMOCK_INCLUDE_GMOCK_INTERNAL_CUSTOM_GMOCK_PORT_H_
diff --git a/extern/gmock/include/gmock/internal/gmock-generated-internal-utils.h b/extern/gmock/include/gmock/internal/gmock-generated-internal-utils.h
deleted file mode 100644
index 7811e43f87c..00000000000
--- a/extern/gmock/include/gmock/internal/gmock-generated-internal-utils.h
+++ /dev/null
@@ -1,279 +0,0 @@
-// This file was GENERATED by command:
-// pump.py gmock-generated-internal-utils.h.pump
-// DO NOT EDIT BY HAND!!!
-
-// Copyright 2007, 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.
-//
-// Author: wan@google.com (Zhanyong Wan)
-
-// Google Mock - a framework for writing C++ mock classes.
-//
-// This file contains template meta-programming utility classes needed
-// for implementing Google Mock.
-
-#ifndef GMOCK_INCLUDE_GMOCK_INTERNAL_GMOCK_GENERATED_INTERNAL_UTILS_H_
-#define GMOCK_INCLUDE_GMOCK_INTERNAL_GMOCK_GENERATED_INTERNAL_UTILS_H_
-
-#include "gmock/internal/gmock-port.h"
-
-namespace testing {
-
-template <typename T>
-class Matcher;
-
-namespace internal {
-
-// An IgnoredValue object can be implicitly constructed from ANY value.
-// This is used in implementing the IgnoreResult(a) action.
-class IgnoredValue {
- public:
- // This constructor template allows any value to be implicitly
- // converted to IgnoredValue. The object has no data member and
- // doesn't try to remember anything about the argument. We
- // deliberately omit the 'explicit' keyword in order to allow the
- // conversion to be implicit.
- template <typename T>
- IgnoredValue(const T& /* ignored */) {} // NOLINT(runtime/explicit)
-};
-
-// MatcherTuple<T>::type is a tuple type where each field is a Matcher
-// for the corresponding field in tuple type T.
-template <typename Tuple>
-struct MatcherTuple;
-
-template <>
-struct MatcherTuple< ::testing::tuple<> > {
- typedef ::testing::tuple< > type;
-};
-
-template <typename A1>
-struct MatcherTuple< ::testing::tuple<A1> > {
- typedef ::testing::tuple<Matcher<A1> > type;
-};
-
-template <typename A1, typename A2>
-struct MatcherTuple< ::testing::tuple<A1, A2> > {
- typedef ::testing::tuple<Matcher<A1>, Matcher<A2> > type;
-};
-
-template <typename A1, typename A2, typename A3>
-struct MatcherTuple< ::testing::tuple<A1, A2, A3> > {
- typedef ::testing::tuple<Matcher<A1>, Matcher<A2>, Matcher<A3> > type;
-};
-
-template <typename A1, typename A2, typename A3, typename A4>
-struct MatcherTuple< ::testing::tuple<A1, A2, A3, A4> > {
- typedef ::testing::tuple<Matcher<A1>, Matcher<A2>, Matcher<A3>,
- Matcher<A4> > type;
-};
-
-template <typename A1, typename A2, typename A3, typename A4, typename A5>
-struct MatcherTuple< ::testing::tuple<A1, A2, A3, A4, A5> > {
- typedef ::testing::tuple<Matcher<A1>, Matcher<A2>, Matcher<A3>, Matcher<A4>,
- Matcher<A5> > type;
-};
-
-template <typename A1, typename A2, typename A3, typename A4, typename A5,
- typename A6>
-struct MatcherTuple< ::testing::tuple<A1, A2, A3, A4, A5, A6> > {
- typedef ::testing::tuple<Matcher<A1>, Matcher<A2>, Matcher<A3>, Matcher<A4>,
- Matcher<A5>, Matcher<A6> > type;
-};
-
-template <typename A1, typename A2, typename A3, typename A4, typename A5,
- typename A6, typename A7>
-struct MatcherTuple< ::testing::tuple<A1, A2, A3, A4, A5, A6, A7> > {
- typedef ::testing::tuple<Matcher<A1>, Matcher<A2>, Matcher<A3>, Matcher<A4>,
- Matcher<A5>, Matcher<A6>, Matcher<A7> > type;
-};
-
-template <typename A1, typename A2, typename A3, typename A4, typename A5,
- typename A6, typename A7, typename A8>
-struct MatcherTuple< ::testing::tuple<A1, A2, A3, A4, A5, A6, A7, A8> > {
- typedef ::testing::tuple<Matcher<A1>, Matcher<A2>, Matcher<A3>, Matcher<A4>,
- Matcher<A5>, Matcher<A6>, Matcher<A7>, Matcher<A8> > type;
-};
-
-template <typename A1, typename A2, typename A3, typename A4, typename A5,
- typename A6, typename A7, typename A8, typename A9>
-struct MatcherTuple< ::testing::tuple<A1, A2, A3, A4, A5, A6, A7, A8, A9> > {
- typedef ::testing::tuple<Matcher<A1>, Matcher<A2>, Matcher<A3>, Matcher<A4>,
- Matcher<A5>, Matcher<A6>, Matcher<A7>, Matcher<A8>, Matcher<A9> > type;
-};
-
-template <typename A1, typename A2, typename A3, typename A4, typename A5,
- typename A6, typename A7, typename A8, typename A9, typename A10>
-struct MatcherTuple< ::testing::tuple<A1, A2, A3, A4, A5, A6, A7, A8, A9,
- A10> > {
- typedef ::testing::tuple<Matcher<A1>, Matcher<A2>, Matcher<A3>, Matcher<A4>,
- Matcher<A5>, Matcher<A6>, Matcher<A7>, Matcher<A8>, Matcher<A9>,
- Matcher<A10> > type;
-};
-
-// Template struct Function<F>, where F must be a function type, contains
-// the following typedefs:
-//
-// Result: the function's return type.
-// ArgumentN: the type of the N-th argument, where N starts with 1.
-// ArgumentTuple: the tuple type consisting of all parameters of F.
-// ArgumentMatcherTuple: the tuple type consisting of Matchers for all
-// parameters of F.
-// MakeResultVoid: the function type obtained by substituting void
-// for the return type of F.
-// MakeResultIgnoredValue:
-// the function type obtained by substituting Something
-// for the return type of F.
-template <typename F>
-struct Function;
-
-template <typename R>
-struct Function<R()> {
- typedef R Result;
- typedef ::testing::tuple<> ArgumentTuple;
- typedef typename MatcherTuple<ArgumentTuple>::type ArgumentMatcherTuple;
- typedef void MakeResultVoid();
- typedef IgnoredValue MakeResultIgnoredValue();
-};
-
-template <typename R, typename A1>
-struct Function<R(A1)>
- : Function<R()> {
- typedef A1 Argument1;
- typedef ::testing::tuple<A1> ArgumentTuple;
- typedef typename MatcherTuple<ArgumentTuple>::type ArgumentMatcherTuple;
- typedef void MakeResultVoid(A1);
- typedef IgnoredValue MakeResultIgnoredValue(A1);
-};
-
-template <typename R, typename A1, typename A2>
-struct Function<R(A1, A2)>
- : Function<R(A1)> {
- typedef A2 Argument2;
- typedef ::testing::tuple<A1, A2> ArgumentTuple;
- typedef typename MatcherTuple<ArgumentTuple>::type ArgumentMatcherTuple;
- typedef void MakeResultVoid(A1, A2);
- typedef IgnoredValue MakeResultIgnoredValue(A1, A2);
-};
-
-template <typename R, typename A1, typename A2, typename A3>
-struct Function<R(A1, A2, A3)>
- : Function<R(A1, A2)> {
- typedef A3 Argument3;
- typedef ::testing::tuple<A1, A2, A3> ArgumentTuple;
- typedef typename MatcherTuple<ArgumentTuple>::type ArgumentMatcherTuple;
- typedef void MakeResultVoid(A1, A2, A3);
- typedef IgnoredValue MakeResultIgnoredValue(A1, A2, A3);
-};
-
-template <typename R, typename A1, typename A2, typename A3, typename A4>
-struct Function<R(A1, A2, A3, A4)>
- : Function<R(A1, A2, A3)> {
- typedef A4 Argument4;
- typedef ::testing::tuple<A1, A2, A3, A4> ArgumentTuple;
- typedef typename MatcherTuple<ArgumentTuple>::type ArgumentMatcherTuple;
- typedef void MakeResultVoid(A1, A2, A3, A4);
- typedef IgnoredValue MakeResultIgnoredValue(A1, A2, A3, A4);
-};
-
-template <typename R, typename A1, typename A2, typename A3, typename A4,
- typename A5>
-struct Function<R(A1, A2, A3, A4, A5)>
- : Function<R(A1, A2, A3, A4)> {
- typedef A5 Argument5;
- typedef ::testing::tuple<A1, A2, A3, A4, A5> ArgumentTuple;
- typedef typename MatcherTuple<ArgumentTuple>::type ArgumentMatcherTuple;
- typedef void MakeResultVoid(A1, A2, A3, A4, A5);
- typedef IgnoredValue MakeResultIgnoredValue(A1, A2, A3, A4, A5);
-};
-
-template <typename R, typename A1, typename A2, typename A3, typename A4,
- typename A5, typename A6>
-struct Function<R(A1, A2, A3, A4, A5, A6)>
- : Function<R(A1, A2, A3, A4, A5)> {
- typedef A6 Argument6;
- typedef ::testing::tuple<A1, A2, A3, A4, A5, A6> ArgumentTuple;
- typedef typename MatcherTuple<ArgumentTuple>::type ArgumentMatcherTuple;
- typedef void MakeResultVoid(A1, A2, A3, A4, A5, A6);
- typedef IgnoredValue MakeResultIgnoredValue(A1, A2, A3, A4, A5, A6);
-};
-
-template <typename R, typename A1, typename A2, typename A3, typename A4,
- typename A5, typename A6, typename A7>
-struct Function<R(A1, A2, A3, A4, A5, A6, A7)>
- : Function<R(A1, A2, A3, A4, A5, A6)> {
- typedef A7 Argument7;
- typedef ::testing::tuple<A1, A2, A3, A4, A5, A6, A7> ArgumentTuple;
- typedef typename MatcherTuple<ArgumentTuple>::type ArgumentMatcherTuple;
- typedef void MakeResultVoid(A1, A2, A3, A4, A5, A6, A7);
- typedef IgnoredValue MakeResultIgnoredValue(A1, A2, A3, A4, A5, A6, A7);
-};
-
-template <typename R, typename A1, typename A2, typename A3, typename A4,
- typename A5, typename A6, typename A7, typename A8>
-struct Function<R(A1, A2, A3, A4, A5, A6, A7, A8)>
- : Function<R(A1, A2, A3, A4, A5, A6, A7)> {
- typedef A8 Argument8;
- typedef ::testing::tuple<A1, A2, A3, A4, A5, A6, A7, A8> ArgumentTuple;
- typedef typename MatcherTuple<ArgumentTuple>::type ArgumentMatcherTuple;
- typedef void MakeResultVoid(A1, A2, A3, A4, A5, A6, A7, A8);
- typedef IgnoredValue MakeResultIgnoredValue(A1, A2, A3, A4, A5, A6, A7, A8);
-};
-
-template <typename R, typename A1, typename A2, typename A3, typename A4,
- typename A5, typename A6, typename A7, typename A8, typename A9>
-struct Function<R(A1, A2, A3, A4, A5, A6, A7, A8, A9)>
- : Function<R(A1, A2, A3, A4, A5, A6, A7, A8)> {
- typedef A9 Argument9;
- typedef ::testing::tuple<A1, A2, A3, A4, A5, A6, A7, A8, A9> ArgumentTuple;
- typedef typename MatcherTuple<ArgumentTuple>::type ArgumentMatcherTuple;
- typedef void MakeResultVoid(A1, A2, A3, A4, A5, A6, A7, A8, A9);
- typedef IgnoredValue MakeResultIgnoredValue(A1, A2, A3, A4, A5, A6, A7, A8,
- A9);
-};
-
-template <typename R, typename A1, typename A2, typename A3, typename A4,
- typename A5, typename A6, typename A7, typename A8, typename A9,
- typename A10>
-struct Function<R(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10)>
- : Function<R(A1, A2, A3, A4, A5, A6, A7, A8, A9)> {
- typedef A10 Argument10;
- typedef ::testing::tuple<A1, A2, A3, A4, A5, A6, A7, A8, A9,
- A10> ArgumentTuple;
- typedef typename MatcherTuple<ArgumentTuple>::type ArgumentMatcherTuple;
- typedef void MakeResultVoid(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10);
- typedef IgnoredValue MakeResultIgnoredValue(A1, A2, A3, A4, A5, A6, A7, A8,
- A9, A10);
-};
-
-} // namespace internal
-
-} // namespace testing
-
-#endif // GMOCK_INCLUDE_GMOCK_INTERNAL_GMOCK_GENERATED_INTERNAL_UTILS_H_
diff --git a/extern/gmock/include/gmock/internal/gmock-internal-utils.h b/extern/gmock/include/gmock/internal/gmock-internal-utils.h
index e2ddb05c91d..fdc049c589c 100644
--- a/extern/gmock/include/gmock/internal/gmock-internal-utils.h
+++ b/extern/gmock/include/gmock/internal/gmock-internal-utils.h
@@ -26,8 +26,7 @@
// 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.
-//
-// Author: wan@google.com (Zhanyong Wan)
+
// Google Mock - a framework for writing C++ mock classes.
//
@@ -35,25 +34,42 @@
// Mock. They are subject to change without notice, so please DO NOT
// USE THEM IN USER CODE.
+// GOOGLETEST_CM0002 DO NOT DELETE
+
#ifndef GMOCK_INCLUDE_GMOCK_INTERNAL_GMOCK_INTERNAL_UTILS_H_
#define GMOCK_INCLUDE_GMOCK_INTERNAL_GMOCK_INTERNAL_UTILS_H_
#include <stdio.h>
#include <ostream> // NOLINT
#include <string>
-
-#include "gmock/internal/gmock-generated-internal-utils.h"
+#include <type_traits>
#include "gmock/internal/gmock-port.h"
#include "gtest/gtest.h"
namespace testing {
+
+template <typename>
+class Matcher;
+
namespace internal {
+// Silence MSVC C4100 (unreferenced formal parameter) and
+// C4805('==': unsafe mix of type 'const int' and type 'const bool')
+#ifdef _MSC_VER
+# pragma warning(push)
+# pragma warning(disable:4100)
+# pragma warning(disable:4805)
+#endif
+
+// Joins a vector of strings as if they are fields of a tuple; returns
+// the joined string.
+GTEST_API_ std::string JoinAsTuple(const Strings& fields);
+
// Converts an identifier name to a space-separated list of lower-case
// words. Each maximum substring of the form [A-Za-z][a-z]*|\d+ is
// treated as one word. For example, both "FooBar123" and
// "foo_bar_123" are converted to "foo bar 123".
-GTEST_API_ string ConvertIdentifierNameToWords(const char* id_name);
+GTEST_API_ std::string ConvertIdentifierNameToWords(const char* id_name);
// PointeeOf<Pointer>::type is the type of a value pointed to by a
// Pointer, which can be either a smart pointer or a raw pointer. The
@@ -80,44 +96,16 @@ inline const typename Pointer::element_type* GetRawPointer(const Pointer& p) {
template <typename Element>
inline Element* GetRawPointer(Element* p) { return p; }
-// This comparator allows linked_ptr to be stored in sets.
-template <typename T>
-struct LinkedPtrLessThan {
- bool operator()(const ::testing::internal::linked_ptr<T>& lhs,
- const ::testing::internal::linked_ptr<T>& rhs) const {
- return lhs.get() < rhs.get();
- }
-};
-
-// Symbian compilation can be done with wchar_t being either a native
-// type or a typedef. Using Google Mock with OpenC without wchar_t
-// should require the definition of _STLP_NO_WCHAR_T.
-//
// MSVC treats wchar_t as a native type usually, but treats it as the
// same as unsigned short when the compiler option /Zc:wchar_t- is
// specified. It defines _NATIVE_WCHAR_T_DEFINED symbol when wchar_t
// is a native type.
-#if (GTEST_OS_SYMBIAN && defined(_STLP_NO_WCHAR_T)) || \
- (defined(_MSC_VER) && !defined(_NATIVE_WCHAR_T_DEFINED))
+#if defined(_MSC_VER) && !defined(_NATIVE_WCHAR_T_DEFINED)
// wchar_t is a typedef.
#else
# define GMOCK_WCHAR_T_IS_NATIVE_ 1
#endif
-// signed wchar_t and unsigned wchar_t are NOT in the C++ standard.
-// Using them is a bad practice and not portable. So DON'T use them.
-//
-// Still, Google Mock is designed to work even if the user uses signed
-// wchar_t or unsigned wchar_t (obviously, assuming the compiler
-// supports them).
-//
-// To gcc,
-// wchar_t == signed wchar_t != unsigned wchar_t == unsigned int
-#ifdef __GNUC__
-// signed/unsigned wchar_t are valid types.
-# define GMOCK_HAS_SIGNED_WCHAR_T_ 1
-#endif
-
// In what follows, we use the term "kind" to indicate whether a type
// is bool, an integer type (excluding bool), a floating-point type,
// or none of them. This categorization is useful for determining
@@ -169,11 +157,11 @@ GMOCK_DECLARE_KIND_(long double, kFloatingPoint);
static_cast< ::testing::internal::TypeKind>( \
::testing::internal::KindOf<type>::value)
-// Evaluates to true iff integer type T is signed.
+// Evaluates to true if and only if integer type T is signed.
#define GMOCK_IS_SIGNED_(T) (static_cast<T>(-1) < 0)
// LosslessArithmeticConvertibleImpl<kFromKind, From, kToKind, To>::value
-// is true iff arithmetic type From can be losslessly converted to
+// is true if and only if arithmetic type From can be losslessly converted to
// arithmetic type To.
//
// It's the user's responsibility to ensure that both From and To are
@@ -182,30 +170,30 @@ GMOCK_DECLARE_KIND_(long double, kFloatingPoint);
// From, and kToKind is the kind of To; the value is
// implementation-defined when the above pre-condition is violated.
template <TypeKind kFromKind, typename From, TypeKind kToKind, typename To>
-struct LosslessArithmeticConvertibleImpl : public false_type {};
+struct LosslessArithmeticConvertibleImpl : public std::false_type {};
// Converting bool to bool is lossless.
template <>
struct LosslessArithmeticConvertibleImpl<kBool, bool, kBool, bool>
- : public true_type {}; // NOLINT
+ : public std::true_type {};
// Converting bool to any integer type is lossless.
template <typename To>
struct LosslessArithmeticConvertibleImpl<kBool, bool, kInteger, To>
- : public true_type {}; // NOLINT
+ : public std::true_type {};
// Converting bool to any floating-point type is lossless.
template <typename To>
struct LosslessArithmeticConvertibleImpl<kBool, bool, kFloatingPoint, To>
- : public true_type {}; // NOLINT
+ : public std::true_type {};
// Converting an integer to bool is lossy.
template <typename From>
struct LosslessArithmeticConvertibleImpl<kInteger, From, kBool, bool>
- : public false_type {}; // NOLINT
+ : public std::false_type {};
-// Converting an integer to another non-bool integer is lossless iff
-// the target type's range encloses the source type's range.
+// Converting an integer to another non-bool integer is lossless
+// if and only if the target type's range encloses the source type's range.
template <typename From, typename To>
struct LosslessArithmeticConvertibleImpl<kInteger, From, kInteger, To>
: public bool_constant<
@@ -223,27 +211,27 @@ struct LosslessArithmeticConvertibleImpl<kInteger, From, kInteger, To>
// the format of a floating-point number is implementation-defined.
template <typename From, typename To>
struct LosslessArithmeticConvertibleImpl<kInteger, From, kFloatingPoint, To>
- : public false_type {}; // NOLINT
+ : public std::false_type {};
// Converting a floating-point to bool is lossy.
template <typename From>
struct LosslessArithmeticConvertibleImpl<kFloatingPoint, From, kBool, bool>
- : public false_type {}; // NOLINT
+ : public std::false_type {};
// Converting a floating-point to an integer is lossy.
template <typename From, typename To>
struct LosslessArithmeticConvertibleImpl<kFloatingPoint, From, kInteger, To>
- : public false_type {}; // NOLINT
+ : public std::false_type {};
// Converting a floating-point to another floating-point is lossless
-// iff the target type is at least as big as the source type.
+// if and only if the target type is at least as big as the source type.
template <typename From, typename To>
struct LosslessArithmeticConvertibleImpl<
kFloatingPoint, From, kFloatingPoint, To>
: public bool_constant<sizeof(From) <= sizeof(To)> {}; // NOLINT
-// LosslessArithmeticConvertible<From, To>::value is true iff arithmetic
-// type From can be losslessly converted to arithmetic type To.
+// LosslessArithmeticConvertible<From, To>::value is true if and only if
+// arithmetic type From can be losslessly converted to arithmetic type To.
//
// It's the user's responsibility to ensure that both From and To are
// raw (i.e. has no CV modifier, is not a pointer, and is not a
@@ -267,7 +255,7 @@ class FailureReporterInterface {
// Reports a failure that occurred at the given source file location.
virtual void ReportFailure(FailureType type, const char* file, int line,
- const string& message) = 0;
+ const std::string& message) = 0;
};
// Returns the failure reporter used by Google Mock.
@@ -279,7 +267,7 @@ GTEST_API_ FailureReporterInterface* GetFailureReporter();
// inline this function to prevent it from showing up in the stack
// trace.
inline void Assert(bool condition, const char* file, int line,
- const string& msg) {
+ const std::string& msg) {
if (!condition) {
GetFailureReporter()->ReportFailure(FailureReporterInterface::kFatal,
file, line, msg);
@@ -292,7 +280,7 @@ inline void Assert(bool condition, const char* file, int line) {
// Verifies that condition is true; generates a non-fatal failure if
// condition is false.
inline void Expect(bool condition, const char* file, int line,
- const string& msg) {
+ const std::string& msg) {
if (!condition) {
GetFailureReporter()->ReportFailure(FailureReporterInterface::kNonfatal,
file, line, msg);
@@ -317,49 +305,36 @@ const char kWarningVerbosity[] = "warning";
// No logs are printed.
const char kErrorVerbosity[] = "error";
-// Returns true iff a log with the given severity is visible according
-// to the --gmock_verbose flag.
+// Returns true if and only if a log with the given severity is visible
+// according to the --gmock_verbose flag.
GTEST_API_ bool LogIsVisible(LogSeverity severity);
-// Prints the given message to stdout iff 'severity' >= the level
+// Prints the given message to stdout if and only if 'severity' >= the level
// specified by the --gmock_verbose flag. If stack_frames_to_skip >=
// 0, also prints the stack trace excluding the top
// stack_frames_to_skip frames. In opt mode, any positive
// stack_frames_to_skip is treated as 0, since we don't know which
// function calls will be inlined by the compiler and need to be
// conservative.
-GTEST_API_ void Log(LogSeverity severity,
- const string& message,
+GTEST_API_ void Log(LogSeverity severity, const std::string& message,
int stack_frames_to_skip);
-// TODO(wan@google.com): group all type utilities together.
-
-// Type traits.
-
-// is_reference<T>::value is non-zero iff T is a reference type.
-template <typename T> struct is_reference : public false_type {};
-template <typename T> struct is_reference<T&> : public true_type {};
-
-// type_equals<T1, T2>::value is non-zero iff T1 and T2 are the same type.
-template <typename T1, typename T2> struct type_equals : public false_type {};
-template <typename T> struct type_equals<T, T> : public true_type {};
+// A marker class that is used to resolve parameterless expectations to the
+// correct overload. This must not be instantiable, to prevent client code from
+// accidentally resolving to the overload; for example:
+//
+// ON_CALL(mock, Method({}, nullptr))...
+//
+class WithoutMatchers {
+ private:
+ WithoutMatchers() {}
+ friend GTEST_API_ WithoutMatchers GetWithoutMatchers();
+};
-// remove_reference<T>::type removes the reference from type T, if any.
-template <typename T> struct remove_reference { typedef T type; }; // NOLINT
-template <typename T> struct remove_reference<T&> { typedef T type; }; // NOLINT
+// Internal use only: access the singleton instance of WithoutMatchers.
+GTEST_API_ WithoutMatchers GetWithoutMatchers();
-// DecayArray<T>::type turns an array type U[N] to const U* and preserves
-// other types. Useful for saving a copy of a function argument.
-template <typename T> struct DecayArray { typedef T type; }; // NOLINT
-template <typename T, size_t N> struct DecayArray<T[N]> {
- typedef const T* type;
-};
-// Sometimes people use arrays whose size is not available at the use site
-// (e.g. extern const char kNamePrefix[]). This specialization covers that
-// case.
-template <typename T> struct DecayArray<T[]> {
- typedef const T* type;
-};
+// Type traits.
// Disable MSVC warnings for infinite recursion, since in this case the
// the recursion is unreachable.
@@ -409,9 +384,8 @@ class StlContainerView {
typedef const type& const_reference;
static const_reference ConstReference(const RawContainer& container) {
- // Ensures that RawContainer is not a const type.
- testing::StaticAssertTypeEq<RawContainer,
- GTEST_REMOVE_CONST_(RawContainer)>();
+ static_assert(!std::is_const<RawContainer>::value,
+ "RawContainer type must not be const");
return container;
}
static type Copy(const RawContainer& container) { return container; }
@@ -421,7 +395,7 @@ class StlContainerView {
template <typename Element, size_t N>
class StlContainerView<Element[N]> {
public:
- typedef GTEST_REMOVE_CONST_(Element) RawElement;
+ typedef typename std::remove_const<Element>::type RawElement;
typedef internal::NativeArray<RawElement> type;
// NativeArray<T> can represent a native array either by value or by
// reference (selected by a constructor argument), so 'const type'
@@ -431,53 +405,32 @@ class StlContainerView<Element[N]> {
typedef const type const_reference;
static const_reference ConstReference(const Element (&array)[N]) {
- // Ensures that Element is not a const type.
- testing::StaticAssertTypeEq<Element, RawElement>();
-#if GTEST_OS_SYMBIAN
- // The Nokia Symbian compiler confuses itself in template instantiation
- // for this call without the cast to Element*:
- // function call '[testing::internal::NativeArray<char *>].NativeArray(
- // {lval} const char *[4], long, testing::internal::RelationToSource)'
- // does not match
- // 'testing::internal::NativeArray<char *>::NativeArray(
- // char *const *, unsigned int, testing::internal::RelationToSource)'
- // (instantiating: 'testing::internal::ContainsMatcherImpl
- // <const char * (&)[4]>::Matches(const char * (&)[4]) const')
- // (instantiating: 'testing::internal::StlContainerView<char *[4]>::
- // ConstReference(const char * (&)[4])')
- // (and though the N parameter type is mismatched in the above explicit
- // conversion of it doesn't help - only the conversion of the array).
- return type(const_cast<Element*>(&array[0]), N,
- RelationToSourceReference());
-#else
+ static_assert(std::is_same<Element, RawElement>::value,
+ "Element type must not be const");
return type(array, N, RelationToSourceReference());
-#endif // GTEST_OS_SYMBIAN
}
static type Copy(const Element (&array)[N]) {
-#if GTEST_OS_SYMBIAN
- return type(const_cast<Element*>(&array[0]), N, RelationToSourceCopy());
-#else
return type(array, N, RelationToSourceCopy());
-#endif // GTEST_OS_SYMBIAN
}
};
// This specialization is used when RawContainer is a native array
// represented as a (pointer, size) tuple.
template <typename ElementPointer, typename Size>
-class StlContainerView< ::testing::tuple<ElementPointer, Size> > {
+class StlContainerView< ::std::tuple<ElementPointer, Size> > {
public:
- typedef GTEST_REMOVE_CONST_(
- typename internal::PointeeOf<ElementPointer>::type) RawElement;
+ typedef typename std::remove_const<
+ typename internal::PointeeOf<ElementPointer>::type>::type RawElement;
typedef internal::NativeArray<RawElement> type;
typedef const type const_reference;
static const_reference ConstReference(
- const ::testing::tuple<ElementPointer, Size>& array) {
- return type(get<0>(array), get<1>(array), RelationToSourceReference());
+ const ::std::tuple<ElementPointer, Size>& array) {
+ return type(std::get<0>(array), std::get<1>(array),
+ RelationToSourceReference());
}
- static type Copy(const ::testing::tuple<ElementPointer, Size>& array) {
- return type(get<0>(array), get<1>(array), RelationToSourceCopy());
+ static type Copy(const ::std::tuple<ElementPointer, Size>& array) {
+ return type(std::get<0>(array), std::get<1>(array), RelationToSourceCopy());
}
};
@@ -499,13 +452,62 @@ struct RemoveConstFromKey<std::pair<const K, V> > {
typedef std::pair<K, V> type;
};
-// Mapping from booleans to types. Similar to boost::bool_<kValue> and
-// std::integral_constant<bool, kValue>.
-template <bool kValue>
-struct BooleanConstant {};
+// Emit an assertion failure due to incorrect DoDefault() usage. Out-of-lined to
+// reduce code size.
+GTEST_API_ void IllegalDoDefault(const char* file, int line);
+
+template <typename F, typename Tuple, size_t... Idx>
+auto ApplyImpl(F&& f, Tuple&& args, IndexSequence<Idx...>) -> decltype(
+ std::forward<F>(f)(std::get<Idx>(std::forward<Tuple>(args))...)) {
+ return std::forward<F>(f)(std::get<Idx>(std::forward<Tuple>(args))...);
+}
+
+// Apply the function to a tuple of arguments.
+template <typename F, typename Tuple>
+auto Apply(F&& f, Tuple&& args)
+ -> decltype(ApplyImpl(std::forward<F>(f), std::forward<Tuple>(args),
+ MakeIndexSequence<std::tuple_size<Tuple>::value>())) {
+ return ApplyImpl(std::forward<F>(f), std::forward<Tuple>(args),
+ MakeIndexSequence<std::tuple_size<Tuple>::value>());
+}
+
+// Template struct Function<F>, where F must be a function type, contains
+// the following typedefs:
+//
+// Result: the function's return type.
+// Arg<N>: the type of the N-th argument, where N starts with 0.
+// ArgumentTuple: the tuple type consisting of all parameters of F.
+// ArgumentMatcherTuple: the tuple type consisting of Matchers for all
+// parameters of F.
+// MakeResultVoid: the function type obtained by substituting void
+// for the return type of F.
+// MakeResultIgnoredValue:
+// the function type obtained by substituting Something
+// for the return type of F.
+template <typename T>
+struct Function;
+
+template <typename R, typename... Args>
+struct Function<R(Args...)> {
+ using Result = R;
+ static constexpr size_t ArgumentCount = sizeof...(Args);
+ template <size_t I>
+ using Arg = ElemFromList<I, typename MakeIndexSequence<sizeof...(Args)>::type,
+ Args...>;
+ using ArgumentTuple = std::tuple<Args...>;
+ using ArgumentMatcherTuple = std::tuple<Matcher<Args>...>;
+ using MakeResultVoid = void(Args...);
+ using MakeResultIgnoredValue = IgnoredValue(Args...);
+};
+
+template <typename R, typename... Args>
+constexpr size_t Function<R(Args...)>::ArgumentCount;
+
+#ifdef _MSC_VER
+# pragma warning(pop)
+#endif
} // namespace internal
} // namespace testing
#endif // GMOCK_INCLUDE_GMOCK_INTERNAL_GMOCK_INTERNAL_UTILS_H_
-
diff --git a/extern/gmock/include/gmock/internal/gmock-port.h b/extern/gmock/include/gmock/internal/gmock-port.h
index 63f4a6802e8..063e2929acd 100644
--- a/extern/gmock/include/gmock/internal/gmock-port.h
+++ b/extern/gmock/include/gmock/internal/gmock-port.h
@@ -26,8 +26,7 @@
// 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.
-//
-// Author: vadimb@google.com (Vadim Berman)
+
//
// Low-level types and utilities for porting Google Mock to various
// platforms. All macros ending with _ and symbols defined in an
@@ -36,6 +35,8 @@
// end with _ are part of Google Mock's public API and can be used by
// code outside Google Mock.
+// GOOGLETEST_CM0002 DO NOT DELETE
+
#ifndef GMOCK_INCLUDE_GMOCK_INTERNAL_GMOCK_PORT_H_
#define GMOCK_INCLUDE_GMOCK_INTERNAL_GMOCK_PORT_H_
@@ -50,19 +51,14 @@
// portability utilities to Google Test's gtest-port.h instead of
// here, as Google Mock depends on Google Test. Only add a utility
// here if it's truly specific to Google Mock.
-#include "gtest/internal/gtest-linked_ptr.h"
+
#include "gtest/internal/gtest-port.h"
#include "gmock/internal/custom/gmock-port.h"
-// To avoid conditional compilation everywhere, we make it
-// gmock-port.h's responsibility to #include the header implementing
-// tr1/tuple. gmock-port.h does this via gtest-port.h, which is
-// guaranteed to pull in the tuple header.
-
-// For MS Visual C++, check the compiler version. At least VS 2003 is
+// For MS Visual C++, check the compiler version. At least VS 2015 is
// required to compile Google Mock.
-#if defined(_MSC_VER) && _MSC_VER < 1310
-# error "At least Visual C++ 2003 (7.1) is required to compile Google Mock."
+#if defined(_MSC_VER) && _MSC_VER < 1900
+# error "At least Visual C++ 2015 (14.0) is required to compile Google Mock."
#endif
// Macro for referencing flags. This is public as we want the user to
@@ -72,18 +68,18 @@
#if !defined(GMOCK_DECLARE_bool_)
// Macros for declaring flags.
-#define GMOCK_DECLARE_bool_(name) extern GTEST_API_ bool GMOCK_FLAG(name)
-#define GMOCK_DECLARE_int32_(name) \
+# define GMOCK_DECLARE_bool_(name) extern GTEST_API_ bool GMOCK_FLAG(name)
+# define GMOCK_DECLARE_int32_(name) \
extern GTEST_API_ ::testing::internal::Int32 GMOCK_FLAG(name)
-#define GMOCK_DECLARE_string_(name) \
+# define GMOCK_DECLARE_string_(name) \
extern GTEST_API_ ::std::string GMOCK_FLAG(name)
// Macros for defining flags.
-#define GMOCK_DEFINE_bool_(name, default_val, doc) \
+# define GMOCK_DEFINE_bool_(name, default_val, doc) \
GTEST_API_ bool GMOCK_FLAG(name) = (default_val)
-#define GMOCK_DEFINE_int32_(name, default_val, doc) \
+# define GMOCK_DEFINE_int32_(name, default_val, doc) \
GTEST_API_ ::testing::internal::Int32 GMOCK_FLAG(name) = (default_val)
-#define GMOCK_DEFINE_string_(name, default_val, doc) \
+# define GMOCK_DEFINE_string_(name, default_val, doc) \
GTEST_API_ ::std::string GMOCK_FLAG(name) = (default_val)
#endif // !defined(GMOCK_DECLARE_bool_)
diff --git a/extern/gmock/include/gmock/internal/gmock-pp.h b/extern/gmock/include/gmock/internal/gmock-pp.h
new file mode 100644
index 00000000000..1ab80e1cdbe
--- /dev/null
+++ b/extern/gmock/include/gmock/internal/gmock-pp.h
@@ -0,0 +1,317 @@
+#ifndef THIRD_PARTY_GOOGLETEST_GOOGLEMOCK_INCLUDE_GMOCK_PP_H_
+#define THIRD_PARTY_GOOGLETEST_GOOGLEMOCK_INCLUDE_GMOCK_PP_H_
+
+#undef GMOCK_PP_INTERNAL_USE_MSVC
+#if defined(__clang__)
+#define GMOCK_PP_INTERNAL_USE_MSVC 0
+#elif defined(_MSC_VER)
+// TODO(iserna): Also verify tradional versus comformant preprocessor.
+static_assert(
+ _MSC_VER >= 1900,
+ "MSVC version not supported. There is support for MSVC 14.0 and above.");
+#define GMOCK_PP_INTERNAL_USE_MSVC 1
+#else
+#define GMOCK_PP_INTERNAL_USE_MSVC 0
+#endif
+
+// Expands and concatenates the arguments. Constructed macros reevaluate.
+#define GMOCK_PP_CAT(_1, _2) GMOCK_PP_INTERNAL_CAT(_1, _2)
+
+// Expands and stringifies the only argument.
+#define GMOCK_PP_STRINGIZE(...) GMOCK_PP_INTERNAL_STRINGIZE(__VA_ARGS__)
+
+// Returns empty. Given a variadic number of arguments.
+#define GMOCK_PP_EMPTY(...)
+
+// Returns a comma. Given a variadic number of arguments.
+#define GMOCK_PP_COMMA(...) ,
+
+// Returns the only argument.
+#define GMOCK_PP_IDENTITY(_1) _1
+
+// MSVC preprocessor collapses __VA_ARGS__ in a single argument, we use a
+// CAT-like directive to force correct evaluation. Each macro has its own.
+#if GMOCK_PP_INTERNAL_USE_MSVC
+
+// Evaluates to the number of arguments after expansion.
+//
+// #define PAIR x, y
+//
+// GMOCK_PP_NARG() => 1
+// GMOCK_PP_NARG(x) => 1
+// GMOCK_PP_NARG(x, y) => 2
+// GMOCK_PP_NARG(PAIR) => 2
+//
+// Requires: the number of arguments after expansion is at most 15.
+#define GMOCK_PP_NARG(...) \
+ GMOCK_PP_INTERNAL_NARG_CAT( \
+ GMOCK_PP_INTERNAL_INTERNAL_16TH(__VA_ARGS__, 15, 14, 13, 12, 11, 10, 9, \
+ 8, 7, 6, 5, 4, 3, 2, 1), )
+
+// Returns 1 if the expansion of arguments has an unprotected comma. Otherwise
+// returns 0. Requires no more than 15 unprotected commas.
+#define GMOCK_PP_HAS_COMMA(...) \
+ GMOCK_PP_INTERNAL_HAS_COMMA_CAT( \
+ GMOCK_PP_INTERNAL_INTERNAL_16TH(__VA_ARGS__, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
+ 1, 1, 1, 1, 1, 0), )
+// Returns the first argument.
+#define GMOCK_PP_HEAD(...) \
+ GMOCK_PP_INTERNAL_HEAD_CAT(GMOCK_PP_INTERNAL_HEAD(__VA_ARGS__), )
+
+// Returns the tail. A variadic list of all arguments minus the first. Requires
+// at least one argument.
+#define GMOCK_PP_TAIL(...) \
+ GMOCK_PP_INTERNAL_TAIL_CAT(GMOCK_PP_INTERNAL_TAIL(__VA_ARGS__), )
+
+// Calls CAT(_Macro, NARG(__VA_ARGS__))(__VA_ARGS__)
+#define GMOCK_PP_VARIADIC_CALL(_Macro, ...) \
+ GMOCK_PP_INTERNAL_VARIADIC_CALL_CAT( \
+ GMOCK_PP_CAT(_Macro, GMOCK_PP_NARG(__VA_ARGS__))(__VA_ARGS__), )
+
+#else // GMOCK_PP_INTERNAL_USE_MSVC
+
+#define GMOCK_PP_NARG(...) \
+ GMOCK_PP_INTERNAL_INTERNAL_16TH(__VA_ARGS__, 15, 14, 13, 12, 11, 10, 9, 8, \
+ 7, 6, 5, 4, 3, 2, 1)
+#define GMOCK_PP_HAS_COMMA(...) \
+ GMOCK_PP_INTERNAL_INTERNAL_16TH(__VA_ARGS__, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
+ 1, 1, 1, 1, 0)
+#define GMOCK_PP_HEAD(...) GMOCK_PP_INTERNAL_HEAD(__VA_ARGS__)
+#define GMOCK_PP_TAIL(...) GMOCK_PP_INTERNAL_TAIL(__VA_ARGS__)
+#define GMOCK_PP_VARIADIC_CALL(_Macro, ...) \
+ GMOCK_PP_CAT(_Macro, GMOCK_PP_NARG(__VA_ARGS__))(__VA_ARGS__)
+
+#endif // GMOCK_PP_INTERNAL_USE_MSVC
+
+// If the arguments after expansion have no tokens, evaluates to `1`. Otherwise
+// evaluates to `0`.
+//
+// Requires: * the number of arguments after expansion is at most 15.
+// * If the argument is a macro, it must be able to be called with one
+// argument.
+//
+// Implementation details:
+//
+// There is one case when it generates a compile error: if the argument is macro
+// that cannot be called with one argument.
+//
+// #define M(a, b) // it doesn't matter what it expands to
+//
+// // Expected: expands to `0`.
+// // Actual: compile error.
+// GMOCK_PP_IS_EMPTY(M)
+//
+// There are 4 cases tested:
+//
+// * __VA_ARGS__ possible expansion has no unparen'd commas. Expected 0.
+// * __VA_ARGS__ possible expansion is not enclosed in parenthesis. Expected 0.
+// * __VA_ARGS__ possible expansion is not a macro that ()-evaluates to a comma.
+// Expected 0
+// * __VA_ARGS__ is empty, or has unparen'd commas, or is enclosed in
+// parenthesis, or is a macro that ()-evaluates to comma. Expected 1.
+//
+// We trigger detection on '0001', i.e. on empty.
+#define GMOCK_PP_IS_EMPTY(...) \
+ GMOCK_PP_INTERNAL_IS_EMPTY(GMOCK_PP_HAS_COMMA(__VA_ARGS__), \
+ GMOCK_PP_HAS_COMMA(GMOCK_PP_COMMA __VA_ARGS__), \
+ GMOCK_PP_HAS_COMMA(__VA_ARGS__()), \
+ GMOCK_PP_HAS_COMMA(GMOCK_PP_COMMA __VA_ARGS__()))
+
+// Evaluates to _Then if _Cond is 1 and _Else if _Cond is 0.
+#define GMOCK_PP_IF(_Cond, _Then, _Else) \
+ GMOCK_PP_CAT(GMOCK_PP_INTERNAL_IF_, _Cond)(_Then, _Else)
+
+// Evaluates to the number of arguments after expansion. Identifies 'empty' as
+// 0.
+//
+// #define PAIR x, y
+//
+// GMOCK_PP_NARG0() => 0
+// GMOCK_PP_NARG0(x) => 1
+// GMOCK_PP_NARG0(x, y) => 2
+// GMOCK_PP_NARG0(PAIR) => 2
+//
+// Requires: * the number of arguments after expansion is at most 15.
+// * If the argument is a macro, it must be able to be called with one
+// argument.
+#define GMOCK_PP_NARG0(...) \
+ GMOCK_PP_IF(GMOCK_PP_IS_EMPTY(__VA_ARGS__), 0, GMOCK_PP_NARG(__VA_ARGS__))
+
+// Expands to 1 if the first argument starts with something in parentheses,
+// otherwise to 0.
+#define GMOCK_PP_IS_BEGIN_PARENS(...) \
+ GMOCK_PP_INTERNAL_ALTERNATE_HEAD( \
+ GMOCK_PP_CAT(GMOCK_PP_INTERNAL_IBP_IS_VARIADIC_R_, \
+ GMOCK_PP_INTERNAL_IBP_IS_VARIADIC_C __VA_ARGS__))
+
+// Expands to 1 is there is only one argument and it is enclosed in parentheses.
+#define GMOCK_PP_IS_ENCLOSED_PARENS(...) \
+ GMOCK_PP_IF(GMOCK_PP_IS_BEGIN_PARENS(__VA_ARGS__), \
+ GMOCK_PP_IS_EMPTY(GMOCK_PP_EMPTY __VA_ARGS__), 0)
+
+// Remove the parens, requires GMOCK_PP_IS_ENCLOSED_PARENS(args) => 1.
+#define GMOCK_PP_REMOVE_PARENS(...) GMOCK_PP_INTERNAL_REMOVE_PARENS __VA_ARGS__
+
+// Expands to _Macro(0, _Data, e1) _Macro(1, _Data, e2) ... _Macro(K -1, _Data,
+// eK) as many of GMOCK_INTERNAL_NARG0 _Tuple.
+// Requires: * |_Macro| can be called with 3 arguments.
+// * |_Tuple| expansion has no more than 15 elements.
+#define GMOCK_PP_FOR_EACH(_Macro, _Data, _Tuple) \
+ GMOCK_PP_CAT(GMOCK_PP_INTERNAL_FOR_EACH_IMPL_, GMOCK_PP_NARG0 _Tuple) \
+ (0, _Macro, _Data, _Tuple)
+
+// Expands to _Macro(0, _Data, ) _Macro(1, _Data, ) ... _Macro(K - 1, _Data, )
+// Empty if _K = 0.
+// Requires: * |_Macro| can be called with 3 arguments.
+// * |_K| literal between 0 and 15
+#define GMOCK_PP_REPEAT(_Macro, _Data, _N) \
+ GMOCK_PP_CAT(GMOCK_PP_INTERNAL_FOR_EACH_IMPL_, _N) \
+ (0, _Macro, _Data, GMOCK_PP_INTENRAL_EMPTY_TUPLE)
+
+// Increments the argument, requires the argument to be between 0 and 15.
+#define GMOCK_PP_INC(_i) GMOCK_PP_CAT(GMOCK_PP_INTERNAL_INC_, _i)
+
+// Returns comma if _i != 0. Requires _i to be between 0 and 15.
+#define GMOCK_PP_COMMA_IF(_i) GMOCK_PP_CAT(GMOCK_PP_INTERNAL_COMMA_IF_, _i)
+
+// Internal details follow. Do not use any of these symbols outside of this
+// file or we will break your code.
+#define GMOCK_PP_INTENRAL_EMPTY_TUPLE (, , , , , , , , , , , , , , , )
+#define GMOCK_PP_INTERNAL_CAT(_1, _2) _1##_2
+#define GMOCK_PP_INTERNAL_STRINGIZE(...) #__VA_ARGS__
+#define GMOCK_PP_INTERNAL_INTERNAL_16TH(_1, _2, _3, _4, _5, _6, _7, _8, _9, \
+ _10, _11, _12, _13, _14, _15, _16, \
+ ...) \
+ _16
+#define GMOCK_PP_INTERNAL_CAT_5(_1, _2, _3, _4, _5) _1##_2##_3##_4##_5
+#define GMOCK_PP_INTERNAL_IS_EMPTY(_1, _2, _3, _4) \
+ GMOCK_PP_HAS_COMMA(GMOCK_PP_INTERNAL_CAT_5(GMOCK_PP_INTERNAL_IS_EMPTY_CASE_, \
+ _1, _2, _3, _4))
+#define GMOCK_PP_INTERNAL_IS_EMPTY_CASE_0001 ,
+#define GMOCK_PP_INTERNAL_IF_1(_Then, _Else) _Then
+#define GMOCK_PP_INTERNAL_IF_0(_Then, _Else) _Else
+#define GMOCK_PP_INTERNAL_HEAD(_1, ...) _1
+#define GMOCK_PP_INTERNAL_TAIL(_1, ...) __VA_ARGS__
+
+#if GMOCK_PP_INTERNAL_USE_MSVC
+#define GMOCK_PP_INTERNAL_NARG_CAT(_1, _2) GMOCK_PP_INTERNAL_NARG_CAT_I(_1, _2)
+#define GMOCK_PP_INTERNAL_HEAD_CAT(_1, _2) GMOCK_PP_INTERNAL_HEAD_CAT_I(_1, _2)
+#define GMOCK_PP_INTERNAL_HAS_COMMA_CAT(_1, _2) \
+ GMOCK_PP_INTERNAL_HAS_COMMA_CAT_I(_1, _2)
+#define GMOCK_PP_INTERNAL_TAIL_CAT(_1, _2) GMOCK_PP_INTERNAL_TAIL_CAT_I(_1, _2)
+#define GMOCK_PP_INTERNAL_VARIADIC_CALL_CAT(_1, _2) \
+ GMOCK_PP_INTERNAL_VARIADIC_CALL_CAT_I(_1, _2)
+#define GMOCK_PP_INTERNAL_NARG_CAT_I(_1, _2) _1##_2
+#define GMOCK_PP_INTERNAL_HEAD_CAT_I(_1, _2) _1##_2
+#define GMOCK_PP_INTERNAL_HAS_COMMA_CAT_I(_1, _2) _1##_2
+#define GMOCK_PP_INTERNAL_TAIL_CAT_I(_1, _2) _1##_2
+#define GMOCK_PP_INTERNAL_VARIADIC_CALL_CAT_I(_1, _2) _1##_2
+#define GMOCK_PP_INTERNAL_ALTERNATE_HEAD(...) \
+ GMOCK_PP_INTERNAL_ALTERNATE_HEAD_CAT(GMOCK_PP_HEAD(__VA_ARGS__), )
+#define GMOCK_PP_INTERNAL_ALTERNATE_HEAD_CAT(_1, _2) \
+ GMOCK_PP_INTERNAL_ALTERNATE_HEAD_CAT_I(_1, _2)
+#define GMOCK_PP_INTERNAL_ALTERNATE_HEAD_CAT_I(_1, _2) _1##_2
+#else // GMOCK_PP_INTERNAL_USE_MSVC
+#define GMOCK_PP_INTERNAL_ALTERNATE_HEAD(...) GMOCK_PP_HEAD(__VA_ARGS__)
+#endif // GMOCK_PP_INTERNAL_USE_MSVC
+
+#define GMOCK_PP_INTERNAL_IBP_IS_VARIADIC_C(...) 1 _
+#define GMOCK_PP_INTERNAL_IBP_IS_VARIADIC_R_1 1,
+#define GMOCK_PP_INTERNAL_IBP_IS_VARIADIC_R_GMOCK_PP_INTERNAL_IBP_IS_VARIADIC_C \
+ 0,
+#define GMOCK_PP_INTERNAL_REMOVE_PARENS(...) __VA_ARGS__
+#define GMOCK_PP_INTERNAL_INC_0 1
+#define GMOCK_PP_INTERNAL_INC_1 2
+#define GMOCK_PP_INTERNAL_INC_2 3
+#define GMOCK_PP_INTERNAL_INC_3 4
+#define GMOCK_PP_INTERNAL_INC_4 5
+#define GMOCK_PP_INTERNAL_INC_5 6
+#define GMOCK_PP_INTERNAL_INC_6 7
+#define GMOCK_PP_INTERNAL_INC_7 8
+#define GMOCK_PP_INTERNAL_INC_8 9
+#define GMOCK_PP_INTERNAL_INC_9 10
+#define GMOCK_PP_INTERNAL_INC_10 11
+#define GMOCK_PP_INTERNAL_INC_11 12
+#define GMOCK_PP_INTERNAL_INC_12 13
+#define GMOCK_PP_INTERNAL_INC_13 14
+#define GMOCK_PP_INTERNAL_INC_14 15
+#define GMOCK_PP_INTERNAL_INC_15 16
+#define GMOCK_PP_INTERNAL_COMMA_IF_0
+#define GMOCK_PP_INTERNAL_COMMA_IF_1 ,
+#define GMOCK_PP_INTERNAL_COMMA_IF_2 ,
+#define GMOCK_PP_INTERNAL_COMMA_IF_3 ,
+#define GMOCK_PP_INTERNAL_COMMA_IF_4 ,
+#define GMOCK_PP_INTERNAL_COMMA_IF_5 ,
+#define GMOCK_PP_INTERNAL_COMMA_IF_6 ,
+#define GMOCK_PP_INTERNAL_COMMA_IF_7 ,
+#define GMOCK_PP_INTERNAL_COMMA_IF_8 ,
+#define GMOCK_PP_INTERNAL_COMMA_IF_9 ,
+#define GMOCK_PP_INTERNAL_COMMA_IF_10 ,
+#define GMOCK_PP_INTERNAL_COMMA_IF_11 ,
+#define GMOCK_PP_INTERNAL_COMMA_IF_12 ,
+#define GMOCK_PP_INTERNAL_COMMA_IF_13 ,
+#define GMOCK_PP_INTERNAL_COMMA_IF_14 ,
+#define GMOCK_PP_INTERNAL_COMMA_IF_15 ,
+#define GMOCK_PP_INTERNAL_CALL_MACRO(_Macro, _i, _Data, _element) \
+ _Macro(_i, _Data, _element)
+#define GMOCK_PP_INTERNAL_FOR_EACH_IMPL_0(_i, _Macro, _Data, _Tuple)
+#define GMOCK_PP_INTERNAL_FOR_EACH_IMPL_1(_i, _Macro, _Data, _Tuple) \
+ GMOCK_PP_INTERNAL_CALL_MACRO(_Macro, _i, _Data, GMOCK_PP_HEAD _Tuple)
+#define GMOCK_PP_INTERNAL_FOR_EACH_IMPL_2(_i, _Macro, _Data, _Tuple) \
+ GMOCK_PP_INTERNAL_CALL_MACRO(_Macro, _i, _Data, GMOCK_PP_HEAD _Tuple) \
+ GMOCK_PP_INTERNAL_FOR_EACH_IMPL_1(GMOCK_PP_INC(_i), _Macro, _Data, \
+ (GMOCK_PP_TAIL _Tuple))
+#define GMOCK_PP_INTERNAL_FOR_EACH_IMPL_3(_i, _Macro, _Data, _Tuple) \
+ GMOCK_PP_INTERNAL_CALL_MACRO(_Macro, _i, _Data, GMOCK_PP_HEAD _Tuple) \
+ GMOCK_PP_INTERNAL_FOR_EACH_IMPL_2(GMOCK_PP_INC(_i), _Macro, _Data, \
+ (GMOCK_PP_TAIL _Tuple))
+#define GMOCK_PP_INTERNAL_FOR_EACH_IMPL_4(_i, _Macro, _Data, _Tuple) \
+ GMOCK_PP_INTERNAL_CALL_MACRO(_Macro, _i, _Data, GMOCK_PP_HEAD _Tuple) \
+ GMOCK_PP_INTERNAL_FOR_EACH_IMPL_3(GMOCK_PP_INC(_i), _Macro, _Data, \
+ (GMOCK_PP_TAIL _Tuple))
+#define GMOCK_PP_INTERNAL_FOR_EACH_IMPL_5(_i, _Macro, _Data, _Tuple) \
+ GMOCK_PP_INTERNAL_CALL_MACRO(_Macro, _i, _Data, GMOCK_PP_HEAD _Tuple) \
+ GMOCK_PP_INTERNAL_FOR_EACH_IMPL_4(GMOCK_PP_INC(_i), _Macro, _Data, \
+ (GMOCK_PP_TAIL _Tuple))
+#define GMOCK_PP_INTERNAL_FOR_EACH_IMPL_6(_i, _Macro, _Data, _Tuple) \
+ GMOCK_PP_INTERNAL_CALL_MACRO(_Macro, _i, _Data, GMOCK_PP_HEAD _Tuple) \
+ GMOCK_PP_INTERNAL_FOR_EACH_IMPL_5(GMOCK_PP_INC(_i), _Macro, _Data, \
+ (GMOCK_PP_TAIL _Tuple))
+#define GMOCK_PP_INTERNAL_FOR_EACH_IMPL_7(_i, _Macro, _Data, _Tuple) \
+ GMOCK_PP_INTERNAL_CALL_MACRO(_Macro, _i, _Data, GMOCK_PP_HEAD _Tuple) \
+ GMOCK_PP_INTERNAL_FOR_EACH_IMPL_6(GMOCK_PP_INC(_i), _Macro, _Data, \
+ (GMOCK_PP_TAIL _Tuple))
+#define GMOCK_PP_INTERNAL_FOR_EACH_IMPL_8(_i, _Macro, _Data, _Tuple) \
+ GMOCK_PP_INTERNAL_CALL_MACRO(_Macro, _i, _Data, GMOCK_PP_HEAD _Tuple) \
+ GMOCK_PP_INTERNAL_FOR_EACH_IMPL_7(GMOCK_PP_INC(_i), _Macro, _Data, \
+ (GMOCK_PP_TAIL _Tuple))
+#define GMOCK_PP_INTERNAL_FOR_EACH_IMPL_9(_i, _Macro, _Data, _Tuple) \
+ GMOCK_PP_INTERNAL_CALL_MACRO(_Macro, _i, _Data, GMOCK_PP_HEAD _Tuple) \
+ GMOCK_PP_INTERNAL_FOR_EACH_IMPL_8(GMOCK_PP_INC(_i), _Macro, _Data, \
+ (GMOCK_PP_TAIL _Tuple))
+#define GMOCK_PP_INTERNAL_FOR_EACH_IMPL_10(_i, _Macro, _Data, _Tuple) \
+ GMOCK_PP_INTERNAL_CALL_MACRO(_Macro, _i, _Data, GMOCK_PP_HEAD _Tuple) \
+ GMOCK_PP_INTERNAL_FOR_EACH_IMPL_9(GMOCK_PP_INC(_i), _Macro, _Data, \
+ (GMOCK_PP_TAIL _Tuple))
+#define GMOCK_PP_INTERNAL_FOR_EACH_IMPL_11(_i, _Macro, _Data, _Tuple) \
+ GMOCK_PP_INTERNAL_CALL_MACRO(_Macro, _i, _Data, GMOCK_PP_HEAD _Tuple) \
+ GMOCK_PP_INTERNAL_FOR_EACH_IMPL_10(GMOCK_PP_INC(_i), _Macro, _Data, \
+ (GMOCK_PP_TAIL _Tuple))
+#define GMOCK_PP_INTERNAL_FOR_EACH_IMPL_12(_i, _Macro, _Data, _Tuple) \
+ GMOCK_PP_INTERNAL_CALL_MACRO(_Macro, _i, _Data, GMOCK_PP_HEAD _Tuple) \
+ GMOCK_PP_INTERNAL_FOR_EACH_IMPL_11(GMOCK_PP_INC(_i), _Macro, _Data, \
+ (GMOCK_PP_TAIL _Tuple))
+#define GMOCK_PP_INTERNAL_FOR_EACH_IMPL_13(_i, _Macro, _Data, _Tuple) \
+ GMOCK_PP_INTERNAL_CALL_MACRO(_Macro, _i, _Data, GMOCK_PP_HEAD _Tuple) \
+ GMOCK_PP_INTERNAL_FOR_EACH_IMPL_12(GMOCK_PP_INC(_i), _Macro, _Data, \
+ (GMOCK_PP_TAIL _Tuple))
+#define GMOCK_PP_INTERNAL_FOR_EACH_IMPL_14(_i, _Macro, _Data, _Tuple) \
+ GMOCK_PP_INTERNAL_CALL_MACRO(_Macro, _i, _Data, GMOCK_PP_HEAD _Tuple) \
+ GMOCK_PP_INTERNAL_FOR_EACH_IMPL_13(GMOCK_PP_INC(_i), _Macro, _Data, \
+ (GMOCK_PP_TAIL _Tuple))
+#define GMOCK_PP_INTERNAL_FOR_EACH_IMPL_15(_i, _Macro, _Data, _Tuple) \
+ GMOCK_PP_INTERNAL_CALL_MACRO(_Macro, _i, _Data, GMOCK_PP_HEAD _Tuple) \
+ GMOCK_PP_INTERNAL_FOR_EACH_IMPL_14(GMOCK_PP_INC(_i), _Macro, _Data, \
+ (GMOCK_PP_TAIL _Tuple))
+
+#endif // THIRD_PARTY_GOOGLETEST_GOOGLEMOCK_INCLUDE_GMOCK_INTERNAL_GMOCK_PP_H_
diff --git a/extern/gmock/src/gmock-all.cc b/extern/gmock/src/gmock-all.cc
index 7aebce7afef..e43c9b7b4c1 100644
--- a/extern/gmock/src/gmock-all.cc
+++ b/extern/gmock/src/gmock-all.cc
@@ -26,8 +26,7 @@
// 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.
-//
-// Author: wan@google.com (Zhanyong Wan)
+
//
// Google C++ Mocking Framework (Google Mock)
//
diff --git a/extern/gmock/src/gmock-cardinalities.cc b/extern/gmock/src/gmock-cardinalities.cc
index 50ec7286eeb..7463f438323 100644
--- a/extern/gmock/src/gmock-cardinalities.cc
+++ b/extern/gmock/src/gmock-cardinalities.cc
@@ -26,8 +26,7 @@
// 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.
-//
-// Author: wan@google.com (Zhanyong Wan)
+
// Google Mock - a framework for writing C++ mock classes.
//
@@ -71,18 +70,18 @@ class BetweenCardinalityImpl : public CardinalityInterface {
// Conservative estimate on the lower/upper bound of the number of
// calls allowed.
- virtual int ConservativeLowerBound() const { return min_; }
- virtual int ConservativeUpperBound() const { return max_; }
+ int ConservativeLowerBound() const override { return min_; }
+ int ConservativeUpperBound() const override { return max_; }
- virtual bool IsSatisfiedByCallCount(int call_count) const {
+ bool IsSatisfiedByCallCount(int call_count) const override {
return min_ <= call_count && call_count <= max_;
}
- virtual bool IsSaturatedByCallCount(int call_count) const {
+ bool IsSaturatedByCallCount(int call_count) const override {
return call_count >= max_;
}
- virtual void DescribeTo(::std::ostream* os) const;
+ void DescribeTo(::std::ostream* os) const override;
private:
const int min_;
@@ -92,7 +91,7 @@ class BetweenCardinalityImpl : public CardinalityInterface {
};
// Formats "n times" in a human-friendly way.
-inline internal::string FormatTimes(int n) {
+inline std::string FormatTimes(int n) {
if (n == 1) {
return "once";
} else if (n == 2) {
diff --git a/extern/gmock/src/gmock-internal-utils.cc b/extern/gmock/src/gmock-internal-utils.cc
index fb5308018a7..e5b547981d1 100644
--- a/extern/gmock/src/gmock-internal-utils.cc
+++ b/extern/gmock/src/gmock-internal-utils.cc
@@ -26,8 +26,7 @@
// 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.
-//
-// Author: wan@google.com (Zhanyong Wan)
+
// Google Mock - a framework for writing C++ mock classes.
//
@@ -47,12 +46,31 @@
namespace testing {
namespace internal {
+// Joins a vector of strings as if they are fields of a tuple; returns
+// the joined string.
+GTEST_API_ std::string JoinAsTuple(const Strings& fields) {
+ switch (fields.size()) {
+ case 0:
+ return "";
+ case 1:
+ return fields[0];
+ default:
+ std::string result = "(" + fields[0];
+ for (size_t i = 1; i < fields.size(); i++) {
+ result += ", ";
+ result += fields[i];
+ }
+ result += ")";
+ return result;
+ }
+}
+
// Converts an identifier name to a space-separated list of lower-case
// words. Each maximum substring of the form [A-Za-z][a-z]*|\d+ is
// treated as one word. For example, both "FooBar123" and
// "foo_bar_123" are converted to "foo bar 123".
-GTEST_API_ string ConvertIdentifierNameToWords(const char* id_name) {
- string result;
+GTEST_API_ std::string ConvertIdentifierNameToWords(const char* id_name) {
+ std::string result;
char prev_char = '\0';
for (const char* p = id_name; *p != '\0'; prev_char = *(p++)) {
// We don't care about the current locale as the input is
@@ -71,12 +89,12 @@ GTEST_API_ string ConvertIdentifierNameToWords(const char* id_name) {
}
// This class reports Google Mock failures as Google Test failures. A
-// user can define another class in a similar fashion if he intends to
+// user can define another class in a similar fashion if they intend to
// use Google Mock with a testing framework other than Google Test.
class GoogleTestFailureReporter : public FailureReporterInterface {
public:
- virtual void ReportFailure(FailureType type, const char* file, int line,
- const string& message) {
+ void ReportFailure(FailureType type, const char* file, int line,
+ const std::string& message) override {
AssertHelper(type == kFatal ?
TestPartResult::kFatalFailure :
TestPartResult::kNonFatalFailure,
@@ -105,8 +123,8 @@ GTEST_API_ FailureReporterInterface* GetFailureReporter() {
// Protects global resources (stdout in particular) used by Log().
static GTEST_DEFINE_STATIC_MUTEX_(g_log_mutex);
-// Returns true iff a log with the given severity is visible according
-// to the --gmock_verbose flag.
+// Returns true if and only if a log with the given severity is visible
+// according to the --gmock_verbose flag.
GTEST_API_ bool LogIsVisible(LogSeverity severity) {
if (GMOCK_FLAG(verbose) == kInfoVerbosity) {
// Always show the log if --gmock_verbose=info.
@@ -121,15 +139,14 @@ GTEST_API_ bool LogIsVisible(LogSeverity severity) {
}
}
-// Prints the given message to stdout iff 'severity' >= the level
+// Prints the given message to stdout if and only if 'severity' >= the level
// specified by the --gmock_verbose flag. If stack_frames_to_skip >=
// 0, also prints the stack trace excluding the top
// stack_frames_to_skip frames. In opt mode, any positive
// stack_frames_to_skip is treated as 0, since we don't know which
// function calls will be inlined by the compiler and need to be
// conservative.
-GTEST_API_ void Log(LogSeverity severity,
- const string& message,
+GTEST_API_ void Log(LogSeverity severity, const std::string& message,
int stack_frames_to_skip) {
if (!LogIsVisible(severity))
return;
@@ -137,9 +154,6 @@ GTEST_API_ void Log(LogSeverity severity,
// Ensures that logs from different threads don't interleave.
MutexLock l(&g_log_mutex);
- // "using ::std::cout;" doesn't work with Symbian's STLport, where cout is a
- // macro.
-
if (severity == kWarning) {
// Prints a GMOCK WARNING marker to make the warnings easily searchable.
std::cout << "\nGMOCK WARNING:";
@@ -170,5 +184,17 @@ GTEST_API_ void Log(LogSeverity severity,
std::cout << ::std::flush;
}
+GTEST_API_ WithoutMatchers GetWithoutMatchers() { return WithoutMatchers(); }
+
+GTEST_API_ void IllegalDoDefault(const char* file, int line) {
+ internal::Assert(
+ false, file, line,
+ "You are using DoDefault() inside a composite action like "
+ "DoAll() or WithArgs(). This is not supported for technical "
+ "reasons. Please instead spell out the default action, or "
+ "assign the default action to an Action variable and use "
+ "the variable in various places.");
+}
+
} // namespace internal
} // namespace testing
diff --git a/extern/gmock/src/gmock-matchers.cc b/extern/gmock/src/gmock-matchers.cc
index e7424510fca..4a3f7af2351 100644
--- a/extern/gmock/src/gmock-matchers.cc
+++ b/extern/gmock/src/gmock-matchers.cc
@@ -26,8 +26,7 @@
// 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.
-//
-// Author: wan@google.com (Zhanyong Wan)
+
// Google Mock - a framework for writing C++ mock classes.
//
@@ -38,98 +37,23 @@
#include "gmock/gmock-generated-matchers.h"
#include <string.h>
+#include <iostream>
#include <sstream>
#include <string>
namespace testing {
-
-// Constructs a matcher that matches a const string& whose value is
-// equal to s.
-Matcher<const internal::string&>::Matcher(const internal::string& s) {
- *this = Eq(s);
-}
-
-// Constructs a matcher that matches a const string& whose value is
-// equal to s.
-Matcher<const internal::string&>::Matcher(const char* s) {
- *this = Eq(internal::string(s));
-}
-
-// Constructs a matcher that matches a string whose value is equal to s.
-Matcher<internal::string>::Matcher(const internal::string& s) { *this = Eq(s); }
-
-// Constructs a matcher that matches a string whose value is equal to s.
-Matcher<internal::string>::Matcher(const char* s) {
- *this = Eq(internal::string(s));
-}
-
-#if GTEST_HAS_STRING_PIECE_
-// Constructs a matcher that matches a const StringPiece& whose value is
-// equal to s.
-Matcher<const StringPiece&>::Matcher(const internal::string& s) {
- *this = Eq(s);
-}
-
-// Constructs a matcher that matches a const StringPiece& whose value is
-// equal to s.
-Matcher<const StringPiece&>::Matcher(const char* s) {
- *this = Eq(internal::string(s));
-}
-
-// Constructs a matcher that matches a const StringPiece& whose value is
-// equal to s.
-Matcher<const StringPiece&>::Matcher(StringPiece s) {
- *this = Eq(s.ToString());
-}
-
-// Constructs a matcher that matches a StringPiece whose value is equal to s.
-Matcher<StringPiece>::Matcher(const internal::string& s) {
- *this = Eq(s);
-}
-
-// Constructs a matcher that matches a StringPiece whose value is equal to s.
-Matcher<StringPiece>::Matcher(const char* s) {
- *this = Eq(internal::string(s));
-}
-
-// Constructs a matcher that matches a StringPiece whose value is equal to s.
-Matcher<StringPiece>::Matcher(StringPiece s) {
- *this = Eq(s.ToString());
-}
-#endif // GTEST_HAS_STRING_PIECE_
-
namespace internal {
-// Joins a vector of strings as if they are fields of a tuple; returns
-// the joined string.
-GTEST_API_ string JoinAsTuple(const Strings& fields) {
- switch (fields.size()) {
- case 0:
- return "";
- case 1:
- return fields[0];
- default:
- string result = "(" + fields[0];
- for (size_t i = 1; i < fields.size(); i++) {
- result += ", ";
- result += fields[i];
- }
- result += ")";
- return result;
- }
-}
-
// Returns the description for a matcher defined using the MATCHER*()
// macro where the user-supplied description string is "", if
// 'negation' is false; otherwise returns the description of the
// negation of the matcher. 'param_values' contains a list of strings
// that are the print-out of the matcher's parameters.
-GTEST_API_ string FormatMatcherDescription(bool negation,
- const char* matcher_name,
- const Strings& param_values) {
- string result = ConvertIdentifierNameToWords(matcher_name);
- if (param_values.size() >= 1)
- result += " " + JoinAsTuple(param_values);
+GTEST_API_ std::string FormatMatcherDescription(bool negation,
+ const char* matcher_name,
+ const Strings& param_values) {
+ std::string result = ConvertIdentifierNameToWords(matcher_name);
+ if (param_values.size() >= 1) result += " " + JoinAsTuple(param_values);
return negation ? "not (" + result + ")" : result;
}
@@ -200,8 +124,7 @@ class MaxBipartiteMatchState {
explicit MaxBipartiteMatchState(const MatchMatrix& graph)
: graph_(&graph),
left_(graph_->LhsSize(), kUnused),
- right_(graph_->RhsSize(), kUnused) {
- }
+ right_(graph_->RhsSize(), kUnused) {}
// Returns the edges of a maximal match, each in the form {left, right}.
ElementMatcherPairs Compute() {
@@ -258,10 +181,8 @@ class MaxBipartiteMatchState {
//
bool TryAugment(size_t ilhs, ::std::vector<char>* seen) {
for (size_t irhs = 0; irhs < graph_->RhsSize(); ++irhs) {
- if ((*seen)[irhs])
- continue;
- if (!graph_->HasEdge(ilhs, irhs))
- continue;
+ if ((*seen)[irhs]) continue;
+ if (!graph_->HasEdge(ilhs, irhs)) continue;
// There's an available edge from ilhs to irhs.
(*seen)[irhs] = 1;
// Next a search is performed to determine whether
@@ -288,7 +209,7 @@ class MaxBipartiteMatchState {
// Each element of the left_ vector represents a left hand side node
// (i.e. an element) and each element of right_ is a right hand side
// node (i.e. a matcher). The values in the left_ vector indicate
- // outflow from that node to a node on the the right_ side. The values
+ // outflow from that node to a node on the right_ side. The values
// in the right_ indicate inflow, and specify which left_ node is
// feeding that right_ node, if any. For example, left_[3] == 1 means
// there's a flow from element #3 to matcher #1. Such a flow would also
@@ -304,8 +225,7 @@ class MaxBipartiteMatchState {
const size_t MaxBipartiteMatchState::kUnused;
-GTEST_API_ ElementMatcherPairs
-FindMaxBipartiteMatching(const MatchMatrix& g) {
+GTEST_API_ ElementMatcherPairs FindMaxBipartiteMatching(const MatchMatrix& g) {
return MaxBipartiteMatchState(g).Compute();
}
@@ -314,7 +234,7 @@ static void LogElementMatcherPairVec(const ElementMatcherPairs& pairs,
typedef ElementMatcherPairs::const_iterator Iter;
::std::ostream& os = *stream;
os << "{";
- const char *sep = "";
+ const char* sep = "";
for (Iter it = pairs.begin(); it != pairs.end(); ++it) {
os << sep << "\n ("
<< "element #" << it->first << ", "
@@ -324,38 +244,6 @@ static void LogElementMatcherPairVec(const ElementMatcherPairs& pairs,
os << "\n}";
}
-// Tries to find a pairing, and explains the result.
-GTEST_API_ bool FindPairing(const MatchMatrix& matrix,
- MatchResultListener* listener) {
- ElementMatcherPairs matches = FindMaxBipartiteMatching(matrix);
-
- size_t max_flow = matches.size();
- bool result = (max_flow == matrix.RhsSize());
-
- if (!result) {
- if (listener->IsInterested()) {
- *listener << "where no permutation of the elements can "
- "satisfy all matchers, and the closest match is "
- << max_flow << " of " << matrix.RhsSize()
- << " matchers with the pairings:\n";
- LogElementMatcherPairVec(matches, listener->stream());
- }
- return false;
- }
-
- if (matches.size() > 1) {
- if (listener->IsInterested()) {
- const char *sep = "where:\n";
- for (size_t mi = 0; mi < matches.size(); ++mi) {
- *listener << sep << " - element #" << matches[mi].first
- << " is matched by matcher #" << matches[mi].second;
- sep = ",\n";
- }
- }
- }
- return true;
-}
-
bool MatchMatrix::NextGraph() {
for (size_t ilhs = 0; ilhs < LhsSize(); ++ilhs) {
for (size_t irhs = 0; irhs < RhsSize(); ++irhs) {
@@ -379,9 +267,9 @@ void MatchMatrix::Randomize() {
}
}
-string MatchMatrix::DebugString() const {
+std::string MatchMatrix::DebugString() const {
::std::stringstream ss;
- const char *sep = "";
+ const char* sep = "";
for (size_t i = 0; i < LhsSize(); ++i) {
ss << sep;
for (size_t j = 0; j < RhsSize(); ++j) {
@@ -394,44 +282,83 @@ string MatchMatrix::DebugString() const {
void UnorderedElementsAreMatcherImplBase::DescribeToImpl(
::std::ostream* os) const {
- if (matcher_describers_.empty()) {
- *os << "is empty";
- return;
- }
- if (matcher_describers_.size() == 1) {
- *os << "has " << Elements(1) << " and that element ";
- matcher_describers_[0]->DescribeTo(os);
- return;
+ switch (match_flags()) {
+ case UnorderedMatcherRequire::ExactMatch:
+ if (matcher_describers_.empty()) {
+ *os << "is empty";
+ return;
+ }
+ if (matcher_describers_.size() == 1) {
+ *os << "has " << Elements(1) << " and that element ";
+ matcher_describers_[0]->DescribeTo(os);
+ return;
+ }
+ *os << "has " << Elements(matcher_describers_.size())
+ << " and there exists some permutation of elements such that:\n";
+ break;
+ case UnorderedMatcherRequire::Superset:
+ *os << "a surjection from elements to requirements exists such that:\n";
+ break;
+ case UnorderedMatcherRequire::Subset:
+ *os << "an injection from elements to requirements exists such that:\n";
+ break;
}
- *os << "has " << Elements(matcher_describers_.size())
- << " and there exists some permutation of elements such that:\n";
+
const char* sep = "";
for (size_t i = 0; i != matcher_describers_.size(); ++i) {
- *os << sep << " - element #" << i << " ";
+ *os << sep;
+ if (match_flags() == UnorderedMatcherRequire::ExactMatch) {
+ *os << " - element #" << i << " ";
+ } else {
+ *os << " - an element ";
+ }
matcher_describers_[i]->DescribeTo(os);
- sep = ", and\n";
+ if (match_flags() == UnorderedMatcherRequire::ExactMatch) {
+ sep = ", and\n";
+ } else {
+ sep = "\n";
+ }
}
}
void UnorderedElementsAreMatcherImplBase::DescribeNegationToImpl(
::std::ostream* os) const {
- if (matcher_describers_.empty()) {
- *os << "isn't empty";
- return;
- }
- if (matcher_describers_.size() == 1) {
- *os << "doesn't have " << Elements(1)
- << ", or has " << Elements(1) << " that ";
- matcher_describers_[0]->DescribeNegationTo(os);
- return;
+ switch (match_flags()) {
+ case UnorderedMatcherRequire::ExactMatch:
+ if (matcher_describers_.empty()) {
+ *os << "isn't empty";
+ return;
+ }
+ if (matcher_describers_.size() == 1) {
+ *os << "doesn't have " << Elements(1) << ", or has " << Elements(1)
+ << " that ";
+ matcher_describers_[0]->DescribeNegationTo(os);
+ return;
+ }
+ *os << "doesn't have " << Elements(matcher_describers_.size())
+ << ", or there exists no permutation of elements such that:\n";
+ break;
+ case UnorderedMatcherRequire::Superset:
+ *os << "no surjection from elements to requirements exists such that:\n";
+ break;
+ case UnorderedMatcherRequire::Subset:
+ *os << "no injection from elements to requirements exists such that:\n";
+ break;
}
- *os << "doesn't have " << Elements(matcher_describers_.size())
- << ", or there exists no permutation of elements such that:\n";
const char* sep = "";
for (size_t i = 0; i != matcher_describers_.size(); ++i) {
- *os << sep << " - element #" << i << " ";
+ *os << sep;
+ if (match_flags() == UnorderedMatcherRequire::ExactMatch) {
+ *os << " - element #" << i << " ";
+ } else {
+ *os << " - an element ";
+ }
matcher_describers_[i]->DescribeTo(os);
- sep = ", and\n";
+ if (match_flags() == UnorderedMatcherRequire::ExactMatch) {
+ sep = ", and\n";
+ } else {
+ sep = "\n";
+ }
}
}
@@ -440,11 +367,9 @@ void UnorderedElementsAreMatcherImplBase::DescribeNegationToImpl(
// and better error reporting.
// Returns false, writing an explanation to 'listener', if and only
// if the success criteria are not met.
-bool UnorderedElementsAreMatcherImplBase::
-VerifyAllElementsAndMatchersAreMatched(
- const ::std::vector<string>& element_printouts,
- const MatchMatrix& matrix,
- MatchResultListener* listener) const {
+bool UnorderedElementsAreMatcherImplBase::VerifyMatchMatrix(
+ const ::std::vector<std::string>& element_printouts,
+ const MatchMatrix& matrix, MatchResultListener* listener) const {
bool result = true;
::std::vector<char> element_matched(matrix.LhsSize(), 0);
::std::vector<char> matcher_matched(matrix.RhsSize(), 0);
@@ -457,12 +382,11 @@ VerifyAllElementsAndMatchersAreMatched(
}
}
- {
+ if (match_flags() & UnorderedMatcherRequire::Superset) {
const char* sep =
"where the following matchers don't match any elements:\n";
for (size_t mi = 0; mi < matcher_matched.size(); ++mi) {
- if (matcher_matched[mi])
- continue;
+ if (matcher_matched[mi]) continue;
result = false;
if (listener->IsInterested()) {
*listener << sep << "matcher #" << mi << ": ";
@@ -472,7 +396,7 @@ VerifyAllElementsAndMatchersAreMatched(
}
}
- {
+ if (match_flags() & UnorderedMatcherRequire::Subset) {
const char* sep =
"where the following elements don't match any matchers:\n";
const char* outer_sep = "";
@@ -480,8 +404,7 @@ VerifyAllElementsAndMatchersAreMatched(
outer_sep = "\nand ";
}
for (size_t ei = 0; ei < element_matched.size(); ++ei) {
- if (element_matched[ei])
- continue;
+ if (element_matched[ei]) continue;
result = false;
if (listener->IsInterested()) {
*listener << outer_sep << sep << "element #" << ei << ": "
@@ -494,5 +417,46 @@ VerifyAllElementsAndMatchersAreMatched(
return result;
}
+bool UnorderedElementsAreMatcherImplBase::FindPairing(
+ const MatchMatrix& matrix, MatchResultListener* listener) const {
+ ElementMatcherPairs matches = FindMaxBipartiteMatching(matrix);
+
+ size_t max_flow = matches.size();
+ if ((match_flags() & UnorderedMatcherRequire::Superset) &&
+ max_flow < matrix.RhsSize()) {
+ if (listener->IsInterested()) {
+ *listener << "where no permutation of the elements can satisfy all "
+ "matchers, and the closest match is "
+ << max_flow << " of " << matrix.RhsSize()
+ << " matchers with the pairings:\n";
+ LogElementMatcherPairVec(matches, listener->stream());
+ }
+ return false;
+ }
+ if ((match_flags() & UnorderedMatcherRequire::Subset) &&
+ max_flow < matrix.LhsSize()) {
+ if (listener->IsInterested()) {
+ *listener
+ << "where not all elements can be matched, and the closest match is "
+ << max_flow << " of " << matrix.RhsSize()
+ << " matchers with the pairings:\n";
+ LogElementMatcherPairVec(matches, listener->stream());
+ }
+ return false;
+ }
+
+ if (matches.size() > 1) {
+ if (listener->IsInterested()) {
+ const char* sep = "where:\n";
+ for (size_t mi = 0; mi < matches.size(); ++mi) {
+ *listener << sep << " - element #" << matches[mi].first
+ << " is matched by matcher #" << matches[mi].second;
+ sep = ",\n";
+ }
+ }
+ }
+ return true;
+}
+
} // namespace internal
} // namespace testing
diff --git a/extern/gmock/src/gmock-spec-builders.cc b/extern/gmock/src/gmock-spec-builders.cc
index 95513420707..f9d3434560b 100644
--- a/extern/gmock/src/gmock-spec-builders.cc
+++ b/extern/gmock/src/gmock-spec-builders.cc
@@ -26,8 +26,7 @@
// 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.
-//
-// Author: wan@google.com (Zhanyong Wan)
+
// Google Mock - a framework for writing C++ mock classes.
//
@@ -39,8 +38,10 @@
#include <stdlib.h>
#include <iostream> // NOLINT
#include <map>
+#include <memory>
#include <set>
#include <string>
+#include <vector>
#include "gmock/gmock.h"
#include "gtest/gtest.h"
@@ -48,6 +49,15 @@
# include <unistd.h> // NOLINT
#endif
+// Silence C4800 (C4800: 'int *const ': forcing value
+// to bool 'true' or 'false') for MSVC 15
+#ifdef _MSC_VER
+#if _MSC_VER == 1900
+# pragma warning(push)
+# pragma warning(disable:4800)
+#endif
+#endif
+
namespace testing {
namespace internal {
@@ -58,16 +68,15 @@ GTEST_API_ GTEST_DEFINE_STATIC_MUTEX_(g_gmock_mutex);
// Logs a message including file and line number information.
GTEST_API_ void LogWithLocation(testing::internal::LogSeverity severity,
const char* file, int line,
- const string& message) {
+ const std::string& message) {
::std::ostringstream s;
s << file << ":" << line << ": " << message << ::std::endl;
Log(severity, s.str(), 0);
}
// Constructs an ExpectationBase object.
-ExpectationBase::ExpectationBase(const char* a_file,
- int a_line,
- const string& a_source_text)
+ExpectationBase::ExpectationBase(const char* a_file, int a_line,
+ const std::string& a_source_text)
: file_(a_file),
line_(a_line),
source_text_(a_source_text),
@@ -100,26 +109,40 @@ void ExpectationBase::RetireAllPreRequisites()
return;
}
- for (ExpectationSet::const_iterator it = immediate_prerequisites_.begin();
- it != immediate_prerequisites_.end(); ++it) {
- ExpectationBase* const prerequisite = it->expectation_base().get();
- if (!prerequisite->is_retired()) {
- prerequisite->RetireAllPreRequisites();
- prerequisite->Retire();
+ ::std::vector<ExpectationBase*> expectations(1, this);
+ while (!expectations.empty()) {
+ ExpectationBase* exp = expectations.back();
+ expectations.pop_back();
+
+ for (ExpectationSet::const_iterator it =
+ exp->immediate_prerequisites_.begin();
+ it != exp->immediate_prerequisites_.end(); ++it) {
+ ExpectationBase* next = it->expectation_base().get();
+ if (!next->is_retired()) {
+ next->Retire();
+ expectations.push_back(next);
+ }
}
}
}
-// Returns true iff all pre-requisites of this expectation have been
-// satisfied.
+// Returns true if and only if all pre-requisites of this expectation
+// have been satisfied.
bool ExpectationBase::AllPrerequisitesAreSatisfied() const
GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex) {
g_gmock_mutex.AssertHeld();
- for (ExpectationSet::const_iterator it = immediate_prerequisites_.begin();
- it != immediate_prerequisites_.end(); ++it) {
- if (!(it->expectation_base()->IsSatisfied()) ||
- !(it->expectation_base()->AllPrerequisitesAreSatisfied()))
- return false;
+ ::std::vector<const ExpectationBase*> expectations(1, this);
+ while (!expectations.empty()) {
+ const ExpectationBase* exp = expectations.back();
+ expectations.pop_back();
+
+ for (ExpectationSet::const_iterator it =
+ exp->immediate_prerequisites_.begin();
+ it != exp->immediate_prerequisites_.end(); ++it) {
+ const ExpectationBase* next = it->expectation_base().get();
+ if (!next->IsSatisfied()) return false;
+ expectations.push_back(next);
+ }
}
return true;
}
@@ -128,19 +151,28 @@ bool ExpectationBase::AllPrerequisitesAreSatisfied() const
void ExpectationBase::FindUnsatisfiedPrerequisites(ExpectationSet* result) const
GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex) {
g_gmock_mutex.AssertHeld();
- for (ExpectationSet::const_iterator it = immediate_prerequisites_.begin();
- it != immediate_prerequisites_.end(); ++it) {
- if (it->expectation_base()->IsSatisfied()) {
- // If *it is satisfied and has a call count of 0, some of its
- // pre-requisites may not be satisfied yet.
- if (it->expectation_base()->call_count_ == 0) {
- it->expectation_base()->FindUnsatisfiedPrerequisites(result);
+ ::std::vector<const ExpectationBase*> expectations(1, this);
+ while (!expectations.empty()) {
+ const ExpectationBase* exp = expectations.back();
+ expectations.pop_back();
+
+ for (ExpectationSet::const_iterator it =
+ exp->immediate_prerequisites_.begin();
+ it != exp->immediate_prerequisites_.end(); ++it) {
+ const ExpectationBase* next = it->expectation_base().get();
+
+ if (next->IsSatisfied()) {
+ // If *it is satisfied and has a call count of 0, some of its
+ // pre-requisites may not be satisfied yet.
+ if (next->call_count_ == 0) {
+ expectations.push_back(next);
+ }
+ } else {
+ // Now that we know next is unsatisfied, we are not so interested
+ // in whether its pre-requisites are satisfied. Therefore we
+ // don't iterate into it here.
+ *result += *it;
}
- } else {
- // Now that we know *it is unsatisfied, we are not so interested
- // in whether its pre-requisites are satisfied. Therefore we
- // don't recursively call FindUnsatisfiedPrerequisites() here.
- *result += *it;
}
}
}
@@ -244,7 +276,7 @@ GTEST_API_ ThreadLocal<Sequence*> g_gmock_implicit_sequence;
// Reports an uninteresting call (whose description is in msg) in the
// manner specified by 'reaction'.
-void ReportUninterestingCall(CallReaction reaction, const string& msg) {
+void ReportUninterestingCall(CallReaction reaction, const std::string& msg) {
// Include a stack trace only if --gmock_verbose=info is specified.
const int stack_frames_to_skip =
GMOCK_FLAG(verbose) == kInfoVerbosity ? 3 : -1;
@@ -255,20 +287,22 @@ void ReportUninterestingCall(CallReaction reaction, const string& msg) {
case kWarn:
Log(kWarning,
msg +
- "\nNOTE: You can safely ignore the above warning unless this "
- "call should not happen. Do not suppress it by blindly adding "
- "an EXPECT_CALL() if you don't mean to enforce the call. "
- "See https://github.com/google/googletest/blob/master/googlemock/docs/CookBook.md#"
- "knowing-when-to-expect for details.\n",
+ "\nNOTE: You can safely ignore the above warning unless this "
+ "call should not happen. Do not suppress it by blindly adding "
+ "an EXPECT_CALL() if you don't mean to enforce the call. "
+ "See "
+ "https://github.com/google/googletest/blob/master/googlemock/"
+ "docs/cook_book.md#"
+ "knowing-when-to-expect for details.\n",
stack_frames_to_skip);
break;
default: // FAIL
- Expect(false, NULL, -1, msg);
+ Expect(false, nullptr, -1, msg);
}
}
UntypedFunctionMockerBase::UntypedFunctionMockerBase()
- : mock_obj_(NULL), name_("") {}
+ : mock_obj_(nullptr), name_("") {}
UntypedFunctionMockerBase::~UntypedFunctionMockerBase() {}
@@ -307,7 +341,7 @@ const void* UntypedFunctionMockerBase::MockObject() const
// We protect mock_obj_ under g_gmock_mutex in case this mock
// function is called from two threads concurrently.
MutexLock l(&g_gmock_mutex);
- Assert(mock_obj_ != NULL, __FILE__, __LINE__,
+ Assert(mock_obj_ != nullptr, __FILE__, __LINE__,
"MockObject() must not be called before RegisterOwner() or "
"SetOwnerAndName() has been called.");
mock_obj = mock_obj_;
@@ -324,7 +358,7 @@ const char* UntypedFunctionMockerBase::Name() const
// We protect name_ under g_gmock_mutex in case this mock
// function is called from two threads concurrently.
MutexLock l(&g_gmock_mutex);
- Assert(name_ != NULL, __FILE__, __LINE__,
+ Assert(name_ != nullptr, __FILE__, __LINE__,
"Name() must not be called before SetOwnerAndName() has "
"been called.");
name = name_;
@@ -335,9 +369,10 @@ const char* UntypedFunctionMockerBase::Name() const
// Calculates the result of invoking this mock function with the given
// arguments, prints it, and returns it. The caller is responsible
// for deleting the result.
-UntypedActionResultHolderBase*
-UntypedFunctionMockerBase::UntypedInvokeWith(const void* const untyped_args)
- GTEST_LOCK_EXCLUDED_(g_gmock_mutex) {
+UntypedActionResultHolderBase* UntypedFunctionMockerBase::UntypedInvokeWith(
+ void* const untyped_args) GTEST_LOCK_EXCLUDED_(g_gmock_mutex) {
+ // See the definition of untyped_expectations_ for why access to it
+ // is unprotected here.
if (untyped_expectations_.size() == 0) {
// No expectation is set on this mock method - we have an
// uninteresting call.
@@ -349,23 +384,26 @@ UntypedFunctionMockerBase::UntypedInvokeWith(const void* const untyped_args)
const CallReaction reaction =
Mock::GetReactionOnUninterestingCalls(MockObject());
- // True iff we need to print this call's arguments and return
+ // True if and only if we need to print this call's arguments and return
// value. This definition must be kept in sync with
// the behavior of ReportUninterestingCall().
const bool need_to_report_uninteresting_call =
// If the user allows this uninteresting call, we print it
- // only when he wants informational messages.
+ // only when they want informational messages.
reaction == kAllow ? LogIsVisible(kInfo) :
- // If the user wants this to be a warning, we print it only
- // when he wants to see warnings.
- reaction == kWarn ? LogIsVisible(kWarning) :
- // Otherwise, the user wants this to be an error, and we
- // should always print detailed information in the error.
- true;
+ // If the user wants this to be a warning, we print
+ // it only when they want to see warnings.
+ reaction == kWarn
+ ? LogIsVisible(kWarning)
+ :
+ // Otherwise, the user wants this to be an error, and we
+ // should always print detailed information in the error.
+ true;
if (!need_to_report_uninteresting_call) {
// Perform the action without printing the call information.
- return this->UntypedPerformDefaultAction(untyped_args, "");
+ return this->UntypedPerformDefaultAction(
+ untyped_args, "Function call: " + std::string(Name()));
}
// Warns about the uninteresting call.
@@ -377,8 +415,7 @@ UntypedFunctionMockerBase::UntypedInvokeWith(const void* const untyped_args)
this->UntypedPerformDefaultAction(untyped_args, ss.str());
// Prints the function result.
- if (result != NULL)
- result->PrintAsActionResult(&ss);
+ if (result != nullptr) result->PrintAsActionResult(&ss);
ReportUninterestingCall(reaction, ss.str());
return result;
@@ -388,7 +425,7 @@ UntypedFunctionMockerBase::UntypedInvokeWith(const void* const untyped_args)
::std::stringstream ss;
::std::stringstream why;
::std::stringstream loc;
- const void* untyped_action = NULL;
+ const void* untyped_action = nullptr;
// The UntypedFindMatchingExpectation() function acquires and
// releases g_gmock_mutex.
@@ -396,19 +433,19 @@ UntypedFunctionMockerBase::UntypedInvokeWith(const void* const untyped_args)
this->UntypedFindMatchingExpectation(
untyped_args, &untyped_action, &is_excessive,
&ss, &why);
- const bool found = untyped_expectation != NULL;
+ const bool found = untyped_expectation != nullptr;
- // True iff we need to print the call's arguments and return value.
+ // True if and only if we need to print the call's arguments
+ // and return value.
// This definition must be kept in sync with the uses of Expect()
// and Log() in this function.
const bool need_to_report_call =
!found || is_excessive || LogIsVisible(kInfo);
if (!need_to_report_call) {
// Perform the action without printing the call information.
- return
- untyped_action == NULL ?
- this->UntypedPerformDefaultAction(untyped_args, "") :
- this->UntypedPerformAction(untyped_action, untyped_args);
+ return untyped_action == nullptr
+ ? this->UntypedPerformDefaultAction(untyped_args, "")
+ : this->UntypedPerformAction(untyped_action, untyped_args);
}
ss << " Function call: " << Name();
@@ -421,16 +458,15 @@ UntypedFunctionMockerBase::UntypedInvokeWith(const void* const untyped_args)
}
UntypedActionResultHolderBase* const result =
- untyped_action == NULL ?
- this->UntypedPerformDefaultAction(untyped_args, ss.str()) :
- this->UntypedPerformAction(untyped_action, untyped_args);
- if (result != NULL)
- result->PrintAsActionResult(&ss);
+ untyped_action == nullptr
+ ? this->UntypedPerformDefaultAction(untyped_args, ss.str())
+ : this->UntypedPerformAction(untyped_action, untyped_args);
+ if (result != nullptr) result->PrintAsActionResult(&ss);
ss << "\n" << why.str();
if (!found) {
// No expectation matches this call - reports a failure.
- Expect(false, NULL, -1, ss.str());
+ Expect(false, nullptr, -1, ss.str());
} else if (is_excessive) {
// We had an upper-bound violation and the failure message is in ss.
Expect(false, untyped_expectation->file(),
@@ -447,6 +483,8 @@ UntypedFunctionMockerBase::UntypedInvokeWith(const void* const untyped_args)
// Returns an Expectation object that references and co-owns exp,
// which must be an expectation on this mock function.
Expectation UntypedFunctionMockerBase::GetHandleOf(ExpectationBase* exp) {
+ // See the definition of untyped_expectations_ for why access to it
+ // is unprotected here.
for (UntypedExpectations::const_iterator it =
untyped_expectations_.begin();
it != untyped_expectations_.end(); ++it) {
@@ -509,6 +547,13 @@ bool UntypedFunctionMockerBase::VerifyAndClearExpectationsLocked()
return expectations_met;
}
+CallReaction intToCallReaction(int mock_behavior) {
+ if (mock_behavior >= kAllow && mock_behavior <= kFail) {
+ return static_cast<internal::CallReaction>(mock_behavior);
+ }
+ return kWarn;
+}
+
} // namespace internal
// Class Mock.
@@ -522,15 +567,15 @@ typedef std::set<internal::UntypedFunctionMockerBase*> FunctionMockers;
// expectations.
struct MockObjectState {
MockObjectState()
- : first_used_file(NULL), first_used_line(-1), leakable(false) {}
+ : first_used_file(nullptr), first_used_line(-1), leakable(false) {}
// Where in the source file an ON_CALL or EXPECT_CALL is first
// invoked on this mock object.
const char* first_used_file;
int first_used_line;
- ::std::string first_used_test_case;
+ ::std::string first_used_test_suite;
::std::string first_used_test;
- bool leakable; // true iff it's OK to leak the object.
+ bool leakable; // true if and only if it's OK to leak the object.
FunctionMockers function_mockers; // All registered methods of the object.
};
@@ -548,9 +593,6 @@ class MockObjectRegistry {
// object alive. Therefore we report any living object as test
// failure, unless the user explicitly asked us to ignore it.
~MockObjectRegistry() {
- // "using ::std::cout;" doesn't work with Symbian's STLport, where cout is
- // a macro.
-
if (!GMOCK_FLAG(catch_leaked_mocks))
return;
@@ -560,7 +602,7 @@ class MockObjectRegistry {
if (it->second.leakable) // The user said it's fine to leak this object.
continue;
- // TODO(wan@google.com): Print the type of the leaked object.
+ // FIXME: Print the type of the leaked object.
// This can help the user identify the leaked object.
std::cout << "\n";
const MockObjectState& state = it->second;
@@ -568,17 +610,23 @@ class MockObjectRegistry {
state.first_used_line);
std::cout << " ERROR: this mock object";
if (state.first_used_test != "") {
- std::cout << " (used in test " << state.first_used_test_case << "."
- << state.first_used_test << ")";
+ std::cout << " (used in test " << state.first_used_test_suite << "."
+ << state.first_used_test << ")";
}
std::cout << " should be deleted but never is. Its address is @"
<< it->first << ".";
leaked_count++;
}
if (leaked_count > 0) {
- std::cout << "\nERROR: " << leaked_count
- << " leaked mock " << (leaked_count == 1 ? "object" : "objects")
- << " found at program exit.\n";
+ std::cout << "\nERROR: " << leaked_count << " leaked mock "
+ << (leaked_count == 1 ? "object" : "objects")
+ << " found at program exit. Expectations on a mock object is "
+ "verified when the object is destructed. Leaking a mock "
+ "means that its expectations aren't verified, which is "
+ "usually a test bug. If you really intend to leak a mock, "
+ "you can suppress this error using "
+ "testing::Mock::AllowLeak(mock_object), or you may use a "
+ "fake or stub instead of a mock.\n";
std::cout.flush();
::std::cerr.flush();
// RUN_ALL_TESTS() has already returned when this destructor is
@@ -649,7 +697,8 @@ internal::CallReaction Mock::GetReactionOnUninterestingCalls(
GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex) {
internal::MutexLock l(&internal::g_gmock_mutex);
return (g_uninteresting_call_reaction.count(mock_obj) == 0) ?
- internal::kDefault : g_uninteresting_call_reaction[mock_obj];
+ internal::intToCallReaction(GMOCK_FLAG(default_mock_behavior)) :
+ g_uninteresting_call_reaction[mock_obj];
}
// Tells Google Mock to ignore mock_obj when checking for leaked mock
@@ -670,7 +719,7 @@ bool Mock::VerifyAndClearExpectations(void* mock_obj)
}
// Verifies all expectations on the given mock object and clears its
-// default actions and expectations. Returns true iff the
+// default actions and expectations. Returns true if and only if the
// verification was successful.
bool Mock::VerifyAndClear(void* mock_obj)
GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex) {
@@ -707,6 +756,19 @@ bool Mock::VerifyAndClearExpectationsLocked(void* mock_obj)
return expectations_met;
}
+bool Mock::IsNaggy(void* mock_obj)
+ GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex) {
+ return Mock::GetReactionOnUninterestingCalls(mock_obj) == internal::kWarn;
+}
+bool Mock::IsNice(void* mock_obj)
+ GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex) {
+ return Mock::GetReactionOnUninterestingCalls(mock_obj) == internal::kAllow;
+}
+bool Mock::IsStrict(void* mock_obj)
+ GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex) {
+ return Mock::GetReactionOnUninterestingCalls(mock_obj) == internal::kFail;
+}
+
// Registers a mock object and a mock method it owns.
void Mock::Register(const void* mock_obj,
internal::UntypedFunctionMockerBase* mocker)
@@ -723,16 +785,13 @@ void Mock::RegisterUseByOnCallOrExpectCall(const void* mock_obj,
GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex) {
internal::MutexLock l(&internal::g_gmock_mutex);
MockObjectState& state = g_mock_object_registry.states()[mock_obj];
- if (state.first_used_file == NULL) {
+ if (state.first_used_file == nullptr) {
state.first_used_file = file;
state.first_used_line = line;
const TestInfo* const test_info =
UnitTest::GetInstance()->current_test_info();
- if (test_info != NULL) {
- // TODO(wan@google.com): record the test case name when the
- // ON_CALL or EXPECT_CALL is invoked from SetUpTestCase() or
- // TearDownTestCase().
- state.first_used_test_case = test_info->test_case_name();
+ if (test_info != nullptr) {
+ state.first_used_test_suite = test_info->test_suite_name();
state.first_used_test = test_info->name();
}
}
@@ -785,7 +844,7 @@ void Mock::ClearDefaultActionsLocked(void* mock_obj)
Expectation::Expectation() {}
Expectation::Expectation(
- const internal::linked_ptr<internal::ExpectationBase>& an_expectation_base)
+ const std::shared_ptr<internal::ExpectationBase>& an_expectation_base)
: expectation_base_(an_expectation_base) {}
Expectation::~Expectation() {}
@@ -793,7 +852,7 @@ Expectation::~Expectation() {}
// Adds an expectation to a sequence.
void Sequence::AddExpectation(const Expectation& expectation) const {
if (*last_expectation_ != expectation) {
- if (last_expectation_->expectation_base() != NULL) {
+ if (last_expectation_->expectation_base() != nullptr) {
expectation.expectation_base()->immediate_prerequisites_
+= *last_expectation_;
}
@@ -803,7 +862,7 @@ void Sequence::AddExpectation(const Expectation& expectation) const {
// Creates the implicit sequence if there isn't one.
InSequence::InSequence() {
- if (internal::g_gmock_implicit_sequence.get() == NULL) {
+ if (internal::g_gmock_implicit_sequence.get() == nullptr) {
internal::g_gmock_implicit_sequence.set(new Sequence);
sequence_created_ = true;
} else {
@@ -816,8 +875,14 @@ InSequence::InSequence() {
InSequence::~InSequence() {
if (sequence_created_) {
delete internal::g_gmock_implicit_sequence.get();
- internal::g_gmock_implicit_sequence.set(NULL);
+ internal::g_gmock_implicit_sequence.set(nullptr);
}
}
} // namespace testing
+
+#ifdef _MSC_VER
+#if _MSC_VER == 1900
+# pragma warning(pop)
+#endif
+#endif
diff --git a/extern/gmock/src/gmock.cc b/extern/gmock/src/gmock.cc
index eac3d842ba0..32b2a7394fd 100644
--- a/extern/gmock/src/gmock.cc
+++ b/extern/gmock/src/gmock.cc
@@ -26,20 +26,16 @@
// 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.
-//
-// Author: wan@google.com (Zhanyong Wan)
+
#include "gmock/gmock.h"
#include "gmock/internal/gmock-port.h"
namespace testing {
-// TODO(wan@google.com): support using environment variables to
-// control the flag values, like what Google Test does.
-
GMOCK_DEFINE_bool_(catch_leaked_mocks, true,
- "true iff Google Mock should report leaked mock objects "
- "as failures.");
+ "true if and only if Google Mock should report leaked "
+ "mock objects as failures.");
GMOCK_DEFINE_string_(verbose, internal::kWarningVerbosity,
"Controls how verbose Google Mock's output is."
@@ -48,6 +44,13 @@ GMOCK_DEFINE_string_(verbose, internal::kWarningVerbosity,
" warning - prints warnings and errors.\n"
" error - prints errors only.");
+GMOCK_DEFINE_int32_(default_mock_behavior, 1,
+ "Controls the default behavior of mocks."
+ " Valid values:\n"
+ " 0 - by default, mocks act as NiceMocks.\n"
+ " 1 - by default, mocks act as NaggyMocks.\n"
+ " 2 - by default, mocks act as StrictMocks.");
+
namespace internal {
// Parses a string as a command line flag. The string should have the
@@ -59,12 +62,12 @@ static const char* ParseGoogleMockFlagValue(const char* str,
const char* flag,
bool def_optional) {
// str and flag must not be NULL.
- if (str == NULL || flag == NULL) return NULL;
+ if (str == nullptr || flag == nullptr) return nullptr;
// The flag must start with "--gmock_".
const std::string flag_str = std::string("--gmock_") + flag;
const size_t flag_len = flag_str.length();
- if (strncmp(str, flag_str.c_str(), flag_len) != 0) return NULL;
+ if (strncmp(str, flag_str.c_str(), flag_len) != 0) return nullptr;
// Skips the flag name.
const char* flag_end = str + flag_len;
@@ -77,7 +80,7 @@ static const char* ParseGoogleMockFlagValue(const char* str,
// If def_optional is true and there are more characters after the
// flag name, or if def_optional is false, there must be a '=' after
// the flag name.
- if (flag_end[0] != '=') return NULL;
+ if (flag_end[0] != '=') return nullptr;
// Returns the string after "=".
return flag_end + 1;
@@ -94,7 +97,7 @@ static bool ParseGoogleMockBoolFlag(const char* str, const char* flag,
const char* const value_str = ParseGoogleMockFlagValue(str, flag, true);
// Aborts if the parsing failed.
- if (value_str == NULL) return false;
+ if (value_str == nullptr) return false;
// Converts the string value to a bool.
*value = !(*value_str == '0' || *value_str == 'f' || *value_str == 'F');
@@ -113,13 +116,26 @@ static bool ParseGoogleMockStringFlag(const char* str, const char* flag,
const char* const value_str = ParseGoogleMockFlagValue(str, flag, false);
// Aborts if the parsing failed.
- if (value_str == NULL) return false;
+ if (value_str == nullptr) return false;
// Sets *value to the value of the flag.
*value = value_str;
return true;
}
+static bool ParseGoogleMockIntFlag(const char* str, const char* flag,
+ int* value) {
+ // Gets the value of the flag as a string.
+ const char* const value_str = ParseGoogleMockFlagValue(str, flag, true);
+
+ // Aborts if the parsing failed.
+ if (value_str == nullptr) return false;
+
+ // Sets *value to the value of the flag.
+ return ParseInt32(Message() << "The value of flag --" << flag,
+ value_str, value);
+}
+
// The internal implementation of InitGoogleMock().
//
// The type parameter CharType can be instantiated to either char or
@@ -138,7 +154,9 @@ void InitGoogleMockImpl(int* argc, CharType** argv) {
// Do we see a Google Mock flag?
if (ParseGoogleMockBoolFlag(arg, "catch_leaked_mocks",
&GMOCK_FLAG(catch_leaked_mocks)) ||
- ParseGoogleMockStringFlag(arg, "verbose", &GMOCK_FLAG(verbose))) {
+ ParseGoogleMockStringFlag(arg, "verbose", &GMOCK_FLAG(verbose)) ||
+ ParseGoogleMockIntFlag(arg, "default_mock_behavior",
+ &GMOCK_FLAG(default_mock_behavior))) {
// Yes. Shift the remainder of the argv list left by one. Note
// that argv has (*argc + 1) elements, the last one always being
// NULL. The following loop moves the trailing NULL element as
@@ -180,4 +198,16 @@ GTEST_API_ void InitGoogleMock(int* argc, wchar_t** argv) {
internal::InitGoogleMockImpl(argc, argv);
}
+// This overloaded version can be used on Arduino/embedded platforms where
+// there is no argc/argv.
+GTEST_API_ void InitGoogleMock() {
+ // Since Arduino doesn't have a command line, fake out the argc/argv arguments
+ int argc = 1;
+ const auto arg0 = "dummy";
+ char* argv0 = const_cast<char*>(arg0);
+ char** argv = &argv0;
+
+ internal::InitGoogleMockImpl(&argc, argv);
+}
+
} // namespace testing
diff --git a/extern/gmock/src/gmock_main.cc b/extern/gmock/src/gmock_main.cc
index bd5be03be22..98611b93535 100644
--- a/extern/gmock/src/gmock_main.cc
+++ b/extern/gmock/src/gmock_main.cc
@@ -26,18 +26,28 @@
// 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.
-//
-// Author: wan@google.com (Zhanyong Wan)
+
#include <iostream>
#include "gmock/gmock.h"
#include "gtest/gtest.h"
+#ifdef ARDUINO
+void setup() {
+ // Since Google Mock depends on Google Test, InitGoogleMock() is
+ // also responsible for initializing Google Test. Therefore there's
+ // no need for calling testing::InitGoogleTest() separately.
+ testing::InitGoogleMock();
+}
+void loop() { RUN_ALL_TESTS(); }
+#else
+
// MS C++ compiler/linker has a bug on Windows (not on Windows CE), which
// causes a link error when _tmain is defined in a static library and UNICODE
// is enabled. For this reason instead of _tmain, main function is used on
// Windows. See the following link to track the current status of this bug:
-// http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=394464 // NOLINT
+// https://web.archive.org/web/20170912203238/connect.microsoft.com/VisualStudio/feedback/details/394464/wmain-link-error-in-the-static-library
+// // NOLINT
#if GTEST_OS_WINDOWS_MOBILE
# include <tchar.h> // NOLINT
@@ -52,3 +62,4 @@ GTEST_API_ int main(int argc, char** argv) {
testing::InitGoogleMock(&argc, argv);
return RUN_ALL_TESTS();
}
+#endif
diff --git a/extern/gtest/CHANGES b/extern/gtest/CHANGES
new file mode 100644
index 00000000000..05521324212
--- /dev/null
+++ b/extern/gtest/CHANGES
@@ -0,0 +1,157 @@
+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
+ given source location -- useful for writing testing utilities.
+* New feature: the universal value printer is moved from Google Mock
+ to Google Test.
+* New feature: type parameters and value parameters are reported in
+ the XML report now.
+* A gtest_disable_pthreads CMake option.
+* Colored output works in GNU Screen sessions now.
+* Parameters of value-parameterized tests are now printed in the
+ textual output.
+* Failures from ad hoc test assertions run before RUN_ALL_TESTS() are
+ now correctly reported.
+* Arguments of ASSERT_XY and EXPECT_XY no longer need to support << to
+ ostream.
+* More complete handling of exceptions.
+* GTEST_ASSERT_XY can be used instead of ASSERT_XY in case the latter
+ name is already used by another library.
+* --gtest_catch_exceptions is now true by default, allowing a test
+ program to continue after an exception is thrown.
+* Value-parameterized test fixtures can now derive from Test and
+ WithParamInterface<T> separately, easing conversion of legacy tests.
+* Death test messages are clearly marked to make them more
+ distinguishable from other messages.
+* Compatibility fixes for Android, Google Native Client, MinGW, HP UX,
+ PowerPC, Lucid autotools, libCStd, Sun C++, Borland C++ Builder (Code Gear),
+ IBM XL C++ (Visual Age C++), and C++0x.
+* Bug fixes and implementation clean-ups.
+* Potentially incompatible changes: disables the harmful 'make install'
+ command in autotools.
+
+Changes for 1.5.0:
+
+ * New feature: assertions can be safely called in multiple threads
+ where the pthreads library is available.
+ * New feature: predicates used inside EXPECT_TRUE() and friends
+ can now generate custom failure messages.
+ * New feature: Google Test can now be compiled as a DLL.
+ * New feature: fused source files are included.
+ * New feature: prints help when encountering unrecognized Google Test flags.
+ * Experimental feature: CMake build script (requires CMake 2.6.4+).
+ * Experimental feature: the Pump script for meta programming.
+ * double values streamed to an assertion are printed with enough precision
+ to differentiate any two different values.
+ * Google Test now works on Solaris and AIX.
+ * Build and test script improvements.
+ * Bug fixes and implementation clean-ups.
+
+ Potentially breaking changes:
+
+ * Stopped supporting VC++ 7.1 with exceptions disabled.
+ * Dropped support for 'make install'.
+
+Changes for 1.4.0:
+
+ * New feature: the event listener API
+ * New feature: test shuffling
+ * New feature: the XML report format is closer to junitreport and can
+ be parsed by Hudson now.
+ * New feature: when a test runs under Visual Studio, its failures are
+ integrated in the IDE.
+ * New feature: /MD(d) versions of VC++ projects.
+ * New feature: elapsed time for the tests is printed by default.
+ * New feature: comes with a TR1 tuple implementation such that Boost
+ is no longer needed for Combine().
+ * New feature: EXPECT_DEATH_IF_SUPPORTED macro and friends.
+ * New feature: the Xcode project can now produce static gtest
+ libraries in addition to a framework.
+ * Compatibility fixes for Solaris, Cygwin, minGW, Windows Mobile,
+ Symbian, gcc, and C++Builder.
+ * Bug fixes and implementation clean-ups.
+
+Changes for 1.3.0:
+
+ * New feature: death tests on Windows, Cygwin, and Mac.
+ * New feature: ability to use Google Test assertions in other testing
+ frameworks.
+ * New feature: ability to run disabled test via
+ --gtest_also_run_disabled_tests.
+ * New feature: the --help flag for printing the usage.
+ * New feature: access to Google Test flag values in user code.
+ * New feature: a script that packs Google Test into one .h and one
+ .cc file for easy deployment.
+ * New feature: support for distributing test functions to multiple
+ machines (requires support from the test runner).
+ * Bug fixes and implementation clean-ups.
+
+Changes for 1.2.1:
+
+ * Compatibility fixes for Linux IA-64 and IBM z/OS.
+ * Added support for using Boost and other TR1 implementations.
+ * Changes to the build scripts to support upcoming release of Google C++
+ Mocking Framework.
+ * Added Makefile to the distribution package.
+ * Improved build instructions in README.
+
+Changes for 1.2.0:
+
+ * New feature: value-parameterized tests.
+ * New feature: the ASSERT/EXPECT_(NON)FATAL_FAILURE(_ON_ALL_THREADS)
+ macros.
+ * Changed the XML report format to match JUnit/Ant's.
+ * Added tests to the Xcode project.
+ * Added scons/SConscript for building with SCons.
+ * Added src/gtest-all.cc for building Google Test from a single file.
+ * Fixed compatibility with Solaris and z/OS.
+ * Enabled running Python tests on systems with python 2.3 installed,
+ e.g. Mac OS X 10.4.
+ * Bug fixes.
+
+Changes for 1.1.0:
+
+ * New feature: type-parameterized tests.
+ * New feature: exception assertions.
+ * New feature: printing elapsed time of tests.
+ * Improved the robustness of death tests.
+ * Added an Xcode project and samples.
+ * Adjusted the output format on Windows to be understandable by Visual Studio.
+ * Minor bug fixes.
+
+Changes for 1.0.1:
+
+ * Added project files for Visual Studio 7.1.
+ * Fixed issues with compiling on Mac OS X.
+ * Fixed issues with compiling on Cygwin.
+
+Changes for 1.0.0:
+
+ * Initial Open Source release of Google Test
diff --git a/extern/gtest/CMakeLists.txt b/extern/gtest/CMakeLists.txt
index 056b32cc99e..42a1cd6fbc7 100644
--- a/extern/gtest/CMakeLists.txt
+++ b/extern/gtest/CMakeLists.txt
@@ -35,34 +35,41 @@ set(INC_SYS
)
set(SRC
+ # src/gtest-all.cc
+ # src/gtest_main.cc
+
src/gtest.cc
src/gtest-death-test.cc
src/gtest-filepath.cc
+ src/gtest-matchers.cc
src/gtest-port.cc
src/gtest-printers.cc
src/gtest-test-part.cc
src/gtest-typed-test.cc
src/gtest-internal-inl.h
- include/gtest/gtest-death-test.h
+
include/gtest/gtest.h
+ include/gtest/gtest_pred_impl.h
+ include/gtest/gtest_prod.h
+ include/gtest/gtest-death-test.h
+ include/gtest/gtest-matchers.h
include/gtest/gtest-message.h
include/gtest/gtest-param-test.h
- include/gtest/gtest_pred_impl.h
include/gtest/gtest-printers.h
- include/gtest/gtest_prod.h
include/gtest/gtest-spi.h
include/gtest/gtest-test-part.h
include/gtest/gtest-typed-test.h
+ include/gtest/internal/custom/gtest.h
+ include/gtest/internal/custom/gtest-port.h
+ include/gtest/internal/custom/gtest-printers.h
include/gtest/internal/gtest-death-test-internal.h
include/gtest/internal/gtest-filepath.h
include/gtest/internal/gtest-internal.h
- include/gtest/internal/gtest-linked_ptr.h
- include/gtest/internal/gtest-param-util-generated.h
include/gtest/internal/gtest-param-util.h
include/gtest/internal/gtest-port.h
+ include/gtest/internal/gtest-port-arch.h
include/gtest/internal/gtest-string.h
- include/gtest/internal/gtest-tuple.h
include/gtest/internal/gtest-type-util.h
)
diff --git a/extern/gtest/CONTRIBUTORS b/extern/gtest/CONTRIBUTORS
new file mode 100644
index 00000000000..feae2fc0441
--- /dev/null
+++ b/extern/gtest/CONTRIBUTORS
@@ -0,0 +1,37 @@
+# This file contains a list of people who've made non-trivial
+# contribution to the Google C++ Testing Framework project. People
+# who commit code to the project are encouraged to add their names
+# here. Please keep the list sorted by first names.
+
+Ajay Joshi <jaj@google.com>
+Balázs Dán <balazs.dan@gmail.com>
+Bharat Mediratta <bharat@menalto.com>
+Chandler Carruth <chandlerc@google.com>
+Chris Prince <cprince@google.com>
+Chris Taylor <taylorc@google.com>
+Dan Egnor <egnor@google.com>
+Eric Roman <eroman@chromium.org>
+Hady Zalek <hady.zalek@gmail.com>
+Jeffrey Yasskin <jyasskin@google.com>
+Jói Sigurðsson <joi@google.com>
+Keir Mierle <mierle@gmail.com>
+Keith Ray <keith.ray@gmail.com>
+Kenton Varda <kenton@google.com>
+Manuel Klimek <klimek@google.com>
+Markus Heule <markus.heule@gmail.com>
+Mika Raento <mikie@iki.fi>
+Miklós Fazekas <mfazekas@szemafor.com>
+Pasi Valminen <pasi.valminen@gmail.com>
+Patrick Hanna <phanna@google.com>
+Patrick Riley <pfr@google.com>
+Peter Kaminski <piotrk@google.com>
+Preston Jackson <preston.a.jackson@gmail.com>
+Rainer Klaffenboeck <rainer.klaffenboeck@dynatrace.com>
+Russ Cox <rsc@google.com>
+Russ Rufer <russ@pentad.com>
+Sean Mcafee <eefacm@gmail.com>
+Sigurður Ásgeirsson <siggi@google.com>
+Tracy Bialik <tracy@pentad.com>
+Vadim Berman <vadimb@google.com>
+Vlad Losev <vladl@google.com>
+Zhanyong Wan <wan@google.com>
diff --git a/extern/gtest/README.blender b/extern/gtest/README.blender
index 6165bd6f717..3f9d80362d8 100644
--- a/extern/gtest/README.blender
+++ b/extern/gtest/README.blender
@@ -1,7 +1,5 @@
Project: Google C++ Testing Framework
URL: https://github.com/google/googletest
License: New BSD
-Upstream version: 1.8.0 (ec44c6c1675)
-Local modifications:
-
-None.
+Upstream version: 1.10.0 (703bd9caab5)
+Local modifications: None
diff --git a/extern/gtest/README.md b/extern/gtest/README.md
index 22df99bd4b0..fe569414864 100644
--- a/extern/gtest/README.md
+++ b/extern/gtest/README.md
@@ -2,6 +2,13 @@
# Google Test #
[![Build Status](https://travis-ci.org/google/googletest.svg?branch=master)](https://travis-ci.org/google/googletest)
+[![Build status](https://ci.appveyor.com/api/projects/status/4o38plt0xbo1ubc8/branch/master?svg=true)](https://ci.appveyor.com/project/GoogleTestAppVeyor/googletest/branch/master)
+
+**Future Plans**:
+* 1.8.x Release - the 1.8.x will be the last release that works with pre-C++11 compilers. The 1.8.x will not accept any requests for any new features and any bugfix requests will only be accepted if proven "critical"
+* Post 1.8.x - work to improve/cleanup/pay technical debt. When this work is completed there will be a 1.9.x tagged release
+* Post 1.9.x googletest will follow [Abseil Live at Head philosophy](https://abseil.io/about/philosophy)
+
Welcome to **Google Test**, Google's C++ test framework!
@@ -11,9 +18,12 @@ maintain and release them together.
Please see the project page above for more information as well as the
mailing list for questions, discussions, and development. There is
-also an IRC channel on OFTC (irc.oftc.net) #gtest available. Please
+also an IRC channel on [OFTC](https://webchat.oftc.net/) (irc.oftc.net) #gtest available. Please
join us!
+Getting started information for **Google Test** is available in the
+[Google Test Primer](googletest/docs/primer.md) documentation.
+
**Google Mock** is an extension to Google Test for writing and using C++ mock
classes. See the separate [Google Mock documentation](googlemock/README.md).
@@ -22,7 +32,7 @@ in its interior [googletest/README.md](googletest/README.md) file.
## Features ##
- * An [XUnit](https://en.wikipedia.org/wiki/XUnit) test framework.
+ * An [xUnit](https://en.wikipedia.org/wiki/XUnit) test framework.
* Test discovery.
* A rich set of assertions.
* User-defined assertions.
@@ -56,9 +66,12 @@ the following notable projects:
* [Protocol Buffers](https://github.com/google/protobuf), Google's data
interchange format.
* The [OpenCV](http://opencv.org/) computer vision library.
+ * [tiny-dnn](https://github.com/tiny-dnn/tiny-dnn): header only, dependency-free deep learning framework in C++11.
## Related Open Source Projects ##
+[GTest Runner](https://github.com/nholthaus/gtest-runner) is a Qt5 based automated test-runner and Graphical User Interface with powerful features for Windows and Linux platforms.
+
[Google Test UI](https://github.com/ospector/gtest-gbar) is test runner that runs
your test binary, allows you to track its progress via a progress bar, and
displays a list of test failures. Clicking on one shows failure text. Google
@@ -69,6 +82,11 @@ listener for Google Test that implements the
[TAP protocol](https://en.wikipedia.org/wiki/Test_Anything_Protocol) for test
result output. If your test runner understands TAP, you may find it useful.
+[gtest-parallel](https://github.com/google/gtest-parallel) is a test runner that
+runs tests from your binary in parallel to provide significant speed-up.
+
+[GoogleTest Adapter](https://marketplace.visualstudio.com/items?itemName=DavidSchuldenfrei.gtest-adapter) is a VS Code extension allowing to view Google Tests in a tree view, and run/debug your tests.
+
## Requirements ##
Google Test is designed to have fairly minimal requirements to build
@@ -78,7 +96,7 @@ effort to support other platforms (e.g. Solaris, AIX, and z/OS).
However, since core members of the Google Test project have no access
to these platforms, Google Test may have outstanding issues there. If
you notice any problems on your platform, please notify
-<googletestframework@googlegroups.com>. Patches for fixing them are
+[googletestframework@googlegroups.com](https://groups.google.com/forum/#!forum/googletestframework). Patches for fixing them are
even more welcome!
### Linux Requirements ###
@@ -93,7 +111,7 @@ package (as described below):
### Windows Requirements ###
- * Microsoft Visual C++ v7.1 or newer
+ * Microsoft Visual C++ 2015 or newer
### Cygwin Requirements ###
@@ -102,37 +120,11 @@ package (as described below):
### Mac OS X Requirements ###
* Mac OS X v10.4 Tiger or newer
- * XCode Developer Tools
-
-### Requirements for Contributors ###
-
-We welcome patches. If you plan to contribute a patch, you need to
-build Google Test and its own tests from a git checkout (described
-below), which has further requirements:
-
- * [Python](https://www.python.org/) v2.3 or newer (for running some of
- the tests and re-generating certain source files from templates)
- * [CMake](https://cmake.org/) v2.6.4 or newer
-
-## Regenerating Source Files ##
-
-Some of Google Test's source files are generated from templates (not
-in the C++ sense) using a script.
-For example, the
-file include/gtest/internal/gtest-type-util.h.pump is used to generate
-gtest-type-util.h in the same directory.
-
-You don't need to worry about regenerating the source files
-unless you need to modify them. You would then modify the
-corresponding `.pump` files and run the '[pump.py](googletest/scripts/pump.py)'
-generator script. See the [Pump Manual](googletest/docs/PumpManual.md).
+ * Xcode Developer Tools
-### Contributing Code ###
+## Contributing change
-We welcome patches. Please read the
-[Developer's Guide](googletest/docs/DevGuide.md)
-for how you can contribute. In particular, make sure you have signed
-the Contributor License Agreement, or we won't be able to accept the
-patch.
+Please read the [`CONTRIBUTING.md`](CONTRIBUTING.md) for details on
+how to contribute to this project.
Happy testing!
diff --git a/extern/gtest/include/gtest/gtest-death-test.h b/extern/gtest/include/gtest/gtest-death-test.h
index 957a69c6a9e..dc878ffbb3a 100644
--- a/extern/gtest/include/gtest/gtest-death-test.h
+++ b/extern/gtest/include/gtest/gtest-death-test.h
@@ -26,14 +26,14 @@
// 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.
+
//
-// Author: wan@google.com (Zhanyong Wan)
-//
-// The Google C++ Testing Framework (Google Test)
+// The Google C++ Testing and Mocking Framework (Google Test)
//
// This header file defines the public API for death tests. It is
// #included by gtest.h so a user doesn't need to include this
// directly.
+// GOOGLETEST_CM0001 DO NOT DELETE
#ifndef GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_
#define GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_
@@ -99,10 +99,11 @@ GTEST_API_ bool InDeathTestChild();
//
// On the regular expressions used in death tests:
//
+// GOOGLETEST_CM0005 DO NOT DELETE
// On POSIX-compliant systems (*nix), we use the <regex.h> library,
// which uses the POSIX extended regex syntax.
//
-// On other platforms (e.g. Windows), we only support a simple regex
+// On other platforms (e.g. Windows or Mac), we only support a simple regex
// syntax implemented as part of Google Test. This limited
// implementation should be enough most of the time when writing
// death tests; though it lacks many features you can find in PCRE
@@ -160,7 +161,6 @@ GTEST_API_ bool InDeathTestChild();
// is rarely a problem as people usually don't put the test binary
// directory in PATH.
//
-// TODO(wan@google.com): make thread-safe death tests search the PATH.
// Asserts that a given statement causes the program to exit, with an
// integer exit status that satisfies predicate, and emitting error output
@@ -169,7 +169,7 @@ GTEST_API_ bool InDeathTestChild();
GTEST_DEATH_TEST_(statement, predicate, regex, GTEST_FATAL_FAILURE_)
// Like ASSERT_EXIT, but continues on to successive tests in the
-// test case, if any:
+// test suite, if any:
# define EXPECT_EXIT(statement, predicate, regex) \
GTEST_DEATH_TEST_(statement, predicate, regex, GTEST_NONFATAL_FAILURE_)
@@ -180,7 +180,7 @@ GTEST_API_ bool InDeathTestChild();
ASSERT_EXIT(statement, ::testing::internal::ExitedUnsuccessfully, regex)
// Like ASSERT_DEATH, but continues on to successive tests in the
-// test case, if any:
+// test suite, if any:
# define EXPECT_DEATH(statement, regex) \
EXPECT_EXIT(statement, ::testing::internal::ExitedUnsuccessfully, regex)
@@ -198,9 +198,10 @@ class GTEST_API_ ExitedWithCode {
const int exit_code_;
};
-# if !GTEST_OS_WINDOWS
+# if !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA
// Tests that an exit code describes an exit due to termination by a
// given signal.
+// GOOGLETEST_CM0006 DO NOT DELETE
class GTEST_API_ KilledBySignal {
public:
explicit KilledBySignal(int signum);
@@ -226,7 +227,7 @@ class GTEST_API_ KilledBySignal {
// return 12;
// }
//
-// TEST(TestCase, TestDieOr12WorksInDgbAndOpt) {
+// TEST(TestSuite, TestDieOr12WorksInDgbAndOpt) {
// int sideeffect = 0;
// // Only asserts in dbg.
// EXPECT_DEBUG_DEATH(DieInDebugOr12(&sideeffect), "death");
@@ -272,6 +273,54 @@ class GTEST_API_ KilledBySignal {
# endif // NDEBUG for EXPECT_DEBUG_DEATH
#endif // GTEST_HAS_DEATH_TEST
+// This macro is used for implementing macros such as
+// EXPECT_DEATH_IF_SUPPORTED and ASSERT_DEATH_IF_SUPPORTED on systems where
+// death tests are not supported. Those macros must compile on such systems
+// if and only if EXPECT_DEATH and ASSERT_DEATH compile with the same parameters
+// on systems that support death tests. This allows one to write such a macro on
+// a system that does not support death tests and be sure that it will compile
+// on a death-test supporting system. It is exposed publicly so that systems
+// that have death-tests with stricter requirements than GTEST_HAS_DEATH_TEST
+// can write their own equivalent of EXPECT_DEATH_IF_SUPPORTED and
+// ASSERT_DEATH_IF_SUPPORTED.
+//
+// Parameters:
+// statement - A statement that a macro such as EXPECT_DEATH would test
+// for program termination. This macro has to make sure this
+// statement is compiled but not executed, to ensure that
+// EXPECT_DEATH_IF_SUPPORTED compiles with a certain
+// parameter if and only if EXPECT_DEATH compiles with it.
+// regex - A regex that a macro such as EXPECT_DEATH would use to test
+// the output of statement. This parameter has to be
+// compiled but not evaluated by this macro, to ensure that
+// this macro only accepts expressions that a macro such as
+// EXPECT_DEATH would accept.
+// terminator - Must be an empty statement for EXPECT_DEATH_IF_SUPPORTED
+// and a return statement for ASSERT_DEATH_IF_SUPPORTED.
+// This ensures that ASSERT_DEATH_IF_SUPPORTED will not
+// compile inside functions where ASSERT_DEATH doesn't
+// compile.
+//
+// The branch that has an always false condition is used to ensure that
+// statement and regex are compiled (and thus syntactically correct) but
+// never executed. The unreachable code macro protects the terminator
+// statement from generating an 'unreachable code' warning in case
+// statement unconditionally returns or throws. The Message constructor at
+// the end allows the syntax of streaming additional messages into the
+// macro, for compilational compatibility with EXPECT_DEATH/ASSERT_DEATH.
+# define GTEST_UNSUPPORTED_DEATH_TEST(statement, regex, terminator) \
+ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
+ if (::testing::internal::AlwaysTrue()) { \
+ GTEST_LOG_(WARNING) \
+ << "Death tests are not supported on this platform.\n" \
+ << "Statement '" #statement "' cannot be verified."; \
+ } else if (::testing::internal::AlwaysFalse()) { \
+ ::testing::internal::RE::PartialMatch(".*", (regex)); \
+ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
+ terminator; \
+ } else \
+ ::testing::Message()
+
// EXPECT_DEATH_IF_SUPPORTED(statement, regex) and
// ASSERT_DEATH_IF_SUPPORTED(statement, regex) expand to real death tests if
// death tests are supported; otherwise they just issue a warning. This is
@@ -284,9 +333,9 @@ class GTEST_API_ KilledBySignal {
ASSERT_DEATH(statement, regex)
#else
# define EXPECT_DEATH_IF_SUPPORTED(statement, regex) \
- GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, )
+ GTEST_UNSUPPORTED_DEATH_TEST(statement, regex, )
# define ASSERT_DEATH_IF_SUPPORTED(statement, regex) \
- GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, return)
+ GTEST_UNSUPPORTED_DEATH_TEST(statement, regex, return)
#endif
} // namespace testing
diff --git a/extern/gtest/include/gtest/gtest-matchers.h b/extern/gtest/include/gtest/gtest-matchers.h
new file mode 100644
index 00000000000..9de6c2e10a2
--- /dev/null
+++ b/extern/gtest/include/gtest/gtest-matchers.h
@@ -0,0 +1,750 @@
+// Copyright 2007, 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.
+
+// The Google C++ Testing and Mocking Framework (Google Test)
+//
+// This file implements just enough of the matcher interface to allow
+// EXPECT_DEATH and friends to accept a matcher argument.
+
+// IWYU pragma: private, include "testing/base/public/gunit.h"
+// IWYU pragma: friend third_party/googletest/googlemock/.*
+// IWYU pragma: friend third_party/googletest/googletest/.*
+
+#ifndef GTEST_INCLUDE_GTEST_GTEST_MATCHERS_H_
+#define GTEST_INCLUDE_GTEST_GTEST_MATCHERS_H_
+
+#include <memory>
+#include <ostream>
+#include <string>
+#include <type_traits>
+
+#include "gtest/gtest-printers.h"
+#include "gtest/internal/gtest-internal.h"
+#include "gtest/internal/gtest-port.h"
+
+// MSVC warning C5046 is new as of VS2017 version 15.8.
+#if defined(_MSC_VER) && _MSC_VER >= 1915
+#define GTEST_MAYBE_5046_ 5046
+#else
+#define GTEST_MAYBE_5046_
+#endif
+
+GTEST_DISABLE_MSC_WARNINGS_PUSH_(
+ 4251 GTEST_MAYBE_5046_ /* class A needs to have dll-interface to be used by
+ clients of class B */
+ /* Symbol involving type with internal linkage not defined */)
+
+namespace testing {
+
+// To implement a matcher Foo for type T, define:
+// 1. a class FooMatcherImpl that implements the
+// MatcherInterface<T> interface, and
+// 2. a factory function that creates a Matcher<T> object from a
+// FooMatcherImpl*.
+//
+// The two-level delegation design makes it possible to allow a user
+// to write "v" instead of "Eq(v)" where a Matcher is expected, which
+// is impossible if we pass matchers by pointers. It also eases
+// ownership management as Matcher objects can now be copied like
+// plain values.
+
+// MatchResultListener is an abstract class. Its << operator can be
+// used by a matcher to explain why a value matches or doesn't match.
+//
+class MatchResultListener {
+ public:
+ // Creates a listener object with the given underlying ostream. The
+ // listener does not own the ostream, and does not dereference it
+ // in the constructor or destructor.
+ explicit MatchResultListener(::std::ostream* os) : stream_(os) {}
+ virtual ~MatchResultListener() = 0; // Makes this class abstract.
+
+ // Streams x to the underlying ostream; does nothing if the ostream
+ // is NULL.
+ template <typename T>
+ MatchResultListener& operator<<(const T& x) {
+ if (stream_ != nullptr) *stream_ << x;
+ return *this;
+ }
+
+ // Returns the underlying ostream.
+ ::std::ostream* stream() { return stream_; }
+
+ // Returns true if and only if the listener is interested in an explanation
+ // of the match result. A matcher's MatchAndExplain() method can use
+ // this information to avoid generating the explanation when no one
+ // intends to hear it.
+ bool IsInterested() const { return stream_ != nullptr; }
+
+ private:
+ ::std::ostream* const stream_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(MatchResultListener);
+};
+
+inline MatchResultListener::~MatchResultListener() {
+}
+
+// An instance of a subclass of this knows how to describe itself as a
+// matcher.
+class MatcherDescriberInterface {
+ public:
+ virtual ~MatcherDescriberInterface() {}
+
+ // Describes this matcher to an ostream. The function should print
+ // a verb phrase that describes the property a value matching this
+ // matcher should have. The subject of the verb phrase is the value
+ // being matched. For example, the DescribeTo() method of the Gt(7)
+ // matcher prints "is greater than 7".
+ virtual void DescribeTo(::std::ostream* os) const = 0;
+
+ // Describes the negation of this matcher to an ostream. For
+ // example, if the description of this matcher is "is greater than
+ // 7", the negated description could be "is not greater than 7".
+ // You are not required to override this when implementing
+ // MatcherInterface, but it is highly advised so that your matcher
+ // can produce good error messages.
+ virtual void DescribeNegationTo(::std::ostream* os) const {
+ *os << "not (";
+ DescribeTo(os);
+ *os << ")";
+ }
+};
+
+// The implementation of a matcher.
+template <typename T>
+class MatcherInterface : public MatcherDescriberInterface {
+ public:
+ // Returns true if and only if the matcher matches x; also explains the
+ // match result to 'listener' if necessary (see the next paragraph), in
+ // the form of a non-restrictive relative clause ("which ...",
+ // "whose ...", etc) that describes x. For example, the
+ // MatchAndExplain() method of the Pointee(...) matcher should
+ // generate an explanation like "which points to ...".
+ //
+ // Implementations of MatchAndExplain() should add an explanation of
+ // the match result *if and only if* they can provide additional
+ // information that's not already present (or not obvious) in the
+ // print-out of x and the matcher's description. Whether the match
+ // succeeds is not a factor in deciding whether an explanation is
+ // needed, as sometimes the caller needs to print a failure message
+ // when the match succeeds (e.g. when the matcher is used inside
+ // Not()).
+ //
+ // For example, a "has at least 10 elements" matcher should explain
+ // what the actual element count is, regardless of the match result,
+ // as it is useful information to the reader; on the other hand, an
+ // "is empty" matcher probably only needs to explain what the actual
+ // size is when the match fails, as it's redundant to say that the
+ // size is 0 when the value is already known to be empty.
+ //
+ // You should override this method when defining a new matcher.
+ //
+ // It's the responsibility of the caller (Google Test) to guarantee
+ // that 'listener' is not NULL. This helps to simplify a matcher's
+ // implementation when it doesn't care about the performance, as it
+ // can talk to 'listener' without checking its validity first.
+ // However, in order to implement dummy listeners efficiently,
+ // listener->stream() may be NULL.
+ virtual bool MatchAndExplain(T x, MatchResultListener* listener) const = 0;
+
+ // Inherits these methods from MatcherDescriberInterface:
+ // virtual void DescribeTo(::std::ostream* os) const = 0;
+ // virtual void DescribeNegationTo(::std::ostream* os) const;
+};
+
+namespace internal {
+
+// Converts a MatcherInterface<T> to a MatcherInterface<const T&>.
+template <typename T>
+class MatcherInterfaceAdapter : public MatcherInterface<const T&> {
+ public:
+ explicit MatcherInterfaceAdapter(const MatcherInterface<T>* impl)
+ : impl_(impl) {}
+ ~MatcherInterfaceAdapter() override { delete impl_; }
+
+ void DescribeTo(::std::ostream* os) const override { impl_->DescribeTo(os); }
+
+ void DescribeNegationTo(::std::ostream* os) const override {
+ impl_->DescribeNegationTo(os);
+ }
+
+ bool MatchAndExplain(const T& x,
+ MatchResultListener* listener) const override {
+ return impl_->MatchAndExplain(x, listener);
+ }
+
+ private:
+ const MatcherInterface<T>* const impl_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(MatcherInterfaceAdapter);
+};
+
+struct AnyEq {
+ template <typename A, typename B>
+ bool operator()(const A& a, const B& b) const { return a == b; }
+};
+struct AnyNe {
+ template <typename A, typename B>
+ bool operator()(const A& a, const B& b) const { return a != b; }
+};
+struct AnyLt {
+ template <typename A, typename B>
+ bool operator()(const A& a, const B& b) const { return a < b; }
+};
+struct AnyGt {
+ template <typename A, typename B>
+ bool operator()(const A& a, const B& b) const { return a > b; }
+};
+struct AnyLe {
+ template <typename A, typename B>
+ bool operator()(const A& a, const B& b) const { return a <= b; }
+};
+struct AnyGe {
+ template <typename A, typename B>
+ bool operator()(const A& a, const B& b) const { return a >= b; }
+};
+
+// A match result listener that ignores the explanation.
+class DummyMatchResultListener : public MatchResultListener {
+ public:
+ DummyMatchResultListener() : MatchResultListener(nullptr) {}
+
+ private:
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(DummyMatchResultListener);
+};
+
+// A match result listener that forwards the explanation to a given
+// ostream. The difference between this and MatchResultListener is
+// that the former is concrete.
+class StreamMatchResultListener : public MatchResultListener {
+ public:
+ explicit StreamMatchResultListener(::std::ostream* os)
+ : MatchResultListener(os) {}
+
+ private:
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(StreamMatchResultListener);
+};
+
+// An internal class for implementing Matcher<T>, which will derive
+// from it. We put functionalities common to all Matcher<T>
+// specializations here to avoid code duplication.
+template <typename T>
+class MatcherBase {
+ public:
+ // Returns true if and only if the matcher matches x; also explains the
+ // match result to 'listener'.
+ bool MatchAndExplain(const T& x, MatchResultListener* listener) const {
+ return impl_->MatchAndExplain(x, listener);
+ }
+
+ // Returns true if and only if this matcher matches x.
+ bool Matches(const T& x) const {
+ DummyMatchResultListener dummy;
+ return MatchAndExplain(x, &dummy);
+ }
+
+ // Describes this matcher to an ostream.
+ void DescribeTo(::std::ostream* os) const { impl_->DescribeTo(os); }
+
+ // Describes the negation of this matcher to an ostream.
+ void DescribeNegationTo(::std::ostream* os) const {
+ impl_->DescribeNegationTo(os);
+ }
+
+ // Explains why x matches, or doesn't match, the matcher.
+ void ExplainMatchResultTo(const T& x, ::std::ostream* os) const {
+ StreamMatchResultListener listener(os);
+ MatchAndExplain(x, &listener);
+ }
+
+ // Returns the describer for this matcher object; retains ownership
+ // of the describer, which is only guaranteed to be alive when
+ // this matcher object is alive.
+ const MatcherDescriberInterface* GetDescriber() const {
+ return impl_.get();
+ }
+
+ protected:
+ MatcherBase() {}
+
+ // Constructs a matcher from its implementation.
+ explicit MatcherBase(const MatcherInterface<const T&>* impl) : impl_(impl) {}
+
+ template <typename U>
+ explicit MatcherBase(
+ const MatcherInterface<U>* impl,
+ typename std::enable_if<!std::is_same<U, const U&>::value>::type* =
+ nullptr)
+ : impl_(new internal::MatcherInterfaceAdapter<U>(impl)) {}
+
+ MatcherBase(const MatcherBase&) = default;
+ MatcherBase& operator=(const MatcherBase&) = default;
+ MatcherBase(MatcherBase&&) = default;
+ MatcherBase& operator=(MatcherBase&&) = default;
+
+ virtual ~MatcherBase() {}
+
+ private:
+ std::shared_ptr<const MatcherInterface<const T&>> impl_;
+};
+
+} // namespace internal
+
+// A Matcher<T> is a copyable and IMMUTABLE (except by assignment)
+// object that can check whether a value of type T matches. The
+// implementation of Matcher<T> is just a std::shared_ptr to const
+// MatcherInterface<T>. Don't inherit from Matcher!
+template <typename T>
+class Matcher : public internal::MatcherBase<T> {
+ public:
+ // Constructs a null matcher. Needed for storing Matcher objects in STL
+ // containers. A default-constructed matcher is not yet initialized. You
+ // cannot use it until a valid value has been assigned to it.
+ explicit Matcher() {} // NOLINT
+
+ // Constructs a matcher from its implementation.
+ explicit Matcher(const MatcherInterface<const T&>* impl)
+ : internal::MatcherBase<T>(impl) {}
+
+ template <typename U>
+ explicit Matcher(
+ const MatcherInterface<U>* impl,
+ typename std::enable_if<!std::is_same<U, const U&>::value>::type* =
+ nullptr)
+ : internal::MatcherBase<T>(impl) {}
+
+ // Implicit constructor here allows people to write
+ // EXPECT_CALL(foo, Bar(5)) instead of EXPECT_CALL(foo, Bar(Eq(5))) sometimes
+ Matcher(T value); // NOLINT
+};
+
+// The following two specializations allow the user to write str
+// instead of Eq(str) and "foo" instead of Eq("foo") when a std::string
+// matcher is expected.
+template <>
+class GTEST_API_ Matcher<const std::string&>
+ : public internal::MatcherBase<const std::string&> {
+ public:
+ Matcher() {}
+
+ explicit Matcher(const MatcherInterface<const std::string&>* impl)
+ : internal::MatcherBase<const std::string&>(impl) {}
+
+ // Allows the user to write str instead of Eq(str) sometimes, where
+ // str is a std::string object.
+ Matcher(const std::string& s); // NOLINT
+
+ // Allows the user to write "foo" instead of Eq("foo") sometimes.
+ Matcher(const char* s); // NOLINT
+};
+
+template <>
+class GTEST_API_ Matcher<std::string>
+ : public internal::MatcherBase<std::string> {
+ public:
+ Matcher() {}
+
+ explicit Matcher(const MatcherInterface<const std::string&>* impl)
+ : internal::MatcherBase<std::string>(impl) {}
+ explicit Matcher(const MatcherInterface<std::string>* impl)
+ : internal::MatcherBase<std::string>(impl) {}
+
+ // Allows the user to write str instead of Eq(str) sometimes, where
+ // str is a string object.
+ Matcher(const std::string& s); // NOLINT
+
+ // Allows the user to write "foo" instead of Eq("foo") sometimes.
+ Matcher(const char* s); // NOLINT
+};
+
+#if GTEST_HAS_ABSL
+// The following two specializations allow the user to write str
+// instead of Eq(str) and "foo" instead of Eq("foo") when a absl::string_view
+// matcher is expected.
+template <>
+class GTEST_API_ Matcher<const absl::string_view&>
+ : public internal::MatcherBase<const absl::string_view&> {
+ public:
+ Matcher() {}
+
+ explicit Matcher(const MatcherInterface<const absl::string_view&>* impl)
+ : internal::MatcherBase<const absl::string_view&>(impl) {}
+
+ // Allows the user to write str instead of Eq(str) sometimes, where
+ // str is a std::string object.
+ Matcher(const std::string& s); // NOLINT
+
+ // Allows the user to write "foo" instead of Eq("foo") sometimes.
+ Matcher(const char* s); // NOLINT
+
+ // Allows the user to pass absl::string_views directly.
+ Matcher(absl::string_view s); // NOLINT
+};
+
+template <>
+class GTEST_API_ Matcher<absl::string_view>
+ : public internal::MatcherBase<absl::string_view> {
+ public:
+ Matcher() {}
+
+ explicit Matcher(const MatcherInterface<const absl::string_view&>* impl)
+ : internal::MatcherBase<absl::string_view>(impl) {}
+ explicit Matcher(const MatcherInterface<absl::string_view>* impl)
+ : internal::MatcherBase<absl::string_view>(impl) {}
+
+ // Allows the user to write str instead of Eq(str) sometimes, where
+ // str is a std::string object.
+ Matcher(const std::string& s); // NOLINT
+
+ // Allows the user to write "foo" instead of Eq("foo") sometimes.
+ Matcher(const char* s); // NOLINT
+
+ // Allows the user to pass absl::string_views directly.
+ Matcher(absl::string_view s); // NOLINT
+};
+#endif // GTEST_HAS_ABSL
+
+// Prints a matcher in a human-readable format.
+template <typename T>
+std::ostream& operator<<(std::ostream& os, const Matcher<T>& matcher) {
+ matcher.DescribeTo(&os);
+ return os;
+}
+
+// The PolymorphicMatcher class template makes it easy to implement a
+// polymorphic matcher (i.e. a matcher that can match values of more
+// than one type, e.g. Eq(n) and NotNull()).
+//
+// To define a polymorphic matcher, a user should provide an Impl
+// class that has a DescribeTo() method and a DescribeNegationTo()
+// method, and define a member function (or member function template)
+//
+// bool MatchAndExplain(const Value& value,
+// MatchResultListener* listener) const;
+//
+// See the definition of NotNull() for a complete example.
+template <class Impl>
+class PolymorphicMatcher {
+ public:
+ explicit PolymorphicMatcher(const Impl& an_impl) : impl_(an_impl) {}
+
+ // Returns a mutable reference to the underlying matcher
+ // implementation object.
+ Impl& mutable_impl() { return impl_; }
+
+ // Returns an immutable reference to the underlying matcher
+ // implementation object.
+ const Impl& impl() const { return impl_; }
+
+ template <typename T>
+ operator Matcher<T>() const {
+ return Matcher<T>(new MonomorphicImpl<const T&>(impl_));
+ }
+
+ private:
+ template <typename T>
+ class MonomorphicImpl : public MatcherInterface<T> {
+ public:
+ explicit MonomorphicImpl(const Impl& impl) : impl_(impl) {}
+
+ virtual void DescribeTo(::std::ostream* os) const { impl_.DescribeTo(os); }
+
+ virtual void DescribeNegationTo(::std::ostream* os) const {
+ impl_.DescribeNegationTo(os);
+ }
+
+ virtual bool MatchAndExplain(T x, MatchResultListener* listener) const {
+ return impl_.MatchAndExplain(x, listener);
+ }
+
+ private:
+ const Impl impl_;
+ };
+
+ Impl impl_;
+};
+
+// Creates a matcher from its implementation.
+// DEPRECATED: Especially in the generic code, prefer:
+// Matcher<T>(new MyMatcherImpl<const T&>(...));
+//
+// MakeMatcher may create a Matcher that accepts its argument by value, which
+// leads to unnecessary copies & lack of support for non-copyable types.
+template <typename T>
+inline Matcher<T> MakeMatcher(const MatcherInterface<T>* impl) {
+ return Matcher<T>(impl);
+}
+
+// Creates a polymorphic matcher from its implementation. This is
+// easier to use than the PolymorphicMatcher<Impl> constructor as it
+// doesn't require you to explicitly write the template argument, e.g.
+//
+// MakePolymorphicMatcher(foo);
+// vs
+// PolymorphicMatcher<TypeOfFoo>(foo);
+template <class Impl>
+inline PolymorphicMatcher<Impl> MakePolymorphicMatcher(const Impl& impl) {
+ return PolymorphicMatcher<Impl>(impl);
+}
+
+namespace internal {
+// Implements a matcher that compares a given value with a
+// pre-supplied value using one of the ==, <=, <, etc, operators. The
+// two values being compared don't have to have the same type.
+//
+// The matcher defined here is polymorphic (for example, Eq(5) can be
+// used to match an int, a short, a double, etc). Therefore we use
+// a template type conversion operator in the implementation.
+//
+// The following template definition assumes that the Rhs parameter is
+// a "bare" type (i.e. neither 'const T' nor 'T&').
+template <typename D, typename Rhs, typename Op>
+class ComparisonBase {
+ public:
+ explicit ComparisonBase(const Rhs& rhs) : rhs_(rhs) {}
+ template <typename Lhs>
+ operator Matcher<Lhs>() const {
+ return Matcher<Lhs>(new Impl<const Lhs&>(rhs_));
+ }
+
+ private:
+ template <typename T>
+ static const T& Unwrap(const T& v) { return v; }
+ template <typename T>
+ static const T& Unwrap(std::reference_wrapper<T> v) { return v; }
+
+ template <typename Lhs, typename = Rhs>
+ class Impl : public MatcherInterface<Lhs> {
+ public:
+ explicit Impl(const Rhs& rhs) : rhs_(rhs) {}
+ bool MatchAndExplain(Lhs lhs,
+ MatchResultListener* /* listener */) const override {
+ return Op()(lhs, Unwrap(rhs_));
+ }
+ void DescribeTo(::std::ostream* os) const override {
+ *os << D::Desc() << " ";
+ UniversalPrint(Unwrap(rhs_), os);
+ }
+ void DescribeNegationTo(::std::ostream* os) const override {
+ *os << D::NegatedDesc() << " ";
+ UniversalPrint(Unwrap(rhs_), os);
+ }
+
+ private:
+ Rhs rhs_;
+ };
+ Rhs rhs_;
+};
+
+template <typename Rhs>
+class EqMatcher : public ComparisonBase<EqMatcher<Rhs>, Rhs, AnyEq> {
+ public:
+ explicit EqMatcher(const Rhs& rhs)
+ : ComparisonBase<EqMatcher<Rhs>, Rhs, AnyEq>(rhs) { }
+ static const char* Desc() { return "is equal to"; }
+ static const char* NegatedDesc() { return "isn't equal to"; }
+};
+template <typename Rhs>
+class NeMatcher : public ComparisonBase<NeMatcher<Rhs>, Rhs, AnyNe> {
+ public:
+ explicit NeMatcher(const Rhs& rhs)
+ : ComparisonBase<NeMatcher<Rhs>, Rhs, AnyNe>(rhs) { }
+ static const char* Desc() { return "isn't equal to"; }
+ static const char* NegatedDesc() { return "is equal to"; }
+};
+template <typename Rhs>
+class LtMatcher : public ComparisonBase<LtMatcher<Rhs>, Rhs, AnyLt> {
+ public:
+ explicit LtMatcher(const Rhs& rhs)
+ : ComparisonBase<LtMatcher<Rhs>, Rhs, AnyLt>(rhs) { }
+ static const char* Desc() { return "is <"; }
+ static const char* NegatedDesc() { return "isn't <"; }
+};
+template <typename Rhs>
+class GtMatcher : public ComparisonBase<GtMatcher<Rhs>, Rhs, AnyGt> {
+ public:
+ explicit GtMatcher(const Rhs& rhs)
+ : ComparisonBase<GtMatcher<Rhs>, Rhs, AnyGt>(rhs) { }
+ static const char* Desc() { return "is >"; }
+ static const char* NegatedDesc() { return "isn't >"; }
+};
+template <typename Rhs>
+class LeMatcher : public ComparisonBase<LeMatcher<Rhs>, Rhs, AnyLe> {
+ public:
+ explicit LeMatcher(const Rhs& rhs)
+ : ComparisonBase<LeMatcher<Rhs>, Rhs, AnyLe>(rhs) { }
+ static const char* Desc() { return "is <="; }
+ static const char* NegatedDesc() { return "isn't <="; }
+};
+template <typename Rhs>
+class GeMatcher : public ComparisonBase<GeMatcher<Rhs>, Rhs, AnyGe> {
+ public:
+ explicit GeMatcher(const Rhs& rhs)
+ : ComparisonBase<GeMatcher<Rhs>, Rhs, AnyGe>(rhs) { }
+ static const char* Desc() { return "is >="; }
+ static const char* NegatedDesc() { return "isn't >="; }
+};
+
+// Implements polymorphic matchers MatchesRegex(regex) and
+// ContainsRegex(regex), which can be used as a Matcher<T> as long as
+// T can be converted to a string.
+class MatchesRegexMatcher {
+ public:
+ MatchesRegexMatcher(const RE* regex, bool full_match)
+ : regex_(regex), full_match_(full_match) {}
+
+#if GTEST_HAS_ABSL
+ bool MatchAndExplain(const absl::string_view& s,
+ MatchResultListener* listener) const {
+ return MatchAndExplain(std::string(s), listener);
+ }
+#endif // GTEST_HAS_ABSL
+
+ // Accepts pointer types, particularly:
+ // const char*
+ // char*
+ // const wchar_t*
+ // wchar_t*
+ template <typename CharType>
+ bool MatchAndExplain(CharType* s, MatchResultListener* listener) const {
+ return s != nullptr && MatchAndExplain(std::string(s), listener);
+ }
+
+ // Matches anything that can convert to std::string.
+ //
+ // This is a template, not just a plain function with const std::string&,
+ // because absl::string_view has some interfering non-explicit constructors.
+ template <class MatcheeStringType>
+ bool MatchAndExplain(const MatcheeStringType& s,
+ MatchResultListener* /* listener */) const {
+ const std::string& s2(s);
+ return full_match_ ? RE::FullMatch(s2, *regex_)
+ : RE::PartialMatch(s2, *regex_);
+ }
+
+ void DescribeTo(::std::ostream* os) const {
+ *os << (full_match_ ? "matches" : "contains") << " regular expression ";
+ UniversalPrinter<std::string>::Print(regex_->pattern(), os);
+ }
+
+ void DescribeNegationTo(::std::ostream* os) const {
+ *os << "doesn't " << (full_match_ ? "match" : "contain")
+ << " regular expression ";
+ UniversalPrinter<std::string>::Print(regex_->pattern(), os);
+ }
+
+ private:
+ const std::shared_ptr<const RE> regex_;
+ const bool full_match_;
+};
+} // namespace internal
+
+// Matches a string that fully matches regular expression 'regex'.
+// The matcher takes ownership of 'regex'.
+inline PolymorphicMatcher<internal::MatchesRegexMatcher> MatchesRegex(
+ const internal::RE* regex) {
+ return MakePolymorphicMatcher(internal::MatchesRegexMatcher(regex, true));
+}
+inline PolymorphicMatcher<internal::MatchesRegexMatcher> MatchesRegex(
+ const std::string& regex) {
+ return MatchesRegex(new internal::RE(regex));
+}
+
+// Matches a string that contains regular expression 'regex'.
+// The matcher takes ownership of 'regex'.
+inline PolymorphicMatcher<internal::MatchesRegexMatcher> ContainsRegex(
+ const internal::RE* regex) {
+ return MakePolymorphicMatcher(internal::MatchesRegexMatcher(regex, false));
+}
+inline PolymorphicMatcher<internal::MatchesRegexMatcher> ContainsRegex(
+ const std::string& regex) {
+ return ContainsRegex(new internal::RE(regex));
+}
+
+// Creates a polymorphic matcher that matches anything equal to x.
+// Note: if the parameter of Eq() were declared as const T&, Eq("foo")
+// wouldn't compile.
+template <typename T>
+inline internal::EqMatcher<T> Eq(T x) { return internal::EqMatcher<T>(x); }
+
+// Constructs a Matcher<T> from a 'value' of type T. The constructed
+// matcher matches any value that's equal to 'value'.
+template <typename T>
+Matcher<T>::Matcher(T value) { *this = Eq(value); }
+
+// Creates a monomorphic matcher that matches anything with type Lhs
+// and equal to rhs. A user may need to use this instead of Eq(...)
+// in order to resolve an overloading ambiguity.
+//
+// TypedEq<T>(x) is just a convenient short-hand for Matcher<T>(Eq(x))
+// or Matcher<T>(x), but more readable than the latter.
+//
+// We could define similar monomorphic matchers for other comparison
+// operations (e.g. TypedLt, TypedGe, and etc), but decided not to do
+// it yet as those are used much less than Eq() in practice. A user
+// can always write Matcher<T>(Lt(5)) to be explicit about the type,
+// for example.
+template <typename Lhs, typename Rhs>
+inline Matcher<Lhs> TypedEq(const Rhs& rhs) { return Eq(rhs); }
+
+// Creates a polymorphic matcher that matches anything >= x.
+template <typename Rhs>
+inline internal::GeMatcher<Rhs> Ge(Rhs x) {
+ return internal::GeMatcher<Rhs>(x);
+}
+
+// Creates a polymorphic matcher that matches anything > x.
+template <typename Rhs>
+inline internal::GtMatcher<Rhs> Gt(Rhs x) {
+ return internal::GtMatcher<Rhs>(x);
+}
+
+// Creates a polymorphic matcher that matches anything <= x.
+template <typename Rhs>
+inline internal::LeMatcher<Rhs> Le(Rhs x) {
+ return internal::LeMatcher<Rhs>(x);
+}
+
+// Creates a polymorphic matcher that matches anything < x.
+template <typename Rhs>
+inline internal::LtMatcher<Rhs> Lt(Rhs x) {
+ return internal::LtMatcher<Rhs>(x);
+}
+
+// Creates a polymorphic matcher that matches anything != x.
+template <typename Rhs>
+inline internal::NeMatcher<Rhs> Ne(Rhs x) {
+ return internal::NeMatcher<Rhs>(x);
+}
+} // namespace testing
+
+GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 5046
+
+#endif // GTEST_INCLUDE_GTEST_GTEST_MATCHERS_H_
diff --git a/extern/gtest/include/gtest/gtest-message.h b/extern/gtest/include/gtest/gtest-message.h
index fe879bca792..4a80e11e6b2 100644
--- a/extern/gtest/include/gtest/gtest-message.h
+++ b/extern/gtest/include/gtest/gtest-message.h
@@ -26,10 +26,9 @@
// 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.
+
//
-// Author: wan@google.com (Zhanyong Wan)
-//
-// The Google C++ Testing Framework (Google Test)
+// The Google C++ Testing and Mocking Framework (Google Test)
//
// This header file defines the Message class.
//
@@ -43,13 +42,19 @@
// to CHANGE WITHOUT NOTICE. Therefore DO NOT DEPEND ON IT in a user
// program!
+// GOOGLETEST_CM0001 DO NOT DELETE
+
#ifndef GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_
#define GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_
#include <limits>
+#include <memory>
#include "gtest/internal/gtest-port.h"
+GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \
+/* class A needs to have dll-interface to be used by clients of class B */)
+
// 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);
@@ -102,14 +107,6 @@ class GTEST_API_ Message {
*ss_ << str;
}
-#if GTEST_OS_SYMBIAN
- // Streams a value (either a pointer or not) to this object.
- template <typename T>
- inline Message& operator <<(const T& value) {
- StreamHelper(typename internal::is_pointer<T>::type(), value);
- return *this;
- }
-#else
// Streams a non-pointer value to this object.
template <typename T>
inline Message& operator <<(const T& val) {
@@ -147,14 +144,13 @@ class GTEST_API_ Message {
// as "(null)".
template <typename T>
inline Message& operator <<(T* const& pointer) { // NOLINT
- if (pointer == NULL) {
+ if (pointer == nullptr) {
*ss_ << "(null)";
} else {
*ss_ << pointer;
}
return *this;
}
-#endif // GTEST_OS_SYMBIAN
// Since the basic IO manipulators are overloaded for both narrow
// and wide streams, we have to provide this specialized definition
@@ -183,12 +179,6 @@ class GTEST_API_ Message {
Message& operator <<(const ::std::wstring& wstr);
#endif // GTEST_HAS_STD_WSTRING
-#if GTEST_HAS_GLOBAL_WSTRING
- // Converts the given wide string to a narrow string using the UTF-8
- // encoding, and streams the result to this Message object.
- Message& operator <<(const ::wstring& wstr);
-#endif // GTEST_HAS_GLOBAL_WSTRING
-
// Gets the text streamed to this object so far as an std::string.
// Each '\0' character in the buffer is replaced with "\\0".
//
@@ -196,32 +186,8 @@ class GTEST_API_ Message {
std::string GetString() const;
private:
-
-#if GTEST_OS_SYMBIAN
- // These are needed as the Nokia Symbian Compiler cannot decide between
- // const T& and const T* in a function template. The Nokia compiler _can_
- // 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 /*is_pointer*/, T* pointer) {
- if (pointer == NULL) {
- *ss_ << "(null)";
- } else {
- *ss_ << pointer;
- }
- }
- template <typename T>
- 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
-
// We'll hold the text streamed to this object here.
- const internal::scoped_ptr< ::std::stringstream> ss_;
+ const std::unique_ptr< ::std::stringstream> ss_;
// We declare (but don't implement) this to prevent the compiler
// from implementing the assignment operator.
@@ -247,4 +213,6 @@ std::string StreamableToString(const T& streamable) {
} // namespace internal
} // namespace testing
+GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251
+
#endif // GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_
diff --git a/extern/gtest/include/gtest/gtest-param-test.h b/extern/gtest/include/gtest/gtest-param-test.h
index 038f9ba79eb..c2e6eae3d83 100644
--- a/extern/gtest/include/gtest/gtest-param-test.h
+++ b/extern/gtest/include/gtest/gtest-param-test.h
@@ -1,7 +1,3 @@
-// This file was GENERATED by command:
-// pump.py gtest-param-test.h.pump
-// DO NOT EDIT BY HAND!!!
-
// Copyright 2008, Google Inc.
// All rights reserved.
//
@@ -31,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.
//
-// Authors: vladl@google.com (Vlad Losev)
-//
// Macros and functions for implementing parameterized tests
-// in Google C++ Testing Framework (Google Test)
+// in Google C++ Testing and Mocking Framework (Google Test)
//
// This file is generated by a SCRIPT. DO NOT EDIT BY HAND!
//
+// GOOGLETEST_CM0001 DO NOT DELETE
#ifndef GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_
#define GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_
@@ -76,10 +71,10 @@ TEST_P(FooTest, HasBlahBlah) {
...
}
-// Finally, you can use INSTANTIATE_TEST_CASE_P to instantiate the test
+// Finally, you can use INSTANTIATE_TEST_SUITE_P to instantiate the test
// case with any set of parameters you want. Google Test defines a number
// of functions for generating test parameters. They return what we call
-// (surprise!) parameter generators. Here is a summary of them, which
+// (surprise!) parameter generators. Here is a summary of them, which
// are all in the testing namespace:
//
//
@@ -97,17 +92,17 @@ TEST_P(FooTest, HasBlahBlah) {
// For more details, see comments at the definitions of these functions below
// in this file.
//
-// The following statement will instantiate tests from the FooTest test case
+// The following statement will instantiate tests from the FooTest test suite
// each with parameter values "meeny", "miny", and "moe".
-INSTANTIATE_TEST_CASE_P(InstantiationName,
- FooTest,
- Values("meeny", "miny", "moe"));
+INSTANTIATE_TEST_SUITE_P(InstantiationName,
+ FooTest,
+ Values("meeny", "miny", "moe"));
// To distinguish different instances of the pattern, (yes, you
-// can instantiate it more then once) the first argument to the
-// INSTANTIATE_TEST_CASE_P macro is a prefix that will be added to the
-// actual test case name. Remember to pick unique prefixes for different
+// can instantiate it more than once) the first argument to the
+// INSTANTIATE_TEST_SUITE_P macro is a prefix that will be added to the
+// actual test suite name. Remember to pick unique prefixes for different
// instantiations. The tests from the instantiation above will have
// these names:
//
@@ -124,7 +119,7 @@ INSTANTIATE_TEST_CASE_P(InstantiationName,
// with parameter values "cat" and "dog":
const char* pets[] = {"cat", "dog"};
-INSTANTIATE_TEST_CASE_P(AnotherInstantiationName, FooTest, ValuesIn(pets));
+INSTANTIATE_TEST_SUITE_P(AnotherInstantiationName, FooTest, ValuesIn(pets));
// The tests from the instantiation above will have these names:
//
@@ -133,9 +128,9 @@ INSTANTIATE_TEST_CASE_P(AnotherInstantiationName, FooTest, ValuesIn(pets));
// * AnotherInstantiationName/FooTest.HasBlahBlah/0 for "cat"
// * AnotherInstantiationName/FooTest.HasBlahBlah/1 for "dog"
//
-// Please note that INSTANTIATE_TEST_CASE_P will instantiate all tests
-// in the given test case, whether their definitions come before or
-// AFTER the INSTANTIATE_TEST_CASE_P statement.
+// Please note that INSTANTIATE_TEST_SUITE_P will instantiate all tests
+// in the given test suite, whether their definitions come before or
+// AFTER the INSTANTIATE_TEST_SUITE_P statement.
//
// Please also note that generator expressions (including parameters to the
// generators) are evaluated in InitGoogleTest(), after main() has started.
@@ -179,31 +174,23 @@ TEST_P(DerivedTest, DoesBlah) {
#endif // 0
-#include "gtest/internal/gtest-port.h"
-
-#if !GTEST_OS_SYMBIAN
-# include <utility>
-#endif
+#include <iterator>
+#include <utility>
-// scripts/fuse_gtest.py depends on gtest's own header being #included
-// *unconditionally*. Therefore these #includes cannot be moved
-// inside #if GTEST_HAS_PARAM_TEST.
#include "gtest/internal/gtest-internal.h"
#include "gtest/internal/gtest-param-util.h"
-#include "gtest/internal/gtest-param-util-generated.h"
-
-#if GTEST_HAS_PARAM_TEST
+#include "gtest/internal/gtest-port.h"
namespace testing {
// Functions producing parameter generators.
//
// Google Test uses these generators to produce parameters for value-
-// parameterized tests. When a parameterized test case is instantiated
+// parameterized tests. When a parameterized test suite is instantiated
// with a particular generator, Google Test creates and runs tests
// for each element in the sequence produced by the generator.
//
-// In the following sample, tests from test case FooTest are instantiated
+// In the following sample, tests from test suite FooTest are instantiated
// each three times with parameter values 3, 5, and 8:
//
// class FooTest : public TestWithParam<int> { ... };
@@ -212,7 +199,7 @@ namespace testing {
// }
// TEST_P(FooTest, TestThat) {
// }
-// INSTANTIATE_TEST_CASE_P(TestSequence, FooTest, Values(3, 5, 8));
+// INSTANTIATE_TEST_SUITE_P(TestSequence, FooTest, Values(3, 5, 8));
//
// Range() returns generators providing sequences of values in a range.
@@ -269,13 +256,13 @@ internal::ParamGenerator<T> Range(T start, T end) {
//
// Examples:
//
-// This instantiates tests from test case StringTest
+// This instantiates tests from test suite StringTest
// each with C-string values of "foo", "bar", and "baz":
//
// const char* strings[] = {"foo", "bar", "baz"};
-// INSTANTIATE_TEST_CASE_P(StringSequence, SrtingTest, ValuesIn(strings));
+// INSTANTIATE_TEST_SUITE_P(StringSequence, StringTest, ValuesIn(strings));
//
-// This instantiates tests from test case StlStringTest
+// This instantiates tests from test suite StlStringTest
// each with STL strings with values "a" and "b":
//
// ::std::vector< ::std::string> GetParameterStrings() {
@@ -285,9 +272,9 @@ internal::ParamGenerator<T> Range(T start, T end) {
// return v;
// }
//
-// INSTANTIATE_TEST_CASE_P(CharSequence,
-// StlStringTest,
-// ValuesIn(GetParameterStrings()));
+// INSTANTIATE_TEST_SUITE_P(CharSequence,
+// StlStringTest,
+// ValuesIn(GetParameterStrings()));
//
//
// This will also instantiate tests from CharTest
@@ -300,16 +287,15 @@ internal::ParamGenerator<T> Range(T start, T end) {
// return list;
// }
// ::std::list<char> l = GetParameterChars();
-// INSTANTIATE_TEST_CASE_P(CharSequence2,
-// CharTest,
-// ValuesIn(l.begin(), l.end()));
+// INSTANTIATE_TEST_SUITE_P(CharSequence2,
+// CharTest,
+// ValuesIn(l.begin(), l.end()));
//
template <typename ForwardIterator>
internal::ParamGenerator<
- typename ::testing::internal::IteratorTraits<ForwardIterator>::value_type>
+ typename std::iterator_traits<ForwardIterator>::value_type>
ValuesIn(ForwardIterator begin, ForwardIterator end) {
- typedef typename ::testing::internal::IteratorTraits<ForwardIterator>
- ::value_type ParamType;
+ typedef typename std::iterator_traits<ForwardIterator>::value_type ParamType;
return internal::ParamGenerator<ParamType>(
new internal::ValuesInIteratorRangeGenerator<ParamType>(begin, end));
}
@@ -332,869 +318,22 @@ internal::ParamGenerator<typename Container::value_type> ValuesIn(
// Values(T v1, T v2, ..., T vN)
// - returns a generator producing sequences with elements v1, v2, ..., vN.
//
-// For example, this instantiates tests from test case BarTest each
+// For example, this instantiates tests from test suite BarTest each
// with values "one", "two", and "three":
//
-// INSTANTIATE_TEST_CASE_P(NumSequence, BarTest, Values("one", "two", "three"));
+// INSTANTIATE_TEST_SUITE_P(NumSequence,
+// BarTest,
+// Values("one", "two", "three"));
//
-// This instantiates tests from test case BazTest each with values 1, 2, 3.5.
+// This instantiates tests from test suite BazTest each with values 1, 2, 3.5.
// The exact type of values will depend on the type of parameter in BazTest.
//
-// INSTANTIATE_TEST_CASE_P(FloatingNumbers, BazTest, Values(1, 2, 3.5));
+// INSTANTIATE_TEST_SUITE_P(FloatingNumbers, BazTest, Values(1, 2, 3.5));
//
-// Currently, Values() supports from 1 to 50 parameters.
//
-template <typename T1>
-internal::ValueArray1<T1> Values(T1 v1) {
- return internal::ValueArray1<T1>(v1);
-}
-
-template <typename T1, typename T2>
-internal::ValueArray2<T1, T2> Values(T1 v1, T2 v2) {
- return internal::ValueArray2<T1, T2>(v1, v2);
-}
-
-template <typename T1, typename T2, typename T3>
-internal::ValueArray3<T1, T2, T3> Values(T1 v1, T2 v2, T3 v3) {
- return internal::ValueArray3<T1, T2, T3>(v1, v2, v3);
-}
-
-template <typename T1, typename T2, typename T3, typename T4>
-internal::ValueArray4<T1, T2, T3, T4> Values(T1 v1, T2 v2, T3 v3, T4 v4) {
- return internal::ValueArray4<T1, T2, T3, T4>(v1, v2, v3, v4);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5>
-internal::ValueArray5<T1, T2, T3, T4, T5> Values(T1 v1, T2 v2, T3 v3, T4 v4,
- T5 v5) {
- return internal::ValueArray5<T1, T2, T3, T4, T5>(v1, v2, v3, v4, v5);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6>
-internal::ValueArray6<T1, T2, T3, T4, T5, T6> Values(T1 v1, T2 v2, T3 v3,
- T4 v4, T5 v5, T6 v6) {
- return internal::ValueArray6<T1, T2, T3, T4, T5, T6>(v1, v2, v3, v4, v5, v6);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7>
-internal::ValueArray7<T1, T2, T3, T4, T5, T6, T7> Values(T1 v1, T2 v2, T3 v3,
- T4 v4, T5 v5, T6 v6, T7 v7) {
- return internal::ValueArray7<T1, T2, T3, T4, T5, T6, T7>(v1, v2, v3, v4, v5,
- v6, v7);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8>
-internal::ValueArray8<T1, T2, T3, T4, T5, T6, T7, T8> Values(T1 v1, T2 v2,
- T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8) {
- return internal::ValueArray8<T1, T2, T3, T4, T5, T6, T7, T8>(v1, v2, v3, v4,
- v5, v6, v7, v8);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9>
-internal::ValueArray9<T1, T2, T3, T4, T5, T6, T7, T8, T9> Values(T1 v1, T2 v2,
- T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9) {
- return internal::ValueArray9<T1, T2, T3, T4, T5, T6, T7, T8, T9>(v1, v2, v3,
- v4, v5, v6, v7, v8, v9);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10>
-internal::ValueArray10<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> Values(T1 v1,
- T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10) {
- return internal::ValueArray10<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(v1,
- v2, v3, v4, v5, v6, v7, v8, v9, v10);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11>
-internal::ValueArray11<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10,
- T11> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11) {
- return internal::ValueArray11<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10,
- T11>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12>
-internal::ValueArray12<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
- T12> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12) {
- return internal::ValueArray12<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
- T12>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13>
-internal::ValueArray13<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
- T13> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13) {
- return internal::ValueArray13<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
- T12, T13>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14>
-internal::ValueArray14<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13, T14 v14) {
- return internal::ValueArray14<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
- T12, T13, T14>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13,
- v14);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15>
-internal::ValueArray15<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8,
- T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15) {
- return internal::ValueArray15<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
- T12, T13, T14, T15>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12,
- v13, v14, v15);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16>
-internal::ValueArray16<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7,
- T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,
- T16 v16) {
- return internal::ValueArray16<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
- T12, T13, T14, T15, T16>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11,
- v12, v13, v14, v15, v16);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17>
-internal::ValueArray17<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7,
- T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,
- T16 v16, T17 v17) {
- return internal::ValueArray17<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
- T12, T13, T14, T15, T16, T17>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10,
- v11, v12, v13, v14, v15, v16, v17);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18>
-internal::ValueArray18<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6,
- T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,
- T16 v16, T17 v17, T18 v18) {
- return internal::ValueArray18<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
- T12, T13, T14, T15, T16, T17, T18>(v1, v2, v3, v4, v5, v6, v7, v8, v9,
- v10, v11, v12, v13, v14, v15, v16, v17, v18);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19>
-internal::ValueArray19<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5,
- T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14,
- T15 v15, T16 v16, T17 v17, T18 v18, T19 v19) {
- return internal::ValueArray19<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
- T12, T13, T14, T15, T16, T17, T18, T19>(v1, v2, v3, v4, v5, v6, v7, v8,
- v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20>
-internal::ValueArray20<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20> Values(T1 v1, T2 v2, T3 v3, T4 v4,
- T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13,
- T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20) {
- return internal::ValueArray20<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
- T12, T13, T14, T15, T16, T17, T18, T19, T20>(v1, v2, v3, v4, v5, v6, v7,
- v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21>
-internal::ValueArray21<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20, T21> Values(T1 v1, T2 v2, T3 v3, T4 v4,
- T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13,
- T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21) {
- return internal::ValueArray21<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
- T12, T13, T14, T15, T16, T17, T18, T19, T20, T21>(v1, v2, v3, v4, v5, v6,
- v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22>
-internal::ValueArray22<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20, T21, T22> Values(T1 v1, T2 v2, T3 v3,
- T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12,
- T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20,
- T21 v21, T22 v22) {
- return internal::ValueArray22<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
- T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22>(v1, v2, v3, v4,
- v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19,
- v20, v21, v22);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23>
-internal::ValueArray23<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20, T21, T22, T23> Values(T1 v1, T2 v2,
- T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12,
- T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20,
- T21 v21, T22 v22, T23 v23) {
- return internal::ValueArray23<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
- T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23>(v1, v2, v3,
- v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19,
- v20, v21, v22, v23);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24>
-internal::ValueArray24<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24> Values(T1 v1, T2 v2,
- T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12,
- T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20,
- T21 v21, T22 v22, T23 v23, T24 v24) {
- return internal::ValueArray24<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
- T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24>(v1, v2,
- v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18,
- v19, v20, v21, v22, v23, v24);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25>
-internal::ValueArray25<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25> Values(T1 v1,
- T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11,
- T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19,
- T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25) {
- return internal::ValueArray25<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
- T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25>(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);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26>
-internal::ValueArray26<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
- T26> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
- T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
- T26 v26) {
- return internal::ValueArray26<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
- T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
- T26>(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);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27>
-internal::ValueArray27<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
- T27> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
- T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
- T26 v26, T27 v27) {
- return internal::ValueArray27<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
- T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
- T26, T27>(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);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28>
-internal::ValueArray28<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
- T28> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
- T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
- T26 v26, T27 v27, T28 v28) {
- return internal::ValueArray28<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
- T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
- T26, T27, T28>(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);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29>
-internal::ValueArray29<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
- T29> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
- T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
- T26 v26, T27 v27, T28 v28, T29 v29) {
- return internal::ValueArray29<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
- T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
- T26, T27, T28, T29>(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);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30>
-internal::ValueArray30<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
- T29, T30> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8,
- T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16,
- T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24,
- T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30) {
- return internal::ValueArray30<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
- T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
- T26, T27, T28, T29, T30>(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);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31>
-internal::ValueArray31<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
- T29, T30, T31> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7,
- T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,
- T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23,
- T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31) {
- return internal::ValueArray31<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
- T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
- T26, T27, T28, T29, T30, T31>(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);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32>
-internal::ValueArray32<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
- T29, T30, T31, T32> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7,
- T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,
- T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23,
- T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31,
- T32 v32) {
- return internal::ValueArray32<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
- T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
- T26, T27, T28, T29, T30, T31, T32>(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);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33>
-internal::ValueArray33<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
- T29, T30, T31, T32, T33> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6,
- T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,
- T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23,
- T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31,
- T32 v32, T33 v33) {
- return internal::ValueArray33<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
- T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
- T26, T27, T28, T29, T30, T31, T32, T33>(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);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34>
-internal::ValueArray34<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
- T29, T30, T31, T32, T33, T34> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5,
- T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14,
- T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22,
- T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30,
- T31 v31, T32 v32, T33 v33, T34 v34) {
- return internal::ValueArray34<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
- T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
- T26, T27, T28, T29, T30, T31, T32, T33, T34>(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);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35>
-internal::ValueArray35<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
- T29, T30, T31, T32, T33, T34, T35> Values(T1 v1, T2 v2, T3 v3, T4 v4,
- T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13,
- T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21,
- T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29,
- T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35) {
- return internal::ValueArray35<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
- T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
- T26, T27, T28, T29, T30, T31, T32, T33, T34, T35>(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);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35,
- typename T36>
-internal::ValueArray36<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
- T29, T30, T31, T32, T33, T34, T35, T36> Values(T1 v1, T2 v2, T3 v3, T4 v4,
- T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13,
- T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21,
- T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29,
- T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36) {
- return internal::ValueArray36<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
- T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
- T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36>(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);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35,
- typename T36, typename T37>
-internal::ValueArray37<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
- T29, T30, T31, T32, T33, T34, T35, T36, T37> Values(T1 v1, T2 v2, T3 v3,
- T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12,
- T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20,
- T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28,
- T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36,
- T37 v37) {
- return internal::ValueArray37<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
- T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
- T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37>(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);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35,
- typename T36, typename T37, typename T38>
-internal::ValueArray38<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
- T29, T30, T31, T32, T33, T34, T35, T36, T37, T38> Values(T1 v1, T2 v2,
- T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12,
- T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20,
- T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28,
- T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36,
- T37 v37, T38 v38) {
- return internal::ValueArray38<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
- T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
- T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38>(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);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35,
- typename T36, typename T37, typename T38, typename T39>
-internal::ValueArray39<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
- T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39> Values(T1 v1, T2 v2,
- T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12,
- T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20,
- T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28,
- T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36,
- T37 v37, T38 v38, T39 v39) {
- return internal::ValueArray39<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
- T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
- T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39>(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);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35,
- typename T36, typename T37, typename T38, typename T39, typename T40>
-internal::ValueArray40<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
- T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40> Values(T1 v1,
- T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11,
- T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19,
- T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27,
- T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35,
- T36 v36, T37 v37, T38 v38, T39 v39, T40 v40) {
- return internal::ValueArray40<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
- T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
- T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
- T40>(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);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35,
- typename T36, typename T37, typename T38, typename T39, typename T40,
- typename T41>
-internal::ValueArray41<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
- T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
- T41> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
- T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
- T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
- T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41) {
- return internal::ValueArray41<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
- T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
- T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
- T40, T41>(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);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35,
- typename T36, typename T37, typename T38, typename T39, typename T40,
- typename T41, typename T42>
-internal::ValueArray42<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
- T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
- T42> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
- T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
- T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
- T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
- T42 v42) {
- return internal::ValueArray42<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
- T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
- T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
- T40, T41, T42>(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);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35,
- typename T36, typename T37, typename T38, typename T39, typename T40,
- typename T41, typename T42, typename T43>
-internal::ValueArray43<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
- T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
- T43> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
- T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
- T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
- T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
- T42 v42, T43 v43) {
- return internal::ValueArray43<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
- T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
- T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
- T40, T41, T42, T43>(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);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35,
- typename T36, typename T37, typename T38, typename T39, typename T40,
- typename T41, typename T42, typename T43, typename T44>
-internal::ValueArray44<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
- T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
- T44> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
- T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
- T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
- T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
- T42 v42, T43 v43, T44 v44) {
- return internal::ValueArray44<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
- T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
- T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
- T40, T41, T42, T43, T44>(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);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35,
- typename T36, typename T37, typename T38, typename T39, typename T40,
- typename T41, typename T42, typename T43, typename T44, typename T45>
-internal::ValueArray45<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
- T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
- T44, T45> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8,
- T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16,
- T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24,
- T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32,
- T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40,
- T41 v41, T42 v42, T43 v43, T44 v44, T45 v45) {
- return internal::ValueArray45<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
- T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
- T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
- T40, T41, T42, T43, T44, T45>(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);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35,
- typename T36, typename T37, typename T38, typename T39, typename T40,
- typename T41, typename T42, typename T43, typename T44, typename T45,
- typename T46>
-internal::ValueArray46<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
- T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
- T44, T45, T46> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7,
- T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,
- T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23,
- T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31,
- T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39,
- T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46) {
- return internal::ValueArray46<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
- T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
- T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
- T40, T41, T42, T43, T44, T45, T46>(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);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35,
- typename T36, typename T37, typename T38, typename T39, typename T40,
- typename T41, typename T42, typename T43, typename T44, typename T45,
- typename T46, typename T47>
-internal::ValueArray47<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
- T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
- T44, T45, T46, T47> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7,
- T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,
- T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23,
- T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31,
- T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39,
- T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47) {
- return internal::ValueArray47<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
- T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
- T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
- T40, T41, T42, T43, T44, T45, T46, T47>(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);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35,
- typename T36, typename T37, typename T38, typename T39, typename T40,
- typename T41, typename T42, typename T43, typename T44, typename T45,
- typename T46, typename T47, typename T48>
-internal::ValueArray48<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
- T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
- T44, T45, T46, T47, T48> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6,
- T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,
- T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23,
- T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31,
- T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39,
- T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47,
- T48 v48) {
- return internal::ValueArray48<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
- T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
- T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
- T40, T41, T42, T43, T44, T45, T46, T47, T48>(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);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35,
- typename T36, typename T37, typename T38, typename T39, typename T40,
- typename T41, typename T42, typename T43, typename T44, typename T45,
- typename T46, typename T47, typename T48, typename T49>
-internal::ValueArray49<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
- T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
- T44, T45, T46, T47, T48, T49> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5,
- T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14,
- T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22,
- T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30,
- T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38,
- T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46,
- T47 v47, T48 v48, T49 v49) {
- return internal::ValueArray49<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
- T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
- T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
- T40, T41, T42, T43, T44, T45, T46, T47, T48, T49>(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);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35,
- typename T36, typename T37, typename T38, typename T39, typename T40,
- typename T41, typename T42, typename T43, typename T44, typename T45,
- typename T46, typename T47, typename T48, typename T49, typename T50>
-internal::ValueArray50<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
- T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
- T44, T45, T46, T47, T48, T49, T50> Values(T1 v1, T2 v2, T3 v3, T4 v4,
- T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13,
- T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21,
- T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29,
- T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37,
- T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45,
- T46 v46, T47 v47, T48 v48, T49 v49, T50 v50) {
- return internal::ValueArray50<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
- T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
- T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
- T40, T41, T42, T43, T44, T45, T46, T47, T48, T49, T50>(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);
+template <typename... T>
+internal::ValueArray<T...> Values(T... v) {
+ return internal::ValueArray<T...>(std::move(v)...);
}
// Bool() allows generating tests with parameters in a set of (false, true).
@@ -1207,7 +346,7 @@ internal::ValueArray50<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
// of multiple flags can be tested when several Bool()'s are combined using
// Combine() function.
//
-// In the following example all tests in the test case FlagDependentTest
+// In the following example all tests in the test suite FlagDependentTest
// will be instantiated twice with parameters false and true.
//
// class FlagDependentTest : public testing::TestWithParam<bool> {
@@ -1215,13 +354,12 @@ internal::ValueArray50<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
// external_flag = GetParam();
// }
// }
-// INSTANTIATE_TEST_CASE_P(BoolSequence, FlagDependentTest, Bool());
+// INSTANTIATE_TEST_SUITE_P(BoolSequence, FlagDependentTest, Bool());
//
inline internal::ParamGenerator<bool> Bool() {
return Values(false, true);
}
-# if GTEST_HAS_COMBINE
// Combine() allows the user to combine two or more sequences to produce
// values of a Cartesian product of those sequences' elements.
//
@@ -1230,215 +368,136 @@ inline internal::ParamGenerator<bool> Bool() {
// - returns a generator producing sequences with elements coming from
// the Cartesian product of elements from the sequences generated by
// gen1, gen2, ..., genN. The sequence elements will have a type of
-// tuple<T1, T2, ..., TN> where T1, T2, ..., TN are the types
+// std::tuple<T1, T2, ..., TN> where T1, T2, ..., TN are the types
// of elements from sequences produces by gen1, gen2, ..., genN.
//
-// Combine can have up to 10 arguments. This number is currently limited
-// by the maximum number of elements in the tuple implementation used by Google
-// Test.
+// Combine can have up to 10 arguments.
//
// Example:
//
-// This will instantiate tests in test case AnimalTest each one with
+// This will instantiate tests in test suite AnimalTest each one with
// the parameter values tuple("cat", BLACK), tuple("cat", WHITE),
// tuple("dog", BLACK), and tuple("dog", WHITE):
//
// enum Color { BLACK, GRAY, WHITE };
// class AnimalTest
-// : public testing::TestWithParam<tuple<const char*, Color> > {...};
+// : public testing::TestWithParam<std::tuple<const char*, Color> > {...};
//
// TEST_P(AnimalTest, AnimalLooksNice) {...}
//
-// INSTANTIATE_TEST_CASE_P(AnimalVariations, AnimalTest,
-// Combine(Values("cat", "dog"),
-// Values(BLACK, WHITE)));
+// INSTANTIATE_TEST_SUITE_P(AnimalVariations, AnimalTest,
+// Combine(Values("cat", "dog"),
+// Values(BLACK, WHITE)));
//
// This will instantiate tests in FlagDependentTest with all variations of two
// Boolean flags:
//
// class FlagDependentTest
-// : public testing::TestWithParam<tuple<bool, bool> > {
+// : public testing::TestWithParam<std::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();
+// std::tie(external_flag_1, external_flag_2) = GetParam();
// }
// };
//
// TEST_P(FlagDependentTest, TestFeature1) {
// // Test your code using external_flag_1 and external_flag_2 here.
// }
-// INSTANTIATE_TEST_CASE_P(TwoBoolSequence, FlagDependentTest,
-// Combine(Bool(), Bool()));
-//
-template <typename Generator1, typename Generator2>
-internal::CartesianProductHolder2<Generator1, Generator2> Combine(
- const Generator1& g1, const Generator2& g2) {
- return internal::CartesianProductHolder2<Generator1, Generator2>(
- g1, g2);
-}
-
-template <typename Generator1, typename Generator2, typename Generator3>
-internal::CartesianProductHolder3<Generator1, Generator2, Generator3> Combine(
- const Generator1& g1, const Generator2& g2, const Generator3& g3) {
- return internal::CartesianProductHolder3<Generator1, Generator2, Generator3>(
- g1, g2, g3);
-}
-
-template <typename Generator1, typename Generator2, typename Generator3,
- typename Generator4>
-internal::CartesianProductHolder4<Generator1, Generator2, Generator3,
- Generator4> Combine(
- const Generator1& g1, const Generator2& g2, const Generator3& g3,
- const Generator4& g4) {
- return internal::CartesianProductHolder4<Generator1, Generator2, Generator3,
- Generator4>(
- g1, g2, g3, g4);
-}
-
-template <typename Generator1, typename Generator2, typename Generator3,
- typename Generator4, typename Generator5>
-internal::CartesianProductHolder5<Generator1, Generator2, Generator3,
- Generator4, Generator5> Combine(
- const Generator1& g1, const Generator2& g2, const Generator3& g3,
- const Generator4& g4, const Generator5& g5) {
- return internal::CartesianProductHolder5<Generator1, Generator2, Generator3,
- Generator4, Generator5>(
- g1, g2, g3, g4, g5);
-}
-
-template <typename Generator1, typename Generator2, typename Generator3,
- typename Generator4, typename Generator5, typename Generator6>
-internal::CartesianProductHolder6<Generator1, Generator2, Generator3,
- Generator4, Generator5, Generator6> Combine(
- const Generator1& g1, const Generator2& g2, const Generator3& g3,
- const Generator4& g4, const Generator5& g5, const Generator6& g6) {
- return internal::CartesianProductHolder6<Generator1, Generator2, Generator3,
- Generator4, Generator5, Generator6>(
- g1, g2, g3, g4, g5, g6);
-}
-
-template <typename Generator1, typename Generator2, typename Generator3,
- typename Generator4, typename Generator5, typename Generator6,
- typename Generator7>
-internal::CartesianProductHolder7<Generator1, Generator2, Generator3,
- Generator4, Generator5, Generator6, Generator7> Combine(
- const Generator1& g1, const Generator2& g2, const Generator3& g3,
- const Generator4& g4, const Generator5& g5, const Generator6& g6,
- const Generator7& g7) {
- return internal::CartesianProductHolder7<Generator1, Generator2, Generator3,
- Generator4, Generator5, Generator6, Generator7>(
- g1, g2, g3, g4, g5, g6, g7);
-}
-
-template <typename Generator1, typename Generator2, typename Generator3,
- typename Generator4, typename Generator5, typename Generator6,
- typename Generator7, typename Generator8>
-internal::CartesianProductHolder8<Generator1, Generator2, Generator3,
- Generator4, Generator5, Generator6, Generator7, Generator8> Combine(
- const Generator1& g1, const Generator2& g2, const Generator3& g3,
- const Generator4& g4, const Generator5& g5, const Generator6& g6,
- const Generator7& g7, const Generator8& g8) {
- return internal::CartesianProductHolder8<Generator1, Generator2, Generator3,
- Generator4, Generator5, Generator6, Generator7, Generator8>(
- g1, g2, g3, g4, g5, g6, g7, g8);
-}
-
-template <typename Generator1, typename Generator2, typename Generator3,
- typename Generator4, typename Generator5, typename Generator6,
- typename Generator7, typename Generator8, typename Generator9>
-internal::CartesianProductHolder9<Generator1, Generator2, Generator3,
- Generator4, Generator5, Generator6, Generator7, Generator8,
- Generator9> Combine(
- const Generator1& g1, const Generator2& g2, const Generator3& g3,
- const Generator4& g4, const Generator5& g5, const Generator6& g6,
- const Generator7& g7, const Generator8& g8, const Generator9& g9) {
- return internal::CartesianProductHolder9<Generator1, Generator2, Generator3,
- Generator4, Generator5, Generator6, Generator7, Generator8, Generator9>(
- g1, g2, g3, g4, g5, g6, g7, g8, g9);
-}
-
-template <typename Generator1, typename Generator2, typename Generator3,
- typename Generator4, typename Generator5, typename Generator6,
- typename Generator7, typename Generator8, typename Generator9,
- typename Generator10>
-internal::CartesianProductHolder10<Generator1, Generator2, Generator3,
- Generator4, Generator5, Generator6, Generator7, Generator8, Generator9,
- Generator10> Combine(
- const Generator1& g1, const Generator2& g2, const Generator3& g3,
- const Generator4& g4, const Generator5& g5, const Generator6& g6,
- const Generator7& g7, const Generator8& g8, const Generator9& g9,
- const Generator10& g10) {
- return internal::CartesianProductHolder10<Generator1, Generator2, Generator3,
- Generator4, Generator5, Generator6, Generator7, Generator8, Generator9,
- Generator10>(
- g1, g2, g3, g4, g5, g6, g7, g8, g9, g10);
-}
-# endif // GTEST_HAS_COMBINE
-
-
-
-# define TEST_P(test_case_name, test_name) \
- class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) \
- : public test_case_name { \
- public: \
- GTEST_TEST_CLASS_NAME_(test_case_name, test_name)() {} \
- virtual void TestBody(); \
- private: \
- static int AddToRegistry() { \
- ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \
- GetTestCasePatternHolder<test_case_name>(\
- #test_case_name, \
- ::testing::internal::CodeLocation(\
- __FILE__, __LINE__))->AddTestPattern(\
- #test_case_name, \
- #test_name, \
- new ::testing::internal::TestMetaFactory< \
- GTEST_TEST_CLASS_NAME_(\
- test_case_name, test_name)>()); \
- return 0; \
- } \
- static int gtest_registering_dummy_ GTEST_ATTRIBUTE_UNUSED_; \
- GTEST_DISALLOW_COPY_AND_ASSIGN_(\
- GTEST_TEST_CLASS_NAME_(test_case_name, test_name)); \
- }; \
- int GTEST_TEST_CLASS_NAME_(test_case_name, \
- test_name)::gtest_registering_dummy_ = \
- GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::AddToRegistry(); \
- void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody()
-
-// The optional last argument to INSTANTIATE_TEST_CASE_P allows the user
-// to specify a function or functor that generates custom test name suffixes
-// based on the test parameters. The function should accept one argument of
-// type testing::TestParamInfo<class ParamType>, and return std::string.
+// INSTANTIATE_TEST_SUITE_P(TwoBoolSequence, FlagDependentTest,
+// Combine(Bool(), Bool()));
+//
+template <typename... Generator>
+internal::CartesianProductHolder<Generator...> Combine(const Generator&... g) {
+ return internal::CartesianProductHolder<Generator...>(g...);
+}
+
+#define TEST_P(test_suite_name, test_name) \
+ class GTEST_TEST_CLASS_NAME_(test_suite_name, test_name) \
+ : public test_suite_name { \
+ public: \
+ GTEST_TEST_CLASS_NAME_(test_suite_name, test_name)() {} \
+ virtual void TestBody(); \
+ \
+ private: \
+ static int AddToRegistry() { \
+ ::testing::UnitTest::GetInstance() \
+ ->parameterized_test_registry() \
+ .GetTestSuitePatternHolder<test_suite_name>( \
+ #test_suite_name, \
+ ::testing::internal::CodeLocation(__FILE__, __LINE__)) \
+ ->AddTestPattern( \
+ GTEST_STRINGIFY_(test_suite_name), GTEST_STRINGIFY_(test_name), \
+ new ::testing::internal::TestMetaFactory<GTEST_TEST_CLASS_NAME_( \
+ test_suite_name, test_name)>()); \
+ return 0; \
+ } \
+ static int gtest_registering_dummy_ GTEST_ATTRIBUTE_UNUSED_; \
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(GTEST_TEST_CLASS_NAME_(test_suite_name, \
+ test_name)); \
+ }; \
+ int GTEST_TEST_CLASS_NAME_(test_suite_name, \
+ test_name)::gtest_registering_dummy_ = \
+ GTEST_TEST_CLASS_NAME_(test_suite_name, test_name)::AddToRegistry(); \
+ void GTEST_TEST_CLASS_NAME_(test_suite_name, test_name)::TestBody()
+
+// The last argument to INSTANTIATE_TEST_SUITE_P allows the user to specify
+// generator and an optional function or functor that generates custom test name
+// suffixes based on the test parameters. Such a function or functor should
+// accept one argument of type testing::TestParamInfo<class ParamType>, and
+// return std::string.
//
// testing::PrintToStringParamName is a builtin test suffix generator that
-// returns the value of testing::PrintToString(GetParam()). It does not work
-// for std::string or C strings.
+// returns the value of testing::PrintToString(GetParam()).
//
// Note: test names must be non-empty, unique, and may only contain ASCII
-// alphanumeric characters or underscore.
-
-# define INSTANTIATE_TEST_CASE_P(prefix, test_case_name, generator, ...) \
- ::testing::internal::ParamGenerator<test_case_name::ParamType> \
- gtest_##prefix##test_case_name##_EvalGenerator_() { return generator; } \
- ::std::string gtest_##prefix##test_case_name##_EvalGenerateName_( \
- const ::testing::TestParamInfo<test_case_name::ParamType>& info) { \
- return ::testing::internal::GetParamNameGen<test_case_name::ParamType> \
- (__VA_ARGS__)(info); \
- } \
- int gtest_##prefix##test_case_name##_dummy_ GTEST_ATTRIBUTE_UNUSED_ = \
- ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \
- GetTestCasePatternHolder<test_case_name>(\
- #test_case_name, \
- ::testing::internal::CodeLocation(\
- __FILE__, __LINE__))->AddTestCaseInstantiation(\
- #prefix, \
- &gtest_##prefix##test_case_name##_EvalGenerator_, \
- &gtest_##prefix##test_case_name##_EvalGenerateName_, \
- __FILE__, __LINE__)
+// alphanumeric characters or underscore. Because PrintToString adds quotes
+// to std::string and C strings, it won't work for these types.
+
+#define GTEST_EXPAND_(arg) arg
+#define GTEST_GET_FIRST_(first, ...) first
+#define GTEST_GET_SECOND_(first, second, ...) second
+
+#define INSTANTIATE_TEST_SUITE_P(prefix, test_suite_name, ...) \
+ static ::testing::internal::ParamGenerator<test_suite_name::ParamType> \
+ gtest_##prefix##test_suite_name##_EvalGenerator_() { \
+ return GTEST_EXPAND_(GTEST_GET_FIRST_(__VA_ARGS__, DUMMY_PARAM_)); \
+ } \
+ static ::std::string gtest_##prefix##test_suite_name##_EvalGenerateName_( \
+ const ::testing::TestParamInfo<test_suite_name::ParamType>& info) { \
+ if (::testing::internal::AlwaysFalse()) { \
+ ::testing::internal::TestNotEmpty(GTEST_EXPAND_(GTEST_GET_SECOND_( \
+ __VA_ARGS__, \
+ ::testing::internal::DefaultParamName<test_suite_name::ParamType>, \
+ DUMMY_PARAM_))); \
+ auto t = std::make_tuple(__VA_ARGS__); \
+ static_assert(std::tuple_size<decltype(t)>::value <= 2, \
+ "Too Many Args!"); \
+ } \
+ return ((GTEST_EXPAND_(GTEST_GET_SECOND_( \
+ __VA_ARGS__, \
+ ::testing::internal::DefaultParamName<test_suite_name::ParamType>, \
+ DUMMY_PARAM_))))(info); \
+ } \
+ static int gtest_##prefix##test_suite_name##_dummy_ \
+ GTEST_ATTRIBUTE_UNUSED_ = \
+ ::testing::UnitTest::GetInstance() \
+ ->parameterized_test_registry() \
+ .GetTestSuitePatternHolder<test_suite_name>( \
+ #test_suite_name, \
+ ::testing::internal::CodeLocation(__FILE__, __LINE__)) \
+ ->AddTestSuiteInstantiation( \
+ #prefix, &gtest_##prefix##test_suite_name##_EvalGenerator_, \
+ &gtest_##prefix##test_suite_name##_EvalGenerateName_, \
+ __FILE__, __LINE__)
+
+// Legacy API is deprecated but still available
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+#define INSTANTIATE_TEST_CASE_P \
+ static_assert(::testing::internal::InstantiateTestCase_P_IsDeprecated(), \
+ ""); \
+ INSTANTIATE_TEST_SUITE_P
+#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
} // namespace testing
-#endif // GTEST_HAS_PARAM_TEST
-
#endif // GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_
diff --git a/extern/gtest/include/gtest/gtest-printers.h b/extern/gtest/include/gtest/gtest-printers.h
index 8a33164cb38..56a05450ef5 100644
--- a/extern/gtest/include/gtest/gtest-printers.h
+++ b/extern/gtest/include/gtest/gtest-printers.h
@@ -26,10 +26,9 @@
// 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.
-//
-// Author: wan@google.com (Zhanyong Wan)
-// Google Test - The Google C++ Testing Framework
+
+// Google Test - The Google C++ Testing and Mocking Framework
//
// This file implements a universal value printer that can print a
// value of any type T:
@@ -46,6 +45,10 @@
// 2. operator<<(ostream&, const T&) defined in either foo or the
// global namespace.
//
+// However if T is an STL-style container then it is printed element-wise
+// unless foo::PrintTo(const T&, ostream*) is defined. Note that
+// operator<<() is ignored for container types.
+//
// If none of the above is defined, it will print the debug string of
// the value if it is a protocol buffer, or print the raw bytes in the
// value otherwise.
@@ -92,20 +95,27 @@
// being defined as many user-defined container types don't have
// value_type.
+// GOOGLETEST_CM0001 DO NOT DELETE
+
#ifndef GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_
#define GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_
+#include <functional>
#include <ostream> // NOLINT
#include <sstream>
#include <string>
+#include <tuple>
+#include <type_traits>
#include <utility>
#include <vector>
-#include "gtest/internal/gtest-port.h"
#include "gtest/internal/gtest-internal.h"
+#include "gtest/internal/gtest-port.h"
-#if GTEST_HAS_STD_TUPLE_
-# include <tuple>
-#endif
+#if GTEST_HAS_ABSL
+#include "absl/strings/string_view.h"
+#include "absl/types/optional.h"
+#include "absl/types/variant.h"
+#endif // GTEST_HAS_ABSL
namespace testing {
@@ -125,7 +135,11 @@ enum TypeKind {
kProtobuf, // a protobuf type
kConvertibleToInteger, // a type implicitly convertible to BiggestInt
// (e.g. a named or unnamed enum type)
- kOtherType // anything else
+#if GTEST_HAS_ABSL
+ kConvertibleToStringView, // a type implicitly convertible to
+ // absl::string_view
+#endif
+ kOtherType // anything else
};
// TypeWithoutFormatter<T, kTypeKind>::PrintValue(value, os) is called
@@ -137,8 +151,10 @@ class TypeWithoutFormatter {
public:
// This default version is called when kTypeKind is kOtherType.
static void PrintValue(const T& value, ::std::ostream* os) {
- PrintBytesInObjectTo(reinterpret_cast<const unsigned char*>(&value),
- sizeof(value), os);
+ PrintBytesInObjectTo(
+ static_cast<const unsigned char*>(
+ reinterpret_cast<const void*>(std::addressof(value))),
+ sizeof(value), os);
}
};
@@ -151,10 +167,10 @@ template <typename T>
class TypeWithoutFormatter<T, kProtobuf> {
public:
static void PrintValue(const T& value, ::std::ostream* os) {
- const ::testing::internal::string short_str = value.ShortDebugString();
- const ::testing::internal::string pretty_str =
- short_str.length() <= kProtobufOneLinerMaxLength ?
- short_str : ("\n" + value.DebugString());
+ std::string pretty_str = value.ShortDebugString();
+ if (pretty_str.length() > kProtobufOneLinerMaxLength) {
+ pretty_str = "\n" + value.DebugString();
+ }
*os << ("<" + pretty_str + ">");
}
};
@@ -175,6 +191,19 @@ class TypeWithoutFormatter<T, kConvertibleToInteger> {
}
};
+#if GTEST_HAS_ABSL
+template <typename T>
+class TypeWithoutFormatter<T, kConvertibleToStringView> {
+ public:
+ // Since T has neither operator<< nor PrintTo() but can be implicitly
+ // converted to absl::string_view, we print it as a absl::string_view.
+ //
+ // Note: the implementation is further below, as it depends on
+ // internal::PrintTo symbol which is defined later in the file.
+ static void PrintValue(const T& value, ::std::ostream* os);
+};
+#endif
+
// Prints the given value to the given ostream. If the value is a
// protocol message, its debug string is printed; if it's an enum or
// of a type implicitly convertible to BiggestInt, it's printed as an
@@ -202,10 +231,19 @@ class TypeWithoutFormatter<T, kConvertibleToInteger> {
template <typename Char, typename CharTraits, typename T>
::std::basic_ostream<Char, CharTraits>& operator<<(
::std::basic_ostream<Char, CharTraits>& os, const T& x) {
- TypeWithoutFormatter<T,
- (internal::IsAProtocolMessage<T>::value ? kProtobuf :
- internal::ImplicitlyConvertible<const T&, internal::BiggestInt>::value ?
- kConvertibleToInteger : kOtherType)>::PrintValue(x, &os);
+ TypeWithoutFormatter<T, (internal::IsAProtocolMessage<T>::value
+ ? kProtobuf
+ : std::is_convertible<
+ const T&, internal::BiggestInt>::value
+ ? kConvertibleToInteger
+ :
+#if GTEST_HAS_ABSL
+ std::is_convertible<
+ const T&, absl::string_view>::value
+ ? kConvertibleToStringView
+ :
+#endif
+ kOtherType)>::PrintValue(x, &os);
return os;
}
@@ -320,16 +358,6 @@ GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const wchar_t);
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);
@@ -364,11 +392,18 @@ class UniversalPrinter;
template <typename T>
void UniversalPrint(const T& value, ::std::ostream* os);
+enum DefaultPrinterType {
+ kPrintContainer,
+ kPrintPointer,
+ kPrintFunctionPointer,
+ kPrintOther,
+};
+template <DefaultPrinterType type> struct WrapPrinterType {};
+
// Used to print an STL-style container when the user doesn't define
// a PrintTo() for it.
template <typename C>
-void DefaultPrintTo(IsContainer /* dummy */,
- false_type /* is not a pointer */,
+void DefaultPrintTo(WrapPrinterType<kPrintContainer> /* dummy */,
const C& container, ::std::ostream* os) {
const size_t kMaxCount = 32; // The maximum number of elements to print.
*os << '{';
@@ -401,40 +436,34 @@ void DefaultPrintTo(IsContainer /* dummy */,
// implementation-defined. Therefore they will be printed as raw
// bytes.)
template <typename T>
-void DefaultPrintTo(IsNotContainer /* dummy */,
- true_type /* is a pointer */,
+void DefaultPrintTo(WrapPrinterType<kPrintPointer> /* dummy */,
T* p, ::std::ostream* os) {
- if (p == NULL) {
+ if (p == nullptr) {
*os << "NULL";
} else {
- // C++ doesn't allow casting from a function pointer to any object
- // pointer.
- //
- // IsTrue() silences warnings: "Condition is always true",
- // "unreachable code".
- if (IsTrue(ImplicitlyConvertible<T*, const void*>::value)) {
- // T is not a function type. We just call << to print p,
- // relying on ADL to pick up user-defined << for their pointer
- // types, if any.
- *os << p;
- } else {
- // T is a function type, so '*os << p' doesn't do what we want
- // (it just prints p as bool). We want to print p as a const
- // void*. However, we cannot cast it to const void* directly,
- // even using reinterpret_cast, as earlier versions of gcc
- // (e.g. 3.4.5) cannot compile the cast when p is a function
- // pointer. Casting to UInt64 first solves the problem.
- *os << reinterpret_cast<const void*>(
- reinterpret_cast<internal::UInt64>(p));
- }
+ // T is not a function type. We just call << to print p,
+ // relying on ADL to pick up user-defined << for their pointer
+ // types, if any.
+ *os << p;
+ }
+}
+template <typename T>
+void DefaultPrintTo(WrapPrinterType<kPrintFunctionPointer> /* dummy */,
+ T* p, ::std::ostream* os) {
+ if (p == nullptr) {
+ *os << "NULL";
+ } else {
+ // T is a function type, so '*os << p' doesn't do what we want
+ // (it just prints p as bool). We want to print p as a const
+ // void*.
+ *os << reinterpret_cast<const void*>(p);
}
}
// Used to print a non-container, non-pointer value when the user
// doesn't define PrintTo() for it.
template <typename T>
-void DefaultPrintTo(IsNotContainer /* dummy */,
- false_type /* is not a pointer */,
+void DefaultPrintTo(WrapPrinterType<kPrintOther> /* dummy */,
const T& value, ::std::ostream* os) {
::testing_internal::DefaultPrintNonContainerTo(value, os);
}
@@ -452,11 +481,8 @@ void DefaultPrintTo(IsNotContainer /* dummy */,
// wants).
template <typename T>
void PrintTo(const T& value, ::std::ostream* os) {
- // DefaultPrintTo() is overloaded. The type of its first two
- // arguments determine which version will be picked. If T is an
- // STL-style container, the version for container will be called; if
- // T is a pointer, the pointer version will be called; otherwise the
- // generic version will be called.
+ // DefaultPrintTo() is overloaded. The type of its first argument
+ // determines which version will be picked.
//
// Note that we check for container types here, prior to we check
// for protocol message types in our operator<<. The rationale is:
@@ -468,13 +494,23 @@ void PrintTo(const T& value, ::std::ostream* os) {
// elements; therefore we check for container types here to ensure
// that our format is used.
//
- // The second argument of DefaultPrintTo() is needed to bypass a bug
- // in Symbian's C++ compiler that prevents it from picking the right
- // overload between:
- //
- // PrintTo(const T& x, ...);
- // PrintTo(T* x, ...);
- DefaultPrintTo(IsContainerTest<T>(0), is_pointer<T>(), value, os);
+ // Note that MSVC and clang-cl do allow an implicit conversion from
+ // pointer-to-function to pointer-to-object, but clang-cl warns on it.
+ // So don't use ImplicitlyConvertible if it can be helped since it will
+ // cause this warning, and use a separate overload of DefaultPrintTo for
+ // function pointers so that the `*os << p` in the object pointer overload
+ // doesn't cause that warning either.
+ DefaultPrintTo(
+ WrapPrinterType <
+ (sizeof(IsContainerTest<T>(0)) == sizeof(IsContainer)) &&
+ !IsRecursiveContainer<T>::value
+ ? kPrintContainer
+ : !std::is_pointer<T>::value
+ ? kPrintOther
+ : std::is_function<typename std::remove_pointer<T>::type>::value
+ ? kPrintFunctionPointer
+ : kPrintPointer > (),
+ value, os);
}
// The following list of PrintTo() overloads tells
@@ -553,27 +589,13 @@ void PrintRawArrayTo(const T a[], size_t count, ::std::ostream* os) {
}
}
-// Overloads for ::string and ::std::string.
-#if GTEST_HAS_GLOBAL_STRING
-GTEST_API_ void PrintStringTo(const ::string&s, ::std::ostream* os);
-inline void PrintTo(const ::string& s, ::std::ostream* os) {
- PrintStringTo(s, os);
-}
-#endif // GTEST_HAS_GLOBAL_STRING
-
+// Overloads for ::std::string.
GTEST_API_ void PrintStringTo(const ::std::string&s, ::std::ostream* os);
inline void PrintTo(const ::std::string& s, ::std::ostream* os) {
PrintStringTo(s, os);
}
-// Overloads for ::wstring and ::std::wstring.
-#if GTEST_HAS_GLOBAL_WSTRING
-GTEST_API_ void PrintWideStringTo(const ::wstring&s, ::std::ostream* os);
-inline void PrintTo(const ::wstring& s, ::std::ostream* os) {
- PrintWideStringTo(s, os);
-}
-#endif // GTEST_HAS_GLOBAL_WSTRING
-
+// Overloads for ::std::wstring.
#if GTEST_HAS_STD_WSTRING
GTEST_API_ void PrintWideStringTo(const ::std::wstring&s, ::std::ostream* os);
inline void PrintTo(const ::std::wstring& s, ::std::ostream* os) {
@@ -581,95 +603,45 @@ inline void PrintTo(const ::std::wstring& s, ::std::ostream* os) {
}
#endif // GTEST_HAS_STD_WSTRING
-#if GTEST_HAS_TR1_TUPLE || GTEST_HAS_STD_TUPLE_
-// Helper function for printing a tuple. T must be instantiated with
-// a tuple type.
-template <typename T>
-void PrintTupleTo(const T& t, ::std::ostream* os);
-#endif // GTEST_HAS_TR1_TUPLE || GTEST_HAS_STD_TUPLE_
-
-#if GTEST_HAS_TR1_TUPLE
-// Overload for ::std::tr1::tuple. Needed for printing function arguments,
-// which are packed as tuples.
-
-// Overloaded PrintTo() for tuples of various arities. We support
-// tuples of up-to 10 fields. The following implementation works
-// regardless of whether tr1::tuple is implemented using the
-// non-standard variadic template feature or not.
-
-inline void PrintTo(const ::std::tr1::tuple<>& t, ::std::ostream* os) {
- PrintTupleTo(t, os);
+#if GTEST_HAS_ABSL
+// Overload for absl::string_view.
+inline void PrintTo(absl::string_view sp, ::std::ostream* os) {
+ PrintTo(::std::string(sp), os);
}
+#endif // GTEST_HAS_ABSL
-template <typename T1>
-void PrintTo(const ::std::tr1::tuple<T1>& t, ::std::ostream* os) {
- PrintTupleTo(t, os);
-}
-
-template <typename T1, typename T2>
-void PrintTo(const ::std::tr1::tuple<T1, T2>& t, ::std::ostream* os) {
- PrintTupleTo(t, os);
-}
-
-template <typename T1, typename T2, typename T3>
-void PrintTo(const ::std::tr1::tuple<T1, T2, T3>& t, ::std::ostream* os) {
- PrintTupleTo(t, os);
-}
-
-template <typename T1, typename T2, typename T3, typename T4>
-void PrintTo(const ::std::tr1::tuple<T1, T2, T3, T4>& t, ::std::ostream* os) {
- PrintTupleTo(t, os);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5>
-void PrintTo(const ::std::tr1::tuple<T1, T2, T3, T4, T5>& t,
- ::std::ostream* os) {
- PrintTupleTo(t, os);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6>
-void PrintTo(const ::std::tr1::tuple<T1, T2, T3, T4, T5, T6>& t,
- ::std::ostream* os) {
- PrintTupleTo(t, os);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7>
-void PrintTo(const ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7>& t,
- ::std::ostream* os) {
- PrintTupleTo(t, os);
-}
+inline void PrintTo(std::nullptr_t, ::std::ostream* os) { *os << "(nullptr)"; }
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8>
-void PrintTo(const ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8>& t,
- ::std::ostream* os) {
- PrintTupleTo(t, os);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9>
-void PrintTo(const ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8, T9>& t,
- ::std::ostream* os) {
- PrintTupleTo(t, os);
+template <typename T>
+void PrintTo(std::reference_wrapper<T> ref, ::std::ostream* os) {
+ UniversalPrinter<T&>::Print(ref.get(), os);
}
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10>
-void PrintTo(
- const ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>& t,
- ::std::ostream* os) {
- PrintTupleTo(t, os);
+// Helper function for printing a tuple. T must be instantiated with
+// a tuple type.
+template <typename T>
+void PrintTupleTo(const T&, std::integral_constant<size_t, 0>,
+ ::std::ostream*) {}
+
+template <typename T, size_t I>
+void PrintTupleTo(const T& t, std::integral_constant<size_t, I>,
+ ::std::ostream* os) {
+ PrintTupleTo(t, std::integral_constant<size_t, I - 1>(), os);
+ GTEST_INTENTIONAL_CONST_COND_PUSH_()
+ if (I > 1) {
+ GTEST_INTENTIONAL_CONST_COND_POP_()
+ *os << ", ";
+ }
+ UniversalPrinter<typename std::tuple_element<I - 1, T>::type>::Print(
+ std::get<I - 1>(t), os);
}
-#endif // GTEST_HAS_TR1_TUPLE
-#if GTEST_HAS_STD_TUPLE_
template <typename... Types>
void PrintTo(const ::std::tuple<Types...>& t, ::std::ostream* os) {
- PrintTupleTo(t, os);
+ *os << "(";
+ PrintTupleTo(t, std::integral_constant<size_t, sizeof...(Types)>(), os);
+ *os << ")";
}
-#endif // GTEST_HAS_STD_TUPLE_
// Overload for std::pair.
template <typename T1, typename T2>
@@ -710,6 +682,48 @@ class UniversalPrinter {
GTEST_DISABLE_MSC_WARNINGS_POP_()
};
+#if GTEST_HAS_ABSL
+
+// Printer for absl::optional
+
+template <typename T>
+class UniversalPrinter<::absl::optional<T>> {
+ public:
+ static void Print(const ::absl::optional<T>& value, ::std::ostream* os) {
+ *os << '(';
+ if (!value) {
+ *os << "nullopt";
+ } else {
+ UniversalPrint(*value, os);
+ }
+ *os << ')';
+ }
+};
+
+// Printer for absl::variant
+
+template <typename... T>
+class UniversalPrinter<::absl::variant<T...>> {
+ public:
+ static void Print(const ::absl::variant<T...>& value, ::std::ostream* os) {
+ *os << '(';
+ absl::visit(Visitor{os}, value);
+ *os << ')';
+ }
+
+ private:
+ struct Visitor {
+ template <typename U>
+ void operator()(const U& u) const {
+ *os << "'" << GetTypeName<U>() << "' with value ";
+ UniversalPrint(u, os);
+ }
+ ::std::ostream* os;
+ };
+};
+
+#endif // GTEST_HAS_ABSL
+
// UniversalPrintArray(begin, len, os) prints an array of 'len'
// elements, starting at address 'begin'.
template <typename T>
@@ -723,7 +737,6 @@ void UniversalPrintArray(const T* begin, size_t len, ::std::ostream* os) {
// If the array has more than kThreshold elements, we'll have to
// omit some details by printing only the first and the last
// kChunkSize elements.
- // TODO(wan@google.com): let the user control the threshold using a flag.
if (len <= kThreshold) {
PrintRawArrayTo(begin, len, os);
} else {
@@ -802,10 +815,10 @@ template <>
class UniversalTersePrinter<const char*> {
public:
static void Print(const char* str, ::std::ostream* os) {
- if (str == NULL) {
+ if (str == nullptr) {
*os << "NULL";
} else {
- UniversalPrint(string(str), os);
+ UniversalPrint(std::string(str), os);
}
}
};
@@ -822,7 +835,7 @@ template <>
class UniversalTersePrinter<const wchar_t*> {
public:
static void Print(const wchar_t* str, ::std::ostream* os) {
- if (str == NULL) {
+ if (str == nullptr) {
*os << "NULL";
} else {
UniversalPrint(::std::wstring(str), os);
@@ -856,110 +869,22 @@ void UniversalPrint(const T& value, ::std::ostream* os) {
UniversalPrinter<T1>::Print(value, os);
}
-typedef ::std::vector<string> Strings;
-
-// TuplePolicy<TupleT> must provide:
-// - tuple_size
-// size of tuple TupleT.
-// - get<size_t I>(const TupleT& t)
-// static function extracting element I of tuple TupleT.
-// - tuple_element<size_t I>::type
-// type of element I of tuple TupleT.
-template <typename TupleT>
-struct TuplePolicy;
-
-#if GTEST_HAS_TR1_TUPLE
-template <typename TupleT>
-struct TuplePolicy {
- typedef TupleT Tuple;
- static const size_t tuple_size = ::std::tr1::tuple_size<Tuple>::value;
-
- template <size_t I>
- struct tuple_element : ::std::tr1::tuple_element<I, Tuple> {};
-
- template <size_t I>
- static typename AddReference<
- const typename ::std::tr1::tuple_element<I, Tuple>::type>::type get(
- const Tuple& tuple) {
- return ::std::tr1::get<I>(tuple);
- }
-};
-template <typename TupleT>
-const size_t TuplePolicy<TupleT>::tuple_size;
-#endif // GTEST_HAS_TR1_TUPLE
-
-#if GTEST_HAS_STD_TUPLE_
-template <typename... Types>
-struct TuplePolicy< ::std::tuple<Types...> > {
- typedef ::std::tuple<Types...> Tuple;
- static const size_t tuple_size = ::std::tuple_size<Tuple>::value;
-
- template <size_t I>
- struct tuple_element : ::std::tuple_element<I, Tuple> {};
-
- template <size_t I>
- static const typename ::std::tuple_element<I, Tuple>::type& get(
- const Tuple& tuple) {
- return ::std::get<I>(tuple);
- }
-};
-template <typename... Types>
-const size_t TuplePolicy< ::std::tuple<Types...> >::tuple_size;
-#endif // GTEST_HAS_STD_TUPLE_
-
-#if GTEST_HAS_TR1_TUPLE || GTEST_HAS_STD_TUPLE_
-// This helper template allows PrintTo() for tuples and
-// UniversalTersePrintTupleFieldsToStrings() to be defined by
-// induction on the number of tuple fields. The idea is that
-// TuplePrefixPrinter<N>::PrintPrefixTo(t, os) prints the first N
-// fields in tuple t, and can be defined in terms of
-// TuplePrefixPrinter<N - 1>.
-//
-// The inductive case.
-template <size_t N>
-struct TuplePrefixPrinter {
- // Prints the first N fields of a tuple.
- template <typename Tuple>
- static void PrintPrefixTo(const Tuple& t, ::std::ostream* os) {
- TuplePrefixPrinter<N - 1>::PrintPrefixTo(t, os);
- GTEST_INTENTIONAL_CONST_COND_PUSH_()
- if (N > 1) {
- GTEST_INTENTIONAL_CONST_COND_POP_()
- *os << ", ";
- }
- UniversalPrinter<
- typename TuplePolicy<Tuple>::template tuple_element<N - 1>::type>
- ::Print(TuplePolicy<Tuple>::template get<N - 1>(t), os);
- }
+typedef ::std::vector< ::std::string> Strings;
// Tersely prints the first N fields of a tuple to a string vector,
// one element for each field.
- template <typename Tuple>
- static void TersePrintPrefixToStrings(const Tuple& t, Strings* strings) {
- TuplePrefixPrinter<N - 1>::TersePrintPrefixToStrings(t, strings);
- ::std::stringstream ss;
- UniversalTersePrint(TuplePolicy<Tuple>::template get<N - 1>(t), &ss);
- strings->push_back(ss.str());
- }
-};
-
-// Base case.
-template <>
-struct TuplePrefixPrinter<0> {
- template <typename Tuple>
- static void PrintPrefixTo(const Tuple&, ::std::ostream*) {}
-
- template <typename Tuple>
- static void TersePrintPrefixToStrings(const Tuple&, Strings*) {}
-};
-
-// Helper function for printing a tuple.
-// Tuple must be either std::tr1::tuple or std::tuple type.
template <typename Tuple>
-void PrintTupleTo(const Tuple& t, ::std::ostream* os) {
- *os << "(";
- TuplePrefixPrinter<TuplePolicy<Tuple>::tuple_size>::PrintPrefixTo(t, os);
- *os << ")";
+void TersePrintPrefixToStrings(const Tuple&, std::integral_constant<size_t, 0>,
+ Strings*) {}
+template <typename Tuple, size_t I>
+void TersePrintPrefixToStrings(const Tuple& t,
+ std::integral_constant<size_t, I>,
+ Strings* strings) {
+ TersePrintPrefixToStrings(t, std::integral_constant<size_t, I - 1>(),
+ strings);
+ ::std::stringstream ss;
+ UniversalTersePrint(std::get<I - 1>(t), &ss);
+ strings->push_back(ss.str());
}
// Prints the fields of a tuple tersely to a string vector, one
@@ -968,14 +893,24 @@ void PrintTupleTo(const Tuple& t, ::std::ostream* os) {
template <typename Tuple>
Strings UniversalTersePrintTupleFieldsToStrings(const Tuple& value) {
Strings result;
- TuplePrefixPrinter<TuplePolicy<Tuple>::tuple_size>::
- TersePrintPrefixToStrings(value, &result);
+ TersePrintPrefixToStrings(
+ value, std::integral_constant<size_t, std::tuple_size<Tuple>::value>(),
+ &result);
return result;
}
-#endif // GTEST_HAS_TR1_TUPLE || GTEST_HAS_STD_TUPLE_
} // namespace internal
+#if GTEST_HAS_ABSL
+namespace internal2 {
+template <typename T>
+void TypeWithoutFormatter<T, kConvertibleToStringView>::PrintValue(
+ const T& value, ::std::ostream* os) {
+ internal::PrintTo(absl::string_view(value), os);
+}
+} // namespace internal2
+#endif
+
template <typename T>
::std::string PrintToString(const T& value) {
::std::stringstream ss;
diff --git a/extern/gtest/include/gtest/gtest-spi.h b/extern/gtest/include/gtest/gtest-spi.h
index f63fa9a1b2a..aa38870e8e1 100644
--- a/extern/gtest/include/gtest/gtest-spi.h
+++ b/extern/gtest/include/gtest/gtest-spi.h
@@ -26,17 +26,21 @@
// 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.
-//
-// Author: wan@google.com (Zhanyong Wan)
+
//
// Utilities for testing Google Test itself and code that uses Google Test
// (e.g. frameworks built on top of Google Test).
+// GOOGLETEST_CM0004 DO NOT DELETE
+
#ifndef GTEST_INCLUDE_GTEST_GTEST_SPI_H_
#define GTEST_INCLUDE_GTEST_GTEST_SPI_H_
#include "gtest/gtest.h"
+GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \
+/* class A needs to have dll-interface to be used by clients of class B */)
+
namespace testing {
// This helper class can be used to mock out Google Test failure reporting
@@ -68,14 +72,15 @@ class GTEST_API_ ScopedFakeTestPartResultReporter
TestPartResultArray* result);
// The d'tor restores the previous test part result reporter.
- virtual ~ScopedFakeTestPartResultReporter();
+ ~ScopedFakeTestPartResultReporter() override;
// Appends the TestPartResult object to the TestPartResultArray
// received in the constructor.
//
// This method is from the TestPartResultReporterInterface
// interface.
- virtual void ReportTestPartResult(const TestPartResult& result);
+ void ReportTestPartResult(const TestPartResult& result) override;
+
private:
void Init();
@@ -97,13 +102,12 @@ class GTEST_API_ SingleFailureChecker {
public:
// The constructor remembers the arguments.
SingleFailureChecker(const TestPartResultArray* results,
- TestPartResult::Type type,
- const string& substr);
+ TestPartResult::Type type, const std::string& substr);
~SingleFailureChecker();
private:
const TestPartResultArray* const results_;
const TestPartResult::Type type_;
- const string substr_;
+ const std::string substr_;
GTEST_DISALLOW_COPY_AND_ASSIGN_(SingleFailureChecker);
};
@@ -112,6 +116,8 @@ class GTEST_API_ SingleFailureChecker {
} // namespace testing
+GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251
+
// A set of macros for testing Google Test assertions or code that's expected
// to generate Google Test fatal failures. It verifies that the given
// statement will cause exactly one fatal Google Test failure with 'substr'
diff --git a/extern/gtest/include/gtest/gtest-test-part.h b/extern/gtest/include/gtest/gtest-test-part.h
index 77eb844839d..05a79853586 100644
--- a/extern/gtest/include/gtest/gtest-test-part.h
+++ b/extern/gtest/include/gtest/gtest-test-part.h
@@ -27,8 +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.
//
-// Author: mheule@google.com (Markus Heule)
-//
+// GOOGLETEST_CM0001 DO NOT DELETE
#ifndef GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_
#define GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_
@@ -38,6 +37,9 @@
#include "gtest/internal/gtest-internal.h"
#include "gtest/internal/gtest-string.h"
+GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \
+/* class A needs to have dll-interface to be used by clients of class B */)
+
namespace testing {
// A copyable object representing the result of a test part (i.e. an
@@ -51,22 +53,20 @@ class GTEST_API_ TestPartResult {
enum Type {
kSuccess, // Succeeded.
kNonFatalFailure, // Failed but the test can continue.
- kFatalFailure // Failed and the test should be terminated.
+ kFatalFailure, // Failed and the test should be terminated.
+ kSkip // Skipped.
};
// C'tor. TestPartResult does NOT have a default constructor.
// Always use this constructor (with parameters) to create a
// TestPartResult object.
- TestPartResult(Type a_type,
- const char* a_file_name,
- int a_line_number,
+ TestPartResult(Type a_type, const char* a_file_name, int a_line_number,
const char* a_message)
: type_(a_type),
- file_name_(a_file_name == NULL ? "" : a_file_name),
+ file_name_(a_file_name == nullptr ? "" : a_file_name),
line_number_(a_line_number),
summary_(ExtractSummary(a_message)),
- message_(a_message) {
- }
+ message_(a_message) {}
// Gets the outcome of the test part.
Type type() const { return type_; }
@@ -74,7 +74,7 @@ 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_.empty() ? NULL : file_name_.c_str();
+ return file_name_.empty() ? nullptr : file_name_.c_str();
}
// Gets the line in the source file where the test part took place,
@@ -87,18 +87,21 @@ class GTEST_API_ TestPartResult {
// Gets the message associated with the test part.
const char* message() const { return message_.c_str(); }
- // Returns true iff the test part passed.
- bool passed() const { return type_ == kSuccess; }
+ // Returns true if and only if the test part was skipped.
+ bool skipped() const { return type_ == kSkip; }
- // Returns true iff the test part failed.
- bool failed() const { return type_ != kSuccess; }
+ // Returns true if and only if the test part passed.
+ bool passed() const { return type_ == kSuccess; }
- // Returns true iff the test part non-fatally failed.
+ // Returns true if and only if the test part non-fatally failed.
bool nonfatally_failed() const { return type_ == kNonFatalFailure; }
- // Returns true iff the test part fatally failed.
+ // Returns true if and only if the test part fatally failed.
bool fatally_failed() const { return type_ == kFatalFailure; }
+ // Returns true if and only if the test part failed.
+ bool failed() const { return fatally_failed() || nonfatally_failed(); }
+
private:
Type type_;
@@ -143,7 +146,7 @@ class GTEST_API_ TestPartResultArray {
};
// This interface knows how to report a test part result.
-class TestPartResultReporterInterface {
+class GTEST_API_ TestPartResultReporterInterface {
public:
virtual ~TestPartResultReporterInterface() {}
@@ -162,8 +165,8 @@ class GTEST_API_ HasNewFatalFailureHelper
: public TestPartResultReporterInterface {
public:
HasNewFatalFailureHelper();
- virtual ~HasNewFatalFailureHelper();
- virtual void ReportTestPartResult(const TestPartResult& result);
+ ~HasNewFatalFailureHelper() override;
+ void ReportTestPartResult(const TestPartResult& result) override;
bool has_new_fatal_failure() const { return has_new_fatal_failure_; }
private:
bool has_new_fatal_failure_;
@@ -176,4 +179,6 @@ class GTEST_API_ HasNewFatalFailureHelper
} // namespace testing
+GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251
+
#endif // GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_
diff --git a/extern/gtest/include/gtest/gtest-typed-test.h b/extern/gtest/include/gtest/gtest-typed-test.h
index 5f69d5678ea..095ce058022 100644
--- a/extern/gtest/include/gtest/gtest-typed-test.h
+++ b/extern/gtest/include/gtest/gtest-typed-test.h
@@ -26,8 +26,9 @@
// 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.
-//
-// Author: wan@google.com (Zhanyong Wan)
+
+
+// GOOGLETEST_CM0001 DO NOT DELETE
#ifndef GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_
#define GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_
@@ -51,22 +52,22 @@ class FooTest : public testing::Test {
T value_;
};
-// Next, associate a list of types with the test case, which will be
+// Next, associate a list of types with the test suite, which will be
// repeated for each type in the list. The typedef is necessary for
// the macro to parse correctly.
typedef testing::Types<char, int, unsigned int> MyTypes;
-TYPED_TEST_CASE(FooTest, MyTypes);
+TYPED_TEST_SUITE(FooTest, MyTypes);
// If the type list contains only one type, you can write that type
// directly without Types<...>:
-// TYPED_TEST_CASE(FooTest, int);
+// TYPED_TEST_SUITE(FooTest, int);
// Then, use TYPED_TEST() instead of TEST_F() to define as many typed
-// tests for this test case as you want.
+// tests for this test suite as you want.
TYPED_TEST(FooTest, DoesBlah) {
- // Inside a test, refer to TypeParam to get the type parameter.
- // Since we are inside a derived class template, C++ requires use to
- // visit the members of FooTest via 'this'.
+ // Inside a test, refer to the special name TypeParam to get the type
+ // parameter. Since we are inside a derived class template, C++ requires
+ // us to visit the members of FooTest via 'this'.
TypeParam n = this->value_;
// To visit static members of the fixture, add the TestFixture::
@@ -82,6 +83,24 @@ TYPED_TEST(FooTest, DoesBlah) {
TYPED_TEST(FooTest, HasPropertyA) { ... }
+// TYPED_TEST_SUITE takes an optional third argument which allows to specify a
+// class that generates custom test name suffixes based on the type. This should
+// be a class which has a static template function GetName(int index) returning
+// a string for each type. The provided integer index equals the index of the
+// type in the provided type list. In many cases the index can be ignored.
+//
+// For example:
+// class MyTypeNames {
+// public:
+// template <typename T>
+// static std::string GetName(int) {
+// if (std::is_same<T, char>()) return "char";
+// if (std::is_same<T, int>()) return "int";
+// if (std::is_same<T, unsigned int>()) return "unsignedInt";
+// }
+// };
+// TYPED_TEST_SUITE(FooTest, MyTypes, MyTypeNames);
+
#endif // 0
// Type-parameterized tests are abstract test patterns parameterized
@@ -107,13 +126,13 @@ class FooTest : public testing::Test {
...
};
-// Next, declare that you will define a type-parameterized test case
+// Next, declare that you will define a type-parameterized test suite
// (the _P suffix is for "parameterized" or "pattern", whichever you
// prefer):
-TYPED_TEST_CASE_P(FooTest);
+TYPED_TEST_SUITE_P(FooTest);
// Then, use TYPED_TEST_P() to define as many type-parameterized tests
-// for this type-parameterized test case as you want.
+// for this type-parameterized test suite as you want.
TYPED_TEST_P(FooTest, DoesBlah) {
// Inside a test, refer to TypeParam to get the type parameter.
TypeParam n = 0;
@@ -124,10 +143,10 @@ TYPED_TEST_P(FooTest, HasPropertyA) { ... }
// Now the tricky part: you need to register all test patterns before
// you can instantiate them. The first argument of the macro is the
-// test case name; the rest are the names of the tests in this test
+// test suite name; the rest are the names of the tests in this test
// case.
-REGISTER_TYPED_TEST_CASE_P(FooTest,
- DoesBlah, HasPropertyA);
+REGISTER_TYPED_TEST_SUITE_P(FooTest,
+ DoesBlah, HasPropertyA);
// Finally, you are free to instantiate the pattern with the types you
// want. If you put the above code in a header file, you can #include
@@ -135,14 +154,19 @@ REGISTER_TYPED_TEST_CASE_P(FooTest,
//
// To distinguish different instances of the pattern, the first
// argument to the INSTANTIATE_* macro is a prefix that will be added
-// to the actual test case name. Remember to pick unique prefixes for
+// to the actual test suite name. Remember to pick unique prefixes for
// different instances.
typedef testing::Types<char, int, unsigned int> MyTypes;
-INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, MyTypes);
+INSTANTIATE_TYPED_TEST_SUITE_P(My, FooTest, MyTypes);
// If the type list contains only one type, you can write that type
// directly without Types<...>:
-// INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, int);
+// INSTANTIATE_TYPED_TEST_SUITE_P(My, FooTest, int);
+//
+// Similar to the optional argument of TYPED_TEST_SUITE above,
+// INSTANTIATE_TEST_SUITE_P takes an optional fourth argument which allows to
+// generate custom names.
+// INSTANTIATE_TYPED_TEST_SUITE_P(My, FooTest, MyTypes, MyTypeNames);
#endif // 0
@@ -156,35 +180,53 @@ INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, MyTypes);
// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
//
// Expands to the name of the typedef for the type parameters of the
-// given test case.
-# define GTEST_TYPE_PARAMS_(TestCaseName) gtest_type_params_##TestCaseName##_
-
-// The 'Types' template argument below must have spaces around it
-// since some compilers may choke on '>>' when passing a template
-// instance (e.g. Types<int>)
-# define TYPED_TEST_CASE(CaseName, Types) \
- typedef ::testing::internal::TypeList< Types >::type \
- GTEST_TYPE_PARAMS_(CaseName)
-
-# define TYPED_TEST(CaseName, TestName) \
- template <typename gtest_TypeParam_> \
- class GTEST_TEST_CLASS_NAME_(CaseName, TestName) \
- : public CaseName<gtest_TypeParam_> { \
- private: \
- typedef CaseName<gtest_TypeParam_> TestFixture; \
- typedef gtest_TypeParam_ TypeParam; \
- virtual void TestBody(); \
- }; \
- bool gtest_##CaseName##_##TestName##_registered_ GTEST_ATTRIBUTE_UNUSED_ = \
- ::testing::internal::TypeParameterizedTest< \
- CaseName, \
- ::testing::internal::TemplateSel< \
- GTEST_TEST_CLASS_NAME_(CaseName, TestName)>, \
- GTEST_TYPE_PARAMS_(CaseName)>::Register(\
- "", ::testing::internal::CodeLocation(__FILE__, __LINE__), \
- #CaseName, #TestName, 0); \
- template <typename gtest_TypeParam_> \
- void GTEST_TEST_CLASS_NAME_(CaseName, TestName)<gtest_TypeParam_>::TestBody()
+// given test suite.
+#define GTEST_TYPE_PARAMS_(TestSuiteName) gtest_type_params_##TestSuiteName##_
+
+// Expands to the name of the typedef for the NameGenerator, responsible for
+// creating the suffixes of the name.
+#define GTEST_NAME_GENERATOR_(TestSuiteName) \
+ gtest_type_params_##TestSuiteName##_NameGenerator
+
+#define TYPED_TEST_SUITE(CaseName, Types, ...) \
+ typedef ::testing::internal::TypeList<Types>::type GTEST_TYPE_PARAMS_( \
+ CaseName); \
+ typedef ::testing::internal::NameGeneratorSelector<__VA_ARGS__>::type \
+ GTEST_NAME_GENERATOR_(CaseName)
+
+# define TYPED_TEST(CaseName, TestName) \
+ template <typename gtest_TypeParam_> \
+ class GTEST_TEST_CLASS_NAME_(CaseName, TestName) \
+ : public CaseName<gtest_TypeParam_> { \
+ private: \
+ typedef CaseName<gtest_TypeParam_> TestFixture; \
+ typedef gtest_TypeParam_ TypeParam; \
+ virtual void TestBody(); \
+ }; \
+ static bool gtest_##CaseName##_##TestName##_registered_ \
+ GTEST_ATTRIBUTE_UNUSED_ = \
+ ::testing::internal::TypeParameterizedTest< \
+ CaseName, \
+ ::testing::internal::TemplateSel<GTEST_TEST_CLASS_NAME_(CaseName, \
+ TestName)>, \
+ GTEST_TYPE_PARAMS_( \
+ CaseName)>::Register("", \
+ ::testing::internal::CodeLocation( \
+ __FILE__, __LINE__), \
+ #CaseName, #TestName, 0, \
+ ::testing::internal::GenerateNames< \
+ GTEST_NAME_GENERATOR_(CaseName), \
+ GTEST_TYPE_PARAMS_(CaseName)>()); \
+ template <typename gtest_TypeParam_> \
+ void GTEST_TEST_CLASS_NAME_(CaseName, \
+ TestName)<gtest_TypeParam_>::TestBody()
+
+// Legacy API is deprecated but still available
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+#define TYPED_TEST_CASE \
+ static_assert(::testing::internal::TypedTestCaseIsDeprecated(), ""); \
+ TYPED_TEST_SUITE
+#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
#endif // GTEST_HAS_TYPED_TEST
@@ -195,68 +237,93 @@ INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, MyTypes);
// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
//
// Expands to the namespace name that the type-parameterized tests for
-// the given type-parameterized test case are defined in. The exact
+// the given type-parameterized test suite are defined in. The exact
// name of the namespace is subject to change without notice.
-# define GTEST_CASE_NAMESPACE_(TestCaseName) \
- gtest_case_##TestCaseName##_
+#define GTEST_SUITE_NAMESPACE_(TestSuiteName) gtest_suite_##TestSuiteName##_
// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
//
// Expands to the name of the variable used to remember the names of
-// the defined tests in the given test case.
-# define GTEST_TYPED_TEST_CASE_P_STATE_(TestCaseName) \
- gtest_typed_test_case_p_state_##TestCaseName##_
+// the defined tests in the given test suite.
+#define GTEST_TYPED_TEST_SUITE_P_STATE_(TestSuiteName) \
+ gtest_typed_test_suite_p_state_##TestSuiteName##_
// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE DIRECTLY.
//
// Expands to the name of the variable used to remember the names of
-// the registered tests in the given test case.
-# define GTEST_REGISTERED_TEST_NAMES_(TestCaseName) \
- gtest_registered_test_names_##TestCaseName##_
+// the registered tests in the given test suite.
+#define GTEST_REGISTERED_TEST_NAMES_(TestSuiteName) \
+ gtest_registered_test_names_##TestSuiteName##_
// The variables defined in the type-parameterized test macros are
// static as typically these macros are used in a .h file that can be
// #included in multiple translation units linked together.
-# define TYPED_TEST_CASE_P(CaseName) \
- static ::testing::internal::TypedTestCasePState \
- GTEST_TYPED_TEST_CASE_P_STATE_(CaseName)
-
-# define TYPED_TEST_P(CaseName, TestName) \
- namespace GTEST_CASE_NAMESPACE_(CaseName) { \
- template <typename gtest_TypeParam_> \
- class TestName : public CaseName<gtest_TypeParam_> { \
- private: \
- typedef CaseName<gtest_TypeParam_> TestFixture; \
- typedef gtest_TypeParam_ TypeParam; \
- virtual void TestBody(); \
- }; \
- static bool gtest_##TestName##_defined_ GTEST_ATTRIBUTE_UNUSED_ = \
- GTEST_TYPED_TEST_CASE_P_STATE_(CaseName).AddTestName(\
- __FILE__, __LINE__, #CaseName, #TestName); \
- } \
- template <typename gtest_TypeParam_> \
- void GTEST_CASE_NAMESPACE_(CaseName)::TestName<gtest_TypeParam_>::TestBody()
-
-# define REGISTER_TYPED_TEST_CASE_P(CaseName, ...) \
- namespace GTEST_CASE_NAMESPACE_(CaseName) { \
- typedef ::testing::internal::Templates<__VA_ARGS__>::type gtest_AllTests_; \
- } \
- static const char* const GTEST_REGISTERED_TEST_NAMES_(CaseName) = \
- GTEST_TYPED_TEST_CASE_P_STATE_(CaseName).VerifyRegisteredTestNames(\
+#define TYPED_TEST_SUITE_P(SuiteName) \
+ static ::testing::internal::TypedTestSuitePState \
+ GTEST_TYPED_TEST_SUITE_P_STATE_(SuiteName)
+
+// Legacy API is deprecated but still available
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+#define TYPED_TEST_CASE_P \
+ static_assert(::testing::internal::TypedTestCase_P_IsDeprecated(), ""); \
+ TYPED_TEST_SUITE_P
+#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+
+#define TYPED_TEST_P(SuiteName, TestName) \
+ namespace GTEST_SUITE_NAMESPACE_(SuiteName) { \
+ template <typename gtest_TypeParam_> \
+ class TestName : public SuiteName<gtest_TypeParam_> { \
+ private: \
+ typedef SuiteName<gtest_TypeParam_> TestFixture; \
+ typedef gtest_TypeParam_ TypeParam; \
+ virtual void TestBody(); \
+ }; \
+ static bool gtest_##TestName##_defined_ GTEST_ATTRIBUTE_UNUSED_ = \
+ GTEST_TYPED_TEST_SUITE_P_STATE_(SuiteName).AddTestName( \
+ __FILE__, __LINE__, #SuiteName, #TestName); \
+ } \
+ template <typename gtest_TypeParam_> \
+ void GTEST_SUITE_NAMESPACE_( \
+ SuiteName)::TestName<gtest_TypeParam_>::TestBody()
+
+#define REGISTER_TYPED_TEST_SUITE_P(SuiteName, ...) \
+ namespace GTEST_SUITE_NAMESPACE_(SuiteName) { \
+ typedef ::testing::internal::Templates<__VA_ARGS__>::type gtest_AllTests_; \
+ } \
+ static const char* const GTEST_REGISTERED_TEST_NAMES_( \
+ SuiteName) GTEST_ATTRIBUTE_UNUSED_ = \
+ GTEST_TYPED_TEST_SUITE_P_STATE_(SuiteName).VerifyRegisteredTestNames( \
__FILE__, __LINE__, #__VA_ARGS__)
-// The 'Types' template argument below must have spaces around it
-// since some compilers may choke on '>>' when passing a template
-// instance (e.g. Types<int>)
-# define INSTANTIATE_TYPED_TEST_CASE_P(Prefix, CaseName, Types) \
- bool gtest_##Prefix##_##CaseName GTEST_ATTRIBUTE_UNUSED_ = \
- ::testing::internal::TypeParameterizedTestCase<CaseName, \
- GTEST_CASE_NAMESPACE_(CaseName)::gtest_AllTests_, \
- ::testing::internal::TypeList< Types >::type>::Register(\
- #Prefix, \
- ::testing::internal::CodeLocation(__FILE__, __LINE__), \
- &GTEST_TYPED_TEST_CASE_P_STATE_(CaseName), \
- #CaseName, GTEST_REGISTERED_TEST_NAMES_(CaseName))
+// Legacy API is deprecated but still available
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+#define REGISTER_TYPED_TEST_CASE_P \
+ static_assert(::testing::internal::RegisterTypedTestCase_P_IsDeprecated(), \
+ ""); \
+ REGISTER_TYPED_TEST_SUITE_P
+#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+
+#define INSTANTIATE_TYPED_TEST_SUITE_P(Prefix, SuiteName, Types, ...) \
+ static bool gtest_##Prefix##_##SuiteName GTEST_ATTRIBUTE_UNUSED_ = \
+ ::testing::internal::TypeParameterizedTestSuite< \
+ SuiteName, GTEST_SUITE_NAMESPACE_(SuiteName)::gtest_AllTests_, \
+ ::testing::internal::TypeList<Types>::type>:: \
+ Register(#Prefix, \
+ ::testing::internal::CodeLocation(__FILE__, __LINE__), \
+ &GTEST_TYPED_TEST_SUITE_P_STATE_(SuiteName), #SuiteName, \
+ GTEST_REGISTERED_TEST_NAMES_(SuiteName), \
+ ::testing::internal::GenerateNames< \
+ ::testing::internal::NameGeneratorSelector< \
+ __VA_ARGS__>::type, \
+ ::testing::internal::TypeList<Types>::type>())
+
+// Legacy API is deprecated but still available
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+#define INSTANTIATE_TYPED_TEST_CASE_P \
+ static_assert( \
+ ::testing::internal::InstantiateTypedTestCase_P_IsDeprecated(), ""); \
+ INSTANTIATE_TYPED_TEST_SUITE_P
+#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
#endif // GTEST_HAS_TYPED_TEST_P
diff --git a/extern/gtest/include/gtest/gtest.h b/extern/gtest/include/gtest/gtest.h
index f846c5bd669..dbe5b1c2c3f 100644
--- a/extern/gtest/include/gtest/gtest.h
+++ b/extern/gtest/include/gtest/gtest.h
@@ -26,10 +26,9 @@
// 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.
+
//
-// Author: wan@google.com (Zhanyong Wan)
-//
-// The Google C++ Testing Framework (Google Test)
+// The Google C++ Testing and Mocking Framework (Google Test)
//
// This header file defines the public API for Google Test. It should be
// included by any test program that uses Google Test.
@@ -48,16 +47,22 @@
// registration from Barthelemy Dagenais' (barthelemy@prologique.com)
// easyUnit framework.
+// GOOGLETEST_CM0001 DO NOT DELETE
+
#ifndef GTEST_INCLUDE_GTEST_GTEST_H_
#define GTEST_INCLUDE_GTEST_GTEST_H_
+#include <cstddef>
#include <limits>
+#include <memory>
#include <ostream>
+#include <type_traits>
#include <vector>
#include "gtest/internal/gtest-internal.h"
#include "gtest/internal/gtest-string.h"
#include "gtest/gtest-death-test.h"
+#include "gtest/gtest-matchers.h"
#include "gtest/gtest-message.h"
#include "gtest/gtest-param-test.h"
#include "gtest/gtest-printers.h"
@@ -65,23 +70,20 @@
#include "gtest/gtest-test-part.h"
#include "gtest/gtest-typed-test.h"
-// Depending on the platform, different string classes are available.
-// On Linux, in addition to ::std::string, Google also makes use of
-// class ::string, which has the same interface as ::std::string, but
-// has a different implementation.
-//
-// You can define GTEST_HAS_GLOBAL_STRING to 1 to indicate that
-// ::string is available AND is a distinct type to ::std::string, or
-// define it to 0 to indicate otherwise.
-//
-// If ::std::string and ::string are the same class on your platform
-// due to aliasing, you should define GTEST_HAS_GLOBAL_STRING to 0.
-//
-// If you do not define GTEST_HAS_GLOBAL_STRING, it is defined
-// heuristically.
+GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \
+/* class A needs to have dll-interface to be used by clients of class B */)
namespace testing {
+// Silence C4100 (unreferenced formal parameter) and 4805
+// unsafe mix of type 'const int' and type 'const bool'
+#ifdef _MSC_VER
+# pragma warning(push)
+# pragma warning(disable:4805)
+# pragma warning(disable:4100)
+#endif
+
+
// Declares the flags.
// This flag temporary enables the disabled tests.
@@ -103,6 +105,10 @@ GTEST_DECLARE_string_(color);
// the tests to run. If the filter is not given all tests are executed.
GTEST_DECLARE_string_(filter);
+// This flag controls whether Google Test installs a signal handler that dumps
+// debugging information when fatal signals are raised.
+GTEST_DECLARE_bool_(install_failure_signal_handler);
+
// This flag causes the Google Test to list tests. None of the tests listed
// are actually run if the flag is provided.
GTEST_DECLARE_bool_(list_tests);
@@ -115,6 +121,9 @@ GTEST_DECLARE_string_(output);
// test.
GTEST_DECLARE_bool_(print_time);
+// This flags control whether Google Test prints UTF8 characters as text.
+GTEST_DECLARE_bool_(print_utf8);
+
// This flag specifies the random number seed.
GTEST_DECLARE_int32_(random_seed);
@@ -135,7 +144,7 @@ GTEST_DECLARE_int32_(stack_trace_depth);
// When this flag is specified, a failed assertion will throw an
// exception if exceptions are enabled, or exit the program with a
-// non-zero code otherwise.
+// non-zero code otherwise. For use with an external test framework.
GTEST_DECLARE_bool_(throw_on_failure);
// When this flag is set with a "host:port" string, on supported
@@ -143,6 +152,10 @@ GTEST_DECLARE_bool_(throw_on_failure);
// the specified host machine.
GTEST_DECLARE_string_(stream_result_to);
+#if GTEST_USE_OWN_FLAGFILE_FLAG_
+GTEST_DECLARE_string_(flagfile);
+#endif // GTEST_USE_OWN_FLAGFILE_FLAG_
+
// The upper limit for valid stack trace depths.
const int kMaxStackTraceDepth = 100;
@@ -160,6 +173,7 @@ class TestEventListenersAccessor;
class TestEventRepeater;
class UnitTestRecordPropertyTestHelper;
class WindowsDeathTest;
+class FuchsiaDeathTest;
class UnitTestImpl* GetUnitTestImpl();
void ReportFailureInUnknownLocation(TestPartResult::Type result_type,
const std::string& message);
@@ -170,7 +184,12 @@ void ReportFailureInUnknownLocation(TestPartResult::Type result_type,
// If we don't forward declare them the compiler might confuse the classes
// in friendship clauses with same named classes on the scope.
class Test;
-class TestCase;
+class TestSuite;
+
+// Old API is still available but deprecated
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+using TestCase = TestSuite;
+#endif
class TestInfo;
class UnitTest;
@@ -259,7 +278,9 @@ class GTEST_API_ AssertionResult {
// Used in EXPECT_TRUE/FALSE(assertion_result).
AssertionResult(const AssertionResult& other);
+#if defined(_MSC_VER) && _MSC_VER < 1910
GTEST_DISABLE_MSC_WARNINGS_PUSH_(4800 /* forcing value to bool */)
+#endif
// Used in the EXPECT_TRUE/FALSE(bool_expression).
//
@@ -271,12 +292,15 @@ class GTEST_API_ AssertionResult {
template <typename T>
explicit AssertionResult(
const T& success,
- typename internal::EnableIf<
- !internal::ImplicitlyConvertible<T, AssertionResult>::value>::type*
- /*enabler*/ = NULL)
+ typename std::enable_if<
+ !std::is_convertible<T, AssertionResult>::value>::type*
+ /*enabler*/
+ = nullptr)
: success_(success) {}
+#if defined(_MSC_VER) && _MSC_VER < 1910
GTEST_DISABLE_MSC_WARNINGS_POP_()
+#endif
// Assignment operator.
AssertionResult& operator=(AssertionResult other) {
@@ -284,7 +308,7 @@ class GTEST_API_ AssertionResult {
return *this;
}
- // Returns true iff the assertion succeeded.
+ // Returns true if and only if the assertion succeeded.
operator bool() const { return success_; } // NOLINT
// Returns the assertion's negation. Used with EXPECT/ASSERT_FALSE.
@@ -295,9 +319,8 @@ class GTEST_API_ AssertionResult {
// assertion's expectation). When nothing has been streamed into the
// object, returns an empty string.
const char* message() const {
- return message_.get() != NULL ? message_->c_str() : "";
+ return message_.get() != nullptr ? message_->c_str() : "";
}
- // TODO(vladl@google.com): Remove this after making sure no clients use it.
// Deprecated; please use message() instead.
const char* failure_message() const { return message(); }
@@ -318,8 +341,7 @@ class GTEST_API_ AssertionResult {
private:
// Appends the contents of message to message_.
void AppendMessage(const Message& a_message) {
- if (message_.get() == NULL)
- message_.reset(new ::std::string);
+ if (message_.get() == nullptr) message_.reset(new ::std::string);
message_->append(a_message.GetString().c_str());
}
@@ -332,7 +354,7 @@ class GTEST_API_ AssertionResult {
// construct is not satisfied with the predicate's outcome.
// Referenced via a pointer to avoid taking too much stack frame space
// with test assertions.
- internal::scoped_ptr< ::std::string> message_;
+ std::unique_ptr< ::std::string> message_;
};
// Makes a successful assertion result.
@@ -345,17 +367,26 @@ GTEST_API_ AssertionResult AssertionFailure();
// Deprecated; use AssertionFailure() << msg.
GTEST_API_ AssertionResult AssertionFailure(const Message& msg);
+} // namespace testing
+
+// Includes the auto-generated header that implements a family of generic
+// predicate assertion macros. This include comes late because it relies on
+// APIs declared above.
+#include "gtest/gtest_pred_impl.h"
+
+namespace testing {
+
// The abstract class that all tests inherit from.
//
-// In Google Test, a unit test program contains one or many TestCases, and
-// each TestCase contains one or many Tests.
+// In Google Test, a unit test program contains one or many TestSuites, and
+// each TestSuite contains one or many Tests.
//
// When you define a test using the TEST macro, you don't need to
// explicitly derive from Test - the TEST macro automatically does
// this for you.
//
// The only time you derive from Test is when defining a test fixture
-// to be used a TEST_F. For example:
+// to be used in a TEST_F. For example:
//
// class FooTest : public testing::Test {
// protected:
@@ -372,49 +403,57 @@ class GTEST_API_ Test {
public:
friend class TestInfo;
- // Defines types for pointers to functions that set up and tear down
- // a test case.
- typedef internal::SetUpTestCaseFunc SetUpTestCaseFunc;
- typedef internal::TearDownTestCaseFunc TearDownTestCaseFunc;
-
// The d'tor is virtual as we intend to inherit from Test.
virtual ~Test();
// Sets up the stuff shared by all tests in this test case.
//
- // Google Test will call Foo::SetUpTestCase() before running the first
+ // Google Test will call Foo::SetUpTestSuite() before running the first
// test in test case Foo. Hence a sub-class can define its own
- // SetUpTestCase() method to shadow the one defined in the super
+ // SetUpTestSuite() method to shadow the one defined in the super
// class.
- static void SetUpTestCase() {}
+ // Failures that happen during SetUpTestSuite are logged but otherwise
+ // ignored.
+ static void SetUpTestSuite() {}
- // Tears down the stuff shared by all tests in this test case.
+ // Tears down the stuff shared by all tests in this test suite.
//
- // Google Test will call Foo::TearDownTestCase() after running the last
+ // Google Test will call Foo::TearDownTestSuite() after running the last
// test in test case Foo. Hence a sub-class can define its own
- // TearDownTestCase() method to shadow the one defined in the super
+ // TearDownTestSuite() method to shadow the one defined in the super
// class.
+ // Failures that happen during TearDownTestSuite are logged but otherwise
+ // ignored.
+ static void TearDownTestSuite() {}
+
+ // Legacy API is deprecated but still available
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
static void TearDownTestCase() {}
+ static void SetUpTestCase() {}
+#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
- // Returns true iff the current test has a fatal failure.
+ // Returns true if and only if the current test has a fatal failure.
static bool HasFatalFailure();
- // Returns true iff the current test has a non-fatal failure.
+ // Returns true if and only if the current test has a non-fatal failure.
static bool HasNonfatalFailure();
- // Returns true iff the current test has a (either fatal or
+ // Returns true if and only if the current test was skipped.
+ static bool IsSkipped();
+
+ // Returns true if and only if the current test has a (either fatal or
// non-fatal) failure.
static bool HasFailure() { return HasFatalFailure() || HasNonfatalFailure(); }
- // Logs a property for the current test, test case, or for the entire
+ // Logs a property for the current test, test suite, 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
+ // test suite. 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
+ // SetUpTestSuite or TearDownTestSuite 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
@@ -433,8 +472,8 @@ class GTEST_API_ Test {
virtual void TearDown();
private:
- // Returns true iff the current test has the same fixture class as
- // the first test in the current test case.
+ // Returns true if and only if the current test has the same fixture class
+ // as the first test in the current test suite.
static bool HasSameFixtureClass();
// Runs the test after the test fixture has been set up.
@@ -452,7 +491,7 @@ class GTEST_API_ Test {
// internal method to avoid clashing with names used in user TESTs.
void DeleteSelf_() { delete this; }
- const internal::scoped_ptr< GTEST_FLAG_SAVER_ > gtest_flag_saver_;
+ const std::unique_ptr<GTEST_FLAG_SAVER_> gtest_flag_saver_;
// Often a user misspells SetUp() as Setup() and spends a long time
// wondering why it is never called by Google Test. The declaration of
@@ -471,7 +510,7 @@ class GTEST_API_ Test {
// If you see an error about overriding the following function or
// about it being private, you have mis-spelled SetUp() as Setup().
struct Setup_should_be_spelled_SetUp {};
- virtual Setup_should_be_spelled_SetUp* Setup() { return NULL; }
+ virtual Setup_should_be_spelled_SetUp* Setup() { return nullptr; }
// We disallow copying Tests.
GTEST_DISALLOW_COPY_AND_ASSIGN_(Test);
@@ -535,24 +574,30 @@ class GTEST_API_ TestResult {
// Returns the number of the test properties.
int test_property_count() const;
- // Returns true iff the test passed (i.e. no test part failed).
- bool Passed() const { return !Failed(); }
+ // Returns true if and only if the test passed (i.e. no test part failed).
+ bool Passed() const { return !Skipped() && !Failed(); }
+
+ // Returns true if and only if the test was skipped.
+ bool Skipped() const;
- // Returns true iff the test failed.
+ // Returns true if and only if the test failed.
bool Failed() const;
- // Returns true iff the test fatally failed.
+ // Returns true if and only if the test fatally failed.
bool HasFatalFailure() const;
- // Returns true iff the test has a non-fatal failure.
+ // Returns true if and only if the test has a non-fatal failure.
bool HasNonfatalFailure() const;
// Returns the elapsed time, in milliseconds.
TimeInMillis elapsed_time() const { return elapsed_time_; }
- // Returns the i-th test part result among all the results. i can range
- // from 0 to test_property_count() - 1. If i is not in that range, aborts
- // the program.
+ // Gets the time of the test case start, in ms from the start of the
+ // UNIX epoch.
+ TimeInMillis start_timestamp() const { return start_timestamp_; }
+
+ // Returns the i-th test part result among all the results. i can range from 0
+ // to total_part_count() - 1. If i is not in that range, aborts the program.
const TestPartResult& GetTestPartResult(int i) const;
// Returns the i-th test property. i can range from 0 to
@@ -562,13 +607,14 @@ class GTEST_API_ TestResult {
private:
friend class TestInfo;
- friend class TestCase;
+ friend class TestSuite;
friend class UnitTest;
friend class internal::DefaultGlobalTestPartResultReporter;
friend class internal::ExecDeathTest;
friend class internal::TestResultAccessor;
friend class internal::UnitTestImpl;
friend class internal::WindowsDeathTest;
+ friend class internal::FuchsiaDeathTest;
// Gets the vector of TestPartResults.
const std::vector<TestPartResult>& test_part_results() const {
@@ -580,6 +626,9 @@ class GTEST_API_ TestResult {
return test_properties_;
}
+ // Sets the start time.
+ void set_start_timestamp(TimeInMillis start) { start_timestamp_ = start; }
+
// Sets the elapsed time.
void set_elapsed_time(TimeInMillis elapsed) { elapsed_time_ = elapsed; }
@@ -593,8 +642,8 @@ class GTEST_API_ TestResult {
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.
+ // testsuite tags. Returns true if the property is valid.
+ // FIXME: Validate attribute names are legal and human readable.
static bool ValidateTestProperty(const std::string& xml_element,
const TestProperty& test_property);
@@ -623,6 +672,8 @@ class GTEST_API_ TestResult {
std::vector<TestProperty> test_properties_;
// Running count of death tests.
int death_test_count_;
+ // The start time, in milliseconds since UNIX Epoch.
+ TimeInMillis start_timestamp_;
// The elapsed time, in milliseconds.
TimeInMillis elapsed_time_;
@@ -632,7 +683,7 @@ class GTEST_API_ TestResult {
// A TestInfo object stores the following information about a test:
//
-// Test case name
+// Test suite name
// Test name
// Whether the test should be run
// A function pointer that creates the test object when invoked
@@ -647,8 +698,13 @@ class GTEST_API_ TestInfo {
// don't inherit from TestInfo.
~TestInfo();
- // Returns the test case name.
- const char* test_case_name() const { return test_case_name_.c_str(); }
+ // Returns the test suite name.
+ const char* test_suite_name() const { return test_suite_name_.c_str(); }
+
+// Legacy API is deprecated but still available
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+ const char* test_case_name() const { return test_suite_name(); }
+#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
// Returns the test name.
const char* name() const { return name_.c_str(); }
@@ -656,17 +712,15 @@ class GTEST_API_ TestInfo {
// Returns the name of the parameter type, or NULL if this is not a typed
// or a type-parameterized test.
const char* type_param() const {
- if (type_param_.get() != NULL)
- return type_param_->c_str();
- return NULL;
+ if (type_param_.get() != nullptr) return type_param_->c_str();
+ return nullptr;
}
// Returns the text representation of the value parameter, or NULL if this
// is not a value-parameterized test.
const char* value_param() const {
- if (value_param_.get() != NULL)
- return value_param_->c_str();
- return NULL;
+ if (value_param_.get() != nullptr) return value_param_->c_str();
+ return nullptr;
}
// Returns the file name where this test is defined.
@@ -675,12 +729,15 @@ class GTEST_API_ TestInfo {
// Returns the line where this test is defined.
int line() const { return location_.line; }
+ // Return true if this test should not be run because it's in another shard.
+ bool is_in_another_shard() const { return is_in_another_shard_; }
+
// 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
+ // The full name of a test Bar in test suite Foo is defined as
// "Foo.Bar". Only the tests that match the filter will run.
//
// A filter is a colon-separated list of glob (not regex) patterns,
@@ -693,12 +750,11 @@ 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.
+ // Returns true if and only if 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_;
+ // The XML report includes tests matching the filter, excluding those
+ // run in other shards.
+ return matches_filter_ && !is_in_another_shard_;
}
// Returns the result of the test.
@@ -709,24 +765,19 @@ class GTEST_API_ TestInfo {
friend class internal::DefaultDeathTestFactory;
#endif // GTEST_HAS_DEATH_TEST
friend class Test;
- friend class TestCase;
+ friend class TestSuite;
friend class internal::UnitTestImpl;
friend class internal::StreamingListenerTest;
friend TestInfo* internal::MakeAndRegisterTestInfo(
- const char* test_case_name,
- const char* name,
- const char* type_param,
- const char* value_param,
- internal::CodeLocation code_location,
- internal::TypeId fixture_class_id,
- Test::SetUpTestCaseFunc set_up_tc,
- Test::TearDownTestCaseFunc tear_down_tc,
+ const char* test_suite_name, const char* name, const char* type_param,
+ const char* value_param, internal::CodeLocation code_location,
+ internal::TypeId fixture_class_id, internal::SetUpTestSuiteFunc set_up_tc,
+ internal::TearDownTestSuiteFunc tear_down_tc,
internal::TestFactoryBase* factory);
// Constructs a TestInfo object. The newly constructed instance assumes
// ownership of the factory object.
- TestInfo(const std::string& test_case_name,
- const std::string& name,
+ TestInfo(const std::string& test_suite_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::CodeLocation a_code_location,
@@ -748,20 +799,21 @@ class GTEST_API_ TestInfo {
}
// These fields are immutable properties of the test.
- const std::string test_case_name_; // Test case name
+ const std::string test_suite_name_; // test suite name
const std::string name_; // Test 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_;
+ const std::unique_ptr<const ::std::string> type_param_;
// Text representation of the value parameter, or NULL if this is not a
// value-parameterized test.
- const internal::scoped_ptr<const ::std::string> value_param_;
+ const std::unique_ptr<const ::std::string> value_param_;
internal::CodeLocation location_;
- const internal::TypeId fixture_class_id_; // ID of the test fixture class
- bool should_run_; // True iff this test should run
- bool is_disabled_; // True iff this test is disabled
- bool matches_filter_; // True if this test matches the
- // user-specified filter.
+ const internal::TypeId fixture_class_id_; // ID of the test fixture class
+ bool should_run_; // True if and only if this test should run
+ bool is_disabled_; // True if and only if this test is disabled
+ bool matches_filter_; // True if this test matches the
+ // user-specified filter.
+ bool is_in_another_shard_; // Will be run in another shard.
internal::TestFactoryBase* const factory_; // The factory that creates
// the test object
@@ -772,90 +824,96 @@ class GTEST_API_ TestInfo {
GTEST_DISALLOW_COPY_AND_ASSIGN_(TestInfo);
};
-// A test case, which consists of a vector of TestInfos.
+// A test suite, which consists of a vector of TestInfos.
//
-// TestCase is not copyable.
-class GTEST_API_ TestCase {
+// TestSuite is not copyable.
+class GTEST_API_ TestSuite {
public:
- // Creates a TestCase with the given name.
+ // Creates a TestSuite with the given name.
//
- // TestCase does NOT have a default constructor. Always use this
- // constructor to create a TestCase object.
+ // TestSuite does NOT have a default constructor. Always use this
+ // constructor to create a TestSuite object.
//
// Arguments:
//
- // name: name of the test case
+ // name: name of the test suite
// a_type_param: the name of the test's type parameter, or NULL if
// this is not a type-parameterized test.
- // set_up_tc: pointer to the function that sets up the test case
- // tear_down_tc: pointer to the function that tears down the test case
- TestCase(const char* name, const char* a_type_param,
- Test::SetUpTestCaseFunc set_up_tc,
- Test::TearDownTestCaseFunc tear_down_tc);
+ // set_up_tc: pointer to the function that sets up the test suite
+ // tear_down_tc: pointer to the function that tears down the test suite
+ TestSuite(const char* name, const char* a_type_param,
+ internal::SetUpTestSuiteFunc set_up_tc,
+ internal::TearDownTestSuiteFunc tear_down_tc);
- // Destructor of TestCase.
- virtual ~TestCase();
+ // Destructor of TestSuite.
+ virtual ~TestSuite();
- // Gets the name of the TestCase.
+ // Gets the name of the TestSuite.
const char* name() const { return name_.c_str(); }
// Returns the name of the parameter type, or NULL if this is not a
- // type-parameterized test case.
+ // type-parameterized test suite.
const char* type_param() const {
- if (type_param_.get() != NULL)
- return type_param_->c_str();
- return NULL;
+ if (type_param_.get() != nullptr) return type_param_->c_str();
+ return nullptr;
}
- // Returns true if any test in this test case should run.
+ // Returns true if any test in this test suite should run.
bool should_run() const { return should_run_; }
- // Gets the number of successful tests in this test case.
+ // Gets the number of successful tests in this test suite.
int successful_test_count() const;
- // Gets the number of failed tests in this test case.
+ // Gets the number of skipped tests in this test suite.
+ int skipped_test_count() const;
+
+ // Gets the number of failed tests in this test suite.
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.
+ // Gets the number of disabled tests in this test suite.
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.
+ // Get the number of tests in this test suite that should run.
int test_to_run_count() const;
- // Gets the number of all tests in this test case.
+ // Gets the number of all tests in this test suite.
int total_test_count() const;
- // Returns true iff the test case passed.
+ // Returns true if and only if the test suite passed.
bool Passed() const { return !Failed(); }
- // Returns true iff the test case failed.
+ // Returns true if and only if the test suite failed.
bool Failed() const { return failed_test_count() > 0; }
// Returns the elapsed time, in milliseconds.
TimeInMillis elapsed_time() const { return elapsed_time_; }
+ // Gets the time of the test suite start, in ms from the start of the
+ // UNIX epoch.
+ TimeInMillis start_timestamp() const { return start_timestamp_; }
+
// Returns the i-th test among all the tests. i can range from 0 to
// 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.
+ // execution of SetUpTestSuite and TearDownTestSuite.
const TestResult& ad_hoc_test_result() const { return ad_hoc_test_result_; }
private:
friend class Test;
friend class internal::UnitTestImpl;
- // Gets the (mutable) vector of TestInfos in this TestCase.
+ // Gets the (mutable) vector of TestInfos in this TestSuite.
std::vector<TestInfo*>& test_info_list() { return test_info_list_; }
- // Gets the (immutable) vector of TestInfos in this TestCase.
+ // Gets the (immutable) vector of TestInfos in this TestSuite.
const std::vector<TestInfo*>& test_info_list() const {
return test_info_list_;
}
@@ -867,51 +925,64 @@ class GTEST_API_ TestCase {
// Sets the should_run member.
void set_should_run(bool should) { should_run_ = should; }
- // Adds a TestInfo to this test case. Will delete the TestInfo upon
- // destruction of the TestCase object.
+ // Adds a TestInfo to this test suite. Will delete the TestInfo upon
+ // destruction of the TestSuite object.
void AddTestInfo(TestInfo * test_info);
- // Clears the results of all tests in this test case.
+ // Clears the results of all tests in this test suite.
void ClearResult();
- // Clears the results of all tests in the given test case.
- static void ClearTestCaseResult(TestCase* test_case) {
- test_case->ClearResult();
+ // Clears the results of all tests in the given test suite.
+ static void ClearTestSuiteResult(TestSuite* test_suite) {
+ test_suite->ClearResult();
}
- // Runs every test in this TestCase.
+ // Runs every test in this TestSuite.
void Run();
- // Runs SetUpTestCase() for this TestCase. This wrapper is needed
- // for catching exceptions thrown from SetUpTestCase().
- void RunSetUpTestCase() { (*set_up_tc_)(); }
+ // Runs SetUpTestSuite() for this TestSuite. This wrapper is needed
+ // for catching exceptions thrown from SetUpTestSuite().
+ void RunSetUpTestSuite() {
+ if (set_up_tc_ != nullptr) {
+ (*set_up_tc_)();
+ }
+ }
- // Runs TearDownTestCase() for this TestCase. This wrapper is
- // needed for catching exceptions thrown from TearDownTestCase().
- void RunTearDownTestCase() { (*tear_down_tc_)(); }
+ // Runs TearDownTestSuite() for this TestSuite. This wrapper is
+ // needed for catching exceptions thrown from TearDownTestSuite().
+ void RunTearDownTestSuite() {
+ if (tear_down_tc_ != nullptr) {
+ (*tear_down_tc_)();
+ }
+ }
- // Returns true iff test passed.
+ // Returns true if and only if test passed.
static bool TestPassed(const TestInfo* test_info) {
return test_info->should_run() && test_info->result()->Passed();
}
- // Returns true iff test failed.
+ // Returns true if and only if test skipped.
+ static bool TestSkipped(const TestInfo* test_info) {
+ return test_info->should_run() && test_info->result()->Skipped();
+ }
+
+ // Returns true if and only if test failed.
static bool TestFailed(const TestInfo* test_info) {
return test_info->should_run() && test_info->result()->Failed();
}
- // Returns true iff the test is disabled and will be reported in the XML
- // report.
+ // Returns true if and only if 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.
+ // Returns true if and only if 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.
+ // Returns true if and only if this test will appear in the XML report.
static bool TestReportable(const TestInfo* test_info) {
return test_info->is_reportable();
}
@@ -921,17 +992,17 @@ class GTEST_API_ TestCase {
return test_info->should_run();
}
- // Shuffles the tests in this test case.
+ // Shuffles the tests in this test suite.
void ShuffleTests(internal::Random* random);
// Restores the test order to before the first shuffle.
void UnshuffleTests();
- // Name of the test case.
+ // Name of the test suite.
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_;
+ const std::unique_ptr<const ::std::string> type_param_;
// The vector of TestInfos in their original order. It owns the
// elements in the vector.
std::vector<TestInfo*> test_info_list_;
@@ -939,20 +1010,22 @@ class GTEST_API_ TestCase {
// shuffling and restoring the test order. The i-th element in this
// vector is the index of the i-th test in the shuffled test list.
std::vector<int> test_indices_;
- // Pointer to the function that sets up the test case.
- Test::SetUpTestCaseFunc set_up_tc_;
- // Pointer to the function that tears down the test case.
- Test::TearDownTestCaseFunc tear_down_tc_;
- // True iff any test in this test case should run.
+ // Pointer to the function that sets up the test suite.
+ internal::SetUpTestSuiteFunc set_up_tc_;
+ // Pointer to the function that tears down the test suite.
+ internal::TearDownTestSuiteFunc tear_down_tc_;
+ // True if and only if any test in this test suite should run.
bool should_run_;
+ // The start time, in milliseconds since UNIX Epoch.
+ TimeInMillis start_timestamp_;
// Elapsed time, in milliseconds.
TimeInMillis elapsed_time_;
- // Holds test properties recorded during execution of SetUpTestCase and
- // TearDownTestCase.
+ // Holds test properties recorded during execution of SetUpTestSuite and
+ // TearDownTestSuite.
TestResult ad_hoc_test_result_;
- // We disallow copying TestCases.
- GTEST_DISALLOW_COPY_AND_ASSIGN_(TestCase);
+ // We disallow copying TestSuites.
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(TestSuite);
};
// An Environment object is capable of setting up and tearing down an
@@ -983,9 +1056,21 @@ class Environment {
// If you see an error about overriding the following function or
// about it being private, you have mis-spelled SetUp() as Setup().
struct Setup_should_be_spelled_SetUp {};
- virtual Setup_should_be_spelled_SetUp* Setup() { return NULL; }
+ virtual Setup_should_be_spelled_SetUp* Setup() { return nullptr; }
};
+#if GTEST_HAS_EXCEPTIONS
+
+// Exception which can be thrown from TestEventListener::OnTestPartResult.
+class GTEST_API_ AssertionException
+ : public internal::GoogleTestFailureException {
+ public:
+ explicit AssertionException(const TestPartResult& result)
+ : GoogleTestFailureException(result) {}
+};
+
+#endif // GTEST_HAS_EXCEPTIONS
+
// The interface for tracing execution of tests. The methods are organized in
// the order the corresponding events are fired.
class TestEventListener {
@@ -1007,20 +1092,32 @@ class TestEventListener {
// Fired after environment set-up for each iteration of tests ends.
virtual void OnEnvironmentsSetUpEnd(const UnitTest& unit_test) = 0;
- // Fired before the test case starts.
- virtual void OnTestCaseStart(const TestCase& test_case) = 0;
+ // Fired before the test suite starts.
+ virtual void OnTestSuiteStart(const TestSuite& /*test_suite*/) {}
+
+ // Legacy API is deprecated but still available
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+ virtual void OnTestCaseStart(const TestCase& /*test_case*/) {}
+#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
// Fired before the test starts.
virtual void OnTestStart(const TestInfo& test_info) = 0;
// Fired after a failed assertion or a SUCCEED() invocation.
+ // If you want to throw an exception from this function to skip to the next
+ // TEST, it must be AssertionException defined above, or inherited from it.
virtual void OnTestPartResult(const TestPartResult& test_part_result) = 0;
// Fired after the test ends.
virtual void OnTestEnd(const TestInfo& test_info) = 0;
- // Fired after the test case ends.
- virtual void OnTestCaseEnd(const TestCase& test_case) = 0;
+ // Fired after the test suite ends.
+ virtual void OnTestSuiteEnd(const TestSuite& /*test_suite*/) {}
+
+// Legacy API is deprecated but still available
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+ virtual void OnTestCaseEnd(const TestCase& /*test_case*/) {}
+#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
// Fired before environment tear-down for each iteration of tests starts.
virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test) = 0;
@@ -1043,21 +1140,30 @@ class TestEventListener {
// above.
class EmptyTestEventListener : public TestEventListener {
public:
- virtual void OnTestProgramStart(const UnitTest& /*unit_test*/) {}
- virtual void OnTestIterationStart(const UnitTest& /*unit_test*/,
- int /*iteration*/) {}
- virtual void OnEnvironmentsSetUpStart(const UnitTest& /*unit_test*/) {}
- virtual void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) {}
- virtual void OnTestCaseStart(const TestCase& /*test_case*/) {}
- virtual void OnTestStart(const TestInfo& /*test_info*/) {}
- virtual void OnTestPartResult(const TestPartResult& /*test_part_result*/) {}
- virtual void OnTestEnd(const TestInfo& /*test_info*/) {}
- virtual void OnTestCaseEnd(const TestCase& /*test_case*/) {}
- virtual void OnEnvironmentsTearDownStart(const UnitTest& /*unit_test*/) {}
- virtual void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) {}
- virtual void OnTestIterationEnd(const UnitTest& /*unit_test*/,
- int /*iteration*/) {}
- virtual void OnTestProgramEnd(const UnitTest& /*unit_test*/) {}
+ void OnTestProgramStart(const UnitTest& /*unit_test*/) override {}
+ void OnTestIterationStart(const UnitTest& /*unit_test*/,
+ int /*iteration*/) override {}
+ void OnEnvironmentsSetUpStart(const UnitTest& /*unit_test*/) override {}
+ void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) override {}
+ void OnTestSuiteStart(const TestSuite& /*test_suite*/) override {}
+// Legacy API is deprecated but still available
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+ void OnTestCaseStart(const TestCase& /*test_case*/) override {}
+#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+
+ void OnTestStart(const TestInfo& /*test_info*/) override {}
+ void OnTestPartResult(const TestPartResult& /*test_part_result*/) override {}
+ void OnTestEnd(const TestInfo& /*test_info*/) override {}
+ void OnTestSuiteEnd(const TestSuite& /*test_suite*/) override {}
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+ void OnTestCaseEnd(const TestCase& /*test_case*/) override {}
+#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+
+ void OnEnvironmentsTearDownStart(const UnitTest& /*unit_test*/) override {}
+ void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) override {}
+ void OnTestIterationEnd(const UnitTest& /*unit_test*/,
+ int /*iteration*/) override {}
+ void OnTestProgramEnd(const UnitTest& /*unit_test*/) override {}
};
// TestEventListeners lets users add listeners to track events in Google Test.
@@ -1097,7 +1203,7 @@ class GTEST_API_ TestEventListeners {
}
private:
- friend class TestCase;
+ friend class TestSuite;
friend class TestInfo;
friend class internal::DefaultGlobalTestPartResultReporter;
friend class internal::NoExecDeathTest;
@@ -1138,7 +1244,7 @@ class GTEST_API_ TestEventListeners {
GTEST_DISALLOW_COPY_AND_ASSIGN_(TestEventListeners);
};
-// A UnitTest consists of a vector of TestCases.
+// A UnitTest consists of a vector of TestSuites.
//
// This is a singleton class. The only instance of UnitTest is
// created when UnitTest::GetInstance() is first called. This
@@ -1167,10 +1273,14 @@ class GTEST_API_ UnitTest {
// was executed. The UnitTest object owns the string.
const char* original_working_dir() const;
- // Returns the TestCase object for the test that's currently running,
+ // Returns the TestSuite object for the test that's currently running,
// or NULL if no test is running.
- const TestCase* current_test_case() const
- GTEST_LOCK_EXCLUDED_(mutex_);
+ const TestSuite* current_test_suite() const GTEST_LOCK_EXCLUDED_(mutex_);
+
+// Legacy API is still available but deprecated
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+ const TestCase* current_test_case() const GTEST_LOCK_EXCLUDED_(mutex_);
+#endif
// Returns the TestInfo object for the test that's currently running,
// or NULL if no test is running.
@@ -1180,31 +1290,40 @@ class GTEST_API_ UnitTest {
// Returns the random seed used at the start of the current test run.
int random_seed() const;
-#if GTEST_HAS_PARAM_TEST
- // Returns the ParameterizedTestCaseRegistry object used to keep track of
+ // Returns the ParameterizedTestSuiteRegistry object used to keep track of
// value-parameterized tests and instantiate and register them.
//
// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
- internal::ParameterizedTestCaseRegistry& parameterized_test_registry()
+ internal::ParameterizedTestSuiteRegistry& parameterized_test_registry()
GTEST_LOCK_EXCLUDED_(mutex_);
-#endif // GTEST_HAS_PARAM_TEST
- // Gets the number of successful test cases.
- int successful_test_case_count() const;
+ // Gets the number of successful test suites.
+ int successful_test_suite_count() const;
- // Gets the number of failed test cases.
- int failed_test_case_count() const;
+ // Gets the number of failed test suites.
+ int failed_test_suite_count() const;
- // Gets the number of all test cases.
- int total_test_case_count() const;
+ // Gets the number of all test suites.
+ int total_test_suite_count() const;
- // Gets the number of all test cases that contain at least one test
+ // Gets the number of all test suites that contain at least one test
// that should run.
+ int test_suite_to_run_count() const;
+
+ // Legacy API is deprecated but still available
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+ int successful_test_case_count() const;
+ int failed_test_case_count() const;
+ int total_test_case_count() const;
int test_case_to_run_count() const;
+#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
// Gets the number of successful tests.
int successful_test_count() const;
+ // Gets the number of skipped tests.
+ int skipped_test_count() const;
+
// Gets the number of failed tests.
int failed_test_count() const;
@@ -1230,19 +1349,25 @@ class GTEST_API_ UnitTest {
// Gets the elapsed time, in milliseconds.
TimeInMillis elapsed_time() const;
- // Returns true iff the unit test passed (i.e. all test cases passed).
+ // Returns true if and only if the unit test passed (i.e. all test suites
+ // passed).
bool Passed() const;
- // Returns true iff the unit test failed (i.e. some test case failed
- // or something outside of all tests failed).
+ // Returns true if and only if the unit test failed (i.e. some test suite
+ // failed or something outside of all tests failed).
bool Failed() const;
- // 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.
+ // Gets the i-th test suite among all the test suites. i can range from 0 to
+ // total_test_suite_count() - 1. If i is not in that range, returns NULL.
+ const TestSuite* GetTestSuite(int i) const;
+
+// Legacy API is deprecated but still available
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
const TestCase* GetTestCase(int i) const;
+#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
// Returns the TestResult containing information on test failures and
- // properties logged outside of individual test cases.
+ // properties logged outside of individual test suites.
const TestResult& ad_hoc_test_result() const;
// Returns the list of event listeners that can be used to track events
@@ -1273,25 +1398,25 @@ class GTEST_API_ UnitTest {
GTEST_LOCK_EXCLUDED_(mutex_);
// 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
+ // inside a test, to current TestSuite's ad_hoc_test_result_ when invoked
+ // from SetUpTestSuite or TearDownTestSuite, 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.
- TestCase* GetMutableTestCase(int i);
+ // Gets the i-th test suite among all the test suites. i can range from 0 to
+ // total_test_suite_count() - 1. If i is not in that range, returns NULL.
+ TestSuite* GetMutableTestSuite(int i);
// Accessors for the implementation object.
internal::UnitTestImpl* impl() { return impl_; }
const internal::UnitTestImpl* impl() const { return impl_; }
- // These classes and funcions are friends as they need to access private
+ // These classes and functions are friends as they need to access private
// members of UnitTest.
+ friend class ScopedTrace;
friend class Test;
friend class internal::AssertHelper;
- friend class internal::ScopedTrace;
friend class internal::StreamingListenerTest;
friend class internal::UnitTestRecordPropertyTestHelper;
friend Environment* AddGlobalTestEnvironment(Environment* env);
@@ -1366,6 +1491,10 @@ GTEST_API_ void InitGoogleTest(int* argc, char** argv);
// UNICODE mode.
GTEST_API_ void InitGoogleTest(int* argc, wchar_t** argv);
+// This overloaded version can be used on Arduino/embedded platforms where
+// there is no argc/argv.
+GTEST_API_ void InitGoogleTest();
+
namespace internal {
// Separate the error generating code from the code path to reduce the stack
@@ -1382,17 +1511,22 @@ AssertionResult CmpHelperEQFailure(const char* lhs_expression,
false);
}
+// This block of code defines operator==/!=
+// to block lexical scope lookup.
+// It prevents using invalid operator==/!= defined at namespace scope.
+struct faketype {};
+inline bool operator==(faketype, faketype) { return true; }
+inline bool operator!=(faketype, faketype) { return false; }
+
// The helper function for {ASSERT|EXPECT}_EQ.
template <typename T1, typename T2>
AssertionResult CmpHelperEQ(const char* lhs_expression,
const char* rhs_expression,
const T1& lhs,
const T2& rhs) {
-GTEST_DISABLE_MSC_WARNINGS_PUSH_(4389 /* signed/unsigned mismatch */)
if (lhs == rhs) {
return AssertionSuccess();
}
-GTEST_DISABLE_MSC_WARNINGS_POP_()
return CmpHelperEQFailure(lhs_expression, rhs_expression, lhs, rhs);
}
@@ -1405,18 +1539,17 @@ GTEST_API_ AssertionResult CmpHelperEQ(const char* lhs_expression,
BiggestInt lhs,
BiggestInt rhs);
-// The helper class for {ASSERT|EXPECT}_EQ. The template argument
-// lhs_is_null_literal is true iff the first argument to ASSERT_EQ()
-// is a null pointer literal. The following default implementation is
-// for lhs_is_null_literal being false.
-template <bool lhs_is_null_literal>
class EqHelper {
public:
// This templatized version is for the general case.
- template <typename T1, typename T2>
+ template <
+ typename T1, typename T2,
+ // Disable this overload for cases where one argument is a pointer
+ // and the other is the null pointer constant.
+ typename std::enable_if<!std::is_integral<T1>::value ||
+ !std::is_pointer<T2>::value>::type* = nullptr>
static AssertionResult Compare(const char* lhs_expression,
- const char* rhs_expression,
- const T1& lhs,
+ const char* rhs_expression, const T1& lhs,
const T2& rhs) {
return CmpHelperEQ(lhs_expression, rhs_expression, lhs, rhs);
}
@@ -1433,49 +1566,15 @@ class EqHelper {
BiggestInt rhs) {
return CmpHelperEQ(lhs_expression, rhs_expression, lhs, rhs);
}
-};
-// This specialization is used when the first argument to ASSERT_EQ()
-// is a null pointer literal, like NULL, false, or 0.
-template <>
-class EqHelper<true> {
- public:
- // We define two overloaded versions of Compare(). The first
- // version will be picked when the second argument to ASSERT_EQ() is
- // NOT a pointer, e.g. ASSERT_EQ(0, AnIntFunction()) or
- // EXPECT_EQ(false, a_bool).
- template <typename T1, typename T2>
- static AssertionResult Compare(
- const char* lhs_expression,
- const char* rhs_expression,
- const T1& lhs,
- const T2& rhs,
- // The following line prevents this overload from being considered if T2
- // is not a pointer type. We need this because ASSERT_EQ(NULL, my_ptr)
- // expands to Compare("", "", NULL, my_ptr), which requires a conversion
- // to match the Secret* in the other overload, which would otherwise make
- // this template match better.
- typename EnableIf<!is_pointer<T2>::value>::type* = 0) {
- return CmpHelperEQ(lhs_expression, rhs_expression, lhs, rhs);
- }
-
- // This version will be picked when the second argument to ASSERT_EQ() is a
- // pointer, e.g. ASSERT_EQ(NULL, a_pointer).
template <typename T>
static AssertionResult Compare(
- const char* lhs_expression,
- const char* rhs_expression,
- // We used to have a second template parameter instead of Secret*. That
- // template parameter would deduce to 'long', making this a better match
- // than the first overload even without the first overload's EnableIf.
- // Unfortunately, gcc with -Wconversion-null warns when "passing NULL to
- // non-pointer argument" (even a deduced integral argument), so the old
- // implementation caused warnings in user code.
- Secret* /* lhs (NULL) */,
- T* rhs) {
+ const char* lhs_expression, const char* rhs_expression,
+ // Handle cases where '0' is used as a null pointer literal.
+ std::nullptr_t /* lhs */, T* rhs) {
// We already know that 'lhs' is a null pointer.
- return CmpHelperEQ(lhs_expression, rhs_expression,
- static_cast<T*>(NULL), rhs);
+ return CmpHelperEQ(lhs_expression, rhs_expression, static_cast<T*>(nullptr),
+ rhs);
}
};
@@ -1704,9 +1803,14 @@ class GTEST_API_ AssertHelper {
GTEST_DISALLOW_COPY_AND_ASSIGN_(AssertHelper);
};
+enum GTestColor { COLOR_DEFAULT, COLOR_RED, COLOR_GREEN, COLOR_YELLOW };
+
+GTEST_API_ GTEST_ATTRIBUTE_PRINTF_(2, 3) void ColoredPrintf(GTestColor color,
+ const char* fmt,
+ ...);
+
} // namespace internal
-#if GTEST_HAS_PARAM_TEST
// The pure interface class that all value-parameterized tests inherit from.
// A value-parameterized class must inherit from both ::testing::Test and
// ::testing::WithParamInterface. In most cases that just means inheriting
@@ -1724,13 +1828,13 @@ class GTEST_API_ AssertHelper {
// FooTest() {
// // Can use GetParam() here.
// }
-// virtual ~FooTest() {
+// ~FooTest() override {
// // Can use GetParam() here.
// }
-// virtual void SetUp() {
+// void SetUp() override {
// // Can use GetParam() here.
// }
-// virtual void TearDown {
+// void TearDown override {
// // Can use GetParam() here.
// }
// };
@@ -1739,7 +1843,7 @@ class GTEST_API_ AssertHelper {
// Foo foo;
// ASSERT_TRUE(foo.DoesBar(GetParam()));
// }
-// INSTANTIATE_TEST_CASE_P(OneToTenRange, FooTest, ::testing::Range(1, 10));
+// INSTANTIATE_TEST_SUITE_P(OneToTenRange, FooTest, ::testing::Range(1, 10));
template <typename T>
class WithParamInterface {
@@ -1748,12 +1852,9 @@ class WithParamInterface {
virtual ~WithParamInterface() {}
// The current parameter value. Is also available in the test fixture's
- // constructor. This member function is non-static, even though it only
- // 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 {
- GTEST_CHECK_(parameter_ != NULL)
+ // constructor.
+ static const ParamType& GetParam() {
+ GTEST_CHECK_(parameter_ != nullptr)
<< "GetParam() can only be called inside a value-parameterized test "
<< "-- did you intend to write TEST_P instead of TEST_F?";
return *parameter_;
@@ -1774,7 +1875,7 @@ class WithParamInterface {
};
template <typename T>
-const T* WithParamInterface<T>::parameter_ = NULL;
+const T* WithParamInterface<T>::parameter_ = nullptr;
// Most value-parameterized classes can ignore the existence of
// WithParamInterface, and can just inherit from ::testing::TestWithParam.
@@ -1783,10 +1884,13 @@ template <typename T>
class TestWithParam : public Test, public WithParamInterface<T> {
};
-#endif // GTEST_HAS_PARAM_TEST
-
// Macros for indicating success/failure in test code.
+// Skips test in runtime.
+// Skipping test aborts current function.
+// Skipped tests are neither successful nor failed.
+#define GTEST_SKIP() GTEST_SKIP_("Skipped")
+
// ADD_FAILURE unconditionally adds a failure to the current test.
// SUCCEED generates a success - it doesn't automatically make the
// current test successful, as a test is only successful when it has
@@ -1816,6 +1920,11 @@ class TestWithParam : public Test, public WithParamInterface<T> {
// Generates a fatal failure with a generic message.
#define GTEST_FAIL() GTEST_FATAL_FAILURE_("Failed")
+// Like GTEST_FAIL(), but at the given source file location.
+#define GTEST_FAIL_AT(file, line) \
+ GTEST_MESSAGE_AT_(file, line, "Failed", \
+ ::testing::TestPartResult::kFatalFailure)
+
// Define this macro to 1 to omit the definition of FAIL(), which is a
// generic name and clashes with some other libraries.
#if !GTEST_DONT_DEFINE_FAIL
@@ -1857,22 +1966,18 @@ class TestWithParam : public Test, public WithParamInterface<T> {
// AssertionResult. For more information on how to use AssertionResult with
// these macros see comments on that class.
#define EXPECT_TRUE(condition) \
- GTEST_TEST_BOOLEAN_((condition), #condition, false, true, \
+ GTEST_TEST_BOOLEAN_(condition, #condition, false, true, \
GTEST_NONFATAL_FAILURE_)
#define EXPECT_FALSE(condition) \
GTEST_TEST_BOOLEAN_(!(condition), #condition, true, false, \
GTEST_NONFATAL_FAILURE_)
#define ASSERT_TRUE(condition) \
- GTEST_TEST_BOOLEAN_((condition), #condition, false, true, \
+ GTEST_TEST_BOOLEAN_(condition, #condition, false, true, \
GTEST_FATAL_FAILURE_)
#define ASSERT_FALSE(condition) \
GTEST_TEST_BOOLEAN_(!(condition), #condition, true, false, \
GTEST_FATAL_FAILURE_)
-// Includes the auto-generated header that implements a family of
-// generic predicate assertion macros.
-#include "gtest/gtest_pred_impl.h"
-
// Macros for testing equalities and inequalities.
//
// * {ASSERT|EXPECT}_EQ(v1, v2): Tests that v1 == v2
@@ -1914,15 +2019,13 @@ class TestWithParam : public Test, public WithParamInterface<T> {
//
// Examples:
//
-// EXPECT_NE(5, Foo());
-// EXPECT_EQ(NULL, a_pointer);
+// EXPECT_NE(Foo(), 5);
+// EXPECT_EQ(a_pointer, NULL);
// ASSERT_LT(i, array_size);
// ASSERT_GT(records.size(), 0) << "There is no record left.";
#define EXPECT_EQ(val1, val2) \
- EXPECT_PRED_FORMAT2(::testing::internal:: \
- EqHelper<GTEST_IS_NULL_LITERAL_(val1)>::Compare, \
- val1, val2)
+ EXPECT_PRED_FORMAT2(::testing::internal::EqHelper::Compare, val1, val2)
#define EXPECT_NE(val1, val2) \
EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperNE, val1, val2)
#define EXPECT_LE(val1, val2) \
@@ -1935,9 +2038,7 @@ class TestWithParam : public Test, public WithParamInterface<T> {
EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperGT, val1, val2)
#define GTEST_ASSERT_EQ(val1, val2) \
- ASSERT_PRED_FORMAT2(::testing::internal:: \
- EqHelper<GTEST_IS_NULL_LITERAL_(val1)>::Compare, \
- val1, val2)
+ ASSERT_PRED_FORMAT2(::testing::internal::EqHelper::Compare, val1, val2)
#define GTEST_ASSERT_NE(val1, val2) \
ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperNE, val1, val2)
#define GTEST_ASSERT_LE(val1, val2) \
@@ -2101,6 +2202,51 @@ GTEST_API_ AssertionResult DoubleLE(const char* expr1, const char* expr2,
#define EXPECT_NO_FATAL_FAILURE(statement) \
GTEST_TEST_NO_FATAL_FAILURE_(statement, GTEST_NONFATAL_FAILURE_)
+// Causes a trace (including the given source file path and line number,
+// and the given message) to be included in every test failure message generated
+// by code in the scope of the lifetime of an instance of this class. The effect
+// is undone with the destruction of the instance.
+//
+// The message argument can be anything streamable to std::ostream.
+//
+// Example:
+// testing::ScopedTrace trace("file.cc", 123, "message");
+//
+class GTEST_API_ ScopedTrace {
+ public:
+ // The c'tor pushes the given source file location and message onto
+ // a trace stack maintained by Google Test.
+
+ // Template version. Uses Message() to convert the values into strings.
+ // Slow, but flexible.
+ template <typename T>
+ ScopedTrace(const char* file, int line, const T& message) {
+ PushTrace(file, line, (Message() << message).GetString());
+ }
+
+ // Optimize for some known types.
+ ScopedTrace(const char* file, int line, const char* message) {
+ PushTrace(file, line, message ? message : "(null)");
+ }
+
+ ScopedTrace(const char* file, int line, const std::string& message) {
+ PushTrace(file, line, message);
+ }
+
+ // The d'tor pops the info pushed by the c'tor.
+ //
+ // Note that the d'tor is not virtual in order to be efficient.
+ // Don't inherit from ScopedTrace!
+ ~ScopedTrace();
+
+ private:
+ void PushTrace(const char* file, int line, std::string message);
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedTrace);
+} GTEST_ATTRIBUTE_UNUSED_; // A ScopedTrace object does its job in its
+ // c'tor and d'tor. Therefore it doesn't
+ // need to be used otherwise.
+
// Causes a trace (including the source file path, the current line
// number, and the given message) to be included in every test failure
// message generated by code in the current scope. The effect is
@@ -2112,13 +2258,17 @@ GTEST_API_ AssertionResult DoubleLE(const char* expr1, const char* expr2,
// of the dummy variable name, thus allowing multiple SCOPED_TRACE()s
// to appear in the same block - as long as they are on different
// lines.
+//
+// Assuming that each thread maintains its own stack of traces.
+// Therefore, a SCOPED_TRACE() would (correctly) only affect the
+// assertions in its own thread.
#define SCOPED_TRACE(message) \
- ::testing::internal::ScopedTrace GTEST_CONCAT_TOKEN_(gtest_trace_, __LINE__)(\
- __FILE__, __LINE__, ::testing::Message() << (message))
+ ::testing::ScopedTrace GTEST_CONCAT_TOKEN_(gtest_trace_, __LINE__)(\
+ __FILE__, __LINE__, (message))
// Compile-time assertion for type equality.
-// StaticAssertTypeEq<type1, type2>() compiles iff type1 and type2 are
-// the same type. The value it returns is not interesting.
+// StaticAssertTypeEq<type1, type2>() compiles if and only if type1 and type2
+// are the same type. The value it returns is not interesting.
//
// Instead of making StaticAssertTypeEq a class template, we make it a
// function template that invokes a helper class template. This
@@ -2147,18 +2297,19 @@ GTEST_API_ AssertionResult DoubleLE(const char* expr1, const char* expr2,
//
// to cause a compiler error.
template <typename T1, typename T2>
-bool StaticAssertTypeEq() {
- (void)internal::StaticAssertTypeEqHelper<T1, T2>();
+constexpr bool StaticAssertTypeEq() noexcept {
+ static_assert(std::is_same<T1, T2>::value,
+ "type1 and type2 are not the same type");
return true;
}
// Defines a test.
//
-// The first parameter is the name of the test case, and the second
-// parameter is the name of the test within the test case.
+// The first parameter is the name of the test suite, and the second
+// parameter is the name of the test within the test suite.
//
-// The convention is to end the test case name with "Test". For
-// example, a test case for the Foo class can be named FooTest.
+// The convention is to end the test suite name with "Test". For
+// example, a test suite for the Foo class can be named FooTest.
//
// Test code should appear between braces after an invocation of
// this macro. Example:
@@ -2177,28 +2328,28 @@ bool StaticAssertTypeEq() {
// code. GetTestTypeId() is guaranteed to always return the same
// value, as it always calls GetTypeId<>() from the Google Test
// framework.
-#define GTEST_TEST(test_case_name, test_name)\
- GTEST_TEST_(test_case_name, test_name, \
- ::testing::Test, ::testing::internal::GetTestTypeId())
+#define GTEST_TEST(test_suite_name, test_name) \
+ GTEST_TEST_(test_suite_name, test_name, ::testing::Test, \
+ ::testing::internal::GetTestTypeId())
// Define this macro to 1 to omit the definition of TEST(), which
// is a generic name and clashes with some other libraries.
#if !GTEST_DONT_DEFINE_TEST
-# define TEST(test_case_name, test_name) GTEST_TEST(test_case_name, test_name)
+#define TEST(test_suite_name, test_name) GTEST_TEST(test_suite_name, test_name)
#endif
// Defines a test that uses a test fixture.
//
// The first parameter is the name of the test fixture class, which
-// also doubles as the test case name. The second parameter is the
-// name of the test within the test case.
+// also doubles as the test suite name. The second parameter is the
+// name of the test within the test suite.
//
// A test fixture class must be declared earlier. The user should put
-// his test code between braces after using this macro. Example:
+// the test code between braces after using this macro. Example:
//
// class FooTest : public testing::Test {
// protected:
-// virtual void SetUp() { b_.AddElement(3); }
+// void SetUp() override { b_.AddElement(3); }
//
// Foo a_;
// Foo b_;
@@ -2209,14 +2360,103 @@ bool StaticAssertTypeEq() {
// }
//
// TEST_F(FooTest, ReturnsElementCountCorrectly) {
-// EXPECT_EQ(0, a_.size());
-// EXPECT_EQ(1, b_.size());
+// EXPECT_EQ(a_.size(), 0);
+// EXPECT_EQ(b_.size(), 1);
// }
-
+//
+// GOOGLETEST_CM0011 DO NOT DELETE
#define TEST_F(test_fixture, test_name)\
GTEST_TEST_(test_fixture, test_name, test_fixture, \
::testing::internal::GetTypeId<test_fixture>())
+// Returns a path to temporary directory.
+// Tries to determine an appropriate directory for the platform.
+GTEST_API_ std::string TempDir();
+
+#ifdef _MSC_VER
+# pragma warning(pop)
+#endif
+
+// Dynamically registers a test with the framework.
+//
+// This is an advanced API only to be used when the `TEST` macros are
+// insufficient. The macros should be preferred when possible, as they avoid
+// most of the complexity of calling this function.
+//
+// The `factory` argument is a factory callable (move-constructible) object or
+// function pointer that creates a new instance of the Test object. It
+// handles ownership to the caller. The signature of the callable is
+// `Fixture*()`, where `Fixture` is the test fixture class for the test. All
+// tests registered with the same `test_suite_name` must return the same
+// fixture type. This is checked at runtime.
+//
+// The framework will infer the fixture class from the factory and will call
+// the `SetUpTestSuite` and `TearDownTestSuite` for it.
+//
+// Must be called before `RUN_ALL_TESTS()` is invoked, otherwise behavior is
+// undefined.
+//
+// Use case example:
+//
+// class MyFixture : public ::testing::Test {
+// public:
+// // All of these optional, just like in regular macro usage.
+// static void SetUpTestSuite() { ... }
+// static void TearDownTestSuite() { ... }
+// void SetUp() override { ... }
+// void TearDown() override { ... }
+// };
+//
+// class MyTest : public MyFixture {
+// public:
+// explicit MyTest(int data) : data_(data) {}
+// void TestBody() override { ... }
+//
+// private:
+// int data_;
+// };
+//
+// void RegisterMyTests(const std::vector<int>& values) {
+// for (int v : values) {
+// ::testing::RegisterTest(
+// "MyFixture", ("Test" + std::to_string(v)).c_str(), nullptr,
+// std::to_string(v).c_str(),
+// __FILE__, __LINE__,
+// // Important to use the fixture type as the return type here.
+// [=]() -> MyFixture* { return new MyTest(v); });
+// }
+// }
+// ...
+// int main(int argc, char** argv) {
+// std::vector<int> values_to_test = LoadValuesFromConfig();
+// RegisterMyTests(values_to_test);
+// ...
+// return RUN_ALL_TESTS();
+// }
+//
+template <int&... ExplicitParameterBarrier, typename Factory>
+TestInfo* RegisterTest(const char* test_suite_name, const char* test_name,
+ const char* type_param, const char* value_param,
+ const char* file, int line, Factory factory) {
+ using TestT = typename std::remove_pointer<decltype(factory())>::type;
+
+ class FactoryImpl : public internal::TestFactoryBase {
+ public:
+ explicit FactoryImpl(Factory f) : factory_(std::move(f)) {}
+ Test* CreateTest() override { return factory_(); }
+
+ private:
+ Factory factory_;
+ };
+
+ return internal::MakeAndRegisterTestInfo(
+ test_suite_name, test_name, type_param, value_param,
+ internal::CodeLocation(file, line), internal::GetTypeId<TestT>(),
+ internal::SuiteApiResolver<TestT>::GetSetUpCaseOrSuite(file, line),
+ internal::SuiteApiResolver<TestT>::GetTearDownCaseOrSuite(file, line),
+ new FactoryImpl{std::move(factory)});
+}
+
} // namespace testing
// Use this function in main() to run all tests. It returns 0 if all
@@ -2233,4 +2473,6 @@ inline int RUN_ALL_TESTS() {
return ::testing::UnitTest::GetInstance()->Run();
}
+GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251
+
#endif // GTEST_INCLUDE_GTEST_GTEST_H_
diff --git a/extern/gtest/include/gtest/gtest_pred_impl.h b/extern/gtest/include/gtest/gtest_pred_impl.h
index 30ae712f50e..d514255c733 100644
--- a/extern/gtest/include/gtest/gtest_pred_impl.h
+++ b/extern/gtest/include/gtest/gtest_pred_impl.h
@@ -27,18 +27,18 @@
// (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 10/31/2011 by command
+// This file is AUTOMATICALLY GENERATED on 01/02/2019 by command
// 'gen_gtest_pred_impl.py 5'. DO NOT EDIT BY HAND!
//
// Implements a family of generic predicate assertion macros.
+// GOOGLETEST_CM0001 DO NOT DELETE
#ifndef GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_
#define GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_
-// Makes sure this header is not included before gtest.h.
-#ifndef GTEST_INCLUDE_GTEST_GTEST_H_
-# error Do not include gtest_pred_impl.h directly. Include gtest.h instead.
-#endif // GTEST_INCLUDE_GTEST_GTEST_H_
+#include "gtest/gtest.h"
+
+namespace testing {
// This header implements a family of generic predicate assertion
// macros:
@@ -90,9 +90,10 @@ AssertionResult AssertPred1Helper(const char* pred_text,
const T1& v1) {
if (pred(v1)) return AssertionSuccess();
- return AssertionFailure() << pred_text << "("
- << e1 << ") evaluates to false, where"
- << "\n" << e1 << " evaluates to " << v1;
+ return AssertionFailure()
+ << pred_text << "(" << e1 << ") evaluates to false, where"
+ << "\n"
+ << e1 << " evaluates to " << ::testing::PrintToString(v1);
}
// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT1.
@@ -134,11 +135,12 @@ AssertionResult AssertPred2Helper(const char* pred_text,
const T2& v2) {
if (pred(v1, v2)) return AssertionSuccess();
- return AssertionFailure() << pred_text << "("
- << e1 << ", "
- << e2 << ") evaluates to false, where"
- << "\n" << e1 << " evaluates to " << v1
- << "\n" << e2 << " evaluates to " << v2;
+ return AssertionFailure()
+ << pred_text << "(" << e1 << ", " << e2
+ << ") evaluates to false, where"
+ << "\n"
+ << e1 << " evaluates to " << ::testing::PrintToString(v1) << "\n"
+ << e2 << " evaluates to " << ::testing::PrintToString(v2);
}
// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT2.
@@ -185,13 +187,13 @@ AssertionResult AssertPred3Helper(const char* pred_text,
const T3& v3) {
if (pred(v1, v2, v3)) return AssertionSuccess();
- return AssertionFailure() << pred_text << "("
- << e1 << ", "
- << e2 << ", "
- << e3 << ") evaluates to false, where"
- << "\n" << e1 << " evaluates to " << v1
- << "\n" << e2 << " evaluates to " << v2
- << "\n" << e3 << " evaluates to " << v3;
+ return AssertionFailure()
+ << pred_text << "(" << e1 << ", " << e2 << ", " << e3
+ << ") evaluates to false, where"
+ << "\n"
+ << e1 << " evaluates to " << ::testing::PrintToString(v1) << "\n"
+ << e2 << " evaluates to " << ::testing::PrintToString(v2) << "\n"
+ << e3 << " evaluates to " << ::testing::PrintToString(v3);
}
// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT3.
@@ -243,15 +245,14 @@ AssertionResult AssertPred4Helper(const char* pred_text,
const T4& v4) {
if (pred(v1, v2, v3, v4)) return AssertionSuccess();
- return AssertionFailure() << pred_text << "("
- << e1 << ", "
- << e2 << ", "
- << e3 << ", "
- << e4 << ") evaluates to false, where"
- << "\n" << e1 << " evaluates to " << v1
- << "\n" << e2 << " evaluates to " << v2
- << "\n" << e3 << " evaluates to " << v3
- << "\n" << e4 << " evaluates to " << v4;
+ return AssertionFailure()
+ << pred_text << "(" << e1 << ", " << e2 << ", " << e3 << ", " << e4
+ << ") evaluates to false, where"
+ << "\n"
+ << e1 << " evaluates to " << ::testing::PrintToString(v1) << "\n"
+ << e2 << " evaluates to " << ::testing::PrintToString(v2) << "\n"
+ << e3 << " evaluates to " << ::testing::PrintToString(v3) << "\n"
+ << e4 << " evaluates to " << ::testing::PrintToString(v4);
}
// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT4.
@@ -308,17 +309,15 @@ AssertionResult AssertPred5Helper(const char* pred_text,
const T5& v5) {
if (pred(v1, v2, v3, v4, v5)) return AssertionSuccess();
- return AssertionFailure() << pred_text << "("
- << e1 << ", "
- << e2 << ", "
- << e3 << ", "
- << e4 << ", "
- << e5 << ") evaluates to false, where"
- << "\n" << e1 << " evaluates to " << v1
- << "\n" << e2 << " evaluates to " << v2
- << "\n" << e3 << " evaluates to " << v3
- << "\n" << e4 << " evaluates to " << v4
- << "\n" << e5 << " evaluates to " << v5;
+ return AssertionFailure()
+ << pred_text << "(" << e1 << ", " << e2 << ", " << e3 << ", " << e4
+ << ", " << e5 << ") evaluates to false, where"
+ << "\n"
+ << e1 << " evaluates to " << ::testing::PrintToString(v1) << "\n"
+ << e2 << " evaluates to " << ::testing::PrintToString(v2) << "\n"
+ << e3 << " evaluates to " << ::testing::PrintToString(v3) << "\n"
+ << e4 << " evaluates to " << ::testing::PrintToString(v4) << "\n"
+ << e5 << " evaluates to " << ::testing::PrintToString(v5);
}
// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT5.
@@ -355,4 +354,6 @@ AssertionResult AssertPred5Helper(const char* pred_text,
+} // namespace testing
+
#endif // GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_
diff --git a/extern/gtest/include/gtest/gtest_prod.h b/extern/gtest/include/gtest/gtest_prod.h
index da80ddc6c70..e651671ebde 100644
--- a/extern/gtest/include/gtest/gtest_prod.h
+++ b/extern/gtest/include/gtest/gtest_prod.h
@@ -26,10 +26,10 @@
// 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.
+
//
-// Author: wan@google.com (Zhanyong Wan)
-//
-// Google C++ Testing Framework definitions useful in production code.
+// Google C++ Testing and Mocking Framework definitions useful in production code.
+// GOOGLETEST_CM0003 DO NOT DELETE
#ifndef GTEST_INCLUDE_GTEST_GTEST_PROD_H_
#define GTEST_INCLUDE_GTEST_GTEST_PROD_H_
@@ -40,17 +40,20 @@
//
// class MyClass {
// private:
-// void MyMethod();
-// FRIEND_TEST(MyClassTest, MyMethod);
+// void PrivateMethod();
+// FRIEND_TEST(MyClassTest, PrivateMethodWorks);
// };
//
// class MyClassTest : public testing::Test {
// // ...
// };
//
-// TEST_F(MyClassTest, MyMethod) {
-// // Can call MyClass::MyMethod() here.
+// TEST_F(MyClassTest, PrivateMethodWorks) {
+// // Can call MyClass::PrivateMethod() here.
// }
+//
+// Note: The test class must be in the same namespace as the class being tested.
+// For example, putting MyClassTest in an anonymous namespace will not work.
#define FRIEND_TEST(test_case_name, test_name)\
friend class test_case_name##_##test_name##_Test
diff --git a/extern/gtest/include/gtest/internal/custom/README.md b/extern/gtest/include/gtest/internal/custom/README.md
new file mode 100644
index 00000000000..ff391fb4e2b
--- /dev/null
+++ b/extern/gtest/include/gtest/internal/custom/README.md
@@ -0,0 +1,56 @@
+# Customization Points
+
+The custom directory is an injection point for custom user configurations.
+
+## Header `gtest.h`
+
+### The following macros can be defined:
+
+* `GTEST_OS_STACK_TRACE_GETTER_` - The name of an implementation of
+ `OsStackTraceGetterInterface`.
+* `GTEST_CUSTOM_TEMPDIR_FUNCTION_` - An override for `testing::TempDir()`. See
+ `testing::TempDir` for semantics and signature.
+
+## Header `gtest-port.h`
+
+The following macros can be defined:
+
+### Flag related macros:
+
+* `GTEST_FLAG(flag_name)`
+* `GTEST_USE_OWN_FLAGFILE_FLAG_` - Define to 0 when the system provides its
+ own flagfile flag parsing.
+* `GTEST_DECLARE_bool_(name)`
+* `GTEST_DECLARE_int32_(name)`
+* `GTEST_DECLARE_string_(name)`
+* `GTEST_DEFINE_bool_(name, default_val, doc)`
+* `GTEST_DEFINE_int32_(name, default_val, doc)`
+* `GTEST_DEFINE_string_(name, default_val, doc)`
+
+### Logging:
+
+* `GTEST_LOG_(severity)`
+* `GTEST_CHECK_(condition)`
+* Functions `LogToStderr()` and `FlushInfoLog()` have to be provided too.
+
+### Threading:
+
+* `GTEST_HAS_NOTIFICATION_` - Enabled if Notification is already provided.
+* `GTEST_HAS_MUTEX_AND_THREAD_LOCAL_` - Enabled if `Mutex` and `ThreadLocal`
+ are already provided. Must also provide `GTEST_DECLARE_STATIC_MUTEX_(mutex)`
+ and `GTEST_DEFINE_STATIC_MUTEX_(mutex)`
+* `GTEST_EXCLUSIVE_LOCK_REQUIRED_(locks)`
+* `GTEST_LOCK_EXCLUDED_(locks)`
+
+### Underlying library support features
+
+* `GTEST_HAS_CXXABI_H_`
+
+### Exporting API symbols:
+
+* `GTEST_API_` - Specifier for exported symbols.
+
+## Header `gtest-printers.h`
+
+* See documentation at `gtest/gtest-printers.h` for details on how to define a
+ custom printer.
diff --git a/extern/gtest/include/gtest/internal/custom/gtest-port.h b/extern/gtest/include/gtest/internal/custom/gtest-port.h
index 7e744bd3bb3..cd85d956d2d 100644
--- a/extern/gtest/include/gtest/internal/custom/gtest-port.h
+++ b/extern/gtest/include/gtest/internal/custom/gtest-port.h
@@ -27,39 +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.
//
-// Injection point for custom user configurations.
-// The following macros can be defined:
-//
-// Flag related macros:
-// GTEST_FLAG(flag_name)
-// GTEST_USE_OWN_FLAGFILE_FLAG_ - Define to 0 when the system provides its
-// own flagfile flag parsing.
-// GTEST_DECLARE_bool_(name)
-// GTEST_DECLARE_int32_(name)
-// GTEST_DECLARE_string_(name)
-// GTEST_DEFINE_bool_(name, default_val, doc)
-// GTEST_DEFINE_int32_(name, default_val, doc)
-// GTEST_DEFINE_string_(name, default_val, doc)
-//
-// Test filtering:
-// GTEST_TEST_FILTER_ENV_VAR_ - The name of an environment variable that
-// will be used if --GTEST_FLAG(test_filter)
-// is not provided.
-//
-// Logging:
-// GTEST_LOG_(severity)
-// GTEST_CHECK_(condition)
-// Functions LogToStderr() and FlushInfoLog() have to be provided too.
-//
-// Threading:
-// GTEST_HAS_NOTIFICATION_ - Enabled if Notification is already provided.
-// GTEST_HAS_MUTEX_AND_THREAD_LOCAL_ - Enabled if Mutex and ThreadLocal are
-// already provided.
-// Must also provide GTEST_DECLARE_STATIC_MUTEX_(mutex) and
-// GTEST_DEFINE_STATIC_MUTEX_(mutex)
-//
-// GTEST_EXCLUSIVE_LOCK_REQUIRED_(locks)
-// GTEST_LOCK_EXCLUDED_(locks)
+// Injection point for custom user configurations. See README for details
//
// ** Custom implementation starts here **
diff --git a/extern/gtest/include/gtest/internal/custom/gtest-printers.h b/extern/gtest/include/gtest/internal/custom/gtest-printers.h
index 60c1ea050b6..eb4467abcab 100644
--- a/extern/gtest/include/gtest/internal/custom/gtest-printers.h
+++ b/extern/gtest/include/gtest/internal/custom/gtest-printers.h
@@ -31,8 +31,8 @@
// installation of gTest.
// It will be included from gtest-printers.h and the overrides in this file
// will be visible to everyone.
-// See documentation at gtest/gtest-printers.h for details on how to define a
-// custom printer.
+//
+// Injection point for custom user configurations. See README for details
//
// ** Custom implementation starts here **
diff --git a/extern/gtest/include/gtest/internal/custom/gtest.h b/extern/gtest/include/gtest/internal/custom/gtest.h
index c27412a8981..4c8e07be23f 100644
--- a/extern/gtest/include/gtest/internal/custom/gtest.h
+++ b/extern/gtest/include/gtest/internal/custom/gtest.h
@@ -27,11 +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.
//
-// Injection point for custom user configurations.
-// The following macros can be defined:
-//
-// GTEST_OS_STACK_TRACE_GETTER_ - The name of an implementation of
-// OsStackTraceGetterInterface.
+// Injection point for custom user configurations. See README for details
//
// ** Custom implementation starts here **
diff --git a/extern/gtest/include/gtest/internal/gtest-death-test-internal.h b/extern/gtest/include/gtest/internal/gtest-death-test-internal.h
index 2b3a78f5bf8..68bd3530618 100644
--- a/extern/gtest/include/gtest/internal/gtest-death-test-internal.h
+++ b/extern/gtest/include/gtest/internal/gtest-death-test-internal.h
@@ -27,19 +27,20 @@
// (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)
+// The Google C++ Testing and Mocking Framework (Google Test)
//
// This header file defines internal utilities needed for implementing
// death tests. They are subject to change without notice.
+// GOOGLETEST_CM0001 DO NOT DELETE
#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_
#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_
+#include "gtest/gtest-matchers.h"
#include "gtest/internal/gtest-internal.h"
#include <stdio.h>
+#include <memory>
namespace testing {
namespace internal {
@@ -53,6 +54,9 @@ const char kInternalRunDeathTestFlag[] = "internal_run_death_test";
#if GTEST_HAS_DEATH_TEST
+GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \
+/* class A needs to have dll-interface to be used by clients of class B */)
+
// DeathTest is a class that hides much of the complexity of the
// GTEST_DEATH_TEST_ macro. It is abstract; its static Create method
// returns a concrete class that depends on the prevailing death test
@@ -76,7 +80,7 @@ class GTEST_API_ DeathTest {
// argument is set. If the death test should be skipped, the pointer
// is set to NULL; otherwise, it is set to the address of a new concrete
// DeathTest object that controls the execution of the current test.
- static bool Create(const char* statement, const RE* regex,
+ static bool Create(const char* statement, Matcher<const std::string&> matcher,
const char* file, int line, DeathTest** test);
DeathTest();
virtual ~DeathTest() { }
@@ -136,25 +140,50 @@ class GTEST_API_ DeathTest {
GTEST_DISALLOW_COPY_AND_ASSIGN_(DeathTest);
};
+GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251
+
// Factory interface for death tests. May be mocked out for testing.
class DeathTestFactory {
public:
virtual ~DeathTestFactory() { }
- virtual bool Create(const char* statement, const RE* regex,
- const char* file, int line, DeathTest** test) = 0;
+ virtual bool Create(const char* statement,
+ Matcher<const std::string&> matcher, const char* file,
+ int line, DeathTest** test) = 0;
};
// A concrete DeathTestFactory implementation for normal use.
class DefaultDeathTestFactory : public DeathTestFactory {
public:
- virtual bool Create(const char* statement, const RE* regex,
- const char* file, int line, DeathTest** test);
+ bool Create(const char* statement, Matcher<const std::string&> matcher,
+ const char* file, int line, DeathTest** test) override;
};
// Returns true if exit_status describes a process that was terminated
// by a signal, or exited normally with a nonzero exit code.
GTEST_API_ bool ExitedUnsuccessfully(int exit_status);
+// A string passed to EXPECT_DEATH (etc.) is caught by one of these overloads
+// and interpreted as a regex (rather than an Eq matcher) for legacy
+// compatibility.
+inline Matcher<const ::std::string&> MakeDeathTestMatcher(
+ ::testing::internal::RE regex) {
+ return ContainsRegex(regex.pattern());
+}
+inline Matcher<const ::std::string&> MakeDeathTestMatcher(const char* regex) {
+ return ContainsRegex(regex);
+}
+inline Matcher<const ::std::string&> MakeDeathTestMatcher(
+ const ::std::string& regex) {
+ return ContainsRegex(regex);
+}
+
+// If a Matcher<const ::std::string&> is passed to EXPECT_DEATH (etc.), it's
+// used directly.
+inline Matcher<const ::std::string&> MakeDeathTestMatcher(
+ Matcher<const ::std::string&> matcher) {
+ return matcher;
+}
+
// Traps C++ exceptions escaping statement and reports them as test
// failures. Note that trapping SEH exceptions is not implemented here.
# if GTEST_HAS_EXCEPTIONS
@@ -182,50 +211,53 @@ GTEST_API_ bool ExitedUnsuccessfully(int exit_status);
// This macro is for implementing ASSERT_DEATH*, EXPECT_DEATH*,
// ASSERT_EXIT*, and EXPECT_EXIT*.
-# define GTEST_DEATH_TEST_(statement, predicate, regex, fail) \
- GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
- if (::testing::internal::AlwaysTrue()) { \
- const ::testing::internal::RE& gtest_regex = (regex); \
- ::testing::internal::DeathTest* gtest_dt; \
- if (!::testing::internal::DeathTest::Create(#statement, &gtest_regex, \
- __FILE__, __LINE__, &gtest_dt)) { \
- goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \
- } \
- if (gtest_dt != NULL) { \
- ::testing::internal::scoped_ptr< ::testing::internal::DeathTest> \
- gtest_dt_ptr(gtest_dt); \
- switch (gtest_dt->AssumeRole()) { \
- case ::testing::internal::DeathTest::OVERSEE_TEST: \
- if (!gtest_dt->Passed(predicate(gtest_dt->Wait()))) { \
- goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \
- } \
- break; \
- case ::testing::internal::DeathTest::EXECUTE_TEST: { \
- ::testing::internal::DeathTest::ReturnSentinel \
- gtest_sentinel(gtest_dt); \
- GTEST_EXECUTE_DEATH_TEST_STATEMENT_(statement, gtest_dt); \
- gtest_dt->Abort(::testing::internal::DeathTest::TEST_DID_NOT_DIE); \
- break; \
- } \
- default: \
- break; \
- } \
- } \
- } else \
- GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__): \
- fail(::testing::internal::DeathTest::LastMessage())
+#define GTEST_DEATH_TEST_(statement, predicate, regex_or_matcher, fail) \
+ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
+ if (::testing::internal::AlwaysTrue()) { \
+ ::testing::internal::DeathTest* gtest_dt; \
+ if (!::testing::internal::DeathTest::Create( \
+ #statement, \
+ ::testing::internal::MakeDeathTestMatcher(regex_or_matcher), \
+ __FILE__, __LINE__, &gtest_dt)) { \
+ goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \
+ } \
+ if (gtest_dt != nullptr) { \
+ std::unique_ptr< ::testing::internal::DeathTest> gtest_dt_ptr(gtest_dt); \
+ switch (gtest_dt->AssumeRole()) { \
+ case ::testing::internal::DeathTest::OVERSEE_TEST: \
+ if (!gtest_dt->Passed(predicate(gtest_dt->Wait()))) { \
+ goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \
+ } \
+ break; \
+ case ::testing::internal::DeathTest::EXECUTE_TEST: { \
+ ::testing::internal::DeathTest::ReturnSentinel gtest_sentinel( \
+ gtest_dt); \
+ GTEST_EXECUTE_DEATH_TEST_STATEMENT_(statement, gtest_dt); \
+ gtest_dt->Abort(::testing::internal::DeathTest::TEST_DID_NOT_DIE); \
+ break; \
+ } \
+ default: \
+ break; \
+ } \
+ } \
+ } else \
+ GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__) \
+ : fail(::testing::internal::DeathTest::LastMessage())
// 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 \
+// NDEBUG mode. In this case we need the statements to be executed and the macro
+// must accept a streamed message even though the message is never printed.
+// The regex object is not evaluated, but it is used to prevent "unused"
+// warnings and to avoid an expression that doesn't compile in debug mode.
+#define GTEST_EXECUTE_STATEMENT_(statement, regex_or_matcher) \
+ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
+ if (::testing::internal::AlwaysTrue()) { \
+ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
+ } else if (!::testing::internal::AlwaysTrue()) { \
+ ::testing::internal::MakeDeathTestMatcher(regex_or_matcher); \
+ } else \
::testing::Message()
// A class representing the parsed contents of the
@@ -264,53 +296,6 @@ class InternalRunDeathTestFlag {
// the flag is specified; otherwise returns NULL.
InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag();
-#else // GTEST_HAS_DEATH_TEST
-
-// This macro is used for implementing macros such as
-// EXPECT_DEATH_IF_SUPPORTED and ASSERT_DEATH_IF_SUPPORTED on systems where
-// death tests are not supported. Those macros must compile on such systems
-// iff EXPECT_DEATH and ASSERT_DEATH compile with the same parameters on
-// systems that support death tests. This allows one to write such a macro
-// on a system that does not support death tests and be sure that it will
-// compile on a death-test supporting system.
-//
-// Parameters:
-// statement - A statement that a macro such as EXPECT_DEATH would test
-// for program termination. This macro has to make sure this
-// statement is compiled but not executed, to ensure that
-// EXPECT_DEATH_IF_SUPPORTED compiles with a certain
-// parameter iff EXPECT_DEATH compiles with it.
-// regex - A regex that a macro such as EXPECT_DEATH would use to test
-// the output of statement. This parameter has to be
-// compiled but not evaluated by this macro, to ensure that
-// this macro only accepts expressions that a macro such as
-// EXPECT_DEATH would accept.
-// terminator - Must be an empty statement for EXPECT_DEATH_IF_SUPPORTED
-// and a return statement for ASSERT_DEATH_IF_SUPPORTED.
-// This ensures that ASSERT_DEATH_IF_SUPPORTED will not
-// compile inside functions where ASSERT_DEATH doesn't
-// compile.
-//
-// The branch that has an always false condition is used to ensure that
-// statement and regex are compiled (and thus syntactically correct) but
-// never executed. The unreachable code macro protects the terminator
-// statement from generating an 'unreachable code' warning in case
-// statement unconditionally returns or throws. The Message constructor at
-// the end allows the syntax of streaming additional messages into the
-// macro, for compilational compatibility with EXPECT_DEATH/ASSERT_DEATH.
-# define GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, terminator) \
- GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
- if (::testing::internal::AlwaysTrue()) { \
- GTEST_LOG_(WARNING) \
- << "Death tests are not supported on this platform.\n" \
- << "Statement '" #statement "' cannot be verified."; \
- } else if (::testing::internal::AlwaysFalse()) { \
- ::testing::internal::RE::PartialMatch(".*", (regex)); \
- GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
- terminator; \
- } else \
- ::testing::Message()
-
#endif // GTEST_HAS_DEATH_TEST
} // namespace internal
diff --git a/extern/gtest/include/gtest/internal/gtest-filepath.h b/extern/gtest/include/gtest/internal/gtest-filepath.h
index 7a13b4b0de6..c11b101516e 100644
--- a/extern/gtest/include/gtest/internal/gtest-filepath.h
+++ b/extern/gtest/include/gtest/internal/gtest-filepath.h
@@ -27,21 +27,24 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
-// Author: keith.ray@gmail.com (Keith Ray)
-//
// Google Test filepath utilities
//
// This header file declares classes and functions used internally by
// Google Test. They are subject to change without notice.
//
-// This file is #included in <gtest/internal/gtest-internal.h>.
+// This file is #included in gtest/internal/gtest-internal.h.
// Do not include this header file separately!
+// GOOGLETEST_CM0001 DO NOT DELETE
+
#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_
#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_
#include "gtest/internal/gtest-string.h"
+GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \
+/* class A needs to have dll-interface to be used by clients of class B */)
+
namespace testing {
namespace internal {
@@ -107,7 +110,7 @@ class GTEST_API_ FilePath {
const FilePath& base_name,
const char* extension);
- // Returns true iff the path is "".
+ // Returns true if and only if the path is "".
bool IsEmpty() const { return pathname_.empty(); }
// If input name has a trailing separator character, removes it and returns
@@ -203,4 +206,6 @@ class GTEST_API_ FilePath {
} // namespace internal
} // namespace testing
+GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251
+
#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_
diff --git a/extern/gtest/include/gtest/internal/gtest-internal.h b/extern/gtest/include/gtest/internal/gtest-internal.h
index ebd1cf615de..94c816a28bd 100644
--- a/extern/gtest/include/gtest/internal/gtest-internal.h
+++ b/extern/gtest/include/gtest/internal/gtest-internal.h
@@ -27,13 +27,13 @@
// (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)
+// The Google C++ Testing and Mocking Framework (Google Test)
//
// This header file declares functions and macros used internally by
// Google Test. They are subject to change without notice.
+// GOOGLETEST_CM0001 DO NOT DELETE
+
#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_
#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_
@@ -58,11 +58,12 @@
#include <map>
#include <set>
#include <string>
+#include <type_traits>
#include <vector>
#include "gtest/gtest-message.h"
-#include "gtest/internal/gtest-string.h"
#include "gtest/internal/gtest-filepath.h"
+#include "gtest/internal/gtest-string.h"
#include "gtest/internal/gtest-type-util.h"
// Due to C++ preprocessor weirdness, we need double indirection to
@@ -76,7 +77,9 @@
#define GTEST_CONCAT_TOKEN_(foo, bar) GTEST_CONCAT_TOKEN_IMPL_(foo, bar)
#define GTEST_CONCAT_TOKEN_IMPL_(foo, bar) foo ## bar
-class ProtocolMessage;
+// Stringifies its argument.
+#define GTEST_STRINGIFY_(name) #name
+
namespace proto2 { class Message; }
namespace testing {
@@ -88,7 +91,7 @@ class Message; // Represents a failure message.
class Test; // Represents a test.
class TestInfo; // Information about a test.
class TestPartResult; // Result of a test part.
-class UnitTest; // A collection of test cases.
+class UnitTest; // A collection of test suites.
template <typename T>
::std::string PrintToString(const T& value);
@@ -96,7 +99,6 @@ template <typename T>
namespace internal {
struct TraceInfo; // Information about a trace point.
-class ScopedTrace; // Implements scoped trace.
class TestInfoImpl; // Opaque implementation of TestInfo
class UnitTestImpl; // Opaque implementation of UnitTest
@@ -104,34 +106,22 @@ class UnitTestImpl; // Opaque implementation of UnitTest
// stack trace.
GTEST_API_ extern const char kStackTraceMarker[];
-// 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
-// different sizes, so we can use sizeof() to test which version is
-// picked by the compiler. These helpers have no implementations, as
-// we only need their signatures.
-//
-// Given IsNullLiteralHelper(x), the compiler will pick the first
-// version if x can be implicitly converted to Secret*, and pick the
-// second version otherwise. Since Secret is a secret and incomplete
-// type, the only expression a user can write that has type Secret* is
-// a null pointer literal. Therefore, we know that x is a null
-// pointer literal if and only if the first version is picked by the
-// compiler.
-char IsNullLiteralHelper(Secret* p);
-char (&IsNullLiteralHelper(...))[2]; // NOLINT
-
-// A compile-time bool constant that is true if and only if x is a
-// null pointer literal (i.e. NULL or any 0-valued compile-time
-// integral constant).
-#ifdef GTEST_ELLIPSIS_NEEDS_POD_
-// We lose support for NULL detection where the compiler doesn't like
-// passing non-POD classes through ellipsis (...).
-# define GTEST_IS_NULL_LITERAL_(x) false
-#else
-# define GTEST_IS_NULL_LITERAL_(x) \
- (sizeof(::testing::internal::IsNullLiteralHelper(x)) == 1)
-#endif // GTEST_ELLIPSIS_NEEDS_POD_
+// An IgnoredValue object can be implicitly constructed from ANY value.
+class IgnoredValue {
+ struct Sink {};
+ public:
+ // This constructor template allows any value to be implicitly
+ // converted to IgnoredValue. The object has no data member and
+ // doesn't try to remember anything about the argument. We
+ // deliberately omit the 'explicit' keyword in order to allow the
+ // conversion to be implicit.
+ // Disable the conversion if T already has a magical conversion operator.
+ // Otherwise we get ambiguity.
+ template <typename T,
+ typename std::enable_if<!std::is_convertible<T, Sink>::value,
+ int>::type = 0>
+ IgnoredValue(const T& /* ignored */) {} // NOLINT(runtime/explicit)
+};
// Appends the user-supplied message to the Google-Test-generated message.
GTEST_API_ std::string AppendUserMessage(
@@ -139,6 +129,9 @@ GTEST_API_ std::string AppendUserMessage(
#if GTEST_HAS_EXCEPTIONS
+GTEST_DISABLE_MSC_WARNINGS_PUSH_(4275 \
+/* an exported class was derived from a class that was not exported */)
+
// 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
@@ -150,32 +143,15 @@ class GTEST_API_ GoogleTestFailureException : public ::std::runtime_error {
explicit GoogleTestFailureException(const TestPartResult& failure);
};
-#endif // GTEST_HAS_EXCEPTIONS
-
-// A helper class for creating scoped traces in user programs.
-class GTEST_API_ ScopedTrace {
- public:
- // The c'tor pushes the given source file location and message onto
- // a trace stack maintained by Google Test.
- ScopedTrace(const char* file, int line, const Message& message);
-
- // The d'tor pops the info pushed by the c'tor.
- //
- // Note that the d'tor is not virtual in order to be efficient.
- // Don't inherit from ScopedTrace!
- ~ScopedTrace();
+GTEST_DISABLE_MSC_WARNINGS_POP_() // 4275
- private:
- GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedTrace);
-} GTEST_ATTRIBUTE_UNUSED_; // A ScopedTrace object does its job in its
- // c'tor and d'tor. Therefore it doesn't
- // need to be used otherwise.
+#endif // GTEST_HAS_EXCEPTIONS
namespace edit_distance {
// Returns the optimal edits to go from 'left' to 'right'.
// All edits cost the same, with replace having lower priority than
// add/remove.
-// Simple implementation of the Wagner–Fischer algorithm.
+// Simple implementation of the Wagner-Fischer algorithm.
// See http://en.wikipedia.org/wiki/Wagner-Fischer_algorithm
enum EditType { kMatch, kAdd, kRemove, kReplace };
GTEST_API_ std::vector<EditType> CalculateOptimalEdits(
@@ -213,7 +189,7 @@ GTEST_API_ std::string DiffStrings(const std::string& left,
// expected_value: "5"
// actual_value: "6"
//
-// The ignoring_case parameter is true iff the assertion is a
+// The ignoring_case parameter is true if and only if the assertion is a
// *_STRCASEEQ*. When it's true, the string " (ignoring case)" will
// be inserted into the message.
GTEST_API_ AssertionResult EqFailure(const char* expected_expression,
@@ -342,15 +318,15 @@ class FloatingPoint {
// Returns the sign bit of this number.
Bits sign_bit() const { return kSignBitMask & u_.bits_; }
- // Returns true iff this is NAN (not a number).
+ // Returns true if and only if this is NAN (not a number).
bool is_nan() const {
// It's a NAN if the exponent bits are all ones and the fraction
// bits are not entirely zeros.
return (exponent_bits() == kExponentBitMask) && (fraction_bits() != 0);
}
- // Returns true iff this number is at most kMaxUlps ULP's away from
- // rhs. In particular, this function:
+ // Returns true if and only if this number is at most kMaxUlps ULP's away
+ // from rhs. In particular, this function:
//
// - returns false if either number is (or both are) NAN.
// - treats really large numbers as almost equal to infinity.
@@ -421,7 +397,7 @@ typedef FloatingPoint<float> Float;
typedef FloatingPoint<double> Double;
// In order to catch the mistake of putting tests that use different
-// test fixture classes in the same test case, we need to assign
+// test fixture classes in the same test suite, we need to assign
// unique IDs to fixture classes and compare them. The TypeId type is
// used to hold such IDs. The user should treat TypeId as an opaque
// type: the only operation allowed on TypeId values is to compare
@@ -481,7 +457,7 @@ class TestFactoryBase {
template <class TestClass>
class TestFactoryImpl : public TestFactoryBase {
public:
- virtual Test* CreateTest() { return new TestClass; }
+ Test* CreateTest() override { return new TestClass; }
};
#if GTEST_OS_WINDOWS
@@ -497,23 +473,76 @@ GTEST_API_ AssertionResult IsHRESULTFailure(const char* expr,
#endif // GTEST_OS_WINDOWS
-// Types of SetUpTestCase() and TearDownTestCase() functions.
-typedef void (*SetUpTestCaseFunc)();
-typedef void (*TearDownTestCaseFunc)();
+// Types of SetUpTestSuite() and TearDownTestSuite() functions.
+using SetUpTestSuiteFunc = void (*)();
+using TearDownTestSuiteFunc = void (*)();
struct CodeLocation {
- CodeLocation(const string& a_file, int a_line) : file(a_file), line(a_line) {}
+ CodeLocation(const std::string& a_file, int a_line)
+ : file(a_file), line(a_line) {}
- string file;
+ std::string file;
int line;
};
+// Helper to identify which setup function for TestCase / TestSuite to call.
+// Only one function is allowed, either TestCase or TestSute but not both.
+
+// Utility functions to help SuiteApiResolver
+using SetUpTearDownSuiteFuncType = void (*)();
+
+inline SetUpTearDownSuiteFuncType GetNotDefaultOrNull(
+ SetUpTearDownSuiteFuncType a, SetUpTearDownSuiteFuncType def) {
+ return a == def ? nullptr : a;
+}
+
+template <typename T>
+// Note that SuiteApiResolver inherits from T because
+// SetUpTestSuite()/TearDownTestSuite() could be protected. Ths way
+// SuiteApiResolver can access them.
+struct SuiteApiResolver : T {
+ // testing::Test is only forward declared at this point. So we make it a
+ // dependend class for the compiler to be OK with it.
+ using Test =
+ typename std::conditional<sizeof(T) != 0, ::testing::Test, void>::type;
+
+ static SetUpTearDownSuiteFuncType GetSetUpCaseOrSuite(const char* filename,
+ int line_num) {
+ SetUpTearDownSuiteFuncType test_case_fp =
+ GetNotDefaultOrNull(&T::SetUpTestCase, &Test::SetUpTestCase);
+ SetUpTearDownSuiteFuncType test_suite_fp =
+ GetNotDefaultOrNull(&T::SetUpTestSuite, &Test::SetUpTestSuite);
+
+ GTEST_CHECK_(!test_case_fp || !test_suite_fp)
+ << "Test can not provide both SetUpTestSuite and SetUpTestCase, please "
+ "make sure there is only one present at "
+ << filename << ":" << line_num;
+
+ return test_case_fp != nullptr ? test_case_fp : test_suite_fp;
+ }
+
+ static SetUpTearDownSuiteFuncType GetTearDownCaseOrSuite(const char* filename,
+ int line_num) {
+ SetUpTearDownSuiteFuncType test_case_fp =
+ GetNotDefaultOrNull(&T::TearDownTestCase, &Test::TearDownTestCase);
+ SetUpTearDownSuiteFuncType test_suite_fp =
+ GetNotDefaultOrNull(&T::TearDownTestSuite, &Test::TearDownTestSuite);
+
+ GTEST_CHECK_(!test_case_fp || !test_suite_fp)
+ << "Test can not provide both TearDownTestSuite and TearDownTestCase,"
+ " please make sure there is only one present at"
+ << filename << ":" << line_num;
+
+ return test_case_fp != nullptr ? test_case_fp : test_suite_fp;
+ }
+};
+
// Creates a new TestInfo object and registers it with Google Test;
// returns the created object.
//
// Arguments:
//
-// test_case_name: name of the test case
+// test_suite_name: name of the test suite
// 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.
@@ -521,21 +550,16 @@ struct CodeLocation {
// or NULL if this is not a type-parameterized test.
// code_location: code location where the test is defined
// fixture_class_id: ID of the test fixture class
-// set_up_tc: pointer to the function that sets up the test case
-// tear_down_tc: pointer to the function that tears down the test case
+// set_up_tc: pointer to the function that sets up the test suite
+// tear_down_tc: pointer to the function that tears down the test suite
// factory: pointer to the factory that creates a test object.
// 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* type_param,
- const char* value_param,
- CodeLocation code_location,
- TypeId fixture_class_id,
- SetUpTestCaseFunc set_up_tc,
- TearDownTestCaseFunc tear_down_tc,
- TestFactoryBase* factory);
+ const char* test_suite_name, const char* name, const char* type_param,
+ const char* value_param, CodeLocation code_location,
+ TypeId fixture_class_id, SetUpTestSuiteFunc set_up_tc,
+ TearDownTestSuiteFunc tear_down_tc, TestFactoryBase* factory);
// If *pstr starts with the given prefix, modifies *pstr to be right
// past the prefix and returns true; otherwise leaves *pstr unchanged
@@ -544,19 +568,23 @@ GTEST_API_ bool SkipPrefix(const char* prefix, const char** pstr);
#if GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P
-// State of the definition of a type-parameterized test case.
-class GTEST_API_ TypedTestCasePState {
+GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \
+/* class A needs to have dll-interface to be used by clients of class B */)
+
+// State of the definition of a type-parameterized test suite.
+class GTEST_API_ TypedTestSuitePState {
public:
- TypedTestCasePState() : registered_(false) {}
+ TypedTestSuitePState() : registered_(false) {}
// Adds the given test name to defined_test_names_ and return true
- // if the test case hasn't been registered; otherwise aborts the
+ // if the test suite hasn't been registered; otherwise aborts the
// program.
bool AddTestName(const char* file, int line, const char* case_name,
const char* test_name) {
if (registered_) {
- fprintf(stderr, "%s Test %s must be defined before "
- "REGISTER_TYPED_TEST_CASE_P(%s, ...).\n",
+ fprintf(stderr,
+ "%s Test %s must be defined before "
+ "REGISTER_TYPED_TEST_SUITE_P(%s, ...).\n",
FormatFileLocation(file, line).c_str(), test_name, case_name);
fflush(stderr);
posix::Abort();
@@ -589,12 +617,19 @@ class GTEST_API_ TypedTestCasePState {
RegisteredTestsMap registered_tests_;
};
+// Legacy API is deprecated but still available
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+using TypedTestCasePState = TypedTestSuitePState;
+#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+
+GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251
+
// Skips to the first non-space char after the first comma in 'str';
// returns NULL if no comma is found in 'str'.
inline const char* SkipComma(const char* str) {
const char* comma = strchr(str, ',');
- if (comma == NULL) {
- return NULL;
+ if (comma == nullptr) {
+ return nullptr;
}
while (IsSpace(*(++comma))) {}
return comma;
@@ -604,7 +639,7 @@ inline const char* SkipComma(const char* str) {
// the entire string if it contains no comma.
inline std::string GetPrefixUntilComma(const char* str) {
const char* comma = strchr(str, ',');
- return comma == NULL ? str : std::string(str, comma);
+ return comma == nullptr ? str : std::string(str, comma);
}
// Splits a given string on a given delimiter, populating a given
@@ -612,6 +647,37 @@ inline std::string GetPrefixUntilComma(const char* str) {
void SplitString(const ::std::string& str, char delimiter,
::std::vector< ::std::string>* dest);
+// The default argument to the template below for the case when the user does
+// not provide a name generator.
+struct DefaultNameGenerator {
+ template <typename T>
+ static std::string GetName(int i) {
+ return StreamableToString(i);
+ }
+};
+
+template <typename Provided = DefaultNameGenerator>
+struct NameGeneratorSelector {
+ typedef Provided type;
+};
+
+template <typename NameGenerator>
+void GenerateNamesRecursively(Types0, std::vector<std::string>*, int) {}
+
+template <typename NameGenerator, typename Types>
+void GenerateNamesRecursively(Types, std::vector<std::string>* result, int i) {
+ result->push_back(NameGenerator::template GetName<typename Types::Head>(i));
+ GenerateNamesRecursively<NameGenerator>(typename Types::Tail(), result,
+ i + 1);
+}
+
+template <typename NameGenerator, typename Types>
+std::vector<std::string> GenerateNames() {
+ std::vector<std::string> result;
+ GenerateNamesRecursively<NameGenerator>(Types(), &result, 0);
+ return result;
+}
+
// TypeParameterizedTest<Fixture, TestSel, Types>::Register()
// registers a list of type-parameterized tests with Google Test. The
// return value is insignificant - we just need to return something
@@ -623,13 +689,13 @@ template <GTEST_TEMPLATE_ Fixture, class TestSel, typename Types>
class TypeParameterizedTest {
public:
// 'index' is the index of the test in the type list 'Types'
- // specified in INSTANTIATE_TYPED_TEST_CASE_P(Prefix, TestCase,
+ // specified in INSTANTIATE_TYPED_TEST_SUITE_P(Prefix, TestSuite,
// Types). Valid values for 'index' are [0, N - 1] where N is the
// length of Types.
- static bool Register(const char* prefix,
- CodeLocation code_location,
- const char* case_name, const char* test_names,
- int index) {
+ static bool Register(const char* prefix, const CodeLocation& code_location,
+ const char* case_name, const char* test_names, int index,
+ const std::vector<std::string>& type_names =
+ GenerateNames<DefaultNameGenerator, Types>()) {
typedef typename Types::Head Type;
typedef Fixture<Type> FixtureClass;
typedef typename GTEST_BIND_(TestSel, Type) TestClass;
@@ -637,20 +703,27 @@ class TypeParameterizedTest {
// First, registers the first type-parameterized test in the type
// list.
MakeAndRegisterTestInfo(
- (std::string(prefix) + (prefix[0] == '\0' ? "" : "/") + case_name + "/"
- + StreamableToString(index)).c_str(),
+ (std::string(prefix) + (prefix[0] == '\0' ? "" : "/") + case_name +
+ "/" + type_names[static_cast<size_t>(index)])
+ .c_str(),
StripTrailingSpaces(GetPrefixUntilComma(test_names)).c_str(),
GetTypeName<Type>().c_str(),
- NULL, // No value parameter.
- code_location,
- GetTypeId<FixtureClass>(),
- TestClass::SetUpTestCase,
- TestClass::TearDownTestCase,
+ nullptr, // No value parameter.
+ code_location, GetTypeId<FixtureClass>(),
+ SuiteApiResolver<TestClass>::GetSetUpCaseOrSuite(
+ code_location.file.c_str(), code_location.line),
+ SuiteApiResolver<TestClass>::GetTearDownCaseOrSuite(
+ code_location.file.c_str(), code_location.line),
new TestFactoryImpl<TestClass>);
// Next, recurses (at compile time) with the tail of the type list.
- return TypeParameterizedTest<Fixture, TestSel, typename Types::Tail>
- ::Register(prefix, code_location, case_name, test_names, index + 1);
+ return TypeParameterizedTest<Fixture, TestSel,
+ typename Types::Tail>::Register(prefix,
+ code_location,
+ case_name,
+ test_names,
+ index + 1,
+ type_names);
}
};
@@ -658,23 +731,27 @@ class TypeParameterizedTest {
template <GTEST_TEMPLATE_ Fixture, class TestSel>
class TypeParameterizedTest<Fixture, TestSel, Types0> {
public:
- static bool Register(const char* /*prefix*/, CodeLocation,
+ static bool Register(const char* /*prefix*/, const CodeLocation&,
const char* /*case_name*/, const char* /*test_names*/,
- int /*index*/) {
+ int /*index*/,
+ const std::vector<std::string>& =
+ std::vector<std::string>() /*type_names*/) {
return true;
}
};
-// TypeParameterizedTestCase<Fixture, Tests, Types>::Register()
+// TypeParameterizedTestSuite<Fixture, Tests, Types>::Register()
// registers *all combinations* of 'Tests' and 'Types' with Google
// Test. The return value is insignificant - we just need to return
// something such that we can call this function in a namespace scope.
template <GTEST_TEMPLATE_ Fixture, typename Tests, typename Types>
-class TypeParameterizedTestCase {
+class TypeParameterizedTestSuite {
public:
static bool Register(const char* prefix, CodeLocation code_location,
- const TypedTestCasePState* state,
- const char* case_name, const char* test_names) {
+ const TypedTestSuitePState* state, const char* case_name,
+ const char* test_names,
+ const std::vector<std::string>& type_names =
+ GenerateNames<DefaultNameGenerator, Types>()) {
std::string test_name = StripTrailingSpaces(
GetPrefixUntilComma(test_names));
if (!state->TestExists(test_name)) {
@@ -691,22 +768,26 @@ class TypeParameterizedTestCase {
// First, register the first test in 'Test' for each type in 'Types'.
TypeParameterizedTest<Fixture, Head, Types>::Register(
- prefix, test_location, case_name, test_names, 0);
+ prefix, test_location, case_name, test_names, 0, type_names);
// Next, recurses (at compile time) with the tail of the test list.
- return TypeParameterizedTestCase<Fixture, typename Tests::Tail, Types>
- ::Register(prefix, code_location, state,
- case_name, SkipComma(test_names));
+ return TypeParameterizedTestSuite<Fixture, typename Tests::Tail,
+ Types>::Register(prefix, code_location,
+ state, case_name,
+ SkipComma(test_names),
+ type_names);
}
};
// The base case for the compile time recursion.
template <GTEST_TEMPLATE_ Fixture, typename Types>
-class TypeParameterizedTestCase<Fixture, Templates0, Types> {
+class TypeParameterizedTestSuite<Fixture, Templates0, Types> {
public:
- static bool Register(const char* /*prefix*/, CodeLocation,
- const TypedTestCasePState* /*state*/,
- const char* /*case_name*/, const char* /*test_names*/) {
+ static bool Register(const char* /*prefix*/, const CodeLocation&,
+ const TypedTestSuitePState* /*state*/,
+ const char* /*case_name*/, const char* /*test_names*/,
+ const std::vector<std::string>& =
+ std::vector<std::string>() /*type_names*/) {
return true;
}
};
@@ -766,145 +847,16 @@ class GTEST_API_ Random {
GTEST_DISALLOW_COPY_AND_ASSIGN_(Random);
};
-// Defining a variable of type CompileAssertTypesEqual<T1, T2> will cause a
-// compiler error iff T1 and T2 are different types.
-template <typename T1, typename T2>
-struct CompileAssertTypesEqual;
-
-template <typename T>
-struct CompileAssertTypesEqual<T, T> {
-};
-
-// Removes the reference from a type if it is a reference type,
-// otherwise leaves it unchanged. This is the same as
-// tr1::remove_reference, which is not widely available yet.
-template <typename T>
-struct RemoveReference { typedef T type; }; // NOLINT
-template <typename T>
-struct RemoveReference<T&> { typedef T type; }; // NOLINT
-
-// A handy wrapper around RemoveReference that works when the argument
-// T depends on template parameters.
-#define GTEST_REMOVE_REFERENCE_(T) \
- typename ::testing::internal::RemoveReference<T>::type
-
-// Removes const from a type if it is a const type, otherwise leaves
-// it unchanged. This is the same as tr1::remove_const, which is not
-// widely available yet.
-template <typename T>
-struct RemoveConst { typedef T type; }; // NOLINT
-template <typename T>
-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.
-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
-// T depends on template parameters.
-#define GTEST_REMOVE_CONST_(T) \
- typename ::testing::internal::RemoveConst<T>::type
-
// Turns const U&, U&, const U, and U all into U.
#define GTEST_REMOVE_REFERENCE_AND_CONST_(T) \
- GTEST_REMOVE_CONST_(GTEST_REMOVE_REFERENCE_(T))
-
-// Adds reference to a type if it is not a reference type,
-// otherwise leaves it unchanged. This is the same as
-// tr1::add_reference, which is not widely available yet.
-template <typename T>
-struct AddReference { typedef T& type; }; // NOLINT
-template <typename T>
-struct AddReference<T&> { typedef T& type; }; // NOLINT
-
-// A handy wrapper around AddReference that works when the argument T
-// depends on template parameters.
-#define GTEST_ADD_REFERENCE_(T) \
- typename ::testing::internal::AddReference<T>::type
-
-// Adds a reference to const on top of T as necessary. For example,
-// it transforms
-//
-// char ==> const char&
-// const char ==> const char&
-// char& ==> const char&
-// const char& ==> const char&
-//
-// The argument T must depend on some template parameters.
-#define GTEST_REFERENCE_TO_CONST_(T) \
- GTEST_ADD_REFERENCE_(const GTEST_REMOVE_REFERENCE_(T))
-
-// ImplicitlyConvertible<From, To>::value is a compile-time bool
-// constant that's true iff type From can be implicitly converted to
-// type To.
-template <typename From, typename To>
-class ImplicitlyConvertible {
- private:
- // We need the following helper functions only for their types.
- // They have no implementations.
-
- // MakeFrom() is an expression whose type is From. We cannot simply
- // use From(), as the type From may not have a public default
- // constructor.
- static typename AddReference<From>::type MakeFrom();
-
- // These two functions are overloaded. Given an expression
- // Helper(x), the compiler will pick the first version if x can be
- // implicitly converted to type To; otherwise it will pick the
- // second version.
- //
- // The first version returns a value of size 1, and the second
- // version returns a value of size 2. Therefore, by checking the
- // size of Helper(x), which can be done at compile time, we can tell
- // which version of Helper() is used, and hence whether x can be
- // implicitly converted to type To.
- static char Helper(To);
- static char (&Helper(...))[2]; // NOLINT
-
- // We have to put the 'public' section after the 'private' section,
- // or MSVC refuses to compile the code.
- public:
-#if defined(__BORLANDC__)
- // C++Builder cannot use member overload resolution during template
- // instantiation. The simplest workaround is to use its C++0x type traits
- // functions (C++Builder 2009 and above only).
- static const bool value = __is_convertible(From, To);
-#else
- // MSVC warns about implicitly converting from double to int for
- // possible loss of data, so we need to temporarily disable the
- // warning.
- GTEST_DISABLE_MSC_WARNINGS_PUSH_(4244)
- static const bool value =
- sizeof(Helper(ImplicitlyConvertible::MakeFrom())) == 1;
- GTEST_DISABLE_MSC_WARNINGS_POP_()
-#endif // __BORLANDC__
-};
-template <typename From, typename To>
-const bool ImplicitlyConvertible<From, To>::value;
+ typename std::remove_const<typename std::remove_reference<T>::type>::type
// IsAProtocolMessage<T>::value is a compile-time bool constant that's
-// true iff T is type ProtocolMessage, proto2::Message, or a subclass
-// of those.
+// true if and only if T is type proto2::Message or a subclass of it.
template <typename T>
struct IsAProtocolMessage
: public bool_constant<
- ImplicitlyConvertible<const T*, const ::ProtocolMessage*>::value ||
- ImplicitlyConvertible<const T*, const ::proto2::Message*>::value> {
-};
+ std::is_convertible<const T*, const ::proto2::Message*>::value> {};
// When the compiler sees expression IsContainerTest<C>(0), if C is an
// STL-style container class, the first overload of IsContainerTest
@@ -917,8 +869,11 @@ struct IsAProtocolMessage
// a container class by checking the type of IsContainerTest<C>(0).
// The value of the expression is insignificant.
//
-// Note that we look for both C::iterator and C::const_iterator. The
-// reason is that C++ injects the name of a class as a member of the
+// In C++11 mode we check the existence of a const_iterator and that an
+// iterator is properly implemented for the container.
+//
+// For pre-C++11 that we look for both C::iterator and C::const_iterator.
+// The reason is that C++ injects the name of a class as a member of the
// class itself (e.g. you can refer to class iterator as either
// 'iterator' or 'iterator::iterator'). If we look for C::iterator
// only, for example, we would mistakenly think that a class named
@@ -928,10 +883,13 @@ struct IsAProtocolMessage
// IsContainerTest(typename C::const_iterator*) and
// IsContainerTest(...) doesn't work with Visual Age C++ and Sun C++.
typedef int IsContainer;
-template <class C>
-IsContainer IsContainerTest(int /* dummy */,
- typename C::iterator* /* it */ = NULL,
- typename C::const_iterator* /* const_it */ = NULL) {
+template <class C,
+ class Iterator = decltype(::std::declval<const C&>().begin()),
+ class = decltype(::std::declval<const C&>().end()),
+ class = decltype(++::std::declval<Iterator&>()),
+ class = decltype(*::std::declval<Iterator>()),
+ class = typename C::const_iterator>
+IsContainer IsContainerTest(int /* dummy */) {
return 0;
}
@@ -939,12 +897,55 @@ typedef char IsNotContainer;
template <class C>
IsNotContainer IsContainerTest(long /* dummy */) { return '\0'; }
-// EnableIf<condition>::type is void when 'Cond' is true, and
-// undefined when 'Cond' is false. To use SFINAE to make a function
-// overload only apply when a particular expression is true, add
-// "typename EnableIf<expression>::type* = 0" as the last parameter.
-template<bool> struct EnableIf;
-template<> struct EnableIf<true> { typedef void type; }; // NOLINT
+// Trait to detect whether a type T is a hash table.
+// The heuristic used is that the type contains an inner type `hasher` and does
+// not contain an inner type `reverse_iterator`.
+// If the container is iterable in reverse, then order might actually matter.
+template <typename T>
+struct IsHashTable {
+ private:
+ template <typename U>
+ static char test(typename U::hasher*, typename U::reverse_iterator*);
+ template <typename U>
+ static int test(typename U::hasher*, ...);
+ template <typename U>
+ static char test(...);
+
+ public:
+ static const bool value = sizeof(test<T>(nullptr, nullptr)) == sizeof(int);
+};
+
+template <typename T>
+const bool IsHashTable<T>::value;
+
+template <typename C,
+ bool = sizeof(IsContainerTest<C>(0)) == sizeof(IsContainer)>
+struct IsRecursiveContainerImpl;
+
+template <typename C>
+struct IsRecursiveContainerImpl<C, false> : public std::false_type {};
+
+// Since the IsRecursiveContainerImpl depends on the IsContainerTest we need to
+// obey the same inconsistencies as the IsContainerTest, namely check if
+// something is a container is relying on only const_iterator in C++11 and
+// is relying on both const_iterator and iterator otherwise
+template <typename C>
+struct IsRecursiveContainerImpl<C, true> {
+ using value_type = decltype(*std::declval<typename C::const_iterator>());
+ using type =
+ std::is_same<typename std::remove_const<
+ typename std::remove_reference<value_type>::type>::type,
+ C>;
+};
+
+// IsRecursiveContainer<Type> is a unary compile-time predicate that
+// evaluates whether C is a recursive container type. A recursive container
+// type is a container type whose value_type is equal to the container type
+// itself. An example for a recursive container type is
+// boost::filesystem::path, whose iterator has a value_type that is equal to
+// boost::filesystem::path.
+template <typename C>
+struct IsRecursiveContainer : public IsRecursiveContainerImpl<C>::type {};
// Utilities for native arrays.
@@ -1068,10 +1069,9 @@ class NativeArray {
}
private:
- enum {
- kCheckTypeIsNotConstOrAReference = StaticAssertTypeEqHelper<
- Element, GTEST_REMOVE_REFERENCE_AND_CONST_(Element)>::value,
- };
+ static_assert(!std::is_const<Element>::value, "Type must not be const");
+ static_assert(!std::is_reference<Element>::value,
+ "Type must not be a reference");
// Initializes this object with a copy of the input.
void InitCopy(const Element* array, size_t a_size) {
@@ -1096,6 +1096,139 @@ class NativeArray {
GTEST_DISALLOW_ASSIGN_(NativeArray);
};
+// Backport of std::index_sequence.
+template <size_t... Is>
+struct IndexSequence {
+ using type = IndexSequence;
+};
+
+// Double the IndexSequence, and one if plus_one is true.
+template <bool plus_one, typename T, size_t sizeofT>
+struct DoubleSequence;
+template <size_t... I, size_t sizeofT>
+struct DoubleSequence<true, IndexSequence<I...>, sizeofT> {
+ using type = IndexSequence<I..., (sizeofT + I)..., 2 * sizeofT>;
+};
+template <size_t... I, size_t sizeofT>
+struct DoubleSequence<false, IndexSequence<I...>, sizeofT> {
+ using type = IndexSequence<I..., (sizeofT + I)...>;
+};
+
+// Backport of std::make_index_sequence.
+// It uses O(ln(N)) instantiation depth.
+template <size_t N>
+struct MakeIndexSequence
+ : DoubleSequence<N % 2 == 1, typename MakeIndexSequence<N / 2>::type,
+ N / 2>::type {};
+
+template <>
+struct MakeIndexSequence<0> : IndexSequence<> {};
+
+// FIXME: This implementation of ElemFromList is O(1) in instantiation depth,
+// but it is O(N^2) in total instantiations. Not sure if this is the best
+// tradeoff, as it will make it somewhat slow to compile.
+template <typename T, size_t, size_t>
+struct ElemFromListImpl {};
+
+template <typename T, size_t I>
+struct ElemFromListImpl<T, I, I> {
+ using type = T;
+};
+
+// Get the Nth element from T...
+// It uses O(1) instantiation depth.
+template <size_t N, typename I, typename... T>
+struct ElemFromList;
+
+template <size_t N, size_t... I, typename... T>
+struct ElemFromList<N, IndexSequence<I...>, T...>
+ : ElemFromListImpl<T, N, I>... {};
+
+template <typename... T>
+class FlatTuple;
+
+template <typename Derived, size_t I>
+struct FlatTupleElemBase;
+
+template <typename... T, size_t I>
+struct FlatTupleElemBase<FlatTuple<T...>, I> {
+ using value_type =
+ typename ElemFromList<I, typename MakeIndexSequence<sizeof...(T)>::type,
+ T...>::type;
+ FlatTupleElemBase() = default;
+ explicit FlatTupleElemBase(value_type t) : value(std::move(t)) {}
+ value_type value;
+};
+
+template <typename Derived, typename Idx>
+struct FlatTupleBase;
+
+template <size_t... Idx, typename... T>
+struct FlatTupleBase<FlatTuple<T...>, IndexSequence<Idx...>>
+ : FlatTupleElemBase<FlatTuple<T...>, Idx>... {
+ using Indices = IndexSequence<Idx...>;
+ FlatTupleBase() = default;
+ explicit FlatTupleBase(T... t)
+ : FlatTupleElemBase<FlatTuple<T...>, Idx>(std::move(t))... {}
+};
+
+// Analog to std::tuple but with different tradeoffs.
+// This class minimizes the template instantiation depth, thus allowing more
+// elements that std::tuple would. std::tuple has been seen to require an
+// instantiation depth of more than 10x the number of elements in some
+// implementations.
+// FlatTuple and ElemFromList are not recursive and have a fixed depth
+// regardless of T...
+// MakeIndexSequence, on the other hand, it is recursive but with an
+// instantiation depth of O(ln(N)).
+template <typename... T>
+class FlatTuple
+ : private FlatTupleBase<FlatTuple<T...>,
+ typename MakeIndexSequence<sizeof...(T)>::type> {
+ using Indices = typename FlatTuple::FlatTupleBase::Indices;
+
+ public:
+ FlatTuple() = default;
+ explicit FlatTuple(T... t) : FlatTuple::FlatTupleBase(std::move(t)...) {}
+
+ template <size_t I>
+ const typename ElemFromList<I, Indices, T...>::type& Get() const {
+ return static_cast<const FlatTupleElemBase<FlatTuple, I>*>(this)->value;
+ }
+
+ template <size_t I>
+ typename ElemFromList<I, Indices, T...>::type& Get() {
+ return static_cast<FlatTupleElemBase<FlatTuple, I>*>(this)->value;
+ }
+};
+
+// Utility functions to be called with static_assert to induce deprecation
+// warnings.
+GTEST_INTERNAL_DEPRECATED(
+ "INSTANTIATE_TEST_CASE_P is deprecated, please use "
+ "INSTANTIATE_TEST_SUITE_P")
+constexpr bool InstantiateTestCase_P_IsDeprecated() { return true; }
+
+GTEST_INTERNAL_DEPRECATED(
+ "TYPED_TEST_CASE_P is deprecated, please use "
+ "TYPED_TEST_SUITE_P")
+constexpr bool TypedTestCase_P_IsDeprecated() { return true; }
+
+GTEST_INTERNAL_DEPRECATED(
+ "TYPED_TEST_CASE is deprecated, please use "
+ "TYPED_TEST_SUITE")
+constexpr bool TypedTestCaseIsDeprecated() { return true; }
+
+GTEST_INTERNAL_DEPRECATED(
+ "REGISTER_TYPED_TEST_CASE_P is deprecated, please use "
+ "REGISTER_TYPED_TEST_SUITE_P")
+constexpr bool RegisterTypedTestCase_P_IsDeprecated() { return true; }
+
+GTEST_INTERNAL_DEPRECATED(
+ "INSTANTIATE_TYPED_TEST_CASE_P is deprecated, please use "
+ "INSTANTIATE_TYPED_TEST_SUITE_P")
+constexpr bool InstantiateTypedTestCase_P_IsDeprecated() { return true; }
+
} // namespace internal
} // namespace testing
@@ -1115,7 +1248,10 @@ class NativeArray {
#define GTEST_SUCCESS_(message) \
GTEST_MESSAGE_(message, ::testing::TestPartResult::kSuccess)
-// Suppresses MSVC warnings 4072 (unreachable code) for the code following
+#define GTEST_SKIP_(message) \
+ return GTEST_MESSAGE_(message, ::testing::TestPartResult::kSkip)
+
+// Suppress MSVC warning 4072 (unreachable code) for the code following
// statement if it returns or throws (or doesn't return or throw in some
// situations).
#define GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement) \
@@ -1207,32 +1343,38 @@ class NativeArray {
" Actual: it does.")
// Expands to the name of the class that implements the given test.
-#define GTEST_TEST_CLASS_NAME_(test_case_name, test_name) \
- test_case_name##_##test_name##_Test
+#define GTEST_TEST_CLASS_NAME_(test_suite_name, test_name) \
+ test_suite_name##_##test_name##_Test
// Helper macro for defining tests.
-#define GTEST_TEST_(test_case_name, test_name, parent_class, parent_id)\
-class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) : public parent_class {\
- public:\
- GTEST_TEST_CLASS_NAME_(test_case_name, test_name)() {}\
- private:\
- virtual void TestBody();\
- static ::testing::TestInfo* const test_info_ GTEST_ATTRIBUTE_UNUSED_;\
- GTEST_DISALLOW_COPY_AND_ASSIGN_(\
- GTEST_TEST_CLASS_NAME_(test_case_name, test_name));\
-};\
-\
-::testing::TestInfo* const GTEST_TEST_CLASS_NAME_(test_case_name, test_name)\
- ::test_info_ =\
- ::testing::internal::MakeAndRegisterTestInfo(\
- #test_case_name, #test_name, NULL, NULL, \
- ::testing::internal::CodeLocation(__FILE__, __LINE__), \
- (parent_id), \
- parent_class::SetUpTestCase, \
- parent_class::TearDownTestCase, \
- new ::testing::internal::TestFactoryImpl<\
- GTEST_TEST_CLASS_NAME_(test_case_name, test_name)>);\
-void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody()
+#define GTEST_TEST_(test_suite_name, test_name, parent_class, parent_id) \
+ static_assert(sizeof(GTEST_STRINGIFY_(test_suite_name)) > 1, \
+ "test_suite_name must not be empty"); \
+ static_assert(sizeof(GTEST_STRINGIFY_(test_name)) > 1, \
+ "test_name must not be empty"); \
+ class GTEST_TEST_CLASS_NAME_(test_suite_name, test_name) \
+ : public parent_class { \
+ public: \
+ GTEST_TEST_CLASS_NAME_(test_suite_name, test_name)() {} \
+ \
+ private: \
+ virtual void TestBody(); \
+ static ::testing::TestInfo* const test_info_ GTEST_ATTRIBUTE_UNUSED_; \
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(GTEST_TEST_CLASS_NAME_(test_suite_name, \
+ test_name)); \
+ }; \
+ \
+ ::testing::TestInfo* const GTEST_TEST_CLASS_NAME_(test_suite_name, \
+ test_name)::test_info_ = \
+ ::testing::internal::MakeAndRegisterTestInfo( \
+ #test_suite_name, #test_name, nullptr, nullptr, \
+ ::testing::internal::CodeLocation(__FILE__, __LINE__), (parent_id), \
+ ::testing::internal::SuiteApiResolver< \
+ parent_class>::GetSetUpCaseOrSuite(__FILE__, __LINE__), \
+ ::testing::internal::SuiteApiResolver< \
+ parent_class>::GetTearDownCaseOrSuite(__FILE__, __LINE__), \
+ new ::testing::internal::TestFactoryImpl<GTEST_TEST_CLASS_NAME_( \
+ test_suite_name, test_name)>); \
+ void GTEST_TEST_CLASS_NAME_(test_suite_name, test_name)::TestBody()
#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_
-
diff --git a/extern/gtest/include/gtest/internal/gtest-linked_ptr.h b/extern/gtest/include/gtest/internal/gtest-linked_ptr.h
deleted file mode 100644
index 36029422174..00000000000
--- a/extern/gtest/include/gtest/internal/gtest-linked_ptr.h
+++ /dev/null
@@ -1,243 +0,0 @@
-// Copyright 2003 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: Dan Egnor (egnor@google.com)
-//
-// A "smart" pointer type with reference tracking. Every pointer to a
-// particular object is kept on a circular linked list. When the last pointer
-// to an object is destroyed or reassigned, the object is deleted.
-//
-// Used properly, this deletes the object when the last reference goes away.
-// There are several caveats:
-// - Like all reference counting schemes, cycles lead to leaks.
-// - Each smart pointer is actually two pointers (8 bytes instead of 4).
-// - Every time a pointer is assigned, the entire list of pointers to that
-// object is traversed. This class is therefore NOT SUITABLE when there
-// will often be more than two or three pointers to a particular object.
-// - References are only tracked as long as linked_ptr<> objects are copied.
-// If a linked_ptr<> is converted to a raw pointer and back, BAD THINGS
-// will happen (double deletion).
-//
-// A good use of this class is storing object references in STL containers.
-// You can safely put linked_ptr<> in a vector<>.
-// Other uses may not be as good.
-//
-// Note: If you use an incomplete type with linked_ptr<>, the class
-// *containing* linked_ptr<> must have a constructor and destructor (even
-// if they do nothing!).
-//
-// Bill Gibbons suggested we use something like this.
-//
-// Thread Safety:
-// Unlike other linked_ptr implementations, in this implementation
-// a linked_ptr object is thread-safe in the sense that:
-// - it's safe to copy linked_ptr objects concurrently,
-// - it's safe to copy *from* a linked_ptr and read its underlying
-// raw pointer (e.g. via get()) concurrently, and
-// - it's safe to write to two linked_ptrs that point to the same
-// shared object concurrently.
-// TODO(wan@google.com): rename this to safe_linked_ptr to avoid
-// confusion with normal linked_ptr.
-
-#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_
-#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_
-
-#include <stdlib.h>
-#include <assert.h>
-
-#include "gtest/internal/gtest-port.h"
-
-namespace testing {
-namespace internal {
-
-// Protects copying of all linked_ptr objects.
-GTEST_API_ GTEST_DECLARE_STATIC_MUTEX_(g_linked_ptr_mutex);
-
-// This is used internally by all instances of linked_ptr<>. It needs to be
-// a non-template class because different types of linked_ptr<> can refer to
-// the same object (linked_ptr<Superclass>(obj) vs linked_ptr<Subclass>(obj)).
-// So, it needs to be possible for different types of linked_ptr to participate
-// in the same circular linked list, so we need a single class type here.
-//
-// DO NOT USE THIS CLASS DIRECTLY YOURSELF. Use linked_ptr<T>.
-class linked_ptr_internal {
- public:
- // Create a new circle that includes only this instance.
- void join_new() {
- next_ = this;
- }
-
- // Many linked_ptr operations may change p.link_ for some linked_ptr
- // variable p in the same circle as this object. Therefore we need
- // to prevent two such operations from occurring concurrently.
- //
- // Note that different types of linked_ptr objects can coexist in a
- // circle (e.g. linked_ptr<Base>, linked_ptr<Derived1>, and
- // linked_ptr<Derived2>). Therefore we must use a single mutex to
- // protect all linked_ptr objects. This can create serious
- // contention in production code, but is acceptable in a testing
- // framework.
-
- // Join an existing circle.
- 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;
- while (p->next_ != ptr) {
- assert(p->next_ != this &&
- "Trying to join() a linked ring we are already in. "
- "Is GMock thread safety enabled?");
- p = p->next_;
- }
- p->next_ = this;
- next_ = ptr;
- }
-
- // 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.
- bool depart()
- GTEST_LOCK_EXCLUDED_(g_linked_ptr_mutex) {
- MutexLock lock(&g_linked_ptr_mutex);
-
- if (next_ == this) return true;
- linked_ptr_internal const* p = next_;
- while (p->next_ != this) {
- assert(p->next_ != next_ &&
- "Trying to depart() a linked ring we are not in. "
- "Is GMock thread safety enabled?");
- p = p->next_;
- }
- p->next_ = next_;
- return false;
- }
-
- private:
- mutable linked_ptr_internal const* next_;
-};
-
-template <typename T>
-class linked_ptr {
- public:
- typedef T element_type;
-
- // Take over ownership of a raw pointer. This should happen as soon as
- // possible after the object is created.
- explicit linked_ptr(T* ptr = NULL) { capture(ptr); }
- ~linked_ptr() { depart(); }
-
- // Copy an existing linked_ptr<>, adding ourselves to the list of references.
- template <typename U> linked_ptr(linked_ptr<U> const& ptr) { copy(&ptr); }
- linked_ptr(linked_ptr const& ptr) { // NOLINT
- assert(&ptr != this);
- copy(&ptr);
- }
-
- // Assignment releases the old value and acquires the new.
- template <typename U> linked_ptr& operator=(linked_ptr<U> const& ptr) {
- depart();
- copy(&ptr);
- return *this;
- }
-
- linked_ptr& operator=(linked_ptr const& ptr) {
- if (&ptr != this) {
- depart();
- copy(&ptr);
- }
- return *this;
- }
-
- // Smart pointer members.
- void reset(T* ptr = NULL) {
- depart();
- capture(ptr);
- }
- T* get() const { return value_; }
- T* operator->() const { return value_; }
- T& operator*() const { return *value_; }
-
- bool operator==(T* p) const { return value_ == p; }
- bool operator!=(T* p) const { return value_ != p; }
- template <typename U>
- bool operator==(linked_ptr<U> const& ptr) const {
- return value_ == ptr.get();
- }
- template <typename U>
- bool operator!=(linked_ptr<U> const& ptr) const {
- return value_ != ptr.get();
- }
-
- private:
- template <typename U>
- friend class linked_ptr;
-
- T* value_;
- linked_ptr_internal link_;
-
- void depart() {
- if (link_.depart()) delete value_;
- }
-
- void capture(T* ptr) {
- value_ = ptr;
- link_.join_new();
- }
-
- template <typename U> void copy(linked_ptr<U> const* ptr) {
- value_ = ptr->get();
- if (value_)
- link_.join(&ptr->link_);
- else
- link_.join_new();
- }
-};
-
-template<typename T> inline
-bool operator==(T* ptr, const linked_ptr<T>& x) {
- return ptr == x.get();
-}
-
-template<typename T> inline
-bool operator!=(T* ptr, const linked_ptr<T>& x) {
- return ptr != x.get();
-}
-
-// A function to convert T* into linked_ptr<T>
-// Doing e.g. make_linked_ptr(new FooBarBaz<type>(arg)) is a shorter notation
-// for linked_ptr<FooBarBaz<type> >(new FooBarBaz<type>(arg))
-template <typename T>
-linked_ptr<T> make_linked_ptr(T* ptr) {
- return linked_ptr<T>(ptr);
-}
-
-} // namespace internal
-} // namespace testing
-
-#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_
diff --git a/extern/gtest/include/gtest/internal/gtest-param-util-generated.h b/extern/gtest/include/gtest/internal/gtest-param-util-generated.h
deleted file mode 100644
index 4d1d81d20ff..00000000000
--- a/extern/gtest/include/gtest/internal/gtest-param-util-generated.h
+++ /dev/null
@@ -1,5146 +0,0 @@
-// This file was GENERATED by command:
-// pump.py gtest-param-util-generated.h.pump
-// DO NOT EDIT BY HAND!!!
-
-// Copyright 2008 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.
-//
-// Author: vladl@google.com (Vlad Losev)
-
-// Type and function utilities for implementing parameterized tests.
-// This file is generated by a SCRIPT. DO NOT EDIT BY HAND!
-//
-// Currently Google Test supports at most 50 arguments in Values,
-// and at most 10 arguments in Combine. Please contact
-// googletestframework@googlegroups.com if you need more.
-// Please note that the number of arguments to Combine is limited
-// by the maximum arity of the implementation of tuple which is
-// currently set at 10.
-
-#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_
-#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_
-
-// scripts/fuse_gtest.py depends on gtest's own header being #included
-// *unconditionally*. Therefore these #includes cannot be moved
-// inside #if GTEST_HAS_PARAM_TEST.
-#include "gtest/internal/gtest-param-util.h"
-#include "gtest/internal/gtest-port.h"
-
-#if GTEST_HAS_PARAM_TEST
-
-namespace testing {
-
-// Forward declarations of ValuesIn(), which is implemented in
-// include/gtest/gtest-param-test.h.
-template <typename ForwardIterator>
-internal::ParamGenerator<
- typename ::testing::internal::IteratorTraits<ForwardIterator>::value_type>
-ValuesIn(ForwardIterator begin, ForwardIterator end);
-
-template <typename T, size_t N>
-internal::ParamGenerator<T> ValuesIn(const T (&array)[N]);
-
-template <class Container>
-internal::ParamGenerator<typename Container::value_type> ValuesIn(
- const Container& container);
-
-namespace internal {
-
-// Used in the Values() function to provide polymorphic capabilities.
-template <typename T1>
-class ValueArray1 {
- public:
- explicit ValueArray1(T1 v1) : v1_(v1) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- const T array[] = {static_cast<T>(v1_)};
- return ValuesIn(array);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray1& other);
-
- const T1 v1_;
-};
-
-template <typename T1, typename T2>
-class ValueArray2 {
- public:
- ValueArray2(T1 v1, T2 v2) : v1_(v1), v2_(v2) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_)};
- return ValuesIn(array);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray2& other);
-
- const T1 v1_;
- const T2 v2_;
-};
-
-template <typename T1, typename T2, typename T3>
-class ValueArray3 {
- public:
- ValueArray3(T1 v1, T2 v2, T3 v3) : v1_(v1), v2_(v2), v3_(v3) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
- static_cast<T>(v3_)};
- return ValuesIn(array);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray3& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4>
-class ValueArray4 {
- public:
- ValueArray4(T1 v1, T2 v2, T3 v3, T4 v4) : v1_(v1), v2_(v2), v3_(v3),
- v4_(v4) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
- static_cast<T>(v3_), static_cast<T>(v4_)};
- return ValuesIn(array);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray4& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5>
-class ValueArray5 {
- public:
- ValueArray5(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5) : v1_(v1), v2_(v2), v3_(v3),
- v4_(v4), v5_(v5) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- 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);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray5& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
- const T5 v5_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6>
-class ValueArray6 {
- public:
- ValueArray6(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6) : v1_(v1), v2_(v2),
- v3_(v3), v4_(v4), v5_(v5), v6_(v6) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- 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);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray6& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
- const T5 v5_;
- const T6 v6_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7>
-class ValueArray7 {
- public:
- ValueArray7(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7) : v1_(v1),
- v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- 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);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray7& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
- const T5 v5_;
- const T6 v6_;
- const T7 v7_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8>
-class ValueArray8 {
- public:
- ValueArray8(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7,
- T8 v8) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
- v8_(v8) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- 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);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray8& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
- const T5 v5_;
- const T6 v6_;
- const T7 v7_;
- const T8 v8_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9>
-class ValueArray9 {
- public:
- ValueArray9(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8,
- T9 v9) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
- v8_(v8), v9_(v9) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- 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);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray9& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
- const T5 v5_;
- const T6 v6_;
- const T7 v7_;
- const T8 v8_;
- const T9 v9_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10>
-class ValueArray10 {
- public:
- ValueArray10(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
- v8_(v8), v9_(v9), v10_(v10) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- 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);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray10& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
- const T5 v5_;
- const T6 v6_;
- const T7 v7_;
- const T8 v8_;
- const T9 v9_;
- const T10 v10_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11>
-class ValueArray11 {
- public:
- ValueArray11(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6),
- v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- 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);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray11& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
- const T5 v5_;
- const T6 v6_;
- const T7 v7_;
- const T8 v8_;
- const T9 v9_;
- const T10 v10_;
- const T11 v11_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12>
-class ValueArray12 {
- public:
- ValueArray12(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5),
- v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- 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);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray12& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
- const T5 v5_;
- const T6 v6_;
- const T7 v7_;
- const T8 v8_;
- const T9 v9_;
- const T10 v10_;
- const T11 v11_;
- const T12 v12_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13>
-class ValueArray13 {
- public:
- ValueArray13(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13) : v1_(v1), v2_(v2), v3_(v3), v4_(v4),
- v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11),
- v12_(v12), v13_(v13) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- 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);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray13& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
- const T5 v5_;
- const T6 v6_;
- const T7 v7_;
- const T8 v8_;
- const T9 v9_;
- const T10 v10_;
- const T11 v11_;
- const T12 v12_;
- const T13 v13_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14>
-class ValueArray14 {
- public:
- ValueArray14(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13, T14 v14) : v1_(v1), v2_(v2), v3_(v3),
- v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
- v11_(v11), v12_(v12), v13_(v13), v14_(v14) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- 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);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray14& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
- const T5 v5_;
- const T6 v6_;
- const T7 v7_;
- const T8 v8_;
- const T9 v9_;
- const T10 v10_;
- const T11 v11_;
- const T12 v12_;
- const T13 v13_;
- const T14 v14_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15>
-class ValueArray15 {
- public:
- ValueArray15(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15) : v1_(v1), v2_(v2),
- v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
- v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- 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);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray15& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
- const T5 v5_;
- const T6 v6_;
- const T7 v7_;
- const T8 v8_;
- const T9 v9_;
- const T10 v10_;
- const T11 v11_;
- const T12 v12_;
- const T13 v13_;
- const T14 v14_;
- const T15 v15_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16>
-class ValueArray16 {
- public:
- ValueArray16(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16) : v1_(v1),
- v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9),
- v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15),
- v16_(v16) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- 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);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray16& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
- const T5 v5_;
- const T6 v6_;
- const T7 v7_;
- const T8 v8_;
- const T9 v9_;
- const T10 v10_;
- const T11 v11_;
- const T12 v12_;
- const T13 v13_;
- const T14 v14_;
- const T15 v15_;
- const T16 v16_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17>
-class ValueArray17 {
- public:
- ValueArray17(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16,
- T17 v17) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
- v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
- v15_(v15), v16_(v16), v17_(v17) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- 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);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray17& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
- const T5 v5_;
- const T6 v6_;
- const T7 v7_;
- const T8 v8_;
- const T9 v9_;
- const T10 v10_;
- const T11 v11_;
- const T12 v12_;
- const T13 v13_;
- const T14 v14_;
- const T15 v15_;
- const T16 v16_;
- const T17 v17_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18>
-class ValueArray18 {
- public:
- ValueArray18(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
- T18 v18) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
- v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
- v15_(v15), v16_(v16), v17_(v17), v18_(v18) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- 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);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray18& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
- const T5 v5_;
- const T6 v6_;
- const T7 v7_;
- const T8 v8_;
- const T9 v9_;
- const T10 v10_;
- const T11 v11_;
- const T12 v12_;
- const T13 v13_;
- const T14 v14_;
- const T15 v15_;
- const T16 v16_;
- const T17 v17_;
- const T18 v18_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19>
-class ValueArray19 {
- public:
- ValueArray19(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
- T18 v18, T19 v19) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6),
- v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13),
- v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- 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);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray19& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
- const T5 v5_;
- const T6 v6_;
- const T7 v7_;
- const T8 v8_;
- const T9 v9_;
- const T10 v10_;
- const T11 v11_;
- const T12 v12_;
- const T13 v13_;
- const T14 v14_;
- const T15 v15_;
- const T16 v16_;
- const T17 v17_;
- const T18 v18_;
- const T19 v19_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20>
-class ValueArray20 {
- public:
- ValueArray20(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
- T18 v18, T19 v19, T20 v20) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5),
- v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12),
- v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18),
- v19_(v19), v20_(v20) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- 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);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray20& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
- const T5 v5_;
- const T6 v6_;
- const T7 v7_;
- const T8 v8_;
- const T9 v9_;
- const T10 v10_;
- const T11 v11_;
- const T12 v12_;
- const T13 v13_;
- const T14 v14_;
- const T15 v15_;
- const T16 v16_;
- const T17 v17_;
- const T18 v18_;
- const T19 v19_;
- const T20 v20_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21>
-class ValueArray21 {
- public:
- ValueArray21(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
- T18 v18, T19 v19, T20 v20, T21 v21) : v1_(v1), v2_(v2), v3_(v3), v4_(v4),
- v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11),
- v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17),
- v18_(v18), v19_(v19), v20_(v20), v21_(v21) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- 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);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray21& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
- const T5 v5_;
- const T6 v6_;
- const T7 v7_;
- const T8 v8_;
- const T9 v9_;
- const T10 v10_;
- const T11 v11_;
- const T12 v12_;
- const T13 v13_;
- const T14 v14_;
- const T15 v15_;
- const T16 v16_;
- const T17 v17_;
- const T18 v18_;
- const T19 v19_;
- const T20 v20_;
- const T21 v21_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22>
-class ValueArray22 {
- public:
- ValueArray22(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
- T18 v18, T19 v19, T20 v20, T21 v21, T22 v22) : v1_(v1), v2_(v2), v3_(v3),
- v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
- v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16),
- v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- 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);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray22& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
- const T5 v5_;
- const T6 v6_;
- const T7 v7_;
- const T8 v8_;
- const T9 v9_;
- const T10 v10_;
- const T11 v11_;
- const T12 v12_;
- const T13 v13_;
- const T14 v14_;
- const T15 v15_;
- const T16 v16_;
- const T17 v17_;
- const T18 v18_;
- const T19 v19_;
- const T20 v20_;
- const T21 v21_;
- const T22 v22_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23>
-class ValueArray23 {
- public:
- ValueArray23(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
- T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23) : v1_(v1), v2_(v2),
- v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
- v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16),
- v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22),
- v23_(v23) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- 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);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray23& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
- const T5 v5_;
- const T6 v6_;
- const T7 v7_;
- const T8 v8_;
- const T9 v9_;
- const T10 v10_;
- const T11 v11_;
- const T12 v12_;
- const T13 v13_;
- const T14 v14_;
- const T15 v15_;
- const T16 v16_;
- const T17 v17_;
- const T18 v18_;
- const T19 v19_;
- const T20 v20_;
- const T21 v21_;
- const T22 v22_;
- const T23 v23_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24>
-class ValueArray24 {
- public:
- ValueArray24(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
- T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24) : v1_(v1),
- v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9),
- v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15),
- v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21),
- v22_(v22), v23_(v23), v24_(v24) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- 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);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray24& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
- const T5 v5_;
- const T6 v6_;
- const T7 v7_;
- const T8 v8_;
- const T9 v9_;
- const T10 v10_;
- const T11 v11_;
- const T12 v12_;
- const T13 v13_;
- const T14 v14_;
- const T15 v15_;
- const T16 v16_;
- const T17 v17_;
- const T18 v18_;
- const T19 v19_;
- const T20 v20_;
- const T21 v21_;
- const T22 v22_;
- const T23 v23_;
- const T24 v24_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25>
-class ValueArray25 {
- public:
- ValueArray25(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
- T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24,
- T25 v25) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
- v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
- v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20),
- v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- 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);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray25& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
- const T5 v5_;
- const T6 v6_;
- const T7 v7_;
- const T8 v8_;
- const T9 v9_;
- const T10 v10_;
- const T11 v11_;
- const T12 v12_;
- const T13 v13_;
- const T14 v14_;
- const T15 v15_;
- const T16 v16_;
- const T17 v17_;
- const T18 v18_;
- const T19 v19_;
- const T20 v20_;
- const T21 v21_;
- const T22 v22_;
- const T23 v23_;
- const T24 v24_;
- const T25 v25_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26>
-class ValueArray26 {
- public:
- ValueArray26(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
- T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
- T26 v26) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
- v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
- v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20),
- v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- 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);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray26& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
- const T5 v5_;
- const T6 v6_;
- const T7 v7_;
- const T8 v8_;
- const T9 v9_;
- const T10 v10_;
- const T11 v11_;
- const T12 v12_;
- const T13 v13_;
- const T14 v14_;
- const T15 v15_;
- const T16 v16_;
- const T17 v17_;
- const T18 v18_;
- const T19 v19_;
- const T20 v20_;
- const T21 v21_;
- const T22 v22_;
- const T23 v23_;
- const T24 v24_;
- const T25 v25_;
- const T26 v26_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27>
-class ValueArray27 {
- public:
- ValueArray27(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
- T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
- T26 v26, T27 v27) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6),
- v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13),
- v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19),
- v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25),
- v26_(v26), v27_(v27) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- 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);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray27& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
- const T5 v5_;
- const T6 v6_;
- const T7 v7_;
- const T8 v8_;
- const T9 v9_;
- const T10 v10_;
- const T11 v11_;
- const T12 v12_;
- const T13 v13_;
- const T14 v14_;
- const T15 v15_;
- const T16 v16_;
- const T17 v17_;
- const T18 v18_;
- const T19 v19_;
- const T20 v20_;
- const T21 v21_;
- const T22 v22_;
- const T23 v23_;
- const T24 v24_;
- const T25 v25_;
- const T26 v26_;
- const T27 v27_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28>
-class ValueArray28 {
- public:
- ValueArray28(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
- T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
- T26 v26, T27 v27, T28 v28) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5),
- v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12),
- v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18),
- v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24),
- v25_(v25), v26_(v26), v27_(v27), v28_(v28) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- 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);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray28& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
- const T5 v5_;
- const T6 v6_;
- const T7 v7_;
- const T8 v8_;
- const T9 v9_;
- const T10 v10_;
- const T11 v11_;
- const T12 v12_;
- const T13 v13_;
- const T14 v14_;
- const T15 v15_;
- const T16 v16_;
- const T17 v17_;
- const T18 v18_;
- const T19 v19_;
- const T20 v20_;
- const T21 v21_;
- const T22 v22_;
- const T23 v23_;
- const T24 v24_;
- const T25 v25_;
- const T26 v26_;
- const T27 v27_;
- const T28 v28_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29>
-class ValueArray29 {
- public:
- ValueArray29(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
- T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
- T26 v26, T27 v27, T28 v28, T29 v29) : v1_(v1), v2_(v2), v3_(v3), v4_(v4),
- v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11),
- v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17),
- v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23),
- v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- 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);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray29& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
- const T5 v5_;
- const T6 v6_;
- const T7 v7_;
- const T8 v8_;
- const T9 v9_;
- const T10 v10_;
- const T11 v11_;
- const T12 v12_;
- const T13 v13_;
- const T14 v14_;
- const T15 v15_;
- const T16 v16_;
- const T17 v17_;
- const T18 v18_;
- const T19 v19_;
- const T20 v20_;
- const T21 v21_;
- const T22 v22_;
- const T23 v23_;
- const T24 v24_;
- const T25 v25_;
- const T26 v26_;
- const T27 v27_;
- const T28 v28_;
- const T29 v29_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30>
-class ValueArray30 {
- public:
- ValueArray30(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
- T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
- T26 v26, T27 v27, T28 v28, T29 v29, T30 v30) : v1_(v1), v2_(v2), v3_(v3),
- v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
- v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16),
- v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22),
- v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28),
- v29_(v29), v30_(v30) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- 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);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray30& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
- const T5 v5_;
- const T6 v6_;
- const T7 v7_;
- const T8 v8_;
- const T9 v9_;
- const T10 v10_;
- const T11 v11_;
- const T12 v12_;
- const T13 v13_;
- const T14 v14_;
- const T15 v15_;
- const T16 v16_;
- const T17 v17_;
- const T18 v18_;
- const T19 v19_;
- const T20 v20_;
- const T21 v21_;
- const T22 v22_;
- const T23 v23_;
- const T24 v24_;
- const T25 v25_;
- const T26 v26_;
- const T27 v27_;
- const T28 v28_;
- const T29 v29_;
- const T30 v30_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31>
-class ValueArray31 {
- public:
- ValueArray31(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
- T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
- T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31) : v1_(v1), v2_(v2),
- v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
- v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16),
- v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22),
- v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28),
- v29_(v29), v30_(v30), v31_(v31) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- 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);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray31& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
- const T5 v5_;
- const T6 v6_;
- const T7 v7_;
- const T8 v8_;
- const T9 v9_;
- const T10 v10_;
- const T11 v11_;
- const T12 v12_;
- const T13 v13_;
- const T14 v14_;
- const T15 v15_;
- const T16 v16_;
- const T17 v17_;
- const T18 v18_;
- const T19 v19_;
- const T20 v20_;
- const T21 v21_;
- const T22 v22_;
- const T23 v23_;
- const T24 v24_;
- const T25 v25_;
- const T26 v26_;
- const T27 v27_;
- const T28 v28_;
- const T29 v29_;
- const T30 v30_;
- const T31 v31_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32>
-class ValueArray32 {
- public:
- ValueArray32(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
- T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
- T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32) : v1_(v1),
- v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9),
- v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15),
- v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21),
- v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27),
- v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- 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);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray32& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
- const T5 v5_;
- const T6 v6_;
- const T7 v7_;
- const T8 v8_;
- const T9 v9_;
- const T10 v10_;
- const T11 v11_;
- const T12 v12_;
- const T13 v13_;
- const T14 v14_;
- const T15 v15_;
- const T16 v16_;
- const T17 v17_;
- const T18 v18_;
- const T19 v19_;
- const T20 v20_;
- const T21 v21_;
- const T22 v22_;
- const T23 v23_;
- const T24 v24_;
- const T25 v25_;
- const T26 v26_;
- const T27 v27_;
- const T28 v28_;
- const T29 v29_;
- const T30 v30_;
- const T31 v31_;
- const T32 v32_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33>
-class ValueArray33 {
- public:
- ValueArray33(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
- T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
- T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32,
- T33 v33) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
- v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
- v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20),
- v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26),
- v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32),
- v33_(v33) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- 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);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray33& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
- const T5 v5_;
- const T6 v6_;
- const T7 v7_;
- const T8 v8_;
- const T9 v9_;
- const T10 v10_;
- const T11 v11_;
- const T12 v12_;
- const T13 v13_;
- const T14 v14_;
- const T15 v15_;
- const T16 v16_;
- const T17 v17_;
- const T18 v18_;
- const T19 v19_;
- const T20 v20_;
- const T21 v21_;
- const T22 v22_;
- const T23 v23_;
- const T24 v24_;
- const T25 v25_;
- const T26 v26_;
- const T27 v27_;
- const T28 v28_;
- const T29 v29_;
- const T30 v30_;
- const T31 v31_;
- const T32 v32_;
- const T33 v33_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34>
-class ValueArray34 {
- public:
- ValueArray34(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
- T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
- T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
- T34 v34) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
- v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
- v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20),
- v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26),
- v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32),
- v33_(v33), v34_(v34) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- 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);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray34& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
- const T5 v5_;
- const T6 v6_;
- const T7 v7_;
- const T8 v8_;
- const T9 v9_;
- const T10 v10_;
- const T11 v11_;
- const T12 v12_;
- const T13 v13_;
- const T14 v14_;
- const T15 v15_;
- const T16 v16_;
- const T17 v17_;
- const T18 v18_;
- const T19 v19_;
- const T20 v20_;
- const T21 v21_;
- const T22 v22_;
- const T23 v23_;
- const T24 v24_;
- const T25 v25_;
- const T26 v26_;
- const T27 v27_;
- const T28 v28_;
- const T29 v29_;
- const T30 v30_;
- const T31 v31_;
- const T32 v32_;
- const T33 v33_;
- const T34 v34_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35>
-class ValueArray35 {
- public:
- ValueArray35(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
- T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
- T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
- T34 v34, T35 v35) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6),
- v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13),
- v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19),
- v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25),
- v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31),
- v32_(v32), v33_(v33), v34_(v34), v35_(v35) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- 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);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray35& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
- const T5 v5_;
- const T6 v6_;
- const T7 v7_;
- const T8 v8_;
- const T9 v9_;
- const T10 v10_;
- const T11 v11_;
- const T12 v12_;
- const T13 v13_;
- const T14 v14_;
- const T15 v15_;
- const T16 v16_;
- const T17 v17_;
- const T18 v18_;
- const T19 v19_;
- const T20 v20_;
- const T21 v21_;
- const T22 v22_;
- const T23 v23_;
- const T24 v24_;
- const T25 v25_;
- const T26 v26_;
- const T27 v27_;
- const T28 v28_;
- const T29 v29_;
- const T30 v30_;
- const T31 v31_;
- const T32 v32_;
- const T33 v33_;
- const T34 v34_;
- const T35 v35_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35,
- typename T36>
-class ValueArray36 {
- public:
- ValueArray36(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
- T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
- T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
- T34 v34, T35 v35, T36 v36) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5),
- v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12),
- v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18),
- v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24),
- v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30),
- v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- 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);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray36& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
- const T5 v5_;
- const T6 v6_;
- const T7 v7_;
- const T8 v8_;
- const T9 v9_;
- const T10 v10_;
- const T11 v11_;
- const T12 v12_;
- const T13 v13_;
- const T14 v14_;
- const T15 v15_;
- const T16 v16_;
- const T17 v17_;
- const T18 v18_;
- const T19 v19_;
- const T20 v20_;
- const T21 v21_;
- const T22 v22_;
- const T23 v23_;
- const T24 v24_;
- const T25 v25_;
- const T26 v26_;
- const T27 v27_;
- const T28 v28_;
- const T29 v29_;
- const T30 v30_;
- const T31 v31_;
- const T32 v32_;
- const T33 v33_;
- const T34 v34_;
- const T35 v35_;
- const T36 v36_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35,
- typename T36, typename T37>
-class ValueArray37 {
- public:
- ValueArray37(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
- T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
- T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
- T34 v34, T35 v35, T36 v36, T37 v37) : v1_(v1), v2_(v2), v3_(v3), v4_(v4),
- v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11),
- v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17),
- v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23),
- v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29),
- v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35),
- v36_(v36), v37_(v37) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- 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);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray37& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
- const T5 v5_;
- const T6 v6_;
- const T7 v7_;
- const T8 v8_;
- const T9 v9_;
- const T10 v10_;
- const T11 v11_;
- const T12 v12_;
- const T13 v13_;
- const T14 v14_;
- const T15 v15_;
- const T16 v16_;
- const T17 v17_;
- const T18 v18_;
- const T19 v19_;
- const T20 v20_;
- const T21 v21_;
- const T22 v22_;
- const T23 v23_;
- const T24 v24_;
- const T25 v25_;
- const T26 v26_;
- const T27 v27_;
- const T28 v28_;
- const T29 v29_;
- const T30 v30_;
- const T31 v31_;
- const T32 v32_;
- const T33 v33_;
- const T34 v34_;
- const T35 v35_;
- const T36 v36_;
- const T37 v37_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35,
- typename T36, typename T37, typename T38>
-class ValueArray38 {
- public:
- ValueArray38(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
- T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
- T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
- T34 v34, T35 v35, T36 v36, T37 v37, T38 v38) : v1_(v1), v2_(v2), v3_(v3),
- v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
- v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16),
- v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22),
- v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28),
- v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34),
- v35_(v35), v36_(v36), v37_(v37), v38_(v38) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- 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);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray38& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
- const T5 v5_;
- const T6 v6_;
- const T7 v7_;
- const T8 v8_;
- const T9 v9_;
- const T10 v10_;
- const T11 v11_;
- const T12 v12_;
- const T13 v13_;
- const T14 v14_;
- const T15 v15_;
- const T16 v16_;
- const T17 v17_;
- const T18 v18_;
- const T19 v19_;
- const T20 v20_;
- const T21 v21_;
- const T22 v22_;
- const T23 v23_;
- const T24 v24_;
- const T25 v25_;
- const T26 v26_;
- const T27 v27_;
- const T28 v28_;
- const T29 v29_;
- const T30 v30_;
- const T31 v31_;
- const T32 v32_;
- const T33 v33_;
- const T34 v34_;
- const T35 v35_;
- const T36 v36_;
- const T37 v37_;
- const T38 v38_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35,
- typename T36, typename T37, typename T38, typename T39>
-class ValueArray39 {
- public:
- ValueArray39(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
- T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
- T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
- T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39) : v1_(v1), v2_(v2),
- v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
- v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16),
- v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22),
- v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28),
- v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34),
- v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- 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);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray39& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
- const T5 v5_;
- const T6 v6_;
- const T7 v7_;
- const T8 v8_;
- const T9 v9_;
- const T10 v10_;
- const T11 v11_;
- const T12 v12_;
- const T13 v13_;
- const T14 v14_;
- const T15 v15_;
- const T16 v16_;
- const T17 v17_;
- const T18 v18_;
- const T19 v19_;
- const T20 v20_;
- const T21 v21_;
- const T22 v22_;
- const T23 v23_;
- const T24 v24_;
- const T25 v25_;
- const T26 v26_;
- const T27 v27_;
- const T28 v28_;
- const T29 v29_;
- const T30 v30_;
- const T31 v31_;
- const T32 v32_;
- const T33 v33_;
- const T34 v34_;
- const T35 v35_;
- const T36 v36_;
- const T37 v37_;
- const T38 v38_;
- const T39 v39_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35,
- typename T36, typename T37, typename T38, typename T39, typename T40>
-class ValueArray40 {
- public:
- ValueArray40(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
- T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
- T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
- T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40) : v1_(v1),
- v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9),
- v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15),
- v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21),
- v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27),
- v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33),
- v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39),
- v40_(v40) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- 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);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray40& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
- const T5 v5_;
- const T6 v6_;
- const T7 v7_;
- const T8 v8_;
- const T9 v9_;
- const T10 v10_;
- const T11 v11_;
- const T12 v12_;
- const T13 v13_;
- const T14 v14_;
- const T15 v15_;
- const T16 v16_;
- const T17 v17_;
- const T18 v18_;
- const T19 v19_;
- const T20 v20_;
- const T21 v21_;
- const T22 v22_;
- const T23 v23_;
- const T24 v24_;
- const T25 v25_;
- const T26 v26_;
- const T27 v27_;
- const T28 v28_;
- const T29 v29_;
- const T30 v30_;
- const T31 v31_;
- const T32 v32_;
- const T33 v33_;
- const T34 v34_;
- const T35 v35_;
- const T36 v36_;
- const T37 v37_;
- const T38 v38_;
- const T39 v39_;
- const T40 v40_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35,
- typename T36, typename T37, typename T38, typename T39, typename T40,
- typename T41>
-class ValueArray41 {
- public:
- ValueArray41(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
- T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
- T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
- T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40,
- T41 v41) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
- v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
- v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20),
- v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26),
- v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32),
- v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38),
- v39_(v39), v40_(v40), v41_(v41) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- 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);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray41& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
- const T5 v5_;
- const T6 v6_;
- const T7 v7_;
- const T8 v8_;
- const T9 v9_;
- const T10 v10_;
- const T11 v11_;
- const T12 v12_;
- const T13 v13_;
- const T14 v14_;
- const T15 v15_;
- const T16 v16_;
- const T17 v17_;
- const T18 v18_;
- const T19 v19_;
- const T20 v20_;
- const T21 v21_;
- const T22 v22_;
- const T23 v23_;
- const T24 v24_;
- const T25 v25_;
- const T26 v26_;
- const T27 v27_;
- const T28 v28_;
- const T29 v29_;
- const T30 v30_;
- const T31 v31_;
- const T32 v32_;
- const T33 v33_;
- const T34 v34_;
- const T35 v35_;
- const T36 v36_;
- const T37 v37_;
- const T38 v38_;
- const T39 v39_;
- const T40 v40_;
- const T41 v41_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35,
- typename T36, typename T37, typename T38, typename T39, typename T40,
- typename T41, typename T42>
-class ValueArray42 {
- public:
- ValueArray42(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
- T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
- T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
- T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
- T42 v42) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
- v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
- v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20),
- v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26),
- v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32),
- v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38),
- v39_(v39), v40_(v40), v41_(v41), v42_(v42) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- 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);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray42& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
- const T5 v5_;
- const T6 v6_;
- const T7 v7_;
- const T8 v8_;
- const T9 v9_;
- const T10 v10_;
- const T11 v11_;
- const T12 v12_;
- const T13 v13_;
- const T14 v14_;
- const T15 v15_;
- const T16 v16_;
- const T17 v17_;
- const T18 v18_;
- const T19 v19_;
- const T20 v20_;
- const T21 v21_;
- const T22 v22_;
- const T23 v23_;
- const T24 v24_;
- const T25 v25_;
- const T26 v26_;
- const T27 v27_;
- const T28 v28_;
- const T29 v29_;
- const T30 v30_;
- const T31 v31_;
- const T32 v32_;
- const T33 v33_;
- const T34 v34_;
- const T35 v35_;
- const T36 v36_;
- const T37 v37_;
- const T38 v38_;
- const T39 v39_;
- const T40 v40_;
- const T41 v41_;
- const T42 v42_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35,
- typename T36, typename T37, typename T38, typename T39, typename T40,
- typename T41, typename T42, typename T43>
-class ValueArray43 {
- public:
- ValueArray43(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
- T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
- T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
- T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
- T42 v42, T43 v43) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6),
- v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13),
- v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19),
- v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25),
- v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31),
- v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37),
- v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- 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);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray43& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
- const T5 v5_;
- const T6 v6_;
- const T7 v7_;
- const T8 v8_;
- const T9 v9_;
- const T10 v10_;
- const T11 v11_;
- const T12 v12_;
- const T13 v13_;
- const T14 v14_;
- const T15 v15_;
- const T16 v16_;
- const T17 v17_;
- const T18 v18_;
- const T19 v19_;
- const T20 v20_;
- const T21 v21_;
- const T22 v22_;
- const T23 v23_;
- const T24 v24_;
- const T25 v25_;
- const T26 v26_;
- const T27 v27_;
- const T28 v28_;
- const T29 v29_;
- const T30 v30_;
- const T31 v31_;
- const T32 v32_;
- const T33 v33_;
- const T34 v34_;
- const T35 v35_;
- const T36 v36_;
- const T37 v37_;
- const T38 v38_;
- const T39 v39_;
- const T40 v40_;
- const T41 v41_;
- const T42 v42_;
- const T43 v43_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35,
- typename T36, typename T37, typename T38, typename T39, typename T40,
- typename T41, typename T42, typename T43, typename T44>
-class ValueArray44 {
- public:
- ValueArray44(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
- T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
- T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
- T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
- T42 v42, T43 v43, T44 v44) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5),
- v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12),
- v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18),
- v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24),
- v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30),
- v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36),
- v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42),
- v43_(v43), v44_(v44) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- 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);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray44& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
- const T5 v5_;
- const T6 v6_;
- const T7 v7_;
- const T8 v8_;
- const T9 v9_;
- const T10 v10_;
- const T11 v11_;
- const T12 v12_;
- const T13 v13_;
- const T14 v14_;
- const T15 v15_;
- const T16 v16_;
- const T17 v17_;
- const T18 v18_;
- const T19 v19_;
- const T20 v20_;
- const T21 v21_;
- const T22 v22_;
- const T23 v23_;
- const T24 v24_;
- const T25 v25_;
- const T26 v26_;
- const T27 v27_;
- const T28 v28_;
- const T29 v29_;
- const T30 v30_;
- const T31 v31_;
- const T32 v32_;
- const T33 v33_;
- const T34 v34_;
- const T35 v35_;
- const T36 v36_;
- const T37 v37_;
- const T38 v38_;
- const T39 v39_;
- const T40 v40_;
- const T41 v41_;
- const T42 v42_;
- const T43 v43_;
- const T44 v44_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35,
- typename T36, typename T37, typename T38, typename T39, typename T40,
- typename T41, typename T42, typename T43, typename T44, typename T45>
-class ValueArray45 {
- public:
- ValueArray45(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
- T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
- T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
- T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
- T42 v42, T43 v43, T44 v44, T45 v45) : v1_(v1), v2_(v2), v3_(v3), v4_(v4),
- v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11),
- v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17),
- v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23),
- v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29),
- v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35),
- v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41),
- v42_(v42), v43_(v43), v44_(v44), v45_(v45) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- 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);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray45& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
- const T5 v5_;
- const T6 v6_;
- const T7 v7_;
- const T8 v8_;
- const T9 v9_;
- const T10 v10_;
- const T11 v11_;
- const T12 v12_;
- const T13 v13_;
- const T14 v14_;
- const T15 v15_;
- const T16 v16_;
- const T17 v17_;
- const T18 v18_;
- const T19 v19_;
- const T20 v20_;
- const T21 v21_;
- const T22 v22_;
- const T23 v23_;
- const T24 v24_;
- const T25 v25_;
- const T26 v26_;
- const T27 v27_;
- const T28 v28_;
- const T29 v29_;
- const T30 v30_;
- const T31 v31_;
- const T32 v32_;
- const T33 v33_;
- const T34 v34_;
- const T35 v35_;
- const T36 v36_;
- const T37 v37_;
- const T38 v38_;
- const T39 v39_;
- const T40 v40_;
- const T41 v41_;
- const T42 v42_;
- const T43 v43_;
- const T44 v44_;
- const T45 v45_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35,
- typename T36, typename T37, typename T38, typename T39, typename T40,
- typename T41, typename T42, typename T43, typename T44, typename T45,
- typename T46>
-class ValueArray46 {
- public:
- ValueArray46(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
- T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
- T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
- T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
- T42 v42, T43 v43, T44 v44, T45 v45, T46 v46) : v1_(v1), v2_(v2), v3_(v3),
- v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
- v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16),
- v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22),
- v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28),
- v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34),
- v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40),
- v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45), v46_(v46) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- 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);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray46& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
- const T5 v5_;
- const T6 v6_;
- const T7 v7_;
- const T8 v8_;
- const T9 v9_;
- const T10 v10_;
- const T11 v11_;
- const T12 v12_;
- const T13 v13_;
- const T14 v14_;
- const T15 v15_;
- const T16 v16_;
- const T17 v17_;
- const T18 v18_;
- const T19 v19_;
- const T20 v20_;
- const T21 v21_;
- const T22 v22_;
- const T23 v23_;
- const T24 v24_;
- const T25 v25_;
- const T26 v26_;
- const T27 v27_;
- const T28 v28_;
- const T29 v29_;
- const T30 v30_;
- const T31 v31_;
- const T32 v32_;
- const T33 v33_;
- const T34 v34_;
- const T35 v35_;
- const T36 v36_;
- const T37 v37_;
- const T38 v38_;
- const T39 v39_;
- const T40 v40_;
- const T41 v41_;
- const T42 v42_;
- const T43 v43_;
- const T44 v44_;
- const T45 v45_;
- const T46 v46_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35,
- typename T36, typename T37, typename T38, typename T39, typename T40,
- typename T41, typename T42, typename T43, typename T44, typename T45,
- typename T46, typename T47>
-class ValueArray47 {
- public:
- ValueArray47(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
- T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
- T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
- T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
- T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47) : v1_(v1), v2_(v2),
- v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
- v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16),
- v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22),
- v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28),
- v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34),
- v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40),
- v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45), v46_(v46),
- v47_(v47) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- 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);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray47& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
- const T5 v5_;
- const T6 v6_;
- const T7 v7_;
- const T8 v8_;
- const T9 v9_;
- const T10 v10_;
- const T11 v11_;
- const T12 v12_;
- const T13 v13_;
- const T14 v14_;
- const T15 v15_;
- const T16 v16_;
- const T17 v17_;
- const T18 v18_;
- const T19 v19_;
- const T20 v20_;
- const T21 v21_;
- const T22 v22_;
- const T23 v23_;
- const T24 v24_;
- const T25 v25_;
- const T26 v26_;
- const T27 v27_;
- const T28 v28_;
- const T29 v29_;
- const T30 v30_;
- const T31 v31_;
- const T32 v32_;
- const T33 v33_;
- const T34 v34_;
- const T35 v35_;
- const T36 v36_;
- const T37 v37_;
- const T38 v38_;
- const T39 v39_;
- const T40 v40_;
- const T41 v41_;
- const T42 v42_;
- const T43 v43_;
- const T44 v44_;
- const T45 v45_;
- const T46 v46_;
- const T47 v47_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35,
- typename T36, typename T37, typename T38, typename T39, typename T40,
- typename T41, typename T42, typename T43, typename T44, typename T45,
- typename T46, typename T47, typename T48>
-class ValueArray48 {
- public:
- ValueArray48(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
- T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
- T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
- T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
- T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48) : v1_(v1),
- v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9),
- v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15),
- v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21),
- v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27),
- v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33),
- v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39),
- v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45),
- v46_(v46), v47_(v47), v48_(v48) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- 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);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray48& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
- const T5 v5_;
- const T6 v6_;
- const T7 v7_;
- const T8 v8_;
- const T9 v9_;
- const T10 v10_;
- const T11 v11_;
- const T12 v12_;
- const T13 v13_;
- const T14 v14_;
- const T15 v15_;
- const T16 v16_;
- const T17 v17_;
- const T18 v18_;
- const T19 v19_;
- const T20 v20_;
- const T21 v21_;
- const T22 v22_;
- const T23 v23_;
- const T24 v24_;
- const T25 v25_;
- const T26 v26_;
- const T27 v27_;
- const T28 v28_;
- const T29 v29_;
- const T30 v30_;
- const T31 v31_;
- const T32 v32_;
- const T33 v33_;
- const T34 v34_;
- const T35 v35_;
- const T36 v36_;
- const T37 v37_;
- const T38 v38_;
- const T39 v39_;
- const T40 v40_;
- const T41 v41_;
- const T42 v42_;
- const T43 v43_;
- const T44 v44_;
- const T45 v45_;
- const T46 v46_;
- const T47 v47_;
- const T48 v48_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35,
- typename T36, typename T37, typename T38, typename T39, typename T40,
- typename T41, typename T42, typename T43, typename T44, typename T45,
- typename T46, typename T47, typename T48, typename T49>
-class ValueArray49 {
- public:
- ValueArray49(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
- T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
- T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
- T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
- T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48,
- T49 v49) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
- v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
- v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20),
- v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26),
- v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32),
- v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38),
- v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44),
- v45_(v45), v46_(v46), v47_(v47), v48_(v48), v49_(v49) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- 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);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray49& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
- const T5 v5_;
- const T6 v6_;
- const T7 v7_;
- const T8 v8_;
- const T9 v9_;
- const T10 v10_;
- const T11 v11_;
- const T12 v12_;
- const T13 v13_;
- const T14 v14_;
- const T15 v15_;
- const T16 v16_;
- const T17 v17_;
- const T18 v18_;
- const T19 v19_;
- const T20 v20_;
- const T21 v21_;
- const T22 v22_;
- const T23 v23_;
- const T24 v24_;
- const T25 v25_;
- const T26 v26_;
- const T27 v27_;
- const T28 v28_;
- const T29 v29_;
- const T30 v30_;
- const T31 v31_;
- const T32 v32_;
- const T33 v33_;
- const T34 v34_;
- const T35 v35_;
- const T36 v36_;
- const T37 v37_;
- const T38 v38_;
- const T39 v39_;
- const T40 v40_;
- const T41 v41_;
- const T42 v42_;
- const T43 v43_;
- const T44 v44_;
- const T45 v45_;
- const T46 v46_;
- const T47 v47_;
- const T48 v48_;
- const T49 v49_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35,
- typename T36, typename T37, typename T38, typename T39, typename T40,
- typename T41, typename T42, typename T43, typename T44, typename T45,
- typename T46, typename T47, typename T48, typename T49, typename T50>
-class ValueArray50 {
- public:
- ValueArray50(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
- T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
- T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
- T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
- T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48, T49 v49,
- T50 v50) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
- v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
- v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20),
- v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26),
- v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32),
- v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38),
- v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44),
- v45_(v45), v46_(v46), v47_(v47), v48_(v48), v49_(v49), v50_(v50) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- 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);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray50& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
- const T5 v5_;
- const T6 v6_;
- const T7 v7_;
- const T8 v8_;
- const T9 v9_;
- const T10 v10_;
- const T11 v11_;
- const T12 v12_;
- const T13 v13_;
- const T14 v14_;
- const T15 v15_;
- const T16 v16_;
- const T17 v17_;
- const T18 v18_;
- const T19 v19_;
- const T20 v20_;
- const T21 v21_;
- const T22 v22_;
- const T23 v23_;
- const T24 v24_;
- const T25 v25_;
- const T26 v26_;
- const T27 v27_;
- const T28 v28_;
- const T29 v29_;
- const T30 v30_;
- const T31 v31_;
- const T32 v32_;
- const T33 v33_;
- const T34 v34_;
- const T35 v35_;
- const T36 v36_;
- const T37 v37_;
- const T38 v38_;
- const T39 v39_;
- const T40 v40_;
- const T41 v41_;
- const T42 v42_;
- const T43 v43_;
- const T44 v44_;
- const T45 v45_;
- const T46 v46_;
- const T47 v47_;
- const T48 v48_;
- const T49 v49_;
- const T50 v50_;
-};
-
-# if GTEST_HAS_COMBINE
-// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
-//
-// Generates values from the Cartesian product of values produced
-// by the argument generators.
-//
-template <typename T1, typename T2>
-class CartesianProductGenerator2
- : public ParamGeneratorInterface< ::testing::tuple<T1, T2> > {
- public:
- typedef ::testing::tuple<T1, T2> ParamType;
-
- CartesianProductGenerator2(const ParamGenerator<T1>& g1,
- const ParamGenerator<T2>& g2)
- : g1_(g1), g2_(g2) {}
- virtual ~CartesianProductGenerator2() {}
-
- virtual ParamIteratorInterface<ParamType>* Begin() const {
- return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin());
- }
- virtual ParamIteratorInterface<ParamType>* End() const {
- return new Iterator(this, g1_, g1_.end(), g2_, g2_.end());
- }
-
- private:
- class Iterator : public ParamIteratorInterface<ParamType> {
- public:
- Iterator(const ParamGeneratorInterface<ParamType>* base,
- const ParamGenerator<T1>& g1,
- const typename ParamGenerator<T1>::iterator& current1,
- const ParamGenerator<T2>& g2,
- const typename ParamGenerator<T2>::iterator& current2)
- : base_(base),
- begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
- begin2_(g2.begin()), end2_(g2.end()), current2_(current2) {
- ComputeCurrentValue();
- }
- virtual ~Iterator() {}
-
- virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
- return base_;
- }
- // Advance should not be called on beyond-of-range iterators
- // so no component iterators must be beyond end of range, either.
- virtual void Advance() {
- assert(!AtEnd());
- ++current2_;
- if (current2_ == end2_) {
- current2_ = begin2_;
- ++current1_;
- }
- ComputeCurrentValue();
- }
- virtual ParamIteratorInterface<ParamType>* Clone() const {
- return new Iterator(*this);
- }
- virtual const ParamType* Current() const { return &current_value_; }
- virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
- // Having the same base generator guarantees that the other
- // iterator is of the same type and we can downcast.
- GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
- << "The program attempted to compare iterators "
- << "from different generators." << std::endl;
- const Iterator* typed_other =
- CheckedDowncastToActualType<const Iterator>(&other);
- // We must report iterators equal if they both point beyond their
- // respective ranges. That can happen in a variety of fashions,
- // so we have to consult AtEnd().
- return (AtEnd() && typed_other->AtEnd()) ||
- (
- current1_ == typed_other->current1_ &&
- current2_ == typed_other->current2_);
- }
-
- private:
- Iterator(const Iterator& other)
- : base_(other.base_),
- begin1_(other.begin1_),
- end1_(other.end1_),
- current1_(other.current1_),
- begin2_(other.begin2_),
- end2_(other.end2_),
- current2_(other.current2_) {
- ComputeCurrentValue();
- }
-
- void ComputeCurrentValue() {
- if (!AtEnd())
- current_value_ = ParamType(*current1_, *current2_);
- }
- bool AtEnd() const {
- // We must report iterator past the end of the range when either of the
- // component iterators has reached the end of its range.
- return
- current1_ == end1_ ||
- current2_ == end2_;
- }
-
- // No implementation - assignment is unsupported.
- void operator=(const Iterator& other);
-
- const ParamGeneratorInterface<ParamType>* const base_;
- // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
- // current[i]_ is the actual traversing iterator.
- const typename ParamGenerator<T1>::iterator begin1_;
- const typename ParamGenerator<T1>::iterator end1_;
- typename ParamGenerator<T1>::iterator current1_;
- const typename ParamGenerator<T2>::iterator begin2_;
- const typename ParamGenerator<T2>::iterator end2_;
- typename ParamGenerator<T2>::iterator current2_;
- ParamType current_value_;
- }; // class CartesianProductGenerator2::Iterator
-
- // No implementation - assignment is unsupported.
- void operator=(const CartesianProductGenerator2& other);
-
- const ParamGenerator<T1> g1_;
- const ParamGenerator<T2> g2_;
-}; // class CartesianProductGenerator2
-
-
-template <typename T1, typename T2, typename T3>
-class CartesianProductGenerator3
- : public ParamGeneratorInterface< ::testing::tuple<T1, T2, T3> > {
- public:
- typedef ::testing::tuple<T1, T2, T3> ParamType;
-
- CartesianProductGenerator3(const ParamGenerator<T1>& g1,
- const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3)
- : g1_(g1), g2_(g2), g3_(g3) {}
- virtual ~CartesianProductGenerator3() {}
-
- virtual ParamIteratorInterface<ParamType>* Begin() const {
- return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,
- g3_.begin());
- }
- virtual ParamIteratorInterface<ParamType>* End() const {
- return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end());
- }
-
- private:
- class Iterator : public ParamIteratorInterface<ParamType> {
- public:
- Iterator(const ParamGeneratorInterface<ParamType>* base,
- const ParamGenerator<T1>& g1,
- const typename ParamGenerator<T1>::iterator& current1,
- const ParamGenerator<T2>& g2,
- const typename ParamGenerator<T2>::iterator& current2,
- const ParamGenerator<T3>& g3,
- const typename ParamGenerator<T3>::iterator& current3)
- : base_(base),
- begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
- begin2_(g2.begin()), end2_(g2.end()), current2_(current2),
- begin3_(g3.begin()), end3_(g3.end()), current3_(current3) {
- ComputeCurrentValue();
- }
- virtual ~Iterator() {}
-
- virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
- return base_;
- }
- // Advance should not be called on beyond-of-range iterators
- // so no component iterators must be beyond end of range, either.
- virtual void Advance() {
- assert(!AtEnd());
- ++current3_;
- if (current3_ == end3_) {
- current3_ = begin3_;
- ++current2_;
- }
- if (current2_ == end2_) {
- current2_ = begin2_;
- ++current1_;
- }
- ComputeCurrentValue();
- }
- virtual ParamIteratorInterface<ParamType>* Clone() const {
- return new Iterator(*this);
- }
- virtual const ParamType* Current() const { return &current_value_; }
- virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
- // Having the same base generator guarantees that the other
- // iterator is of the same type and we can downcast.
- GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
- << "The program attempted to compare iterators "
- << "from different generators." << std::endl;
- const Iterator* typed_other =
- CheckedDowncastToActualType<const Iterator>(&other);
- // We must report iterators equal if they both point beyond their
- // respective ranges. That can happen in a variety of fashions,
- // so we have to consult AtEnd().
- return (AtEnd() && typed_other->AtEnd()) ||
- (
- current1_ == typed_other->current1_ &&
- current2_ == typed_other->current2_ &&
- current3_ == typed_other->current3_);
- }
-
- private:
- Iterator(const Iterator& other)
- : base_(other.base_),
- begin1_(other.begin1_),
- end1_(other.end1_),
- current1_(other.current1_),
- begin2_(other.begin2_),
- end2_(other.end2_),
- current2_(other.current2_),
- begin3_(other.begin3_),
- end3_(other.end3_),
- current3_(other.current3_) {
- ComputeCurrentValue();
- }
-
- void ComputeCurrentValue() {
- if (!AtEnd())
- current_value_ = ParamType(*current1_, *current2_, *current3_);
- }
- bool AtEnd() const {
- // We must report iterator past the end of the range when either of the
- // component iterators has reached the end of its range.
- return
- current1_ == end1_ ||
- current2_ == end2_ ||
- current3_ == end3_;
- }
-
- // No implementation - assignment is unsupported.
- void operator=(const Iterator& other);
-
- const ParamGeneratorInterface<ParamType>* const base_;
- // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
- // current[i]_ is the actual traversing iterator.
- const typename ParamGenerator<T1>::iterator begin1_;
- const typename ParamGenerator<T1>::iterator end1_;
- typename ParamGenerator<T1>::iterator current1_;
- const typename ParamGenerator<T2>::iterator begin2_;
- const typename ParamGenerator<T2>::iterator end2_;
- typename ParamGenerator<T2>::iterator current2_;
- const typename ParamGenerator<T3>::iterator begin3_;
- const typename ParamGenerator<T3>::iterator end3_;
- typename ParamGenerator<T3>::iterator current3_;
- ParamType current_value_;
- }; // class CartesianProductGenerator3::Iterator
-
- // No implementation - assignment is unsupported.
- void operator=(const CartesianProductGenerator3& other);
-
- const ParamGenerator<T1> g1_;
- const ParamGenerator<T2> g2_;
- const ParamGenerator<T3> g3_;
-}; // class CartesianProductGenerator3
-
-
-template <typename T1, typename T2, typename T3, typename T4>
-class CartesianProductGenerator4
- : public ParamGeneratorInterface< ::testing::tuple<T1, T2, T3, T4> > {
- public:
- typedef ::testing::tuple<T1, T2, T3, T4> ParamType;
-
- CartesianProductGenerator4(const ParamGenerator<T1>& g1,
- const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,
- const ParamGenerator<T4>& g4)
- : g1_(g1), g2_(g2), g3_(g3), g4_(g4) {}
- virtual ~CartesianProductGenerator4() {}
-
- virtual ParamIteratorInterface<ParamType>* Begin() const {
- return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,
- g3_.begin(), g4_, g4_.begin());
- }
- virtual ParamIteratorInterface<ParamType>* End() const {
- return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(),
- g4_, g4_.end());
- }
-
- private:
- class Iterator : public ParamIteratorInterface<ParamType> {
- public:
- Iterator(const ParamGeneratorInterface<ParamType>* base,
- const ParamGenerator<T1>& g1,
- const typename ParamGenerator<T1>::iterator& current1,
- const ParamGenerator<T2>& g2,
- const typename ParamGenerator<T2>::iterator& current2,
- const ParamGenerator<T3>& g3,
- const typename ParamGenerator<T3>::iterator& current3,
- const ParamGenerator<T4>& g4,
- const typename ParamGenerator<T4>::iterator& current4)
- : base_(base),
- begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
- begin2_(g2.begin()), end2_(g2.end()), current2_(current2),
- begin3_(g3.begin()), end3_(g3.end()), current3_(current3),
- begin4_(g4.begin()), end4_(g4.end()), current4_(current4) {
- ComputeCurrentValue();
- }
- virtual ~Iterator() {}
-
- virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
- return base_;
- }
- // Advance should not be called on beyond-of-range iterators
- // so no component iterators must be beyond end of range, either.
- virtual void Advance() {
- assert(!AtEnd());
- ++current4_;
- if (current4_ == end4_) {
- current4_ = begin4_;
- ++current3_;
- }
- if (current3_ == end3_) {
- current3_ = begin3_;
- ++current2_;
- }
- if (current2_ == end2_) {
- current2_ = begin2_;
- ++current1_;
- }
- ComputeCurrentValue();
- }
- virtual ParamIteratorInterface<ParamType>* Clone() const {
- return new Iterator(*this);
- }
- virtual const ParamType* Current() const { return &current_value_; }
- virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
- // Having the same base generator guarantees that the other
- // iterator is of the same type and we can downcast.
- GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
- << "The program attempted to compare iterators "
- << "from different generators." << std::endl;
- const Iterator* typed_other =
- CheckedDowncastToActualType<const Iterator>(&other);
- // We must report iterators equal if they both point beyond their
- // respective ranges. That can happen in a variety of fashions,
- // so we have to consult AtEnd().
- return (AtEnd() && typed_other->AtEnd()) ||
- (
- current1_ == typed_other->current1_ &&
- current2_ == typed_other->current2_ &&
- current3_ == typed_other->current3_ &&
- current4_ == typed_other->current4_);
- }
-
- private:
- Iterator(const Iterator& other)
- : base_(other.base_),
- begin1_(other.begin1_),
- end1_(other.end1_),
- current1_(other.current1_),
- begin2_(other.begin2_),
- end2_(other.end2_),
- current2_(other.current2_),
- begin3_(other.begin3_),
- end3_(other.end3_),
- current3_(other.current3_),
- begin4_(other.begin4_),
- end4_(other.end4_),
- current4_(other.current4_) {
- ComputeCurrentValue();
- }
-
- void ComputeCurrentValue() {
- if (!AtEnd())
- current_value_ = ParamType(*current1_, *current2_, *current3_,
- *current4_);
- }
- bool AtEnd() const {
- // We must report iterator past the end of the range when either of the
- // component iterators has reached the end of its range.
- return
- current1_ == end1_ ||
- current2_ == end2_ ||
- current3_ == end3_ ||
- current4_ == end4_;
- }
-
- // No implementation - assignment is unsupported.
- void operator=(const Iterator& other);
-
- const ParamGeneratorInterface<ParamType>* const base_;
- // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
- // current[i]_ is the actual traversing iterator.
- const typename ParamGenerator<T1>::iterator begin1_;
- const typename ParamGenerator<T1>::iterator end1_;
- typename ParamGenerator<T1>::iterator current1_;
- const typename ParamGenerator<T2>::iterator begin2_;
- const typename ParamGenerator<T2>::iterator end2_;
- typename ParamGenerator<T2>::iterator current2_;
- const typename ParamGenerator<T3>::iterator begin3_;
- const typename ParamGenerator<T3>::iterator end3_;
- typename ParamGenerator<T3>::iterator current3_;
- const typename ParamGenerator<T4>::iterator begin4_;
- const typename ParamGenerator<T4>::iterator end4_;
- typename ParamGenerator<T4>::iterator current4_;
- ParamType current_value_;
- }; // class CartesianProductGenerator4::Iterator
-
- // No implementation - assignment is unsupported.
- void operator=(const CartesianProductGenerator4& other);
-
- const ParamGenerator<T1> g1_;
- const ParamGenerator<T2> g2_;
- const ParamGenerator<T3> g3_;
- const ParamGenerator<T4> g4_;
-}; // class CartesianProductGenerator4
-
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5>
-class CartesianProductGenerator5
- : public ParamGeneratorInterface< ::testing::tuple<T1, T2, T3, T4, T5> > {
- public:
- typedef ::testing::tuple<T1, T2, T3, T4, T5> ParamType;
-
- CartesianProductGenerator5(const ParamGenerator<T1>& g1,
- const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,
- const ParamGenerator<T4>& g4, const ParamGenerator<T5>& g5)
- : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5) {}
- virtual ~CartesianProductGenerator5() {}
-
- virtual ParamIteratorInterface<ParamType>* Begin() const {
- return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,
- g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin());
- }
- virtual ParamIteratorInterface<ParamType>* End() const {
- return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(),
- g4_, g4_.end(), g5_, g5_.end());
- }
-
- private:
- class Iterator : public ParamIteratorInterface<ParamType> {
- public:
- Iterator(const ParamGeneratorInterface<ParamType>* base,
- const ParamGenerator<T1>& g1,
- const typename ParamGenerator<T1>::iterator& current1,
- const ParamGenerator<T2>& g2,
- const typename ParamGenerator<T2>::iterator& current2,
- const ParamGenerator<T3>& g3,
- const typename ParamGenerator<T3>::iterator& current3,
- const ParamGenerator<T4>& g4,
- const typename ParamGenerator<T4>::iterator& current4,
- const ParamGenerator<T5>& g5,
- const typename ParamGenerator<T5>::iterator& current5)
- : base_(base),
- begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
- begin2_(g2.begin()), end2_(g2.end()), current2_(current2),
- begin3_(g3.begin()), end3_(g3.end()), current3_(current3),
- begin4_(g4.begin()), end4_(g4.end()), current4_(current4),
- begin5_(g5.begin()), end5_(g5.end()), current5_(current5) {
- ComputeCurrentValue();
- }
- virtual ~Iterator() {}
-
- virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
- return base_;
- }
- // Advance should not be called on beyond-of-range iterators
- // so no component iterators must be beyond end of range, either.
- virtual void Advance() {
- assert(!AtEnd());
- ++current5_;
- if (current5_ == end5_) {
- current5_ = begin5_;
- ++current4_;
- }
- if (current4_ == end4_) {
- current4_ = begin4_;
- ++current3_;
- }
- if (current3_ == end3_) {
- current3_ = begin3_;
- ++current2_;
- }
- if (current2_ == end2_) {
- current2_ = begin2_;
- ++current1_;
- }
- ComputeCurrentValue();
- }
- virtual ParamIteratorInterface<ParamType>* Clone() const {
- return new Iterator(*this);
- }
- virtual const ParamType* Current() const { return &current_value_; }
- virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
- // Having the same base generator guarantees that the other
- // iterator is of the same type and we can downcast.
- GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
- << "The program attempted to compare iterators "
- << "from different generators." << std::endl;
- const Iterator* typed_other =
- CheckedDowncastToActualType<const Iterator>(&other);
- // We must report iterators equal if they both point beyond their
- // respective ranges. That can happen in a variety of fashions,
- // so we have to consult AtEnd().
- return (AtEnd() && typed_other->AtEnd()) ||
- (
- current1_ == typed_other->current1_ &&
- current2_ == typed_other->current2_ &&
- current3_ == typed_other->current3_ &&
- current4_ == typed_other->current4_ &&
- current5_ == typed_other->current5_);
- }
-
- private:
- Iterator(const Iterator& other)
- : base_(other.base_),
- begin1_(other.begin1_),
- end1_(other.end1_),
- current1_(other.current1_),
- begin2_(other.begin2_),
- end2_(other.end2_),
- current2_(other.current2_),
- begin3_(other.begin3_),
- end3_(other.end3_),
- current3_(other.current3_),
- begin4_(other.begin4_),
- end4_(other.end4_),
- current4_(other.current4_),
- begin5_(other.begin5_),
- end5_(other.end5_),
- current5_(other.current5_) {
- ComputeCurrentValue();
- }
-
- void ComputeCurrentValue() {
- if (!AtEnd())
- current_value_ = ParamType(*current1_, *current2_, *current3_,
- *current4_, *current5_);
- }
- bool AtEnd() const {
- // We must report iterator past the end of the range when either of the
- // component iterators has reached the end of its range.
- return
- current1_ == end1_ ||
- current2_ == end2_ ||
- current3_ == end3_ ||
- current4_ == end4_ ||
- current5_ == end5_;
- }
-
- // No implementation - assignment is unsupported.
- void operator=(const Iterator& other);
-
- const ParamGeneratorInterface<ParamType>* const base_;
- // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
- // current[i]_ is the actual traversing iterator.
- const typename ParamGenerator<T1>::iterator begin1_;
- const typename ParamGenerator<T1>::iterator end1_;
- typename ParamGenerator<T1>::iterator current1_;
- const typename ParamGenerator<T2>::iterator begin2_;
- const typename ParamGenerator<T2>::iterator end2_;
- typename ParamGenerator<T2>::iterator current2_;
- const typename ParamGenerator<T3>::iterator begin3_;
- const typename ParamGenerator<T3>::iterator end3_;
- typename ParamGenerator<T3>::iterator current3_;
- const typename ParamGenerator<T4>::iterator begin4_;
- const typename ParamGenerator<T4>::iterator end4_;
- typename ParamGenerator<T4>::iterator current4_;
- const typename ParamGenerator<T5>::iterator begin5_;
- const typename ParamGenerator<T5>::iterator end5_;
- typename ParamGenerator<T5>::iterator current5_;
- ParamType current_value_;
- }; // class CartesianProductGenerator5::Iterator
-
- // No implementation - assignment is unsupported.
- void operator=(const CartesianProductGenerator5& other);
-
- const ParamGenerator<T1> g1_;
- const ParamGenerator<T2> g2_;
- const ParamGenerator<T3> g3_;
- const ParamGenerator<T4> g4_;
- const ParamGenerator<T5> g5_;
-}; // class CartesianProductGenerator5
-
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6>
-class CartesianProductGenerator6
- : public ParamGeneratorInterface< ::testing::tuple<T1, T2, T3, T4, T5,
- T6> > {
- public:
- typedef ::testing::tuple<T1, T2, T3, T4, T5, T6> ParamType;
-
- CartesianProductGenerator6(const ParamGenerator<T1>& g1,
- const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,
- const ParamGenerator<T4>& g4, const ParamGenerator<T5>& g5,
- const ParamGenerator<T6>& g6)
- : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6) {}
- virtual ~CartesianProductGenerator6() {}
-
- virtual ParamIteratorInterface<ParamType>* Begin() const {
- return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,
- g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin());
- }
- virtual ParamIteratorInterface<ParamType>* End() const {
- return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(),
- g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end());
- }
-
- private:
- class Iterator : public ParamIteratorInterface<ParamType> {
- public:
- Iterator(const ParamGeneratorInterface<ParamType>* base,
- const ParamGenerator<T1>& g1,
- const typename ParamGenerator<T1>::iterator& current1,
- const ParamGenerator<T2>& g2,
- const typename ParamGenerator<T2>::iterator& current2,
- const ParamGenerator<T3>& g3,
- const typename ParamGenerator<T3>::iterator& current3,
- const ParamGenerator<T4>& g4,
- const typename ParamGenerator<T4>::iterator& current4,
- const ParamGenerator<T5>& g5,
- const typename ParamGenerator<T5>::iterator& current5,
- const ParamGenerator<T6>& g6,
- const typename ParamGenerator<T6>::iterator& current6)
- : base_(base),
- begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
- begin2_(g2.begin()), end2_(g2.end()), current2_(current2),
- begin3_(g3.begin()), end3_(g3.end()), current3_(current3),
- begin4_(g4.begin()), end4_(g4.end()), current4_(current4),
- begin5_(g5.begin()), end5_(g5.end()), current5_(current5),
- begin6_(g6.begin()), end6_(g6.end()), current6_(current6) {
- ComputeCurrentValue();
- }
- virtual ~Iterator() {}
-
- virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
- return base_;
- }
- // Advance should not be called on beyond-of-range iterators
- // so no component iterators must be beyond end of range, either.
- virtual void Advance() {
- assert(!AtEnd());
- ++current6_;
- if (current6_ == end6_) {
- current6_ = begin6_;
- ++current5_;
- }
- if (current5_ == end5_) {
- current5_ = begin5_;
- ++current4_;
- }
- if (current4_ == end4_) {
- current4_ = begin4_;
- ++current3_;
- }
- if (current3_ == end3_) {
- current3_ = begin3_;
- ++current2_;
- }
- if (current2_ == end2_) {
- current2_ = begin2_;
- ++current1_;
- }
- ComputeCurrentValue();
- }
- virtual ParamIteratorInterface<ParamType>* Clone() const {
- return new Iterator(*this);
- }
- virtual const ParamType* Current() const { return &current_value_; }
- virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
- // Having the same base generator guarantees that the other
- // iterator is of the same type and we can downcast.
- GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
- << "The program attempted to compare iterators "
- << "from different generators." << std::endl;
- const Iterator* typed_other =
- CheckedDowncastToActualType<const Iterator>(&other);
- // We must report iterators equal if they both point beyond their
- // respective ranges. That can happen in a variety of fashions,
- // so we have to consult AtEnd().
- return (AtEnd() && typed_other->AtEnd()) ||
- (
- current1_ == typed_other->current1_ &&
- current2_ == typed_other->current2_ &&
- current3_ == typed_other->current3_ &&
- current4_ == typed_other->current4_ &&
- current5_ == typed_other->current5_ &&
- current6_ == typed_other->current6_);
- }
-
- private:
- Iterator(const Iterator& other)
- : base_(other.base_),
- begin1_(other.begin1_),
- end1_(other.end1_),
- current1_(other.current1_),
- begin2_(other.begin2_),
- end2_(other.end2_),
- current2_(other.current2_),
- begin3_(other.begin3_),
- end3_(other.end3_),
- current3_(other.current3_),
- begin4_(other.begin4_),
- end4_(other.end4_),
- current4_(other.current4_),
- begin5_(other.begin5_),
- end5_(other.end5_),
- current5_(other.current5_),
- begin6_(other.begin6_),
- end6_(other.end6_),
- current6_(other.current6_) {
- ComputeCurrentValue();
- }
-
- void ComputeCurrentValue() {
- if (!AtEnd())
- current_value_ = ParamType(*current1_, *current2_, *current3_,
- *current4_, *current5_, *current6_);
- }
- bool AtEnd() const {
- // We must report iterator past the end of the range when either of the
- // component iterators has reached the end of its range.
- return
- current1_ == end1_ ||
- current2_ == end2_ ||
- current3_ == end3_ ||
- current4_ == end4_ ||
- current5_ == end5_ ||
- current6_ == end6_;
- }
-
- // No implementation - assignment is unsupported.
- void operator=(const Iterator& other);
-
- const ParamGeneratorInterface<ParamType>* const base_;
- // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
- // current[i]_ is the actual traversing iterator.
- const typename ParamGenerator<T1>::iterator begin1_;
- const typename ParamGenerator<T1>::iterator end1_;
- typename ParamGenerator<T1>::iterator current1_;
- const typename ParamGenerator<T2>::iterator begin2_;
- const typename ParamGenerator<T2>::iterator end2_;
- typename ParamGenerator<T2>::iterator current2_;
- const typename ParamGenerator<T3>::iterator begin3_;
- const typename ParamGenerator<T3>::iterator end3_;
- typename ParamGenerator<T3>::iterator current3_;
- const typename ParamGenerator<T4>::iterator begin4_;
- const typename ParamGenerator<T4>::iterator end4_;
- typename ParamGenerator<T4>::iterator current4_;
- const typename ParamGenerator<T5>::iterator begin5_;
- const typename ParamGenerator<T5>::iterator end5_;
- typename ParamGenerator<T5>::iterator current5_;
- const typename ParamGenerator<T6>::iterator begin6_;
- const typename ParamGenerator<T6>::iterator end6_;
- typename ParamGenerator<T6>::iterator current6_;
- ParamType current_value_;
- }; // class CartesianProductGenerator6::Iterator
-
- // No implementation - assignment is unsupported.
- void operator=(const CartesianProductGenerator6& other);
-
- const ParamGenerator<T1> g1_;
- const ParamGenerator<T2> g2_;
- const ParamGenerator<T3> g3_;
- const ParamGenerator<T4> g4_;
- const ParamGenerator<T5> g5_;
- const ParamGenerator<T6> g6_;
-}; // class CartesianProductGenerator6
-
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7>
-class CartesianProductGenerator7
- : public ParamGeneratorInterface< ::testing::tuple<T1, T2, T3, T4, T5, T6,
- T7> > {
- public:
- typedef ::testing::tuple<T1, T2, T3, T4, T5, T6, T7> ParamType;
-
- CartesianProductGenerator7(const ParamGenerator<T1>& g1,
- const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,
- const ParamGenerator<T4>& g4, const ParamGenerator<T5>& g5,
- const ParamGenerator<T6>& g6, const ParamGenerator<T7>& g7)
- : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7) {}
- virtual ~CartesianProductGenerator7() {}
-
- virtual ParamIteratorInterface<ParamType>* Begin() const {
- return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,
- g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_,
- g7_.begin());
- }
- virtual ParamIteratorInterface<ParamType>* End() const {
- return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(),
- g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end());
- }
-
- private:
- class Iterator : public ParamIteratorInterface<ParamType> {
- public:
- Iterator(const ParamGeneratorInterface<ParamType>* base,
- const ParamGenerator<T1>& g1,
- const typename ParamGenerator<T1>::iterator& current1,
- const ParamGenerator<T2>& g2,
- const typename ParamGenerator<T2>::iterator& current2,
- const ParamGenerator<T3>& g3,
- const typename ParamGenerator<T3>::iterator& current3,
- const ParamGenerator<T4>& g4,
- const typename ParamGenerator<T4>::iterator& current4,
- const ParamGenerator<T5>& g5,
- const typename ParamGenerator<T5>::iterator& current5,
- const ParamGenerator<T6>& g6,
- const typename ParamGenerator<T6>::iterator& current6,
- const ParamGenerator<T7>& g7,
- const typename ParamGenerator<T7>::iterator& current7)
- : base_(base),
- begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
- begin2_(g2.begin()), end2_(g2.end()), current2_(current2),
- begin3_(g3.begin()), end3_(g3.end()), current3_(current3),
- begin4_(g4.begin()), end4_(g4.end()), current4_(current4),
- begin5_(g5.begin()), end5_(g5.end()), current5_(current5),
- begin6_(g6.begin()), end6_(g6.end()), current6_(current6),
- begin7_(g7.begin()), end7_(g7.end()), current7_(current7) {
- ComputeCurrentValue();
- }
- virtual ~Iterator() {}
-
- virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
- return base_;
- }
- // Advance should not be called on beyond-of-range iterators
- // so no component iterators must be beyond end of range, either.
- virtual void Advance() {
- assert(!AtEnd());
- ++current7_;
- if (current7_ == end7_) {
- current7_ = begin7_;
- ++current6_;
- }
- if (current6_ == end6_) {
- current6_ = begin6_;
- ++current5_;
- }
- if (current5_ == end5_) {
- current5_ = begin5_;
- ++current4_;
- }
- if (current4_ == end4_) {
- current4_ = begin4_;
- ++current3_;
- }
- if (current3_ == end3_) {
- current3_ = begin3_;
- ++current2_;
- }
- if (current2_ == end2_) {
- current2_ = begin2_;
- ++current1_;
- }
- ComputeCurrentValue();
- }
- virtual ParamIteratorInterface<ParamType>* Clone() const {
- return new Iterator(*this);
- }
- virtual const ParamType* Current() const { return &current_value_; }
- virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
- // Having the same base generator guarantees that the other
- // iterator is of the same type and we can downcast.
- GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
- << "The program attempted to compare iterators "
- << "from different generators." << std::endl;
- const Iterator* typed_other =
- CheckedDowncastToActualType<const Iterator>(&other);
- // We must report iterators equal if they both point beyond their
- // respective ranges. That can happen in a variety of fashions,
- // so we have to consult AtEnd().
- return (AtEnd() && typed_other->AtEnd()) ||
- (
- current1_ == typed_other->current1_ &&
- current2_ == typed_other->current2_ &&
- current3_ == typed_other->current3_ &&
- current4_ == typed_other->current4_ &&
- current5_ == typed_other->current5_ &&
- current6_ == typed_other->current6_ &&
- current7_ == typed_other->current7_);
- }
-
- private:
- Iterator(const Iterator& other)
- : base_(other.base_),
- begin1_(other.begin1_),
- end1_(other.end1_),
- current1_(other.current1_),
- begin2_(other.begin2_),
- end2_(other.end2_),
- current2_(other.current2_),
- begin3_(other.begin3_),
- end3_(other.end3_),
- current3_(other.current3_),
- begin4_(other.begin4_),
- end4_(other.end4_),
- current4_(other.current4_),
- begin5_(other.begin5_),
- end5_(other.end5_),
- current5_(other.current5_),
- begin6_(other.begin6_),
- end6_(other.end6_),
- current6_(other.current6_),
- begin7_(other.begin7_),
- end7_(other.end7_),
- current7_(other.current7_) {
- ComputeCurrentValue();
- }
-
- void ComputeCurrentValue() {
- if (!AtEnd())
- current_value_ = ParamType(*current1_, *current2_, *current3_,
- *current4_, *current5_, *current6_, *current7_);
- }
- bool AtEnd() const {
- // We must report iterator past the end of the range when either of the
- // component iterators has reached the end of its range.
- return
- current1_ == end1_ ||
- current2_ == end2_ ||
- current3_ == end3_ ||
- current4_ == end4_ ||
- current5_ == end5_ ||
- current6_ == end6_ ||
- current7_ == end7_;
- }
-
- // No implementation - assignment is unsupported.
- void operator=(const Iterator& other);
-
- const ParamGeneratorInterface<ParamType>* const base_;
- // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
- // current[i]_ is the actual traversing iterator.
- const typename ParamGenerator<T1>::iterator begin1_;
- const typename ParamGenerator<T1>::iterator end1_;
- typename ParamGenerator<T1>::iterator current1_;
- const typename ParamGenerator<T2>::iterator begin2_;
- const typename ParamGenerator<T2>::iterator end2_;
- typename ParamGenerator<T2>::iterator current2_;
- const typename ParamGenerator<T3>::iterator begin3_;
- const typename ParamGenerator<T3>::iterator end3_;
- typename ParamGenerator<T3>::iterator current3_;
- const typename ParamGenerator<T4>::iterator begin4_;
- const typename ParamGenerator<T4>::iterator end4_;
- typename ParamGenerator<T4>::iterator current4_;
- const typename ParamGenerator<T5>::iterator begin5_;
- const typename ParamGenerator<T5>::iterator end5_;
- typename ParamGenerator<T5>::iterator current5_;
- const typename ParamGenerator<T6>::iterator begin6_;
- const typename ParamGenerator<T6>::iterator end6_;
- typename ParamGenerator<T6>::iterator current6_;
- const typename ParamGenerator<T7>::iterator begin7_;
- const typename ParamGenerator<T7>::iterator end7_;
- typename ParamGenerator<T7>::iterator current7_;
- ParamType current_value_;
- }; // class CartesianProductGenerator7::Iterator
-
- // No implementation - assignment is unsupported.
- void operator=(const CartesianProductGenerator7& other);
-
- const ParamGenerator<T1> g1_;
- const ParamGenerator<T2> g2_;
- const ParamGenerator<T3> g3_;
- const ParamGenerator<T4> g4_;
- const ParamGenerator<T5> g5_;
- const ParamGenerator<T6> g6_;
- const ParamGenerator<T7> g7_;
-}; // class CartesianProductGenerator7
-
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8>
-class CartesianProductGenerator8
- : public ParamGeneratorInterface< ::testing::tuple<T1, T2, T3, T4, T5, T6,
- T7, T8> > {
- public:
- typedef ::testing::tuple<T1, T2, T3, T4, T5, T6, T7, T8> ParamType;
-
- CartesianProductGenerator8(const ParamGenerator<T1>& g1,
- const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,
- const ParamGenerator<T4>& g4, const ParamGenerator<T5>& g5,
- const ParamGenerator<T6>& g6, const ParamGenerator<T7>& g7,
- const ParamGenerator<T8>& g8)
- : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7),
- g8_(g8) {}
- virtual ~CartesianProductGenerator8() {}
-
- virtual ParamIteratorInterface<ParamType>* Begin() const {
- return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,
- g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_,
- g7_.begin(), g8_, g8_.begin());
- }
- virtual ParamIteratorInterface<ParamType>* End() const {
- return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(),
- g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end(), g8_,
- g8_.end());
- }
-
- private:
- class Iterator : public ParamIteratorInterface<ParamType> {
- public:
- Iterator(const ParamGeneratorInterface<ParamType>* base,
- const ParamGenerator<T1>& g1,
- const typename ParamGenerator<T1>::iterator& current1,
- const ParamGenerator<T2>& g2,
- const typename ParamGenerator<T2>::iterator& current2,
- const ParamGenerator<T3>& g3,
- const typename ParamGenerator<T3>::iterator& current3,
- const ParamGenerator<T4>& g4,
- const typename ParamGenerator<T4>::iterator& current4,
- const ParamGenerator<T5>& g5,
- const typename ParamGenerator<T5>::iterator& current5,
- const ParamGenerator<T6>& g6,
- const typename ParamGenerator<T6>::iterator& current6,
- const ParamGenerator<T7>& g7,
- const typename ParamGenerator<T7>::iterator& current7,
- const ParamGenerator<T8>& g8,
- const typename ParamGenerator<T8>::iterator& current8)
- : base_(base),
- begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
- begin2_(g2.begin()), end2_(g2.end()), current2_(current2),
- begin3_(g3.begin()), end3_(g3.end()), current3_(current3),
- begin4_(g4.begin()), end4_(g4.end()), current4_(current4),
- begin5_(g5.begin()), end5_(g5.end()), current5_(current5),
- begin6_(g6.begin()), end6_(g6.end()), current6_(current6),
- begin7_(g7.begin()), end7_(g7.end()), current7_(current7),
- begin8_(g8.begin()), end8_(g8.end()), current8_(current8) {
- ComputeCurrentValue();
- }
- virtual ~Iterator() {}
-
- virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
- return base_;
- }
- // Advance should not be called on beyond-of-range iterators
- // so no component iterators must be beyond end of range, either.
- virtual void Advance() {
- assert(!AtEnd());
- ++current8_;
- if (current8_ == end8_) {
- current8_ = begin8_;
- ++current7_;
- }
- if (current7_ == end7_) {
- current7_ = begin7_;
- ++current6_;
- }
- if (current6_ == end6_) {
- current6_ = begin6_;
- ++current5_;
- }
- if (current5_ == end5_) {
- current5_ = begin5_;
- ++current4_;
- }
- if (current4_ == end4_) {
- current4_ = begin4_;
- ++current3_;
- }
- if (current3_ == end3_) {
- current3_ = begin3_;
- ++current2_;
- }
- if (current2_ == end2_) {
- current2_ = begin2_;
- ++current1_;
- }
- ComputeCurrentValue();
- }
- virtual ParamIteratorInterface<ParamType>* Clone() const {
- return new Iterator(*this);
- }
- virtual const ParamType* Current() const { return &current_value_; }
- virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
- // Having the same base generator guarantees that the other
- // iterator is of the same type and we can downcast.
- GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
- << "The program attempted to compare iterators "
- << "from different generators." << std::endl;
- const Iterator* typed_other =
- CheckedDowncastToActualType<const Iterator>(&other);
- // We must report iterators equal if they both point beyond their
- // respective ranges. That can happen in a variety of fashions,
- // so we have to consult AtEnd().
- return (AtEnd() && typed_other->AtEnd()) ||
- (
- current1_ == typed_other->current1_ &&
- current2_ == typed_other->current2_ &&
- current3_ == typed_other->current3_ &&
- current4_ == typed_other->current4_ &&
- current5_ == typed_other->current5_ &&
- current6_ == typed_other->current6_ &&
- current7_ == typed_other->current7_ &&
- current8_ == typed_other->current8_);
- }
-
- private:
- Iterator(const Iterator& other)
- : base_(other.base_),
- begin1_(other.begin1_),
- end1_(other.end1_),
- current1_(other.current1_),
- begin2_(other.begin2_),
- end2_(other.end2_),
- current2_(other.current2_),
- begin3_(other.begin3_),
- end3_(other.end3_),
- current3_(other.current3_),
- begin4_(other.begin4_),
- end4_(other.end4_),
- current4_(other.current4_),
- begin5_(other.begin5_),
- end5_(other.end5_),
- current5_(other.current5_),
- begin6_(other.begin6_),
- end6_(other.end6_),
- current6_(other.current6_),
- begin7_(other.begin7_),
- end7_(other.end7_),
- current7_(other.current7_),
- begin8_(other.begin8_),
- end8_(other.end8_),
- current8_(other.current8_) {
- ComputeCurrentValue();
- }
-
- void ComputeCurrentValue() {
- if (!AtEnd())
- current_value_ = ParamType(*current1_, *current2_, *current3_,
- *current4_, *current5_, *current6_, *current7_, *current8_);
- }
- bool AtEnd() const {
- // We must report iterator past the end of the range when either of the
- // component iterators has reached the end of its range.
- return
- current1_ == end1_ ||
- current2_ == end2_ ||
- current3_ == end3_ ||
- current4_ == end4_ ||
- current5_ == end5_ ||
- current6_ == end6_ ||
- current7_ == end7_ ||
- current8_ == end8_;
- }
-
- // No implementation - assignment is unsupported.
- void operator=(const Iterator& other);
-
- const ParamGeneratorInterface<ParamType>* const base_;
- // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
- // current[i]_ is the actual traversing iterator.
- const typename ParamGenerator<T1>::iterator begin1_;
- const typename ParamGenerator<T1>::iterator end1_;
- typename ParamGenerator<T1>::iterator current1_;
- const typename ParamGenerator<T2>::iterator begin2_;
- const typename ParamGenerator<T2>::iterator end2_;
- typename ParamGenerator<T2>::iterator current2_;
- const typename ParamGenerator<T3>::iterator begin3_;
- const typename ParamGenerator<T3>::iterator end3_;
- typename ParamGenerator<T3>::iterator current3_;
- const typename ParamGenerator<T4>::iterator begin4_;
- const typename ParamGenerator<T4>::iterator end4_;
- typename ParamGenerator<T4>::iterator current4_;
- const typename ParamGenerator<T5>::iterator begin5_;
- const typename ParamGenerator<T5>::iterator end5_;
- typename ParamGenerator<T5>::iterator current5_;
- const typename ParamGenerator<T6>::iterator begin6_;
- const typename ParamGenerator<T6>::iterator end6_;
- typename ParamGenerator<T6>::iterator current6_;
- const typename ParamGenerator<T7>::iterator begin7_;
- const typename ParamGenerator<T7>::iterator end7_;
- typename ParamGenerator<T7>::iterator current7_;
- const typename ParamGenerator<T8>::iterator begin8_;
- const typename ParamGenerator<T8>::iterator end8_;
- typename ParamGenerator<T8>::iterator current8_;
- ParamType current_value_;
- }; // class CartesianProductGenerator8::Iterator
-
- // No implementation - assignment is unsupported.
- void operator=(const CartesianProductGenerator8& other);
-
- const ParamGenerator<T1> g1_;
- const ParamGenerator<T2> g2_;
- const ParamGenerator<T3> g3_;
- const ParamGenerator<T4> g4_;
- const ParamGenerator<T5> g5_;
- const ParamGenerator<T6> g6_;
- const ParamGenerator<T7> g7_;
- const ParamGenerator<T8> g8_;
-}; // class CartesianProductGenerator8
-
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9>
-class CartesianProductGenerator9
- : public ParamGeneratorInterface< ::testing::tuple<T1, T2, T3, T4, T5, T6,
- T7, T8, T9> > {
- public:
- typedef ::testing::tuple<T1, T2, T3, T4, T5, T6, T7, T8, T9> ParamType;
-
- CartesianProductGenerator9(const ParamGenerator<T1>& g1,
- const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,
- const ParamGenerator<T4>& g4, const ParamGenerator<T5>& g5,
- const ParamGenerator<T6>& g6, const ParamGenerator<T7>& g7,
- const ParamGenerator<T8>& g8, const ParamGenerator<T9>& g9)
- : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8),
- g9_(g9) {}
- virtual ~CartesianProductGenerator9() {}
-
- virtual ParamIteratorInterface<ParamType>* Begin() const {
- return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,
- g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_,
- g7_.begin(), g8_, g8_.begin(), g9_, g9_.begin());
- }
- virtual ParamIteratorInterface<ParamType>* End() const {
- return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(),
- g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end(), g8_,
- g8_.end(), g9_, g9_.end());
- }
-
- private:
- class Iterator : public ParamIteratorInterface<ParamType> {
- public:
- Iterator(const ParamGeneratorInterface<ParamType>* base,
- const ParamGenerator<T1>& g1,
- const typename ParamGenerator<T1>::iterator& current1,
- const ParamGenerator<T2>& g2,
- const typename ParamGenerator<T2>::iterator& current2,
- const ParamGenerator<T3>& g3,
- const typename ParamGenerator<T3>::iterator& current3,
- const ParamGenerator<T4>& g4,
- const typename ParamGenerator<T4>::iterator& current4,
- const ParamGenerator<T5>& g5,
- const typename ParamGenerator<T5>::iterator& current5,
- const ParamGenerator<T6>& g6,
- const typename ParamGenerator<T6>::iterator& current6,
- const ParamGenerator<T7>& g7,
- const typename ParamGenerator<T7>::iterator& current7,
- const ParamGenerator<T8>& g8,
- const typename ParamGenerator<T8>::iterator& current8,
- const ParamGenerator<T9>& g9,
- const typename ParamGenerator<T9>::iterator& current9)
- : base_(base),
- begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
- begin2_(g2.begin()), end2_(g2.end()), current2_(current2),
- begin3_(g3.begin()), end3_(g3.end()), current3_(current3),
- begin4_(g4.begin()), end4_(g4.end()), current4_(current4),
- begin5_(g5.begin()), end5_(g5.end()), current5_(current5),
- begin6_(g6.begin()), end6_(g6.end()), current6_(current6),
- begin7_(g7.begin()), end7_(g7.end()), current7_(current7),
- begin8_(g8.begin()), end8_(g8.end()), current8_(current8),
- begin9_(g9.begin()), end9_(g9.end()), current9_(current9) {
- ComputeCurrentValue();
- }
- virtual ~Iterator() {}
-
- virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
- return base_;
- }
- // Advance should not be called on beyond-of-range iterators
- // so no component iterators must be beyond end of range, either.
- virtual void Advance() {
- assert(!AtEnd());
- ++current9_;
- if (current9_ == end9_) {
- current9_ = begin9_;
- ++current8_;
- }
- if (current8_ == end8_) {
- current8_ = begin8_;
- ++current7_;
- }
- if (current7_ == end7_) {
- current7_ = begin7_;
- ++current6_;
- }
- if (current6_ == end6_) {
- current6_ = begin6_;
- ++current5_;
- }
- if (current5_ == end5_) {
- current5_ = begin5_;
- ++current4_;
- }
- if (current4_ == end4_) {
- current4_ = begin4_;
- ++current3_;
- }
- if (current3_ == end3_) {
- current3_ = begin3_;
- ++current2_;
- }
- if (current2_ == end2_) {
- current2_ = begin2_;
- ++current1_;
- }
- ComputeCurrentValue();
- }
- virtual ParamIteratorInterface<ParamType>* Clone() const {
- return new Iterator(*this);
- }
- virtual const ParamType* Current() const { return &current_value_; }
- virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
- // Having the same base generator guarantees that the other
- // iterator is of the same type and we can downcast.
- GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
- << "The program attempted to compare iterators "
- << "from different generators." << std::endl;
- const Iterator* typed_other =
- CheckedDowncastToActualType<const Iterator>(&other);
- // We must report iterators equal if they both point beyond their
- // respective ranges. That can happen in a variety of fashions,
- // so we have to consult AtEnd().
- return (AtEnd() && typed_other->AtEnd()) ||
- (
- current1_ == typed_other->current1_ &&
- current2_ == typed_other->current2_ &&
- current3_ == typed_other->current3_ &&
- current4_ == typed_other->current4_ &&
- current5_ == typed_other->current5_ &&
- current6_ == typed_other->current6_ &&
- current7_ == typed_other->current7_ &&
- current8_ == typed_other->current8_ &&
- current9_ == typed_other->current9_);
- }
-
- private:
- Iterator(const Iterator& other)
- : base_(other.base_),
- begin1_(other.begin1_),
- end1_(other.end1_),
- current1_(other.current1_),
- begin2_(other.begin2_),
- end2_(other.end2_),
- current2_(other.current2_),
- begin3_(other.begin3_),
- end3_(other.end3_),
- current3_(other.current3_),
- begin4_(other.begin4_),
- end4_(other.end4_),
- current4_(other.current4_),
- begin5_(other.begin5_),
- end5_(other.end5_),
- current5_(other.current5_),
- begin6_(other.begin6_),
- end6_(other.end6_),
- current6_(other.current6_),
- begin7_(other.begin7_),
- end7_(other.end7_),
- current7_(other.current7_),
- begin8_(other.begin8_),
- end8_(other.end8_),
- current8_(other.current8_),
- begin9_(other.begin9_),
- end9_(other.end9_),
- current9_(other.current9_) {
- ComputeCurrentValue();
- }
-
- void ComputeCurrentValue() {
- if (!AtEnd())
- current_value_ = ParamType(*current1_, *current2_, *current3_,
- *current4_, *current5_, *current6_, *current7_, *current8_,
- *current9_);
- }
- bool AtEnd() const {
- // We must report iterator past the end of the range when either of the
- // component iterators has reached the end of its range.
- return
- current1_ == end1_ ||
- current2_ == end2_ ||
- current3_ == end3_ ||
- current4_ == end4_ ||
- current5_ == end5_ ||
- current6_ == end6_ ||
- current7_ == end7_ ||
- current8_ == end8_ ||
- current9_ == end9_;
- }
-
- // No implementation - assignment is unsupported.
- void operator=(const Iterator& other);
-
- const ParamGeneratorInterface<ParamType>* const base_;
- // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
- // current[i]_ is the actual traversing iterator.
- const typename ParamGenerator<T1>::iterator begin1_;
- const typename ParamGenerator<T1>::iterator end1_;
- typename ParamGenerator<T1>::iterator current1_;
- const typename ParamGenerator<T2>::iterator begin2_;
- const typename ParamGenerator<T2>::iterator end2_;
- typename ParamGenerator<T2>::iterator current2_;
- const typename ParamGenerator<T3>::iterator begin3_;
- const typename ParamGenerator<T3>::iterator end3_;
- typename ParamGenerator<T3>::iterator current3_;
- const typename ParamGenerator<T4>::iterator begin4_;
- const typename ParamGenerator<T4>::iterator end4_;
- typename ParamGenerator<T4>::iterator current4_;
- const typename ParamGenerator<T5>::iterator begin5_;
- const typename ParamGenerator<T5>::iterator end5_;
- typename ParamGenerator<T5>::iterator current5_;
- const typename ParamGenerator<T6>::iterator begin6_;
- const typename ParamGenerator<T6>::iterator end6_;
- typename ParamGenerator<T6>::iterator current6_;
- const typename ParamGenerator<T7>::iterator begin7_;
- const typename ParamGenerator<T7>::iterator end7_;
- typename ParamGenerator<T7>::iterator current7_;
- const typename ParamGenerator<T8>::iterator begin8_;
- const typename ParamGenerator<T8>::iterator end8_;
- typename ParamGenerator<T8>::iterator current8_;
- const typename ParamGenerator<T9>::iterator begin9_;
- const typename ParamGenerator<T9>::iterator end9_;
- typename ParamGenerator<T9>::iterator current9_;
- ParamType current_value_;
- }; // class CartesianProductGenerator9::Iterator
-
- // No implementation - assignment is unsupported.
- void operator=(const CartesianProductGenerator9& other);
-
- const ParamGenerator<T1> g1_;
- const ParamGenerator<T2> g2_;
- const ParamGenerator<T3> g3_;
- const ParamGenerator<T4> g4_;
- const ParamGenerator<T5> g5_;
- const ParamGenerator<T6> g6_;
- const ParamGenerator<T7> g7_;
- const ParamGenerator<T8> g8_;
- const ParamGenerator<T9> g9_;
-}; // class CartesianProductGenerator9
-
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10>
-class CartesianProductGenerator10
- : public ParamGeneratorInterface< ::testing::tuple<T1, T2, T3, T4, T5, T6,
- T7, T8, T9, T10> > {
- public:
- typedef ::testing::tuple<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> ParamType;
-
- CartesianProductGenerator10(const ParamGenerator<T1>& g1,
- const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,
- const ParamGenerator<T4>& g4, const ParamGenerator<T5>& g5,
- const ParamGenerator<T6>& g6, const ParamGenerator<T7>& g7,
- const ParamGenerator<T8>& g8, const ParamGenerator<T9>& g9,
- const ParamGenerator<T10>& g10)
- : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8),
- g9_(g9), g10_(g10) {}
- virtual ~CartesianProductGenerator10() {}
-
- virtual ParamIteratorInterface<ParamType>* Begin() const {
- return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,
- g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_,
- g7_.begin(), g8_, g8_.begin(), g9_, g9_.begin(), g10_, g10_.begin());
- }
- virtual ParamIteratorInterface<ParamType>* End() const {
- return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(),
- g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end(), g8_,
- g8_.end(), g9_, g9_.end(), g10_, g10_.end());
- }
-
- private:
- class Iterator : public ParamIteratorInterface<ParamType> {
- public:
- Iterator(const ParamGeneratorInterface<ParamType>* base,
- const ParamGenerator<T1>& g1,
- const typename ParamGenerator<T1>::iterator& current1,
- const ParamGenerator<T2>& g2,
- const typename ParamGenerator<T2>::iterator& current2,
- const ParamGenerator<T3>& g3,
- const typename ParamGenerator<T3>::iterator& current3,
- const ParamGenerator<T4>& g4,
- const typename ParamGenerator<T4>::iterator& current4,
- const ParamGenerator<T5>& g5,
- const typename ParamGenerator<T5>::iterator& current5,
- const ParamGenerator<T6>& g6,
- const typename ParamGenerator<T6>::iterator& current6,
- const ParamGenerator<T7>& g7,
- const typename ParamGenerator<T7>::iterator& current7,
- const ParamGenerator<T8>& g8,
- const typename ParamGenerator<T8>::iterator& current8,
- const ParamGenerator<T9>& g9,
- const typename ParamGenerator<T9>::iterator& current9,
- const ParamGenerator<T10>& g10,
- const typename ParamGenerator<T10>::iterator& current10)
- : base_(base),
- begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
- begin2_(g2.begin()), end2_(g2.end()), current2_(current2),
- begin3_(g3.begin()), end3_(g3.end()), current3_(current3),
- begin4_(g4.begin()), end4_(g4.end()), current4_(current4),
- begin5_(g5.begin()), end5_(g5.end()), current5_(current5),
- begin6_(g6.begin()), end6_(g6.end()), current6_(current6),
- begin7_(g7.begin()), end7_(g7.end()), current7_(current7),
- begin8_(g8.begin()), end8_(g8.end()), current8_(current8),
- begin9_(g9.begin()), end9_(g9.end()), current9_(current9),
- begin10_(g10.begin()), end10_(g10.end()), current10_(current10) {
- ComputeCurrentValue();
- }
- virtual ~Iterator() {}
-
- virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
- return base_;
- }
- // Advance should not be called on beyond-of-range iterators
- // so no component iterators must be beyond end of range, either.
- virtual void Advance() {
- assert(!AtEnd());
- ++current10_;
- if (current10_ == end10_) {
- current10_ = begin10_;
- ++current9_;
- }
- if (current9_ == end9_) {
- current9_ = begin9_;
- ++current8_;
- }
- if (current8_ == end8_) {
- current8_ = begin8_;
- ++current7_;
- }
- if (current7_ == end7_) {
- current7_ = begin7_;
- ++current6_;
- }
- if (current6_ == end6_) {
- current6_ = begin6_;
- ++current5_;
- }
- if (current5_ == end5_) {
- current5_ = begin5_;
- ++current4_;
- }
- if (current4_ == end4_) {
- current4_ = begin4_;
- ++current3_;
- }
- if (current3_ == end3_) {
- current3_ = begin3_;
- ++current2_;
- }
- if (current2_ == end2_) {
- current2_ = begin2_;
- ++current1_;
- }
- ComputeCurrentValue();
- }
- virtual ParamIteratorInterface<ParamType>* Clone() const {
- return new Iterator(*this);
- }
- virtual const ParamType* Current() const { return &current_value_; }
- virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
- // Having the same base generator guarantees that the other
- // iterator is of the same type and we can downcast.
- GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
- << "The program attempted to compare iterators "
- << "from different generators." << std::endl;
- const Iterator* typed_other =
- CheckedDowncastToActualType<const Iterator>(&other);
- // We must report iterators equal if they both point beyond their
- // respective ranges. That can happen in a variety of fashions,
- // so we have to consult AtEnd().
- return (AtEnd() && typed_other->AtEnd()) ||
- (
- current1_ == typed_other->current1_ &&
- current2_ == typed_other->current2_ &&
- current3_ == typed_other->current3_ &&
- current4_ == typed_other->current4_ &&
- current5_ == typed_other->current5_ &&
- current6_ == typed_other->current6_ &&
- current7_ == typed_other->current7_ &&
- current8_ == typed_other->current8_ &&
- current9_ == typed_other->current9_ &&
- current10_ == typed_other->current10_);
- }
-
- private:
- Iterator(const Iterator& other)
- : base_(other.base_),
- begin1_(other.begin1_),
- end1_(other.end1_),
- current1_(other.current1_),
- begin2_(other.begin2_),
- end2_(other.end2_),
- current2_(other.current2_),
- begin3_(other.begin3_),
- end3_(other.end3_),
- current3_(other.current3_),
- begin4_(other.begin4_),
- end4_(other.end4_),
- current4_(other.current4_),
- begin5_(other.begin5_),
- end5_(other.end5_),
- current5_(other.current5_),
- begin6_(other.begin6_),
- end6_(other.end6_),
- current6_(other.current6_),
- begin7_(other.begin7_),
- end7_(other.end7_),
- current7_(other.current7_),
- begin8_(other.begin8_),
- end8_(other.end8_),
- current8_(other.current8_),
- begin9_(other.begin9_),
- end9_(other.end9_),
- current9_(other.current9_),
- begin10_(other.begin10_),
- end10_(other.end10_),
- current10_(other.current10_) {
- ComputeCurrentValue();
- }
-
- void ComputeCurrentValue() {
- if (!AtEnd())
- current_value_ = ParamType(*current1_, *current2_, *current3_,
- *current4_, *current5_, *current6_, *current7_, *current8_,
- *current9_, *current10_);
- }
- bool AtEnd() const {
- // We must report iterator past the end of the range when either of the
- // component iterators has reached the end of its range.
- return
- current1_ == end1_ ||
- current2_ == end2_ ||
- current3_ == end3_ ||
- current4_ == end4_ ||
- current5_ == end5_ ||
- current6_ == end6_ ||
- current7_ == end7_ ||
- current8_ == end8_ ||
- current9_ == end9_ ||
- current10_ == end10_;
- }
-
- // No implementation - assignment is unsupported.
- void operator=(const Iterator& other);
-
- const ParamGeneratorInterface<ParamType>* const base_;
- // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
- // current[i]_ is the actual traversing iterator.
- const typename ParamGenerator<T1>::iterator begin1_;
- const typename ParamGenerator<T1>::iterator end1_;
- typename ParamGenerator<T1>::iterator current1_;
- const typename ParamGenerator<T2>::iterator begin2_;
- const typename ParamGenerator<T2>::iterator end2_;
- typename ParamGenerator<T2>::iterator current2_;
- const typename ParamGenerator<T3>::iterator begin3_;
- const typename ParamGenerator<T3>::iterator end3_;
- typename ParamGenerator<T3>::iterator current3_;
- const typename ParamGenerator<T4>::iterator begin4_;
- const typename ParamGenerator<T4>::iterator end4_;
- typename ParamGenerator<T4>::iterator current4_;
- const typename ParamGenerator<T5>::iterator begin5_;
- const typename ParamGenerator<T5>::iterator end5_;
- typename ParamGenerator<T5>::iterator current5_;
- const typename ParamGenerator<T6>::iterator begin6_;
- const typename ParamGenerator<T6>::iterator end6_;
- typename ParamGenerator<T6>::iterator current6_;
- const typename ParamGenerator<T7>::iterator begin7_;
- const typename ParamGenerator<T7>::iterator end7_;
- typename ParamGenerator<T7>::iterator current7_;
- const typename ParamGenerator<T8>::iterator begin8_;
- const typename ParamGenerator<T8>::iterator end8_;
- typename ParamGenerator<T8>::iterator current8_;
- const typename ParamGenerator<T9>::iterator begin9_;
- const typename ParamGenerator<T9>::iterator end9_;
- typename ParamGenerator<T9>::iterator current9_;
- const typename ParamGenerator<T10>::iterator begin10_;
- const typename ParamGenerator<T10>::iterator end10_;
- typename ParamGenerator<T10>::iterator current10_;
- ParamType current_value_;
- }; // class CartesianProductGenerator10::Iterator
-
- // No implementation - assignment is unsupported.
- void operator=(const CartesianProductGenerator10& other);
-
- const ParamGenerator<T1> g1_;
- const ParamGenerator<T2> g2_;
- const ParamGenerator<T3> g3_;
- const ParamGenerator<T4> g4_;
- const ParamGenerator<T5> g5_;
- const ParamGenerator<T6> g6_;
- const ParamGenerator<T7> g7_;
- const ParamGenerator<T8> g8_;
- const ParamGenerator<T9> g9_;
- const ParamGenerator<T10> g10_;
-}; // class CartesianProductGenerator10
-
-
-// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
-//
-// Helper classes providing Combine() with polymorphic features. They allow
-// casting CartesianProductGeneratorN<T> to ParamGenerator<U> if T is
-// convertible to U.
-//
-template <class Generator1, class Generator2>
-class CartesianProductHolder2 {
- public:
-CartesianProductHolder2(const Generator1& g1, const Generator2& g2)
- : g1_(g1), g2_(g2) {}
- template <typename T1, typename T2>
- operator ParamGenerator< ::testing::tuple<T1, T2> >() const {
- return ParamGenerator< ::testing::tuple<T1, T2> >(
- new CartesianProductGenerator2<T1, T2>(
- static_cast<ParamGenerator<T1> >(g1_),
- static_cast<ParamGenerator<T2> >(g2_)));
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const CartesianProductHolder2& other);
-
- const Generator1 g1_;
- const Generator2 g2_;
-}; // class CartesianProductHolder2
-
-template <class Generator1, class Generator2, class Generator3>
-class CartesianProductHolder3 {
- public:
-CartesianProductHolder3(const Generator1& g1, const Generator2& g2,
- const Generator3& g3)
- : g1_(g1), g2_(g2), g3_(g3) {}
- template <typename T1, typename T2, typename T3>
- operator ParamGenerator< ::testing::tuple<T1, T2, T3> >() const {
- return ParamGenerator< ::testing::tuple<T1, T2, T3> >(
- new CartesianProductGenerator3<T1, T2, T3>(
- static_cast<ParamGenerator<T1> >(g1_),
- static_cast<ParamGenerator<T2> >(g2_),
- static_cast<ParamGenerator<T3> >(g3_)));
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const CartesianProductHolder3& other);
-
- const Generator1 g1_;
- const Generator2 g2_;
- const Generator3 g3_;
-}; // class CartesianProductHolder3
-
-template <class Generator1, class Generator2, class Generator3,
- class Generator4>
-class CartesianProductHolder4 {
- public:
-CartesianProductHolder4(const Generator1& g1, const Generator2& g2,
- const Generator3& g3, const Generator4& g4)
- : g1_(g1), g2_(g2), g3_(g3), g4_(g4) {}
- template <typename T1, typename T2, typename T3, typename T4>
- operator ParamGenerator< ::testing::tuple<T1, T2, T3, T4> >() const {
- return ParamGenerator< ::testing::tuple<T1, T2, T3, T4> >(
- new CartesianProductGenerator4<T1, T2, T3, T4>(
- static_cast<ParamGenerator<T1> >(g1_),
- static_cast<ParamGenerator<T2> >(g2_),
- static_cast<ParamGenerator<T3> >(g3_),
- static_cast<ParamGenerator<T4> >(g4_)));
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const CartesianProductHolder4& other);
-
- const Generator1 g1_;
- const Generator2 g2_;
- const Generator3 g3_;
- const Generator4 g4_;
-}; // class CartesianProductHolder4
-
-template <class Generator1, class Generator2, class Generator3,
- class Generator4, class Generator5>
-class CartesianProductHolder5 {
- public:
-CartesianProductHolder5(const Generator1& g1, const Generator2& g2,
- const Generator3& g3, const Generator4& g4, const Generator5& g5)
- : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5) {}
- template <typename T1, typename T2, typename T3, typename T4, typename T5>
- operator ParamGenerator< ::testing::tuple<T1, T2, T3, T4, T5> >() const {
- return ParamGenerator< ::testing::tuple<T1, T2, T3, T4, T5> >(
- new CartesianProductGenerator5<T1, T2, T3, T4, T5>(
- static_cast<ParamGenerator<T1> >(g1_),
- static_cast<ParamGenerator<T2> >(g2_),
- static_cast<ParamGenerator<T3> >(g3_),
- static_cast<ParamGenerator<T4> >(g4_),
- static_cast<ParamGenerator<T5> >(g5_)));
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const CartesianProductHolder5& other);
-
- const Generator1 g1_;
- const Generator2 g2_;
- const Generator3 g3_;
- const Generator4 g4_;
- const Generator5 g5_;
-}; // class CartesianProductHolder5
-
-template <class Generator1, class Generator2, class Generator3,
- class Generator4, class Generator5, class Generator6>
-class CartesianProductHolder6 {
- public:
-CartesianProductHolder6(const Generator1& g1, const Generator2& g2,
- const Generator3& g3, const Generator4& g4, const Generator5& g5,
- const Generator6& g6)
- : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6) {}
- template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6>
- operator ParamGenerator< ::testing::tuple<T1, T2, T3, T4, T5, T6> >() const {
- return ParamGenerator< ::testing::tuple<T1, T2, T3, T4, T5, T6> >(
- new CartesianProductGenerator6<T1, T2, T3, T4, T5, T6>(
- static_cast<ParamGenerator<T1> >(g1_),
- static_cast<ParamGenerator<T2> >(g2_),
- static_cast<ParamGenerator<T3> >(g3_),
- static_cast<ParamGenerator<T4> >(g4_),
- static_cast<ParamGenerator<T5> >(g5_),
- static_cast<ParamGenerator<T6> >(g6_)));
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const CartesianProductHolder6& other);
-
- const Generator1 g1_;
- const Generator2 g2_;
- const Generator3 g3_;
- const Generator4 g4_;
- const Generator5 g5_;
- const Generator6 g6_;
-}; // class CartesianProductHolder6
-
-template <class Generator1, class Generator2, class Generator3,
- class Generator4, class Generator5, class Generator6, class Generator7>
-class CartesianProductHolder7 {
- public:
-CartesianProductHolder7(const Generator1& g1, const Generator2& g2,
- const Generator3& g3, const Generator4& g4, const Generator5& g5,
- const Generator6& g6, const Generator7& g7)
- : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7) {}
- template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7>
- operator ParamGenerator< ::testing::tuple<T1, T2, T3, T4, T5, T6,
- T7> >() const {
- return ParamGenerator< ::testing::tuple<T1, T2, T3, T4, T5, T6, T7> >(
- new CartesianProductGenerator7<T1, T2, T3, T4, T5, T6, T7>(
- static_cast<ParamGenerator<T1> >(g1_),
- static_cast<ParamGenerator<T2> >(g2_),
- static_cast<ParamGenerator<T3> >(g3_),
- static_cast<ParamGenerator<T4> >(g4_),
- static_cast<ParamGenerator<T5> >(g5_),
- static_cast<ParamGenerator<T6> >(g6_),
- static_cast<ParamGenerator<T7> >(g7_)));
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const CartesianProductHolder7& other);
-
- const Generator1 g1_;
- const Generator2 g2_;
- const Generator3 g3_;
- const Generator4 g4_;
- const Generator5 g5_;
- const Generator6 g6_;
- const Generator7 g7_;
-}; // class CartesianProductHolder7
-
-template <class Generator1, class Generator2, class Generator3,
- class Generator4, class Generator5, class Generator6, class Generator7,
- class Generator8>
-class CartesianProductHolder8 {
- public:
-CartesianProductHolder8(const Generator1& g1, const Generator2& g2,
- const Generator3& g3, const Generator4& g4, const Generator5& g5,
- const Generator6& g6, const Generator7& g7, const Generator8& g8)
- : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7),
- g8_(g8) {}
- template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8>
- operator ParamGenerator< ::testing::tuple<T1, T2, T3, T4, T5, T6, T7,
- T8> >() const {
- return ParamGenerator< ::testing::tuple<T1, T2, T3, T4, T5, T6, T7, T8> >(
- new CartesianProductGenerator8<T1, T2, T3, T4, T5, T6, T7, T8>(
- static_cast<ParamGenerator<T1> >(g1_),
- static_cast<ParamGenerator<T2> >(g2_),
- static_cast<ParamGenerator<T3> >(g3_),
- static_cast<ParamGenerator<T4> >(g4_),
- static_cast<ParamGenerator<T5> >(g5_),
- static_cast<ParamGenerator<T6> >(g6_),
- static_cast<ParamGenerator<T7> >(g7_),
- static_cast<ParamGenerator<T8> >(g8_)));
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const CartesianProductHolder8& other);
-
- const Generator1 g1_;
- const Generator2 g2_;
- const Generator3 g3_;
- const Generator4 g4_;
- const Generator5 g5_;
- const Generator6 g6_;
- const Generator7 g7_;
- const Generator8 g8_;
-}; // class CartesianProductHolder8
-
-template <class Generator1, class Generator2, class Generator3,
- class Generator4, class Generator5, class Generator6, class Generator7,
- class Generator8, class Generator9>
-class CartesianProductHolder9 {
- public:
-CartesianProductHolder9(const Generator1& g1, const Generator2& g2,
- const Generator3& g3, const Generator4& g4, const Generator5& g5,
- const Generator6& g6, const Generator7& g7, const Generator8& g8,
- const Generator9& g9)
- : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8),
- g9_(g9) {}
- template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9>
- operator ParamGenerator< ::testing::tuple<T1, T2, T3, T4, T5, T6, T7, T8,
- T9> >() const {
- return ParamGenerator< ::testing::tuple<T1, T2, T3, T4, T5, T6, T7, T8,
- T9> >(
- new CartesianProductGenerator9<T1, T2, T3, T4, T5, T6, T7, T8, T9>(
- static_cast<ParamGenerator<T1> >(g1_),
- static_cast<ParamGenerator<T2> >(g2_),
- static_cast<ParamGenerator<T3> >(g3_),
- static_cast<ParamGenerator<T4> >(g4_),
- static_cast<ParamGenerator<T5> >(g5_),
- static_cast<ParamGenerator<T6> >(g6_),
- static_cast<ParamGenerator<T7> >(g7_),
- static_cast<ParamGenerator<T8> >(g8_),
- static_cast<ParamGenerator<T9> >(g9_)));
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const CartesianProductHolder9& other);
-
- const Generator1 g1_;
- const Generator2 g2_;
- const Generator3 g3_;
- const Generator4 g4_;
- const Generator5 g5_;
- const Generator6 g6_;
- const Generator7 g7_;
- const Generator8 g8_;
- const Generator9 g9_;
-}; // class CartesianProductHolder9
-
-template <class Generator1, class Generator2, class Generator3,
- class Generator4, class Generator5, class Generator6, class Generator7,
- class Generator8, class Generator9, class Generator10>
-class CartesianProductHolder10 {
- public:
-CartesianProductHolder10(const Generator1& g1, const Generator2& g2,
- const Generator3& g3, const Generator4& g4, const Generator5& g5,
- const Generator6& g6, const Generator7& g7, const Generator8& g8,
- const Generator9& g9, const Generator10& g10)
- : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8),
- g9_(g9), g10_(g10) {}
- template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10>
- operator ParamGenerator< ::testing::tuple<T1, T2, T3, T4, T5, T6, T7, T8, T9,
- T10> >() const {
- return ParamGenerator< ::testing::tuple<T1, T2, T3, T4, T5, T6, T7, T8, T9,
- T10> >(
- new CartesianProductGenerator10<T1, T2, T3, T4, T5, T6, T7, T8, T9,
- T10>(
- static_cast<ParamGenerator<T1> >(g1_),
- static_cast<ParamGenerator<T2> >(g2_),
- static_cast<ParamGenerator<T3> >(g3_),
- static_cast<ParamGenerator<T4> >(g4_),
- static_cast<ParamGenerator<T5> >(g5_),
- static_cast<ParamGenerator<T6> >(g6_),
- static_cast<ParamGenerator<T7> >(g7_),
- static_cast<ParamGenerator<T8> >(g8_),
- static_cast<ParamGenerator<T9> >(g9_),
- static_cast<ParamGenerator<T10> >(g10_)));
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const CartesianProductHolder10& other);
-
- const Generator1 g1_;
- const Generator2 g2_;
- const Generator3 g3_;
- const Generator4 g4_;
- const Generator5 g5_;
- const Generator6 g6_;
- const Generator7 g7_;
- const Generator8 g8_;
- const Generator9 g9_;
- const Generator10 g10_;
-}; // class CartesianProductHolder10
-
-# endif // GTEST_HAS_COMBINE
-
-} // namespace internal
-} // namespace testing
-
-#endif // GTEST_HAS_PARAM_TEST
-
-#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_
diff --git a/extern/gtest/include/gtest/internal/gtest-param-util.h b/extern/gtest/include/gtest/internal/gtest-param-util.h
index 82cab9b0201..97533993c0c 100644
--- a/extern/gtest/include/gtest/internal/gtest-param-util.h
+++ b/extern/gtest/include/gtest/internal/gtest-param-util.h
@@ -26,33 +26,30 @@
// 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.
-//
-// Author: vladl@google.com (Vlad Losev)
+
// Type and function utilities for implementing parameterized tests.
+// GOOGLETEST_CM0001 DO NOT DELETE
+
#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_
#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_
#include <ctype.h>
+#include <cassert>
#include <iterator>
+#include <memory>
#include <set>
+#include <tuple>
#include <utility>
#include <vector>
-// scripts/fuse_gtest.py depends on gtest's own header being #included
-// *unconditionally*. Therefore these #includes cannot be moved
-// inside #if GTEST_HAS_PARAM_TEST.
#include "gtest/internal/gtest-internal.h"
-#include "gtest/internal/gtest-linked_ptr.h"
#include "gtest/internal/gtest-port.h"
#include "gtest/gtest-printers.h"
-#if GTEST_HAS_PARAM_TEST
-
namespace testing {
-
// Input to a parameterized test name generator, describing a test parameter.
// Consists of the parameter value and the integer parameter index.
template <class ParamType>
@@ -76,13 +73,14 @@ struct PrintToStringParamName {
namespace internal {
// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
-//
+// Utility Functions
+
// Outputs a message explaining invalid registration of different
-// fixture class for the same test case. This may happen when
+// fixture class for the same test suite. This may happen when
// TEST_P macro is used to define two tests with the same name
// but in different namespaces.
-GTEST_API_ void ReportInvalidTestCaseType(const char* test_case_name,
- CodeLocation code_location);
+GTEST_API_ void ReportInvalidTestSuiteType(const char* test_suite_name,
+ CodeLocation code_location);
template <typename> class ParamGeneratorInterface;
template <typename> class ParamGenerator;
@@ -157,7 +155,7 @@ class ParamIterator {
private:
friend class ParamGenerator<T>;
explicit ParamIterator(ParamIteratorInterface<T>* impl) : impl_(impl) {}
- scoped_ptr<ParamIteratorInterface<T> > impl_;
+ std::unique_ptr<ParamIteratorInterface<T> > impl_;
};
// ParamGeneratorInterface<T> is the binary interface to access generators
@@ -196,7 +194,7 @@ class ParamGenerator {
iterator end() const { return iterator(impl_->End()); }
private:
- linked_ptr<const ParamGeneratorInterface<T> > impl_;
+ std::shared_ptr<const ParamGeneratorInterface<T> > impl_;
};
// Generates values from a range of two comparable values. Can be used to
@@ -209,12 +207,12 @@ class RangeGenerator : public ParamGeneratorInterface<T> {
RangeGenerator(T begin, T end, IncrementT step)
: begin_(begin), end_(end),
step_(step), end_index_(CalculateEndIndex(begin, end, step)) {}
- virtual ~RangeGenerator() {}
+ ~RangeGenerator() override {}
- virtual ParamIteratorInterface<T>* Begin() const {
+ ParamIteratorInterface<T>* Begin() const override {
return new Iterator(this, begin_, 0, step_);
}
- virtual ParamIteratorInterface<T>* End() const {
+ ParamIteratorInterface<T>* End() const override {
return new Iterator(this, end_, end_index_, step_);
}
@@ -224,20 +222,20 @@ class RangeGenerator : public ParamGeneratorInterface<T> {
Iterator(const ParamGeneratorInterface<T>* base, T value, int index,
IncrementT step)
: base_(base), value_(value), index_(index), step_(step) {}
- virtual ~Iterator() {}
+ ~Iterator() override {}
- virtual const ParamGeneratorInterface<T>* BaseGenerator() const {
+ const ParamGeneratorInterface<T>* BaseGenerator() const override {
return base_;
}
- virtual void Advance() {
+ void Advance() override {
value_ = static_cast<T>(value_ + step_);
index_++;
}
- virtual ParamIteratorInterface<T>* Clone() const {
+ ParamIteratorInterface<T>* Clone() const override {
return new Iterator(*this);
}
- virtual const T* Current() const { return &value_; }
- virtual bool Equals(const ParamIteratorInterface<T>& other) const {
+ const T* Current() const override { return &value_; }
+ bool Equals(const ParamIteratorInterface<T>& other) const override {
// Having the same base generator guarantees that the other
// iterator is of the same type and we can downcast.
GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
@@ -294,12 +292,12 @@ class ValuesInIteratorRangeGenerator : public ParamGeneratorInterface<T> {
template <typename ForwardIterator>
ValuesInIteratorRangeGenerator(ForwardIterator begin, ForwardIterator end)
: container_(begin, end) {}
- virtual ~ValuesInIteratorRangeGenerator() {}
+ ~ValuesInIteratorRangeGenerator() override {}
- virtual ParamIteratorInterface<T>* Begin() const {
+ ParamIteratorInterface<T>* Begin() const override {
return new Iterator(this, container_.begin());
}
- virtual ParamIteratorInterface<T>* End() const {
+ ParamIteratorInterface<T>* End() const override {
return new Iterator(this, container_.end());
}
@@ -311,16 +309,16 @@ class ValuesInIteratorRangeGenerator : public ParamGeneratorInterface<T> {
Iterator(const ParamGeneratorInterface<T>* base,
typename ContainerType::const_iterator iterator)
: base_(base), iterator_(iterator) {}
- virtual ~Iterator() {}
+ ~Iterator() override {}
- virtual const ParamGeneratorInterface<T>* BaseGenerator() const {
+ const ParamGeneratorInterface<T>* BaseGenerator() const override {
return base_;
}
- virtual void Advance() {
+ void Advance() override {
++iterator_;
value_.reset();
}
- virtual ParamIteratorInterface<T>* Clone() const {
+ ParamIteratorInterface<T>* Clone() const override {
return new Iterator(*this);
}
// We need to use cached value referenced by iterator_ because *iterator_
@@ -330,12 +328,11 @@ class ValuesInIteratorRangeGenerator : public ParamGeneratorInterface<T> {
// can advance iterator_ beyond the end of the range, and we cannot
// detect that fact. The client code, on the other hand, is
// responsible for not calling Current() on an out-of-range iterator.
- virtual const T* Current() const {
- if (value_.get() == NULL)
- value_.reset(new T(*iterator_));
+ const T* Current() const override {
+ if (value_.get() == nullptr) value_.reset(new T(*iterator_));
return value_.get();
}
- virtual bool Equals(const ParamIteratorInterface<T>& other) const {
+ bool Equals(const ParamIteratorInterface<T>& other) const override {
// Having the same base generator guarantees that the other
// iterator is of the same type and we can downcast.
GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
@@ -358,9 +355,9 @@ class ValuesInIteratorRangeGenerator : public ParamGeneratorInterface<T> {
// A cached value of *iterator_. We keep it here to allow access by
// pointer in the wrapping iterator's operator->().
// value_ needs to be mutable to be accessed in Current().
- // Use of scoped_ptr helps manage cached value's lifetime,
+ // Use of std::unique_ptr helps manage cached value's lifetime,
// which is bound by the lifespan of the iterator itself.
- mutable scoped_ptr<const T> value_;
+ mutable std::unique_ptr<const T> value_;
}; // class ValuesInIteratorRangeGenerator::Iterator
// No implementation - assignment is unsupported.
@@ -380,25 +377,12 @@ std::string DefaultParamName(const TestParamInfo<ParamType>& info) {
return name_stream.GetString();
}
-// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
-//
-// Parameterized test name overload helpers, which help the
-// INSTANTIATE_TEST_CASE_P macro choose between the default parameterized
-// test name generator and user param name generator.
-template <class ParamType, class ParamNameGenFunctor>
-ParamNameGenFunctor GetParamNameGen(ParamNameGenFunctor func) {
- return func;
-}
-
-template <class ParamType>
-struct ParamNameGenFunc {
- typedef std::string Type(const TestParamInfo<ParamType>&);
-};
-
-template <class ParamType>
-typename ParamNameGenFunc<ParamType>::Type *GetParamNameGen() {
- return DefaultParamName;
+template <typename T = int>
+void TestNotEmpty() {
+ static_assert(sizeof(T) == 0, "Empty arguments are not allowed.");
}
+template <typename T = int>
+void TestNotEmpty(const T&) {}
// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
//
@@ -410,7 +394,7 @@ class ParameterizedTestFactory : public TestFactoryBase {
typedef typename TestClass::ParamType ParamType;
explicit ParameterizedTestFactory(ParamType parameter) :
parameter_(parameter) {}
- virtual Test* CreateTest() {
+ Test* CreateTest() override {
TestClass::SetParam(&parameter_);
return new TestClass();
}
@@ -438,19 +422,19 @@ class TestMetaFactoryBase {
// TestMetaFactory creates test factories for passing into
// MakeAndRegisterTestInfo function. Since MakeAndRegisterTestInfo receives
// ownership of test factory pointer, same factory object cannot be passed
-// into that method twice. But ParameterizedTestCaseInfo is going to call
+// into that method twice. But ParameterizedTestSuiteInfo is going to call
// it for each Test/Parameter value combination. Thus it needs meta factory
// creator class.
-template <class TestCase>
+template <class TestSuite>
class TestMetaFactory
- : public TestMetaFactoryBase<typename TestCase::ParamType> {
+ : public TestMetaFactoryBase<typename TestSuite::ParamType> {
public:
- typedef typename TestCase::ParamType ParamType;
+ using ParamType = typename TestSuite::ParamType;
TestMetaFactory() {}
- virtual TestFactoryBase* CreateTestFactory(ParamType parameter) {
- return new ParameterizedTestFactory<TestCase>(parameter);
+ TestFactoryBase* CreateTestFactory(ParamType parameter) override {
+ return new ParameterizedTestFactory<TestSuite>(parameter);
}
private:
@@ -459,107 +443,106 @@ class TestMetaFactory
// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
//
-// ParameterizedTestCaseInfoBase is a generic interface
-// to ParameterizedTestCaseInfo classes. ParameterizedTestCaseInfoBase
+// ParameterizedTestSuiteInfoBase is a generic interface
+// to ParameterizedTestSuiteInfo classes. ParameterizedTestSuiteInfoBase
// accumulates test information provided by TEST_P macro invocations
-// and generators provided by INSTANTIATE_TEST_CASE_P macro invocations
+// and generators provided by INSTANTIATE_TEST_SUITE_P macro invocations
// and uses that information to register all resulting test instances
-// in RegisterTests method. The ParameterizeTestCaseRegistry class holds
-// a collection of pointers to the ParameterizedTestCaseInfo objects
+// in RegisterTests method. The ParameterizeTestSuiteRegistry class holds
+// a collection of pointers to the ParameterizedTestSuiteInfo objects
// and calls RegisterTests() on each of them when asked.
-class ParameterizedTestCaseInfoBase {
+class ParameterizedTestSuiteInfoBase {
public:
- virtual ~ParameterizedTestCaseInfoBase() {}
+ virtual ~ParameterizedTestSuiteInfoBase() {}
- // Base part of test case name for display purposes.
- virtual const string& GetTestCaseName() const = 0;
+ // Base part of test suite name for display purposes.
+ virtual const std::string& GetTestSuiteName() const = 0;
// Test case id to verify identity.
- virtual TypeId GetTestCaseTypeId() const = 0;
+ virtual TypeId GetTestSuiteTypeId() const = 0;
// UnitTest class invokes this method to register tests in this
- // test case right before running them in RUN_ALL_TESTS macro.
- // This method should not be called more then once on any single
- // instance of a ParameterizedTestCaseInfoBase derived class.
+ // test suite right before running them in RUN_ALL_TESTS macro.
+ // This method should not be called more than once on any single
+ // instance of a ParameterizedTestSuiteInfoBase derived class.
virtual void RegisterTests() = 0;
protected:
- ParameterizedTestCaseInfoBase() {}
+ ParameterizedTestSuiteInfoBase() {}
private:
- GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseInfoBase);
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestSuiteInfoBase);
};
// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
//
-// ParameterizedTestCaseInfo accumulates tests obtained from TEST_P
-// macro invocations for a particular test case and generators
-// obtained from INSTANTIATE_TEST_CASE_P macro invocations for that
-// test case. It registers tests with all values generated by all
+// ParameterizedTestSuiteInfo accumulates tests obtained from TEST_P
+// macro invocations for a particular test suite and generators
+// obtained from INSTANTIATE_TEST_SUITE_P macro invocations for that
+// test suite. It registers tests with all values generated by all
// generators when asked.
-template <class TestCase>
-class ParameterizedTestCaseInfo : public ParameterizedTestCaseInfoBase {
+template <class TestSuite>
+class ParameterizedTestSuiteInfo : public ParameterizedTestSuiteInfoBase {
public:
// ParamType and GeneratorCreationFunc are private types but are required
// for declarations of public methods AddTestPattern() and
- // AddTestCaseInstantiation().
- typedef typename TestCase::ParamType ParamType;
+ // AddTestSuiteInstantiation().
+ using ParamType = typename TestSuite::ParamType;
// A function that returns an instance of appropriate generator type.
typedef ParamGenerator<ParamType>(GeneratorCreationFunc)();
- typedef typename ParamNameGenFunc<ParamType>::Type ParamNameGeneratorFunc;
+ using ParamNameGeneratorFunc = std::string(const TestParamInfo<ParamType>&);
- explicit ParameterizedTestCaseInfo(
- const char* name, CodeLocation code_location)
- : test_case_name_(name), code_location_(code_location) {}
+ explicit ParameterizedTestSuiteInfo(const char* name,
+ CodeLocation code_location)
+ : test_suite_name_(name), code_location_(code_location) {}
// Test case base name for display purposes.
- virtual const string& GetTestCaseName() const { return test_case_name_; }
+ const std::string& GetTestSuiteName() const override {
+ return test_suite_name_;
+ }
// Test case id to verify identity.
- virtual TypeId GetTestCaseTypeId() const { return GetTypeId<TestCase>(); }
+ TypeId GetTestSuiteTypeId() const override { return GetTypeId<TestSuite>(); }
// TEST_P macro uses AddTestPattern() to record information
// about a single test in a LocalTestInfo structure.
- // test_case_name is the base name of the test case (without invocation
+ // test_suite_name is the base name of the test suite (without invocation
// prefix). test_base_name is the name of an individual test without
// parameter index. For the test SequenceA/FooTest.DoBar/1 FooTest is
- // test case base name and DoBar is test base name.
- void AddTestPattern(const char* test_case_name,
- const char* test_base_name,
+ // test suite base name and DoBar is test base name.
+ void AddTestPattern(const char* test_suite_name, const char* test_base_name,
TestMetaFactoryBase<ParamType>* meta_factory) {
- tests_.push_back(linked_ptr<TestInfo>(new TestInfo(test_case_name,
- test_base_name,
- meta_factory)));
+ tests_.push_back(std::shared_ptr<TestInfo>(
+ new TestInfo(test_suite_name, test_base_name, meta_factory)));
}
- // INSTANTIATE_TEST_CASE_P macro uses AddGenerator() to record information
+ // INSTANTIATE_TEST_SUITE_P macro uses AddGenerator() to record information
// about a generator.
- int AddTestCaseInstantiation(const string& instantiation_name,
- GeneratorCreationFunc* func,
- ParamNameGeneratorFunc* name_func,
- const char* file,
- int line) {
+ int AddTestSuiteInstantiation(const std::string& instantiation_name,
+ GeneratorCreationFunc* func,
+ ParamNameGeneratorFunc* name_func,
+ const char* file, int line) {
instantiations_.push_back(
InstantiationInfo(instantiation_name, func, name_func, file, line));
return 0; // Return value used only to run this method in namespace scope.
}
- // UnitTest class invokes this method to register tests in this test case
- // test cases right before running tests in RUN_ALL_TESTS macro.
- // This method should not be called more then once on any single
- // instance of a ParameterizedTestCaseInfoBase derived class.
- // UnitTest has a guard to prevent from calling this method more then once.
- virtual void RegisterTests() {
+ // UnitTest class invokes this method to register tests in this test suite
+ // test suites right before running tests in RUN_ALL_TESTS macro.
+ // This method should not be called more than once on any single
+ // instance of a ParameterizedTestSuiteInfoBase derived class.
+ // UnitTest has a guard to prevent from calling this method more than once.
+ void RegisterTests() override {
for (typename TestInfoContainer::iterator test_it = tests_.begin();
test_it != tests_.end(); ++test_it) {
- linked_ptr<TestInfo> test_info = *test_it;
+ std::shared_ptr<TestInfo> test_info = *test_it;
for (typename InstantiationContainer::iterator gen_it =
instantiations_.begin(); gen_it != instantiations_.end();
++gen_it) {
- const string& instantiation_name = gen_it->name;
+ const std::string& instantiation_name = gen_it->name;
ParamGenerator<ParamType> generator((*gen_it->generator)());
ParamNameGeneratorFunc* name_func = gen_it->name_func;
const char* file = gen_it->file;
int line = gen_it->line;
- string test_case_name;
+ std::string test_suite_name;
if ( !instantiation_name.empty() )
- test_case_name = instantiation_name + "/";
- test_case_name += test_info->test_case_base_name;
+ test_suite_name = instantiation_name + "/";
+ test_suite_name += test_info->test_suite_base_name;
size_t i = 0;
std::set<std::string> test_param_names;
@@ -582,39 +565,39 @@ class ParameterizedTestCaseInfo : public ParameterizedTestCaseInfoBase {
test_param_names.insert(param_name);
- test_name_stream << test_info->test_base_name << "/" << param_name;
+ if (!test_info->test_base_name.empty()) {
+ test_name_stream << test_info->test_base_name << "/";
+ }
+ test_name_stream << param_name;
MakeAndRegisterTestInfo(
- test_case_name.c_str(),
- test_name_stream.GetString().c_str(),
- NULL, // No type parameter.
- PrintToString(*param_it).c_str(),
- code_location_,
- GetTestCaseTypeId(),
- TestCase::SetUpTestCase,
- TestCase::TearDownTestCase,
+ test_suite_name.c_str(), test_name_stream.GetString().c_str(),
+ nullptr, // No type parameter.
+ PrintToString(*param_it).c_str(), code_location_,
+ GetTestSuiteTypeId(),
+ SuiteApiResolver<TestSuite>::GetSetUpCaseOrSuite(file, line),
+ SuiteApiResolver<TestSuite>::GetTearDownCaseOrSuite(file, line),
test_info->test_meta_factory->CreateTestFactory(*param_it));
} // for param_it
} // for gen_it
} // for test_it
- } // RegisterTests
+ } // RegisterTests
private:
// LocalTestInfo structure keeps information about a single test registered
// with TEST_P macro.
struct TestInfo {
- TestInfo(const char* a_test_case_base_name,
- const char* a_test_base_name,
- TestMetaFactoryBase<ParamType>* a_test_meta_factory) :
- test_case_base_name(a_test_case_base_name),
- test_base_name(a_test_base_name),
- test_meta_factory(a_test_meta_factory) {}
-
- const string test_case_base_name;
- const string test_base_name;
- const scoped_ptr<TestMetaFactoryBase<ParamType> > test_meta_factory;
+ TestInfo(const char* a_test_suite_base_name, const char* a_test_base_name,
+ TestMetaFactoryBase<ParamType>* a_test_meta_factory)
+ : test_suite_base_name(a_test_suite_base_name),
+ test_base_name(a_test_base_name),
+ test_meta_factory(a_test_meta_factory) {}
+
+ const std::string test_suite_base_name;
+ const std::string test_base_name;
+ const std::unique_ptr<TestMetaFactoryBase<ParamType> > test_meta_factory;
};
- typedef ::std::vector<linked_ptr<TestInfo> > TestInfoContainer;
- // Records data received from INSTANTIATE_TEST_CASE_P macros:
+ using TestInfoContainer = ::std::vector<std::shared_ptr<TestInfo> >;
+ // Records data received from INSTANTIATE_TEST_SUITE_P macros:
// <Instantiation name, Sequence generator creation function,
// Name generator function, Source file, Source line>
struct InstantiationInfo {
@@ -651,81 +634,250 @@ class ParameterizedTestCaseInfo : public ParameterizedTestCaseInfoBase {
return true;
}
- const string test_case_name_;
+ const std::string test_suite_name_;
CodeLocation code_location_;
TestInfoContainer tests_;
InstantiationContainer instantiations_;
- GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseInfo);
-}; // class ParameterizedTestCaseInfo
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestSuiteInfo);
+}; // class ParameterizedTestSuiteInfo
+
+// Legacy API is deprecated but still available
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+template <class TestCase>
+using ParameterizedTestCaseInfo = ParameterizedTestSuiteInfo<TestCase>;
+#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
//
-// ParameterizedTestCaseRegistry contains a map of ParameterizedTestCaseInfoBase
-// classes accessed by test case names. TEST_P and INSTANTIATE_TEST_CASE_P
-// macros use it to locate their corresponding ParameterizedTestCaseInfo
-// descriptors.
-class ParameterizedTestCaseRegistry {
+// ParameterizedTestSuiteRegistry contains a map of
+// ParameterizedTestSuiteInfoBase classes accessed by test suite names. TEST_P
+// and INSTANTIATE_TEST_SUITE_P macros use it to locate their corresponding
+// ParameterizedTestSuiteInfo descriptors.
+class ParameterizedTestSuiteRegistry {
public:
- ParameterizedTestCaseRegistry() {}
- ~ParameterizedTestCaseRegistry() {
- for (TestCaseInfoContainer::iterator it = test_case_infos_.begin();
- it != test_case_infos_.end(); ++it) {
- delete *it;
+ ParameterizedTestSuiteRegistry() {}
+ ~ParameterizedTestSuiteRegistry() {
+ for (auto& test_suite_info : test_suite_infos_) {
+ delete test_suite_info;
}
}
// Looks up or creates and returns a structure containing information about
- // tests and instantiations of a particular test case.
- template <class TestCase>
- ParameterizedTestCaseInfo<TestCase>* GetTestCasePatternHolder(
- const char* test_case_name,
- CodeLocation code_location) {
- ParameterizedTestCaseInfo<TestCase>* typed_test_info = NULL;
- for (TestCaseInfoContainer::iterator it = test_case_infos_.begin();
- it != test_case_infos_.end(); ++it) {
- if ((*it)->GetTestCaseName() == test_case_name) {
- if ((*it)->GetTestCaseTypeId() != GetTypeId<TestCase>()) {
+ // tests and instantiations of a particular test suite.
+ template <class TestSuite>
+ ParameterizedTestSuiteInfo<TestSuite>* GetTestSuitePatternHolder(
+ const char* test_suite_name, CodeLocation code_location) {
+ ParameterizedTestSuiteInfo<TestSuite>* typed_test_info = nullptr;
+ for (auto& test_suite_info : test_suite_infos_) {
+ if (test_suite_info->GetTestSuiteName() == test_suite_name) {
+ if (test_suite_info->GetTestSuiteTypeId() != GetTypeId<TestSuite>()) {
// Complain about incorrect usage of Google Test facilities
// and terminate the program since we cannot guaranty correct
- // test case setup and tear-down in this case.
- ReportInvalidTestCaseType(test_case_name, code_location);
+ // test suite setup and tear-down in this case.
+ ReportInvalidTestSuiteType(test_suite_name, code_location);
posix::Abort();
} else {
// At this point we are sure that the object we found is of the same
// type we are looking for, so we downcast it to that type
// without further checks.
typed_test_info = CheckedDowncastToActualType<
- ParameterizedTestCaseInfo<TestCase> >(*it);
+ ParameterizedTestSuiteInfo<TestSuite> >(test_suite_info);
}
break;
}
}
- if (typed_test_info == NULL) {
- typed_test_info = new ParameterizedTestCaseInfo<TestCase>(
- test_case_name, code_location);
- test_case_infos_.push_back(typed_test_info);
+ if (typed_test_info == nullptr) {
+ typed_test_info = new ParameterizedTestSuiteInfo<TestSuite>(
+ test_suite_name, code_location);
+ test_suite_infos_.push_back(typed_test_info);
}
return typed_test_info;
}
void RegisterTests() {
- for (TestCaseInfoContainer::iterator it = test_case_infos_.begin();
- it != test_case_infos_.end(); ++it) {
- (*it)->RegisterTests();
+ for (auto& test_suite_info : test_suite_infos_) {
+ test_suite_info->RegisterTests();
}
}
+// Legacy API is deprecated but still available
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+ template <class TestCase>
+ ParameterizedTestCaseInfo<TestCase>* GetTestCasePatternHolder(
+ const char* test_case_name, CodeLocation code_location) {
+ return GetTestSuitePatternHolder<TestCase>(test_case_name, code_location);
+ }
+
+#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
private:
- typedef ::std::vector<ParameterizedTestCaseInfoBase*> TestCaseInfoContainer;
+ using TestSuiteInfoContainer = ::std::vector<ParameterizedTestSuiteInfoBase*>;
- TestCaseInfoContainer test_case_infos_;
+ TestSuiteInfoContainer test_suite_infos_;
- GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseRegistry);
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestSuiteRegistry);
};
} // namespace internal
-} // namespace testing
-#endif // GTEST_HAS_PARAM_TEST
+// Forward declarations of ValuesIn(), which is implemented in
+// include/gtest/gtest-param-test.h.
+template <class Container>
+internal::ParamGenerator<typename Container::value_type> ValuesIn(
+ const Container& container);
+
+namespace internal {
+// Used in the Values() function to provide polymorphic capabilities.
+
+template <typename... Ts>
+class ValueArray {
+ public:
+ ValueArray(Ts... v) : v_{std::move(v)...} {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const { // NOLINT
+ return ValuesIn(MakeVector<T>(MakeIndexSequence<sizeof...(Ts)>()));
+ }
+
+ private:
+ template <typename T, size_t... I>
+ std::vector<T> MakeVector(IndexSequence<I...>) const {
+ return std::vector<T>{static_cast<T>(v_.template Get<I>())...};
+ }
+
+ FlatTuple<Ts...> v_;
+};
+
+template <typename... T>
+class CartesianProductGenerator
+ : public ParamGeneratorInterface<::std::tuple<T...>> {
+ public:
+ typedef ::std::tuple<T...> ParamType;
+
+ CartesianProductGenerator(const std::tuple<ParamGenerator<T>...>& g)
+ : generators_(g) {}
+ ~CartesianProductGenerator() override {}
+
+ ParamIteratorInterface<ParamType>* Begin() const override {
+ return new Iterator(this, generators_, false);
+ }
+ ParamIteratorInterface<ParamType>* End() const override {
+ return new Iterator(this, generators_, true);
+ }
+
+ private:
+ template <class I>
+ class IteratorImpl;
+ template <size_t... I>
+ class IteratorImpl<IndexSequence<I...>>
+ : public ParamIteratorInterface<ParamType> {
+ public:
+ IteratorImpl(const ParamGeneratorInterface<ParamType>* base,
+ const std::tuple<ParamGenerator<T>...>& generators, bool is_end)
+ : base_(base),
+ begin_(std::get<I>(generators).begin()...),
+ end_(std::get<I>(generators).end()...),
+ current_(is_end ? end_ : begin_) {
+ ComputeCurrentValue();
+ }
+ ~IteratorImpl() override {}
+
+ const ParamGeneratorInterface<ParamType>* BaseGenerator() const override {
+ return base_;
+ }
+ // Advance should not be called on beyond-of-range iterators
+ // so no component iterators must be beyond end of range, either.
+ void Advance() override {
+ assert(!AtEnd());
+ // Advance the last iterator.
+ ++std::get<sizeof...(T) - 1>(current_);
+ // if that reaches end, propagate that up.
+ AdvanceIfEnd<sizeof...(T) - 1>();
+ ComputeCurrentValue();
+ }
+ ParamIteratorInterface<ParamType>* Clone() const override {
+ return new IteratorImpl(*this);
+ }
+
+ const ParamType* Current() const override { return current_value_.get(); }
+
+ bool Equals(const ParamIteratorInterface<ParamType>& other) const override {
+ // Having the same base generator guarantees that the other
+ // iterator is of the same type and we can downcast.
+ GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
+ << "The program attempted to compare iterators "
+ << "from different generators." << std::endl;
+ const IteratorImpl* typed_other =
+ CheckedDowncastToActualType<const IteratorImpl>(&other);
+
+ // We must report iterators equal if they both point beyond their
+ // respective ranges. That can happen in a variety of fashions,
+ // so we have to consult AtEnd().
+ if (AtEnd() && typed_other->AtEnd()) return true;
+
+ bool same = true;
+ bool dummy[] = {
+ (same = same && std::get<I>(current_) ==
+ std::get<I>(typed_other->current_))...};
+ (void)dummy;
+ return same;
+ }
+
+ private:
+ template <size_t ThisI>
+ void AdvanceIfEnd() {
+ if (std::get<ThisI>(current_) != std::get<ThisI>(end_)) return;
+
+ bool last = ThisI == 0;
+ if (last) {
+ // We are done. Nothing else to propagate.
+ return;
+ }
+
+ constexpr size_t NextI = ThisI - (ThisI != 0);
+ std::get<ThisI>(current_) = std::get<ThisI>(begin_);
+ ++std::get<NextI>(current_);
+ AdvanceIfEnd<NextI>();
+ }
+
+ void ComputeCurrentValue() {
+ if (!AtEnd())
+ current_value_ = std::make_shared<ParamType>(*std::get<I>(current_)...);
+ }
+ bool AtEnd() const {
+ bool at_end = false;
+ bool dummy[] = {
+ (at_end = at_end || std::get<I>(current_) == std::get<I>(end_))...};
+ (void)dummy;
+ return at_end;
+ }
+
+ const ParamGeneratorInterface<ParamType>* const base_;
+ std::tuple<typename ParamGenerator<T>::iterator...> begin_;
+ std::tuple<typename ParamGenerator<T>::iterator...> end_;
+ std::tuple<typename ParamGenerator<T>::iterator...> current_;
+ std::shared_ptr<ParamType> current_value_;
+ };
+
+ using Iterator = IteratorImpl<typename MakeIndexSequence<sizeof...(T)>::type>;
+
+ std::tuple<ParamGenerator<T>...> generators_;
+};
+
+template <class... Gen>
+class CartesianProductHolder {
+ public:
+ CartesianProductHolder(const Gen&... g) : generators_(g...) {}
+ template <typename... T>
+ operator ParamGenerator<::std::tuple<T...>>() const {
+ return ParamGenerator<::std::tuple<T...>>(
+ new CartesianProductGenerator<T...>(generators_));
+ }
+
+ private:
+ std::tuple<Gen...> generators_;
+};
+
+} // namespace internal
+} // namespace testing
#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_
diff --git a/extern/gtest/include/gtest/internal/gtest-port-arch.h b/extern/gtest/include/gtest/internal/gtest-port-arch.h
index 74ab949057c..cece93dba12 100644
--- a/extern/gtest/include/gtest/internal/gtest-port-arch.h
+++ b/extern/gtest/include/gtest/internal/gtest-port-arch.h
@@ -27,7 +27,7 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
-// The Google C++ Testing Framework (Google Test)
+// The Google C++ Testing and Mocking Framework (Google Test)
//
// This header file defines the GTEST_OS_* macro.
// It is separate from gtest-port.h so that custom/gtest-port.h can include it.
@@ -38,14 +38,13 @@
// Determines the platform on which Google Test is compiled.
#ifdef __CYGWIN__
# define GTEST_OS_CYGWIN 1
-#elif defined __SYMBIAN32__
-# define GTEST_OS_SYMBIAN 1
+# elif defined(__MINGW__) || defined(__MINGW32__) || defined(__MINGW64__)
+# define GTEST_OS_WINDOWS_MINGW 1
+# define GTEST_OS_WINDOWS 1
#elif defined _WIN32
# define GTEST_OS_WINDOWS 1
# ifdef _WIN32_WCE
# define GTEST_OS_WINDOWS_MOBILE 1
-# elif defined(__MINGW__) || defined(__MINGW32__)
-# define GTEST_OS_WINDOWS_MINGW 1
# elif defined(WINAPI_FAMILY)
# include <winapifamily.h>
# if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
@@ -54,6 +53,9 @@
# define GTEST_OS_WINDOWS_PHONE 1
# elif WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)
# define GTEST_OS_WINDOWS_RT 1
+# elif WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_TV_TITLE)
+# define GTEST_OS_WINDOWS_PHONE 1
+# define GTEST_OS_WINDOWS_TV_TITLE 1
# else
// WINAPI_FAMILY defined but no known partition matched.
// Default to desktop.
@@ -62,13 +64,21 @@
# else
# define GTEST_OS_WINDOWS_DESKTOP 1
# endif // _WIN32_WCE
+#elif defined __OS2__
+# define GTEST_OS_OS2 1
#elif defined __APPLE__
# define GTEST_OS_MAC 1
# if TARGET_OS_IPHONE
# define GTEST_OS_IOS 1
# endif
+#elif defined __DragonFly__
+# define GTEST_OS_DRAGONFLY 1
#elif defined __FreeBSD__
# define GTEST_OS_FREEBSD 1
+#elif defined __Fuchsia__
+# define GTEST_OS_FUCHSIA 1
+#elif defined(__GLIBC__) && defined(__FreeBSD_kernel__)
+# define GTEST_OS_GNU_KFREEBSD 1
#elif defined __linux__
# define GTEST_OS_LINUX 1
# if defined __ANDROID__
@@ -84,10 +94,14 @@
# define GTEST_OS_HPUX 1
#elif defined __native_client__
# define GTEST_OS_NACL 1
+#elif defined __NetBSD__
+# define GTEST_OS_NETBSD 1
#elif defined __OpenBSD__
# define GTEST_OS_OPENBSD 1
#elif defined __QNX__
# define GTEST_OS_QNX 1
+#elif defined(__HAIKU__)
+#define GTEST_OS_HAIKU 1
#endif // __CYGWIN__
#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_ARCH_H_
diff --git a/extern/gtest/include/gtest/internal/gtest-port.h b/extern/gtest/include/gtest/internal/gtest-port.h
index 0094ed5077e..063fcb1083b 100644
--- a/extern/gtest/include/gtest/internal/gtest-port.h
+++ b/extern/gtest/include/gtest/internal/gtest-port.h
@@ -27,8 +27,6 @@
// (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)
-//
// Low-level types and utilities for porting Google Test to various
// platforms. All macros ending with _ and symbols defined in an
// internal namespace are subject to change without notice. Code
@@ -40,6 +38,8 @@
// files are expected to #include this. Therefore, it cannot #include
// any other Google Test header.
+// GOOGLETEST_CM0001 DO NOT DELETE
+
#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_
#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_
@@ -72,12 +72,6 @@
// is/isn't available.
// GTEST_HAS_EXCEPTIONS - Define it to 1/0 to indicate that exceptions
// are enabled.
-// GTEST_HAS_GLOBAL_STRING - Define it to 1/0 to indicate that ::string
-// is/isn't available (some systems define
-// ::string, which is different to std::string).
-// GTEST_HAS_GLOBAL_WSTRING - Define it to 1/0 to indicate that ::string
-// is/isn't available (some systems define
-// ::wstring, which is different to std::wstring).
// GTEST_HAS_POSIX_RE - Define it to 1/0 to indicate that POSIX regular
// expressions are/aren't available.
// GTEST_HAS_PTHREAD - Define it to 1/0 to indicate that <pthread.h>
@@ -87,8 +81,6 @@
// GTEST_HAS_STD_WSTRING - Define it to 1/0 to indicate that
// std::wstring does/doesn't work (Google Test can
// be used where std::wstring is unavailable).
-// GTEST_HAS_TR1_TUPLE - Define it to 1/0 to indicate tr1::tuple
-// is/isn't available.
// GTEST_HAS_SEH - Define it to 1/0 to indicate whether the
// compiler supports Microsoft's "Structured
// Exception Handling".
@@ -96,12 +88,6 @@
// - Define it to 1/0 to indicate whether the
// platform supports I/O stream redirection using
// dup() and dup2().
-// GTEST_USE_OWN_TR1_TUPLE - Define it to 1/0 to indicate whether Google
-// 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
@@ -109,6 +95,12 @@
// GTEST_CREATE_SHARED_LIBRARY
// - Define to 1 when compiling Google Test itself
// as a shared library.
+// GTEST_DEFAULT_DEATH_TEST_STYLE
+// - The default value of --gtest_death_test_style.
+// The legacy default has been "fast" in the open
+// source version since 2008. The recommended value
+// is "threadsafe", and can be set in
+// custom/gtest-port.h.
// Platform-indicating macros
// --------------------------
@@ -121,17 +113,22 @@
//
// GTEST_OS_AIX - IBM AIX
// GTEST_OS_CYGWIN - Cygwin
+// GTEST_OS_DRAGONFLY - DragonFlyBSD
// GTEST_OS_FREEBSD - FreeBSD
+// GTEST_OS_FUCHSIA - Fuchsia
+// GTEST_OS_GNU_KFREEBSD - GNU/kFreeBSD
+// GTEST_OS_HAIKU - Haiku
// GTEST_OS_HPUX - HP-UX
// GTEST_OS_LINUX - Linux
// GTEST_OS_LINUX_ANDROID - Google Android
// GTEST_OS_MAC - Mac OS X
// GTEST_OS_IOS - iOS
// GTEST_OS_NACL - Google Native Client (NaCl)
+// GTEST_OS_NETBSD - NetBSD
// GTEST_OS_OPENBSD - OpenBSD
+// GTEST_OS_OS2 - OS/2
// GTEST_OS_QNX - QNX
// GTEST_OS_SOLARIS - Sun Solaris
-// GTEST_OS_SYMBIAN - Symbian
// GTEST_OS_WINDOWS - Windows (Desktop, MinGW, or Mobile)
// GTEST_OS_WINDOWS_DESKTOP - Windows Desktop
// GTEST_OS_WINDOWS_MINGW - MinGW
@@ -140,7 +137,7 @@
// GTEST_OS_WINDOWS_RT - Windows Store App/WinRT
// GTEST_OS_ZOS - z/OS
//
-// Among the platforms, Cygwin, Linux, Max OS X, and Windows have the
+// Among the platforms, Cygwin, Linux, Mac OS X, and Windows have the
// most stable support. Since core members of the Google Test project
// don't have access to other platforms, support for them may be less
// stable. If you notice any problems on your platform, please notify
@@ -166,19 +163,16 @@
// EXPECT_DEATH(DoSomethingDeadly());
// #endif
//
-// GTEST_HAS_COMBINE - the Combine() function (for value-parameterized
-// tests)
// GTEST_HAS_DEATH_TEST - death tests
-// GTEST_HAS_PARAM_TEST - value-parameterized tests
// GTEST_HAS_TYPED_TEST - typed tests
// GTEST_HAS_TYPED_TEST_P - type-parameterized tests
// GTEST_IS_THREADSAFE - Google Test is thread-safe.
+// GOOGLETEST_CM0007 DO NOT DELETE
// GTEST_USES_POSIX_RE - enhanced POSIX regex is used. Do not confuse with
// GTEST_HAS_POSIX_RE (see above) which users can
// define themselves.
// GTEST_USES_SIMPLE_RE - our own simple regex is used;
-// the above two are mutually exclusive.
-// GTEST_CAN_COMPARE_NULL - accepts untyped NULL in EXPECT_EQ().
+// the above RE\b(s) are mutually exclusive.
// Misc public macros
// ------------------
@@ -204,28 +198,16 @@
// GTEST_INTENTIONAL_CONST_COND_POP_ - finish code section where MSVC C4127
// is suppressed.
//
-// C++11 feature wrappers:
-//
-// testing::internal::move - portability wrapper for std::move.
-//
// Synchronization:
// Mutex, MutexLock, ThreadLocal, GetThreadCount()
// - synchronization primitives.
//
-// Template meta programming:
-// is_pointer - as in TR1; needed on Symbian and IBM XL C/C++ only.
-// IteratorTraits - partial implementation of std::iterator_traits, which
-// is not available in libCstd when compiled with Sun C++.
-//
-// Smart pointers:
-// scoped_ptr - as in TR2.
-//
// Regular expressions:
// RE - a simple regular expression class using the POSIX
-// Extended Regular Expression syntax on UNIX-like
-// platforms, or a reduced regular exception syntax on
-// other platforms, including Windows.
-//
+// Extended Regular Expression syntax on UNIX-like platforms
+// GOOGLETEST_CM0008 DO NOT DELETE
+// or a reduced regular exception syntax on other
+// platforms, including Windows.
// Logging:
// GTEST_LOG_() - logs messages at the specified severity level.
// LogToStderr() - directs all log messages to stderr.
@@ -255,12 +237,20 @@
// BoolFromGTestEnv() - parses a bool environment variable.
// Int32FromGTestEnv() - parses an Int32 environment variable.
// StringFromGTestEnv() - parses a string environment variable.
+//
+// Deprecation warnings:
+// GTEST_INTERNAL_DEPRECATED(message) - attribute marking a function as
+// deprecated; calling a marked function
+// should generate a compiler warning
#include <ctype.h> // for isspace, etc
#include <stddef.h> // for ptrdiff_t
-#include <stdlib.h>
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
+#include <memory>
+#include <type_traits>
+
#ifndef _WIN32_WCE
# include <sys/types.h>
# include <sys/stat.h>
@@ -272,9 +262,10 @@
#endif
#include <algorithm> // NOLINT
-#include <iostream> // NOLINT
-#include <sstream> // NOLINT
-#include <string> // NOLINT
+#include <iostream> // NOLINT
+#include <sstream> // NOLINT
+#include <string> // NOLINT
+#include <tuple>
#include <utility>
#include <vector> // NOLINT
@@ -306,85 +297,32 @@
// GTEST_DISABLE_MSC_WARNINGS_PUSH_(4800 4385)
// /* code that triggers warnings C4800 and C4385 */
// GTEST_DISABLE_MSC_WARNINGS_POP_()
-#if _MSC_VER >= 1500
+#if defined(_MSC_VER)
# define GTEST_DISABLE_MSC_WARNINGS_PUSH_(warnings) \
__pragma(warning(push)) \
__pragma(warning(disable: warnings))
# define GTEST_DISABLE_MSC_WARNINGS_POP_() \
__pragma(warning(pop))
#else
-// Older versions of MSVC don't have __pragma.
+// Not all compilers are MSVC
# define GTEST_DISABLE_MSC_WARNINGS_PUSH_(warnings)
# define GTEST_DISABLE_MSC_WARNINGS_POP_()
#endif
-#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
-
-// Distinct from C++11 language support, some environments don't provide
-// proper C++11 library support. Notably, it's possible to build in
-// C++11 mode when targeting Mac OS X 10.6, which has an old libstdc++
-// with no C++11 support.
-//
-// libstdc++ has sufficient C++11 support as of GCC 4.6.0, __GLIBCXX__
-// 20110325, but maintenance releases in the 4.4 and 4.5 series followed
-// this date, so check for those versions by their date stamps.
-// https://gcc.gnu.org/onlinedocs/libstdc++/manual/abi.html#abi.versioning
-#if GTEST_LANG_CXX11 && \
- (!defined(__GLIBCXX__) || ( \
- __GLIBCXX__ >= 20110325ul && /* GCC >= 4.6.0 */ \
- /* Blacklist of patch releases of older branches: */ \
- __GLIBCXX__ != 20110416ul && /* GCC 4.4.6 */ \
- __GLIBCXX__ != 20120313ul && /* GCC 4.4.7 */ \
- __GLIBCXX__ != 20110428ul && /* GCC 4.5.3 */ \
- __GLIBCXX__ != 20120702ul)) /* GCC 4.5.4 */
-# define GTEST_STDLIB_CXX11 1
-#endif
-
-// Only use C++11 library features if the library provides them.
-#if GTEST_STDLIB_CXX11
-# define GTEST_HAS_STD_BEGIN_AND_END_ 1
-# define GTEST_HAS_STD_FORWARD_LIST_ 1
-# define GTEST_HAS_STD_FUNCTION_ 1
-# define GTEST_HAS_STD_INITIALIZER_LIST_ 1
-# define GTEST_HAS_STD_MOVE_ 1
-# define GTEST_HAS_STD_SHARED_PTR_ 1
-# define GTEST_HAS_STD_TYPE_TRAITS_ 1
-# define GTEST_HAS_STD_UNIQUE_PTR_ 1
-#endif
-
-// C++11 specifies that <tuple> provides std::tuple.
-// Some platforms still might not have it, however.
-#if GTEST_LANG_CXX11
-# define GTEST_HAS_STD_TUPLE_ 1
-# if defined(__clang__)
-// Inspired by http://clang.llvm.org/docs/LanguageExtensions.html#__has_include
-# if defined(__has_include) && !__has_include(<tuple>)
-# undef GTEST_HAS_STD_TUPLE_
-# endif
-# elif defined(_MSC_VER)
-// Inspired by boost/config/stdlib/dinkumware.hpp
-# if defined(_CPPLIB_VER) && _CPPLIB_VER < 520
-# undef GTEST_HAS_STD_TUPLE_
-# endif
-# elif defined(__GLIBCXX__)
-// Inspired by boost/config/stdlib/libstdcpp3.hpp,
-// http://gcc.gnu.org/gcc-4.2/changes.html and
-// http://gcc.gnu.org/onlinedocs/libstdc++/manual/bk01pt01ch01.html#manual.intro.status.standard.200x
-# if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 2)
-# undef GTEST_HAS_STD_TUPLE_
-# endif
-# endif
+// Clang on Windows does not understand MSVC's pragma warning.
+// We need clang-specific way to disable function deprecation warning.
+#ifdef __clang__
+# define GTEST_DISABLE_MSC_DEPRECATED_PUSH_() \
+ _Pragma("clang diagnostic push") \
+ _Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"") \
+ _Pragma("clang diagnostic ignored \"-Wdeprecated-implementations\"")
+#define GTEST_DISABLE_MSC_DEPRECATED_POP_() \
+ _Pragma("clang diagnostic pop")
+#else
+# define GTEST_DISABLE_MSC_DEPRECATED_PUSH_() \
+ GTEST_DISABLE_MSC_WARNINGS_PUSH_(4996)
+# define GTEST_DISABLE_MSC_DEPRECATED_POP_() \
+ GTEST_DISABLE_MSC_WARNINGS_POP_()
#endif
// Brings in definitions for functions used in the testing::internal::posix
@@ -396,10 +334,16 @@
# include <io.h>
# endif
// In order to avoid having to include <windows.h>, use forward declaration
-// assuming CRITICAL_SECTION is a typedef of _RTL_CRITICAL_SECTION.
+#if GTEST_OS_WINDOWS_MINGW && !defined(__MINGW64_VERSION_MAJOR)
+// MinGW defined _CRITICAL_SECTION and _RTL_CRITICAL_SECTION as two
+// separate (equivalent) structs, instead of using typedef
+typedef struct _CRITICAL_SECTION GTEST_CRITICAL_SECTION;
+#else
+// Assume CRITICAL_SECTION is a typedef of _RTL_CRITICAL_SECTION.
// This assumption is verified by
// WindowsTypesTest.CRITICAL_SECTIONIs_RTL_CRITICAL_SECTION.
-struct _RTL_CRITICAL_SECTION;
+typedef struct _RTL_CRITICAL_SECTION GTEST_CRITICAL_SECTION;
+#endif
#else
// This assumes that non-Windows OSes provide unistd.h. For OSes where this
// is not the case, we need to include headers that provide the functions
@@ -413,7 +357,8 @@ struct _RTL_CRITICAL_SECTION;
# include <android/api-level.h> // NOLINT
#endif
-// Defines this to true iff Google Test can use POSIX regular expressions.
+// Defines this to true if and only if Google Test can use POSIX regular
+// expressions.
#ifndef GTEST_HAS_POSIX_RE
# if GTEST_OS_LINUX_ANDROID
// On Android, <regex.h> is only available starting with Gingerbread.
@@ -453,8 +398,11 @@ struct _RTL_CRITICAL_SECTION;
#ifndef GTEST_HAS_EXCEPTIONS
// The user didn't tell us whether exceptions are enabled, so we need
// to figure it out.
-# if defined(_MSC_VER) || defined(__BORLANDC__)
-// MSVC's and C++Builder's implementations of the STL use the _HAS_EXCEPTIONS
+# if defined(_MSC_VER) && defined(_CPPUNWIND)
+// MSVC defines _CPPUNWIND to 1 if and only if exceptions are enabled.
+# define GTEST_HAS_EXCEPTIONS 1
+# elif defined(__BORLANDC__)
+// C++Builder's implementation of the STL uses the _HAS_EXCEPTIONS
// macro to enable exceptions, so we'll do the same.
// Assumes that exceptions are enabled by default.
# ifndef _HAS_EXCEPTIONS
@@ -462,16 +410,17 @@ struct _RTL_CRITICAL_SECTION;
# endif // _HAS_EXCEPTIONS
# define GTEST_HAS_EXCEPTIONS _HAS_EXCEPTIONS
# elif defined(__clang__)
-// clang defines __EXCEPTIONS iff exceptions are enabled before clang 220714,
-// but iff cleanups are enabled after that. In Obj-C++ files, there can be
-// cleanups for ObjC exceptions which also need cleanups, even if C++ exceptions
-// are disabled. clang has __has_feature(cxx_exceptions) which checks for C++
-// exceptions starting at clang r206352, but which checked for cleanups prior to
-// that. To reliably check for C++ exception availability with clang, check for
+// clang defines __EXCEPTIONS if and only if exceptions are enabled before clang
+// 220714, but if and only if cleanups are enabled after that. In Obj-C++ files,
+// there can be cleanups for ObjC exceptions which also need cleanups, even if
+// C++ exceptions are disabled. clang has __has_feature(cxx_exceptions) which
+// checks for C++ exceptions starting at clang r206352, but which checked for
+// cleanups prior to that. To reliably check for C++ exception availability with
+// clang, check for
// __EXCEPTIONS && __has_feature(cxx_exceptions).
# define GTEST_HAS_EXCEPTIONS (__EXCEPTIONS && __has_feature(cxx_exceptions))
# elif defined(__GNUC__) && __EXCEPTIONS
-// gcc defines __EXCEPTIONS to 1 iff exceptions are enabled.
+// gcc defines __EXCEPTIONS to 1 if and only if exceptions are enabled.
# define GTEST_HAS_EXCEPTIONS 1
# elif defined(__SUNPRO_CC)
// Sun Pro CC supports exceptions. However, there is no compile-time way of
@@ -479,7 +428,7 @@ struct _RTL_CRITICAL_SECTION;
// they are enabled unless the user tells us otherwise.
# define GTEST_HAS_EXCEPTIONS 1
# elif defined(__IBMCPP__) && __EXCEPTIONS
-// xlC defines __EXCEPTIONS to 1 iff exceptions are enabled.
+// xlC defines __EXCEPTIONS to 1 if and only if exceptions are enabled.
# define GTEST_HAS_EXCEPTIONS 1
# elif defined(__HP_aCC)
// Exception handling is in effect by default in HP aCC compiler. It has to
@@ -498,38 +447,21 @@ struct _RTL_CRITICAL_SECTION;
# define GTEST_HAS_STD_STRING 1
#elif !GTEST_HAS_STD_STRING
// The user told us that ::std::string isn't available.
-# error "Google Test cannot be used where ::std::string isn't available."
+# error "::std::string isn't available."
#endif // !defined(GTEST_HAS_STD_STRING)
-#ifndef GTEST_HAS_GLOBAL_STRING
-// The user didn't tell us whether ::string is available, so we need
-// to figure it out.
-
-# define GTEST_HAS_GLOBAL_STRING 0
-
-#endif // GTEST_HAS_GLOBAL_STRING
-
#ifndef GTEST_HAS_STD_WSTRING
// The user didn't tell us whether ::std::wstring is available, so we need
// to figure it out.
-// TODO(wan@google.com): uses autoconf to detect whether ::std::wstring
-// is available.
-
// Cygwin 1.7 and below doesn't support ::std::wstring.
// Solaris' libc++ doesn't support it either. Android has
// no support for it at least as recent as Froyo (2.2).
-# define GTEST_HAS_STD_WSTRING \
- (!(GTEST_OS_LINUX_ANDROID || GTEST_OS_CYGWIN || GTEST_OS_SOLARIS))
+#define GTEST_HAS_STD_WSTRING \
+ (!(GTEST_OS_LINUX_ANDROID || GTEST_OS_CYGWIN || GTEST_OS_SOLARIS || \
+ GTEST_OS_HAIKU))
#endif // GTEST_HAS_STD_WSTRING
-#ifndef GTEST_HAS_GLOBAL_WSTRING
-// The user didn't tell us whether ::wstring is available, so we need
-// to figure it out.
-# define GTEST_HAS_GLOBAL_WSTRING \
- (GTEST_HAS_STD_WSTRING && GTEST_HAS_GLOBAL_STRING)
-#endif // GTEST_HAS_GLOBAL_WSTRING
-
// Determines whether RTTI is available.
#ifndef GTEST_HAS_RTTI
// The user didn't tell us whether RTTI is enabled, so we need to
@@ -537,14 +469,15 @@ struct _RTL_CRITICAL_SECTION;
# ifdef _MSC_VER
-# ifdef _CPPRTTI // MSVC defines this macro iff RTTI is enabled.
+#ifdef _CPPRTTI // MSVC defines this macro if and only if RTTI is enabled.
# define GTEST_HAS_RTTI 1
# else
# define GTEST_HAS_RTTI 0
# endif
-// Starting with version 4.3.2, gcc defines __GXX_RTTI iff RTTI is enabled.
-# elif defined(__GNUC__) && (GTEST_GCC_VER_ >= 40302)
+// Starting with version 4.3.2, gcc defines __GXX_RTTI if and only if RTTI is
+// enabled.
+# elif defined(__GNUC__)
# ifdef __GXX_RTTI
// When building against STLport with the Android NDK and with
@@ -600,8 +533,11 @@ struct _RTL_CRITICAL_SECTION;
//
// 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 \
- || GTEST_OS_QNX || GTEST_OS_FREEBSD || GTEST_OS_NACL)
+#define GTEST_HAS_PTHREAD \
+ (GTEST_OS_LINUX || GTEST_OS_MAC || GTEST_OS_HPUX || GTEST_OS_QNX || \
+ GTEST_OS_FREEBSD || GTEST_OS_NACL || GTEST_OS_NETBSD || GTEST_OS_FUCHSIA || \
+ GTEST_OS_DRAGONFLY || GTEST_OS_GNU_KFREEBSD || GTEST_OS_OPENBSD || \
+ GTEST_OS_HAIKU)
#endif // GTEST_HAS_PTHREAD
#if GTEST_HAS_PTHREAD
@@ -613,138 +549,6 @@ struct _RTL_CRITICAL_SECTION;
# include <time.h> // NOLINT
#endif
-// Determines if hash_map/hash_set are available.
-// Only used for testing against those containers.
-#if !defined(GTEST_HAS_HASH_MAP_)
-# if _MSC_VER
-# define GTEST_HAS_HASH_MAP_ 1 // Indicates that hash_map is available.
-# define GTEST_HAS_HASH_SET_ 1 // Indicates that hash_set is available.
-# endif // _MSC_VER
-#endif // !defined(GTEST_HAS_HASH_MAP_)
-
-// Determines whether Google Test can use tr1/tuple. You can define
-// 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
-# endif
-#endif // GTEST_HAS_TR1_TUPLE
-
-// Determines whether Google Test's own tr1 tuple implementation
-// should be used.
-#ifndef GTEST_USE_OWN_TR1_TUPLE
-// 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, 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
-# endif
-
-#endif // GTEST_USE_OWN_TR1_TUPLE
-
-// To avoid conditional compilation everywhere, we make it
-// gtest-port.h's responsibility to #include the header implementing
-// tuple.
-#if GTEST_HAS_STD_TUPLE_
-# include <tuple> // IWYU pragma: export
-# define GTEST_TUPLE_NAMESPACE_ ::std
-#endif // GTEST_HAS_STD_TUPLE_
-
-// We include tr1::tuple even if std::tuple is available to define printers for
-// them.
-#if GTEST_HAS_TR1_TUPLE
-# ifndef GTEST_TUPLE_NAMESPACE_
-# define GTEST_TUPLE_NAMESPACE_ ::std::tr1
-# endif // GTEST_TUPLE_NAMESPACE_
-
-# if GTEST_USE_OWN_TR1_TUPLE
-# include "gtest/internal/gtest-tuple.h" // IWYU pragma: export // NOLINT
-# 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
-// use STLport's tuple implementation, which unfortunately doesn't
-// work as the copy of STLport distributed with Symbian is incomplete.
-// By making sure BOOST_HAS_TR1_TUPLE is undefined, we force Boost to
-// use its own tuple implementation.
-# ifdef BOOST_HAS_TR1_TUPLE
-# undef BOOST_HAS_TR1_TUPLE
-# endif // BOOST_HAS_TR1_TUPLE
-
-// This prevents <boost/tr1/detail/config.hpp>, which defines
-// BOOST_HAS_TR1_TUPLE, from being #included by Boost's <tuple>.
-# define BOOST_TR1_DETAIL_CONFIG_HPP_INCLUDED
-# include <tuple> // IWYU pragma: export // NOLINT
-
-# elif defined(__GNUC__) && (GTEST_GCC_VER_ >= 40000)
-// GCC 4.0+ implements tr1/tuple in the <tr1/tuple> header. This does
-// not conform to the TR1 spec, which requires the header to be <tuple>.
-
-# if !GTEST_HAS_RTTI && GTEST_GCC_VER_ < 40302
-// Until version 4.3.2, gcc has a bug that causes <tr1/functional>,
-// which is #included by <tr1/tuple>, to not compile when RTTI is
-// disabled. _TR1_FUNCTIONAL is the header guard for
-// <tr1/functional>. Hence the following #define is a hack to prevent
-// <tr1/functional> from being included.
-# define _TR1_FUNCTIONAL 1
-# include <tr1/tuple>
-# undef _TR1_FUNCTIONAL // Allows the user to #include
- // <tr1/functional> if he chooses to.
-# else
-# include <tr1/tuple> // NOLINT
-# endif // !GTEST_HAS_RTTI && GTEST_GCC_VER_ < 40302
-
-# else
-// If the compiler is not GCC 4.0+, we assume the user is using a
-// spec-conforming TR1 implementation.
-# include <tuple> // IWYU pragma: export // NOLINT
-# endif // GTEST_USE_OWN_TR1_TUPLE
-
-#endif // GTEST_HAS_TR1_TUPLE
-
// Determines whether clone(2) is supported.
// Usually it will only be available on Linux, excluding
// Linux on the Itanium architecture.
@@ -754,8 +558,12 @@ using ::std::tuple_size;
# if GTEST_OS_LINUX && !defined(__ia64__)
# if GTEST_OS_LINUX_ANDROID
-// On Android, clone() is only available on ARM starting with Gingerbread.
-# if defined(__arm__) && __ANDROID_API__ >= 9
+// On Android, clone() became available at different API levels for each 32-bit
+// architecture.
+# if defined(__LP64__) || \
+ (defined(__arm__) && __ANDROID_API__ >= 9) || \
+ (defined(__mips__) && __ANDROID_API__ >= 12) || \
+ (defined(__i386__) && __ANDROID_API__ >= 17)
# define GTEST_HAS_CLONE 1
# else
# define GTEST_HAS_CLONE 0
@@ -774,55 +582,41 @@ using ::std::tuple_size;
#ifndef GTEST_HAS_STREAM_REDIRECTION
// By default, we assume that stream redirection is supported on all
// platforms except known mobile ones.
-# if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN || \
- GTEST_OS_WINDOWS_PHONE || GTEST_OS_WINDOWS_RT
+# if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_WINDOWS_PHONE || GTEST_OS_WINDOWS_RT
# define GTEST_HAS_STREAM_REDIRECTION 0
# else
# define GTEST_HAS_STREAM_REDIRECTION 1
-# endif // !GTEST_OS_WINDOWS_MOBILE && !GTEST_OS_SYMBIAN
+# endif // !GTEST_OS_WINDOWS_MOBILE
#endif // GTEST_HAS_STREAM_REDIRECTION
// Determines whether to support death tests.
-// 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_CYGWIN || GTEST_OS_SOLARIS || \
- (GTEST_OS_MAC && !GTEST_OS_IOS) || \
- (GTEST_OS_WINDOWS_DESKTOP && _MSC_VER >= 1400) || \
- GTEST_OS_WINDOWS_MINGW || GTEST_OS_AIX || GTEST_OS_HPUX || \
- GTEST_OS_OPENBSD || GTEST_OS_QNX || GTEST_OS_FREEBSD)
+#if (GTEST_OS_LINUX || GTEST_OS_CYGWIN || GTEST_OS_SOLARIS || \
+ (GTEST_OS_MAC && !GTEST_OS_IOS) || \
+ (GTEST_OS_WINDOWS_DESKTOP && _MSC_VER) || GTEST_OS_WINDOWS_MINGW || \
+ GTEST_OS_AIX || GTEST_OS_HPUX || GTEST_OS_OPENBSD || GTEST_OS_QNX || \
+ GTEST_OS_FREEBSD || GTEST_OS_NETBSD || GTEST_OS_FUCHSIA || \
+ GTEST_OS_DRAGONFLY || GTEST_OS_GNU_KFREEBSD || GTEST_OS_HAIKU)
# define GTEST_HAS_DEATH_TEST 1
#endif
-// We don't support MSVC 7.1 with exceptions disabled now. Therefore
-// all the compilers we care about are adequate for supporting
-// value-parameterized tests.
-#define GTEST_HAS_PARAM_TEST 1
-
// Determines whether to support type-driven tests.
// Typed tests need <typeinfo> and variadic macros, which GCC, VC++ 8.0,
// Sun Pro CC, IBM Visual Age, and HP aCC support.
-#if defined(__GNUC__) || (_MSC_VER >= 1400) || defined(__SUNPRO_CC) || \
+#if defined(__GNUC__) || defined(_MSC_VER) || defined(__SUNPRO_CC) || \
defined(__IBMCPP__) || defined(__HP_aCC)
# define GTEST_HAS_TYPED_TEST 1
# define GTEST_HAS_TYPED_TEST_P 1
#endif
-// Determines whether to support Combine(). This only makes sense when
-// value-parameterized tests are enabled. The implementation doesn't
-// work on Sun Studio since it doesn't understand templated conversion
-// operators.
-#if GTEST_HAS_PARAM_TEST && GTEST_HAS_TR1_TUPLE && !defined(__SUNPRO_CC)
-# define GTEST_HAS_COMBINE 1
-#endif
-
// Determines whether the system compiler uses UTF-16 for encoding wide strings.
#define GTEST_WIDE_STRING_USES_UTF16_ \
- (GTEST_OS_WINDOWS || GTEST_OS_CYGWIN || GTEST_OS_SYMBIAN || GTEST_OS_AIX)
+ (GTEST_OS_WINDOWS || GTEST_OS_CYGWIN || GTEST_OS_AIX || GTEST_OS_OS2)
// Determines whether test results can be streamed to a socket.
-#if GTEST_OS_LINUX
+#if GTEST_OS_LINUX || GTEST_OS_GNU_KFREEBSD || GTEST_OS_DRAGONFLY || \
+ GTEST_OS_FREEBSD || GTEST_OS_NETBSD || GTEST_OS_OPENBSD
# define GTEST_CAN_STREAM_RESULTS_ 1
#endif
@@ -864,15 +658,33 @@ using ::std::tuple_size;
# define GTEST_ATTRIBUTE_UNUSED_
#endif
+// Use this annotation before a function that takes a printf format string.
+#if (defined(__GNUC__) || defined(__clang__)) && !defined(COMPILER_ICC)
+# if defined(__MINGW_PRINTF_FORMAT)
+// MinGW has two different printf implementations. Ensure the format macro
+// matches the selected implementation. See
+// https://sourceforge.net/p/mingw-w64/wiki2/gnu%20printf/.
+# define GTEST_ATTRIBUTE_PRINTF_(string_index, first_to_check) \
+ __attribute__((__format__(__MINGW_PRINTF_FORMAT, string_index, \
+ first_to_check)))
+# else
+# define GTEST_ATTRIBUTE_PRINTF_(string_index, first_to_check) \
+ __attribute__((__format__(__printf__, string_index, first_to_check)))
+# endif
+#else
+# define GTEST_ATTRIBUTE_PRINTF_(string_index, first_to_check)
+#endif
+
+
// A macro to disallow operator=
// This should be used in the private: declarations for a class.
-#define GTEST_DISALLOW_ASSIGN_(type)\
- void operator=(type const &)
+#define GTEST_DISALLOW_ASSIGN_(type) \
+ void operator=(type const &) = delete
// A macro to disallow copy constructor and operator=
// This should be used in the private: declarations for a class.
-#define GTEST_DISALLOW_COPY_AND_ASSIGN_(type)\
- type(type const &);\
+#define GTEST_DISALLOW_COPY_AND_ASSIGN_(type) \
+ type(type const &) = delete; \
GTEST_DISALLOW_ASSIGN_(type)
// Tell the compiler to warn about unused return values for functions declared
@@ -880,11 +692,11 @@ using ::std::tuple_size;
// following the argument list:
//
// Sprocket* AllocateSprocket() GTEST_MUST_USE_RESULT_;
-#if defined(__GNUC__) && (GTEST_GCC_VER_ >= 30400) && !defined(COMPILER_ICC)
+#if defined(__GNUC__) && !defined(COMPILER_ICC)
# define GTEST_MUST_USE_RESULT_ __attribute__ ((warn_unused_result))
#else
# define GTEST_MUST_USE_RESULT_
-#endif // __GNUC__ && (GTEST_GCC_VER_ >= 30400) && !COMPILER_ICC
+#endif // __GNUC__ && !COMPILER_ICC
// MS C++ compiler emits warning when a conditional expression is compile time
// constant. In some contexts this warning is false positive and needs to be
@@ -913,13 +725,22 @@ using ::std::tuple_size;
# define GTEST_HAS_SEH 0
# endif
-#define GTEST_IS_THREADSAFE \
- (GTEST_HAS_MUTEX_AND_THREAD_LOCAL_ \
- || (GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT) \
- || GTEST_HAS_PTHREAD)
-
#endif // GTEST_HAS_SEH
+#ifndef GTEST_IS_THREADSAFE
+
+#define GTEST_IS_THREADSAFE \
+ (GTEST_HAS_MUTEX_AND_THREAD_LOCAL_ || \
+ (GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT) || \
+ GTEST_HAS_PTHREAD)
+
+#endif // GTEST_IS_THREADSAFE
+
+// GTEST_API_ qualifies all symbols that must be exported. The definitions below
+// are guarded by #ifndef to give embedders a chance to define GTEST_API_ in
+// gtest/internal/custom/gtest-port.h
+#ifndef GTEST_API_
+
#ifdef _MSC_VER
# if GTEST_LINKED_AS_SHARED_LIBRARY
# define GTEST_API_ __declspec(dllimport)
@@ -928,11 +749,17 @@ using ::std::tuple_size;
# endif
#elif __GNUC__ >= 4 || defined(__clang__)
# define GTEST_API_ __attribute__((visibility ("default")))
-#endif // _MSC_VER
+#endif // _MSC_VER
+
+#endif // GTEST_API_
#ifndef GTEST_API_
# define GTEST_API_
-#endif
+#endif // GTEST_API_
+
+#ifndef GTEST_DEFAULT_DEATH_TEST_STYLE
+# define GTEST_DEFAULT_DEATH_TEST_STYLE "fast"
+#endif // GTEST_DEFAULT_DEATH_TEST_STYLE
#ifdef __GNUC__
// Ask the compiler to never inline a given function.
@@ -942,10 +769,12 @@ using ::std::tuple_size;
#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
+#if !defined(GTEST_HAS_CXXABI_H_)
+# if defined(__GLIBCXX__) || (defined(_LIBCPP_VERSION) && !defined(_MSC_VER))
+# define GTEST_HAS_CXXABI_H_ 1
+# else
+# define GTEST_HAS_CXXABI_H_ 0
+# endif
#endif
// A function level attribute to disable checking for use of uninitialized
@@ -973,6 +802,18 @@ using ::std::tuple_size;
# define GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_
#endif // __clang__
+// A function level attribute to disable HWAddressSanitizer instrumentation.
+#if defined(__clang__)
+# if __has_feature(hwaddress_sanitizer)
+# define GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_ \
+ __attribute__((no_sanitize("hwaddress")))
+# else
+# define GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_
+# endif // __has_feature(hwaddress_sanitizer)
+#else
+# define GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_
+#endif // __clang__
+
// A function level attribute to disable ThreadSanitizer instrumentation.
#if defined(__clang__)
# if __has_feature(thread_sanitizer)
@@ -989,16 +830,13 @@ namespace testing {
class Message;
-#if defined(GTEST_TUPLE_NAMESPACE_)
-// Import tuple and friends into the ::testing namespace.
-// It is part of our interface, having them in ::testing allows us to change
-// their types as needed.
-using GTEST_TUPLE_NAMESPACE_::get;
-using GTEST_TUPLE_NAMESPACE_::make_tuple;
-using GTEST_TUPLE_NAMESPACE_::tuple;
-using GTEST_TUPLE_NAMESPACE_::tuple_size;
-using GTEST_TUPLE_NAMESPACE_::tuple_element;
-#endif // defined(GTEST_TUPLE_NAMESPACE_)
+// Legacy imports for backwards compatibility.
+// New code should use std:: names directly.
+using std::get;
+using std::make_tuple;
+using std::tuple;
+using std::tuple_element;
+using std::tuple_size;
namespace internal {
@@ -1007,150 +845,30 @@ namespace internal {
// 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
-// size of a static array:
+// The GTEST_COMPILE_ASSERT_ is a legacy macro used to verify that a compile
+// time expression is true (in new code, use static_assert instead). For
+// example, you could use it to verify the size of a static array:
//
// GTEST_COMPILE_ASSERT_(GTEST_ARRAY_SIZE_(names) == NUM_NAMES,
// names_incorrect_size);
//
-// or to make sure a struct is smaller than a certain size:
-//
-// GTEST_COMPILE_ASSERT_(sizeof(foo) < 128, foo_too_large);
-//
-// The second argument to the macro is the name of the variable. If
-// the expression is false, most compilers will issue a warning/error
-// containing the name of the variable.
-
-#if GTEST_LANG_CXX11
-# define GTEST_COMPILE_ASSERT_(expr, msg) static_assert(expr, #msg)
-#else // !GTEST_LANG_CXX11
-template <bool>
- struct CompileAssert {
-};
-
-# define GTEST_COMPILE_ASSERT_(expr, msg) \
- typedef ::testing::internal::CompileAssert<(static_cast<bool>(expr))> \
- msg[static_cast<bool>(expr) ? 1 : -1] GTEST_ATTRIBUTE_UNUSED_
-#endif // !GTEST_LANG_CXX11
-
-// Implementation details of GTEST_COMPILE_ASSERT_:
-//
-// (In C++11, we simply use static_assert instead of the following)
-//
-// - GTEST_COMPILE_ASSERT_ works by defining an array type that has -1
-// elements (and thus is invalid) when the expression is false.
-//
-// - The simpler definition
-//
-// #define GTEST_COMPILE_ASSERT_(expr, msg) typedef char msg[(expr) ? 1 : -1]
-//
-// does not work, as gcc supports variable-length arrays whose sizes
-// are determined at run-time (this is gcc's extension and not part
-// of the C++ standard). As a result, gcc fails to reject the
-// following code with the simple definition:
-//
-// int foo;
-// GTEST_COMPILE_ASSERT_(foo, msg); // not supposed to compile as foo is
-// // not a compile-time constant.
-//
-// - By using the type CompileAssert<(bool(expr))>, we ensures that
-// expr is a compile-time constant. (Template arguments must be
-// determined at compile-time.)
-//
-// - The outter parentheses in CompileAssert<(bool(expr))> are necessary
-// to work around a bug in gcc 3.4.4 and 4.0.1. If we had written
-//
-// CompileAssert<bool(expr)>
-//
-// instead, these compilers will refuse to compile
-//
-// GTEST_COMPILE_ASSERT_(5 > 0, some_message);
-//
-// (They seem to think the ">" in "5 > 0" marks the end of the
-// template argument list.)
-//
-// - The array size is (bool(expr) ? 1 : -1), instead of simply
-//
-// ((expr) ? 1 : -1).
-//
-// This is to avoid running into a bug in MS VC 7.1, which
-// causes ((0.0) ? 1 : -1) to incorrectly evaluate to 1.
-
-// StaticAssertTypeEqHelper is used by StaticAssertTypeEq defined in gtest.h.
-//
-// This template is declared, but intentionally undefined.
-template <typename T1, typename T2>
-struct StaticAssertTypeEqHelper;
-
-template <typename T>
-struct StaticAssertTypeEqHelper<T, T> {
- enum { value = true };
-};
+// The second argument to the macro must be a valid C++ identifier. If the
+// expression is false, compiler will issue an error containing this identifier.
+#define GTEST_COMPILE_ASSERT_(expr, msg) static_assert(expr, #msg)
// Evaluates to the number of elements in 'array'.
#define GTEST_ARRAY_SIZE_(array) (sizeof(array) / sizeof(array[0]))
-#if GTEST_HAS_GLOBAL_STRING
-typedef ::string string;
-#else
-typedef ::std::string string;
-#endif // GTEST_HAS_GLOBAL_STRING
-
-#if GTEST_HAS_GLOBAL_WSTRING
-typedef ::wstring wstring;
-#elif GTEST_HAS_STD_WSTRING
-typedef ::std::wstring wstring;
-#endif // GTEST_HAS_GLOBAL_WSTRING
-
// A helper for suppressing warnings on constant condition. It just
// returns 'condition'.
GTEST_API_ bool IsTrue(bool condition);
-// Defines scoped_ptr.
-
-// This implementation of scoped_ptr is PARTIAL - it only contains
-// enough stuff to satisfy Google Test's need.
-template <typename T>
-class scoped_ptr {
- public:
- typedef T element_type;
-
- explicit scoped_ptr(T* p = NULL) : ptr_(p) {}
- ~scoped_ptr() { reset(); }
-
- T& operator*() const { return *ptr_; }
- T* operator->() const { return ptr_; }
- T* get() const { return ptr_; }
-
- T* release() {
- T* const ptr = ptr_;
- ptr_ = NULL;
- return ptr;
- }
-
- void reset(T* p = NULL) {
- if (p != ptr_) {
- if (IsTrue(sizeof(T) > 0)) { // Makes sure T is a complete type.
- delete ptr_;
- }
- ptr_ = p;
- }
- }
-
- friend void swap(scoped_ptr& a, scoped_ptr& b) {
- using std::swap;
- swap(a.ptr_, b.ptr_);
- }
-
- private:
- T* ptr_;
-
- GTEST_DISALLOW_COPY_AND_ASSIGN_(scoped_ptr);
-};
-
// Defines RE.
+#if GTEST_USES_PCRE
+// if used, PCRE is injected by custom/gtest-port.h
+#elif GTEST_USES_POSIX_RE || GTEST_USES_SIMPLE_RE
+
// A simple C++ wrapper for <regex.h>. It uses the POSIX Extended
// Regular Expression syntax.
class GTEST_API_ RE {
@@ -1162,25 +880,16 @@ class GTEST_API_ RE {
// Constructs an RE from a string.
RE(const ::std::string& regex) { Init(regex.c_str()); } // NOLINT
-#if GTEST_HAS_GLOBAL_STRING
-
- RE(const ::string& regex) { Init(regex.c_str()); } // NOLINT
-
-#endif // GTEST_HAS_GLOBAL_STRING
-
RE(const char* regex) { Init(regex); } // NOLINT
~RE();
// Returns the string representation of the regex.
const char* pattern() const { return pattern_; }
- // FullMatch(str, re) returns true iff regular expression re matches
- // the entire str.
- // PartialMatch(str, re) returns true iff regular expression re
+ // FullMatch(str, re) returns true if and only if regular expression re
+ // matches the entire str.
+ // PartialMatch(str, re) returns true if and only if regular expression re
// matches a substring of str (including str itself).
- //
- // TODO(wan@google.com): make FullMatch() and PartialMatch() work
- // when str contains NUL characters.
static bool FullMatch(const ::std::string& str, const RE& re) {
return FullMatch(str.c_str(), re);
}
@@ -1188,43 +897,30 @@ class GTEST_API_ RE {
return PartialMatch(str.c_str(), re);
}
-#if GTEST_HAS_GLOBAL_STRING
-
- static bool FullMatch(const ::string& str, const RE& re) {
- return FullMatch(str.c_str(), re);
- }
- static bool PartialMatch(const ::string& str, const RE& re) {
- return PartialMatch(str.c_str(), re);
- }
-
-#endif // GTEST_HAS_GLOBAL_STRING
-
static bool FullMatch(const char* str, const RE& re);
static bool PartialMatch(const char* str, const RE& re);
private:
void Init(const char* regex);
-
- // 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_;
-#if GTEST_USES_POSIX_RE
+# if GTEST_USES_POSIX_RE
regex_t full_regex_; // For FullMatch().
regex_t partial_regex_; // For PartialMatch().
-#else // GTEST_USES_SIMPLE_RE
+# else // GTEST_USES_SIMPLE_RE
const char* full_pattern_; // For FullMatch();
-#endif
+# endif
GTEST_DISALLOW_ASSIGN_(RE);
};
+#endif // GTEST_USES_PCRE
+
// 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);
@@ -1273,7 +969,7 @@ class GTEST_API_ GTestLog {
__FILE__, __LINE__).GetStream()
inline void LogToStderr() {}
-inline void FlushInfoLog() { fflush(NULL); }
+inline void FlushInfoLog() { fflush(nullptr); }
#endif // !defined(GTEST_LOG_)
@@ -1310,14 +1006,25 @@ inline void FlushInfoLog() { fflush(NULL); }
GTEST_LOG_(FATAL) << #posix_call << "failed with error " \
<< gtest_error
-#if GTEST_HAS_STD_MOVE_
-using std::move;
-#else // GTEST_HAS_STD_MOVE_
+// Transforms "T" into "const T&" according to standard reference collapsing
+// rules (this is only needed as a backport for C++98 compilers that do not
+// support reference collapsing). Specifically, it transforms:
+//
+// char ==> const char&
+// const char ==> const char&
+// char& ==> char&
+// const char& ==> const char&
+//
+// Note that the non-const reference will not have "const" added. This is
+// standard, and necessary so that "T" can always bind to "const T&".
template <typename T>
-const T& move(const T& t) {
- return t;
-}
-#endif // GTEST_HAS_STD_MOVE_
+struct ConstRef { typedef const T& type; };
+template <typename T>
+struct ConstRef<T&> { typedef T& type; };
+
+// The argument T must depend on some template parameters.
+#define GTEST_REFERENCE_TO_CONST_(T) \
+ typename ::testing::internal::ConstRef<T>::type
// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
//
@@ -1372,13 +1079,13 @@ inline To DownCast_(From* f) { // so we only accept pointers
GTEST_INTENTIONAL_CONST_COND_PUSH_()
if (false) {
GTEST_INTENTIONAL_CONST_COND_POP_()
- const To to = NULL;
- ::testing::internal::ImplicitCast_<From*>(to);
+ const To to = nullptr;
+ ::testing::internal::ImplicitCast_<From*>(to);
}
#if GTEST_HAS_RTTI
// RTTI: debug mode only!
- GTEST_CHECK_(f == NULL || dynamic_cast<To>(f) != NULL);
+ GTEST_CHECK_(f == nullptr || dynamic_cast<To>(f) != nullptr);
#endif
return static_cast<To>(f);
}
@@ -1417,10 +1124,6 @@ GTEST_API_ void CaptureStderr();
GTEST_API_ std::string GetCapturedStderr();
#endif // GTEST_HAS_STREAM_REDIRECTION
-
-// Returns a path to temporary directory.
-GTEST_API_ std::string TempDir();
-
// Returns the size (in bytes) of a file.
GTEST_API_ size_t GetFileSize(FILE* file);
@@ -1428,14 +1131,15 @@ GTEST_API_ size_t GetFileSize(FILE* file);
GTEST_API_ std::string ReadEntireFile(FILE* file);
// All command line arguments.
-GTEST_API_ const ::std::vector<testing::internal::string>& GetArgvs();
+GTEST_API_ std::vector<std::string> GetArgvs();
#if GTEST_HAS_DEATH_TEST
-const ::std::vector<testing::internal::string>& GetInjectableArgvs();
-void SetInjectableArgvs(const ::std::vector<testing::internal::string>*
- new_argvs);
-
+std::vector<std::string> GetInjectableArgvs();
+// Deprecated: pass the args vector by value instead.
+void SetInjectableArgvs(const std::vector<std::string>* new_argvs);
+void SetInjectableArgvs(const std::vector<std::string>& new_argvs);
+void ClearInjectableArgvs();
#endif // GTEST_HAS_DEATH_TEST
@@ -1450,7 +1154,7 @@ inline void SleepMilliseconds(int n) {
0, // 0 seconds.
n * 1000L * 1000L, // And n ms.
};
- nanosleep(&time, NULL);
+ nanosleep(&time, nullptr);
}
# endif // GTEST_HAS_PTHREAD
@@ -1468,7 +1172,7 @@ inline void SleepMilliseconds(int n) {
class Notification {
public:
Notification() : notified_(false) {
- GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_init(&mutex_, NULL));
+ GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_init(&mutex_, nullptr));
}
~Notification() {
pthread_mutex_destroy(&mutex_);
@@ -1526,7 +1230,8 @@ class GTEST_API_ AutoHandle {
void Reset(Handle handle);
private:
- // Returns true iff the handle is a valid handle object that can be closed.
+ // Returns true if and only if the handle is a valid handle object that can be
+ // closed.
bool IsCloseable() const;
Handle handle_;
@@ -1577,7 +1282,7 @@ class ThreadWithParamBase {
// pass into pthread_create().
extern "C" inline void* ThreadFuncWithCLinkage(void* thread) {
static_cast<ThreadWithParamBase*>(thread)->Run();
- return NULL;
+ return nullptr;
}
// Helper class for testing Google Test's multi-threading constructs.
@@ -1606,20 +1311,19 @@ class ThreadWithParam : public ThreadWithParamBase {
// The thread can be created only after all fields except thread_
// have been initialized.
GTEST_CHECK_POSIX_SUCCESS_(
- pthread_create(&thread_, 0, &ThreadFuncWithCLinkage, base));
+ pthread_create(&thread_, nullptr, &ThreadFuncWithCLinkage, base));
}
- ~ThreadWithParam() { Join(); }
+ ~ThreadWithParam() override { Join(); }
void Join() {
if (!finished_) {
- GTEST_CHECK_POSIX_SUCCESS_(pthread_join(thread_, 0));
+ GTEST_CHECK_POSIX_SUCCESS_(pthread_join(thread_, nullptr));
finished_ = true;
}
}
- virtual void Run() {
- if (thread_can_start_ != NULL)
- thread_can_start_->WaitForNotification();
+ void Run() override {
+ if (thread_can_start_ != nullptr) thread_can_start_->WaitForNotification();
func_(param_);
}
@@ -1629,7 +1333,8 @@ class ThreadWithParam : public ThreadWithParamBase {
// When non-NULL, used to block execution until the controller thread
// notifies.
Notification* const thread_can_start_;
- bool finished_; // true iff we know that the thread function has finished.
+ bool finished_; // true if and only if we know that the thread function has
+ // finished.
pthread_t thread_; // The native thread object.
GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadWithParam);
@@ -1685,7 +1390,7 @@ class GTEST_API_ Mutex {
// Initializes owner_thread_id_ and critical_section_ in static mutexes.
void ThreadSafeLazyInit();
- // Per http://blogs.msdn.com/b/oldnewthing/archive/2004/02/23/78395.aspx,
+ // Per https://blogs.msdn.microsoft.com/oldnewthing/20040223-00/?p=40503,
// we assume that 0 is an invalid value for thread IDs.
unsigned int owner_thread_id_;
@@ -1693,7 +1398,7 @@ class GTEST_API_ Mutex {
// by the linker.
MutexType type_;
long critical_section_init_phase_; // NOLINT
- _RTL_CRITICAL_SECTION* critical_section_;
+ GTEST_CRITICAL_SECTION* critical_section_;
GTEST_DISALLOW_COPY_AND_ASSIGN_(Mutex);
};
@@ -1913,7 +1618,7 @@ class ThreadLocal : public ThreadLocalBase {
GTEST_DISALLOW_COPY_AND_ASSIGN_(InstanceValueHolderFactory);
};
- scoped_ptr<ValueHolderFactory> default_factory_;
+ std::unique_ptr<ValueHolderFactory> default_factory_;
GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadLocal);
};
@@ -1969,15 +1674,20 @@ class MutexBase {
extern ::testing::internal::MutexBase mutex
// Defines and statically (i.e. at link time) initializes a static mutex.
-# define GTEST_DEFINE_STATIC_MUTEX_(mutex) \
- ::testing::internal::MutexBase mutex = { PTHREAD_MUTEX_INITIALIZER, false, pthread_t() }
+// 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, false, 0}
// The Mutex class can only be used for mutexes created at runtime. It
// shares its API with MutexBase otherwise.
class Mutex : public MutexBase {
public:
Mutex() {
- GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_init(&mutex_, NULL));
+ GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_init(&mutex_, nullptr));
has_owner_ = false;
}
~Mutex() {
@@ -2027,7 +1737,7 @@ extern "C" inline void DeleteThreadLocalValue(void* value_holder) {
// Implements thread-local storage on pthreads-based systems.
template <typename T>
-class ThreadLocal {
+class GTEST_API_ ThreadLocal {
public:
ThreadLocal()
: key_(CreateKey()), default_factory_(new DefaultValueHolderFactory()) {}
@@ -2075,7 +1785,7 @@ class ThreadLocal {
T* GetOrCreateValue() const {
ThreadLocalValueHolderBase* const holder =
static_cast<ThreadLocalValueHolderBase*>(pthread_getspecific(key_));
- if (holder != NULL) {
+ if (holder != nullptr) {
return CheckedDowncastToActualType<ValueHolder>(holder)->pointer();
}
@@ -2119,7 +1829,7 @@ class ThreadLocal {
// A key pthreads uses for looking up per-thread values.
const pthread_key_t key_;
- scoped_ptr<ValueHolderFactory> default_factory_;
+ std::unique_ptr<ValueHolderFactory> default_factory_;
GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadLocal);
};
@@ -2159,7 +1869,7 @@ class GTestMutexLock {
typedef GTestMutexLock MutexLock;
template <typename T>
-class ThreadLocal {
+class GTEST_API_ ThreadLocal {
public:
ThreadLocal() : value_() {}
explicit ThreadLocal(const T& value) : value_(value) {}
@@ -2177,58 +1887,8 @@ class ThreadLocal {
// we cannot detect it.
GTEST_API_ size_t GetThreadCount();
-// Passing non-POD classes through ellipsis (...) crashes the ARM
-// compiler and generates a warning in Sun Studio. The Nokia Symbian
-// and the IBM XL C/C++ compiler try to instantiate a copy constructor
-// for objects passed through ellipsis (...), failing for uncopyable
-// objects. We define this to ensure that only POD is passed through
-// ellipsis on these systems.
-#if defined(__SYMBIAN32__) || defined(__IBMCPP__) || defined(__SUNPRO_CC)
-// We lose support for NULL detection where the compiler doesn't like
-// passing non-POD classes through ellipsis (...).
-# define GTEST_ELLIPSIS_NEEDS_POD_ 1
-#else
-# define GTEST_CAN_COMPARE_NULL 1
-#endif
-
-// The Nokia Symbian and IBM XL C/C++ compilers cannot decide between
-// const T& and const T* in a function template. These compilers
-// _can_ decide between class template specializations for T and T*,
-// so a tr1::type_traits-like is_pointer works.
-#if defined(__SYMBIAN32__) || defined(__IBMCPP__)
-# define GTEST_NEEDS_IS_POINTER_ 1
-#endif
-
-template <bool bool_value>
-struct bool_constant {
- typedef bool_constant<bool_value> type;
- static const bool value = bool_value;
-};
-template <bool bool_value> const bool bool_constant<bool_value>::value;
-
-typedef bool_constant<false> false_type;
-typedef bool_constant<true> true_type;
-
-template <typename T>
-struct is_pointer : public false_type {};
-
-template <typename T>
-struct is_pointer<T*> : public true_type {};
-
-template <typename Iterator>
-struct IteratorTraits {
- typedef typename Iterator::value_type value_type;
-};
-
-template <typename T>
-struct IteratorTraits<T*> {
- typedef T value_type;
-};
-
-template <typename T>
-struct IteratorTraits<const T*> {
- typedef T value_type;
-};
+template <bool B>
+using bool_constant = std::integral_constant<bool, B>;
#if GTEST_OS_WINDOWS
# define GTEST_PATH_SEP_ "\\"
@@ -2351,7 +2011,7 @@ inline bool IsDir(const StatStruct& st) { return S_ISDIR(st.st_mode); }
// Functions deprecated by MSVC 8.0.
-GTEST_DISABLE_MSC_WARNINGS_PUSH_(4996 /* deprecated function */)
+GTEST_DISABLE_MSC_DEPRECATED_PUSH_()
inline const char* StrNCpy(char* dest, const char* src, size_t n) {
return strncpy(dest, src, n);
@@ -2385,29 +2045,29 @@ inline int Close(int fd) { return close(fd); }
inline const char* StrError(int errnum) { return strerror(errnum); }
#endif
inline const char* GetEnv(const char* name) {
-#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_WINDOWS_PHONE | GTEST_OS_WINDOWS_RT
+#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_WINDOWS_PHONE || GTEST_OS_WINDOWS_RT
// We are on Windows CE, which has no environment variables.
static_cast<void>(name); // To prevent 'unused argument' warning.
- return NULL;
+ return nullptr;
#elif defined(__BORLANDC__) || defined(__SunOS_5_8) || defined(__SunOS_5_9)
// Environment variables which we programmatically clear will be set to the
// empty string rather than unset (NULL). Handle that case.
const char* const env = getenv(name);
- return (env != NULL && env[0] != '\0') ? env : NULL;
+ return (env != nullptr && env[0] != '\0') ? env : nullptr;
#else
return getenv(name);
#endif
}
-GTEST_DISABLE_MSC_WARNINGS_POP_()
+GTEST_DISABLE_MSC_DEPRECATED_POP_()
#if GTEST_OS_WINDOWS_MOBILE
// Windows CE has no C library. The abort() function is used in
// several places in Google Test. This implementation provides a reasonable
// imitation of standard behaviour.
-void Abort();
+[[noreturn]] void Abort();
#else
-inline void Abort() { abort(); }
+[[noreturn]] inline void Abort() { abort(); }
#endif // GTEST_OS_WINDOWS_MOBILE
} // namespace posix
@@ -2417,13 +2077,12 @@ inline void Abort() { abort(); }
// 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
+#if _MSC_VER && !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.
+// Windows CE does not define _snprintf_s
# define GTEST_SNPRINTF_ _snprintf
#else
# define GTEST_SNPRINTF_ snprintf
@@ -2515,15 +2174,15 @@ typedef TypeWithSize<8>::Int TimeInMillis; // Represents time in milliseconds.
# define GTEST_DECLARE_bool_(name) GTEST_API_ extern bool GTEST_FLAG(name)
# define GTEST_DECLARE_int32_(name) \
GTEST_API_ extern ::testing::internal::Int32 GTEST_FLAG(name)
-#define GTEST_DECLARE_string_(name) \
+# define GTEST_DECLARE_string_(name) \
GTEST_API_ extern ::std::string GTEST_FLAG(name)
// Macros for defining flags.
-#define GTEST_DEFINE_bool_(name, default_val, doc) \
+# define GTEST_DEFINE_bool_(name, default_val, doc) \
GTEST_API_ bool GTEST_FLAG(name) = (default_val)
-#define GTEST_DEFINE_int32_(name, default_val, doc) \
+# 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) \
+# define GTEST_DEFINE_string_(name, default_val, doc) \
GTEST_API_ ::std::string GTEST_FLAG(name) = (default_val)
#endif // !defined(GTEST_DECLARE_bool_)
@@ -2537,18 +2196,36 @@ typedef TypeWithSize<8>::Int TimeInMillis; // Represents time in milliseconds.
// Parses 'str' for a 32-bit signed integer. If successful, writes the result
// to *value and returns true; otherwise leaves *value unchanged and returns
// false.
-// TODO(chandlerc): Find a better way to refactor flag and environment parsing
-// out of both gtest-port.cc and gtest.cc to avoid exporting this utility
-// function.
bool ParseInt32(const Message& src_text, const char* str, Int32* value);
// Parses a bool/Int32/string from the environment variable
// corresponding to the given Google Test flag.
bool BoolFromGTestEnv(const char* flag, bool default_val);
GTEST_API_ Int32 Int32FromGTestEnv(const char* flag, Int32 default_val);
-std::string StringFromGTestEnv(const char* flag, const char* default_val);
+std::string OutputFlagAlsoCheckEnvVar();
+const char* StringFromGTestEnv(const char* flag, const char* default_val);
} // namespace internal
} // namespace testing
+#if !defined(GTEST_INTERNAL_DEPRECATED)
+
+// Internal Macro to mark an API deprecated, for googletest usage only
+// Usage: class GTEST_INTERNAL_DEPRECATED(message) MyClass or
+// GTEST_INTERNAL_DEPRECATED(message) <return_type> myFunction(); Every usage of
+// a deprecated entity will trigger a warning when compiled with
+// `-Wdeprecated-declarations` option (clang, gcc, any __GNUC__ compiler).
+// For msvc /W3 option will need to be used
+// Note that for 'other' compilers this macro evaluates to nothing to prevent
+// compilations errors.
+#if defined(_MSC_VER)
+#define GTEST_INTERNAL_DEPRECATED(message) __declspec(deprecated(message))
+#elif defined(__GNUC__)
+#define GTEST_INTERNAL_DEPRECATED(message) __attribute__((deprecated(message)))
+#else
+#define GTEST_INTERNAL_DEPRECATED(message)
+#endif
+
+#endif // !defined(GTEST_INTERNAL_DEPRECATED)
+
#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_
diff --git a/extern/gtest/include/gtest/internal/gtest-string.h b/extern/gtest/include/gtest/internal/gtest-string.h
index 97f1a7fdd2c..82aaa63bf46 100644
--- a/extern/gtest/include/gtest/internal/gtest-string.h
+++ b/extern/gtest/include/gtest/internal/gtest-string.h
@@ -27,17 +27,17 @@
// (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)
+// The Google C++ Testing and Mocking 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>.
+// This header file is #included by gtest-internal.h.
// It should not be #included by other files.
+// GOOGLETEST_CM0001 DO NOT DELETE
+
#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_
#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_
@@ -94,7 +94,8 @@ class GTEST_API_ String {
static const char* Utf16ToAnsi(LPCWSTR utf16_str);
#endif
- // Compares two C strings. Returns true iff they have the same content.
+ // Compares two C strings. Returns true if and only if 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,
@@ -107,16 +108,16 @@ class GTEST_API_ String {
// returned.
static std::string ShowWideCString(const wchar_t* wide_c_str);
- // Compares two wide C strings. Returns true iff they have the same
- // content.
+ // Compares two wide C strings. Returns true if and only if 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.
+ // Compares two C strings, ignoring case. Returns true if and only if
+ // 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,
@@ -124,8 +125,8 @@ class GTEST_API_ 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.
+ // Compares two wide C strings, ignoring case. Returns true if and only if
+ // 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,
@@ -139,8 +140,8 @@ class GTEST_API_ String {
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.
+ // Returns true if and only if 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);
@@ -150,6 +151,9 @@ class GTEST_API_ String {
// Formats an int value as "%X".
static std::string FormatHexInt(int value);
+ // Formats an int value as "%X".
+ static std::string FormatHexUInt32(UInt32 value);
+
// Formats a byte as "%02X".
static std::string FormatByte(unsigned char value);
diff --git a/extern/gtest/include/gtest/internal/gtest-tuple.h b/extern/gtest/include/gtest/internal/gtest-tuple.h
deleted file mode 100644
index e9b405340a8..00000000000
--- a/extern/gtest/include/gtest/internal/gtest-tuple.h
+++ /dev/null
@@ -1,1020 +0,0 @@
-// This file was GENERATED by command:
-// pump.py gtest-tuple.h.pump
-// DO NOT EDIT BY HAND!!!
-
-// Copyright 2009 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.
-//
-// Author: wan@google.com (Zhanyong Wan)
-
-// Implements a subset of TR1 tuple needed by Google Test and Google Mock.
-
-#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_
-#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_
-
-#include <utility> // For ::std::pair.
-
-// The compiler used in Symbian has a bug that prevents us from declaring the
-// tuple template as a friend (it complains that tuple is redefined). This
-// hack bypasses the bug by declaring the members that should otherwise be
-// private as public.
-// Sun Studio versions < 12 also have the above bug.
-#if defined(__SYMBIAN32__) || (defined(__SUNPRO_CC) && __SUNPRO_CC < 0x590)
-# define GTEST_DECLARE_TUPLE_AS_FRIEND_ public:
-#else
-# define GTEST_DECLARE_TUPLE_AS_FRIEND_ \
- template <GTEST_10_TYPENAMES_(U)> friend class tuple; \
- private:
-#endif
-
-// Visual Studio 2010, 2012, and 2013 define symbols in std::tr1 that conflict
-// with our own definitions. Therefore using our own tuple does not work on
-// those compilers.
-#if defined(_MSC_VER) && _MSC_VER >= 1600 /* 1600 is Visual Studio 2010 */
-# error "gtest's tuple doesn't compile on Visual Studio 2010 or later. \
-GTEST_USE_OWN_TR1_TUPLE must be set to 0 on those compilers."
-#endif
-
-// GTEST_n_TUPLE_(T) is the type of an n-tuple.
-#define GTEST_0_TUPLE_(T) tuple<>
-#define GTEST_1_TUPLE_(T) tuple<T##0, void, void, void, void, void, void, \
- void, void, void>
-#define GTEST_2_TUPLE_(T) tuple<T##0, T##1, void, void, void, void, void, \
- void, void, void>
-#define GTEST_3_TUPLE_(T) tuple<T##0, T##1, T##2, void, void, void, void, \
- void, void, void>
-#define GTEST_4_TUPLE_(T) tuple<T##0, T##1, T##2, T##3, void, void, void, \
- void, void, void>
-#define GTEST_5_TUPLE_(T) tuple<T##0, T##1, T##2, T##3, T##4, void, void, \
- void, void, void>
-#define GTEST_6_TUPLE_(T) tuple<T##0, T##1, T##2, T##3, T##4, T##5, void, \
- void, void, void>
-#define GTEST_7_TUPLE_(T) tuple<T##0, T##1, T##2, T##3, T##4, T##5, T##6, \
- void, void, void>
-#define GTEST_8_TUPLE_(T) tuple<T##0, T##1, T##2, T##3, T##4, T##5, T##6, \
- T##7, void, void>
-#define GTEST_9_TUPLE_(T) tuple<T##0, T##1, T##2, T##3, T##4, T##5, T##6, \
- T##7, T##8, void>
-#define GTEST_10_TUPLE_(T) tuple<T##0, T##1, T##2, T##3, T##4, T##5, T##6, \
- T##7, T##8, T##9>
-
-// GTEST_n_TYPENAMES_(T) declares a list of n typenames.
-#define GTEST_0_TYPENAMES_(T)
-#define GTEST_1_TYPENAMES_(T) typename T##0
-#define GTEST_2_TYPENAMES_(T) typename T##0, typename T##1
-#define GTEST_3_TYPENAMES_(T) typename T##0, typename T##1, typename T##2
-#define GTEST_4_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \
- typename T##3
-#define GTEST_5_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \
- typename T##3, typename T##4
-#define GTEST_6_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \
- typename T##3, typename T##4, typename T##5
-#define GTEST_7_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \
- typename T##3, typename T##4, typename T##5, typename T##6
-#define GTEST_8_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \
- typename T##3, typename T##4, typename T##5, typename T##6, typename T##7
-#define GTEST_9_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \
- typename T##3, typename T##4, typename T##5, typename T##6, \
- typename T##7, typename T##8
-#define GTEST_10_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \
- typename T##3, typename T##4, typename T##5, typename T##6, \
- typename T##7, typename T##8, typename T##9
-
-// In theory, defining stuff in the ::std namespace is undefined
-// behavior. We can do this as we are playing the role of a standard
-// library vendor.
-namespace std {
-namespace tr1 {
-
-template <typename T0 = void, typename T1 = void, typename T2 = void,
- typename T3 = void, typename T4 = void, typename T5 = void,
- typename T6 = void, typename T7 = void, typename T8 = void,
- typename T9 = void>
-class tuple;
-
-// Anything in namespace gtest_internal is Google Test's INTERNAL
-// IMPLEMENTATION DETAIL and MUST NOT BE USED DIRECTLY in user code.
-namespace gtest_internal {
-
-// ByRef<T>::type is T if T is a reference; otherwise it's const T&.
-template <typename T>
-struct ByRef { typedef const T& type; }; // NOLINT
-template <typename T>
-struct ByRef<T&> { typedef T& type; }; // NOLINT
-
-// A handy wrapper for ByRef.
-#define GTEST_BY_REF_(T) typename ::std::tr1::gtest_internal::ByRef<T>::type
-
-// AddRef<T>::type is T if T is a reference; otherwise it's T&. This
-// is the same as tr1::add_reference<T>::type.
-template <typename T>
-struct AddRef { typedef T& type; }; // NOLINT
-template <typename T>
-struct AddRef<T&> { typedef T& type; }; // NOLINT
-
-// A handy wrapper for AddRef.
-#define GTEST_ADD_REF_(T) typename ::std::tr1::gtest_internal::AddRef<T>::type
-
-// A helper for implementing get<k>().
-template <int k> class Get;
-
-// A helper for implementing tuple_element<k, T>. kIndexValid is true
-// iff k < the number of fields in tuple type T.
-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;
-};
-
-template <GTEST_10_TYPENAMES_(T)>
-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;
-};
-
-template <GTEST_10_TYPENAMES_(T)>
-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;
-};
-
-template <GTEST_10_TYPENAMES_(T)>
-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;
-};
-
-template <GTEST_10_TYPENAMES_(T)>
-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;
-};
-
-template <GTEST_10_TYPENAMES_(T)>
-struct TupleElement<true, 9, GTEST_10_TUPLE_(T) > {
- typedef T9 type;
-};
-
-} // namespace gtest_internal
-
-template <>
-class tuple<> {
- public:
- tuple() {}
- tuple(const tuple& /* t */) {}
- tuple& operator=(const tuple& /* t */) { return *this; }
-};
-
-template <GTEST_1_TYPENAMES_(T)>
-class GTEST_1_TUPLE_(T) {
- public:
- template <int k> friend class gtest_internal::Get;
-
- tuple() : f0_() {}
-
- explicit tuple(GTEST_BY_REF_(T0) f0) : f0_(f0) {}
-
- tuple(const tuple& t) : f0_(t.f0_) {}
-
- template <GTEST_1_TYPENAMES_(U)>
- tuple(const GTEST_1_TUPLE_(U)& t) : f0_(t.f0_) {}
-
- tuple& operator=(const tuple& t) { return CopyFrom(t); }
-
- template <GTEST_1_TYPENAMES_(U)>
- tuple& operator=(const GTEST_1_TUPLE_(U)& t) {
- return CopyFrom(t);
- }
-
- GTEST_DECLARE_TUPLE_AS_FRIEND_
-
- template <GTEST_1_TYPENAMES_(U)>
- tuple& CopyFrom(const GTEST_1_TUPLE_(U)& t) {
- f0_ = t.f0_;
- return *this;
- }
-
- T0 f0_;
-};
-
-template <GTEST_2_TYPENAMES_(T)>
-class GTEST_2_TUPLE_(T) {
- public:
- template <int k> friend class gtest_internal::Get;
-
- tuple() : f0_(), f1_() {}
-
- explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1) : f0_(f0),
- f1_(f1) {}
-
- tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_) {}
-
- template <GTEST_2_TYPENAMES_(U)>
- tuple(const GTEST_2_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_) {}
- template <typename U0, typename U1>
- tuple(const ::std::pair<U0, U1>& p) : f0_(p.first), f1_(p.second) {}
-
- tuple& operator=(const tuple& t) { return CopyFrom(t); }
-
- template <GTEST_2_TYPENAMES_(U)>
- tuple& operator=(const GTEST_2_TUPLE_(U)& t) {
- return CopyFrom(t);
- }
- template <typename U0, typename U1>
- tuple& operator=(const ::std::pair<U0, U1>& p) {
- f0_ = p.first;
- f1_ = p.second;
- return *this;
- }
-
- GTEST_DECLARE_TUPLE_AS_FRIEND_
-
- template <GTEST_2_TYPENAMES_(U)>
- tuple& CopyFrom(const GTEST_2_TUPLE_(U)& t) {
- f0_ = t.f0_;
- f1_ = t.f1_;
- return *this;
- }
-
- T0 f0_;
- T1 f1_;
-};
-
-template <GTEST_3_TYPENAMES_(T)>
-class GTEST_3_TUPLE_(T) {
- public:
- template <int k> friend class gtest_internal::Get;
-
- tuple() : f0_(), f1_(), f2_() {}
-
- explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1,
- GTEST_BY_REF_(T2) f2) : f0_(f0), f1_(f1), f2_(f2) {}
-
- tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_) {}
-
- template <GTEST_3_TYPENAMES_(U)>
- tuple(const GTEST_3_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_) {}
-
- tuple& operator=(const tuple& t) { return CopyFrom(t); }
-
- template <GTEST_3_TYPENAMES_(U)>
- tuple& operator=(const GTEST_3_TUPLE_(U)& t) {
- return CopyFrom(t);
- }
-
- GTEST_DECLARE_TUPLE_AS_FRIEND_
-
- template <GTEST_3_TYPENAMES_(U)>
- tuple& CopyFrom(const GTEST_3_TUPLE_(U)& t) {
- f0_ = t.f0_;
- f1_ = t.f1_;
- f2_ = t.f2_;
- return *this;
- }
-
- T0 f0_;
- T1 f1_;
- T2 f2_;
-};
-
-template <GTEST_4_TYPENAMES_(T)>
-class GTEST_4_TUPLE_(T) {
- public:
- template <int k> friend class gtest_internal::Get;
-
- tuple() : f0_(), f1_(), f2_(), f3_() {}
-
- explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1,
- GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3) : f0_(f0), f1_(f1), f2_(f2),
- f3_(f3) {}
-
- tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_) {}
-
- template <GTEST_4_TYPENAMES_(U)>
- tuple(const GTEST_4_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_),
- f3_(t.f3_) {}
-
- tuple& operator=(const tuple& t) { return CopyFrom(t); }
-
- template <GTEST_4_TYPENAMES_(U)>
- tuple& operator=(const GTEST_4_TUPLE_(U)& t) {
- return CopyFrom(t);
- }
-
- GTEST_DECLARE_TUPLE_AS_FRIEND_
-
- template <GTEST_4_TYPENAMES_(U)>
- tuple& CopyFrom(const GTEST_4_TUPLE_(U)& t) {
- f0_ = t.f0_;
- f1_ = t.f1_;
- f2_ = t.f2_;
- f3_ = t.f3_;
- return *this;
- }
-
- T0 f0_;
- T1 f1_;
- T2 f2_;
- T3 f3_;
-};
-
-template <GTEST_5_TYPENAMES_(T)>
-class GTEST_5_TUPLE_(T) {
- public:
- template <int k> friend class gtest_internal::Get;
-
- tuple() : f0_(), f1_(), f2_(), f3_(), f4_() {}
-
- explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1,
- GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3,
- GTEST_BY_REF_(T4) f4) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4) {}
-
- tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_),
- f4_(t.f4_) {}
-
- template <GTEST_5_TYPENAMES_(U)>
- tuple(const GTEST_5_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_),
- f3_(t.f3_), f4_(t.f4_) {}
-
- tuple& operator=(const tuple& t) { return CopyFrom(t); }
-
- template <GTEST_5_TYPENAMES_(U)>
- tuple& operator=(const GTEST_5_TUPLE_(U)& t) {
- return CopyFrom(t);
- }
-
- GTEST_DECLARE_TUPLE_AS_FRIEND_
-
- template <GTEST_5_TYPENAMES_(U)>
- tuple& CopyFrom(const GTEST_5_TUPLE_(U)& t) {
- f0_ = t.f0_;
- f1_ = t.f1_;
- f2_ = t.f2_;
- f3_ = t.f3_;
- f4_ = t.f4_;
- return *this;
- }
-
- T0 f0_;
- T1 f1_;
- T2 f2_;
- T3 f3_;
- T4 f4_;
-};
-
-template <GTEST_6_TYPENAMES_(T)>
-class GTEST_6_TUPLE_(T) {
- public:
- template <int k> friend class gtest_internal::Get;
-
- tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_() {}
-
- explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1,
- GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4,
- GTEST_BY_REF_(T5) f5) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4),
- f5_(f5) {}
-
- tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_),
- f4_(t.f4_), f5_(t.f5_) {}
-
- template <GTEST_6_TYPENAMES_(U)>
- tuple(const GTEST_6_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_),
- f3_(t.f3_), f4_(t.f4_), f5_(t.f5_) {}
-
- tuple& operator=(const tuple& t) { return CopyFrom(t); }
-
- template <GTEST_6_TYPENAMES_(U)>
- tuple& operator=(const GTEST_6_TUPLE_(U)& t) {
- return CopyFrom(t);
- }
-
- GTEST_DECLARE_TUPLE_AS_FRIEND_
-
- template <GTEST_6_TYPENAMES_(U)>
- tuple& CopyFrom(const GTEST_6_TUPLE_(U)& t) {
- f0_ = t.f0_;
- f1_ = t.f1_;
- f2_ = t.f2_;
- f3_ = t.f3_;
- f4_ = t.f4_;
- f5_ = t.f5_;
- return *this;
- }
-
- T0 f0_;
- T1 f1_;
- T2 f2_;
- T3 f3_;
- T4 f4_;
- T5 f5_;
-};
-
-template <GTEST_7_TYPENAMES_(T)>
-class GTEST_7_TUPLE_(T) {
- public:
- template <int k> friend class gtest_internal::Get;
-
- tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_() {}
-
- explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1,
- GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4,
- GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6) : f0_(f0), f1_(f1), f2_(f2),
- f3_(f3), f4_(f4), f5_(f5), f6_(f6) {}
-
- tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_),
- f4_(t.f4_), f5_(t.f5_), f6_(t.f6_) {}
-
- template <GTEST_7_TYPENAMES_(U)>
- tuple(const GTEST_7_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_),
- f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_) {}
-
- tuple& operator=(const tuple& t) { return CopyFrom(t); }
-
- template <GTEST_7_TYPENAMES_(U)>
- tuple& operator=(const GTEST_7_TUPLE_(U)& t) {
- return CopyFrom(t);
- }
-
- GTEST_DECLARE_TUPLE_AS_FRIEND_
-
- template <GTEST_7_TYPENAMES_(U)>
- tuple& CopyFrom(const GTEST_7_TUPLE_(U)& t) {
- f0_ = t.f0_;
- f1_ = t.f1_;
- f2_ = t.f2_;
- f3_ = t.f3_;
- f4_ = t.f4_;
- f5_ = t.f5_;
- f6_ = t.f6_;
- return *this;
- }
-
- T0 f0_;
- T1 f1_;
- T2 f2_;
- T3 f3_;
- T4 f4_;
- T5 f5_;
- T6 f6_;
-};
-
-template <GTEST_8_TYPENAMES_(T)>
-class GTEST_8_TUPLE_(T) {
- public:
- template <int k> friend class gtest_internal::Get;
-
- tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_(), f7_() {}
-
- explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1,
- GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4,
- GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6,
- GTEST_BY_REF_(T7) f7) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4),
- f5_(f5), f6_(f6), f7_(f7) {}
-
- tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_),
- f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_) {}
-
- template <GTEST_8_TYPENAMES_(U)>
- tuple(const GTEST_8_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_),
- f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_) {}
-
- tuple& operator=(const tuple& t) { return CopyFrom(t); }
-
- template <GTEST_8_TYPENAMES_(U)>
- tuple& operator=(const GTEST_8_TUPLE_(U)& t) {
- return CopyFrom(t);
- }
-
- GTEST_DECLARE_TUPLE_AS_FRIEND_
-
- template <GTEST_8_TYPENAMES_(U)>
- tuple& CopyFrom(const GTEST_8_TUPLE_(U)& t) {
- f0_ = t.f0_;
- f1_ = t.f1_;
- f2_ = t.f2_;
- f3_ = t.f3_;
- f4_ = t.f4_;
- f5_ = t.f5_;
- f6_ = t.f6_;
- f7_ = t.f7_;
- return *this;
- }
-
- T0 f0_;
- T1 f1_;
- T2 f2_;
- T3 f3_;
- T4 f4_;
- T5 f5_;
- T6 f6_;
- T7 f7_;
-};
-
-template <GTEST_9_TYPENAMES_(T)>
-class GTEST_9_TUPLE_(T) {
- public:
- template <int k> friend class gtest_internal::Get;
-
- tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_(), f7_(), f8_() {}
-
- explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1,
- GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4,
- GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6, GTEST_BY_REF_(T7) f7,
- GTEST_BY_REF_(T8) f8) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4),
- f5_(f5), f6_(f6), f7_(f7), f8_(f8) {}
-
- tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_),
- f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_) {}
-
- template <GTEST_9_TYPENAMES_(U)>
- tuple(const GTEST_9_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_),
- f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_) {}
-
- tuple& operator=(const tuple& t) { return CopyFrom(t); }
-
- template <GTEST_9_TYPENAMES_(U)>
- tuple& operator=(const GTEST_9_TUPLE_(U)& t) {
- return CopyFrom(t);
- }
-
- GTEST_DECLARE_TUPLE_AS_FRIEND_
-
- template <GTEST_9_TYPENAMES_(U)>
- tuple& CopyFrom(const GTEST_9_TUPLE_(U)& t) {
- f0_ = t.f0_;
- f1_ = t.f1_;
- f2_ = t.f2_;
- f3_ = t.f3_;
- f4_ = t.f4_;
- f5_ = t.f5_;
- f6_ = t.f6_;
- f7_ = t.f7_;
- f8_ = t.f8_;
- return *this;
- }
-
- T0 f0_;
- T1 f1_;
- T2 f2_;
- T3 f3_;
- T4 f4_;
- T5 f5_;
- T6 f6_;
- T7 f7_;
- T8 f8_;
-};
-
-template <GTEST_10_TYPENAMES_(T)>
-class tuple {
- public:
- template <int k> friend class gtest_internal::Get;
-
- tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_(), f7_(), f8_(),
- f9_() {}
-
- explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1,
- GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4,
- GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6, GTEST_BY_REF_(T7) f7,
- GTEST_BY_REF_(T8) f8, GTEST_BY_REF_(T9) f9) : f0_(f0), f1_(f1), f2_(f2),
- f3_(f3), f4_(f4), f5_(f5), f6_(f6), f7_(f7), f8_(f8), f9_(f9) {}
-
- tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_),
- f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_), f9_(t.f9_) {}
-
- template <GTEST_10_TYPENAMES_(U)>
- tuple(const GTEST_10_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_),
- f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_),
- f9_(t.f9_) {}
-
- tuple& operator=(const tuple& t) { return CopyFrom(t); }
-
- template <GTEST_10_TYPENAMES_(U)>
- tuple& operator=(const GTEST_10_TUPLE_(U)& t) {
- return CopyFrom(t);
- }
-
- GTEST_DECLARE_TUPLE_AS_FRIEND_
-
- template <GTEST_10_TYPENAMES_(U)>
- tuple& CopyFrom(const GTEST_10_TUPLE_(U)& t) {
- f0_ = t.f0_;
- f1_ = t.f1_;
- f2_ = t.f2_;
- f3_ = t.f3_;
- f4_ = t.f4_;
- f5_ = t.f5_;
- f6_ = t.f6_;
- f7_ = t.f7_;
- f8_ = t.f8_;
- f9_ = t.f9_;
- return *this;
- }
-
- T0 f0_;
- T1 f1_;
- T2 f2_;
- T3 f3_;
- T4 f4_;
- T5 f5_;
- T6 f6_;
- T7 f7_;
- T8 f8_;
- T9 f9_;
-};
-
-// 6.1.3.2 Tuple creation functions.
-
-// Known limitations: we don't support passing an
-// std::tr1::reference_wrapper<T> to make_tuple(). And we don't
-// implement tie().
-
-inline tuple<> make_tuple() { return tuple<>(); }
-
-template <GTEST_1_TYPENAMES_(T)>
-inline GTEST_1_TUPLE_(T) make_tuple(const T0& f0) {
- return GTEST_1_TUPLE_(T)(f0);
-}
-
-template <GTEST_2_TYPENAMES_(T)>
-inline GTEST_2_TUPLE_(T) make_tuple(const T0& f0, const T1& f1) {
- return GTEST_2_TUPLE_(T)(f0, f1);
-}
-
-template <GTEST_3_TYPENAMES_(T)>
-inline GTEST_3_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2) {
- return GTEST_3_TUPLE_(T)(f0, f1, f2);
-}
-
-template <GTEST_4_TYPENAMES_(T)>
-inline GTEST_4_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2,
- const T3& f3) {
- return GTEST_4_TUPLE_(T)(f0, f1, f2, f3);
-}
-
-template <GTEST_5_TYPENAMES_(T)>
-inline GTEST_5_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2,
- const T3& f3, const T4& f4) {
- return GTEST_5_TUPLE_(T)(f0, f1, f2, f3, f4);
-}
-
-template <GTEST_6_TYPENAMES_(T)>
-inline GTEST_6_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2,
- const T3& f3, const T4& f4, const T5& f5) {
- return GTEST_6_TUPLE_(T)(f0, f1, f2, f3, f4, f5);
-}
-
-template <GTEST_7_TYPENAMES_(T)>
-inline GTEST_7_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2,
- const T3& f3, const T4& f4, const T5& f5, const T6& f6) {
- return GTEST_7_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6);
-}
-
-template <GTEST_8_TYPENAMES_(T)>
-inline GTEST_8_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2,
- const T3& f3, const T4& f4, const T5& f5, const T6& f6, const T7& f7) {
- return GTEST_8_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6, f7);
-}
-
-template <GTEST_9_TYPENAMES_(T)>
-inline GTEST_9_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2,
- const T3& f3, const T4& f4, const T5& f5, const T6& f6, const T7& f7,
- const T8& f8) {
- return GTEST_9_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6, f7, f8);
-}
-
-template <GTEST_10_TYPENAMES_(T)>
-inline GTEST_10_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2,
- const T3& f3, const T4& f4, const T5& f5, const T6& f6, const T7& f7,
- const T8& f8, const T9& f9) {
- return GTEST_10_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6, f7, f8, f9);
-}
-
-// 6.1.3.3 Tuple helper classes.
-
-template <typename Tuple> struct tuple_size;
-
-template <GTEST_0_TYPENAMES_(T)>
-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;
-};
-
-template <GTEST_2_TYPENAMES_(T)>
-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;
-};
-
-template <GTEST_4_TYPENAMES_(T)>
-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;
-};
-
-template <GTEST_6_TYPENAMES_(T)>
-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;
-};
-
-template <GTEST_8_TYPENAMES_(T)>
-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;
-};
-
-template <GTEST_10_TYPENAMES_(T)>
-struct tuple_size<GTEST_10_TUPLE_(T) > {
- static const int value = 10;
-};
-
-template <int k, class Tuple>
-struct tuple_element {
- typedef typename gtest_internal::TupleElement<
- k < (tuple_size<Tuple>::value), k, Tuple>::type type;
-};
-
-#define GTEST_TUPLE_ELEMENT_(k, Tuple) typename tuple_element<k, Tuple >::type
-
-// 6.1.3.4 Element access.
-
-namespace gtest_internal {
-
-template <>
-class Get<0> {
- public:
- template <class Tuple>
- static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(0, Tuple))
- Field(Tuple& t) { return t.f0_; } // NOLINT
-
- template <class Tuple>
- static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(0, Tuple))
- ConstField(const Tuple& t) { return t.f0_; }
-};
-
-template <>
-class Get<1> {
- public:
- template <class Tuple>
- static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(1, Tuple))
- Field(Tuple& t) { return t.f1_; } // NOLINT
-
- template <class Tuple>
- static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(1, Tuple))
- ConstField(const Tuple& t) { return t.f1_; }
-};
-
-template <>
-class Get<2> {
- public:
- template <class Tuple>
- static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(2, Tuple))
- Field(Tuple& t) { return t.f2_; } // NOLINT
-
- template <class Tuple>
- static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(2, Tuple))
- ConstField(const Tuple& t) { return t.f2_; }
-};
-
-template <>
-class Get<3> {
- public:
- template <class Tuple>
- static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(3, Tuple))
- Field(Tuple& t) { return t.f3_; } // NOLINT
-
- template <class Tuple>
- static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(3, Tuple))
- ConstField(const Tuple& t) { return t.f3_; }
-};
-
-template <>
-class Get<4> {
- public:
- template <class Tuple>
- static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(4, Tuple))
- Field(Tuple& t) { return t.f4_; } // NOLINT
-
- template <class Tuple>
- static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(4, Tuple))
- ConstField(const Tuple& t) { return t.f4_; }
-};
-
-template <>
-class Get<5> {
- public:
- template <class Tuple>
- static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(5, Tuple))
- Field(Tuple& t) { return t.f5_; } // NOLINT
-
- template <class Tuple>
- static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(5, Tuple))
- ConstField(const Tuple& t) { return t.f5_; }
-};
-
-template <>
-class Get<6> {
- public:
- template <class Tuple>
- static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(6, Tuple))
- Field(Tuple& t) { return t.f6_; } // NOLINT
-
- template <class Tuple>
- static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(6, Tuple))
- ConstField(const Tuple& t) { return t.f6_; }
-};
-
-template <>
-class Get<7> {
- public:
- template <class Tuple>
- static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(7, Tuple))
- Field(Tuple& t) { return t.f7_; } // NOLINT
-
- template <class Tuple>
- static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(7, Tuple))
- ConstField(const Tuple& t) { return t.f7_; }
-};
-
-template <>
-class Get<8> {
- public:
- template <class Tuple>
- static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(8, Tuple))
- Field(Tuple& t) { return t.f8_; } // NOLINT
-
- template <class Tuple>
- static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(8, Tuple))
- ConstField(const Tuple& t) { return t.f8_; }
-};
-
-template <>
-class Get<9> {
- public:
- template <class Tuple>
- static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(9, Tuple))
- Field(Tuple& t) { return t.f9_; } // NOLINT
-
- template <class Tuple>
- static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(9, Tuple))
- ConstField(const Tuple& t) { return t.f9_; }
-};
-
-} // namespace gtest_internal
-
-template <int k, GTEST_10_TYPENAMES_(T)>
-GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(k, GTEST_10_TUPLE_(T)))
-get(GTEST_10_TUPLE_(T)& t) {
- return gtest_internal::Get<k>::Field(t);
-}
-
-template <int k, GTEST_10_TYPENAMES_(T)>
-GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(k, GTEST_10_TUPLE_(T)))
-get(const GTEST_10_TUPLE_(T)& t) {
- return gtest_internal::Get<k>::ConstField(t);
-}
-
-// 6.1.3.5 Relational operators
-
-// We only implement == and !=, as we don't have a need for the rest yet.
-
-namespace gtest_internal {
-
-// SameSizeTuplePrefixComparator<k, k>::Eq(t1, t2) returns true if the
-// first k fields of t1 equals the first k fields of t2.
-// SameSizeTuplePrefixComparator(k1, k2) would be a compiler error if
-// k1 != k2.
-template <int kSize1, int kSize2>
-struct SameSizeTuplePrefixComparator;
-
-template <>
-struct SameSizeTuplePrefixComparator<0, 0> {
- template <class Tuple1, class Tuple2>
- static bool Eq(const Tuple1& /* t1 */, const Tuple2& /* t2 */) {
- return true;
- }
-};
-
-template <int k>
-struct SameSizeTuplePrefixComparator<k, k> {
- template <class Tuple1, class Tuple2>
- static bool Eq(const Tuple1& t1, const Tuple2& t2) {
- return SameSizeTuplePrefixComparator<k - 1, k - 1>::Eq(t1, t2) &&
- ::std::tr1::get<k - 1>(t1) == ::std::tr1::get<k - 1>(t2);
- }
-};
-
-} // namespace gtest_internal
-
-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);
-}
-
-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 !(t == u); }
-
-// 6.1.4 Pairs.
-// Unimplemented.
-
-} // namespace tr1
-} // namespace std
-
-#undef GTEST_0_TUPLE_
-#undef GTEST_1_TUPLE_
-#undef GTEST_2_TUPLE_
-#undef GTEST_3_TUPLE_
-#undef GTEST_4_TUPLE_
-#undef GTEST_5_TUPLE_
-#undef GTEST_6_TUPLE_
-#undef GTEST_7_TUPLE_
-#undef GTEST_8_TUPLE_
-#undef GTEST_9_TUPLE_
-#undef GTEST_10_TUPLE_
-
-#undef GTEST_0_TYPENAMES_
-#undef GTEST_1_TYPENAMES_
-#undef GTEST_2_TYPENAMES_
-#undef GTEST_3_TYPENAMES_
-#undef GTEST_4_TYPENAMES_
-#undef GTEST_5_TYPENAMES_
-#undef GTEST_6_TYPENAMES_
-#undef GTEST_7_TYPENAMES_
-#undef GTEST_8_TYPENAMES_
-#undef GTEST_9_TYPENAMES_
-#undef GTEST_10_TYPENAMES_
-
-#undef GTEST_DECLARE_TUPLE_AS_FRIEND_
-#undef GTEST_BY_REF_
-#undef GTEST_ADD_REF_
-#undef GTEST_TUPLE_ELEMENT_
-
-#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_
diff --git a/extern/gtest/include/gtest/internal/gtest-type-util.h b/extern/gtest/include/gtest/internal/gtest-type-util.h
index e46f7cfcb48..3d7542d1fb3 100644
--- a/extern/gtest/include/gtest/internal/gtest-type-util.h
+++ b/extern/gtest/include/gtest/internal/gtest-type-util.h
@@ -30,17 +30,17 @@
// 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.
-//
-// Author: wan@google.com (Zhanyong Wan)
// Type utilities needed for implementing typed and type-parameterized
// tests. This file is generated by a SCRIPT. DO NOT EDIT BY HAND!
//
// Currently we support at most 50 types in a list, and at most 50
-// type-parameterized tests in one type-parameterized test case.
+// type-parameterized tests in one type-parameterized test suite.
// Please contact googletestframework@googlegroups.com if you need
// more.
+// GOOGLETEST_CM0001 DO NOT DELETE
+
#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_
#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_
@@ -57,6 +57,22 @@
namespace testing {
namespace internal {
+// Canonicalizes a given name with respect to the Standard C++ Library.
+// This handles removing the inline namespace within `std` that is
+// used by various standard libraries (e.g., `std::__1`). Names outside
+// of namespace std are returned unmodified.
+inline std::string CanonicalizeForStdLibVersioning(std::string s) {
+ static const char prefix[] = "std::__";
+ if (s.compare(0, strlen(prefix), prefix) == 0) {
+ std::string::size_type end = s.find("::", strlen(prefix));
+ if (end != s.npos) {
+ // Erase everything between the initial `std` and the second `::`.
+ s.erase(strlen("std"), end - strlen("std"));
+ }
+ }
+ return s;
+}
+
// GetTypeName<T>() returns a human-readable name of type T.
// NB: This function is also used in Google Mock, so don't move it inside of
// the typed-test-only section below.
@@ -72,10 +88,10 @@ std::string GetTypeName() {
# if GTEST_HAS_CXXABI_H_
using abi::__cxa_demangle;
# endif // GTEST_HAS_CXXABI_H_
- char* const readable_name = __cxa_demangle(name, 0, 0, &status);
+ char* const readable_name = __cxa_demangle(name, nullptr, nullptr, &status);
const std::string name_str(status == 0 ? readable_name : name);
free(readable_name);
- return name_str;
+ return CanonicalizeForStdLibVersioning(name_str);
# else
return name;
# endif // GTEST_HAS_CXXABI_H_ || __HP_aCC
@@ -89,18 +105,6 @@ std::string GetTypeName() {
#if GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P
-// AssertyTypeEq<T1, T2>::type is defined iff T1 and T2 are the same
-// type. This can be used as a compile-time assertion to ensure that
-// two types are equal.
-
-template <typename T1, typename T2>
-struct AssertTypeEq;
-
-template <typename T>
-struct AssertTypeEq<T, T> {
- typedef bool type;
-};
-
// A unique type used as the default value for the arguments of class
// template Types. This allows us to simulate variadic templates
// (e.g. Types<int>, Type<int, double>, and etc), which C++ doesn't
@@ -3295,8 +3299,8 @@ struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
};
// The TypeList template makes it possible to use either a single type
-// or a Types<...> list in TYPED_TEST_CASE() and
-// INSTANTIATE_TYPED_TEST_CASE_P().
+// or a Types<...> list in TYPED_TEST_SUITE() and
+// INSTANTIATE_TYPED_TEST_SUITE_P().
template <typename T>
struct TypeList {
diff --git a/extern/gtest/src/gtest-all.cc b/extern/gtest/src/gtest-all.cc
index 0a9cee52233..ad292905cf3 100644
--- a/extern/gtest/src/gtest-all.cc
+++ b/extern/gtest/src/gtest-all.cc
@@ -26,10 +26,9 @@
// 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.
+
//
-// Author: mheule@google.com (Markus Heule)
-//
-// Google C++ Testing Framework (Google Test)
+// Google C++ Testing and Mocking Framework (Google Test)
//
// Sometimes it's desirable to build Google Test by compiling a single file.
// This file serves this purpose.
@@ -42,6 +41,7 @@
#include "src/gtest.cc"
#include "src/gtest-death-test.cc"
#include "src/gtest-filepath.cc"
+#include "src/gtest-matchers.cc"
#include "src/gtest-port.cc"
#include "src/gtest-printers.cc"
#include "src/gtest-test-part.cc"
diff --git a/extern/gtest/src/gtest-death-test.cc b/extern/gtest/src/gtest-death-test.cc
index a01a3698308..da09a1cfc23 100644
--- a/extern/gtest/src/gtest-death-test.cc
+++ b/extern/gtest/src/gtest-death-test.cc
@@ -26,12 +26,14 @@
// 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.
-//
-// Author: wan@google.com (Zhanyong Wan), vladl@google.com (Vlad Losev)
+
//
// This file implements death tests.
#include "gtest/gtest-death-test.h"
+
+#include <utility>
+
#include "gtest/internal/gtest-port.h"
#include "gtest/internal/custom/gtest.h"
@@ -62,26 +64,36 @@
# include <spawn.h>
# endif // GTEST_OS_QNX
+# if GTEST_OS_FUCHSIA
+# include <lib/fdio/fd.h>
+# include <lib/fdio/io.h>
+# include <lib/fdio/spawn.h>
+# include <lib/zx/channel.h>
+# include <lib/zx/port.h>
+# include <lib/zx/process.h>
+# include <lib/zx/socket.h>
+# include <zircon/processargs.h>
+# include <zircon/syscalls.h>
+# include <zircon/syscalls/policy.h>
+# include <zircon/syscalls/port.h>
+# endif // GTEST_OS_FUCHSIA
+
#endif // GTEST_HAS_DEATH_TEST
#include "gtest/gtest-message.h"
#include "gtest/internal/gtest-string.h"
-
-// Indicates that this translation unit is part of Google Test's
-// implementation. It must come before gtest-internal-inl.h is
-// included, or there will be a compiler error. This trick exists to
-// prevent the accidental inclusion of gtest-internal-inl.h in the
-// user's code.
-#define GTEST_IMPLEMENTATION_ 1
#include "src/gtest-internal-inl.h"
-#undef GTEST_IMPLEMENTATION_
namespace testing {
// Constants.
// The default death test style.
-static const char kDefaultDeathTestStyle[] = "fast";
+//
+// This is defined in internal/gtest-port.h as "fast", but can be overridden by
+// a definition in internal/custom/gtest-port.h. The recommended value, which is
+// used internally at Google, is "threadsafe".
+static const char kDefaultDeathTestStyle[] = GTEST_DEFAULT_DEATH_TEST_STYLE;
GTEST_DEFINE_string_(
death_test_style,
@@ -110,8 +122,8 @@ 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 "
- "the '|' characters. This flag is specified if and only if the current "
- "process is a sub-process launched for running a thread-safe "
+ "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
@@ -121,7 +133,7 @@ namespace internal {
// Valid only for fast death tests. Indicates the code is running in the
// child process of a fast style death test.
-# if !GTEST_OS_WINDOWS
+# if !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA
static bool g_in_fast_death_test_child = false;
# endif
@@ -131,10 +143,10 @@ static bool g_in_fast_death_test_child = false;
// 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
+# if GTEST_OS_WINDOWS || GTEST_OS_FUCHSIA
- // On Windows, death tests are thread-safe regardless of the value of the
- // death_test_style flag.
+ // On Windows and Fuchsia, death tests are thread-safe regardless of the value
+ // of the death_test_style flag.
return !GTEST_FLAG(internal_run_death_test).empty();
# else
@@ -154,7 +166,7 @@ ExitedWithCode::ExitedWithCode(int exit_code) : exit_code_(exit_code) {
// ExitedWithCode function-call operator.
bool ExitedWithCode::operator()(int exit_status) const {
-# if GTEST_OS_WINDOWS
+# if GTEST_OS_WINDOWS || GTEST_OS_FUCHSIA
return exit_status == exit_code_;
@@ -162,10 +174,10 @@ bool ExitedWithCode::operator()(int exit_status) const {
return WIFEXITED(exit_status) && WEXITSTATUS(exit_status) == exit_code_;
-# endif // GTEST_OS_WINDOWS
+# endif // GTEST_OS_WINDOWS || GTEST_OS_FUCHSIA
}
-# if !GTEST_OS_WINDOWS
+# if !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA
// KilledBySignal constructor.
KilledBySignal::KilledBySignal(int signum) : signum_(signum) {
}
@@ -182,7 +194,7 @@ bool KilledBySignal::operator()(int exit_status) const {
# endif // defined(GTEST_KILLED_BY_SIGNAL_OVERRIDE_)
return WIFSIGNALED(exit_status) && WTERMSIG(exit_status) == signum_;
}
-# endif // !GTEST_OS_WINDOWS
+# endif // !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA
namespace internal {
@@ -193,7 +205,7 @@ namespace internal {
static std::string ExitSummary(int exit_code) {
Message m;
-# if GTEST_OS_WINDOWS
+# if GTEST_OS_WINDOWS || GTEST_OS_FUCHSIA
m << "Exited with exit status " << exit_code;
@@ -209,7 +221,7 @@ static std::string ExitSummary(int exit_code) {
m << " (core dumped)";
}
# endif
-# endif // GTEST_OS_WINDOWS
+# endif // GTEST_OS_WINDOWS || GTEST_OS_FUCHSIA
return m.GetString();
}
@@ -220,7 +232,7 @@ bool ExitedUnsuccessfully(int exit_status) {
return !ExitedWithCode(0)(exit_status);
}
-# if !GTEST_OS_WINDOWS
+# if !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA
// Generates a textual failure message when a death test finds more than
// one thread running, or cannot determine the number of threads, prior
// to executing the given statement. It is the responsibility of the
@@ -229,13 +241,19 @@ 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_ << " ";
- if (thread_count == 0)
+ if (thread_count == 0) {
msg << "couldn't detect the number of threads.";
- else
+ } else {
msg << "detected " << thread_count << " threads.";
+ }
+ msg << " See "
+ "https://github.com/google/googletest/blob/master/googletest/docs/"
+ "advanced.md#death-tests-and-threads"
+ << " for more explanation and suggested solutions, especially if"
+ << " this is the last message you see before your test times out.";
return msg.GetString();
}
-# endif // !GTEST_OS_WINDOWS
+# endif // !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA
// Flag characters for reporting a death test that did not die.
static const char kDeathTestLived = 'L';
@@ -243,6 +261,13 @@ static const char kDeathTestReturned = 'R';
static const char kDeathTestThrew = 'T';
static const char kDeathTestInternalError = 'I';
+#if GTEST_OS_FUCHSIA
+
+// File descriptor used for the pipe in the child process.
+static const int kFuchsiaReadPipeFd = 3;
+
+#endif
+
// An enumeration describing all of the possible ways that a death test can
// conclude. DIED means that the process died while executing the test
// code; LIVED means that process lived beyond the end of the test code;
@@ -250,8 +275,6 @@ static const char kDeathTestInternalError = 'I';
// statement, which is not allowed; THREW means that the test statement
// returned control by throwing an exception. IN_PROGRESS means the test
// has not yet concluded.
-// TODO(vladl@google.com): Unify names and possibly values for
-// AbortReason, DeathTestOutcome, and flag characters above.
enum DeathTestOutcome { IN_PROGRESS, DIED, LIVED, RETURNED, THREW };
// Routine for aborting the program which is safe to call from an
@@ -259,13 +282,13 @@ 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 std::string& message) {
+static 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.
const InternalRunDeathTestFlag* const flag =
GetUnitTestImpl()->internal_run_death_test_flag();
- if (flag != NULL) {
+ if (flag != nullptr) {
FILE* parent = posix::FDOpen(flag->write_fd(), "w");
fputc(kDeathTestInternalError, parent);
fprintf(parent, "%s", message.c_str());
@@ -345,7 +368,7 @@ static void FailFromInternalError(int fd) {
// for the current test.
DeathTest::DeathTest() {
TestInfo* const info = GetUnitTestImpl()->current_test_info();
- if (info == NULL) {
+ if (info == nullptr) {
DeathTestAbort("Cannot run a death test outside of a TEST or "
"TEST_F construct");
}
@@ -353,10 +376,11 @@ DeathTest::DeathTest() {
// Creates and returns a death test by dispatching to the current
// death test factory.
-bool DeathTest::Create(const char* statement, const RE* regex,
- const char* file, int line, DeathTest** test) {
+bool DeathTest::Create(const char* statement,
+ Matcher<const std::string&> matcher, const char* file,
+ int line, DeathTest** test) {
return GetUnitTestImpl()->death_test_factory()->Create(
- statement, regex, file, line, test);
+ statement, std::move(matcher), file, line, test);
}
const char* DeathTest::LastMessage() {
@@ -372,9 +396,9 @@ std::string DeathTest::last_death_test_message_;
// Provides cross platform implementation for some death functionality.
class DeathTestImpl : public DeathTest {
protected:
- DeathTestImpl(const char* a_statement, const RE* a_regex)
+ DeathTestImpl(const char* a_statement, Matcher<const std::string&> matcher)
: statement_(a_statement),
- regex_(a_regex),
+ matcher_(std::move(matcher)),
spawned_(false),
status_(-1),
outcome_(IN_PROGRESS),
@@ -382,13 +406,12 @@ class DeathTestImpl : public DeathTest {
write_fd_(-1) {}
// read_fd_ is expected to be closed and cleared by a derived class.
- ~DeathTestImpl() { GTEST_DEATH_TEST_CHECK_(read_fd_ == -1); }
+ ~DeathTestImpl() override { GTEST_DEATH_TEST_CHECK_(read_fd_ == -1); }
- void Abort(AbortReason reason);
- virtual bool Passed(bool status_ok);
+ void Abort(AbortReason reason) override;
+ bool Passed(bool status_ok) override;
const char* statement() const { return statement_; }
- const RE* regex() const { return regex_; }
bool spawned() const { return spawned_; }
void set_spawned(bool is_spawned) { spawned_ = is_spawned; }
int status() const { return status_; }
@@ -406,13 +429,15 @@ class DeathTestImpl : public DeathTest {
// case of unexpected codes.
void ReadAndInterpretStatusByte();
+ // Returns stderr output from the child process.
+ virtual std::string GetErrorLogs();
+
private:
// The textual content of the code this object is testing. This class
// doesn't own this string and should not attempt to delete it.
const char* const statement_;
- // The regular expression which test output must match. DeathTestImpl
- // doesn't own this object and should not attempt to delete it.
- const RE* const regex_;
+ // A matcher that's expected to match the stderr output by the child process.
+ Matcher<const std::string&> matcher_;
// True if the death test child process has been successfully spawned.
bool spawned_;
// The exit status of the child process.
@@ -474,6 +499,10 @@ void DeathTestImpl::ReadAndInterpretStatusByte() {
set_read_fd(-1);
}
+std::string DeathTestImpl::GetErrorLogs() {
+ return GetCapturedStderr();
+}
+
// Signals that the death test code which should have exited, didn't.
// Should be called only in a death test child process.
// Writes a status byte to the child's status file descriptor, then
@@ -527,22 +556,21 @@ static ::std::string FormatDeathTestOutput(const ::std::string& output) {
// in the format specified by wait(2). On Windows, this is the
// value supplied to the ExitProcess() API or a numeric code
// of the exception that terminated the program.
-// regex: A regular expression object to be applied to
-// the test's captured standard error output; the death test
-// fails if it does not match.
+// matcher_: A matcher that's expected to match the stderr output by the child
+// process.
//
// Argument:
// status_ok: true if exit_status is acceptable in the context of
// this particular death test, which fails if it is false
//
-// Returns true iff all of the above conditions are met. Otherwise, the
-// first failing condition, in the order given above, is the one that is
+// Returns true if and only if all of the above conditions are met. Otherwise,
+// the first failing condition, in the order given above, is the one that is
// reported. Also sets the last death test message string.
bool DeathTestImpl::Passed(bool status_ok) {
if (!spawned())
return false;
- const std::string error_message = GetCapturedStderr();
+ const std::string error_message = GetErrorLogs();
bool success = false;
Message buffer;
@@ -563,13 +591,15 @@ bool DeathTestImpl::Passed(bool status_ok) {
break;
case DIED:
if (status_ok) {
- const bool matched = RE::PartialMatch(error_message.c_str(), *regex());
- if (matched) {
+ if (matcher_.Matches(error_message)) {
success = true;
} else {
+ std::ostringstream stream;
+ matcher_.DescribeTo(&stream);
buffer << " Result: died but not with expected error.\n"
- << " Expected: " << regex()->pattern() << "\n"
- << "Actual msg:\n" << FormatDeathTestOutput(error_message);
+ << " Expected: " << stream.str() << "\n"
+ << "Actual msg:\n"
+ << FormatDeathTestOutput(error_message);
}
} else {
buffer << " Result: died but not with expected exit code:\n"
@@ -618,11 +648,11 @@ bool DeathTestImpl::Passed(bool status_ok) {
//
class WindowsDeathTest : public DeathTestImpl {
public:
- WindowsDeathTest(const char* a_statement,
- const RE* a_regex,
- const char* file,
- int line)
- : DeathTestImpl(a_statement, a_regex), file_(file), line_(line) {}
+ WindowsDeathTest(const char* a_statement, Matcher<const std::string&> matcher,
+ const char* file, int line)
+ : DeathTestImpl(a_statement, std::move(matcher)),
+ file_(file),
+ line_(line) {}
// All of these virtual functions are inherited from DeathTest.
virtual int Wait();
@@ -699,7 +729,7 @@ DeathTest::TestRole WindowsDeathTest::AssumeRole() {
const TestInfo* const info = impl->current_test_info();
const int death_test_index = info->result()->death_test_count();
- if (flag != NULL) {
+ if (flag != nullptr) {
// ParseInternalRunDeathTestFlag() has performed all the necessary
// processing.
set_write_fd(flag->write_fd());
@@ -708,8 +738,8 @@ DeathTest::TestRole WindowsDeathTest::AssumeRole() {
// WindowsDeathTest uses an anonymous pipe to communicate results of
// a death test.
- SECURITY_ATTRIBUTES handles_are_inheritable = {
- sizeof(SECURITY_ATTRIBUTES), NULL, TRUE };
+ SECURITY_ATTRIBUTES handles_are_inheritable = {sizeof(SECURITY_ATTRIBUTES),
+ nullptr, TRUE};
HANDLE read_handle, write_handle;
GTEST_DEATH_TEST_CHECK_(
::CreatePipe(&read_handle, &write_handle, &handles_are_inheritable,
@@ -720,13 +750,13 @@ DeathTest::TestRole WindowsDeathTest::AssumeRole() {
write_handle_.Reset(write_handle);
event_handle_.Reset(::CreateEvent(
&handles_are_inheritable,
- TRUE, // The event will automatically reset to non-signaled state.
- FALSE, // The initial state is non-signalled.
- NULL)); // The even is unnamed.
- GTEST_DEATH_TEST_CHECK_(event_handle_.Get() != NULL);
- const std::string filter_flag =
- std::string("--") + GTEST_FLAG_PREFIX_ + kFilterFlag + "=" +
- info->test_case_name() + "." + info->name();
+ TRUE, // The event will automatically reset to non-signaled state.
+ FALSE, // The initial state is non-signalled.
+ nullptr)); // The even is unnamed.
+ GTEST_DEATH_TEST_CHECK_(event_handle_.Get() != nullptr);
+ const std::string filter_flag = std::string("--") + GTEST_FLAG_PREFIX_ +
+ kFilterFlag + "=" + info->test_suite_name() +
+ "." + info->name();
const std::string internal_flag =
std::string("--") + GTEST_FLAG_PREFIX_ + kInternalRunDeathTestFlag +
"=" + file_ + "|" + StreamableToString(line_) + "|" +
@@ -739,10 +769,9 @@ DeathTest::TestRole WindowsDeathTest::AssumeRole() {
"|" + StreamableToString(reinterpret_cast<size_t>(event_handle_.Get()));
char executable_path[_MAX_PATH + 1]; // NOLINT
- GTEST_DEATH_TEST_CHECK_(
- _MAX_PATH + 1 != ::GetModuleFileNameA(NULL,
- executable_path,
- _MAX_PATH));
+ GTEST_DEATH_TEST_CHECK_(_MAX_PATH + 1 != ::GetModuleFileNameA(nullptr,
+ executable_path,
+ _MAX_PATH));
std::string command_line =
std::string(::GetCommandLineA()) + " " + filter_flag + " \"" +
@@ -763,33 +792,290 @@ DeathTest::TestRole WindowsDeathTest::AssumeRole() {
startup_info.hStdError = ::GetStdHandle(STD_ERROR_HANDLE);
PROCESS_INFORMATION process_info;
- GTEST_DEATH_TEST_CHECK_(::CreateProcessA(
- executable_path,
- const_cast<char*>(command_line.c_str()),
- NULL, // Retuned process handle is not inheritable.
- NULL, // Retuned thread handle is not inheritable.
- TRUE, // Child inherits all inheritable handles (for write_handle_).
- 0x0, // Default creation flags.
- NULL, // Inherit the parent's environment.
- UnitTest::GetInstance()->original_working_dir(),
- &startup_info,
- &process_info) != FALSE);
+ GTEST_DEATH_TEST_CHECK_(
+ ::CreateProcessA(
+ executable_path, const_cast<char*>(command_line.c_str()),
+ nullptr, // Retuned process handle is not inheritable.
+ nullptr, // Retuned thread handle is not inheritable.
+ TRUE, // Child inherits all inheritable handles (for write_handle_).
+ 0x0, // Default creation flags.
+ nullptr, // Inherit the parent's environment.
+ UnitTest::GetInstance()->original_working_dir(), &startup_info,
+ &process_info) != FALSE);
child_handle_.Reset(process_info.hProcess);
::CloseHandle(process_info.hThread);
set_spawned(true);
return OVERSEE_TEST;
}
-# else // We are not on Windows.
+
+# elif GTEST_OS_FUCHSIA
+
+class FuchsiaDeathTest : public DeathTestImpl {
+ public:
+ FuchsiaDeathTest(const char* a_statement, Matcher<const std::string&> matcher,
+ const char* file, int line)
+ : DeathTestImpl(a_statement, std::move(matcher)),
+ file_(file),
+ line_(line) {}
+
+ // All of these virtual functions are inherited from DeathTest.
+ int Wait() override;
+ TestRole AssumeRole() override;
+ std::string GetErrorLogs() override;
+
+ private:
+ // 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.
+ const int line_;
+ // The stderr data captured by the child process.
+ std::string captured_stderr_;
+
+ zx::process child_process_;
+ zx::channel exception_channel_;
+ zx::socket stderr_socket_;
+};
+
+// Utility class for accumulating command-line arguments.
+class Arguments {
+ public:
+ Arguments() { args_.push_back(nullptr); }
+
+ ~Arguments() {
+ for (std::vector<char*>::iterator i = args_.begin(); i != args_.end();
+ ++i) {
+ free(*i);
+ }
+ }
+ void AddArgument(const char* argument) {
+ args_.insert(args_.end() - 1, posix::StrDup(argument));
+ }
+
+ template <typename Str>
+ void AddArguments(const ::std::vector<Str>& arguments) {
+ for (typename ::std::vector<Str>::const_iterator i = arguments.begin();
+ i != arguments.end();
+ ++i) {
+ args_.insert(args_.end() - 1, posix::StrDup(i->c_str()));
+ }
+ }
+ char* const* Argv() {
+ return &args_[0];
+ }
+
+ int size() {
+ return args_.size() - 1;
+ }
+
+ private:
+ std::vector<char*> args_;
+};
+
+// Waits for the child in a death test to exit, returning its exit
+// status, or 0 if no child process exists. As a side effect, sets the
+// outcome data member.
+int FuchsiaDeathTest::Wait() {
+ const int kProcessKey = 0;
+ const int kSocketKey = 1;
+ const int kExceptionKey = 2;
+
+ if (!spawned())
+ return 0;
+
+ // Create a port to wait for socket/task/exception events.
+ zx_status_t status_zx;
+ zx::port port;
+ status_zx = zx::port::create(0, &port);
+ GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK);
+
+ // Register to wait for the child process to terminate.
+ status_zx = child_process_.wait_async(
+ port, kProcessKey, ZX_PROCESS_TERMINATED, ZX_WAIT_ASYNC_ONCE);
+ GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK);
+
+ // Register to wait for the socket to be readable or closed.
+ status_zx = stderr_socket_.wait_async(
+ port, kSocketKey, ZX_SOCKET_READABLE | ZX_SOCKET_PEER_CLOSED,
+ ZX_WAIT_ASYNC_ONCE);
+ GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK);
+
+ // Register to wait for an exception.
+ status_zx = exception_channel_.wait_async(
+ port, kExceptionKey, ZX_CHANNEL_READABLE, ZX_WAIT_ASYNC_ONCE);
+ GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK);
+
+ bool process_terminated = false;
+ bool socket_closed = false;
+ do {
+ zx_port_packet_t packet = {};
+ status_zx = port.wait(zx::time::infinite(), &packet);
+ GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK);
+
+ if (packet.key == kExceptionKey) {
+ // Process encountered an exception. Kill it directly rather than
+ // letting other handlers process the event. We will get a kProcessKey
+ // event when the process actually terminates.
+ status_zx = child_process_.kill();
+ GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK);
+ } else if (packet.key == kProcessKey) {
+ // Process terminated.
+ GTEST_DEATH_TEST_CHECK_(ZX_PKT_IS_SIGNAL_ONE(packet.type));
+ GTEST_DEATH_TEST_CHECK_(packet.signal.observed & ZX_PROCESS_TERMINATED);
+ process_terminated = true;
+ } else if (packet.key == kSocketKey) {
+ GTEST_DEATH_TEST_CHECK_(ZX_PKT_IS_SIGNAL_ONE(packet.type));
+ if (packet.signal.observed & ZX_SOCKET_READABLE) {
+ // Read data from the socket.
+ constexpr size_t kBufferSize = 1024;
+ do {
+ size_t old_length = captured_stderr_.length();
+ size_t bytes_read = 0;
+ captured_stderr_.resize(old_length + kBufferSize);
+ status_zx = stderr_socket_.read(
+ 0, &captured_stderr_.front() + old_length, kBufferSize,
+ &bytes_read);
+ captured_stderr_.resize(old_length + bytes_read);
+ } while (status_zx == ZX_OK);
+ if (status_zx == ZX_ERR_PEER_CLOSED) {
+ socket_closed = true;
+ } else {
+ GTEST_DEATH_TEST_CHECK_(status_zx == ZX_ERR_SHOULD_WAIT);
+ status_zx = stderr_socket_.wait_async(
+ port, kSocketKey, ZX_SOCKET_READABLE | ZX_SOCKET_PEER_CLOSED,
+ ZX_WAIT_ASYNC_ONCE);
+ GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK);
+ }
+ } else {
+ GTEST_DEATH_TEST_CHECK_(packet.signal.observed & ZX_SOCKET_PEER_CLOSED);
+ socket_closed = true;
+ }
+ }
+ } while (!process_terminated && !socket_closed);
+
+ ReadAndInterpretStatusByte();
+
+ zx_info_process_t buffer;
+ status_zx = child_process_.get_info(
+ ZX_INFO_PROCESS, &buffer, sizeof(buffer), nullptr, nullptr);
+ GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK);
+
+ GTEST_DEATH_TEST_CHECK_(buffer.exited);
+ set_status(buffer.return_code);
+ return status();
+}
+
+// The AssumeRole process for a Fuchsia death test. It creates a child
+// process with the same executable as the current process to run the
+// death test. The child process is given the --gtest_filter and
+// --gtest_internal_run_death_test flags such that it knows to run the
+// current death test only.
+DeathTest::TestRole FuchsiaDeathTest::AssumeRole() {
+ const UnitTestImpl* const impl = GetUnitTestImpl();
+ const InternalRunDeathTestFlag* const flag =
+ impl->internal_run_death_test_flag();
+ const TestInfo* const info = impl->current_test_info();
+ const int death_test_index = info->result()->death_test_count();
+
+ if (flag != nullptr) {
+ // ParseInternalRunDeathTestFlag() has performed all the necessary
+ // processing.
+ set_write_fd(kFuchsiaReadPipeFd);
+ return EXECUTE_TEST;
+ }
+
+ // Flush the log buffers since the log streams are shared with the child.
+ FlushInfoLog();
+
+ // Build the child process command line.
+ const std::string filter_flag = std::string("--") + GTEST_FLAG_PREFIX_ +
+ kFilterFlag + "=" + info->test_suite_name() +
+ "." + info->name();
+ const std::string internal_flag =
+ std::string("--") + GTEST_FLAG_PREFIX_ + kInternalRunDeathTestFlag + "="
+ + file_ + "|"
+ + StreamableToString(line_) + "|"
+ + StreamableToString(death_test_index);
+ Arguments args;
+ args.AddArguments(GetInjectableArgvs());
+ args.AddArgument(filter_flag.c_str());
+ args.AddArgument(internal_flag.c_str());
+
+ // Build the pipe for communication with the child.
+ zx_status_t status;
+ zx_handle_t child_pipe_handle;
+ int child_pipe_fd;
+ status = fdio_pipe_half(&child_pipe_fd, &child_pipe_handle);
+ GTEST_DEATH_TEST_CHECK_(status == ZX_OK);
+ set_read_fd(child_pipe_fd);
+
+ // Set the pipe handle for the child.
+ fdio_spawn_action_t spawn_actions[2] = {};
+ fdio_spawn_action_t* add_handle_action = &spawn_actions[0];
+ add_handle_action->action = FDIO_SPAWN_ACTION_ADD_HANDLE;
+ add_handle_action->h.id = PA_HND(PA_FD, kFuchsiaReadPipeFd);
+ add_handle_action->h.handle = child_pipe_handle;
+
+ // Create a socket pair will be used to receive the child process' stderr.
+ zx::socket stderr_producer_socket;
+ status =
+ zx::socket::create(0, &stderr_producer_socket, &stderr_socket_);
+ GTEST_DEATH_TEST_CHECK_(status >= 0);
+ int stderr_producer_fd = -1;
+ status =
+ fdio_fd_create(stderr_producer_socket.release(), &stderr_producer_fd);
+ GTEST_DEATH_TEST_CHECK_(status >= 0);
+
+ // Make the stderr socket nonblocking.
+ GTEST_DEATH_TEST_CHECK_(fcntl(stderr_producer_fd, F_SETFL, 0) == 0);
+
+ fdio_spawn_action_t* add_stderr_action = &spawn_actions[1];
+ add_stderr_action->action = FDIO_SPAWN_ACTION_CLONE_FD;
+ add_stderr_action->fd.local_fd = stderr_producer_fd;
+ add_stderr_action->fd.target_fd = STDERR_FILENO;
+
+ // Create a child job.
+ zx_handle_t child_job = ZX_HANDLE_INVALID;
+ status = zx_job_create(zx_job_default(), 0, & child_job);
+ GTEST_DEATH_TEST_CHECK_(status == ZX_OK);
+ zx_policy_basic_t policy;
+ policy.condition = ZX_POL_NEW_ANY;
+ policy.policy = ZX_POL_ACTION_ALLOW;
+ status = zx_job_set_policy(
+ child_job, ZX_JOB_POL_RELATIVE, ZX_JOB_POL_BASIC, &policy, 1);
+ GTEST_DEATH_TEST_CHECK_(status == ZX_OK);
+
+ // Create an exception channel attached to the |child_job|, to allow
+ // us to suppress the system default exception handler from firing.
+ status =
+ zx_task_create_exception_channel(
+ child_job, 0, exception_channel_.reset_and_get_address());
+ GTEST_DEATH_TEST_CHECK_(status == ZX_OK);
+
+ // Spawn the child process.
+ status = fdio_spawn_etc(
+ child_job, FDIO_SPAWN_CLONE_ALL, args.Argv()[0], args.Argv(), nullptr,
+ 2, spawn_actions, child_process_.reset_and_get_address(), nullptr);
+ GTEST_DEATH_TEST_CHECK_(status == ZX_OK);
+
+ set_spawned(true);
+ return OVERSEE_TEST;
+}
+
+std::string FuchsiaDeathTest::GetErrorLogs() {
+ return captured_stderr_;
+}
+
+#else // We are neither on Windows, nor on Fuchsia.
// ForkingDeathTest provides implementations for most of the abstract
// methods of the DeathTest interface. Only the AssumeRole method is
// left undefined.
class ForkingDeathTest : public DeathTestImpl {
public:
- ForkingDeathTest(const char* statement, const RE* regex);
+ ForkingDeathTest(const char* statement, Matcher<const std::string&> matcher);
// All of these virtual functions are inherited from DeathTest.
- virtual int Wait();
+ int Wait() override;
protected:
void set_child_pid(pid_t child_pid) { child_pid_ = child_pid; }
@@ -800,9 +1086,9 @@ class ForkingDeathTest : public DeathTestImpl {
};
// Constructs a ForkingDeathTest.
-ForkingDeathTest::ForkingDeathTest(const char* a_statement, const RE* a_regex)
- : DeathTestImpl(a_statement, a_regex),
- child_pid_(-1) {}
+ForkingDeathTest::ForkingDeathTest(const char* a_statement,
+ Matcher<const std::string&> matcher)
+ : DeathTestImpl(a_statement, std::move(matcher)), child_pid_(-1) {}
// Waits for the child in a death test to exit, returning its exit
// status, or 0 if no child process exists. As a side effect, sets the
@@ -823,9 +1109,9 @@ int ForkingDeathTest::Wait() {
// in the child process.
class NoExecDeathTest : public ForkingDeathTest {
public:
- NoExecDeathTest(const char* a_statement, const RE* a_regex) :
- ForkingDeathTest(a_statement, a_regex) { }
- virtual TestRole AssumeRole();
+ NoExecDeathTest(const char* a_statement, Matcher<const std::string&> matcher)
+ : ForkingDeathTest(a_statement, std::move(matcher)) {}
+ TestRole AssumeRole() override;
};
// The AssumeRole process for a fork-and-run death test. It implements a
@@ -878,16 +1164,18 @@ DeathTest::TestRole NoExecDeathTest::AssumeRole() {
// only this specific death test to be run.
class ExecDeathTest : public ForkingDeathTest {
public:
- ExecDeathTest(const char* a_statement, const RE* a_regex,
- const char* file, int line) :
- ForkingDeathTest(a_statement, a_regex), file_(file), line_(line) { }
- virtual TestRole AssumeRole();
+ ExecDeathTest(const char* a_statement, Matcher<const std::string&> matcher,
+ const char* file, int line)
+ : ForkingDeathTest(a_statement, std::move(matcher)),
+ file_(file),
+ line_(line) {}
+ TestRole AssumeRole() override;
+
private:
- static ::std::vector<testing::internal::string>
- GetArgvsForDeathTestChildProcess() {
- ::std::vector<testing::internal::string> args = GetInjectableArgvs();
+ static ::std::vector<std::string> GetArgvsForDeathTestChildProcess() {
+ ::std::vector<std::string> args = GetInjectableArgvs();
# if defined(GTEST_EXTRA_DEATH_TEST_COMMAND_LINE_ARGS_)
- ::std::vector<testing::internal::string> extra_args =
+ ::std::vector<std::string> extra_args =
GTEST_EXTRA_DEATH_TEST_COMMAND_LINE_ARGS_();
args.insert(args.end(), extra_args.begin(), extra_args.end());
# endif // defined(GTEST_EXTRA_DEATH_TEST_COMMAND_LINE_ARGS_)
@@ -902,9 +1190,7 @@ class ExecDeathTest : public ForkingDeathTest {
// Utility class for accumulating command-line arguments.
class Arguments {
public:
- Arguments() {
- args_.push_back(NULL);
- }
+ Arguments() { args_.push_back(nullptr); }
~Arguments() {
for (std::vector<char*>::iterator i = args_.begin(); i != args_.end();
@@ -986,6 +1272,7 @@ static int ExecDeathTestChildMain(void* child_arg) {
}
# endif // !GTEST_OS_QNX
+# if GTEST_HAS_CLONE
// Two utility routines that together determine the direction the stack
// grows.
// This could be accomplished more elegantly by a single recursive
@@ -995,20 +1282,26 @@ 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.
-void StackLowerThanAddress(const void* ptr, bool* result) GTEST_NO_INLINE_;
-void StackLowerThanAddress(const void* ptr, bool* result) {
+static void StackLowerThanAddress(const void* ptr,
+ bool* result) GTEST_NO_INLINE_;
+// HWAddressSanitizer add a random tag to the MSB of the local variable address,
+// making comparison result unpredictable.
+GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_
+static void StackLowerThanAddress(const void* ptr, bool* result) {
int dummy;
*result = (&dummy < ptr);
}
// Make sure AddressSanitizer does not tamper with the stack here.
GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_
-bool StackGrowsDown() {
+GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_
+static bool StackGrowsDown() {
int dummy;
bool result;
StackLowerThanAddress(&dummy, &result);
return result;
}
+# endif // GTEST_HAS_CLONE
// 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
@@ -1046,7 +1339,8 @@ static pid_t ExecDeathTestSpawnChild(char* const* argv, int close_fd) {
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());
+ child_pid =
+ spawn(args.argv[0], 0, nullptr, &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));
@@ -1070,9 +1364,9 @@ static pid_t ExecDeathTestSpawnChild(char* const* argv, int close_fd) {
if (!use_fork) {
static const bool stack_grows_down = StackGrowsDown();
- const size_t stack_size = getpagesize();
+ const auto stack_size = static_cast<size_t>(getpagesize());
// MMAP_ANONYMOUS is not defined on Mac, so we use MAP_ANON instead.
- void* const stack = mmap(NULL, stack_size, PROT_READ | PROT_WRITE,
+ void* const stack = mmap(nullptr, stack_size, PROT_READ | PROT_WRITE,
MAP_ANON | MAP_PRIVATE, -1, 0);
GTEST_DEATH_TEST_CHECK_(stack != MAP_FAILED);
@@ -1086,8 +1380,9 @@ static pid_t ExecDeathTestSpawnChild(char* const* argv, int close_fd) {
void* const stack_top =
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);
+ GTEST_DEATH_TEST_CHECK_(
+ static_cast<size_t>(stack_size) > kMaxStackAlignment &&
+ reinterpret_cast<uintptr_t>(stack_top) % kMaxStackAlignment == 0);
child_pid = clone(&ExecDeathTestChildMain, stack_top, SIGCHLD, &args);
@@ -1104,7 +1399,7 @@ static pid_t ExecDeathTestSpawnChild(char* const* argv, int close_fd) {
# endif // GTEST_OS_QNX
# if GTEST_OS_LINUX
GTEST_DEATH_TEST_CHECK_SYSCALL_(
- sigaction(SIGPROF, &saved_sigprof_action, NULL));
+ sigaction(SIGPROF, &saved_sigprof_action, nullptr));
# endif // GTEST_OS_LINUX
GTEST_DEATH_TEST_CHECK_(child_pid != -1);
@@ -1122,7 +1417,7 @@ DeathTest::TestRole ExecDeathTest::AssumeRole() {
const TestInfo* const info = impl->current_test_info();
const int death_test_index = info->result()->death_test_count();
- if (flag != NULL) {
+ if (flag != nullptr) {
set_write_fd(flag->write_fd());
return EXECUTE_TEST;
}
@@ -1133,9 +1428,9 @@ 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 std::string filter_flag =
- std::string("--") + GTEST_FLAG_PREFIX_ + kFilterFlag + "="
- + info->test_case_name() + "." + info->name();
+ const std::string filter_flag = std::string("--") + GTEST_FLAG_PREFIX_ +
+ kFilterFlag + "=" + info->test_suite_name() +
+ "." + info->name();
const std::string internal_flag =
std::string("--") + GTEST_FLAG_PREFIX_ + kInternalRunDeathTestFlag + "="
+ file_ + "|" + StreamableToString(line_) + "|"
@@ -1168,7 +1463,8 @@ DeathTest::TestRole ExecDeathTest::AssumeRole() {
// by the "test" argument to its address. If the test should be
// skipped, sets that pointer to NULL. Returns true, unless the
// flag is set to an invalid value.
-bool DefaultDeathTestFactory::Create(const char* statement, const RE* regex,
+bool DefaultDeathTestFactory::Create(const char* statement,
+ Matcher<const std::string&> matcher,
const char* file, int line,
DeathTest** test) {
UnitTestImpl* const impl = GetUnitTestImpl();
@@ -1177,7 +1473,7 @@ bool DefaultDeathTestFactory::Create(const char* statement, const RE* regex,
const int death_test_index = impl->current_test_info()
->increment_death_test_count();
- if (flag != NULL) {
+ if (flag != nullptr) {
if (death_test_index > flag->index()) {
DeathTest::set_last_death_test_message(
"Death test count (" + StreamableToString(death_test_index)
@@ -1188,7 +1484,7 @@ bool DefaultDeathTestFactory::Create(const char* statement, const RE* regex,
if (!(flag->file() == file && flag->line() == line &&
flag->index() == death_test_index)) {
- *test = NULL;
+ *test = nullptr;
return true;
}
}
@@ -1197,15 +1493,22 @@ bool DefaultDeathTestFactory::Create(const char* statement, const RE* regex,
if (GTEST_FLAG(death_test_style) == "threadsafe" ||
GTEST_FLAG(death_test_style) == "fast") {
- *test = new WindowsDeathTest(statement, regex, file, line);
+ *test = new WindowsDeathTest(statement, std::move(matcher), file, line);
+ }
+
+# elif GTEST_OS_FUCHSIA
+
+ if (GTEST_FLAG(death_test_style) == "threadsafe" ||
+ GTEST_FLAG(death_test_style) == "fast") {
+ *test = new FuchsiaDeathTest(statement, std::move(matcher), file, line);
}
# else
if (GTEST_FLAG(death_test_style) == "threadsafe") {
- *test = new ExecDeathTest(statement, regex, file, line);
+ *test = new ExecDeathTest(statement, std::move(matcher), file, line);
} else if (GTEST_FLAG(death_test_style) == "fast") {
- *test = new NoExecDeathTest(statement, regex);
+ *test = new NoExecDeathTest(statement, std::move(matcher));
}
# endif // GTEST_OS_WINDOWS
@@ -1224,7 +1527,7 @@ bool DefaultDeathTestFactory::Create(const char* statement, const RE* regex,
// Recreates the pipe and event handles from the provided parameters,
// signals the event, and returns a file descriptor wrapped around the pipe
// handle. This function is called in the child process only.
-int GetStatusFileDescriptor(unsigned int parent_process_id,
+static int GetStatusFileDescriptor(unsigned int parent_process_id,
size_t write_handle_as_size_t,
size_t event_handle_as_size_t) {
AutoHandle parent_process_handle(::OpenProcess(PROCESS_DUP_HANDLE,
@@ -1235,15 +1538,13 @@ int GetStatusFileDescriptor(unsigned int parent_process_id,
StreamableToString(parent_process_id));
}
- // TODO(vladl@google.com): Replace the following check with a
- // compile-time assertion when available.
GTEST_CHECK_(sizeof(HANDLE) <= sizeof(size_t));
const HANDLE write_handle =
reinterpret_cast<HANDLE>(write_handle_as_size_t);
HANDLE dup_write_handle;
- // The newly initialized handle is accessible only in in the parent
+ // The newly initialized handle is accessible only in the parent
// process. To obtain one accessible within the child, we need to use
// DuplicateHandle.
if (!::DuplicateHandle(parent_process_handle.Get(), write_handle,
@@ -1292,7 +1593,7 @@ int GetStatusFileDescriptor(unsigned int parent_process_id,
// initialized from the GTEST_FLAG(internal_run_death_test) flag if
// the flag is specified; otherwise returns NULL.
InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag() {
- if (GTEST_FLAG(internal_run_death_test) == "") return NULL;
+ if (GTEST_FLAG(internal_run_death_test) == "") return nullptr;
// GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we
// can use it here.
@@ -1320,6 +1621,16 @@ InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag() {
write_fd = GetStatusFileDescriptor(parent_process_id,
write_handle_as_size_t,
event_handle_as_size_t);
+
+# elif GTEST_OS_FUCHSIA
+
+ if (fields.size() != 3
+ || !ParseNaturalNumber(fields[1], &line)
+ || !ParseNaturalNumber(fields[2], &index)) {
+ DeathTestAbort("Bad --gtest_internal_run_death_test flag: "
+ + GTEST_FLAG(internal_run_death_test));
+ }
+
# else
if (fields.size() != 4
diff --git a/extern/gtest/src/gtest-filepath.cc b/extern/gtest/src/gtest-filepath.cc
index 0292dc11957..bd7b99ff03e 100644
--- a/extern/gtest/src/gtest-filepath.cc
+++ b/extern/gtest/src/gtest-filepath.cc
@@ -26,28 +26,25 @@
// 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: keith.ray@gmail.com (Keith Ray)
-#include "gtest/gtest-message.h"
#include "gtest/internal/gtest-filepath.h"
-#include "gtest/internal/gtest-port.h"
#include <stdlib.h>
+#include "gtest/internal/gtest-port.h"
+#include "gtest/gtest-message.h"
#if GTEST_OS_WINDOWS_MOBILE
# include <windows.h>
#elif GTEST_OS_WINDOWS
# include <direct.h>
# include <io.h>
-#elif GTEST_OS_SYMBIAN
-// Symbian OpenC has PATH_MAX in sys/syslimits.h
-# include <sys/syslimits.h>
#else
# include <limits.h>
# include <climits> // Some Linux distributions define PATH_MAX here.
#endif // GTEST_OS_WINDOWS_MOBILE
+#include "gtest/internal/gtest-string.h"
+
#if GTEST_OS_WINDOWS
# define GTEST_PATH_MAX_ _MAX_PATH
#elif defined(PATH_MAX)
@@ -58,8 +55,6 @@
# define GTEST_PATH_MAX_ _POSIX_PATH_MAX
#endif // GTEST_OS_WINDOWS
-#include "gtest/internal/gtest-string.h"
-
namespace testing {
namespace internal {
@@ -97,13 +92,14 @@ static bool IsPathSeparator(char c) {
// Returns the current working directory, or "" if unsuccessful.
FilePath FilePath::GetCurrentDir() {
-#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_WINDOWS_PHONE || GTEST_OS_WINDOWS_RT
- // Windows CE doesn't have a current directory, so we just return
+#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_WINDOWS_PHONE || \
+ GTEST_OS_WINDOWS_RT || ARDUINO || defined(ESP_PLATFORM)
+ // These platforms do not have a current directory, so we just return
// something reasonable.
return FilePath(kCurrentDirectoryString);
#elif GTEST_OS_WINDOWS
char cwd[GTEST_PATH_MAX_ + 1] = { '\0' };
- return FilePath(_getcwd(cwd, sizeof(cwd)) == NULL ? "" : cwd);
+ return FilePath(_getcwd(cwd, sizeof(cwd)) == nullptr ? "" : cwd);
#else
char cwd[GTEST_PATH_MAX_ + 1] = { '\0' };
char* result = getcwd(cwd, sizeof(cwd));
@@ -111,9 +107,9 @@ FilePath FilePath::GetCurrentDir() {
// getcwd will likely fail in NaCl due to the sandbox, so return something
// reasonable. The user may have provided a shim implementation for getcwd,
// however, so fallback only when failure is detected.
- return FilePath(result == NULL ? kCurrentDirectoryString : cwd);
+ return FilePath(result == nullptr ? kCurrentDirectoryString : cwd);
# endif // GTEST_OS_NACL
- return FilePath(result == NULL ? "" : cwd);
+ return FilePath(result == nullptr ? "" : cwd);
#endif // GTEST_OS_WINDOWS_MOBILE
}
@@ -130,7 +126,7 @@ FilePath FilePath::RemoveExtension(const char* extension) const {
return *this;
}
-// Returns a pointer to the last occurence of a valid path separator in
+// Returns a pointer to the last occurrence of a valid path separator in
// the FilePath. On Windows, for example, both '/' and '\' are valid path
// separators. Returns NULL if no path separator was found.
const char* FilePath::FindLastPathSeparator() const {
@@ -138,8 +134,8 @@ const char* FilePath::FindLastPathSeparator() const {
#if GTEST_HAS_ALT_PATH_SEP_
const char* const last_alt_sep = strrchr(c_str(), kAlternatePathSeparator);
// Comparing two pointers of which only one is NULL is undefined.
- if (last_alt_sep != NULL &&
- (last_sep == NULL || last_alt_sep > last_sep)) {
+ if (last_alt_sep != nullptr &&
+ (last_sep == nullptr || last_alt_sep > last_sep)) {
return last_alt_sep;
}
#endif
@@ -167,7 +163,7 @@ FilePath FilePath::RemoveFileName() const {
const char* const last_sep = FindLastPathSeparator();
std::string dir;
if (last_sep) {
- dir = std::string(c_str(), last_sep + 1 - c_str());
+ dir = std::string(c_str(), static_cast<size_t>(last_sep + 1 - c_str()));
} else {
dir = kCurrentDirectoryString;
}
@@ -252,9 +248,6 @@ bool FilePath::DirectoryExists() const {
// root directory per disk drive.)
bool FilePath::IsRootDirectory() const {
#if GTEST_OS_WINDOWS
- // TODO(wan@google.com): on Windows a network share like
- // \\server\share can be a root directory, although it cannot be the
- // current directory. Handle this properly.
return pathname_.length() == 3 && IsAbsolutePath();
#else
return pathname_.length() == 1 && IsPathSeparator(pathname_.c_str()[0]);
@@ -326,7 +319,7 @@ bool FilePath::CreateFolder() const {
#if GTEST_OS_WINDOWS_MOBILE
FilePath removed_sep(this->RemoveTrailingPathSeparator());
LPCWSTR unicode = String::AnsiToUtf16(removed_sep.c_str());
- int result = CreateDirectory(unicode, NULL) ? 0 : -1;
+ int result = CreateDirectory(unicode, nullptr) ? 0 : -1;
delete [] unicode;
#elif GTEST_OS_WINDOWS
int result = _mkdir(pathname_.c_str());
@@ -352,9 +345,8 @@ FilePath FilePath::RemoveTrailingPathSeparator() const {
// Removes any redundant separators that might be in the pathname.
// For example, "bar///foo" becomes "bar/foo". Does not eliminate other
// redundancies that might be in a pathname involving "." or "..".
-// TODO(wan@google.com): handle Windows network shares (e.g. \\server\share).
void FilePath::Normalize() {
- if (pathname_.c_str() == NULL) {
+ if (pathname_.c_str() == nullptr) {
pathname_ = "";
return;
}
diff --git a/extern/gtest/src/gtest-internal-inl.h b/extern/gtest/src/gtest-internal-inl.h
index ed8a682a964..8ed70daab09 100644
--- a/extern/gtest/src/gtest-internal-inl.h
+++ b/extern/gtest/src/gtest-internal-inl.h
@@ -27,24 +27,13 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-// Utility functions and classes used by the Google C++ testing framework.
-//
-// Author: wan@google.com (Zhanyong Wan)
-//
+// Utility functions and classes used by the Google C++ testing framework.//
// This file contains purely Google Test's internal implementation. Please
// DO NOT #INCLUDE IT IN A USER PROGRAM.
#ifndef GTEST_SRC_GTEST_INTERNAL_INL_H_
#define GTEST_SRC_GTEST_INTERNAL_INL_H_
-// GTEST_IMPLEMENTATION_ is defined to 1 iff the current translation unit is
-// part of Google Test's implementation; otherwise it's undefined.
-#if !GTEST_IMPLEMENTATION_
-// If this file is included from the user's code, just say no.
-# error "gtest-internal-inl.h is part of Google Test's internal implementation."
-# error "It must not be included except by Google Test itself."
-#endif // GTEST_IMPLEMENTATION_
-
#ifndef _WIN32_WCE
# include <errno.h>
#endif // !_WIN32_WCE
@@ -53,6 +42,7 @@
#include <string.h> // For memmove.
#include <algorithm>
+#include <memory>
#include <string>
#include <vector>
@@ -67,9 +57,12 @@
# include <windows.h> // NOLINT
#endif // GTEST_OS_WINDOWS
-#include "gtest/gtest.h" // NOLINT
+#include "gtest/gtest.h"
#include "gtest/gtest-spi.h"
+GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \
+/* class A needs to have dll-interface to be used by clients of class B */)
+
namespace testing {
// Declares the flags.
@@ -94,6 +87,7 @@ const char kFilterFlag[] = "filter";
const char kListTestsFlag[] = "list_tests";
const char kOutputFlag[] = "output";
const char kPrintTimeFlag[] = "print_time";
+const char kPrintUTF8Flag[] = "print_utf8";
const char kRandomSeedFlag[] = "random_seed";
const char kRepeatFlag[] = "repeat";
const char kShuffleFlag[] = "shuffle";
@@ -105,14 +99,14 @@ const char kFlagfileFlag[] = "flagfile";
// A valid random seed must be in [1, kMaxRandomSeed].
const int kMaxRandomSeed = 99999;
-// g_help_flag is true iff the --help flag or an equivalent form is
-// specified on the command line.
+// g_help_flag is true if and only if the --help flag or an equivalent form
+// is specified on the command line.
GTEST_API_ extern bool g_help_flag;
// Returns the current time in milliseconds.
GTEST_API_ TimeInMillis GetTimeInMillis();
-// Returns true iff Google Test should use colors in the output.
+// Returns true if and only if Google Test should use colors in the output.
GTEST_API_ bool ShouldUseColor(bool stdout_is_tty);
// Formats the given time in milliseconds as seconds.
@@ -174,6 +168,7 @@ class GTestFlagSaver {
list_tests_ = GTEST_FLAG(list_tests);
output_ = GTEST_FLAG(output);
print_time_ = GTEST_FLAG(print_time);
+ print_utf8_ = GTEST_FLAG(print_utf8);
random_seed_ = GTEST_FLAG(random_seed);
repeat_ = GTEST_FLAG(repeat);
shuffle_ = GTEST_FLAG(shuffle);
@@ -195,6 +190,7 @@ class GTestFlagSaver {
GTEST_FLAG(list_tests) = list_tests_;
GTEST_FLAG(output) = output_;
GTEST_FLAG(print_time) = print_time_;
+ GTEST_FLAG(print_utf8) = print_utf8_;
GTEST_FLAG(random_seed) = random_seed_;
GTEST_FLAG(repeat) = repeat_;
GTEST_FLAG(shuffle) = shuffle_;
@@ -216,6 +212,7 @@ class GTestFlagSaver {
bool list_tests_;
std::string output_;
bool print_time_;
+ bool print_utf8_;
internal::Int32 random_seed_;
internal::Int32 repeat_;
bool shuffle_;
@@ -234,7 +231,7 @@ 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:
-// UTF-16 if sizeof(wchar_t) == 2 (on Windows, Cygwin, Symbian OS)
+// UTF-16 if sizeof(wchar_t) == 2 (on Windows, Cygwin)
// UTF-32 if sizeof(wchar_t) == 4 (on Linux)
// Parameter str points to a null-terminated wide string.
// Parameter num_chars may additionally limit the number
@@ -269,8 +266,8 @@ GTEST_API_ bool ShouldShard(const char* total_shards_str,
GTEST_API_ Int32 Int32FromEnvOrDie(const char* env_var, Int32 default_val);
// Given the total number of shards, the shard index, and the test id,
-// returns true iff the test should be run on this shard. The test id is
-// some arbitrary but unique non-negative integer assigned to each test
+// returns true if and only if the test should be run on this shard. The test id
+// is some arbitrary but unique non-negative integer assigned to each test
// method. Assumes that 0 <= shard_index < total_shards.
GTEST_API_ bool ShouldRunTestOnShard(
int total_shards, int shard_index, int test_id);
@@ -301,7 +298,8 @@ void ForEach(const Container& c, Functor functor) {
// in range [0, v.size()).
template <typename E>
inline E GetElementOr(const std::vector<E>& v, int i, E default_value) {
- return (i < 0 || i >= static_cast<int>(v.size())) ? default_value : v[i];
+ return (i < 0 || i >= static_cast<int>(v.size())) ? default_value
+ : v[static_cast<size_t>(i)];
}
// Performs an in-place shuffle of a range of the vector's elements.
@@ -323,8 +321,11 @@ void ShuffleRange(internal::Random* random, int begin, int end,
// http://en.wikipedia.org/wiki/Fisher-Yates_shuffle
for (int range_width = end - begin; range_width >= 2; range_width--) {
const int last_in_range = begin + range_width - 1;
- const int selected = begin + random->Generate(range_width);
- std::swap((*v)[selected], (*v)[last_in_range]);
+ const int selected =
+ begin +
+ static_cast<int>(random->Generate(static_cast<UInt32>(range_width)));
+ std::swap((*v)[static_cast<size_t>(selected)],
+ (*v)[static_cast<size_t>(last_in_range)]);
}
}
@@ -351,7 +352,7 @@ class TestPropertyKeyIs {
// TestPropertyKeyIs has NO default constructor.
explicit TestPropertyKeyIs(const std::string& key) : key_(key) {}
- // Returns true iff the test name of test property matches on key_.
+ // Returns true if and only if the test name of test property matches on key_.
bool operator()(const TestProperty& test_property) const {
return test_property.key() == key_;
}
@@ -384,17 +385,17 @@ class GTEST_API_ UnitTestOptions {
// Functions for processing the gtest_filter flag.
- // Returns true iff the wildcard pattern matches the string. The
- // first ':' or '\0' character in pattern marks the end of it.
+ // Returns true if and only if the wildcard pattern matches the string.
+ // The first ':' or '\0' character in pattern marks the end of it.
//
// This recursive algorithm isn't very efficient, but is clear and
// works well enough for matching test names, which are short.
static bool PatternMatchesString(const char *pattern, const char *str);
- // Returns true iff the user-specified filter matches the test case
- // name and the test name.
- static bool FilterMatchesTest(const std::string &test_case_name,
- const std::string &test_name);
+ // Returns true if and only if the user-specified filter matches the test
+ // suite name and the test name.
+ static bool FilterMatchesTest(const std::string& test_suite_name,
+ const std::string& test_name);
#if GTEST_OS_WINDOWS
// Function for supporting the gtest_catch_exception flag.
@@ -426,7 +427,7 @@ class OsStackTraceGetterInterface {
// 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 std::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
@@ -446,10 +447,20 @@ class OsStackTraceGetter : public OsStackTraceGetterInterface {
public:
OsStackTraceGetter() {}
- virtual string CurrentStackTrace(int max_depth, int skip_count);
- virtual void UponLeavingGTest();
+ std::string CurrentStackTrace(int max_depth, int skip_count) override;
+ void UponLeavingGTest() override;
private:
+#if GTEST_HAS_ABSL
+ Mutex mutex_; // Protects all internal state.
+
+ // We save the stack frame below the frame that calls user code.
+ // We do this because the address of the frame immediately below
+ // the user code changes between the call to UponLeavingGTest()
+ // and any calls to the stack trace code from within the user code.
+ void* caller_frame_ = nullptr;
+#endif // GTEST_HAS_ABSL
+
GTEST_DISALLOW_COPY_AND_ASSIGN_(OsStackTraceGetter);
};
@@ -468,7 +479,7 @@ class DefaultGlobalTestPartResultReporter
explicit DefaultGlobalTestPartResultReporter(UnitTestImpl* unit_test);
// Implements the TestPartResultReporterInterface. Reports the test part
// result in the current test.
- virtual void ReportTestPartResult(const TestPartResult& result);
+ void ReportTestPartResult(const TestPartResult& result) override;
private:
UnitTestImpl* const unit_test_;
@@ -484,7 +495,7 @@ class DefaultPerThreadTestPartResultReporter
explicit DefaultPerThreadTestPartResultReporter(UnitTestImpl* unit_test);
// Implements the TestPartResultReporterInterface. The implementation just
// delegates to the current global test part result reporter of *unit_test_.
- virtual void ReportTestPartResult(const TestPartResult& result);
+ void ReportTestPartResult(const TestPartResult& result) override;
private:
UnitTestImpl* const unit_test_;
@@ -522,22 +533,25 @@ class GTEST_API_ UnitTestImpl {
void SetTestPartResultReporterForCurrentThread(
TestPartResultReporterInterface* reporter);
- // Gets the number of successful test cases.
- int successful_test_case_count() const;
+ // Gets the number of successful test suites.
+ int successful_test_suite_count() const;
- // Gets the number of failed test cases.
- int failed_test_case_count() const;
+ // Gets the number of failed test suites.
+ int failed_test_suite_count() const;
- // Gets the number of all test cases.
- int total_test_case_count() const;
+ // Gets the number of all test suites.
+ int total_test_suite_count() const;
- // Gets the number of all test cases that contain at least one test
+ // Gets the number of all test suites that contain at least one test
// that should run.
- int test_case_to_run_count() const;
+ int test_suite_to_run_count() const;
// Gets the number of successful tests.
int successful_test_count() const;
+ // Gets the number of skipped tests.
+ int skipped_test_count() const;
+
// Gets the number of failed tests.
int failed_test_count() const;
@@ -563,27 +577,33 @@ class GTEST_API_ UnitTestImpl {
// Gets the elapsed time, in milliseconds.
TimeInMillis elapsed_time() const { return elapsed_time_; }
- // Returns true iff the unit test passed (i.e. all test cases passed).
+ // Returns true if and only if the unit test passed (i.e. all test suites
+ // passed).
bool Passed() const { return !Failed(); }
- // Returns true iff the unit test failed (i.e. some test case failed
- // or something outside of all tests failed).
+ // Returns true if and only if the unit test failed (i.e. some test suite
+ // failed or something outside of all tests failed).
bool Failed() const {
- return failed_test_case_count() > 0 || ad_hoc_test_result()->Failed();
+ return failed_test_suite_count() > 0 || ad_hoc_test_result()->Failed();
}
- // 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.
- const TestCase* GetTestCase(int i) const {
- const int index = GetElementOr(test_case_indices_, i, -1);
- return index < 0 ? NULL : test_cases_[i];
+ // Gets the i-th test suite among all the test suites. i can range from 0 to
+ // total_test_suite_count() - 1. If i is not in that range, returns NULL.
+ const TestSuite* GetTestSuite(int i) const {
+ const int index = GetElementOr(test_suite_indices_, i, -1);
+ return index < 0 ? nullptr : test_suites_[static_cast<size_t>(i)];
}
- // 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.
- TestCase* GetMutableTestCase(int i) {
- const int index = GetElementOr(test_case_indices_, i, -1);
- return index < 0 ? NULL : test_cases_[index];
+ // Legacy API is deprecated but still available
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+ const TestCase* GetTestCase(int i) const { return GetTestSuite(i); }
+#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+
+ // Gets the i-th test suite among all the test suites. i can range from 0 to
+ // total_test_suite_count() - 1. If i is not in that range, returns NULL.
+ TestSuite* GetMutableSuiteCase(int i) {
+ const int index = GetElementOr(test_suite_indices_, i, -1);
+ return index < 0 ? nullptr : test_suites_[static_cast<size_t>(index)];
}
// Provides access to the event listener list.
@@ -620,30 +640,38 @@ class GTEST_API_ UnitTestImpl {
// trace but Bar() and CurrentOsStackTraceExceptTop() won't.
std::string CurrentOsStackTraceExceptTop(int skip_count) GTEST_NO_INLINE_;
- // Finds and returns a TestCase with the given name. If one doesn't
+ // Finds and returns a TestSuite with the given name. If one doesn't
// exist, creates one and returns it.
//
// Arguments:
//
- // test_case_name: name of the test case
+ // test_suite_name: name of the test suite
// type_param: the name of the test's type parameter, or NULL if
// this is not a typed or a type-parameterized test.
- // set_up_tc: pointer to the function that sets up the test case
- // tear_down_tc: pointer to the function that tears down the test case
- TestCase* GetTestCase(const char* test_case_name,
- const char* type_param,
- Test::SetUpTestCaseFunc set_up_tc,
- Test::TearDownTestCaseFunc tear_down_tc);
+ // set_up_tc: pointer to the function that sets up the test suite
+ // tear_down_tc: pointer to the function that tears down the test suite
+ TestSuite* GetTestSuite(const char* test_suite_name, const char* type_param,
+ internal::SetUpTestSuiteFunc set_up_tc,
+ internal::TearDownTestSuiteFunc tear_down_tc);
+
+// Legacy API is deprecated but still available
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+ TestCase* GetTestCase(const char* test_case_name, const char* type_param,
+ internal::SetUpTestSuiteFunc set_up_tc,
+ internal::TearDownTestSuiteFunc tear_down_tc) {
+ return GetTestSuite(test_case_name, type_param, set_up_tc, tear_down_tc);
+ }
+#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
// Adds a TestInfo to the unit test.
//
// Arguments:
//
- // set_up_tc: pointer to the function that sets up the test case
- // tear_down_tc: pointer to the function that tears down the test case
+ // set_up_tc: pointer to the function that sets up the test suite
+ // tear_down_tc: pointer to the function that tears down the test suite
// test_info: the TestInfo object
- void AddTestInfo(Test::SetUpTestCaseFunc set_up_tc,
- Test::TearDownTestCaseFunc tear_down_tc,
+ void AddTestInfo(internal::SetUpTestSuiteFunc set_up_tc,
+ internal::TearDownTestSuiteFunc tear_down_tc,
TestInfo* test_info) {
// In order to support thread-safe death tests, we need to
// remember the original working directory when the test program
@@ -658,23 +686,20 @@ class GTEST_API_ UnitTestImpl {
<< "Failed to get the current working directory.";
}
- GetTestCase(test_info->test_case_name(),
- test_info->type_param(),
- set_up_tc,
- tear_down_tc)->AddTestInfo(test_info);
+ GetTestSuite(test_info->test_suite_name(), test_info->type_param(),
+ set_up_tc, tear_down_tc)
+ ->AddTestInfo(test_info);
}
-#if GTEST_HAS_PARAM_TEST
- // Returns ParameterizedTestCaseRegistry object used to keep track of
+ // Returns ParameterizedTestSuiteRegistry object used to keep track of
// value-parameterized tests and instantiate and register them.
- internal::ParameterizedTestCaseRegistry& parameterized_test_registry() {
+ internal::ParameterizedTestSuiteRegistry& parameterized_test_registry() {
return parameterized_test_registry_;
}
-#endif // GTEST_HAS_PARAM_TEST
- // Sets the TestCase object for the test that's currently running.
- void set_current_test_case(TestCase* a_current_test_case) {
- current_test_case_ = a_current_test_case;
+ // Sets the TestSuite object for the test that's currently running.
+ void set_current_test_suite(TestSuite* a_current_test_suite) {
+ current_test_suite_ = a_current_test_suite;
}
// Sets the TestInfo object for the test that's currently running. If
@@ -685,7 +710,7 @@ class GTEST_API_ UnitTestImpl {
}
// Registers all parameterized tests defined using TEST_P and
- // INSTANTIATE_TEST_CASE_P, creating regular tests for each test/parameter
+ // INSTANTIATE_TEST_SUITE_P, creating regular tests for each test/parameter
// combination. This method can be called more then once; it has guards
// protecting from registering the tests more then once. If
// value-parameterized tests are disabled, RegisterParameterizedTests is
@@ -700,7 +725,7 @@ class GTEST_API_ UnitTestImpl {
// Clears the results of all tests, except the ad hoc tests.
void ClearNonAdHocTestResult() {
- ForEach(test_cases_, TestCase::ClearTestCaseResult);
+ ForEach(test_suites_, TestSuite::ClearTestSuiteResult);
}
// Clears the results of ad-hoc test assertions.
@@ -709,7 +734,7 @@ class GTEST_API_ UnitTestImpl {
}
// 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
+ // context of a test or a test suite, 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);
@@ -721,7 +746,7 @@ class GTEST_API_ UnitTestImpl {
// Matches the full name of each test against the user-specified
// filter to decide whether the test should run, then records the
- // result in each TestCase and TestInfo object.
+ // result in each TestSuite and TestInfo object.
// If shard_tests == HONOR_SHARDING_PROTOCOL, further filters tests
// based on sharding variables in the environment.
// Returns the number of tests that should run.
@@ -730,7 +755,7 @@ class GTEST_API_ UnitTestImpl {
// Prints the names of the tests matching the user-specified filter flag.
void ListTestsMatchingFilter();
- const TestCase* current_test_case() const { return current_test_case_; }
+ const TestSuite* current_test_suite() const { return current_test_suite_; }
TestInfo* current_test_info() { return current_test_info_; }
const TestInfo* current_test_info() const { return current_test_info_; }
@@ -791,11 +816,11 @@ class GTEST_API_ UnitTestImpl {
// Gets the random number generator.
internal::Random* random() { return &random_; }
- // Shuffles all test cases, and the tests within each test case,
+ // Shuffles all test suites, and the tests within each test suite,
// making sure that death tests are still run first.
void ShuffleTests();
- // Restores the test cases and tests to their order before the first shuffle.
+ // Restores the test suites and tests to their order before the first shuffle.
void UnshuffleTests();
// Returns the value of GTEST_FLAG(catch_exceptions) at the moment
@@ -835,33 +860,31 @@ class GTEST_API_ UnitTestImpl {
// before/after the tests are run.
std::vector<Environment*> environments_;
- // The vector of TestCases in their original order. It owns the
+ // The vector of TestSuites in their original order. It owns the
// elements in the vector.
- std::vector<TestCase*> test_cases_;
+ std::vector<TestSuite*> test_suites_;
- // Provides a level of indirection for the test case list to allow
- // easy shuffling and restoring the test case order. The i-th
- // element of this vector is the index of the i-th test case in the
+ // Provides a level of indirection for the test suite list to allow
+ // easy shuffling and restoring the test suite order. The i-th
+ // element of this vector is the index of the i-th test suite in the
// shuffled order.
- std::vector<int> test_case_indices_;
+ std::vector<int> test_suite_indices_;
-#if GTEST_HAS_PARAM_TEST
// ParameterizedTestRegistry object used to register value-parameterized
// tests.
- internal::ParameterizedTestCaseRegistry parameterized_test_registry_;
+ internal::ParameterizedTestSuiteRegistry parameterized_test_registry_;
// Indicates whether RegisterParameterizedTests() has been called already.
bool parameterized_tests_registered_;
-#endif // GTEST_HAS_PARAM_TEST
- // Index of the last death test case registered. Initially -1.
- int last_death_test_case_;
+ // Index of the last death test suite registered. Initially -1.
+ int last_death_test_suite_;
- // This points to the TestCase for the currently running test. It
- // changes as Google Test goes through one test case after another.
+ // This points to the TestSuite for the currently running test. It
+ // changes as Google Test goes through one test suite after another.
// When no test is running, this is set to NULL and Google Test
// stores assertion results in ad_hoc_test_result_. Initially NULL.
- TestCase* current_test_case_;
+ TestSuite* current_test_suite_;
// This points to the TestInfo for the currently running test. It
// changes as Google Test goes through one test after another. When
@@ -889,7 +912,7 @@ class GTEST_API_ UnitTestImpl {
// desired.
OsStackTraceGetterInterface* os_stack_trace_getter_;
- // True iff PostFlagParsingInit() has been called.
+ // True if and only if PostFlagParsingInit() has been called.
bool post_flag_parse_init_performed_;
// The random number seed used at the beginning of the test run.
@@ -908,8 +931,8 @@ class GTEST_API_ UnitTestImpl {
#if GTEST_HAS_DEATH_TEST
// The decomposed components of the gtest_internal_run_death_test flag,
// parsed when RUN_ALL_TESTS is called.
- internal::scoped_ptr<InternalRunDeathTestFlag> internal_run_death_test_flag_;
- internal::scoped_ptr<internal::DeathTestFactory> death_test_factory_;
+ std::unique_ptr<InternalRunDeathTestFlag> internal_run_death_test_flag_;
+ std::unique_ptr<internal::DeathTestFactory> death_test_factory_;
#endif // GTEST_HAS_DEATH_TEST
// A per-thread stack of traces created by the SCOPED_TRACE() macro.
@@ -992,8 +1015,6 @@ bool ParseNaturalNumber(const ::std::string& str, Integer* number) {
const bool parse_success = *end == '\0' && errno == 0;
- // TODO(vladl@google.com): Convert this to compile time assertion when it is
- // available.
GTEST_CHECK_(sizeof(Integer) <= sizeof(parsed));
const Integer result = static_cast<Integer>(parsed);
@@ -1032,7 +1053,7 @@ class TestResultAccessor {
#if GTEST_CAN_STREAM_RESULTS_
// Streams test results to the given port on the given host machine.
-class GTEST_API_ StreamingListener : public EmptyTestEventListener {
+class StreamingListener : public EmptyTestEventListener {
public:
// Abstract base class for writing strings to a socket.
class AbstractSocketWriter {
@@ -1040,37 +1061,35 @@ class GTEST_API_ StreamingListener : public EmptyTestEventListener {
virtual ~AbstractSocketWriter() {}
// Sends a string to the socket.
- virtual void Send(const string& message) = 0;
+ virtual void Send(const std::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");
- }
+ void SendLn(const std::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)
+ SocketWriter(const std::string& host, const std::string& port)
: sockfd_(-1), host_name_(host), port_num_(port) {
MakeConnection();
}
- virtual ~SocketWriter() {
+ ~SocketWriter() override {
if (sockfd_ != -1)
CloseConnection();
}
// Sends a string to the socket.
- virtual void Send(const string& message) {
+ void Send(const std::string& message) override {
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) {
+ const auto len = static_cast<size_t>(message.length());
+ if (write(sockfd_, message.c_str(), len) != static_cast<ssize_t>(len)) {
GTEST_LOG_(WARNING)
<< "stream_result_to: failed to stream to "
<< host_name_ << ":" << port_num_;
@@ -1082,7 +1101,7 @@ class GTEST_API_ StreamingListener : public EmptyTestEventListener {
void MakeConnection();
// Closes the socket.
- void CloseConnection() {
+ void CloseConnection() override {
GTEST_CHECK_(sockfd_ != -1)
<< "CloseConnection() can be called only when there is a connection.";
@@ -1091,26 +1110,28 @@ class GTEST_API_ StreamingListener : public EmptyTestEventListener {
}
int sockfd_; // socket file descriptor
- const string host_name_;
- const string port_num_;
+ const std::string host_name_;
+ const std::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);
+ static std::string UrlEncode(const char* str);
- StreamingListener(const string& host, const string& port)
- : socket_writer_(new SocketWriter(host, port)) { Start(); }
+ StreamingListener(const std::string& host, const std::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 */) {
+ void OnTestProgramStart(const UnitTest& /* unit_test */) override {
SendLn("event=TestProgramStart");
}
- void OnTestProgramEnd(const UnitTest& unit_test) {
+ void OnTestProgramEnd(const UnitTest& unit_test) override {
// 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()));
@@ -1119,42 +1140,47 @@ class GTEST_API_ StreamingListener : public EmptyTestEventListener {
socket_writer_->CloseConnection();
}
- void OnTestIterationStart(const UnitTest& /* unit_test */, int iteration) {
+ void OnTestIterationStart(const UnitTest& /* unit_test */,
+ int iteration) override {
SendLn("event=TestIterationStart&iteration=" +
StreamableToString(iteration));
}
- void OnTestIterationEnd(const UnitTest& unit_test, int /* iteration */) {
+ void OnTestIterationEnd(const UnitTest& unit_test,
+ int /* iteration */) override {
SendLn("event=TestIterationEnd&passed=" +
FormatBool(unit_test.Passed()) + "&elapsed_time=" +
StreamableToString(unit_test.elapsed_time()) + "ms");
}
- void OnTestCaseStart(const TestCase& test_case) {
+ // Note that "event=TestCaseStart" is a wire format and has to remain
+ // "case" for compatibilty
+ void OnTestCaseStart(const TestCase& test_case) override {
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");
+ // Note that "event=TestCaseEnd" is a wire format and has to remain
+ // "case" for compatibilty
+ void OnTestCaseEnd(const TestCase& test_case) override {
+ SendLn("event=TestCaseEnd&passed=" + FormatBool(test_case.Passed()) +
+ "&elapsed_time=" + StreamableToString(test_case.elapsed_time()) +
+ "ms");
}
- void OnTestStart(const TestInfo& test_info) {
+ void OnTestStart(const TestInfo& test_info) override {
SendLn(std::string("event=TestStart&name=") + test_info.name());
}
- void OnTestEnd(const TestInfo& test_info) {
+ void OnTestEnd(const TestInfo& test_info) override {
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) {
+ void OnTestPartResult(const TestPartResult& test_part_result) override {
const char* file_name = test_part_result.file_name();
- if (file_name == NULL)
- file_name = "";
+ if (file_name == nullptr) file_name = "";
SendLn("event=TestPartResult&file=" + UrlEncode(file_name) +
"&line=" + StreamableToString(test_part_result.line_number()) +
"&message=" + UrlEncode(test_part_result.message()));
@@ -1162,15 +1188,15 @@ class GTEST_API_ StreamingListener : public EmptyTestEventListener {
private:
// Sends the given message and a newline to the socket.
- void SendLn(const string& message) { socket_writer_->SendLn(message); }
+ void SendLn(const std::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"; }
+ std::string FormatBool(bool value) { return value ? "1" : "0"; }
- const scoped_ptr<AbstractSocketWriter> socket_writer_;
+ const std::unique_ptr<AbstractSocketWriter> socket_writer_;
GTEST_DISALLOW_COPY_AND_ASSIGN_(StreamingListener);
}; // class StreamingListener
@@ -1180,4 +1206,6 @@ class GTEST_API_ StreamingListener : public EmptyTestEventListener {
} // namespace internal
} // namespace testing
+GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251
+
#endif // GTEST_SRC_GTEST_INTERNAL_INL_H_
diff --git a/extern/gtest/src/gtest-matchers.cc b/extern/gtest/src/gtest-matchers.cc
new file mode 100644
index 00000000000..7d2fb6851ec
--- /dev/null
+++ b/extern/gtest/src/gtest-matchers.cc
@@ -0,0 +1,97 @@
+// Copyright 2007, 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.
+
+// The Google C++ Testing and Mocking Framework (Google Test)
+//
+// This file implements just enough of the matcher interface to allow
+// EXPECT_DEATH and friends to accept a matcher argument.
+
+#include "gtest/internal/gtest-internal.h"
+#include "gtest/internal/gtest-port.h"
+#include "gtest/gtest-matchers.h"
+
+#include <string>
+
+namespace testing {
+
+// Constructs a matcher that matches a const std::string& whose value is
+// equal to s.
+Matcher<const std::string&>::Matcher(const std::string& s) { *this = Eq(s); }
+
+// Constructs a matcher that matches a const std::string& whose value is
+// equal to s.
+Matcher<const std::string&>::Matcher(const char* s) {
+ *this = Eq(std::string(s));
+}
+
+// Constructs a matcher that matches a std::string whose value is equal to
+// s.
+Matcher<std::string>::Matcher(const std::string& s) { *this = Eq(s); }
+
+// Constructs a matcher that matches a std::string whose value is equal to
+// s.
+Matcher<std::string>::Matcher(const char* s) { *this = Eq(std::string(s)); }
+
+#if GTEST_HAS_ABSL
+// Constructs a matcher that matches a const absl::string_view& whose value is
+// equal to s.
+Matcher<const absl::string_view&>::Matcher(const std::string& s) {
+ *this = Eq(s);
+}
+
+// Constructs a matcher that matches a const absl::string_view& whose value is
+// equal to s.
+Matcher<const absl::string_view&>::Matcher(const char* s) {
+ *this = Eq(std::string(s));
+}
+
+// Constructs a matcher that matches a const absl::string_view& whose value is
+// equal to s.
+Matcher<const absl::string_view&>::Matcher(absl::string_view s) {
+ *this = Eq(std::string(s));
+}
+
+// Constructs a matcher that matches a absl::string_view whose value is equal to
+// s.
+Matcher<absl::string_view>::Matcher(const std::string& s) { *this = Eq(s); }
+
+// Constructs a matcher that matches a absl::string_view whose value is equal to
+// s.
+Matcher<absl::string_view>::Matcher(const char* s) {
+ *this = Eq(std::string(s));
+}
+
+// Constructs a matcher that matches a absl::string_view whose value is equal to
+// s.
+Matcher<absl::string_view>::Matcher(absl::string_view s) {
+ *this = Eq(std::string(s));
+}
+#endif // GTEST_HAS_ABSL
+
+} // namespace testing
diff --git a/extern/gtest/src/gtest-port.cc b/extern/gtest/src/gtest-port.cc
index e5bf3dd2be4..fc5ba6becc5 100644
--- a/extern/gtest/src/gtest-port.cc
+++ b/extern/gtest/src/gtest-port.cc
@@ -26,22 +26,25 @@
// 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.
-//
-// Author: wan@google.com (Zhanyong Wan)
+
#include "gtest/internal/gtest-port.h"
#include <limits.h>
-#include <stdlib.h>
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
#include <fstream>
+#include <memory>
#if GTEST_OS_WINDOWS
# include <windows.h>
# include <io.h>
# include <sys/stat.h>
# include <map> // Used in ThreadLocal.
+# ifdef _MSC_VER
+# include <crtdbg.h>
+# endif // _MSC_VER
#else
# include <unistd.h>
#endif // GTEST_OS_WINDOWS
@@ -52,6 +55,14 @@
# include <mach/vm_map.h>
#endif // GTEST_OS_MAC
+#if GTEST_OS_DRAGONFLY || GTEST_OS_FREEBSD || GTEST_OS_GNU_KFREEBSD || \
+ GTEST_OS_NETBSD || GTEST_OS_OPENBSD
+# include <sys/sysctl.h>
+# if GTEST_OS_DRAGONFLY || GTEST_OS_FREEBSD || GTEST_OS_GNU_KFREEBSD
+# include <sys/user.h>
+# endif
+#endif
+
#if GTEST_OS_QNX
# include <devctl.h>
# include <fcntl.h>
@@ -63,19 +74,16 @@
# include <sys/types.h>
#endif // GTEST_OS_AIX
+#if GTEST_OS_FUCHSIA
+# include <zircon/process.h>
+# include <zircon/syscalls.h>
+#endif // GTEST_OS_FUCHSIA
+
#include "gtest/gtest-spi.h"
#include "gtest/gtest-message.h"
#include "gtest/internal/gtest-internal.h"
#include "gtest/internal/gtest-string.h"
-
-// Indicates that this translation unit is part of Google Test's
-// implementation. It must come before gtest-internal-inl.h is
-// included, or there will be a compiler error. This trick exists to
-// prevent the accidental inclusion of gtest-internal-inl.h in the
-// user's code.
-#define GTEST_IMPLEMENTATION_ 1
#include "src/gtest-internal-inl.h"
-#undef GTEST_IMPLEMENTATION_
namespace testing {
namespace internal {
@@ -93,7 +101,7 @@ const int kStdErrFileno = STDERR_FILENO;
namespace {
template <typename T>
-T ReadProcFileField(const string& filename, int field) {
+T ReadProcFileField(const std::string& filename, int field) {
std::string dummy;
std::ifstream file(filename.c_str());
while (field-- > 0) {
@@ -107,9 +115,9 @@ T ReadProcFileField(const string& filename, int field) {
// Returns the number of active threads, or 0 when there is an error.
size_t GetThreadCount() {
- const string filename =
+ const std::string filename =
(Message() << "/proc/" << getpid() << "/stat").GetString();
- return ReadProcFileField<int>(filename, 19);
+ return ReadProcFileField<size_t>(filename, 19);
}
#elif GTEST_OS_MAC
@@ -131,6 +139,81 @@ size_t GetThreadCount() {
}
}
+#elif GTEST_OS_DRAGONFLY || GTEST_OS_FREEBSD || GTEST_OS_GNU_KFREEBSD || \
+ GTEST_OS_NETBSD
+
+#if GTEST_OS_NETBSD
+#undef KERN_PROC
+#define KERN_PROC KERN_PROC2
+#define kinfo_proc kinfo_proc2
+#endif
+
+#if GTEST_OS_DRAGONFLY
+#define KP_NLWP(kp) (kp.kp_nthreads)
+#elif GTEST_OS_FREEBSD || GTEST_OS_GNU_KFREEBSD
+#define KP_NLWP(kp) (kp.ki_numthreads)
+#elif GTEST_OS_NETBSD
+#define KP_NLWP(kp) (kp.p_nlwps)
+#endif
+
+// Returns the number of threads running in the process, or 0 to indicate that
+// we cannot detect it.
+size_t GetThreadCount() {
+ int mib[] = {
+ CTL_KERN,
+ KERN_PROC,
+ KERN_PROC_PID,
+ getpid(),
+#if GTEST_OS_NETBSD
+ sizeof(struct kinfo_proc),
+ 1,
+#endif
+ };
+ u_int miblen = sizeof(mib) / sizeof(mib[0]);
+ struct kinfo_proc info;
+ size_t size = sizeof(info);
+ if (sysctl(mib, miblen, &info, &size, NULL, 0)) {
+ return 0;
+ }
+ return static_cast<size_t>(KP_NLWP(info));
+}
+#elif GTEST_OS_OPENBSD
+
+// Returns the number of threads running in the process, or 0 to indicate that
+// we cannot detect it.
+size_t GetThreadCount() {
+ int mib[] = {
+ CTL_KERN,
+ KERN_PROC,
+ KERN_PROC_PID | KERN_PROC_SHOW_THREADS,
+ getpid(),
+ sizeof(struct kinfo_proc),
+ 0,
+ };
+ u_int miblen = sizeof(mib) / sizeof(mib[0]);
+
+ // get number of structs
+ size_t size;
+ if (sysctl(mib, miblen, NULL, &size, NULL, 0)) {
+ return 0;
+ }
+ mib[5] = size / mib[4];
+
+ // populate array of structs
+ struct kinfo_proc info[mib[5]];
+ if (sysctl(mib, miblen, &info, &size, NULL, 0)) {
+ return 0;
+ }
+
+ // exclude empty members
+ int nthreads = 0;
+ for (int i = 0; i < size / mib[4]; i++) {
+ if (info[i].p_tid != -1)
+ nthreads++;
+ }
+ return nthreads;
+}
+
#elif GTEST_OS_QNX
// Returns the number of threads running in the process, or 0 to indicate that
@@ -142,7 +225,7 @@ size_t GetThreadCount() {
}
procfs_info process_info;
const int status =
- devctl(fd, DCMD_PROC_INFO, &process_info, sizeof(process_info), NULL);
+ devctl(fd, DCMD_PROC_INFO, &process_info, sizeof(process_info), nullptr);
close(fd);
if (status == EOK) {
return static_cast<size_t>(process_info.num_threads);
@@ -156,7 +239,7 @@ size_t GetThreadCount() {
size_t GetThreadCount() {
struct procentry64 entry;
pid_t pid = getpid();
- int status = getprocs64(&entry, sizeof(entry), NULL, 0, &pid, 1);
+ int status = getprocs64(&entry, sizeof(entry), nullptr, 0, &pid, 1);
if (status == 1) {
return entry.pi_thcount;
} else {
@@ -164,6 +247,25 @@ size_t GetThreadCount() {
}
}
+#elif GTEST_OS_FUCHSIA
+
+size_t GetThreadCount() {
+ int dummy_buffer;
+ size_t avail;
+ zx_status_t status = zx_object_get_info(
+ zx_process_self(),
+ ZX_INFO_PROCESS_THREADS,
+ &dummy_buffer,
+ 0,
+ nullptr,
+ &avail);
+ if (status == ZX_OK) {
+ return avail;
+ } else {
+ return 0;
+ }
+}
+
#else
size_t GetThreadCount() {
@@ -177,7 +279,7 @@ size_t GetThreadCount() {
#if GTEST_IS_THREADSAFE && GTEST_OS_WINDOWS
void SleepMilliseconds(int n) {
- ::Sleep(n);
+ ::Sleep(static_cast<DWORD>(n));
}
AutoHandle::AutoHandle()
@@ -215,15 +317,15 @@ void AutoHandle::Reset(HANDLE handle) {
bool AutoHandle::IsCloseable() const {
// Different Windows APIs may use either of these values to represent an
// invalid handle.
- return handle_ != NULL && handle_ != INVALID_HANDLE_VALUE;
+ return handle_ != nullptr && handle_ != INVALID_HANDLE_VALUE;
}
Notification::Notification()
- : event_(::CreateEvent(NULL, // Default security attributes.
- TRUE, // Do not reset automatically.
- FALSE, // Initially unset.
- NULL)) { // Anonymous event.
- GTEST_CHECK_(event_.Get() != NULL);
+ : event_(::CreateEvent(nullptr, // Default security attributes.
+ TRUE, // Do not reset automatically.
+ FALSE, // Initially unset.
+ nullptr)) { // Anonymous event.
+ GTEST_CHECK_(event_.Get() != nullptr);
}
void Notification::Notify() {
@@ -246,13 +348,10 @@ Mutex::Mutex()
Mutex::~Mutex() {
// Static mutexes are leaked intentionally. It is not thread-safe to try
// to clean them up.
- // TODO(yukawa): Switch to Slim Reader/Writer (SRW) Locks, which requires
- // nothing to clean it up but is available only on Vista and later.
- // http://msdn.microsoft.com/en-us/library/windows/desktop/aa904937.aspx
if (type_ == kDynamic) {
::DeleteCriticalSection(critical_section_);
delete critical_section_;
- critical_section_ = NULL;
+ critical_section_ = nullptr;
}
}
@@ -279,6 +378,41 @@ void Mutex::AssertHeld() {
<< "The current thread is not holding the mutex @" << this;
}
+namespace {
+
+#ifdef _MSC_VER
+// Use the RAII idiom to flag mem allocs that are intentionally never
+// deallocated. The motivation is to silence the false positive mem leaks
+// that are reported by the debug version of MS's CRT which can only detect
+// if an alloc is missing a matching deallocation.
+// Example:
+// MemoryIsNotDeallocated memory_is_not_deallocated;
+// critical_section_ = new CRITICAL_SECTION;
+//
+class MemoryIsNotDeallocated
+{
+ public:
+ MemoryIsNotDeallocated() : old_crtdbg_flag_(0) {
+ old_crtdbg_flag_ = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
+ // Set heap allocation block type to _IGNORE_BLOCK so that MS debug CRT
+ // doesn't report mem leak if there's no matching deallocation.
+ _CrtSetDbgFlag(old_crtdbg_flag_ & ~_CRTDBG_ALLOC_MEM_DF);
+ }
+
+ ~MemoryIsNotDeallocated() {
+ // Restore the original _CRTDBG_ALLOC_MEM_DF flag
+ _CrtSetDbgFlag(old_crtdbg_flag_);
+ }
+
+ private:
+ int old_crtdbg_flag_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(MemoryIsNotDeallocated);
+};
+#endif // _MSC_VER
+
+} // namespace
+
// Initializes owner_thread_id_ and critical_section_ in static mutexes.
void Mutex::ThreadSafeLazyInit() {
// Dynamic mutexes are initialized in the constructor.
@@ -289,7 +423,13 @@ void Mutex::ThreadSafeLazyInit() {
// If critical_section_init_phase_ was 0 before the exchange, we
// are the first to test it and need to perform the initialization.
owner_thread_id_ = 0;
- critical_section_ = new CRITICAL_SECTION;
+ {
+ // Use RAII to flag that following mem alloc is never deallocated.
+#ifdef _MSC_VER
+ MemoryIsNotDeallocated memory_is_not_deallocated;
+#endif // _MSC_VER
+ critical_section_ = new CRITICAL_SECTION;
+ }
::InitializeCriticalSection(critical_section_);
// Updates the critical_section_init_phase_ to 2 to signal
// initialization complete.
@@ -328,17 +468,16 @@ class ThreadWithParamSupport : public ThreadWithParamBase {
Notification* thread_can_start) {
ThreadMainParam* param = new ThreadMainParam(runnable, thread_can_start);
DWORD thread_id;
- // TODO(yukawa): Consider to use _beginthreadex instead.
HANDLE thread_handle = ::CreateThread(
- NULL, // Default security.
- 0, // Default stack size.
+ nullptr, // Default security.
+ 0, // Default stack size.
&ThreadWithParamSupport::ThreadMain,
- param, // Parameter to ThreadMainStatic
- 0x0, // Default creation flags.
+ param, // Parameter to ThreadMainStatic
+ 0x0, // Default creation flags.
&thread_id); // Need a valid pointer for the call to work under Win98.
- GTEST_CHECK_(thread_handle != NULL) << "CreateThread failed with error "
- << ::GetLastError() << ".";
- if (thread_handle == NULL) {
+ GTEST_CHECK_(thread_handle != nullptr)
+ << "CreateThread failed with error " << ::GetLastError() << ".";
+ if (thread_handle == nullptr) {
delete param;
}
return thread_handle;
@@ -350,15 +489,15 @@ class ThreadWithParamSupport : public ThreadWithParamBase {
: runnable_(runnable),
thread_can_start_(thread_can_start) {
}
- scoped_ptr<Runnable> runnable_;
+ std::unique_ptr<Runnable> runnable_;
// Does not own.
Notification* thread_can_start_;
};
static DWORD WINAPI ThreadMain(void* ptr) {
// Transfers ownership.
- scoped_ptr<ThreadMainParam> param(static_cast<ThreadMainParam*>(ptr));
- if (param->thread_can_start_ != NULL)
+ std::unique_ptr<ThreadMainParam> param(static_cast<ThreadMainParam*>(ptr));
+ if (param->thread_can_start_ != nullptr)
param->thread_can_start_->WaitForNotification();
param->runnable_->Run();
return 0;
@@ -416,7 +555,7 @@ class ThreadLocalRegistryImpl {
thread_local_values
.insert(std::make_pair(
thread_local_instance,
- linked_ptr<ThreadLocalValueHolderBase>(
+ std::shared_ptr<ThreadLocalValueHolderBase>(
thread_local_instance->NewValueForCurrentThread())))
.first;
}
@@ -425,7 +564,7 @@ class ThreadLocalRegistryImpl {
static void OnThreadLocalDestroyed(
const ThreadLocalBase* thread_local_instance) {
- std::vector<linked_ptr<ThreadLocalValueHolderBase> > value_holders;
+ std::vector<std::shared_ptr<ThreadLocalValueHolderBase> > value_holders;
// Clean up the ThreadLocalValues data structure while holding the lock, but
// defer the destruction of the ThreadLocalValueHolderBases.
{
@@ -453,7 +592,7 @@ class ThreadLocalRegistryImpl {
static void OnThreadExit(DWORD thread_id) {
GTEST_CHECK_(thread_id != 0) << ::GetLastError();
- std::vector<linked_ptr<ThreadLocalValueHolderBase> > value_holders;
+ std::vector<std::shared_ptr<ThreadLocalValueHolderBase> > value_holders;
// Clean up the ThreadIdToThreadLocals data structure while holding the
// lock, but defer the destruction of the ThreadLocalValueHolderBases.
{
@@ -480,7 +619,8 @@ class ThreadLocalRegistryImpl {
private:
// In a particular thread, maps a ThreadLocal object to its value.
typedef std::map<const ThreadLocalBase*,
- linked_ptr<ThreadLocalValueHolderBase> > ThreadLocalValues;
+ std::shared_ptr<ThreadLocalValueHolderBase> >
+ ThreadLocalValues;
// Stores all ThreadIdToThreadLocals having values in a thread, indexed by
// thread's ID.
typedef std::map<DWORD, ThreadLocalValues> ThreadIdToThreadLocals;
@@ -495,18 +635,17 @@ class ThreadLocalRegistryImpl {
HANDLE thread = ::OpenThread(SYNCHRONIZE | THREAD_QUERY_INFORMATION,
FALSE,
thread_id);
- GTEST_CHECK_(thread != NULL);
- // We need to to pass a valid thread ID pointer into CreateThread for it
+ GTEST_CHECK_(thread != nullptr);
+ // We need to pass a valid thread ID pointer into CreateThread for it
// to work correctly under Win98.
DWORD watcher_thread_id;
HANDLE watcher_thread = ::CreateThread(
- NULL, // Default security.
- 0, // Default stack size
+ nullptr, // Default security.
+ 0, // Default stack size
&ThreadLocalRegistryImpl::WatcherThreadFunc,
reinterpret_cast<LPVOID>(new ThreadIdAndHandle(thread_id, thread)),
- CREATE_SUSPENDED,
- &watcher_thread_id);
- GTEST_CHECK_(watcher_thread != NULL);
+ CREATE_SUSPENDED, &watcher_thread_id);
+ GTEST_CHECK_(watcher_thread != nullptr);
// Give the watcher thread the same priority as ours to avoid being
// blocked by it.
::SetThreadPriority(watcher_thread,
@@ -531,7 +670,10 @@ class ThreadLocalRegistryImpl {
// Returns map of thread local instances.
static ThreadIdToThreadLocals* GetThreadLocalsMapLocked() {
mutex_.AssertHeld();
- static ThreadIdToThreadLocals* map = new ThreadIdToThreadLocals;
+#ifdef _MSC_VER
+ MemoryIsNotDeallocated memory_is_not_deallocated;
+#endif // _MSC_VER
+ static ThreadIdToThreadLocals* map = new ThreadIdToThreadLocals();
return map;
}
@@ -573,7 +715,7 @@ RE::~RE() {
free(const_cast<char*>(pattern_));
}
-// Returns true iff regular expression re matches the entire str.
+// Returns true if and only if regular expression re matches the entire str.
bool RE::FullMatch(const char* str, const RE& re) {
if (!re.is_valid_) return false;
@@ -581,8 +723,8 @@ bool RE::FullMatch(const char* str, const RE& re) {
return regexec(&re.full_regex_, str, 1, &match, 0) == 0;
}
-// Returns true iff regular expression re matches a substring of str
-// (including str itself).
+// Returns true if and only if regular expression re matches a substring of
+// str (including str itself).
bool RE::PartialMatch(const char* str, const RE& re) {
if (!re.is_valid_) return false;
@@ -622,14 +764,14 @@ void RE::Init(const char* regex) {
#elif GTEST_USES_SIMPLE_RE
-// Returns true iff ch appears anywhere in str (excluding the
+// Returns true if and only if ch appears anywhere in str (excluding the
// terminating '\0' character).
bool IsInSet(char ch, const char* str) {
- return ch != '\0' && strchr(str, ch) != NULL;
+ return ch != '\0' && strchr(str, ch) != nullptr;
}
-// Returns true iff ch belongs to the given classification. Unlike
-// similar functions in <ctype.h>, these aren't affected by the
+// Returns true if and only if ch belongs to the given classification.
+// Unlike similar functions in <ctype.h>, these aren't affected by the
// current locale.
bool IsAsciiDigit(char ch) { return '0' <= ch && ch <= '9'; }
bool IsAsciiPunct(char ch) {
@@ -642,13 +784,13 @@ bool IsAsciiWordChar(char ch) {
('0' <= ch && ch <= '9') || ch == '_';
}
-// Returns true iff "\\c" is a supported escape sequence.
+// Returns true if and only if "\\c" is a supported escape sequence.
bool IsValidEscape(char c) {
return (IsAsciiPunct(c) || IsInSet(c, "dDfnrsStvwW"));
}
-// Returns true iff the given atom (specified by escaped and pattern)
-// matches ch. The result is undefined if the atom is invalid.
+// Returns true if and only if the given atom (specified by escaped and
+// pattern) matches ch. The result is undefined if the atom is invalid.
bool AtomMatchesChar(bool escaped, char pattern_char, char ch) {
if (escaped) { // "\\p" where p is pattern_char.
switch (pattern_char) {
@@ -671,7 +813,7 @@ bool AtomMatchesChar(bool escaped, char pattern_char, char ch) {
}
// Helper function used by ValidateRegex() to format error messages.
-std::string FormatRegexSyntaxError(const char* regex, int index) {
+static std::string FormatRegexSyntaxError(const char* regex, int index) {
return (Message() << "Syntax error at index " << index
<< " in simple regular expression \"" << regex << "\": ").GetString();
}
@@ -679,17 +821,14 @@ std::string FormatRegexSyntaxError(const char* regex, int index) {
// Generates non-fatal failures and returns false if regex is invalid;
// otherwise returns true.
bool ValidateRegex(const char* regex) {
- if (regex == NULL) {
- // TODO(wan@google.com): fix the source file location in the
- // assertion failures to match where the regex is used in user
- // code.
+ if (regex == nullptr) {
ADD_FAILURE() << "NULL is not a valid simple regular expression.";
return false;
}
bool is_valid = true;
- // True iff ?, *, or + can follow the previous atom.
+ // True if and only if ?, *, or + can follow the previous atom.
bool prev_repeatable = false;
for (int i = 0; regex[i]; i++) {
if (regex[i] == '\\') { // An escape sequence
@@ -765,8 +904,8 @@ bool MatchRepetitionAndRegexAtHead(
return false;
}
-// Returns true iff regex matches a prefix of str. regex must be a
-// valid simple regular expression and not start with "^", or the
+// Returns true if and only if regex matches a prefix of str. regex must
+// be a valid simple regular expression and not start with "^", or the
// result is undefined.
bool MatchRegexAtHead(const char* regex, const char* str) {
if (*regex == '\0') // An empty regex matches a prefix of anything.
@@ -796,8 +935,8 @@ bool MatchRegexAtHead(const char* regex, const char* str) {
}
}
-// Returns true iff regex matches any substring of str. regex must be
-// a valid simple regular expression, or the result is undefined.
+// Returns true if and only if regex matches any substring of str. regex must
+// be a valid simple regular expression, or the result is undefined.
//
// The algorithm is recursive, but the recursion depth doesn't exceed
// the regex length, so we won't need to worry about running out of
@@ -805,8 +944,7 @@ bool MatchRegexAtHead(const char* regex, const char* str) {
// exponential with respect to the regex length + the string length,
// but usually it's must faster (often close to linear).
bool MatchRegexAnywhere(const char* regex, const char* str) {
- if (regex == NULL || str == NULL)
- return false;
+ if (regex == nullptr || str == nullptr) return false;
if (*regex == '^')
return MatchRegexAtHead(regex + 1, str);
@@ -826,21 +964,21 @@ RE::~RE() {
free(const_cast<char*>(full_pattern_));
}
-// Returns true iff regular expression re matches the entire str.
+// Returns true if and only if regular expression re matches the entire str.
bool RE::FullMatch(const char* str, const RE& re) {
return re.is_valid_ && MatchRegexAnywhere(re.full_pattern_, str);
}
-// Returns true iff regular expression re matches a substring of str
-// (including str itself).
+// Returns true if and only if regular expression re matches a substring of
+// str (including str itself).
bool RE::PartialMatch(const char* str, const RE& re) {
return re.is_valid_ && MatchRegexAnywhere(re.pattern_, str);
}
// Initializes an RE from its string representation.
void RE::Init(const char* regex) {
- pattern_ = full_pattern_ = NULL;
- if (regex != NULL) {
+ pattern_ = full_pattern_ = nullptr;
+ if (regex != nullptr) {
pattern_ = posix::StrDup(regex);
}
@@ -878,7 +1016,7 @@ 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 std::string file_name(file == NULL ? kUnknownFile : file);
+ const std::string file_name(file == nullptr ? kUnknownFile : file);
if (line < 0) {
return file_name + ":";
@@ -897,7 +1035,7 @@ 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 std::string file_name(file == NULL ? kUnknownFile : file);
+ const std::string file_name(file == nullptr ? kUnknownFile : file);
if (line < 0)
return file_name;
@@ -923,9 +1061,10 @@ GTestLog::~GTestLog() {
posix::Abort();
}
}
+
// Disable Microsoft deprecation warnings for POSIX functions called from
// this class (creat, dup, dup2, and close)
-GTEST_DISABLE_MSC_WARNINGS_PUSH_(4996)
+GTEST_DISABLE_MSC_DEPRECATED_PUSH_()
#if GTEST_HAS_STREAM_REDIRECTION
@@ -963,20 +1102,22 @@ class CapturedStream {
// 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";
+ // The location /data/local/tmp is directly accessible from native code.
+ // '/sdcard' and other variants cannot be relied on, as they are not
+ // guaranteed to be mounted, or may have a delay in mounting.
+ char name_template[] = "/data/local/tmp/gtest_captured_stream.XXXXXX";
# else
char name_template[] = "/tmp/captured_stream.XXXXXX";
# endif // GTEST_OS_LINUX_ANDROID
const int captured_fd = mkstemp(name_template);
+ if (captured_fd == -1) {
+ GTEST_LOG_(WARNING)
+ << "Failed to create tmp file " << name_template
+ << " for test; does the test have access to the /tmp directory?";
+ }
filename_ = name_template;
# endif // GTEST_OS_WINDOWS
- fflush(NULL);
+ fflush(nullptr);
dup2(captured_fd, fd_);
close(captured_fd);
}
@@ -988,13 +1129,17 @@ class CapturedStream {
std::string GetCapturedString() {
if (uncaptured_fd_ != -1) {
// Restores the original stream.
- fflush(NULL);
+ fflush(nullptr);
dup2(uncaptured_fd_, fd_);
close(uncaptured_fd_);
uncaptured_fd_ = -1;
}
FILE* const file = posix::FOpen(filename_.c_str(), "r");
+ if (file == nullptr) {
+ GTEST_LOG_(FATAL) << "Failed to open tmp file " << filename_
+ << " for capturing stream.";
+ }
const std::string content = ReadEntireFile(file);
posix::FClose(file);
return content;
@@ -1009,14 +1154,15 @@ class CapturedStream {
GTEST_DISALLOW_COPY_AND_ASSIGN_(CapturedStream);
};
-GTEST_DISABLE_MSC_WARNINGS_POP_()
+GTEST_DISABLE_MSC_DEPRECATED_POP_()
-static CapturedStream* g_captured_stderr = NULL;
-static CapturedStream* g_captured_stdout = NULL;
+static CapturedStream* g_captured_stderr = nullptr;
+static CapturedStream* g_captured_stdout = nullptr;
// Starts capturing an output stream (stdout/stderr).
-void CaptureStream(int fd, const char* stream_name, CapturedStream** stream) {
- if (*stream != NULL) {
+static void CaptureStream(int fd, const char* stream_name,
+ CapturedStream** stream) {
+ if (*stream != nullptr) {
GTEST_LOG_(FATAL) << "Only one " << stream_name
<< " capturer can exist at a time.";
}
@@ -1024,11 +1170,11 @@ void CaptureStream(int fd, const char* stream_name, CapturedStream** stream) {
}
// Stops capturing the output stream and returns the captured string.
-std::string GetCapturedStream(CapturedStream** captured_stream) {
+static std::string GetCapturedStream(CapturedStream** captured_stream) {
const std::string content = (*captured_stream)->GetCapturedString();
delete *captured_stream;
- *captured_stream = NULL;
+ *captured_stream = nullptr;
return content;
}
@@ -1055,23 +1201,9 @@ std::string GetCapturedStderr() {
#endif // GTEST_HAS_STREAM_REDIRECTION
-std::string TempDir() {
-#if GTEST_OS_WINDOWS_MOBILE
- return "\\temp\\";
-#elif GTEST_OS_WINDOWS
- const char* temp_dir = posix::GetEnv("TEMP");
- if (temp_dir == NULL || temp_dir[0] == '\0')
- return "\\temp\\";
- else if (temp_dir[strlen(temp_dir) - 1] == '\\')
- return temp_dir;
- else
- return std::string(temp_dir) + "\\";
-#elif GTEST_OS_LINUX_ANDROID
- return "/sdcard/";
-#else
- return "/tmp/";
-#endif // GTEST_OS_WINDOWS_MOBILE
-}
+
+
+
size_t GetFileSize(FILE* file) {
fseek(file, 0, SEEK_END);
@@ -1101,22 +1233,30 @@ std::string ReadEntireFile(FILE* file) {
}
#if GTEST_HAS_DEATH_TEST
+static const std::vector<std::string>* g_injected_test_argvs =
+ nullptr; // Owned.
-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) {
+std::vector<std::string> GetInjectableArgvs() {
+ if (g_injected_test_argvs != nullptr) {
return *g_injected_test_argvs;
}
return GetArgvs();
}
+
+void SetInjectableArgvs(const std::vector<std::string>* new_argvs) {
+ if (g_injected_test_argvs != new_argvs) delete g_injected_test_argvs;
+ g_injected_test_argvs = new_argvs;
+}
+
+void SetInjectableArgvs(const std::vector<std::string>& new_argvs) {
+ SetInjectableArgvs(
+ new std::vector<std::string>(new_argvs.begin(), new_argvs.end()));
+}
+
+void ClearInjectableArgvs() {
+ delete g_injected_test_argvs;
+ g_injected_test_argvs = nullptr;
+}
#endif // GTEST_HAS_DEATH_TEST
#if GTEST_OS_WINDOWS_MOBILE
@@ -1148,7 +1288,7 @@ static std::string FlagToEnvVar(const char* flag) {
// unchanged and returns false.
bool ParseInt32(const Message& src_text, const char* str, Int32* value) {
// Parses the environment variable as a decimal integer.
- char* end = NULL;
+ char* end = nullptr;
const long long_value = strtol(str, &end, 10); // NOLINT
// Has strtol() consumed all characters in the string?
@@ -1187,15 +1327,16 @@ bool ParseInt32(const Message& src_text, const char* str, Int32* value) {
// Reads and returns the Boolean environment variable corresponding to
// the given flag; if it's not set, returns default_value.
//
-// The value is considered true iff it's not "0".
+// The value is considered true if and only if it's not "0".
bool BoolFromGTestEnv(const char* flag, bool default_value) {
#if defined(GTEST_GET_BOOL_FROM_ENV_)
return GTEST_GET_BOOL_FROM_ENV_(flag, default_value);
-#endif // defined(GTEST_GET_BOOL_FROM_ENV_)
+#else
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;
+ return string_value == nullptr ? default_value
+ : strcmp(string_value, "0") != 0;
+#endif // defined(GTEST_GET_BOOL_FROM_ENV_)
}
// Reads and returns a 32-bit integer stored in the environment
@@ -1204,10 +1345,10 @@ bool BoolFromGTestEnv(const char* flag, bool default_value) {
Int32 Int32FromGTestEnv(const char* flag, Int32 default_value) {
#if defined(GTEST_GET_INT32_FROM_ENV_)
return GTEST_GET_INT32_FROM_ENV_(flag, default_value);
-#endif // defined(GTEST_GET_INT32_FROM_ENV_)
+#else
const std::string env_var = FlagToEnvVar(flag);
const char* const string_value = posix::GetEnv(env_var.c_str());
- if (string_value == NULL) {
+ if (string_value == nullptr) {
// The environment variable is not set.
return default_value;
}
@@ -1222,37 +1363,36 @@ Int32 Int32FromGTestEnv(const char* flag, Int32 default_value) {
}
return result;
+#endif // defined(GTEST_GET_INT32_FROM_ENV_)
+}
+
+// As a special case for the 'output' flag, if GTEST_OUTPUT is not
+// set, we look for XML_OUTPUT_FILE, which is set by the Bazel build
+// system. The value of XML_OUTPUT_FILE is a filename without the
+// "xml:" prefix of GTEST_OUTPUT.
+// Note that this is meant to be called at the call site so it does
+// not check that the flag is 'output'
+// In essence this checks an env variable called XML_OUTPUT_FILE
+// and if it is set we prepend "xml:" to its value, if it not set we return ""
+std::string OutputFlagAlsoCheckEnvVar(){
+ std::string default_value_for_output_flag = "";
+ const char* xml_output_file_env = posix::GetEnv("XML_OUTPUT_FILE");
+ if (nullptr != xml_output_file_env) {
+ default_value_for_output_flag = std::string("xml:") + xml_output_file_env;
+ }
+ return default_value_for_output_flag;
}
// Reads and returns the string environment variable corresponding to
// the given flag; if it's not set, returns default_value.
-std::string StringFromGTestEnv(const char* flag, const char* default_value) {
+const char* StringFromGTestEnv(const char* flag, const char* default_value) {
#if defined(GTEST_GET_STRING_FROM_ENV_)
return GTEST_GET_STRING_FROM_ENV_(flag, default_value);
-#endif // defined(GTEST_GET_STRING_FROM_ENV_)
+#else
const std::string env_var = FlagToEnvVar(flag);
- const char* value = posix::GetEnv(env_var.c_str());
- if (value != NULL) {
- return value;
- }
-
- // As a special case for the 'output' flag, if GTEST_OUTPUT is not
- // set, we look for XML_OUTPUT_FILE, which is set by the Bazel build
- // system. The value of XML_OUTPUT_FILE is a filename without the
- // "xml:" prefix of GTEST_OUTPUT.
- //
- // The net priority order after flag processing is thus:
- // --gtest_output command line flag
- // GTEST_OUTPUT environment variable
- // XML_OUTPUT_FILE environment variable
- // 'default_value'
- if (strcmp(flag, "output") == 0) {
- value = posix::GetEnv("XML_OUTPUT_FILE");
- if (value != NULL) {
- return std::string("xml:") + value;
- }
- }
- return default_value;
+ const char* const value = posix::GetEnv(env_var.c_str());
+ return value == nullptr ? default_value : value;
+#endif // defined(GTEST_GET_STRING_FROM_ENV_)
}
} // namespace internal
diff --git a/extern/gtest/src/gtest-printers.cc b/extern/gtest/src/gtest-printers.cc
index a2df412f8a2..3337be312ea 100644
--- a/extern/gtest/src/gtest-printers.cc
+++ b/extern/gtest/src/gtest-printers.cc
@@ -26,10 +26,9 @@
// 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.
-//
-// Author: wan@google.com (Zhanyong Wan)
-// Google Test - The Google C++ Testing Framework
+
+// Google Test - The Google C++ Testing and Mocking Framework
//
// This file implements a universal value printer that can print a
// value of any type T:
@@ -43,12 +42,13 @@
// defines Foo.
#include "gtest/gtest-printers.h"
-#include <ctype.h>
#include <stdio.h>
+#include <cctype>
#include <cwchar>
#include <ostream> // NOLINT
#include <string>
#include "gtest/internal/gtest-port.h"
+#include "src/gtest-internal-inl.h"
namespace testing {
@@ -59,6 +59,7 @@ using ::std::ostream;
// Prints a segment of bytes in the given object.
GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_
GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_
+GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_
GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_
void PrintByteSegmentInObjectTo(const unsigned char* obj_bytes, size_t start,
size_t count, ostream* os) {
@@ -89,7 +90,6 @@ void PrintBytesInObjectToImpl(const unsigned char* obj_bytes, size_t count,
// If the object size is bigger than kThreshold, we'll have to omit
// some details by printing only the first and the last kChunkSize
// bytes.
- // TODO(wan): let the user control the threshold using a flag.
if (count < kThreshold) {
PrintByteSegmentInObjectTo(obj_bytes, 0, count, os);
} else {
@@ -123,7 +123,7 @@ namespace internal {
// Depending on the value of a char (or wchar_t), we print it in one
// of three formats:
// - as is if it's a printable ASCII (e.g. 'a', '2', ' '),
-// - as a hexidecimal escape sequence (e.g. '\x7F'), or
+// - as a hexadecimal escape sequence (e.g. '\x7F'), or
// - as a special escape sequence (e.g. '\r', '\n').
enum CharFormat {
kAsIs,
@@ -144,7 +144,8 @@ inline bool IsPrintableAscii(wchar_t c) {
// which is the type of c.
template <typename UnsignedChar, typename Char>
static CharFormat PrintAsCharLiteralTo(Char c, ostream* os) {
- switch (static_cast<wchar_t>(c)) {
+ wchar_t w_c = static_cast<wchar_t>(c);
+ switch (w_c) {
case L'\0':
*os << "\\0";
break;
@@ -176,11 +177,14 @@ static CharFormat PrintAsCharLiteralTo(Char c, ostream* os) {
*os << "\\v";
break;
default:
- if (IsPrintableAscii(c)) {
+ if (IsPrintableAscii(w_c)) {
*os << static_cast<char>(c);
return kAsIs;
} else {
- *os << "\\x" + String::FormatHexInt(static_cast<UnsignedChar>(c));
+ ostream::fmtflags flags = os->flags();
+ *os << "\\x" << std::hex << std::uppercase
+ << static_cast<int>(static_cast<UnsignedChar>(c));
+ os->flags(flags);
return kHexEscape;
}
}
@@ -227,13 +231,13 @@ void PrintCharAndCodeTo(Char c, ostream* os) {
return;
*os << " (" << static_cast<int>(c);
- // For more convenience, we print c's code again in hexidecimal,
+ // For more convenience, we print c's code again in hexadecimal,
// unless c was already printed in the form '\x##' or the code is in
// [1, 9].
if (format == kHexEscape || (1 <= c && c <= 9)) {
// Do nothing.
} else {
- *os << ", 0x" << String::FormatHexInt(static_cast<UnsignedChar>(c));
+ *os << ", 0x" << String::FormatHexInt(static_cast<int>(c));
}
*os << ")";
}
@@ -258,12 +262,14 @@ void PrintTo(wchar_t wc, ostream* os) {
template <typename CharType>
GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_
GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_
+GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_
GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_
-static void PrintCharsAsStringTo(
+static CharFormat PrintCharsAsStringTo(
const CharType* begin, size_t len, ostream* os) {
const char* const kQuoteBegin = sizeof(CharType) == 1 ? "\"" : "L\"";
*os << kQuoteBegin;
bool is_previous_hex = false;
+ CharFormat print_format = kAsIs;
for (size_t index = 0; index < len; ++index) {
const CharType cur = begin[index];
if (is_previous_hex && IsXDigit(cur)) {
@@ -273,8 +279,13 @@ static void PrintCharsAsStringTo(
*os << "\" " << kQuoteBegin;
}
is_previous_hex = PrintAsStringLiteralTo(cur, os) == kHexEscape;
+ // Remember if any characters required hex escaping.
+ if (is_previous_hex) {
+ print_format = kHexEscape;
+ }
}
*os << "\"";
+ return print_format;
}
// Prints a (const) char/wchar_t array of 'len' elements, starting at address
@@ -282,6 +293,7 @@ static void PrintCharsAsStringTo(
template <typename CharType>
GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_
GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_
+GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_
GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_
static void UniversalPrintCharArray(
const CharType* begin, size_t len, ostream* os) {
@@ -318,7 +330,7 @@ void UniversalPrintArray(const wchar_t* begin, size_t len, ostream* os) {
// Prints the given C string to the ostream.
void PrintTo(const char* s, ostream* os) {
- if (s == NULL) {
+ if (s == nullptr) {
*os << "NULL";
} else {
*os << ImplicitCast_<const void*>(s) << " pointing to ";
@@ -335,32 +347,89 @@ void PrintTo(const char* s, ostream* os) {
#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED)
// Prints the given wide C string to the ostream.
void PrintTo(const wchar_t* s, ostream* os) {
- if (s == NULL) {
+ if (s == nullptr) {
*os << "NULL";
} else {
*os << ImplicitCast_<const void*>(s) << " pointing to ";
- PrintCharsAsStringTo(s, std::wcslen(s), os);
+ PrintCharsAsStringTo(s, wcslen(s), os);
}
}
#endif // wchar_t is native
-// Prints a ::string object.
-#if GTEST_HAS_GLOBAL_STRING
-void PrintStringTo(const ::string& s, ostream* os) {
- PrintCharsAsStringTo(s.data(), s.size(), os);
+namespace {
+
+bool ContainsUnprintableControlCodes(const char* str, size_t length) {
+ const unsigned char *s = reinterpret_cast<const unsigned char *>(str);
+
+ for (size_t i = 0; i < length; i++) {
+ unsigned char ch = *s++;
+ if (std::iscntrl(ch)) {
+ switch (ch) {
+ case '\t':
+ case '\n':
+ case '\r':
+ break;
+ default:
+ return true;
+ }
+ }
+ }
+ return false;
}
-#endif // GTEST_HAS_GLOBAL_STRING
-void PrintStringTo(const ::std::string& s, ostream* os) {
- PrintCharsAsStringTo(s.data(), s.size(), os);
+bool IsUTF8TrailByte(unsigned char t) { return 0x80 <= t && t<= 0xbf; }
+
+bool IsValidUTF8(const char* str, size_t length) {
+ const unsigned char *s = reinterpret_cast<const unsigned char *>(str);
+
+ for (size_t i = 0; i < length;) {
+ unsigned char lead = s[i++];
+
+ if (lead <= 0x7f) {
+ continue; // single-byte character (ASCII) 0..7F
+ }
+ if (lead < 0xc2) {
+ return false; // trail byte or non-shortest form
+ } else if (lead <= 0xdf && (i + 1) <= length && IsUTF8TrailByte(s[i])) {
+ ++i; // 2-byte character
+ } else if (0xe0 <= lead && lead <= 0xef && (i + 2) <= length &&
+ IsUTF8TrailByte(s[i]) &&
+ IsUTF8TrailByte(s[i + 1]) &&
+ // check for non-shortest form and surrogate
+ (lead != 0xe0 || s[i] >= 0xa0) &&
+ (lead != 0xed || s[i] < 0xa0)) {
+ i += 2; // 3-byte character
+ } else if (0xf0 <= lead && lead <= 0xf4 && (i + 3) <= length &&
+ IsUTF8TrailByte(s[i]) &&
+ IsUTF8TrailByte(s[i + 1]) &&
+ IsUTF8TrailByte(s[i + 2]) &&
+ // check for non-shortest form
+ (lead != 0xf0 || s[i] >= 0x90) &&
+ (lead != 0xf4 || s[i] < 0x90)) {
+ i += 3; // 4-byte character
+ } else {
+ return false;
+ }
+ }
+ return true;
}
-// Prints a ::wstring object.
-#if GTEST_HAS_GLOBAL_WSTRING
-void PrintWideStringTo(const ::wstring& s, ostream* os) {
- PrintCharsAsStringTo(s.data(), s.size(), os);
+void ConditionalPrintAsText(const char* str, size_t length, ostream* os) {
+ if (!ContainsUnprintableControlCodes(str, length) &&
+ IsValidUTF8(str, length)) {
+ *os << "\n As Text: \"" << str << "\"";
+ }
+}
+
+} // anonymous namespace
+
+void PrintStringTo(const ::std::string& s, ostream* os) {
+ if (PrintCharsAsStringTo(s.data(), s.size(), os) == kHexEscape) {
+ if (GTEST_FLAG(print_utf8)) {
+ ConditionalPrintAsText(s.data(), s.size(), os);
+ }
+ }
}
-#endif // GTEST_HAS_GLOBAL_WSTRING
#if GTEST_HAS_STD_WSTRING
void PrintWideStringTo(const ::std::wstring& s, ostream* os) {
diff --git a/extern/gtest/src/gtest-test-part.cc b/extern/gtest/src/gtest-test-part.cc
index fb0e35425e1..178317a6bcd 100644
--- a/extern/gtest/src/gtest-test-part.cc
+++ b/extern/gtest/src/gtest-test-part.cc
@@ -26,21 +26,12 @@
// 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.
+
//
-// Author: mheule@google.com (Markus Heule)
-//
-// The Google C++ Testing Framework (Google Test)
+// The Google C++ Testing and Mocking Framework (Google Test)
#include "gtest/gtest-test-part.h"
-
-// Indicates that this translation unit is part of Google Test's
-// implementation. It must come before gtest-internal-inl.h is
-// included, or there will be a compiler error. This trick exists to
-// prevent the accidental inclusion of gtest-internal-inl.h in the
-// user's code.
-#define GTEST_IMPLEMENTATION_ 1
#include "src/gtest-internal-inl.h"
-#undef GTEST_IMPLEMENTATION_
namespace testing {
@@ -50,18 +41,21 @@ using internal::GetUnitTestImpl;
// in it.
std::string TestPartResult::ExtractSummary(const char* message) {
const char* const stack_trace = strstr(message, internal::kStackTraceMarker);
- return stack_trace == NULL ? message :
- std::string(message, stack_trace);
+ return stack_trace == nullptr ? message : std::string(message, stack_trace);
}
// Prints a TestPartResult object.
std::ostream& operator<<(std::ostream& os, const TestPartResult& result) {
- return os
- << result.file_name() << ":" << result.line_number() << ": "
- << (result.type() == TestPartResult::kSuccess ? "Success" :
- result.type() == TestPartResult::kFatalFailure ? "Fatal failure" :
- "Non-fatal failure") << ":\n"
- << result.message() << std::endl;
+ return os << result.file_name() << ":" << result.line_number() << ": "
+ << (result.type() == TestPartResult::kSuccess
+ ? "Success"
+ : result.type() == TestPartResult::kSkip
+ ? "Skipped"
+ : result.type() == TestPartResult::kFatalFailure
+ ? "Fatal failure"
+ : "Non-fatal failure")
+ << ":\n"
+ << result.message() << std::endl;
}
// Appends a TestPartResult to the array.
@@ -76,7 +70,7 @@ const TestPartResult& TestPartResultArray::GetTestPartResult(int index) const {
internal::posix::Abort();
}
- return array_[index];
+ return array_[static_cast<size_t>(index)];
}
// Returns the number of TestPartResult objects in the array.
diff --git a/extern/gtest/src/gtest-typed-test.cc b/extern/gtest/src/gtest-typed-test.cc
index df1eef4754e..8677caf732b 100644
--- a/extern/gtest/src/gtest-typed-test.cc
+++ b/extern/gtest/src/gtest-typed-test.cc
@@ -26,10 +26,10 @@
// 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.
-//
-// Author: wan@google.com (Zhanyong Wan)
+
#include "gtest/gtest-typed-test.h"
+
#include "gtest/gtest.h"
namespace testing {
@@ -48,7 +48,7 @@ static const char* SkipSpaces(const char* str) {
static std::vector<std::string> SplitIntoTestNames(const char* src) {
std::vector<std::string> name_vec;
src = SkipSpaces(src);
- for (; src != NULL; src = SkipComma(src)) {
+ for (; src != nullptr; src = SkipComma(src)) {
name_vec.push_back(StripTrailingSpaces(GetPrefixUntilComma(src)));
}
return name_vec;
@@ -57,7 +57,7 @@ static std::vector<std::string> SplitIntoTestNames(const char* src) {
// Verifies that registered_tests match the test names in
// registered_tests_; returns registered_tests if successful, or
// aborts the program otherwise.
-const char* TypedTestCasePState::VerifyRegisteredTestNames(
+const char* TypedTestSuitePState::VerifyRegisteredTestNames(
const char* file, int line, const char* registered_tests) {
typedef RegisteredTestsMap::const_iterator RegisteredTestIter;
registered_ = true;
@@ -89,7 +89,7 @@ const char* TypedTestCasePState::VerifyRegisteredTestNames(
tests.insert(name);
} else {
errors << "No test named " << name
- << " can be found in this test case.\n";
+ << " can be found in this test suite.\n";
}
}
diff --git a/extern/gtest/src/gtest.cc b/extern/gtest/src/gtest.cc
index d882ab2e36a..a5b4e5ac78c 100644
--- a/extern/gtest/src/gtest.cc
+++ b/extern/gtest/src/gtest.cc
@@ -26,10 +26,9 @@
// 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.
+
//
-// Author: wan@google.com (Zhanyong Wan)
-//
-// The Google C++ Testing Framework (Google Test)
+// The Google C++ Testing and Mocking Framework (Google Test)
#include "gtest/gtest.h"
#include "gtest/internal/custom/gtest.h"
@@ -55,8 +54,6 @@
#if GTEST_OS_LINUX
-// TODO(kenton@google.com): Use autoconf to detect availability of
-// gettimeofday().
# define GTEST_HAS_GETTIMEOFDAY_ 1
# include <fcntl.h> // NOLINT
@@ -69,10 +66,6 @@
# include <unistd.h> // NOLINT
# include <string>
-#elif GTEST_OS_SYMBIAN
-# define GTEST_HAS_GETTIMEOFDAY_ 1
-# include <sys/time.h> // NOLINT
-
#elif GTEST_OS_ZOS
# define GTEST_HAS_GETTIMEOFDAY_ 1
# include <sys/time.h> // NOLINT
@@ -87,6 +80,11 @@
#elif GTEST_OS_WINDOWS // We are on Windows proper.
+# include <windows.h> // NOLINT
+# undef min
+
+# include <crtdbg.h> // NOLINT
+# include <debugapi.h> // NOLINT
# include <io.h> // NOLINT
# include <sys/timeb.h> // NOLINT
# include <sys/types.h> // NOLINT
@@ -94,25 +92,13 @@
# if GTEST_OS_WINDOWS_MINGW
// MinGW has gettimeofday() but not _ftime64().
-// TODO(kenton@google.com): Use autoconf to detect availability of
-// gettimeofday().
-// TODO(kenton@google.com): There are other ways to get the time on
-// Windows, like GetTickCount() or GetSystemTimeAsFileTime(). MinGW
-// supports these. consider using them instead.
# define GTEST_HAS_GETTIMEOFDAY_ 1
# include <sys/time.h> // NOLINT
# endif // GTEST_OS_WINDOWS_MINGW
-// cpplint thinks that the header is already included, so we want to
-// silence it.
-# include <windows.h> // NOLINT
-# undef min
-
#else
// Assume other platforms have gettimeofday().
-// TODO(kenton@google.com): Use autoconf to detect availability of
-// gettimeofday().
# define GTEST_HAS_GETTIMEOFDAY_ 1
// cpplint thinks that the header is already included, so we want to
@@ -133,19 +119,25 @@
# include <sys/types.h> // NOLINT
#endif
-// Indicates that this translation unit is part of Google Test's
-// implementation. It must come before gtest-internal-inl.h is
-// included, or there will be a compiler error. This trick is to
-// prevent a user from accidentally including gtest-internal-inl.h in
-// his code.
-#define GTEST_IMPLEMENTATION_ 1
#include "src/gtest-internal-inl.h"
-#undef GTEST_IMPLEMENTATION_
#if GTEST_OS_WINDOWS
# define vsnprintf _vsnprintf
#endif // GTEST_OS_WINDOWS
+#if GTEST_OS_MAC
+#ifndef GTEST_OS_IOS
+#include <crt_externs.h>
+#endif
+#endif
+
+#if GTEST_HAS_ABSL
+#include "absl/debugging/failure_signal_handler.h"
+#include "absl/debugging/stacktrace.h"
+#include "absl/debugging/symbolize.h"
+#include "absl/strings/str_cat.h"
+#endif // GTEST_HAS_ABSL
+
namespace testing {
using internal::CountIf;
@@ -155,20 +147,22 @@ using internal::Shuffle;
// Constants.
-// A test whose test case name or test name matches this filter is
+// A test whose test suite name or test name matches this filter is
// disabled and not run.
static const char kDisableTestFilter[] = "DISABLED_*:*/DISABLED_*";
-// A test case whose name matches this filter is considered a death
-// test case and will be run before test cases whose name doesn't
+// A test suite whose name matches this filter is considered a death
+// test suite and will be run before test suites whose name doesn't
// match this filter.
-static const char kDeathTestCaseFilter[] = "*DeathTest:*DeathTest/*";
+static const char kDeathTestSuiteFilter[] = "*DeathTest:*DeathTest/*";
// A test filter that matches everything.
static const char kUniversalFilter[] = "*";
-// The default output file for XML output.
-static const char kDefaultOutputFile[] = "test_detail.xml";
+// The default output format.
+static const char kDefaultOutputFormat[] = "xml";
+// The default output file.
+static const char kDefaultOutputFile[] = "test_detail";
// The environment variable name for the test shard index.
static const char kTestShardIndex[] = "GTEST_SHARD_INDEX";
@@ -183,19 +177,35 @@ namespace internal {
// stack trace.
const char kStackTraceMarker[] = "\nStack trace:\n";
-// g_help_flag is true iff the --help flag or an equivalent form is
-// specified on the command line.
+// g_help_flag is true if and only if the --help flag or an equivalent form
+// is specified on the command line.
bool g_help_flag = false;
+// Utilty function to Open File for Writing
+static FILE* OpenFileForWriting(const std::string& output_file) {
+ FILE* fileout = nullptr;
+ FilePath output_file_path(output_file);
+ FilePath output_dir(output_file_path.RemoveFileName());
+
+ if (output_dir.CreateDirectoriesRecursively()) {
+ fileout = posix::FOpen(output_file.c_str(), "w");
+ }
+ if (fileout == nullptr) {
+ GTEST_LOG_(FATAL) << "Unable to open file \"" << output_file << "\"";
+ }
+ return fileout;
+}
+
} // namespace internal
+// Bazel passes in the argument to '--test_filter' via the TESTBRIDGE_TEST_ONLY
+// environment variable.
static const char* GetDefaultFilter() {
-#ifdef GTEST_TEST_FILTER_ENV_VAR_
- const char* const testbridge_test_only = getenv(GTEST_TEST_FILTER_ENV_VAR_);
- if (testbridge_test_only != NULL) {
+ const char* const testbridge_test_only =
+ internal::posix::GetEnv("TESTBRIDGE_TEST_ONLY");
+ if (testbridge_test_only != nullptr) {
return testbridge_test_only;
}
-#endif // GTEST_TEST_FILTER_ENV_VAR_
return kUniversalFilter;
}
@@ -205,15 +215,14 @@ GTEST_DEFINE_bool_(
"Run disabled tests too, in addition to the tests normally being run.");
GTEST_DEFINE_bool_(
- break_on_failure,
- internal::BoolFromGTestEnv("break_on_failure", false),
- "True iff a failed assertion should be a debugger break-point.");
+ break_on_failure, internal::BoolFromGTestEnv("break_on_failure", false),
+ "True if and only if a failed assertion should be a debugger "
+ "break-point.");
-GTEST_DEFINE_bool_(
- catch_exceptions,
- internal::BoolFromGTestEnv("catch_exceptions", true),
- "True iff " GTEST_NAME_
- " should catch exceptions and treat them as test failures.");
+GTEST_DEFINE_bool_(catch_exceptions,
+ internal::BoolFromGTestEnv("catch_exceptions", true),
+ "True if and only if " GTEST_NAME_
+ " should catch exceptions and treat them as test failures.");
GTEST_DEFINE_string_(
color,
@@ -232,26 +241,41 @@ GTEST_DEFINE_string_(
"exclude). A test is run if it matches one of the positive "
"patterns and does not match any of the negative patterns.");
+GTEST_DEFINE_bool_(
+ install_failure_signal_handler,
+ internal::BoolFromGTestEnv("install_failure_signal_handler", false),
+ "If true and supported on the current platform, " GTEST_NAME_ " should "
+ "install a signal handler that dumps debugging information when fatal "
+ "signals are raised.");
+
GTEST_DEFINE_bool_(list_tests, false,
"List all tests without running them.");
+// The net priority order after flag processing is thus:
+// --gtest_output command line flag
+// GTEST_OUTPUT environment variable
+// XML_OUTPUT_FILE environment variable
+// ''
GTEST_DEFINE_string_(
output,
- internal::StringFromGTestEnv("output", ""),
- "A format (currently must be \"xml\"), optionally followed "
- "by a colon and an output file name or directory. A directory "
- "is indicated by a trailing pathname separator. "
+ internal::StringFromGTestEnv("output",
+ internal::OutputFlagAlsoCheckEnvVar().c_str()),
+ "A format (defaults to \"xml\" but can be specified to be \"json\"), "
+ "optionally followed by a colon and an output file name or directory. "
+ "A directory is indicated by a trailing pathname separator. "
"Examples: \"xml:filename.xml\", \"xml::directoryname/\". "
"If a directory is specified, output files will be created "
"within that directory, with file-names based on the test "
"executable's name and, if necessary, made unique by adding "
"digits.");
-GTEST_DEFINE_bool_(
- print_time,
- internal::BoolFromGTestEnv("print_time", true),
- "True iff " GTEST_NAME_
- " should display elapsed time in text output.");
+GTEST_DEFINE_bool_(print_time, internal::BoolFromGTestEnv("print_time", true),
+ "True if and only if " GTEST_NAME_
+ " should display elapsed time in text output.");
+
+GTEST_DEFINE_bool_(print_utf8, internal::BoolFromGTestEnv("print_utf8", true),
+ "True if and only if " GTEST_NAME_
+ " prints UTF8 characters as text.");
GTEST_DEFINE_int32_(
random_seed,
@@ -265,16 +289,14 @@ GTEST_DEFINE_int32_(
"How many times to repeat each test. Specify a negative number "
"for repeating forever. Useful for shaking out flaky tests.");
-GTEST_DEFINE_bool_(
- show_internal_stack_frames, false,
- "True iff " GTEST_NAME_ " should include internal stack frames when "
- "printing test failure stack traces.");
+GTEST_DEFINE_bool_(show_internal_stack_frames, false,
+ "True if and only if " GTEST_NAME_
+ " should include internal stack frames when "
+ "printing test failure stack traces.");
-GTEST_DEFINE_bool_(
- shuffle,
- internal::BoolFromGTestEnv("shuffle", false),
- "True iff " GTEST_NAME_
- " should randomize tests' order on every run.");
+GTEST_DEFINE_bool_(shuffle, internal::BoolFromGTestEnv("shuffle", false),
+ "True if and only if " GTEST_NAME_
+ " should randomize tests' order on every run.");
GTEST_DEFINE_int32_(
stack_trace_depth,
@@ -294,7 +316,7 @@ GTEST_DEFINE_bool_(
internal::BoolFromGTestEnv("throw_on_failure", false),
"When this flag is specified, a failed assertion will throw an exception "
"if exceptions are enabled or exit the program with a non-zero code "
- "otherwise.");
+ "otherwise. For use with an external test framework.");
#if GTEST_USE_OWN_FLAGFILE_FLAG_
GTEST_DEFINE_string_(
@@ -310,7 +332,8 @@ namespace internal {
// than kMaxRange.
UInt32 Random::Generate(UInt32 range) {
// These constants are the same as are used in glibc's rand(3).
- state_ = (1103515245U*state_ + 12345U) % kMaxRange;
+ // Use wider types than necessary to prevent unsigned overflow diagnostics.
+ state_ = static_cast<UInt32>(1103515245ULL*state_ + 12345U) % kMaxRange;
GTEST_CHECK_(range > 0)
<< "Cannot generate a number in the range [0, 0).";
@@ -324,16 +347,16 @@ UInt32 Random::Generate(UInt32 range) {
return state_ % range;
}
-// GTestIsInitialized() returns true iff the user has initialized
+// GTestIsInitialized() returns true if and only if the user has initialized
// Google Test. Useful for catching the user mistake of not initializing
// Google Test before calling RUN_ALL_TESTS().
static bool GTestIsInitialized() { return GetArgvs().size() > 0; }
-// Iterates over a vector of TestCases, keeping a running sum of the
+// Iterates over a vector of TestSuites, keeping a running sum of the
// results of calling a given int-returning method on each.
// Returns the sum.
-static int SumOverTestCaseList(const std::vector<TestCase*>& case_list,
- int (TestCase::*method)() const) {
+static int SumOverTestSuiteList(const std::vector<TestSuite*>& case_list,
+ int (TestSuite::*method)() const) {
int sum = 0;
for (size_t i = 0; i < case_list.size(); i++) {
sum += (case_list[i]->*method)();
@@ -341,20 +364,20 @@ static int SumOverTestCaseList(const std::vector<TestCase*>& case_list,
return sum;
}
-// Returns true iff the test case passed.
-static bool TestCasePassed(const TestCase* test_case) {
- return test_case->should_run() && test_case->Passed();
+// Returns true if and only if the test suite passed.
+static bool TestSuitePassed(const TestSuite* test_suite) {
+ return test_suite->should_run() && test_suite->Passed();
}
-// Returns true iff the test case failed.
-static bool TestCaseFailed(const TestCase* test_case) {
- return test_case->should_run() && test_case->Failed();
+// Returns true if and only if the test suite failed.
+static bool TestSuiteFailed(const TestSuite* test_suite) {
+ return test_suite->should_run() && test_suite->Failed();
}
-// Returns true iff test_case contains at least one test that should
-// run.
-static bool ShouldRunTestCase(const TestCase* test_case) {
- return test_case->should_run();
+// Returns true if and only if test_suite contains at least one test that
+// should run.
+static bool ShouldRunTestSuite(const TestSuite* test_suite) {
+ return test_suite->should_run();
}
// AssertHelper constructor.
@@ -380,16 +403,16 @@ void AssertHelper::operator=(const Message& message) const {
); // NOLINT
}
-// Mutex for linked pointers.
-GTEST_API_ GTEST_DEFINE_STATIC_MUTEX_(g_linked_ptr_mutex);
-
// A copy of all command line arguments. Set by InitGoogleTest().
-::std::vector<testing::internal::string> g_argvs;
+static ::std::vector<std::string> g_argvs;
-const ::std::vector<testing::internal::string>& GetArgvs() {
+::std::vector<std::string> GetArgvs() {
#if defined(GTEST_CUSTOM_GET_ARGVS_)
- return GTEST_CUSTOM_GET_ARGVS_();
-#else // defined(GTEST_CUSTOM_GET_ARGVS_)
+ // GTEST_CUSTOM_GET_ARGVS_() may return a container of std::string or
+ // ::string. This code converts it to the appropriate type.
+ const auto& custom = GTEST_CUSTOM_GET_ARGVS_();
+ return ::std::vector<std::string>(custom.begin(), custom.end());
+#else // defined(GTEST_CUSTOM_GET_ARGVS_)
return g_argvs;
#endif // defined(GTEST_CUSTOM_GET_ARGVS_)
}
@@ -399,7 +422,7 @@ const ::std::vector<testing::internal::string>& GetArgvs() {
FilePath GetCurrentExecutableName() {
FilePath result;
-#if GTEST_OS_WINDOWS
+#if GTEST_OS_WINDOWS || GTEST_OS_OS2
result.Set(FilePath(GetArgvs()[0]).RemoveExtension("exe"));
#else
result.Set(FilePath(GetArgvs()[0]));
@@ -413,34 +436,32 @@ FilePath GetCurrentExecutableName() {
// Returns the output format, or "" for normal printed output.
std::string UnitTestOptions::GetOutputFormat() {
const char* const gtest_output_flag = GTEST_FLAG(output).c_str();
- if (gtest_output_flag == NULL) return std::string("");
-
const char* const colon = strchr(gtest_output_flag, ':');
- return (colon == NULL) ?
- std::string(gtest_output_flag) :
- std::string(gtest_output_flag, colon - gtest_output_flag);
+ return (colon == nullptr)
+ ? std::string(gtest_output_flag)
+ : std::string(gtest_output_flag,
+ static_cast<size_t>(colon - gtest_output_flag));
}
// Returns the name of the requested output file, or the default if none
// was explicitly specified.
std::string UnitTestOptions::GetAbsolutePathToOutputFile() {
const char* const gtest_output_flag = GTEST_FLAG(output).c_str();
- if (gtest_output_flag == NULL)
- return "";
+
+ std::string format = GetOutputFormat();
+ if (format.empty())
+ format = std::string(kDefaultOutputFormat);
const char* const colon = strchr(gtest_output_flag, ':');
- if (colon == NULL)
- return internal::FilePath::ConcatPaths(
+ if (colon == nullptr)
+ return internal::FilePath::MakeFileName(
internal::FilePath(
UnitTest::GetInstance()->original_working_dir()),
- internal::FilePath(kDefaultOutputFile)).string();
+ internal::FilePath(kDefaultOutputFile), 0,
+ format.c_str()).string();
internal::FilePath output_name(colon + 1);
if (!output_name.IsAbsolutePath())
- // TODO(wan@google.com): on Windows \some\path is not an absolute
- // path (as its meaning depends on the current drive), yet the
- // following logic for turning it into an absolute path is wrong.
- // Fix it.
output_name = internal::FilePath::ConcatPaths(
internal::FilePath(UnitTest::GetInstance()->original_working_dir()),
internal::FilePath(colon + 1));
@@ -454,8 +475,8 @@ std::string UnitTestOptions::GetAbsolutePathToOutputFile() {
return result.string();
}
-// Returns true iff the wildcard pattern matches the string. The
-// first ':' or '\0' character in pattern marks the end of it.
+// Returns true if and only if the wildcard pattern matches the string.
+// The first ':' or '\0' character in pattern marks the end of it.
//
// This recursive algorithm isn't very efficient, but is clear and
// works well enough for matching test names, which are short.
@@ -488,7 +509,7 @@ bool UnitTestOptions::MatchesFilter(
cur_pattern = strchr(cur_pattern, ':');
// Returns if no more pattern can be found.
- if (cur_pattern == NULL) {
+ if (cur_pattern == nullptr) {
return false;
}
@@ -497,11 +518,11 @@ bool UnitTestOptions::MatchesFilter(
}
}
-// Returns true iff the user-specified filter matches the test case
-// name and the test name.
-bool UnitTestOptions::FilterMatchesTest(const std::string &test_case_name,
- const std::string &test_name) {
- const std::string& full_name = test_case_name + "." + test_name.c_str();
+// Returns true if and only if the user-specified filter matches the test
+// suite name and the test name.
+bool UnitTestOptions::FilterMatchesTest(const std::string& test_suite_name,
+ const std::string& test_name) {
+ const std::string& full_name = test_suite_name + "." + test_name.c_str();
// Split --gtest_filter at '-', if there is one, to separate into
// positive filter and negative filter portions
@@ -509,7 +530,7 @@ bool UnitTestOptions::FilterMatchesTest(const std::string &test_case_name,
const char* const dash = strchr(p, '-');
std::string positive;
std::string negative;
- if (dash == NULL) {
+ if (dash == nullptr) {
positive = GTEST_FLAG(filter).c_str(); // Whole string is a positive filter
negative = "";
} else {
@@ -628,12 +649,12 @@ extern const TypeId kTestTypeIdInGoogleTest = GetTestTypeId();
// This predicate-formatter checks that 'results' contains a test part
// failure of the given type and that the failure message contains the
// given substring.
-AssertionResult HasOneFailure(const char* /* results_expr */,
- const char* /* type_expr */,
- const char* /* substr_expr */,
- const TestPartResultArray& results,
- TestPartResult::Type type,
- const string& substr) {
+static AssertionResult HasOneFailure(const char* /* results_expr */,
+ const char* /* type_expr */,
+ const char* /* substr_expr */,
+ const TestPartResultArray& results,
+ TestPartResult::Type type,
+ const std::string& substr) {
const std::string expected(type == TestPartResult::kFatalFailure ?
"1 fatal failure" :
"1 non-fatal failure");
@@ -654,7 +675,7 @@ AssertionResult HasOneFailure(const char* /* results_expr */,
<< r;
}
- if (strstr(r.message(), substr.c_str()) == NULL) {
+ if (strstr(r.message(), substr.c_str()) == nullptr) {
return AssertionFailure() << "Expected: " << expected << " containing \""
<< substr << "\"\n"
<< " Actual:\n"
@@ -667,13 +688,10 @@ AssertionResult HasOneFailure(const char* /* results_expr */,
// The constructor of SingleFailureChecker remembers where to look up
// test part results, what type of failure we expect, and what
// substring the failure message should contain.
-SingleFailureChecker:: SingleFailureChecker(
- const TestPartResultArray* results,
- TestPartResult::Type type,
- const string& substr)
- : results_(results),
- type_(type),
- substr_(substr) {}
+SingleFailureChecker::SingleFailureChecker(const TestPartResultArray* results,
+ TestPartResult::Type type,
+ const std::string& substr)
+ : results_(results), type_(type), substr_(substr) {}
// The destructor of SingleFailureChecker verifies that the given
// TestPartResultArray contains exactly one failure that has the given
@@ -726,61 +744,66 @@ void UnitTestImpl::SetTestPartResultReporterForCurrentThread(
per_thread_test_part_result_reporter_.set(reporter);
}
-// Gets the number of successful test cases.
-int UnitTestImpl::successful_test_case_count() const {
- return CountIf(test_cases_, TestCasePassed);
+// Gets the number of successful test suites.
+int UnitTestImpl::successful_test_suite_count() const {
+ return CountIf(test_suites_, TestSuitePassed);
}
-// Gets the number of failed test cases.
-int UnitTestImpl::failed_test_case_count() const {
- return CountIf(test_cases_, TestCaseFailed);
+// Gets the number of failed test suites.
+int UnitTestImpl::failed_test_suite_count() const {
+ return CountIf(test_suites_, TestSuiteFailed);
}
-// Gets the number of all test cases.
-int UnitTestImpl::total_test_case_count() const {
- return static_cast<int>(test_cases_.size());
+// Gets the number of all test suites.
+int UnitTestImpl::total_test_suite_count() const {
+ return static_cast<int>(test_suites_.size());
}
-// Gets the number of all test cases that contain at least one test
+// Gets the number of all test suites that contain at least one test
// that should run.
-int UnitTestImpl::test_case_to_run_count() const {
- return CountIf(test_cases_, ShouldRunTestCase);
+int UnitTestImpl::test_suite_to_run_count() const {
+ return CountIf(test_suites_, ShouldRunTestSuite);
}
// Gets the number of successful tests.
int UnitTestImpl::successful_test_count() const {
- return SumOverTestCaseList(test_cases_, &TestCase::successful_test_count);
+ return SumOverTestSuiteList(test_suites_, &TestSuite::successful_test_count);
+}
+
+// Gets the number of skipped tests.
+int UnitTestImpl::skipped_test_count() const {
+ return SumOverTestSuiteList(test_suites_, &TestSuite::skipped_test_count);
}
// Gets the number of failed tests.
int UnitTestImpl::failed_test_count() const {
- return SumOverTestCaseList(test_cases_, &TestCase::failed_test_count);
+ return SumOverTestSuiteList(test_suites_, &TestSuite::failed_test_count);
}
// Gets the number of disabled tests that will be reported in the XML report.
int UnitTestImpl::reportable_disabled_test_count() const {
- return SumOverTestCaseList(test_cases_,
- &TestCase::reportable_disabled_test_count);
+ return SumOverTestSuiteList(test_suites_,
+ &TestSuite::reportable_disabled_test_count);
}
// Gets the number of disabled tests.
int UnitTestImpl::disabled_test_count() const {
- return SumOverTestCaseList(test_cases_, &TestCase::disabled_test_count);
+ return SumOverTestSuiteList(test_suites_, &TestSuite::disabled_test_count);
}
// Gets the number of tests to be printed in the XML report.
int UnitTestImpl::reportable_test_count() const {
- return SumOverTestCaseList(test_cases_, &TestCase::reportable_test_count);
+ return SumOverTestSuiteList(test_suites_, &TestSuite::reportable_test_count);
}
// Gets the number of all tests.
int UnitTestImpl::total_test_count() const {
- return SumOverTestCaseList(test_cases_, &TestCase::total_test_count);
+ return SumOverTestSuiteList(test_suites_, &TestSuite::total_test_count);
}
// Gets the number of tests that should run.
int UnitTestImpl::test_to_run_count() const {
- return SumOverTestCaseList(test_cases_, &TestCase::test_to_run_count);
+ return SumOverTestSuiteList(test_suites_, &TestSuite::test_to_run_count);
}
// Returns the current OS stack trace as an std::string.
@@ -814,8 +837,6 @@ TimeInMillis GetTimeInMillis() {
SYSTEMTIME now_systime;
FILETIME now_filetime;
ULARGE_INTEGER now_int64;
- // TODO(kenton@google.com): Shouldn't this just use
- // GetSystemTimeAsFileTime()?
GetSystemTime(&now_systime);
if (SystemTimeToFileTime(&now_systime, &now_filetime)) {
now_int64.LowPart = now_filetime.dwLowDateTime;
@@ -830,16 +851,14 @@ TimeInMillis GetTimeInMillis() {
// MSVC 8 deprecates _ftime64(), so we want to suppress warning 4996
// (deprecated function) there.
- // TODO(kenton@google.com): Use GetTickCount()? Or use
- // SystemTimeToFileTime()
- GTEST_DISABLE_MSC_WARNINGS_PUSH_(4996)
+ GTEST_DISABLE_MSC_DEPRECATED_PUSH_()
_ftime64(&now);
- GTEST_DISABLE_MSC_WARNINGS_POP_()
+ GTEST_DISABLE_MSC_DEPRECATED_POP_()
return static_cast<TimeInMillis>(now.time) * 1000 + now.millitm;
#elif GTEST_HAS_GETTIMEOFDAY_
struct timeval now;
- gettimeofday(&now, NULL);
+ gettimeofday(&now, nullptr);
return static_cast<TimeInMillis>(now.tv_sec) * 1000 + now.tv_usec / 1000;
#else
# error "Don't know how to get the current time on your system."
@@ -856,11 +875,10 @@ TimeInMillis GetTimeInMillis() {
// value using delete[]. Returns the wide string, or NULL if the
// input is NULL.
LPCWSTR String::AnsiToUtf16(const char* ansi) {
- if (!ansi) return NULL;
+ if (!ansi) return nullptr;
const int length = strlen(ansi);
const int unicode_length =
- MultiByteToWideChar(CP_ACP, 0, ansi, length,
- NULL, 0);
+ MultiByteToWideChar(CP_ACP, 0, ansi, length, nullptr, 0);
WCHAR* unicode = new WCHAR[unicode_length + 1];
MultiByteToWideChar(CP_ACP, 0, ansi, length,
unicode, unicode_length);
@@ -873,33 +891,33 @@ LPCWSTR String::AnsiToUtf16(const char* ansi) {
// value using delete[]. Returns the ANSI string, or NULL if the
// input is NULL.
const char* String::Utf16ToAnsi(LPCWSTR utf16_str) {
- if (!utf16_str) return NULL;
- const int ansi_length =
- WideCharToMultiByte(CP_ACP, 0, utf16_str, -1,
- NULL, 0, NULL, NULL);
+ if (!utf16_str) return nullptr;
+ const int ansi_length = WideCharToMultiByte(CP_ACP, 0, utf16_str, -1, nullptr,
+ 0, nullptr, nullptr);
char* ansi = new char[ansi_length + 1];
- WideCharToMultiByte(CP_ACP, 0, utf16_str, -1,
- ansi, ansi_length, NULL, NULL);
+ WideCharToMultiByte(CP_ACP, 0, utf16_str, -1, ansi, ansi_length, nullptr,
+ nullptr);
ansi[ansi_length] = 0;
return ansi;
}
#endif // GTEST_OS_WINDOWS_MOBILE
-// Compares two C strings. Returns true iff they have the same content.
+// Compares two C strings. Returns true if and only if 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.
bool String::CStringEquals(const char * lhs, const char * rhs) {
- if ( lhs == NULL ) return rhs == NULL;
+ if (lhs == nullptr) return rhs == nullptr;
- if ( rhs == NULL ) return false;
+ if (rhs == nullptr) return false;
return strcmp(lhs, rhs) == 0;
}
-#if GTEST_HAS_STD_WSTRING || GTEST_HAS_GLOBAL_WSTRING
+#if GTEST_HAS_STD_WSTRING
// Converts an array of wide chars to a narrow string using the UTF-8
// encoding, and streams the result to the given Message object.
@@ -917,7 +935,7 @@ static void StreamWideCharsToMessage(const wchar_t* wstr, size_t length,
}
}
-#endif // GTEST_HAS_STD_WSTRING || GTEST_HAS_GLOBAL_WSTRING
+#endif // GTEST_HAS_STD_WSTRING
void SplitString(const ::std::string& str, char delimiter,
::std::vector< ::std::string>* dest) {
@@ -967,15 +985,6 @@ Message& Message::operator <<(const ::std::wstring& wstr) {
}
#endif // GTEST_HAS_STD_WSTRING
-#if GTEST_HAS_GLOBAL_WSTRING
-// Converts the given wide string to a narrow string using the UTF-8
-// encoding, and streams the result to this Message object.
-Message& Message::operator <<(const ::wstring& wstr) {
- internal::StreamWideCharsToMessage(wstr.c_str(), wstr.length(), this);
- return *this;
-}
-#endif // GTEST_HAS_GLOBAL_WSTRING
-
// Gets the text streamed to this object so far as an std::string.
// Each '\0' character in the buffer is replaced with "\\0".
std::string Message::GetString() const {
@@ -986,10 +995,9 @@ std::string Message::GetString() const {
// Used in EXPECT_TRUE/FALSE(assertion_result).
AssertionResult::AssertionResult(const AssertionResult& other)
: success_(other.success_),
- message_(other.message_.get() != NULL ?
- new ::std::string(*other.message_) :
- static_cast< ::std::string*>(NULL)) {
-}
+ message_(other.message_.get() != nullptr
+ ? new ::std::string(*other.message_)
+ : static_cast< ::std::string*>(nullptr)) {}
// Swaps two AssertionResults.
void AssertionResult::swap(AssertionResult& other) {
@@ -1001,8 +1009,7 @@ void AssertionResult::swap(AssertionResult& other) {
// Returns the assertion's negation. Used with EXPECT/ASSERT_FALSE.
AssertionResult AssertionResult::operator!() const {
AssertionResult negation(!success_);
- if (message_.get() != NULL)
- negation << *message_;
+ if (message_.get() != nullptr) negation << *message_;
return negation;
}
@@ -1171,7 +1178,7 @@ class Hunk {
// Print a unified diff header for one hunk.
// The format is
// "@@ -<left_start>,<left_length> +<right_start>,<right_length> @@"
- // where the left/right parts are ommitted if unnecessary.
+ // where the left/right parts are omitted if unnecessary.
void PrintHeader(std::ostream* ss) const {
*ss << "@@ ";
if (removes_) {
@@ -1228,9 +1235,10 @@ std::string CreateUnifiedDiff(const std::vector<std::string>& left,
for (; edit_i < edits.size(); ++edit_i) {
if (n_suffix >= context) {
// Continue only if the next hunk is very close.
- std::vector<EditType>::const_iterator it = edits.begin() + edit_i;
+ auto it = edits.begin() + static_cast<int>(edit_i);
while (it != edits.end() && *it == kMatch) ++it;
- if (it == edits.end() || (it - edits.begin()) - edit_i >= context) {
+ if (it == edits.end() ||
+ static_cast<size_t>(it - edits.begin()) - edit_i >= context) {
// There is no next edit or it is too far away.
break;
}
@@ -1306,7 +1314,7 @@ std::vector<std::string> SplitEscapedString(const std::string& str) {
// lhs_value: "5"
// rhs_value: "6"
//
-// The ignoring_case parameter is true iff the assertion is a
+// The ignoring_case parameter is true if and only if the assertion is a
// *_STRCASEEQ*. When it's true, the string "Ignoring case" will
// be inserted into the message.
AssertionResult EqFailure(const char* lhs_expression,
@@ -1315,13 +1323,14 @@ AssertionResult EqFailure(const char* lhs_expression,
const std::string& rhs_value,
bool ignoring_case) {
Message msg;
- msg << " Expected: " << lhs_expression;
+ msg << "Expected equality of these values:";
+ msg << "\n " << lhs_expression;
if (lhs_value != lhs_expression) {
- msg << "\n Which is: " << lhs_value;
+ msg << "\n Which is: " << lhs_value;
}
- msg << "\nTo be equal to: " << rhs_expression;
+ msg << "\n " << rhs_expression;
if (rhs_value != rhs_expression) {
- msg << "\n Which is: " << rhs_value;
+ msg << "\n Which is: " << rhs_value;
}
if (ignoring_case) {
@@ -1368,8 +1377,6 @@ AssertionResult DoubleNearPredFormat(const char* expr1,
const double diff = fabs(val1 - val2);
if (diff <= abs_error) return AssertionSuccess();
- // TODO(wan): do not print the value of an expression if it's
- // already a literal.
return AssertionFailure()
<< "The difference between " << expr1 << " and " << expr2
<< " is " << diff << ", which exceeds " << abs_error_expr << ", where\n"
@@ -1550,22 +1557,20 @@ namespace {
// Helper functions for implementing IsSubString() and IsNotSubstring().
-// This group of overloaded functions return true iff needle is a
-// substring of haystack. NULL is considered a substring of itself
-// only.
+// This group of overloaded functions return true if and only if needle
+// is a substring of haystack. NULL is considered a substring of
+// itself only.
bool IsSubstringPred(const char* needle, const char* haystack) {
- if (needle == NULL || haystack == NULL)
- return needle == haystack;
+ if (needle == nullptr || haystack == nullptr) return needle == haystack;
- return strstr(haystack, needle) != NULL;
+ return strstr(haystack, needle) != nullptr;
}
bool IsSubstringPred(const wchar_t* needle, const wchar_t* haystack) {
- if (needle == NULL || haystack == NULL)
- return needle == haystack;
+ if (needle == nullptr || haystack == nullptr) return needle == haystack;
- return wcsstr(haystack, needle) != NULL;
+ return wcsstr(haystack, needle) != nullptr;
}
// StringType here can be either ::std::string or ::std::wstring.
@@ -1663,7 +1668,7 @@ namespace {
AssertionResult HRESULTFailureHelper(const char* expr,
const char* expected,
long hr) { // NOLINT
-# if GTEST_OS_WINDOWS_MOBILE
+# if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_WINDOWS_TV_TITLE
// Windows CE doesn't support FormatMessage.
const char error_text[] = "";
@@ -1679,12 +1684,12 @@ AssertionResult HRESULTFailureHelper(const char* expr,
// Gets the system's human readable message string for this HRESULT.
char error_text[kBufSize] = { '\0' };
DWORD message_length = ::FormatMessageA(kFlags,
- 0, // no source, we're asking system
- hr, // the error
- 0, // no line width restrictions
+ 0, // no source, we're asking system
+ static_cast<DWORD>(hr), // the error
+ 0, // no line width restrictions
error_text, // output buffer
- kBufSize, // buf size
- NULL); // no arguments for inserts
+ kBufSize, // buf size
+ nullptr); // no arguments for inserts
// Trims tailing white space (FormatMessage leaves a trailing CR-LF)
for (; message_length && IsSpace(error_text[message_length - 1]);
--message_length) {
@@ -1720,7 +1725,7 @@ AssertionResult IsHRESULTFailure(const char* expr, long hr) { // NOLINT
// Utility functions for encoding Unicode text (wide strings) in
// UTF-8.
-// A Unicode code-point can have upto 21 bits, and is encoded in UTF-8
+// A Unicode code-point can have up to 21 bits, and is encoded in UTF-8
// like this:
//
// Code-point length Encoding
@@ -1758,7 +1763,7 @@ inline UInt32 ChopLowBits(UInt32* bits, int n) {
// to "(Invalid Unicode 0xXXXXXXXX)".
std::string CodePointToUtf8(UInt32 code_point) {
if (code_point > kMaxCodePoint4) {
- return "(Invalid Unicode 0x" + String::FormatHexInt(code_point) + ")";
+ return "(Invalid Unicode 0x" + String::FormatHexUInt32(code_point) + ")";
}
char str[5]; // Big enough for the largest valid code point.
@@ -1784,9 +1789,9 @@ std::string CodePointToUtf8(UInt32 code_point) {
return str;
}
-// The following two functions only make sense if the the system
+// The following two functions only make sense if the system
// uses UTF-16 for wide string encoding. All supported systems
-// with 16 bit wchar_t (Windows, Cygwin, Symbian OS) do use UTF-16.
+// with 16 bit wchar_t (Windows, Cygwin) do use UTF-16.
// Determines if the arguments constitute UTF-16 surrogate pair
// and thus should be combined into a single Unicode code point
@@ -1799,17 +1804,20 @@ inline bool IsUtf16SurrogatePair(wchar_t first, wchar_t second) {
// Creates a Unicode code point from UTF16 surrogate pair.
inline UInt32 CreateCodePointFromUtf16SurrogatePair(wchar_t first,
wchar_t second) {
+ const auto first_u = static_cast<UInt32>(first);
+ const auto second_u = static_cast<UInt32>(second);
const UInt32 mask = (1 << 10) - 1;
- return (sizeof(wchar_t) == 2) ?
- (((first & mask) << 10) | (second & mask)) + 0x10000 :
- // This function should not be called when the condition is
- // false, but we provide a sensible default in case it is.
- static_cast<UInt32>(first);
+ return (sizeof(wchar_t) == 2)
+ ? (((first_u & mask) << 10) | (second_u & mask)) + 0x10000
+ :
+ // This function should not be called when the condition is
+ // false, but we provide a sensible default in case it is.
+ first_u;
}
// Converts a wide string to a narrow string in UTF-8 encoding.
// The wide string is assumed to have the following encoding:
-// UTF-16 if sizeof(wchar_t) == 2 (on Windows, Cygwin, Symbian OS)
+// UTF-16 if sizeof(wchar_t) == 2 (on Windows, Cygwin)
// UTF-32 if sizeof(wchar_t) == 4 (on Linux)
// Parameter str points to a null-terminated wide string.
// Parameter num_chars may additionally limit the number
@@ -1846,21 +1854,21 @@ std::string WideStringToUtf8(const wchar_t* str, int num_chars) {
// Converts a wide C string to an std::string using the UTF-8 encoding.
// NULL will be converted to "(null)".
std::string String::ShowWideCString(const wchar_t * wide_c_str) {
- if (wide_c_str == NULL) return "(null)";
+ if (wide_c_str == nullptr) return "(null)";
return internal::WideStringToUtf8(wide_c_str, -1);
}
-// Compares two wide C strings. Returns true iff they have the same
-// content.
+// Compares two wide C strings. Returns true if and only if 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.
bool String::WideCStringEquals(const wchar_t * lhs, const wchar_t * rhs) {
- if (lhs == NULL) return rhs == NULL;
+ if (lhs == nullptr) return rhs == nullptr;
- if (rhs == NULL) return false;
+ if (rhs == nullptr) return false;
return wcscmp(lhs, rhs) == 0;
}
@@ -1896,37 +1904,35 @@ AssertionResult CmpHelperSTRNE(const char* s1_expression,
<< " vs " << PrintToString(s2);
}
-// Compares two C strings, ignoring case. Returns true iff they have
+// Compares two C strings, ignoring case. Returns true if and only if 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.
bool String::CaseInsensitiveCStringEquals(const char * lhs, const char * rhs) {
- if (lhs == NULL)
- return rhs == NULL;
- if (rhs == NULL)
- return false;
+ if (lhs == nullptr) return rhs == nullptr;
+ if (rhs == nullptr) return false;
return posix::StrCaseCmp(lhs, rhs) == 0;
}
- // 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.
+// Compares two wide C strings, ignoring case. Returns true if and only if 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.
bool String::CaseInsensitiveWideCStringEquals(const wchar_t* lhs,
const wchar_t* rhs) {
- if (lhs == NULL) return rhs == NULL;
+ if (lhs == nullptr) return rhs == nullptr;
- if (rhs == NULL) return false;
+ if (rhs == nullptr) return false;
#if GTEST_OS_WINDOWS
return _wcsicmp(lhs, rhs) == 0;
@@ -1937,14 +1943,14 @@ bool String::CaseInsensitiveWideCStringEquals(const wchar_t* lhs,
// Other unknown OSes may not define it either.
wint_t left, right;
do {
- left = towlower(*lhs++);
- right = towlower(*rhs++);
+ left = towlower(static_cast<wint_t>(*lhs++));
+ right = towlower(static_cast<wint_t>(*rhs++));
} while (left && left == right);
return left == right;
#endif // OS selector
}
-// Returns true iff str ends with the given suffix, ignoring case.
+// Returns true if and only if str ends with the given suffix, ignoring case.
// Any string is considered to end with an empty suffix.
bool String::EndsWithCaseInsensitive(
const std::string& str, const std::string& suffix) {
@@ -1963,12 +1969,17 @@ std::string String::FormatIntWidth2(int value) {
}
// Formats an int value as "%X".
-std::string String::FormatHexInt(int value) {
+std::string String::FormatHexUInt32(UInt32 value) {
std::stringstream ss;
ss << std::hex << std::uppercase << value;
return ss.str();
}
+// Formats an int value as "%X".
+std::string String::FormatHexInt(int value) {
+ return FormatHexUInt32(static_cast<UInt32>(value));
+}
+
// Formats a byte as "%02X".
std::string String::FormatByte(unsigned char value) {
std::stringstream ss;
@@ -1985,7 +1996,7 @@ std::string StringStreamToString(::std::stringstream* ss) {
const char* const end = start + str.length();
std::string result;
- result.reserve(2 * (end - start));
+ result.reserve(static_cast<size_t>(2 * (end - start)));
for (const char* ch = start; ch != end; ++ch) {
if (*ch == '\0') {
result += "\\0"; // Replaces NUL with "\\0";
@@ -2015,9 +2026,7 @@ std::string AppendUserMessage(const std::string& gtest_msg,
// Creates an empty TestResult.
TestResult::TestResult()
- : death_test_count_(0),
- elapsed_time_(0) {
-}
+ : death_test_count_(0), start_timestamp_(0), elapsed_time_(0) {}
// D'tor.
TestResult::~TestResult() {
@@ -2029,7 +2038,7 @@ TestResult::~TestResult() {
const TestPartResult& TestResult::GetTestPartResult(int i) const {
if (i < 0 || i >= total_part_count())
internal::posix::Abort();
- return test_part_results_.at(i);
+ return test_part_results_.at(static_cast<size_t>(i));
}
// Returns the i-th test property. i can range from 0 to
@@ -2038,7 +2047,7 @@ const TestPartResult& TestResult::GetTestPartResult(int i) const {
const TestProperty& TestResult::GetTestProperty(int i) const {
if (i < 0 || i >= test_property_count())
internal::posix::Abort();
- return test_properties_.at(i);
+ return test_properties_.at(static_cast<size_t>(i));
}
// Clears the test part results.
@@ -2086,23 +2095,18 @@ static const char* const kReservedTestSuitesAttributes[] = {
// The list of reserved attributes used in the <testsuite> element of XML
// output.
static const char* const kReservedTestSuiteAttributes[] = {
- "disabled",
- "errors",
- "failures",
- "name",
- "tests",
- "time"
-};
+ "disabled", "errors", "failures", "name", "tests", "time", "timestamp"};
// The list of reserved attributes used in the <testcase> element of XML output.
static const char* const kReservedTestCaseAttributes[] = {
- "classname",
- "name",
- "status",
- "time",
- "type_param",
- "value_param"
-};
+ "classname", "name", "status", "time", "type_param",
+ "value_param", "file", "line"};
+
+// Use a slightly different set for allowed output to ensure existing tests can
+// still RecordProperty("result") or "RecordProperty(timestamp")
+static const char* const kReservedOutputTestCaseAttributes[] = {
+ "classname", "name", "status", "time", "type_param",
+ "value_param", "file", "line", "result", "timestamp"};
template <int kSize>
std::vector<std::string> ArrayAsVector(const char* const (&array)[kSize]) {
@@ -2124,6 +2128,22 @@ static std::vector<std::string> GetReservedAttributesForElement(
return std::vector<std::string>();
}
+// TODO(jdesprez): Merge the two getReserved attributes once skip is improved
+static std::vector<std::string> GetReservedOutputAttributesForElement(
+ const std::string& xml_element) {
+ if (xml_element == "testsuites") {
+ return ArrayAsVector(kReservedTestSuitesAttributes);
+ } else if (xml_element == "testsuite") {
+ return ArrayAsVector(kReservedTestSuiteAttributes);
+ } else if (xml_element == "testcase") {
+ return ArrayAsVector(kReservedOutputTestCaseAttributes);
+ } else {
+ GTEST_CHECK_(false) << "Unrecognized xml_element provided: " << xml_element;
+ }
+ // This code is unreachable but some compilers may not realizes that.
+ return std::vector<std::string>();
+}
+
static std::string FormatWordList(const std::vector<std::string>& words) {
Message word_list;
for (size_t i = 0; i < words.size(); ++i) {
@@ -2138,8 +2158,9 @@ static std::string FormatWordList(const std::vector<std::string>& words) {
return word_list.GetString();
}
-bool ValidateTestPropertyName(const std::string& property_name,
- const std::vector<std::string>& reserved_names) {
+static bool ValidateTestPropertyName(
+ const std::string& property_name,
+ const std::vector<std::string>& reserved_names) {
if (std::find(reserved_names.begin(), reserved_names.end(), property_name) !=
reserved_names.end()) {
ADD_FAILURE() << "Reserved key used in RecordProperty(): " << property_name
@@ -2166,7 +2187,17 @@ void TestResult::Clear() {
elapsed_time_ = 0;
}
-// Returns true iff the test failed.
+// Returns true off the test part was skipped.
+static bool TestPartSkipped(const TestPartResult& result) {
+ return result.skipped();
+}
+
+// Returns true if and only if the test was skipped.
+bool TestResult::Skipped() const {
+ return !Failed() && CountIf(test_part_results_, TestPartSkipped) > 0;
+}
+
+// Returns true if and only if the test failed.
bool TestResult::Failed() const {
for (int i = 0; i < total_part_count(); ++i) {
if (GetTestPartResult(i).failed())
@@ -2175,22 +2206,22 @@ bool TestResult::Failed() const {
return false;
}
-// Returns true iff the test part fatally failed.
+// Returns true if and only if the test part fatally failed.
static bool TestPartFatallyFailed(const TestPartResult& result) {
return result.fatally_failed();
}
-// Returns true iff the test fatally failed.
+// Returns true if and only if the test fatally failed.
bool TestResult::HasFatalFailure() const {
return CountIf(test_part_results_, TestPartFatallyFailed) > 0;
}
-// Returns true iff the test part non-fatally failed.
+// Returns true if and only if the test part non-fatally failed.
static bool TestPartNonfatallyFailed(const TestPartResult& result) {
return result.nonfatally_failed();
}
-// Returns true iff the test has a non-fatal failure.
+// Returns true if and only if the test has a non-fatal failure.
bool TestResult::HasNonfatalFailure() const {
return CountIf(test_part_results_, TestPartNonfatallyFailed) > 0;
}
@@ -2253,25 +2284,25 @@ void ReportFailureInUnknownLocation(TestPartResult::Type result_type,
// AddTestPartResult.
UnitTest::GetInstance()->AddTestPartResult(
result_type,
- NULL, // No info about the source file where the exception occurred.
- -1, // We have no info on which line caused the exception.
+ nullptr, // No info about the source file where the exception occurred.
+ -1, // We have no info on which line caused the exception.
message,
- ""); // No stack trace, either.
+ ""); // No stack trace, either.
}
} // namespace internal
-// Google Test requires all tests in the same test case to use the same test
+// Google Test requires all tests in the same test suite to use the same test
// fixture class. This function checks if the current test has the
-// same fixture class as the first test in the current test case. If
+// same fixture class as the first test in the current test suite. If
// yes, it returns true; otherwise it generates a Google Test failure and
// returns false.
bool Test::HasSameFixtureClass() {
internal::UnitTestImpl* const impl = internal::GetUnitTestImpl();
- const TestCase* const test_case = impl->current_test_case();
+ const TestSuite* const test_suite = impl->current_test_suite();
- // Info about the first test in the current test case.
- const TestInfo* const first_test_info = test_case->test_info_list()[0];
+ // Info about the first test in the current test suite.
+ const TestInfo* const first_test_info = test_suite->test_info_list()[0];
const internal::TypeId first_fixture_id = first_test_info->fixture_class_id_;
const char* const first_test_name = first_test_info->name();
@@ -2287,7 +2318,7 @@ bool Test::HasSameFixtureClass() {
const bool this_is_TEST = this_fixture_id == internal::GetTestTypeId();
if (first_is_TEST || this_is_TEST) {
- // Both TEST and TEST_F appear in same test case, which is incorrect.
+ // Both TEST and TEST_F appear in same test suite, which is incorrect.
// Tell the user how to fix this.
// Gets the name of the TEST and the name of the TEST_F. Note
@@ -2299,9 +2330,9 @@ bool Test::HasSameFixtureClass() {
first_is_TEST ? this_test_name : first_test_name;
ADD_FAILURE()
- << "All tests in the same test case must use the same test fixture\n"
- << "class, so mixing TEST_F and TEST in the same test case is\n"
- << "illegal. In test case " << this_test_info->test_case_name()
+ << "All tests in the same test suite must use the same test fixture\n"
+ << "class, so mixing TEST_F and TEST in the same test suite is\n"
+ << "illegal. In test suite " << this_test_info->test_suite_name()
<< ",\n"
<< "test " << TEST_F_name << " is defined using TEST_F but\n"
<< "test " << TEST_name << " is defined using TEST. You probably\n"
@@ -2311,15 +2342,15 @@ bool Test::HasSameFixtureClass() {
// Two fixture classes with the same name appear in two different
// namespaces, which is not allowed. Tell the user how to fix this.
ADD_FAILURE()
- << "All tests in the same test case must use the same test fixture\n"
- << "class. However, in test case "
- << this_test_info->test_case_name() << ",\n"
- << "you defined test " << first_test_name
- << " and test " << this_test_name << "\n"
+ << "All tests in the same test suite must use the same test fixture\n"
+ << "class. However, in test suite "
+ << this_test_info->test_suite_name() << ",\n"
+ << "you defined test " << first_test_name << " and test "
+ << this_test_name << "\n"
<< "using two different test fixture classes. This can happen if\n"
<< "the two classes are from different namespaces or translation\n"
<< "units and have the same name. You should probably rename one\n"
- << "of the classes to put the tests into different test cases.";
+ << "of the classes to put the tests into different test suites.";
}
return false;
}
@@ -2352,7 +2383,7 @@ namespace internal {
static std::string FormatCxxExceptionMessage(const char* description,
const char* location) {
Message message;
- if (description != NULL) {
+ if (description != nullptr) {
message << "C++ exception with description \"" << description << "\"";
} else {
message << "Unknown C++ exception";
@@ -2436,6 +2467,8 @@ Result HandleExceptionsInMethodIfSupported(
#if GTEST_HAS_EXCEPTIONS
try {
return HandleSehExceptionsInMethodIfSupported(object, method, location);
+ } catch (const AssertionException&) { // NOLINT
+ // This failure was reported already.
} catch (const internal::GoogleTestFailureException&) { // NOLINT
// This exception type can only be thrown by a failed Google
// Test assertion with the intention of letting another testing
@@ -2448,7 +2481,7 @@ Result HandleExceptionsInMethodIfSupported(
} catch (...) { // NOLINT
internal::ReportFailureInUnknownLocation(
TestPartResult::kFatalFailure,
- FormatCxxExceptionMessage(NULL, location));
+ FormatCxxExceptionMessage(nullptr, location));
}
return static_cast<Result>(0);
#else
@@ -2468,8 +2501,9 @@ void Test::Run() {
internal::UnitTestImpl* const impl = internal::GetUnitTestImpl();
impl->os_stack_trace_getter()->UponLeavingGTest();
internal::HandleExceptionsInMethodIfSupported(this, &Test::SetUp, "SetUp()");
- // We will run the test only if SetUp() was successful.
- if (!HasFatalFailure()) {
+ // We will run the test only if SetUp() was successful and didn't call
+ // GTEST_SKIP().
+ if (!HasFatalFailure() && !IsSkipped()) {
impl->os_stack_trace_getter()->UponLeavingGTest();
internal::HandleExceptionsInMethodIfSupported(
this, &Test::TestBody, "the test body");
@@ -2483,32 +2517,36 @@ void Test::Run() {
this, &Test::TearDown, "TearDown()");
}
-// Returns true iff the current test has a fatal failure.
+// Returns true if and only if the current test has a fatal failure.
bool Test::HasFatalFailure() {
return internal::GetUnitTestImpl()->current_test_result()->HasFatalFailure();
}
-// Returns true iff the current test has a non-fatal failure.
+// Returns true if and only if the current test has a non-fatal failure.
bool Test::HasNonfatalFailure() {
return internal::GetUnitTestImpl()->current_test_result()->
HasNonfatalFailure();
}
+// Returns true if and only if the current test was skipped.
+bool Test::IsSkipped() {
+ return internal::GetUnitTestImpl()->current_test_result()->Skipped();
+}
+
// class TestInfo
// Constructs a TestInfo object. It assumes ownership of the test factory
// object.
-TestInfo::TestInfo(const std::string& a_test_case_name,
- const std::string& a_name,
- const char* a_type_param,
+TestInfo::TestInfo(const std::string& a_test_suite_name,
+ const std::string& a_name, const char* a_type_param,
const char* a_value_param,
internal::CodeLocation a_code_location,
internal::TypeId fixture_class_id,
internal::TestFactoryBase* factory)
- : test_case_name_(a_test_case_name),
+ : test_suite_name_(a_test_suite_name),
name_(a_name),
- type_param_(a_type_param ? new std::string(a_type_param) : NULL),
- value_param_(a_value_param ? new std::string(a_value_param) : NULL),
+ type_param_(a_type_param ? new std::string(a_type_param) : nullptr),
+ value_param_(a_value_param ? new std::string(a_value_param) : nullptr),
location_(a_code_location),
fixture_class_id_(fixture_class_id),
should_run_(false),
@@ -2527,7 +2565,7 @@ namespace internal {
//
// Arguments:
//
-// test_case_name: name of the test case
+// test_suite_name: name of the test suite
// 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.
@@ -2535,49 +2573,40 @@ namespace internal {
// or NULL if this is not a value-parameterized test.
// code_location: code location where the test is defined
// fixture_class_id: ID of the test fixture class
-// set_up_tc: pointer to the function that sets up the test case
-// tear_down_tc: pointer to the function that tears down the test case
+// set_up_tc: pointer to the function that sets up the test suite
+// tear_down_tc: pointer to the function that tears down the test suite
// factory: pointer to the factory that creates a test object.
// The newly created TestInfo instance will assume
// ownership of the factory object.
TestInfo* MakeAndRegisterTestInfo(
- const char* test_case_name,
- const char* name,
- const char* type_param,
- const char* value_param,
- CodeLocation code_location,
- TypeId fixture_class_id,
- SetUpTestCaseFunc set_up_tc,
- TearDownTestCaseFunc tear_down_tc,
- TestFactoryBase* factory) {
+ const char* test_suite_name, const char* name, const char* type_param,
+ const char* value_param, CodeLocation code_location,
+ TypeId fixture_class_id, SetUpTestSuiteFunc set_up_tc,
+ TearDownTestSuiteFunc tear_down_tc, TestFactoryBase* factory) {
TestInfo* const test_info =
- new TestInfo(test_case_name, name, type_param, value_param,
+ new TestInfo(test_suite_name, name, type_param, value_param,
code_location, fixture_class_id, factory);
GetUnitTestImpl()->AddTestInfo(set_up_tc, tear_down_tc, test_info);
return test_info;
}
-#if GTEST_HAS_PARAM_TEST
-void ReportInvalidTestCaseType(const char* test_case_name,
- CodeLocation code_location) {
+void ReportInvalidTestSuiteType(const char* test_suite_name,
+ CodeLocation code_location) {
Message errors;
errors
- << "Attempted redefinition of test case " << test_case_name << ".\n"
- << "All tests in the same test case must use the same test fixture\n"
- << "class. However, in test case " << test_case_name << ", you tried\n"
+ << "Attempted redefinition of test suite " << test_suite_name << ".\n"
+ << "All tests in the same test suite must use the same test fixture\n"
+ << "class. However, in test suite " << test_suite_name << ", you tried\n"
<< "to define a test using a fixture class different from the one\n"
<< "used earlier. This can happen if the two fixture classes are\n"
<< "from different namespaces and have the same name. You should\n"
<< "probably rename one of the classes to put the tests into different\n"
- << "test cases.";
+ << "test suites.";
- fprintf(stderr, "%s %s",
- FormatFileLocation(code_location.file.c_str(),
- code_location.line).c_str(),
- errors.GetString().c_str());
+ GTEST_LOG_(ERROR) << FormatFileLocation(code_location.file.c_str(),
+ code_location.line)
+ << " " << errors.GetString();
}
-#endif // GTEST_HAS_PARAM_TEST
-
} // namespace internal
namespace {
@@ -2585,7 +2614,7 @@ namespace {
// A predicate that checks the test name of a TestInfo against a known
// value.
//
-// This is used for implementation of the TestCase class only. We put
+// This is used for implementation of the TestSuite class only. We put
// it in the anonymous namespace to prevent polluting the outer
// namespace.
//
@@ -2598,7 +2627,7 @@ class TestNameIs {
explicit TestNameIs(const char* name)
: name_(name) {}
- // Returns true iff the test name of test_info matches name_.
+ // Returns true if and only if the test name of test_info matches name_.
bool operator()(const TestInfo * test_info) const {
return test_info && test_info->name() == name_;
}
@@ -2612,15 +2641,13 @@ class TestNameIs {
namespace internal {
// This method expands all parameterized tests registered with macros TEST_P
-// and INSTANTIATE_TEST_CASE_P into regular tests and registers those.
+// and INSTANTIATE_TEST_SUITE_P into regular tests and registers those.
// This will be done just once during the program runtime.
void UnitTestImpl::RegisterParameterizedTests() {
-#if GTEST_HAS_PARAM_TEST
if (!parameterized_tests_registered_) {
parameterized_test_registry_.RegisterTests();
parameterized_tests_registered_ = true;
}
-#endif
}
} // namespace internal
@@ -2648,19 +2675,23 @@ void TestInfo::Run() {
factory_, &internal::TestFactoryBase::CreateTest,
"the test fixture's constructor");
- // Runs the test only if the test object was created and its
- // constructor didn't generate a fatal failure.
- if ((test != NULL) && !Test::HasFatalFailure()) {
+ // Runs the test if the constructor didn't generate a fatal failure or invoke
+ // GTEST_SKIP().
+ // Note that the object will not be null
+ if (!Test::HasFatalFailure() && !Test::IsSkipped()) {
// This doesn't throw as all user code that can throw are wrapped into
// exception handling code.
test->Run();
}
- // Deletes the test object.
- impl->os_stack_trace_getter()->UponLeavingGTest();
- internal::HandleExceptionsInMethodIfSupported(
- test, &Test::DeleteSelf_, "the test fixture's destructor");
+ if (test != nullptr) {
+ // Deletes the test object.
+ impl->os_stack_trace_getter()->UponLeavingGTest();
+ internal::HandleExceptionsInMethodIfSupported(
+ test, &Test::DeleteSelf_, "the test fixture's destructor");
+ }
+ result_.set_start_timestamp(start);
result_.set_elapsed_time(internal::GetTimeInMillis() - start);
// Notifies the unit test event listener that a test has just finished.
@@ -2668,134 +2699,151 @@ void TestInfo::Run() {
// Tells UnitTest to stop associating assertion results to this
// test.
- impl->set_current_test_info(NULL);
+ impl->set_current_test_info(nullptr);
}
-// class TestCase
+// class TestSuite
-// Gets the number of successful tests in this test case.
-int TestCase::successful_test_count() const {
+// Gets the number of successful tests in this test suite.
+int TestSuite::successful_test_count() const {
return CountIf(test_info_list_, TestPassed);
}
-// Gets the number of failed tests in this test case.
-int TestCase::failed_test_count() const {
+// Gets the number of successful tests in this test suite.
+int TestSuite::skipped_test_count() const {
+ return CountIf(test_info_list_, TestSkipped);
+}
+
+// Gets the number of failed tests in this test suite.
+int TestSuite::failed_test_count() const {
return CountIf(test_info_list_, TestFailed);
}
// Gets the number of disabled tests that will be reported in the XML report.
-int TestCase::reportable_disabled_test_count() const {
+int TestSuite::reportable_disabled_test_count() const {
return CountIf(test_info_list_, TestReportableDisabled);
}
-// Gets the number of disabled tests in this test case.
-int TestCase::disabled_test_count() const {
+// Gets the number of disabled tests in this test suite.
+int TestSuite::disabled_test_count() const {
return CountIf(test_info_list_, TestDisabled);
}
// Gets the number of tests to be printed in the XML report.
-int TestCase::reportable_test_count() const {
+int TestSuite::reportable_test_count() const {
return CountIf(test_info_list_, TestReportable);
}
-// Get the number of tests in this test case that should run.
-int TestCase::test_to_run_count() const {
+// Get the number of tests in this test suite that should run.
+int TestSuite::test_to_run_count() const {
return CountIf(test_info_list_, ShouldRunTest);
}
// Gets the number of all tests.
-int TestCase::total_test_count() const {
+int TestSuite::total_test_count() const {
return static_cast<int>(test_info_list_.size());
}
-// Creates a TestCase with the given name.
+// Creates a TestSuite with the given name.
//
// Arguments:
//
-// name: name of the test case
-// a_type_param: the name of the test case's type parameter, or NULL if
-// this is not a typed or a type-parameterized test case.
-// set_up_tc: pointer to the function that sets up the test case
-// tear_down_tc: pointer to the function that tears down the test case
-TestCase::TestCase(const char* a_name, const char* a_type_param,
- Test::SetUpTestCaseFunc set_up_tc,
- Test::TearDownTestCaseFunc tear_down_tc)
+// name: name of the test suite
+// a_type_param: the name of the test suite's type parameter, or NULL if
+// this is not a typed or a type-parameterized test suite.
+// set_up_tc: pointer to the function that sets up the test suite
+// tear_down_tc: pointer to the function that tears down the test suite
+TestSuite::TestSuite(const char* a_name, const char* a_type_param,
+ internal::SetUpTestSuiteFunc set_up_tc,
+ internal::TearDownTestSuiteFunc tear_down_tc)
: name_(a_name),
- type_param_(a_type_param ? new std::string(a_type_param) : NULL),
+ type_param_(a_type_param ? new std::string(a_type_param) : nullptr),
set_up_tc_(set_up_tc),
tear_down_tc_(tear_down_tc),
should_run_(false),
- elapsed_time_(0) {
-}
+ start_timestamp_(0),
+ elapsed_time_(0) {}
-// Destructor of TestCase.
-TestCase::~TestCase() {
+// Destructor of TestSuite.
+TestSuite::~TestSuite() {
// Deletes every Test in the collection.
ForEach(test_info_list_, internal::Delete<TestInfo>);
}
// Returns the i-th test among all the tests. i can range from 0 to
// total_test_count() - 1. If i is not in that range, returns NULL.
-const TestInfo* TestCase::GetTestInfo(int i) const {
+const TestInfo* TestSuite::GetTestInfo(int i) const {
const int index = GetElementOr(test_indices_, i, -1);
- return index < 0 ? NULL : test_info_list_[index];
+ return index < 0 ? nullptr : test_info_list_[static_cast<size_t>(index)];
}
// Returns the i-th test among all the tests. i can range from 0 to
// total_test_count() - 1. If i is not in that range, returns NULL.
-TestInfo* TestCase::GetMutableTestInfo(int i) {
+TestInfo* TestSuite::GetMutableTestInfo(int i) {
const int index = GetElementOr(test_indices_, i, -1);
- return index < 0 ? NULL : test_info_list_[index];
+ return index < 0 ? nullptr : test_info_list_[static_cast<size_t>(index)];
}
-// Adds a test to this test case. Will delete the test upon
-// destruction of the TestCase object.
-void TestCase::AddTestInfo(TestInfo * test_info) {
+// Adds a test to this test suite. Will delete the test upon
+// destruction of the TestSuite object.
+void TestSuite::AddTestInfo(TestInfo* test_info) {
test_info_list_.push_back(test_info);
test_indices_.push_back(static_cast<int>(test_indices_.size()));
}
-// Runs every test in this TestCase.
-void TestCase::Run() {
+// Runs every test in this TestSuite.
+void TestSuite::Run() {
if (!should_run_) return;
internal::UnitTestImpl* const impl = internal::GetUnitTestImpl();
- impl->set_current_test_case(this);
+ impl->set_current_test_suite(this);
TestEventListener* repeater = UnitTest::GetInstance()->listeners().repeater();
+ // Call both legacy and the new API
+ repeater->OnTestSuiteStart(*this);
+// Legacy API is deprecated but still available
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI
repeater->OnTestCaseStart(*this);
+#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI
+
impl->os_stack_trace_getter()->UponLeavingGTest();
internal::HandleExceptionsInMethodIfSupported(
- this, &TestCase::RunSetUpTestCase, "SetUpTestCase()");
+ this, &TestSuite::RunSetUpTestSuite, "SetUpTestSuite()");
- const internal::TimeInMillis start = internal::GetTimeInMillis();
+ start_timestamp_ = internal::GetTimeInMillis();
for (int i = 0; i < total_test_count(); i++) {
GetMutableTestInfo(i)->Run();
}
- elapsed_time_ = internal::GetTimeInMillis() - start;
+ elapsed_time_ = internal::GetTimeInMillis() - start_timestamp_;
impl->os_stack_trace_getter()->UponLeavingGTest();
internal::HandleExceptionsInMethodIfSupported(
- this, &TestCase::RunTearDownTestCase, "TearDownTestCase()");
+ this, &TestSuite::RunTearDownTestSuite, "TearDownTestSuite()");
+ // Call both legacy and the new API
+ repeater->OnTestSuiteEnd(*this);
+// Legacy API is deprecated but still available
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI
repeater->OnTestCaseEnd(*this);
- impl->set_current_test_case(NULL);
+#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI
+
+ impl->set_current_test_suite(nullptr);
}
-// Clears the results of all tests in this test case.
-void TestCase::ClearResult() {
+// Clears the results of all tests in this test suite.
+void TestSuite::ClearResult() {
ad_hoc_test_result_.Clear();
ForEach(test_info_list_, TestInfo::ClearTestResult);
}
-// Shuffles the tests in this test case.
-void TestCase::ShuffleTests(internal::Random* random) {
+// Shuffles the tests in this test suite.
+void TestSuite::ShuffleTests(internal::Random* random) {
Shuffle(random, &test_indices_);
}
// Restores the test order to before the first shuffle.
-void TestCase::UnshuffleTests() {
+void TestSuite::UnshuffleTests() {
for (size_t i = 0; i < test_indices_.size(); i++) {
test_indices_[i] = static_cast<int>(i);
}
@@ -2818,9 +2866,9 @@ static std::string FormatTestCount(int test_count) {
return FormatCountableNoun(test_count, "test", "tests");
}
-// Formats the count of test cases.
-static std::string FormatTestCaseCount(int test_case_count) {
- return FormatCountableNoun(test_case_count, "test case", "test cases");
+// Formats the count of test suites.
+static std::string FormatTestSuiteCount(int test_suite_count) {
+ return FormatCountableNoun(test_suite_count, "test suite", "test suites");
}
// Converts a TestPartResult::Type enum to human-friendly string
@@ -2829,6 +2877,8 @@ static std::string FormatTestCaseCount(int test_case_count) {
// between the two when viewing the test result.
static const char * TestPartResultTypeToString(TestPartResult::Type type) {
switch (type) {
+ case TestPartResult::kSkip:
+ return "Skipped";
case TestPartResult::kSuccess:
return "Success";
@@ -2876,19 +2926,11 @@ static void PrintTestPartResult(const TestPartResult& test_part_result) {
}
// class PrettyUnitTestResultPrinter
-
-enum GTestColor {
- COLOR_DEFAULT,
- COLOR_RED,
- COLOR_GREEN,
- COLOR_YELLOW
-};
-
#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE && \
- !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT
+ !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT && !GTEST_OS_WINDOWS_MINGW
// Returns the character attribute for the given color.
-WORD GetColorAttribute(GTestColor color) {
+static WORD GetColorAttribute(GTestColor color) {
switch (color) {
case COLOR_RED: return FOREGROUND_RED;
case COLOR_GREEN: return FOREGROUND_GREEN;
@@ -2897,27 +2939,59 @@ WORD GetColorAttribute(GTestColor color) {
}
}
+static int GetBitOffset(WORD color_mask) {
+ if (color_mask == 0) return 0;
+
+ int bitOffset = 0;
+ while ((color_mask & 1) == 0) {
+ color_mask >>= 1;
+ ++bitOffset;
+ }
+ return bitOffset;
+}
+
+static WORD GetNewColor(GTestColor color, WORD old_color_attrs) {
+ // Let's reuse the BG
+ static const WORD background_mask = BACKGROUND_BLUE | BACKGROUND_GREEN |
+ BACKGROUND_RED | BACKGROUND_INTENSITY;
+ static const WORD foreground_mask = FOREGROUND_BLUE | FOREGROUND_GREEN |
+ FOREGROUND_RED | FOREGROUND_INTENSITY;
+ const WORD existing_bg = old_color_attrs & background_mask;
+
+ WORD new_color =
+ GetColorAttribute(color) | existing_bg | FOREGROUND_INTENSITY;
+ static const int bg_bitOffset = GetBitOffset(background_mask);
+ static const int fg_bitOffset = GetBitOffset(foreground_mask);
+
+ if (((new_color & background_mask) >> bg_bitOffset) ==
+ ((new_color & foreground_mask) >> fg_bitOffset)) {
+ new_color ^= FOREGROUND_INTENSITY; // invert intensity
+ }
+ return new_color;
+}
+
#else
// Returns the ANSI color code for the given color. COLOR_DEFAULT is
// an invalid input.
-const char* GetAnsiColorCode(GTestColor color) {
+static const char* GetAnsiColorCode(GTestColor color) {
switch (color) {
case COLOR_RED: return "1";
case COLOR_GREEN: return "2";
case COLOR_YELLOW: return "3";
- default: return NULL;
- };
+ default:
+ return nullptr;
+ }
}
#endif // GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE
-// Returns true iff Google Test should use colors in the output.
+// Returns true if and only if Google Test should use colors in the output.
bool ShouldUseColor(bool stdout_is_tty) {
const char* const gtest_color = GTEST_FLAG(color).c_str();
if (String::CaseInsensitiveCStringEquals(gtest_color, "auto")) {
-#if GTEST_OS_WINDOWS
+#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MINGW
// On Windows the TERM variable is usually not set, but the
// console there does support colors.
return stdout_is_tty;
@@ -2957,15 +3031,14 @@ void ColoredPrintf(GTestColor color, const char* fmt, ...) {
va_list args;
va_start(args, fmt);
-#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN || GTEST_OS_ZOS || \
- GTEST_OS_IOS || GTEST_OS_WINDOWS_PHONE || GTEST_OS_WINDOWS_RT
+#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_ZOS || GTEST_OS_IOS || \
+ GTEST_OS_WINDOWS_PHONE || GTEST_OS_WINDOWS_RT || defined(ESP_PLATFORM)
const bool use_color = AlwaysFalse();
#else
static const bool in_color_mode =
ShouldUseColor(posix::IsATTY(posix::FileNo(stdout)) != 0);
const bool use_color = in_color_mode && (color != COLOR_DEFAULT);
-#endif // GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN || GTEST_OS_ZOS
- // The '!= 0' comparison is necessary to satisfy MSVC 7.1.
+#endif // GTEST_OS_WINDOWS_MOBILE || GTEST_OS_ZOS
if (!use_color) {
vprintf(fmt, args);
@@ -2974,20 +3047,21 @@ void ColoredPrintf(GTestColor color, const char* fmt, ...) {
}
#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE && \
- !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT
+ !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT && !GTEST_OS_WINDOWS_MINGW
const HANDLE stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE);
// Gets the current text color.
CONSOLE_SCREEN_BUFFER_INFO buffer_info;
GetConsoleScreenBufferInfo(stdout_handle, &buffer_info);
const WORD old_color_attrs = buffer_info.wAttributes;
+ const WORD new_color = GetNewColor(color, old_color_attrs);
// We need to flush the stream buffers into the console before each
// SetConsoleTextAttribute call lest it affect the text that is already
// printed but has not yet reached the console.
fflush(stdout);
- SetConsoleTextAttribute(stdout_handle,
- GetColorAttribute(color) | FOREGROUND_INTENSITY);
+ SetConsoleTextAttribute(stdout_handle, new_color);
+
vprintf(fmt, args);
fflush(stdout);
@@ -3001,23 +3075,22 @@ void ColoredPrintf(GTestColor color, const char* fmt, ...) {
va_end(args);
}
-// Text printed in Google Test's text output and --gunit_list_tests
+// Text printed in Google Test's text output and --gtest_list_tests
// output to label the type parameter and value parameter for a test.
static const char kTypeParamLabel[] = "TypeParam";
static const char kValueParamLabel[] = "GetParam()";
-void PrintFullTestCommentIfPresent(const TestInfo& test_info) {
+static void PrintFullTestCommentIfPresent(const TestInfo& test_info) {
const char* const type_param = test_info.type_param();
const char* const value_param = test_info.value_param();
- if (type_param != NULL || value_param != NULL) {
+ if (type_param != nullptr || value_param != nullptr) {
printf(", where ");
- if (type_param != NULL) {
+ if (type_param != nullptr) {
printf("%s = %s", kTypeParamLabel, type_param);
- if (value_param != NULL)
- printf(" and ");
+ if (value_param != nullptr) printf(" and ");
}
- if (value_param != NULL) {
+ if (value_param != nullptr) {
printf("%s = %s", kValueParamLabel, value_param);
}
}
@@ -3029,27 +3102,39 @@ void PrintFullTestCommentIfPresent(const TestInfo& test_info) {
class PrettyUnitTestResultPrinter : public TestEventListener {
public:
PrettyUnitTestResultPrinter() {}
- static void PrintTestName(const char * test_case, const char * test) {
- printf("%s.%s", test_case, test);
+ static void PrintTestName(const char* test_suite, const char* test) {
+ printf("%s.%s", test_suite, test);
}
// The following methods override what's in the TestEventListener class.
- virtual void OnTestProgramStart(const UnitTest& /*unit_test*/) {}
- virtual void OnTestIterationStart(const UnitTest& unit_test, int iteration);
- virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test);
- virtual void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) {}
- virtual void OnTestCaseStart(const TestCase& test_case);
- virtual void OnTestStart(const TestInfo& test_info);
- virtual void OnTestPartResult(const TestPartResult& result);
- virtual void OnTestEnd(const TestInfo& test_info);
- virtual void OnTestCaseEnd(const TestCase& test_case);
- virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test);
- virtual void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) {}
- virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration);
- virtual void OnTestProgramEnd(const UnitTest& /*unit_test*/) {}
+ void OnTestProgramStart(const UnitTest& /*unit_test*/) override {}
+ void OnTestIterationStart(const UnitTest& unit_test, int iteration) override;
+ void OnEnvironmentsSetUpStart(const UnitTest& unit_test) override;
+ void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) override {}
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+ void OnTestCaseStart(const TestCase& test_case) override;
+#else
+ void OnTestSuiteStart(const TestSuite& test_suite) override;
+#endif // OnTestCaseStart
+
+ void OnTestStart(const TestInfo& test_info) override;
+
+ void OnTestPartResult(const TestPartResult& result) override;
+ void OnTestEnd(const TestInfo& test_info) override;
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+ void OnTestCaseEnd(const TestCase& test_case) override;
+#else
+ void OnTestSuiteEnd(const TestSuite& test_suite) override;
+#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+
+ void OnEnvironmentsTearDownStart(const UnitTest& unit_test) override;
+ void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) override {}
+ void OnTestIterationEnd(const UnitTest& unit_test, int iteration) override;
+ void OnTestProgramEnd(const UnitTest& /*unit_test*/) override {}
private:
static void PrintFailedTests(const UnitTest& unit_test);
+ static void PrintSkippedTests(const UnitTest& unit_test);
};
// Fired before each iteration of tests starts.
@@ -3084,7 +3169,7 @@ void PrettyUnitTestResultPrinter::OnTestIterationStart(
ColoredPrintf(COLOR_GREEN, "[==========] ");
printf("Running %s from %s.\n",
FormatTestCount(unit_test.test_to_run_count()).c_str(),
- FormatTestCaseCount(unit_test.test_case_to_run_count()).c_str());
+ FormatTestSuiteCount(unit_test.test_suite_to_run_count()).c_str());
fflush(stdout);
}
@@ -3095,22 +3180,38 @@ void PrettyUnitTestResultPrinter::OnEnvironmentsSetUpStart(
fflush(stdout);
}
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
void PrettyUnitTestResultPrinter::OnTestCaseStart(const TestCase& test_case) {
const std::string counts =
FormatCountableNoun(test_case.test_to_run_count(), "test", "tests");
ColoredPrintf(COLOR_GREEN, "[----------] ");
printf("%s from %s", counts.c_str(), test_case.name());
- if (test_case.type_param() == NULL) {
+ if (test_case.type_param() == nullptr) {
printf("\n");
} else {
printf(", where %s = %s\n", kTypeParamLabel, test_case.type_param());
}
fflush(stdout);
}
+#else
+void PrettyUnitTestResultPrinter::OnTestSuiteStart(
+ const TestSuite& test_suite) {
+ const std::string counts =
+ FormatCountableNoun(test_suite.test_to_run_count(), "test", "tests");
+ ColoredPrintf(COLOR_GREEN, "[----------] ");
+ printf("%s from %s", counts.c_str(), test_suite.name());
+ if (test_suite.type_param() == nullptr) {
+ printf("\n");
+ } else {
+ printf(", where %s = %s\n", kTypeParamLabel, test_suite.type_param());
+ }
+ fflush(stdout);
+}
+#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
void PrettyUnitTestResultPrinter::OnTestStart(const TestInfo& test_info) {
ColoredPrintf(COLOR_GREEN, "[ RUN ] ");
- PrintTestName(test_info.test_case_name(), test_info.name());
+ PrintTestName(test_info.test_suite_name(), test_info.name());
printf("\n");
fflush(stdout);
}
@@ -3118,22 +3219,29 @@ void PrettyUnitTestResultPrinter::OnTestStart(const TestInfo& test_info) {
// Called after an assertion failure.
void PrettyUnitTestResultPrinter::OnTestPartResult(
const TestPartResult& result) {
- // If the test part succeeded, we don't need to do anything.
- if (result.type() == TestPartResult::kSuccess)
- return;
-
- // Print failure message from the assertion (e.g. expected this and got that).
- PrintTestPartResult(result);
- fflush(stdout);
+ switch (result.type()) {
+ // If the test part succeeded, or was skipped,
+ // we don't need to do anything.
+ case TestPartResult::kSkip:
+ case TestPartResult::kSuccess:
+ return;
+ default:
+ // Print failure message from the assertion
+ // (e.g. expected this and got that).
+ PrintTestPartResult(result);
+ fflush(stdout);
+ }
}
void PrettyUnitTestResultPrinter::OnTestEnd(const TestInfo& test_info) {
if (test_info.result()->Passed()) {
ColoredPrintf(COLOR_GREEN, "[ OK ] ");
+ } else if (test_info.result()->Skipped()) {
+ ColoredPrintf(COLOR_GREEN, "[ SKIPPED ] ");
} else {
ColoredPrintf(COLOR_RED, "[ FAILED ] ");
}
- PrintTestName(test_info.test_case_name(), test_info.name());
+ PrintTestName(test_info.test_suite_name(), test_info.name());
if (test_info.result()->Failed())
PrintFullTestCommentIfPresent(test_info);
@@ -3146,17 +3254,29 @@ void PrettyUnitTestResultPrinter::OnTestEnd(const TestInfo& test_info) {
fflush(stdout);
}
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
void PrettyUnitTestResultPrinter::OnTestCaseEnd(const TestCase& test_case) {
if (!GTEST_FLAG(print_time)) return;
const std::string counts =
FormatCountableNoun(test_case.test_to_run_count(), "test", "tests");
ColoredPrintf(COLOR_GREEN, "[----------] ");
- printf("%s from %s (%s ms total)\n\n",
- counts.c_str(), test_case.name(),
+ printf("%s from %s (%s ms total)\n\n", counts.c_str(), test_case.name(),
internal::StreamableToString(test_case.elapsed_time()).c_str());
fflush(stdout);
}
+#else
+void PrettyUnitTestResultPrinter::OnTestSuiteEnd(const TestSuite& test_suite) {
+ if (!GTEST_FLAG(print_time)) return;
+
+ const std::string counts =
+ FormatCountableNoun(test_suite.test_to_run_count(), "test", "tests");
+ ColoredPrintf(COLOR_GREEN, "[----------] ");
+ printf("%s from %s (%s ms total)\n\n", counts.c_str(), test_suite.name(),
+ internal::StreamableToString(test_suite.elapsed_time()).c_str());
+ fflush(stdout);
+}
+#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
void PrettyUnitTestResultPrinter::OnEnvironmentsTearDownStart(
const UnitTest& /*unit_test*/) {
@@ -3172,30 +3292,54 @@ void PrettyUnitTestResultPrinter::PrintFailedTests(const UnitTest& unit_test) {
return;
}
- for (int i = 0; i < unit_test.total_test_case_count(); ++i) {
- const TestCase& test_case = *unit_test.GetTestCase(i);
- if (!test_case.should_run() || (test_case.failed_test_count() == 0)) {
+ for (int i = 0; i < unit_test.total_test_suite_count(); ++i) {
+ const TestSuite& test_suite = *unit_test.GetTestSuite(i);
+ if (!test_suite.should_run() || (test_suite.failed_test_count() == 0)) {
continue;
}
- for (int j = 0; j < test_case.total_test_count(); ++j) {
- const TestInfo& test_info = *test_case.GetTestInfo(j);
- if (!test_info.should_run() || test_info.result()->Passed()) {
+ for (int j = 0; j < test_suite.total_test_count(); ++j) {
+ const TestInfo& test_info = *test_suite.GetTestInfo(j);
+ if (!test_info.should_run() || !test_info.result()->Failed()) {
continue;
}
ColoredPrintf(COLOR_RED, "[ FAILED ] ");
- printf("%s.%s", test_case.name(), test_info.name());
+ printf("%s.%s", test_suite.name(), test_info.name());
PrintFullTestCommentIfPresent(test_info);
printf("\n");
}
}
}
+// Internal helper for printing the list of skipped tests.
+void PrettyUnitTestResultPrinter::PrintSkippedTests(const UnitTest& unit_test) {
+ const int skipped_test_count = unit_test.skipped_test_count();
+ if (skipped_test_count == 0) {
+ return;
+ }
+
+ for (int i = 0; i < unit_test.total_test_suite_count(); ++i) {
+ const TestSuite& test_suite = *unit_test.GetTestSuite(i);
+ if (!test_suite.should_run() || (test_suite.skipped_test_count() == 0)) {
+ continue;
+ }
+ for (int j = 0; j < test_suite.total_test_count(); ++j) {
+ const TestInfo& test_info = *test_suite.GetTestInfo(j);
+ if (!test_info.should_run() || !test_info.result()->Skipped()) {
+ continue;
+ }
+ ColoredPrintf(COLOR_GREEN, "[ SKIPPED ] ");
+ printf("%s.%s", test_suite.name(), test_info.name());
+ printf("\n");
+ }
+ }
+}
+
void PrettyUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test,
int /*iteration*/) {
ColoredPrintf(COLOR_GREEN, "[==========] ");
printf("%s from %s ran.",
FormatTestCount(unit_test.test_to_run_count()).c_str(),
- FormatTestCaseCount(unit_test.test_case_to_run_count()).c_str());
+ FormatTestSuiteCount(unit_test.test_suite_to_run_count()).c_str());
if (GTEST_FLAG(print_time)) {
printf(" (%s ms total)",
internal::StreamableToString(unit_test.elapsed_time()).c_str());
@@ -3204,6 +3348,13 @@ void PrettyUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test,
ColoredPrintf(COLOR_GREEN, "[ PASSED ] ");
printf("%s.\n", FormatTestCount(unit_test.successful_test_count()).c_str());
+ const int skipped_test_count = unit_test.skipped_test_count();
+ if (skipped_test_count > 0) {
+ ColoredPrintf(COLOR_GREEN, "[ SKIPPED ] ");
+ printf("%s, listed below:\n", FormatTestCount(skipped_test_count).c_str());
+ PrintSkippedTests(unit_test);
+ }
+
int num_failures = unit_test.failed_test_count();
if (!unit_test.Passed()) {
const int failed_test_count = unit_test.failed_test_count();
@@ -3236,7 +3387,7 @@ void PrettyUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test,
class TestEventRepeater : public TestEventListener {
public:
TestEventRepeater() : forwarding_enabled_(true) {}
- virtual ~TestEventRepeater();
+ ~TestEventRepeater() override;
void Append(TestEventListener *listener);
TestEventListener* Release(TestEventListener* listener);
@@ -3245,19 +3396,27 @@ class TestEventRepeater : public TestEventListener {
bool forwarding_enabled() const { return forwarding_enabled_; }
void set_forwarding_enabled(bool enable) { forwarding_enabled_ = enable; }
- virtual void OnTestProgramStart(const UnitTest& unit_test);
- virtual void OnTestIterationStart(const UnitTest& unit_test, int iteration);
- virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test);
- virtual void OnEnvironmentsSetUpEnd(const UnitTest& unit_test);
- virtual void OnTestCaseStart(const TestCase& test_case);
- virtual void OnTestStart(const TestInfo& test_info);
- virtual void OnTestPartResult(const TestPartResult& result);
- virtual void OnTestEnd(const TestInfo& test_info);
- virtual void OnTestCaseEnd(const TestCase& test_case);
- virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test);
- virtual void OnEnvironmentsTearDownEnd(const UnitTest& unit_test);
- virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration);
- virtual void OnTestProgramEnd(const UnitTest& unit_test);
+ void OnTestProgramStart(const UnitTest& unit_test) override;
+ void OnTestIterationStart(const UnitTest& unit_test, int iteration) override;
+ void OnEnvironmentsSetUpStart(const UnitTest& unit_test) override;
+ void OnEnvironmentsSetUpEnd(const UnitTest& unit_test) override;
+// Legacy API is deprecated but still available
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+ void OnTestCaseStart(const TestSuite& parameter) override;
+#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+ void OnTestSuiteStart(const TestSuite& parameter) override;
+ void OnTestStart(const TestInfo& test_info) override;
+ void OnTestPartResult(const TestPartResult& result) override;
+ void OnTestEnd(const TestInfo& test_info) override;
+// Legacy API is deprecated but still available
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+ void OnTestCaseEnd(const TestCase& parameter) override;
+#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+ void OnTestSuiteEnd(const TestSuite& parameter) override;
+ void OnEnvironmentsTearDownStart(const UnitTest& unit_test) override;
+ void OnEnvironmentsTearDownEnd(const UnitTest& unit_test) override;
+ void OnTestIterationEnd(const UnitTest& unit_test, int iteration) override;
+ void OnTestProgramEnd(const UnitTest& unit_test) override;
private:
// Controls whether events will be forwarded to listeners_. Set to false
@@ -3277,16 +3436,15 @@ void TestEventRepeater::Append(TestEventListener *listener) {
listeners_.push_back(listener);
}
-// TODO(vladl@google.com): Factor the search functionality into Vector::Find.
TestEventListener* TestEventRepeater::Release(TestEventListener *listener) {
for (size_t i = 0; i < listeners_.size(); ++i) {
if (listeners_[i] == listener) {
- listeners_.erase(listeners_.begin() + i);
+ listeners_.erase(listeners_.begin() + static_cast<int>(i));
return listener;
}
}
- return NULL;
+ return nullptr;
}
// Since most methods are very similar, use macros to reduce boilerplate.
@@ -3301,25 +3459,33 @@ void TestEventRepeater::Name(const Type& parameter) { \
}
// This defines a member that forwards the call to all listeners in reverse
// order.
-#define GTEST_REVERSE_REPEATER_METHOD_(Name, Type) \
-void TestEventRepeater::Name(const Type& parameter) { \
- if (forwarding_enabled_) { \
- for (int i = static_cast<int>(listeners_.size()) - 1; i >= 0; i--) { \
- listeners_[i]->Name(parameter); \
- } \
- } \
-}
+#define GTEST_REVERSE_REPEATER_METHOD_(Name, Type) \
+ void TestEventRepeater::Name(const Type& parameter) { \
+ if (forwarding_enabled_) { \
+ for (size_t i = listeners_.size(); i != 0; i--) { \
+ listeners_[i - 1]->Name(parameter); \
+ } \
+ } \
+ }
GTEST_REPEATER_METHOD_(OnTestProgramStart, UnitTest)
GTEST_REPEATER_METHOD_(OnEnvironmentsSetUpStart, UnitTest)
-GTEST_REPEATER_METHOD_(OnTestCaseStart, TestCase)
+// Legacy API is deprecated but still available
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+GTEST_REPEATER_METHOD_(OnTestCaseStart, TestSuite)
+#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+GTEST_REPEATER_METHOD_(OnTestSuiteStart, TestSuite)
GTEST_REPEATER_METHOD_(OnTestStart, TestInfo)
GTEST_REPEATER_METHOD_(OnTestPartResult, TestPartResult)
GTEST_REPEATER_METHOD_(OnEnvironmentsTearDownStart, UnitTest)
GTEST_REVERSE_REPEATER_METHOD_(OnEnvironmentsSetUpEnd, UnitTest)
GTEST_REVERSE_REPEATER_METHOD_(OnEnvironmentsTearDownEnd, UnitTest)
GTEST_REVERSE_REPEATER_METHOD_(OnTestEnd, TestInfo)
-GTEST_REVERSE_REPEATER_METHOD_(OnTestCaseEnd, TestCase)
+// Legacy API is deprecated but still available
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+GTEST_REVERSE_REPEATER_METHOD_(OnTestCaseEnd, TestSuite)
+#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+GTEST_REVERSE_REPEATER_METHOD_(OnTestSuiteEnd, TestSuite)
GTEST_REVERSE_REPEATER_METHOD_(OnTestProgramEnd, UnitTest)
#undef GTEST_REPEATER_METHOD_
@@ -3337,8 +3503,8 @@ void TestEventRepeater::OnTestIterationStart(const UnitTest& unit_test,
void TestEventRepeater::OnTestIterationEnd(const UnitTest& unit_test,
int iteration) {
if (forwarding_enabled_) {
- for (int i = static_cast<int>(listeners_.size()) - 1; i >= 0; i--) {
- listeners_[i]->OnTestIterationEnd(unit_test, iteration);
+ for (size_t i = listeners_.size(); i > 0; i--) {
+ listeners_[i - 1]->OnTestIterationEnd(unit_test, iteration);
}
}
}
@@ -3350,7 +3516,12 @@ class XmlUnitTestResultPrinter : public EmptyTestEventListener {
public:
explicit XmlUnitTestResultPrinter(const char* output_file);
- virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration);
+ void OnTestIterationEnd(const UnitTest& unit_test, int iteration) override;
+ void ListTestsMatchingFilter(const std::vector<TestSuite*>& test_suites);
+
+ // Prints an XML summary of all unit tests.
+ static void PrintXmlTestsList(std::ostream* stream,
+ const std::vector<TestSuite*>& test_suites);
private:
// Is c a whitespace character that is normalized to a space character
@@ -3395,12 +3566,12 @@ class XmlUnitTestResultPrinter : public EmptyTestEventListener {
// Streams an XML representation of a TestInfo object.
static void OutputXmlTestInfo(::std::ostream* stream,
- const char* test_case_name,
+ const char* test_suite_name,
const TestInfo& test_info);
- // Prints an XML representation of a TestCase object
- static void PrintXmlTestCase(::std::ostream* stream,
- const TestCase& test_case);
+ // Prints an XML representation of a TestSuite object
+ static void PrintXmlTestSuite(::std::ostream* stream,
+ const TestSuite& test_suite);
// Prints an XML summary of unit_test to output stream out.
static void PrintXmlUnitTest(::std::ostream* stream,
@@ -3412,6 +3583,11 @@ class XmlUnitTestResultPrinter : public EmptyTestEventListener {
// to delimit this attribute from prior attributes.
static std::string TestPropertiesAsXmlAttributes(const TestResult& result);
+ // Streams an XML representation of the test properties of a TestResult
+ // object.
+ static void OutputXmlTestProperties(std::ostream* stream,
+ const TestResult& result);
+
// The output file.
const std::string output_file_;
@@ -3421,46 +3597,30 @@ class XmlUnitTestResultPrinter : public EmptyTestEventListener {
// Creates a new XmlUnitTestResultPrinter.
XmlUnitTestResultPrinter::XmlUnitTestResultPrinter(const char* output_file)
: output_file_(output_file) {
- if (output_file_.c_str() == NULL || output_file_.empty()) {
- fprintf(stderr, "XML output file may not be null\n");
- fflush(stderr);
- exit(EXIT_FAILURE);
+ if (output_file_.empty()) {
+ GTEST_LOG_(FATAL) << "XML output file may not be null";
}
}
// Called after the unit test ends.
void XmlUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test,
int /*iteration*/) {
- FILE* xmlout = NULL;
- FilePath output_file(output_file_);
- FilePath output_dir(output_file.RemoveFileName());
-
- if (output_dir.CreateDirectoriesRecursively()) {
- xmlout = posix::FOpen(output_file_.c_str(), "w");
- }
- if (xmlout == NULL) {
- // TODO(wan): report the reason of the failure.
- //
- // We don't do it for now as:
- //
- // 1. There is no urgent need for it.
- // 2. It's a bit involved to make the errno variable thread-safe on
- // all three operating systems (Linux, Windows, and Mac OS).
- // 3. To interpret the meaning of errno in a thread-safe way,
- // we need the strerror_r() function, which is not available on
- // Windows.
- fprintf(stderr,
- "Unable to open file \"%s\"\n",
- output_file_.c_str());
- fflush(stderr);
- exit(EXIT_FAILURE);
- }
+ FILE* xmlout = OpenFileForWriting(output_file_);
std::stringstream stream;
PrintXmlUnitTest(&stream, unit_test);
fprintf(xmlout, "%s", StringStreamToString(&stream).c_str());
fclose(xmlout);
}
+void XmlUnitTestResultPrinter::ListTestsMatchingFilter(
+ const std::vector<TestSuite*>& test_suites) {
+ FILE* xmlout = OpenFileForWriting(output_file_);
+ std::stringstream stream;
+ PrintXmlTestsList(&stream, test_suites);
+ fprintf(xmlout, "%s", StringStreamToString(&stream).c_str());
+ fclose(xmlout);
+}
+
// Returns an XML-escaped copy of the input string str. If is_attribute
// is true, the text is meant to appear as an attribute value, and
// normalizable whitespace is preserved by replacing it with character
@@ -3471,8 +3631,6 @@ void XmlUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test,
// module will consist of ordinary English text.
// If this module is ever modified to produce version 1.1 XML output,
// most invalid characters can be retained using character references.
-// TODO(wan): It might be nice to have a minimally invasive, human-readable
-// escaping scheme for invalid characters, rather than dropping them.
std::string XmlUnitTestResultPrinter::EscapeXml(
const std::string& str, bool is_attribute) {
Message m;
@@ -3532,11 +3690,12 @@ std::string XmlUnitTestResultPrinter::RemoveInvalidXmlCharacters(
// The following routines generate an XML representation of a UnitTest
// object.
+// GOOGLETEST_CM0009 DO NOT DELETE
//
// This is how Google Test concepts map to the DTD:
//
// <testsuites name="AllTests"> <-- corresponds to a UnitTest object
-// <testsuite name="testcase-name"> <-- corresponds to a TestCase object
+// <testsuite name="testcase-name"> <-- corresponds to a TestSuite object
// <testcase name="test-name"> <-- corresponds to a TestInfo object
// <failure message="...">...</failure>
// <failure message="...">...</failure>
@@ -3560,12 +3719,11 @@ static bool PortableLocaltime(time_t seconds, struct tm* out) {
// MINGW <time.h> provides neither localtime_r nor localtime_s, but uses
// Windows' localtime(), which has a thread-local tm buffer.
struct tm* tm_ptr = localtime(&seconds); // NOLINT
- if (tm_ptr == NULL)
- return false;
+ if (tm_ptr == nullptr) return false;
*out = *tm_ptr;
return true;
#else
- return localtime_r(&seconds, out) != NULL;
+ return localtime_r(&seconds, out) != nullptr;
#endif
}
@@ -3591,7 +3749,7 @@ void XmlUnitTestResultPrinter::OutputXmlCDataSection(::std::ostream* stream,
*stream << "<![CDATA[";
for (;;) {
const char* const next_segment = strstr(segment, "]]>");
- if (next_segment != NULL) {
+ if (next_segment != nullptr) {
stream->write(
segment, static_cast<std::streamsize>(next_segment - segment));
*stream << "]]>]]&gt;<![CDATA[";
@@ -3610,7 +3768,7 @@ void XmlUnitTestResultPrinter::OutputXmlAttribute(
const std::string& name,
const std::string& value) {
const std::vector<std::string>& allowed_names =
- GetReservedAttributesForElement(element_name);
+ GetReservedOutputAttributesForElement(element_name);
GTEST_CHECK_(std::find(allowed_names.begin(), allowed_names.end(), name) !=
allowed_names.end())
@@ -3621,30 +3779,47 @@ void XmlUnitTestResultPrinter::OutputXmlAttribute(
}
// Prints an XML representation of a TestInfo object.
-// TODO(wan): There is also value in printing properties with the plain printer.
void XmlUnitTestResultPrinter::OutputXmlTestInfo(::std::ostream* stream,
- const char* test_case_name,
+ const char* test_suite_name,
const TestInfo& test_info) {
const TestResult& result = *test_info.result();
- const std::string kTestcase = "testcase";
+ const std::string kTestsuite = "testcase";
+
+ if (test_info.is_in_another_shard()) {
+ return;
+ }
*stream << " <testcase";
- OutputXmlAttribute(stream, kTestcase, "name", test_info.name());
+ OutputXmlAttribute(stream, kTestsuite, "name", test_info.name());
- if (test_info.value_param() != NULL) {
- OutputXmlAttribute(stream, kTestcase, "value_param",
+ if (test_info.value_param() != nullptr) {
+ OutputXmlAttribute(stream, kTestsuite, "value_param",
test_info.value_param());
}
- if (test_info.type_param() != NULL) {
- OutputXmlAttribute(stream, kTestcase, "type_param", test_info.type_param());
+ if (test_info.type_param() != nullptr) {
+ OutputXmlAttribute(stream, kTestsuite, "type_param",
+ test_info.type_param());
+ }
+ if (GTEST_FLAG(list_tests)) {
+ OutputXmlAttribute(stream, kTestsuite, "file", test_info.file());
+ OutputXmlAttribute(stream, kTestsuite, "line",
+ StreamableToString(test_info.line()));
+ *stream << " />\n";
+ return;
}
- OutputXmlAttribute(stream, kTestcase, "status",
+ OutputXmlAttribute(stream, kTestsuite, "status",
test_info.should_run() ? "run" : "notrun");
- OutputXmlAttribute(stream, kTestcase, "time",
+ OutputXmlAttribute(stream, kTestsuite, "result",
+ test_info.should_run()
+ ? (result.Skipped() ? "skipped" : "completed")
+ : "suppressed");
+ OutputXmlAttribute(stream, kTestsuite, "time",
FormatTimeInMillisAsSeconds(result.elapsed_time()));
- OutputXmlAttribute(stream, kTestcase, "classname", test_case_name);
- *stream << TestPropertiesAsXmlAttributes(result);
+ OutputXmlAttribute(
+ stream, kTestsuite, "timestamp",
+ FormatEpochTimeInMillisAsIso8601(result.start_timestamp()));
+ OutputXmlAttribute(stream, kTestsuite, "classname", test_suite_name);
int failures = 0;
for (int i = 0; i < result.total_part_count(); ++i) {
@@ -3653,46 +3828,56 @@ void XmlUnitTestResultPrinter::OutputXmlTestInfo(::std::ostream* stream,
if (++failures == 1) {
*stream << ">\n";
}
- const string location = internal::FormatCompilerIndependentFileLocation(
- part.file_name(), part.line_number());
- const string summary = location + "\n" + part.summary();
+ const std::string location =
+ internal::FormatCompilerIndependentFileLocation(part.file_name(),
+ part.line_number());
+ const std::string summary = location + "\n" + part.summary();
*stream << " <failure message=\""
<< EscapeXmlAttribute(summary.c_str())
<< "\" type=\"\">";
- const string detail = location + "\n" + part.message();
+ const std::string detail = location + "\n" + part.message();
OutputXmlCDataSection(stream, RemoveInvalidXmlCharacters(detail).c_str());
*stream << "</failure>\n";
}
}
- if (failures == 0)
+ if (failures == 0 && result.test_property_count() == 0) {
*stream << " />\n";
- else
+ } else {
+ if (failures == 0) {
+ *stream << ">\n";
+ }
+ OutputXmlTestProperties(stream, result);
*stream << " </testcase>\n";
+ }
}
-// Prints an XML representation of a TestCase object
-void XmlUnitTestResultPrinter::PrintXmlTestCase(std::ostream* stream,
- const TestCase& test_case) {
+// Prints an XML representation of a TestSuite object
+void XmlUnitTestResultPrinter::PrintXmlTestSuite(std::ostream* stream,
+ const TestSuite& test_suite) {
const std::string kTestsuite = "testsuite";
*stream << " <" << kTestsuite;
- OutputXmlAttribute(stream, kTestsuite, "name", test_case.name());
+ OutputXmlAttribute(stream, kTestsuite, "name", test_suite.name());
OutputXmlAttribute(stream, kTestsuite, "tests",
- StreamableToString(test_case.reportable_test_count()));
- OutputXmlAttribute(stream, kTestsuite, "failures",
- StreamableToString(test_case.failed_test_count()));
- OutputXmlAttribute(
- stream, kTestsuite, "disabled",
- StreamableToString(test_case.reportable_disabled_test_count()));
- OutputXmlAttribute(stream, kTestsuite, "errors", "0");
- OutputXmlAttribute(stream, kTestsuite, "time",
- FormatTimeInMillisAsSeconds(test_case.elapsed_time()));
- *stream << TestPropertiesAsXmlAttributes(test_case.ad_hoc_test_result())
- << ">\n";
-
- for (int i = 0; i < test_case.total_test_count(); ++i) {
- if (test_case.GetTestInfo(i)->is_reportable())
- OutputXmlTestInfo(stream, test_case.name(), *test_case.GetTestInfo(i));
+ StreamableToString(test_suite.reportable_test_count()));
+ if (!GTEST_FLAG(list_tests)) {
+ OutputXmlAttribute(stream, kTestsuite, "failures",
+ StreamableToString(test_suite.failed_test_count()));
+ OutputXmlAttribute(
+ stream, kTestsuite, "disabled",
+ StreamableToString(test_suite.reportable_disabled_test_count()));
+ OutputXmlAttribute(stream, kTestsuite, "errors", "0");
+ OutputXmlAttribute(stream, kTestsuite, "time",
+ FormatTimeInMillisAsSeconds(test_suite.elapsed_time()));
+ OutputXmlAttribute(
+ stream, kTestsuite, "timestamp",
+ FormatEpochTimeInMillisAsIso8601(test_suite.start_timestamp()));
+ *stream << TestPropertiesAsXmlAttributes(test_suite.ad_hoc_test_result());
+ }
+ *stream << ">\n";
+ for (int i = 0; i < test_suite.total_test_count(); ++i) {
+ if (test_suite.GetTestInfo(i)->is_reportable())
+ OutputXmlTestInfo(stream, test_suite.name(), *test_suite.GetTestInfo(i));
}
*stream << " </" << kTestsuite << ">\n";
}
@@ -3713,25 +3898,46 @@ void XmlUnitTestResultPrinter::PrintXmlUnitTest(std::ostream* stream,
stream, kTestsuites, "disabled",
StreamableToString(unit_test.reportable_disabled_test_count()));
OutputXmlAttribute(stream, kTestsuites, "errors", "0");
+ OutputXmlAttribute(stream, kTestsuites, "time",
+ FormatTimeInMillisAsSeconds(unit_test.elapsed_time()));
OutputXmlAttribute(
stream, kTestsuites, "timestamp",
FormatEpochTimeInMillisAsIso8601(unit_test.start_timestamp()));
- OutputXmlAttribute(stream, kTestsuites, "time",
- FormatTimeInMillisAsSeconds(unit_test.elapsed_time()));
if (GTEST_FLAG(shuffle)) {
OutputXmlAttribute(stream, kTestsuites, "random_seed",
StreamableToString(unit_test.random_seed()));
}
-
*stream << TestPropertiesAsXmlAttributes(unit_test.ad_hoc_test_result());
OutputXmlAttribute(stream, kTestsuites, "name", "AllTests");
*stream << ">\n";
- for (int i = 0; i < unit_test.total_test_case_count(); ++i) {
- if (unit_test.GetTestCase(i)->reportable_test_count() > 0)
- PrintXmlTestCase(stream, *unit_test.GetTestCase(i));
+ for (int i = 0; i < unit_test.total_test_suite_count(); ++i) {
+ if (unit_test.GetTestSuite(i)->reportable_test_count() > 0)
+ PrintXmlTestSuite(stream, *unit_test.GetTestSuite(i));
+ }
+ *stream << "</" << kTestsuites << ">\n";
+}
+
+void XmlUnitTestResultPrinter::PrintXmlTestsList(
+ std::ostream* stream, const std::vector<TestSuite*>& test_suites) {
+ const std::string kTestsuites = "testsuites";
+
+ *stream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
+ *stream << "<" << kTestsuites;
+
+ int total_tests = 0;
+ for (auto test_suite : test_suites) {
+ total_tests += test_suite->total_test_count();
+ }
+ OutputXmlAttribute(stream, kTestsuites, "tests",
+ StreamableToString(total_tests));
+ OutputXmlAttribute(stream, kTestsuites, "name", "AllTests");
+ *stream << ">\n";
+
+ for (auto test_suite : test_suites) {
+ PrintXmlTestSuite(stream, *test_suite);
}
*stream << "</" << kTestsuites << ">\n";
}
@@ -3749,8 +3955,403 @@ std::string XmlUnitTestResultPrinter::TestPropertiesAsXmlAttributes(
return attributes.GetString();
}
+void XmlUnitTestResultPrinter::OutputXmlTestProperties(
+ std::ostream* stream, const TestResult& result) {
+ const std::string kProperties = "properties";
+ const std::string kProperty = "property";
+
+ if (result.test_property_count() <= 0) {
+ return;
+ }
+
+ *stream << "<" << kProperties << ">\n";
+ for (int i = 0; i < result.test_property_count(); ++i) {
+ const TestProperty& property = result.GetTestProperty(i);
+ *stream << "<" << kProperty;
+ *stream << " name=\"" << EscapeXmlAttribute(property.key()) << "\"";
+ *stream << " value=\"" << EscapeXmlAttribute(property.value()) << "\"";
+ *stream << "/>\n";
+ }
+ *stream << "</" << kProperties << ">\n";
+}
+
// End XmlUnitTestResultPrinter
+// This class generates an JSON output file.
+class JsonUnitTestResultPrinter : public EmptyTestEventListener {
+ public:
+ explicit JsonUnitTestResultPrinter(const char* output_file);
+
+ void OnTestIterationEnd(const UnitTest& unit_test, int iteration) override;
+
+ // Prints an JSON summary of all unit tests.
+ static void PrintJsonTestList(::std::ostream* stream,
+ const std::vector<TestSuite*>& test_suites);
+
+ private:
+ // Returns an JSON-escaped copy of the input string str.
+ static std::string EscapeJson(const std::string& str);
+
+ //// Verifies that the given attribute belongs to the given element and
+ //// streams the attribute as JSON.
+ static void OutputJsonKey(std::ostream* stream,
+ const std::string& element_name,
+ const std::string& name,
+ const std::string& value,
+ const std::string& indent,
+ bool comma = true);
+ static void OutputJsonKey(std::ostream* stream,
+ const std::string& element_name,
+ const std::string& name,
+ int value,
+ const std::string& indent,
+ bool comma = true);
+
+ // Streams a JSON representation of a TestInfo object.
+ static void OutputJsonTestInfo(::std::ostream* stream,
+ const char* test_suite_name,
+ const TestInfo& test_info);
+
+ // Prints a JSON representation of a TestSuite object
+ static void PrintJsonTestSuite(::std::ostream* stream,
+ const TestSuite& test_suite);
+
+ // Prints a JSON summary of unit_test to output stream out.
+ static void PrintJsonUnitTest(::std::ostream* stream,
+ const UnitTest& unit_test);
+
+ // Produces a string representing the test properties in a result as
+ // a JSON dictionary.
+ static std::string TestPropertiesAsJson(const TestResult& result,
+ const std::string& indent);
+
+ // The output file.
+ const std::string output_file_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(JsonUnitTestResultPrinter);
+};
+
+// Creates a new JsonUnitTestResultPrinter.
+JsonUnitTestResultPrinter::JsonUnitTestResultPrinter(const char* output_file)
+ : output_file_(output_file) {
+ if (output_file_.empty()) {
+ GTEST_LOG_(FATAL) << "JSON output file may not be null";
+ }
+}
+
+void JsonUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test,
+ int /*iteration*/) {
+ FILE* jsonout = OpenFileForWriting(output_file_);
+ std::stringstream stream;
+ PrintJsonUnitTest(&stream, unit_test);
+ fprintf(jsonout, "%s", StringStreamToString(&stream).c_str());
+ fclose(jsonout);
+}
+
+// Returns an JSON-escaped copy of the input string str.
+std::string JsonUnitTestResultPrinter::EscapeJson(const std::string& str) {
+ Message m;
+
+ for (size_t i = 0; i < str.size(); ++i) {
+ const char ch = str[i];
+ switch (ch) {
+ case '\\':
+ case '"':
+ case '/':
+ m << '\\' << ch;
+ break;
+ case '\b':
+ m << "\\b";
+ break;
+ case '\t':
+ m << "\\t";
+ break;
+ case '\n':
+ m << "\\n";
+ break;
+ case '\f':
+ m << "\\f";
+ break;
+ case '\r':
+ m << "\\r";
+ break;
+ default:
+ if (ch < ' ') {
+ m << "\\u00" << String::FormatByte(static_cast<unsigned char>(ch));
+ } else {
+ m << ch;
+ }
+ break;
+ }
+ }
+
+ return m.GetString();
+}
+
+// The following routines generate an JSON representation of a UnitTest
+// object.
+
+// Formats the given time in milliseconds as seconds.
+static std::string FormatTimeInMillisAsDuration(TimeInMillis ms) {
+ ::std::stringstream ss;
+ ss << (static_cast<double>(ms) * 1e-3) << "s";
+ return ss.str();
+}
+
+// Converts the given epoch time in milliseconds to a date string in the
+// RFC3339 format, without the timezone information.
+static std::string FormatEpochTimeInMillisAsRFC3339(TimeInMillis ms) {
+ struct tm time_struct;
+ if (!PortableLocaltime(static_cast<time_t>(ms / 1000), &time_struct))
+ return "";
+ // YYYY-MM-DDThh:mm:ss
+ return StreamableToString(time_struct.tm_year + 1900) + "-" +
+ String::FormatIntWidth2(time_struct.tm_mon + 1) + "-" +
+ String::FormatIntWidth2(time_struct.tm_mday) + "T" +
+ String::FormatIntWidth2(time_struct.tm_hour) + ":" +
+ String::FormatIntWidth2(time_struct.tm_min) + ":" +
+ String::FormatIntWidth2(time_struct.tm_sec) + "Z";
+}
+
+static inline std::string Indent(size_t width) {
+ return std::string(width, ' ');
+}
+
+void JsonUnitTestResultPrinter::OutputJsonKey(
+ std::ostream* stream,
+ const std::string& element_name,
+ const std::string& name,
+ const std::string& value,
+ const std::string& indent,
+ bool comma) {
+ const std::vector<std::string>& allowed_names =
+ GetReservedOutputAttributesForElement(element_name);
+
+ GTEST_CHECK_(std::find(allowed_names.begin(), allowed_names.end(), name) !=
+ allowed_names.end())
+ << "Key \"" << name << "\" is not allowed for value \"" << element_name
+ << "\".";
+
+ *stream << indent << "\"" << name << "\": \"" << EscapeJson(value) << "\"";
+ if (comma)
+ *stream << ",\n";
+}
+
+void JsonUnitTestResultPrinter::OutputJsonKey(
+ std::ostream* stream,
+ const std::string& element_name,
+ const std::string& name,
+ int value,
+ const std::string& indent,
+ bool comma) {
+ const std::vector<std::string>& allowed_names =
+ GetReservedOutputAttributesForElement(element_name);
+
+ GTEST_CHECK_(std::find(allowed_names.begin(), allowed_names.end(), name) !=
+ allowed_names.end())
+ << "Key \"" << name << "\" is not allowed for value \"" << element_name
+ << "\".";
+
+ *stream << indent << "\"" << name << "\": " << StreamableToString(value);
+ if (comma)
+ *stream << ",\n";
+}
+
+// Prints a JSON representation of a TestInfo object.
+void JsonUnitTestResultPrinter::OutputJsonTestInfo(::std::ostream* stream,
+ const char* test_suite_name,
+ const TestInfo& test_info) {
+ const TestResult& result = *test_info.result();
+ const std::string kTestsuite = "testcase";
+ const std::string kIndent = Indent(10);
+
+ *stream << Indent(8) << "{\n";
+ OutputJsonKey(stream, kTestsuite, "name", test_info.name(), kIndent);
+
+ if (test_info.value_param() != nullptr) {
+ OutputJsonKey(stream, kTestsuite, "value_param", test_info.value_param(),
+ kIndent);
+ }
+ if (test_info.type_param() != nullptr) {
+ OutputJsonKey(stream, kTestsuite, "type_param", test_info.type_param(),
+ kIndent);
+ }
+ if (GTEST_FLAG(list_tests)) {
+ OutputJsonKey(stream, kTestsuite, "file", test_info.file(), kIndent);
+ OutputJsonKey(stream, kTestsuite, "line", test_info.line(), kIndent, false);
+ *stream << "\n" << Indent(8) << "}";
+ return;
+ }
+
+ OutputJsonKey(stream, kTestsuite, "status",
+ test_info.should_run() ? "RUN" : "NOTRUN", kIndent);
+ OutputJsonKey(stream, kTestsuite, "result",
+ test_info.should_run()
+ ? (result.Skipped() ? "SKIPPED" : "COMPLETED")
+ : "SUPPRESSED",
+ kIndent);
+ OutputJsonKey(stream, kTestsuite, "timestamp",
+ FormatEpochTimeInMillisAsRFC3339(result.start_timestamp()),
+ kIndent);
+ OutputJsonKey(stream, kTestsuite, "time",
+ FormatTimeInMillisAsDuration(result.elapsed_time()), kIndent);
+ OutputJsonKey(stream, kTestsuite, "classname", test_suite_name, kIndent,
+ false);
+ *stream << TestPropertiesAsJson(result, kIndent);
+
+ int failures = 0;
+ for (int i = 0; i < result.total_part_count(); ++i) {
+ const TestPartResult& part = result.GetTestPartResult(i);
+ if (part.failed()) {
+ *stream << ",\n";
+ if (++failures == 1) {
+ *stream << kIndent << "\"" << "failures" << "\": [\n";
+ }
+ const std::string location =
+ internal::FormatCompilerIndependentFileLocation(part.file_name(),
+ part.line_number());
+ const std::string message = EscapeJson(location + "\n" + part.message());
+ *stream << kIndent << " {\n"
+ << kIndent << " \"failure\": \"" << message << "\",\n"
+ << kIndent << " \"type\": \"\"\n"
+ << kIndent << " }";
+ }
+ }
+
+ if (failures > 0)
+ *stream << "\n" << kIndent << "]";
+ *stream << "\n" << Indent(8) << "}";
+}
+
+// Prints an JSON representation of a TestSuite object
+void JsonUnitTestResultPrinter::PrintJsonTestSuite(
+ std::ostream* stream, const TestSuite& test_suite) {
+ const std::string kTestsuite = "testsuite";
+ const std::string kIndent = Indent(6);
+
+ *stream << Indent(4) << "{\n";
+ OutputJsonKey(stream, kTestsuite, "name", test_suite.name(), kIndent);
+ OutputJsonKey(stream, kTestsuite, "tests", test_suite.reportable_test_count(),
+ kIndent);
+ if (!GTEST_FLAG(list_tests)) {
+ OutputJsonKey(stream, kTestsuite, "failures",
+ test_suite.failed_test_count(), kIndent);
+ OutputJsonKey(stream, kTestsuite, "disabled",
+ test_suite.reportable_disabled_test_count(), kIndent);
+ OutputJsonKey(stream, kTestsuite, "errors", 0, kIndent);
+ OutputJsonKey(
+ stream, kTestsuite, "timestamp",
+ FormatEpochTimeInMillisAsRFC3339(test_suite.start_timestamp()),
+ kIndent);
+ OutputJsonKey(stream, kTestsuite, "time",
+ FormatTimeInMillisAsDuration(test_suite.elapsed_time()),
+ kIndent, false);
+ *stream << TestPropertiesAsJson(test_suite.ad_hoc_test_result(), kIndent)
+ << ",\n";
+ }
+
+ *stream << kIndent << "\"" << kTestsuite << "\": [\n";
+
+ bool comma = false;
+ for (int i = 0; i < test_suite.total_test_count(); ++i) {
+ if (test_suite.GetTestInfo(i)->is_reportable()) {
+ if (comma) {
+ *stream << ",\n";
+ } else {
+ comma = true;
+ }
+ OutputJsonTestInfo(stream, test_suite.name(), *test_suite.GetTestInfo(i));
+ }
+ }
+ *stream << "\n" << kIndent << "]\n" << Indent(4) << "}";
+}
+
+// Prints a JSON summary of unit_test to output stream out.
+void JsonUnitTestResultPrinter::PrintJsonUnitTest(std::ostream* stream,
+ const UnitTest& unit_test) {
+ const std::string kTestsuites = "testsuites";
+ const std::string kIndent = Indent(2);
+ *stream << "{\n";
+
+ OutputJsonKey(stream, kTestsuites, "tests", unit_test.reportable_test_count(),
+ kIndent);
+ OutputJsonKey(stream, kTestsuites, "failures", unit_test.failed_test_count(),
+ kIndent);
+ OutputJsonKey(stream, kTestsuites, "disabled",
+ unit_test.reportable_disabled_test_count(), kIndent);
+ OutputJsonKey(stream, kTestsuites, "errors", 0, kIndent);
+ if (GTEST_FLAG(shuffle)) {
+ OutputJsonKey(stream, kTestsuites, "random_seed", unit_test.random_seed(),
+ kIndent);
+ }
+ OutputJsonKey(stream, kTestsuites, "timestamp",
+ FormatEpochTimeInMillisAsRFC3339(unit_test.start_timestamp()),
+ kIndent);
+ OutputJsonKey(stream, kTestsuites, "time",
+ FormatTimeInMillisAsDuration(unit_test.elapsed_time()), kIndent,
+ false);
+
+ *stream << TestPropertiesAsJson(unit_test.ad_hoc_test_result(), kIndent)
+ << ",\n";
+
+ OutputJsonKey(stream, kTestsuites, "name", "AllTests", kIndent);
+ *stream << kIndent << "\"" << kTestsuites << "\": [\n";
+
+ bool comma = false;
+ for (int i = 0; i < unit_test.total_test_suite_count(); ++i) {
+ if (unit_test.GetTestSuite(i)->reportable_test_count() > 0) {
+ if (comma) {
+ *stream << ",\n";
+ } else {
+ comma = true;
+ }
+ PrintJsonTestSuite(stream, *unit_test.GetTestSuite(i));
+ }
+ }
+
+ *stream << "\n" << kIndent << "]\n" << "}\n";
+}
+
+void JsonUnitTestResultPrinter::PrintJsonTestList(
+ std::ostream* stream, const std::vector<TestSuite*>& test_suites) {
+ const std::string kTestsuites = "testsuites";
+ const std::string kIndent = Indent(2);
+ *stream << "{\n";
+ int total_tests = 0;
+ for (auto test_suite : test_suites) {
+ total_tests += test_suite->total_test_count();
+ }
+ OutputJsonKey(stream, kTestsuites, "tests", total_tests, kIndent);
+
+ OutputJsonKey(stream, kTestsuites, "name", "AllTests", kIndent);
+ *stream << kIndent << "\"" << kTestsuites << "\": [\n";
+
+ for (size_t i = 0; i < test_suites.size(); ++i) {
+ if (i != 0) {
+ *stream << ",\n";
+ }
+ PrintJsonTestSuite(stream, *test_suites[i]);
+ }
+
+ *stream << "\n"
+ << kIndent << "]\n"
+ << "}\n";
+}
+// Produces a string representing the test properties in a result as
+// a JSON dictionary.
+std::string JsonUnitTestResultPrinter::TestPropertiesAsJson(
+ const TestResult& result, const std::string& indent) {
+ Message attributes;
+ for (int i = 0; i < result.test_property_count(); ++i) {
+ const TestProperty& property = result.GetTestProperty(i);
+ attributes << ",\n" << indent << "\"" << property.key() << "\": "
+ << "\"" << EscapeJson(property.value()) << "\"";
+ }
+ return attributes.GetString();
+}
+
+// End JsonUnitTestResultPrinter
+
#if GTEST_CAN_STREAM_RESULTS_
// Checks if str contains '=', '&', '%' or '\n' characters. If yes,
@@ -3758,8 +4359,8 @@ std::string XmlUnitTestResultPrinter::TestPropertiesAsXmlAttributes(
// example, replaces "=" with "%3D". This algorithm is O(strlen(str))
// in both time and space -- important as the input str may contain an
// arbitrarily long test failure message and stack trace.
-string StreamingListener::UrlEncode(const char* str) {
- string result;
+std::string StreamingListener::UrlEncode(const char* str) {
+ std::string result;
result.reserve(strlen(str) + 1);
for (char ch = *str; ch != '\0'; ch = *++str) {
switch (ch) {
@@ -3785,7 +4386,7 @@ void StreamingListener::SocketWriter::MakeConnection() {
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC; // To allow both IPv4 and IPv6 addresses.
hints.ai_socktype = SOCK_STREAM;
- addrinfo* servinfo = NULL;
+ addrinfo* servinfo = nullptr;
// Use the getaddrinfo() to get a linked list of IP addresses for
// the given host name.
@@ -3797,7 +4398,7 @@ void StreamingListener::SocketWriter::MakeConnection() {
}
// Loop through all the results and connect to the first we can.
- for (addrinfo* cur_addr = servinfo; sockfd_ == -1 && cur_addr != NULL;
+ for (addrinfo* cur_addr = servinfo; sockfd_ == -1 && cur_addr != nullptr;
cur_addr = cur_addr->ai_next) {
sockfd_ = socket(
cur_addr->ai_family, cur_addr->ai_socktype, cur_addr->ai_protocol);
@@ -3821,47 +4422,82 @@ void StreamingListener::SocketWriter::MakeConnection() {
// End of class Streaming Listener
#endif // GTEST_CAN_STREAM_RESULTS__
-// Class ScopedTrace
+// class OsStackTraceGetter
-// Pushes the given source file location and message onto a per-thread
-// trace stack maintained by Google Test.
-ScopedTrace::ScopedTrace(const char* file, int line, const Message& message)
- GTEST_LOCK_EXCLUDED_(&UnitTest::mutex_) {
- TraceInfo trace;
- trace.file = file;
- trace.line = line;
- trace.message = message.GetString();
+const char* const OsStackTraceGetterInterface::kElidedFramesMarker =
+ "... " GTEST_NAME_ " internal frames ...";
- UnitTest::GetInstance()->PushGTestTrace(trace);
-}
+std::string OsStackTraceGetter::CurrentStackTrace(int max_depth, int skip_count)
+ GTEST_LOCK_EXCLUDED_(mutex_) {
+#if GTEST_HAS_ABSL
+ std::string result;
-// Pops the info pushed by the c'tor.
-ScopedTrace::~ScopedTrace()
- GTEST_LOCK_EXCLUDED_(&UnitTest::mutex_) {
- UnitTest::GetInstance()->PopGTestTrace();
-}
+ if (max_depth <= 0) {
+ return result;
+ }
+ max_depth = std::min(max_depth, kMaxStackTraceDepth);
-// class OsStackTraceGetter
+ std::vector<void*> raw_stack(max_depth);
+ // Skips the frames requested by the caller, plus this function.
+ const int raw_stack_size =
+ absl::GetStackTrace(&raw_stack[0], max_depth, skip_count + 1);
-const char* const OsStackTraceGetterInterface::kElidedFramesMarker =
- "... " GTEST_NAME_ " internal frames ...";
+ void* caller_frame = nullptr;
+ {
+ MutexLock lock(&mutex_);
+ caller_frame = caller_frame_;
+ }
+
+ for (int i = 0; i < raw_stack_size; ++i) {
+ if (raw_stack[i] == caller_frame &&
+ !GTEST_FLAG(show_internal_stack_frames)) {
+ // Add a marker to the trace and stop adding frames.
+ absl::StrAppend(&result, kElidedFramesMarker, "\n");
+ break;
+ }
+
+ char tmp[1024];
+ const char* symbol = "(unknown)";
+ if (absl::Symbolize(raw_stack[i], tmp, sizeof(tmp))) {
+ symbol = tmp;
+ }
+
+ char line[1024];
+ snprintf(line, sizeof(line), " %p: %s\n", raw_stack[i], symbol);
+ result += line;
+ }
-string OsStackTraceGetter::CurrentStackTrace(int /*max_depth*/,
- int /*skip_count*/) {
+ return result;
+
+#else // !GTEST_HAS_ABSL
+ static_cast<void>(max_depth);
+ static_cast<void>(skip_count);
return "";
+#endif // GTEST_HAS_ABSL
}
-void OsStackTraceGetter::UponLeavingGTest() {}
+void OsStackTraceGetter::UponLeavingGTest() GTEST_LOCK_EXCLUDED_(mutex_) {
+#if GTEST_HAS_ABSL
+ void* caller_frame = nullptr;
+ if (absl::GetStackTrace(&caller_frame, 1, 3) <= 0) {
+ caller_frame = nullptr;
+ }
+
+ MutexLock lock(&mutex_);
+ caller_frame_ = caller_frame;
+#endif // GTEST_HAS_ABSL
+}
// A helper class that creates the premature-exit file in its
// constructor and deletes the file in its destructor.
class ScopedPrematureExitFile {
public:
explicit ScopedPrematureExitFile(const char* premature_exit_filepath)
- : premature_exit_filepath_(premature_exit_filepath) {
+ : premature_exit_filepath_(premature_exit_filepath ?
+ premature_exit_filepath : "") {
// If a path to the premature-exit file is specified...
- if (premature_exit_filepath != NULL && *premature_exit_filepath != '\0') {
+ if (!premature_exit_filepath_.empty()) {
// create the file with a single "0" character in it. I/O
// errors are ignored as there's nothing better we can do and we
// don't want to fail the test because of this.
@@ -3872,13 +4508,18 @@ class ScopedPrematureExitFile {
}
~ScopedPrematureExitFile() {
- if (premature_exit_filepath_ != NULL && *premature_exit_filepath_ != '\0') {
- remove(premature_exit_filepath_);
+ if (!premature_exit_filepath_.empty()) {
+ int retval = remove(premature_exit_filepath_.c_str());
+ if (retval) {
+ GTEST_LOG_(ERROR) << "Failed to remove premature exit filepath \""
+ << premature_exit_filepath_ << "\" with error "
+ << retval;
+ }
}
}
private:
- const char* const premature_exit_filepath_;
+ const std::string premature_exit_filepath_;
GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedPrematureExitFile);
};
@@ -3889,9 +4530,8 @@ class ScopedPrematureExitFile {
TestEventListeners::TestEventListeners()
: repeater_(new internal::TestEventRepeater()),
- default_result_printer_(NULL),
- default_xml_generator_(NULL) {
-}
+ default_result_printer_(nullptr),
+ default_xml_generator_(nullptr) {}
TestEventListeners::~TestEventListeners() { delete repeater_; }
@@ -3908,9 +4548,9 @@ void TestEventListeners::Append(TestEventListener* listener) {
// NULL if the listener is not found in the list.
TestEventListener* TestEventListeners::Release(TestEventListener* listener) {
if (listener == default_result_printer_)
- default_result_printer_ = NULL;
+ default_result_printer_ = nullptr;
else if (listener == default_xml_generator_)
- default_xml_generator_ = NULL;
+ default_xml_generator_ = nullptr;
return repeater_->Release(listener);
}
@@ -3929,8 +4569,7 @@ void TestEventListeners::SetDefaultResultPrinter(TestEventListener* listener) {
// list.
delete Release(default_result_printer_);
default_result_printer_ = listener;
- if (listener != NULL)
- Append(listener);
+ if (listener != nullptr) Append(listener);
}
}
@@ -3945,8 +4584,7 @@ void TestEventListeners::SetDefaultXmlGenerator(TestEventListener* listener) {
// list.
delete Release(default_xml_generator_);
default_xml_generator_ = listener;
- if (listener != NULL)
- Append(listener);
+ if (listener != nullptr) Append(listener);
}
}
@@ -3970,52 +4608,66 @@ void TestEventListeners::SuppressEventForwarding() {
// call this before main() starts, from which point on the return
// value will never change.
UnitTest* UnitTest::GetInstance() {
- // When compiled with MSVC 7.1 in optimized mode, destroying the
- // UnitTest object upon exiting the program messes up the exit code,
- // causing successful tests to appear failed. We have to use a
- // different implementation in this case to bypass the compiler bug.
- // This implementation makes the compiler happy, at the cost of
- // leaking the UnitTest object.
-
// CodeGear C++Builder insists on a public destructor for the
// default implementation. Use this implementation to keep good OO
// design with private destructor.
-#if (_MSC_VER == 1310 && !defined(_DEBUG)) || defined(__BORLANDC__)
+#if defined(__BORLANDC__)
static UnitTest* const instance = new UnitTest;
return instance;
#else
static UnitTest instance;
return &instance;
-#endif // (_MSC_VER == 1310 && !defined(_DEBUG)) || defined(__BORLANDC__)
+#endif // defined(__BORLANDC__)
}
-// Gets the number of successful test cases.
-int UnitTest::successful_test_case_count() const {
- return impl()->successful_test_case_count();
+// Gets the number of successful test suites.
+int UnitTest::successful_test_suite_count() const {
+ return impl()->successful_test_suite_count();
}
-// Gets the number of failed test cases.
-int UnitTest::failed_test_case_count() const {
- return impl()->failed_test_case_count();
+// Gets the number of failed test suites.
+int UnitTest::failed_test_suite_count() const {
+ return impl()->failed_test_suite_count();
}
-// Gets the number of all test cases.
-int UnitTest::total_test_case_count() const {
- return impl()->total_test_case_count();
+// Gets the number of all test suites.
+int UnitTest::total_test_suite_count() const {
+ return impl()->total_test_suite_count();
}
-// Gets the number of all test cases that contain at least one test
+// Gets the number of all test suites that contain at least one test
// that should run.
+int UnitTest::test_suite_to_run_count() const {
+ return impl()->test_suite_to_run_count();
+}
+
+// Legacy API is deprecated but still available
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+int UnitTest::successful_test_case_count() const {
+ return impl()->successful_test_suite_count();
+}
+int UnitTest::failed_test_case_count() const {
+ return impl()->failed_test_suite_count();
+}
+int UnitTest::total_test_case_count() const {
+ return impl()->total_test_suite_count();
+}
int UnitTest::test_case_to_run_count() const {
- return impl()->test_case_to_run_count();
+ return impl()->test_suite_to_run_count();
}
+#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
// Gets the number of successful tests.
int UnitTest::successful_test_count() const {
return impl()->successful_test_count();
}
+// Gets the number of skipped tests.
+int UnitTest::skipped_test_count() const {
+ return impl()->skipped_test_count();
+}
+
// Gets the number of failed tests.
int UnitTest::failed_test_count() const { return impl()->failed_test_count(); }
@@ -4051,29 +4703,37 @@ internal::TimeInMillis UnitTest::elapsed_time() const {
return impl()->elapsed_time();
}
-// Returns true iff the unit test passed (i.e. all test cases passed).
+// Returns true if and only if the unit test passed (i.e. all test suites
+// passed).
bool UnitTest::Passed() const { return impl()->Passed(); }
-// Returns true iff the unit test failed (i.e. some test case failed
-// or something outside of all tests failed).
+// Returns true if and only if the unit test failed (i.e. some test suite
+// failed or something outside of all tests failed).
bool UnitTest::Failed() const { return impl()->Failed(); }
-// 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.
+// Gets the i-th test suite among all the test suites. i can range from 0 to
+// total_test_suite_count() - 1. If i is not in that range, returns NULL.
+const TestSuite* UnitTest::GetTestSuite(int i) const {
+ return impl()->GetTestSuite(i);
+}
+
+// Legacy API is deprecated but still available
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
const TestCase* UnitTest::GetTestCase(int i) const {
return impl()->GetTestCase(i);
}
+#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
// Returns the TestResult containing information on test failures and
-// properties logged outside of individual test cases.
+// properties logged outside of individual test suites.
const TestResult& UnitTest::ad_hoc_test_result() const {
return *impl()->ad_hoc_test_result();
}
-// 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.
-TestCase* UnitTest::GetMutableTestCase(int i) {
- return impl()->GetMutableTestCase(i);
+// Gets the i-th test suite among all the test suites. i can range from 0 to
+// total_test_suite_count() - 1. If i is not in that range, returns NULL.
+TestSuite* UnitTest::GetMutableTestSuite(int i) {
+ return impl()->GetMutableSuiteCase(i);
}
// Returns the list of event listeners that can be used to track events
@@ -4093,8 +4753,8 @@ TestEventListeners& UnitTest::listeners() {
// We don't protect this under mutex_, as we only support calling it
// from the main thread.
Environment* UnitTest::AddEnvironment(Environment* env) {
- if (env == NULL) {
- return NULL;
+ if (env == nullptr) {
+ return nullptr;
}
impl_->environments().push_back(env);
@@ -4118,25 +4778,24 @@ void UnitTest::AddTestPartResult(
if (impl_->gtest_trace_stack().size() > 0) {
msg << "\n" << GTEST_NAME_ << " trace:";
- for (int i = static_cast<int>(impl_->gtest_trace_stack().size());
- i > 0; --i) {
+ for (size_t i = impl_->gtest_trace_stack().size(); i > 0; --i) {
const internal::TraceInfo& trace = impl_->gtest_trace_stack()[i - 1];
msg << "\n" << internal::FormatFileLocation(trace.file, trace.line)
<< " " << trace.message;
}
}
- if (os_stack_trace.c_str() != NULL && !os_stack_trace.empty()) {
+ if (os_stack_trace.c_str() != nullptr && !os_stack_trace.empty()) {
msg << internal::kStackTraceMarker << os_stack_trace;
}
- const TestPartResult result =
- TestPartResult(result_type, file_name, line_number,
- msg.GetString().c_str());
+ const TestPartResult result = TestPartResult(
+ result_type, file_name, line_number, msg.GetString().c_str());
impl_->GetTestPartResultReporterForCurrentThread()->
ReportTestPartResult(result);
- if (result_type != TestPartResult::kSuccess) {
+ if (result_type != TestPartResult::kSuccess &&
+ result_type != TestPartResult::kSkip) {
// gtest_break_on_failure takes precedence over
// gtest_throw_on_failure. This allows a user to set the latter
// in the code (perhaps in order to use Google Test assertions
@@ -4148,12 +4807,16 @@ void UnitTest::AddTestPartResult(
// when a failure happens and both the --gtest_break_on_failure and
// the --gtest_catch_exceptions flags are specified.
DebugBreak();
+#elif (!defined(__native_client__)) && \
+ ((defined(__clang__) || defined(__GNUC__)) && \
+ (defined(__x86_64__) || defined(__i386__)))
+ // with clang/gcc we can achieve the same effect on x86 by invoking int3
+ asm("int3");
#else
- // Dereference NULL through a volatile pointer to prevent the compiler
+ // Dereference nullptr through a volatile pointer to prevent the compiler
// from removing. We use this rather than abort() or __builtin_trap() for
- // portability: Symbian doesn't implement abort() well, and some debuggers
- // don't correctly trap abort().
- *static_cast<volatile int*>(NULL) = 1;
+ // portability: some debuggers don't correctly trap abort().
+ *static_cast<volatile int*>(nullptr) = 1;
#endif // GTEST_OS_WINDOWS
} else if (GTEST_FLAG(throw_on_failure)) {
#if GTEST_HAS_EXCEPTIONS
@@ -4168,8 +4831,8 @@ void UnitTest::AddTestPartResult(
}
// 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
+// inside a test, to current TestSuite's ad_hoc_test_result_ when invoked
+// from SetUpTestSuite or TearDownTestSuite, 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 UnitTest::RecordProperty(const std::string& key,
@@ -4208,14 +4871,15 @@ int UnitTest::Run() {
// that understands the premature-exit-file protocol to report the
// test as having failed.
const internal::ScopedPrematureExitFile premature_exit_file(
- in_death_test_child_process ?
- NULL : internal::posix::GetEnv("TEST_PREMATURE_EXIT_FILE"));
+ in_death_test_child_process
+ ? nullptr
+ : internal::posix::GetEnv("TEST_PREMATURE_EXIT_FILE"));
// Captures the value of GTEST_FLAG(catch_exceptions). This value will be
// used for the duration of the program.
impl()->set_catch_exceptions(GTEST_FLAG(catch_exceptions));
-#if GTEST_HAS_SEH
+#if GTEST_OS_WINDOWS
// Either the user wants Google Test to catch exceptions thrown by the
// tests or this is executing in the context of death test child
// process. In either case the user does not want to see pop-up dialogs
@@ -4234,25 +4898,29 @@ int UnitTest::Run() {
_set_error_mode(_OUT_TO_STDERR);
# endif
-# if _MSC_VER >= 1400 && !GTEST_OS_WINDOWS_MOBILE
+# if defined(_MSC_VER) && !GTEST_OS_WINDOWS_MOBILE
// In the debug version, Visual Studio pops up a separate dialog
// offering a choice to debug the aborted program. We need to suppress
// this dialog or it will pop up for every EXPECT/ASSERT_DEATH statement
// executed. Google Test will notify the user of any unexpected
// failure via stderr.
- //
- // VC++ doesn't define _set_abort_behavior() prior to the version 8.0.
- // Users of prior VC versions shall suffer the agony and pain of
- // clicking through the countless debug dialogs.
- // TODO(vladl@google.com): find a way to suppress the abort dialog() in the
- // debug mode when compiled with VC 7.1 or lower.
if (!GTEST_FLAG(break_on_failure))
_set_abort_behavior(
0x0, // Clear the following flags:
_WRITE_ABORT_MSG | _CALL_REPORTFAULT); // pop-up window, core dump.
# endif
+
+ // In debug mode, the Windows CRT can crash with an assertion over invalid
+ // input (e.g. passing an invalid file descriptor). The default handling
+ // for these assertions is to pop up a dialog and wait for user input.
+ // Instead ask the CRT to dump such assertions to stderr non-interactively.
+ if (!IsDebuggerPresent()) {
+ (void)_CrtSetReportMode(_CRT_ASSERT,
+ _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
+ (void)_CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
+ }
}
-#endif // GTEST_HAS_SEH
+#endif // GTEST_OS_WINDOWS
return internal::HandleExceptionsInMethodIfSupported(
impl(),
@@ -4266,13 +4934,22 @@ const char* UnitTest::original_working_dir() const {
return impl_->original_working_dir_.c_str();
}
-// Returns the TestCase object for the test that's currently running,
+// Returns the TestSuite object for the test that's currently running,
// or NULL if no test is running.
+const TestSuite* UnitTest::current_test_suite() const
+ GTEST_LOCK_EXCLUDED_(mutex_) {
+ internal::MutexLock lock(&mutex_);
+ return impl_->current_test_suite();
+}
+
+// Legacy API is still available but deprecated
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
const TestCase* UnitTest::current_test_case() const
GTEST_LOCK_EXCLUDED_(mutex_) {
internal::MutexLock lock(&mutex_);
- return impl_->current_test_case();
+ return impl_->current_test_suite();
}
+#endif
// Returns the TestInfo object for the test that's currently running,
// or NULL if no test is running.
@@ -4285,15 +4962,12 @@ const TestInfo* UnitTest::current_test_info() const
// Returns the random seed used at the start of the current test run.
int UnitTest::random_seed() const { return impl_->random_seed(); }
-#if GTEST_HAS_PARAM_TEST
-// Returns ParameterizedTestCaseRegistry object used to keep track of
+// Returns ParameterizedTestSuiteRegistry object used to keep track of
// value-parameterized tests and instantiate and register them.
-internal::ParameterizedTestCaseRegistry&
- UnitTest::parameterized_test_registry()
- GTEST_LOCK_EXCLUDED_(mutex_) {
+internal::ParameterizedTestSuiteRegistry&
+UnitTest::parameterized_test_registry() GTEST_LOCK_EXCLUDED_(mutex_) {
return impl_->parameterized_test_registry();
}
-#endif // GTEST_HAS_PARAM_TEST
// Creates an empty UnitTest.
UnitTest::UnitTest() {
@@ -4325,25 +4999,22 @@ namespace internal {
UnitTestImpl::UnitTestImpl(UnitTest* parent)
: parent_(parent),
GTEST_DISABLE_MSC_WARNINGS_PUSH_(4355 /* using this in initializer */)
- default_global_test_part_result_reporter_(this),
+ default_global_test_part_result_reporter_(this),
default_per_thread_test_part_result_reporter_(this),
- GTEST_DISABLE_MSC_WARNINGS_POP_()
- global_test_part_result_repoter_(
+ GTEST_DISABLE_MSC_WARNINGS_POP_() global_test_part_result_repoter_(
&default_global_test_part_result_reporter_),
per_thread_test_part_result_reporter_(
&default_per_thread_test_part_result_reporter_),
-#if GTEST_HAS_PARAM_TEST
parameterized_test_registry_(),
parameterized_tests_registered_(false),
-#endif // GTEST_HAS_PARAM_TEST
- last_death_test_case_(-1),
- current_test_case_(NULL),
- current_test_info_(NULL),
+ last_death_test_suite_(-1),
+ current_test_suite_(nullptr),
+ current_test_info_(nullptr),
ad_hoc_test_result_(),
- os_stack_trace_getter_(NULL),
+ os_stack_trace_getter_(nullptr),
post_flag_parse_init_performed_(false),
random_seed_(0), // Will be overridden by the flag before first use.
- random_(0), // Will be reseeded before first use.
+ random_(0), // Will be reseeded before first use.
start_timestamp_(0),
elapsed_time_(0),
#if GTEST_HAS_DEATH_TEST
@@ -4355,8 +5026,8 @@ UnitTestImpl::UnitTestImpl(UnitTest* parent)
}
UnitTestImpl::~UnitTestImpl() {
- // Deletes every TestCase.
- ForEach(test_cases_, internal::Delete<TestCase>);
+ // Deletes every TestSuite.
+ ForEach(test_suites_, internal::Delete<TestSuite>);
// Deletes every Environment.
ForEach(environments_, internal::Delete<Environment>);
@@ -4365,20 +5036,20 @@ UnitTestImpl::~UnitTestImpl() {
}
// Adds a TestProperty to the current TestResult object when invoked in a
-// context of a test, to current test case's ad_hoc_test_result when invoke
-// from SetUpTestCase/TearDownTestCase, or to the global property set
+// context of a test, to current test suite's ad_hoc_test_result when invoke
+// from SetUpTestSuite/TearDownTestSuite, or to the global property set
// otherwise. If the result already contains a property with the same key,
// the value will be updated.
void UnitTestImpl::RecordProperty(const TestProperty& test_property) {
std::string xml_element;
TestResult* test_result; // TestResult appropriate for property recording.
- if (current_test_info_ != NULL) {
+ if (current_test_info_ != nullptr) {
xml_element = "testcase";
test_result = &(current_test_info_->result_);
- } else if (current_test_case_ != NULL) {
+ } else if (current_test_suite_ != nullptr) {
xml_element = "testsuite";
- test_result = &(current_test_case_->ad_hoc_test_result_);
+ test_result = &(current_test_suite_->ad_hoc_test_result_);
} else {
xml_element = "testsuites";
test_result = &ad_hoc_test_result_;
@@ -4390,7 +5061,7 @@ void UnitTestImpl::RecordProperty(const TestProperty& test_property) {
// Disables event forwarding if the control is currently in a death test
// subprocess. Must not be called before InitGoogleTest.
void UnitTestImpl::SuppressTestEventsIfInSubprocess() {
- if (internal_run_death_test_flag_.get() != NULL)
+ if (internal_run_death_test_flag_.get() != nullptr)
listeners()->SuppressEventForwarding();
}
#endif // GTEST_HAS_DEATH_TEST
@@ -4402,10 +5073,12 @@ void UnitTestImpl::ConfigureXmlOutput() {
if (output_format == "xml") {
listeners()->SetDefaultXmlGenerator(new XmlUnitTestResultPrinter(
UnitTestOptions::GetAbsolutePathToOutputFile().c_str()));
+ } else if (output_format == "json") {
+ listeners()->SetDefaultXmlGenerator(new JsonUnitTestResultPrinter(
+ UnitTestOptions::GetAbsolutePathToOutputFile().c_str()));
} else if (output_format != "") {
- printf("WARNING: unrecognized output format \"%s\" ignored.\n",
- output_format.c_str());
- fflush(stdout);
+ GTEST_LOG_(WARNING) << "WARNING: unrecognized output format \""
+ << output_format << "\" ignored.";
}
}
@@ -4420,9 +5093,8 @@ void UnitTestImpl::ConfigureStreamingOutput() {
listeners()->Append(new StreamingListener(target.substr(0, pos),
target.substr(pos+1)));
} else {
- printf("WARNING: unrecognized streaming target \"%s\" ignored.\n",
- target.c_str());
- fflush(stdout);
+ GTEST_LOG_(WARNING) << "unrecognized streaming target \"" << target
+ << "\" ignored.";
}
}
}
@@ -4461,77 +5133,83 @@ void UnitTestImpl::PostFlagParsingInit() {
// Configures listeners for streaming test results to the specified server.
ConfigureStreamingOutput();
#endif // GTEST_CAN_STREAM_RESULTS_
+
+#if GTEST_HAS_ABSL
+ if (GTEST_FLAG(install_failure_signal_handler)) {
+ absl::FailureSignalHandlerOptions options;
+ absl::InstallFailureSignalHandler(options);
+ }
+#endif // GTEST_HAS_ABSL
}
}
-// A predicate that checks the name of a TestCase against a known
+// A predicate that checks the name of a TestSuite against a known
// value.
//
// This is used for implementation of the UnitTest class only. We put
// it in the anonymous namespace to prevent polluting the outer
// namespace.
//
-// TestCaseNameIs is copyable.
-class TestCaseNameIs {
+// TestSuiteNameIs is copyable.
+class TestSuiteNameIs {
public:
// Constructor.
- explicit TestCaseNameIs(const std::string& name)
- : name_(name) {}
+ explicit TestSuiteNameIs(const std::string& name) : name_(name) {}
- // Returns true iff the name of test_case matches name_.
- bool operator()(const TestCase* test_case) const {
- return test_case != NULL && strcmp(test_case->name(), name_.c_str()) == 0;
+ // Returns true if and only if the name of test_suite matches name_.
+ bool operator()(const TestSuite* test_suite) const {
+ return test_suite != nullptr &&
+ strcmp(test_suite->name(), name_.c_str()) == 0;
}
private:
std::string name_;
};
-// Finds and returns a TestCase with the given name. If one doesn't
+// Finds and returns a TestSuite with the given name. If one doesn't
// exist, creates one and returns it. It's the CALLER'S
// RESPONSIBILITY to ensure that this function is only called WHEN THE
// TESTS ARE NOT SHUFFLED.
//
// Arguments:
//
-// test_case_name: name of the test case
-// type_param: the name of the test case's type parameter, or NULL if
-// this is not a typed or a type-parameterized test case.
-// set_up_tc: pointer to the function that sets up the test case
-// tear_down_tc: pointer to the function that tears down the test case
-TestCase* UnitTestImpl::GetTestCase(const char* test_case_name,
- const char* type_param,
- Test::SetUpTestCaseFunc set_up_tc,
- Test::TearDownTestCaseFunc tear_down_tc) {
- // Can we find a TestCase with the given name?
- const std::vector<TestCase*>::const_iterator test_case =
- std::find_if(test_cases_.begin(), test_cases_.end(),
- TestCaseNameIs(test_case_name));
-
- if (test_case != test_cases_.end())
- return *test_case;
+// test_suite_name: name of the test suite
+// type_param: the name of the test suite's type parameter, or NULL if
+// this is not a typed or a type-parameterized test suite.
+// set_up_tc: pointer to the function that sets up the test suite
+// tear_down_tc: pointer to the function that tears down the test suite
+TestSuite* UnitTestImpl::GetTestSuite(
+ const char* test_suite_name, const char* type_param,
+ internal::SetUpTestSuiteFunc set_up_tc,
+ internal::TearDownTestSuiteFunc tear_down_tc) {
+ // Can we find a TestSuite with the given name?
+ const auto test_suite =
+ std::find_if(test_suites_.rbegin(), test_suites_.rend(),
+ TestSuiteNameIs(test_suite_name));
+
+ if (test_suite != test_suites_.rend()) return *test_suite;
// No. Let's create one.
- TestCase* const new_test_case =
- new TestCase(test_case_name, type_param, set_up_tc, tear_down_tc);
-
- // Is this a death test case?
- if (internal::UnitTestOptions::MatchesFilter(test_case_name,
- kDeathTestCaseFilter)) {
- // Yes. Inserts the test case after the last death test case
- // defined so far. This only works when the test cases haven't
+ auto* const new_test_suite =
+ new TestSuite(test_suite_name, type_param, set_up_tc, tear_down_tc);
+
+ // Is this a death test suite?
+ if (internal::UnitTestOptions::MatchesFilter(test_suite_name,
+ kDeathTestSuiteFilter)) {
+ // Yes. Inserts the test suite after the last death test suite
+ // defined so far. This only works when the test suites haven't
// been shuffled. Otherwise we may end up running a death test
// after a non-death test.
- ++last_death_test_case_;
- test_cases_.insert(test_cases_.begin() + last_death_test_case_,
- new_test_case);
+ ++last_death_test_suite_;
+ test_suites_.insert(test_suites_.begin() + last_death_test_suite_,
+ new_test_suite);
} else {
// No. Appends to the end of the list.
- test_cases_.push_back(new_test_case);
+ test_suites_.push_back(new_test_suite);
}
- test_case_indices_.push_back(static_cast<int>(test_case_indices_.size()));
- return new_test_case;
+ test_suite_indices_.push_back(static_cast<int>(test_suite_indices_.size()));
+ return new_test_suite;
}
// Helpers for setting up / tearing down the given environment. They
@@ -4549,13 +5227,9 @@ static void TearDownEnvironment(Environment* env) { env->TearDown(); }
// All other functions called from RunAllTests() may safely assume that
// parameterized tests are ready to be counted and run.
bool UnitTestImpl::RunAllTests() {
- // Makes sure InitGoogleTest() was called.
- if (!GTestIsInitialized()) {
- printf("%s",
- "\nThis test program did NOT call ::testing::InitGoogleTest "
- "before calling RUN_ALL_TESTS(). Please fix it.\n");
- return false;
- }
+ // True if and only if Google Test is initialized before RUN_ALL_TESTS() is
+ // called.
+ const bool gtest_is_initialized_before_run_all_tests = GTestIsInitialized();
// Do not run any test if the --help flag was specified.
if (g_help_flag)
@@ -4570,12 +5244,13 @@ bool UnitTestImpl::RunAllTests() {
// protocol.
internal::WriteToShardStatusFileIfNeeded();
- // True iff we are in a subprocess for running a thread-safe-style
+ // True if and only if we are in a subprocess for running a thread-safe-style
// death test.
bool in_subprocess_for_death_test = false;
#if GTEST_HAS_DEATH_TEST
- in_subprocess_for_death_test = (internal_run_death_test_flag_.get() != NULL);
+ in_subprocess_for_death_test =
+ (internal_run_death_test_flag_.get() != nullptr);
# if defined(GTEST_EXTRA_DEATH_TEST_CHILD_SETUP_)
if (in_subprocess_for_death_test) {
GTEST_EXTRA_DEATH_TEST_CHILD_SETUP_();
@@ -4602,7 +5277,7 @@ bool UnitTestImpl::RunAllTests() {
random_seed_ = GTEST_FLAG(shuffle) ?
GetRandomSeedFromFlag(GTEST_FLAG(random_seed)) : 0;
- // True iff at least one test has failed.
+ // True if and only if at least one test has failed.
bool failed = false;
TestEventListener* repeater = listeners()->repeater();
@@ -4614,17 +5289,17 @@ bool UnitTestImpl::RunAllTests() {
// when we are inside the subprocess of a death test.
const int repeat = in_subprocess_for_death_test ? 1 : GTEST_FLAG(repeat);
// Repeats forever if the repeat count is negative.
- const bool forever = repeat < 0;
- for (int i = 0; forever || i != repeat; i++) {
+ const bool gtest_repeat_forever = repeat < 0;
+ for (int i = 0; gtest_repeat_forever || i != repeat; i++) {
// We want to preserve failures generated by ad-hoc test
// assertions executed before RUN_ALL_TESTS().
ClearNonAdHocTestResult();
const TimeInMillis start = GetTimeInMillis();
- // Shuffles test cases and tests if requested.
+ // Shuffles test suites and tests if requested.
if (has_tests_to_run && GTEST_FLAG(shuffle)) {
- random()->Reseed(random_seed_);
+ random()->Reseed(static_cast<UInt32>(random_seed_));
// This should be done before calling OnTestIterationStart(),
// such that a test event listener can see the actual test order
// in the event.
@@ -4634,19 +5309,33 @@ bool UnitTestImpl::RunAllTests() {
// Tells the unit test event listeners that the tests are about to start.
repeater->OnTestIterationStart(*parent_, i);
- // Runs each test case if there is at least one test to run.
+ // Runs each test suite if there is at least one test to run.
if (has_tests_to_run) {
// Sets up all environments beforehand.
repeater->OnEnvironmentsSetUpStart(*parent_);
ForEach(environments_, SetUpEnvironment);
repeater->OnEnvironmentsSetUpEnd(*parent_);
- // Runs the tests only if there was no fatal failure during global
- // set-up.
- if (!Test::HasFatalFailure()) {
- for (int test_index = 0; test_index < total_test_case_count();
+ // Runs the tests only if there was no fatal failure or skip triggered
+ // during global set-up.
+ if (Test::IsSkipped()) {
+ // Emit diagnostics when global set-up calls skip, as it will not be
+ // emitted by default.
+ TestResult& test_result =
+ *internal::GetUnitTestImpl()->current_test_result();
+ for (int j = 0; j < test_result.total_part_count(); ++j) {
+ const TestPartResult& test_part_result =
+ test_result.GetTestPartResult(j);
+ if (test_part_result.type() == TestPartResult::kSkip) {
+ const std::string& result = test_part_result.message();
+ printf("%s\n", result.c_str());
+ }
+ }
+ fflush(stdout);
+ } else if (!Test::HasFatalFailure()) {
+ for (int test_index = 0; test_index < total_test_suite_count();
test_index++) {
- GetMutableTestCase(test_index)->Run();
+ GetMutableSuiteCase(test_index)->Run();
}
}
@@ -4683,6 +5372,20 @@ bool UnitTestImpl::RunAllTests() {
repeater->OnTestProgramEnd(*parent_);
+ if (!gtest_is_initialized_before_run_all_tests) {
+ ColoredPrintf(
+ COLOR_RED,
+ "\nIMPORTANT NOTICE - DO NOT IGNORE:\n"
+ "This test program did NOT call " GTEST_INIT_GOOGLE_TEST_NAME_
+ "() before calling RUN_ALL_TESTS(). This is INVALID. Soon " GTEST_NAME_
+ " will start to enforce the valid usage. "
+ "Please fix it ASAP, or IT WILL START TO FAIL.\n"); // NOLINT
+#if GTEST_FOR_GOOGLE_
+ ColoredPrintf(COLOR_RED,
+ "For more details, see http://wiki/Main/ValidGUnitMain.\n");
+#endif // GTEST_FOR_GOOGLE_
+ }
+
return !failed;
}
@@ -4692,9 +5395,9 @@ bool UnitTestImpl::RunAllTests() {
// be created, prints an error and exits.
void WriteToShardStatusFileIfNeeded() {
const char* const test_shard_file = posix::GetEnv(kTestShardStatusFile);
- if (test_shard_file != NULL) {
+ if (test_shard_file != nullptr) {
FILE* const file = posix::FOpen(test_shard_file, "w");
- if (file == NULL) {
+ if (file == nullptr) {
ColoredPrintf(COLOR_RED,
"Could not write to the test shard status file \"%s\" "
"specified by the %s environment variable.\n",
@@ -4729,7 +5432,7 @@ bool ShouldShard(const char* total_shards_env,
<< "Invalid environment variables: you have "
<< kTestShardIndex << " = " << shard_index
<< ", but have left " << kTestTotalShards << " unset.\n";
- ColoredPrintf(COLOR_RED, msg.GetString().c_str());
+ ColoredPrintf(COLOR_RED, "%s", msg.GetString().c_str());
fflush(stdout);
exit(EXIT_FAILURE);
} else if (total_shards != -1 && shard_index == -1) {
@@ -4737,7 +5440,7 @@ bool ShouldShard(const char* total_shards_env,
<< "Invalid environment variables: you have "
<< kTestTotalShards << " = " << total_shards
<< ", but have left " << kTestShardIndex << " unset.\n";
- ColoredPrintf(COLOR_RED, msg.GetString().c_str());
+ ColoredPrintf(COLOR_RED, "%s", msg.GetString().c_str());
fflush(stdout);
exit(EXIT_FAILURE);
} else if (shard_index < 0 || shard_index >= total_shards) {
@@ -4746,7 +5449,7 @@ bool ShouldShard(const char* total_shards_env,
<< kTestShardIndex << " < " << kTestTotalShards
<< ", but you have " << kTestShardIndex << "=" << shard_index
<< ", " << kTestTotalShards << "=" << total_shards << ".\n";
- ColoredPrintf(COLOR_RED, msg.GetString().c_str());
+ ColoredPrintf(COLOR_RED, "%s", msg.GetString().c_str());
fflush(stdout);
exit(EXIT_FAILURE);
}
@@ -4759,7 +5462,7 @@ bool ShouldShard(const char* total_shards_env,
// and aborts.
Int32 Int32FromEnvOrDie(const char* var, Int32 default_val) {
const char* str_val = posix::GetEnv(var);
- if (str_val == NULL) {
+ if (str_val == nullptr) {
return default_val;
}
@@ -4772,8 +5475,8 @@ Int32 Int32FromEnvOrDie(const char* var, Int32 default_val) {
}
// Given the total number of shards, the shard index, and the test id,
-// returns true iff the test should be run on this shard. The test id is
-// some arbitrary but unique non-negative integer assigned to each test
+// returns true if and only if the test should be run on this shard. The test id
+// is some arbitrary but unique non-negative integer assigned to each test
// method. Assumes that 0 <= shard_index < total_shards.
bool ShouldRunTestOnShard(int total_shards, int shard_index, int test_id) {
return (test_id % total_shards) == shard_index;
@@ -4781,11 +5484,11 @@ bool ShouldRunTestOnShard(int total_shards, int shard_index, int test_id) {
// Compares the name of each test with the user-specified filter to
// decide whether the test should be run, then records the result in
-// each TestCase and TestInfo object.
+// each TestSuite and TestInfo object.
// If shard_tests == true, further filters tests based on sharding
// variables in the environment - see
-// http://code.google.com/p/googletest/wiki/GoogleTestAdvancedGuide.
-// Returns the number of tests that should run.
+// https://github.com/google/googletest/blob/master/googletest/docs/advanced.md
+// . Returns the number of tests that should run.
int UnitTestImpl::FilterTests(ReactionToSharding shard_tests) {
const Int32 total_shards = shard_tests == HONOR_SHARDING_PROTOCOL ?
Int32FromEnvOrDie(kTestTotalShards, -1) : -1;
@@ -4798,42 +5501,40 @@ int UnitTestImpl::FilterTests(ReactionToSharding shard_tests) {
// this shard.
int num_runnable_tests = 0;
int num_selected_tests = 0;
- for (size_t i = 0; i < test_cases_.size(); i++) {
- TestCase* const test_case = test_cases_[i];
- const std::string &test_case_name = test_case->name();
- test_case->set_should_run(false);
+ for (auto* test_suite : test_suites_) {
+ const std::string& test_suite_name = test_suite->name();
+ test_suite->set_should_run(false);
- for (size_t j = 0; j < test_case->test_info_list().size(); j++) {
- TestInfo* const test_info = test_case->test_info_list()[j];
+ for (size_t j = 0; j < test_suite->test_info_list().size(); j++) {
+ TestInfo* const test_info = test_suite->test_info_list()[j];
const std::string test_name(test_info->name());
- // A test is disabled if test case name or test name matches
+ // A test is disabled if test suite name or test name matches
// kDisableTestFilter.
- const bool is_disabled =
- internal::UnitTestOptions::MatchesFilter(test_case_name,
- kDisableTestFilter) ||
- internal::UnitTestOptions::MatchesFilter(test_name,
- kDisableTestFilter);
+ const bool is_disabled = internal::UnitTestOptions::MatchesFilter(
+ test_suite_name, kDisableTestFilter) ||
+ internal::UnitTestOptions::MatchesFilter(
+ test_name, kDisableTestFilter);
test_info->is_disabled_ = is_disabled;
- const bool matches_filter =
- internal::UnitTestOptions::FilterMatchesTest(test_case_name,
- test_name);
+ const bool matches_filter = internal::UnitTestOptions::FilterMatchesTest(
+ test_suite_name, test_name);
test_info->matches_filter_ = matches_filter;
const bool is_runnable =
(GTEST_FLAG(also_run_disabled_tests) || !is_disabled) &&
matches_filter;
- const bool is_selected = is_runnable &&
- (shard_tests == IGNORE_SHARDING_PROTOCOL ||
- ShouldRunTestOnShard(total_shards, shard_index,
- num_runnable_tests));
+ const bool is_in_another_shard =
+ shard_tests != IGNORE_SHARDING_PROTOCOL &&
+ !ShouldRunTestOnShard(total_shards, shard_index, num_runnable_tests);
+ test_info->is_in_another_shard_ = is_in_another_shard;
+ const bool is_selected = is_runnable && !is_in_another_shard;
num_runnable_tests += is_runnable;
num_selected_tests += is_selected;
test_info->should_run_ = is_selected;
- test_case->set_should_run(test_case->should_run() || is_selected);
+ test_suite->set_should_run(test_suite->should_run() || is_selected);
}
}
return num_selected_tests;
@@ -4844,7 +5545,7 @@ int UnitTestImpl::FilterTests(ReactionToSharding shard_tests) {
// max_length characters, only prints the first max_length characters
// and "...".
static void PrintOnOneLine(const char* str, int max_length) {
- if (str != NULL) {
+ if (str != nullptr) {
for (int i = 0; *str != '\0'; ++str) {
if (i >= max_length) {
printf("...");
@@ -4866,27 +5567,25 @@ void UnitTestImpl::ListTestsMatchingFilter() {
// Print at most this many characters for each type/value parameter.
const int kMaxParamLength = 250;
- for (size_t i = 0; i < test_cases_.size(); i++) {
- const TestCase* const test_case = test_cases_[i];
- bool printed_test_case_name = false;
+ for (auto* test_suite : test_suites_) {
+ bool printed_test_suite_name = false;
- for (size_t j = 0; j < test_case->test_info_list().size(); j++) {
- const TestInfo* const test_info =
- test_case->test_info_list()[j];
+ for (size_t j = 0; j < test_suite->test_info_list().size(); j++) {
+ const TestInfo* const test_info = test_suite->test_info_list()[j];
if (test_info->matches_filter_) {
- if (!printed_test_case_name) {
- printed_test_case_name = true;
- printf("%s.", test_case->name());
- if (test_case->type_param() != NULL) {
+ if (!printed_test_suite_name) {
+ printed_test_suite_name = true;
+ printf("%s.", test_suite->name());
+ if (test_suite->type_param() != nullptr) {
printf(" # %s = ", kTypeParamLabel);
// We print the type parameter on a single line to make
// the output easy to parse by a program.
- PrintOnOneLine(test_case->type_param(), kMaxParamLength);
+ PrintOnOneLine(test_suite->type_param(), kMaxParamLength);
}
printf("\n");
}
printf(" %s", test_info->name());
- if (test_info->value_param() != NULL) {
+ if (test_info->value_param() != nullptr) {
printf(" # %s = ", kValueParamLabel);
// We print the value parameter on a single line to make the
// output easy to parse by a program.
@@ -4897,6 +5596,23 @@ void UnitTestImpl::ListTestsMatchingFilter() {
}
}
fflush(stdout);
+ const std::string& output_format = UnitTestOptions::GetOutputFormat();
+ if (output_format == "xml" || output_format == "json") {
+ FILE* fileout = OpenFileForWriting(
+ UnitTestOptions::GetAbsolutePathToOutputFile().c_str());
+ std::stringstream stream;
+ if (output_format == "xml") {
+ XmlUnitTestResultPrinter(
+ UnitTestOptions::GetAbsolutePathToOutputFile().c_str())
+ .PrintXmlTestsList(&stream, test_suites_);
+ } else if (output_format == "json") {
+ JsonUnitTestResultPrinter(
+ UnitTestOptions::GetAbsolutePathToOutputFile().c_str())
+ .PrintJsonTestList(&stream, test_suites_);
+ }
+ fprintf(fileout, "%s", StringStreamToString(&stream).c_str());
+ fclose(fileout);
+ }
}
// Sets the OS stack trace getter.
@@ -4916,7 +5632,7 @@ void UnitTestImpl::set_os_stack_trace_getter(
// otherwise, creates an OsStackTraceGetter, makes it the current
// getter, and returns it.
OsStackTraceGetterInterface* UnitTestImpl::os_stack_trace_getter() {
- if (os_stack_trace_getter_ == NULL) {
+ if (os_stack_trace_getter_ == nullptr) {
#ifdef GTEST_OS_STACK_TRACE_GETTER_
os_stack_trace_getter_ = new GTEST_OS_STACK_TRACE_GETTER_;
#else
@@ -4927,36 +5643,40 @@ OsStackTraceGetterInterface* UnitTestImpl::os_stack_trace_getter() {
return os_stack_trace_getter_;
}
-// Returns the TestResult for the test that's currently running, or
-// the TestResult for the ad hoc test if no test is running.
+// Returns the most specific TestResult currently running.
TestResult* UnitTestImpl::current_test_result() {
- return current_test_info_ ?
- &(current_test_info_->result_) : &ad_hoc_test_result_;
+ if (current_test_info_ != nullptr) {
+ return &current_test_info_->result_;
+ }
+ if (current_test_suite_ != nullptr) {
+ return &current_test_suite_->ad_hoc_test_result_;
+ }
+ return &ad_hoc_test_result_;
}
-// Shuffles all test cases, and the tests within each test case,
+// Shuffles all test suites, and the tests within each test suite,
// making sure that death tests are still run first.
void UnitTestImpl::ShuffleTests() {
- // Shuffles the death test cases.
- ShuffleRange(random(), 0, last_death_test_case_ + 1, &test_case_indices_);
+ // Shuffles the death test suites.
+ ShuffleRange(random(), 0, last_death_test_suite_ + 1, &test_suite_indices_);
- // Shuffles the non-death test cases.
- ShuffleRange(random(), last_death_test_case_ + 1,
- static_cast<int>(test_cases_.size()), &test_case_indices_);
+ // Shuffles the non-death test suites.
+ ShuffleRange(random(), last_death_test_suite_ + 1,
+ static_cast<int>(test_suites_.size()), &test_suite_indices_);
- // Shuffles the tests inside each test case.
- for (size_t i = 0; i < test_cases_.size(); i++) {
- test_cases_[i]->ShuffleTests(random());
+ // Shuffles the tests inside each test suite.
+ for (auto& test_suite : test_suites_) {
+ test_suite->ShuffleTests(random());
}
}
-// Restores the test cases and tests to their order before the first shuffle.
+// Restores the test suites and tests to their order before the first shuffle.
void UnitTestImpl::UnshuffleTests() {
- for (size_t i = 0; i < test_cases_.size(); i++) {
- // Unshuffles the tests in each test case.
- test_cases_[i]->UnshuffleTests();
- // Resets the index of each test case.
- test_case_indices_[i] = static_cast<int>(i);
+ for (size_t i = 0; i < test_suites_.size(); i++) {
+ // Unshuffles the tests in each test suite.
+ test_suites_[i]->UnshuffleTests();
+ // Resets the index of each test suite.
+ test_suite_indices_[i] = static_cast<int>(i);
}
}
@@ -5012,16 +5732,15 @@ bool SkipPrefix(const char* prefix, const char** pstr) {
// part can be omitted.
//
// Returns the value of the flag, or NULL if the parsing failed.
-const char* ParseFlagValue(const char* str,
- const char* flag,
- bool def_optional) {
+static const char* ParseFlagValue(const char* str, const char* flag,
+ bool def_optional) {
// str and flag must not be NULL.
- if (str == NULL || flag == NULL) return NULL;
+ if (str == nullptr || flag == nullptr) return nullptr;
// The flag must start with "--" followed by GTEST_FLAG_PREFIX_.
const std::string flag_str = std::string("--") + GTEST_FLAG_PREFIX_ + flag;
const size_t flag_len = flag_str.length();
- if (strncmp(str, flag_str.c_str(), flag_len) != 0) return NULL;
+ if (strncmp(str, flag_str.c_str(), flag_len) != 0) return nullptr;
// Skips the flag name.
const char* flag_end = str + flag_len;
@@ -5034,7 +5753,7 @@ const char* ParseFlagValue(const char* str,
// If def_optional is true and there are more characters after the
// flag name, or if def_optional is false, there must be a '=' after
// the flag name.
- if (flag_end[0] != '=') return NULL;
+ if (flag_end[0] != '=') return nullptr;
// Returns the string after "=".
return flag_end + 1;
@@ -5050,12 +5769,12 @@ const char* ParseFlagValue(const char* str,
//
// On success, stores the value of the flag in *value, and returns
// true. On failure, returns false without changing *value.
-bool ParseBoolFlag(const char* str, const char* flag, bool* value) {
+static bool ParseBoolFlag(const char* str, const char* flag, bool* value) {
// Gets the value of the flag as a string.
const char* const value_str = ParseFlagValue(str, flag, true);
// Aborts if the parsing failed.
- if (value_str == NULL) return false;
+ if (value_str == nullptr) return false;
// Converts the string value to a bool.
*value = !(*value_str == '0' || *value_str == 'f' || *value_str == 'F');
@@ -5072,7 +5791,7 @@ bool ParseInt32Flag(const char* str, const char* flag, Int32* value) {
const char* const value_str = ParseFlagValue(str, flag, false);
// Aborts if the parsing failed.
- if (value_str == NULL) return false;
+ if (value_str == nullptr) return false;
// Sets *value to the value of the flag.
return ParseInt32(Message() << "The value of flag --" << flag,
@@ -5084,12 +5803,13 @@ bool ParseInt32Flag(const char* str, const char* flag, Int32* value) {
//
// On success, stores the value of the flag in *value, and returns
// true. On failure, returns false without changing *value.
-bool ParseStringFlag(const char* str, const char* flag, std::string* value) {
+template <typename String>
+static bool ParseStringFlag(const char* str, const char* flag, String* value) {
// Gets the value of the flag as a string.
const char* const value_str = ParseFlagValue(str, flag, false);
// Aborts if the parsing failed.
- if (value_str == NULL) return false;
+ if (value_str == nullptr) return false;
// Sets *value to the value of the flag.
*value = value_str;
@@ -5120,8 +5840,6 @@ static bool HasGoogleTestFlagPrefix(const char* str) {
// @Y changes the color to yellow.
// @D changes to the default terminal text color.
//
-// TODO(wan@google.com): Write tests for this once we add stdout
-// capturing to Google Test.
static void PrintColorEncoded(const char* str) {
GTestColor color = COLOR_DEFAULT; // The current color.
@@ -5131,7 +5849,7 @@ static void PrintColorEncoded(const char* str) {
// next segment.
for (;;) {
const char* p = strchr(str, '@');
- if (p == NULL) {
+ if (p == nullptr) {
ColoredPrintf(color, "%s", str);
return;
}
@@ -5186,24 +5904,25 @@ static const char kColorEncodedHelpMessage[] =
" Enable/disable colored output. The default is @Gauto@D.\n"
" -@G-" GTEST_FLAG_PREFIX_ "print_time=0@D\n"
" Don't print the elapsed time of each test.\n"
-" @G--" GTEST_FLAG_PREFIX_ "output=xml@Y[@G:@YDIRECTORY_PATH@G"
+" @G--" GTEST_FLAG_PREFIX_ "output=@Y(@Gjson@Y|@Gxml@Y)[@G:@YDIRECTORY_PATH@G"
GTEST_PATH_SEP_ "@Y|@G:@YFILE_PATH]@D\n"
-" Generate an XML report in the given directory or with the given file\n"
-" name. @YFILE_PATH@D defaults to @Gtest_details.xml@D.\n"
-#if GTEST_CAN_STREAM_RESULTS_
+" Generate a JSON or XML report in the given directory or with the given\n"
+" file name. @YFILE_PATH@D defaults to @Gtest_detail.xml@D.\n"
+# if GTEST_CAN_STREAM_RESULTS_
" @G--" GTEST_FLAG_PREFIX_ "stream_result_to=@YHOST@G:@YPORT@D\n"
" Stream test results to the given server.\n"
-#endif // GTEST_CAN_STREAM_RESULTS_
+# endif // GTEST_CAN_STREAM_RESULTS_
"\n"
"Assertion Behavior:\n"
-#if GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS
+# if GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS
" @G--" GTEST_FLAG_PREFIX_ "death_test_style=@Y(@Gfast@Y|@Gthreadsafe@Y)@D\n"
" Set the default death test style.\n"
-#endif // GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS
+# endif // GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS
" @G--" GTEST_FLAG_PREFIX_ "break_on_failure@D\n"
" Turn assertion failures into debugger break-points.\n"
" @G--" GTEST_FLAG_PREFIX_ "throw_on_failure@D\n"
-" Turn assertion failures into C++ exceptions.\n"
+" Turn assertion failures into C++ exceptions for use by an external\n"
+" test framework.\n"
" @G--" GTEST_FLAG_PREFIX_ "catch_exceptions=0@D\n"
" Do not report exceptions as test failures. Instead, allow them\n"
" to crash the program or throw a pop-up (on Windows).\n"
@@ -5220,7 +5939,7 @@ static const char kColorEncodedHelpMessage[] =
"(not one in your own code or tests), please report it to\n"
"@G<" GTEST_DEV_EMAIL_ ">@D.\n";
-bool ParseGoogleTestFlag(const char* const arg) {
+static bool ParseGoogleTestFlag(const char* const arg) {
return ParseBoolFlag(arg, kAlsoRunDisabledTestsFlag,
&GTEST_FLAG(also_run_disabled_tests)) ||
ParseBoolFlag(arg, kBreakOnFailureFlag,
@@ -5238,6 +5957,7 @@ bool ParseGoogleTestFlag(const char* const arg) {
ParseBoolFlag(arg, kListTestsFlag, &GTEST_FLAG(list_tests)) ||
ParseStringFlag(arg, kOutputFlag, &GTEST_FLAG(output)) ||
ParseBoolFlag(arg, kPrintTimeFlag, &GTEST_FLAG(print_time)) ||
+ ParseBoolFlag(arg, kPrintUTF8Flag, &GTEST_FLAG(print_utf8)) ||
ParseInt32Flag(arg, kRandomSeedFlag, &GTEST_FLAG(random_seed)) ||
ParseInt32Flag(arg, kRepeatFlag, &GTEST_FLAG(repeat)) ||
ParseBoolFlag(arg, kShuffleFlag, &GTEST_FLAG(shuffle)) ||
@@ -5250,14 +5970,11 @@ bool ParseGoogleTestFlag(const char* const arg) {
}
#if GTEST_USE_OWN_FLAGFILE_FLAG_
-void LoadFlagsFromFile(const std::string& path) {
+static void LoadFlagsFromFile(const std::string& path) {
FILE* flagfile = posix::FOpen(path.c_str(), "r");
if (!flagfile) {
- fprintf(stderr,
- "Unable to open file \"%s\"\n",
- GTEST_FLAG(flagfile).c_str());
- fflush(stderr);
- exit(EXIT_FAILURE);
+ GTEST_LOG_(FATAL) << "Unable to open file \"" << GTEST_FLAG(flagfile)
+ << "\"";
}
std::string contents(ReadEntireFile(flagfile));
posix::FClose(flagfile);
@@ -5331,6 +6048,17 @@ void ParseGoogleTestFlagsOnlyImpl(int* argc, CharType** argv) {
// other parts of Google Test.
void ParseGoogleTestFlagsOnly(int* argc, char** argv) {
ParseGoogleTestFlagsOnlyImpl(argc, argv);
+
+ // Fix the value of *_NSGetArgc() on macOS, but if and only if
+ // *_NSGetArgv() == argv
+ // Only applicable to char** version of argv
+#if GTEST_OS_MAC
+#ifndef GTEST_OS_IOS
+ if (*_NSGetArgv() == argv) {
+ *_NSGetArgc() = *argc;
+ }
+#endif
+#endif
}
void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv) {
ParseGoogleTestFlagsOnlyImpl(argc, argv);
@@ -5352,6 +6080,10 @@ void InitGoogleTestImpl(int* argc, CharType** argv) {
g_argvs.push_back(StreamableToString(argv[i]));
}
+#if GTEST_HAS_ABSL
+ absl::InitializeSymbolizer(g_argvs[0].c_str());
+#endif // GTEST_HAS_ABSL
+
ParseGoogleTestFlagsOnly(argc, argv);
GetUnitTestImpl()->PostFlagParsingInit();
}
@@ -5385,4 +6117,61 @@ void InitGoogleTest(int* argc, wchar_t** argv) {
#endif // defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_)
}
+// This overloaded version can be used on Arduino/embedded platforms where
+// there is no argc/argv.
+void InitGoogleTest() {
+ // Since Arduino doesn't have a command line, fake out the argc/argv arguments
+ int argc = 1;
+ const auto arg0 = "dummy";
+ char* argv0 = const_cast<char*>(arg0);
+ char** argv = &argv0;
+
+#if defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_)
+ GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_(&argc, argv);
+#else // defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_)
+ internal::InitGoogleTestImpl(&argc, argv);
+#endif // defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_)
+}
+
+std::string TempDir() {
+#if defined(GTEST_CUSTOM_TEMPDIR_FUNCTION_)
+ return GTEST_CUSTOM_TEMPDIR_FUNCTION_();
+#endif
+
+#if GTEST_OS_WINDOWS_MOBILE
+ return "\\temp\\";
+#elif GTEST_OS_WINDOWS
+ const char* temp_dir = internal::posix::GetEnv("TEMP");
+ if (temp_dir == nullptr || temp_dir[0] == '\0')
+ return "\\temp\\";
+ else if (temp_dir[strlen(temp_dir) - 1] == '\\')
+ return temp_dir;
+ else
+ return std::string(temp_dir) + "\\";
+#elif GTEST_OS_LINUX_ANDROID
+ return "/sdcard/";
+#else
+ return "/tmp/";
+#endif // GTEST_OS_WINDOWS_MOBILE
+}
+
+// Class ScopedTrace
+
+// Pushes the given source file location and message onto a per-thread
+// trace stack maintained by Google Test.
+void ScopedTrace::PushTrace(const char* file, int line, std::string message) {
+ internal::TraceInfo trace;
+ trace.file = file;
+ trace.line = line;
+ trace.message.swap(message);
+
+ UnitTest::GetInstance()->PushGTestTrace(trace);
+}
+
+// Pops the info pushed by the c'tor.
+ScopedTrace::~ScopedTrace()
+ GTEST_LOCK_EXCLUDED_(&UnitTest::mutex_) {
+ UnitTest::GetInstance()->PopGTestTrace();
+}
+
} // namespace testing
diff --git a/extern/gtest/src/gtest_main.cc b/extern/gtest/src/gtest_main.cc
index f3028225523..f6e1dd96fb3 100644
--- a/extern/gtest/src/gtest_main.cc
+++ b/extern/gtest/src/gtest_main.cc
@@ -27,12 +27,21 @@
// (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 <stdio.h>
-
+#include <cstdio>
#include "gtest/gtest.h"
+#ifdef ARDUINO
+void setup() {
+ testing::InitGoogleTest();
+}
+
+void loop() { RUN_ALL_TESTS(); }
+
+#else
+
GTEST_API_ int main(int argc, char **argv) {
- printf("Running main() from gtest_main.cc\n");
+ printf("Running main() from %s\n", __FILE__);
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
+#endif
diff --git a/extern/mantaflow/CMakeLists.txt b/extern/mantaflow/CMakeLists.txt
index bdee06349d2..8b7453bf4c5 100644
--- a/extern/mantaflow/CMakeLists.txt
+++ b/extern/mantaflow/CMakeLists.txt
@@ -54,6 +54,10 @@ if(WITH_OPENVDB)
add_definitions(-DOPENVDB_STATICLIB)
endif()
+if(WITH_OPENVDB_BLOSC)
+ add_definitions(-DOPENVDB_BLOSC=1)
+endif()
+
if(WIN32)
add_definitions(-D_USE_MATH_DEFINES)
endif()
@@ -106,10 +110,12 @@ set(SRC
${MANTA_PP}/fastmarch.cpp
${MANTA_PP}/fastmarch.h
${MANTA_PP}/fastmarch.h.reg.cpp
- ${MANTA_PP}/fileio/ioutil.cpp
${MANTA_PP}/fileio/iogrids.cpp
${MANTA_PP}/fileio/iomeshes.cpp
${MANTA_PP}/fileio/ioparticles.cpp
+ ${MANTA_PP}/fileio/ioutil.cpp
+ ${MANTA_PP}/fileio/iovdb.cpp
+ ${MANTA_PP}/fileio/mantaio.cpp
${MANTA_PP}/fileio/mantaio.h
${MANTA_PP}/fileio/mantaio.h.reg.cpp
${MANTA_PP}/fluidsolver.cpp
diff --git a/extern/mantaflow/helper/pwrapper/pconvert.cpp b/extern/mantaflow/helper/pwrapper/pconvert.cpp
index 9ada75519fc..861a2c070bd 100644
--- a/extern/mantaflow/helper/pwrapper/pconvert.cpp
+++ b/extern/mantaflow/helper/pwrapper/pconvert.cpp
@@ -96,6 +96,37 @@ template<> PyObject *toPy<PbClass *>(const PbClass_Ptr &obj)
{
return obj->getPyObject();
}
+template<> PyObject *toPy<std::vector<PbClass *>>(const std::vector<PbClass *> &vec)
+{
+ PyObject *listObj = PyList_New(vec.size());
+ if (!listObj)
+ throw logic_error("Unable to allocate memory for Python list");
+ for (unsigned int i = 0; i < vec.size(); i++) {
+ PbClass *pb = vec[i];
+ PyObject *item = pb->getPyObject();
+ if (!item) {
+ Py_DECREF(listObj);
+ throw logic_error("Unable to allocate memory for Python list");
+ }
+ PyList_SET_ITEM(listObj, i, item);
+ }
+ return listObj;
+}
+template<> PyObject *toPy<std::vector<float>>(const std::vector<float> &vec)
+{
+ PyObject *listObj = PyList_New(vec.size());
+ if (!listObj)
+ throw logic_error("Unable to allocate memory for Python list");
+ for (unsigned int i = 0; i < vec.size(); i++) {
+ PyObject *item = toPy<float>(vec[i]);
+ if (!item) {
+ Py_DECREF(listObj);
+ throw logic_error("Unable to allocate memory for Python list");
+ }
+ PyList_SET_ITEM(listObj, i, item);
+ }
+ return listObj;
+}
template<> float fromPy<float>(PyObject *obj)
{
@@ -125,6 +156,42 @@ template<> PyObject *fromPy<PyObject *>(PyObject *obj)
{
return obj;
}
+template<> PbClass *fromPy<PbClass *>(PyObject *obj)
+{
+ PbClass *pbo = Pb::objFromPy(obj);
+
+ if (!PyType_Check(obj))
+ return pbo;
+
+ const char *tname = ((PyTypeObject *)obj)->tp_name;
+ pbo->setName(tname);
+
+ return pbo;
+}
+template<> std::vector<PbClass *> fromPy<std::vector<PbClass *>>(PyObject *obj)
+{
+ std::vector<PbClass *> vec;
+ if (PyList_Check(obj)) {
+ int sz = PyList_Size(obj);
+ for (int i = 0; i < sz; ++i) {
+ PyObject *lobj = PyList_GetItem(obj, i);
+ vec.push_back(fromPy<PbClass *>(lobj));
+ }
+ }
+ return vec;
+}
+template<> std::vector<float> fromPy<std::vector<float>>(PyObject *obj)
+{
+ std::vector<float> vec;
+ if (PyList_Check(obj)) {
+ int sz = PyList_Size(obj);
+ for (int i = 0; i < sz; ++i) {
+ PyObject *lobj = PyList_GetItem(obj, i);
+ vec.push_back(fromPy<float>(lobj));
+ }
+ }
+ return vec;
+}
template<> int fromPy<int>(PyObject *obj)
{
#if PY_MAJOR_VERSION <= 2
@@ -259,11 +326,10 @@ template<class T> T *tmpAlloc(PyObject *obj, std::vector<void *> *tmp)
{
if (!tmp)
throw Error("dynamic de-ref not supported for this type");
- void *ptr = malloc(sizeof(T));
- tmp->push_back(ptr);
- *((T *)ptr) = fromPy<T>(obj);
- return (T *)ptr;
+ T *ptr = new T(fromPy<T>(obj));
+ tmp->push_back(ptr);
+ return ptr;
}
template<> float *fromPyPtr<float>(PyObject *obj, std::vector<void *> *tmp)
{
@@ -301,6 +367,11 @@ template<> Vec4i *fromPyPtr<Vec4i>(PyObject *obj, std::vector<void *> *tmp)
{
return tmpAlloc<Vec4i>(obj, tmp);
}
+template<>
+std::vector<PbClass *> *fromPyPtr<std::vector<PbClass *>>(PyObject *obj, std::vector<void *> *tmp)
+{
+ return tmpAlloc<std::vector<PbClass *>>(obj, tmp);
+}
template<> bool isPy<float>(PyObject *obj)
{
@@ -404,6 +475,18 @@ template<> bool isPy<PbType>(PyObject *obj)
{
return PyType_Check(obj);
}
+template<> bool isPy<std::vector<PbClass *>>(PyObject *obj)
+{
+ if (PyList_Check(obj))
+ return true;
+ return false;
+}
+template<> bool isPy<std::vector<float>>(PyObject *obj)
+{
+ if (PyList_Check(obj))
+ return true;
+ return false;
+}
//******************************************************************************
// PbArgs class defs
@@ -417,7 +500,7 @@ PbArgs::PbArgs(PyObject *linarg, PyObject *dict) : mLinArgs(0), mKwds(0)
PbArgs::~PbArgs()
{
for (int i = 0; i < (int)mTmpStorage.size(); i++)
- free(mTmpStorage[i]);
+ operator delete(mTmpStorage[i]);
mTmpStorage.clear();
}
diff --git a/extern/mantaflow/helper/pwrapper/pconvert.h b/extern/mantaflow/helper/pwrapper/pconvert.h
index 9c72b8b57b9..87f4248f6f1 100644
--- a/extern/mantaflow/helper/pwrapper/pconvert.h
+++ b/extern/mantaflow/helper/pwrapper/pconvert.h
@@ -57,6 +57,10 @@ template<> Vec3 *fromPyPtr<Vec3>(PyObject *obj, std::vector<void *> *tmp);
template<> Vec3i *fromPyPtr<Vec3i>(PyObject *obj, std::vector<void *> *tmp);
template<> Vec4 *fromPyPtr<Vec4>(PyObject *obj, std::vector<void *> *tmp);
template<> Vec4i *fromPyPtr<Vec4i>(PyObject *obj, std::vector<void *> *tmp);
+template<>
+std::vector<PbClass *> *fromPyPtr<std::vector<PbClass *>>(PyObject *obj, std::vector<void *> *tmp);
+template<>
+std::vector<float> *fromPyPtr<std::vector<float>>(PyObject *obj, std::vector<void *> *tmp);
PyObject *incref(PyObject *obj);
template<class T> PyObject *toPy(const T &v)
@@ -99,6 +103,9 @@ template<> Vec4 fromPy<Vec4>(PyObject *obj);
template<> Vec4i fromPy<Vec4i>(PyObject *obj);
template<> PbType fromPy<PbType>(PyObject *obj);
template<> PbTypeVec fromPy<PbTypeVec>(PyObject *obj);
+template<> PbClass *fromPy<PbClass *>(PyObject *obj);
+template<> std::vector<PbClass *> fromPy<std::vector<PbClass *>>(PyObject *obj);
+template<> std::vector<float> fromPy<std::vector<float>>(PyObject *obj);
template<> PyObject *toPy<int>(const int &v);
template<> PyObject *toPy<std::string>(const std::string &val);
@@ -111,6 +118,8 @@ template<> PyObject *toPy<Vec4i>(const Vec4i &v);
template<> PyObject *toPy<Vec4>(const Vec4 &v);
typedef PbClass *PbClass_Ptr;
template<> PyObject *toPy<PbClass *>(const PbClass_Ptr &obj);
+template<> PyObject *toPy<std::vector<PbClass *>>(const std::vector<PbClass *> &vec);
+template<> PyObject *toPy<std::vector<float>>(const std::vector<float> &vec);
template<> bool isPy<float>(PyObject *obj);
template<> bool isPy<double>(PyObject *obj);
@@ -124,6 +133,8 @@ template<> bool isPy<Vec3i>(PyObject *obj);
template<> bool isPy<Vec4>(PyObject *obj);
template<> bool isPy<Vec4i>(PyObject *obj);
template<> bool isPy<PbType>(PyObject *obj);
+template<> bool isPy<std::vector<PbClass *>>(PyObject *obj);
+template<> bool isPy<std::vector<float>>(PyObject *obj);
//! Encapsulation of python arguments
class PbArgs {
diff --git a/extern/mantaflow/helper/util/randomstream.h b/extern/mantaflow/helper/util/randomstream.h
index 35b9c7d8858..6c20ddc6a14 100644
--- a/extern/mantaflow/helper/util/randomstream.h
+++ b/extern/mantaflow/helper/util/randomstream.h
@@ -16,13 +16,13 @@
#ifndef _RANDOMSTREAM_H
#define _RANDOMSTREAM_H
-namespace Manta {
-
#include <iostream>
#include <stdio.h>
#include <time.h>
#include "vectorbase.h"
+namespace Manta {
+
class MTRand {
// Data
public:
diff --git a/extern/mantaflow/preprocessed/fileio/iogrids.cpp b/extern/mantaflow/preprocessed/fileio/iogrids.cpp
index acd1bda5174..e2550d6db8b 100644
--- a/extern/mantaflow/preprocessed/fileio/iogrids.cpp
+++ b/extern/mantaflow/preprocessed/fileio/iogrids.cpp
@@ -27,10 +27,6 @@ extern "C" {
}
#endif
-#if OPENVDB == 1
-# include "openvdb/openvdb.h"
-#endif
-
#include "cnpy.h"
#include "mantaio.h"
#include "grid.h"
@@ -279,54 +275,87 @@ static int unifyGridType(int type)
// grid data
//*****************************************************************************
-template<class T> void writeGridTxt(const string &name, Grid<T> *grid)
+template<class T> int writeGridTxt(const string &name, Grid<T> *grid)
{
debMsg("writing grid " << grid->getName() << " to text file " << name, 1);
ofstream ofs(name.c_str());
if (!ofs.good())
errMsg("writeGridTxt: can't open file " << name);
+ return 0;
FOR_IJK(*grid)
{
ofs << Vec3i(i, j, k) << " = " << (*grid)(i, j, k) << "\n";
}
ofs.close();
+ return 1;
+}
+
+int writeGridsTxt(const string &name, std::vector<PbClass *> *grids)
+{
+ errMsg("writeGridsTxt: writing multiple grids to one .txt file not supported yet");
+ return 0;
}
-template<class T> void writeGridRaw(const string &name, Grid<T> *grid)
+int readGridsTxt(const string &name, std::vector<PbClass *> *grids)
+{
+ errMsg("readGridsTxt: writing multiple grids from one .txt file not supported yet");
+ return 0;
+}
+
+template<class T> int writeGridRaw(const string &name, Grid<T> *grid)
{
debMsg("writing grid " << grid->getName() << " to raw file " << name, 1);
#if NO_ZLIB != 1
gzFile gzf = (gzFile)safeGzopen(name.c_str(), "wb1"); // do some compression
- if (!gzf)
+ if (!gzf) {
errMsg("writeGridRaw: can't open file " << name);
+ return 0;
+ }
+
gzwrite(gzf, &((*grid)[0]), sizeof(T) * grid->getSizeX() * grid->getSizeY() * grid->getSizeZ());
- gzclose(gzf);
+ return (gzclose(gzf) == Z_OK);
#else
debMsg("file format not supported without zlib", 1);
+ return 0;
#endif
}
-template<class T> void readGridRaw(const string &name, Grid<T> *grid)
+template<class T> int readGridRaw(const string &name, Grid<T> *grid)
{
debMsg("reading grid " << grid->getName() << " from raw file " << name, 1);
#if NO_ZLIB != 1
gzFile gzf = (gzFile)safeGzopen(name.c_str(), "rb");
- if (!gzf)
+ if (!gzf) {
errMsg("readGridRaw: can't open file " << name);
+ return 0;
+ }
IndexInt bytes = sizeof(T) * grid->getSizeX() * grid->getSizeY() * grid->getSizeZ();
IndexInt readBytes = gzread(gzf, &((*grid)[0]), bytes);
assertMsg(bytes == readBytes,
"can't read raw file, stream length does not match, " << bytes << " vs " << readBytes);
- gzclose(gzf);
+ return (gzclose(gzf) == Z_OK);
#else
debMsg("file format not supported without zlib", 1);
+ return 0;
#endif
}
+int writeGridsRaw(const string &name, std::vector<PbClass *> *grids)
+{
+ errMsg("writeGridsRaw: writing multiple grids to one .raw file not supported yet");
+ return 0;
+}
+
+int readGridsRaw(const string &name, std::vector<PbClass *> *grids)
+{
+ errMsg("readGridsRaw: reading multiple grids from one .raw file not supported yet");
+ return 0;
+}
+
//! legacy headers for reading old files
typedef struct {
int dimX, dimY, dimZ;
@@ -473,7 +502,7 @@ void PbRegister_printUniFileInfoString()
// actual read/write functions
-template<class T> void writeGridUni(const string &name, Grid<T> *grid)
+template<class T> int writeGridUni(const string &name, Grid<T> *grid)
{
debMsg("Writing grid " << grid->getName() << " to uni file " << name, 1);
@@ -496,12 +525,16 @@ template<class T> void writeGridUni(const string &name, Grid<T> *grid)
head.elementType = 1;
else if (grid->getType() & GridBase::TypeVec3)
head.elementType = 2;
- else
+ else {
errMsg("writeGridUni: unknown element type");
+ return 0;
+ }
gzFile gzf = (gzFile)safeGzopen(name.c_str(), "wb1"); // do some compression
- if (!gzf)
+ if (!gzf) {
errMsg("writeGridUni: can't open file " << name);
+ return 0;
+ }
gzwrite(gzf, ID, 4);
# if FLOATINGPOINT_PRECISION != 1
@@ -515,21 +548,24 @@ template<class T> void writeGridUni(const string &name, Grid<T> *grid)
gzwrite(gzf, &head, sizeof(UniHeader));
gzwrite(gzf, ptr, sizeof(T) * head.dimX * head.dimY * head.dimZ);
# endif
- gzclose(gzf);
+ return (gzclose(gzf) == Z_OK);
#else
debMsg("file format not supported without zlib", 1);
+ return 0;
#endif
};
-template<class T> void readGridUni(const string &name, Grid<T> *grid)
+template<class T> int readGridUni(const string &name, Grid<T> *grid)
{
debMsg("Reading grid " << grid->getName() << " from uni file " << name, 1);
#if NO_ZLIB != 1
gzFile gzf = (gzFile)safeGzopen(name.c_str(), "rb");
- if (!gzf)
+ if (!gzf) {
errMsg("readGridUni: can't open file " << name);
+ return 0;
+ }
char ID[5] = {0, 0, 0, 0, 0};
gzread(gzf, ID, 4);
@@ -609,17 +645,44 @@ template<class T> void readGridUni(const string &name, Grid<T> *grid)
}
else {
errMsg("readGridUni: Unknown header '" << ID << "' ");
+ return 0;
}
- gzclose(gzf);
+ return (gzclose(gzf) == Z_OK);
#else
debMsg("file format not supported without zlib", 1);
+ return 0;
#endif
};
-template<class T> void writeGridVol(const string &name, Grid<T> *grid)
+int writeGridsUni(const string &name, std::vector<PbClass *> *grids)
+{
+ errMsg("writeGridsUni: writing multiple grids to one .uni file not supported yet");
+ return 0;
+}
+
+int readGridsUni(const string &name, std::vector<PbClass *> *grids)
+{
+ errMsg("readGridsUni: reading multiple grids from one .uni file not supported yet");
+ return 0;
+}
+
+template<class T> int writeGridVol(const string &name, Grid<T> *grid)
{
debMsg("writing grid " << grid->getName() << " to vol file " << name, 1);
errMsg("writeGridVol: Type not yet supported!");
+ return 0;
+}
+
+int writeGridsVol(const string &name, std::vector<PbClass *> *grids)
+{
+ errMsg("writeGridsVol: writing multiple grids to one .vol file not supported yet");
+ return 0;
+}
+
+int readGridsVol(const string &name, std::vector<PbClass *> *grids)
+{
+ errMsg("readGridsVol: reading multiple grids from one .vol file not supported yet");
+ return 0;
}
struct volHeader {
@@ -631,7 +694,7 @@ struct volHeader {
Vec3 bboxMin, bboxMax;
};
-template<> void writeGridVol<Real>(const string &name, Grid<Real> *grid)
+template<> int writeGridVol<Real>(const string &name, Grid<Real> *grid)
{
debMsg("writing real grid " << grid->getName() << " to vol file " << name, 1);
@@ -651,7 +714,7 @@ template<> void writeGridVol<Real>(const string &name, Grid<Real> *grid)
FILE *fp = fopen(name.c_str(), "wb");
if (fp == NULL) {
errMsg("writeGridVol: Cannot open '" << name << "'");
- return;
+ return 0;
}
fwrite(&header, sizeof(volHeader), 1, fp);
@@ -667,17 +730,17 @@ template<> void writeGridVol<Real>(const string &name, Grid<Real> *grid)
fwrite(&value, sizeof(float), 1, fp);
}
#endif
-
- fclose(fp);
+ return (!fclose(fp));
};
-template<class T> void readGridVol(const string &name, Grid<T> *grid)
+template<class T> int readGridVol(const string &name, Grid<T> *grid)
{
debMsg("writing grid " << grid->getName() << " to vol file " << name, 1);
errMsg("readGridVol: Type not yet supported!");
+ return 0;
}
-template<> void readGridVol<Real>(const string &name, Grid<Real> *grid)
+template<> int readGridVol<Real>(const string &name, Grid<Real> *grid)
{
debMsg("reading real grid " << grid->getName() << " from vol file " << name, 1);
@@ -685,7 +748,7 @@ template<> void readGridVol<Real>(const string &name, Grid<Real> *grid)
FILE *fp = fopen(name.c_str(), "rb");
if (fp == NULL) {
errMsg("readGridVol: Cannot open '" << name << "'");
- return;
+ return 0;
}
// note, only very basic file format checks here!
@@ -697,17 +760,17 @@ template<> void readGridVol<Real>(const string &name, Grid<Real> *grid)
<< grid->getSize());
#if FLOATINGPOINT_PRECISION != 1
errMsg("readGridVol: Double precision not yet supported");
+ return 0;
#else
const unsigned int s = sizeof(float) * header.dimX * header.dimY * header.dimZ;
assertMsg(fread(&((*grid)[0]), 1, s, fp) == s, "can't read file, no / not enough data");
#endif
-
- fclose(fp);
+ return (!fclose(fp));
};
// 4d grids IO
-template<class T> void writeGrid4dUni(const string &name, Grid4d<T> *grid)
+template<class T> int writeGrid4dUni(const string &name, Grid4d<T> *grid)
{
debMsg("writing grid4d " << grid->getName() << " to uni file " << name, 1);
@@ -733,12 +796,16 @@ template<class T> void writeGrid4dUni(const string &name, Grid4d<T> *grid)
head.elementType = 2;
else if (grid->getType() & Grid4dBase::TypeVec4)
head.elementType = 2;
- else
+ else {
errMsg("writeGrid4dUni: unknown element type");
+ return 0;
+ }
gzFile gzf = (gzFile)safeGzopen(name.c_str(), "wb1"); // do some compression
- if (!gzf)
+ if (!gzf) {
errMsg("writeGrid4dUni: can't open file " << name);
+ return 0;
+ }
gzwrite(gzf, ID, 4);
# if FLOATINGPOINT_PRECISION != 1
@@ -753,16 +820,17 @@ template<class T> void writeGrid4dUni(const string &name, Grid4d<T> *grid)
gzwrite(gzf, ptr, sizeof(T) * head.dimX * head.dimY * head.dimZ * 1);
}
# endif
- gzclose(gzf);
+ return (gzclose(gzf) == Z_OK);
#else
debMsg("file format not supported without zlib", 1);
+ return 0;
#endif
};
//! note, reading 4d uni grids is slightly more complicated than 3d ones
//! as it optionally supports sliced reading
template<class T>
-void readGrid4dUni(
+int readGrid4dUni(
const string &name, Grid4d<T> *grid, int readTslice, Grid4d<T> *slice, void **fileHandle)
{
if (grid)
@@ -779,8 +847,10 @@ void readGrid4dUni(
// optionally - reuse file handle, if valid one is passed in fileHandle pointer...
if ((!fileHandle) || (fileHandle && (*fileHandle == NULL))) {
gzf = (gzFile)safeGzopen(name.c_str(), "rb");
- if (!gzf)
+ if (!gzf) {
errMsg("readGrid4dUni: can't open file " << name);
+ return 0;
+ }
gzread(gzf, ID, 4);
if (fileHandle) {
@@ -792,7 +862,7 @@ void readGrid4dUni(
gzf = (gzFile)(*fileHandle);
void *ptr = &((*slice)[0]);
gzread(gzf, ptr, sizeof(T) * slice->getStrideT() * 1); // quick and dirty...
- return;
+ return 1;
}
if ((!strcmp(ID, "M4T2")) || (!strcmp(ID, "M4T3"))) {
@@ -867,6 +937,7 @@ void readGrid4dUni(
# if FLOATINGPOINT_PRECISION != 1
errMsg("readGrid4dUni: NYI (2)"); // slice read not yet supported for double
+ return 0;
# else
assertMsg(slice, "No 3d slice grid data given");
assertMsg(readTslice < head.dimT,
@@ -884,10 +955,12 @@ void readGrid4dUni(
}
if (!fileHandle) {
- gzclose(gzf);
+ return (gzclose(gzf) == Z_OK);
}
+ return 1;
#else
debMsg("file format not supported without zlib", 1);
+ return 0;
#endif
};
void readGrid4dUniCleanup(void **fileHandle)
@@ -900,296 +973,61 @@ void readGrid4dUniCleanup(void **fileHandle)
}
}
-template<class T> void writeGrid4dRaw(const string &name, Grid4d<T> *grid)
+template<class T> int writeGrid4dRaw(const string &name, Grid4d<T> *grid)
{
debMsg("writing grid4d " << grid->getName() << " to raw file " << name, 1);
#if NO_ZLIB != 1
gzFile gzf = (gzFile)safeGzopen(name.c_str(), "wb1"); // do some compression
- if (!gzf)
+ if (!gzf) {
errMsg("writeGrid4dRaw: can't open file " << name);
+ return 0;
+ }
gzwrite(gzf,
&((*grid)[0]),
sizeof(T) * grid->getSizeX() * grid->getSizeY() * grid->getSizeZ() * grid->getSizeT());
- gzclose(gzf);
+ return (gzclose(gzf) == Z_OK);
#else
debMsg("file format not supported without zlib", 1);
+ return 0;
#endif
}
-template<class T> void readGrid4dRaw(const string &name, Grid4d<T> *grid)
+template<class T> int readGrid4dRaw(const string &name, Grid4d<T> *grid)
{
debMsg("reading grid4d " << grid->getName() << " from raw file " << name, 1);
#if NO_ZLIB != 1
gzFile gzf = (gzFile)safeGzopen(name.c_str(), "rb");
- if (!gzf)
+ if (!gzf) {
errMsg("readGrid4dRaw: can't open file " << name);
-
+ return 0;
+ }
IndexInt bytes = sizeof(T) * grid->getSizeX() * grid->getSizeY() * grid->getSizeZ() *
grid->getSizeT();
IndexInt readBytes = gzread(gzf, &((*grid)[0]), bytes);
assertMsg(bytes == readBytes,
"can't read raw file, stream length does not match, " << bytes << " vs " << readBytes);
- gzclose(gzf);
+ return (gzclose(gzf) == Z_OK);
#else
debMsg("file format not supported without zlib", 1);
+ return 0;
#endif
}
//*****************************************************************************
-// optional openvdb export
-
-#if OPENVDB == 1
-
-template<class T> void writeGridVDB(const string &name, Grid<T> *grid)
-{
- debMsg("Writing grid " << grid->getName() << " to vdb file " << name << " not yet supported!",
- 1);
-}
-
-template<class T> void readGridVDB(const string &name, Grid<T> *grid)
-{
- debMsg("Reading grid " << grid->getName() << " from vdb file " << name << " not yet supported!",
- 1);
-}
-
-template<> void writeGridVDB(const string &name, Grid<int> *grid)
-{
- debMsg("Writing int grid " << grid->getName() << " to vdb file " << name, 1);
-
- // Create an empty int32-point grid with background value 0.
- openvdb::initialize();
- openvdb::Int32Grid::Ptr gridVDB = openvdb::Int32Grid::create();
- gridVDB->setTransform(
- openvdb::math::Transform::createLinearTransform(1. / grid->getSizeX())); // voxel size
-
- // Get an accessor for coordinate-based access to voxels.
- openvdb::Int32Grid::Accessor accessor = gridVDB->getAccessor();
-
- gridVDB->setGridClass(openvdb::GRID_UNKNOWN);
-
- // Name the grid "density".
- gridVDB->setName(grid->getName());
-
- openvdb::io::File file(name);
-
- FOR_IJK(*grid)
- {
- openvdb::Coord xyz(i, j, k);
- accessor.setValue(xyz, (*grid)(i, j, k));
- }
-
- // Add the grid pointer to a container.
- openvdb::GridPtrVec gridsVDB;
- gridsVDB.push_back(gridVDB);
-
- // Write out the contents of the container.
- file.write(gridsVDB);
- file.close();
-}
-
-template<> void readGridVDB(const string &name, Grid<int> *grid)
-{
- debMsg("Reading int grid " << grid->getName() << " from vdb file " << name, 1);
-
- openvdb::initialize();
- openvdb::io::File file(name);
- file.open();
-
- openvdb::GridBase::Ptr baseGrid;
- for (openvdb::io::File::NameIterator nameIter = file.beginName(); nameIter != file.endName();
- ++nameIter) {
-# ifndef BLENDER
- // Read in only the grid we are interested in.
- if (nameIter.gridName() == grid->getName()) {
- baseGrid = file.readGrid(nameIter.gridName());
- }
- else {
- debMsg("skipping grid " << nameIter.gridName(), 1);
- }
-# else
- // For Blender, skip name check and pick first grid from loop
- baseGrid = file.readGrid(nameIter.gridName());
- break;
-# endif
- }
- file.close();
- openvdb::Int32Grid::Ptr gridVDB = openvdb::gridPtrCast<openvdb::Int32Grid>(baseGrid);
-
- openvdb::Int32Grid::Accessor accessor = gridVDB->getAccessor();
-
- FOR_IJK(*grid)
- {
- openvdb::Coord xyz(i, j, k);
- int v = accessor.getValue(xyz);
- (*grid)(i, j, k) = v;
- }
-}
-
-template<> void writeGridVDB(const string &name, Grid<Real> *grid)
-{
- debMsg("Writing real grid " << grid->getName() << " to vdb file " << name, 1);
-
- // Create an empty floating-point grid with background value 0.
- openvdb::initialize();
- openvdb::FloatGrid::Ptr gridVDB = openvdb::FloatGrid::create();
- gridVDB->setTransform(
- openvdb::math::Transform::createLinearTransform(1. / grid->getSizeX())); // voxel size
-
- // Get an accessor for coordinate-based access to voxels.
- openvdb::FloatGrid::Accessor accessor = gridVDB->getAccessor();
-
- // Identify the grid as a level set.
- gridVDB->setGridClass(openvdb::GRID_FOG_VOLUME);
-
- // Name the grid "density".
- gridVDB->setName(grid->getName());
-
- openvdb::io::File file(name);
-
- FOR_IJK(*grid)
- {
- openvdb::Coord xyz(i, j, k);
- accessor.setValue(xyz, (*grid)(i, j, k));
- }
-
- // Add the grid pointer to a container.
- openvdb::GridPtrVec gridsVDB;
- gridsVDB.push_back(gridVDB);
-
- // Write out the contents of the container.
- file.write(gridsVDB);
- file.close();
-};
-
-template<> void readGridVDB(const string &name, Grid<Real> *grid)
-{
- debMsg("Reading real grid " << grid->getName() << " from vdb file " << name, 1);
-
- openvdb::initialize();
- openvdb::io::File file(name);
- file.open();
-
- openvdb::GridBase::Ptr baseGrid;
- for (openvdb::io::File::NameIterator nameIter = file.beginName(); nameIter != file.endName();
- ++nameIter) {
-# ifndef BLENDER
- // Read in only the grid we are interested in.
- if (nameIter.gridName() == grid->getName()) {
- baseGrid = file.readGrid(nameIter.gridName());
- }
- else {
- debMsg("skipping grid " << nameIter.gridName(), 1);
- }
-# else
- // For Blender, skip name check and pick first grid from loop
- baseGrid = file.readGrid(nameIter.gridName());
- break;
-# endif
- }
- file.close();
- openvdb::FloatGrid::Ptr gridVDB = openvdb::gridPtrCast<openvdb::FloatGrid>(baseGrid);
-
- openvdb::FloatGrid::Accessor accessor = gridVDB->getAccessor();
-
- FOR_IJK(*grid)
- {
- openvdb::Coord xyz(i, j, k);
- float v = accessor.getValue(xyz);
- (*grid)(i, j, k) = v;
- }
-};
-
-template<> void writeGridVDB(const string &name, Grid<Vec3> *grid)
-{
- debMsg("Writing vec3 grid " << grid->getName() << " to vdb file " << name, 1);
-
- openvdb::initialize();
- openvdb::Vec3SGrid::Ptr gridVDB = openvdb::Vec3SGrid::create();
- // note , warning - velocity content currently not scaled...
- gridVDB->setTransform(
- openvdb::math::Transform::createLinearTransform(1. / grid->getSizeX())); // voxel size
- openvdb::Vec3SGrid::Accessor accessor = gridVDB->getAccessor();
-
- // MAC or regular vec grid?
- if (grid->getType() & GridBase::TypeMAC)
- gridVDB->setGridClass(openvdb::GRID_STAGGERED);
- else
- gridVDB->setGridClass(openvdb::GRID_UNKNOWN);
-
- gridVDB->setName(grid->getName());
-
- openvdb::io::File file(name);
- FOR_IJK(*grid)
- {
- openvdb::Coord xyz(i, j, k);
- Vec3 v = (*grid)(i, j, k);
- openvdb::Vec3f vo((float)v[0], (float)v[1], (float)v[2]);
- accessor.setValue(xyz, vo);
- }
-
- openvdb::GridPtrVec gridsVDB;
- gridsVDB.push_back(gridVDB);
-
- file.write(gridsVDB);
- file.close();
-};
-
-template<> void readGridVDB(const string &name, Grid<Vec3> *grid)
-{
- debMsg("Reading vec3 grid " << grid->getName() << " from vdb file " << name, 1);
-
- openvdb::initialize();
- openvdb::io::File file(name);
- file.open();
-
- openvdb::GridBase::Ptr baseGrid;
- for (openvdb::io::File::NameIterator nameIter = file.beginName(); nameIter != file.endName();
- ++nameIter) {
-# ifndef BLENDER
- // Read in only the grid we are interested in.
- if (nameIter.gridName() == grid->getName()) {
- baseGrid = file.readGrid(nameIter.gridName());
- }
- else {
- debMsg("skipping grid " << nameIter.gridName(), 1);
- }
-# else
- // For Blender, skip name check and pick first grid from loop
- baseGrid = file.readGrid(nameIter.gridName());
- break;
-# endif
- }
- file.close();
- openvdb::Vec3SGrid::Ptr gridVDB = openvdb::gridPtrCast<openvdb::Vec3SGrid>(baseGrid);
-
- openvdb::Vec3SGrid::Accessor accessor = gridVDB->getAccessor();
-
- FOR_IJK(*grid)
- {
- openvdb::Coord xyz(i, j, k);
- openvdb::Vec3f v = accessor.getValue(xyz);
- (*grid)(i, j, k).x = (float)v[0];
- (*grid)(i, j, k).y = (float)v[1];
- (*grid)(i, j, k).z = (float)v[2];
- }
-};
-
-#endif // OPENVDB==1
-
-//*****************************************************************************
// npz file support (warning - read works, but write generates uncompressed npz; i.e. not
// recommended for large volumes)
-template<class T> void writeGridNumpy(const string &name, Grid<T> *grid)
+template<class T> int writeGridNumpy(const string &name, Grid<T> *grid)
{
#if NO_ZLIB == 1
debMsg("file format not supported without zlib", 1);
- return;
+ return 0;
#endif
#if FLOATINGPOINT_PRECISION != 1
errMsg("writeGridNumpy: Double precision not yet supported");
+ return 0;
#endif
// find suffix to differentiate between npy <-> npz , TODO: check for actual "npy" string
@@ -1211,8 +1049,10 @@ template<class T> void writeGridNumpy(const string &name, Grid<T> *grid)
uDim = 1;
else if (grid->getType() & GridBase::TypeVec3 || grid->getType() & GridBase::TypeMAC)
uDim = 3;
- else
+ else {
errMsg("writeGridNumpy: unknown element type");
+ return 0;
+ }
const std::vector<size_t> shape = {static_cast<size_t>(grid->getSizeZ()),
static_cast<size_t>(grid->getSizeY()),
@@ -1234,16 +1074,18 @@ template<class T> void writeGridNumpy(const string &name, Grid<T> *grid)
else {
cnpy::npy_save(name, &grid[0], shape, "w");
}
+ return 1;
};
-template<class T> void readGridNumpy(const string &name, Grid<T> *grid)
+template<class T> int readGridNumpy(const string &name, Grid<T> *grid)
{
#if NO_ZLIB == 1
debMsg("file format not supported without zlib", 1);
- return;
+ return 0;
#endif
#if FLOATINGPOINT_PRECISION != 1
errMsg("readGridNumpy: Double precision not yet supported");
+ return 0;
#endif
// find suffix to differentiate between npy <-> npz
@@ -1279,8 +1121,10 @@ template<class T> void readGridNumpy(const string &name, Grid<T> *grid)
uDim = 1;
else if (grid->getType() & GridBase::TypeVec3 || grid->getType() & GridBase::TypeMAC)
uDim = 3;
- else
+ else {
errMsg("readGridNumpy: unknown element type");
+ return 0;
+ }
assertMsg(gridArr.shape[3] == uDim,
"grid data dim doesn't match, " << gridArr.shape[3] << " vs " << uDim);
@@ -1299,8 +1143,21 @@ template<class T> void readGridNumpy(const string &name, Grid<T> *grid)
memcpy(&((*grid)[0]),
gridArr.data<T>(),
sizeof(T) * grid->getSizeX() * grid->getSizeY() * grid->getSizeZ());
+ return 1;
};
+int writeGridsNumpy(const string &name, std::vector<PbClass *> *grids)
+{
+ errMsg("writeGridsNumpy: writing multiple grids to one .npz file not supported yet");
+ return 0;
+}
+
+int readGridsNumpy(const string &name, std::vector<PbClass *> *grids)
+{
+ errMsg("readGridsNumpy: reading multiple grids from one .npz file not supported yet");
+ return 0;
+}
+
// adopted from getUniFileSize
void getNpzFileSize(
const string &name, int &x, int &y, int &z, int *t = NULL, std::string *info = NULL)
@@ -1521,77 +1378,63 @@ void PbRegister_quantizeGridVec3()
}
// explicit instantiation
-template void writeGridRaw<int>(const string &name, Grid<int> *grid);
-template void writeGridRaw<Real>(const string &name, Grid<Real> *grid);
-template void writeGridRaw<Vec3>(const string &name, Grid<Vec3> *grid);
-template void writeGridUni<int>(const string &name, Grid<int> *grid);
-template void writeGridUni<Real>(const string &name, Grid<Real> *grid);
-template void writeGridUni<Vec3>(const string &name, Grid<Vec3> *grid);
-template void writeGridVol<int>(const string &name, Grid<int> *grid);
-template void writeGridVol<Vec3>(const string &name, Grid<Vec3> *grid);
-template void writeGridTxt<int>(const string &name, Grid<int> *grid);
-template void writeGridTxt<Real>(const string &name, Grid<Real> *grid);
-template void writeGridTxt<Vec3>(const string &name, Grid<Vec3> *grid);
-
-template void readGridRaw<int>(const string &name, Grid<int> *grid);
-template void readGridRaw<Real>(const string &name, Grid<Real> *grid);
-template void readGridRaw<Vec3>(const string &name, Grid<Vec3> *grid);
-template void readGridUni<int>(const string &name, Grid<int> *grid);
-template void readGridUni<Real>(const string &name, Grid<Real> *grid);
-template void readGridUni<Vec3>(const string &name, Grid<Vec3> *grid);
-template void readGridVol<int>(const string &name, Grid<int> *grid);
-template void readGridVol<Vec3>(const string &name, Grid<Vec3> *grid);
-
-template void readGrid4dUni<int>(
+template int writeGridRaw<int>(const string &name, Grid<int> *grid);
+template int writeGridRaw<Real>(const string &name, Grid<Real> *grid);
+template int writeGridRaw<Vec3>(const string &name, Grid<Vec3> *grid);
+template int writeGridUni<int>(const string &name, Grid<int> *grid);
+template int writeGridUni<Real>(const string &name, Grid<Real> *grid);
+template int writeGridUni<Vec3>(const string &name, Grid<Vec3> *grid);
+template int writeGridVol<int>(const string &name, Grid<int> *grid);
+template int writeGridVol<Vec3>(const string &name, Grid<Vec3> *grid);
+template int writeGridTxt<int>(const string &name, Grid<int> *grid);
+template int writeGridTxt<Real>(const string &name, Grid<Real> *grid);
+template int writeGridTxt<Vec3>(const string &name, Grid<Vec3> *grid);
+
+template int readGridRaw<int>(const string &name, Grid<int> *grid);
+template int readGridRaw<Real>(const string &name, Grid<Real> *grid);
+template int readGridRaw<Vec3>(const string &name, Grid<Vec3> *grid);
+template int readGridUni<int>(const string &name, Grid<int> *grid);
+template int readGridUni<Real>(const string &name, Grid<Real> *grid);
+template int readGridUni<Vec3>(const string &name, Grid<Vec3> *grid);
+template int readGridVol<int>(const string &name, Grid<int> *grid);
+template int readGridVol<Vec3>(const string &name, Grid<Vec3> *grid);
+
+template int readGrid4dUni<int>(
const string &name, Grid4d<int> *grid, int readTslice, Grid4d<int> *slice, void **fileHandle);
-template void readGrid4dUni<Real>(const string &name,
- Grid4d<Real> *grid,
- int readTslice,
- Grid4d<Real> *slice,
- void **fileHandle);
-template void readGrid4dUni<Vec3>(const string &name,
- Grid4d<Vec3> *grid,
- int readTslice,
- Grid4d<Vec3> *slice,
- void **fileHandle);
-template void readGrid4dUni<Vec4>(const string &name,
- Grid4d<Vec4> *grid,
- int readTslice,
- Grid4d<Vec4> *slice,
- void **fileHandle);
-template void writeGrid4dUni<int>(const string &name, Grid4d<int> *grid);
-template void writeGrid4dUni<Real>(const string &name, Grid4d<Real> *grid);
-template void writeGrid4dUni<Vec3>(const string &name, Grid4d<Vec3> *grid);
-template void writeGrid4dUni<Vec4>(const string &name, Grid4d<Vec4> *grid);
-
-template void readGrid4dRaw<int>(const string &name, Grid4d<int> *grid);
-template void readGrid4dRaw<Real>(const string &name, Grid4d<Real> *grid);
-template void readGrid4dRaw<Vec3>(const string &name, Grid4d<Vec3> *grid);
-template void readGrid4dRaw<Vec4>(const string &name, Grid4d<Vec4> *grid);
-template void writeGrid4dRaw<int>(const string &name, Grid4d<int> *grid);
-template void writeGrid4dRaw<Real>(const string &name, Grid4d<Real> *grid);
-template void writeGrid4dRaw<Vec3>(const string &name, Grid4d<Vec3> *grid);
-template void writeGrid4dRaw<Vec4>(const string &name, Grid4d<Vec4> *grid);
-
-template void writeGridNumpy<int>(const string &name, Grid<int> *grid);
-template void writeGridNumpy<Real>(const string &name, Grid<Real> *grid);
-template void writeGridNumpy<Vec3>(const string &name, Grid<Vec3> *grid);
-template void readGridNumpy<int>(const string &name, Grid<int> *grid);
-template void readGridNumpy<Real>(const string &name, Grid<Real> *grid);
-template void readGridNumpy<Vec3>(const string &name, Grid<Vec3> *grid);
-
-#if OPENVDB == 1
-template void writeGridVDB<int>(const string &name, Grid<int> *grid);
-template void writeGridVDB<Vec3>(const string &name, Grid<Vec3> *grid);
-template void writeGridVDB<Real>(const string &name, Grid<Real> *grid);
-
-template void readGridVDB<int>(const string &name, Grid<int> *grid);
-template void readGridVDB<Vec3>(const string &name, Grid<Vec3> *grid);
-template void readGridVDB<Real>(const string &name, Grid<Real> *grid);
-#endif // OPENVDB==1
+template int readGrid4dUni<Real>(const string &name,
+ Grid4d<Real> *grid,
+ int readTslice,
+ Grid4d<Real> *slice,
+ void **fileHandle);
+template int readGrid4dUni<Vec3>(const string &name,
+ Grid4d<Vec3> *grid,
+ int readTslice,
+ Grid4d<Vec3> *slice,
+ void **fileHandle);
+template int readGrid4dUni<Vec4>(const string &name,
+ Grid4d<Vec4> *grid,
+ int readTslice,
+ Grid4d<Vec4> *slice,
+ void **fileHandle);
+template int writeGrid4dUni<int>(const string &name, Grid4d<int> *grid);
+template int writeGrid4dUni<Real>(const string &name, Grid4d<Real> *grid);
+template int writeGrid4dUni<Vec3>(const string &name, Grid4d<Vec3> *grid);
+template int writeGrid4dUni<Vec4>(const string &name, Grid4d<Vec4> *grid);
+
+template int readGrid4dRaw<int>(const string &name, Grid4d<int> *grid);
+template int readGrid4dRaw<Real>(const string &name, Grid4d<Real> *grid);
+template int readGrid4dRaw<Vec3>(const string &name, Grid4d<Vec3> *grid);
+template int readGrid4dRaw<Vec4>(const string &name, Grid4d<Vec4> *grid);
+template int writeGrid4dRaw<int>(const string &name, Grid4d<int> *grid);
+template int writeGrid4dRaw<Real>(const string &name, Grid4d<Real> *grid);
+template int writeGrid4dRaw<Vec3>(const string &name, Grid4d<Vec3> *grid);
+template int writeGrid4dRaw<Vec4>(const string &name, Grid4d<Vec4> *grid);
+
+template int writeGridNumpy<int>(const string &name, Grid<int> *grid);
+template int writeGridNumpy<Real>(const string &name, Grid<Real> *grid);
+template int writeGridNumpy<Vec3>(const string &name, Grid<Vec3> *grid);
+template int readGridNumpy<int>(const string &name, Grid<int> *grid);
+template int readGridNumpy<Real>(const string &name, Grid<Real> *grid);
+template int readGridNumpy<Vec3>(const string &name, Grid<Vec3> *grid);
} // namespace Manta
-
-namespace Manta {
-
-}
diff --git a/extern/mantaflow/preprocessed/fileio/iomeshes.cpp b/extern/mantaflow/preprocessed/fileio/iomeshes.cpp
index 906b849fffb..1c50376de77 100644
--- a/extern/mantaflow/preprocessed/fileio/iomeshes.cpp
+++ b/extern/mantaflow/preprocessed/fileio/iomeshes.cpp
@@ -146,21 +146,25 @@ void mdataReadConvert<Vec3>(gzFile &gzf, MeshDataImpl<Vec3> &mdata, void *ptr, i
// mesh data
//*****************************************************************************
-void readBobjFile(const string &name, Mesh *mesh, bool append)
+int readBobjFile(const string &name, Mesh *mesh, bool append)
{
debMsg("reading mesh file " << name, 1);
if (!append)
mesh->clear();
- else
+ else {
errMsg("readBobj: append not yet implemented!");
+ return 0;
+ }
#if NO_ZLIB != 1
const Real dx = mesh->getParent()->getDx();
const Vec3 gs = toVec3(mesh->getParent()->getGridSize());
gzFile gzf = (gzFile)safeGzopen(name.c_str(), "rb1"); // do some compression
- if (!gzf)
+ if (!gzf) {
errMsg("readBobj: unable to open file");
+ return 0;
+ }
// read vertices
int num = 0;
@@ -198,15 +202,16 @@ void readBobjFile(const string &name, Mesh *mesh, bool append)
}
}
// note - vortex sheet info ignored for now... (see writeBobj)
- gzclose(gzf);
debMsg("read mesh , triangles " << mesh->numTris() << ", vertices " << mesh->numNodes() << " ",
1);
+ return (gzclose(gzf) == Z_OK);
#else
debMsg("file format not supported without zlib", 1);
+ return 0;
#endif
}
-void writeBobjFile(const string &name, Mesh *mesh)
+int writeBobjFile(const string &name, Mesh *mesh)
{
debMsg("writing mesh file " << name, 1);
#if NO_ZLIB != 1
@@ -214,8 +219,10 @@ void writeBobjFile(const string &name, Mesh *mesh)
const Vec3i gs = mesh->getParent()->getGridSize();
gzFile gzf = (gzFile)safeGzopen(name.c_str(), "wb1"); // do some compression
- if (!gzf)
+ if (!gzf) {
errMsg("writeBobj: unable to open file");
+ return 0;
+ }
// write vertices
int numVerts = mesh->numNodes();
@@ -292,18 +299,21 @@ void writeBobjFile(const string &name, Mesh *mesh)
}
}
- gzclose(gzf);
+ return (gzclose(gzf) == Z_OK);
#else
debMsg("file format not supported without zlib", 1);
+ return 0;
#endif
}
-void readObjFile(const std::string &name, Mesh *mesh, bool append)
+int readObjFile(const std::string &name, Mesh *mesh, bool append)
{
ifstream ifs(name.c_str());
- if (!ifs.good())
+ if (!ifs.good()) {
errMsg("can't open file '" + name + "'");
+ return 0;
+ }
if (!append)
mesh->clear();
@@ -323,8 +333,10 @@ void readObjFile(const std::string &name, Mesh *mesh, bool append)
}
else if (id == "vn") {
// normals
- if (!mesh->numNodes())
+ if (!mesh->numNodes()) {
errMsg("invalid amount of nodes");
+ return 0;
+ }
Node n = mesh->nodes(cnt);
ifs >> n.normal.x >> n.normal.y >> n.normal.z;
cnt++;
@@ -349,8 +361,10 @@ void readObjFile(const std::string &name, Mesh *mesh, bool append)
if (face.find('/') != string::npos)
face = face.substr(0, face.find('/')); // ignore other indices
int idx = atoi(face.c_str()) - 1;
- if (idx < 0)
+ if (idx < 0) {
errMsg("invalid face encountered");
+ return 0;
+ }
idx += nodebase;
t.c[i] = idx;
}
@@ -363,17 +377,20 @@ void readObjFile(const std::string &name, Mesh *mesh, bool append)
getline(ifs, id);
}
ifs.close();
+ return 1;
}
// write regular .obj file, in line with bobj.gz output (but only verts & tris for now)
-void writeObjFile(const string &name, Mesh *mesh)
+int writeObjFile(const string &name, Mesh *mesh)
{
const Real dx = mesh->getParent()->getDx();
const Vec3i gs = mesh->getParent()->getGridSize();
ofstream ofs(name.c_str());
- if (!ofs.good())
+ if (!ofs.good()) {
errMsg("writeObjFile: can't open file " << name);
+ return 0;
+ }
ofs << "o MantaMesh\n";
@@ -405,16 +422,19 @@ void writeObjFile(const string &name, Mesh *mesh)
}
ofs.close();
+ return 1;
}
-template<class T> void readMdataUni(const std::string &name, MeshDataImpl<T> *mdata)
+template<class T> int readMdataUni(const std::string &name, MeshDataImpl<T> *mdata)
{
debMsg("reading mesh data " << mdata->getName() << " from uni file " << name, 1);
#if NO_ZLIB != 1
gzFile gzf = (gzFile)safeGzopen(name.c_str(), "rb");
- if (!gzf)
+ if (!gzf) {
errMsg("can't open file " << name);
+ return 0;
+ }
char ID[5] = {0, 0, 0, 0, 0};
gzread(gzf, ID, 4);
@@ -440,13 +460,14 @@ template<class T> void readMdataUni(const std::string &name, MeshDataImpl<T> *md
<< readBytes);
# endif
}
- gzclose(gzf);
+ return (gzclose(gzf) == Z_OK);
#else
debMsg("file format not supported without zlib", 1);
+ return 0;
#endif
}
-template<class T> void writeMdataUni(const std::string &name, MeshDataImpl<T> *mdata)
+template<class T> int writeMdataUni(const std::string &name, MeshDataImpl<T> *mdata)
{
debMsg("writing mesh data " << mdata->getName() << " to uni file " << name, 1);
@@ -461,8 +482,10 @@ template<class T> void writeMdataUni(const std::string &name, MeshDataImpl<T> *m
head.timestamp = stamp.time;
gzFile gzf = (gzFile)safeGzopen(name.c_str(), "wb1"); // do some compression
- if (!gzf)
+ if (!gzf) {
errMsg("can't open file " << name);
+ return 0;
+ }
gzwrite(gzf, ID, 4);
# if FLOATINGPOINT_PRECISION != 1
@@ -474,19 +497,20 @@ template<class T> void writeMdataUni(const std::string &name, MeshDataImpl<T> *m
gzwrite(gzf, &head, sizeof(UniMeshHeader));
gzwrite(gzf, &(mdata->get(0)), sizeof(T) * head.dim);
# endif
- gzclose(gzf);
+ return (gzclose(gzf) == Z_OK);
#else
debMsg("file format not supported without zlib", 1);
+ return 0;
#endif
};
// explicit instantiation
-template void writeMdataUni<int>(const std::string &name, MeshDataImpl<int> *mdata);
-template void writeMdataUni<Real>(const std::string &name, MeshDataImpl<Real> *mdata);
-template void writeMdataUni<Vec3>(const std::string &name, MeshDataImpl<Vec3> *mdata);
-template void readMdataUni<int>(const std::string &name, MeshDataImpl<int> *mdata);
-template void readMdataUni<Real>(const std::string &name, MeshDataImpl<Real> *mdata);
-template void readMdataUni<Vec3>(const std::string &name, MeshDataImpl<Vec3> *mdata);
+template int writeMdataUni<int>(const std::string &name, MeshDataImpl<int> *mdata);
+template int writeMdataUni<Real>(const std::string &name, MeshDataImpl<Real> *mdata);
+template int writeMdataUni<Vec3>(const std::string &name, MeshDataImpl<Vec3> *mdata);
+template int readMdataUni<int>(const std::string &name, MeshDataImpl<int> *mdata);
+template int readMdataUni<Real>(const std::string &name, MeshDataImpl<Real> *mdata);
+template int readMdataUni<Vec3>(const std::string &name, MeshDataImpl<Vec3> *mdata);
} // namespace Manta
diff --git a/extern/mantaflow/preprocessed/fileio/ioparticles.cpp b/extern/mantaflow/preprocessed/fileio/ioparticles.cpp
index 2eab485beb3..84283a25b07 100644
--- a/extern/mantaflow/preprocessed/fileio/ioparticles.cpp
+++ b/extern/mantaflow/preprocessed/fileio/ioparticles.cpp
@@ -158,7 +158,7 @@ void pdataReadConvert<Vec3>(gzFile &gzf,
static const int PartSysSize = sizeof(Vector3D<float>) + sizeof(int);
-void writeParticlesUni(const std::string &name, const BasicParticleSystem *parts)
+int writeParticlesUni(const std::string &name, const BasicParticleSystem *parts)
{
debMsg("writing particles " << parts->getName() << " to uni file " << name, 1);
@@ -177,8 +177,10 @@ void writeParticlesUni(const std::string &name, const BasicParticleSystem *parts
head.timestamp = stamp.time;
gzFile gzf = (gzFile)safeGzopen(name.c_str(), "wb1"); // do some compression
- if (!gzf)
+ if (!gzf) {
errMsg("can't open file " << name);
+ return 0;
+ }
gzwrite(gzf, ID, 4);
# if FLOATINGPOINT_PRECISION != 1
@@ -195,26 +197,30 @@ void writeParticlesUni(const std::string &name, const BasicParticleSystem *parts
gzwrite(gzf, &head, sizeof(UniPartHeader));
gzwrite(gzf, &((*parts)[0]), PartSysSize * head.dim);
# endif
- gzclose(gzf);
+ return (gzclose(gzf) == Z_OK);
#else
debMsg("file format not supported without zlib", 1);
+ return 0;
#endif
};
-void readParticlesUni(const std::string &name, BasicParticleSystem *parts)
+int readParticlesUni(const std::string &name, BasicParticleSystem *parts)
{
debMsg("reading particles " << parts->getName() << " from uni file " << name, 1);
#if NO_ZLIB != 1
gzFile gzf = (gzFile)safeGzopen(name.c_str(), "rb");
- if (!gzf)
+ if (!gzf) {
errMsg("can't open file " << name);
+ return 0;
+ }
char ID[5] = {0, 0, 0, 0, 0};
gzread(gzf, ID, 4);
if (!strcmp(ID, "PB01")) {
errMsg("particle uni file format v01 not supported anymore");
+ return 0;
}
else if (!strcmp(ID, "PB02")) {
// current file format
@@ -249,13 +255,14 @@ void readParticlesUni(const std::string &name, BasicParticleSystem *parts)
parts->transformPositions(Vec3i(head.dimX, head.dimY, head.dimZ),
parts->getParent()->getGridSize());
}
- gzclose(gzf);
+ return (gzclose(gzf) == Z_OK);
#else
debMsg("file format not supported without zlib", 1);
+ return 0;
#endif
};
-template<class T> void writePdataUni(const std::string &name, ParticleDataImpl<T> *pdata)
+template<class T> int writePdataUni(const std::string &name, ParticleDataImpl<T> *pdata)
{
debMsg("writing particle data " << pdata->getName() << " to uni file " << name, 1);
@@ -274,8 +281,10 @@ template<class T> void writePdataUni(const std::string &name, ParticleDataImpl<T
head.timestamp = stamp.time;
gzFile gzf = (gzFile)safeGzopen(name.c_str(), "wb1"); // do some compression
- if (!gzf)
+ if (!gzf) {
errMsg("can't open file " << name);
+ return 0;
+ }
gzwrite(gzf, ID, 4);
# if FLOATINGPOINT_PRECISION != 1
@@ -287,21 +296,24 @@ template<class T> void writePdataUni(const std::string &name, ParticleDataImpl<T
gzwrite(gzf, &head, sizeof(UniPartHeader));
gzwrite(gzf, &(pdata->get(0)), sizeof(T) * head.dim);
# endif
- gzclose(gzf);
+ return (gzclose(gzf) == Z_OK);
#else
debMsg("file format not supported without zlib", 1);
+ return 0;
#endif
};
-template<class T> void readPdataUni(const std::string &name, ParticleDataImpl<T> *pdata)
+template<class T> int readPdataUni(const std::string &name, ParticleDataImpl<T> *pdata)
{
debMsg("reading particle data " << pdata->getName() << " from uni file " << name, 1);
#if NO_ZLIB != 1
gzFile gzf = (gzFile)safeGzopen(name.c_str(), "rb");
- if (!gzf)
+ if (!gzf) {
errMsg("can't open file " << name);
+ return 0;
+ }
char ID[5] = {0, 0, 0, 0, 0};
gzread(gzf, ID, 4);
@@ -327,18 +339,19 @@ template<class T> void readPdataUni(const std::string &name, ParticleDataImpl<T>
<< readBytes);
# endif
}
- gzclose(gzf);
+ return (gzclose(gzf) == Z_OK);
#else
debMsg("file format not supported without zlib", 1);
+ return 0;
#endif
}
// explicit instantiation
-template void writePdataUni<int>(const std::string &name, ParticleDataImpl<int> *pdata);
-template void writePdataUni<Real>(const std::string &name, ParticleDataImpl<Real> *pdata);
-template void writePdataUni<Vec3>(const std::string &name, ParticleDataImpl<Vec3> *pdata);
-template void readPdataUni<int>(const std::string &name, ParticleDataImpl<int> *pdata);
-template void readPdataUni<Real>(const std::string &name, ParticleDataImpl<Real> *pdata);
-template void readPdataUni<Vec3>(const std::string &name, ParticleDataImpl<Vec3> *pdata);
+template int writePdataUni<int>(const std::string &name, ParticleDataImpl<int> *pdata);
+template int writePdataUni<Real>(const std::string &name, ParticleDataImpl<Real> *pdata);
+template int writePdataUni<Vec3>(const std::string &name, ParticleDataImpl<Vec3> *pdata);
+template int readPdataUni<int>(const std::string &name, ParticleDataImpl<int> *pdata);
+template int readPdataUni<Real>(const std::string &name, ParticleDataImpl<Real> *pdata);
+template int readPdataUni<Vec3>(const std::string &name, ParticleDataImpl<Vec3> *pdata);
} // namespace Manta
diff --git a/extern/mantaflow/preprocessed/fileio/ioutil.cpp b/extern/mantaflow/preprocessed/fileio/ioutil.cpp
index e04633c5634..cc63cf87ac1 100644
--- a/extern/mantaflow/preprocessed/fileio/ioutil.cpp
+++ b/extern/mantaflow/preprocessed/fileio/ioutil.cpp
@@ -18,6 +18,10 @@
#include "mantaio.h"
+#if OPENVDB == 1
+# include "openvdb/openvdb.h"
+#endif
+
#if NO_ZLIB != 1
extern "C" {
# include <zlib.h>
@@ -40,7 +44,7 @@ static wstring stringToWstring(const char *str)
MultiByteToWideChar(CP_UTF8, 0, str, strlen(str), &strWide[0], length_wc);
return strWide;
}
-# endif
+# endif // WIN32==1
void *safeGzopen(const char *filename, const char *mode)
{
@@ -55,6 +59,54 @@ void *safeGzopen(const char *filename, const char *mode)
return gzfile;
}
-#endif
+#endif // NO_ZLIB != 1
+
+#if defined(OPENVDB)
+// Convert from OpenVDB value to Manta value.
+template<class S, class T> void convertFrom(S &in, T *out)
+{
+ errMsg("OpenVDB convertFrom Warning: Unsupported type conversion");
+}
+
+template<> void convertFrom(int &in, int *out)
+{
+ (*out) = in;
+}
+
+template<> void convertFrom(float &in, Real *out)
+{
+ (*out) = (Real)in;
+}
+
+template<> void convertFrom(openvdb::Vec3s &in, Vec3 *out)
+{
+ (*out).x = in.x();
+ (*out).y = in.y();
+ (*out).z = in.z();
+}
+
+// Convert to OpenVDB value from Manta value.
+template<class S, class T> void convertTo(S *out, T &in)
+{
+ errMsg("OpenVDB convertTo Warning: Unsupported type conversion");
+}
+
+template<> void convertTo(int *out, int &in)
+{
+ (*out) = in;
+}
+
+template<> void convertTo(float *out, Real &in)
+{
+ (*out) = (float)in;
+}
+
+template<> void convertTo(openvdb::Vec3s *out, Vec3 &in)
+{
+ (*out).x() = in.x;
+ (*out).y() = in.y;
+ (*out).z() = in.z;
+}
+#endif // OPENVDB==1
} // namespace
diff --git a/extern/mantaflow/preprocessed/fileio/iovdb.cpp b/extern/mantaflow/preprocessed/fileio/iovdb.cpp
new file mode 100644
index 00000000000..b31f7e0e760
--- /dev/null
+++ b/extern/mantaflow/preprocessed/fileio/iovdb.cpp
@@ -0,0 +1,618 @@
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2020 Sebastian Barschkis, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Loading and writing grids and particles from and to OpenVDB files.
+ *
+ ******************************************************************************/
+
+#include <iostream>
+#include <fstream>
+#include <cstdlib>
+#include <cstring>
+
+#include "mantaio.h"
+#include "grid.h"
+#include "vector4d.h"
+#include "grid4d.h"
+#include "particle.h"
+
+#if OPENVDB == 1
+# include "openvdb/openvdb.h"
+# include <openvdb/points/PointConversion.h>
+# include <openvdb/points/PointCount.h>
+#endif
+
+#define POSITION_NAME "P"
+#define FLAG_NAME "U"
+
+using namespace std;
+
+namespace Manta {
+
+#if OPENVDB == 1
+
+template<class GridType, class T> void importVDB(typename GridType::Ptr from, Grid<T> *to)
+{
+ using ValueT = typename GridType::ValueType;
+ typename GridType::Accessor accessor = from->getAccessor();
+
+ FOR_IJK(*to)
+ {
+ openvdb::Coord xyz(i, j, k);
+ ValueT vdbValue = accessor.getValue(xyz);
+ T toMantaValue;
+ convertFrom(vdbValue, &toMantaValue);
+ to->set(i, j, k, toMantaValue);
+ }
+}
+
+template<class VDBType, class T>
+void importVDB(VDBType vdbValue, ParticleDataImpl<T> *to, int index, float voxelSize)
+{
+ (void)voxelSize; // Unused
+ T toMantaValue;
+ convertFrom(vdbValue, &toMantaValue);
+ to->set(index, toMantaValue);
+}
+
+void importVDB(openvdb::points::PointDataGrid::Ptr from,
+ BasicParticleSystem *to,
+ std::vector<ParticleDataBase *> &toPData,
+ float voxelSize)
+{
+ openvdb::Index64 count = openvdb::points::pointCount(from->tree());
+ to->resizeAll(count);
+
+ int cnt = 0;
+ for (auto leafIter = from->tree().cbeginLeaf(); leafIter; ++leafIter) {
+ const openvdb::points::AttributeArray &positionArray = leafIter->constAttributeArray(
+ POSITION_NAME);
+ const openvdb::points::AttributeArray &flagArray = leafIter->constAttributeArray(FLAG_NAME);
+
+ openvdb::points::AttributeHandle<openvdb::Vec3s> positionHandle(positionArray);
+ openvdb::points::AttributeHandle<int> flagHandle(flagArray);
+
+ // Get vdb handles to pdata objects in pdata list
+ std::vector<std::tuple<int, openvdb::points::AttributeHandle<int>>> pDataHandlesInt;
+ std::vector<std::tuple<int, openvdb::points::AttributeHandle<float>>> pDataHandlesReal;
+ std::vector<std::tuple<int, openvdb::points::AttributeHandle<openvdb::Vec3s>>>
+ pDataHandlesVec3;
+
+ int pDataIndex = 0;
+ for (ParticleDataBase *pdb : toPData) {
+ std::string name = pdb->getName();
+ const openvdb::points::AttributeArray &pDataArray = leafIter->constAttributeArray(name);
+
+ if (pdb->getType() == ParticleDataBase::TypeInt) {
+ openvdb::points::AttributeHandle<int> intHandle(pDataArray);
+ std::tuple<int, openvdb::points::AttributeHandle<int>> tuple = std::make_tuple(pDataIndex,
+ intHandle);
+ pDataHandlesInt.push_back(tuple);
+ }
+ else if (pdb->getType() == ParticleDataBase::TypeReal) {
+ openvdb::points::AttributeHandle<float> floatHandle(pDataArray);
+ std::tuple<int, openvdb::points::AttributeHandle<float>> tuple = std::make_tuple(
+ pDataIndex, floatHandle);
+ pDataHandlesReal.push_back(tuple);
+ }
+ else if (pdb->getType() == ParticleDataBase::TypeVec3) {
+ openvdb::points::AttributeHandle<openvdb::Vec3s> vec3Handle(pDataArray);
+ std::tuple<int, openvdb::points::AttributeHandle<openvdb::Vec3s>> tuple = std::make_tuple(
+ pDataIndex, vec3Handle);
+ pDataHandlesVec3.push_back(tuple);
+ }
+ else {
+ errMsg("importVDB: unknown ParticleDataBase type");
+ }
+ ++pDataIndex;
+ }
+
+ for (auto indexIter = leafIter->beginIndexOn(); indexIter; ++indexIter) {
+ // Extract the voxel-space position of the point (always between (-0.5, -0.5, -0.5) and (0.5,
+ // 0.5, 0.5)).
+ openvdb::Vec3s voxelPosition = positionHandle.get(*indexIter);
+ const openvdb::Vec3d xyz = indexIter.getCoord().asVec3d();
+ // Compute the world-space position of the point.
+ openvdb::Vec3f worldPosition = from->transform().indexToWorld(voxelPosition + xyz);
+ int flag = flagHandle.get(*indexIter);
+
+ Vec3 toMantaValue;
+ convertFrom(worldPosition, &toMantaValue);
+ (*to)[cnt].pos = toMantaValue;
+ (*to)[cnt].pos /= voxelSize; // convert from world space to grid space
+ (*to)[cnt].flag = flag;
+
+ for (std::tuple<int, openvdb::points::AttributeHandle<int>> tuple : pDataHandlesInt) {
+ int pDataIndex = std::get<0>(tuple);
+ int vdbValue = std::get<1>(tuple).get(*indexIter);
+
+ ParticleDataImpl<int> *pdi = dynamic_cast<ParticleDataImpl<int> *>(toPData[pDataIndex]);
+ importVDB<int, int>(vdbValue, pdi, cnt, voxelSize);
+ }
+ for (std::tuple<int, openvdb::points::AttributeHandle<float>> tuple : pDataHandlesReal) {
+ int pDataIndex = std::get<0>(tuple);
+ float vdbValue = std::get<1>(tuple).get(*indexIter);
+
+ ParticleDataImpl<Real> *pdi = dynamic_cast<ParticleDataImpl<Real> *>(toPData[pDataIndex]);
+ importVDB<float, Real>(vdbValue, pdi, cnt, voxelSize);
+ }
+ for (std::tuple<int, openvdb::points::AttributeHandle<openvdb::Vec3s>> tuple :
+ pDataHandlesVec3) {
+ int pDataIndex = std::get<0>(tuple);
+ openvdb::Vec3f voxelPosition = std::get<1>(tuple).get(*indexIter);
+
+ ParticleDataImpl<Vec3> *pdi = dynamic_cast<ParticleDataImpl<Vec3> *>(toPData[pDataIndex]);
+ importVDB<openvdb::Vec3s, Vec3>(voxelPosition, pdi, cnt, voxelSize);
+ }
+ ++cnt;
+ }
+ }
+}
+
+template<class GridType>
+static void setGridOptions(typename GridType::Ptr grid,
+ string name,
+ openvdb::GridClass cls,
+ float voxelSize,
+ bool precisionHalf)
+{
+ grid->setTransform(openvdb::math::Transform::createLinearTransform(voxelSize));
+ grid->setGridClass(cls);
+ grid->setName(name);
+ grid->setSaveFloatAsHalf(precisionHalf);
+}
+
+template<class T, class GridType> typename GridType::Ptr exportVDB(Grid<T> *from)
+{
+ using ValueT = typename GridType::ValueType;
+ typename GridType::Ptr to = GridType::create();
+ typename GridType::Accessor accessor = to->getAccessor();
+
+ FOR_IJK(*from)
+ {
+ openvdb::Coord xyz(i, j, k);
+ T fromMantaValue = (*from)(i, j, k);
+ ValueT vdbValue;
+ convertTo(&vdbValue, fromMantaValue);
+ accessor.setValue(xyz, vdbValue);
+ }
+ return to;
+}
+
+template<class MantaType, class VDBType>
+void exportVDB(ParticleDataImpl<MantaType> *from,
+ openvdb::points::PointDataGrid::Ptr to,
+ openvdb::tools::PointIndexGrid::Ptr pIndex,
+ bool skipDeletedParts)
+{
+ std::vector<VDBType> vdbValues;
+ std::string name = from->getName();
+
+ FOR_PARTS(*from)
+ {
+ // Optionally, skip exporting particles that have been marked as deleted
+ BasicParticleSystem *pp = dynamic_cast<BasicParticleSystem *>(from->getParticleSys());
+ if (skipDeletedParts && !pp->isActive(idx)) {
+ continue;
+ }
+ MantaType fromMantaValue = (*from)[idx];
+ VDBType vdbValue;
+ convertTo(&vdbValue, fromMantaValue);
+ vdbValues.push_back(vdbValue);
+ }
+
+ openvdb::NamePair attribute =
+ openvdb::points::TypedAttributeArray<VDBType, openvdb::points::NullCodec>::attributeType();
+ openvdb::points::appendAttribute(to->tree(), name, attribute);
+
+ // Create a wrapper around the vdb values vector.
+ const openvdb::points::PointAttributeVector<VDBType> wrapper(vdbValues);
+
+ // Populate the attribute on the points
+ openvdb::points::populateAttribute<openvdb::points::PointDataTree,
+ openvdb::tools::PointIndexTree,
+ openvdb::points::PointAttributeVector<VDBType>>(
+ to->tree(), pIndex->tree(), name, wrapper);
+}
+
+openvdb::points::PointDataGrid::Ptr exportVDB(BasicParticleSystem *from,
+ std::vector<ParticleDataBase *> &fromPData,
+ bool skipDeletedParts,
+ float voxelSize)
+{
+ std::vector<openvdb::Vec3s> positions;
+ std::vector<int> flags;
+
+ FOR_PARTS(*from)
+ {
+ // Optionally, skip exporting particles that have been marked as deleted
+ if (skipDeletedParts && !from->isActive(idx)) {
+ continue;
+ }
+ Vector3D<float> pos = toVec3f((*from)[idx].pos);
+ pos *= voxelSize; // convert from grid space to world space
+ openvdb::Vec3s posVDB(pos.x, pos.y, pos.z);
+ positions.push_back(posVDB);
+
+ int flag = (*from)[idx].flag;
+ flags.push_back(flag);
+ }
+
+ const openvdb::points::PointAttributeVector<openvdb::Vec3s> positionsWrapper(positions);
+ openvdb::math::Transform::Ptr transform = openvdb::math::Transform::createLinearTransform(
+ voxelSize);
+
+ openvdb::tools::PointIndexGrid::Ptr pointIndexGrid =
+ openvdb::tools::createPointIndexGrid<openvdb::tools::PointIndexGrid>(positionsWrapper,
+ *transform);
+
+ // TODO (sebbas): Use custom codec for attributes?
+ // using Codec = openvdb::points::FixedPointCodec</*1-byte=*/false, openvdb::points::UnitRange>;
+ openvdb::points::PointDataGrid::Ptr to =
+ openvdb::points::createPointDataGrid<openvdb::points::NullCodec /*Codec*/,
+ openvdb::points::PointDataGrid>(
+ *pointIndexGrid, positionsWrapper, *transform);
+
+ openvdb::NamePair flagAttribute =
+ openvdb::points::TypedAttributeArray<int,
+ openvdb::points::NullCodec /*Codec*/>::attributeType();
+ openvdb::points::appendAttribute(to->tree(), FLAG_NAME, flagAttribute);
+ // Create a wrapper around the flag vector.
+ openvdb::points::PointAttributeVector<int> flagWrapper(flags);
+ // Populate the "flag" attribute on the points
+ openvdb::points::populateAttribute<openvdb::points::PointDataTree,
+ openvdb::tools::PointIndexTree,
+ openvdb::points::PointAttributeVector<int>>(
+ to->tree(), pointIndexGrid->tree(), FLAG_NAME, flagWrapper);
+
+ // Add all already buffered pdata to this particle grid
+ for (ParticleDataBase *pdb : fromPData) {
+ if (pdb->getType() == ParticleDataBase::TypeInt) {
+ debMsg("Writing int particle data '" << pdb->getName() << "'", 1);
+ ParticleDataImpl<int> *pdi = dynamic_cast<ParticleDataImpl<int> *>(pdb);
+ exportVDB<int, int>(pdi, to, pointIndexGrid, skipDeletedParts);
+ }
+ else if (pdb->getType() == ParticleDataBase::TypeReal) {
+ debMsg("Writing real particle data '" << pdb->getName() << "'", 1);
+ ParticleDataImpl<Real> *pdi = dynamic_cast<ParticleDataImpl<Real> *>(pdb);
+ exportVDB<Real, float>(pdi, to, pointIndexGrid, skipDeletedParts);
+ }
+ else if (pdb->getType() == ParticleDataBase::TypeVec3) {
+ debMsg("Writing Vec3 particle data '" << pdb->getName() << "'", 1);
+ ParticleDataImpl<Vec3> *pdi = dynamic_cast<ParticleDataImpl<Vec3> *>(pdb);
+ exportVDB<Vec3, openvdb::Vec3s>(pdi, to, pointIndexGrid, skipDeletedParts);
+ }
+ else {
+ errMsg("exportVDB: unknown ParticleDataBase type");
+ }
+ }
+ return to;
+}
+
+static void registerCustomCodecs()
+{
+ using Codec = openvdb::points::FixedPointCodec</*1-byte=*/false, openvdb::points::UnitRange>;
+ openvdb::points::TypedAttributeArray<int, Codec>::registerType();
+}
+
+int writeObjectsVDB(const string &filename,
+ std::vector<PbClass *> *objects,
+ float worldSize,
+ bool skipDeletedParts,
+ int compression,
+ bool precisionHalf)
+{
+ openvdb::initialize();
+ openvdb::io::File file(filename);
+ openvdb::GridPtrVec gridsVDB;
+
+ // TODO (sebbas): Use custom codec for flag attribute?
+ // Register codecs one, this makes sure custom attributes can be read
+ // registerCustomCodecs();
+
+ std::vector<ParticleDataBase *> pdbBuffer;
+
+ for (std::vector<PbClass *>::iterator iter = objects->begin(); iter != objects->end(); ++iter) {
+ openvdb::GridClass gClass = openvdb::GRID_UNKNOWN;
+ openvdb::GridBase::Ptr vdbGrid;
+
+ PbClass *object = dynamic_cast<PbClass *>(*iter);
+ const Real dx = object->getParent()->getDx();
+ const Real voxelSize = worldSize * dx;
+ const string objectName = object->getName();
+
+ if (GridBase *mantaGrid = dynamic_cast<GridBase *>(*iter)) {
+
+ if (mantaGrid->getType() & GridBase::TypeInt) {
+ debMsg("Writing int grid '" << mantaGrid->getName() << "' to vdb file " << filename, 1);
+ Grid<int> *mantaIntGrid = (Grid<int> *)mantaGrid;
+ vdbGrid = exportVDB<int, openvdb::Int32Grid>(mantaIntGrid);
+ gridsVDB.push_back(vdbGrid);
+ }
+ else if (mantaGrid->getType() & GridBase::TypeReal) {
+ debMsg("Writing real grid '" << mantaGrid->getName() << "' to vdb file " << filename, 1);
+ gClass = (mantaGrid->getType() & GridBase::TypeLevelset) ? openvdb::GRID_LEVEL_SET :
+ openvdb::GRID_FOG_VOLUME;
+ Grid<Real> *mantaRealGrid = (Grid<Real> *)mantaGrid;
+ vdbGrid = exportVDB<Real, openvdb::FloatGrid>(mantaRealGrid);
+ gridsVDB.push_back(vdbGrid);
+ }
+ else if (mantaGrid->getType() & GridBase::TypeVec3) {
+ debMsg("Writing vec3 grid '" << mantaGrid->getName() << "' to vdb file " << filename, 1);
+ gClass = (mantaGrid->getType() & GridBase::TypeMAC) ? openvdb::GRID_STAGGERED :
+ openvdb::GRID_UNKNOWN;
+ Grid<Vec3> *mantaVec3Grid = (Grid<Vec3> *)mantaGrid;
+ vdbGrid = exportVDB<Vec3, openvdb::Vec3SGrid>(mantaVec3Grid);
+ gridsVDB.push_back(vdbGrid);
+ }
+ else {
+ errMsg("writeObjectsVDB: unknown grid type");
+ return 0;
+ }
+ }
+ else if (BasicParticleSystem *mantaPP = dynamic_cast<BasicParticleSystem *>(*iter)) {
+ debMsg("Writing particle system '" << mantaPP->getName()
+ << "' (and buffered pData) to vdb file " << filename,
+ 1);
+ vdbGrid = exportVDB(mantaPP, pdbBuffer, skipDeletedParts, voxelSize);
+ gridsVDB.push_back(vdbGrid);
+ pdbBuffer.clear();
+ }
+ // Particle data will only be saved if there is a particle system too.
+ else if (ParticleDataBase *mantaPPImpl = dynamic_cast<ParticleDataBase *>(*iter)) {
+ debMsg("Buffering particle data '" << mantaPPImpl->getName() << "' to vdb file " << filename,
+ 1);
+ pdbBuffer.push_back(mantaPPImpl);
+ }
+ else {
+ errMsg("writeObjectsVDB: Unsupported Python object. Cannot write to .vdb file " << filename);
+ return 0;
+ }
+
+ // Set additional grid attributes, e.g. name, grid class, compression level, etc.
+ if (vdbGrid) {
+ setGridOptions<openvdb::GridBase>(vdbGrid, objectName, gClass, voxelSize, precisionHalf);
+ }
+ }
+
+ // Give out a warning if pData items were present but could not be saved due to missing particle
+ // system.
+ if (!pdbBuffer.empty()) {
+ for (ParticleDataBase *pdb : pdbBuffer) {
+ debMsg("writeObjectsVDB Warning: Particle data '"
+ << pdb->getName()
+ << "' has not been saved. It's parent particle system was needs to be given too.",
+ 1);
+ }
+ }
+
+ // Write only if the is at least one grid, optionally write with compression.
+ if (gridsVDB.size()) {
+ int vdb_flags = openvdb::io::COMPRESS_ACTIVE_MASK;
+ switch (compression) {
+ case COMPRESSION_NONE: {
+ vdb_flags = openvdb::io::COMPRESS_NONE;
+ break;
+ }
+ case COMPRESSION_ZIP: {
+ vdb_flags |= openvdb::io::COMPRESS_ZIP;
+ break;
+ }
+ case COMPRESSION_BLOSC: {
+# if OPENVDB_BLOSC == 1
+ vdb_flags |= openvdb::io::COMPRESS_BLOSC;
+# else
+ debMsg("OpenVDB was built without Blosc support, using Zip compression instead", 1);
+ vdb_flags |= openvdb::io::COMPRESS_ZIP;
+# endif // OPENVDB_BLOSC==1
+ break;
+ }
+ }
+ file.setCompression(vdb_flags);
+ file.write(gridsVDB);
+ }
+ file.close();
+ return 1;
+}
+
+int readObjectsVDB(const string &filename, std::vector<PbClass *> *objects, float worldSize)
+{
+
+ openvdb::initialize();
+ openvdb::io::File file(filename);
+ openvdb::GridPtrVec gridsVDB;
+
+ // TODO (sebbas): Use custom codec for flag attribute?
+ // Register codecs one, this makes sure custom attributes can be read
+ // registerCustomCodecs();
+
+ try {
+ file.setCopyMaxBytes(0);
+ file.open();
+ gridsVDB = *(file.getGrids());
+ openvdb::MetaMap::Ptr metadata = file.getMetadata();
+ (void)metadata; // Unused for now
+ }
+ catch (const openvdb::IoError &e) {
+ debMsg("readObjectsVDB: Could not open vdb file " << filename, 1);
+ file.close();
+ return 0;
+ }
+ file.close();
+
+ // A buffer to store a handle to pData objects. These will be read alongside a particle system.
+ std::vector<ParticleDataBase *> pdbBuffer;
+
+ for (std::vector<PbClass *>::iterator iter = objects->begin(); iter != objects->end(); ++iter) {
+
+ if (gridsVDB.empty()) {
+ debMsg("readObjectsVDB: No vdb grids in file " << filename, 1);
+ }
+ // If there is just one grid in this file, load it regardless of name match (to vdb caches per
+ // grid).
+ bool onlyGrid = (gridsVDB.size() == 1);
+
+ PbClass *object = dynamic_cast<PbClass *>(*iter);
+ const Real dx = object->getParent()->getDx();
+ const Real voxelSize = worldSize * dx;
+
+ // Particle data objects are treated separately - buffered and inserted when reading the
+ // particle system
+ if (ParticleDataBase *mantaPPImpl = dynamic_cast<ParticleDataBase *>(*iter)) {
+ debMsg("Buffering particle data '" << mantaPPImpl->getName() << "' from vdb file "
+ << filename,
+ 1);
+ pdbBuffer.push_back(mantaPPImpl);
+ continue;
+ }
+
+ // For every manta object, we loop through the vdb grid list and check for a match
+ for (const openvdb::GridBase::Ptr &vdbGrid : gridsVDB) {
+ bool nameMatch = (vdbGrid->getName() == (*iter)->getName());
+
+ // Sanity checks: Only load valid grids and make sure names match.
+ if (!vdbGrid) {
+ debMsg("Skipping invalid vdb grid '" << vdbGrid->getName() << "' in file " << filename, 1);
+ continue;
+ }
+ if (!nameMatch && !onlyGrid) {
+ continue;
+ }
+ if (GridBase *mantaGrid = dynamic_cast<GridBase *>(*iter)) {
+
+ if (mantaGrid->getType() & GridBase::TypeInt) {
+ debMsg("Reading into grid '" << mantaGrid->getName() << "' from int grid '"
+ << vdbGrid->getName() << "' in vdb file " << filename,
+ 1);
+ openvdb::Int32Grid::Ptr vdbIntGrid = openvdb::gridPtrCast<openvdb::Int32Grid>(vdbGrid);
+ Grid<int> *mantaIntGrid = (Grid<int> *)mantaGrid;
+ importVDB<openvdb::Int32Grid, int>(vdbIntGrid, mantaIntGrid);
+ }
+ else if (mantaGrid->getType() & GridBase::TypeReal) {
+ debMsg("Reading into grid '" << mantaGrid->getName() << "' from real grid '"
+ << vdbGrid->getName() << "' in vdb file " << filename,
+ 1);
+ openvdb::FloatGrid::Ptr vdbFloatGrid = openvdb::gridPtrCast<openvdb::FloatGrid>(vdbGrid);
+ Grid<Real> *mantaRealGrid = (Grid<Real> *)mantaGrid;
+ importVDB<openvdb::FloatGrid, Real>(vdbFloatGrid, mantaRealGrid);
+ }
+ else if (mantaGrid->getType() & GridBase::TypeVec3) {
+ debMsg("Reading into grid '" << mantaGrid->getName() << "' from vec3 grid '"
+ << vdbGrid->getName() << "' in vdb file " << filename,
+ 1);
+ openvdb::Vec3SGrid::Ptr vdbVec3Grid = openvdb::gridPtrCast<openvdb::Vec3SGrid>(vdbGrid);
+ Grid<Vec3> *mantaVec3Grid = (Grid<Vec3> *)mantaGrid;
+ importVDB<openvdb::Vec3SGrid, Vec3>(vdbVec3Grid, mantaVec3Grid);
+ }
+ else {
+ errMsg("readObjectsVDB: unknown grid type");
+ return 0;
+ }
+ }
+ else if (BasicParticleSystem *mantaPP = dynamic_cast<BasicParticleSystem *>(*iter)) {
+ debMsg("Reading into particle system '" << mantaPP->getName() << "' from particle system '"
+ << vdbGrid->getName() << "' in vdb file "
+ << filename,
+ 1);
+ openvdb::points::PointDataGrid::Ptr vdbPointGrid =
+ openvdb::gridPtrCast<openvdb::points::PointDataGrid>(vdbGrid);
+ importVDB(vdbPointGrid, mantaPP, pdbBuffer, voxelSize);
+ pdbBuffer.clear();
+ }
+ else {
+ errMsg("readObjectsVDB: Unsupported Python object. Cannot read from .vdb file "
+ << filename);
+ return 0;
+ }
+ }
+ }
+
+ // Give out a warning if pData items were present but could not be read due to missing particle
+ // system.
+ if (!pdbBuffer.empty()) {
+ for (ParticleDataBase *pdb : pdbBuffer) {
+ debMsg("readObjectsVDB Warning: Particle data '"
+ << pdb->getName()
+ << "' has not been read. The parent particle system needs to be given too.",
+ 1);
+ }
+ }
+
+ return 1;
+}
+
+template void importVDB<int, int>(int vdbValue,
+ ParticleDataImpl<int> *to,
+ int index,
+ float voxelSize = 1.0);
+template void importVDB<float, Real>(float vdbValue,
+ ParticleDataImpl<Real> *to,
+ int index,
+ float voxelSize = 1.0);
+template void importVDB<openvdb::Vec3f, Vec3>(openvdb::Vec3s vdbValue,
+ ParticleDataImpl<Vec3> *to,
+ int index,
+ float voxelSize = 1.0);
+
+void importVDB(openvdb::points::PointDataGrid::Ptr from,
+ BasicParticleSystem *to,
+ std::vector<ParticleDataBase *> &toPData,
+ float voxelSize = 1.0);
+template void importVDB<openvdb::Int32Grid, int>(openvdb::Int32Grid::Ptr from, Grid<int> *to);
+template void importVDB<openvdb::FloatGrid, Real>(openvdb::FloatGrid::Ptr from, Grid<Real> *to);
+template void importVDB<openvdb::Vec3SGrid, Vec3>(openvdb::Vec3SGrid::Ptr from, Grid<Vec3> *to);
+
+template openvdb::Int32Grid::Ptr exportVDB<int, openvdb::Int32Grid>(Grid<int> *from);
+template openvdb::FloatGrid::Ptr exportVDB<Real, openvdb::FloatGrid>(Grid<Real> *from);
+template openvdb::Vec3SGrid::Ptr exportVDB<Vec3, openvdb::Vec3SGrid>(Grid<Vec3> *from);
+
+openvdb::points::PointDataGrid::Ptr exportVDB(BasicParticleSystem *from,
+ std::vector<ParticleDataBase *> &fromPData,
+ bool skipDeletedParts = false,
+ float voxelSize = 1.0);
+template void exportVDB<int, int>(ParticleDataImpl<int> *from,
+ openvdb::points::PointDataGrid::Ptr to,
+ openvdb::tools::PointIndexGrid::Ptr pIndex,
+ bool skipDeletedParts = false);
+template void exportVDB<Real, float>(ParticleDataImpl<Real> *from,
+ openvdb::points::PointDataGrid::Ptr to,
+ openvdb::tools::PointIndexGrid::Ptr pIndex,
+ bool skipDeletedParts = false);
+template void exportVDB<Vec3, openvdb::Vec3s>(ParticleDataImpl<Vec3> *from,
+ openvdb::points::PointDataGrid::Ptr to,
+ openvdb::tools::PointIndexGrid::Ptr pIndex,
+ bool skipDeletedParts = false);
+
+#else
+
+int writeObjectsVDB(const string &filename,
+ std::vector<PbClass *> *objects,
+ float worldSize,
+ bool skipDeletedParts,
+ int compression,
+ bool precisionHalf)
+{
+ errMsg("Cannot save to .vdb file. Mantaflow has not been built with OpenVDB support.");
+ return 0;
+}
+
+int readObjectsVDB(const string &filename, std::vector<PbClass *> *objects, float worldSize)
+{
+ errMsg("Cannot load from .vdb file. Mantaflow has not been built with OpenVDB support.");
+ return 0;
+}
+
+#endif // OPENVDB==1
+
+} // namespace Manta
diff --git a/extern/mantaflow/preprocessed/fileio/mantaio.cpp b/extern/mantaflow/preprocessed/fileio/mantaio.cpp
new file mode 100644
index 00000000000..fd2b36bf7cb
--- /dev/null
+++ b/extern/mantaflow/preprocessed/fileio/mantaio.cpp
@@ -0,0 +1,144 @@
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2020 Sebastian Barschkis, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * General functions that make use of functions from other io files.
+ *
+ ******************************************************************************/
+
+#include "mantaio.h"
+
+using namespace std;
+
+namespace Manta {
+
+int load(const string &name, std::vector<PbClass *> &objects, float worldSize = 1.0)
+{
+ if (name.find_last_of('.') == string::npos)
+ errMsg("file '" + name + "' does not have an extension");
+ string ext = name.substr(name.find_last_of('.'));
+
+ if (ext == ".raw")
+ return readGridsRaw(name, &objects);
+ else if (ext == ".uni")
+ return readGridsUni(name, &objects);
+ else if (ext == ".vol")
+ return readGridsVol(name, &objects);
+ if (ext == ".vdb")
+ return readObjectsVDB(name, &objects, worldSize);
+ else if (ext == ".npz")
+ return readGridsNumpy(name, &objects);
+ else if (ext == ".txt")
+ return readGridsTxt(name, &objects);
+ else
+ errMsg("file '" + name + "' filetype not supported");
+ return 0;
+}
+static PyObject *_W_0(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "load", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const string &name = _args.get<string>("name", 0, &_lock);
+ std::vector<PbClass *> &objects = *_args.getPtr<std::vector<PbClass *>>(
+ "objects", 1, &_lock);
+ float worldSize = _args.getOpt<float>("worldSize", 2, 1.0, &_lock);
+ _retval = toPy(load(name, objects, worldSize));
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "load", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("load", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_load("", "load", _W_0);
+extern "C" {
+void PbRegister_load()
+{
+ KEEP_UNUSED(_RP_load);
+}
+}
+
+int save(const string &name,
+ std::vector<PbClass *> &objects,
+ float worldSize = 1.0,
+ bool skipDeletedParts = false,
+ int compression = COMPRESSION_ZIP,
+ bool precisionHalf = true)
+{
+ if (name.find_last_of('.') == string::npos)
+ errMsg("file '" + name + "' does not have an extension");
+ string ext = name.substr(name.find_last_of('.'));
+
+ if (ext == ".raw")
+ return writeGridsRaw(name, &objects);
+ else if (ext == ".uni")
+ return writeGridsUni(name, &objects);
+ else if (ext == ".vol")
+ return writeGridsVol(name, &objects);
+ if (ext == ".vdb")
+ return writeObjectsVDB(
+ name, &objects, worldSize, skipDeletedParts, compression, precisionHalf);
+ else if (ext == ".npz")
+ return writeGridsNumpy(name, &objects);
+ else if (ext == ".txt")
+ return writeGridsTxt(name, &objects);
+ else
+ errMsg("file '" + name + "' filetype not supported");
+ return 0;
+}
+static PyObject *_W_1(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
+{
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
+ pbPreparePlugin(parent, "save", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const string &name = _args.get<string>("name", 0, &_lock);
+ std::vector<PbClass *> &objects = *_args.getPtr<std::vector<PbClass *>>(
+ "objects", 1, &_lock);
+ float worldSize = _args.getOpt<float>("worldSize", 2, 1.0, &_lock);
+ bool skipDeletedParts = _args.getOpt<bool>("skipDeletedParts", 3, false, &_lock);
+ int compression = _args.getOpt<int>("compression", 4, COMPRESSION_ZIP, &_lock);
+ bool precisionHalf = _args.getOpt<bool>("precisionHalf", 5, true, &_lock);
+ _retval = toPy(save(name, objects, worldSize, skipDeletedParts, compression, precisionHalf));
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "save", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("save", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_save("", "save", _W_1);
+extern "C" {
+void PbRegister_save()
+{
+ KEEP_UNUSED(_RP_save);
+}
+}
+
+} // namespace Manta
diff --git a/extern/mantaflow/preprocessed/fileio/mantaio.h b/extern/mantaflow/preprocessed/fileio/mantaio.h
index fbfe4bdd5d4..8b543ad4f93 100644
--- a/extern/mantaflow/preprocessed/fileio/mantaio.h
+++ b/extern/mantaflow/preprocessed/fileio/mantaio.h
@@ -21,62 +21,98 @@
#include <string>
+#include "manta.h"
+
+// OpenVDB compression flags
+#define COMPRESSION_NONE 0
+#define COMPRESSION_ZIP 1
+#define COMPRESSION_BLOSC 2
+
namespace Manta {
-// forward decl.
+// Forward declations
class Mesh;
class FlagGrid;
+class GridBase;
template<class T> class Grid;
template<class T> class Grid4d;
class BasicParticleSystem;
template<class T> class ParticleDataImpl;
template<class T> class MeshDataImpl;
-void writeObjFile(const std::string &name, Mesh *mesh);
-void writeBobjFile(const std::string &name, Mesh *mesh);
-void readObjFile(const std::string &name, Mesh *mesh, bool append);
-void readBobjFile(const std::string &name, Mesh *mesh, bool append);
-
-template<class T> void writeGridRaw(const std::string &name, Grid<T> *grid);
-template<class T> void writeGridUni(const std::string &name, Grid<T> *grid);
-template<class T> void writeGridVol(const std::string &name, Grid<T> *grid);
-template<class T> void writeGridTxt(const std::string &name, Grid<T> *grid);
-
-#if OPENVDB == 1
-template<class T> void writeGridVDB(const std::string &name, Grid<T> *grid);
-template<class T> void readGridVDB(const std::string &name, Grid<T> *grid);
-#endif // OPENVDB==1
-template<class T> void writeGridNumpy(const std::string &name, Grid<T> *grid);
-template<class T> void readGridNumpy(const std::string &name, Grid<T> *grid);
-
-template<class T> void readGridUni(const std::string &name, Grid<T> *grid);
-template<class T> void readGridRaw(const std::string &name, Grid<T> *grid);
-template<class T> void readGridVol(const std::string &name, Grid<T> *grid);
-
-template<class T> void writeGrid4dUni(const std::string &name, Grid4d<T> *grid);
+// Obj format
+int writeObjFile(const std::string &name, Mesh *mesh);
+int writeBobjFile(const std::string &name, Mesh *mesh);
+int readObjFile(const std::string &name, Mesh *mesh, bool append);
+int readBobjFile(const std::string &name, Mesh *mesh, bool append);
+
+// Other formats (Raw, Uni, Vol)
+template<class T> int readGridUni(const std::string &name, Grid<T> *grid);
+template<class T> int readGridRaw(const std::string &name, Grid<T> *grid);
+template<class T> int readGridVol(const std::string &name, Grid<T> *grid);
+int readGridsRaw(const std::string &name, std::vector<PbClass *> *grids);
+int readGridsUni(const std::string &name, std::vector<PbClass *> *grids);
+int readGridsVol(const std::string &name, std::vector<PbClass *> *grids);
+int readGridsTxt(const std::string &name, std::vector<PbClass *> *grids);
+
+template<class T> int writeGridRaw(const std::string &name, Grid<T> *grid);
+template<class T> int writeGridUni(const std::string &name, Grid<T> *grid);
+template<class T> int writeGridVol(const std::string &name, Grid<T> *grid);
+template<class T> int writeGridTxt(const std::string &name, Grid<T> *grid);
+int writeGridsRaw(const std::string &name, std::vector<PbClass *> *grids);
+int writeGridsUni(const std::string &name, std::vector<PbClass *> *grids);
+int writeGridsVol(const std::string &name, std::vector<PbClass *> *grids);
+int writeGridsTxt(const std::string &name, std::vector<PbClass *> *grids);
+
+// OpenVDB
+int writeObjectsVDB(const std::string &filename,
+ std::vector<PbClass *> *objects,
+ float scale = 1.0,
+ bool skipDeletedParts = false,
+ int compression = COMPRESSION_ZIP,
+ bool precisionHalf = true);
+int readObjectsVDB(const std::string &filename,
+ std::vector<PbClass *> *objects,
+ float scale = 1.0);
+
+// Numpy
+template<class T> int writeGridNumpy(const std::string &name, Grid<T> *grid);
+template<class T> int readGridNumpy(const std::string &name, Grid<T> *grid);
+
+int writeGridsNumpy(const std::string &name, std::vector<PbClass *> *grids);
+int readGridsNumpy(const std::string &name, std::vector<PbClass *> *grids);
+
+// 4D Grids
+template<class T> int writeGrid4dUni(const std::string &name, Grid4d<T> *grid);
template<class T>
-void readGrid4dUni(const std::string &name,
- Grid4d<T> *grid,
- int readTslice = -1,
- Grid4d<T> *slice = NULL,
- void **fileHandle = NULL);
+int readGrid4dUni(const std::string &name,
+ Grid4d<T> *grid,
+ int readTslice = -1,
+ Grid4d<T> *slice = NULL,
+ void **fileHandle = NULL);
void readGrid4dUniCleanup(void **fileHandle);
-template<class T> void writeGrid4dRaw(const std::string &name, Grid4d<T> *grid);
-template<class T> void readGrid4dRaw(const std::string &name, Grid4d<T> *grid);
+template<class T> int writeGrid4dRaw(const std::string &name, Grid4d<T> *grid);
+template<class T> int readGrid4dRaw(const std::string &name, Grid4d<T> *grid);
-void writeParticlesUni(const std::string &name, const BasicParticleSystem *parts);
-void readParticlesUni(const std::string &name, BasicParticleSystem *parts);
+// Particles + particle data
+int writeParticlesUni(const std::string &name, const BasicParticleSystem *parts);
+int readParticlesUni(const std::string &name, BasicParticleSystem *parts);
-template<class T> void writePdataUni(const std::string &name, ParticleDataImpl<T> *pdata);
-template<class T> void readPdataUni(const std::string &name, ParticleDataImpl<T> *pdata);
+template<class T> int writePdataUni(const std::string &name, ParticleDataImpl<T> *pdata);
+template<class T> int readPdataUni(const std::string &name, ParticleDataImpl<T> *pdata);
-template<class T> void writeMdataUni(const std::string &name, MeshDataImpl<T> *mdata);
-template<class T> void readMdataUni(const std::string &name, MeshDataImpl<T> *mdata);
+// Mesh data
+template<class T> int writeMdataUni(const std::string &name, MeshDataImpl<T> *mdata);
+template<class T> int readMdataUni(const std::string &name, MeshDataImpl<T> *mdata);
+// Helpers
void getUniFileSize(
const std::string &name, int &x, int &y, int &z, int *t = NULL, std::string *info = NULL);
-
void *safeGzopen(const char *filename, const char *mode);
+#if OPENVDB == 1
+template<class S, class T> void convertFrom(S &in, T *out);
+template<class S, class T> void convertTo(S *out, T &in);
+#endif
} // namespace Manta
diff --git a/extern/mantaflow/preprocessed/gitinfo.h b/extern/mantaflow/preprocessed/gitinfo.h
index 023974fd6cd..73ff70b10a0 100644
--- a/extern/mantaflow/preprocessed/gitinfo.h
+++ b/extern/mantaflow/preprocessed/gitinfo.h
@@ -1,3 +1,3 @@
-#define MANTA_GIT_VERSION "commit b61bf9efa7a1d8ca98635076a7e9f2c4dacb2914"
+#define MANTA_GIT_VERSION "commit d80d3c821de74315ab26b5efd153d41477b976c4"
diff --git a/extern/mantaflow/preprocessed/grid.cpp b/extern/mantaflow/preprocessed/grid.cpp
index 0ea3afb91f4..76716beb1ac 100644
--- a/extern/mantaflow/preprocessed/grid.cpp
+++ b/extern/mantaflow/preprocessed/grid.cpp
@@ -122,48 +122,52 @@ template<class T> void Grid<T>::swap(Grid<T> &other)
mData = dswap;
}
-template<class T> void Grid<T>::load(string name)
+template<class T> int Grid<T>::load(string name)
{
if (name.find_last_of('.') == string::npos)
errMsg("file '" + name + "' does not have an extension");
string ext = name.substr(name.find_last_of('.'));
if (ext == ".raw")
- readGridRaw(name, this);
+ return readGridRaw(name, this);
else if (ext == ".uni")
- readGridUni(name, this);
+ return readGridUni(name, this);
else if (ext == ".vol")
- readGridVol(name, this);
+ return readGridVol(name, this);
else if (ext == ".npz")
- readGridNumpy(name, this);
-#if OPENVDB == 1
- else if (ext == ".vdb")
- readGridVDB(name, this);
-#endif // OPENVDB==1
+ return readGridNumpy(name, this);
+ else if (ext == ".vdb") {
+ std::vector<PbClass *> grids;
+ grids.push_back(this);
+ return readObjectsVDB(name, &grids);
+ }
else
errMsg("file '" + name + "' filetype not supported");
+ return 0;
}
-template<class T> void Grid<T>::save(string name)
+template<class T> int Grid<T>::save(string name)
{
if (name.find_last_of('.') == string::npos)
errMsg("file '" + name + "' does not have an extension");
string ext = name.substr(name.find_last_of('.'));
if (ext == ".raw")
- writeGridRaw(name, this);
+ return writeGridRaw(name, this);
else if (ext == ".uni")
- writeGridUni(name, this);
+ return writeGridUni(name, this);
else if (ext == ".vol")
- writeGridVol(name, this);
-#if OPENVDB == 1
- else if (ext == ".vdb")
- writeGridVDB(name, this);
-#endif // OPENVDB==1
+ return writeGridVol(name, this);
else if (ext == ".npz")
- writeGridNumpy(name, this);
+ return writeGridNumpy(name, this);
+ else if (ext == ".vdb") {
+ std::vector<PbClass *> grids;
+ grids.push_back(this);
+ return writeObjectsVDB(name, &grids);
+ }
else if (ext == ".txt")
- writeGridTxt(name, this);
+ return writeGridTxt(name, this);
else
errMsg("file '" + name + "' filetype not supported");
+ return 0;
}
//******************************************************************************
diff --git a/extern/mantaflow/preprocessed/grid.h b/extern/mantaflow/preprocessed/grid.h
index fe386cfc269..a7aac80891a 100644
--- a/extern/mantaflow/preprocessed/grid.h
+++ b/extern/mantaflow/preprocessed/grid.h
@@ -409,7 +409,7 @@ template<class T> class Grid : public GridBase {
typedef T BASETYPE;
typedef GridBase BASETYPE_GRID;
- void save(std::string name);
+ int save(std::string name);
static PyObject *_W_10(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
{
try {
@@ -422,8 +422,7 @@ template<class T> class Grid : public GridBase {
ArgLocker _lock;
std::string name = _args.get<std::string>("name", 0, &_lock);
pbo->_args.copy(_args);
- _retval = getPyNone();
- pbo->save(name);
+ _retval = toPy(pbo->save(name));
pbo->_args.check();
}
pbFinalizePlugin(pbo->getParent(), "Grid::save", !noTiming);
@@ -435,7 +434,7 @@ template<class T> class Grid : public GridBase {
}
}
- void load(std::string name);
+ int load(std::string name);
static PyObject *_W_11(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
{
try {
@@ -448,8 +447,7 @@ template<class T> class Grid : public GridBase {
ArgLocker _lock;
std::string name = _args.get<std::string>("name", 0, &_lock);
pbo->_args.copy(_args);
- _retval = getPyNone();
- pbo->load(name);
+ _retval = toPy(pbo->load(name));
pbo->_args.check();
}
pbFinalizePlugin(pbo->getParent(), "Grid::load", !noTiming);
@@ -554,6 +552,12 @@ template<class T> class Grid : public GridBase {
return mData[idx];
}
+ //! set data
+ inline void set(int i, int j, int k, T &val)
+ {
+ mData[index(i, j, k)] = val;
+ }
+
// interpolated access
inline T getInterpolated(const Vec3 &pos) const
{
diff --git a/extern/mantaflow/preprocessed/grid4d.cpp b/extern/mantaflow/preprocessed/grid4d.cpp
index 41d69b2d33a..48f80d90b9f 100644
--- a/extern/mantaflow/preprocessed/grid4d.cpp
+++ b/extern/mantaflow/preprocessed/grid4d.cpp
@@ -121,30 +121,32 @@ template<class T> void Grid4d<T>::swap(Grid4d<T> &other)
mData = dswap;
}
-template<class T> void Grid4d<T>::load(string name)
+template<class T> int Grid4d<T>::load(string name)
{
if (name.find_last_of('.') == string::npos)
errMsg("file '" + name + "' does not have an extension");
string ext = name.substr(name.find_last_of('.'));
if (ext == ".uni")
- readGrid4dUni(name, this);
+ return readGrid4dUni(name, this);
else if (ext == ".raw")
- readGrid4dRaw(name, this);
+ return readGrid4dRaw(name, this);
else
errMsg("file '" + name + "' filetype not supported");
+ return 0;
}
-template<class T> void Grid4d<T>::save(string name)
+template<class T> int Grid4d<T>::save(string name)
{
if (name.find_last_of('.') == string::npos)
errMsg("file '" + name + "' does not have an extension");
string ext = name.substr(name.find_last_of('.'));
if (ext == ".uni")
- writeGrid4dUni(name, this);
+ return writeGrid4dUni(name, this);
else if (ext == ".raw")
- writeGrid4dRaw(name, this);
+ return writeGrid4dRaw(name, this);
else
errMsg("file '" + name + "' filetype not supported");
+ return 0;
}
//******************************************************************************
diff --git a/extern/mantaflow/preprocessed/grid4d.h b/extern/mantaflow/preprocessed/grid4d.h
index c3a98788da3..ee36c681ec5 100644
--- a/extern/mantaflow/preprocessed/grid4d.h
+++ b/extern/mantaflow/preprocessed/grid4d.h
@@ -372,7 +372,7 @@ template<class T> class Grid4d : public Grid4dBase {
typedef T BASETYPE;
typedef Grid4dBase BASETYPE_GRID;
- void save(std::string name);
+ int save(std::string name);
static PyObject *_W_9(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
{
try {
@@ -385,8 +385,7 @@ template<class T> class Grid4d : public Grid4dBase {
ArgLocker _lock;
std::string name = _args.get<std::string>("name", 0, &_lock);
pbo->_args.copy(_args);
- _retval = getPyNone();
- pbo->save(name);
+ _retval = toPy(pbo->save(name));
pbo->_args.check();
}
pbFinalizePlugin(pbo->getParent(), "Grid4d::save", !noTiming);
@@ -398,7 +397,7 @@ template<class T> class Grid4d : public Grid4dBase {
}
}
- void load(std::string name);
+ int load(std::string name);
static PyObject *_W_10(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
{
try {
@@ -411,8 +410,7 @@ template<class T> class Grid4d : public Grid4dBase {
ArgLocker _lock;
std::string name = _args.get<std::string>("name", 0, &_lock);
pbo->_args.copy(_args);
- _retval = getPyNone();
- pbo->load(name);
+ _retval = toPy(pbo->load(name));
pbo->_args.check();
}
pbFinalizePlugin(pbo->getParent(), "Grid4d::load", !noTiming);
diff --git a/extern/mantaflow/preprocessed/particle.cpp b/extern/mantaflow/preprocessed/particle.cpp
index 41af5d3ba81..c719fc8f27d 100644
--- a/extern/mantaflow/preprocessed/particle.cpp
+++ b/extern/mantaflow/preprocessed/particle.cpp
@@ -214,20 +214,26 @@ void BasicParticleSystem::writeParticlesRawVelocityGz(const string name) const
#endif
}
-void BasicParticleSystem::load(const string name)
+int BasicParticleSystem::load(const string name)
{
if (name.find_last_of('.') == string::npos)
errMsg("file '" + name + "' does not have an extension");
string ext = name.substr(name.find_last_of('.'));
if (ext == ".uni")
- readParticlesUni(name, this);
+ return readParticlesUni(name, this);
+ else if (ext == ".vdb") {
+ std::vector<PbClass *> parts;
+ parts.push_back(this);
+ return readObjectsVDB(name, &parts);
+ }
else if (ext == ".raw") // raw = uni for now
- readParticlesUni(name, this);
+ return readParticlesUni(name, this);
else
errMsg("particle '" + name + "' filetype not supported for loading");
+ return 0;
}
-void BasicParticleSystem::save(const string name) const
+int BasicParticleSystem::save(const string name)
{
if (name.find_last_of('.') == string::npos)
errMsg("file '" + name + "' does not have an extension");
@@ -235,16 +241,22 @@ void BasicParticleSystem::save(const string name) const
if (ext == ".txt")
this->writeParticlesText(name);
else if (ext == ".uni")
- writeParticlesUni(name, this);
+ return writeParticlesUni(name, this);
else if (ext == ".raw") // raw = uni for now
- writeParticlesUni(name, this);
- // raw data formats, very basic for simple data transfer to other programs
+ return writeParticlesUni(name, this);
+ else if (ext == ".vdb") {
+ std::vector<PbClass *> parts;
+ parts.push_back(this);
+ return writeObjectsVDB(name, &parts);
+ // raw data formats, very basic for simple data transfer to other programs
+ }
else if (ext == ".posgz")
this->writeParticlesRawPositionsGz(name);
else if (ext == ".velgz")
this->writeParticlesRawVelocityGz(name);
else
errMsg("particle '" + name + "' filetype not supported for saving");
+ return 0;
}
void BasicParticleSystem::printParts(IndexInt start, IndexInt stop, bool printIndex)
@@ -372,30 +384,42 @@ template<> void ParticleDataImpl<Vec3>::initNewValue(IndexInt idx, Vec3 pos)
}
}
-template<typename T> void ParticleDataImpl<T>::load(string name)
+template<typename T> int ParticleDataImpl<T>::load(string name)
{
if (name.find_last_of('.') == string::npos)
errMsg("file '" + name + "' does not have an extension");
string ext = name.substr(name.find_last_of('.'));
if (ext == ".uni")
- readPdataUni<T>(name, this);
+ return readPdataUni<T>(name, this);
+ else if (ext == ".vdb") {
+ std::vector<PbClass *> parts;
+ parts.push_back(this);
+ return readObjectsVDB(name, &parts);
+ }
else if (ext == ".raw") // raw = uni for now
- readPdataUni<T>(name, this);
+ return readPdataUni<T>(name, this);
else
errMsg("particle data '" + name + "' filetype not supported for loading");
+ return 0;
}
-template<typename T> void ParticleDataImpl<T>::save(string name)
+template<typename T> int ParticleDataImpl<T>::save(string name)
{
if (name.find_last_of('.') == string::npos)
errMsg("file '" + name + "' does not have an extension");
string ext = name.substr(name.find_last_of('.'));
if (ext == ".uni")
- writePdataUni<T>(name, this);
+ return writePdataUni<T>(name, this);
+ else if (ext == ".vdb") {
+ std::vector<PbClass *> parts;
+ parts.push_back(this);
+ return writeObjectsVDB(name, &parts);
+ }
else if (ext == ".raw") // raw = uni for now
- writePdataUni<T>(name, this);
+ return writePdataUni<T>(name, this);
else
errMsg("particle data '" + name + "' filetype not supported for saving");
+ return 0;
}
// specializations
diff --git a/extern/mantaflow/preprocessed/particle.h b/extern/mantaflow/preprocessed/particle.h
index d9dd3f49c38..0be141ed26f 100644
--- a/extern/mantaflow/preprocessed/particle.h
+++ b/extern/mantaflow/preprocessed/particle.h
@@ -646,7 +646,7 @@ class BasicParticleSystem : public ParticleSystem<BasicParticleData> {
}
//! file io
- void save(const std::string name) const;
+ int save(const std::string name);
static PyObject *_W_13(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
{
try {
@@ -659,8 +659,7 @@ class BasicParticleSystem : public ParticleSystem<BasicParticleData> {
ArgLocker _lock;
const std::string name = _args.get<std::string>("name", 0, &_lock);
pbo->_args.copy(_args);
- _retval = getPyNone();
- pbo->save(name);
+ _retval = toPy(pbo->save(name));
pbo->_args.check();
}
pbFinalizePlugin(pbo->getParent(), "BasicParticleSystem::save", !noTiming);
@@ -672,7 +671,7 @@ class BasicParticleSystem : public ParticleSystem<BasicParticleData> {
}
}
- void load(const std::string name);
+ int load(const std::string name);
static PyObject *_W_14(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
{
try {
@@ -685,8 +684,7 @@ class BasicParticleSystem : public ParticleSystem<BasicParticleData> {
ArgLocker _lock;
const std::string name = _args.get<std::string>("name", 0, &_lock);
pbo->_args.copy(_args);
- _retval = getPyNone();
- pbo->load(name);
+ _retval = toPy(pbo->load(name));
pbo->_args.check();
}
pbFinalizePlugin(pbo->getParent(), "BasicParticleSystem::load", !noTiming);
@@ -1022,11 +1020,15 @@ class ParticleDataBase : public PbClass {
return;
}
- //! set base pointer
+ //! set / get base pointer to parent particle system
void setParticleSys(ParticleBase *set)
{
mpParticleSys = set;
}
+ ParticleBase *getParticleSys()
+ {
+ return mpParticleSys;
+ }
//! debugging
inline void checkPartIndex(IndexInt idx) const;
@@ -1094,6 +1096,13 @@ template<class T> class ParticleDataImpl : public ParticleDataBase {
return mData[idx];
}
+ //! set data
+ inline void set(const IndexInt idx, T &val)
+ {
+ DEBUG_ONLY(checkPartIndex(idx));
+ mData[idx] = val;
+ }
+
//! set all values to 0, note - different from particleSystem::clear! doesnt modify size of array
//! (has to stay in sync with parent system)
void clear();
@@ -1716,7 +1725,7 @@ template<class T> class ParticleDataImpl : public ParticleDataBase {
}
//! file io
- void save(const std::string name);
+ int save(const std::string name);
static PyObject *_W_46(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
{
try {
@@ -1729,8 +1738,7 @@ template<class T> class ParticleDataImpl : public ParticleDataBase {
ArgLocker _lock;
const std::string name = _args.get<std::string>("name", 0, &_lock);
pbo->_args.copy(_args);
- _retval = getPyNone();
- pbo->save(name);
+ _retval = toPy(pbo->save(name));
pbo->_args.check();
}
pbFinalizePlugin(pbo->getParent(), "ParticleDataImpl::save", !noTiming);
@@ -1742,7 +1750,7 @@ template<class T> class ParticleDataImpl : public ParticleDataBase {
}
}
- void load(const std::string name);
+ int load(const std::string name);
static PyObject *_W_47(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
{
try {
@@ -1755,8 +1763,7 @@ template<class T> class ParticleDataImpl : public ParticleDataBase {
ArgLocker _lock;
const std::string name = _args.get<std::string>("name", 0, &_lock);
pbo->_args.copy(_args);
- _retval = getPyNone();
- pbo->load(name);
+ _retval = toPy(pbo->load(name));
pbo->_args.check();
}
pbFinalizePlugin(pbo->getParent(), "ParticleDataImpl::load", !noTiming);
diff --git a/extern/mantaflow/preprocessed/plugin/secondaryparticles.cpp b/extern/mantaflow/preprocessed/plugin/secondaryparticles.cpp
index 5e24b6f28db..5aae7285f1a 100644
--- a/extern/mantaflow/preprocessed/plugin/secondaryparticles.cpp
+++ b/extern/mantaflow/preprocessed/plugin/secondaryparticles.cpp
@@ -118,7 +118,9 @@ struct knFlipComputeSecondaryParticlePotentials : public KernelBase {
for (IndexInt x = i - radius; x <= i + radius; x++) {
for (IndexInt y = j - radius; y <= j + radius; y++) {
for (IndexInt z = k - radius; z <= k + radius; z++) {
- if ((x == i && y == j && z == k) || !flags.isInBounds(Vec3i(x, y, z)) ||
+ // ensure that xyz is in bounds: use bnd=1 to ensure that vel.getCentered() always has a
+ // neighbor cell
+ if ((x == i && y == j && z == k) || !flags.isInBounds(Vec3i(x, y, z), 1) ||
(flags(x, y, z) & jtype))
continue;
diff --git a/extern/mantaflow/preprocessed/python/defines.py.reg.cpp b/extern/mantaflow/preprocessed/python/defines.py.reg.cpp
index 1866957534c..f5b439b9cff 100644
--- a/extern/mantaflow/preprocessed/python/defines.py.reg.cpp
+++ b/extern/mantaflow/preprocessed/python/defines.py.reg.cpp
@@ -15,7 +15,8 @@ static const Pb::Register _reg(
"4\nTypeInflow = 8\nTypeOutflow = 16\nTypeStick = 64\nTypeReserved = 256\n\n# "
"integration mode\nIntEuler = 0\nIntRK2 = 1\nIntRK4 = 2\n\n# CG preconditioner\nPcNone "
" = 0\nPcMIC = 1\nPcMGDynamic = 2\nPcMGStatic = 3\n\n# particles\nPtypeSpray = "
- "2\nPtypeBubble = 4\nPtypeFoam = 8\nPtypeTracer = 16\n\n\n\n\n");
+ "2\nPtypeBubble = 4\nPtypeFoam = 8\nPtypeTracer = 16\n\n# OpenVDB export "
+ "flags\nCompression_None = 0\nCompression_Zip = 1\nCompression_Blosc = 2\n\n\n\n\n");
extern "C" {
void PbRegister_file_0()
{
diff --git a/extern/mantaflow/preprocessed/registration.cpp b/extern/mantaflow/preprocessed/registration.cpp
index c5bdddf4a18..6c1e68e6523 100644
--- a/extern/mantaflow/preprocessed/registration.cpp
+++ b/extern/mantaflow/preprocessed/registration.cpp
@@ -45,6 +45,8 @@ extern void PbRegister_printUniFileInfoString();
extern void PbRegister_getNpzFileSize();
extern void PbRegister_quantizeGrid();
extern void PbRegister_quantizeGridVec3();
+extern void PbRegister_load();
+extern void PbRegister_save();
extern void PbRegister_resetPhiInObs();
extern void PbRegister_advectSemiLagrange();
extern void PbRegister_addGravity();
@@ -238,6 +240,8 @@ void MantaEnsureRegistration()
PbRegister_getNpzFileSize();
PbRegister_quantizeGrid();
PbRegister_quantizeGridVec3();
+ PbRegister_load();
+ PbRegister_save();
PbRegister_resetPhiInObs();
PbRegister_advectSemiLagrange();
PbRegister_addGravity();