From 7e2fe33dbc1924150a1179fa2646fc385299c7b7 Mon Sep 17 00:00:00 2001 From: Anthony Doan Date: Sat, 20 May 2017 01:54:59 -0700 Subject: [PATCH] init init --- .../BasicMatrixMultiplication/template.cu | 125 + .../libwb/.clang-format | 21 + .../libwb/.travis.yml | 65 + .../libwb/CMakeLists.txt | 34 + .../libwb/LICENSE.TXT | 36 + CUDA_BasicMatrixMultiplication/libwb/Makefile | 56 + .../libwb/README.md | 7 + .../libwb/appveyor.yml | 54 + .../libwb/sources.cmake | 31 + .../libwb/vendor/catch.hpp | 10414 ++++++++++++++++ .../libwb/vendor/json11.cpp | 1013 ++ .../libwb/vendor/json11.hpp | 300 + CUDA_BasicMatrixMultiplication/libwb/wb.h | 155 + .../libwb/wbArg.cpp | 105 + CUDA_BasicMatrixMultiplication/libwb/wbArg.h | 33 + .../libwb/wbAssert.h | 24 + .../libwb/wbCUDA.cpp | 25 + CUDA_BasicMatrixMultiplication/libwb/wbCUDA.h | 77 + CUDA_BasicMatrixMultiplication/libwb/wbCast.h | 29 + .../libwb/wbComparator.h | 187 + .../libwb/wbDataset.cpp | 177 + .../libwb/wbDataset.h | 52 + .../libwb/wbDataset_test.cpp | 23 + .../libwb/wbDirectory.cpp | 88 + .../libwb/wbDirectory.h | 9 + .../libwb/wbExit.cpp | 119 + CUDA_BasicMatrixMultiplication/libwb/wbExit.h | 7 + .../libwb/wbExport.cpp | 510 + .../libwb/wbExport.h | 106 + .../libwb/wbFile.cpp | 353 + CUDA_BasicMatrixMultiplication/libwb/wbFile.h | 56 + .../libwb/wbImage.cpp | 134 + .../libwb/wbImage.h | 40 + .../libwb/wbImport.cpp | 711 ++ .../libwb/wbImport.h | 103 + .../libwb/wbInit.cpp | 85 + CUDA_BasicMatrixMultiplication/libwb/wbInit.h | 11 + .../libwb/wbLogger.cpp | 310 + .../libwb/wbLogger.h | 87 + CUDA_BasicMatrixMultiplication/libwb/wbMD5.h | 311 + .../libwb/wbMPI.cpp | 75 + CUDA_BasicMatrixMultiplication/libwb/wbMPI.h | 37 + .../libwb/wbMalloc.h | 140 + .../libwb/wbPPM.cpp | 199 + CUDA_BasicMatrixMultiplication/libwb/wbPPM.h | 11 + .../libwb/wbPath.cpp | 42 + CUDA_BasicMatrixMultiplication/libwb/wbPath.h | 30 + .../libwb/wbSolution.cpp | 271 + .../libwb/wbSolution.h | 40 + .../libwb/wbSparse.cpp | 82 + .../libwb/wbSparse.h | 10 + .../libwb/wbString.h | 324 + .../libwb/wbThrust.h | 15 + .../libwb/wbTimer.cpp | 493 + .../libwb/wbTimer.h | 139 + .../libwb/wbTypes.h | 55 + .../libwb/wbUtils.h | 10 + .../libwb/wb_test.cpp | 4 + CUDA_Convolution/Convolution/template.cu | 175 + CUDA_Convolution/libwb/.clang-format | 21 + CUDA_Convolution/libwb/.travis.yml | 65 + CUDA_Convolution/libwb/CMakeLists.txt | 34 + CUDA_Convolution/libwb/LICENSE.TXT | 36 + CUDA_Convolution/libwb/Makefile | 56 + CUDA_Convolution/libwb/README.md | 7 + CUDA_Convolution/libwb/appveyor.yml | 54 + CUDA_Convolution/libwb/sources.cmake | 31 + CUDA_Convolution/libwb/vendor/catch.hpp | 10414 ++++++++++++++++ CUDA_Convolution/libwb/vendor/json11.cpp | 1013 ++ CUDA_Convolution/libwb/vendor/json11.hpp | 300 + CUDA_Convolution/libwb/wb.h | 155 + CUDA_Convolution/libwb/wbArg.cpp | 105 + CUDA_Convolution/libwb/wbArg.h | 33 + CUDA_Convolution/libwb/wbAssert.h | 24 + CUDA_Convolution/libwb/wbCUDA.cpp | 25 + CUDA_Convolution/libwb/wbCUDA.h | 77 + CUDA_Convolution/libwb/wbCast.h | 29 + CUDA_Convolution/libwb/wbComparator.h | 187 + CUDA_Convolution/libwb/wbDataset.cpp | 177 + CUDA_Convolution/libwb/wbDataset.h | 52 + CUDA_Convolution/libwb/wbDataset_test.cpp | 23 + CUDA_Convolution/libwb/wbDirectory.cpp | 88 + CUDA_Convolution/libwb/wbDirectory.h | 9 + CUDA_Convolution/libwb/wbExit.cpp | 119 + CUDA_Convolution/libwb/wbExit.h | 7 + CUDA_Convolution/libwb/wbExport.cpp | 510 + CUDA_Convolution/libwb/wbExport.h | 106 + CUDA_Convolution/libwb/wbFile.cpp | 353 + CUDA_Convolution/libwb/wbFile.h | 56 + CUDA_Convolution/libwb/wbImage.cpp | 134 + CUDA_Convolution/libwb/wbImage.h | 40 + CUDA_Convolution/libwb/wbImport.cpp | 711 ++ CUDA_Convolution/libwb/wbImport.h | 103 + CUDA_Convolution/libwb/wbInit.cpp | 85 + CUDA_Convolution/libwb/wbInit.h | 11 + CUDA_Convolution/libwb/wbLogger.cpp | 310 + CUDA_Convolution/libwb/wbLogger.h | 87 + CUDA_Convolution/libwb/wbMD5.h | 311 + CUDA_Convolution/libwb/wbMPI.cpp | 75 + CUDA_Convolution/libwb/wbMPI.h | 37 + CUDA_Convolution/libwb/wbMalloc.h | 140 + CUDA_Convolution/libwb/wbPPM.cpp | 199 + CUDA_Convolution/libwb/wbPPM.h | 11 + CUDA_Convolution/libwb/wbPath.cpp | 42 + CUDA_Convolution/libwb/wbPath.h | 30 + CUDA_Convolution/libwb/wbSolution.cpp | 271 + CUDA_Convolution/libwb/wbSolution.h | 40 + CUDA_Convolution/libwb/wbSparse.cpp | 82 + CUDA_Convolution/libwb/wbSparse.h | 10 + CUDA_Convolution/libwb/wbString.h | 324 + CUDA_Convolution/libwb/wbThrust.h | 15 + CUDA_Convolution/libwb/wbTimer.cpp | 493 + CUDA_Convolution/libwb/wbTimer.h | 139 + CUDA_Convolution/libwb/wbTypes.h | 55 + CUDA_Convolution/libwb/wbUtils.h | 10 + CUDA_Convolution/libwb/wb_test.cpp | 4 + CUDA_DeviceQuery/DeviceQuery/template.cu | 54 + CUDA_DeviceQuery/libwb/.clang-format | 21 + CUDA_DeviceQuery/libwb/.travis.yml | 65 + CUDA_DeviceQuery/libwb/CMakeLists.txt | 34 + CUDA_DeviceQuery/libwb/LICENSE.TXT | 36 + CUDA_DeviceQuery/libwb/Makefile | 56 + CUDA_DeviceQuery/libwb/README.md | 7 + CUDA_DeviceQuery/libwb/appveyor.yml | 54 + CUDA_DeviceQuery/libwb/sources.cmake | 31 + CUDA_DeviceQuery/libwb/vendor/catch.hpp | 10414 ++++++++++++++++ CUDA_DeviceQuery/libwb/vendor/json11.cpp | 1013 ++ CUDA_DeviceQuery/libwb/vendor/json11.hpp | 300 + CUDA_DeviceQuery/libwb/wb.h | 155 + CUDA_DeviceQuery/libwb/wbArg.cpp | 105 + CUDA_DeviceQuery/libwb/wbArg.h | 33 + CUDA_DeviceQuery/libwb/wbAssert.h | 24 + CUDA_DeviceQuery/libwb/wbCUDA.cpp | 25 + CUDA_DeviceQuery/libwb/wbCUDA.h | 77 + CUDA_DeviceQuery/libwb/wbCast.h | 29 + CUDA_DeviceQuery/libwb/wbComparator.h | 187 + CUDA_DeviceQuery/libwb/wbDataset.cpp | 177 + CUDA_DeviceQuery/libwb/wbDataset.h | 52 + CUDA_DeviceQuery/libwb/wbDataset_test.cpp | 23 + CUDA_DeviceQuery/libwb/wbDirectory.cpp | 88 + CUDA_DeviceQuery/libwb/wbDirectory.h | 9 + CUDA_DeviceQuery/libwb/wbExit.cpp | 119 + CUDA_DeviceQuery/libwb/wbExit.h | 7 + CUDA_DeviceQuery/libwb/wbExport.cpp | 510 + CUDA_DeviceQuery/libwb/wbExport.h | 106 + CUDA_DeviceQuery/libwb/wbFile.cpp | 353 + CUDA_DeviceQuery/libwb/wbFile.h | 56 + CUDA_DeviceQuery/libwb/wbImage.cpp | 134 + CUDA_DeviceQuery/libwb/wbImage.h | 40 + CUDA_DeviceQuery/libwb/wbImport.cpp | 711 ++ CUDA_DeviceQuery/libwb/wbImport.h | 103 + CUDA_DeviceQuery/libwb/wbInit.cpp | 85 + CUDA_DeviceQuery/libwb/wbInit.h | 11 + CUDA_DeviceQuery/libwb/wbLogger.cpp | 310 + CUDA_DeviceQuery/libwb/wbLogger.h | 87 + CUDA_DeviceQuery/libwb/wbMD5.h | 311 + CUDA_DeviceQuery/libwb/wbMPI.cpp | 75 + CUDA_DeviceQuery/libwb/wbMPI.h | 37 + CUDA_DeviceQuery/libwb/wbMalloc.h | 140 + CUDA_DeviceQuery/libwb/wbPPM.cpp | 199 + CUDA_DeviceQuery/libwb/wbPPM.h | 11 + CUDA_DeviceQuery/libwb/wbPath.cpp | 42 + CUDA_DeviceQuery/libwb/wbPath.h | 30 + CUDA_DeviceQuery/libwb/wbSolution.cpp | 271 + CUDA_DeviceQuery/libwb/wbSolution.h | 40 + CUDA_DeviceQuery/libwb/wbSparse.cpp | 82 + CUDA_DeviceQuery/libwb/wbSparse.h | 10 + CUDA_DeviceQuery/libwb/wbString.h | 324 + CUDA_DeviceQuery/libwb/wbThrust.h | 15 + CUDA_DeviceQuery/libwb/wbTimer.cpp | 493 + CUDA_DeviceQuery/libwb/wbTimer.h | 139 + CUDA_DeviceQuery/libwb/wbTypes.h | 55 + CUDA_DeviceQuery/libwb/wbUtils.h | 10 + CUDA_DeviceQuery/libwb/wb_test.cpp | 4 + CUDA_Histogram/Histogram/template.cu | 188 + CUDA_Histogram/libwb/.clang-format | 21 + CUDA_Histogram/libwb/.travis.yml | 65 + CUDA_Histogram/libwb/CMakeLists.txt | 34 + CUDA_Histogram/libwb/LICENSE.TXT | 36 + CUDA_Histogram/libwb/Makefile | 56 + CUDA_Histogram/libwb/README.md | 7 + CUDA_Histogram/libwb/appveyor.yml | 54 + CUDA_Histogram/libwb/sources.cmake | 31 + CUDA_Histogram/libwb/vendor/catch.hpp | 10414 ++++++++++++++++ CUDA_Histogram/libwb/vendor/json11.cpp | 1013 ++ CUDA_Histogram/libwb/vendor/json11.hpp | 300 + CUDA_Histogram/libwb/wb.h | 155 + CUDA_Histogram/libwb/wbArg.cpp | 105 + CUDA_Histogram/libwb/wbArg.h | 33 + CUDA_Histogram/libwb/wbAssert.h | 24 + CUDA_Histogram/libwb/wbCUDA.cpp | 25 + CUDA_Histogram/libwb/wbCUDA.h | 77 + CUDA_Histogram/libwb/wbCast.h | 29 + CUDA_Histogram/libwb/wbComparator.h | 187 + CUDA_Histogram/libwb/wbDataset.cpp | 177 + CUDA_Histogram/libwb/wbDataset.h | 52 + CUDA_Histogram/libwb/wbDataset_test.cpp | 23 + CUDA_Histogram/libwb/wbDirectory.cpp | 88 + CUDA_Histogram/libwb/wbDirectory.h | 9 + CUDA_Histogram/libwb/wbExit.cpp | 119 + CUDA_Histogram/libwb/wbExit.h | 7 + CUDA_Histogram/libwb/wbExport.cpp | 510 + CUDA_Histogram/libwb/wbExport.h | 106 + CUDA_Histogram/libwb/wbFile.cpp | 353 + CUDA_Histogram/libwb/wbFile.h | 56 + CUDA_Histogram/libwb/wbImage.cpp | 134 + CUDA_Histogram/libwb/wbImage.h | 40 + CUDA_Histogram/libwb/wbImport.cpp | 711 ++ CUDA_Histogram/libwb/wbImport.h | 103 + CUDA_Histogram/libwb/wbInit.cpp | 85 + CUDA_Histogram/libwb/wbInit.h | 11 + CUDA_Histogram/libwb/wbLogger.cpp | 310 + CUDA_Histogram/libwb/wbLogger.h | 87 + CUDA_Histogram/libwb/wbMD5.h | 311 + CUDA_Histogram/libwb/wbMPI.cpp | 75 + CUDA_Histogram/libwb/wbMPI.h | 37 + CUDA_Histogram/libwb/wbMalloc.h | 140 + CUDA_Histogram/libwb/wbPPM.cpp | 199 + CUDA_Histogram/libwb/wbPPM.h | 11 + CUDA_Histogram/libwb/wbPath.cpp | 42 + CUDA_Histogram/libwb/wbPath.h | 30 + CUDA_Histogram/libwb/wbSolution.cpp | 271 + CUDA_Histogram/libwb/wbSolution.h | 40 + CUDA_Histogram/libwb/wbSparse.cpp | 82 + CUDA_Histogram/libwb/wbSparse.h | 10 + CUDA_Histogram/libwb/wbString.h | 324 + CUDA_Histogram/libwb/wbThrust.h | 15 + CUDA_Histogram/libwb/wbTimer.cpp | 493 + CUDA_Histogram/libwb/wbTimer.h | 139 + CUDA_Histogram/libwb/wbTypes.h | 55 + CUDA_Histogram/libwb/wbUtils.h | 10 + CUDA_Histogram/libwb/wb_test.cpp | 4 + CUDA_ListScan/ListScan/template.cu | 176 + CUDA_ListScan/libwb/.clang-format | 21 + CUDA_ListScan/libwb/.travis.yml | 65 + CUDA_ListScan/libwb/CMakeLists.txt | 34 + CUDA_ListScan/libwb/LICENSE.TXT | 36 + CUDA_ListScan/libwb/Makefile | 56 + CUDA_ListScan/libwb/README.md | 7 + CUDA_ListScan/libwb/appveyor.yml | 54 + CUDA_ListScan/libwb/sources.cmake | 31 + CUDA_ListScan/libwb/vendor/catch.hpp | 10414 ++++++++++++++++ CUDA_ListScan/libwb/vendor/json11.cpp | 1013 ++ CUDA_ListScan/libwb/vendor/json11.hpp | 300 + CUDA_ListScan/libwb/wb.h | 155 + CUDA_ListScan/libwb/wbArg.cpp | 105 + CUDA_ListScan/libwb/wbArg.h | 33 + CUDA_ListScan/libwb/wbAssert.h | 24 + CUDA_ListScan/libwb/wbCUDA.cpp | 25 + CUDA_ListScan/libwb/wbCUDA.h | 77 + CUDA_ListScan/libwb/wbCast.h | 29 + CUDA_ListScan/libwb/wbComparator.h | 187 + CUDA_ListScan/libwb/wbDataset.cpp | 177 + CUDA_ListScan/libwb/wbDataset.h | 52 + CUDA_ListScan/libwb/wbDataset_test.cpp | 23 + CUDA_ListScan/libwb/wbDirectory.cpp | 88 + CUDA_ListScan/libwb/wbDirectory.h | 9 + CUDA_ListScan/libwb/wbExit.cpp | 119 + CUDA_ListScan/libwb/wbExit.h | 7 + CUDA_ListScan/libwb/wbExport.cpp | 510 + CUDA_ListScan/libwb/wbExport.h | 106 + CUDA_ListScan/libwb/wbFile.cpp | 353 + CUDA_ListScan/libwb/wbFile.h | 56 + CUDA_ListScan/libwb/wbImage.cpp | 134 + CUDA_ListScan/libwb/wbImage.h | 40 + CUDA_ListScan/libwb/wbImport.cpp | 711 ++ CUDA_ListScan/libwb/wbImport.h | 103 + CUDA_ListScan/libwb/wbInit.cpp | 85 + CUDA_ListScan/libwb/wbInit.h | 11 + CUDA_ListScan/libwb/wbLogger.cpp | 310 + CUDA_ListScan/libwb/wbLogger.h | 87 + CUDA_ListScan/libwb/wbMD5.h | 311 + CUDA_ListScan/libwb/wbMPI.cpp | 75 + CUDA_ListScan/libwb/wbMPI.h | 37 + CUDA_ListScan/libwb/wbMalloc.h | 140 + CUDA_ListScan/libwb/wbPPM.cpp | 199 + CUDA_ListScan/libwb/wbPPM.h | 11 + CUDA_ListScan/libwb/wbPath.cpp | 42 + CUDA_ListScan/libwb/wbPath.h | 30 + CUDA_ListScan/libwb/wbSolution.cpp | 271 + CUDA_ListScan/libwb/wbSolution.h | 40 + CUDA_ListScan/libwb/wbSparse.cpp | 82 + CUDA_ListScan/libwb/wbSparse.h | 10 + CUDA_ListScan/libwb/wbString.h | 324 + CUDA_ListScan/libwb/wbThrust.h | 15 + CUDA_ListScan/libwb/wbTimer.cpp | 493 + CUDA_ListScan/libwb/wbTimer.h | 139 + CUDA_ListScan/libwb/wbTypes.h | 55 + CUDA_ListScan/libwb/wbUtils.h | 10 + CUDA_ListScan/libwb/wb_test.cpp | 4 + .../TiledMatrixMultiplication/template.cu | 154 + .../libwb/.clang-format | 21 + .../libwb/.travis.yml | 65 + .../libwb/CMakeLists.txt | 34 + .../libwb/LICENSE.TXT | 36 + CUDA_TiledMatrixMultiplication/libwb/Makefile | 56 + .../libwb/README.md | 7 + .../libwb/appveyor.yml | 54 + .../libwb/sources.cmake | 31 + .../libwb/vendor/catch.hpp | 10414 ++++++++++++++++ .../libwb/vendor/json11.cpp | 1013 ++ .../libwb/vendor/json11.hpp | 300 + CUDA_TiledMatrixMultiplication/libwb/wb.h | 155 + .../libwb/wbArg.cpp | 105 + CUDA_TiledMatrixMultiplication/libwb/wbArg.h | 33 + .../libwb/wbAssert.h | 24 + .../libwb/wbCUDA.cpp | 25 + CUDA_TiledMatrixMultiplication/libwb/wbCUDA.h | 77 + CUDA_TiledMatrixMultiplication/libwb/wbCast.h | 29 + .../libwb/wbComparator.h | 187 + .../libwb/wbDataset.cpp | 177 + .../libwb/wbDataset.h | 52 + .../libwb/wbDataset_test.cpp | 23 + .../libwb/wbDirectory.cpp | 88 + .../libwb/wbDirectory.h | 9 + .../libwb/wbExit.cpp | 119 + CUDA_TiledMatrixMultiplication/libwb/wbExit.h | 7 + .../libwb/wbExport.cpp | 510 + .../libwb/wbExport.h | 106 + .../libwb/wbFile.cpp | 353 + CUDA_TiledMatrixMultiplication/libwb/wbFile.h | 56 + .../libwb/wbImage.cpp | 134 + .../libwb/wbImage.h | 40 + .../libwb/wbImport.cpp | 711 ++ .../libwb/wbImport.h | 103 + .../libwb/wbInit.cpp | 85 + CUDA_TiledMatrixMultiplication/libwb/wbInit.h | 11 + .../libwb/wbLogger.cpp | 310 + .../libwb/wbLogger.h | 87 + CUDA_TiledMatrixMultiplication/libwb/wbMD5.h | 311 + .../libwb/wbMPI.cpp | 75 + CUDA_TiledMatrixMultiplication/libwb/wbMPI.h | 37 + .../libwb/wbMalloc.h | 140 + .../libwb/wbPPM.cpp | 199 + CUDA_TiledMatrixMultiplication/libwb/wbPPM.h | 11 + .../libwb/wbPath.cpp | 42 + CUDA_TiledMatrixMultiplication/libwb/wbPath.h | 30 + .../libwb/wbSolution.cpp | 271 + .../libwb/wbSolution.h | 40 + .../libwb/wbSparse.cpp | 82 + .../libwb/wbSparse.h | 10 + .../libwb/wbString.h | 324 + .../libwb/wbThrust.h | 15 + .../libwb/wbTimer.cpp | 493 + .../libwb/wbTimer.h | 139 + .../libwb/wbTypes.h | 55 + .../libwb/wbUtils.h | 10 + .../libwb/wb_test.cpp | 4 + CUDA_VectorAdd/VectorAdd/template.cu | 83 + CUDA_VectorAdd/libwb/.clang-format | 21 + CUDA_VectorAdd/libwb/.travis.yml | 65 + CUDA_VectorAdd/libwb/CMakeLists.txt | 34 + CUDA_VectorAdd/libwb/LICENSE.TXT | 36 + CUDA_VectorAdd/libwb/Makefile | 56 + CUDA_VectorAdd/libwb/README.md | 7 + CUDA_VectorAdd/libwb/appveyor.yml | 54 + CUDA_VectorAdd/libwb/sources.cmake | 31 + CUDA_VectorAdd/libwb/vendor/catch.hpp | 10414 ++++++++++++++++ CUDA_VectorAdd/libwb/vendor/json11.cpp | 1013 ++ CUDA_VectorAdd/libwb/vendor/json11.hpp | 300 + CUDA_VectorAdd/libwb/wb.h | 155 + CUDA_VectorAdd/libwb/wbArg.cpp | 105 + CUDA_VectorAdd/libwb/wbArg.h | 33 + CUDA_VectorAdd/libwb/wbAssert.h | 24 + CUDA_VectorAdd/libwb/wbCUDA.cpp | 25 + CUDA_VectorAdd/libwb/wbCUDA.h | 77 + CUDA_VectorAdd/libwb/wbCast.h | 29 + CUDA_VectorAdd/libwb/wbComparator.h | 187 + CUDA_VectorAdd/libwb/wbDataset.cpp | 177 + CUDA_VectorAdd/libwb/wbDataset.h | 52 + CUDA_VectorAdd/libwb/wbDataset_test.cpp | 23 + CUDA_VectorAdd/libwb/wbDirectory.cpp | 88 + CUDA_VectorAdd/libwb/wbDirectory.h | 9 + CUDA_VectorAdd/libwb/wbExit.cpp | 119 + CUDA_VectorAdd/libwb/wbExit.h | 7 + CUDA_VectorAdd/libwb/wbExport.cpp | 510 + CUDA_VectorAdd/libwb/wbExport.h | 106 + CUDA_VectorAdd/libwb/wbFile.cpp | 353 + CUDA_VectorAdd/libwb/wbFile.h | 56 + CUDA_VectorAdd/libwb/wbImage.cpp | 134 + CUDA_VectorAdd/libwb/wbImage.h | 40 + CUDA_VectorAdd/libwb/wbImport.cpp | 711 ++ CUDA_VectorAdd/libwb/wbImport.h | 103 + CUDA_VectorAdd/libwb/wbInit.cpp | 85 + CUDA_VectorAdd/libwb/wbInit.h | 11 + CUDA_VectorAdd/libwb/wbLogger.cpp | 310 + CUDA_VectorAdd/libwb/wbLogger.h | 87 + CUDA_VectorAdd/libwb/wbMD5.h | 311 + CUDA_VectorAdd/libwb/wbMPI.cpp | 75 + CUDA_VectorAdd/libwb/wbMPI.h | 37 + CUDA_VectorAdd/libwb/wbMalloc.h | 140 + CUDA_VectorAdd/libwb/wbPPM.cpp | 199 + CUDA_VectorAdd/libwb/wbPPM.h | 11 + CUDA_VectorAdd/libwb/wbPath.cpp | 42 + CUDA_VectorAdd/libwb/wbPath.h | 30 + CUDA_VectorAdd/libwb/wbSolution.cpp | 271 + CUDA_VectorAdd/libwb/wbSolution.h | 40 + CUDA_VectorAdd/libwb/wbSparse.cpp | 82 + CUDA_VectorAdd/libwb/wbSparse.h | 10 + CUDA_VectorAdd/libwb/wbString.h | 324 + CUDA_VectorAdd/libwb/wbThrust.h | 15 + CUDA_VectorAdd/libwb/wbTimer.cpp | 493 + CUDA_VectorAdd/libwb/wbTimer.h | 139 + CUDA_VectorAdd/libwb/wbTypes.h | 55 + CUDA_VectorAdd/libwb/wbUtils.h | 10 + CUDA_VectorAdd/libwb/wb_test.cpp | 4 + OpenCL_VectorAdd/VectorAdd/template.cpp | 146 + OpenCL_VectorAdd/libwb/.clang-format | 21 + OpenCL_VectorAdd/libwb/.travis.yml | 65 + OpenCL_VectorAdd/libwb/CMakeLists.txt | 34 + OpenCL_VectorAdd/libwb/LICENSE.TXT | 36 + OpenCL_VectorAdd/libwb/Makefile | 56 + OpenCL_VectorAdd/libwb/README.md | 7 + OpenCL_VectorAdd/libwb/appveyor.yml | 54 + OpenCL_VectorAdd/libwb/sources.cmake | 31 + OpenCL_VectorAdd/libwb/vendor/catch.hpp | 10414 ++++++++++++++++ OpenCL_VectorAdd/libwb/vendor/json11.cpp | 1013 ++ OpenCL_VectorAdd/libwb/vendor/json11.hpp | 300 + OpenCL_VectorAdd/libwb/wb.h | 155 + OpenCL_VectorAdd/libwb/wbArg.cpp | 105 + OpenCL_VectorAdd/libwb/wbArg.h | 33 + OpenCL_VectorAdd/libwb/wbAssert.h | 24 + OpenCL_VectorAdd/libwb/wbCUDA.cpp | 25 + OpenCL_VectorAdd/libwb/wbCUDA.h | 77 + OpenCL_VectorAdd/libwb/wbCast.h | 29 + OpenCL_VectorAdd/libwb/wbComparator.h | 187 + OpenCL_VectorAdd/libwb/wbDataset.cpp | 177 + OpenCL_VectorAdd/libwb/wbDataset.h | 52 + OpenCL_VectorAdd/libwb/wbDataset_test.cpp | 23 + OpenCL_VectorAdd/libwb/wbDirectory.cpp | 88 + OpenCL_VectorAdd/libwb/wbDirectory.h | 9 + OpenCL_VectorAdd/libwb/wbExit.cpp | 119 + OpenCL_VectorAdd/libwb/wbExit.h | 7 + OpenCL_VectorAdd/libwb/wbExport.cpp | 510 + OpenCL_VectorAdd/libwb/wbExport.h | 106 + OpenCL_VectorAdd/libwb/wbFile.cpp | 353 + OpenCL_VectorAdd/libwb/wbFile.h | 56 + OpenCL_VectorAdd/libwb/wbImage.cpp | 134 + OpenCL_VectorAdd/libwb/wbImage.h | 40 + OpenCL_VectorAdd/libwb/wbImport.cpp | 711 ++ OpenCL_VectorAdd/libwb/wbImport.h | 103 + OpenCL_VectorAdd/libwb/wbInit.cpp | 85 + OpenCL_VectorAdd/libwb/wbInit.h | 11 + OpenCL_VectorAdd/libwb/wbLogger.cpp | 310 + OpenCL_VectorAdd/libwb/wbLogger.h | 87 + OpenCL_VectorAdd/libwb/wbMD5.h | 311 + OpenCL_VectorAdd/libwb/wbMPI.cpp | 75 + OpenCL_VectorAdd/libwb/wbMPI.h | 37 + OpenCL_VectorAdd/libwb/wbMalloc.h | 140 + OpenCL_VectorAdd/libwb/wbPPM.cpp | 199 + OpenCL_VectorAdd/libwb/wbPPM.h | 11 + OpenCL_VectorAdd/libwb/wbPath.cpp | 42 + OpenCL_VectorAdd/libwb/wbPath.h | 30 + OpenCL_VectorAdd/libwb/wbSolution.cpp | 271 + OpenCL_VectorAdd/libwb/wbSolution.h | 40 + OpenCL_VectorAdd/libwb/wbSparse.cpp | 82 + OpenCL_VectorAdd/libwb/wbSparse.h | 10 + OpenCL_VectorAdd/libwb/wbString.h | 324 + OpenCL_VectorAdd/libwb/wbThrust.h | 15 + OpenCL_VectorAdd/libwb/wbTimer.cpp | 493 + OpenCL_VectorAdd/libwb/wbTimer.h | 139 + OpenCL_VectorAdd/libwb/wbTypes.h | 55 + OpenCL_VectorAdd/libwb/wbUtils.h | 10 + OpenCL_VectorAdd/libwb/wb_test.cpp | 4 + 464 files changed, 144581 insertions(+) create mode 100644 CUDA_BasicMatrixMultiplication/BasicMatrixMultiplication/template.cu create mode 100644 CUDA_BasicMatrixMultiplication/libwb/.clang-format create mode 100644 CUDA_BasicMatrixMultiplication/libwb/.travis.yml create mode 100644 CUDA_BasicMatrixMultiplication/libwb/CMakeLists.txt create mode 100644 CUDA_BasicMatrixMultiplication/libwb/LICENSE.TXT create mode 100644 CUDA_BasicMatrixMultiplication/libwb/Makefile create mode 100644 CUDA_BasicMatrixMultiplication/libwb/README.md create mode 100644 CUDA_BasicMatrixMultiplication/libwb/appveyor.yml create mode 100644 CUDA_BasicMatrixMultiplication/libwb/sources.cmake create mode 100644 CUDA_BasicMatrixMultiplication/libwb/vendor/catch.hpp create mode 100644 CUDA_BasicMatrixMultiplication/libwb/vendor/json11.cpp create mode 100644 CUDA_BasicMatrixMultiplication/libwb/vendor/json11.hpp create mode 100644 CUDA_BasicMatrixMultiplication/libwb/wb.h create mode 100644 CUDA_BasicMatrixMultiplication/libwb/wbArg.cpp create mode 100644 CUDA_BasicMatrixMultiplication/libwb/wbArg.h create mode 100644 CUDA_BasicMatrixMultiplication/libwb/wbAssert.h create mode 100644 CUDA_BasicMatrixMultiplication/libwb/wbCUDA.cpp create mode 100644 CUDA_BasicMatrixMultiplication/libwb/wbCUDA.h create mode 100644 CUDA_BasicMatrixMultiplication/libwb/wbCast.h create mode 100644 CUDA_BasicMatrixMultiplication/libwb/wbComparator.h create mode 100644 CUDA_BasicMatrixMultiplication/libwb/wbDataset.cpp create mode 100644 CUDA_BasicMatrixMultiplication/libwb/wbDataset.h create mode 100644 CUDA_BasicMatrixMultiplication/libwb/wbDataset_test.cpp create mode 100644 CUDA_BasicMatrixMultiplication/libwb/wbDirectory.cpp create mode 100644 CUDA_BasicMatrixMultiplication/libwb/wbDirectory.h create mode 100644 CUDA_BasicMatrixMultiplication/libwb/wbExit.cpp create mode 100644 CUDA_BasicMatrixMultiplication/libwb/wbExit.h create mode 100644 CUDA_BasicMatrixMultiplication/libwb/wbExport.cpp create mode 100644 CUDA_BasicMatrixMultiplication/libwb/wbExport.h create mode 100644 CUDA_BasicMatrixMultiplication/libwb/wbFile.cpp create mode 100644 CUDA_BasicMatrixMultiplication/libwb/wbFile.h create mode 100644 CUDA_BasicMatrixMultiplication/libwb/wbImage.cpp create mode 100644 CUDA_BasicMatrixMultiplication/libwb/wbImage.h create mode 100644 CUDA_BasicMatrixMultiplication/libwb/wbImport.cpp create mode 100644 CUDA_BasicMatrixMultiplication/libwb/wbImport.h create mode 100644 CUDA_BasicMatrixMultiplication/libwb/wbInit.cpp create mode 100644 CUDA_BasicMatrixMultiplication/libwb/wbInit.h create mode 100644 CUDA_BasicMatrixMultiplication/libwb/wbLogger.cpp create mode 100644 CUDA_BasicMatrixMultiplication/libwb/wbLogger.h create mode 100644 CUDA_BasicMatrixMultiplication/libwb/wbMD5.h create mode 100644 CUDA_BasicMatrixMultiplication/libwb/wbMPI.cpp create mode 100644 CUDA_BasicMatrixMultiplication/libwb/wbMPI.h create mode 100644 CUDA_BasicMatrixMultiplication/libwb/wbMalloc.h create mode 100644 CUDA_BasicMatrixMultiplication/libwb/wbPPM.cpp create mode 100644 CUDA_BasicMatrixMultiplication/libwb/wbPPM.h create mode 100644 CUDA_BasicMatrixMultiplication/libwb/wbPath.cpp create mode 100644 CUDA_BasicMatrixMultiplication/libwb/wbPath.h create mode 100644 CUDA_BasicMatrixMultiplication/libwb/wbSolution.cpp create mode 100644 CUDA_BasicMatrixMultiplication/libwb/wbSolution.h create mode 100644 CUDA_BasicMatrixMultiplication/libwb/wbSparse.cpp create mode 100644 CUDA_BasicMatrixMultiplication/libwb/wbSparse.h create mode 100644 CUDA_BasicMatrixMultiplication/libwb/wbString.h create mode 100644 CUDA_BasicMatrixMultiplication/libwb/wbThrust.h create mode 100644 CUDA_BasicMatrixMultiplication/libwb/wbTimer.cpp create mode 100644 CUDA_BasicMatrixMultiplication/libwb/wbTimer.h create mode 100644 CUDA_BasicMatrixMultiplication/libwb/wbTypes.h create mode 100644 CUDA_BasicMatrixMultiplication/libwb/wbUtils.h create mode 100644 CUDA_BasicMatrixMultiplication/libwb/wb_test.cpp create mode 100644 CUDA_Convolution/Convolution/template.cu create mode 100644 CUDA_Convolution/libwb/.clang-format create mode 100644 CUDA_Convolution/libwb/.travis.yml create mode 100644 CUDA_Convolution/libwb/CMakeLists.txt create mode 100644 CUDA_Convolution/libwb/LICENSE.TXT create mode 100644 CUDA_Convolution/libwb/Makefile create mode 100644 CUDA_Convolution/libwb/README.md create mode 100644 CUDA_Convolution/libwb/appveyor.yml create mode 100644 CUDA_Convolution/libwb/sources.cmake create mode 100644 CUDA_Convolution/libwb/vendor/catch.hpp create mode 100644 CUDA_Convolution/libwb/vendor/json11.cpp create mode 100644 CUDA_Convolution/libwb/vendor/json11.hpp create mode 100644 CUDA_Convolution/libwb/wb.h create mode 100644 CUDA_Convolution/libwb/wbArg.cpp create mode 100644 CUDA_Convolution/libwb/wbArg.h create mode 100644 CUDA_Convolution/libwb/wbAssert.h create mode 100644 CUDA_Convolution/libwb/wbCUDA.cpp create mode 100644 CUDA_Convolution/libwb/wbCUDA.h create mode 100644 CUDA_Convolution/libwb/wbCast.h create mode 100644 CUDA_Convolution/libwb/wbComparator.h create mode 100644 CUDA_Convolution/libwb/wbDataset.cpp create mode 100644 CUDA_Convolution/libwb/wbDataset.h create mode 100644 CUDA_Convolution/libwb/wbDataset_test.cpp create mode 100644 CUDA_Convolution/libwb/wbDirectory.cpp create mode 100644 CUDA_Convolution/libwb/wbDirectory.h create mode 100644 CUDA_Convolution/libwb/wbExit.cpp create mode 100644 CUDA_Convolution/libwb/wbExit.h create mode 100644 CUDA_Convolution/libwb/wbExport.cpp create mode 100644 CUDA_Convolution/libwb/wbExport.h create mode 100644 CUDA_Convolution/libwb/wbFile.cpp create mode 100644 CUDA_Convolution/libwb/wbFile.h create mode 100644 CUDA_Convolution/libwb/wbImage.cpp create mode 100644 CUDA_Convolution/libwb/wbImage.h create mode 100644 CUDA_Convolution/libwb/wbImport.cpp create mode 100644 CUDA_Convolution/libwb/wbImport.h create mode 100644 CUDA_Convolution/libwb/wbInit.cpp create mode 100644 CUDA_Convolution/libwb/wbInit.h create mode 100644 CUDA_Convolution/libwb/wbLogger.cpp create mode 100644 CUDA_Convolution/libwb/wbLogger.h create mode 100644 CUDA_Convolution/libwb/wbMD5.h create mode 100644 CUDA_Convolution/libwb/wbMPI.cpp create mode 100644 CUDA_Convolution/libwb/wbMPI.h create mode 100644 CUDA_Convolution/libwb/wbMalloc.h create mode 100644 CUDA_Convolution/libwb/wbPPM.cpp create mode 100644 CUDA_Convolution/libwb/wbPPM.h create mode 100644 CUDA_Convolution/libwb/wbPath.cpp create mode 100644 CUDA_Convolution/libwb/wbPath.h create mode 100644 CUDA_Convolution/libwb/wbSolution.cpp create mode 100644 CUDA_Convolution/libwb/wbSolution.h create mode 100644 CUDA_Convolution/libwb/wbSparse.cpp create mode 100644 CUDA_Convolution/libwb/wbSparse.h create mode 100644 CUDA_Convolution/libwb/wbString.h create mode 100644 CUDA_Convolution/libwb/wbThrust.h create mode 100644 CUDA_Convolution/libwb/wbTimer.cpp create mode 100644 CUDA_Convolution/libwb/wbTimer.h create mode 100644 CUDA_Convolution/libwb/wbTypes.h create mode 100644 CUDA_Convolution/libwb/wbUtils.h create mode 100644 CUDA_Convolution/libwb/wb_test.cpp create mode 100644 CUDA_DeviceQuery/DeviceQuery/template.cu create mode 100644 CUDA_DeviceQuery/libwb/.clang-format create mode 100644 CUDA_DeviceQuery/libwb/.travis.yml create mode 100644 CUDA_DeviceQuery/libwb/CMakeLists.txt create mode 100644 CUDA_DeviceQuery/libwb/LICENSE.TXT create mode 100644 CUDA_DeviceQuery/libwb/Makefile create mode 100644 CUDA_DeviceQuery/libwb/README.md create mode 100644 CUDA_DeviceQuery/libwb/appveyor.yml create mode 100644 CUDA_DeviceQuery/libwb/sources.cmake create mode 100644 CUDA_DeviceQuery/libwb/vendor/catch.hpp create mode 100644 CUDA_DeviceQuery/libwb/vendor/json11.cpp create mode 100644 CUDA_DeviceQuery/libwb/vendor/json11.hpp create mode 100644 CUDA_DeviceQuery/libwb/wb.h create mode 100644 CUDA_DeviceQuery/libwb/wbArg.cpp create mode 100644 CUDA_DeviceQuery/libwb/wbArg.h create mode 100644 CUDA_DeviceQuery/libwb/wbAssert.h create mode 100644 CUDA_DeviceQuery/libwb/wbCUDA.cpp create mode 100644 CUDA_DeviceQuery/libwb/wbCUDA.h create mode 100644 CUDA_DeviceQuery/libwb/wbCast.h create mode 100644 CUDA_DeviceQuery/libwb/wbComparator.h create mode 100644 CUDA_DeviceQuery/libwb/wbDataset.cpp create mode 100644 CUDA_DeviceQuery/libwb/wbDataset.h create mode 100644 CUDA_DeviceQuery/libwb/wbDataset_test.cpp create mode 100644 CUDA_DeviceQuery/libwb/wbDirectory.cpp create mode 100644 CUDA_DeviceQuery/libwb/wbDirectory.h create mode 100644 CUDA_DeviceQuery/libwb/wbExit.cpp create mode 100644 CUDA_DeviceQuery/libwb/wbExit.h create mode 100644 CUDA_DeviceQuery/libwb/wbExport.cpp create mode 100644 CUDA_DeviceQuery/libwb/wbExport.h create mode 100644 CUDA_DeviceQuery/libwb/wbFile.cpp create mode 100644 CUDA_DeviceQuery/libwb/wbFile.h create mode 100644 CUDA_DeviceQuery/libwb/wbImage.cpp create mode 100644 CUDA_DeviceQuery/libwb/wbImage.h create mode 100644 CUDA_DeviceQuery/libwb/wbImport.cpp create mode 100644 CUDA_DeviceQuery/libwb/wbImport.h create mode 100644 CUDA_DeviceQuery/libwb/wbInit.cpp create mode 100644 CUDA_DeviceQuery/libwb/wbInit.h create mode 100644 CUDA_DeviceQuery/libwb/wbLogger.cpp create mode 100644 CUDA_DeviceQuery/libwb/wbLogger.h create mode 100644 CUDA_DeviceQuery/libwb/wbMD5.h create mode 100644 CUDA_DeviceQuery/libwb/wbMPI.cpp create mode 100644 CUDA_DeviceQuery/libwb/wbMPI.h create mode 100644 CUDA_DeviceQuery/libwb/wbMalloc.h create mode 100644 CUDA_DeviceQuery/libwb/wbPPM.cpp create mode 100644 CUDA_DeviceQuery/libwb/wbPPM.h create mode 100644 CUDA_DeviceQuery/libwb/wbPath.cpp create mode 100644 CUDA_DeviceQuery/libwb/wbPath.h create mode 100644 CUDA_DeviceQuery/libwb/wbSolution.cpp create mode 100644 CUDA_DeviceQuery/libwb/wbSolution.h create mode 100644 CUDA_DeviceQuery/libwb/wbSparse.cpp create mode 100644 CUDA_DeviceQuery/libwb/wbSparse.h create mode 100644 CUDA_DeviceQuery/libwb/wbString.h create mode 100644 CUDA_DeviceQuery/libwb/wbThrust.h create mode 100644 CUDA_DeviceQuery/libwb/wbTimer.cpp create mode 100644 CUDA_DeviceQuery/libwb/wbTimer.h create mode 100644 CUDA_DeviceQuery/libwb/wbTypes.h create mode 100644 CUDA_DeviceQuery/libwb/wbUtils.h create mode 100644 CUDA_DeviceQuery/libwb/wb_test.cpp create mode 100644 CUDA_Histogram/Histogram/template.cu create mode 100644 CUDA_Histogram/libwb/.clang-format create mode 100644 CUDA_Histogram/libwb/.travis.yml create mode 100644 CUDA_Histogram/libwb/CMakeLists.txt create mode 100644 CUDA_Histogram/libwb/LICENSE.TXT create mode 100644 CUDA_Histogram/libwb/Makefile create mode 100644 CUDA_Histogram/libwb/README.md create mode 100644 CUDA_Histogram/libwb/appveyor.yml create mode 100644 CUDA_Histogram/libwb/sources.cmake create mode 100644 CUDA_Histogram/libwb/vendor/catch.hpp create mode 100644 CUDA_Histogram/libwb/vendor/json11.cpp create mode 100644 CUDA_Histogram/libwb/vendor/json11.hpp create mode 100644 CUDA_Histogram/libwb/wb.h create mode 100644 CUDA_Histogram/libwb/wbArg.cpp create mode 100644 CUDA_Histogram/libwb/wbArg.h create mode 100644 CUDA_Histogram/libwb/wbAssert.h create mode 100644 CUDA_Histogram/libwb/wbCUDA.cpp create mode 100644 CUDA_Histogram/libwb/wbCUDA.h create mode 100644 CUDA_Histogram/libwb/wbCast.h create mode 100644 CUDA_Histogram/libwb/wbComparator.h create mode 100644 CUDA_Histogram/libwb/wbDataset.cpp create mode 100644 CUDA_Histogram/libwb/wbDataset.h create mode 100644 CUDA_Histogram/libwb/wbDataset_test.cpp create mode 100644 CUDA_Histogram/libwb/wbDirectory.cpp create mode 100644 CUDA_Histogram/libwb/wbDirectory.h create mode 100644 CUDA_Histogram/libwb/wbExit.cpp create mode 100644 CUDA_Histogram/libwb/wbExit.h create mode 100644 CUDA_Histogram/libwb/wbExport.cpp create mode 100644 CUDA_Histogram/libwb/wbExport.h create mode 100644 CUDA_Histogram/libwb/wbFile.cpp create mode 100644 CUDA_Histogram/libwb/wbFile.h create mode 100644 CUDA_Histogram/libwb/wbImage.cpp create mode 100644 CUDA_Histogram/libwb/wbImage.h create mode 100644 CUDA_Histogram/libwb/wbImport.cpp create mode 100644 CUDA_Histogram/libwb/wbImport.h create mode 100644 CUDA_Histogram/libwb/wbInit.cpp create mode 100644 CUDA_Histogram/libwb/wbInit.h create mode 100644 CUDA_Histogram/libwb/wbLogger.cpp create mode 100644 CUDA_Histogram/libwb/wbLogger.h create mode 100644 CUDA_Histogram/libwb/wbMD5.h create mode 100644 CUDA_Histogram/libwb/wbMPI.cpp create mode 100644 CUDA_Histogram/libwb/wbMPI.h create mode 100644 CUDA_Histogram/libwb/wbMalloc.h create mode 100644 CUDA_Histogram/libwb/wbPPM.cpp create mode 100644 CUDA_Histogram/libwb/wbPPM.h create mode 100644 CUDA_Histogram/libwb/wbPath.cpp create mode 100644 CUDA_Histogram/libwb/wbPath.h create mode 100644 CUDA_Histogram/libwb/wbSolution.cpp create mode 100644 CUDA_Histogram/libwb/wbSolution.h create mode 100644 CUDA_Histogram/libwb/wbSparse.cpp create mode 100644 CUDA_Histogram/libwb/wbSparse.h create mode 100644 CUDA_Histogram/libwb/wbString.h create mode 100644 CUDA_Histogram/libwb/wbThrust.h create mode 100644 CUDA_Histogram/libwb/wbTimer.cpp create mode 100644 CUDA_Histogram/libwb/wbTimer.h create mode 100644 CUDA_Histogram/libwb/wbTypes.h create mode 100644 CUDA_Histogram/libwb/wbUtils.h create mode 100644 CUDA_Histogram/libwb/wb_test.cpp create mode 100644 CUDA_ListScan/ListScan/template.cu create mode 100644 CUDA_ListScan/libwb/.clang-format create mode 100644 CUDA_ListScan/libwb/.travis.yml create mode 100644 CUDA_ListScan/libwb/CMakeLists.txt create mode 100644 CUDA_ListScan/libwb/LICENSE.TXT create mode 100644 CUDA_ListScan/libwb/Makefile create mode 100644 CUDA_ListScan/libwb/README.md create mode 100644 CUDA_ListScan/libwb/appveyor.yml create mode 100644 CUDA_ListScan/libwb/sources.cmake create mode 100644 CUDA_ListScan/libwb/vendor/catch.hpp create mode 100644 CUDA_ListScan/libwb/vendor/json11.cpp create mode 100644 CUDA_ListScan/libwb/vendor/json11.hpp create mode 100644 CUDA_ListScan/libwb/wb.h create mode 100644 CUDA_ListScan/libwb/wbArg.cpp create mode 100644 CUDA_ListScan/libwb/wbArg.h create mode 100644 CUDA_ListScan/libwb/wbAssert.h create mode 100644 CUDA_ListScan/libwb/wbCUDA.cpp create mode 100644 CUDA_ListScan/libwb/wbCUDA.h create mode 100644 CUDA_ListScan/libwb/wbCast.h create mode 100644 CUDA_ListScan/libwb/wbComparator.h create mode 100644 CUDA_ListScan/libwb/wbDataset.cpp create mode 100644 CUDA_ListScan/libwb/wbDataset.h create mode 100644 CUDA_ListScan/libwb/wbDataset_test.cpp create mode 100644 CUDA_ListScan/libwb/wbDirectory.cpp create mode 100644 CUDA_ListScan/libwb/wbDirectory.h create mode 100644 CUDA_ListScan/libwb/wbExit.cpp create mode 100644 CUDA_ListScan/libwb/wbExit.h create mode 100644 CUDA_ListScan/libwb/wbExport.cpp create mode 100644 CUDA_ListScan/libwb/wbExport.h create mode 100644 CUDA_ListScan/libwb/wbFile.cpp create mode 100644 CUDA_ListScan/libwb/wbFile.h create mode 100644 CUDA_ListScan/libwb/wbImage.cpp create mode 100644 CUDA_ListScan/libwb/wbImage.h create mode 100644 CUDA_ListScan/libwb/wbImport.cpp create mode 100644 CUDA_ListScan/libwb/wbImport.h create mode 100644 CUDA_ListScan/libwb/wbInit.cpp create mode 100644 CUDA_ListScan/libwb/wbInit.h create mode 100644 CUDA_ListScan/libwb/wbLogger.cpp create mode 100644 CUDA_ListScan/libwb/wbLogger.h create mode 100644 CUDA_ListScan/libwb/wbMD5.h create mode 100644 CUDA_ListScan/libwb/wbMPI.cpp create mode 100644 CUDA_ListScan/libwb/wbMPI.h create mode 100644 CUDA_ListScan/libwb/wbMalloc.h create mode 100644 CUDA_ListScan/libwb/wbPPM.cpp create mode 100644 CUDA_ListScan/libwb/wbPPM.h create mode 100644 CUDA_ListScan/libwb/wbPath.cpp create mode 100644 CUDA_ListScan/libwb/wbPath.h create mode 100644 CUDA_ListScan/libwb/wbSolution.cpp create mode 100644 CUDA_ListScan/libwb/wbSolution.h create mode 100644 CUDA_ListScan/libwb/wbSparse.cpp create mode 100644 CUDA_ListScan/libwb/wbSparse.h create mode 100644 CUDA_ListScan/libwb/wbString.h create mode 100644 CUDA_ListScan/libwb/wbThrust.h create mode 100644 CUDA_ListScan/libwb/wbTimer.cpp create mode 100644 CUDA_ListScan/libwb/wbTimer.h create mode 100644 CUDA_ListScan/libwb/wbTypes.h create mode 100644 CUDA_ListScan/libwb/wbUtils.h create mode 100644 CUDA_ListScan/libwb/wb_test.cpp create mode 100644 CUDA_TiledMatrixMultiplication/TiledMatrixMultiplication/template.cu create mode 100644 CUDA_TiledMatrixMultiplication/libwb/.clang-format create mode 100644 CUDA_TiledMatrixMultiplication/libwb/.travis.yml create mode 100644 CUDA_TiledMatrixMultiplication/libwb/CMakeLists.txt create mode 100644 CUDA_TiledMatrixMultiplication/libwb/LICENSE.TXT create mode 100644 CUDA_TiledMatrixMultiplication/libwb/Makefile create mode 100644 CUDA_TiledMatrixMultiplication/libwb/README.md create mode 100644 CUDA_TiledMatrixMultiplication/libwb/appveyor.yml create mode 100644 CUDA_TiledMatrixMultiplication/libwb/sources.cmake create mode 100644 CUDA_TiledMatrixMultiplication/libwb/vendor/catch.hpp create mode 100644 CUDA_TiledMatrixMultiplication/libwb/vendor/json11.cpp create mode 100644 CUDA_TiledMatrixMultiplication/libwb/vendor/json11.hpp create mode 100644 CUDA_TiledMatrixMultiplication/libwb/wb.h create mode 100644 CUDA_TiledMatrixMultiplication/libwb/wbArg.cpp create mode 100644 CUDA_TiledMatrixMultiplication/libwb/wbArg.h create mode 100644 CUDA_TiledMatrixMultiplication/libwb/wbAssert.h create mode 100644 CUDA_TiledMatrixMultiplication/libwb/wbCUDA.cpp create mode 100644 CUDA_TiledMatrixMultiplication/libwb/wbCUDA.h create mode 100644 CUDA_TiledMatrixMultiplication/libwb/wbCast.h create mode 100644 CUDA_TiledMatrixMultiplication/libwb/wbComparator.h create mode 100644 CUDA_TiledMatrixMultiplication/libwb/wbDataset.cpp create mode 100644 CUDA_TiledMatrixMultiplication/libwb/wbDataset.h create mode 100644 CUDA_TiledMatrixMultiplication/libwb/wbDataset_test.cpp create mode 100644 CUDA_TiledMatrixMultiplication/libwb/wbDirectory.cpp create mode 100644 CUDA_TiledMatrixMultiplication/libwb/wbDirectory.h create mode 100644 CUDA_TiledMatrixMultiplication/libwb/wbExit.cpp create mode 100644 CUDA_TiledMatrixMultiplication/libwb/wbExit.h create mode 100644 CUDA_TiledMatrixMultiplication/libwb/wbExport.cpp create mode 100644 CUDA_TiledMatrixMultiplication/libwb/wbExport.h create mode 100644 CUDA_TiledMatrixMultiplication/libwb/wbFile.cpp create mode 100644 CUDA_TiledMatrixMultiplication/libwb/wbFile.h create mode 100644 CUDA_TiledMatrixMultiplication/libwb/wbImage.cpp create mode 100644 CUDA_TiledMatrixMultiplication/libwb/wbImage.h create mode 100644 CUDA_TiledMatrixMultiplication/libwb/wbImport.cpp create mode 100644 CUDA_TiledMatrixMultiplication/libwb/wbImport.h create mode 100644 CUDA_TiledMatrixMultiplication/libwb/wbInit.cpp create mode 100644 CUDA_TiledMatrixMultiplication/libwb/wbInit.h create mode 100644 CUDA_TiledMatrixMultiplication/libwb/wbLogger.cpp create mode 100644 CUDA_TiledMatrixMultiplication/libwb/wbLogger.h create mode 100644 CUDA_TiledMatrixMultiplication/libwb/wbMD5.h create mode 100644 CUDA_TiledMatrixMultiplication/libwb/wbMPI.cpp create mode 100644 CUDA_TiledMatrixMultiplication/libwb/wbMPI.h create mode 100644 CUDA_TiledMatrixMultiplication/libwb/wbMalloc.h create mode 100644 CUDA_TiledMatrixMultiplication/libwb/wbPPM.cpp create mode 100644 CUDA_TiledMatrixMultiplication/libwb/wbPPM.h create mode 100644 CUDA_TiledMatrixMultiplication/libwb/wbPath.cpp create mode 100644 CUDA_TiledMatrixMultiplication/libwb/wbPath.h create mode 100644 CUDA_TiledMatrixMultiplication/libwb/wbSolution.cpp create mode 100644 CUDA_TiledMatrixMultiplication/libwb/wbSolution.h create mode 100644 CUDA_TiledMatrixMultiplication/libwb/wbSparse.cpp create mode 100644 CUDA_TiledMatrixMultiplication/libwb/wbSparse.h create mode 100644 CUDA_TiledMatrixMultiplication/libwb/wbString.h create mode 100644 CUDA_TiledMatrixMultiplication/libwb/wbThrust.h create mode 100644 CUDA_TiledMatrixMultiplication/libwb/wbTimer.cpp create mode 100644 CUDA_TiledMatrixMultiplication/libwb/wbTimer.h create mode 100644 CUDA_TiledMatrixMultiplication/libwb/wbTypes.h create mode 100644 CUDA_TiledMatrixMultiplication/libwb/wbUtils.h create mode 100644 CUDA_TiledMatrixMultiplication/libwb/wb_test.cpp create mode 100644 CUDA_VectorAdd/VectorAdd/template.cu create mode 100644 CUDA_VectorAdd/libwb/.clang-format create mode 100644 CUDA_VectorAdd/libwb/.travis.yml create mode 100644 CUDA_VectorAdd/libwb/CMakeLists.txt create mode 100644 CUDA_VectorAdd/libwb/LICENSE.TXT create mode 100644 CUDA_VectorAdd/libwb/Makefile create mode 100644 CUDA_VectorAdd/libwb/README.md create mode 100644 CUDA_VectorAdd/libwb/appveyor.yml create mode 100644 CUDA_VectorAdd/libwb/sources.cmake create mode 100644 CUDA_VectorAdd/libwb/vendor/catch.hpp create mode 100644 CUDA_VectorAdd/libwb/vendor/json11.cpp create mode 100644 CUDA_VectorAdd/libwb/vendor/json11.hpp create mode 100644 CUDA_VectorAdd/libwb/wb.h create mode 100644 CUDA_VectorAdd/libwb/wbArg.cpp create mode 100644 CUDA_VectorAdd/libwb/wbArg.h create mode 100644 CUDA_VectorAdd/libwb/wbAssert.h create mode 100644 CUDA_VectorAdd/libwb/wbCUDA.cpp create mode 100644 CUDA_VectorAdd/libwb/wbCUDA.h create mode 100644 CUDA_VectorAdd/libwb/wbCast.h create mode 100644 CUDA_VectorAdd/libwb/wbComparator.h create mode 100644 CUDA_VectorAdd/libwb/wbDataset.cpp create mode 100644 CUDA_VectorAdd/libwb/wbDataset.h create mode 100644 CUDA_VectorAdd/libwb/wbDataset_test.cpp create mode 100644 CUDA_VectorAdd/libwb/wbDirectory.cpp create mode 100644 CUDA_VectorAdd/libwb/wbDirectory.h create mode 100644 CUDA_VectorAdd/libwb/wbExit.cpp create mode 100644 CUDA_VectorAdd/libwb/wbExit.h create mode 100644 CUDA_VectorAdd/libwb/wbExport.cpp create mode 100644 CUDA_VectorAdd/libwb/wbExport.h create mode 100644 CUDA_VectorAdd/libwb/wbFile.cpp create mode 100644 CUDA_VectorAdd/libwb/wbFile.h create mode 100644 CUDA_VectorAdd/libwb/wbImage.cpp create mode 100644 CUDA_VectorAdd/libwb/wbImage.h create mode 100644 CUDA_VectorAdd/libwb/wbImport.cpp create mode 100644 CUDA_VectorAdd/libwb/wbImport.h create mode 100644 CUDA_VectorAdd/libwb/wbInit.cpp create mode 100644 CUDA_VectorAdd/libwb/wbInit.h create mode 100644 CUDA_VectorAdd/libwb/wbLogger.cpp create mode 100644 CUDA_VectorAdd/libwb/wbLogger.h create mode 100644 CUDA_VectorAdd/libwb/wbMD5.h create mode 100644 CUDA_VectorAdd/libwb/wbMPI.cpp create mode 100644 CUDA_VectorAdd/libwb/wbMPI.h create mode 100644 CUDA_VectorAdd/libwb/wbMalloc.h create mode 100644 CUDA_VectorAdd/libwb/wbPPM.cpp create mode 100644 CUDA_VectorAdd/libwb/wbPPM.h create mode 100644 CUDA_VectorAdd/libwb/wbPath.cpp create mode 100644 CUDA_VectorAdd/libwb/wbPath.h create mode 100644 CUDA_VectorAdd/libwb/wbSolution.cpp create mode 100644 CUDA_VectorAdd/libwb/wbSolution.h create mode 100644 CUDA_VectorAdd/libwb/wbSparse.cpp create mode 100644 CUDA_VectorAdd/libwb/wbSparse.h create mode 100644 CUDA_VectorAdd/libwb/wbString.h create mode 100644 CUDA_VectorAdd/libwb/wbThrust.h create mode 100644 CUDA_VectorAdd/libwb/wbTimer.cpp create mode 100644 CUDA_VectorAdd/libwb/wbTimer.h create mode 100644 CUDA_VectorAdd/libwb/wbTypes.h create mode 100644 CUDA_VectorAdd/libwb/wbUtils.h create mode 100644 CUDA_VectorAdd/libwb/wb_test.cpp create mode 100644 OpenCL_VectorAdd/VectorAdd/template.cpp create mode 100644 OpenCL_VectorAdd/libwb/.clang-format create mode 100644 OpenCL_VectorAdd/libwb/.travis.yml create mode 100644 OpenCL_VectorAdd/libwb/CMakeLists.txt create mode 100644 OpenCL_VectorAdd/libwb/LICENSE.TXT create mode 100644 OpenCL_VectorAdd/libwb/Makefile create mode 100644 OpenCL_VectorAdd/libwb/README.md create mode 100644 OpenCL_VectorAdd/libwb/appveyor.yml create mode 100644 OpenCL_VectorAdd/libwb/sources.cmake create mode 100644 OpenCL_VectorAdd/libwb/vendor/catch.hpp create mode 100644 OpenCL_VectorAdd/libwb/vendor/json11.cpp create mode 100644 OpenCL_VectorAdd/libwb/vendor/json11.hpp create mode 100644 OpenCL_VectorAdd/libwb/wb.h create mode 100644 OpenCL_VectorAdd/libwb/wbArg.cpp create mode 100644 OpenCL_VectorAdd/libwb/wbArg.h create mode 100644 OpenCL_VectorAdd/libwb/wbAssert.h create mode 100644 OpenCL_VectorAdd/libwb/wbCUDA.cpp create mode 100644 OpenCL_VectorAdd/libwb/wbCUDA.h create mode 100644 OpenCL_VectorAdd/libwb/wbCast.h create mode 100644 OpenCL_VectorAdd/libwb/wbComparator.h create mode 100644 OpenCL_VectorAdd/libwb/wbDataset.cpp create mode 100644 OpenCL_VectorAdd/libwb/wbDataset.h create mode 100644 OpenCL_VectorAdd/libwb/wbDataset_test.cpp create mode 100644 OpenCL_VectorAdd/libwb/wbDirectory.cpp create mode 100644 OpenCL_VectorAdd/libwb/wbDirectory.h create mode 100644 OpenCL_VectorAdd/libwb/wbExit.cpp create mode 100644 OpenCL_VectorAdd/libwb/wbExit.h create mode 100644 OpenCL_VectorAdd/libwb/wbExport.cpp create mode 100644 OpenCL_VectorAdd/libwb/wbExport.h create mode 100644 OpenCL_VectorAdd/libwb/wbFile.cpp create mode 100644 OpenCL_VectorAdd/libwb/wbFile.h create mode 100644 OpenCL_VectorAdd/libwb/wbImage.cpp create mode 100644 OpenCL_VectorAdd/libwb/wbImage.h create mode 100644 OpenCL_VectorAdd/libwb/wbImport.cpp create mode 100644 OpenCL_VectorAdd/libwb/wbImport.h create mode 100644 OpenCL_VectorAdd/libwb/wbInit.cpp create mode 100644 OpenCL_VectorAdd/libwb/wbInit.h create mode 100644 OpenCL_VectorAdd/libwb/wbLogger.cpp create mode 100644 OpenCL_VectorAdd/libwb/wbLogger.h create mode 100644 OpenCL_VectorAdd/libwb/wbMD5.h create mode 100644 OpenCL_VectorAdd/libwb/wbMPI.cpp create mode 100644 OpenCL_VectorAdd/libwb/wbMPI.h create mode 100644 OpenCL_VectorAdd/libwb/wbMalloc.h create mode 100644 OpenCL_VectorAdd/libwb/wbPPM.cpp create mode 100644 OpenCL_VectorAdd/libwb/wbPPM.h create mode 100644 OpenCL_VectorAdd/libwb/wbPath.cpp create mode 100644 OpenCL_VectorAdd/libwb/wbPath.h create mode 100644 OpenCL_VectorAdd/libwb/wbSolution.cpp create mode 100644 OpenCL_VectorAdd/libwb/wbSolution.h create mode 100644 OpenCL_VectorAdd/libwb/wbSparse.cpp create mode 100644 OpenCL_VectorAdd/libwb/wbSparse.h create mode 100644 OpenCL_VectorAdd/libwb/wbString.h create mode 100644 OpenCL_VectorAdd/libwb/wbThrust.h create mode 100644 OpenCL_VectorAdd/libwb/wbTimer.cpp create mode 100644 OpenCL_VectorAdd/libwb/wbTimer.h create mode 100644 OpenCL_VectorAdd/libwb/wbTypes.h create mode 100644 OpenCL_VectorAdd/libwb/wbUtils.h create mode 100644 OpenCL_VectorAdd/libwb/wb_test.cpp diff --git a/CUDA_BasicMatrixMultiplication/BasicMatrixMultiplication/template.cu b/CUDA_BasicMatrixMultiplication/BasicMatrixMultiplication/template.cu new file mode 100644 index 0000000..5f3b2a8 --- /dev/null +++ b/CUDA_BasicMatrixMultiplication/BasicMatrixMultiplication/template.cu @@ -0,0 +1,125 @@ + +#include + +#define wbCheck(stmt) \ + do { \ + cudaError_t err = stmt; \ + if (err != cudaSuccess) { \ + wbLog(ERROR, "Failed to run stmt ", #stmt); \ + wbLog(ERROR, "Got CUDA error ... ", cudaGetErrorString(err)); \ + return -1; \ + } \ + } while (0) + +// Compute C = A * B +__global__ void matrixMultiply(float *A, float *B, float *C, int numARows, int numAColumns, int numBRows, int numBColumns, int numCRows, int numCColumns) { + int Row = blockIdx.y * blockDim.y + threadIdx.y; + int Col = blockIdx.x * blockDim.x + threadIdx.x; + + if ((Row < numCRows) && (Col < numCColumns)) { + float Pvalue = 0; + for (int k = 0; k < numAColumns; ++k) { + Pvalue += A[Row * numAColumns + k] * B[k * numBColumns + Col]; + } + C[Row * numCColumns + Col] = Pvalue; + } +} + +int main(int argc, char **argv) { + wbArg_t args; + float *hostA; // The A matrix + float *hostB; // The B matrix + float *hostC; // The output C matrix + float *deviceA; + float *deviceB; + float *deviceC; + int numARows; // number of rows in the matrix A + int numAColumns; // number of columns in the matrix A + int numBRows; // number of rows in the matrix B + int numBColumns; // number of columns in the matrix B + int numCRows; // number of rows in the matrix C + int numCColumns; // number of columns in the matrix C + + hostC = NULL; + int sizeA, sizeB, sizeC; + + args = wbArg_read(argc, argv); + + wbTime_start(Generic, "Importing data and creating memory on host"); + hostA = (float *)wbImport(wbArg_getInputFile(args, 0), &numARows, + &numAColumns); + hostB = (float *)wbImport(wbArg_getInputFile(args, 1), &numBRows, + &numBColumns); + + //@@ Set numCRows and numCColumns + numCRows = numARows; + numCColumns = numBColumns; + + sizeA = numARows * numAColumns * sizeof(float); + sizeB = numBRows * numBColumns * sizeof(float); + sizeC = numCRows * numCColumns * sizeof(float); + + //@@ Allocate the hostC matrix + + hostC = (float *) malloc(sizeC); + + wbTime_stop(Generic, "Importing data and creating memory on host"); + + wbLog(TRACE, "The dimensions of A are ", numARows, " x ", numAColumns); + wbLog(TRACE, "The dimensions of B are ", numBRows, " x ", numBColumns); + + wbTime_start(GPU, "Allocating GPU memory."); + //@@ Allocate GPU memory here + + wbCheck(cudaMalloc((void**) &deviceA, sizeA)); + wbCheck(cudaMalloc((void**) &deviceB, sizeB)); + wbCheck(cudaMalloc((void**) &deviceC, sizeC)); + + wbTime_stop(GPU, "Allocating GPU memory."); + + wbTime_start(GPU, "Copying input memory to the GPU."); + //@@ Copy memory to the GPU here + + wbCheck(cudaMemcpy(deviceA, hostA, sizeA, cudaMemcpyHostToDevice)); + wbCheck(cudaMemcpy(deviceB, hostB, sizeB, cudaMemcpyHostToDevice)); + + wbTime_stop(GPU, "Copying input memory to the GPU."); + + //@@ Initialize the grid and block dimensions here + + // TILE_WIDTH = 16 + dim3 dimBlock(16, 16, 1); + dim3 dimGrid(numBColumns / 16, numARows / 16, 1); + + wbTime_start(Compute, "Performing CUDA computation"); + //@@ Launch the GPU Kernel + + matrixMultiply<<>>(deviceA, deviceB, deviceC, numARows, numAColumns, numBRows, numBColumns, numCRows, numCColumns); + wbCheck(cudaDeviceSynchronize()); + + wbTime_stop(Compute, "Performing CUDA computation"); + + wbTime_start(Copy, "Copying output memory to the CPU"); + //@@ Copy the GPU memory back to the CPU + + wbCheck(cudaMemcpy(hostC, deviceC, sizeC, cudaMemcpyDeviceToHost)); + + wbTime_stop(Copy, "Copying output memory to the CPU"); + + wbTime_start(GPU, "Freeing GPU Memory"); + //@@ Free the GPU memory + + cudaFree(deviceA); + cudaFree(deviceB); + cudaFree(deviceC); + + wbTime_stop(GPU, "Freeing GPU Memory"); + + wbSolution(args, hostC, numCRows, numCColumns); + + free(hostA); + free(hostB); + free(hostC); + + return 0; +} diff --git a/CUDA_BasicMatrixMultiplication/libwb/.clang-format b/CUDA_BasicMatrixMultiplication/libwb/.clang-format new file mode 100644 index 0000000..4757ed4 --- /dev/null +++ b/CUDA_BasicMatrixMultiplication/libwb/.clang-format @@ -0,0 +1,21 @@ +--- +Language: Cpp +BasedOnStyle: LLVM +ColumnLimit: 75 +AccessModifierOffset: -2 +BreakBeforeBraces: Attach +AlignTrailingComments: true +AlignEscapedNewlinesLeft: false +AlignConsecutiveAssignments: true +AlignOperands: true +AllowShortFunctionsOnASingleLine: false +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AlwaysBreakTemplateDeclarations: true +IndentCaseLabels: true +SpacesBeforeTrailingComments: 1 +Standard: Cpp11 +TabWidth: 4 +UseTab: Never +SortIncludes: false +... diff --git a/CUDA_BasicMatrixMultiplication/libwb/.travis.yml b/CUDA_BasicMatrixMultiplication/libwb/.travis.yml new file mode 100644 index 0000000..e32c621 --- /dev/null +++ b/CUDA_BasicMatrixMultiplication/libwb/.travis.yml @@ -0,0 +1,65 @@ +# Use new trusty images, should yield newer compilers and packages +sudo: required +dist: precise +language: cpp + +matrix: + include: + - compiler: gcc + addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - g++-4.9 + env: COMPILER=g++-4.9 + - compiler: gcc + addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - g++-5 + env: COMPILER=g++-5 + - compiler: clang + addons: + apt: + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-precise-3.6 + packages: + - clang-3.6 + env: COMPILER=clang++-3.6 + - compiler: clang + addons: + apt: + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-precise-3.7 + packages: + - clang-3.7 + env: COMPILER=clang++-3.7 +# - compiler: gcc +# addons: +# apt: +# sources: +# - ubuntu-toolchain-r-test +# packages: +# - g++-6 +# env: COMPILER=g++-6 + # - compiler: clang + # addons: + # apt: + # sources: + # - ubuntu-toolchain-r-test + # - llvm-toolchain-precise-3.8 + # packages: + # - clang-3.8 + # env: COMPILER=clang++-3.8 + +before_install: + - sudo apt-get update -qq +script: + - $COMPILER --version + - make CXX=$COMPILER test + - ./test diff --git a/CUDA_BasicMatrixMultiplication/libwb/CMakeLists.txt b/CUDA_BasicMatrixMultiplication/libwb/CMakeLists.txt new file mode 100644 index 0000000..f732c32 --- /dev/null +++ b/CUDA_BasicMatrixMultiplication/libwb/CMakeLists.txt @@ -0,0 +1,34 @@ +cmake_minimum_required(VERSION 2.8 FATAL_ERROR) + +set(CMAKE_BUILD_TYPE Release) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) +set(CMAKE_COLOR_MAKEFILE ON) +set(VERBOSE_BUILD ON) +set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) +set(CMAKE_MACOSX_RPATH TRUE) +set_property(GLOBAL PROPERTY USE_FOLDERS ON) + + +project(wb) + +set(current_dir "${CMAKE_CURRENT_SOURCE_DIR}") + +if(NOT EXISTS "${CMAKE_CURRENT_BINARY_DIR}/cotire.cmake") + file(DOWNLOAD "https://raw.githubusercontent.com/sakra/cotire/master/CMake/cotire.cmake" "${CMAKE_CURRENT_BINARY_DIR}/cotire.cmake") +endif() + + + +include(${current_dir}/sources.cmake) + +set(WBLIB_STATIC ${WBLIB}) +set(WBLIB_SHARED lib${WBLIB}) + +add_library(${WBLIB_STATIC} STATIC ${LIBWB_SOURCE_FILES} ) +add_library(${WBLIB_SHARED} SHARED ${LIBWB_SOURCE_FILES} ) +set_property(TARGET ${WBLIB_STATIC} PROPERTY CXX_STANDARD 11) +set_property(TARGET ${WBLIB_SHARED} PROPERTY CXX_STANDARD 11) +if (UNIX) + set_target_properties(${WBLIB_SHARED} PROPERTIES OUTPUT_NAME ${WBLIB_STATIC}) +endif (UNIX) +set_property(TARGET ${WBLIB} PROPERTY CXX_STANDARD 11) diff --git a/CUDA_BasicMatrixMultiplication/libwb/LICENSE.TXT b/CUDA_BasicMatrixMultiplication/libwb/LICENSE.TXT new file mode 100644 index 0000000..8df244d --- /dev/null +++ b/CUDA_BasicMatrixMultiplication/libwb/LICENSE.TXT @@ -0,0 +1,36 @@ +Copyright (c) 2016, Abdul Dakkak All rights reserved. + +Developed by: Abdul Dakkak + IMPACT Group + University of Illinois, Urbana-Champaign + impact.crhc.illinois.edu + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal with the +Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, +sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +Redistributions of source code must retain the above +copyright notice, this list of conditions and the following +disclaimers. +Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following +disclaimers in the documentation and/or other materials +provided with the distribution. +Neither the names of Abdul Dakkak, Impact Group, nor the +names of its contributors may be used to endorse or promote +products derived from this Software without specific prior +written permission. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +WITH THE SOFTWARE. diff --git a/CUDA_BasicMatrixMultiplication/libwb/Makefile b/CUDA_BasicMatrixMultiplication/libwb/Makefile new file mode 100644 index 0000000..b8a72d7 --- /dev/null +++ b/CUDA_BasicMatrixMultiplication/libwb/Makefile @@ -0,0 +1,56 @@ +########################################## +# Options +########################################## +WB_LIB_PATH=$(CURDIR)/lib +WB_SRC_PATH=$(CURDIR) + +########################################## +########################################## + +DEFINES= +CXX_FLAGS=-fPIC -Wno-unused-function -x c++ -O3 -g -std=c++11 -Wall -Wno-unused-function -pedantic -I . -I $(WB_SRC_PATH) $(DEFINES) +LIBS=-lm -lstdc++ + +########################################## +########################################## + +UNAME_S := $(shell uname -s) +ifeq ($(UNAME_S),Linux) + LIBS += -lrt +endif + +########################################## +########################################## + +SOURCES := $(shell find $(WB_SRC_PATH) ! -name "*_test.cpp" -name "*.cpp") +TESTS := $(shell find $(WB_SRC_PATH) -name "*_test.cpp") + +OBJECTS = $(SOURCES:.cpp=.o) +TESTOBJECTS = $(TESTS:.cpp=.o) + +############################################## +# OUTPUT +############################################## + +.PHONY: all +.SUFFIXES: .o .cpp +all: libwb.so + +.cpp.o: + $(CXX) $(DEFINES) $(CXX_FLAGS) -c -o $@ $< + +libwb.so: $(OBJECTS) + mkdir -p $(WB_LIB_PATH) + $(CXX) -fPIC -shared -o $(WB_LIB_PATH)/$@ $(OBJECTS) $(LIBS) + +libwb.a: $(OBJECTS) + mkdir -p $(WB_LIB_PATH) + ar rcs -o $(WB_LIB_PATH)/$@ $(OBJECTS) + +test: $(TESTOBJECTS) $(OBJECTS) + $(CXX) -fPIC -o $@ $(TESTOBJECTS) $(OBJECTS) $(LIBS) + + +clean: + rm -fr $(ARCH) + -rm -f $(EXES) *.o *~ \ No newline at end of file diff --git a/CUDA_BasicMatrixMultiplication/libwb/README.md b/CUDA_BasicMatrixMultiplication/libwb/README.md new file mode 100644 index 0000000..0486f93 --- /dev/null +++ b/CUDA_BasicMatrixMultiplication/libwb/README.md @@ -0,0 +1,7 @@ + +# libWB + +[![Travis Build Status](https://travis-ci.org/abduld/libwb.svg?branch=master)](https://travis-ci.org/abduld/libwb) +[![AppVeyor status](https://ci.appveyor.com/api/projects/status/0nx5ie7gn5c0e6ai/branch/master?svg=true)](https://ci.appveyor.com/project/abduld/libwb/branch/master) + \ No newline at end of file diff --git a/CUDA_BasicMatrixMultiplication/libwb/appveyor.yml b/CUDA_BasicMatrixMultiplication/libwb/appveyor.yml new file mode 100644 index 0000000..e7a6c95 --- /dev/null +++ b/CUDA_BasicMatrixMultiplication/libwb/appveyor.yml @@ -0,0 +1,54 @@ + + +# Operating system (build VM template) +os: + - Visual Studio 2015 + + +# scripts that are called at very beginning, before repo cloning +init: + - echo init step + - git config --global core.autocrlf input + - cmake --version + - C:\"Program Files (x86)"\"Microsoft Visual Studio 14.0"\VC\vcvarsall.bat %PLATFORM% + +# clone directory +clone_folder: c:\projects\libwb +# fetch repository as zip archive +shallow_clone: true # default is "false" + +# branches to build +branches: + # whitelist + only: + - master + +platform: + - x64 +configuration: + - Release + +environment: + P: "c:/projects/libs" + + +install: + # by default, all script lines are interpreted as batch + +build: + project: ALL_BUILD.vcxproj # path to Visual Studio solution or project + +# scripts to run before build +before_build: + - echo Running cmake... + - cd c:\projects\libwb + - cmake -G "Visual Studio 14 2015 Win64" -DCMAKE_INSTALL_PREFIX=%P% + +# after_build: +# - echo after_build step + + +# on_finish always executes regardless of passed or failed builds +# on_finish: +# - echo on_finish step +# - ps: ls \ No newline at end of file diff --git a/CUDA_BasicMatrixMultiplication/libwb/sources.cmake b/CUDA_BasicMatrixMultiplication/libwb/sources.cmake new file mode 100644 index 0000000..4ac1b10 --- /dev/null +++ b/CUDA_BasicMatrixMultiplication/libwb/sources.cmake @@ -0,0 +1,31 @@ + +set(WBLIB "wb") + +include_directories(${CMAKE_CURRENT_LIST_DIR}) + +file(GLOB THESE_CPP_FILES + ${CMAKE_CURRENT_LIST_DIR}/*.cpp +) + +file(GLOB THESE_TEST_FILES + ${CMAKE_CURRENT_LIST_DIR}/*_test.cpp +) + +list(REMOVE_ITEM THESE_CPP_FILES ${THESE_TEST_FILES}) + +file(GLOB THESE_HEADER_FILES + ${CMAKE_CURRENT_LIST_DIR}/*.h +) + +list(APPEND LIBWB_HEADER_FILES + ${THESE_HEADER_FILES} +) + +list(APPEND LIBWB_SOURCE_FILES + ${THESE_CPP_FILES} + ${CMAKE_CURRENT_LIST_DIR}/vendor/json11.cpp +) + +list(APPEND LIBWB_TEST_FILES + ${THESE_TEST_FILES} +) diff --git a/CUDA_BasicMatrixMultiplication/libwb/vendor/catch.hpp b/CUDA_BasicMatrixMultiplication/libwb/vendor/catch.hpp new file mode 100644 index 0000000..f52eebd --- /dev/null +++ b/CUDA_BasicMatrixMultiplication/libwb/vendor/catch.hpp @@ -0,0 +1,10414 @@ +/* + * Catch v1.3.6 + * Generated: 2016-03-11 18:30:42.852700 + * ---------------------------------------------------------- + * This file has been merged from multiple headers. Please don't edit it directly + * Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved. + * + * Distributed under the Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + */ +#ifndef TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED +#define TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED + +#define TWOBLUECUBES_CATCH_HPP_INCLUDED + +#ifdef __clang__ +# pragma clang system_header +#elif defined __GNUC__ +# pragma GCC system_header +#endif + +// #included from: internal/catch_suppress_warnings.h + +#ifdef __clang__ +# ifdef __ICC // icpc defines the __clang__ macro +# pragma warning(push) +# pragma warning(disable: 161 1682) +# else // __ICC +# pragma clang diagnostic ignored "-Wglobal-constructors" +# pragma clang diagnostic ignored "-Wvariadic-macros" +# pragma clang diagnostic ignored "-Wc99-extensions" +# pragma clang diagnostic ignored "-Wunused-variable" +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wpadded" +# pragma clang diagnostic ignored "-Wc++98-compat" +# pragma clang diagnostic ignored "-Wc++98-compat-pedantic" +# pragma clang diagnostic ignored "-Wswitch-enum" +# pragma clang diagnostic ignored "-Wcovered-switch-default" +# endif +#elif defined __GNUC__ +# pragma GCC diagnostic ignored "-Wvariadic-macros" +# pragma GCC diagnostic ignored "-Wunused-variable" +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wpadded" +#endif +#if defined(CATCH_CONFIG_MAIN) || defined(CATCH_CONFIG_RUNNER) +# define CATCH_IMPL +#endif + +#ifdef CATCH_IMPL +# ifndef CLARA_CONFIG_MAIN +# define CLARA_CONFIG_MAIN_NOT_DEFINED +# define CLARA_CONFIG_MAIN +# endif +#endif + +// #included from: internal/catch_notimplemented_exception.h +#define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_H_INCLUDED + +// #included from: catch_common.h +#define TWOBLUECUBES_CATCH_COMMON_H_INCLUDED + +#define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line +#define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) +#define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ ) + +#define INTERNAL_CATCH_STRINGIFY2( expr ) #expr +#define INTERNAL_CATCH_STRINGIFY( expr ) INTERNAL_CATCH_STRINGIFY2( expr ) + +#include +#include +#include + +// #included from: catch_compiler_capabilities.h +#define TWOBLUECUBES_CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED + +// Detect a number of compiler features - mostly C++11/14 conformance - by compiler +// The following features are defined: +// +// CATCH_CONFIG_CPP11_NULLPTR : is nullptr supported? +// CATCH_CONFIG_CPP11_NOEXCEPT : is noexcept supported? +// CATCH_CONFIG_CPP11_GENERATED_METHODS : The delete and default keywords for compiler generated methods +// CATCH_CONFIG_CPP11_IS_ENUM : std::is_enum is supported? +// CATCH_CONFIG_CPP11_TUPLE : std::tuple is supported +// CATCH_CONFIG_CPP11_LONG_LONG : is long long supported? +// CATCH_CONFIG_CPP11_OVERRIDE : is override supported? +// CATCH_CONFIG_CPP11_UNIQUE_PTR : is unique_ptr supported (otherwise use auto_ptr) + +// CATCH_CONFIG_CPP11_OR_GREATER : Is C++11 supported? + +// CATCH_CONFIG_VARIADIC_MACROS : are variadic macros supported? + +// **************** +// Note to maintainers: if new toggles are added please document them +// in configuration.md, too +// **************** + +// In general each macro has a _NO_ form +// (e.g. CATCH_CONFIG_CPP11_NO_NULLPTR) which disables the feature. +// Many features, at point of detection, define an _INTERNAL_ macro, so they +// can be combined, en-mass, with the _NO_ forms later. + +// All the C++11 features can be disabled with CATCH_CONFIG_NO_CPP11 + +#if defined(__cplusplus) && __cplusplus >= 201103L +# define CATCH_CPP11_OR_GREATER +#endif + +#ifdef __clang__ + +# if __has_feature(cxx_nullptr) +# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR +# endif + +# if __has_feature(cxx_noexcept) +# define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT +# endif + +# if defined(CATCH_CPP11_OR_GREATER) +# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS _Pragma( "clang diagnostic ignored \"-Wparentheses\"" ) +# endif + +#endif // __clang__ + +//////////////////////////////////////////////////////////////////////////////// +// Borland +#ifdef __BORLANDC__ + +#endif // __BORLANDC__ + +//////////////////////////////////////////////////////////////////////////////// +// EDG +#ifdef __EDG_VERSION__ + +#endif // __EDG_VERSION__ + +//////////////////////////////////////////////////////////////////////////////// +// Digital Mars +#ifdef __DMC__ + +#endif // __DMC__ + +//////////////////////////////////////////////////////////////////////////////// +// GCC +#ifdef __GNUC__ + +# if __GNUC__ == 4 && __GNUC_MINOR__ >= 6 && defined(__GXX_EXPERIMENTAL_CXX0X__) +# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR +# endif + +# if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS) && defined(CATCH_CPP11_OR_GREATER) +# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS _Pragma( "GCC diagnostic ignored \"-Wparentheses\"" ) +# endif + +// - otherwise more recent versions define __cplusplus >= 201103L +// and will get picked up below + +#endif // __GNUC__ + +//////////////////////////////////////////////////////////////////////////////// +// Visual C++ +#ifdef _MSC_VER + +#if (_MSC_VER >= 1600) +# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR +# define CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR +#endif + +#if (_MSC_VER >= 1900 ) // (VC++ 13 (VS2015)) +#define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT +#define CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS +#endif + +#endif // _MSC_VER + +//////////////////////////////////////////////////////////////////////////////// + +// Use variadic macros if the compiler supports them +#if ( defined _MSC_VER && _MSC_VER > 1400 && !defined __EDGE__) || \ + ( defined __WAVE__ && __WAVE_HAS_VARIADICS ) || \ + ( defined __GNUC__ && __GNUC__ >= 3 ) || \ + ( !defined __cplusplus && __STDC_VERSION__ >= 199901L || __cplusplus >= 201103L ) + +#define CATCH_INTERNAL_CONFIG_VARIADIC_MACROS + +#endif + +//////////////////////////////////////////////////////////////////////////////// +// C++ language feature support + +// catch all support for C++11 +#if defined(CATCH_CPP11_OR_GREATER) + +# if !defined(CATCH_INTERNAL_CONFIG_CPP11_NULLPTR) +# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR +# endif + +# ifndef CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT +# define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT +# endif + +# ifndef CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS +# define CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS +# endif + +# ifndef CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM +# define CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM +# endif + +# ifndef CATCH_INTERNAL_CONFIG_CPP11_TUPLE +# define CATCH_INTERNAL_CONFIG_CPP11_TUPLE +# endif + +# ifndef CATCH_INTERNAL_CONFIG_VARIADIC_MACROS +# define CATCH_INTERNAL_CONFIG_VARIADIC_MACROS +# endif + +# if !defined(CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG) +# define CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG +# endif + +# if !defined(CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE) +# define CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE +# endif +# if !defined(CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) +# define CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR +# endif + +#endif // __cplusplus >= 201103L + +// Now set the actual defines based on the above + anything the user has configured +#if defined(CATCH_INTERNAL_CONFIG_CPP11_NULLPTR) && !defined(CATCH_CONFIG_CPP11_NO_NULLPTR) && !defined(CATCH_CONFIG_CPP11_NULLPTR) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_NULLPTR +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_CONFIG_CPP11_NO_NOEXCEPT) && !defined(CATCH_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_NOEXCEPT +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS) && !defined(CATCH_CONFIG_CPP11_NO_GENERATED_METHODS) && !defined(CATCH_CONFIG_CPP11_GENERATED_METHODS) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_GENERATED_METHODS +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM) && !defined(CATCH_CONFIG_CPP11_NO_IS_ENUM) && !defined(CATCH_CONFIG_CPP11_IS_ENUM) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_IS_ENUM +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_TUPLE) && !defined(CATCH_CONFIG_CPP11_NO_TUPLE) && !defined(CATCH_CONFIG_CPP11_TUPLE) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_TUPLE +#endif +#if defined(CATCH_INTERNAL_CONFIG_VARIADIC_MACROS) && !defined(CATCH_CONFIG_NO_VARIADIC_MACROS) && !defined(CATCH_CONFIG_VARIADIC_MACROS) +# define CATCH_CONFIG_VARIADIC_MACROS +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG) && !defined(CATCH_CONFIG_NO_LONG_LONG) && !defined(CATCH_CONFIG_CPP11_LONG_LONG) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_LONG_LONG +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE) && !defined(CATCH_CONFIG_NO_OVERRIDE) && !defined(CATCH_CONFIG_CPP11_OVERRIDE) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_OVERRIDE +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) && !defined(CATCH_CONFIG_NO_UNIQUE_PTR) && !defined(CATCH_CONFIG_CPP11_UNIQUE_PTR) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_UNIQUE_PTR +#endif + +#if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS) +# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS +#endif + +// noexcept support: +#if defined(CATCH_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_NOEXCEPT) +# define CATCH_NOEXCEPT noexcept +# define CATCH_NOEXCEPT_IS(x) noexcept(x) +#else +# define CATCH_NOEXCEPT throw() +# define CATCH_NOEXCEPT_IS(x) +#endif + +// nullptr support +#ifdef CATCH_CONFIG_CPP11_NULLPTR +# define CATCH_NULL nullptr +#else +# define CATCH_NULL NULL +#endif + +// override support +#ifdef CATCH_CONFIG_CPP11_OVERRIDE +# define CATCH_OVERRIDE override +#else +# define CATCH_OVERRIDE +#endif + +// unique_ptr support +#ifdef CATCH_CONFIG_CPP11_UNIQUE_PTR +# define CATCH_AUTO_PTR( T ) std::unique_ptr +#else +# define CATCH_AUTO_PTR( T ) std::auto_ptr +#endif + +namespace Catch { + + struct IConfig; + + struct CaseSensitive { enum Choice { + Yes, + No + }; }; + + class NonCopyable { +#ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + NonCopyable( NonCopyable const& ) = delete; + NonCopyable( NonCopyable && ) = delete; + NonCopyable& operator = ( NonCopyable const& ) = delete; + NonCopyable& operator = ( NonCopyable && ) = delete; +#else + NonCopyable( NonCopyable const& info ); + NonCopyable& operator = ( NonCopyable const& ); +#endif + + protected: + NonCopyable() {} + virtual ~NonCopyable(); + }; + + class SafeBool { + public: + typedef void (SafeBool::*type)() const; + + static type makeSafe( bool value ) { + return value ? &SafeBool::trueValue : 0; + } + private: + void trueValue() const {} + }; + + template + inline void deleteAll( ContainerT& container ) { + typename ContainerT::const_iterator it = container.begin(); + typename ContainerT::const_iterator itEnd = container.end(); + for(; it != itEnd; ++it ) + delete *it; + } + template + inline void deleteAllValues( AssociativeContainerT& container ) { + typename AssociativeContainerT::const_iterator it = container.begin(); + typename AssociativeContainerT::const_iterator itEnd = container.end(); + for(; it != itEnd; ++it ) + delete it->second; + } + + bool startsWith( std::string const& s, std::string const& prefix ); + bool endsWith( std::string const& s, std::string const& suffix ); + bool contains( std::string const& s, std::string const& infix ); + void toLowerInPlace( std::string& s ); + std::string toLower( std::string const& s ); + std::string trim( std::string const& str ); + bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ); + + struct pluralise { + pluralise( std::size_t count, std::string const& label ); + + friend std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ); + + std::size_t m_count; + std::string m_label; + }; + + struct SourceLineInfo { + + SourceLineInfo(); + SourceLineInfo( char const* _file, std::size_t _line ); + SourceLineInfo( SourceLineInfo const& other ); +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + SourceLineInfo( SourceLineInfo && ) = default; + SourceLineInfo& operator = ( SourceLineInfo const& ) = default; + SourceLineInfo& operator = ( SourceLineInfo && ) = default; +# endif + bool empty() const; + bool operator == ( SourceLineInfo const& other ) const; + bool operator < ( SourceLineInfo const& other ) const; + + std::string file; + std::size_t line; + }; + + std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ); + + // This is just here to avoid compiler warnings with macro constants and boolean literals + inline bool isTrue( bool value ){ return value; } + inline bool alwaysTrue() { return true; } + inline bool alwaysFalse() { return false; } + + void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo ); + + void seedRng( IConfig const& config ); + unsigned int rngSeed(); + + // Use this in variadic streaming macros to allow + // >> +StreamEndStop + // as well as + // >> stuff +StreamEndStop + struct StreamEndStop { + std::string operator+() { + return std::string(); + } + }; + template + T const& operator + ( T const& value, StreamEndStop ) { + return value; + } +} + +#define CATCH_INTERNAL_LINEINFO ::Catch::SourceLineInfo( __FILE__, static_cast( __LINE__ ) ) +#define CATCH_INTERNAL_ERROR( msg ) ::Catch::throwLogicError( msg, CATCH_INTERNAL_LINEINFO ); + +#include + +namespace Catch { + + class NotImplementedException : public std::exception + { + public: + NotImplementedException( SourceLineInfo const& lineInfo ); + NotImplementedException( NotImplementedException const& ) {} + + virtual ~NotImplementedException() CATCH_NOEXCEPT {} + + virtual const char* what() const CATCH_NOEXCEPT; + + private: + std::string m_what; + SourceLineInfo m_lineInfo; + }; + +} // end namespace Catch + +/////////////////////////////////////////////////////////////////////////////// +#define CATCH_NOT_IMPLEMENTED throw Catch::NotImplementedException( CATCH_INTERNAL_LINEINFO ) + +// #included from: internal/catch_context.h +#define TWOBLUECUBES_CATCH_CONTEXT_H_INCLUDED + +// #included from: catch_interfaces_generators.h +#define TWOBLUECUBES_CATCH_INTERFACES_GENERATORS_H_INCLUDED + +#include + +namespace Catch { + + struct IGeneratorInfo { + virtual ~IGeneratorInfo(); + virtual bool moveNext() = 0; + virtual std::size_t getCurrentIndex() const = 0; + }; + + struct IGeneratorsForTest { + virtual ~IGeneratorsForTest(); + + virtual IGeneratorInfo& getGeneratorInfo( std::string const& fileInfo, std::size_t size ) = 0; + virtual bool moveNext() = 0; + }; + + IGeneratorsForTest* createGeneratorsForTest(); + +} // end namespace Catch + +// #included from: catch_ptr.hpp +#define TWOBLUECUBES_CATCH_PTR_HPP_INCLUDED + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpadded" +#endif + +namespace Catch { + + // An intrusive reference counting smart pointer. + // T must implement addRef() and release() methods + // typically implementing the IShared interface + template + class Ptr { + public: + Ptr() : m_p( CATCH_NULL ){} + Ptr( T* p ) : m_p( p ){ + if( m_p ) + m_p->addRef(); + } + Ptr( Ptr const& other ) : m_p( other.m_p ){ + if( m_p ) + m_p->addRef(); + } + ~Ptr(){ + if( m_p ) + m_p->release(); + } + void reset() { + if( m_p ) + m_p->release(); + m_p = CATCH_NULL; + } + Ptr& operator = ( T* p ){ + Ptr temp( p ); + swap( temp ); + return *this; + } + Ptr& operator = ( Ptr const& other ){ + Ptr temp( other ); + swap( temp ); + return *this; + } + void swap( Ptr& other ) { std::swap( m_p, other.m_p ); } + T* get() const{ return m_p; } + T& operator*() const { return *m_p; } + T* operator->() const { return m_p; } + bool operator !() const { return m_p == CATCH_NULL; } + operator SafeBool::type() const { return SafeBool::makeSafe( m_p != CATCH_NULL ); } + + private: + T* m_p; + }; + + struct IShared : NonCopyable { + virtual ~IShared(); + virtual void addRef() const = 0; + virtual void release() const = 0; + }; + + template + struct SharedImpl : T { + + SharedImpl() : m_rc( 0 ){} + + virtual void addRef() const { + ++m_rc; + } + virtual void release() const { + if( --m_rc == 0 ) + delete this; + } + + mutable unsigned int m_rc; + }; + +} // end namespace Catch + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +#include +#include +#include + +namespace Catch { + + class TestCase; + class Stream; + struct IResultCapture; + struct IRunner; + struct IGeneratorsForTest; + struct IConfig; + + struct IContext + { + virtual ~IContext(); + + virtual IResultCapture* getResultCapture() = 0; + virtual IRunner* getRunner() = 0; + virtual size_t getGeneratorIndex( std::string const& fileInfo, size_t totalSize ) = 0; + virtual bool advanceGeneratorsForCurrentTest() = 0; + virtual Ptr getConfig() const = 0; + }; + + struct IMutableContext : IContext + { + virtual ~IMutableContext(); + virtual void setResultCapture( IResultCapture* resultCapture ) = 0; + virtual void setRunner( IRunner* runner ) = 0; + virtual void setConfig( Ptr const& config ) = 0; + }; + + IContext& getCurrentContext(); + IMutableContext& getCurrentMutableContext(); + void cleanUpContext(); + Stream createStream( std::string const& streamName ); + +} + +// #included from: internal/catch_test_registry.hpp +#define TWOBLUECUBES_CATCH_TEST_REGISTRY_HPP_INCLUDED + +// #included from: catch_interfaces_testcase.h +#define TWOBLUECUBES_CATCH_INTERFACES_TESTCASE_H_INCLUDED + +#include + +namespace Catch { + + class TestSpec; + + struct ITestCase : IShared { + virtual void invoke () const = 0; + protected: + virtual ~ITestCase(); + }; + + class TestCase; + struct IConfig; + + struct ITestCaseRegistry { + virtual ~ITestCaseRegistry(); + virtual std::vector const& getAllTests() const = 0; + virtual std::vector const& getAllTestsSorted( IConfig const& config ) const = 0; + }; + + bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ); + std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ); + std::vector const& getAllTestCasesSorted( IConfig const& config ); + +} + +namespace Catch { + +template +class MethodTestCase : public SharedImpl { + +public: + MethodTestCase( void (C::*method)() ) : m_method( method ) {} + + virtual void invoke() const { + C obj; + (obj.*m_method)(); + } + +private: + virtual ~MethodTestCase() {} + + void (C::*m_method)(); +}; + +typedef void(*TestFunction)(); + +struct NameAndDesc { + NameAndDesc( const char* _name = "", const char* _description= "" ) + : name( _name ), description( _description ) + {} + + const char* name; + const char* description; +}; + +void registerTestCase + ( ITestCase* testCase, + char const* className, + NameAndDesc const& nameAndDesc, + SourceLineInfo const& lineInfo ); + +struct AutoReg { + + AutoReg + ( TestFunction function, + SourceLineInfo const& lineInfo, + NameAndDesc const& nameAndDesc ); + + template + AutoReg + ( void (C::*method)(), + char const* className, + NameAndDesc const& nameAndDesc, + SourceLineInfo const& lineInfo ) { + + registerTestCase + ( new MethodTestCase( method ), + className, + nameAndDesc, + lineInfo ); + } + + ~AutoReg(); + +private: + AutoReg( AutoReg const& ); + void operator= ( AutoReg const& ); +}; + +void registerTestCaseFunction + ( TestFunction function, + SourceLineInfo const& lineInfo, + NameAndDesc const& nameAndDesc ); + +} // end namespace Catch + +#ifdef CATCH_CONFIG_VARIADIC_MACROS + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_TESTCASE( ... ) \ + static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )(); \ + namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( __VA_ARGS__ ) ); }\ + static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )() + + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \ + namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); } + + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, ... )\ + namespace{ \ + struct INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ) : ClassName{ \ + void test(); \ + }; \ + Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test, #ClassName, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); \ + } \ + void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test() + + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, ... ) \ + Catch::AutoReg( Function, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( __VA_ARGS__ ) ); + +#else + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_TESTCASE( Name, Desc ) \ + static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )(); \ + namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( Name, Desc ) ); }\ + static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )() + + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, Name, Desc ) \ + namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( Name, Desc ), CATCH_INTERNAL_LINEINFO ); } + + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, TestName, Desc )\ + namespace{ \ + struct INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ) : ClassName{ \ + void test(); \ + }; \ + Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test, #ClassName, Catch::NameAndDesc( TestName, Desc ), CATCH_INTERNAL_LINEINFO ); \ + } \ + void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test() + + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, Name, Desc ) \ + Catch::AutoReg( Function, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( Name, Desc ) ); +#endif + +// #included from: internal/catch_capture.hpp +#define TWOBLUECUBES_CATCH_CAPTURE_HPP_INCLUDED + +// #included from: catch_result_builder.h +#define TWOBLUECUBES_CATCH_RESULT_BUILDER_H_INCLUDED + +// #included from: catch_result_type.h +#define TWOBLUECUBES_CATCH_RESULT_TYPE_H_INCLUDED + +namespace Catch { + + // ResultWas::OfType enum + struct ResultWas { enum OfType { + Unknown = -1, + Ok = 0, + Info = 1, + Warning = 2, + + FailureBit = 0x10, + + ExpressionFailed = FailureBit | 1, + ExplicitFailure = FailureBit | 2, + + Exception = 0x100 | FailureBit, + + ThrewException = Exception | 1, + DidntThrowException = Exception | 2, + + FatalErrorCondition = 0x200 | FailureBit + + }; }; + + inline bool isOk( ResultWas::OfType resultType ) { + return ( resultType & ResultWas::FailureBit ) == 0; + } + inline bool isJustInfo( int flags ) { + return flags == ResultWas::Info; + } + + // ResultDisposition::Flags enum + struct ResultDisposition { enum Flags { + Normal = 0x01, + + ContinueOnFailure = 0x02, // Failures fail test, but execution continues + FalseTest = 0x04, // Prefix expression with ! + SuppressFail = 0x08 // Failures are reported but do not fail the test + }; }; + + inline ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs ) { + return static_cast( static_cast( lhs ) | static_cast( rhs ) ); + } + + inline bool shouldContinueOnFailure( int flags ) { return ( flags & ResultDisposition::ContinueOnFailure ) != 0; } + inline bool isFalseTest( int flags ) { return ( flags & ResultDisposition::FalseTest ) != 0; } + inline bool shouldSuppressFailure( int flags ) { return ( flags & ResultDisposition::SuppressFail ) != 0; } + +} // end namespace Catch + +// #included from: catch_assertionresult.h +#define TWOBLUECUBES_CATCH_ASSERTIONRESULT_H_INCLUDED + +#include + +namespace Catch { + + struct AssertionInfo + { + AssertionInfo() {} + AssertionInfo( std::string const& _macroName, + SourceLineInfo const& _lineInfo, + std::string const& _capturedExpression, + ResultDisposition::Flags _resultDisposition ); + + std::string macroName; + SourceLineInfo lineInfo; + std::string capturedExpression; + ResultDisposition::Flags resultDisposition; + }; + + struct AssertionResultData + { + AssertionResultData() : resultType( ResultWas::Unknown ) {} + + std::string reconstructedExpression; + std::string message; + ResultWas::OfType resultType; + }; + + class AssertionResult { + public: + AssertionResult(); + AssertionResult( AssertionInfo const& info, AssertionResultData const& data ); + ~AssertionResult(); +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + AssertionResult( AssertionResult const& ) = default; + AssertionResult( AssertionResult && ) = default; + AssertionResult& operator = ( AssertionResult const& ) = default; + AssertionResult& operator = ( AssertionResult && ) = default; +# endif + + bool isOk() const; + bool succeeded() const; + ResultWas::OfType getResultType() const; + bool hasExpression() const; + bool hasMessage() const; + std::string getExpression() const; + std::string getExpressionInMacro() const; + bool hasExpandedExpression() const; + std::string getExpandedExpression() const; + std::string getMessage() const; + SourceLineInfo getSourceInfo() const; + std::string getTestMacroName() const; + + protected: + AssertionInfo m_info; + AssertionResultData m_resultData; + }; + +} // end namespace Catch + +// #included from: catch_matchers.hpp +#define TWOBLUECUBES_CATCH_MATCHERS_HPP_INCLUDED + +namespace Catch { +namespace Matchers { + namespace Impl { + + namespace Generic { + template class AllOf; + template class AnyOf; + template class Not; + } + + template + struct Matcher : SharedImpl + { + typedef ExpressionT ExpressionType; + + virtual ~Matcher() {} + virtual Ptr clone() const = 0; + virtual bool match( ExpressionT const& expr ) const = 0; + virtual std::string toString() const = 0; + + Generic::AllOf operator && ( Matcher const& other ) const; + Generic::AnyOf operator || ( Matcher const& other ) const; + Generic::Not operator ! () const; + }; + + template + struct MatcherImpl : Matcher { + + virtual Ptr > clone() const { + return Ptr >( new DerivedT( static_cast( *this ) ) ); + } + }; + + namespace Generic { + template + class Not : public MatcherImpl, ExpressionT> { + public: + explicit Not( Matcher const& matcher ) : m_matcher(matcher.clone()) {} + Not( Not const& other ) : m_matcher( other.m_matcher ) {} + + virtual bool match( ExpressionT const& expr ) const CATCH_OVERRIDE { + return !m_matcher->match( expr ); + } + + virtual std::string toString() const CATCH_OVERRIDE { + return "not " + m_matcher->toString(); + } + private: + Ptr< Matcher > m_matcher; + }; + + template + class AllOf : public MatcherImpl, ExpressionT> { + public: + + AllOf() {} + AllOf( AllOf const& other ) : m_matchers( other.m_matchers ) {} + + AllOf& add( Matcher const& matcher ) { + m_matchers.push_back( matcher.clone() ); + return *this; + } + virtual bool match( ExpressionT const& expr ) const + { + for( std::size_t i = 0; i < m_matchers.size(); ++i ) + if( !m_matchers[i]->match( expr ) ) + return false; + return true; + } + virtual std::string toString() const { + std::ostringstream oss; + oss << "( "; + for( std::size_t i = 0; i < m_matchers.size(); ++i ) { + if( i != 0 ) + oss << " and "; + oss << m_matchers[i]->toString(); + } + oss << " )"; + return oss.str(); + } + + AllOf operator && ( Matcher const& other ) const { + AllOf allOfExpr( *this ); + allOfExpr.add( other ); + return allOfExpr; + } + + private: + std::vector > > m_matchers; + }; + + template + class AnyOf : public MatcherImpl, ExpressionT> { + public: + + AnyOf() {} + AnyOf( AnyOf const& other ) : m_matchers( other.m_matchers ) {} + + AnyOf& add( Matcher const& matcher ) { + m_matchers.push_back( matcher.clone() ); + return *this; + } + virtual bool match( ExpressionT const& expr ) const + { + for( std::size_t i = 0; i < m_matchers.size(); ++i ) + if( m_matchers[i]->match( expr ) ) + return true; + return false; + } + virtual std::string toString() const { + std::ostringstream oss; + oss << "( "; + for( std::size_t i = 0; i < m_matchers.size(); ++i ) { + if( i != 0 ) + oss << " or "; + oss << m_matchers[i]->toString(); + } + oss << " )"; + return oss.str(); + } + + AnyOf operator || ( Matcher const& other ) const { + AnyOf anyOfExpr( *this ); + anyOfExpr.add( other ); + return anyOfExpr; + } + + private: + std::vector > > m_matchers; + }; + + } // namespace Generic + + template + Generic::AllOf Matcher::operator && ( Matcher const& other ) const { + Generic::AllOf allOfExpr; + allOfExpr.add( *this ); + allOfExpr.add( other ); + return allOfExpr; + } + + template + Generic::AnyOf Matcher::operator || ( Matcher const& other ) const { + Generic::AnyOf anyOfExpr; + anyOfExpr.add( *this ); + anyOfExpr.add( other ); + return anyOfExpr; + } + + template + Generic::Not Matcher::operator ! () const { + return Generic::Not( *this ); + } + + namespace StdString { + + inline std::string makeString( std::string const& str ) { return str; } + inline std::string makeString( const char* str ) { return str ? std::string( str ) : std::string(); } + + struct CasedString + { + CasedString( std::string const& str, CaseSensitive::Choice caseSensitivity ) + : m_caseSensitivity( caseSensitivity ), + m_str( adjustString( str ) ) + {} + std::string adjustString( std::string const& str ) const { + return m_caseSensitivity == CaseSensitive::No + ? toLower( str ) + : str; + + } + std::string toStringSuffix() const + { + return m_caseSensitivity == CaseSensitive::No + ? " (case insensitive)" + : ""; + } + CaseSensitive::Choice m_caseSensitivity; + std::string m_str; + }; + + struct Equals : MatcherImpl { + Equals( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) + : m_data( str, caseSensitivity ) + {} + Equals( Equals const& other ) : m_data( other.m_data ){} + + virtual ~Equals(); + + virtual bool match( std::string const& expr ) const { + return m_data.m_str == m_data.adjustString( expr );; + } + virtual std::string toString() const { + return "equals: \"" + m_data.m_str + "\"" + m_data.toStringSuffix(); + } + + CasedString m_data; + }; + + struct Contains : MatcherImpl { + Contains( std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) + : m_data( substr, caseSensitivity ){} + Contains( Contains const& other ) : m_data( other.m_data ){} + + virtual ~Contains(); + + virtual bool match( std::string const& expr ) const { + return m_data.adjustString( expr ).find( m_data.m_str ) != std::string::npos; + } + virtual std::string toString() const { + return "contains: \"" + m_data.m_str + "\"" + m_data.toStringSuffix(); + } + + CasedString m_data; + }; + + struct StartsWith : MatcherImpl { + StartsWith( std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) + : m_data( substr, caseSensitivity ){} + + StartsWith( StartsWith const& other ) : m_data( other.m_data ){} + + virtual ~StartsWith(); + + virtual bool match( std::string const& expr ) const { + return startsWith( m_data.adjustString( expr ), m_data.m_str ); + } + virtual std::string toString() const { + return "starts with: \"" + m_data.m_str + "\"" + m_data.toStringSuffix(); + } + + CasedString m_data; + }; + + struct EndsWith : MatcherImpl { + EndsWith( std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) + : m_data( substr, caseSensitivity ){} + EndsWith( EndsWith const& other ) : m_data( other.m_data ){} + + virtual ~EndsWith(); + + virtual bool match( std::string const& expr ) const { + return endsWith( m_data.adjustString( expr ), m_data.m_str ); + } + virtual std::string toString() const { + return "ends with: \"" + m_data.m_str + "\"" + m_data.toStringSuffix(); + } + + CasedString m_data; + }; + } // namespace StdString + } // namespace Impl + + // The following functions create the actual matcher objects. + // This allows the types to be inferred + template + inline Impl::Generic::Not Not( Impl::Matcher const& m ) { + return Impl::Generic::Not( m ); + } + + template + inline Impl::Generic::AllOf AllOf( Impl::Matcher const& m1, + Impl::Matcher const& m2 ) { + return Impl::Generic::AllOf().add( m1 ).add( m2 ); + } + template + inline Impl::Generic::AllOf AllOf( Impl::Matcher const& m1, + Impl::Matcher const& m2, + Impl::Matcher const& m3 ) { + return Impl::Generic::AllOf().add( m1 ).add( m2 ).add( m3 ); + } + template + inline Impl::Generic::AnyOf AnyOf( Impl::Matcher const& m1, + Impl::Matcher const& m2 ) { + return Impl::Generic::AnyOf().add( m1 ).add( m2 ); + } + template + inline Impl::Generic::AnyOf AnyOf( Impl::Matcher const& m1, + Impl::Matcher const& m2, + Impl::Matcher const& m3 ) { + return Impl::Generic::AnyOf().add( m1 ).add( m2 ).add( m3 ); + } + + inline Impl::StdString::Equals Equals( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) { + return Impl::StdString::Equals( str, caseSensitivity ); + } + inline Impl::StdString::Equals Equals( const char* str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) { + return Impl::StdString::Equals( Impl::StdString::makeString( str ), caseSensitivity ); + } + inline Impl::StdString::Contains Contains( std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) { + return Impl::StdString::Contains( substr, caseSensitivity ); + } + inline Impl::StdString::Contains Contains( const char* substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) { + return Impl::StdString::Contains( Impl::StdString::makeString( substr ), caseSensitivity ); + } + inline Impl::StdString::StartsWith StartsWith( std::string const& substr ) { + return Impl::StdString::StartsWith( substr ); + } + inline Impl::StdString::StartsWith StartsWith( const char* substr ) { + return Impl::StdString::StartsWith( Impl::StdString::makeString( substr ) ); + } + inline Impl::StdString::EndsWith EndsWith( std::string const& substr ) { + return Impl::StdString::EndsWith( substr ); + } + inline Impl::StdString::EndsWith EndsWith( const char* substr ) { + return Impl::StdString::EndsWith( Impl::StdString::makeString( substr ) ); + } + +} // namespace Matchers + +using namespace Matchers; + +} // namespace Catch + +namespace Catch { + + struct TestFailureException{}; + + template class ExpressionLhs; + + struct STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison; + + struct CopyableStream { + CopyableStream() {} + CopyableStream( CopyableStream const& other ) { + oss << other.oss.str(); + } + CopyableStream& operator=( CopyableStream const& other ) { + oss.str(""); + oss << other.oss.str(); + return *this; + } + std::ostringstream oss; + }; + + class ResultBuilder { + public: + ResultBuilder( char const* macroName, + SourceLineInfo const& lineInfo, + char const* capturedExpression, + ResultDisposition::Flags resultDisposition, + char const* secondArg = "" ); + + template + ExpressionLhs operator <= ( T const& operand ); + ExpressionLhs operator <= ( bool value ); + + template + ResultBuilder& operator << ( T const& value ) { + m_stream.oss << value; + return *this; + } + + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( RhsT const& ); + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || ( RhsT const& ); + + ResultBuilder& setResultType( ResultWas::OfType result ); + ResultBuilder& setResultType( bool result ); + ResultBuilder& setLhs( std::string const& lhs ); + ResultBuilder& setRhs( std::string const& rhs ); + ResultBuilder& setOp( std::string const& op ); + + void endExpression(); + + std::string reconstructExpression() const; + AssertionResult build() const; + + void useActiveException( ResultDisposition::Flags resultDisposition = ResultDisposition::Normal ); + void captureResult( ResultWas::OfType resultType ); + void captureExpression(); + void captureExpectedException( std::string const& expectedMessage ); + void captureExpectedException( Matchers::Impl::Matcher const& matcher ); + void handleResult( AssertionResult const& result ); + void react(); + bool shouldDebugBreak() const; + bool allowThrows() const; + + private: + AssertionInfo m_assertionInfo; + AssertionResultData m_data; + struct ExprComponents { + ExprComponents() : testFalse( false ) {} + bool testFalse; + std::string lhs, rhs, op; + } m_exprComponents; + CopyableStream m_stream; + + bool m_shouldDebugBreak; + bool m_shouldThrow; + }; + +} // namespace Catch + +// Include after due to circular dependency: +// #included from: catch_expression_lhs.hpp +#define TWOBLUECUBES_CATCH_EXPRESSION_LHS_HPP_INCLUDED + +// #included from: catch_evaluate.hpp +#define TWOBLUECUBES_CATCH_EVALUATE_HPP_INCLUDED + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable:4389) // '==' : signed/unsigned mismatch +#endif + +#include + +namespace Catch { +namespace Internal { + + enum Operator { + IsEqualTo, + IsNotEqualTo, + IsLessThan, + IsGreaterThan, + IsLessThanOrEqualTo, + IsGreaterThanOrEqualTo + }; + + template struct OperatorTraits { static const char* getName(){ return "*error*"; } }; + template<> struct OperatorTraits { static const char* getName(){ return "=="; } }; + template<> struct OperatorTraits { static const char* getName(){ return "!="; } }; + template<> struct OperatorTraits { static const char* getName(){ return "<"; } }; + template<> struct OperatorTraits { static const char* getName(){ return ">"; } }; + template<> struct OperatorTraits { static const char* getName(){ return "<="; } }; + template<> struct OperatorTraits{ static const char* getName(){ return ">="; } }; + + template + inline T& opCast(T const& t) { return const_cast(t); } + +// nullptr_t support based on pull request #154 from Konstantin Baumann +#ifdef CATCH_CONFIG_CPP11_NULLPTR + inline std::nullptr_t opCast(std::nullptr_t) { return nullptr; } +#endif // CATCH_CONFIG_CPP11_NULLPTR + + // So the compare overloads can be operator agnostic we convey the operator as a template + // enum, which is used to specialise an Evaluator for doing the comparison. + template + class Evaluator{}; + + template + struct Evaluator { + static bool evaluate( T1 const& lhs, T2 const& rhs) { + return bool( opCast( lhs ) == opCast( rhs ) ); + } + }; + template + struct Evaluator { + static bool evaluate( T1 const& lhs, T2 const& rhs ) { + return bool( opCast( lhs ) != opCast( rhs ) ); + } + }; + template + struct Evaluator { + static bool evaluate( T1 const& lhs, T2 const& rhs ) { + return bool( opCast( lhs ) < opCast( rhs ) ); + } + }; + template + struct Evaluator { + static bool evaluate( T1 const& lhs, T2 const& rhs ) { + return bool( opCast( lhs ) > opCast( rhs ) ); + } + }; + template + struct Evaluator { + static bool evaluate( T1 const& lhs, T2 const& rhs ) { + return bool( opCast( lhs ) >= opCast( rhs ) ); + } + }; + template + struct Evaluator { + static bool evaluate( T1 const& lhs, T2 const& rhs ) { + return bool( opCast( lhs ) <= opCast( rhs ) ); + } + }; + + template + bool applyEvaluator( T1 const& lhs, T2 const& rhs ) { + return Evaluator::evaluate( lhs, rhs ); + } + + // This level of indirection allows us to specialise for integer types + // to avoid signed/ unsigned warnings + + // "base" overload + template + bool compare( T1 const& lhs, T2 const& rhs ) { + return Evaluator::evaluate( lhs, rhs ); + } + + // unsigned X to int + template bool compare( unsigned int lhs, int rhs ) { + return applyEvaluator( lhs, static_cast( rhs ) ); + } + template bool compare( unsigned long lhs, int rhs ) { + return applyEvaluator( lhs, static_cast( rhs ) ); + } + template bool compare( unsigned char lhs, int rhs ) { + return applyEvaluator( lhs, static_cast( rhs ) ); + } + + // unsigned X to long + template bool compare( unsigned int lhs, long rhs ) { + return applyEvaluator( lhs, static_cast( rhs ) ); + } + template bool compare( unsigned long lhs, long rhs ) { + return applyEvaluator( lhs, static_cast( rhs ) ); + } + template bool compare( unsigned char lhs, long rhs ) { + return applyEvaluator( lhs, static_cast( rhs ) ); + } + + // int to unsigned X + template bool compare( int lhs, unsigned int rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( int lhs, unsigned long rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( int lhs, unsigned char rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + + // long to unsigned X + template bool compare( long lhs, unsigned int rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( long lhs, unsigned long rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( long lhs, unsigned char rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + + // pointer to long (when comparing against NULL) + template bool compare( long lhs, T* rhs ) { + return Evaluator::evaluate( reinterpret_cast( lhs ), rhs ); + } + template bool compare( T* lhs, long rhs ) { + return Evaluator::evaluate( lhs, reinterpret_cast( rhs ) ); + } + + // pointer to int (when comparing against NULL) + template bool compare( int lhs, T* rhs ) { + return Evaluator::evaluate( reinterpret_cast( lhs ), rhs ); + } + template bool compare( T* lhs, int rhs ) { + return Evaluator::evaluate( lhs, reinterpret_cast( rhs ) ); + } + +#ifdef CATCH_CONFIG_CPP11_LONG_LONG + // long long to unsigned X + template bool compare( long long lhs, unsigned int rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( long long lhs, unsigned long rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( long long lhs, unsigned long long rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( long long lhs, unsigned char rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + + // unsigned long long to X + template bool compare( unsigned long long lhs, int rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( unsigned long long lhs, long rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( unsigned long long lhs, long long rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( unsigned long long lhs, char rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + + // pointer to long long (when comparing against NULL) + template bool compare( long long lhs, T* rhs ) { + return Evaluator::evaluate( reinterpret_cast( lhs ), rhs ); + } + template bool compare( T* lhs, long long rhs ) { + return Evaluator::evaluate( lhs, reinterpret_cast( rhs ) ); + } +#endif // CATCH_CONFIG_CPP11_LONG_LONG + +#ifdef CATCH_CONFIG_CPP11_NULLPTR + // pointer to nullptr_t (when comparing against nullptr) + template bool compare( std::nullptr_t, T* rhs ) { + return Evaluator::evaluate( nullptr, rhs ); + } + template bool compare( T* lhs, std::nullptr_t ) { + return Evaluator::evaluate( lhs, nullptr ); + } +#endif // CATCH_CONFIG_CPP11_NULLPTR + +} // end of namespace Internal +} // end of namespace Catch + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +// #included from: catch_tostring.h +#define TWOBLUECUBES_CATCH_TOSTRING_H_INCLUDED + +#include +#include +#include +#include +#include + +#ifdef __OBJC__ +// #included from: catch_objc_arc.hpp +#define TWOBLUECUBES_CATCH_OBJC_ARC_HPP_INCLUDED + +#import + +#ifdef __has_feature +#define CATCH_ARC_ENABLED __has_feature(objc_arc) +#else +#define CATCH_ARC_ENABLED 0 +#endif + +void arcSafeRelease( NSObject* obj ); +id performOptionalSelector( id obj, SEL sel ); + +#if !CATCH_ARC_ENABLED +inline void arcSafeRelease( NSObject* obj ) { + [obj release]; +} +inline id performOptionalSelector( id obj, SEL sel ) { + if( [obj respondsToSelector: sel] ) + return [obj performSelector: sel]; + return nil; +} +#define CATCH_UNSAFE_UNRETAINED +#define CATCH_ARC_STRONG +#else +inline void arcSafeRelease( NSObject* ){} +inline id performOptionalSelector( id obj, SEL sel ) { +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Warc-performSelector-leaks" +#endif + if( [obj respondsToSelector: sel] ) + return [obj performSelector: sel]; +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + return nil; +} +#define CATCH_UNSAFE_UNRETAINED __unsafe_unretained +#define CATCH_ARC_STRONG __strong +#endif + +#endif + +#ifdef CATCH_CONFIG_CPP11_TUPLE +#include +#endif + +#ifdef CATCH_CONFIG_CPP11_IS_ENUM +#include +#endif + +namespace Catch { + +// Why we're here. +template +std::string toString( T const& value ); + +// Built in overloads + +std::string toString( std::string const& value ); +std::string toString( std::wstring const& value ); +std::string toString( const char* const value ); +std::string toString( char* const value ); +std::string toString( const wchar_t* const value ); +std::string toString( wchar_t* const value ); +std::string toString( int value ); +std::string toString( unsigned long value ); +std::string toString( unsigned int value ); +std::string toString( const double value ); +std::string toString( const float value ); +std::string toString( bool value ); +std::string toString( char value ); +std::string toString( signed char value ); +std::string toString( unsigned char value ); + +#ifdef CATCH_CONFIG_CPP11_LONG_LONG +std::string toString( long long value ); +std::string toString( unsigned long long value ); +#endif + +#ifdef CATCH_CONFIG_CPP11_NULLPTR +std::string toString( std::nullptr_t ); +#endif + +#ifdef __OBJC__ + std::string toString( NSString const * const& nsstring ); + std::string toString( NSString * CATCH_ARC_STRONG const& nsstring ); + std::string toString( NSObject* const& nsObject ); +#endif + +namespace Detail { + + extern const std::string unprintableString; + + struct BorgType { + template BorgType( T const& ); + }; + + struct TrueType { char sizer[1]; }; + struct FalseType { char sizer[2]; }; + + TrueType& testStreamable( std::ostream& ); + FalseType testStreamable( FalseType ); + + FalseType operator<<( std::ostream const&, BorgType const& ); + + template + struct IsStreamInsertable { + static std::ostream &s; + static T const&t; + enum { value = sizeof( testStreamable(s << t) ) == sizeof( TrueType ) }; + }; + +#if defined(CATCH_CONFIG_CPP11_IS_ENUM) + template::value + > + struct EnumStringMaker + { + static std::string convert( T const& ) { return unprintableString; } + }; + + template + struct EnumStringMaker + { + static std::string convert( T const& v ) + { + return ::Catch::toString( + static_cast::type>(v) + ); + } + }; +#endif + template + struct StringMakerBase { +#if defined(CATCH_CONFIG_CPP11_IS_ENUM) + template + static std::string convert( T const& v ) + { + return EnumStringMaker::convert( v ); + } +#else + template + static std::string convert( T const& ) { return unprintableString; } +#endif + }; + + template<> + struct StringMakerBase { + template + static std::string convert( T const& _value ) { + std::ostringstream oss; + oss << _value; + return oss.str(); + } + }; + + std::string rawMemoryToString( const void *object, std::size_t size ); + + template + inline std::string rawMemoryToString( const T& object ) { + return rawMemoryToString( &object, sizeof(object) ); + } + +} // end namespace Detail + +template +struct StringMaker : + Detail::StringMakerBase::value> {}; + +template +struct StringMaker { + template + static std::string convert( U* p ) { + if( !p ) + return "NULL"; + else + return Detail::rawMemoryToString( p ); + } +}; + +template +struct StringMaker { + static std::string convert( R C::* p ) { + if( !p ) + return "NULL"; + else + return Detail::rawMemoryToString( p ); + } +}; + +namespace Detail { + template + std::string rangeToString( InputIterator first, InputIterator last ); +} + +//template +//struct StringMaker > { +// static std::string convert( std::vector const& v ) { +// return Detail::rangeToString( v.begin(), v.end() ); +// } +//}; + +template +std::string toString( std::vector const& v ) { + return Detail::rangeToString( v.begin(), v.end() ); +} + +#ifdef CATCH_CONFIG_CPP11_TUPLE + +// toString for tuples +namespace TupleDetail { + template< + typename Tuple, + std::size_t N = 0, + bool = (N < std::tuple_size::value) + > + struct ElementPrinter { + static void print( const Tuple& tuple, std::ostream& os ) + { + os << ( N ? ", " : " " ) + << Catch::toString(std::get(tuple)); + ElementPrinter::print(tuple,os); + } + }; + + template< + typename Tuple, + std::size_t N + > + struct ElementPrinter { + static void print( const Tuple&, std::ostream& ) {} + }; + +} + +template +struct StringMaker> { + + static std::string convert( const std::tuple& tuple ) + { + std::ostringstream os; + os << '{'; + TupleDetail::ElementPrinter>::print( tuple, os ); + os << " }"; + return os.str(); + } +}; +#endif // CATCH_CONFIG_CPP11_TUPLE + +namespace Detail { + template + std::string makeString( T const& value ) { + return StringMaker::convert( value ); + } +} // end namespace Detail + +/// \brief converts any type to a string +/// +/// The default template forwards on to ostringstream - except when an +/// ostringstream overload does not exist - in which case it attempts to detect +/// that and writes {?}. +/// Overload (not specialise) this template for custom typs that you don't want +/// to provide an ostream overload for. +template +std::string toString( T const& value ) { + return StringMaker::convert( value ); +} + + namespace Detail { + template + std::string rangeToString( InputIterator first, InputIterator last ) { + std::ostringstream oss; + oss << "{ "; + if( first != last ) { + oss << Catch::toString( *first ); + for( ++first ; first != last ; ++first ) + oss << ", " << Catch::toString( *first ); + } + oss << " }"; + return oss.str(); + } +} + +} // end namespace Catch + +namespace Catch { + +// Wraps the LHS of an expression and captures the operator and RHS (if any) - +// wrapping them all in a ResultBuilder object +template +class ExpressionLhs { + ExpressionLhs& operator = ( ExpressionLhs const& ); +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + ExpressionLhs& operator = ( ExpressionLhs && ) = delete; +# endif + +public: + ExpressionLhs( ResultBuilder& rb, T lhs ) : m_rb( rb ), m_lhs( lhs ) {} +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + ExpressionLhs( ExpressionLhs const& ) = default; + ExpressionLhs( ExpressionLhs && ) = default; +# endif + + template + ResultBuilder& operator == ( RhsT const& rhs ) { + return captureExpression( rhs ); + } + + template + ResultBuilder& operator != ( RhsT const& rhs ) { + return captureExpression( rhs ); + } + + template + ResultBuilder& operator < ( RhsT const& rhs ) { + return captureExpression( rhs ); + } + + template + ResultBuilder& operator > ( RhsT const& rhs ) { + return captureExpression( rhs ); + } + + template + ResultBuilder& operator <= ( RhsT const& rhs ) { + return captureExpression( rhs ); + } + + template + ResultBuilder& operator >= ( RhsT const& rhs ) { + return captureExpression( rhs ); + } + + ResultBuilder& operator == ( bool rhs ) { + return captureExpression( rhs ); + } + + ResultBuilder& operator != ( bool rhs ) { + return captureExpression( rhs ); + } + + void endExpression() { + bool value = m_lhs ? true : false; + m_rb + .setLhs( Catch::toString( value ) ) + .setResultType( value ) + .endExpression(); + } + + // Only simple binary expressions are allowed on the LHS. + // If more complex compositions are required then place the sub expression in parentheses + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator + ( RhsT const& ); + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator - ( RhsT const& ); + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator / ( RhsT const& ); + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator * ( RhsT const& ); + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( RhsT const& ); + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || ( RhsT const& ); + +private: + template + ResultBuilder& captureExpression( RhsT const& rhs ) { + return m_rb + .setResultType( Internal::compare( m_lhs, rhs ) ) + .setLhs( Catch::toString( m_lhs ) ) + .setRhs( Catch::toString( rhs ) ) + .setOp( Internal::OperatorTraits::getName() ); + } + +private: + ResultBuilder& m_rb; + T m_lhs; +}; + +} // end namespace Catch + + +namespace Catch { + + template + inline ExpressionLhs ResultBuilder::operator <= ( T const& operand ) { + return ExpressionLhs( *this, operand ); + } + + inline ExpressionLhs ResultBuilder::operator <= ( bool value ) { + return ExpressionLhs( *this, value ); + } + +} // namespace Catch + +// #included from: catch_message.h +#define TWOBLUECUBES_CATCH_MESSAGE_H_INCLUDED + +#include + +namespace Catch { + + struct MessageInfo { + MessageInfo( std::string const& _macroName, + SourceLineInfo const& _lineInfo, + ResultWas::OfType _type ); + + std::string macroName; + SourceLineInfo lineInfo; + ResultWas::OfType type; + std::string message; + unsigned int sequence; + + bool operator == ( MessageInfo const& other ) const { + return sequence == other.sequence; + } + bool operator < ( MessageInfo const& other ) const { + return sequence < other.sequence; + } + private: + static unsigned int globalCount; + }; + + struct MessageBuilder { + MessageBuilder( std::string const& macroName, + SourceLineInfo const& lineInfo, + ResultWas::OfType type ) + : m_info( macroName, lineInfo, type ) + {} + + template + MessageBuilder& operator << ( T const& value ) { + m_stream << value; + return *this; + } + + MessageInfo m_info; + std::ostringstream m_stream; + }; + + class ScopedMessage { + public: + ScopedMessage( MessageBuilder const& builder ); + ScopedMessage( ScopedMessage const& other ); + ~ScopedMessage(); + + MessageInfo m_info; + }; + +} // end namespace Catch + +// #included from: catch_interfaces_capture.h +#define TWOBLUECUBES_CATCH_INTERFACES_CAPTURE_H_INCLUDED + +#include + +namespace Catch { + + class TestCase; + class AssertionResult; + struct AssertionInfo; + struct SectionInfo; + struct SectionEndInfo; + struct MessageInfo; + class ScopedMessageBuilder; + struct Counts; + + struct IResultCapture { + + virtual ~IResultCapture(); + + virtual void assertionEnded( AssertionResult const& result ) = 0; + virtual bool sectionStarted( SectionInfo const& sectionInfo, + Counts& assertions ) = 0; + virtual void sectionEnded( SectionEndInfo const& endInfo ) = 0; + virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) = 0; + virtual void pushScopedMessage( MessageInfo const& message ) = 0; + virtual void popScopedMessage( MessageInfo const& message ) = 0; + + virtual std::string getCurrentTestName() const = 0; + virtual const AssertionResult* getLastResult() const = 0; + + virtual void handleFatalErrorCondition( std::string const& message ) = 0; + }; + + IResultCapture& getResultCapture(); +} + +// #included from: catch_debugger.h +#define TWOBLUECUBES_CATCH_DEBUGGER_H_INCLUDED + +// #included from: catch_platform.h +#define TWOBLUECUBES_CATCH_PLATFORM_H_INCLUDED + +#if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) +#define CATCH_PLATFORM_MAC +#elif defined(__IPHONE_OS_VERSION_MIN_REQUIRED) +#define CATCH_PLATFORM_IPHONE +#elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) +#define CATCH_PLATFORM_WINDOWS +#endif + +#include + +namespace Catch{ + + bool isDebuggerActive(); + void writeToDebugConsole( std::string const& text ); +} + +#ifdef CATCH_PLATFORM_MAC + + // The following code snippet based on: + // http://cocoawithlove.com/2008/03/break-into-debugger.html + #ifdef DEBUG + #if defined(__ppc64__) || defined(__ppc__) + #define CATCH_BREAK_INTO_DEBUGGER() \ + if( Catch::isDebuggerActive() ) { \ + __asm__("li r0, 20\nsc\nnop\nli r0, 37\nli r4, 2\nsc\nnop\n" \ + : : : "memory","r0","r3","r4" ); \ + } + #else + #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) {__asm__("int $3\n" : : );} + #endif + #endif + +#elif defined(_MSC_VER) + #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { __debugbreak(); } +#elif defined(__MINGW32__) + extern "C" __declspec(dllimport) void __stdcall DebugBreak(); + #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { DebugBreak(); } +#endif + +#ifndef CATCH_BREAK_INTO_DEBUGGER +#define CATCH_BREAK_INTO_DEBUGGER() Catch::alwaysTrue(); +#endif + +// #included from: catch_interfaces_runner.h +#define TWOBLUECUBES_CATCH_INTERFACES_RUNNER_H_INCLUDED + +namespace Catch { + class TestCase; + + struct IRunner { + virtual ~IRunner(); + virtual bool aborting() const = 0; + }; +} + +/////////////////////////////////////////////////////////////////////////////// +// In the event of a failure works out if the debugger needs to be invoked +// and/or an exception thrown and takes appropriate action. +// This needs to be done as a macro so the debugger will stop in the user +// source code rather than in Catch library code +#define INTERNAL_CATCH_REACT( resultBuilder ) \ + if( resultBuilder.shouldDebugBreak() ) CATCH_BREAK_INTO_DEBUGGER(); \ + resultBuilder.react(); + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \ + try { \ + CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ + ( __catchResult <= expr ).endExpression(); \ + } \ + catch( ... ) { \ + __catchResult.useActiveException( Catch::ResultDisposition::Normal ); \ + } \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::isTrue( false && static_cast(expr) ) ) // expr here is never evaluated at runtime but it forces the compiler to give it a look + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_IF( expr, resultDisposition, macroName ) \ + INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ); \ + if( Catch::getResultCapture().getLastResult()->succeeded() ) + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_ELSE( expr, resultDisposition, macroName ) \ + INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ); \ + if( !Catch::getResultCapture().getLastResult()->succeeded() ) + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_NO_THROW( expr, resultDisposition, macroName ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \ + try { \ + expr; \ + __catchResult.captureResult( Catch::ResultWas::Ok ); \ + } \ + catch( ... ) { \ + __catchResult.useActiveException( resultDisposition ); \ + } \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::alwaysFalse() ) + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_THROWS( expr, resultDisposition, matcher, macroName ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition, #matcher ); \ + if( __catchResult.allowThrows() ) \ + try { \ + expr; \ + __catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \ + } \ + catch( ... ) { \ + __catchResult.captureExpectedException( matcher ); \ + } \ + else \ + __catchResult.captureResult( Catch::ResultWas::Ok ); \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::alwaysFalse() ) + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_THROWS_AS( expr, exceptionType, resultDisposition, macroName ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \ + if( __catchResult.allowThrows() ) \ + try { \ + expr; \ + __catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \ + } \ + catch( exceptionType ) { \ + __catchResult.captureResult( Catch::ResultWas::Ok ); \ + } \ + catch( ... ) { \ + __catchResult.useActiveException( resultDisposition ); \ + } \ + else \ + __catchResult.captureResult( Catch::ResultWas::Ok ); \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::alwaysFalse() ) + +/////////////////////////////////////////////////////////////////////////////// +#ifdef CATCH_CONFIG_VARIADIC_MACROS + #define INTERNAL_CATCH_MSG( messageType, resultDisposition, macroName, ... ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \ + __catchResult << __VA_ARGS__ + ::Catch::StreamEndStop(); \ + __catchResult.captureResult( messageType ); \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::alwaysFalse() ) +#else + #define INTERNAL_CATCH_MSG( messageType, resultDisposition, macroName, log ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \ + __catchResult << log + ::Catch::StreamEndStop(); \ + __catchResult.captureResult( messageType ); \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::alwaysFalse() ) +#endif + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_INFO( log, macroName ) \ + Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME( scopedMessage ) = Catch::MessageBuilder( macroName, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log; + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CHECK_THAT( arg, matcher, resultDisposition, macroName ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #arg ", " #matcher, resultDisposition ); \ + try { \ + std::string matcherAsString = (matcher).toString(); \ + __catchResult \ + .setLhs( Catch::toString( arg ) ) \ + .setRhs( matcherAsString == Catch::Detail::unprintableString ? #matcher : matcherAsString ) \ + .setOp( "matches" ) \ + .setResultType( (matcher).match( arg ) ); \ + __catchResult.captureExpression(); \ + } catch( ... ) { \ + __catchResult.useActiveException( resultDisposition | Catch::ResultDisposition::ContinueOnFailure ); \ + } \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::alwaysFalse() ) + +// #included from: internal/catch_section.h +#define TWOBLUECUBES_CATCH_SECTION_H_INCLUDED + +// #included from: catch_section_info.h +#define TWOBLUECUBES_CATCH_SECTION_INFO_H_INCLUDED + +// #included from: catch_totals.hpp +#define TWOBLUECUBES_CATCH_TOTALS_HPP_INCLUDED + +#include + +namespace Catch { + + struct Counts { + Counts() : passed( 0 ), failed( 0 ), failedButOk( 0 ) {} + + Counts operator - ( Counts const& other ) const { + Counts diff; + diff.passed = passed - other.passed; + diff.failed = failed - other.failed; + diff.failedButOk = failedButOk - other.failedButOk; + return diff; + } + Counts& operator += ( Counts const& other ) { + passed += other.passed; + failed += other.failed; + failedButOk += other.failedButOk; + return *this; + } + + std::size_t total() const { + return passed + failed + failedButOk; + } + bool allPassed() const { + return failed == 0 && failedButOk == 0; + } + bool allOk() const { + return failed == 0; + } + + std::size_t passed; + std::size_t failed; + std::size_t failedButOk; + }; + + struct Totals { + + Totals operator - ( Totals const& other ) const { + Totals diff; + diff.assertions = assertions - other.assertions; + diff.testCases = testCases - other.testCases; + return diff; + } + + Totals delta( Totals const& prevTotals ) const { + Totals diff = *this - prevTotals; + if( diff.assertions.failed > 0 ) + ++diff.testCases.failed; + else if( diff.assertions.failedButOk > 0 ) + ++diff.testCases.failedButOk; + else + ++diff.testCases.passed; + return diff; + } + + Totals& operator += ( Totals const& other ) { + assertions += other.assertions; + testCases += other.testCases; + return *this; + } + + Counts assertions; + Counts testCases; + }; +} + +namespace Catch { + + struct SectionInfo { + SectionInfo + ( SourceLineInfo const& _lineInfo, + std::string const& _name, + std::string const& _description = std::string() ); + + std::string name; + std::string description; + SourceLineInfo lineInfo; + }; + + struct SectionEndInfo { + SectionEndInfo( SectionInfo const& _sectionInfo, Counts const& _prevAssertions, double _durationInSeconds ) + : sectionInfo( _sectionInfo ), prevAssertions( _prevAssertions ), durationInSeconds( _durationInSeconds ) + {} + + SectionInfo sectionInfo; + Counts prevAssertions; + double durationInSeconds; + }; + +} // end namespace Catch + +// #included from: catch_timer.h +#define TWOBLUECUBES_CATCH_TIMER_H_INCLUDED + +#ifdef CATCH_PLATFORM_WINDOWS +typedef unsigned long long uint64_t; +#else +#include +#endif + +namespace Catch { + + class Timer { + public: + Timer() : m_ticks( 0 ) {} + void start(); + unsigned int getElapsedMicroseconds() const; + unsigned int getElapsedMilliseconds() const; + double getElapsedSeconds() const; + + private: + uint64_t m_ticks; + }; + +} // namespace Catch + +#include + +namespace Catch { + + class Section : NonCopyable { + public: + Section( SectionInfo const& info ); + ~Section(); + + // This indicates whether the section should be executed or not + operator bool() const; + + private: + SectionInfo m_info; + + std::string m_name; + Counts m_assertions; + bool m_sectionIncluded; + Timer m_timer; + }; + +} // end namespace Catch + +#ifdef CATCH_CONFIG_VARIADIC_MACROS + #define INTERNAL_CATCH_SECTION( ... ) \ + if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) ) +#else + #define INTERNAL_CATCH_SECTION( name, desc ) \ + if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, name, desc ) ) +#endif + +// #included from: internal/catch_generators.hpp +#define TWOBLUECUBES_CATCH_GENERATORS_HPP_INCLUDED + +#include +#include +#include +#include + +namespace Catch { + +template +struct IGenerator { + virtual ~IGenerator() {} + virtual T getValue( std::size_t index ) const = 0; + virtual std::size_t size () const = 0; +}; + +template +class BetweenGenerator : public IGenerator { +public: + BetweenGenerator( T from, T to ) : m_from( from ), m_to( to ){} + + virtual T getValue( std::size_t index ) const { + return m_from+static_cast( index ); + } + + virtual std::size_t size() const { + return static_cast( 1+m_to-m_from ); + } + +private: + + T m_from; + T m_to; +}; + +template +class ValuesGenerator : public IGenerator { +public: + ValuesGenerator(){} + + void add( T value ) { + m_values.push_back( value ); + } + + virtual T getValue( std::size_t index ) const { + return m_values[index]; + } + + virtual std::size_t size() const { + return m_values.size(); + } + +private: + std::vector m_values; +}; + +template +class CompositeGenerator { +public: + CompositeGenerator() : m_totalSize( 0 ) {} + + // *** Move semantics, similar to auto_ptr *** + CompositeGenerator( CompositeGenerator& other ) + : m_fileInfo( other.m_fileInfo ), + m_totalSize( 0 ) + { + move( other ); + } + + CompositeGenerator& setFileInfo( const char* fileInfo ) { + m_fileInfo = fileInfo; + return *this; + } + + ~CompositeGenerator() { + deleteAll( m_composed ); + } + + operator T () const { + size_t overallIndex = getCurrentContext().getGeneratorIndex( m_fileInfo, m_totalSize ); + + typename std::vector*>::const_iterator it = m_composed.begin(); + typename std::vector*>::const_iterator itEnd = m_composed.end(); + for( size_t index = 0; it != itEnd; ++it ) + { + const IGenerator* generator = *it; + if( overallIndex >= index && overallIndex < index + generator->size() ) + { + return generator->getValue( overallIndex-index ); + } + index += generator->size(); + } + CATCH_INTERNAL_ERROR( "Indexed past end of generated range" ); + return T(); // Suppress spurious "not all control paths return a value" warning in Visual Studio - if you know how to fix this please do so + } + + void add( const IGenerator* generator ) { + m_totalSize += generator->size(); + m_composed.push_back( generator ); + } + + CompositeGenerator& then( CompositeGenerator& other ) { + move( other ); + return *this; + } + + CompositeGenerator& then( T value ) { + ValuesGenerator* valuesGen = new ValuesGenerator(); + valuesGen->add( value ); + add( valuesGen ); + return *this; + } + +private: + + void move( CompositeGenerator& other ) { + std::copy( other.m_composed.begin(), other.m_composed.end(), std::back_inserter( m_composed ) ); + m_totalSize += other.m_totalSize; + other.m_composed.clear(); + } + + std::vector*> m_composed; + std::string m_fileInfo; + size_t m_totalSize; +}; + +namespace Generators +{ + template + CompositeGenerator between( T from, T to ) { + CompositeGenerator generators; + generators.add( new BetweenGenerator( from, to ) ); + return generators; + } + + template + CompositeGenerator values( T val1, T val2 ) { + CompositeGenerator generators; + ValuesGenerator* valuesGen = new ValuesGenerator(); + valuesGen->add( val1 ); + valuesGen->add( val2 ); + generators.add( valuesGen ); + return generators; + } + + template + CompositeGenerator values( T val1, T val2, T val3 ){ + CompositeGenerator generators; + ValuesGenerator* valuesGen = new ValuesGenerator(); + valuesGen->add( val1 ); + valuesGen->add( val2 ); + valuesGen->add( val3 ); + generators.add( valuesGen ); + return generators; + } + + template + CompositeGenerator values( T val1, T val2, T val3, T val4 ) { + CompositeGenerator generators; + ValuesGenerator* valuesGen = new ValuesGenerator(); + valuesGen->add( val1 ); + valuesGen->add( val2 ); + valuesGen->add( val3 ); + valuesGen->add( val4 ); + generators.add( valuesGen ); + return generators; + } + +} // end namespace Generators + +using namespace Generators; + +} // end namespace Catch + +#define INTERNAL_CATCH_LINESTR2( line ) #line +#define INTERNAL_CATCH_LINESTR( line ) INTERNAL_CATCH_LINESTR2( line ) + +#define INTERNAL_CATCH_GENERATE( expr ) expr.setFileInfo( __FILE__ "(" INTERNAL_CATCH_LINESTR( __LINE__ ) ")" ) + +// #included from: internal/catch_interfaces_exception.h +#define TWOBLUECUBES_CATCH_INTERFACES_EXCEPTION_H_INCLUDED + +#include +#include + +// #included from: catch_interfaces_registry_hub.h +#define TWOBLUECUBES_CATCH_INTERFACES_REGISTRY_HUB_H_INCLUDED + +#include + +namespace Catch { + + class TestCase; + struct ITestCaseRegistry; + struct IExceptionTranslatorRegistry; + struct IExceptionTranslator; + struct IReporterRegistry; + struct IReporterFactory; + + struct IRegistryHub { + virtual ~IRegistryHub(); + + virtual IReporterRegistry const& getReporterRegistry() const = 0; + virtual ITestCaseRegistry const& getTestCaseRegistry() const = 0; + virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() = 0; + }; + + struct IMutableRegistryHub { + virtual ~IMutableRegistryHub(); + virtual void registerReporter( std::string const& name, Ptr const& factory ) = 0; + virtual void registerListener( Ptr const& factory ) = 0; + virtual void registerTest( TestCase const& testInfo ) = 0; + virtual void registerTranslator( const IExceptionTranslator* translator ) = 0; + }; + + IRegistryHub& getRegistryHub(); + IMutableRegistryHub& getMutableRegistryHub(); + void cleanUp(); + std::string translateActiveException(); + +} + +namespace Catch { + + typedef std::string(*exceptionTranslateFunction)(); + + struct IExceptionTranslator; + typedef std::vector ExceptionTranslators; + + struct IExceptionTranslator { + virtual ~IExceptionTranslator(); + virtual std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const = 0; + }; + + struct IExceptionTranslatorRegistry { + virtual ~IExceptionTranslatorRegistry(); + + virtual std::string translateActiveException() const = 0; + }; + + class ExceptionTranslatorRegistrar { + template + class ExceptionTranslator : public IExceptionTranslator { + public: + + ExceptionTranslator( std::string(*translateFunction)( T& ) ) + : m_translateFunction( translateFunction ) + {} + + virtual std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const CATCH_OVERRIDE { + try { + if( it == itEnd ) + throw; + else + return (*it)->translate( it+1, itEnd ); + } + catch( T& ex ) { + return m_translateFunction( ex ); + } + } + + protected: + std::string(*m_translateFunction)( T& ); + }; + + public: + template + ExceptionTranslatorRegistrar( std::string(*translateFunction)( T& ) ) { + getMutableRegistryHub().registerTranslator + ( new ExceptionTranslator( translateFunction ) ); + } + }; +} + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) \ + static std::string INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator )( signature ); \ + namespace{ Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ) ); }\ + static std::string INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator )( signature ) + +// #included from: internal/catch_approx.hpp +#define TWOBLUECUBES_CATCH_APPROX_HPP_INCLUDED + +#include +#include + +namespace Catch { +namespace Detail { + + class Approx { + public: + explicit Approx ( double value ) + : m_epsilon( std::numeric_limits::epsilon()*100 ), + m_scale( 1.0 ), + m_value( value ) + {} + + Approx( Approx const& other ) + : m_epsilon( other.m_epsilon ), + m_scale( other.m_scale ), + m_value( other.m_value ) + {} + + static Approx custom() { + return Approx( 0 ); + } + + Approx operator()( double value ) { + Approx approx( value ); + approx.epsilon( m_epsilon ); + approx.scale( m_scale ); + return approx; + } + + friend bool operator == ( double lhs, Approx const& rhs ) { + // Thanks to Richard Harris for his help refining this formula + return fabs( lhs - rhs.m_value ) < rhs.m_epsilon * (rhs.m_scale + (std::max)( fabs(lhs), fabs(rhs.m_value) ) ); + } + + friend bool operator == ( Approx const& lhs, double rhs ) { + return operator==( rhs, lhs ); + } + + friend bool operator != ( double lhs, Approx const& rhs ) { + return !operator==( lhs, rhs ); + } + + friend bool operator != ( Approx const& lhs, double rhs ) { + return !operator==( rhs, lhs ); + } + + Approx& epsilon( double newEpsilon ) { + m_epsilon = newEpsilon; + return *this; + } + + Approx& scale( double newScale ) { + m_scale = newScale; + return *this; + } + + std::string toString() const { + std::ostringstream oss; + oss << "Approx( " << Catch::toString( m_value ) << " )"; + return oss.str(); + } + + private: + double m_epsilon; + double m_scale; + double m_value; + }; +} + +template<> +inline std::string toString( Detail::Approx const& value ) { + return value.toString(); +} + +} // end namespace Catch + +// #included from: internal/catch_interfaces_tag_alias_registry.h +#define TWOBLUECUBES_CATCH_INTERFACES_TAG_ALIAS_REGISTRY_H_INCLUDED + +// #included from: catch_tag_alias.h +#define TWOBLUECUBES_CATCH_TAG_ALIAS_H_INCLUDED + +#include + +namespace Catch { + + struct TagAlias { + TagAlias( std::string _tag, SourceLineInfo _lineInfo ) : tag( _tag ), lineInfo( _lineInfo ) {} + + std::string tag; + SourceLineInfo lineInfo; + }; + + struct RegistrarForTagAliases { + RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ); + }; + +} // end namespace Catch + +#define CATCH_REGISTER_TAG_ALIAS( alias, spec ) namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); } +// #included from: catch_option.hpp +#define TWOBLUECUBES_CATCH_OPTION_HPP_INCLUDED + +namespace Catch { + + // An optional type + template + class Option { + public: + Option() : nullableValue( CATCH_NULL ) {} + Option( T const& _value ) + : nullableValue( new( storage ) T( _value ) ) + {} + Option( Option const& _other ) + : nullableValue( _other ? new( storage ) T( *_other ) : CATCH_NULL ) + {} + + ~Option() { + reset(); + } + + Option& operator= ( Option const& _other ) { + if( &_other != this ) { + reset(); + if( _other ) + nullableValue = new( storage ) T( *_other ); + } + return *this; + } + Option& operator = ( T const& _value ) { + reset(); + nullableValue = new( storage ) T( _value ); + return *this; + } + + void reset() { + if( nullableValue ) + nullableValue->~T(); + nullableValue = CATCH_NULL; + } + + T& operator*() { return *nullableValue; } + T const& operator*() const { return *nullableValue; } + T* operator->() { return nullableValue; } + const T* operator->() const { return nullableValue; } + + T valueOr( T const& defaultValue ) const { + return nullableValue ? *nullableValue : defaultValue; + } + + bool some() const { return nullableValue != CATCH_NULL; } + bool none() const { return nullableValue == CATCH_NULL; } + + bool operator !() const { return nullableValue == CATCH_NULL; } + operator SafeBool::type() const { + return SafeBool::makeSafe( some() ); + } + + private: + T* nullableValue; + char storage[sizeof(T)]; + }; + +} // end namespace Catch + +namespace Catch { + + struct ITagAliasRegistry { + virtual ~ITagAliasRegistry(); + virtual Option find( std::string const& alias ) const = 0; + virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const = 0; + + static ITagAliasRegistry const& get(); + }; + +} // end namespace Catch + +// These files are included here so the single_include script doesn't put them +// in the conditionally compiled sections +// #included from: internal/catch_test_case_info.h +#define TWOBLUECUBES_CATCH_TEST_CASE_INFO_H_INCLUDED + +#include +#include + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpadded" +#endif + +namespace Catch { + + struct ITestCase; + + struct TestCaseInfo { + enum SpecialProperties{ + None = 0, + IsHidden = 1 << 1, + ShouldFail = 1 << 2, + MayFail = 1 << 3, + Throws = 1 << 4 + }; + + TestCaseInfo( std::string const& _name, + std::string const& _className, + std::string const& _description, + std::set const& _tags, + SourceLineInfo const& _lineInfo ); + + TestCaseInfo( TestCaseInfo const& other ); + + friend void setTags( TestCaseInfo& testCaseInfo, std::set const& tags ); + + bool isHidden() const; + bool throws() const; + bool okToFail() const; + bool expectedToFail() const; + + std::string name; + std::string className; + std::string description; + std::set tags; + std::set lcaseTags; + std::string tagsAsString; + SourceLineInfo lineInfo; + SpecialProperties properties; + }; + + class TestCase : public TestCaseInfo { + public: + + TestCase( ITestCase* testCase, TestCaseInfo const& info ); + TestCase( TestCase const& other ); + + TestCase withName( std::string const& _newName ) const; + + void invoke() const; + + TestCaseInfo const& getTestCaseInfo() const; + + void swap( TestCase& other ); + bool operator == ( TestCase const& other ) const; + bool operator < ( TestCase const& other ) const; + TestCase& operator = ( TestCase const& other ); + + private: + Ptr test; + }; + + TestCase makeTestCase( ITestCase* testCase, + std::string const& className, + std::string const& name, + std::string const& description, + SourceLineInfo const& lineInfo ); +} + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + + +#ifdef __OBJC__ +// #included from: internal/catch_objc.hpp +#define TWOBLUECUBES_CATCH_OBJC_HPP_INCLUDED + +#import + +#include + +// NB. Any general catch headers included here must be included +// in catch.hpp first to make sure they are included by the single +// header for non obj-usage + +/////////////////////////////////////////////////////////////////////////////// +// This protocol is really only here for (self) documenting purposes, since +// all its methods are optional. +@protocol OcFixture + +@optional + +-(void) setUp; +-(void) tearDown; + +@end + +namespace Catch { + + class OcMethod : public SharedImpl { + + public: + OcMethod( Class cls, SEL sel ) : m_cls( cls ), m_sel( sel ) {} + + virtual void invoke() const { + id obj = [[m_cls alloc] init]; + + performOptionalSelector( obj, @selector(setUp) ); + performOptionalSelector( obj, m_sel ); + performOptionalSelector( obj, @selector(tearDown) ); + + arcSafeRelease( obj ); + } + private: + virtual ~OcMethod() {} + + Class m_cls; + SEL m_sel; + }; + + namespace Detail{ + + inline std::string getAnnotation( Class cls, + std::string const& annotationName, + std::string const& testCaseName ) { + NSString* selStr = [[NSString alloc] initWithFormat:@"Catch_%s_%s", annotationName.c_str(), testCaseName.c_str()]; + SEL sel = NSSelectorFromString( selStr ); + arcSafeRelease( selStr ); + id value = performOptionalSelector( cls, sel ); + if( value ) + return [(NSString*)value UTF8String]; + return ""; + } + } + + inline size_t registerTestMethods() { + size_t noTestMethods = 0; + int noClasses = objc_getClassList( CATCH_NULL, 0 ); + + Class* classes = (CATCH_UNSAFE_UNRETAINED Class *)malloc( sizeof(Class) * noClasses); + objc_getClassList( classes, noClasses ); + + for( int c = 0; c < noClasses; c++ ) { + Class cls = classes[c]; + { + u_int count; + Method* methods = class_copyMethodList( cls, &count ); + for( u_int m = 0; m < count ; m++ ) { + SEL selector = method_getName(methods[m]); + std::string methodName = sel_getName(selector); + if( startsWith( methodName, "Catch_TestCase_" ) ) { + std::string testCaseName = methodName.substr( 15 ); + std::string name = Detail::getAnnotation( cls, "Name", testCaseName ); + std::string desc = Detail::getAnnotation( cls, "Description", testCaseName ); + const char* className = class_getName( cls ); + + getMutableRegistryHub().registerTest( makeTestCase( new OcMethod( cls, selector ), className, name.c_str(), desc.c_str(), SourceLineInfo() ) ); + noTestMethods++; + } + } + free(methods); + } + } + return noTestMethods; + } + + namespace Matchers { + namespace Impl { + namespace NSStringMatchers { + + template + struct StringHolder : MatcherImpl{ + StringHolder( NSString* substr ) : m_substr( [substr copy] ){} + StringHolder( StringHolder const& other ) : m_substr( [other.m_substr copy] ){} + StringHolder() { + arcSafeRelease( m_substr ); + } + + NSString* m_substr; + }; + + struct Equals : StringHolder { + Equals( NSString* substr ) : StringHolder( substr ){} + + virtual bool match( ExpressionType const& str ) const { + return (str != nil || m_substr == nil ) && + [str isEqualToString:m_substr]; + } + + virtual std::string toString() const { + return "equals string: " + Catch::toString( m_substr ); + } + }; + + struct Contains : StringHolder { + Contains( NSString* substr ) : StringHolder( substr ){} + + virtual bool match( ExpressionType const& str ) const { + return (str != nil || m_substr == nil ) && + [str rangeOfString:m_substr].location != NSNotFound; + } + + virtual std::string toString() const { + return "contains string: " + Catch::toString( m_substr ); + } + }; + + struct StartsWith : StringHolder { + StartsWith( NSString* substr ) : StringHolder( substr ){} + + virtual bool match( ExpressionType const& str ) const { + return (str != nil || m_substr == nil ) && + [str rangeOfString:m_substr].location == 0; + } + + virtual std::string toString() const { + return "starts with: " + Catch::toString( m_substr ); + } + }; + struct EndsWith : StringHolder { + EndsWith( NSString* substr ) : StringHolder( substr ){} + + virtual bool match( ExpressionType const& str ) const { + return (str != nil || m_substr == nil ) && + [str rangeOfString:m_substr].location == [str length] - [m_substr length]; + } + + virtual std::string toString() const { + return "ends with: " + Catch::toString( m_substr ); + } + }; + + } // namespace NSStringMatchers + } // namespace Impl + + inline Impl::NSStringMatchers::Equals + Equals( NSString* substr ){ return Impl::NSStringMatchers::Equals( substr ); } + + inline Impl::NSStringMatchers::Contains + Contains( NSString* substr ){ return Impl::NSStringMatchers::Contains( substr ); } + + inline Impl::NSStringMatchers::StartsWith + StartsWith( NSString* substr ){ return Impl::NSStringMatchers::StartsWith( substr ); } + + inline Impl::NSStringMatchers::EndsWith + EndsWith( NSString* substr ){ return Impl::NSStringMatchers::EndsWith( substr ); } + + } // namespace Matchers + + using namespace Matchers; + +} // namespace Catch + +/////////////////////////////////////////////////////////////////////////////// +#define OC_TEST_CASE( name, desc )\ ++(NSString*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Name_test ) \ +{\ +return @ name; \ +}\ ++(NSString*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Description_test ) \ +{ \ +return @ desc; \ +} \ +-(void) INTERNAL_CATCH_UNIQUE_NAME( Catch_TestCase_test ) + +#endif + +#ifdef CATCH_IMPL +// #included from: internal/catch_impl.hpp +#define TWOBLUECUBES_CATCH_IMPL_HPP_INCLUDED + +// Collect all the implementation files together here +// These are the equivalent of what would usually be cpp files + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wweak-vtables" +#endif + +// #included from: ../catch_session.hpp +#define TWOBLUECUBES_CATCH_RUNNER_HPP_INCLUDED + +// #included from: internal/catch_commandline.hpp +#define TWOBLUECUBES_CATCH_COMMANDLINE_HPP_INCLUDED + +// #included from: catch_config.hpp +#define TWOBLUECUBES_CATCH_CONFIG_HPP_INCLUDED + +// #included from: catch_test_spec_parser.hpp +#define TWOBLUECUBES_CATCH_TEST_SPEC_PARSER_HPP_INCLUDED + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpadded" +#endif + +// #included from: catch_test_spec.hpp +#define TWOBLUECUBES_CATCH_TEST_SPEC_HPP_INCLUDED + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpadded" +#endif + +// #included from: catch_wildcard_pattern.hpp +#define TWOBLUECUBES_CATCH_WILDCARD_PATTERN_HPP_INCLUDED + +namespace Catch +{ + class WildcardPattern { + enum WildcardPosition { + NoWildcard = 0, + WildcardAtStart = 1, + WildcardAtEnd = 2, + WildcardAtBothEnds = WildcardAtStart | WildcardAtEnd + }; + + public: + + WildcardPattern( std::string const& pattern, CaseSensitive::Choice caseSensitivity ) + : m_caseSensitivity( caseSensitivity ), + m_wildcard( NoWildcard ), + m_pattern( adjustCase( pattern ) ) + { + if( startsWith( m_pattern, "*" ) ) { + m_pattern = m_pattern.substr( 1 ); + m_wildcard = WildcardAtStart; + } + if( endsWith( m_pattern, "*" ) ) { + m_pattern = m_pattern.substr( 0, m_pattern.size()-1 ); + m_wildcard = static_cast( m_wildcard | WildcardAtEnd ); + } + } + virtual ~WildcardPattern(); + virtual bool matches( std::string const& str ) const { + switch( m_wildcard ) { + case NoWildcard: + return m_pattern == adjustCase( str ); + case WildcardAtStart: + return endsWith( adjustCase( str ), m_pattern ); + case WildcardAtEnd: + return startsWith( adjustCase( str ), m_pattern ); + case WildcardAtBothEnds: + return contains( adjustCase( str ), m_pattern ); + } + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunreachable-code" +#endif + throw std::logic_error( "Unknown enum" ); +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + } + private: + std::string adjustCase( std::string const& str ) const { + return m_caseSensitivity == CaseSensitive::No ? toLower( str ) : str; + } + CaseSensitive::Choice m_caseSensitivity; + WildcardPosition m_wildcard; + std::string m_pattern; + }; +} + +#include +#include + +namespace Catch { + + class TestSpec { + struct Pattern : SharedImpl<> { + virtual ~Pattern(); + virtual bool matches( TestCaseInfo const& testCase ) const = 0; + }; + class NamePattern : public Pattern { + public: + NamePattern( std::string const& name ) + : m_wildcardPattern( toLower( name ), CaseSensitive::No ) + {} + virtual ~NamePattern(); + virtual bool matches( TestCaseInfo const& testCase ) const { + return m_wildcardPattern.matches( toLower( testCase.name ) ); + } + private: + WildcardPattern m_wildcardPattern; + }; + + class TagPattern : public Pattern { + public: + TagPattern( std::string const& tag ) : m_tag( toLower( tag ) ) {} + virtual ~TagPattern(); + virtual bool matches( TestCaseInfo const& testCase ) const { + return testCase.lcaseTags.find( m_tag ) != testCase.lcaseTags.end(); + } + private: + std::string m_tag; + }; + + class ExcludedPattern : public Pattern { + public: + ExcludedPattern( Ptr const& underlyingPattern ) : m_underlyingPattern( underlyingPattern ) {} + virtual ~ExcludedPattern(); + virtual bool matches( TestCaseInfo const& testCase ) const { return !m_underlyingPattern->matches( testCase ); } + private: + Ptr m_underlyingPattern; + }; + + struct Filter { + std::vector > m_patterns; + + bool matches( TestCaseInfo const& testCase ) const { + // All patterns in a filter must match for the filter to be a match + for( std::vector >::const_iterator it = m_patterns.begin(), itEnd = m_patterns.end(); it != itEnd; ++it ) + if( !(*it)->matches( testCase ) ) + return false; + return true; + } + }; + + public: + bool hasFilters() const { + return !m_filters.empty(); + } + bool matches( TestCaseInfo const& testCase ) const { + // A TestSpec matches if any filter matches + for( std::vector::const_iterator it = m_filters.begin(), itEnd = m_filters.end(); it != itEnd; ++it ) + if( it->matches( testCase ) ) + return true; + return false; + } + + private: + std::vector m_filters; + + friend class TestSpecParser; + }; +} + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +namespace Catch { + + class TestSpecParser { + enum Mode{ None, Name, QuotedName, Tag }; + Mode m_mode; + bool m_exclusion; + std::size_t m_start, m_pos; + std::string m_arg; + TestSpec::Filter m_currentFilter; + TestSpec m_testSpec; + ITagAliasRegistry const* m_tagAliases; + + public: + TestSpecParser( ITagAliasRegistry const& tagAliases ) : m_tagAliases( &tagAliases ) {} + + TestSpecParser& parse( std::string const& arg ) { + m_mode = None; + m_exclusion = false; + m_start = std::string::npos; + m_arg = m_tagAliases->expandAliases( arg ); + for( m_pos = 0; m_pos < m_arg.size(); ++m_pos ) + visitChar( m_arg[m_pos] ); + if( m_mode == Name ) + addPattern(); + return *this; + } + TestSpec testSpec() { + addFilter(); + return m_testSpec; + } + private: + void visitChar( char c ) { + if( m_mode == None ) { + switch( c ) { + case ' ': return; + case '~': m_exclusion = true; return; + case '[': return startNewMode( Tag, ++m_pos ); + case '"': return startNewMode( QuotedName, ++m_pos ); + default: startNewMode( Name, m_pos ); break; + } + } + if( m_mode == Name ) { + if( c == ',' ) { + addPattern(); + addFilter(); + } + else if( c == '[' ) { + if( subString() == "exclude:" ) + m_exclusion = true; + else + addPattern(); + startNewMode( Tag, ++m_pos ); + } + } + else if( m_mode == QuotedName && c == '"' ) + addPattern(); + else if( m_mode == Tag && c == ']' ) + addPattern(); + } + void startNewMode( Mode mode, std::size_t start ) { + m_mode = mode; + m_start = start; + } + std::string subString() const { return m_arg.substr( m_start, m_pos - m_start ); } + template + void addPattern() { + std::string token = subString(); + if( startsWith( token, "exclude:" ) ) { + m_exclusion = true; + token = token.substr( 8 ); + } + if( !token.empty() ) { + Ptr pattern = new T( token ); + if( m_exclusion ) + pattern = new TestSpec::ExcludedPattern( pattern ); + m_currentFilter.m_patterns.push_back( pattern ); + } + m_exclusion = false; + m_mode = None; + } + void addFilter() { + if( !m_currentFilter.m_patterns.empty() ) { + m_testSpec.m_filters.push_back( m_currentFilter ); + m_currentFilter = TestSpec::Filter(); + } + } + }; + inline TestSpec parseTestSpec( std::string const& arg ) { + return TestSpecParser( ITagAliasRegistry::get() ).parse( arg ).testSpec(); + } + +} // namespace Catch + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +// #included from: catch_interfaces_config.h +#define TWOBLUECUBES_CATCH_INTERFACES_CONFIG_H_INCLUDED + +#include +#include +#include + +namespace Catch { + + struct Verbosity { enum Level { + NoOutput = 0, + Quiet, + Normal + }; }; + + struct WarnAbout { enum What { + Nothing = 0x00, + NoAssertions = 0x01 + }; }; + + struct ShowDurations { enum OrNot { + DefaultForReporter, + Always, + Never + }; }; + struct RunTests { enum InWhatOrder { + InDeclarationOrder, + InLexicographicalOrder, + InRandomOrder + }; }; + struct UseColour { enum YesOrNo { + Auto, + Yes, + No + }; }; + + class TestSpec; + + struct IConfig : IShared { + + virtual ~IConfig(); + + virtual bool allowThrows() const = 0; + virtual std::ostream& stream() const = 0; + virtual std::string name() const = 0; + virtual bool includeSuccessfulResults() const = 0; + virtual bool shouldDebugBreak() const = 0; + virtual bool warnAboutMissingAssertions() const = 0; + virtual int abortAfter() const = 0; + virtual bool showInvisibles() const = 0; + virtual ShowDurations::OrNot showDurations() const = 0; + virtual TestSpec const& testSpec() const = 0; + virtual RunTests::InWhatOrder runOrder() const = 0; + virtual unsigned int rngSeed() const = 0; + virtual UseColour::YesOrNo useColour() const = 0; + }; +} + +// #included from: catch_stream.h +#define TWOBLUECUBES_CATCH_STREAM_H_INCLUDED + +// #included from: catch_streambuf.h +#define TWOBLUECUBES_CATCH_STREAMBUF_H_INCLUDED + +#include + +namespace Catch { + + class StreamBufBase : public std::streambuf { + public: + virtual ~StreamBufBase() CATCH_NOEXCEPT; + }; +} + +#include +#include +#include + +namespace Catch { + + std::ostream& cout(); + std::ostream& cerr(); + + struct IStream { + virtual ~IStream() CATCH_NOEXCEPT; + virtual std::ostream& stream() const = 0; + }; + + class FileStream : public IStream { + mutable std::ofstream m_ofs; + public: + FileStream( std::string const& filename ); + virtual ~FileStream() CATCH_NOEXCEPT; + public: // IStream + virtual std::ostream& stream() const CATCH_OVERRIDE; + }; + + class CoutStream : public IStream { + mutable std::ostream m_os; + public: + CoutStream(); + virtual ~CoutStream() CATCH_NOEXCEPT; + + public: // IStream + virtual std::ostream& stream() const CATCH_OVERRIDE; + }; + + class DebugOutStream : public IStream { + std::auto_ptr m_streamBuf; + mutable std::ostream m_os; + public: + DebugOutStream(); + virtual ~DebugOutStream() CATCH_NOEXCEPT; + + public: // IStream + virtual std::ostream& stream() const CATCH_OVERRIDE; + }; +} + +#include +#include +#include +#include +#include + +#ifndef CATCH_CONFIG_CONSOLE_WIDTH +#define CATCH_CONFIG_CONSOLE_WIDTH 80 +#endif + +namespace Catch { + + struct ConfigData { + + ConfigData() + : listTests( false ), + listTags( false ), + listReporters( false ), + listTestNamesOnly( false ), + showSuccessfulTests( false ), + shouldDebugBreak( false ), + noThrow( false ), + showHelp( false ), + showInvisibles( false ), + filenamesAsTags( false ), + abortAfter( -1 ), + rngSeed( 0 ), + verbosity( Verbosity::Normal ), + warnings( WarnAbout::Nothing ), + showDurations( ShowDurations::DefaultForReporter ), + runOrder( RunTests::InDeclarationOrder ), + useColour( UseColour::Auto ) + {} + + bool listTests; + bool listTags; + bool listReporters; + bool listTestNamesOnly; + + bool showSuccessfulTests; + bool shouldDebugBreak; + bool noThrow; + bool showHelp; + bool showInvisibles; + bool filenamesAsTags; + + int abortAfter; + unsigned int rngSeed; + + Verbosity::Level verbosity; + WarnAbout::What warnings; + ShowDurations::OrNot showDurations; + RunTests::InWhatOrder runOrder; + UseColour::YesOrNo useColour; + + std::string outputFilename; + std::string name; + std::string processName; + + std::vector reporterNames; + std::vector testsOrTags; + }; + + class Config : public SharedImpl { + private: + Config( Config const& other ); + Config& operator = ( Config const& other ); + virtual void dummy(); + public: + + Config() + {} + + Config( ConfigData const& data ) + : m_data( data ), + m_stream( openStream() ) + { + if( !data.testsOrTags.empty() ) { + TestSpecParser parser( ITagAliasRegistry::get() ); + for( std::size_t i = 0; i < data.testsOrTags.size(); ++i ) + parser.parse( data.testsOrTags[i] ); + m_testSpec = parser.testSpec(); + } + } + + virtual ~Config() { + } + + std::string const& getFilename() const { + return m_data.outputFilename ; + } + + bool listTests() const { return m_data.listTests; } + bool listTestNamesOnly() const { return m_data.listTestNamesOnly; } + bool listTags() const { return m_data.listTags; } + bool listReporters() const { return m_data.listReporters; } + + std::string getProcessName() const { return m_data.processName; } + + bool shouldDebugBreak() const { return m_data.shouldDebugBreak; } + + std::vector getReporterNames() const { return m_data.reporterNames; } + + int abortAfter() const { return m_data.abortAfter; } + + TestSpec const& testSpec() const { return m_testSpec; } + + bool showHelp() const { return m_data.showHelp; } + bool showInvisibles() const { return m_data.showInvisibles; } + + // IConfig interface + virtual bool allowThrows() const { return !m_data.noThrow; } + virtual std::ostream& stream() const { return m_stream->stream(); } + virtual std::string name() const { return m_data.name.empty() ? m_data.processName : m_data.name; } + virtual bool includeSuccessfulResults() const { return m_data.showSuccessfulTests; } + virtual bool warnAboutMissingAssertions() const { return m_data.warnings & WarnAbout::NoAssertions; } + virtual ShowDurations::OrNot showDurations() const { return m_data.showDurations; } + virtual RunTests::InWhatOrder runOrder() const { return m_data.runOrder; } + virtual unsigned int rngSeed() const { return m_data.rngSeed; } + virtual UseColour::YesOrNo useColour() const { return m_data.useColour; } + + private: + + IStream const* openStream() { + if( m_data.outputFilename.empty() ) + return new CoutStream(); + else if( m_data.outputFilename[0] == '%' ) { + if( m_data.outputFilename == "%debug" ) + return new DebugOutStream(); + else + throw std::domain_error( "Unrecognised stream: " + m_data.outputFilename ); + } + else + return new FileStream( m_data.outputFilename ); + } + ConfigData m_data; + + std::auto_ptr m_stream; + TestSpec m_testSpec; + }; + +} // end namespace Catch + +// #included from: catch_clara.h +#define TWOBLUECUBES_CATCH_CLARA_H_INCLUDED + +// Use Catch's value for console width (store Clara's off to the side, if present) +#ifdef CLARA_CONFIG_CONSOLE_WIDTH +#define CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH CLARA_CONFIG_CONSOLE_WIDTH +#undef CLARA_CONFIG_CONSOLE_WIDTH +#endif +#define CLARA_CONFIG_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH + +// Declare Clara inside the Catch namespace +#define STITCH_CLARA_OPEN_NAMESPACE namespace Catch { +// #included from: ../external/clara.h + +// Version 0.0.1.1 + +// Only use header guard if we are not using an outer namespace +#if !defined(TWOBLUECUBES_CLARA_H_INCLUDED) || defined(STITCH_CLARA_OPEN_NAMESPACE) + +#ifndef STITCH_CLARA_OPEN_NAMESPACE +#define TWOBLUECUBES_CLARA_H_INCLUDED +#define STITCH_CLARA_OPEN_NAMESPACE +#define STITCH_CLARA_CLOSE_NAMESPACE +#else +#define STITCH_CLARA_CLOSE_NAMESPACE } +#endif + +#define STITCH_TBC_TEXT_FORMAT_OPEN_NAMESPACE STITCH_CLARA_OPEN_NAMESPACE + +// ----------- #included from tbc_text_format.h ----------- + +// Only use header guard if we are not using an outer namespace +#if !defined(TBC_TEXT_FORMAT_H_INCLUDED) || defined(STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE) +#ifndef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE +#define TBC_TEXT_FORMAT_H_INCLUDED +#endif + +#include +#include +#include +#include + +// Use optional outer namespace +#ifdef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE +namespace STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE { +#endif + +namespace Tbc { + +#ifdef TBC_TEXT_FORMAT_CONSOLE_WIDTH + const unsigned int consoleWidth = TBC_TEXT_FORMAT_CONSOLE_WIDTH; +#else + const unsigned int consoleWidth = 80; +#endif + + struct TextAttributes { + TextAttributes() + : initialIndent( std::string::npos ), + indent( 0 ), + width( consoleWidth-1 ), + tabChar( '\t' ) + {} + + TextAttributes& setInitialIndent( std::size_t _value ) { initialIndent = _value; return *this; } + TextAttributes& setIndent( std::size_t _value ) { indent = _value; return *this; } + TextAttributes& setWidth( std::size_t _value ) { width = _value; return *this; } + TextAttributes& setTabChar( char _value ) { tabChar = _value; return *this; } + + std::size_t initialIndent; // indent of first line, or npos + std::size_t indent; // indent of subsequent lines, or all if initialIndent is npos + std::size_t width; // maximum width of text, including indent. Longer text will wrap + char tabChar; // If this char is seen the indent is changed to current pos + }; + + class Text { + public: + Text( std::string const& _str, TextAttributes const& _attr = TextAttributes() ) + : attr( _attr ) + { + std::string wrappableChars = " [({.,/|\\-"; + std::size_t indent = _attr.initialIndent != std::string::npos + ? _attr.initialIndent + : _attr.indent; + std::string remainder = _str; + + while( !remainder.empty() ) { + if( lines.size() >= 1000 ) { + lines.push_back( "... message truncated due to excessive size" ); + return; + } + std::size_t tabPos = std::string::npos; + std::size_t width = (std::min)( remainder.size(), _attr.width - indent ); + std::size_t pos = remainder.find_first_of( '\n' ); + if( pos <= width ) { + width = pos; + } + pos = remainder.find_last_of( _attr.tabChar, width ); + if( pos != std::string::npos ) { + tabPos = pos; + if( remainder[width] == '\n' ) + width--; + remainder = remainder.substr( 0, tabPos ) + remainder.substr( tabPos+1 ); + } + + if( width == remainder.size() ) { + spliceLine( indent, remainder, width ); + } + else if( remainder[width] == '\n' ) { + spliceLine( indent, remainder, width ); + if( width <= 1 || remainder.size() != 1 ) + remainder = remainder.substr( 1 ); + indent = _attr.indent; + } + else { + pos = remainder.find_last_of( wrappableChars, width ); + if( pos != std::string::npos && pos > 0 ) { + spliceLine( indent, remainder, pos ); + if( remainder[0] == ' ' ) + remainder = remainder.substr( 1 ); + } + else { + spliceLine( indent, remainder, width-1 ); + lines.back() += "-"; + } + if( lines.size() == 1 ) + indent = _attr.indent; + if( tabPos != std::string::npos ) + indent += tabPos; + } + } + } + + void spliceLine( std::size_t _indent, std::string& _remainder, std::size_t _pos ) { + lines.push_back( std::string( _indent, ' ' ) + _remainder.substr( 0, _pos ) ); + _remainder = _remainder.substr( _pos ); + } + + typedef std::vector::const_iterator const_iterator; + + const_iterator begin() const { return lines.begin(); } + const_iterator end() const { return lines.end(); } + std::string const& last() const { return lines.back(); } + std::size_t size() const { return lines.size(); } + std::string const& operator[]( std::size_t _index ) const { return lines[_index]; } + std::string toString() const { + std::ostringstream oss; + oss << *this; + return oss.str(); + } + + inline friend std::ostream& operator << ( std::ostream& _stream, Text const& _text ) { + for( Text::const_iterator it = _text.begin(), itEnd = _text.end(); + it != itEnd; ++it ) { + if( it != _text.begin() ) + _stream << "\n"; + _stream << *it; + } + return _stream; + } + + private: + std::string str; + TextAttributes attr; + std::vector lines; + }; + +} // end namespace Tbc + +#ifdef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE +} // end outer namespace +#endif + +#endif // TBC_TEXT_FORMAT_H_INCLUDED + +// ----------- end of #include from tbc_text_format.h ----------- +// ........... back in clara.h + +#undef STITCH_TBC_TEXT_FORMAT_OPEN_NAMESPACE + +// ----------- #included from clara_compilers.h ----------- + +#ifndef TWOBLUECUBES_CLARA_COMPILERS_H_INCLUDED +#define TWOBLUECUBES_CLARA_COMPILERS_H_INCLUDED + +// Detect a number of compiler features - mostly C++11/14 conformance - by compiler +// The following features are defined: +// +// CLARA_CONFIG_CPP11_NULLPTR : is nullptr supported? +// CLARA_CONFIG_CPP11_NOEXCEPT : is noexcept supported? +// CLARA_CONFIG_CPP11_GENERATED_METHODS : The delete and default keywords for compiler generated methods +// CLARA_CONFIG_CPP11_OVERRIDE : is override supported? +// CLARA_CONFIG_CPP11_UNIQUE_PTR : is unique_ptr supported (otherwise use auto_ptr) + +// CLARA_CONFIG_CPP11_OR_GREATER : Is C++11 supported? + +// CLARA_CONFIG_VARIADIC_MACROS : are variadic macros supported? + +// In general each macro has a _NO_ form +// (e.g. CLARA_CONFIG_CPP11_NO_NULLPTR) which disables the feature. +// Many features, at point of detection, define an _INTERNAL_ macro, so they +// can be combined, en-mass, with the _NO_ forms later. + +// All the C++11 features can be disabled with CLARA_CONFIG_NO_CPP11 + +#ifdef __clang__ + +#if __has_feature(cxx_nullptr) +#define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR +#endif + +#if __has_feature(cxx_noexcept) +#define CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT +#endif + +#endif // __clang__ + +//////////////////////////////////////////////////////////////////////////////// +// GCC +#ifdef __GNUC__ + +#if __GNUC__ == 4 && __GNUC_MINOR__ >= 6 && defined(__GXX_EXPERIMENTAL_CXX0X__) +#define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR +#endif + +// - otherwise more recent versions define __cplusplus >= 201103L +// and will get picked up below + +#endif // __GNUC__ + +//////////////////////////////////////////////////////////////////////////////// +// Visual C++ +#ifdef _MSC_VER + +#if (_MSC_VER >= 1600) +#define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR +#define CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR +#endif + +#if (_MSC_VER >= 1900 ) // (VC++ 13 (VS2015)) +#define CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT +#define CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS +#endif + +#endif // _MSC_VER + +//////////////////////////////////////////////////////////////////////////////// +// C++ language feature support + +// catch all support for C++11 +#if defined(__cplusplus) && __cplusplus >= 201103L + +#define CLARA_CPP11_OR_GREATER + +#if !defined(CLARA_INTERNAL_CONFIG_CPP11_NULLPTR) +#define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR +#endif + +#ifndef CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT +#define CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT +#endif + +#ifndef CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS +#define CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS +#endif + +#if !defined(CLARA_INTERNAL_CONFIG_CPP11_OVERRIDE) +#define CLARA_INTERNAL_CONFIG_CPP11_OVERRIDE +#endif +#if !defined(CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) +#define CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR +#endif + +#endif // __cplusplus >= 201103L + +// Now set the actual defines based on the above + anything the user has configured +#if defined(CLARA_INTERNAL_CONFIG_CPP11_NULLPTR) && !defined(CLARA_CONFIG_CPP11_NO_NULLPTR) && !defined(CLARA_CONFIG_CPP11_NULLPTR) && !defined(CLARA_CONFIG_NO_CPP11) +#define CLARA_CONFIG_CPP11_NULLPTR +#endif +#if defined(CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT) && !defined(CLARA_CONFIG_CPP11_NO_NOEXCEPT) && !defined(CLARA_CONFIG_CPP11_NOEXCEPT) && !defined(CLARA_CONFIG_NO_CPP11) +#define CLARA_CONFIG_CPP11_NOEXCEPT +#endif +#if defined(CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS) && !defined(CLARA_CONFIG_CPP11_NO_GENERATED_METHODS) && !defined(CLARA_CONFIG_CPP11_GENERATED_METHODS) && !defined(CLARA_CONFIG_NO_CPP11) +#define CLARA_CONFIG_CPP11_GENERATED_METHODS +#endif +#if defined(CLARA_INTERNAL_CONFIG_CPP11_OVERRIDE) && !defined(CLARA_CONFIG_NO_OVERRIDE) && !defined(CLARA_CONFIG_CPP11_OVERRIDE) && !defined(CLARA_CONFIG_NO_CPP11) +#define CLARA_CONFIG_CPP11_OVERRIDE +#endif +#if defined(CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) && !defined(CLARA_CONFIG_NO_UNIQUE_PTR) && !defined(CLARA_CONFIG_CPP11_UNIQUE_PTR) && !defined(CLARA_CONFIG_NO_CPP11) +#define CLARA_CONFIG_CPP11_UNIQUE_PTR +#endif + +// noexcept support: +#if defined(CLARA_CONFIG_CPP11_NOEXCEPT) && !defined(CLARA_NOEXCEPT) +#define CLARA_NOEXCEPT noexcept +# define CLARA_NOEXCEPT_IS(x) noexcept(x) +#else +#define CLARA_NOEXCEPT throw() +# define CLARA_NOEXCEPT_IS(x) +#endif + +// nullptr support +#ifdef CLARA_CONFIG_CPP11_NULLPTR +#define CLARA_NULL nullptr +#else +#define CLARA_NULL NULL +#endif + +// override support +#ifdef CLARA_CONFIG_CPP11_OVERRIDE +#define CLARA_OVERRIDE override +#else +#define CLARA_OVERRIDE +#endif + +// unique_ptr support +#ifdef CLARA_CONFIG_CPP11_UNIQUE_PTR +# define CLARA_AUTO_PTR( T ) std::unique_ptr +#else +# define CLARA_AUTO_PTR( T ) std::auto_ptr +#endif + +#endif // TWOBLUECUBES_CLARA_COMPILERS_H_INCLUDED + +// ----------- end of #include from clara_compilers.h ----------- +// ........... back in clara.h + +#include +#include +#include + +// Use optional outer namespace +#ifdef STITCH_CLARA_OPEN_NAMESPACE +STITCH_CLARA_OPEN_NAMESPACE +#endif + +namespace Clara { + + struct UnpositionalTag {}; + + extern UnpositionalTag _; + +#ifdef CLARA_CONFIG_MAIN + UnpositionalTag _; +#endif + + namespace Detail { + +#ifdef CLARA_CONSOLE_WIDTH + const unsigned int consoleWidth = CLARA_CONFIG_CONSOLE_WIDTH; +#else + const unsigned int consoleWidth = 80; +#endif + + // Use this to try and stop compiler from warning about unreachable code + inline bool isTrue( bool value ) { return value; } + + using namespace Tbc; + + inline bool startsWith( std::string const& str, std::string const& prefix ) { + return str.size() >= prefix.size() && str.substr( 0, prefix.size() ) == prefix; + } + + template struct RemoveConstRef{ typedef T type; }; + template struct RemoveConstRef{ typedef T type; }; + template struct RemoveConstRef{ typedef T type; }; + template struct RemoveConstRef{ typedef T type; }; + + template struct IsBool { static const bool value = false; }; + template<> struct IsBool { static const bool value = true; }; + + template + void convertInto( std::string const& _source, T& _dest ) { + std::stringstream ss; + ss << _source; + ss >> _dest; + if( ss.fail() ) + throw std::runtime_error( "Unable to convert " + _source + " to destination type" ); + } + inline void convertInto( std::string const& _source, std::string& _dest ) { + _dest = _source; + } + inline void convertInto( std::string const& _source, bool& _dest ) { + std::string sourceLC = _source; + std::transform( sourceLC.begin(), sourceLC.end(), sourceLC.begin(), ::tolower ); + if( sourceLC == "y" || sourceLC == "1" || sourceLC == "true" || sourceLC == "yes" || sourceLC == "on" ) + _dest = true; + else if( sourceLC == "n" || sourceLC == "0" || sourceLC == "false" || sourceLC == "no" || sourceLC == "off" ) + _dest = false; + else + throw std::runtime_error( "Expected a boolean value but did not recognise:\n '" + _source + "'" ); + } + inline void convertInto( bool _source, bool& _dest ) { + _dest = _source; + } + template + inline void convertInto( bool, T& ) { + if( isTrue( true ) ) + throw std::runtime_error( "Invalid conversion" ); + } + + template + struct IArgFunction { + virtual ~IArgFunction() {} +#ifdef CLARA_CONFIG_CPP11_GENERATED_METHODS + IArgFunction() = default; + IArgFunction( IArgFunction const& ) = default; +#endif + virtual void set( ConfigT& config, std::string const& value ) const = 0; + virtual void setFlag( ConfigT& config ) const = 0; + virtual bool takesArg() const = 0; + virtual IArgFunction* clone() const = 0; + }; + + template + class BoundArgFunction { + public: + BoundArgFunction() : functionObj( CLARA_NULL ) {} + BoundArgFunction( IArgFunction* _functionObj ) : functionObj( _functionObj ) {} + BoundArgFunction( BoundArgFunction const& other ) : functionObj( other.functionObj ? other.functionObj->clone() : CLARA_NULL ) {} + BoundArgFunction& operator = ( BoundArgFunction const& other ) { + IArgFunction* newFunctionObj = other.functionObj ? other.functionObj->clone() : CLARA_NULL; + delete functionObj; + functionObj = newFunctionObj; + return *this; + } + ~BoundArgFunction() { delete functionObj; } + + void set( ConfigT& config, std::string const& value ) const { + functionObj->set( config, value ); + } + void setFlag( ConfigT& config ) const { + functionObj->setFlag( config ); + } + bool takesArg() const { return functionObj->takesArg(); } + + bool isSet() const { + return functionObj != CLARA_NULL; + } + private: + IArgFunction* functionObj; + }; + + template + struct NullBinder : IArgFunction{ + virtual void set( C&, std::string const& ) const {} + virtual void setFlag( C& ) const {} + virtual bool takesArg() const { return true; } + virtual IArgFunction* clone() const { return new NullBinder( *this ); } + }; + + template + struct BoundDataMember : IArgFunction{ + BoundDataMember( M C::* _member ) : member( _member ) {} + virtual void set( C& p, std::string const& stringValue ) const { + convertInto( stringValue, p.*member ); + } + virtual void setFlag( C& p ) const { + convertInto( true, p.*member ); + } + virtual bool takesArg() const { return !IsBool::value; } + virtual IArgFunction* clone() const { return new BoundDataMember( *this ); } + M C::* member; + }; + template + struct BoundUnaryMethod : IArgFunction{ + BoundUnaryMethod( void (C::*_member)( M ) ) : member( _member ) {} + virtual void set( C& p, std::string const& stringValue ) const { + typename RemoveConstRef::type value; + convertInto( stringValue, value ); + (p.*member)( value ); + } + virtual void setFlag( C& p ) const { + typename RemoveConstRef::type value; + convertInto( true, value ); + (p.*member)( value ); + } + virtual bool takesArg() const { return !IsBool::value; } + virtual IArgFunction* clone() const { return new BoundUnaryMethod( *this ); } + void (C::*member)( M ); + }; + template + struct BoundNullaryMethod : IArgFunction{ + BoundNullaryMethod( void (C::*_member)() ) : member( _member ) {} + virtual void set( C& p, std::string const& stringValue ) const { + bool value; + convertInto( stringValue, value ); + if( value ) + (p.*member)(); + } + virtual void setFlag( C& p ) const { + (p.*member)(); + } + virtual bool takesArg() const { return false; } + virtual IArgFunction* clone() const { return new BoundNullaryMethod( *this ); } + void (C::*member)(); + }; + + template + struct BoundUnaryFunction : IArgFunction{ + BoundUnaryFunction( void (*_function)( C& ) ) : function( _function ) {} + virtual void set( C& obj, std::string const& stringValue ) const { + bool value; + convertInto( stringValue, value ); + if( value ) + function( obj ); + } + virtual void setFlag( C& p ) const { + function( p ); + } + virtual bool takesArg() const { return false; } + virtual IArgFunction* clone() const { return new BoundUnaryFunction( *this ); } + void (*function)( C& ); + }; + + template + struct BoundBinaryFunction : IArgFunction{ + BoundBinaryFunction( void (*_function)( C&, T ) ) : function( _function ) {} + virtual void set( C& obj, std::string const& stringValue ) const { + typename RemoveConstRef::type value; + convertInto( stringValue, value ); + function( obj, value ); + } + virtual void setFlag( C& obj ) const { + typename RemoveConstRef::type value; + convertInto( true, value ); + function( obj, value ); + } + virtual bool takesArg() const { return !IsBool::value; } + virtual IArgFunction* clone() const { return new BoundBinaryFunction( *this ); } + void (*function)( C&, T ); + }; + + } // namespace Detail + + struct Parser { + Parser() : separators( " \t=:" ) {} + + struct Token { + enum Type { Positional, ShortOpt, LongOpt }; + Token( Type _type, std::string const& _data ) : type( _type ), data( _data ) {} + Type type; + std::string data; + }; + + void parseIntoTokens( int argc, char const* const argv[], std::vector& tokens ) const { + const std::string doubleDash = "--"; + for( int i = 1; i < argc && argv[i] != doubleDash; ++i ) + parseIntoTokens( argv[i] , tokens); + } + void parseIntoTokens( std::string arg, std::vector& tokens ) const { + while( !arg.empty() ) { + Parser::Token token( Parser::Token::Positional, arg ); + arg = ""; + if( token.data[0] == '-' ) { + if( token.data.size() > 1 && token.data[1] == '-' ) { + token = Parser::Token( Parser::Token::LongOpt, token.data.substr( 2 ) ); + } + else { + token = Parser::Token( Parser::Token::ShortOpt, token.data.substr( 1 ) ); + if( token.data.size() > 1 && separators.find( token.data[1] ) == std::string::npos ) { + arg = "-" + token.data.substr( 1 ); + token.data = token.data.substr( 0, 1 ); + } + } + } + if( token.type != Parser::Token::Positional ) { + std::size_t pos = token.data.find_first_of( separators ); + if( pos != std::string::npos ) { + arg = token.data.substr( pos+1 ); + token.data = token.data.substr( 0, pos ); + } + } + tokens.push_back( token ); + } + } + std::string separators; + }; + + template + struct CommonArgProperties { + CommonArgProperties() {} + CommonArgProperties( Detail::BoundArgFunction const& _boundField ) : boundField( _boundField ) {} + + Detail::BoundArgFunction boundField; + std::string description; + std::string detail; + std::string placeholder; // Only value if boundField takes an arg + + bool takesArg() const { + return !placeholder.empty(); + } + void validate() const { + if( !boundField.isSet() ) + throw std::logic_error( "option not bound" ); + } + }; + struct OptionArgProperties { + std::vector shortNames; + std::string longName; + + bool hasShortName( std::string const& shortName ) const { + return std::find( shortNames.begin(), shortNames.end(), shortName ) != shortNames.end(); + } + bool hasLongName( std::string const& _longName ) const { + return _longName == longName; + } + }; + struct PositionalArgProperties { + PositionalArgProperties() : position( -1 ) {} + int position; // -1 means non-positional (floating) + + bool isFixedPositional() const { + return position != -1; + } + }; + + template + class CommandLine { + + struct Arg : CommonArgProperties, OptionArgProperties, PositionalArgProperties { + Arg() {} + Arg( Detail::BoundArgFunction const& _boundField ) : CommonArgProperties( _boundField ) {} + + using CommonArgProperties::placeholder; // !TBD + + std::string dbgName() const { + if( !longName.empty() ) + return "--" + longName; + if( !shortNames.empty() ) + return "-" + shortNames[0]; + return "positional args"; + } + std::string commands() const { + std::ostringstream oss; + bool first = true; + std::vector::const_iterator it = shortNames.begin(), itEnd = shortNames.end(); + for(; it != itEnd; ++it ) { + if( first ) + first = false; + else + oss << ", "; + oss << "-" << *it; + } + if( !longName.empty() ) { + if( !first ) + oss << ", "; + oss << "--" << longName; + } + if( !placeholder.empty() ) + oss << " <" << placeholder << ">"; + return oss.str(); + } + }; + + typedef CLARA_AUTO_PTR( Arg ) ArgAutoPtr; + + friend void addOptName( Arg& arg, std::string const& optName ) + { + if( optName.empty() ) + return; + if( Detail::startsWith( optName, "--" ) ) { + if( !arg.longName.empty() ) + throw std::logic_error( "Only one long opt may be specified. '" + + arg.longName + + "' already specified, now attempting to add '" + + optName + "'" ); + arg.longName = optName.substr( 2 ); + } + else if( Detail::startsWith( optName, "-" ) ) + arg.shortNames.push_back( optName.substr( 1 ) ); + else + throw std::logic_error( "option must begin with - or --. Option was: '" + optName + "'" ); + } + friend void setPositionalArg( Arg& arg, int position ) + { + arg.position = position; + } + + class ArgBuilder { + public: + ArgBuilder( Arg* arg ) : m_arg( arg ) {} + + // Bind a non-boolean data member (requires placeholder string) + template + void bind( M C::* field, std::string const& placeholder ) { + m_arg->boundField = new Detail::BoundDataMember( field ); + m_arg->placeholder = placeholder; + } + // Bind a boolean data member (no placeholder required) + template + void bind( bool C::* field ) { + m_arg->boundField = new Detail::BoundDataMember( field ); + } + + // Bind a method taking a single, non-boolean argument (requires a placeholder string) + template + void bind( void (C::* unaryMethod)( M ), std::string const& placeholder ) { + m_arg->boundField = new Detail::BoundUnaryMethod( unaryMethod ); + m_arg->placeholder = placeholder; + } + + // Bind a method taking a single, boolean argument (no placeholder string required) + template + void bind( void (C::* unaryMethod)( bool ) ) { + m_arg->boundField = new Detail::BoundUnaryMethod( unaryMethod ); + } + + // Bind a method that takes no arguments (will be called if opt is present) + template + void bind( void (C::* nullaryMethod)() ) { + m_arg->boundField = new Detail::BoundNullaryMethod( nullaryMethod ); + } + + // Bind a free function taking a single argument - the object to operate on (no placeholder string required) + template + void bind( void (* unaryFunction)( C& ) ) { + m_arg->boundField = new Detail::BoundUnaryFunction( unaryFunction ); + } + + // Bind a free function taking a single argument - the object to operate on (requires a placeholder string) + template + void bind( void (* binaryFunction)( C&, T ), std::string const& placeholder ) { + m_arg->boundField = new Detail::BoundBinaryFunction( binaryFunction ); + m_arg->placeholder = placeholder; + } + + ArgBuilder& describe( std::string const& description ) { + m_arg->description = description; + return *this; + } + ArgBuilder& detail( std::string const& detail ) { + m_arg->detail = detail; + return *this; + } + + protected: + Arg* m_arg; + }; + + class OptBuilder : public ArgBuilder { + public: + OptBuilder( Arg* arg ) : ArgBuilder( arg ) {} + OptBuilder( OptBuilder& other ) : ArgBuilder( other ) {} + + OptBuilder& operator[]( std::string const& optName ) { + addOptName( *ArgBuilder::m_arg, optName ); + return *this; + } + }; + + public: + + CommandLine() + : m_boundProcessName( new Detail::NullBinder() ), + m_highestSpecifiedArgPosition( 0 ), + m_throwOnUnrecognisedTokens( false ) + {} + CommandLine( CommandLine const& other ) + : m_boundProcessName( other.m_boundProcessName ), + m_options ( other.m_options ), + m_positionalArgs( other.m_positionalArgs ), + m_highestSpecifiedArgPosition( other.m_highestSpecifiedArgPosition ), + m_throwOnUnrecognisedTokens( other.m_throwOnUnrecognisedTokens ) + { + if( other.m_floatingArg.get() ) + m_floatingArg.reset( new Arg( *other.m_floatingArg ) ); + } + + CommandLine& setThrowOnUnrecognisedTokens( bool shouldThrow = true ) { + m_throwOnUnrecognisedTokens = shouldThrow; + return *this; + } + + OptBuilder operator[]( std::string const& optName ) { + m_options.push_back( Arg() ); + addOptName( m_options.back(), optName ); + OptBuilder builder( &m_options.back() ); + return builder; + } + + ArgBuilder operator[]( int position ) { + m_positionalArgs.insert( std::make_pair( position, Arg() ) ); + if( position > m_highestSpecifiedArgPosition ) + m_highestSpecifiedArgPosition = position; + setPositionalArg( m_positionalArgs[position], position ); + ArgBuilder builder( &m_positionalArgs[position] ); + return builder; + } + + // Invoke this with the _ instance + ArgBuilder operator[]( UnpositionalTag ) { + if( m_floatingArg.get() ) + throw std::logic_error( "Only one unpositional argument can be added" ); + m_floatingArg.reset( new Arg() ); + ArgBuilder builder( m_floatingArg.get() ); + return builder; + } + + template + void bindProcessName( M C::* field ) { + m_boundProcessName = new Detail::BoundDataMember( field ); + } + template + void bindProcessName( void (C::*_unaryMethod)( M ) ) { + m_boundProcessName = new Detail::BoundUnaryMethod( _unaryMethod ); + } + + void optUsage( std::ostream& os, std::size_t indent = 0, std::size_t width = Detail::consoleWidth ) const { + typename std::vector::const_iterator itBegin = m_options.begin(), itEnd = m_options.end(), it; + std::size_t maxWidth = 0; + for( it = itBegin; it != itEnd; ++it ) + maxWidth = (std::max)( maxWidth, it->commands().size() ); + + for( it = itBegin; it != itEnd; ++it ) { + Detail::Text usage( it->commands(), Detail::TextAttributes() + .setWidth( maxWidth+indent ) + .setIndent( indent ) ); + Detail::Text desc( it->description, Detail::TextAttributes() + .setWidth( width - maxWidth - 3 ) ); + + for( std::size_t i = 0; i < (std::max)( usage.size(), desc.size() ); ++i ) { + std::string usageCol = i < usage.size() ? usage[i] : ""; + os << usageCol; + + if( i < desc.size() && !desc[i].empty() ) + os << std::string( indent + 2 + maxWidth - usageCol.size(), ' ' ) + << desc[i]; + os << "\n"; + } + } + } + std::string optUsage() const { + std::ostringstream oss; + optUsage( oss ); + return oss.str(); + } + + void argSynopsis( std::ostream& os ) const { + for( int i = 1; i <= m_highestSpecifiedArgPosition; ++i ) { + if( i > 1 ) + os << " "; + typename std::map::const_iterator it = m_positionalArgs.find( i ); + if( it != m_positionalArgs.end() ) + os << "<" << it->second.placeholder << ">"; + else if( m_floatingArg.get() ) + os << "<" << m_floatingArg->placeholder << ">"; + else + throw std::logic_error( "non consecutive positional arguments with no floating args" ); + } + // !TBD No indication of mandatory args + if( m_floatingArg.get() ) { + if( m_highestSpecifiedArgPosition > 1 ) + os << " "; + os << "[<" << m_floatingArg->placeholder << "> ...]"; + } + } + std::string argSynopsis() const { + std::ostringstream oss; + argSynopsis( oss ); + return oss.str(); + } + + void usage( std::ostream& os, std::string const& procName ) const { + validate(); + os << "usage:\n " << procName << " "; + argSynopsis( os ); + if( !m_options.empty() ) { + os << " [options]\n\nwhere options are: \n"; + optUsage( os, 2 ); + } + os << "\n"; + } + std::string usage( std::string const& procName ) const { + std::ostringstream oss; + usage( oss, procName ); + return oss.str(); + } + + ConfigT parse( int argc, char const* const argv[] ) const { + ConfigT config; + parseInto( argc, argv, config ); + return config; + } + + std::vector parseInto( int argc, char const* argv[], ConfigT& config ) const { + std::string processName = argv[0]; + std::size_t lastSlash = processName.find_last_of( "/\\" ); + if( lastSlash != std::string::npos ) + processName = processName.substr( lastSlash+1 ); + m_boundProcessName.set( config, processName ); + std::vector tokens; + Parser parser; + parser.parseIntoTokens( argc, argv, tokens ); + return populate( tokens, config ); + } + + std::vector populate( std::vector const& tokens, ConfigT& config ) const { + validate(); + std::vector unusedTokens = populateOptions( tokens, config ); + unusedTokens = populateFixedArgs( unusedTokens, config ); + unusedTokens = populateFloatingArgs( unusedTokens, config ); + return unusedTokens; + } + + std::vector populateOptions( std::vector const& tokens, ConfigT& config ) const { + std::vector unusedTokens; + std::vector errors; + for( std::size_t i = 0; i < tokens.size(); ++i ) { + Parser::Token const& token = tokens[i]; + typename std::vector::const_iterator it = m_options.begin(), itEnd = m_options.end(); + for(; it != itEnd; ++it ) { + Arg const& arg = *it; + + try { + if( ( token.type == Parser::Token::ShortOpt && arg.hasShortName( token.data ) ) || + ( token.type == Parser::Token::LongOpt && arg.hasLongName( token.data ) ) ) { + if( arg.takesArg() ) { + if( i == tokens.size()-1 || tokens[i+1].type != Parser::Token::Positional ) + errors.push_back( "Expected argument to option: " + token.data ); + else + arg.boundField.set( config, tokens[++i].data ); + } + else { + arg.boundField.setFlag( config ); + } + break; + } + } + catch( std::exception& ex ) { + errors.push_back( std::string( ex.what() ) + "\n- while parsing: (" + arg.commands() + ")" ); + } + } + if( it == itEnd ) { + if( token.type == Parser::Token::Positional || !m_throwOnUnrecognisedTokens ) + unusedTokens.push_back( token ); + else if( errors.empty() && m_throwOnUnrecognisedTokens ) + errors.push_back( "unrecognised option: " + token.data ); + } + } + if( !errors.empty() ) { + std::ostringstream oss; + for( std::vector::const_iterator it = errors.begin(), itEnd = errors.end(); + it != itEnd; + ++it ) { + if( it != errors.begin() ) + oss << "\n"; + oss << *it; + } + throw std::runtime_error( oss.str() ); + } + return unusedTokens; + } + std::vector populateFixedArgs( std::vector const& tokens, ConfigT& config ) const { + std::vector unusedTokens; + int position = 1; + for( std::size_t i = 0; i < tokens.size(); ++i ) { + Parser::Token const& token = tokens[i]; + typename std::map::const_iterator it = m_positionalArgs.find( position ); + if( it != m_positionalArgs.end() ) + it->second.boundField.set( config, token.data ); + else + unusedTokens.push_back( token ); + if( token.type == Parser::Token::Positional ) + position++; + } + return unusedTokens; + } + std::vector populateFloatingArgs( std::vector const& tokens, ConfigT& config ) const { + if( !m_floatingArg.get() ) + return tokens; + std::vector unusedTokens; + for( std::size_t i = 0; i < tokens.size(); ++i ) { + Parser::Token const& token = tokens[i]; + if( token.type == Parser::Token::Positional ) + m_floatingArg->boundField.set( config, token.data ); + else + unusedTokens.push_back( token ); + } + return unusedTokens; + } + + void validate() const + { + if( m_options.empty() && m_positionalArgs.empty() && !m_floatingArg.get() ) + throw std::logic_error( "No options or arguments specified" ); + + for( typename std::vector::const_iterator it = m_options.begin(), + itEnd = m_options.end(); + it != itEnd; ++it ) + it->validate(); + } + + private: + Detail::BoundArgFunction m_boundProcessName; + std::vector m_options; + std::map m_positionalArgs; + ArgAutoPtr m_floatingArg; + int m_highestSpecifiedArgPosition; + bool m_throwOnUnrecognisedTokens; + }; + +} // end namespace Clara + +STITCH_CLARA_CLOSE_NAMESPACE +#undef STITCH_CLARA_OPEN_NAMESPACE +#undef STITCH_CLARA_CLOSE_NAMESPACE + +#endif // TWOBLUECUBES_CLARA_H_INCLUDED +#undef STITCH_CLARA_OPEN_NAMESPACE + +// Restore Clara's value for console width, if present +#ifdef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH +#define CLARA_CONFIG_CONSOLE_WIDTH CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH +#undef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH +#endif + +#include + +namespace Catch { + + inline void abortAfterFirst( ConfigData& config ) { config.abortAfter = 1; } + inline void abortAfterX( ConfigData& config, int x ) { + if( x < 1 ) + throw std::runtime_error( "Value after -x or --abortAfter must be greater than zero" ); + config.abortAfter = x; + } + inline void addTestOrTags( ConfigData& config, std::string const& _testSpec ) { config.testsOrTags.push_back( _testSpec ); } + inline void addReporterName( ConfigData& config, std::string const& _reporterName ) { config.reporterNames.push_back( _reporterName ); } + + inline void addWarning( ConfigData& config, std::string const& _warning ) { + if( _warning == "NoAssertions" ) + config.warnings = static_cast( config.warnings | WarnAbout::NoAssertions ); + else + throw std::runtime_error( "Unrecognised warning: '" + _warning + "'" ); + } + inline void setOrder( ConfigData& config, std::string const& order ) { + if( startsWith( "declared", order ) ) + config.runOrder = RunTests::InDeclarationOrder; + else if( startsWith( "lexical", order ) ) + config.runOrder = RunTests::InLexicographicalOrder; + else if( startsWith( "random", order ) ) + config.runOrder = RunTests::InRandomOrder; + else + throw std::runtime_error( "Unrecognised ordering: '" + order + "'" ); + } + inline void setRngSeed( ConfigData& config, std::string const& seed ) { + if( seed == "time" ) { + config.rngSeed = static_cast( std::time(0) ); + } + else { + std::stringstream ss; + ss << seed; + ss >> config.rngSeed; + if( ss.fail() ) + throw std::runtime_error( "Argment to --rng-seed should be the word 'time' or a number" ); + } + } + inline void setVerbosity( ConfigData& config, int level ) { + // !TBD: accept strings? + config.verbosity = static_cast( level ); + } + inline void setShowDurations( ConfigData& config, bool _showDurations ) { + config.showDurations = _showDurations + ? ShowDurations::Always + : ShowDurations::Never; + } + inline void setUseColour( ConfigData& config, std::string const& value ) { + std::string mode = toLower( value ); + + if( mode == "yes" ) + config.useColour = UseColour::Yes; + else if( mode == "no" ) + config.useColour = UseColour::No; + else if( mode == "auto" ) + config.useColour = UseColour::Auto; + else + throw std::runtime_error( "colour mode must be one of: auto, yes or no" ); + } + inline void forceColour( ConfigData& config ) { + config.useColour = UseColour::Yes; + } + inline void loadTestNamesFromFile( ConfigData& config, std::string const& _filename ) { + std::ifstream f( _filename.c_str() ); + if( !f.is_open() ) + throw std::domain_error( "Unable to load input file: " + _filename ); + + std::string line; + while( std::getline( f, line ) ) { + line = trim(line); + if( !line.empty() && !startsWith( line, "#" ) ) + addTestOrTags( config, "\"" + line + "\"," ); + } + } + + inline Clara::CommandLine makeCommandLineParser() { + + using namespace Clara; + CommandLine cli; + + cli.bindProcessName( &ConfigData::processName ); + + cli["-?"]["-h"]["--help"] + .describe( "display usage information" ) + .bind( &ConfigData::showHelp ); + + cli["-l"]["--list-tests"] + .describe( "list all/matching test cases" ) + .bind( &ConfigData::listTests ); + + cli["-t"]["--list-tags"] + .describe( "list all/matching tags" ) + .bind( &ConfigData::listTags ); + + cli["-s"]["--success"] + .describe( "include successful tests in output" ) + .bind( &ConfigData::showSuccessfulTests ); + + cli["-b"]["--break"] + .describe( "break into debugger on failure" ) + .bind( &ConfigData::shouldDebugBreak ); + + cli["-e"]["--nothrow"] + .describe( "skip exception tests" ) + .bind( &ConfigData::noThrow ); + + cli["-i"]["--invisibles"] + .describe( "show invisibles (tabs, newlines)" ) + .bind( &ConfigData::showInvisibles ); + + cli["-o"]["--out"] + .describe( "output filename" ) + .bind( &ConfigData::outputFilename, "filename" ); + + cli["-r"]["--reporter"] +// .placeholder( "name[:filename]" ) + .describe( "reporter to use (defaults to console)" ) + .bind( &addReporterName, "name" ); + + cli["-n"]["--name"] + .describe( "suite name" ) + .bind( &ConfigData::name, "name" ); + + cli["-a"]["--abort"] + .describe( "abort at first failure" ) + .bind( &abortAfterFirst ); + + cli["-x"]["--abortx"] + .describe( "abort after x failures" ) + .bind( &abortAfterX, "no. failures" ); + + cli["-w"]["--warn"] + .describe( "enable warnings" ) + .bind( &addWarning, "warning name" ); + +// - needs updating if reinstated +// cli.into( &setVerbosity ) +// .describe( "level of verbosity (0=no output)" ) +// .shortOpt( "v") +// .longOpt( "verbosity" ) +// .placeholder( "level" ); + + cli[_] + .describe( "which test or tests to use" ) + .bind( &addTestOrTags, "test name, pattern or tags" ); + + cli["-d"]["--durations"] + .describe( "show test durations" ) + .bind( &setShowDurations, "yes|no" ); + + cli["-f"]["--input-file"] + .describe( "load test names to run from a file" ) + .bind( &loadTestNamesFromFile, "filename" ); + + cli["-#"]["--filenames-as-tags"] + .describe( "adds a tag for the filename" ) + .bind( &ConfigData::filenamesAsTags ); + + // Less common commands which don't have a short form + cli["--list-test-names-only"] + .describe( "list all/matching test cases names only" ) + .bind( &ConfigData::listTestNamesOnly ); + + cli["--list-reporters"] + .describe( "list all reporters" ) + .bind( &ConfigData::listReporters ); + + cli["--order"] + .describe( "test case order (defaults to decl)" ) + .bind( &setOrder, "decl|lex|rand" ); + + cli["--rng-seed"] + .describe( "set a specific seed for random numbers" ) + .bind( &setRngSeed, "'time'|number" ); + + cli["--force-colour"] + .describe( "force colourised output (deprecated)" ) + .bind( &forceColour ); + + cli["--use-colour"] + .describe( "should output be colourised" ) + .bind( &setUseColour, "yes|no" ); + + return cli; + } + +} // end namespace Catch + +// #included from: internal/catch_list.hpp +#define TWOBLUECUBES_CATCH_LIST_HPP_INCLUDED + +// #included from: catch_text.h +#define TWOBLUECUBES_CATCH_TEXT_H_INCLUDED + +#define TBC_TEXT_FORMAT_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH + +#define CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE Catch +// #included from: ../external/tbc_text_format.h +// Only use header guard if we are not using an outer namespace +#ifndef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE +# ifdef TWOBLUECUBES_TEXT_FORMAT_H_INCLUDED +# ifndef TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED +# define TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED +# endif +# else +# define TWOBLUECUBES_TEXT_FORMAT_H_INCLUDED +# endif +#endif +#ifndef TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED +#include +#include +#include + +// Use optional outer namespace +#ifdef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE +namespace CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE { +#endif + +namespace Tbc { + +#ifdef TBC_TEXT_FORMAT_CONSOLE_WIDTH + const unsigned int consoleWidth = TBC_TEXT_FORMAT_CONSOLE_WIDTH; +#else + const unsigned int consoleWidth = 80; +#endif + + struct TextAttributes { + TextAttributes() + : initialIndent( std::string::npos ), + indent( 0 ), + width( consoleWidth-1 ), + tabChar( '\t' ) + {} + + TextAttributes& setInitialIndent( std::size_t _value ) { initialIndent = _value; return *this; } + TextAttributes& setIndent( std::size_t _value ) { indent = _value; return *this; } + TextAttributes& setWidth( std::size_t _value ) { width = _value; return *this; } + TextAttributes& setTabChar( char _value ) { tabChar = _value; return *this; } + + std::size_t initialIndent; // indent of first line, or npos + std::size_t indent; // indent of subsequent lines, or all if initialIndent is npos + std::size_t width; // maximum width of text, including indent. Longer text will wrap + char tabChar; // If this char is seen the indent is changed to current pos + }; + + class Text { + public: + Text( std::string const& _str, TextAttributes const& _attr = TextAttributes() ) + : attr( _attr ) + { + std::string wrappableChars = " [({.,/|\\-"; + std::size_t indent = _attr.initialIndent != std::string::npos + ? _attr.initialIndent + : _attr.indent; + std::string remainder = _str; + + while( !remainder.empty() ) { + if( lines.size() >= 1000 ) { + lines.push_back( "... message truncated due to excessive size" ); + return; + } + std::size_t tabPos = std::string::npos; + std::size_t width = (std::min)( remainder.size(), _attr.width - indent ); + std::size_t pos = remainder.find_first_of( '\n' ); + if( pos <= width ) { + width = pos; + } + pos = remainder.find_last_of( _attr.tabChar, width ); + if( pos != std::string::npos ) { + tabPos = pos; + if( remainder[width] == '\n' ) + width--; + remainder = remainder.substr( 0, tabPos ) + remainder.substr( tabPos+1 ); + } + + if( width == remainder.size() ) { + spliceLine( indent, remainder, width ); + } + else if( remainder[width] == '\n' ) { + spliceLine( indent, remainder, width ); + if( width <= 1 || remainder.size() != 1 ) + remainder = remainder.substr( 1 ); + indent = _attr.indent; + } + else { + pos = remainder.find_last_of( wrappableChars, width ); + if( pos != std::string::npos && pos > 0 ) { + spliceLine( indent, remainder, pos ); + if( remainder[0] == ' ' ) + remainder = remainder.substr( 1 ); + } + else { + spliceLine( indent, remainder, width-1 ); + lines.back() += "-"; + } + if( lines.size() == 1 ) + indent = _attr.indent; + if( tabPos != std::string::npos ) + indent += tabPos; + } + } + } + + void spliceLine( std::size_t _indent, std::string& _remainder, std::size_t _pos ) { + lines.push_back( std::string( _indent, ' ' ) + _remainder.substr( 0, _pos ) ); + _remainder = _remainder.substr( _pos ); + } + + typedef std::vector::const_iterator const_iterator; + + const_iterator begin() const { return lines.begin(); } + const_iterator end() const { return lines.end(); } + std::string const& last() const { return lines.back(); } + std::size_t size() const { return lines.size(); } + std::string const& operator[]( std::size_t _index ) const { return lines[_index]; } + std::string toString() const { + std::ostringstream oss; + oss << *this; + return oss.str(); + } + + inline friend std::ostream& operator << ( std::ostream& _stream, Text const& _text ) { + for( Text::const_iterator it = _text.begin(), itEnd = _text.end(); + it != itEnd; ++it ) { + if( it != _text.begin() ) + _stream << "\n"; + _stream << *it; + } + return _stream; + } + + private: + std::string str; + TextAttributes attr; + std::vector lines; + }; + +} // end namespace Tbc + +#ifdef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE +} // end outer namespace +#endif + +#endif // TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED +#undef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE + +namespace Catch { + using Tbc::Text; + using Tbc::TextAttributes; +} + +// #included from: catch_console_colour.hpp +#define TWOBLUECUBES_CATCH_CONSOLE_COLOUR_HPP_INCLUDED + +namespace Catch { + + struct Colour { + enum Code { + None = 0, + + White, + Red, + Green, + Blue, + Cyan, + Yellow, + Grey, + + Bright = 0x10, + + BrightRed = Bright | Red, + BrightGreen = Bright | Green, + LightGrey = Bright | Grey, + BrightWhite = Bright | White, + + // By intention + FileName = LightGrey, + Warning = Yellow, + ResultError = BrightRed, + ResultSuccess = BrightGreen, + ResultExpectedFailure = Warning, + + Error = BrightRed, + Success = Green, + + OriginalExpression = Cyan, + ReconstructedExpression = Yellow, + + SecondaryText = LightGrey, + Headers = White + }; + + // Use constructed object for RAII guard + Colour( Code _colourCode ); + Colour( Colour const& other ); + ~Colour(); + + // Use static method for one-shot changes + static void use( Code _colourCode ); + + private: + bool m_moved; + }; + + inline std::ostream& operator << ( std::ostream& os, Colour const& ) { return os; } + +} // end namespace Catch + +// #included from: catch_interfaces_reporter.h +#define TWOBLUECUBES_CATCH_INTERFACES_REPORTER_H_INCLUDED + +#include +#include +#include +#include + +namespace Catch +{ + struct ReporterConfig { + explicit ReporterConfig( Ptr const& _fullConfig ) + : m_stream( &_fullConfig->stream() ), m_fullConfig( _fullConfig ) {} + + ReporterConfig( Ptr const& _fullConfig, std::ostream& _stream ) + : m_stream( &_stream ), m_fullConfig( _fullConfig ) {} + + std::ostream& stream() const { return *m_stream; } + Ptr fullConfig() const { return m_fullConfig; } + + private: + std::ostream* m_stream; + Ptr m_fullConfig; + }; + + struct ReporterPreferences { + ReporterPreferences() + : shouldRedirectStdOut( false ) + {} + + bool shouldRedirectStdOut; + }; + + template + struct LazyStat : Option { + LazyStat() : used( false ) {} + LazyStat& operator=( T const& _value ) { + Option::operator=( _value ); + used = false; + return *this; + } + void reset() { + Option::reset(); + used = false; + } + bool used; + }; + + struct TestRunInfo { + TestRunInfo( std::string const& _name ) : name( _name ) {} + std::string name; + }; + struct GroupInfo { + GroupInfo( std::string const& _name, + std::size_t _groupIndex, + std::size_t _groupsCount ) + : name( _name ), + groupIndex( _groupIndex ), + groupsCounts( _groupsCount ) + {} + + std::string name; + std::size_t groupIndex; + std::size_t groupsCounts; + }; + + struct AssertionStats { + AssertionStats( AssertionResult const& _assertionResult, + std::vector const& _infoMessages, + Totals const& _totals ) + : assertionResult( _assertionResult ), + infoMessages( _infoMessages ), + totals( _totals ) + { + if( assertionResult.hasMessage() ) { + // Copy message into messages list. + // !TBD This should have been done earlier, somewhere + MessageBuilder builder( assertionResult.getTestMacroName(), assertionResult.getSourceInfo(), assertionResult.getResultType() ); + builder << assertionResult.getMessage(); + builder.m_info.message = builder.m_stream.str(); + + infoMessages.push_back( builder.m_info ); + } + } + virtual ~AssertionStats(); + +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + AssertionStats( AssertionStats const& ) = default; + AssertionStats( AssertionStats && ) = default; + AssertionStats& operator = ( AssertionStats const& ) = default; + AssertionStats& operator = ( AssertionStats && ) = default; +# endif + + AssertionResult assertionResult; + std::vector infoMessages; + Totals totals; + }; + + struct SectionStats { + SectionStats( SectionInfo const& _sectionInfo, + Counts const& _assertions, + double _durationInSeconds, + bool _missingAssertions ) + : sectionInfo( _sectionInfo ), + assertions( _assertions ), + durationInSeconds( _durationInSeconds ), + missingAssertions( _missingAssertions ) + {} + virtual ~SectionStats(); +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + SectionStats( SectionStats const& ) = default; + SectionStats( SectionStats && ) = default; + SectionStats& operator = ( SectionStats const& ) = default; + SectionStats& operator = ( SectionStats && ) = default; +# endif + + SectionInfo sectionInfo; + Counts assertions; + double durationInSeconds; + bool missingAssertions; + }; + + struct TestCaseStats { + TestCaseStats( TestCaseInfo const& _testInfo, + Totals const& _totals, + std::string const& _stdOut, + std::string const& _stdErr, + bool _aborting ) + : testInfo( _testInfo ), + totals( _totals ), + stdOut( _stdOut ), + stdErr( _stdErr ), + aborting( _aborting ) + {} + virtual ~TestCaseStats(); + +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + TestCaseStats( TestCaseStats const& ) = default; + TestCaseStats( TestCaseStats && ) = default; + TestCaseStats& operator = ( TestCaseStats const& ) = default; + TestCaseStats& operator = ( TestCaseStats && ) = default; +# endif + + TestCaseInfo testInfo; + Totals totals; + std::string stdOut; + std::string stdErr; + bool aborting; + }; + + struct TestGroupStats { + TestGroupStats( GroupInfo const& _groupInfo, + Totals const& _totals, + bool _aborting ) + : groupInfo( _groupInfo ), + totals( _totals ), + aborting( _aborting ) + {} + TestGroupStats( GroupInfo const& _groupInfo ) + : groupInfo( _groupInfo ), + aborting( false ) + {} + virtual ~TestGroupStats(); + +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + TestGroupStats( TestGroupStats const& ) = default; + TestGroupStats( TestGroupStats && ) = default; + TestGroupStats& operator = ( TestGroupStats const& ) = default; + TestGroupStats& operator = ( TestGroupStats && ) = default; +# endif + + GroupInfo groupInfo; + Totals totals; + bool aborting; + }; + + struct TestRunStats { + TestRunStats( TestRunInfo const& _runInfo, + Totals const& _totals, + bool _aborting ) + : runInfo( _runInfo ), + totals( _totals ), + aborting( _aborting ) + {} + virtual ~TestRunStats(); + +# ifndef CATCH_CONFIG_CPP11_GENERATED_METHODS + TestRunStats( TestRunStats const& _other ) + : runInfo( _other.runInfo ), + totals( _other.totals ), + aborting( _other.aborting ) + {} +# else + TestRunStats( TestRunStats const& ) = default; + TestRunStats( TestRunStats && ) = default; + TestRunStats& operator = ( TestRunStats const& ) = default; + TestRunStats& operator = ( TestRunStats && ) = default; +# endif + + TestRunInfo runInfo; + Totals totals; + bool aborting; + }; + + struct IStreamingReporter : IShared { + virtual ~IStreamingReporter(); + + // Implementing class must also provide the following static method: + // static std::string getDescription(); + + virtual ReporterPreferences getPreferences() const = 0; + + virtual void noMatchingTestCases( std::string const& spec ) = 0; + + virtual void testRunStarting( TestRunInfo const& testRunInfo ) = 0; + virtual void testGroupStarting( GroupInfo const& groupInfo ) = 0; + + virtual void testCaseStarting( TestCaseInfo const& testInfo ) = 0; + virtual void sectionStarting( SectionInfo const& sectionInfo ) = 0; + + virtual void assertionStarting( AssertionInfo const& assertionInfo ) = 0; + + // The return value indicates if the messages buffer should be cleared: + virtual bool assertionEnded( AssertionStats const& assertionStats ) = 0; + + virtual void sectionEnded( SectionStats const& sectionStats ) = 0; + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) = 0; + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) = 0; + virtual void testRunEnded( TestRunStats const& testRunStats ) = 0; + + virtual void skipTest( TestCaseInfo const& testInfo ) = 0; + }; + + struct IReporterFactory : IShared { + virtual ~IReporterFactory(); + virtual IStreamingReporter* create( ReporterConfig const& config ) const = 0; + virtual std::string getDescription() const = 0; + }; + + struct IReporterRegistry { + typedef std::map > FactoryMap; + typedef std::vector > Listeners; + + virtual ~IReporterRegistry(); + virtual IStreamingReporter* create( std::string const& name, Ptr const& config ) const = 0; + virtual FactoryMap const& getFactories() const = 0; + virtual Listeners const& getListeners() const = 0; + }; + + Ptr addReporter( Ptr const& existingReporter, Ptr const& additionalReporter ); + +} + +#include +#include + +namespace Catch { + + inline std::size_t listTests( Config const& config ) { + + TestSpec testSpec = config.testSpec(); + if( config.testSpec().hasFilters() ) + Catch::cout() << "Matching test cases:\n"; + else { + Catch::cout() << "All available test cases:\n"; + testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); + } + + std::size_t matchedTests = 0; + TextAttributes nameAttr, tagsAttr; + nameAttr.setInitialIndent( 2 ).setIndent( 4 ); + tagsAttr.setIndent( 6 ); + + std::vector matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); + for( std::vector::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); + it != itEnd; + ++it ) { + matchedTests++; + TestCaseInfo const& testCaseInfo = it->getTestCaseInfo(); + Colour::Code colour = testCaseInfo.isHidden() + ? Colour::SecondaryText + : Colour::None; + Colour colourGuard( colour ); + + Catch::cout() << Text( testCaseInfo.name, nameAttr ) << std::endl; + if( !testCaseInfo.tags.empty() ) + Catch::cout() << Text( testCaseInfo.tagsAsString, tagsAttr ) << std::endl; + } + + if( !config.testSpec().hasFilters() ) + Catch::cout() << pluralise( matchedTests, "test case" ) << "\n" << std::endl; + else + Catch::cout() << pluralise( matchedTests, "matching test case" ) << "\n" << std::endl; + return matchedTests; + } + + inline std::size_t listTestsNamesOnly( Config const& config ) { + TestSpec testSpec = config.testSpec(); + if( !config.testSpec().hasFilters() ) + testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); + std::size_t matchedTests = 0; + std::vector matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); + for( std::vector::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); + it != itEnd; + ++it ) { + matchedTests++; + TestCaseInfo const& testCaseInfo = it->getTestCaseInfo(); + Catch::cout() << testCaseInfo.name << std::endl; + } + return matchedTests; + } + + struct TagInfo { + TagInfo() : count ( 0 ) {} + void add( std::string const& spelling ) { + ++count; + spellings.insert( spelling ); + } + std::string all() const { + std::string out; + for( std::set::const_iterator it = spellings.begin(), itEnd = spellings.end(); + it != itEnd; + ++it ) + out += "[" + *it + "]"; + return out; + } + std::set spellings; + std::size_t count; + }; + + inline std::size_t listTags( Config const& config ) { + TestSpec testSpec = config.testSpec(); + if( config.testSpec().hasFilters() ) + Catch::cout() << "Tags for matching test cases:\n"; + else { + Catch::cout() << "All available tags:\n"; + testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); + } + + std::map tagCounts; + + std::vector matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); + for( std::vector::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); + it != itEnd; + ++it ) { + for( std::set::const_iterator tagIt = it->getTestCaseInfo().tags.begin(), + tagItEnd = it->getTestCaseInfo().tags.end(); + tagIt != tagItEnd; + ++tagIt ) { + std::string tagName = *tagIt; + std::string lcaseTagName = toLower( tagName ); + std::map::iterator countIt = tagCounts.find( lcaseTagName ); + if( countIt == tagCounts.end() ) + countIt = tagCounts.insert( std::make_pair( lcaseTagName, TagInfo() ) ).first; + countIt->second.add( tagName ); + } + } + + for( std::map::const_iterator countIt = tagCounts.begin(), + countItEnd = tagCounts.end(); + countIt != countItEnd; + ++countIt ) { + std::ostringstream oss; + oss << " " << std::setw(2) << countIt->second.count << " "; + Text wrapper( countIt->second.all(), TextAttributes() + .setInitialIndent( 0 ) + .setIndent( oss.str().size() ) + .setWidth( CATCH_CONFIG_CONSOLE_WIDTH-10 ) ); + Catch::cout() << oss.str() << wrapper << "\n"; + } + Catch::cout() << pluralise( tagCounts.size(), "tag" ) << "\n" << std::endl; + return tagCounts.size(); + } + + inline std::size_t listReporters( Config const& /*config*/ ) { + Catch::cout() << "Available reporters:\n"; + IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories(); + IReporterRegistry::FactoryMap::const_iterator itBegin = factories.begin(), itEnd = factories.end(), it; + std::size_t maxNameLen = 0; + for(it = itBegin; it != itEnd; ++it ) + maxNameLen = (std::max)( maxNameLen, it->first.size() ); + + for(it = itBegin; it != itEnd; ++it ) { + Text wrapper( it->second->getDescription(), TextAttributes() + .setInitialIndent( 0 ) + .setIndent( 7+maxNameLen ) + .setWidth( CATCH_CONFIG_CONSOLE_WIDTH - maxNameLen-8 ) ); + Catch::cout() << " " + << it->first + << ":" + << std::string( maxNameLen - it->first.size() + 2, ' ' ) + << wrapper << "\n"; + } + Catch::cout() << std::endl; + return factories.size(); + } + + inline Option list( Config const& config ) { + Option listedCount; + if( config.listTests() ) + listedCount = listedCount.valueOr(0) + listTests( config ); + if( config.listTestNamesOnly() ) + listedCount = listedCount.valueOr(0) + listTestsNamesOnly( config ); + if( config.listTags() ) + listedCount = listedCount.valueOr(0) + listTags( config ); + if( config.listReporters() ) + listedCount = listedCount.valueOr(0) + listReporters( config ); + return listedCount; + } + +} // end namespace Catch + +// #included from: internal/catch_run_context.hpp +#define TWOBLUECUBES_CATCH_RUNNER_IMPL_HPP_INCLUDED + +// #included from: catch_test_case_tracker.hpp +#define TWOBLUECUBES_CATCH_TEST_CASE_TRACKER_HPP_INCLUDED + +#include +#include +#include +#include + +namespace Catch { +namespace TestCaseTracking { + + struct ITracker : SharedImpl<> { + virtual ~ITracker(); + + // static queries + virtual std::string name() const = 0; + + // dynamic queries + virtual bool isComplete() const = 0; // Successfully completed or failed + virtual bool isSuccessfullyCompleted() const = 0; + virtual bool isOpen() const = 0; // Started but not complete + virtual bool hasChildren() const = 0; + + virtual ITracker& parent() = 0; + + // actions + virtual void close() = 0; // Successfully complete + virtual void fail() = 0; + virtual void markAsNeedingAnotherRun() = 0; + + virtual void addChild( Ptr const& child ) = 0; + virtual ITracker* findChild( std::string const& name ) = 0; + virtual void openChild() = 0; + }; + + class TrackerContext { + + enum RunState { + NotStarted, + Executing, + CompletedCycle + }; + + Ptr m_rootTracker; + ITracker* m_currentTracker; + RunState m_runState; + + public: + + static TrackerContext& instance() { + static TrackerContext s_instance; + return s_instance; + } + + TrackerContext() + : m_currentTracker( CATCH_NULL ), + m_runState( NotStarted ) + {} + + ITracker& startRun(); + + void endRun() { + m_rootTracker.reset(); + m_currentTracker = CATCH_NULL; + m_runState = NotStarted; + } + + void startCycle() { + m_currentTracker = m_rootTracker.get(); + m_runState = Executing; + } + void completeCycle() { + m_runState = CompletedCycle; + } + + bool completedCycle() const { + return m_runState == CompletedCycle; + } + ITracker& currentTracker() { + return *m_currentTracker; + } + void setCurrentTracker( ITracker* tracker ) { + m_currentTracker = tracker; + } + }; + + class TrackerBase : public ITracker { + protected: + enum CycleState { + NotStarted, + Executing, + ExecutingChildren, + NeedsAnotherRun, + CompletedSuccessfully, + Failed + }; + class TrackerHasName { + std::string m_name; + public: + TrackerHasName( std::string const& name ) : m_name( name ) {} + bool operator ()( Ptr const& tracker ) { + return tracker->name() == m_name; + } + }; + typedef std::vector > Children; + std::string m_name; + TrackerContext& m_ctx; + ITracker* m_parent; + Children m_children; + CycleState m_runState; + public: + TrackerBase( std::string const& name, TrackerContext& ctx, ITracker* parent ) + : m_name( name ), + m_ctx( ctx ), + m_parent( parent ), + m_runState( NotStarted ) + {} + virtual ~TrackerBase(); + + virtual std::string name() const CATCH_OVERRIDE { + return m_name; + } + virtual bool isComplete() const CATCH_OVERRIDE { + return m_runState == CompletedSuccessfully || m_runState == Failed; + } + virtual bool isSuccessfullyCompleted() const CATCH_OVERRIDE { + return m_runState == CompletedSuccessfully; + } + virtual bool isOpen() const CATCH_OVERRIDE { + return m_runState != NotStarted && !isComplete(); + } + virtual bool hasChildren() const CATCH_OVERRIDE { + return !m_children.empty(); + } + + virtual void addChild( Ptr const& child ) CATCH_OVERRIDE { + m_children.push_back( child ); + } + + virtual ITracker* findChild( std::string const& name ) CATCH_OVERRIDE { + Children::const_iterator it = std::find_if( m_children.begin(), m_children.end(), TrackerHasName( name ) ); + return( it != m_children.end() ) + ? it->get() + : CATCH_NULL; + } + virtual ITracker& parent() CATCH_OVERRIDE { + assert( m_parent ); // Should always be non-null except for root + return *m_parent; + } + + virtual void openChild() CATCH_OVERRIDE { + if( m_runState != ExecutingChildren ) { + m_runState = ExecutingChildren; + if( m_parent ) + m_parent->openChild(); + } + } + void open() { + m_runState = Executing; + moveToThis(); + if( m_parent ) + m_parent->openChild(); + } + + virtual void close() CATCH_OVERRIDE { + + // Close any still open children (e.g. generators) + while( &m_ctx.currentTracker() != this ) + m_ctx.currentTracker().close(); + + switch( m_runState ) { + case NotStarted: + case CompletedSuccessfully: + case Failed: + throw std::logic_error( "Illogical state" ); + + case NeedsAnotherRun: + break;; + + case Executing: + m_runState = CompletedSuccessfully; + break; + case ExecutingChildren: + if( m_children.empty() || m_children.back()->isComplete() ) + m_runState = CompletedSuccessfully; + break; + + default: + throw std::logic_error( "Unexpected state" ); + } + moveToParent(); + m_ctx.completeCycle(); + } + virtual void fail() CATCH_OVERRIDE { + m_runState = Failed; + if( m_parent ) + m_parent->markAsNeedingAnotherRun(); + moveToParent(); + m_ctx.completeCycle(); + } + virtual void markAsNeedingAnotherRun() CATCH_OVERRIDE { + m_runState = NeedsAnotherRun; + } + private: + void moveToParent() { + assert( m_parent ); + m_ctx.setCurrentTracker( m_parent ); + } + void moveToThis() { + m_ctx.setCurrentTracker( this ); + } + }; + + class SectionTracker : public TrackerBase { + public: + SectionTracker( std::string const& name, TrackerContext& ctx, ITracker* parent ) + : TrackerBase( name, ctx, parent ) + {} + virtual ~SectionTracker(); + + static SectionTracker& acquire( TrackerContext& ctx, std::string const& name ) { + SectionTracker* section = CATCH_NULL; + + ITracker& currentTracker = ctx.currentTracker(); + if( ITracker* childTracker = currentTracker.findChild( name ) ) { + section = dynamic_cast( childTracker ); + assert( section ); + } + else { + section = new SectionTracker( name, ctx, ¤tTracker ); + currentTracker.addChild( section ); + } + if( !ctx.completedCycle() && !section->isComplete() ) { + + section->open(); + } + return *section; + } + }; + + class IndexTracker : public TrackerBase { + int m_size; + int m_index; + public: + IndexTracker( std::string const& name, TrackerContext& ctx, ITracker* parent, int size ) + : TrackerBase( name, ctx, parent ), + m_size( size ), + m_index( -1 ) + {} + virtual ~IndexTracker(); + + static IndexTracker& acquire( TrackerContext& ctx, std::string const& name, int size ) { + IndexTracker* tracker = CATCH_NULL; + + ITracker& currentTracker = ctx.currentTracker(); + if( ITracker* childTracker = currentTracker.findChild( name ) ) { + tracker = dynamic_cast( childTracker ); + assert( tracker ); + } + else { + tracker = new IndexTracker( name, ctx, ¤tTracker, size ); + currentTracker.addChild( tracker ); + } + + if( !ctx.completedCycle() && !tracker->isComplete() ) { + if( tracker->m_runState != ExecutingChildren && tracker->m_runState != NeedsAnotherRun ) + tracker->moveNext(); + tracker->open(); + } + + return *tracker; + } + + int index() const { return m_index; } + + void moveNext() { + m_index++; + m_children.clear(); + } + + virtual void close() CATCH_OVERRIDE { + TrackerBase::close(); + if( m_runState == CompletedSuccessfully && m_index < m_size-1 ) + m_runState = Executing; + } + }; + + inline ITracker& TrackerContext::startRun() { + m_rootTracker = new SectionTracker( "{root}", *this, CATCH_NULL ); + m_currentTracker = CATCH_NULL; + m_runState = Executing; + return *m_rootTracker; + } + +} // namespace TestCaseTracking + +using TestCaseTracking::ITracker; +using TestCaseTracking::TrackerContext; +using TestCaseTracking::SectionTracker; +using TestCaseTracking::IndexTracker; + +} // namespace Catch + +// #included from: catch_fatal_condition.hpp +#define TWOBLUECUBES_CATCH_FATAL_CONDITION_H_INCLUDED + +namespace Catch { + + // Report the error condition then exit the process + inline void fatal( std::string const& message, int exitCode ) { + IContext& context = Catch::getCurrentContext(); + IResultCapture* resultCapture = context.getResultCapture(); + resultCapture->handleFatalErrorCondition( message ); + + if( Catch::alwaysTrue() ) // avoids "no return" warnings + exit( exitCode ); + } + +} // namespace Catch + +#if defined ( CATCH_PLATFORM_WINDOWS ) ///////////////////////////////////////// + +namespace Catch { + + struct FatalConditionHandler { + void reset() {} + }; + +} // namespace Catch + +#else // Not Windows - assumed to be POSIX compatible ////////////////////////// + +#include + +namespace Catch { + + struct SignalDefs { int id; const char* name; }; + extern SignalDefs signalDefs[]; + SignalDefs signalDefs[] = { + { SIGINT, "SIGINT - Terminal interrupt signal" }, + { SIGILL, "SIGILL - Illegal instruction signal" }, + { SIGFPE, "SIGFPE - Floating point error signal" }, + { SIGSEGV, "SIGSEGV - Segmentation violation signal" }, + { SIGTERM, "SIGTERM - Termination request signal" }, + { SIGABRT, "SIGABRT - Abort (abnormal termination) signal" } + }; + + struct FatalConditionHandler { + + static void handleSignal( int sig ) { + for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) + if( sig == signalDefs[i].id ) + fatal( signalDefs[i].name, -sig ); + fatal( "", -sig ); + } + + FatalConditionHandler() : m_isSet( true ) { + for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) + signal( signalDefs[i].id, handleSignal ); + } + ~FatalConditionHandler() { + reset(); + } + void reset() { + if( m_isSet ) { + for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) + signal( signalDefs[i].id, SIG_DFL ); + m_isSet = false; + } + } + + bool m_isSet; + }; + +} // namespace Catch + +#endif // not Windows + +#include +#include + +namespace Catch { + + class StreamRedirect { + + public: + StreamRedirect( std::ostream& stream, std::string& targetString ) + : m_stream( stream ), + m_prevBuf( stream.rdbuf() ), + m_targetString( targetString ) + { + stream.rdbuf( m_oss.rdbuf() ); + } + + ~StreamRedirect() { + m_targetString += m_oss.str(); + m_stream.rdbuf( m_prevBuf ); + } + + private: + std::ostream& m_stream; + std::streambuf* m_prevBuf; + std::ostringstream m_oss; + std::string& m_targetString; + }; + + /////////////////////////////////////////////////////////////////////////// + + class RunContext : public IResultCapture, public IRunner { + + RunContext( RunContext const& ); + void operator =( RunContext const& ); + + public: + + explicit RunContext( Ptr const& _config, Ptr const& reporter ) + : m_runInfo( _config->name() ), + m_context( getCurrentMutableContext() ), + m_activeTestCase( CATCH_NULL ), + m_config( _config ), + m_reporter( reporter ) + { + m_context.setRunner( this ); + m_context.setConfig( m_config ); + m_context.setResultCapture( this ); + m_reporter->testRunStarting( m_runInfo ); + } + + virtual ~RunContext() { + m_reporter->testRunEnded( TestRunStats( m_runInfo, m_totals, aborting() ) ); + } + + void testGroupStarting( std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount ) { + m_reporter->testGroupStarting( GroupInfo( testSpec, groupIndex, groupsCount ) ); + } + void testGroupEnded( std::string const& testSpec, Totals const& totals, std::size_t groupIndex, std::size_t groupsCount ) { + m_reporter->testGroupEnded( TestGroupStats( GroupInfo( testSpec, groupIndex, groupsCount ), totals, aborting() ) ); + } + + Totals runTest( TestCase const& testCase ) { + Totals prevTotals = m_totals; + + std::string redirectedCout; + std::string redirectedCerr; + + TestCaseInfo testInfo = testCase.getTestCaseInfo(); + + m_reporter->testCaseStarting( testInfo ); + + m_activeTestCase = &testCase; + + do { + m_trackerContext.startRun(); + do { + m_trackerContext.startCycle(); + m_testCaseTracker = &SectionTracker::acquire( m_trackerContext, testInfo.name ); + runCurrentTest( redirectedCout, redirectedCerr ); + } + while( !m_testCaseTracker->isSuccessfullyCompleted() && !aborting() ); + } + // !TBD: deprecated - this will be replaced by indexed trackers + while( getCurrentContext().advanceGeneratorsForCurrentTest() && !aborting() ); + + Totals deltaTotals = m_totals.delta( prevTotals ); + m_totals.testCases += deltaTotals.testCases; + m_reporter->testCaseEnded( TestCaseStats( testInfo, + deltaTotals, + redirectedCout, + redirectedCerr, + aborting() ) ); + + m_activeTestCase = CATCH_NULL; + m_testCaseTracker = CATCH_NULL; + + return deltaTotals; + } + + Ptr config() const { + return m_config; + } + + private: // IResultCapture + + virtual void assertionEnded( AssertionResult const& result ) { + if( result.getResultType() == ResultWas::Ok ) { + m_totals.assertions.passed++; + } + else if( !result.isOk() ) { + m_totals.assertions.failed++; + } + + if( m_reporter->assertionEnded( AssertionStats( result, m_messages, m_totals ) ) ) + m_messages.clear(); + + // Reset working state + m_lastAssertionInfo = AssertionInfo( "", m_lastAssertionInfo.lineInfo, "{Unknown expression after the reported line}" , m_lastAssertionInfo.resultDisposition ); + m_lastResult = result; + } + + virtual bool sectionStarted ( + SectionInfo const& sectionInfo, + Counts& assertions + ) + { + std::ostringstream oss; + oss << sectionInfo.name << "@" << sectionInfo.lineInfo; + + ITracker& sectionTracker = SectionTracker::acquire( m_trackerContext, oss.str() ); + if( !sectionTracker.isOpen() ) + return false; + m_activeSections.push_back( §ionTracker ); + + m_lastAssertionInfo.lineInfo = sectionInfo.lineInfo; + + m_reporter->sectionStarting( sectionInfo ); + + assertions = m_totals.assertions; + + return true; + } + bool testForMissingAssertions( Counts& assertions ) { + if( assertions.total() != 0 ) + return false; + if( !m_config->warnAboutMissingAssertions() ) + return false; + if( m_trackerContext.currentTracker().hasChildren() ) + return false; + m_totals.assertions.failed++; + assertions.failed++; + return true; + } + + virtual void sectionEnded( SectionEndInfo const& endInfo ) { + Counts assertions = m_totals.assertions - endInfo.prevAssertions; + bool missingAssertions = testForMissingAssertions( assertions ); + + if( !m_activeSections.empty() ) { + m_activeSections.back()->close(); + m_activeSections.pop_back(); + } + + m_reporter->sectionEnded( SectionStats( endInfo.sectionInfo, assertions, endInfo.durationInSeconds, missingAssertions ) ); + m_messages.clear(); + } + + virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) { + if( m_unfinishedSections.empty() ) + m_activeSections.back()->fail(); + else + m_activeSections.back()->close(); + m_activeSections.pop_back(); + + m_unfinishedSections.push_back( endInfo ); + } + + virtual void pushScopedMessage( MessageInfo const& message ) { + m_messages.push_back( message ); + } + + virtual void popScopedMessage( MessageInfo const& message ) { + m_messages.erase( std::remove( m_messages.begin(), m_messages.end(), message ), m_messages.end() ); + } + + virtual std::string getCurrentTestName() const { + return m_activeTestCase + ? m_activeTestCase->getTestCaseInfo().name + : ""; + } + + virtual const AssertionResult* getLastResult() const { + return &m_lastResult; + } + + virtual void handleFatalErrorCondition( std::string const& message ) { + ResultBuilder resultBuilder = makeUnexpectedResultBuilder(); + resultBuilder.setResultType( ResultWas::FatalErrorCondition ); + resultBuilder << message; + resultBuilder.captureExpression(); + + handleUnfinishedSections(); + + // Recreate section for test case (as we will lose the one that was in scope) + TestCaseInfo const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); + SectionInfo testCaseSection( testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description ); + + Counts assertions; + assertions.failed = 1; + SectionStats testCaseSectionStats( testCaseSection, assertions, 0, false ); + m_reporter->sectionEnded( testCaseSectionStats ); + + TestCaseInfo testInfo = m_activeTestCase->getTestCaseInfo(); + + Totals deltaTotals; + deltaTotals.testCases.failed = 1; + m_reporter->testCaseEnded( TestCaseStats( testInfo, + deltaTotals, + "", + "", + false ) ); + m_totals.testCases.failed++; + testGroupEnded( "", m_totals, 1, 1 ); + m_reporter->testRunEnded( TestRunStats( m_runInfo, m_totals, false ) ); + } + + public: + // !TBD We need to do this another way! + bool aborting() const { + return m_totals.assertions.failed == static_cast( m_config->abortAfter() ); + } + + private: + + void runCurrentTest( std::string& redirectedCout, std::string& redirectedCerr ) { + TestCaseInfo const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); + SectionInfo testCaseSection( testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description ); + m_reporter->sectionStarting( testCaseSection ); + Counts prevAssertions = m_totals.assertions; + double duration = 0; + try { + m_lastAssertionInfo = AssertionInfo( "TEST_CASE", testCaseInfo.lineInfo, "", ResultDisposition::Normal ); + + seedRng( *m_config ); + + Timer timer; + timer.start(); + if( m_reporter->getPreferences().shouldRedirectStdOut ) { + StreamRedirect coutRedir( Catch::cout(), redirectedCout ); + StreamRedirect cerrRedir( Catch::cerr(), redirectedCerr ); + invokeActiveTestCase(); + } + else { + invokeActiveTestCase(); + } + duration = timer.getElapsedSeconds(); + } + catch( TestFailureException& ) { + // This just means the test was aborted due to failure + } + catch(...) { + makeUnexpectedResultBuilder().useActiveException(); + } + m_testCaseTracker->close(); + handleUnfinishedSections(); + m_messages.clear(); + + Counts assertions = m_totals.assertions - prevAssertions; + bool missingAssertions = testForMissingAssertions( assertions ); + + if( testCaseInfo.okToFail() ) { + std::swap( assertions.failedButOk, assertions.failed ); + m_totals.assertions.failed -= assertions.failedButOk; + m_totals.assertions.failedButOk += assertions.failedButOk; + } + + SectionStats testCaseSectionStats( testCaseSection, assertions, duration, missingAssertions ); + m_reporter->sectionEnded( testCaseSectionStats ); + } + + void invokeActiveTestCase() { + FatalConditionHandler fatalConditionHandler; // Handle signals + m_activeTestCase->invoke(); + fatalConditionHandler.reset(); + } + + private: + + ResultBuilder makeUnexpectedResultBuilder() const { + return ResultBuilder( m_lastAssertionInfo.macroName.c_str(), + m_lastAssertionInfo.lineInfo, + m_lastAssertionInfo.capturedExpression.c_str(), + m_lastAssertionInfo.resultDisposition ); + } + + void handleUnfinishedSections() { + // If sections ended prematurely due to an exception we stored their + // infos here so we can tear them down outside the unwind process. + for( std::vector::const_reverse_iterator it = m_unfinishedSections.rbegin(), + itEnd = m_unfinishedSections.rend(); + it != itEnd; + ++it ) + sectionEnded( *it ); + m_unfinishedSections.clear(); + } + + TestRunInfo m_runInfo; + IMutableContext& m_context; + TestCase const* m_activeTestCase; + ITracker* m_testCaseTracker; + ITracker* m_currentSectionTracker; + AssertionResult m_lastResult; + + Ptr m_config; + Totals m_totals; + Ptr m_reporter; + std::vector m_messages; + AssertionInfo m_lastAssertionInfo; + std::vector m_unfinishedSections; + std::vector m_activeSections; + TrackerContext m_trackerContext; + }; + + IResultCapture& getResultCapture() { + if( IResultCapture* capture = getCurrentContext().getResultCapture() ) + return *capture; + else + throw std::logic_error( "No result capture instance" ); + } + +} // end namespace Catch + +// #included from: internal/catch_version.h +#define TWOBLUECUBES_CATCH_VERSION_H_INCLUDED + +namespace Catch { + + // Versioning information + struct Version { + Version( unsigned int _majorVersion, + unsigned int _minorVersion, + unsigned int _patchNumber, + std::string const& _branchName, + unsigned int _buildNumber ); + + unsigned int const majorVersion; + unsigned int const minorVersion; + unsigned int const patchNumber; + + // buildNumber is only used if branchName is not null + std::string const branchName; + unsigned int const buildNumber; + + friend std::ostream& operator << ( std::ostream& os, Version const& version ); + + private: + void operator=( Version const& ); + }; + + extern Version libraryVersion; +} + +#include +#include +#include + +namespace Catch { + + Ptr createReporter( std::string const& reporterName, Ptr const& config ) { + Ptr reporter = getRegistryHub().getReporterRegistry().create( reporterName, config.get() ); + if( !reporter ) { + std::ostringstream oss; + oss << "No reporter registered with name: '" << reporterName << "'"; + throw std::domain_error( oss.str() ); + } + return reporter; + } + + Ptr makeReporter( Ptr const& config ) { + std::vector reporters = config->getReporterNames(); + if( reporters.empty() ) + reporters.push_back( "console" ); + + Ptr reporter; + for( std::vector::const_iterator it = reporters.begin(), itEnd = reporters.end(); + it != itEnd; + ++it ) + reporter = addReporter( reporter, createReporter( *it, config ) ); + return reporter; + } + Ptr addListeners( Ptr const& config, Ptr reporters ) { + IReporterRegistry::Listeners listeners = getRegistryHub().getReporterRegistry().getListeners(); + for( IReporterRegistry::Listeners::const_iterator it = listeners.begin(), itEnd = listeners.end(); + it != itEnd; + ++it ) + reporters = addReporter(reporters, (*it)->create( ReporterConfig( config ) ) ); + return reporters; + } + + Totals runTests( Ptr const& config ) { + + Ptr iconfig = config.get(); + + Ptr reporter = makeReporter( config ); + reporter = addListeners( iconfig, reporter ); + + RunContext context( iconfig, reporter ); + + Totals totals; + + context.testGroupStarting( config->name(), 1, 1 ); + + TestSpec testSpec = config->testSpec(); + if( !testSpec.hasFilters() ) + testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "~[.]" ).testSpec(); // All not hidden tests + + std::vector const& allTestCases = getAllTestCasesSorted( *iconfig ); + for( std::vector::const_iterator it = allTestCases.begin(), itEnd = allTestCases.end(); + it != itEnd; + ++it ) { + if( !context.aborting() && matchTest( *it, testSpec, *iconfig ) ) + totals += context.runTest( *it ); + else + reporter->skipTest( *it ); + } + + context.testGroupEnded( iconfig->name(), totals, 1, 1 ); + return totals; + } + + void applyFilenamesAsTags( IConfig const& config ) { + std::vector const& tests = getAllTestCasesSorted( config ); + for(std::size_t i = 0; i < tests.size(); ++i ) { + TestCase& test = const_cast( tests[i] ); + std::set tags = test.tags; + + std::string filename = test.lineInfo.file; + std::string::size_type lastSlash = filename.find_last_of( "\\/" ); + if( lastSlash != std::string::npos ) + filename = filename.substr( lastSlash+1 ); + + std::string::size_type lastDot = filename.find_last_of( "." ); + if( lastDot != std::string::npos ) + filename = filename.substr( 0, lastDot ); + + tags.insert( "#" + filename ); + setTags( test, tags ); + } + } + + class Session : NonCopyable { + static bool alreadyInstantiated; + + public: + + struct OnUnusedOptions { enum DoWhat { Ignore, Fail }; }; + + Session() + : m_cli( makeCommandLineParser() ) { + if( alreadyInstantiated ) { + std::string msg = "Only one instance of Catch::Session can ever be used"; + Catch::cerr() << msg << std::endl; + throw std::logic_error( msg ); + } + alreadyInstantiated = true; + } + ~Session() { + Catch::cleanUp(); + } + + void showHelp( std::string const& processName ) { + Catch::cout() << "\nCatch v" << libraryVersion << "\n"; + + m_cli.usage( Catch::cout(), processName ); + Catch::cout() << "For more detail usage please see the project docs\n" << std::endl; + } + + int applyCommandLine( int argc, char const* argv[], OnUnusedOptions::DoWhat unusedOptionBehaviour = OnUnusedOptions::Fail ) { + try { + m_cli.setThrowOnUnrecognisedTokens( unusedOptionBehaviour == OnUnusedOptions::Fail ); + m_unusedTokens = m_cli.parseInto( argc, argv, m_configData ); + if( m_configData.showHelp ) + showHelp( m_configData.processName ); + m_config.reset(); + } + catch( std::exception& ex ) { + { + Colour colourGuard( Colour::Red ); + Catch::cerr() + << "\nError(s) in input:\n" + << Text( ex.what(), TextAttributes().setIndent(2) ) + << "\n\n"; + } + m_cli.usage( Catch::cout(), m_configData.processName ); + return (std::numeric_limits::max)(); + } + return 0; + } + + void useConfigData( ConfigData const& _configData ) { + m_configData = _configData; + m_config.reset(); + } + + int run( int argc, char const* argv[] ) { + + int returnCode = applyCommandLine( argc, argv ); + if( returnCode == 0 ) + returnCode = run(); + return returnCode; + } + int run( int argc, char* argv[] ) { + return run( argc, const_cast( argv ) ); + } + + int run() { + if( m_configData.showHelp ) + return 0; + + try + { + config(); // Force config to be constructed + + seedRng( *m_config ); + + if( m_configData.filenamesAsTags ) + applyFilenamesAsTags( *m_config ); + + // Handle list request + if( Option listed = list( config() ) ) + return static_cast( *listed ); + + return static_cast( runTests( m_config ).assertions.failed ); + } + catch( std::exception& ex ) { + Catch::cerr() << ex.what() << std::endl; + return (std::numeric_limits::max)(); + } + } + + Clara::CommandLine const& cli() const { + return m_cli; + } + std::vector const& unusedTokens() const { + return m_unusedTokens; + } + ConfigData& configData() { + return m_configData; + } + Config& config() { + if( !m_config ) + m_config = new Config( m_configData ); + return *m_config; + } + private: + Clara::CommandLine m_cli; + std::vector m_unusedTokens; + ConfigData m_configData; + Ptr m_config; + }; + + bool Session::alreadyInstantiated = false; + +} // end namespace Catch + +// #included from: catch_registry_hub.hpp +#define TWOBLUECUBES_CATCH_REGISTRY_HUB_HPP_INCLUDED + +// #included from: catch_test_case_registry_impl.hpp +#define TWOBLUECUBES_CATCH_TEST_CASE_REGISTRY_IMPL_HPP_INCLUDED + +#include +#include +#include +#include +#include + +namespace Catch { + + struct LexSort { + bool operator() (TestCase i,TestCase j) const { return (i sortTests( IConfig const& config, std::vector const& unsortedTestCases ) { + + std::vector sorted = unsortedTestCases; + + switch( config.runOrder() ) { + case RunTests::InLexicographicalOrder: + std::sort( sorted.begin(), sorted.end(), LexSort() ); + break; + case RunTests::InRandomOrder: + { + seedRng( config ); + + RandomNumberGenerator rng; + std::random_shuffle( sorted.begin(), sorted.end(), rng ); + } + break; + case RunTests::InDeclarationOrder: + // already in declaration order + break; + } + return sorted; + } + bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ) { + return testSpec.matches( testCase ) && ( config.allowThrows() || !testCase.throws() ); + } + + void enforceNoDuplicateTestCases( std::vector const& functions ) { + std::set seenFunctions; + for( std::vector::const_iterator it = functions.begin(), itEnd = functions.end(); + it != itEnd; + ++it ) { + std::pair::const_iterator, bool> prev = seenFunctions.insert( *it ); + if( !prev.second ){ + Catch::cerr() + << Colour( Colour::Red ) + << "error: TEST_CASE( \"" << it->name << "\" ) already defined.\n" + << "\tFirst seen at " << prev.first->getTestCaseInfo().lineInfo << "\n" + << "\tRedefined at " << it->getTestCaseInfo().lineInfo << std::endl; + exit(1); + } + } + } + + std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ) { + std::vector filtered; + filtered.reserve( testCases.size() ); + for( std::vector::const_iterator it = testCases.begin(), itEnd = testCases.end(); + it != itEnd; + ++it ) + if( matchTest( *it, testSpec, config ) ) + filtered.push_back( *it ); + return filtered; + } + std::vector const& getAllTestCasesSorted( IConfig const& config ) { + return getRegistryHub().getTestCaseRegistry().getAllTestsSorted( config ); + } + + class TestRegistry : public ITestCaseRegistry { + public: + TestRegistry() + : m_currentSortOrder( RunTests::InDeclarationOrder ), + m_unnamedCount( 0 ) + {} + virtual ~TestRegistry(); + + virtual void registerTest( TestCase const& testCase ) { + std::string name = testCase.getTestCaseInfo().name; + if( name == "" ) { + std::ostringstream oss; + oss << "Anonymous test case " << ++m_unnamedCount; + return registerTest( testCase.withName( oss.str() ) ); + } + m_functions.push_back( testCase ); + } + + virtual std::vector const& getAllTests() const { + return m_functions; + } + virtual std::vector const& getAllTestsSorted( IConfig const& config ) const { + if( m_sortedFunctions.empty() ) + enforceNoDuplicateTestCases( m_functions ); + + if( m_currentSortOrder != config.runOrder() || m_sortedFunctions.empty() ) { + m_sortedFunctions = sortTests( config, m_functions ); + m_currentSortOrder = config.runOrder(); + } + return m_sortedFunctions; + } + + private: + std::vector m_functions; + mutable RunTests::InWhatOrder m_currentSortOrder; + mutable std::vector m_sortedFunctions; + size_t m_unnamedCount; + std::ios_base::Init m_ostreamInit; // Forces cout/ cerr to be initialised + }; + + /////////////////////////////////////////////////////////////////////////// + + class FreeFunctionTestCase : public SharedImpl { + public: + + FreeFunctionTestCase( TestFunction fun ) : m_fun( fun ) {} + + virtual void invoke() const { + m_fun(); + } + + private: + virtual ~FreeFunctionTestCase(); + + TestFunction m_fun; + }; + + inline std::string extractClassName( std::string const& classOrQualifiedMethodName ) { + std::string className = classOrQualifiedMethodName; + if( startsWith( className, "&" ) ) + { + std::size_t lastColons = className.rfind( "::" ); + std::size_t penultimateColons = className.rfind( "::", lastColons-1 ); + if( penultimateColons == std::string::npos ) + penultimateColons = 1; + className = className.substr( penultimateColons, lastColons-penultimateColons ); + } + return className; + } + + void registerTestCase + ( ITestCase* testCase, + char const* classOrQualifiedMethodName, + NameAndDesc const& nameAndDesc, + SourceLineInfo const& lineInfo ) { + + getMutableRegistryHub().registerTest + ( makeTestCase + ( testCase, + extractClassName( classOrQualifiedMethodName ), + nameAndDesc.name, + nameAndDesc.description, + lineInfo ) ); + } + void registerTestCaseFunction + ( TestFunction function, + SourceLineInfo const& lineInfo, + NameAndDesc const& nameAndDesc ) { + registerTestCase( new FreeFunctionTestCase( function ), "", nameAndDesc, lineInfo ); + } + + /////////////////////////////////////////////////////////////////////////// + + AutoReg::AutoReg + ( TestFunction function, + SourceLineInfo const& lineInfo, + NameAndDesc const& nameAndDesc ) { + registerTestCaseFunction( function, lineInfo, nameAndDesc ); + } + + AutoReg::~AutoReg() {} + +} // end namespace Catch + +// #included from: catch_reporter_registry.hpp +#define TWOBLUECUBES_CATCH_REPORTER_REGISTRY_HPP_INCLUDED + +#include + +namespace Catch { + + class ReporterRegistry : public IReporterRegistry { + + public: + + virtual ~ReporterRegistry() CATCH_OVERRIDE {} + + virtual IStreamingReporter* create( std::string const& name, Ptr const& config ) const CATCH_OVERRIDE { + FactoryMap::const_iterator it = m_factories.find( name ); + if( it == m_factories.end() ) + return CATCH_NULL; + return it->second->create( ReporterConfig( config ) ); + } + + void registerReporter( std::string const& name, Ptr const& factory ) { + m_factories.insert( std::make_pair( name, factory ) ); + } + void registerListener( Ptr const& factory ) { + m_listeners.push_back( factory ); + } + + virtual FactoryMap const& getFactories() const CATCH_OVERRIDE { + return m_factories; + } + virtual Listeners const& getListeners() const CATCH_OVERRIDE { + return m_listeners; + } + + private: + FactoryMap m_factories; + Listeners m_listeners; + }; +} + +// #included from: catch_exception_translator_registry.hpp +#define TWOBLUECUBES_CATCH_EXCEPTION_TRANSLATOR_REGISTRY_HPP_INCLUDED + +#ifdef __OBJC__ +#import "Foundation/Foundation.h" +#endif + +namespace Catch { + + class ExceptionTranslatorRegistry : public IExceptionTranslatorRegistry { + public: + ~ExceptionTranslatorRegistry() { + deleteAll( m_translators ); + } + + virtual void registerTranslator( const IExceptionTranslator* translator ) { + m_translators.push_back( translator ); + } + + virtual std::string translateActiveException() const { + try { +#ifdef __OBJC__ + // In Objective-C try objective-c exceptions first + @try { + return tryTranslators(); + } + @catch (NSException *exception) { + return Catch::toString( [exception description] ); + } +#else + return tryTranslators(); +#endif + } + catch( TestFailureException& ) { + throw; + } + catch( std::exception& ex ) { + return ex.what(); + } + catch( std::string& msg ) { + return msg; + } + catch( const char* msg ) { + return msg; + } + catch(...) { + return "Unknown exception"; + } + } + + std::string tryTranslators() const { + if( m_translators.empty() ) + throw; + else + return m_translators[0]->translate( m_translators.begin()+1, m_translators.end() ); + } + + private: + std::vector m_translators; + }; +} + +namespace Catch { + + namespace { + + class RegistryHub : public IRegistryHub, public IMutableRegistryHub { + + RegistryHub( RegistryHub const& ); + void operator=( RegistryHub const& ); + + public: // IRegistryHub + RegistryHub() { + } + virtual IReporterRegistry const& getReporterRegistry() const CATCH_OVERRIDE { + return m_reporterRegistry; + } + virtual ITestCaseRegistry const& getTestCaseRegistry() const CATCH_OVERRIDE { + return m_testCaseRegistry; + } + virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() CATCH_OVERRIDE { + return m_exceptionTranslatorRegistry; + } + + public: // IMutableRegistryHub + virtual void registerReporter( std::string const& name, Ptr const& factory ) CATCH_OVERRIDE { + m_reporterRegistry.registerReporter( name, factory ); + } + virtual void registerListener( Ptr const& factory ) CATCH_OVERRIDE { + m_reporterRegistry.registerListener( factory ); + } + virtual void registerTest( TestCase const& testInfo ) CATCH_OVERRIDE { + m_testCaseRegistry.registerTest( testInfo ); + } + virtual void registerTranslator( const IExceptionTranslator* translator ) CATCH_OVERRIDE { + m_exceptionTranslatorRegistry.registerTranslator( translator ); + } + + private: + TestRegistry m_testCaseRegistry; + ReporterRegistry m_reporterRegistry; + ExceptionTranslatorRegistry m_exceptionTranslatorRegistry; + }; + + // Single, global, instance + inline RegistryHub*& getTheRegistryHub() { + static RegistryHub* theRegistryHub = CATCH_NULL; + if( !theRegistryHub ) + theRegistryHub = new RegistryHub(); + return theRegistryHub; + } + } + + IRegistryHub& getRegistryHub() { + return *getTheRegistryHub(); + } + IMutableRegistryHub& getMutableRegistryHub() { + return *getTheRegistryHub(); + } + void cleanUp() { + delete getTheRegistryHub(); + getTheRegistryHub() = CATCH_NULL; + cleanUpContext(); + } + std::string translateActiveException() { + return getRegistryHub().getExceptionTranslatorRegistry().translateActiveException(); + } + +} // end namespace Catch + +// #included from: catch_notimplemented_exception.hpp +#define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_HPP_INCLUDED + +#include + +namespace Catch { + + NotImplementedException::NotImplementedException( SourceLineInfo const& lineInfo ) + : m_lineInfo( lineInfo ) { + std::ostringstream oss; + oss << lineInfo << ": function "; + oss << "not implemented"; + m_what = oss.str(); + } + + const char* NotImplementedException::what() const CATCH_NOEXCEPT { + return m_what.c_str(); + } + +} // end namespace Catch + +// #included from: catch_context_impl.hpp +#define TWOBLUECUBES_CATCH_CONTEXT_IMPL_HPP_INCLUDED + +// #included from: catch_stream.hpp +#define TWOBLUECUBES_CATCH_STREAM_HPP_INCLUDED + +#include +#include +#include + +namespace Catch { + + template + class StreamBufImpl : public StreamBufBase { + char data[bufferSize]; + WriterF m_writer; + + public: + StreamBufImpl() { + setp( data, data + sizeof(data) ); + } + + ~StreamBufImpl() CATCH_NOEXCEPT { + sync(); + } + + private: + int overflow( int c ) { + sync(); + + if( c != EOF ) { + if( pbase() == epptr() ) + m_writer( std::string( 1, static_cast( c ) ) ); + else + sputc( static_cast( c ) ); + } + return 0; + } + + int sync() { + if( pbase() != pptr() ) { + m_writer( std::string( pbase(), static_cast( pptr() - pbase() ) ) ); + setp( pbase(), epptr() ); + } + return 0; + } + }; + + /////////////////////////////////////////////////////////////////////////// + + FileStream::FileStream( std::string const& filename ) { + m_ofs.open( filename.c_str() ); + if( m_ofs.fail() ) { + std::ostringstream oss; + oss << "Unable to open file: '" << filename << "'"; + throw std::domain_error( oss.str() ); + } + } + + std::ostream& FileStream::stream() const { + return m_ofs; + } + + struct OutputDebugWriter { + + void operator()( std::string const&str ) { + writeToDebugConsole( str ); + } + }; + + DebugOutStream::DebugOutStream() + : m_streamBuf( new StreamBufImpl() ), + m_os( m_streamBuf.get() ) + {} + + std::ostream& DebugOutStream::stream() const { + return m_os; + } + + // Store the streambuf from cout up-front because + // cout may get redirected when running tests + CoutStream::CoutStream() + : m_os( Catch::cout().rdbuf() ) + {} + + std::ostream& CoutStream::stream() const { + return m_os; + } + +#ifndef CATCH_CONFIG_NOSTDOUT // If you #define this you must implement these functions + std::ostream& cout() { + return std::cout; + } + std::ostream& cerr() { + return std::cerr; + } +#endif +} + +namespace Catch { + + class Context : public IMutableContext { + + Context() : m_config( CATCH_NULL ), m_runner( CATCH_NULL ), m_resultCapture( CATCH_NULL ) {} + Context( Context const& ); + void operator=( Context const& ); + + public: // IContext + virtual IResultCapture* getResultCapture() { + return m_resultCapture; + } + virtual IRunner* getRunner() { + return m_runner; + } + virtual size_t getGeneratorIndex( std::string const& fileInfo, size_t totalSize ) { + return getGeneratorsForCurrentTest() + .getGeneratorInfo( fileInfo, totalSize ) + .getCurrentIndex(); + } + virtual bool advanceGeneratorsForCurrentTest() { + IGeneratorsForTest* generators = findGeneratorsForCurrentTest(); + return generators && generators->moveNext(); + } + + virtual Ptr getConfig() const { + return m_config; + } + + public: // IMutableContext + virtual void setResultCapture( IResultCapture* resultCapture ) { + m_resultCapture = resultCapture; + } + virtual void setRunner( IRunner* runner ) { + m_runner = runner; + } + virtual void setConfig( Ptr const& config ) { + m_config = config; + } + + friend IMutableContext& getCurrentMutableContext(); + + private: + IGeneratorsForTest* findGeneratorsForCurrentTest() { + std::string testName = getResultCapture()->getCurrentTestName(); + + std::map::const_iterator it = + m_generatorsByTestName.find( testName ); + return it != m_generatorsByTestName.end() + ? it->second + : CATCH_NULL; + } + + IGeneratorsForTest& getGeneratorsForCurrentTest() { + IGeneratorsForTest* generators = findGeneratorsForCurrentTest(); + if( !generators ) { + std::string testName = getResultCapture()->getCurrentTestName(); + generators = createGeneratorsForTest(); + m_generatorsByTestName.insert( std::make_pair( testName, generators ) ); + } + return *generators; + } + + private: + Ptr m_config; + IRunner* m_runner; + IResultCapture* m_resultCapture; + std::map m_generatorsByTestName; + }; + + namespace { + Context* currentContext = CATCH_NULL; + } + IMutableContext& getCurrentMutableContext() { + if( !currentContext ) + currentContext = new Context(); + return *currentContext; + } + IContext& getCurrentContext() { + return getCurrentMutableContext(); + } + + void cleanUpContext() { + delete currentContext; + currentContext = CATCH_NULL; + } +} + +// #included from: catch_console_colour_impl.hpp +#define TWOBLUECUBES_CATCH_CONSOLE_COLOUR_IMPL_HPP_INCLUDED + +namespace Catch { + namespace { + + struct IColourImpl { + virtual ~IColourImpl() {} + virtual void use( Colour::Code _colourCode ) = 0; + }; + + struct NoColourImpl : IColourImpl { + void use( Colour::Code ) {} + + static IColourImpl* instance() { + static NoColourImpl s_instance; + return &s_instance; + } + }; + + } // anon namespace +} // namespace Catch + +#if !defined( CATCH_CONFIG_COLOUR_NONE ) && !defined( CATCH_CONFIG_COLOUR_WINDOWS ) && !defined( CATCH_CONFIG_COLOUR_ANSI ) +# ifdef CATCH_PLATFORM_WINDOWS +# define CATCH_CONFIG_COLOUR_WINDOWS +# else +# define CATCH_CONFIG_COLOUR_ANSI +# endif +#endif + +#if defined ( CATCH_CONFIG_COLOUR_WINDOWS ) ///////////////////////////////////////// + +#ifndef NOMINMAX +#define NOMINMAX +#endif + +#ifdef __AFXDLL +#include +#else +#include +#endif + +namespace Catch { +namespace { + + class Win32ColourImpl : public IColourImpl { + public: + Win32ColourImpl() : stdoutHandle( GetStdHandle(STD_OUTPUT_HANDLE) ) + { + CONSOLE_SCREEN_BUFFER_INFO csbiInfo; + GetConsoleScreenBufferInfo( stdoutHandle, &csbiInfo ); + originalForegroundAttributes = csbiInfo.wAttributes & ~( BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_BLUE | BACKGROUND_INTENSITY ); + originalBackgroundAttributes = csbiInfo.wAttributes & ~( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY ); + } + + virtual void use( Colour::Code _colourCode ) { + switch( _colourCode ) { + case Colour::None: return setTextAttribute( originalForegroundAttributes ); + case Colour::White: return setTextAttribute( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE ); + case Colour::Red: return setTextAttribute( FOREGROUND_RED ); + case Colour::Green: return setTextAttribute( FOREGROUND_GREEN ); + case Colour::Blue: return setTextAttribute( FOREGROUND_BLUE ); + case Colour::Cyan: return setTextAttribute( FOREGROUND_BLUE | FOREGROUND_GREEN ); + case Colour::Yellow: return setTextAttribute( FOREGROUND_RED | FOREGROUND_GREEN ); + case Colour::Grey: return setTextAttribute( 0 ); + + case Colour::LightGrey: return setTextAttribute( FOREGROUND_INTENSITY ); + case Colour::BrightRed: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED ); + case Colour::BrightGreen: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN ); + case Colour::BrightWhite: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE ); + + case Colour::Bright: throw std::logic_error( "not a colour" ); + } + } + + private: + void setTextAttribute( WORD _textAttribute ) { + SetConsoleTextAttribute( stdoutHandle, _textAttribute | originalBackgroundAttributes ); + } + HANDLE stdoutHandle; + WORD originalForegroundAttributes; + WORD originalBackgroundAttributes; + }; + + IColourImpl* platformColourInstance() { + static Win32ColourImpl s_instance; + + Ptr config = getCurrentContext().getConfig(); + UseColour::YesOrNo colourMode = config + ? config->useColour() + : UseColour::Auto; + if( colourMode == UseColour::Auto ) + colourMode = !isDebuggerActive() + ? UseColour::Yes + : UseColour::No; + return colourMode == UseColour::Yes + ? &s_instance + : NoColourImpl::instance(); + } + +} // end anon namespace +} // end namespace Catch + +#elif defined( CATCH_CONFIG_COLOUR_ANSI ) ////////////////////////////////////// + +#include + +namespace Catch { +namespace { + + // use POSIX/ ANSI console terminal codes + // Thanks to Adam Strzelecki for original contribution + // (http://github.com/nanoant) + // https://github.com/philsquared/Catch/pull/131 + class PosixColourImpl : public IColourImpl { + public: + virtual void use( Colour::Code _colourCode ) { + switch( _colourCode ) { + case Colour::None: + case Colour::White: return setColour( "[0m" ); + case Colour::Red: return setColour( "[0;31m" ); + case Colour::Green: return setColour( "[0;32m" ); + case Colour::Blue: return setColour( "[0:34m" ); + case Colour::Cyan: return setColour( "[0;36m" ); + case Colour::Yellow: return setColour( "[0;33m" ); + case Colour::Grey: return setColour( "[1;30m" ); + + case Colour::LightGrey: return setColour( "[0;37m" ); + case Colour::BrightRed: return setColour( "[1;31m" ); + case Colour::BrightGreen: return setColour( "[1;32m" ); + case Colour::BrightWhite: return setColour( "[1;37m" ); + + case Colour::Bright: throw std::logic_error( "not a colour" ); + } + } + static IColourImpl* instance() { + static PosixColourImpl s_instance; + return &s_instance; + } + + private: + void setColour( const char* _escapeCode ) { + Catch::cout() << '\033' << _escapeCode; + } + }; + + IColourImpl* platformColourInstance() { + Ptr config = getCurrentContext().getConfig(); + UseColour::YesOrNo colourMode = config + ? config->useColour() + : UseColour::Auto; + if( colourMode == UseColour::Auto ) + colourMode = (!isDebuggerActive() && isatty(STDOUT_FILENO) ) + ? UseColour::Yes + : UseColour::No; + return colourMode == UseColour::Yes + ? PosixColourImpl::instance() + : NoColourImpl::instance(); + } + +} // end anon namespace +} // end namespace Catch + +#else // not Windows or ANSI /////////////////////////////////////////////// + +namespace Catch { + + static IColourImpl* platformColourInstance() { return NoColourImpl::instance(); } + +} // end namespace Catch + +#endif // Windows/ ANSI/ None + +namespace Catch { + + Colour::Colour( Code _colourCode ) : m_moved( false ) { use( _colourCode ); } + Colour::Colour( Colour const& _other ) : m_moved( false ) { const_cast( _other ).m_moved = true; } + Colour::~Colour(){ if( !m_moved ) use( None ); } + + void Colour::use( Code _colourCode ) { + static IColourImpl* impl = platformColourInstance(); + impl->use( _colourCode ); + } + +} // end namespace Catch + +// #included from: catch_generators_impl.hpp +#define TWOBLUECUBES_CATCH_GENERATORS_IMPL_HPP_INCLUDED + +#include +#include +#include + +namespace Catch { + + struct GeneratorInfo : IGeneratorInfo { + + GeneratorInfo( std::size_t size ) + : m_size( size ), + m_currentIndex( 0 ) + {} + + bool moveNext() { + if( ++m_currentIndex == m_size ) { + m_currentIndex = 0; + return false; + } + return true; + } + + std::size_t getCurrentIndex() const { + return m_currentIndex; + } + + std::size_t m_size; + std::size_t m_currentIndex; + }; + + /////////////////////////////////////////////////////////////////////////// + + class GeneratorsForTest : public IGeneratorsForTest { + + public: + ~GeneratorsForTest() { + deleteAll( m_generatorsInOrder ); + } + + IGeneratorInfo& getGeneratorInfo( std::string const& fileInfo, std::size_t size ) { + std::map::const_iterator it = m_generatorsByName.find( fileInfo ); + if( it == m_generatorsByName.end() ) { + IGeneratorInfo* info = new GeneratorInfo( size ); + m_generatorsByName.insert( std::make_pair( fileInfo, info ) ); + m_generatorsInOrder.push_back( info ); + return *info; + } + return *it->second; + } + + bool moveNext() { + std::vector::const_iterator it = m_generatorsInOrder.begin(); + std::vector::const_iterator itEnd = m_generatorsInOrder.end(); + for(; it != itEnd; ++it ) { + if( (*it)->moveNext() ) + return true; + } + return false; + } + + private: + std::map m_generatorsByName; + std::vector m_generatorsInOrder; + }; + + IGeneratorsForTest* createGeneratorsForTest() + { + return new GeneratorsForTest(); + } + +} // end namespace Catch + +// #included from: catch_assertionresult.hpp +#define TWOBLUECUBES_CATCH_ASSERTIONRESULT_HPP_INCLUDED + +namespace Catch { + + AssertionInfo::AssertionInfo( std::string const& _macroName, + SourceLineInfo const& _lineInfo, + std::string const& _capturedExpression, + ResultDisposition::Flags _resultDisposition ) + : macroName( _macroName ), + lineInfo( _lineInfo ), + capturedExpression( _capturedExpression ), + resultDisposition( _resultDisposition ) + {} + + AssertionResult::AssertionResult() {} + + AssertionResult::AssertionResult( AssertionInfo const& info, AssertionResultData const& data ) + : m_info( info ), + m_resultData( data ) + {} + + AssertionResult::~AssertionResult() {} + + // Result was a success + bool AssertionResult::succeeded() const { + return Catch::isOk( m_resultData.resultType ); + } + + // Result was a success, or failure is suppressed + bool AssertionResult::isOk() const { + return Catch::isOk( m_resultData.resultType ) || shouldSuppressFailure( m_info.resultDisposition ); + } + + ResultWas::OfType AssertionResult::getResultType() const { + return m_resultData.resultType; + } + + bool AssertionResult::hasExpression() const { + return !m_info.capturedExpression.empty(); + } + + bool AssertionResult::hasMessage() const { + return !m_resultData.message.empty(); + } + + std::string AssertionResult::getExpression() const { + if( isFalseTest( m_info.resultDisposition ) ) + return "!" + m_info.capturedExpression; + else + return m_info.capturedExpression; + } + std::string AssertionResult::getExpressionInMacro() const { + if( m_info.macroName.empty() ) + return m_info.capturedExpression; + else + return m_info.macroName + "( " + m_info.capturedExpression + " )"; + } + + bool AssertionResult::hasExpandedExpression() const { + return hasExpression() && getExpandedExpression() != getExpression(); + } + + std::string AssertionResult::getExpandedExpression() const { + return m_resultData.reconstructedExpression; + } + + std::string AssertionResult::getMessage() const { + return m_resultData.message; + } + SourceLineInfo AssertionResult::getSourceInfo() const { + return m_info.lineInfo; + } + + std::string AssertionResult::getTestMacroName() const { + return m_info.macroName; + } + +} // end namespace Catch + +// #included from: catch_test_case_info.hpp +#define TWOBLUECUBES_CATCH_TEST_CASE_INFO_HPP_INCLUDED + +namespace Catch { + + inline TestCaseInfo::SpecialProperties parseSpecialTag( std::string const& tag ) { + if( startsWith( tag, "." ) || + tag == "hide" || + tag == "!hide" ) + return TestCaseInfo::IsHidden; + else if( tag == "!throws" ) + return TestCaseInfo::Throws; + else if( tag == "!shouldfail" ) + return TestCaseInfo::ShouldFail; + else if( tag == "!mayfail" ) + return TestCaseInfo::MayFail; + else + return TestCaseInfo::None; + } + inline bool isReservedTag( std::string const& tag ) { + return parseSpecialTag( tag ) == TestCaseInfo::None && tag.size() > 0 && !isalnum( tag[0] ); + } + inline void enforceNotReservedTag( std::string const& tag, SourceLineInfo const& _lineInfo ) { + if( isReservedTag( tag ) ) { + { + Colour colourGuard( Colour::Red ); + Catch::cerr() + << "Tag name [" << tag << "] not allowed.\n" + << "Tag names starting with non alpha-numeric characters are reserved\n"; + } + { + Colour colourGuard( Colour::FileName ); + Catch::cerr() << _lineInfo << std::endl; + } + exit(1); + } + } + + TestCase makeTestCase( ITestCase* _testCase, + std::string const& _className, + std::string const& _name, + std::string const& _descOrTags, + SourceLineInfo const& _lineInfo ) + { + bool isHidden( startsWith( _name, "./" ) ); // Legacy support + + // Parse out tags + std::set tags; + std::string desc, tag; + bool inTag = false; + for( std::size_t i = 0; i < _descOrTags.size(); ++i ) { + char c = _descOrTags[i]; + if( !inTag ) { + if( c == '[' ) + inTag = true; + else + desc += c; + } + else { + if( c == ']' ) { + TestCaseInfo::SpecialProperties prop = parseSpecialTag( tag ); + if( prop == TestCaseInfo::IsHidden ) + isHidden = true; + else if( prop == TestCaseInfo::None ) + enforceNotReservedTag( tag, _lineInfo ); + + tags.insert( tag ); + tag.clear(); + inTag = false; + } + else + tag += c; + } + } + if( isHidden ) { + tags.insert( "hide" ); + tags.insert( "." ); + } + + TestCaseInfo info( _name, _className, desc, tags, _lineInfo ); + return TestCase( _testCase, info ); + } + + void setTags( TestCaseInfo& testCaseInfo, std::set const& tags ) + { + testCaseInfo.tags = tags; + testCaseInfo.lcaseTags.clear(); + + std::ostringstream oss; + for( std::set::const_iterator it = tags.begin(), itEnd = tags.end(); it != itEnd; ++it ) { + oss << "[" << *it << "]"; + std::string lcaseTag = toLower( *it ); + testCaseInfo.properties = static_cast( testCaseInfo.properties | parseSpecialTag( lcaseTag ) ); + testCaseInfo.lcaseTags.insert( lcaseTag ); + } + testCaseInfo.tagsAsString = oss.str(); + } + + TestCaseInfo::TestCaseInfo( std::string const& _name, + std::string const& _className, + std::string const& _description, + std::set const& _tags, + SourceLineInfo const& _lineInfo ) + : name( _name ), + className( _className ), + description( _description ), + lineInfo( _lineInfo ), + properties( None ) + { + setTags( *this, _tags ); + } + + TestCaseInfo::TestCaseInfo( TestCaseInfo const& other ) + : name( other.name ), + className( other.className ), + description( other.description ), + tags( other.tags ), + lcaseTags( other.lcaseTags ), + tagsAsString( other.tagsAsString ), + lineInfo( other.lineInfo ), + properties( other.properties ) + {} + + bool TestCaseInfo::isHidden() const { + return ( properties & IsHidden ) != 0; + } + bool TestCaseInfo::throws() const { + return ( properties & Throws ) != 0; + } + bool TestCaseInfo::okToFail() const { + return ( properties & (ShouldFail | MayFail ) ) != 0; + } + bool TestCaseInfo::expectedToFail() const { + return ( properties & (ShouldFail ) ) != 0; + } + + TestCase::TestCase( ITestCase* testCase, TestCaseInfo const& info ) : TestCaseInfo( info ), test( testCase ) {} + + TestCase::TestCase( TestCase const& other ) + : TestCaseInfo( other ), + test( other.test ) + {} + + TestCase TestCase::withName( std::string const& _newName ) const { + TestCase other( *this ); + other.name = _newName; + return other; + } + + void TestCase::swap( TestCase& other ) { + test.swap( other.test ); + name.swap( other.name ); + className.swap( other.className ); + description.swap( other.description ); + tags.swap( other.tags ); + lcaseTags.swap( other.lcaseTags ); + tagsAsString.swap( other.tagsAsString ); + std::swap( TestCaseInfo::properties, static_cast( other ).properties ); + std::swap( lineInfo, other.lineInfo ); + } + + void TestCase::invoke() const { + test->invoke(); + } + + bool TestCase::operator == ( TestCase const& other ) const { + return test.get() == other.test.get() && + name == other.name && + className == other.className; + } + + bool TestCase::operator < ( TestCase const& other ) const { + return name < other.name; + } + TestCase& TestCase::operator = ( TestCase const& other ) { + TestCase temp( other ); + swap( temp ); + return *this; + } + + TestCaseInfo const& TestCase::getTestCaseInfo() const + { + return *this; + } + +} // end namespace Catch + +// #included from: catch_version.hpp +#define TWOBLUECUBES_CATCH_VERSION_HPP_INCLUDED + +namespace Catch { + + Version::Version + ( unsigned int _majorVersion, + unsigned int _minorVersion, + unsigned int _patchNumber, + std::string const& _branchName, + unsigned int _buildNumber ) + : majorVersion( _majorVersion ), + minorVersion( _minorVersion ), + patchNumber( _patchNumber ), + branchName( _branchName ), + buildNumber( _buildNumber ) + {} + + std::ostream& operator << ( std::ostream& os, Version const& version ) { + os << version.majorVersion << "." + << version.minorVersion << "." + << version.patchNumber; + + if( !version.branchName.empty() ) { + os << "-" << version.branchName + << "." << version.buildNumber; + } + return os; + } + + Version libraryVersion( 1, 3, 6, "", 0 ); + +} + +// #included from: catch_message.hpp +#define TWOBLUECUBES_CATCH_MESSAGE_HPP_INCLUDED + +namespace Catch { + + MessageInfo::MessageInfo( std::string const& _macroName, + SourceLineInfo const& _lineInfo, + ResultWas::OfType _type ) + : macroName( _macroName ), + lineInfo( _lineInfo ), + type( _type ), + sequence( ++globalCount ) + {} + + // This may need protecting if threading support is added + unsigned int MessageInfo::globalCount = 0; + + //////////////////////////////////////////////////////////////////////////// + + ScopedMessage::ScopedMessage( MessageBuilder const& builder ) + : m_info( builder.m_info ) + { + m_info.message = builder.m_stream.str(); + getResultCapture().pushScopedMessage( m_info ); + } + ScopedMessage::ScopedMessage( ScopedMessage const& other ) + : m_info( other.m_info ) + {} + + ScopedMessage::~ScopedMessage() { + getResultCapture().popScopedMessage( m_info ); + } + +} // end namespace Catch + +// #included from: catch_legacy_reporter_adapter.hpp +#define TWOBLUECUBES_CATCH_LEGACY_REPORTER_ADAPTER_HPP_INCLUDED + +// #included from: catch_legacy_reporter_adapter.h +#define TWOBLUECUBES_CATCH_LEGACY_REPORTER_ADAPTER_H_INCLUDED + +namespace Catch +{ + // Deprecated + struct IReporter : IShared { + virtual ~IReporter(); + + virtual bool shouldRedirectStdout() const = 0; + + virtual void StartTesting() = 0; + virtual void EndTesting( Totals const& totals ) = 0; + virtual void StartGroup( std::string const& groupName ) = 0; + virtual void EndGroup( std::string const& groupName, Totals const& totals ) = 0; + virtual void StartTestCase( TestCaseInfo const& testInfo ) = 0; + virtual void EndTestCase( TestCaseInfo const& testInfo, Totals const& totals, std::string const& stdOut, std::string const& stdErr ) = 0; + virtual void StartSection( std::string const& sectionName, std::string const& description ) = 0; + virtual void EndSection( std::string const& sectionName, Counts const& assertions ) = 0; + virtual void NoAssertionsInSection( std::string const& sectionName ) = 0; + virtual void NoAssertionsInTestCase( std::string const& testName ) = 0; + virtual void Aborted() = 0; + virtual void Result( AssertionResult const& result ) = 0; + }; + + class LegacyReporterAdapter : public SharedImpl + { + public: + LegacyReporterAdapter( Ptr const& legacyReporter ); + virtual ~LegacyReporterAdapter(); + + virtual ReporterPreferences getPreferences() const; + virtual void noMatchingTestCases( std::string const& ); + virtual void testRunStarting( TestRunInfo const& ); + virtual void testGroupStarting( GroupInfo const& groupInfo ); + virtual void testCaseStarting( TestCaseInfo const& testInfo ); + virtual void sectionStarting( SectionInfo const& sectionInfo ); + virtual void assertionStarting( AssertionInfo const& ); + virtual bool assertionEnded( AssertionStats const& assertionStats ); + virtual void sectionEnded( SectionStats const& sectionStats ); + virtual void testCaseEnded( TestCaseStats const& testCaseStats ); + virtual void testGroupEnded( TestGroupStats const& testGroupStats ); + virtual void testRunEnded( TestRunStats const& testRunStats ); + virtual void skipTest( TestCaseInfo const& ); + + private: + Ptr m_legacyReporter; + }; +} + +namespace Catch +{ + LegacyReporterAdapter::LegacyReporterAdapter( Ptr const& legacyReporter ) + : m_legacyReporter( legacyReporter ) + {} + LegacyReporterAdapter::~LegacyReporterAdapter() {} + + ReporterPreferences LegacyReporterAdapter::getPreferences() const { + ReporterPreferences prefs; + prefs.shouldRedirectStdOut = m_legacyReporter->shouldRedirectStdout(); + return prefs; + } + + void LegacyReporterAdapter::noMatchingTestCases( std::string const& ) {} + void LegacyReporterAdapter::testRunStarting( TestRunInfo const& ) { + m_legacyReporter->StartTesting(); + } + void LegacyReporterAdapter::testGroupStarting( GroupInfo const& groupInfo ) { + m_legacyReporter->StartGroup( groupInfo.name ); + } + void LegacyReporterAdapter::testCaseStarting( TestCaseInfo const& testInfo ) { + m_legacyReporter->StartTestCase( testInfo ); + } + void LegacyReporterAdapter::sectionStarting( SectionInfo const& sectionInfo ) { + m_legacyReporter->StartSection( sectionInfo.name, sectionInfo.description ); + } + void LegacyReporterAdapter::assertionStarting( AssertionInfo const& ) { + // Not on legacy interface + } + + bool LegacyReporterAdapter::assertionEnded( AssertionStats const& assertionStats ) { + if( assertionStats.assertionResult.getResultType() != ResultWas::Ok ) { + for( std::vector::const_iterator it = assertionStats.infoMessages.begin(), itEnd = assertionStats.infoMessages.end(); + it != itEnd; + ++it ) { + if( it->type == ResultWas::Info ) { + ResultBuilder rb( it->macroName.c_str(), it->lineInfo, "", ResultDisposition::Normal ); + rb << it->message; + rb.setResultType( ResultWas::Info ); + AssertionResult result = rb.build(); + m_legacyReporter->Result( result ); + } + } + } + m_legacyReporter->Result( assertionStats.assertionResult ); + return true; + } + void LegacyReporterAdapter::sectionEnded( SectionStats const& sectionStats ) { + if( sectionStats.missingAssertions ) + m_legacyReporter->NoAssertionsInSection( sectionStats.sectionInfo.name ); + m_legacyReporter->EndSection( sectionStats.sectionInfo.name, sectionStats.assertions ); + } + void LegacyReporterAdapter::testCaseEnded( TestCaseStats const& testCaseStats ) { + m_legacyReporter->EndTestCase + ( testCaseStats.testInfo, + testCaseStats.totals, + testCaseStats.stdOut, + testCaseStats.stdErr ); + } + void LegacyReporterAdapter::testGroupEnded( TestGroupStats const& testGroupStats ) { + if( testGroupStats.aborting ) + m_legacyReporter->Aborted(); + m_legacyReporter->EndGroup( testGroupStats.groupInfo.name, testGroupStats.totals ); + } + void LegacyReporterAdapter::testRunEnded( TestRunStats const& testRunStats ) { + m_legacyReporter->EndTesting( testRunStats.totals ); + } + void LegacyReporterAdapter::skipTest( TestCaseInfo const& ) { + } +} + +// #included from: catch_timer.hpp + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wc++11-long-long" +#endif + +#ifdef CATCH_PLATFORM_WINDOWS +#include +#else +#include +#endif + +namespace Catch { + + namespace { +#ifdef CATCH_PLATFORM_WINDOWS + uint64_t getCurrentTicks() { + static uint64_t hz=0, hzo=0; + if (!hz) { + QueryPerformanceFrequency( reinterpret_cast( &hz ) ); + QueryPerformanceCounter( reinterpret_cast( &hzo ) ); + } + uint64_t t; + QueryPerformanceCounter( reinterpret_cast( &t ) ); + return ((t-hzo)*1000000)/hz; + } +#else + uint64_t getCurrentTicks() { + timeval t; + gettimeofday(&t,CATCH_NULL); + return static_cast( t.tv_sec ) * 1000000ull + static_cast( t.tv_usec ); + } +#endif + } + + void Timer::start() { + m_ticks = getCurrentTicks(); + } + unsigned int Timer::getElapsedMicroseconds() const { + return static_cast(getCurrentTicks() - m_ticks); + } + unsigned int Timer::getElapsedMilliseconds() const { + return static_cast(getElapsedMicroseconds()/1000); + } + double Timer::getElapsedSeconds() const { + return getElapsedMicroseconds()/1000000.0; + } + +} // namespace Catch + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif +// #included from: catch_common.hpp +#define TWOBLUECUBES_CATCH_COMMON_HPP_INCLUDED + +namespace Catch { + + bool startsWith( std::string const& s, std::string const& prefix ) { + return s.size() >= prefix.size() && s.substr( 0, prefix.size() ) == prefix; + } + bool endsWith( std::string const& s, std::string const& suffix ) { + return s.size() >= suffix.size() && s.substr( s.size()-suffix.size(), suffix.size() ) == suffix; + } + bool contains( std::string const& s, std::string const& infix ) { + return s.find( infix ) != std::string::npos; + } + void toLowerInPlace( std::string& s ) { + std::transform( s.begin(), s.end(), s.begin(), ::tolower ); + } + std::string toLower( std::string const& s ) { + std::string lc = s; + toLowerInPlace( lc ); + return lc; + } + std::string trim( std::string const& str ) { + static char const* whitespaceChars = "\n\r\t "; + std::string::size_type start = str.find_first_not_of( whitespaceChars ); + std::string::size_type end = str.find_last_not_of( whitespaceChars ); + + return start != std::string::npos ? str.substr( start, 1+end-start ) : ""; + } + + bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ) { + bool replaced = false; + std::size_t i = str.find( replaceThis ); + while( i != std::string::npos ) { + replaced = true; + str = str.substr( 0, i ) + withThis + str.substr( i+replaceThis.size() ); + if( i < str.size()-withThis.size() ) + i = str.find( replaceThis, i+withThis.size() ); + else + i = std::string::npos; + } + return replaced; + } + + pluralise::pluralise( std::size_t count, std::string const& label ) + : m_count( count ), + m_label( label ) + {} + + std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ) { + os << pluraliser.m_count << " " << pluraliser.m_label; + if( pluraliser.m_count != 1 ) + os << "s"; + return os; + } + + SourceLineInfo::SourceLineInfo() : line( 0 ){} + SourceLineInfo::SourceLineInfo( char const* _file, std::size_t _line ) + : file( _file ), + line( _line ) + {} + SourceLineInfo::SourceLineInfo( SourceLineInfo const& other ) + : file( other.file ), + line( other.line ) + {} + bool SourceLineInfo::empty() const { + return file.empty(); + } + bool SourceLineInfo::operator == ( SourceLineInfo const& other ) const { + return line == other.line && file == other.file; + } + bool SourceLineInfo::operator < ( SourceLineInfo const& other ) const { + return line < other.line || ( line == other.line && file < other.file ); + } + + void seedRng( IConfig const& config ) { + if( config.rngSeed() != 0 ) + std::srand( config.rngSeed() ); + } + unsigned int rngSeed() { + return getCurrentContext().getConfig()->rngSeed(); + } + + std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ) { +#ifndef __GNUG__ + os << info.file << "(" << info.line << ")"; +#else + os << info.file << ":" << info.line; +#endif + return os; + } + + void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo ) { + std::ostringstream oss; + oss << locationInfo << ": Internal Catch error: '" << message << "'"; + if( alwaysTrue() ) + throw std::logic_error( oss.str() ); + } +} + +// #included from: catch_section.hpp +#define TWOBLUECUBES_CATCH_SECTION_HPP_INCLUDED + +namespace Catch { + + SectionInfo::SectionInfo + ( SourceLineInfo const& _lineInfo, + std::string const& _name, + std::string const& _description ) + : name( _name ), + description( _description ), + lineInfo( _lineInfo ) + {} + + Section::Section( SectionInfo const& info ) + : m_info( info ), + m_sectionIncluded( getResultCapture().sectionStarted( m_info, m_assertions ) ) + { + m_timer.start(); + } + + Section::~Section() { + if( m_sectionIncluded ) { + SectionEndInfo endInfo( m_info, m_assertions, m_timer.getElapsedSeconds() ); + if( std::uncaught_exception() ) + getResultCapture().sectionEndedEarly( endInfo ); + else + getResultCapture().sectionEnded( endInfo ); + } + } + + // This indicates whether the section should be executed or not + Section::operator bool() const { + return m_sectionIncluded; + } + +} // end namespace Catch + +// #included from: catch_debugger.hpp +#define TWOBLUECUBES_CATCH_DEBUGGER_HPP_INCLUDED + +#include + +#ifdef CATCH_PLATFORM_MAC + + #include + #include + #include + #include + #include + + namespace Catch{ + + // The following function is taken directly from the following technical note: + // http://developer.apple.com/library/mac/#qa/qa2004/qa1361.html + + // Returns true if the current process is being debugged (either + // running under the debugger or has a debugger attached post facto). + bool isDebuggerActive(){ + + int mib[4]; + struct kinfo_proc info; + size_t size; + + // Initialize the flags so that, if sysctl fails for some bizarre + // reason, we get a predictable result. + + info.kp_proc.p_flag = 0; + + // Initialize mib, which tells sysctl the info we want, in this case + // we're looking for information about a specific process ID. + + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PID; + mib[3] = getpid(); + + // Call sysctl. + + size = sizeof(info); + if( sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, CATCH_NULL, 0) != 0 ) { + Catch::cerr() << "\n** Call to sysctl failed - unable to determine if debugger is active **\n" << std::endl; + return false; + } + + // We're being debugged if the P_TRACED flag is set. + + return ( (info.kp_proc.p_flag & P_TRACED) != 0 ); + } + } // namespace Catch + +#elif defined(_MSC_VER) + extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); + namespace Catch { + bool isDebuggerActive() { + return IsDebuggerPresent() != 0; + } + } +#elif defined(__MINGW32__) + extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); + namespace Catch { + bool isDebuggerActive() { + return IsDebuggerPresent() != 0; + } + } +#else + namespace Catch { + inline bool isDebuggerActive() { return false; } + } +#endif // Platform + +#ifdef CATCH_PLATFORM_WINDOWS + extern "C" __declspec(dllimport) void __stdcall OutputDebugStringA( const char* ); + namespace Catch { + void writeToDebugConsole( std::string const& text ) { + ::OutputDebugStringA( text.c_str() ); + } + } +#else + namespace Catch { + void writeToDebugConsole( std::string const& text ) { + // !TBD: Need a version for Mac/ XCode and other IDEs + Catch::cout() << text; + } + } +#endif // Platform + +// #included from: catch_tostring.hpp +#define TWOBLUECUBES_CATCH_TOSTRING_HPP_INCLUDED + +namespace Catch { + +namespace Detail { + + const std::string unprintableString = "{?}"; + + namespace { + const int hexThreshold = 255; + + struct Endianness { + enum Arch { Big, Little }; + + static Arch which() { + union _{ + int asInt; + char asChar[sizeof (int)]; + } u; + + u.asInt = 1; + return ( u.asChar[sizeof(int)-1] == 1 ) ? Big : Little; + } + }; + } + + std::string rawMemoryToString( const void *object, std::size_t size ) + { + // Reverse order for little endian architectures + int i = 0, end = static_cast( size ), inc = 1; + if( Endianness::which() == Endianness::Little ) { + i = end-1; + end = inc = -1; + } + + unsigned char const *bytes = static_cast(object); + std::ostringstream os; + os << "0x" << std::setfill('0') << std::hex; + for( ; i != end; i += inc ) + os << std::setw(2) << static_cast(bytes[i]); + return os.str(); + } +} + +std::string toString( std::string const& value ) { + std::string s = value; + if( getCurrentContext().getConfig()->showInvisibles() ) { + for(size_t i = 0; i < s.size(); ++i ) { + std::string subs; + switch( s[i] ) { + case '\n': subs = "\\n"; break; + case '\t': subs = "\\t"; break; + default: break; + } + if( !subs.empty() ) { + s = s.substr( 0, i ) + subs + s.substr( i+1 ); + ++i; + } + } + } + return "\"" + s + "\""; +} +std::string toString( std::wstring const& value ) { + + std::string s; + s.reserve( value.size() ); + for(size_t i = 0; i < value.size(); ++i ) + s += value[i] <= 0xff ? static_cast( value[i] ) : '?'; + return Catch::toString( s ); +} + +std::string toString( const char* const value ) { + return value ? Catch::toString( std::string( value ) ) : std::string( "{null string}" ); +} + +std::string toString( char* const value ) { + return Catch::toString( static_cast( value ) ); +} + +std::string toString( const wchar_t* const value ) +{ + return value ? Catch::toString( std::wstring(value) ) : std::string( "{null string}" ); +} + +std::string toString( wchar_t* const value ) +{ + return Catch::toString( static_cast( value ) ); +} + +std::string toString( int value ) { + std::ostringstream oss; + oss << value; + if( value > Detail::hexThreshold ) + oss << " (0x" << std::hex << value << ")"; + return oss.str(); +} + +std::string toString( unsigned long value ) { + std::ostringstream oss; + oss << value; + if( value > Detail::hexThreshold ) + oss << " (0x" << std::hex << value << ")"; + return oss.str(); +} + +std::string toString( unsigned int value ) { + return Catch::toString( static_cast( value ) ); +} + +template +std::string fpToString( T value, int precision ) { + std::ostringstream oss; + oss << std::setprecision( precision ) + << std::fixed + << value; + std::string d = oss.str(); + std::size_t i = d.find_last_not_of( '0' ); + if( i != std::string::npos && i != d.size()-1 ) { + if( d[i] == '.' ) + i++; + d = d.substr( 0, i+1 ); + } + return d; +} + +std::string toString( const double value ) { + return fpToString( value, 10 ); +} +std::string toString( const float value ) { + return fpToString( value, 5 ) + "f"; +} + +std::string toString( bool value ) { + return value ? "true" : "false"; +} + +std::string toString( char value ) { + return value < ' ' + ? toString( static_cast( value ) ) + : Detail::makeString( value ); +} + +std::string toString( signed char value ) { + return toString( static_cast( value ) ); +} + +std::string toString( unsigned char value ) { + return toString( static_cast( value ) ); +} + +#ifdef CATCH_CONFIG_CPP11_LONG_LONG +std::string toString( long long value ) { + std::ostringstream oss; + oss << value; + if( value > Detail::hexThreshold ) + oss << " (0x" << std::hex << value << ")"; + return oss.str(); +} +std::string toString( unsigned long long value ) { + std::ostringstream oss; + oss << value; + if( value > Detail::hexThreshold ) + oss << " (0x" << std::hex << value << ")"; + return oss.str(); +} +#endif + +#ifdef CATCH_CONFIG_CPP11_NULLPTR +std::string toString( std::nullptr_t ) { + return "nullptr"; +} +#endif + +#ifdef __OBJC__ + std::string toString( NSString const * const& nsstring ) { + if( !nsstring ) + return "nil"; + return "@" + toString([nsstring UTF8String]); + } + std::string toString( NSString * CATCH_ARC_STRONG const& nsstring ) { + if( !nsstring ) + return "nil"; + return "@" + toString([nsstring UTF8String]); + } + std::string toString( NSObject* const& nsObject ) { + return toString( [nsObject description] ); + } +#endif + +} // end namespace Catch + +// #included from: catch_result_builder.hpp +#define TWOBLUECUBES_CATCH_RESULT_BUILDER_HPP_INCLUDED + +namespace Catch { + + std::string capturedExpressionWithSecondArgument( std::string const& capturedExpression, std::string const& secondArg ) { + return secondArg.empty() || secondArg == "\"\"" + ? capturedExpression + : capturedExpression + ", " + secondArg; + } + ResultBuilder::ResultBuilder( char const* macroName, + SourceLineInfo const& lineInfo, + char const* capturedExpression, + ResultDisposition::Flags resultDisposition, + char const* secondArg ) + : m_assertionInfo( macroName, lineInfo, capturedExpressionWithSecondArgument( capturedExpression, secondArg ), resultDisposition ), + m_shouldDebugBreak( false ), + m_shouldThrow( false ) + {} + + ResultBuilder& ResultBuilder::setResultType( ResultWas::OfType result ) { + m_data.resultType = result; + return *this; + } + ResultBuilder& ResultBuilder::setResultType( bool result ) { + m_data.resultType = result ? ResultWas::Ok : ResultWas::ExpressionFailed; + return *this; + } + ResultBuilder& ResultBuilder::setLhs( std::string const& lhs ) { + m_exprComponents.lhs = lhs; + return *this; + } + ResultBuilder& ResultBuilder::setRhs( std::string const& rhs ) { + m_exprComponents.rhs = rhs; + return *this; + } + ResultBuilder& ResultBuilder::setOp( std::string const& op ) { + m_exprComponents.op = op; + return *this; + } + + void ResultBuilder::endExpression() { + m_exprComponents.testFalse = isFalseTest( m_assertionInfo.resultDisposition ); + captureExpression(); + } + + void ResultBuilder::useActiveException( ResultDisposition::Flags resultDisposition ) { + m_assertionInfo.resultDisposition = resultDisposition; + m_stream.oss << Catch::translateActiveException(); + captureResult( ResultWas::ThrewException ); + } + + void ResultBuilder::captureResult( ResultWas::OfType resultType ) { + setResultType( resultType ); + captureExpression(); + } + void ResultBuilder::captureExpectedException( std::string const& expectedMessage ) { + if( expectedMessage.empty() ) + captureExpectedException( Matchers::Impl::Generic::AllOf() ); + else + captureExpectedException( Matchers::Equals( expectedMessage ) ); + } + + void ResultBuilder::captureExpectedException( Matchers::Impl::Matcher const& matcher ) { + + assert( m_exprComponents.testFalse == false ); + AssertionResultData data = m_data; + data.resultType = ResultWas::Ok; + data.reconstructedExpression = m_assertionInfo.capturedExpression; + + std::string actualMessage = Catch::translateActiveException(); + if( !matcher.match( actualMessage ) ) { + data.resultType = ResultWas::ExpressionFailed; + data.reconstructedExpression = actualMessage; + } + AssertionResult result( m_assertionInfo, data ); + handleResult( result ); + } + + void ResultBuilder::captureExpression() { + AssertionResult result = build(); + handleResult( result ); + } + void ResultBuilder::handleResult( AssertionResult const& result ) + { + getResultCapture().assertionEnded( result ); + + if( !result.isOk() ) { + if( getCurrentContext().getConfig()->shouldDebugBreak() ) + m_shouldDebugBreak = true; + if( getCurrentContext().getRunner()->aborting() || (m_assertionInfo.resultDisposition & ResultDisposition::Normal) ) + m_shouldThrow = true; + } + } + void ResultBuilder::react() { + if( m_shouldThrow ) + throw Catch::TestFailureException(); + } + + bool ResultBuilder::shouldDebugBreak() const { return m_shouldDebugBreak; } + bool ResultBuilder::allowThrows() const { return getCurrentContext().getConfig()->allowThrows(); } + + AssertionResult ResultBuilder::build() const + { + assert( m_data.resultType != ResultWas::Unknown ); + + AssertionResultData data = m_data; + + // Flip bool results if testFalse is set + if( m_exprComponents.testFalse ) { + if( data.resultType == ResultWas::Ok ) + data.resultType = ResultWas::ExpressionFailed; + else if( data.resultType == ResultWas::ExpressionFailed ) + data.resultType = ResultWas::Ok; + } + + data.message = m_stream.oss.str(); + data.reconstructedExpression = reconstructExpression(); + if( m_exprComponents.testFalse ) { + if( m_exprComponents.op == "" ) + data.reconstructedExpression = "!" + data.reconstructedExpression; + else + data.reconstructedExpression = "!(" + data.reconstructedExpression + ")"; + } + return AssertionResult( m_assertionInfo, data ); + } + std::string ResultBuilder::reconstructExpression() const { + if( m_exprComponents.op == "" ) + return m_exprComponents.lhs.empty() ? m_assertionInfo.capturedExpression : m_exprComponents.op + m_exprComponents.lhs; + else if( m_exprComponents.op == "matches" ) + return m_exprComponents.lhs + " " + m_exprComponents.rhs; + else if( m_exprComponents.op != "!" ) { + if( m_exprComponents.lhs.size() + m_exprComponents.rhs.size() < 40 && + m_exprComponents.lhs.find("\n") == std::string::npos && + m_exprComponents.rhs.find("\n") == std::string::npos ) + return m_exprComponents.lhs + " " + m_exprComponents.op + " " + m_exprComponents.rhs; + else + return m_exprComponents.lhs + "\n" + m_exprComponents.op + "\n" + m_exprComponents.rhs; + } + else + return "{can't expand - use " + m_assertionInfo.macroName + "_FALSE( " + m_assertionInfo.capturedExpression.substr(1) + " ) instead of " + m_assertionInfo.macroName + "( " + m_assertionInfo.capturedExpression + " ) for better diagnostics}"; + } + +} // end namespace Catch + +// #included from: catch_tag_alias_registry.hpp +#define TWOBLUECUBES_CATCH_TAG_ALIAS_REGISTRY_HPP_INCLUDED + +// #included from: catch_tag_alias_registry.h +#define TWOBLUECUBES_CATCH_TAG_ALIAS_REGISTRY_H_INCLUDED + +#include + +namespace Catch { + + class TagAliasRegistry : public ITagAliasRegistry { + public: + virtual ~TagAliasRegistry(); + virtual Option find( std::string const& alias ) const; + virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const; + void add( char const* alias, char const* tag, SourceLineInfo const& lineInfo ); + static TagAliasRegistry& get(); + + private: + std::map m_registry; + }; + +} // end namespace Catch + +#include +#include + +namespace Catch { + + TagAliasRegistry::~TagAliasRegistry() {} + + Option TagAliasRegistry::find( std::string const& alias ) const { + std::map::const_iterator it = m_registry.find( alias ); + if( it != m_registry.end() ) + return it->second; + else + return Option(); + } + + std::string TagAliasRegistry::expandAliases( std::string const& unexpandedTestSpec ) const { + std::string expandedTestSpec = unexpandedTestSpec; + for( std::map::const_iterator it = m_registry.begin(), itEnd = m_registry.end(); + it != itEnd; + ++it ) { + std::size_t pos = expandedTestSpec.find( it->first ); + if( pos != std::string::npos ) { + expandedTestSpec = expandedTestSpec.substr( 0, pos ) + + it->second.tag + + expandedTestSpec.substr( pos + it->first.size() ); + } + } + return expandedTestSpec; + } + + void TagAliasRegistry::add( char const* alias, char const* tag, SourceLineInfo const& lineInfo ) { + + if( !startsWith( alias, "[@" ) || !endsWith( alias, "]" ) ) { + std::ostringstream oss; + oss << "error: tag alias, \"" << alias << "\" is not of the form [@alias name].\n" << lineInfo; + throw std::domain_error( oss.str().c_str() ); + } + if( !m_registry.insert( std::make_pair( alias, TagAlias( tag, lineInfo ) ) ).second ) { + std::ostringstream oss; + oss << "error: tag alias, \"" << alias << "\" already registered.\n" + << "\tFirst seen at " << find(alias)->lineInfo << "\n" + << "\tRedefined at " << lineInfo; + throw std::domain_error( oss.str().c_str() ); + } + } + + TagAliasRegistry& TagAliasRegistry::get() { + static TagAliasRegistry instance; + return instance; + + } + + ITagAliasRegistry::~ITagAliasRegistry() {} + ITagAliasRegistry const& ITagAliasRegistry::get() { return TagAliasRegistry::get(); } + + RegistrarForTagAliases::RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ) { + try { + TagAliasRegistry::get().add( alias, tag, lineInfo ); + } + catch( std::exception& ex ) { + Colour colourGuard( Colour::Red ); + Catch::cerr() << ex.what() << std::endl; + exit(1); + } + } + +} // end namespace Catch + +// #included from: ../reporters/catch_reporter_multi.hpp +#define TWOBLUECUBES_CATCH_REPORTER_MULTI_HPP_INCLUDED + +namespace Catch { + +class MultipleReporters : public SharedImpl { + typedef std::vector > Reporters; + Reporters m_reporters; + +public: + void add( Ptr const& reporter ) { + m_reporters.push_back( reporter ); + } + +public: // IStreamingReporter + + virtual ReporterPreferences getPreferences() const CATCH_OVERRIDE { + return m_reporters[0]->getPreferences(); + } + + virtual void noMatchingTestCases( std::string const& spec ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->noMatchingTestCases( spec ); + } + + virtual void testRunStarting( TestRunInfo const& testRunInfo ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->testRunStarting( testRunInfo ); + } + + virtual void testGroupStarting( GroupInfo const& groupInfo ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->testGroupStarting( groupInfo ); + } + + virtual void testCaseStarting( TestCaseInfo const& testInfo ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->testCaseStarting( testInfo ); + } + + virtual void sectionStarting( SectionInfo const& sectionInfo ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->sectionStarting( sectionInfo ); + } + + virtual void assertionStarting( AssertionInfo const& assertionInfo ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->assertionStarting( assertionInfo ); + } + + // The return value indicates if the messages buffer should be cleared: + virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE { + bool clearBuffer = false; + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + clearBuffer |= (*it)->assertionEnded( assertionStats ); + return clearBuffer; + } + + virtual void sectionEnded( SectionStats const& sectionStats ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->sectionEnded( sectionStats ); + } + + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->testCaseEnded( testCaseStats ); + } + + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->testGroupEnded( testGroupStats ); + } + + virtual void testRunEnded( TestRunStats const& testRunStats ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->testRunEnded( testRunStats ); + } + + virtual void skipTest( TestCaseInfo const& testInfo ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->skipTest( testInfo ); + } +}; + +Ptr addReporter( Ptr const& existingReporter, Ptr const& additionalReporter ) { + Ptr resultingReporter; + + if( existingReporter ) { + MultipleReporters* multi = dynamic_cast( existingReporter.get() ); + if( !multi ) { + multi = new MultipleReporters; + resultingReporter = Ptr( multi ); + if( existingReporter ) + multi->add( existingReporter ); + } + else + resultingReporter = existingReporter; + multi->add( additionalReporter ); + } + else + resultingReporter = additionalReporter; + + return resultingReporter; +} + +} // end namespace Catch + +// #included from: ../reporters/catch_reporter_xml.hpp +#define TWOBLUECUBES_CATCH_REPORTER_XML_HPP_INCLUDED + +// #included from: catch_reporter_bases.hpp +#define TWOBLUECUBES_CATCH_REPORTER_BASES_HPP_INCLUDED + +#include + +namespace Catch { + + struct StreamingReporterBase : SharedImpl { + + StreamingReporterBase( ReporterConfig const& _config ) + : m_config( _config.fullConfig() ), + stream( _config.stream() ) + { + m_reporterPrefs.shouldRedirectStdOut = false; + } + + virtual ReporterPreferences getPreferences() const CATCH_OVERRIDE { + return m_reporterPrefs; + } + + virtual ~StreamingReporterBase() CATCH_OVERRIDE; + + virtual void noMatchingTestCases( std::string const& ) CATCH_OVERRIDE {} + + virtual void testRunStarting( TestRunInfo const& _testRunInfo ) CATCH_OVERRIDE { + currentTestRunInfo = _testRunInfo; + } + virtual void testGroupStarting( GroupInfo const& _groupInfo ) CATCH_OVERRIDE { + currentGroupInfo = _groupInfo; + } + + virtual void testCaseStarting( TestCaseInfo const& _testInfo ) CATCH_OVERRIDE { + currentTestCaseInfo = _testInfo; + } + virtual void sectionStarting( SectionInfo const& _sectionInfo ) CATCH_OVERRIDE { + m_sectionStack.push_back( _sectionInfo ); + } + + virtual void sectionEnded( SectionStats const& /* _sectionStats */ ) CATCH_OVERRIDE { + m_sectionStack.pop_back(); + } + virtual void testCaseEnded( TestCaseStats const& /* _testCaseStats */ ) CATCH_OVERRIDE { + currentTestCaseInfo.reset(); + } + virtual void testGroupEnded( TestGroupStats const& /* _testGroupStats */ ) CATCH_OVERRIDE { + currentGroupInfo.reset(); + } + virtual void testRunEnded( TestRunStats const& /* _testRunStats */ ) CATCH_OVERRIDE { + currentTestCaseInfo.reset(); + currentGroupInfo.reset(); + currentTestRunInfo.reset(); + } + + virtual void skipTest( TestCaseInfo const& ) CATCH_OVERRIDE { + // Don't do anything with this by default. + // It can optionally be overridden in the derived class. + } + + Ptr m_config; + std::ostream& stream; + + LazyStat currentTestRunInfo; + LazyStat currentGroupInfo; + LazyStat currentTestCaseInfo; + + std::vector m_sectionStack; + ReporterPreferences m_reporterPrefs; + }; + + struct CumulativeReporterBase : SharedImpl { + template + struct Node : SharedImpl<> { + explicit Node( T const& _value ) : value( _value ) {} + virtual ~Node() {} + + typedef std::vector > ChildNodes; + T value; + ChildNodes children; + }; + struct SectionNode : SharedImpl<> { + explicit SectionNode( SectionStats const& _stats ) : stats( _stats ) {} + virtual ~SectionNode(); + + bool operator == ( SectionNode const& other ) const { + return stats.sectionInfo.lineInfo == other.stats.sectionInfo.lineInfo; + } + bool operator == ( Ptr const& other ) const { + return operator==( *other ); + } + + SectionStats stats; + typedef std::vector > ChildSections; + typedef std::vector Assertions; + ChildSections childSections; + Assertions assertions; + std::string stdOut; + std::string stdErr; + }; + + struct BySectionInfo { + BySectionInfo( SectionInfo const& other ) : m_other( other ) {} + BySectionInfo( BySectionInfo const& other ) : m_other( other.m_other ) {} + bool operator() ( Ptr const& node ) const { + return node->stats.sectionInfo.lineInfo == m_other.lineInfo; + } + private: + void operator=( BySectionInfo const& ); + SectionInfo const& m_other; + }; + + typedef Node TestCaseNode; + typedef Node TestGroupNode; + typedef Node TestRunNode; + + CumulativeReporterBase( ReporterConfig const& _config ) + : m_config( _config.fullConfig() ), + stream( _config.stream() ) + { + m_reporterPrefs.shouldRedirectStdOut = false; + } + ~CumulativeReporterBase(); + + virtual ReporterPreferences getPreferences() const CATCH_OVERRIDE { + return m_reporterPrefs; + } + + virtual void testRunStarting( TestRunInfo const& ) CATCH_OVERRIDE {} + virtual void testGroupStarting( GroupInfo const& ) CATCH_OVERRIDE {} + + virtual void testCaseStarting( TestCaseInfo const& ) CATCH_OVERRIDE {} + + virtual void sectionStarting( SectionInfo const& sectionInfo ) CATCH_OVERRIDE { + SectionStats incompleteStats( sectionInfo, Counts(), 0, false ); + Ptr node; + if( m_sectionStack.empty() ) { + if( !m_rootSection ) + m_rootSection = new SectionNode( incompleteStats ); + node = m_rootSection; + } + else { + SectionNode& parentNode = *m_sectionStack.back(); + SectionNode::ChildSections::const_iterator it = + std::find_if( parentNode.childSections.begin(), + parentNode.childSections.end(), + BySectionInfo( sectionInfo ) ); + if( it == parentNode.childSections.end() ) { + node = new SectionNode( incompleteStats ); + parentNode.childSections.push_back( node ); + } + else + node = *it; + } + m_sectionStack.push_back( node ); + m_deepestSection = node; + } + + virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE {} + + virtual bool assertionEnded( AssertionStats const& assertionStats ) { + assert( !m_sectionStack.empty() ); + SectionNode& sectionNode = *m_sectionStack.back(); + sectionNode.assertions.push_back( assertionStats ); + return true; + } + virtual void sectionEnded( SectionStats const& sectionStats ) CATCH_OVERRIDE { + assert( !m_sectionStack.empty() ); + SectionNode& node = *m_sectionStack.back(); + node.stats = sectionStats; + m_sectionStack.pop_back(); + } + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE { + Ptr node = new TestCaseNode( testCaseStats ); + assert( m_sectionStack.size() == 0 ); + node->children.push_back( m_rootSection ); + m_testCases.push_back( node ); + m_rootSection.reset(); + + assert( m_deepestSection ); + m_deepestSection->stdOut = testCaseStats.stdOut; + m_deepestSection->stdErr = testCaseStats.stdErr; + } + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE { + Ptr node = new TestGroupNode( testGroupStats ); + node->children.swap( m_testCases ); + m_testGroups.push_back( node ); + } + virtual void testRunEnded( TestRunStats const& testRunStats ) CATCH_OVERRIDE { + Ptr node = new TestRunNode( testRunStats ); + node->children.swap( m_testGroups ); + m_testRuns.push_back( node ); + testRunEndedCumulative(); + } + virtual void testRunEndedCumulative() = 0; + + virtual void skipTest( TestCaseInfo const& ) CATCH_OVERRIDE {} + + Ptr m_config; + std::ostream& stream; + std::vector m_assertions; + std::vector > > m_sections; + std::vector > m_testCases; + std::vector > m_testGroups; + + std::vector > m_testRuns; + + Ptr m_rootSection; + Ptr m_deepestSection; + std::vector > m_sectionStack; + ReporterPreferences m_reporterPrefs; + + }; + + template + char const* getLineOfChars() { + static char line[CATCH_CONFIG_CONSOLE_WIDTH] = {0}; + if( !*line ) { + memset( line, C, CATCH_CONFIG_CONSOLE_WIDTH-1 ); + line[CATCH_CONFIG_CONSOLE_WIDTH-1] = 0; + } + return line; + } + + struct TestEventListenerBase : StreamingReporterBase { + TestEventListenerBase( ReporterConfig const& _config ) + : StreamingReporterBase( _config ) + {} + + virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE {} + virtual bool assertionEnded( AssertionStats const& ) CATCH_OVERRIDE { + return false; + } + }; + +} // end namespace Catch + +// #included from: ../internal/catch_reporter_registrars.hpp +#define TWOBLUECUBES_CATCH_REPORTER_REGISTRARS_HPP_INCLUDED + +namespace Catch { + + template + class LegacyReporterRegistrar { + + class ReporterFactory : public IReporterFactory { + virtual IStreamingReporter* create( ReporterConfig const& config ) const { + return new LegacyReporterAdapter( new T( config ) ); + } + + virtual std::string getDescription() const { + return T::getDescription(); + } + }; + + public: + + LegacyReporterRegistrar( std::string const& name ) { + getMutableRegistryHub().registerReporter( name, new ReporterFactory() ); + } + }; + + template + class ReporterRegistrar { + + class ReporterFactory : public SharedImpl { + + // *** Please Note ***: + // - If you end up here looking at a compiler error because it's trying to register + // your custom reporter class be aware that the native reporter interface has changed + // to IStreamingReporter. The "legacy" interface, IReporter, is still supported via + // an adapter. Just use REGISTER_LEGACY_REPORTER to take advantage of the adapter. + // However please consider updating to the new interface as the old one is now + // deprecated and will probably be removed quite soon! + // Please contact me via github if you have any questions at all about this. + // In fact, ideally, please contact me anyway to let me know you've hit this - as I have + // no idea who is actually using custom reporters at all (possibly no-one!). + // The new interface is designed to minimise exposure to interface changes in the future. + virtual IStreamingReporter* create( ReporterConfig const& config ) const { + return new T( config ); + } + + virtual std::string getDescription() const { + return T::getDescription(); + } + }; + + public: + + ReporterRegistrar( std::string const& name ) { + getMutableRegistryHub().registerReporter( name, new ReporterFactory() ); + } + }; + + template + class ListenerRegistrar { + + class ListenerFactory : public SharedImpl { + + virtual IStreamingReporter* create( ReporterConfig const& config ) const { + return new T( config ); + } + virtual std::string getDescription() const { + return ""; + } + }; + + public: + + ListenerRegistrar() { + getMutableRegistryHub().registerListener( new ListenerFactory() ); + } + }; +} + +#define INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) \ + namespace{ Catch::LegacyReporterRegistrar catch_internal_RegistrarFor##reporterType( name ); } + +#define INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) \ + namespace{ Catch::ReporterRegistrar catch_internal_RegistrarFor##reporterType( name ); } + +#define INTERNAL_CATCH_REGISTER_LISTENER( listenerType ) \ + namespace{ Catch::ListenerRegistrar catch_internal_RegistrarFor##listenerType; } + +// #included from: ../internal/catch_xmlwriter.hpp +#define TWOBLUECUBES_CATCH_XMLWRITER_HPP_INCLUDED + +#include +#include +#include +#include + +namespace Catch { + + class XmlEncode { + public: + enum ForWhat { ForTextNodes, ForAttributes }; + + XmlEncode( std::string const& str, ForWhat forWhat = ForTextNodes ) + : m_str( str ), + m_forWhat( forWhat ) + {} + + void encodeTo( std::ostream& os ) const { + + // Apostrophe escaping not necessary if we always use " to write attributes + // (see: http://www.w3.org/TR/xml/#syntax) + + for( std::size_t i = 0; i < m_str.size(); ++ i ) { + char c = m_str[i]; + switch( c ) { + case '<': os << "<"; break; + case '&': os << "&"; break; + + case '>': + // See: http://www.w3.org/TR/xml/#syntax + if( i > 2 && m_str[i-1] == ']' && m_str[i-2] == ']' ) + os << ">"; + else + os << c; + break; + + case '\"': + if( m_forWhat == ForAttributes ) + os << """; + else + os << c; + break; + + default: + // Escape control chars - based on contribution by @espenalb in PR #465 + if ( ( c < '\x09' ) || ( c > '\x0D' && c < '\x20') || c=='\x7F' ) + os << "&#x" << std::uppercase << std::hex << static_cast( c ); + else + os << c; + } + } + } + + friend std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ) { + xmlEncode.encodeTo( os ); + return os; + } + + private: + std::string m_str; + ForWhat m_forWhat; + }; + + class XmlWriter { + public: + + class ScopedElement { + public: + ScopedElement( XmlWriter* writer ) + : m_writer( writer ) + {} + + ScopedElement( ScopedElement const& other ) + : m_writer( other.m_writer ){ + other.m_writer = CATCH_NULL; + } + + ~ScopedElement() { + if( m_writer ) + m_writer->endElement(); + } + + ScopedElement& writeText( std::string const& text, bool indent = true ) { + m_writer->writeText( text, indent ); + return *this; + } + + template + ScopedElement& writeAttribute( std::string const& name, T const& attribute ) { + m_writer->writeAttribute( name, attribute ); + return *this; + } + + private: + mutable XmlWriter* m_writer; + }; + + XmlWriter() + : m_tagIsOpen( false ), + m_needsNewline( false ), + m_os( &Catch::cout() ) + {} + + XmlWriter( std::ostream& os ) + : m_tagIsOpen( false ), + m_needsNewline( false ), + m_os( &os ) + {} + + ~XmlWriter() { + while( !m_tags.empty() ) + endElement(); + } + + XmlWriter& startElement( std::string const& name ) { + ensureTagClosed(); + newlineIfNecessary(); + stream() << m_indent << "<" << name; + m_tags.push_back( name ); + m_indent += " "; + m_tagIsOpen = true; + return *this; + } + + ScopedElement scopedElement( std::string const& name ) { + ScopedElement scoped( this ); + startElement( name ); + return scoped; + } + + XmlWriter& endElement() { + newlineIfNecessary(); + m_indent = m_indent.substr( 0, m_indent.size()-2 ); + if( m_tagIsOpen ) { + stream() << "/>\n"; + m_tagIsOpen = false; + } + else { + stream() << m_indent << "\n"; + } + m_tags.pop_back(); + return *this; + } + + XmlWriter& writeAttribute( std::string const& name, std::string const& attribute ) { + if( !name.empty() && !attribute.empty() ) + stream() << " " << name << "=\"" << XmlEncode( attribute, XmlEncode::ForAttributes ) << "\""; + return *this; + } + + XmlWriter& writeAttribute( std::string const& name, bool attribute ) { + stream() << " " << name << "=\"" << ( attribute ? "true" : "false" ) << "\""; + return *this; + } + + template + XmlWriter& writeAttribute( std::string const& name, T const& attribute ) { + std::ostringstream oss; + oss << attribute; + return writeAttribute( name, oss.str() ); + } + + XmlWriter& writeText( std::string const& text, bool indent = true ) { + if( !text.empty() ){ + bool tagWasOpen = m_tagIsOpen; + ensureTagClosed(); + if( tagWasOpen && indent ) + stream() << m_indent; + stream() << XmlEncode( text ); + m_needsNewline = true; + } + return *this; + } + + XmlWriter& writeComment( std::string const& text ) { + ensureTagClosed(); + stream() << m_indent << ""; + m_needsNewline = true; + return *this; + } + + XmlWriter& writeBlankLine() { + ensureTagClosed(); + stream() << "\n"; + return *this; + } + + void setStream( std::ostream& os ) { + m_os = &os; + } + + private: + XmlWriter( XmlWriter const& ); + void operator=( XmlWriter const& ); + + std::ostream& stream() { + return *m_os; + } + + void ensureTagClosed() { + if( m_tagIsOpen ) { + stream() << ">\n"; + m_tagIsOpen = false; + } + } + + void newlineIfNecessary() { + if( m_needsNewline ) { + stream() << "\n"; + m_needsNewline = false; + } + } + + bool m_tagIsOpen; + bool m_needsNewline; + std::vector m_tags; + std::string m_indent; + std::ostream* m_os; + }; + +} +// #included from: catch_reenable_warnings.h + +#define TWOBLUECUBES_CATCH_REENABLE_WARNINGS_H_INCLUDED + +#ifdef __clang__ +# ifdef __ICC // icpc defines the __clang__ macro +# pragma warning(pop) +# else +# pragma clang diagnostic pop +# endif +#elif defined __GNUC__ +# pragma GCC diagnostic pop +#endif + + +namespace Catch { + class XmlReporter : public StreamingReporterBase { + public: + XmlReporter( ReporterConfig const& _config ) + : StreamingReporterBase( _config ), + m_sectionDepth( 0 ) + { + m_reporterPrefs.shouldRedirectStdOut = true; + } + + virtual ~XmlReporter() CATCH_OVERRIDE; + + static std::string getDescription() { + return "Reports test results as an XML document"; + } + + public: // StreamingReporterBase + + virtual void noMatchingTestCases( std::string const& s ) CATCH_OVERRIDE { + StreamingReporterBase::noMatchingTestCases( s ); + } + + virtual void testRunStarting( TestRunInfo const& testInfo ) CATCH_OVERRIDE { + StreamingReporterBase::testRunStarting( testInfo ); + m_xml.setStream( stream ); + m_xml.startElement( "Catch" ); + if( !m_config->name().empty() ) + m_xml.writeAttribute( "name", m_config->name() ); + } + + virtual void testGroupStarting( GroupInfo const& groupInfo ) CATCH_OVERRIDE { + StreamingReporterBase::testGroupStarting( groupInfo ); + m_xml.startElement( "Group" ) + .writeAttribute( "name", groupInfo.name ); + } + + virtual void testCaseStarting( TestCaseInfo const& testInfo ) CATCH_OVERRIDE { + StreamingReporterBase::testCaseStarting(testInfo); + m_xml.startElement( "TestCase" ).writeAttribute( "name", trim( testInfo.name ) ); + + if ( m_config->showDurations() == ShowDurations::Always ) + m_testCaseTimer.start(); + } + + virtual void sectionStarting( SectionInfo const& sectionInfo ) CATCH_OVERRIDE { + StreamingReporterBase::sectionStarting( sectionInfo ); + if( m_sectionDepth++ > 0 ) { + m_xml.startElement( "Section" ) + .writeAttribute( "name", trim( sectionInfo.name ) ) + .writeAttribute( "description", sectionInfo.description ); + } + } + + virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE { } + + virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE { + const AssertionResult& assertionResult = assertionStats.assertionResult; + + // Print any info messages in tags. + if( assertionStats.assertionResult.getResultType() != ResultWas::Ok ) { + for( std::vector::const_iterator it = assertionStats.infoMessages.begin(), itEnd = assertionStats.infoMessages.end(); + it != itEnd; + ++it ) { + if( it->type == ResultWas::Info ) { + m_xml.scopedElement( "Info" ) + .writeText( it->message ); + } else if ( it->type == ResultWas::Warning ) { + m_xml.scopedElement( "Warning" ) + .writeText( it->message ); + } + } + } + + // Drop out if result was successful but we're not printing them. + if( !m_config->includeSuccessfulResults() && isOk(assertionResult.getResultType()) ) + return true; + + // Print the expression if there is one. + if( assertionResult.hasExpression() ) { + m_xml.startElement( "Expression" ) + .writeAttribute( "success", assertionResult.succeeded() ) + .writeAttribute( "type", assertionResult.getTestMacroName() ) + .writeAttribute( "filename", assertionResult.getSourceInfo().file ) + .writeAttribute( "line", assertionResult.getSourceInfo().line ); + + m_xml.scopedElement( "Original" ) + .writeText( assertionResult.getExpression() ); + m_xml.scopedElement( "Expanded" ) + .writeText( assertionResult.getExpandedExpression() ); + } + + // And... Print a result applicable to each result type. + switch( assertionResult.getResultType() ) { + case ResultWas::ThrewException: + m_xml.scopedElement( "Exception" ) + .writeAttribute( "filename", assertionResult.getSourceInfo().file ) + .writeAttribute( "line", assertionResult.getSourceInfo().line ) + .writeText( assertionResult.getMessage() ); + break; + case ResultWas::FatalErrorCondition: + m_xml.scopedElement( "Fatal Error Condition" ) + .writeAttribute( "filename", assertionResult.getSourceInfo().file ) + .writeAttribute( "line", assertionResult.getSourceInfo().line ) + .writeText( assertionResult.getMessage() ); + break; + case ResultWas::Info: + m_xml.scopedElement( "Info" ) + .writeText( assertionResult.getMessage() ); + break; + case ResultWas::Warning: + // Warning will already have been written + break; + case ResultWas::ExplicitFailure: + m_xml.scopedElement( "Failure" ) + .writeText( assertionResult.getMessage() ); + break; + default: + break; + } + + if( assertionResult.hasExpression() ) + m_xml.endElement(); + + return true; + } + + virtual void sectionEnded( SectionStats const& sectionStats ) CATCH_OVERRIDE { + StreamingReporterBase::sectionEnded( sectionStats ); + if( --m_sectionDepth > 0 ) { + XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResults" ); + e.writeAttribute( "successes", sectionStats.assertions.passed ); + e.writeAttribute( "failures", sectionStats.assertions.failed ); + e.writeAttribute( "expectedFailures", sectionStats.assertions.failedButOk ); + + if ( m_config->showDurations() == ShowDurations::Always ) + e.writeAttribute( "durationInSeconds", sectionStats.durationInSeconds ); + + m_xml.endElement(); + } + } + + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE { + StreamingReporterBase::testCaseEnded( testCaseStats ); + XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResult" ); + e.writeAttribute( "success", testCaseStats.totals.assertions.allOk() ); + + if ( m_config->showDurations() == ShowDurations::Always ) + e.writeAttribute( "durationInSeconds", m_testCaseTimer.getElapsedSeconds() ); + + m_xml.endElement(); + } + + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE { + StreamingReporterBase::testGroupEnded( testGroupStats ); + // TODO: Check testGroupStats.aborting and act accordingly. + m_xml.scopedElement( "OverallResults" ) + .writeAttribute( "successes", testGroupStats.totals.assertions.passed ) + .writeAttribute( "failures", testGroupStats.totals.assertions.failed ) + .writeAttribute( "expectedFailures", testGroupStats.totals.assertions.failedButOk ); + m_xml.endElement(); + } + + virtual void testRunEnded( TestRunStats const& testRunStats ) CATCH_OVERRIDE { + StreamingReporterBase::testRunEnded( testRunStats ); + m_xml.scopedElement( "OverallResults" ) + .writeAttribute( "successes", testRunStats.totals.assertions.passed ) + .writeAttribute( "failures", testRunStats.totals.assertions.failed ) + .writeAttribute( "expectedFailures", testRunStats.totals.assertions.failedButOk ); + m_xml.endElement(); + } + + private: + Timer m_testCaseTimer; + XmlWriter m_xml; + int m_sectionDepth; + }; + + INTERNAL_CATCH_REGISTER_REPORTER( "xml", XmlReporter ) + +} // end namespace Catch + +// #included from: ../reporters/catch_reporter_junit.hpp +#define TWOBLUECUBES_CATCH_REPORTER_JUNIT_HPP_INCLUDED + +#include + +namespace Catch { + + class JunitReporter : public CumulativeReporterBase { + public: + JunitReporter( ReporterConfig const& _config ) + : CumulativeReporterBase( _config ), + xml( _config.stream() ) + { + m_reporterPrefs.shouldRedirectStdOut = true; + } + + virtual ~JunitReporter() CATCH_OVERRIDE; + + static std::string getDescription() { + return "Reports test results in an XML format that looks like Ant's junitreport target"; + } + + virtual void noMatchingTestCases( std::string const& /*spec*/ ) CATCH_OVERRIDE {} + + virtual void testRunStarting( TestRunInfo const& runInfo ) CATCH_OVERRIDE { + CumulativeReporterBase::testRunStarting( runInfo ); + xml.startElement( "testsuites" ); + } + + virtual void testGroupStarting( GroupInfo const& groupInfo ) CATCH_OVERRIDE { + suiteTimer.start(); + stdOutForSuite.str(""); + stdErrForSuite.str(""); + unexpectedExceptions = 0; + CumulativeReporterBase::testGroupStarting( groupInfo ); + } + + virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE { + if( assertionStats.assertionResult.getResultType() == ResultWas::ThrewException ) + unexpectedExceptions++; + return CumulativeReporterBase::assertionEnded( assertionStats ); + } + + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE { + stdOutForSuite << testCaseStats.stdOut; + stdErrForSuite << testCaseStats.stdErr; + CumulativeReporterBase::testCaseEnded( testCaseStats ); + } + + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE { + double suiteTime = suiteTimer.getElapsedSeconds(); + CumulativeReporterBase::testGroupEnded( testGroupStats ); + writeGroup( *m_testGroups.back(), suiteTime ); + } + + virtual void testRunEndedCumulative() CATCH_OVERRIDE { + xml.endElement(); + } + + void writeGroup( TestGroupNode const& groupNode, double suiteTime ) { + XmlWriter::ScopedElement e = xml.scopedElement( "testsuite" ); + TestGroupStats const& stats = groupNode.value; + xml.writeAttribute( "name", stats.groupInfo.name ); + xml.writeAttribute( "errors", unexpectedExceptions ); + xml.writeAttribute( "failures", stats.totals.assertions.failed-unexpectedExceptions ); + xml.writeAttribute( "tests", stats.totals.assertions.total() ); + xml.writeAttribute( "hostname", "tbd" ); // !TBD + if( m_config->showDurations() == ShowDurations::Never ) + xml.writeAttribute( "time", "" ); + else + xml.writeAttribute( "time", suiteTime ); + xml.writeAttribute( "timestamp", "tbd" ); // !TBD + + // Write test cases + for( TestGroupNode::ChildNodes::const_iterator + it = groupNode.children.begin(), itEnd = groupNode.children.end(); + it != itEnd; + ++it ) + writeTestCase( **it ); + + xml.scopedElement( "system-out" ).writeText( trim( stdOutForSuite.str() ), false ); + xml.scopedElement( "system-err" ).writeText( trim( stdErrForSuite.str() ), false ); + } + + void writeTestCase( TestCaseNode const& testCaseNode ) { + TestCaseStats const& stats = testCaseNode.value; + + // All test cases have exactly one section - which represents the + // test case itself. That section may have 0-n nested sections + assert( testCaseNode.children.size() == 1 ); + SectionNode const& rootSection = *testCaseNode.children.front(); + + std::string className = stats.testInfo.className; + + if( className.empty() ) { + if( rootSection.childSections.empty() ) + className = "global"; + } + writeSection( className, "", rootSection ); + } + + void writeSection( std::string const& className, + std::string const& rootName, + SectionNode const& sectionNode ) { + std::string name = trim( sectionNode.stats.sectionInfo.name ); + if( !rootName.empty() ) + name = rootName + "/" + name; + + if( !sectionNode.assertions.empty() || + !sectionNode.stdOut.empty() || + !sectionNode.stdErr.empty() ) { + XmlWriter::ScopedElement e = xml.scopedElement( "testcase" ); + if( className.empty() ) { + xml.writeAttribute( "classname", name ); + xml.writeAttribute( "name", "root" ); + } + else { + xml.writeAttribute( "classname", className ); + xml.writeAttribute( "name", name ); + } + xml.writeAttribute( "time", Catch::toString( sectionNode.stats.durationInSeconds ) ); + + writeAssertions( sectionNode ); + + if( !sectionNode.stdOut.empty() ) + xml.scopedElement( "system-out" ).writeText( trim( sectionNode.stdOut ), false ); + if( !sectionNode.stdErr.empty() ) + xml.scopedElement( "system-err" ).writeText( trim( sectionNode.stdErr ), false ); + } + for( SectionNode::ChildSections::const_iterator + it = sectionNode.childSections.begin(), + itEnd = sectionNode.childSections.end(); + it != itEnd; + ++it ) + if( className.empty() ) + writeSection( name, "", **it ); + else + writeSection( className, name, **it ); + } + + void writeAssertions( SectionNode const& sectionNode ) { + for( SectionNode::Assertions::const_iterator + it = sectionNode.assertions.begin(), itEnd = sectionNode.assertions.end(); + it != itEnd; + ++it ) + writeAssertion( *it ); + } + void writeAssertion( AssertionStats const& stats ) { + AssertionResult const& result = stats.assertionResult; + if( !result.isOk() ) { + std::string elementName; + switch( result.getResultType() ) { + case ResultWas::ThrewException: + case ResultWas::FatalErrorCondition: + elementName = "error"; + break; + case ResultWas::ExplicitFailure: + elementName = "failure"; + break; + case ResultWas::ExpressionFailed: + elementName = "failure"; + break; + case ResultWas::DidntThrowException: + elementName = "failure"; + break; + + // We should never see these here: + case ResultWas::Info: + case ResultWas::Warning: + case ResultWas::Ok: + case ResultWas::Unknown: + case ResultWas::FailureBit: + case ResultWas::Exception: + elementName = "internalError"; + break; + } + + XmlWriter::ScopedElement e = xml.scopedElement( elementName ); + + xml.writeAttribute( "message", result.getExpandedExpression() ); + xml.writeAttribute( "type", result.getTestMacroName() ); + + std::ostringstream oss; + if( !result.getMessage().empty() ) + oss << result.getMessage() << "\n"; + for( std::vector::const_iterator + it = stats.infoMessages.begin(), + itEnd = stats.infoMessages.end(); + it != itEnd; + ++it ) + if( it->type == ResultWas::Info ) + oss << it->message << "\n"; + + oss << "at " << result.getSourceInfo(); + xml.writeText( oss.str(), false ); + } + } + + XmlWriter xml; + Timer suiteTimer; + std::ostringstream stdOutForSuite; + std::ostringstream stdErrForSuite; + unsigned int unexpectedExceptions; + }; + + INTERNAL_CATCH_REGISTER_REPORTER( "junit", JunitReporter ) + +} // end namespace Catch + +// #included from: ../reporters/catch_reporter_console.hpp +#define TWOBLUECUBES_CATCH_REPORTER_CONSOLE_HPP_INCLUDED + +namespace Catch { + + struct ConsoleReporter : StreamingReporterBase { + ConsoleReporter( ReporterConfig const& _config ) + : StreamingReporterBase( _config ), + m_headerPrinted( false ) + {} + + virtual ~ConsoleReporter() CATCH_OVERRIDE; + static std::string getDescription() { + return "Reports test results as plain lines of text"; + } + + virtual void noMatchingTestCases( std::string const& spec ) CATCH_OVERRIDE { + stream << "No test cases matched '" << spec << "'" << std::endl; + } + + virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE { + } + + virtual bool assertionEnded( AssertionStats const& _assertionStats ) CATCH_OVERRIDE { + AssertionResult const& result = _assertionStats.assertionResult; + + bool printInfoMessages = true; + + // Drop out if result was successful and we're not printing those + if( !m_config->includeSuccessfulResults() && result.isOk() ) { + if( result.getResultType() != ResultWas::Warning ) + return false; + printInfoMessages = false; + } + + lazyPrint(); + + AssertionPrinter printer( stream, _assertionStats, printInfoMessages ); + printer.print(); + stream << std::endl; + return true; + } + + virtual void sectionStarting( SectionInfo const& _sectionInfo ) CATCH_OVERRIDE { + m_headerPrinted = false; + StreamingReporterBase::sectionStarting( _sectionInfo ); + } + virtual void sectionEnded( SectionStats const& _sectionStats ) CATCH_OVERRIDE { + if( _sectionStats.missingAssertions ) { + lazyPrint(); + Colour colour( Colour::ResultError ); + if( m_sectionStack.size() > 1 ) + stream << "\nNo assertions in section"; + else + stream << "\nNo assertions in test case"; + stream << " '" << _sectionStats.sectionInfo.name << "'\n" << std::endl; + } + if( m_headerPrinted ) { + if( m_config->showDurations() == ShowDurations::Always ) + stream << "Completed in " << _sectionStats.durationInSeconds << "s" << std::endl; + m_headerPrinted = false; + } + else { + if( m_config->showDurations() == ShowDurations::Always ) + stream << _sectionStats.sectionInfo.name << " completed in " << _sectionStats.durationInSeconds << "s" << std::endl; + } + StreamingReporterBase::sectionEnded( _sectionStats ); + } + + virtual void testCaseEnded( TestCaseStats const& _testCaseStats ) CATCH_OVERRIDE { + StreamingReporterBase::testCaseEnded( _testCaseStats ); + m_headerPrinted = false; + } + virtual void testGroupEnded( TestGroupStats const& _testGroupStats ) CATCH_OVERRIDE { + if( currentGroupInfo.used ) { + printSummaryDivider(); + stream << "Summary for group '" << _testGroupStats.groupInfo.name << "':\n"; + printTotals( _testGroupStats.totals ); + stream << "\n" << std::endl; + } + StreamingReporterBase::testGroupEnded( _testGroupStats ); + } + virtual void testRunEnded( TestRunStats const& _testRunStats ) CATCH_OVERRIDE { + printTotalsDivider( _testRunStats.totals ); + printTotals( _testRunStats.totals ); + stream << std::endl; + StreamingReporterBase::testRunEnded( _testRunStats ); + } + + private: + + class AssertionPrinter { + void operator= ( AssertionPrinter const& ); + public: + AssertionPrinter( std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages ) + : stream( _stream ), + stats( _stats ), + result( _stats.assertionResult ), + colour( Colour::None ), + message( result.getMessage() ), + messages( _stats.infoMessages ), + printInfoMessages( _printInfoMessages ) + { + switch( result.getResultType() ) { + case ResultWas::Ok: + colour = Colour::Success; + passOrFail = "PASSED"; + //if( result.hasMessage() ) + if( _stats.infoMessages.size() == 1 ) + messageLabel = "with message"; + if( _stats.infoMessages.size() > 1 ) + messageLabel = "with messages"; + break; + case ResultWas::ExpressionFailed: + if( result.isOk() ) { + colour = Colour::Success; + passOrFail = "FAILED - but was ok"; + } + else { + colour = Colour::Error; + passOrFail = "FAILED"; + } + if( _stats.infoMessages.size() == 1 ) + messageLabel = "with message"; + if( _stats.infoMessages.size() > 1 ) + messageLabel = "with messages"; + break; + case ResultWas::ThrewException: + colour = Colour::Error; + passOrFail = "FAILED"; + messageLabel = "due to unexpected exception with message"; + break; + case ResultWas::FatalErrorCondition: + colour = Colour::Error; + passOrFail = "FAILED"; + messageLabel = "due to a fatal error condition"; + break; + case ResultWas::DidntThrowException: + colour = Colour::Error; + passOrFail = "FAILED"; + messageLabel = "because no exception was thrown where one was expected"; + break; + case ResultWas::Info: + messageLabel = "info"; + break; + case ResultWas::Warning: + messageLabel = "warning"; + break; + case ResultWas::ExplicitFailure: + passOrFail = "FAILED"; + colour = Colour::Error; + if( _stats.infoMessages.size() == 1 ) + messageLabel = "explicitly with message"; + if( _stats.infoMessages.size() > 1 ) + messageLabel = "explicitly with messages"; + break; + // These cases are here to prevent compiler warnings + case ResultWas::Unknown: + case ResultWas::FailureBit: + case ResultWas::Exception: + passOrFail = "** internal error **"; + colour = Colour::Error; + break; + } + } + + void print() const { + printSourceInfo(); + if( stats.totals.assertions.total() > 0 ) { + if( result.isOk() ) + stream << "\n"; + printResultType(); + printOriginalExpression(); + printReconstructedExpression(); + } + else { + stream << "\n"; + } + printMessage(); + } + + private: + void printResultType() const { + if( !passOrFail.empty() ) { + Colour colourGuard( colour ); + stream << passOrFail << ":\n"; + } + } + void printOriginalExpression() const { + if( result.hasExpression() ) { + Colour colourGuard( Colour::OriginalExpression ); + stream << " "; + stream << result.getExpressionInMacro(); + stream << "\n"; + } + } + void printReconstructedExpression() const { + if( result.hasExpandedExpression() ) { + stream << "with expansion:\n"; + Colour colourGuard( Colour::ReconstructedExpression ); + stream << Text( result.getExpandedExpression(), TextAttributes().setIndent(2) ) << "\n"; + } + } + void printMessage() const { + if( !messageLabel.empty() ) + stream << messageLabel << ":" << "\n"; + for( std::vector::const_iterator it = messages.begin(), itEnd = messages.end(); + it != itEnd; + ++it ) { + // If this assertion is a warning ignore any INFO messages + if( printInfoMessages || it->type != ResultWas::Info ) + stream << Text( it->message, TextAttributes().setIndent(2) ) << "\n"; + } + } + void printSourceInfo() const { + Colour colourGuard( Colour::FileName ); + stream << result.getSourceInfo() << ": "; + } + + std::ostream& stream; + AssertionStats const& stats; + AssertionResult const& result; + Colour::Code colour; + std::string passOrFail; + std::string messageLabel; + std::string message; + std::vector messages; + bool printInfoMessages; + }; + + void lazyPrint() { + + if( !currentTestRunInfo.used ) + lazyPrintRunInfo(); + if( !currentGroupInfo.used ) + lazyPrintGroupInfo(); + + if( !m_headerPrinted ) { + printTestCaseAndSectionHeader(); + m_headerPrinted = true; + } + } + void lazyPrintRunInfo() { + stream << "\n" << getLineOfChars<'~'>() << "\n"; + Colour colour( Colour::SecondaryText ); + stream << currentTestRunInfo->name + << " is a Catch v" << libraryVersion << " host application.\n" + << "Run with -? for options\n\n"; + + if( m_config->rngSeed() != 0 ) + stream << "Randomness seeded to: " << m_config->rngSeed() << "\n\n"; + + currentTestRunInfo.used = true; + } + void lazyPrintGroupInfo() { + if( !currentGroupInfo->name.empty() && currentGroupInfo->groupsCounts > 1 ) { + printClosedHeader( "Group: " + currentGroupInfo->name ); + currentGroupInfo.used = true; + } + } + void printTestCaseAndSectionHeader() { + assert( !m_sectionStack.empty() ); + printOpenHeader( currentTestCaseInfo->name ); + + if( m_sectionStack.size() > 1 ) { + Colour colourGuard( Colour::Headers ); + + std::vector::const_iterator + it = m_sectionStack.begin()+1, // Skip first section (test case) + itEnd = m_sectionStack.end(); + for( ; it != itEnd; ++it ) + printHeaderString( it->name, 2 ); + } + + SourceLineInfo lineInfo = m_sectionStack.front().lineInfo; + + if( !lineInfo.empty() ){ + stream << getLineOfChars<'-'>() << "\n"; + Colour colourGuard( Colour::FileName ); + stream << lineInfo << "\n"; + } + stream << getLineOfChars<'.'>() << "\n" << std::endl; + } + + void printClosedHeader( std::string const& _name ) { + printOpenHeader( _name ); + stream << getLineOfChars<'.'>() << "\n"; + } + void printOpenHeader( std::string const& _name ) { + stream << getLineOfChars<'-'>() << "\n"; + { + Colour colourGuard( Colour::Headers ); + printHeaderString( _name ); + } + } + + // if string has a : in first line will set indent to follow it on + // subsequent lines + void printHeaderString( std::string const& _string, std::size_t indent = 0 ) { + std::size_t i = _string.find( ": " ); + if( i != std::string::npos ) + i+=2; + else + i = 0; + stream << Text( _string, TextAttributes() + .setIndent( indent+i) + .setInitialIndent( indent ) ) << "\n"; + } + + struct SummaryColumn { + + SummaryColumn( std::string const& _label, Colour::Code _colour ) + : label( _label ), + colour( _colour ) + {} + SummaryColumn addRow( std::size_t count ) { + std::ostringstream oss; + oss << count; + std::string row = oss.str(); + for( std::vector::iterator it = rows.begin(); it != rows.end(); ++it ) { + while( it->size() < row.size() ) + *it = " " + *it; + while( it->size() > row.size() ) + row = " " + row; + } + rows.push_back( row ); + return *this; + } + + std::string label; + Colour::Code colour; + std::vector rows; + + }; + + void printTotals( Totals const& totals ) { + if( totals.testCases.total() == 0 ) { + stream << Colour( Colour::Warning ) << "No tests ran\n"; + } + else if( totals.assertions.total() > 0 && totals.assertions.allPassed() ) { + stream << Colour( Colour::ResultSuccess ) << "All tests passed"; + stream << " (" + << pluralise( totals.assertions.passed, "assertion" ) << " in " + << pluralise( totals.testCases.passed, "test case" ) << ")" + << "\n"; + } + else { + + std::vector columns; + columns.push_back( SummaryColumn( "", Colour::None ) + .addRow( totals.testCases.total() ) + .addRow( totals.assertions.total() ) ); + columns.push_back( SummaryColumn( "passed", Colour::Success ) + .addRow( totals.testCases.passed ) + .addRow( totals.assertions.passed ) ); + columns.push_back( SummaryColumn( "failed", Colour::ResultError ) + .addRow( totals.testCases.failed ) + .addRow( totals.assertions.failed ) ); + columns.push_back( SummaryColumn( "failed as expected", Colour::ResultExpectedFailure ) + .addRow( totals.testCases.failedButOk ) + .addRow( totals.assertions.failedButOk ) ); + + printSummaryRow( "test cases", columns, 0 ); + printSummaryRow( "assertions", columns, 1 ); + } + } + void printSummaryRow( std::string const& label, std::vector const& cols, std::size_t row ) { + for( std::vector::const_iterator it = cols.begin(); it != cols.end(); ++it ) { + std::string value = it->rows[row]; + if( it->label.empty() ) { + stream << label << ": "; + if( value != "0" ) + stream << value; + else + stream << Colour( Colour::Warning ) << "- none -"; + } + else if( value != "0" ) { + stream << Colour( Colour::LightGrey ) << " | "; + stream << Colour( it->colour ) + << value << " " << it->label; + } + } + stream << "\n"; + } + + static std::size_t makeRatio( std::size_t number, std::size_t total ) { + std::size_t ratio = total > 0 ? CATCH_CONFIG_CONSOLE_WIDTH * number/ total : 0; + return ( ratio == 0 && number > 0 ) ? 1 : ratio; + } + static std::size_t& findMax( std::size_t& i, std::size_t& j, std::size_t& k ) { + if( i > j && i > k ) + return i; + else if( j > k ) + return j; + else + return k; + } + + void printTotalsDivider( Totals const& totals ) { + if( totals.testCases.total() > 0 ) { + std::size_t failedRatio = makeRatio( totals.testCases.failed, totals.testCases.total() ); + std::size_t failedButOkRatio = makeRatio( totals.testCases.failedButOk, totals.testCases.total() ); + std::size_t passedRatio = makeRatio( totals.testCases.passed, totals.testCases.total() ); + while( failedRatio + failedButOkRatio + passedRatio < CATCH_CONFIG_CONSOLE_WIDTH-1 ) + findMax( failedRatio, failedButOkRatio, passedRatio )++; + while( failedRatio + failedButOkRatio + passedRatio > CATCH_CONFIG_CONSOLE_WIDTH-1 ) + findMax( failedRatio, failedButOkRatio, passedRatio )--; + + stream << Colour( Colour::Error ) << std::string( failedRatio, '=' ); + stream << Colour( Colour::ResultExpectedFailure ) << std::string( failedButOkRatio, '=' ); + if( totals.testCases.allPassed() ) + stream << Colour( Colour::ResultSuccess ) << std::string( passedRatio, '=' ); + else + stream << Colour( Colour::Success ) << std::string( passedRatio, '=' ); + } + else { + stream << Colour( Colour::Warning ) << std::string( CATCH_CONFIG_CONSOLE_WIDTH-1, '=' ); + } + stream << "\n"; + } + void printSummaryDivider() { + stream << getLineOfChars<'-'>() << "\n"; + } + + private: + bool m_headerPrinted; + }; + + INTERNAL_CATCH_REGISTER_REPORTER( "console", ConsoleReporter ) + +} // end namespace Catch + +// #included from: ../reporters/catch_reporter_compact.hpp +#define TWOBLUECUBES_CATCH_REPORTER_COMPACT_HPP_INCLUDED + +namespace Catch { + + struct CompactReporter : StreamingReporterBase { + + CompactReporter( ReporterConfig const& _config ) + : StreamingReporterBase( _config ) + {} + + virtual ~CompactReporter(); + + static std::string getDescription() { + return "Reports test results on a single line, suitable for IDEs"; + } + + virtual ReporterPreferences getPreferences() const { + ReporterPreferences prefs; + prefs.shouldRedirectStdOut = false; + return prefs; + } + + virtual void noMatchingTestCases( std::string const& spec ) { + stream << "No test cases matched '" << spec << "'" << std::endl; + } + + virtual void assertionStarting( AssertionInfo const& ) { + } + + virtual bool assertionEnded( AssertionStats const& _assertionStats ) { + AssertionResult const& result = _assertionStats.assertionResult; + + bool printInfoMessages = true; + + // Drop out if result was successful and we're not printing those + if( !m_config->includeSuccessfulResults() && result.isOk() ) { + if( result.getResultType() != ResultWas::Warning ) + return false; + printInfoMessages = false; + } + + AssertionPrinter printer( stream, _assertionStats, printInfoMessages ); + printer.print(); + + stream << std::endl; + return true; + } + + virtual void testRunEnded( TestRunStats const& _testRunStats ) { + printTotals( _testRunStats.totals ); + stream << "\n" << std::endl; + StreamingReporterBase::testRunEnded( _testRunStats ); + } + + private: + class AssertionPrinter { + void operator= ( AssertionPrinter const& ); + public: + AssertionPrinter( std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages ) + : stream( _stream ) + , stats( _stats ) + , result( _stats.assertionResult ) + , messages( _stats.infoMessages ) + , itMessage( _stats.infoMessages.begin() ) + , printInfoMessages( _printInfoMessages ) + {} + + void print() { + printSourceInfo(); + + itMessage = messages.begin(); + + switch( result.getResultType() ) { + case ResultWas::Ok: + printResultType( Colour::ResultSuccess, passedString() ); + printOriginalExpression(); + printReconstructedExpression(); + if ( ! result.hasExpression() ) + printRemainingMessages( Colour::None ); + else + printRemainingMessages(); + break; + case ResultWas::ExpressionFailed: + if( result.isOk() ) + printResultType( Colour::ResultSuccess, failedString() + std::string( " - but was ok" ) ); + else + printResultType( Colour::Error, failedString() ); + printOriginalExpression(); + printReconstructedExpression(); + printRemainingMessages(); + break; + case ResultWas::ThrewException: + printResultType( Colour::Error, failedString() ); + printIssue( "unexpected exception with message:" ); + printMessage(); + printExpressionWas(); + printRemainingMessages(); + break; + case ResultWas::FatalErrorCondition: + printResultType( Colour::Error, failedString() ); + printIssue( "fatal error condition with message:" ); + printMessage(); + printExpressionWas(); + printRemainingMessages(); + break; + case ResultWas::DidntThrowException: + printResultType( Colour::Error, failedString() ); + printIssue( "expected exception, got none" ); + printExpressionWas(); + printRemainingMessages(); + break; + case ResultWas::Info: + printResultType( Colour::None, "info" ); + printMessage(); + printRemainingMessages(); + break; + case ResultWas::Warning: + printResultType( Colour::None, "warning" ); + printMessage(); + printRemainingMessages(); + break; + case ResultWas::ExplicitFailure: + printResultType( Colour::Error, failedString() ); + printIssue( "explicitly" ); + printRemainingMessages( Colour::None ); + break; + // These cases are here to prevent compiler warnings + case ResultWas::Unknown: + case ResultWas::FailureBit: + case ResultWas::Exception: + printResultType( Colour::Error, "** internal error **" ); + break; + } + } + + private: + // Colour::LightGrey + + static Colour::Code dimColour() { return Colour::FileName; } + +#ifdef CATCH_PLATFORM_MAC + static const char* failedString() { return "FAILED"; } + static const char* passedString() { return "PASSED"; } +#else + static const char* failedString() { return "failed"; } + static const char* passedString() { return "passed"; } +#endif + + void printSourceInfo() const { + Colour colourGuard( Colour::FileName ); + stream << result.getSourceInfo() << ":"; + } + + void printResultType( Colour::Code colour, std::string passOrFail ) const { + if( !passOrFail.empty() ) { + { + Colour colourGuard( colour ); + stream << " " << passOrFail; + } + stream << ":"; + } + } + + void printIssue( std::string issue ) const { + stream << " " << issue; + } + + void printExpressionWas() { + if( result.hasExpression() ) { + stream << ";"; + { + Colour colour( dimColour() ); + stream << " expression was:"; + } + printOriginalExpression(); + } + } + + void printOriginalExpression() const { + if( result.hasExpression() ) { + stream << " " << result.getExpression(); + } + } + + void printReconstructedExpression() const { + if( result.hasExpandedExpression() ) { + { + Colour colour( dimColour() ); + stream << " for: "; + } + stream << result.getExpandedExpression(); + } + } + + void printMessage() { + if ( itMessage != messages.end() ) { + stream << " '" << itMessage->message << "'"; + ++itMessage; + } + } + + void printRemainingMessages( Colour::Code colour = dimColour() ) { + if ( itMessage == messages.end() ) + return; + + // using messages.end() directly yields compilation error: + std::vector::const_iterator itEnd = messages.end(); + const std::size_t N = static_cast( std::distance( itMessage, itEnd ) ); + + { + Colour colourGuard( colour ); + stream << " with " << pluralise( N, "message" ) << ":"; + } + + for(; itMessage != itEnd; ) { + // If this assertion is a warning ignore any INFO messages + if( printInfoMessages || itMessage->type != ResultWas::Info ) { + stream << " '" << itMessage->message << "'"; + if ( ++itMessage != itEnd ) { + Colour colourGuard( dimColour() ); + stream << " and"; + } + } + } + } + + private: + std::ostream& stream; + AssertionStats const& stats; + AssertionResult const& result; + std::vector messages; + std::vector::const_iterator itMessage; + bool printInfoMessages; + }; + + // Colour, message variants: + // - white: No tests ran. + // - red: Failed [both/all] N test cases, failed [both/all] M assertions. + // - white: Passed [both/all] N test cases (no assertions). + // - red: Failed N tests cases, failed M assertions. + // - green: Passed [both/all] N tests cases with M assertions. + + std::string bothOrAll( std::size_t count ) const { + return count == 1 ? "" : count == 2 ? "both " : "all " ; + } + + void printTotals( const Totals& totals ) const { + if( totals.testCases.total() == 0 ) { + stream << "No tests ran."; + } + else if( totals.testCases.failed == totals.testCases.total() ) { + Colour colour( Colour::ResultError ); + const std::string qualify_assertions_failed = + totals.assertions.failed == totals.assertions.total() ? + bothOrAll( totals.assertions.failed ) : ""; + stream << + "Failed " << bothOrAll( totals.testCases.failed ) + << pluralise( totals.testCases.failed, "test case" ) << ", " + "failed " << qualify_assertions_failed << + pluralise( totals.assertions.failed, "assertion" ) << "."; + } + else if( totals.assertions.total() == 0 ) { + stream << + "Passed " << bothOrAll( totals.testCases.total() ) + << pluralise( totals.testCases.total(), "test case" ) + << " (no assertions)."; + } + else if( totals.assertions.failed ) { + Colour colour( Colour::ResultError ); + stream << + "Failed " << pluralise( totals.testCases.failed, "test case" ) << ", " + "failed " << pluralise( totals.assertions.failed, "assertion" ) << "."; + } + else { + Colour colour( Colour::ResultSuccess ); + stream << + "Passed " << bothOrAll( totals.testCases.passed ) + << pluralise( totals.testCases.passed, "test case" ) << + " with " << pluralise( totals.assertions.passed, "assertion" ) << "."; + } + } + }; + + INTERNAL_CATCH_REGISTER_REPORTER( "compact", CompactReporter ) + +} // end namespace Catch + +namespace Catch { + // These are all here to avoid warnings about not having any out of line + // virtual methods + NonCopyable::~NonCopyable() {} + IShared::~IShared() {} + IStream::~IStream() CATCH_NOEXCEPT {} + FileStream::~FileStream() CATCH_NOEXCEPT {} + CoutStream::~CoutStream() CATCH_NOEXCEPT {} + DebugOutStream::~DebugOutStream() CATCH_NOEXCEPT {} + StreamBufBase::~StreamBufBase() CATCH_NOEXCEPT {} + IContext::~IContext() {} + IResultCapture::~IResultCapture() {} + ITestCase::~ITestCase() {} + ITestCaseRegistry::~ITestCaseRegistry() {} + IRegistryHub::~IRegistryHub() {} + IMutableRegistryHub::~IMutableRegistryHub() {} + IExceptionTranslator::~IExceptionTranslator() {} + IExceptionTranslatorRegistry::~IExceptionTranslatorRegistry() {} + IReporter::~IReporter() {} + IReporterFactory::~IReporterFactory() {} + IReporterRegistry::~IReporterRegistry() {} + IStreamingReporter::~IStreamingReporter() {} + AssertionStats::~AssertionStats() {} + SectionStats::~SectionStats() {} + TestCaseStats::~TestCaseStats() {} + TestGroupStats::~TestGroupStats() {} + TestRunStats::~TestRunStats() {} + CumulativeReporterBase::SectionNode::~SectionNode() {} + CumulativeReporterBase::~CumulativeReporterBase() {} + + StreamingReporterBase::~StreamingReporterBase() {} + ConsoleReporter::~ConsoleReporter() {} + CompactReporter::~CompactReporter() {} + IRunner::~IRunner() {} + IMutableContext::~IMutableContext() {} + IConfig::~IConfig() {} + XmlReporter::~XmlReporter() {} + JunitReporter::~JunitReporter() {} + TestRegistry::~TestRegistry() {} + FreeFunctionTestCase::~FreeFunctionTestCase() {} + IGeneratorInfo::~IGeneratorInfo() {} + IGeneratorsForTest::~IGeneratorsForTest() {} + WildcardPattern::~WildcardPattern() {} + TestSpec::Pattern::~Pattern() {} + TestSpec::NamePattern::~NamePattern() {} + TestSpec::TagPattern::~TagPattern() {} + TestSpec::ExcludedPattern::~ExcludedPattern() {} + + Matchers::Impl::StdString::Equals::~Equals() {} + Matchers::Impl::StdString::Contains::~Contains() {} + Matchers::Impl::StdString::StartsWith::~StartsWith() {} + Matchers::Impl::StdString::EndsWith::~EndsWith() {} + + void Config::dummy() {} + + namespace TestCaseTracking { + ITracker::~ITracker() {} + TrackerBase::~TrackerBase() {} + SectionTracker::~SectionTracker() {} + IndexTracker::~IndexTracker() {} + } +} + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +#endif + +#ifdef CATCH_CONFIG_MAIN +// #included from: internal/catch_default_main.hpp +#define TWOBLUECUBES_CATCH_DEFAULT_MAIN_HPP_INCLUDED + +#ifndef __OBJC__ + +// Standard C/C++ main entry point +int main (int argc, char * argv[]) { + return Catch::Session().run( argc, argv ); +} + +#else // __OBJC__ + +// Objective-C entry point +int main (int argc, char * const argv[]) { +#if !CATCH_ARC_ENABLED + NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; +#endif + + Catch::registerTestMethods(); + int result = Catch::Session().run( argc, (char* const*)argv ); + +#if !CATCH_ARC_ENABLED + [pool drain]; +#endif + + return result; +} + +#endif // __OBJC__ + +#endif + +#ifdef CLARA_CONFIG_MAIN_NOT_DEFINED +# undef CLARA_CONFIG_MAIN +#endif + +////// + +// If this config identifier is defined then all CATCH macros are prefixed with CATCH_ +#ifdef CATCH_CONFIG_PREFIX_ALL + +#define CATCH_REQUIRE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE" ) +#define CATCH_REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, "CATCH_REQUIRE_FALSE" ) + +#define CATCH_REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, "", "CATCH_REQUIRE_THROWS" ) +#define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THROWS_AS" ) +#define CATCH_REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, matcher, "CATCH_REQUIRE_THROWS_WITH" ) +#define CATCH_REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_NOTHROW" ) + +#define CATCH_CHECK( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK" ) +#define CATCH_CHECK_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, "CATCH_CHECK_FALSE" ) +#define CATCH_CHECKED_IF( expr ) INTERNAL_CATCH_IF( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECKED_IF" ) +#define CATCH_CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECKED_ELSE" ) +#define CATCH_CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, "CATCH_CHECK_NOFAIL" ) + +#define CATCH_CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THROWS" ) +#define CATCH_CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THROWS_AS" ) +#define CATCH_CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, matcher, "CATCH_CHECK_THROWS_WITH" ) +#define CATCH_CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_NOTHROW" ) + +#define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THAT" ) +#define CATCH_REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THAT" ) + +#define CATCH_INFO( msg ) INTERNAL_CATCH_INFO( msg, "CATCH_INFO" ) +#define CATCH_WARN( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, "CATCH_WARN", msg ) +#define CATCH_SCOPED_INFO( msg ) INTERNAL_CATCH_INFO( msg, "CATCH_INFO" ) +#define CATCH_CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CATCH_CAPTURE" ) +#define CATCH_SCOPED_CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CATCH_CAPTURE" ) + +#ifdef CATCH_CONFIG_VARIADIC_MACROS + #define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ ) + #define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ ) + #define CATCH_METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ ) + #define CATCH_REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ ) + #define CATCH_SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) + #define CATCH_FAIL( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "CATCH_FAIL", __VA_ARGS__ ) + #define CATCH_SUCCEED( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "CATCH_SUCCEED", __VA_ARGS__ ) +#else + #define CATCH_TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description ) + #define CATCH_TEST_CASE_METHOD( className, name, description ) INTERNAL_CATCH_TEST_CASE_METHOD( className, name, description ) + #define CATCH_METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description ) + #define CATCH_REGISTER_TEST_CASE( function, name, description ) INTERNAL_CATCH_REGISTER_TESTCASE( function, name, description ) + #define CATCH_SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description ) + #define CATCH_FAIL( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "CATCH_FAIL", msg ) + #define CATCH_SUCCEED( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "CATCH_SUCCEED", msg ) +#endif +#define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE( "", "" ) + +#define CATCH_REGISTER_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) +#define CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) + +#define CATCH_GENERATE( expr) INTERNAL_CATCH_GENERATE( expr ) + +// "BDD-style" convenience wrappers +#ifdef CATCH_CONFIG_VARIADIC_MACROS +#define CATCH_SCENARIO( ... ) CATCH_TEST_CASE( "Scenario: " __VA_ARGS__ ) +#define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ ) +#else +#define CATCH_SCENARIO( name, tags ) CATCH_TEST_CASE( "Scenario: " name, tags ) +#define CATCH_SCENARIO_METHOD( className, name, tags ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " name, tags ) +#endif +#define CATCH_GIVEN( desc ) CATCH_SECTION( std::string( "Given: ") + desc, "" ) +#define CATCH_WHEN( desc ) CATCH_SECTION( std::string( " When: ") + desc, "" ) +#define CATCH_AND_WHEN( desc ) CATCH_SECTION( std::string( " And: ") + desc, "" ) +#define CATCH_THEN( desc ) CATCH_SECTION( std::string( " Then: ") + desc, "" ) +#define CATCH_AND_THEN( desc ) CATCH_SECTION( std::string( " And: ") + desc, "" ) + +// If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required +#else + +#define REQUIRE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal, "REQUIRE" ) +#define REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, "REQUIRE_FALSE" ) + +#define REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, "", "REQUIRE_THROWS" ) +#define REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::Normal, "REQUIRE_THROWS_AS" ) +#define REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, matcher, "REQUIRE_THROWS_WITH" ) +#define REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::Normal, "REQUIRE_NOTHROW" ) + +#define CHECK( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK" ) +#define CHECK_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, "CHECK_FALSE" ) +#define CHECKED_IF( expr ) INTERNAL_CATCH_IF( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECKED_IF" ) +#define CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECKED_ELSE" ) +#define CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, "CHECK_NOFAIL" ) + +#define CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, "", "CHECK_THROWS" ) +#define CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THROWS_AS" ) +#define CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, matcher, "CHECK_THROWS_WITH" ) +#define CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK_NOTHROW" ) + +#define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THAT" ) +#define REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::Normal, "REQUIRE_THAT" ) + +#define INFO( msg ) INTERNAL_CATCH_INFO( msg, "INFO" ) +#define WARN( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, "WARN", msg ) +#define SCOPED_INFO( msg ) INTERNAL_CATCH_INFO( msg, "INFO" ) +#define CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CAPTURE" ) +#define SCOPED_CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CAPTURE" ) + +#ifdef CATCH_CONFIG_VARIADIC_MACROS + #define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ ) + #define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ ) + #define METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ ) + #define REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ ) + #define SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) + #define FAIL( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "FAIL", __VA_ARGS__ ) + #define SUCCEED( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "SUCCEED", __VA_ARGS__ ) +#else + #define TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description ) + #define TEST_CASE_METHOD( className, name, description ) INTERNAL_CATCH_TEST_CASE_METHOD( className, name, description ) + #define METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description ) + #define REGISTER_TEST_CASE( method, name, description ) INTERNAL_CATCH_REGISTER_TESTCASE( method, name, description ) + #define SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description ) + #define FAIL( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "FAIL", msg ) + #define SUCCEED( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "SUCCEED", msg ) +#endif +#define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE( "", "" ) + +#define REGISTER_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) +#define REGISTER_LEGACY_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) + +#define GENERATE( expr) INTERNAL_CATCH_GENERATE( expr ) + +#endif + +#define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) + +// "BDD-style" convenience wrappers +#ifdef CATCH_CONFIG_VARIADIC_MACROS +#define SCENARIO( ... ) TEST_CASE( "Scenario: " __VA_ARGS__ ) +#define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ ) +#else +#define SCENARIO( name, tags ) TEST_CASE( "Scenario: " name, tags ) +#define SCENARIO_METHOD( className, name, tags ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " name, tags ) +#endif +#define GIVEN( desc ) SECTION( std::string(" Given: ") + desc, "" ) +#define WHEN( desc ) SECTION( std::string(" When: ") + desc, "" ) +#define AND_WHEN( desc ) SECTION( std::string("And when: ") + desc, "" ) +#define THEN( desc ) SECTION( std::string(" Then: ") + desc, "" ) +#define AND_THEN( desc ) SECTION( std::string(" And: ") + desc, "" ) + +using Catch::Detail::Approx; + +#endif // TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED + diff --git a/CUDA_BasicMatrixMultiplication/libwb/vendor/json11.cpp b/CUDA_BasicMatrixMultiplication/libwb/vendor/json11.cpp new file mode 100644 index 0000000..f401c26 --- /dev/null +++ b/CUDA_BasicMatrixMultiplication/libwb/vendor/json11.cpp @@ -0,0 +1,1013 @@ +/* Copyright (c) 2013 Dropbox, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy + * of this software and associated documentation files (the "Software"), to + * deal + * in the Software without restriction, including without limitation the + * rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN + * THE SOFTWARE. + */ + +#include "json11.hpp" +#include +#include +#include +#include +#include +#include + +namespace json11 { + +static const int max_depth = 200; + +using std::string; +using std::vector; +using std::map; +using std::make_shared; +using std::initializer_list; +using std::move; + +/* * * * * * * * * * * * * * * * * * * * + * Serialization + */ + +static void dump(std::nullptr_t, string &out) { + out += "null"; +} + +static void dump(double value, string &out) { + if (std::isfinite(value)) { + char buf[32]; +//PMO +#ifndef _MSC_VER + snprintf(buf, sizeof buf, "%.17g", value); +#else + _snprintf_s(buf, sizeof buf, "%.17g", value); +#endif + out += buf; + } else { + out += "null"; + } +} + +static void dump(int value, string &out) { + char buf[32]; +//PMO +#ifndef _MSC_VER + snprintf(buf, sizeof buf, "%d", value); +#else + _snprintf_s(buf, sizeof buf, "%d", value); +#endif + out += buf; +} + +static void dump(int64_t value, string &out) { + char buf[64]; +//PMO +#ifndef _MSC_VER + snprintf(buf, sizeof buf, "%" PRId64, value); +#else + _snprintf_s(buf, sizeof buf, "%" PRId64, value); +#endif + out += buf; +} + +static void dump(uint64_t value, string &out) { + char buf[128]; +//PMO +#ifndef _MSC_VER + snprintf(buf, sizeof buf, "%" PRIu64, value); +#else + _snprintf_s(buf, sizeof buf, "%" PRIu64, value); +#endif + out += buf; +} + +static void dump(bool value, string &out) { + out += value ? "true" : "false"; +} + +static void dump(const string &value, string &out) { + out += '"'; + for (size_t i = 0; i < value.length(); i++) { + const char ch = value[i]; + if (ch == '\\') { + out += "\\\\"; + } else if (ch == '"') { + out += "\\\""; + } else if (ch == '\b') { + out += "\\b"; + } else if (ch == '\f') { + out += "\\f"; + } else if (ch == '\n') { + out += "\\n"; + } else if (ch == '\r') { + out += "\\r"; + } else if (ch == '\t') { + out += "\\t"; + } else if (static_cast(ch) <= 0x1f) { + char buf[8]; +//PMO +#ifndef _MSC_VER + snprintf(buf, sizeof buf, "\\u%04x", ch); +#else + _snprintf_s(buf, sizeof buf, "\\u%04x", ch); +#endif + out += buf; + } else if (static_cast(ch) == 0xe2 && + static_cast(value[i + 1]) == 0x80 && + static_cast(value[i + 2]) == 0xa8) { + out += "\\u2028"; + i += 2; + } else if (static_cast(ch) == 0xe2 && + static_cast(value[i + 1]) == 0x80 && + static_cast(value[i + 2]) == 0xa9) { + out += "\\u2029"; + i += 2; + } else { + out += ch; + } + } + out += '"'; +} + +static void dump(const Json::array &values, string &out) { + bool first = true; + out += "["; + for (const auto &value : values) { + if (!first) + out += ", "; + value.dump(out); + first = false; + } + out += "]"; +} + +static void dump(const Json::object &values, string &out) { + bool first = true; + out += "{"; + for (const auto &kv : values) { + if (!first) + out += ", "; + dump(kv.first, out); + out += ": "; + kv.second.dump(out); + first = false; + } + out += "}"; +} + +void Json::dump(string &out) const { + m_ptr->dump(out); +} + +/* * * * * * * * * * * * * * * * * * * * + * Value wrappers + */ + +template +class Value : public JsonValue { +protected: + // Constructors + explicit Value(const T &value) : m_value(value) { + } + explicit Value(T &&value) : m_value(move(value)) { + } + + // Get type tag + Json::Type type() const override { + return tag; + } + + // Comparisons + bool equals(const JsonValue *other) const override { + return m_value == static_cast *>(other)->m_value; + } + bool less(const JsonValue *other) const override { + return m_value < static_cast *>(other)->m_value; + } + + const T m_value; + void dump(string &out) const override { + json11::dump(m_value, out); + } +}; + +class JsonDouble final : public Value { + double number_value() const override { + return m_value; + } + int int_value() const override { + return static_cast(m_value); + } + int64_t int64_value() const override { + return (int64_t)m_value; + } + uint64_t uint64_value() const override { + return (uint64_t)m_value; + } + bool equals(const JsonValue *other) const override { + return m_value == other->number_value(); + } + bool less(const JsonValue *other) const override { + return m_value < other->number_value(); + } + +public: + explicit JsonDouble(double value) : Value(value) { + } +}; + +class JsonInt final : public Value { + double number_value() const override { + return m_value; + } + int int_value() const override { + return m_value; + } + int64_t int64_value() const override { + return m_value; + } + uint64_t uint64_value() const override { + return m_value; + } + bool equals(const JsonValue *other) const override { + return m_value == other->number_value(); + } + bool less(const JsonValue *other) const override { + return m_value < other->number_value(); + } + +public: + explicit JsonInt(int value) : Value(value) { + } +}; + +class JsonInt64 final : public Value { + double number_value() const override { + return m_value; + } + int int_value() const override { + return (int)m_value; + } + int64_t int64_value() const override { + return m_value; + } + uint64_t uint64_value() const override { + return (uint64_t)m_value; + } + bool equals(const JsonValue *other) const override { + return m_value == other->number_value(); + } + bool less(const JsonValue *other) const override { + return m_value < other->number_value(); + } + +public: + explicit JsonInt64(int64_t value) : Value(value) { + } +}; + +class JsonUInt64 final : public Value { + double number_value() const override { + return m_value; + } + int int_value() const override { + return (int)m_value; + } + int64_t int64_value() const override { + return (int64_t)m_value; + } + uint64_t uint64_value() const override { + return m_value; + } + bool equals(const JsonValue *other) const override { + return m_value == other->number_value(); + } + bool less(const JsonValue *other) const override { + return m_value < other->number_value(); + } + +public: + explicit JsonUInt64(uint64_t value) : Value(value) { + } +}; + +class JsonBoolean final : public Value { + bool bool_value() const override { + return m_value; + } + +public: + explicit JsonBoolean(bool value) : Value(value) { + } +}; + +class JsonString final : public Value { + const string &string_value() const override { + return m_value; + } + +public: + explicit JsonString(const string &value) : Value(value) { + } + explicit JsonString(string &&value) : Value(move(value)) { + } +}; + +class JsonArray final : public Value { + const Json::array &array_items() const override { + return m_value; + } + const Json &operator[](size_t i) const override; + +public: + explicit JsonArray(const Json::array &value) : Value(value) { + } + explicit JsonArray(Json::array &&value) : Value(move(value)) { + } +}; + +class JsonObject final : public Value { + const Json::object &object_items() const override { + return m_value; + } + const Json &operator[](const string &key) const override; + +public: + explicit JsonObject(const Json::object &value) : Value(value) { + } + explicit JsonObject(Json::object &&value) : Value(move(value)) { + } +}; + +class JsonNull final : public Value { +public: + JsonNull() : Value(nullptr) { + } +}; + +/* * * * * * * * * * * * * * * * * * * * + * Static globals - static-init-safe + */ +struct Statics { + const std::shared_ptr null = make_shared(); + const std::shared_ptr t = make_shared(true); + const std::shared_ptr f = make_shared(false); + const string empty_string; + const vector empty_vector; + const map empty_map; + Statics() { + } +}; + +static const Statics &statics() { + static const Statics s{}; + return s; +} + +static const Json &static_null() { + // This has to be separate, not in Statics, because Json() accesses + // statics().null. + static const Json json_null; + return json_null; +} + +/* * * * * * * * * * * * * * * * * * * * + * Constructors + */ + +Json::Json() NOEXCEPT : m_ptr(statics().null) { +} +Json::Json(std::nullptr_t) NOEXCEPT : m_ptr(statics().null) { +} +Json::Json(double value) : m_ptr(make_shared(value)) { +} +Json::Json(int value) : m_ptr(make_shared(value)) { +} +Json::Json(int64_t value) : m_ptr(make_shared(value)) { +} +Json::Json(uint64_t value) : m_ptr(make_shared(value)) { +} +Json::Json(bool value) : m_ptr(value ? statics().t : statics().f) { +} +Json::Json(const string &value) : m_ptr(make_shared(value)) { +} +Json::Json(string &&value) : m_ptr(make_shared(move(value))) { +} +Json::Json(const char *value) : m_ptr(make_shared(value)) { +} +Json::Json(const Json::array &values) + : m_ptr(make_shared(values)) { +} +Json::Json(Json::array &&values) + : m_ptr(make_shared(move(values))) { +} +Json::Json(const Json::object &values) + : m_ptr(make_shared(values)) { +} +Json::Json(Json::object &&values) + : m_ptr(make_shared(move(values))) { +} + +/* * * * * * * * * * * * * * * * * * * * + * Accessors + */ + +Json::Type Json::type() const { + return m_ptr->type(); +} +double Json::number_value() const { + return m_ptr->number_value(); +} +int Json::int_value() const { + return m_ptr->int_value(); +} +int64_t Json::int64_value() const { + return m_ptr->int64_value(); +} +uint64_t Json::uint64_value() const { + return m_ptr->uint64_value(); +} +bool Json::bool_value() const { + return m_ptr->bool_value(); +} +const string &Json::string_value() const { + return m_ptr->string_value(); +} +const vector &Json::array_items() const { + return m_ptr->array_items(); +} +const map &Json::object_items() const { + return m_ptr->object_items(); +} +const Json &Json::operator[](size_t i) const { + return (*m_ptr)[i]; +} +const Json &Json::operator[](const string &key) const { + return (*m_ptr)[key]; +} + +double JsonValue::number_value() const { + return 0; +} +int JsonValue::int_value() const { + return 0; +} +int64_t JsonValue::int64_value() const { + return 0; +} +uint64_t JsonValue::uint64_value() const { + return 0; +} +bool JsonValue::bool_value() const { + return false; +} +const string &JsonValue::string_value() const { + return statics().empty_string; +} +const vector &JsonValue::array_items() const { + return statics().empty_vector; +} +const map &JsonValue::object_items() const { + return statics().empty_map; +} +const Json &JsonValue::operator[](size_t) const { + return static_null(); +} +const Json &JsonValue::operator[](const string &) const { + return static_null(); +} + +const Json &JsonObject::operator[](const string &key) const { + auto iter = m_value.find(key); + return (iter == m_value.end()) ? static_null() : iter->second; +} +const Json &JsonArray::operator[](size_t i) const { + if (i >= m_value.size()) + return static_null(); + else + return m_value[i]; +} + +/* * * * * * * * * * * * * * * * * * * * + * Comparison + */ + +bool Json::operator==(const Json &other) const { + if (m_ptr->type() != other.m_ptr->type()) + return false; + + return m_ptr->equals(other.m_ptr.get()); +} + +bool Json::operator<(const Json &other) const { + if (m_ptr->type() != other.m_ptr->type()) + return m_ptr->type() < other.m_ptr->type(); + + return m_ptr->less(other.m_ptr.get()); +} + +/* * * * * * * * * * * * * * * * * * * * + * Parsing + */ + +/* esc(c) + * + * Format char c suitable for printing in an error message. + */ +static inline string esc(char c) { + char buf[12]; + if (static_cast(c) >= 0x20 && static_cast(c) <= 0x7f) { +//PMO +#ifndef _MSC_VER + snprintf(buf, sizeof buf, "'%c' (%d)", c, c); +#else + _snprintf_s(buf, sizeof buf, "'%c' (%d)", c, c); +#endif + } else { +//PMO +#ifndef _MSC_VER + snprintf(buf, sizeof buf, "(%d)", c); +#else + _snprintf_s(buf, sizeof buf, "(%d)", c); +#endif + } + return string(buf); +} + +static inline bool in_range(long x, long lower, long upper) { + return (x >= lower && x <= upper); +} + +/* JsonParser + * + * Object that tracks all state of an in-progress parse. + */ +struct JsonParser { + + /* State + */ + const string &str; + size_t i; + string &err; + bool failed; + const JsonParse strategy; + + /* fail(msg, err_ret = Json()) + * + * Mark this parse as failed. + */ + Json fail(string &&msg) { + return fail(move(msg), Json()); + } + + template + T fail(string &&msg, const T err_ret) { + if (!failed) + err = std::move(msg); + failed = true; + return err_ret; + } + + /* consume_whitespace() + * + * Advance until the current character is non-whitespace. + */ + void consume_whitespace() { + while (str[i] == ' ' || str[i] == '\r' || str[i] == '\n' || + str[i] == '\t') + i++; + } + + /* consume_comment() + * + * Advance comments (c-style inline and multiline). + */ + bool consume_comment() { + bool comment_found = false; + if (str[i] == '/') { + i++; + if (i == str.size()) + return fail("unexpected end of input inside comment", 0); + if (str[i] == '/') { // inline comment + i++; + if (i == str.size()) + return fail("unexpected end of input inside inline comment", 0); + // advance until next line + while (str[i] != '\n') { + i++; + if (i == str.size()) + return fail("unexpected end of input inside inline comment", + 0); + } + comment_found = true; + } else if (str[i] == '*') { // multiline comment + i++; + if (i > str.size() - 2) + return fail("unexpected end of input inside multi-line comment", + 0); + // advance until closing tokens + while (!(str[i] == '*' && str[i + 1] == '/')) { + i++; + if (i > str.size() - 2) + return fail( + "unexpected end of input inside multi-line comment", 0); + } + i += 2; + if (i == str.size()) + return fail("unexpected end of input inside multi-line comment", + 0); + comment_found = true; + } else + return fail("malformed comment", 0); + } + return comment_found; + } + + /* consume_garbage() + * + * Advance until the current character is non-whitespace and non-comment. + */ + void consume_garbage() { + consume_whitespace(); + if (strategy == JsonParse::COMMENTS) { + bool comment_found = false; + do { + comment_found = consume_comment(); + consume_whitespace(); + } while (comment_found); + } + } + + /* get_next_token() + * + * Return the next non-whitespace character. If the end of the input is + * reached, + * flag an error and return 0. + */ + char get_next_token() { + consume_garbage(); + if (i == str.size()) + return fail("unexpected end of input", 0); + + return str[i++]; + } + + /* encode_utf8(pt, out) + * + * Encode pt as UTF-8 and add it to out. + */ + void encode_utf8(long pt, string &out) { + if (pt < 0) + return; + + if (pt < 0x80) { + out += static_cast(pt); + } else if (pt < 0x800) { + out += static_cast((pt >> 6) | 0xC0); + out += static_cast((pt & 0x3F) | 0x80); + } else if (pt < 0x10000) { + out += static_cast((pt >> 12) | 0xE0); + out += static_cast(((pt >> 6) & 0x3F) | 0x80); + out += static_cast((pt & 0x3F) | 0x80); + } else { + out += static_cast((pt >> 18) | 0xF0); + out += static_cast(((pt >> 12) & 0x3F) | 0x80); + out += static_cast(((pt >> 6) & 0x3F) | 0x80); + out += static_cast((pt & 0x3F) | 0x80); + } + } + + /* parse_string() + * + * Parse a string, starting at the current position. + */ + string parse_string() { + string out; + long last_escaped_codepoint = -1; + while (true) { + if (i == str.size()) + return fail("unexpected end of input in string", ""); + + char ch = str[i++]; + + if (ch == '"') { + encode_utf8(last_escaped_codepoint, out); + return out; + } + + if (in_range(ch, 0, 0x1f)) + return fail("unescaped " + esc(ch) + " in string", ""); + + // The usual case: non-escaped characters + if (ch != '\\') { + encode_utf8(last_escaped_codepoint, out); + last_escaped_codepoint = -1; + out += ch; + continue; + } + + // Handle escapes + if (i == str.size()) + return fail("unexpected end of input in string", ""); + + ch = str[i++]; + + if (ch == 'u') { + // Extract 4-byte escape sequence + string esc = str.substr(i, 4); + // Explicitly check length of the substring. The following loop + // relies on std::string returning the terminating NUL when + // accessing str[length]. Checking here reduces brittleness. + if (esc.length() < 4) { + return fail("bad \\u escape: " + esc, ""); + } + for (int j = 0; j < 4; j++) { + if (!in_range(esc[j], 'a', 'f') && !in_range(esc[j], 'A', 'F') && + !in_range(esc[j], '0', '9')) + return fail("bad \\u escape: " + esc, ""); + } + + long codepoint = strtol(esc.data(), nullptr, 16); + + // JSON specifies that characters outside the BMP shall be encoded + // as a pair + // of 4-hex-digit \u escapes encoding their surrogate pair + // components. Check + // whether we're in the middle of such a beast: the previous + // codepoint was an + // escaped lead (high) surrogate, and this is a trail (low) + // surrogate. + if (in_range(last_escaped_codepoint, 0xD800, 0xDBFF) && + in_range(codepoint, 0xDC00, 0xDFFF)) { + // Reassemble the two surrogate pairs into one astral-plane + // character, per + // the UTF-16 algorithm. + encode_utf8((((last_escaped_codepoint - 0xD800) << 10) | + (codepoint - 0xDC00)) + + 0x10000, + out); + last_escaped_codepoint = -1; + } else { + encode_utf8(last_escaped_codepoint, out); + last_escaped_codepoint = codepoint; + } + + i += 4; + continue; + } + + encode_utf8(last_escaped_codepoint, out); + last_escaped_codepoint = -1; + + if (ch == 'b') { + out += '\b'; + } else if (ch == 'f') { + out += '\f'; + } else if (ch == 'n') { + out += '\n'; + } else if (ch == 'r') { + out += '\r'; + } else if (ch == 't') { + out += '\t'; + } else if (ch == '"' || ch == '\\' || ch == '/') { + out += ch; + } else { + return fail("invalid escape character " + esc(ch), ""); + } + } + } + + /* parse_number() + * + * Parse a double. + */ + Json parse_number() { + size_t start_pos = i; + + if (str[i] == '-') + i++; + + // Integer part + if (str[i] == '0') { + i++; + if (in_range(str[i], '0', '9')) + return fail("leading 0s not permitted in numbers"); + } else if (in_range(str[i], '1', '9')) { + i++; + while (in_range(str[i], '0', '9')) + i++; + } else { + return fail("invalid " + esc(str[i]) + " in number"); + } + + if (str[i] != '.' && str[i] != 'e' && str[i] != 'E' && + (i - start_pos) <= + static_cast(std::numeric_limits::digits10)) { + return std::atoi(str.c_str() + start_pos); + } + + // Decimal part + if (str[i] == '.') { + i++; + if (!in_range(str[i], '0', '9')) + return fail("at least one digit required in fractional part"); + + while (in_range(str[i], '0', '9')) + i++; + } + + // Exponent part + if (str[i] == 'e' || str[i] == 'E') { + i++; + + if (str[i] == '+' || str[i] == '-') + i++; + + if (!in_range(str[i], '0', '9')) + return fail("at least one digit required in exponent"); + + while (in_range(str[i], '0', '9')) + i++; + } + + return std::strtod(str.c_str() + start_pos, nullptr); + } + + /* expect(str, res) + * + * Expect that 'str' starts at the character that was just read. If it + * does, advance + * the input and return res. If not, flag an error. + */ + Json expect(const string &expected, Json res) { + assert(i != 0); + i--; + if (str.compare(i, expected.length(), expected) == 0) { + i += expected.length(); + return res; + } else { + return fail("parse error: expected " + expected + ", got " + + str.substr(i, expected.length())); + } + } + + /* parse_json() + * + * Parse a JSON object. + */ + Json parse_json(int depth) { + if (depth > max_depth) { + return fail("exceeded maximum nesting depth"); + } + + char ch = get_next_token(); + if (failed) + return Json(); + + if (ch == '-' || (ch >= '0' && ch <= '9')) { + i--; + return parse_number(); + } + + if (ch == 't') + return expect("true", true); + + if (ch == 'f') + return expect("false", false); + + if (ch == 'n') + return expect("null", Json()); + + if (ch == '"') + return parse_string(); + + if (ch == '{') { + map data; + ch = get_next_token(); + if (ch == '}') + return data; + + while (1) { + if (ch != '"') + return fail("expected '\"' in object, got " + esc(ch)); + + string key = parse_string(); + if (failed) + return Json(); + + ch = get_next_token(); + if (ch != ':') + return fail("expected ':' in object, got " + esc(ch)); + + data[std::move(key)] = parse_json(depth + 1); + if (failed) + return Json(); + + ch = get_next_token(); + if (ch == '}') + break; + if (ch != ',') + return fail("expected ',' in object, got " + esc(ch)); + + ch = get_next_token(); + } + return data; + } + + if (ch == '[') { + vector data; + ch = get_next_token(); + if (ch == ']') + return data; + + while (1) { + i--; + data.push_back(parse_json(depth + 1)); + if (failed) + return Json(); + + ch = get_next_token(); + if (ch == ']') + break; + if (ch != ',') + return fail("expected ',' in list, got " + esc(ch)); + + ch = get_next_token(); + (void)ch; + } + return data; + } + + return fail("expected value, got " + esc(ch)); + } +}; + +Json Json::parse(const string &in, string &err, JsonParse strategy) { + JsonParser parser{in, 0, err, false, strategy}; + Json result = parser.parse_json(0); + + // Check for any trailing garbage + parser.consume_garbage(); + if (parser.i != in.size()) + return parser.fail("unexpected trailing " + esc(in[parser.i])); + + return result; +} + +// Documented in json11.hpp +vector Json::parse_multi(const string &in, string &err, + JsonParse strategy) { + JsonParser parser{in, 0, err, false, strategy}; + + vector json_vec; + while (parser.i != in.size() && !parser.failed) { + json_vec.push_back(parser.parse_json(0)); + // Check for another object + parser.consume_garbage(); + } + return json_vec; +} + +/* * * * * * * * * * * * * * * * * * * * + * Shape-checking + */ + +bool Json::has_shape(const shape &types, string &err) const { + if (!is_object()) { + err = "expected JSON object, got " + dump(); + return false; + } + + for (auto &item : types) { + if ((*this)[item.first].type() != item.second) { + err = "bad type for " + item.first + " in " + dump(); + return false; + } + } + + return true; +} + +} // namespace json11 diff --git a/CUDA_BasicMatrixMultiplication/libwb/vendor/json11.hpp b/CUDA_BasicMatrixMultiplication/libwb/vendor/json11.hpp new file mode 100644 index 0000000..9e0f0d9 --- /dev/null +++ b/CUDA_BasicMatrixMultiplication/libwb/vendor/json11.hpp @@ -0,0 +1,300 @@ +/* json11 + * + * json11 is a tiny JSON library for C++11, providing JSON parsing and + * serialization. + * + * The core object provided by the library is json11::Json. A Json object + * represents any JSON + * value: null, bool, number (int or double), string (std::string), array + * (std::vector), or + * object (std::map). + * + * Json objects act like values: they can be assigned, copied, moved, + * compared for equality or + * order, etc. There are also helper methods Json::dump, to serialize a + * Json to a string, and + * Json::parse (static) to parse a std::string as a Json object. + * + * Internally, the various types of Json object are represented by the + * JsonValue class + * hierarchy. + * + * A note on numbers - JSON specifies the syntax of number formatting but + * not its semantics, + * so some JSON implementations distinguish between integers and + * floating-point numbers, while + * some don't. In json11, we choose the latter. Because some JSON + * implementations (namely + * Javascript itself) treat all numbers as the same type, distinguishing + * the two leads + * to JSON that will be *silently* changed by a round-trip through those + * implementations. + * Dangerous! To avoid that risk, json11 stores all numbers as double + * internally, but also + * provides integer helpers. + * + * Fortunately, double-precision IEEE754 ('double') can precisely store any + * integer in the + * range +/-2^53, which includes every 'int' on most systems. (Timestamps + * often use int64 + * or long long to avoid the Y2038K problem; a double storing microseconds + * since some epoch + * will be exact for +/- 275 years.) + */ + +/* Copyright (c) 2013 Dropbox, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy + * of this software and associated documentation files (the "Software"), to + * deal + * in the Software without restriction, including without limitation the + * rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN + * THE SOFTWARE. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +//PMO +#ifndef _MSC_VER +#define NOEXCEPT noexcept +#else +#define NOEXCEPT _NOEXCEPT +#endif + +namespace json11 { + +enum JsonParse { STANDARD, COMMENTS }; + +class JsonValue; + +class Json final { +public: + // Types + enum Type { + NUL, + NUMBER, + NUMBER64, + UNUMBER64, + BOOL, + STRING, + ARRAY, + OBJECT + }; + + // Array and object typedefs + typedef std::vector array; + typedef std::map object; + + // Constructors for the various types of JSON value. + //PMO + //Json() noexcept; // NUL + Json() NOEXCEPT; // NUL + //Json(std::nullptr_t) noexcept; // NUL + Json(std::nullptr_t) NOEXCEPT; // NUL + Json(double value); // NUMBER + Json(int value); // NUMBER + Json(int64_t value); // NUMBER64 + Json(uint64_t value); // UNUMBER64 + Json(bool value); // BOOL + Json(const std::string &value); // STRING + Json(std::string &&value); // STRING + Json(const char *value); // STRING + Json(const array &values); // ARRAY + Json(array &&values); // ARRAY + Json(const object &values); // OBJECT + Json(object &&values); // OBJECT + + // Implicit constructor: anything with a to_json() function. + template + Json(const T &t) : Json(t.to_json()) { + } + + // Implicit constructor: map-like objects (std::map, std::unordered_map, + // etc) + template < + class M, + typename std::enable_if< + std::is_constructible::value && + std::is_constructible::value, + int>::type = 0> + Json(const M &m) : Json(object(m.begin(), m.end())) { + } + + // Implicit constructor: vector-like objects (std::list, std::vector, + // std::set, etc) + template ::value, + int>::type = 0> + Json(const V &v) : Json(array(v.begin(), v.end())) { + } + + // This prevents Json(some_pointer) from accidentally producing a bool. + // Use + // Json(bool(some_pointer)) if that behavior is desired. + Json(void *) = delete; + + // Accessors + Type type() const; + + bool is_null() const { + return type() == NUL; + } + bool is_number() const { + return type() == NUMBER; + } + bool is_number64() const { + return type() == NUMBER64; + } + bool is_unumber64() const { + return type() == UNUMBER64; + } + bool is_bool() const { + return type() == BOOL; + } + bool is_string() const { + return type() == STRING; + } + bool is_array() const { + return type() == ARRAY; + } + bool is_object() const { + return type() == OBJECT; + } + + // Return the enclosed value if this is a number, 0 otherwise. Note that + // json11 does not + // distinguish between integer and non-integer numbers - number_value() + // and int_value() + // can both be applied to a NUMBER-typed object. + double number_value() const; + int int_value() const; + int64_t int64_value() const; + uint64_t uint64_value() const; + + // Return the enclosed value if this is a boolean, false otherwise. + bool bool_value() const; + // Return the enclosed string if this is a string, "" otherwise. + const std::string &string_value() const; + // Return the enclosed std::vector if this is an array, or an empty + // vector otherwise. + const array &array_items() const; + // Return the enclosed std::map if this is an object, or an empty map + // otherwise. + const object &object_items() const; + + // Return a reference to arr[i] if this is an array, Json() otherwise. + const Json &operator[](size_t i) const; + // Return a reference to obj[key] if this is an object, Json() otherwise. + const Json &operator[](const std::string &key) const; + + // Serialize. + void dump(std::string &out) const; + std::string dump() const { + std::string out; + dump(out); + return out; + } + + // Parse. If parse fails, return Json() and assign an error message to + // err. + static Json parse(const std::string &in, std::string &err, + JsonParse strategy = JsonParse::STANDARD); + static Json parse(const char *in, std::string &err, + JsonParse strategy = JsonParse::STANDARD) { + if (in) { + return parse(std::string(in), err, strategy); + } else { + err = "null input"; + return nullptr; + } + } + // Parse multiple objects, concatenated or separated by whitespace + static std::vector + parse_multi(const std::string &in, std::string &err, + JsonParse strategy = JsonParse::STANDARD); + + bool operator==(const Json &rhs) const; + bool operator<(const Json &rhs) const; + bool operator!=(const Json &rhs) const { + return !(*this == rhs); + } + bool operator<=(const Json &rhs) const { + return !(rhs < *this); + } + bool operator>(const Json &rhs) const { + return (rhs < *this); + } + bool operator>=(const Json &rhs) const { + return !(*this < rhs); + } + + /* has_shape(types, err) + * + * Return true if this is a JSON object and, for each item in types, has + * a field of + * the given type. If not, return false and set err to a descriptive + * message. + */ + typedef std::initializer_list> shape; + bool has_shape(const shape &types, std::string &err) const; + +private: + std::shared_ptr m_ptr; +}; + +// Internal class hierarchy - JsonValue objects are not exposed to users of +// this API. +class JsonValue { +protected: + friend class Json; + friend class JsonInt; + friend class JsonInt64; + friend class JsonUInt64; + friend class JsonDouble; + virtual Json::Type type() const = 0; + virtual bool equals(const JsonValue *other) const = 0; + virtual bool less(const JsonValue *other) const = 0; + virtual void dump(std::string &out) const = 0; + virtual double number_value() const; + virtual int int_value() const; + virtual int64_t int64_value() const; + virtual uint64_t uint64_value() const; + virtual bool bool_value() const; + virtual const std::string &string_value() const; + virtual const Json::array &array_items() const; + virtual const Json &operator[](size_t i) const; + virtual const Json::object &object_items() const; + virtual const Json &operator[](const std::string &key) const; + virtual ~JsonValue() { + } +}; + +} // namespace json11 diff --git a/CUDA_BasicMatrixMultiplication/libwb/wb.h b/CUDA_BasicMatrixMultiplication/libwb/wb.h new file mode 100644 index 0000000..8f41e23 --- /dev/null +++ b/CUDA_BasicMatrixMultiplication/libwb/wb.h @@ -0,0 +1,155 @@ + + +#ifndef __WB_H__ +#define __WB_H__ + +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ + +#include +#include +#include +#include + +#ifdef _MSC_VER + +// set minimal warning level +#pragma warning(push,0) +// some warnings still occur at this level +// if necessary, disable specific warnings not covered by previous pragma +#pragma warning(disable : 4244 4056 4305 4800 4267 4996 4756 4661 4385 4101) + +#define __func__ __FUNCTION__ +#ifndef _CRT_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_WARNINGS 1 +#endif /* _CRT_SECURE_NO_WARNINGS */ +#define _CRT_SECURE_NO_DEPRECATE 1 +#define _CRT_NONSTDC_NO_DEPRECATE 1 +#include +#include +#include +#define WB_USE_WINDOWS +#else /* _MSC_VER */ +#include +#include +#include +#include +#define WB_USE_UNIX +#ifdef __APPLE__ +#include +#define WB_USE_DARWIN +#else /* __APPLE__ */ +#define WB_USE_LINUX +#endif /* __APPLE__ */ +#endif /* _MSC_VER */ + +#define wbStmt(stmt) stmt + +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ + +#define wbLine __LINE__ +#define wbFile __FILE__ +#define wbFunction __func__ + +#define wbExit() \ + wbAssert(0); \ + exit(1) + +#ifdef WB_USE_COURSERA +#define wbLogger_printOnExit 1 +#else /* WB_USE_COURSERA */ +#define wbLogger_printOnLog 1 +#endif /* WB_USE_COURSERA */ + +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ + +#ifdef __cplusplus +#define EXTERN_C extern "C" +#define START_EXTERN_C EXTERN_C { +#define END_EXTERN_C } +#else +#define EXTERN_C +#define START_EXTERN_C +#define END_EXTERN_C +#endif /* __cplusplus */ + +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ + +#include +#define WB_USE_JSON11 1 + +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ + +#define LAZY_FILE_LOAD +extern char *solutionJSON; + +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ + +#ifdef WB_USE_OPENCL +#ifdef WB_USE_DARWIN +#include +#else /* WB_USE_DARWIN */ +#include +#endif /* WB_USE_DARWIN */ +#endif /* WB_USE_OPENCL */ + +#include "wbTypes.h" + +#include "wbAssert.h" +#include "wbMalloc.h" +#include "wbString.h" +#include "wbUtils.h" + +#include "wbArg.h" +#include "wbCUDA.h" +#include "wbCast.h" +#include "wbComparator.h" +#include "wbDirectory.h" +#include "wbExit.h" +#include "wbExport.h" +#include "wbFile.h" +#include "wbImage.h" +#include "wbImport.h" +#include "wbInit.h" +#include "wbLogger.h" +#include "wbMD5.h" +#include "wbMPI.h" +#include "wbSolution.h" +#include "wbSparse.h" +#include "wbThrust.h" +#include "wbTimer.h" +#include "wbPath.h" + +#include "wbDataset.h" + +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ + +#endif /* __WB_H__ */ diff --git a/CUDA_BasicMatrixMultiplication/libwb/wbArg.cpp b/CUDA_BasicMatrixMultiplication/libwb/wbArg.cpp new file mode 100644 index 0000000..2a5c736 --- /dev/null +++ b/CUDA_BasicMatrixMultiplication/libwb/wbArg.cpp @@ -0,0 +1,105 @@ + +#include "wb.h" + +EXTERN_C wbArg_t wbArg_new(int *argc, char ***argv) { + wbArg_t arg; + + wb_init(argc, argv); + + wbArg_setInputCount(arg, 0); + wbArg_setInputFiles(arg, NULL); + wbArg_setOutputFile(arg, NULL); + wbArg_setType(arg, NULL); + wbArg_setExpectedOutputFile(arg, NULL); + return arg; +} + +EXTERN_C void wbArg_delete(wbArg_t arg) { + if (wbArg_getInputCount(arg) > 0 && wbArg_getInputFiles(arg) != NULL) { + int ii; + for (ii = 0; ii < wbArg_getInputCount(arg); ii++) { + wbDelete(wbArg_getInputFile(arg, ii)); + } + wbDelete(wbArg_getInputFiles(arg)); + wbArg_setInputCount(arg, 0); + wbArg_setInputFiles(arg, NULL); + } + if (wbArg_getOutputFile(arg)) { + wbDelete(wbArg_getOutputFile(arg)); + wbArg_setOutputFile(arg, NULL); + } + if (wbArg_getExpectedOutputFile(arg)) { + wbDelete(wbArg_getExpectedOutputFile(arg)); + wbArg_setExpectedOutputFile(arg, NULL); + } + if (wbArg_getType(arg)) { + wbDelete(wbArg_getType(arg)); + wbArg_setType(arg, NULL); + } + return; +} + +static int getInputFileCount(char *arg) { + int count = 1; + while (*arg != '\0' && *arg != '-') { + if (*arg == ',') { + count++; + } + arg++; + } + return count; +} + +static char **parseInputFiles(char *arg, int *resCount) { + int count; + int ii = 0; + char **files; + char *token; + + count = getInputFileCount(arg); + + files = wbNewArray(char *, count); + + token = strtok(arg, ","); + while (token != NULL) { + files[ii++] = wbString_duplicate(token); + token = strtok(NULL, ","); + } + *resCount = ii; + return files; +} + +static char *parseString(char *arg) { + return wbString_duplicate(arg); +} + +EXTERN_C wbArg_t wbArg_read(int argc, char **argv) { + int ii; + wbArg_t arg; + + arg = wbArg_new(&argc, &argv); + for (ii = 0; ii < argc; ii++) { + if (wbString_startsWith(argv[ii], "-i")) { + int fileCount; + char **files; + + files = parseInputFiles(argv[ii + 1], &fileCount); + + wbArg_setInputCount(arg, fileCount); + wbArg_setInputFiles(arg, files); + } else if (wbString_startsWith(argv[ii], "-o")) { + char *file = parseString(argv[ii + 1]); + wbArg_setOutputFile(arg, file); + } else if (wbString_startsWith(argv[ii], "-e")) { + char *file = parseString(argv[ii + 1]); + wbArg_setExpectedOutputFile(arg, file); + } else if (wbString_startsWith(argv[ii], "-t")) { + char *type = parseString(argv[ii + 1]); + wbArg_setType(arg, type); + } else if (argv[ii][0] == '-') { + wbLog(ERROR, "Unexpected program option ", argv[ii]); + } + } + + return arg; +} diff --git a/CUDA_BasicMatrixMultiplication/libwb/wbArg.h b/CUDA_BasicMatrixMultiplication/libwb/wbArg.h new file mode 100644 index 0000000..c98bcf7 --- /dev/null +++ b/CUDA_BasicMatrixMultiplication/libwb/wbArg.h @@ -0,0 +1,33 @@ + + +#ifndef __WB_ARG_H__ +#define __WB_ARG_H__ + +struct st_wbArg_t { + int inputCount; + char **inputFiles; + char *outputFile; + char *expectedOutput; + char *type; +}; + +#define wbArg_getInputCount(wa) ((wa).inputCount) +#define wbArg_getInputFiles(wa) ((wa).inputFiles) +#define wbArg_getInputFile(wa, ii) (wbArg_getInputFiles(wa)[ii]) +#define wbArg_getOutputFile(wa) ((wa).outputFile) +#define wbArg_getExpectedOutputFile(wa) ((wa).expectedOutput) +#define wbArg_getType(wa) ((wa).type) + +#define wbArg_setInputCount(wa, val) (wbArg_getInputCount(wa) = val) +#define wbArg_setInputFiles(wa, val) (wbArg_getInputFiles(wa) = val) +#define wbArg_setInputFile(wa, ii, val) (wbArg_getInputFile(wa, ii) = val) +#define wbArg_setOutputFile(wa, val) (wbArg_getOutputFile(wa) = val) +#define wbArg_setExpectedOutputFile(wa, val) \ + (wbArg_getExpectedOutputFile(wa) = val) +#define wbArg_setType(wa, val) (wbArg_getType(wa) = val) + +EXTERN_C wbArg_t wbArg_new(int *argc, char ***argv); +EXTERN_C void wbArg_delete(wbArg_t arg); +EXTERN_C wbArg_t wbArg_read(int argc, char **argv); + +#endif /* __WB_ARG_H__ */ diff --git a/CUDA_BasicMatrixMultiplication/libwb/wbAssert.h b/CUDA_BasicMatrixMultiplication/libwb/wbAssert.h new file mode 100644 index 0000000..b8ed669 --- /dev/null +++ b/CUDA_BasicMatrixMultiplication/libwb/wbAssert.h @@ -0,0 +1,24 @@ + + +#ifndef __WB_ASSERT_H__ +#define __WB_ASSERT_H__ + +#include + +#ifdef WB_DEBUG +#define wbAssert(cond) assert(cond) +#define wbAssertMessage(msg, cond) \ + do { \ + if (!(cond)) { \ + wbPrint(msg); \ + wbAssert(cond); \ + } \ + } while (0) +#else /* WB_DEBUG */ +#define wbAssert(...) +#define wbAssertMessage(...) +#endif /* WB_DEBUG */ + +#define wbTodo(msg) wbAssertMessage(msg, false) + +#endif /* __WB_ASSERT_H__ */ diff --git a/CUDA_BasicMatrixMultiplication/libwb/wbCUDA.cpp b/CUDA_BasicMatrixMultiplication/libwb/wbCUDA.cpp new file mode 100644 index 0000000..cb26895 --- /dev/null +++ b/CUDA_BasicMatrixMultiplication/libwb/wbCUDA.cpp @@ -0,0 +1,25 @@ + +#include "wb.h" +#ifdef WB_USE_CUDA + +int _cudaMemoryListIdx = 0; + +size_t _cudaMallocSize = 0; + +wbCUDAMemory_t _cudaMemoryList[_cudaMemoryListSize]; + +char *wbRandom_list(size_t sz) { + size_t ii; + char *rands = wbNewArray(char, sz); + int *irands = (int *)rands; + for (ii = 0; ii < sz / sizeof(int); ii++) { + irands[ii] = rand(); + } + while (ii < sz) { + rands[ii] = (char)(rand() % 255); + ii++; + } + return rands; +} + +#endif /* WB_USE_CUDA */ diff --git a/CUDA_BasicMatrixMultiplication/libwb/wbCUDA.h b/CUDA_BasicMatrixMultiplication/libwb/wbCUDA.h new file mode 100644 index 0000000..658ff39 --- /dev/null +++ b/CUDA_BasicMatrixMultiplication/libwb/wbCUDA.h @@ -0,0 +1,77 @@ + +#ifndef __WB_CUDA_H__ +#define __WB_CUDA_H__ + +#ifdef WB_USE_CUDA +#ifdef __PGI +#define __GNUC__ 4 +#endif /* __PGI */ +#include +#include + +typedef struct st_wbCUDAMemory_t { + void *mem; + size_t sz; +} wbCUDAMemory_t; + +#define _cudaMemoryListSize 1024 + +extern size_t _cudaMallocSize; +extern wbCUDAMemory_t _cudaMemoryList[]; +extern int _cudaMemoryListIdx; + +char *wbRandom_list(size_t sz); + +static inline cudaError_t wbCUDAMalloc(void **devPtr, size_t sz) { + int idx = _cudaMemoryListIdx; + + cudaError_t err = cudaMalloc(devPtr, sz); + + if (idx == 0) { + srand(time(NULL)); + memset(_cudaMemoryList, 0, + sizeof(wbCUDAMemory_t) * _cudaMemoryListSize); + } + + if (err == cudaSuccess) { +#if 0 + char * rands = wbRandom_list(sz); + // can use curand here, but do not want to invoke a kernel + err = cudaMemcpy(*devPtr, rands, sz, cudaMemcpyHostToDevice); + wbFree(rands); +#else + err = cudaMemset(*devPtr, 0, sz); +#endif + } + + _cudaMallocSize += sz; + _cudaMemoryList[idx].mem = *devPtr; + _cudaMemoryList[idx].sz = sz; + _cudaMemoryListIdx++; + return err; +} + +static inline cudaError_t wbCUDAFree(void *mem) { + int idx = _cudaMemoryListIdx; + if (idx == 0) { + memset(_cudaMemoryList, 0, + sizeof(wbCUDAMemory_t) * _cudaMemoryListSize); + } + for (int ii = 0; ii < idx; ii++) { + if (_cudaMemoryList[ii].mem != NULL && + _cudaMemoryList[ii].mem == mem) { + cudaError_t err = cudaFree(mem); + _cudaMallocSize -= _cudaMemoryList[ii].sz; + _cudaMemoryList[ii].mem = NULL; + return err; + } + } + return cudaErrorMemoryAllocation; +} + +#define cudaMalloc(elem, err) wbCUDAMalloc((void **)elem, err) +#define cudaFree wbCUDAFree + +#endif /* WB_USE_CUDA */ + +#endif /* __WB_CUDA_H__ */ diff --git a/CUDA_BasicMatrixMultiplication/libwb/wbCast.h b/CUDA_BasicMatrixMultiplication/libwb/wbCast.h new file mode 100644 index 0000000..01e8387 --- /dev/null +++ b/CUDA_BasicMatrixMultiplication/libwb/wbCast.h @@ -0,0 +1,29 @@ + + +#ifndef __WB_CAST_H__ +#define __WB_CAST_H__ + +template +static inline void wbCast(X &x, const Y &y, size_t len) { + size_t ii; + + for (ii = 0; ii < len; ii++) { + x[ii] = (X)y[ii]; + } + + return; +} + +template +static inline X *wbCast(const Y &y, size_t len) { + size_t ii; + X *x = wbNewArray(X, len); + + for (ii = 0; ii < len; ii++) { + x[ii] = (X)y[ii]; + } + + return x; +} + +#endif /* __WB_CAST_H__ */ diff --git a/CUDA_BasicMatrixMultiplication/libwb/wbComparator.h b/CUDA_BasicMatrixMultiplication/libwb/wbComparator.h new file mode 100644 index 0000000..26fd0cb --- /dev/null +++ b/CUDA_BasicMatrixMultiplication/libwb/wbComparator.h @@ -0,0 +1,187 @@ + + +#ifndef __WB_COMPARATOR_H__ +#define __WB_COMPARATOR_H__ + +#include "wb.h" + +template +static inline T _abs(const T &a) { + return a < 0 ? -a : a; +} + +static inline wbBool _almostEqual(double A, double B, double eps) { + if (A == 0) { + return _abs(B) < eps; + } else if (B == 0) { + return _abs(A) < eps; + } else { +#if 0 + double d = max(_abs(A), _abs(B)); + double g = (_abs(A - B) / d); +#else + double g = _abs(A - B); +#endif + if (g <= eps) { + return wbTrue; + } else { + return wbFalse; + } + } +} + +static inline wbBool _almostEqual(float A, float B, float eps) { + if (A == 0) { + return _abs(B) < eps; + } else if (B == 0) { + return _abs(A) < eps; + } else { +#if 0 + float d = max(_abs(A), _abs(B)); + float g = (_abs(A - B) / d); +#else + float g = _abs(A - B); +#endif + if (g <= eps) { + return wbTrue; + } else { + return wbFalse; + } + } +} + +static inline wbBool _almostEqual(double A, double B) { + return _almostEqual(A, B, 0.2); +} + +static inline wbBool _almostEqual(float A, float B) { + return _almostEqual(A, B, 0.2f); +} + +static inline wbBool _almostEqual2sComplement(float A, float B, + int maxUlps) { + // Make sure maxUlps is non-negative and small enough that the + // default NAN won't compare as equal to anything. + + int aInt, bInt, intDiff; + + wbAssert(maxUlps > 0 && maxUlps < 4 * 1024 * 1024); + + int *tmp = reinterpret_cast(&A); + aInt = *tmp; + + // Make aInt lexicographically ordered as a twos-complement int + if (aInt < 0) { + aInt = 0x80000000 - aInt; + } + // Make bInt lexicographically ordered as a twos-complement int + tmp = reinterpret_cast(&B); + bInt = *tmp; + if (bInt < 0) { + bInt = 0x80000000 - bInt; + } + intDiff = _abs(aInt - bInt); + if (intDiff <= maxUlps) { + return wbTrue; + } + return wbFalse; +} + +static inline wbBool _almostEqual2sComplement(float A, float B) { + return _almostEqual2sComplement(A, B, 4); +} + +static inline wbBool _almostEqual2sComplement(double A, double B, + int maxUlps) { + // Make sure maxUlps is non-negative and small enough that the + // default NAN won't compare as equal to anything. + + int64_t aInt, bInt, intDiff; + + wbAssert(maxUlps > 0 && maxUlps < 4 * 1024 * 1024); + + int64_t *tmp = reinterpret_cast(&A); + aInt = *tmp; + + // Make aInt lexicographically ordered as a twos-complement int + if (aInt < 0) { + aInt = 0x80000000 - aInt; + } + // Make bInt lexicographically ordered as a twos-complement int + tmp = reinterpret_cast(&B); + bInt = *tmp; + if (bInt < 0) { + bInt = 0x80000000 - bInt; + } + intDiff = _abs(aInt - bInt); + if (intDiff <= maxUlps) { + return wbTrue; + } + return wbFalse; +} + +static inline wbBool _almostEqual2sComplement(double A, double B) { + return _almostEqual2sComplement(A, B, 4); +} + +template +static inline int wbCompare(const T &a, const T &b) { + if (a == b) { + return 0; + } else if (a < b) { + return -1; + } else { + return 1; + } +} + +template <> +inline int wbCompare(const double &a, const double &b) { + if (_almostEqual(a, b)) { + return 0; + } else if (a < b) { + return -1; + } else { + return 1; + } +} + +template <> +inline int wbCompare(const float &a, const float &b) { + if (_almostEqual(a, b)) { + return 0; + } else if (a < b) { + return -1; + } else { + return 1; + } +} + +template +static inline wbBool wbEqualQ(const T &a, const T &b) { + return wbCompare(a, b) == 0; +} + +template +static inline wbBool wbUnequalQ(const T &a, const T &b) { + return wbCompare(a, b) != 0; +} + +template +static inline wbBool wbEqualQ(const T *a, const T *b, size_t n) { + size_t ii; + + for (ii = 0; ii < n; ii++) { + if (wbUnequalQ(a[ii], b[ii])) { + return wbFalse; + } + } + return wbTrue; +} + +template +static inline wbBool wbUnequalQ(const T *a, const T *b, size_t n) { + return !wbEqualQ(a, b, n); +} + +#endif /* __WB_COMPARATOR_H__ */ diff --git a/CUDA_BasicMatrixMultiplication/libwb/wbDataset.cpp b/CUDA_BasicMatrixMultiplication/libwb/wbDataset.cpp new file mode 100644 index 0000000..a11f064 --- /dev/null +++ b/CUDA_BasicMatrixMultiplication/libwb/wbDataset.cpp @@ -0,0 +1,177 @@ +#include "wb.h" + +template +static inline T _min(const T &x, const T &y) { + return x < y ? x : y; +} + +template +static inline T _max(const T &x, const T &y) { + return x > y ? x : y; +} + +template +inline T lerp(const double &x, const T &start, const T &end) { + return (1 - x) * start + x * end; +} + +static inline void genRandom(void *trgt, wbType_t type, double minVal, + double maxVal) { + const int span = maxVal - minVal; + const int r = rand(); + const double rf = ((double)r) / ((double)RAND_MAX); + switch (type) { + case wbType_ascii: + *((char *)trgt) = (r % span) + minVal; // random printable character; + break; + case wbType_bit8: + *((char *)trgt) = lerp(rf, minVal, maxVal); + break; + case wbType_ubit8: + *((unsigned char *)trgt) = lerp(rf, minVal, maxVal); + break; + case wbType_integer: + *((int *)trgt) = lerp(rf, minVal, maxVal); + break; + case wbType_float: { + *((float *)trgt) = lerp(rf, minVal, maxVal); + break; + } + case wbType_double: { + *((double *)trgt) = lerp(rf, minVal, maxVal); + break; + } + case wbType_unknown: + wbAssert(false && "Invalid wbType_unknown"); + break; + } + return; +} + +static inline void *genRandomList(wbType_t type, size_t len, double minVal, + double maxVal) { + size_t ii; + void *data = wbNewArray(char, wbType_size(type) * len); + switch (type) { + case wbType_ascii: + case wbType_bit8: { + char *iter = (char *)data; + for (ii = 0; ii < len; ii++) { + genRandom(iter++, type, minVal, maxVal); + } + break; + } + case wbType_ubit8: { + unsigned char *iter = (unsigned char *)data; + for (ii = 0; ii < len; ii++) { + genRandom(iter++, type, minVal, maxVal); + } + break; + } + case wbType_integer: { + int *iter = (int *)data; + for (ii = 0; ii < len; ii++) { + genRandom(iter++, type, minVal, maxVal); + } + break; + } + case wbType_float: { + float *iter = (float *)data; + for (ii = 0; ii < len; ii++) { + genRandom(iter++, type, minVal, maxVal); + } + break; + } + case wbType_double: { + double *iter = (double *)data; + for (ii = 0; ii < len; ii++) { + genRandom(iter++, type, minVal, maxVal); + } + break; + } + case wbType_unknown: + wbAssert(false && "Invalid wbType_unknown"); + break; + } + return data; +} + +static void genRaw(const char *path, wbRaw_GenerateParams_t params) { + int rows = _max(1, params.rows); + int cols = _max(1, params.cols); + double minVal = params.minVal; + double maxVal = params.maxVal; + wbType_t type = params.type; + void *data = genRandomList(type, rows * cols, minVal, maxVal); + wbExport(path, wbExportKind_raw, data, rows, cols, type); + wbDelete(data); +} + +static void genCSV(const char *path, wbCSV_GenerateParams_t params) { + int rows = _max(1, params.rows); + int cols = _max(1, params.cols); + double minVal = params.minVal; + double maxVal = params.maxVal; + wbType_t type = params.type; + void *data = genRandomList(type, rows * cols, minVal, maxVal); + wbExport(path, wbExportKind_csv, data, rows, cols, type); + wbDelete(data); +} + +static void genTSV(const char *path, wbTSV_GenerateParams_t params) { + int rows = _max(1, params.rows); + int cols = _max(1, params.cols); + double minVal = params.minVal; + double maxVal = params.maxVal; + wbType_t type = params.type; + void *data = genRandomList(type, rows * cols, minVal, maxVal); + wbExport(path, wbExportKind_tsv, data, rows, cols, type); + wbDelete(data); +} + +static void genText(const char *path, wbText_GenerateParams_t params) { + int length = _max(1, params.length); + wbType_t type = wbType_ascii; + void *data = genRandomList(type, length, 32, 128); + wbExport(path, wbExportKind_text, data, length, 1, type); + wbDelete(data); +} + +static void genPPM(const char *path, wbPPM_GenerateParams_t params) { + int width = _max(1, params.width); + int height = _max(1, params.height); + int channels = _max(1, params.channels); + double minVal = params.minVal; + double maxVal = params.maxVal; + wbType_t type = wbType_float; + float *data = (float *)genRandomList(type, width * height * channels, + minVal, maxVal); + wbImage_t img = wbImage_new(width, height, channels, data); + wbExport(path, img); + wbImage_delete(img); +} + +EXTERN_C void wbDataset_generate(const char *path, wbExportKind_t kind, + wbGenerateParams_t params) { + wbDirectory_create(wbDirectory_name(path)); + + switch (kind) { + case wbExportKind_raw: + genRaw(path, params.raw); + break; + case wbExportKind_csv: + genCSV(path, params.csv); + break; + case wbExportKind_tsv: + genTSV(path, params.tsv); + break; + case wbExportKind_ppm: + genPPM(path, params.ppm); + break; + case wbExportKind_text: + genText(path, params.text); + break; + default: + wbAssert(false && "Invalid Export kind"); + } +} diff --git a/CUDA_BasicMatrixMultiplication/libwb/wbDataset.h b/CUDA_BasicMatrixMultiplication/libwb/wbDataset.h new file mode 100644 index 0000000..ce81c28 --- /dev/null +++ b/CUDA_BasicMatrixMultiplication/libwb/wbDataset.h @@ -0,0 +1,52 @@ +#ifndef __WB_DATASET_H__ +#define __WB_DATASET_H__ + +#include "wbImport.h" +#include "wbTypes.h" + +typedef struct { + int rows; + int cols; + wbType_t type; + double minVal; + double maxVal; +} wbCSV_GenerateParams_t; + +typedef struct { + int rows; + int cols; + wbType_t type; + double minVal; + double maxVal; +} wbTSV_GenerateParams_t; + +typedef struct { + int rows; + int cols; + double minVal; + double maxVal; + wbType_t type; +} wbRaw_GenerateParams_t; + +typedef struct { + int width; + int height; + int channels; + double minVal; + double maxVal; +} wbPPM_GenerateParams_t; + +typedef struct { int length; } wbText_GenerateParams_t; + +typedef union { + wbCSV_GenerateParams_t csv; + wbRaw_GenerateParams_t raw; + wbTSV_GenerateParams_t tsv; + wbPPM_GenerateParams_t ppm; + wbText_GenerateParams_t text; +} wbGenerateParams_t; + +EXTERN_C void wbDataset_generate(const char *path, wbExportKind_t kind, + wbGenerateParams_t params); + +#endif /* __WB_DATASET_H__ */ diff --git a/CUDA_BasicMatrixMultiplication/libwb/wbDataset_test.cpp b/CUDA_BasicMatrixMultiplication/libwb/wbDataset_test.cpp new file mode 100644 index 0000000..4f08042 --- /dev/null +++ b/CUDA_BasicMatrixMultiplication/libwb/wbDataset_test.cpp @@ -0,0 +1,23 @@ + +#include "wb.h" +#include "vendor/catch.hpp" + +TEST_CASE("Can create Raw dataset", "[DataGenerator]") { + wbGenerateParams_t params; + params.raw.rows = 2; + params.raw.cols = 300; + params.raw.minVal = 0; + params.raw.maxVal = 30; + params.raw.type = wbType_integer; + wbDataset_generate( + wbPath_join(wbDirectory_current(), "test-dataset", "test.raw"), + wbExportKind_raw, params); +} + +TEST_CASE("Can create Text dataset", "[DataGenerator]") { + wbGenerateParams_t params; + params.text.length = 2000; + wbDataset_generate( + wbPath_join(wbDirectory_current(), "test-dataset", "test.txt"), + wbExportKind_text, params); +} diff --git a/CUDA_BasicMatrixMultiplication/libwb/wbDirectory.cpp b/CUDA_BasicMatrixMultiplication/libwb/wbDirectory.cpp new file mode 100644 index 0000000..10dc8c5 --- /dev/null +++ b/CUDA_BasicMatrixMultiplication/libwb/wbDirectory.cpp @@ -0,0 +1,88 @@ +#include "wb.h" + +#ifndef PATH_MAX +#ifdef FILENAME_MAX +#define PATH_MAX FILENAME_MAX +#else /* FILENAME_MAX */ +#define PATH_MAX 4096 +#endif /* FILENAME_MAX */ +#endif /* PATH_MAX */ + +#ifdef WB_USE_UNIX +const char wbDirectorySeperator = '/'; +static char *getcwd_(char *buf, int maxLen) { + return getcwd(buf, maxLen); +} +static void mkdir_(const char *dir) { + mkdir(dir, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); +} +#else /* WB_USE_LINUX */ +const char wbDirectorySeperator = '\\'; +static char *getcwd_(char *buf, int maxLen) { + return _getcwd(buf, maxLen); +} +static void mkdir_(const char *dir) { + _mkdir(dir); +} +#endif /* WB_USE_LINUX */ + +EXTERN_C const char * wbDirectory_create(const char *dir) { + char tmp[PATH_MAX]; + char *p = NULL; + size_t len; +//PMO +#ifndef _MSC_VER + snprintf(tmp, sizeof(tmp), "%s", dir); +#else + _snprintf_s(tmp, sizeof(tmp), "%s", dir); +#endif + len = strlen(tmp); + if (tmp[len - 1] == wbDirectorySeperator) { + tmp[len - 1] = 0; + } + for (p = tmp + 1; *p; p++) { + if (*p == wbDirectorySeperator) { + *p = 0; + mkdir_(tmp); + *p = wbDirectorySeperator; + } + } + mkdir_(tmp); + return dir; +} + +EXTERN_C char *wbDirectory_name(const char *pth0) { + char *pth = wbString_duplicate(pth0); + char *p = strrchr(pth, wbDirectorySeperator); + if (p) { + p[0] = 0; + } + return pth; +} + +EXTERN_C char *wbDirectory_current() { + char *tmp = wbNewArray(char, PATH_MAX + 1); + if (getcwd_(tmp, PATH_MAX)) { + return tmp; + } + + wbDelete(tmp); + + int error = errno; + switch (error) { + case EACCES: + std::cerr + << "Cannot get current directory :: access denied. exiting..." + << std::endl; + exit(-1); + case ENOMEM: + std::cerr << "Cannot get current directory :: insufficient storage. " + "exiting..." + << std::endl; + exit(-1); + default: + std::cerr << "Cannot get current directory :: unrecognised error " + << error << std::endl; + exit(-1); + } +} \ No newline at end of file diff --git a/CUDA_BasicMatrixMultiplication/libwb/wbDirectory.h b/CUDA_BasicMatrixMultiplication/libwb/wbDirectory.h new file mode 100644 index 0000000..cb14f81 --- /dev/null +++ b/CUDA_BasicMatrixMultiplication/libwb/wbDirectory.h @@ -0,0 +1,9 @@ +#ifndef __WB_DIRECTORY__ +#define __WB_DIRECTORY__ + +extern const char wbDirectorySeperator; +EXTERN_C char *wbDirectory_name(const char *pth); +EXTERN_C const char * wbDirectory_create(const char *dir); +EXTERN_C char *wbDirectory_current(); + +#endif /* __WB_DIRECTORY__ */ diff --git a/CUDA_BasicMatrixMultiplication/libwb/wbExit.cpp b/CUDA_BasicMatrixMultiplication/libwb/wbExit.cpp new file mode 100644 index 0000000..a7edc3a --- /dev/null +++ b/CUDA_BasicMatrixMultiplication/libwb/wbExit.cpp @@ -0,0 +1,119 @@ + +#include "wb.h" + +enum { + wbMPI_timerTag = 2, + wbMPI_loggerTag = 4, + wbMPI_solutionExistsTag = 8, + wbMPI_solutionTag = 16 +}; + +void wb_atExit(void) { + using std::cout; + using std::endl; + +#ifdef WB_USE_CUDA + cudaDeviceSynchronize(); +#endif /* WB_USE_CUDA */ + + int nranks = rankCount(); + if (nranks > 1) { +#ifdef WB_USE_MPI + if (isMasterQ) { +#ifdef wbLogger_printOnExit + cout << "==$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$" << endl; + + cout << "{\n"; + cout << wbString_quote("timer") << ":"; + cout << "[\n"; + for (int ii = 0; ii < nranks; ii++) { + if (ii == 0) { + cout << wbTimer_toJSON(); + } else { + const char *msg = wbMPI_getStringFromRank(ii, wbMPI_timerTag); + if (msg != NULL && strlen(msg) != 0) { + cout << ",\n"; + cout << msg; + // free(msg); + } + } + } + cout << "]" << endl; // close timer + + cout << "," << endl; // start logger + cout << wbString_quote("logger") << ":"; + cout << "[\n"; + for (int ii = 0; ii < nranks; ii++) { + if (ii == 0) { + cout << wbLogger_toJSON(); + } else { + const char *msg = wbMPI_getStringFromRank(ii, wbMPI_loggerTag); + if (msg != NULL && strlen(msg) != 0) { + cout << ",\n"; + cout << msg; + // free(msg); + } + } + } + cout << "]" << endl; // close logger + + cout << "," << endl; // start solutionExists + cout << wbString_quote("cuda_memory") << ":" << _cudaMallocSize + << ",\n"; + + if (solutionJSON) { + cout << wbString_quote("solution_exists") << ": true,\n"; + cout << wbString_quote("solution") << ":" << solutionJSON << "\n"; + } else { + cout << wbString_quote("solution_exists") << ": false\n"; + } + cout << "}" << endl; // close json + + } else { + wbMPI_sendStringToMaster(wbTimer_toJSON().c_str(), wbMPI_timerTag); + wbMPI_sendStringToMaster(wbLogger_toJSON().c_str(), wbMPI_loggerTag); + } +#endif /* wbLogger_printOnExit */ + +#endif /* WB_USE_MPI */ + } else { +#ifdef wbLogger_printOnExit + cout << "==$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$" << endl; + + cout << "{\n" << wbString_quote("timer") << ":[" << wbTimer_toJSON() + << "],\n" << wbString_quote("logger") << ":[" << wbLogger_toJSON() + << "],\n"; + +#ifdef WB_USE_CUDA + cout << wbString_quote("cuda_memory") << ":" << _cudaMallocSize + << ",\n"; +#endif /* WB_USE_CUDA */ + + if (solutionJSON) { + cout << wbString_quote("solution_exists") << ": true,\n"; + cout << wbString_quote("solution") << ":" << solutionJSON << "\n"; + } else { + cout << wbString_quote("solution_exists") << ": false\n"; + } + cout << "}" << endl; +#endif /* wbLogger_printOnExit */ + } + + // wbTimer_delete(_timer); + // wbLogger_delete(_logger); + + _timer = NULL; + _logger = NULL; + +// wbFile_atExit(); + +#ifdef WB_USE_CUDA + cudaDeviceReset(); +#endif + + exit(0); + + // assert(0); + + return; +} diff --git a/CUDA_BasicMatrixMultiplication/libwb/wbExit.h b/CUDA_BasicMatrixMultiplication/libwb/wbExit.h new file mode 100644 index 0000000..4400108 --- /dev/null +++ b/CUDA_BasicMatrixMultiplication/libwb/wbExit.h @@ -0,0 +1,7 @@ + +#ifndef __WB_EXIT_H__ +#define __WB_EXIT_H__ + +void wb_atExit(void); + +#endif /* __WB_EXIT_H__ */ diff --git a/CUDA_BasicMatrixMultiplication/libwb/wbExport.cpp b/CUDA_BasicMatrixMultiplication/libwb/wbExport.cpp new file mode 100644 index 0000000..59b7a33 --- /dev/null +++ b/CUDA_BasicMatrixMultiplication/libwb/wbExport.cpp @@ -0,0 +1,510 @@ + +#include "wb.h" + +static inline void wbExportText_setFile(wbExportText_t text, + const char *path) { + if (text != NULL) { + if (wbExportText_getFile(text) != NULL) { + wbFile_delete(wbExportText_getFile(text)); + } + if (path != NULL) { + wbExportText_getFile(text) = wbFile_open(path, "w+"); + } else { + wbExportText_getFile(text) = NULL; + } + } + + return; +} + +static inline wbExportText_t wbExportText_new(void) { + wbExportText_t text; + + text = wbNew(struct st_wbExportText_t); + + wbExportText_getFile(text) = NULL; + wbExportText_setLength(text, -1); + + return text; +} + +static inline void wbExportText_delete(wbExportText_t text) { + if (text != NULL) { + wbExportText_setFile(text, NULL); + wbDelete(text); + } + return; +} + +static inline void wbExportText_write(wbExportText_t text, + const char *data, int length) { + int ii; + FILE *handle; + wbFile_t file; + + if (text == NULL || wbExportText_getFile(text) == NULL) { + return; + } + + file = wbExportText_getFile(text); + + handle = wbFile_getFileHandle(file); + + if (handle == NULL) { + return; + } + + for (ii = 0; ii < length; ii++) { + fprintf(handle, "%c", data[ii]); + } + + return; +} + +static inline void wbExportRaw_setFile(wbExportRaw_t raw, + const char *path) { + if (raw != NULL) { + if (wbExportRaw_getFile(raw) != NULL) { + wbFile_delete(wbExportRaw_getFile(raw)); + } + if (path != NULL) { + wbExportRaw_getFile(raw) = wbFile_open(path, "w+"); + } else { + wbExportRaw_getFile(raw) = NULL; + } + } + + return; +} + +static inline wbExportRaw_t wbExportRaw_new(void) { + wbExportRaw_t raw; + + raw = wbNew(struct st_wbExportRaw_t); + + wbExportRaw_getFile(raw) = NULL; + wbExportRaw_setRowCount(raw, -1); + wbExportRaw_setColumnCount(raw, -1); + + return raw; +} + +static inline void wbExportRaw_delete(wbExportRaw_t raw) { + if (raw != NULL) { + wbExportRaw_setFile(raw, NULL); + wbDelete(raw); + } + return; +} + +static inline void wbExportRaw_write(wbExportRaw_t raw, void *data, + int rows, int columns, + wbType_t type) { + int ii, jj; + FILE *handle; + wbFile_t file; + + if (raw == NULL || wbExportRaw_getFile(raw) == NULL) { + return; + } + + file = wbExportRaw_getFile(raw); + + handle = wbFile_getFileHandle(file); + + if (handle == NULL) { + return; + } + + if (columns == 1) { + fprintf(handle, "%d\n", rows); + } else { + fprintf(handle, "%d %d\n", rows, columns); + } + + for (ii = 0; ii < rows; ii++) { + for (jj = 0; jj < columns; jj++) { + if (type == wbType_integer) { + int elem = ((int *)data)[ii * columns + jj]; + fprintf(handle, "%d", elem); + } else if (type == wbType_ubit8) { + int elem = ((unsigned char *)data)[ii * columns + jj]; + fprintf(handle, "%d", elem); + } else { + wbReal_t elem = ((wbReal_t *)data)[ii * columns + jj]; + fprintf(handle, "%f", elem); + } + if (jj == columns - 1) { + fprintf(handle, "\n"); + } else { + fprintf(handle, " "); + } + } + } + + return; +} + +static inline void wbExportCSV_setFile(wbExportCSV_t csv, + const char *path) { + if (csv != NULL) { + if (wbExportCSV_getFile(csv) != NULL) { + wbFile_delete(wbExportCSV_getFile(csv)); + } + if (path != NULL) { + wbExportCSV_getFile(csv) = wbFile_open(path, "w+"); + } else { + wbExportCSV_getFile(csv) = NULL; + } + } + + return; +} + +static inline wbExportCSV_t wbExportCSV_new(void) { + wbExportCSV_t csv; + + csv = wbNew(struct st_wbExportCSV_t); + + wbExportCSV_getFile(csv) = NULL; + wbExportCSV_setColumnCount(csv, -1); + wbExportCSV_setRowCount(csv, -1); + wbExportCSV_setSeperator(csv, '\0'); + + return csv; +} + +static inline void wbExportCSV_delete(wbExportCSV_t csv) { + if (csv != NULL) { + wbExportCSV_setFile(csv, NULL); + wbDelete(csv); + } +} + +static inline void wbExportCSV_write(wbExportCSV_t csv, void *data, + int rows, int columns, char sep, + wbType_t type) { + int ii, jj; + wbFile_t file; + FILE *handle; + char seperator[2]; + + if (csv == NULL || wbExportCSV_getFile(csv) == NULL) { + return; + } + + file = wbExportCSV_getFile(csv); + + handle = wbFile_getFileHandle(file); + + if (handle == NULL) { + return; + } + + if (sep == '\0') { + seperator[0] = ','; + } else { + seperator[0] = sep; + } + seperator[1] = '\0'; + + for (ii = 0; ii < rows; ii++) { + for (jj = 0; jj < columns; jj++) { + if (type == wbType_integer) { + int elem = ((int *)data)[ii * columns + jj]; + fprintf(handle, "%d", elem); + } else if (type == wbType_ubit8) { + int elem = ((unsigned char *)data)[ii * columns + jj]; + fprintf(handle, "%d", elem); + } else { + wbReal_t elem = ((wbReal_t *)data)[ii * columns + jj]; + fprintf(handle, "%f", elem); + } + if (jj == columns - 1) { + fprintf(handle, "\n"); + } else { + fprintf(handle, "%s", seperator); + } + } + } + + return; +} + +static inline wbExport_t wbExport_open(const char *file, + wbExportKind_t kind) { + wbExport_t exprt; + + if (file == NULL) { + wbLog(ERROR, "Go NULL for file value."); + wbExit(); + } + + wbExport_setFile(exprt, NULL); + wbExport_setKind(exprt, kind); + + if (kind == wbExportKind_raw) { + wbExportRaw_t raw = wbExportRaw_new(); + wbExportRaw_setFile(raw, file); + wbExport_setRaw(exprt, raw); + } else if (kind == wbExportKind_text) { + wbExportText_t txt = wbExportText_new(); + wbExportText_setFile(txt, file); + wbExport_setText(exprt, txt); + } else if (kind == wbExportKind_tsv || kind == wbExportKind_csv) { + wbExportCSV_t csv = wbExportCSV_new(); + if (kind == wbExportKind_csv) { + wbExportCSV_setSeperator(csv, ','); + } else { + wbExportCSV_setSeperator(csv, '\t'); + } + wbExportCSV_setFile(csv, file); + wbExport_setCSV(exprt, csv); + } else if (kind == wbExportKind_ppm) { + wbExport_setFile(exprt, wbString_duplicate(file)); + } else { + wbLog(ERROR, "Invalid export type."); + wbExit(); + } + + return exprt; +} + +static inline wbExport_t wbExport_open(const char *file, + const char *type0) { + wbExport_t exprt; + wbExportKind_t kind; + char *type; + + type = wbString_toLower(type0); + + if (wbString_sameQ(type, "csv")) { + kind = wbExportKind_csv; + } else if (wbString_sameQ(type, "tsv")) { + kind = wbExportKind_tsv; + } else if (wbString_sameQ(type, "raw") || wbString_sameQ(type, "dat")) { + kind = wbExportKind_raw; + } else if (wbString_sameQ(type, "ppm") || wbString_sameQ(type, "pbm")) { + kind = wbExportKind_ppm; + } else if (wbString_sameQ(type, "txt") || wbString_sameQ(type, "text")) { + kind = wbExportKind_text; + } else { + wbLog(ERROR, "Invalid export type ", type0); + wbExit(); + } + + exprt = wbExport_open(file, kind); + + wbDelete(type); + + return exprt; +} + +static inline void wbExport_close(wbExport_t exprt) { + wbExportKind_t kind; + + kind = wbExport_getKind(exprt); + + if (wbExport_getFile(exprt)) { + wbDelete(wbExport_getFile(exprt)); + } + + if (kind == wbExportKind_tsv || kind == wbExportKind_csv) { + wbExportCSV_t csv = wbExport_getCSV(exprt); + wbExportCSV_delete(csv); + wbExport_setCSV(exprt, NULL); + } else if (kind == wbExportKind_raw) { + wbExportRaw_t raw = wbExport_getRaw(exprt); + wbExportRaw_delete(raw); + wbExport_setRaw(exprt, NULL); + } else if (kind == wbExportKind_text) { + wbExportText_t text = wbExport_getText(exprt); + wbExportText_delete(text); + wbExport_setText(exprt, NULL); + } else if (kind == wbExportKind_ppm) { + } else { + wbLog(ERROR, "Invalid export type."); + wbExit(); + } + return; +} + +static inline void wbExport_writeAsImage(wbExport_t exprt, wbImage_t img) { + wbAssert(wbExport_getKind(exprt) == wbExportKind_ppm); + + wbPPM_export(wbExport_getFile(exprt), img); + + return; +} + +static inline void wbExport_write(wbExport_t exprt, void *data, int rows, + int columns, char sep, wbType_t type) { + wbExportKind_t kind; + + kind = wbExport_getKind(exprt); + if (kind == wbExportKind_tsv || kind == wbExportKind_csv) { + wbExportCSV_t csv = wbExport_getCSV(exprt); + wbExportCSV_write(csv, data, rows, columns, sep, type); + } else if (kind == wbExportKind_raw) { + wbExportRaw_t raw = wbExport_getRaw(exprt); + wbExportRaw_write(raw, data, rows, columns, type); + } else if (kind == wbExportKind_text) { + wbExportText_t text = wbExport_getText(exprt); + if (columns == 0) { + columns = 1; + } + if (rows == 0) { + rows = 1; + } + wbExportText_write(text, (const char *)data, rows * columns); + } else { + wbLog(ERROR, "Invalid export type."); + wbExit(); + } + return; +} + +static inline void wbExport_write(wbExport_t exprt, void *data, int rows, + int columns, wbType_t type) { + wbExport_write(exprt, data, rows, columns, ',', type); +} + +static wbExportKind_t _parseExportExtension(const char *file) { + char *extension; + wbExportKind_t kind; + + extension = wbFile_extension(file); + + if (wbString_sameQ(extension, "csv")) { + kind = wbExportKind_csv; + } else if (wbString_sameQ(extension, "tsv")) { + kind = wbExportKind_tsv; + } else if (wbString_sameQ(extension, "raw") || + wbString_sameQ(extension, "dat")) { + kind = wbExportKind_raw; + } else if (wbString_sameQ(extension, "text") || + wbString_sameQ(extension, "txt")) { + kind = wbExportKind_text; + } else if (wbString_sameQ(extension, "ppm")) { + kind = wbExportKind_ppm; + } else { + kind = wbExportKind_unknown; + wbLog(ERROR, "File ", file, " does not have a compatible extension."); + } + + wbDelete(extension); + + return kind; +} + +static void wbExport(const char *file, void *data, int rows, int columns, + wbType_t type) { + wbExportKind_t kind; + wbExport_t exprt; + + if (file == NULL) { + return; + } + + kind = _parseExportExtension(file); + exprt = wbExport_open(file, kind); + + wbExport_write(exprt, data, rows, columns, type); + wbExport_close(exprt); +} + +void wbExport(const char *file, unsigned char *data, int rows) { + wbExport(file, data, rows, 1); + return; +} + +void wbExport(const char *file, int *data, int rows) { + wbExport(file, data, rows, 1); + return; +} + +void wbExport(const char *file, wbReal_t *data, int rows) { + wbExport(file, data, rows, 1); + return; +} + +void wbExport(const char *file, unsigned char *data, int rows, + int columns) { + wbExportKind_t kind; + wbExport_t exprt; + + if (file == NULL) { + return; + } + + kind = _parseExportExtension(file); + exprt = wbExport_open(file, kind); + + wbExport_write(exprt, data, rows, columns, wbType_ubit8); + wbExport_close(exprt); +} + +void wbExport(const char *file, int *data, int rows, int columns) { + wbExportKind_t kind; + wbExport_t exprt; + + if (file == NULL) { + return; + } + + kind = _parseExportExtension(file); + exprt = wbExport_open(file, kind); + + wbExport_write(exprt, data, rows, columns, wbType_integer); + wbExport_close(exprt); +} + +void wbExport(const char *file, wbReal_t *data, int rows, int columns) { + wbExportKind_t kind; + wbExport_t exprt; + + if (file == NULL) { + return; + } + + kind = _parseExportExtension(file); + exprt = wbExport_open(file, kind); + + wbExport_write(exprt, data, rows, columns, wbType_real); + wbExport_close(exprt); +} + +void wbExport(const char *file, wbExportKind_t kind, void *data, int rows, + int columns, wbType_t type) { + wbExport_t exprt; + + if (file == NULL) { + return; + } + + exprt = wbExport_open(file, kind); + + wbExport_write(exprt, data, rows, columns, type); + wbExport_close(exprt); +} + +void wbExport(const char *file, wbImage_t img) { + wbExportKind_t kind; + wbExport_t exprt; + + if (file == NULL) { + return; + } + + kind = _parseExportExtension(file); + exprt = wbExport_open(file, kind); + + wbAssert(kind == wbExportKind_ppm); + + wbExport_writeAsImage(exprt, img); + wbExport_close(exprt); +} + +void wbExport_text(const char *file, void *data, int length) { + wbExport(file, wbExportKind_text, data, 1, length, wbType_ascii); +} diff --git a/CUDA_BasicMatrixMultiplication/libwb/wbExport.h b/CUDA_BasicMatrixMultiplication/libwb/wbExport.h new file mode 100644 index 0000000..dd16b3f --- /dev/null +++ b/CUDA_BasicMatrixMultiplication/libwb/wbExport.h @@ -0,0 +1,106 @@ + + +#ifndef __WB_EXPORT_H__ +#define __WB_EXPORT_H__ + +#include "wb.h" +#include "wbFile.h" +#include "wbPPM.h" + +typedef enum en_wbExportKind_t { + wbExportKind_unknown = -1, + wbExportKind_raw = 0x1000, + wbExportKind_csv, + wbExportKind_tsv, + wbExportKind_ppm, + wbExportKind_text, +} wbExportKind_t; + +typedef struct st_wbExportText_t { + int length; + wbFile_t file; +} * wbExportText_t; + +#define wbExportText_getLength(txt) ((txt)->length) +#define wbExportText_getFile(txt) ((txt)->file) + +#define wbExportText_setLength(txt, val) \ + (wbExportText_getLength(txt) = val) + +typedef struct st_wbExportRaw_t { + int rows; + int columns; + wbFile_t file; +} * wbExportRaw_t; + +#define wbExportRaw_getColumnCount(raw) ((raw)->columns) +#define wbExportRaw_getRowCount(raw) ((raw)->rows) +#define wbExportRaw_getFile(raw) ((raw)->file) + +#define wbExportRaw_setRowCount(raw, val) \ + (wbExportRaw_getRowCount(raw) = val) +#define wbExportRaw_setColumnCount(raw, val) \ + (wbExportRaw_getColumnCount(raw) = val) + +typedef struct st_wbExportCSV_t { + int rows; + int columns; + wbFile_t file; + char seperator; +} * wbExportCSV_t; + +#define wbExportCSV_getRowCount(csv) ((csv)->rows) +#define wbExportCSV_getColumnCount(csv) ((csv)->columns) +#define wbExportCSV_getFile(csv) ((csv)->file) +#define wbExportCSV_getSeperator(csv) ((csv)->seperator) + +#define wbExportCSV_setRowCount(csv, val) \ + (wbExportCSV_getRowCount(csv) = val) +#define wbExportCSV_setColumnCount(csv, val) \ + (wbExportCSV_getColumnCount(csv) = val) +#define wbExportCSV_setSeperator(csv, val) \ + (wbExportCSV_getSeperator(csv) = val) + +typedef struct st_wbExport_t { + wbExportKind_t kind; + union { + wbExportRaw_t raw; + wbExportCSV_t csv; + wbImage_t img; + wbExportText_t text; + } container; + char *file; +} wbExport_t; + +#define wbExport_getKind(exprt) ((exprt).kind) +#define wbExport_getContainer(exprt) ((exprt).container) +#define wbExport_getRaw(exprt) (wbExport_getContainer(exprt).raw) +#define wbExport_getCSV(exprt) (wbExport_getContainer(exprt).csv) +#define wbExport_getImage(exprt) (wbExport_getContainer(exprt).img) +#define wbExport_getText(exprt) (wbExport_getContainer(exprt).text) +#define wbExport_getFile(exprt) ((exprt).file) + +#define wbExport_setKind(exprt, val) (wbExport_getKind(exprt) = val) +#define wbExport_setRaw(exprt, val) (wbExport_getRaw(exprt) = val) +#define wbExport_setCSV(exprt, val) (wbExport_getCSV(exprt) = val) +#define wbExport_setImage(exprt, val) (wbExport_getImage(exprt) = val) +#define wbExport_setText(exprt, val) (wbExport_getText(exprt) = val) +#define wbExport_setFile(exprt, val) (wbExport_getFile(exprt) = val) + +void wbExport(const char *file, int *data, int rows, int columns); +void wbExport(const char *file, int *data, int rows); +void wbExport(const char *file, unsigned char *data, int rows, + int columns); +void wbExport(const char *file, unsigned char *data, int rows); +void wbExport(const char *file, int *data, int rows, int columns); +void wbExport(const char *file, int *data, int rows); +void wbExport(const char *file, wbReal_t *data, int rows, int columns); +void wbExport(const char *file, wbReal_t *data, int rows); +void wbExport(const char *file, wbImage_t img); + +void wbExport(const char *file, wbExportKind_t kind, void *data, int rows, + int columns, wbType_t type); + +void wbExport_text(const char *file, void *data, int length); + +#endif /* __WB_EXPORT_H__ */ diff --git a/CUDA_BasicMatrixMultiplication/libwb/wbFile.cpp b/CUDA_BasicMatrixMultiplication/libwb/wbFile.cpp new file mode 100644 index 0000000..b3fdbe7 --- /dev/null +++ b/CUDA_BasicMatrixMultiplication/libwb/wbFile.cpp @@ -0,0 +1,353 @@ + + +#include "wb.h" + +#define wbFile_maxCount 256 + +static wbFile_t wbFile_handles[wbFile_maxCount]; + +static int wbFile_nextIndex(void) { + int ii; + for (ii = 0; ii < wbFile_maxCount; ii++) { + if (wbFile_handles[ii] == NULL) { + return ii; + } + } + wbLog(ERROR, "Ran out of file handles."); + wbExit(); + return -1; +} + +wbFile_t wbFile_new(void) { + int idx = wbFile_nextIndex(); + wbFile_t file = wbNew(struct st_wbFile_t); + + wbAssert(idx >= 0); + + wbFile_setIndex(file, idx); + wbFile_setFileName(file, NULL); + wbFile_setMode(file, NULL); + wbFile_setFileHandle(file, NULL); + wbFile_setData(file, NULL); + + wbFile_handles[idx] = file; + + return file; +} + +void wbFile_delete(wbFile_t file) { + if (file != NULL) { + int idx = wbFile_getIndex(file); + if (wbFile_getFileName(file) != NULL) { + wbDelete(wbFile_getFileName(file)); + } + if (wbFile_getMode(file) != NULL) { + wbDelete(wbFile_getMode(file)); + } + if (wbFile_getFileHandle(file) != NULL) { + fflush(wbFile_getFileHandle(file)); + fclose(wbFile_getFileHandle(file)); + } + if (idx >= 0) { + wbAssert(wbFile_handles[idx] == file); + wbFile_handles[idx] = NULL; + } + if (wbFile_getData(file) != NULL) { + wbDelete(wbFile_getData(file)); + } + wbDelete(file); + } +} + +void wbFile_init(void) { + int ii; + + for (ii = 0; ii < wbFile_maxCount; ii++) { + wbFile_handles[ii] = NULL; + } +} + +void wbFile_atExit(void) { + int ii; + + for (ii = 0; ii < wbFile_maxCount; ii++) { + if (wbFile_handles[ii] != NULL) { + wbFile_delete(wbFile_handles[ii]); + } + } +} + +int wbFile_count(void) { + int ii, count = 0; + + for (ii = 0; ii < wbFile_maxCount; ii++) { + if (wbFile_handles[ii] != NULL) { + count++; + } + } + return count; +} + +wbFile_t wbFile_open(const char *fileName, const char *mode) { + FILE *handle; + wbFile_t file; + + if (fileName == NULL) { + return NULL; + } + + handle = fopen(fileName, mode); + if (handle == NULL) { + wbLog(ERROR, "Failed to open ", file, " in mode ", mode); + return NULL; + } + + file = wbFile_new(); + wbFile_setFileName(file, wbString_duplicate(fileName)); + wbFile_setMode(file, wbString_duplicate(mode)); + wbFile_setFileHandle(file, handle); + + return file; +} + +wbFile_t wbFile_open(const char *fileName) { + return wbFile_open(fileName, "r"); +} + +void wbFile_close(wbFile_t file) { + wbFile_delete(file); +} + +char *wbFile_read(wbFile_t file, size_t size, size_t count) { + size_t res; + char *buffer; + size_t bufferLen; + FILE *handle; + + if (file == NULL) { + return NULL; + } +#ifndef LAZY_FILE_LOAD + if (wbFile_getData(file) != NULL) { + char *data = wbFile_getData(file) + wbFile_getDataOffset(file); + wbFile_setDataOffset(file, wbFile_getDataOffset(file) + size * count); + return data; + } +#endif /* LAZY_FILE_LOAD */ + + handle = wbFile_getFileHandle(file); + bufferLen = size * count + 1; + buffer = wbNewArray(char, bufferLen); + + res = fread(buffer, size, count, handle); + // make valid C string + buffer[size * res] = '\0'; + + return buffer; +} + +char *wbFile_read(wbFile_t file, size_t len) { + char *buffer = wbFile_read(file, sizeof(char), len); + return buffer; +} + +void wbFile_rewind(wbFile_t file) { + if (file == NULL) { + return; + } + + if (wbFile_getData(file) == NULL) { + FILE *handle; + handle = wbFile_getFileHandle(file); + wbAssert(handle != NULL); + rewind(handle); + } +#ifndef LAZY_FILE_LOAD + else { + wbFile_setDataOffset(file, 0); + } +#endif + + return; +} + +size_t wbFile_size(wbFile_t file) { + size_t len; + FILE *handle; + + if (file == NULL) { + return 0; + } +#ifndef LAZY_FILE_LOAD + if (wbFile_getData(file) != NULL) { + if (wbFile_getLength(file) == 0) { + wbFile_setLength(file, strlen(wbFile_getData(file))); + } + return wbFile_getLength(file); + } +#endif /* LAZY_FILE_LOAD */ + + handle = wbFile_getFileHandle(file); + + fseek(handle, 0, SEEK_END); + len = ftell(handle); + rewind(handle); + + return len; +} + +char *wbFile_read(wbFile_t file) { + size_t len; + + if (file == NULL) { + return NULL; + } + + len = wbFile_size(file); + + if (len == 0) { + return NULL; + } + + wbFile_setLength(file, len); + + return wbFile_read(file, len); +} + +#define MAX_CHARS_PER_LINE (1 << 17) + +static char buffer[MAX_CHARS_PER_LINE]; + +char *wbFile_readLine(wbFile_t file) { + if (file == NULL) { + return NULL; + } +#ifdef LAZY_FILE_LOAD + FILE *handle; + memset(buffer, 0, MAX_CHARS_PER_LINE); + + handle = wbFile_getFileHandle(file); + + if (fgets(buffer, MAX_CHARS_PER_LINE - 1, handle)) { + return buffer; + } else { + // wbLog(ERROR, "Was not able to read line from ", + // wbFile_getFileName(file)); + return NULL; + } +#else + size_t newOffset; + size_t lenToNewLine = 0; + const char *tmp; + + if (wbFile_getData(file) == NULL) { + wbFile_setData(file, wbFile_read(file)); + fclose(wbFile_getFileHandle(file)); + wbFile_setFileHandle(file, NULL); + wbFile_setDataOffset(file, 0); + wbFile_setLength(file, strlen(wbFile_getData(file))); + } + + memset(buffer, 0, MAX_CHARS_PER_LINE); + + if (wbFile_getDataOffset(file) >= wbFile_getLength(file)) { + return NULL; + } + + newOffset = wbFile_getDataOffset(file); + tmp = wbFile_getData(file) + wbFile_getDataOffset(file); + while (newOffset < wbFile_getLength(file) && *tmp != '\n') { + tmp++; + lenToNewLine++; + newOffset++; + } + + memcpy(buffer, wbFile_getData(file) + wbFile_getDataOffset(file), + lenToNewLine); + wbFile_setDataOffset(file, newOffset + 1); + + return buffer; +#endif +} + +void wbFile_write(wbFile_t file, const void *buffer, size_t size, + size_t count) { + size_t res; + FILE *handle; + + if (file == NULL) { + return; + } + + handle = wbFile_getFileHandle(file); + + res = fwrite(buffer, size, count, handle); + if (res != count) { + wbLog(ERROR, "Failed to write data to ", wbFile_getFileName(file)); + } + + return; +} + +void wbFile_write(wbFile_t file, const void *buffer, size_t len) { + wbFile_write(file, buffer, sizeof(char), len); + return; +} + +void wbFile_write(wbFile_t file, const char *buffer) { + size_t len; + + len = strlen(buffer); + wbFile_write(file, buffer, len); + + return; +} + +void wbFile_writeLine(wbFile_t file, const char *buffer0) { + string buffer = wbString(buffer0, "\n"); + wbFile_write(file, buffer.c_str()); +} + +void wbFile_write(wbFile_t file, string buffer) { + wbFile_write(file, buffer.c_str()); +} + +void wbFile_writeLine(wbFile_t file, string buffer0) { + string buffer = buffer0 + "\n"; + wbFile_write(file, buffer.c_str()); +} + +wbBool wbFile_existsQ(const char *path) { + if (path == NULL) { + return wbFalse; + } else { + FILE *file = fopen(path, "r"); + if (file != NULL) { + fclose(file); + return wbTrue; + } + return wbFalse; + } +} + +char *wbFile_extension(const char *file) { + char *extension; + char *extensionLower; + char *end; + size_t len; + + len = strlen(file); + end = (char *)&file[len - 1]; + while (*end != '.') { + end--; + } + if (*end == '.') { + end++; + } + + extension = wbString_duplicate(end); + extensionLower = wbString_toLower(extension); + wbDelete(extension); + + return extensionLower; +} diff --git a/CUDA_BasicMatrixMultiplication/libwb/wbFile.h b/CUDA_BasicMatrixMultiplication/libwb/wbFile.h new file mode 100644 index 0000000..ea6b0cb --- /dev/null +++ b/CUDA_BasicMatrixMultiplication/libwb/wbFile.h @@ -0,0 +1,56 @@ + + +#ifndef __WB_FILE_H__ +#define __WB_FILE_H__ + +struct st_wbFile_t { + int index; + char *file; + char *mode; + char *data; + FILE *handle; + size_t len; + size_t offset; +}; + +#define wbFile_getIndex(file) ((file)->index) +#define wbFile_getFileName(file) ((file)->file) +#define wbFile_getMode(file) ((file)->mode) +#define wbFile_getData(file) ((file)->data) +#define wbFile_getLength(file) ((file)->len) +#define wbFile_getDataOffset(file) ((file)->offset) +#define wbFile_getFileHandle(file) ((file)->handle) + +#define wbFile_setIndex(file, val) (wbFile_getIndex(file) = val) +#define wbFile_setFileName(file, val) (wbFile_getFileName(file) = val) +#define wbFile_setMode(file, val) (wbFile_getMode(file) = val) +#define wbFile_setData(file, val) (wbFile_getData(file) = val) +#define wbFile_setLength(file, val) (wbFile_getLength(file) = val) +#define wbFile_setDataOffset(file, val) (wbFile_getDataOffset(file) = val) +#define wbFile_setFileHandle(file, val) (wbFile_getFileHandle(file) = val) + +wbFile_t wbFile_new(void); +void wbFile_delete(wbFile_t file); +void wbFile_close(wbFile_t file); +void wbFile_init(void); +void wbFile_atExit(void); +int wbFile_count(void); +wbFile_t wbFile_open(const char *fileName, const char *mode); +wbFile_t wbFile_open(const char *fileName); +char *wbFile_read(wbFile_t file, size_t size, size_t count); +char *wbFile_read(wbFile_t file, size_t len); +void wbFile_rewind(wbFile_t file); +size_t wbFile_size(wbFile_t file); +char *wbFile_read(wbFile_t file); +char *wbFile_readLine(wbFile_t file); +void wbFile_write(wbFile_t file, const void *buffer, size_t size, + size_t count); +void wbFile_write(wbFile_t file, const void *buffer, size_t len); +void wbFile_write(wbFile_t file, const char *buffer); +void wbFile_writeLine(wbFile_t file, const char *buffer0); +void wbFile_write(wbFile_t file, string buffer); +void wbFile_writeLine(wbFile_t file, string buffer0); +wbBool wbFile_existsQ(const char *path); +char *wbFile_extension(const char *file); + +#endif /* __WB_FILE_H__ */ diff --git a/CUDA_BasicMatrixMultiplication/libwb/wbImage.cpp b/CUDA_BasicMatrixMultiplication/libwb/wbImage.cpp new file mode 100644 index 0000000..1d95928 --- /dev/null +++ b/CUDA_BasicMatrixMultiplication/libwb/wbImage.cpp @@ -0,0 +1,134 @@ + + +#include "wb.h" + +static inline float _min(float x, float y) { + return x < y ? x : y; +} + +static inline float _max(float x, float y) { + return x > y ? x : y; +} + +static inline float _clamp(float x, float start, float end) { + return _min(_max(x, start), end); +} + +wbImage_t wbImage_new(int width, int height, int channels, float *data) { + wbImage_t img; + + img = wbNew(struct st_wbImage_t); + + wbImage_setWidth(img, width); + wbImage_setHeight(img, height); + wbImage_setChannels(img, channels); + wbImage_setPitch(img, width * channels); + + wbImage_setData(img, data); + return img; +} + +wbImage_t wbImage_new(int width, int height, int channels) { + float *data = wbNewArray(float, width *height *channels); + return wbImage_new(width, height, channels, data); +} + +wbImage_t wbImage_new(int width, int height) { + return wbImage_new(width, height, wbImage_channels); +} + +void wbImage_delete(wbImage_t img) { + if (img != NULL) { + if (wbImage_getData(img) != NULL) { + wbDelete(wbImage_getData(img)); + } + wbDelete(img); + } +} + +static inline void wbImage_setPixel(wbImage_t img, int x, int y, int c, + float val) { + float *data = wbImage_getData(img); + int channels = wbImage_getChannels(img); + int pitch = wbImage_getPitch(img); + + data[y * pitch + x * channels + c] = val; + + return; +} + +static inline float wbImage_getPixel(wbImage_t img, int x, int y, int c) { + float *data = wbImage_getData(img); + int channels = wbImage_getChannels(img); + int pitch = wbImage_getPitch(img); + + return data[y * pitch + x * channels + c]; +} + +wbBool wbImage_sameQ(wbImage_t a, wbImage_t b, + wbImage_onSameFunction_t onUnSame) { + if (a == NULL || b == NULL) { + wbLog(ERROR, "Comparing null images."); + return wbFalse; + } else if (a == b) { + return wbTrue; + } else if (wbImage_getWidth(a) != wbImage_getWidth(b)) { + wbLog(ERROR, "Image widths do not match."); + return wbFalse; + } else if (wbImage_getHeight(a) != wbImage_getHeight(b)) { + wbLog(ERROR, "Image heights do not match."); + return wbFalse; + } else if (wbImage_getChannels(a) != wbImage_getChannels(b)) { + wbLog(ERROR, "Image channels do not match."); + return wbFalse; + } else { + float *aData, *bData; + int width, height, channels; + int ii, jj, kk; + + aData = wbImage_getData(a); + bData = wbImage_getData(b); + + wbAssert(aData != NULL); + wbAssert(bData != NULL); + + width = wbImage_getWidth(a); + height = wbImage_getHeight(a); + channels = wbImage_getChannels(a); + + for (ii = 0; ii < height; ii++) { + for (jj = 0; jj < width; jj++) { + for (kk = 0; kk < channels; kk++) { + float x, y; + if (channels <= 3) { + x = _clamp(*aData++, 0, 1); + y = _clamp(*bData++, 0, 1); + } else { + x = *aData++; + y = *bData++; + } + if (wbUnequalQ(x, y)) { + if (onUnSame != NULL) { + string str = wbString( + "Image pixels do not match at position ( row = ", + wbString(ii, ", col = ", jj, ", channel = ", kk, + ") expecting a value of "), + wbString(y, " but got a computed value of ", x)); + onUnSame(str); + } + return wbFalse; + } + } + } + } + return wbTrue; + } +} + +static void wbImage_onUnsameFunction(string str) { + wbLog(ERROR, str); +} + +wbBool wbImage_sameQ(wbImage_t a, wbImage_t b) { + return wbImage_sameQ(a, b, wbImage_onUnsameFunction); +} diff --git a/CUDA_BasicMatrixMultiplication/libwb/wbImage.h b/CUDA_BasicMatrixMultiplication/libwb/wbImage.h new file mode 100644 index 0000000..020eec5 --- /dev/null +++ b/CUDA_BasicMatrixMultiplication/libwb/wbImage.h @@ -0,0 +1,40 @@ + + +#ifndef __IMAGE_H__ +#define __IMAGE_H__ + +#include "wbTypes.h" + +struct st_wbImage_t { + int width; + int height; + int channels; + int pitch; + float *data; +}; + +#define wbImage_channels 3 + +#define wbImage_getWidth(img) ((img)->width) +#define wbImage_getHeight(img) ((img)->height) +#define wbImage_getChannels(img) ((img)->channels) +#define wbImage_getPitch(img) ((img)->pitch) +#define wbImage_getData(img) ((img)->data) + +#define wbImage_setWidth(img, val) (wbImage_getWidth(img) = val) +#define wbImage_setHeight(img, val) (wbImage_getHeight(img) = val) +#define wbImage_setChannels(img, val) (wbImage_getChannels(img) = val) +#define wbImage_setPitch(img, val) (wbImage_getPitch(img) = val) +#define wbImage_setData(img, val) (wbImage_getData(img) = val) + +typedef void (*wbImage_onSameFunction_t)(string str); + +wbImage_t wbImage_new(int width, int height, int channels, float *data); +wbImage_t wbImage_new(int width, int height, int channels); +wbImage_t wbImage_new(int width, int height); +void wbImage_delete(wbImage_t img); +wbBool wbImage_sameQ(wbImage_t a, wbImage_t b, + wbImage_onSameFunction_t onUnSame); +wbBool wbImage_sameQ(wbImage_t a, wbImage_t b); + +#endif /* __IMAGE_H__ */ diff --git a/CUDA_BasicMatrixMultiplication/libwb/wbImport.cpp b/CUDA_BasicMatrixMultiplication/libwb/wbImport.cpp new file mode 100644 index 0000000..fccc071 --- /dev/null +++ b/CUDA_BasicMatrixMultiplication/libwb/wbImport.cpp @@ -0,0 +1,711 @@ + + +#include "wb.h" + +static inline void wbImportCSV_setFile(wbImportCSV_t csv, + const char *path) { + if (csv != NULL) { + if (wbImportCSV_getFile(csv) != NULL) { + wbFile_delete(wbImportCSV_getFile(csv)); + } + if (path != NULL) { + wbImportCSV_getFile(csv) = wbFile_open(path, "r"); + } else { + wbImportCSV_getFile(csv) = NULL; + } + } + + return; +} + +static inline wbImportCSV_t wbImportCSV_new(void) { + wbImportCSV_t csv; + + csv = wbNew(struct st_wbImportCSV_t); + + wbImportCSV_setRowCount(csv, -1); + wbImportCSV_setColumnCount(csv, -1); + wbImportCSV_setData(csv, NULL); + wbImportCSV_getFile(csv) = NULL; + wbImportCSV_setSeperator(csv, '\0'); + + return csv; +} + +static inline void wbImportCSV_delete(wbImportCSV_t csv) { + if (csv != NULL) { + wbImportCSV_setFile(csv, NULL); + if (wbImportCSV_getData(csv)) { + wbDelete(wbImportCSV_getData(csv)); + } + wbDelete(csv); + } +} + +static inline wbImportCSV_t wbImportCSV_findDimensions(wbImportCSV_t csv, + int *resRows, + int *resColumns) { + int rows = 0, columns = -1; + char *line; + wbFile_t file; + char seperator[2]; + + if (csv == NULL) { + return NULL; + } + + if (wbImportCSV_getSeperator(csv) == '\0') { + seperator[0] = ','; + } else { + seperator[0] = wbImportCSV_getSeperator(csv); + } + seperator[1] = '\0'; + + file = wbImportCSV_getFile(csv); + + while ((line = wbFile_readLine(file)) != NULL) { + int currColumn = 0; + char *token = strtok(line, seperator); + while (token != NULL) { + token = strtok(NULL, seperator); + currColumn++; + } + rows++; + if (columns == -1) { + columns = currColumn; + } + if (columns != currColumn) { + wbLog(ERROR, "The csv file is not rectangular."); + } + wbAssert(columns == currColumn); + } + + wbFile_rewind(file); + + *resRows = rows; + *resColumns = columns; + + return csv; +} + +static inline int *csv_readAsInteger(wbFile_t file, char sep, int rows, + int columns) { + int ii = 0; + int *data; + char *line; + int var; + char seperator[2]; + + if (file == NULL) { + return NULL; + } + + data = wbNewArray(int, rows *columns); + + if (sep == '\0') { + seperator[0] = ','; + } else { + seperator[0] = sep; + } + seperator[1] = '\0'; + + // printf("cols = %d rows = %d\n", columns, rows); + if (columns == 1) { + while ((line = wbFile_readLine(file)) != NULL) { + sscanf(line, "%d", &var); + // printf("reading %d\n", var); + data[ii++] = var; + } + } else { + while ((line = wbFile_readLine(file)) != NULL) { + char *token = strtok(line, seperator); + while (token != NULL) { + sscanf(token, "%d", &var); + token = strtok(NULL, seperator); + data[ii++] = var; + } + } + } + + return data; +} + +static inline wbReal_t *csv_readAsReal(wbFile_t file, char sep, int rows, + int columns) { + int ii = 0; + wbReal_t *data; + char *line; + wbReal_t var; + char seperator[2]; + + if (file == NULL) { + return NULL; + } + + data = wbNewArray(wbReal_t, rows * columns); + + if (sep == '\0') { + seperator[0] = ','; + } else { + seperator[0] = sep; + } + seperator[1] = '\0'; + + if (columns == 1) { + while ((line = wbFile_readLine(file)) != NULL) { + sscanf(line, "%f", &var); + data[ii++] = var; + } + } else { + while ((line = wbFile_readLine(file)) != NULL) { + char *token = strtok(line, seperator); + while (token != NULL) { + sscanf(token, "%f", &var); + token = strtok(NULL, seperator); + data[ii++] = var; + } + } + } + + return data; +} + +static inline wbImportCSV_t wbImportCSV_read(wbImportCSV_t csv, + wbType_t type) { + void *data; + wbFile_t file; + char seperator; + int rows, columns; + + if (csv == NULL) { + return NULL; + } + + if (wbImportCSV_getRowCount(csv) == -1 || + wbImportCSV_getColumnCount(csv) == -1) { + if (wbImportCSV_findDimensions(csv, &rows, &columns) == NULL) { + wbLog(ERROR, "Failed to figure out csv dimensions."); + return NULL; + } + wbImportCSV_setRowCount(csv, rows); + wbImportCSV_setColumnCount(csv, columns); + } + + file = wbImportCSV_getFile(csv); + seperator = wbImportCSV_getSeperator(csv); + rows = wbImportCSV_getRowCount(csv); + columns = wbImportCSV_getColumnCount(csv); + + if (wbImportCSV_getData(csv) != NULL) { + wbDelete(wbImportCSV_getData(csv)); + wbImportCSV_setData(csv, NULL); + } + + if (type == wbType_integer) { + // printf("ReadXXXing as integer...\n"); + data = csv_readAsInteger(file, seperator, rows, columns); + } else { + data = csv_readAsReal(file, seperator, rows, columns); + } + + wbImportCSV_setData(csv, data); + + return csv; +} + +static inline wbImportCSV_t wbImportCSV_readAsInteger(wbImportCSV_t csv) { + return wbImportCSV_read(csv, wbType_integer); +} + +static inline wbImportCSV_t wbImportCSV_readAsReal(wbImportCSV_t csv) { + return wbImportCSV_read(csv, wbType_real); +} + +static inline void wbImportRaw_setFile(wbImportRaw_t raw, + const char *path) { + if (raw != NULL) { + if (wbImportRaw_getFile(raw) != NULL) { + wbFile_delete(wbImportRaw_getFile(raw)); + } + if (path != NULL) { + wbImportRaw_getFile(raw) = wbFile_open(path, "r"); + } else { + wbImportRaw_getFile(raw) = NULL; + } + } + + return; +} + +static inline wbImportRaw_t wbImportRaw_new(void) { + wbImportRaw_t raw; + + raw = wbNew(struct st_wbImportRaw_t); + + wbImportRaw_setRowCount(raw, -1); + wbImportRaw_setColumnCount(raw, -1); + wbImportRaw_setData(raw, NULL); + wbImportRaw_getFile(raw) = NULL; + + return raw; +} + +static inline void wbImportRaw_delete(wbImportRaw_t raw) { + if (raw != NULL) { + wbImportRaw_setFile(raw, NULL); + if (wbImportRaw_getData(raw)) { + wbDelete(wbImportRaw_getData(raw)); + } + wbDelete(raw); + } +} + +static inline wbBool lineHasSpace(const char *line) { + while (*line != '\0') { + if (*line == ' ') { + return wbTrue; + } + line++; + } + return wbFalse; +} + +static inline char *lineStrip(const char *line) { + char *sl = wbString_duplicate(line); + char *iter = sl; + size_t slen = strlen(line); + + iter += slen - 1; + while (*iter == '\0' || *iter == '\r' || *iter == '\t' || + *iter == '\n' || *iter == ' ') { + *iter-- = '\0'; + } + return sl; +} + +static inline wbBool wbImportRaw_findDimensions(wbImportRaw_t raw) { + if (raw != NULL) { + int rows; + int columns; + char *line; + wbFile_t file; + char *strippedLine; + + file = wbImportRaw_getFile(raw); + + wbFile_rewind(file); + + line = wbFile_readLine(file); + + if (line == NULL) { + return wbTrue; + } + + strippedLine = lineStrip(line); + + if (lineHasSpace(strippedLine)) { + sscanf(strippedLine, "%d %d", &rows, &columns); + } else { + columns = 1; + sscanf(strippedLine, "%d", &rows); + } + + wbImportRaw_setRowCount(raw, rows); + wbImportRaw_setColumnCount(raw, columns); + + wbDelete(strippedLine); + + return wbFalse; + } + + return wbTrue; +} + +static inline wbImportRaw_t wbImportRaw_read(wbImportRaw_t raw, + wbType_t type) { + void *data; + wbFile_t file; + char seperator; + int rows, columns; + + if (raw == NULL) { + return NULL; + } + + if (wbImportRaw_getRowCount(raw) == -1 || + wbImportRaw_getColumnCount(raw) == -1) { + if (wbImportRaw_findDimensions(raw)) { + wbLog(ERROR, "Failed to figure out raw dimensions."); + return NULL; + } + } + + file = wbImportRaw_getFile(raw); + seperator = ' '; + rows = wbImportRaw_getRowCount(raw); + columns = wbImportRaw_getColumnCount(raw); + + if (wbImportRaw_getData(raw) != NULL) { + wbDelete(wbImportRaw_getData(raw)); + wbImportRaw_setData(raw, NULL); + } + + if (type == wbType_integer) { + // printf("Rdin gas integer...\n"); + data = csv_readAsInteger(file, seperator, rows, columns); + } else { + data = csv_readAsReal(file, seperator, rows, columns); + } + + wbImportRaw_setData(raw, data); + + return raw; +} + +static inline wbImportRaw_t wbImportRaw_readAsInteger(wbImportRaw_t raw) { + return wbImportRaw_read(raw, wbType_integer); +} + +static inline wbImportRaw_t wbImportRaw_readAsReal(wbImportRaw_t raw) { + return wbImportRaw_read(raw, wbType_real); +} + +static inline wbImportText_t wbImportText_new(void) { + wbImportText_t text; + + text = wbNew(struct st_wbImportText_t); + + wbImportText_setLength(text, 0); + wbImportText_setData(text, NULL); + wbImportText_getFile(text) = NULL; + + return text; +} + +static inline void wbImportText_setFile(wbImportText_t text, + const char *path) { + if (text != NULL) { + if (wbImportText_getFile(text) != NULL) { + wbFile_delete(wbImportText_getFile(text)); + } + if (path != NULL) { + wbImportText_getFile(text) = wbFile_open(path, "r"); + } else { + wbImportText_getFile(text) = NULL; + } + } + + return; +} + +static inline void wbImportText_delete(wbImportText_t text) { + if (text != NULL) { + wbImportText_setFile(text, NULL); + if (wbImportText_getData(text)) { + wbDelete(wbImportText_getData(text)); + } + wbDelete(text); + } +} + +static inline wbImportText_t wbImportText_read(wbImportText_t text) { + char *data; + wbFile_t file; + int length; + + if (text == NULL) { + return NULL; + } + + file = wbImportText_getFile(text); + + if (wbImportText_getData(text) != NULL) { + wbDelete(wbImportText_getData(text)); + wbImportText_setData(text, NULL); + } + + length = wbFile_size(file); + data = wbFile_read(file, length); + + wbImportText_setData(text, data); + wbImportText_setLength(text, length); + + return text; +} + +static inline wbImport_t wbImport_open(const char *file, + wbImportKind_t kind) { + wbImport_t imp; + + if (file == NULL) { + wbLog(ERROR, "Go NULL for file value."); + wbExit(); + } + + if (!wbFile_existsQ(file)) { + wbLog(ERROR, "File ", file, " does not exist."); + wbExit(); + } + + wbImport_setKind(imp, kind); + + if (kind == wbImportKind_raw) { + wbImportRaw_t raw = wbImportRaw_new(); + wbImportRaw_setFile(raw, file); + wbImport_setRaw(imp, raw); + } else if (kind == wbImportKind_tsv || kind == wbImportKind_csv) { + wbImportCSV_t csv = wbImportCSV_new(); + if (kind == wbImportKind_csv) { + wbImportCSV_setSeperator(csv, ','); + } else { + wbImportCSV_setSeperator(csv, '\t'); + } + wbImportCSV_setFile(csv, file); + wbImport_setCSV(imp, csv); + } else if (kind == wbImportKind_text) { + wbImportText_t text = wbImportText_new(); + wbImportText_setFile(text, file); + wbImport_setText(imp, text); + } else if (kind == wbImportKind_ppm) { + wbImage_t img = wbPPM_import(file); + wbImport_setImage(imp, img); + } else { + wbLog(ERROR, "Invalid import type."); + wbExit(); + } + + return imp; +} + +static inline wbImport_t wbImport_open(const char *file, + const char *type0) { + wbImport_t imp; + wbImportKind_t kind; + char *type; + + type = wbString_toLower(type0); + + if (wbString_sameQ(type, "csv")) { + kind = wbImportKind_csv; + } else if (wbString_sameQ(type, "tsv")) { + kind = wbImportKind_tsv; + } else if (wbString_sameQ(type, "raw") || wbString_sameQ(type, "dat")) { + kind = wbImportKind_raw; + } else if (wbString_sameQ(type, "ppm")) { + kind = wbImportKind_ppm; + } else if (wbString_sameQ(type, "text") || wbString_sameQ(type, "txt")) { + kind = wbImportKind_text; + } else { + wbLog(ERROR, "Invalid import type ", type0); + wbExit(); + } + + imp = wbImport_open(file, kind); + + wbDelete(type); + + return imp; +} + +static inline void wbImport_close(wbImport_t imp) { + wbImportKind_t kind; + + kind = wbImport_getKind(imp); + if (kind == wbImportKind_tsv || kind == wbImportKind_csv) { + wbImportCSV_t csv = wbImport_getCSV(imp); + wbImportCSV_delete(csv); + wbImport_setCSV(imp, NULL); + } else if (kind == wbImportKind_raw) { + wbImportRaw_t raw = wbImport_getRaw(imp); + wbImportRaw_delete(raw); + wbImport_setRaw(imp, NULL); + } else if (kind == wbImportKind_text) { + wbImportText_t text = wbImport_getText(imp); + wbImportText_delete(text); + wbImport_setText(imp, NULL); + } else if (kind == wbImportKind_ppm) { + } else { + wbLog(ERROR, "Invalid import type."); + wbExit(); + } + return; +} + +static inline void *wbImport_read(wbImport_t imp, wbType_t type) { + void *data = NULL; + wbImportKind_t kind; + + kind = wbImport_getKind(imp); + if (kind == wbImportKind_tsv || kind == wbImportKind_csv) { + wbImportCSV_t csv = wbImport_getCSV(imp); + wbImportCSV_read(csv, type); + data = wbImportCSV_getData(csv); + } else if (kind == wbImportKind_raw) { + wbImportRaw_t raw = wbImport_getRaw(imp); + wbImportRaw_read(raw, type); + data = wbImportRaw_getData(raw); + } else if (wbImportKind_text == kind) { + wbImportText_t text = wbImport_getText(imp); + text = wbImportText_read(text); + data = wbImportText_getData(text); + + } else { + wbLog(ERROR, "Invalid import type."); + wbExit(); + } + return data; +} + +static inline int *wbImport_readAsInteger(wbImport_t imp) { + void *data = wbImport_read(imp, wbType_integer); + return (int *)data; +} + +static inline wbReal_t *wbImport_readAsReal(wbImport_t imp) { + void *data = wbImport_read(imp, wbType_real); + return (wbReal_t *)data; +} + +static inline wbChar_t *wbImport_readAsText(wbImport_t imp) { + void *data = wbImport_read(imp, wbType_ubit8); + return (wbChar_t *)data; +} + +static wbImportKind_t _parseImportExtension(const char *file) { + char *extension; + wbImportKind_t kind; + + extension = wbFile_extension(file); + + if (wbString_sameQ(extension, "csv")) { + kind = wbImportKind_csv; + } else if (wbString_sameQ(extension, "tsv")) { + kind = wbImportKind_tsv; + } else if (wbString_sameQ(extension, "raw") || + wbString_sameQ(extension, "dat")) { + kind = wbImportKind_raw; + } else if (wbString_sameQ(extension, "ppm") || + wbString_sameQ(extension, "pbm")) { + kind = wbImportKind_ppm; + } else if (wbString_sameQ(extension, "text") || + wbString_sameQ(extension, "txt")) { + kind = wbImportKind_text; + } else { + kind = wbImportKind_unknown; + wbLog(ERROR, "File ", file, " does not have a compatible extension."); + } + + wbDelete(extension); + + return kind; +} + +void *wbImport(const char *file, int *resRows, int *resColumns, + const char *type) { + void *data, *res; + wbImport_t imp; + size_t sz; + int columns = 0, rows = 0; + wbImportKind_t kind; + + if (file == NULL) { + fprintf(stderr, "Failed to import file.\n"); + wbExit(); + } + + kind = _parseImportExtension(file); + + wbAssert(kind != wbImportKind_unknown); + + imp = wbImport_open(file, kind); + if (wbString_sameQ(type, "Real")) { + data = wbImport_readAsReal(imp); + sz = sizeof(wbReal_t); + } else if (wbString_sameQ(type, "Text")) { + data = wbImport_readAsText(imp); + sz = sizeof(char); + } else { + // printf("Reading as integer..d\n"); + data = wbImport_readAsInteger(imp); + sz = sizeof(int); + } + + if (kind == wbImportKind_csv || kind == wbImportKind_tsv) { + rows = wbImportCSV_getRowCount(wbImport_getCSV(imp)); + columns = wbImportCSV_getColumnCount(wbImport_getCSV(imp)); + } else if (kind == wbImportKind_raw) { + rows = wbImportRaw_getRowCount(wbImport_getRaw(imp)); + columns = wbImportRaw_getColumnCount(wbImport_getRaw(imp)); + } else if (kind == wbImportKind_text) { + rows = 1; + columns = wbImportText_getLength(wbImport_getText(imp)); + } + + if (rows == 1 && columns > 0) { + rows = columns; + columns = 1; + } + + if (resRows != NULL) { + *resRows = rows; + } + + if (resColumns != NULL) { + *resColumns = columns; + } + + res = wbMalloc(sz * rows * columns); + memcpy(res, data, sz * rows * columns); + + wbImport_close(imp); + + return res; +} + +void *wbImport(const char *file, int *rows, int *columns) { + return wbImport(file, rows, columns, "Real"); +} + +EXTERN_C void *wbImport(const char *file, int *rows) { + return wbImport(file, rows, NULL, "Real"); +} + +void *wbImport(const char *file, int *res_rows, const char *type) { + int cols, rows; + void *res = wbImport(file, &rows, &cols, type); + if (rows == 1 && cols > 1) { + rows = cols; + } + *res_rows = rows; + return res; +} + +wbImage_t wbImport(const char *file) { + wbImage_t img; + wbImport_t imp; + wbImportKind_t kind; + + if (file == NULL) { + fprintf(stderr, "Failed to import file.\n"); + wbExit(); + } + + kind = _parseImportExtension(file); + + wbAssert(kind == wbImportKind_ppm); + + imp = wbImport_open(file, kind); + img = wbImport_getImage(imp); + wbImport_close(imp); + + return img; +} + +int wbImport_flag(const char *file) { + int res; + wbFile_t fh = wbFile_open(file, "r"); + const char *line = wbFile_readLine(fh); + sscanf(line, "%d", &res); + wbFile_close(fh); + return res; +} diff --git a/CUDA_BasicMatrixMultiplication/libwb/wbImport.h b/CUDA_BasicMatrixMultiplication/libwb/wbImport.h new file mode 100644 index 0000000..ce13e1b --- /dev/null +++ b/CUDA_BasicMatrixMultiplication/libwb/wbImport.h @@ -0,0 +1,103 @@ + +#ifndef __WB_IMPORT_H__ +#define __WB_IMPORT_H__ + +#include "wbImage.h" + +typedef enum en_wbImportKind_t { + wbImportKind_unknown = -1, + wbImportKind_raw = 0x1000, + wbImportKind_csv, + wbImportKind_tsv, + wbImportKind_ppm, + wbImportKind_text +} wbImportKind_t; + +#define wbType_real wbType_float + +typedef struct st_wbImportCSV_t { + int rows; + int columns; + void *data; + wbFile_t file; + char seperator; +} * wbImportCSV_t; + +#define wbImportCSV_getRowCount(csv) ((csv)->rows) +#define wbImportCSV_getColumnCount(csv) ((csv)->columns) +#define wbImportCSV_getData(csv) ((csv)->data) +#define wbImportCSV_getFile(csv) ((csv)->file) +#define wbImportCSV_getSeperator(csv) ((csv)->seperator) + +#define wbImportCSV_setRowCount(csv, val) \ + (wbImportCSV_getRowCount(csv) = val) +#define wbImportCSV_setColumnCount(csv, val) \ + (wbImportCSV_getColumnCount(csv) = val) +#define wbImportCSV_setData(csv, val) (wbImportCSV_getData(csv) = val) +#define wbImportCSV_setSeperator(csv, val) \ + (wbImportCSV_getSeperator(csv) = val) + +typedef struct st_wbImportRaw_t { + int rows; + int columns; + void *data; + wbFile_t file; +} * wbImportRaw_t; + +#define wbImportRaw_getRowCount(raw) ((raw)->rows) +#define wbImportRaw_getColumnCount(raw) ((raw)->columns) +#define wbImportRaw_getData(raw) ((raw)->data) +#define wbImportRaw_getFile(raw) ((raw)->file) + +#define wbImportRaw_setRowCount(raw, val) \ + (wbImportRaw_getRowCount(raw) = val) +#define wbImportRaw_setColumnCount(raw, val) \ + (wbImportRaw_getColumnCount(raw) = val) +#define wbImportRaw_setData(raw, val) (wbImportRaw_getData(raw) = val) + +typedef struct st_wbImportText_t { + int length; + char *data; + wbFile_t file; +} * wbImportText_t; + +#define wbImportText_getLength(txt) ((txt)->length) +#define wbImportText_getData(txt) ((txt)->data) +#define wbImportText_getFile(txt) ((txt)->file) + +#define wbImportText_setLength(txt, val) \ + (wbImportText_getLength(txt) = val) +#define wbImportText_setData(txt, val) (wbImportText_getData(txt) = val) + +typedef struct st_wbImport_t { + wbImportKind_t kind; + union { + wbImportRaw_t raw; + wbImportCSV_t csv; + wbImportText_t text; + wbImage_t img; + } container; +} wbImport_t; + +#define wbImport_getKind(imp) ((imp).kind) +#define wbImport_getContainer(imp) ((imp).container) +#define wbImport_getRaw(imp) (wbImport_getContainer(imp).raw) +#define wbImport_getCSV(imp) (wbImport_getContainer(imp).csv) +#define wbImport_getText(imp) (wbImport_getContainer(imp).text) +#define wbImport_getImage(imp) (wbImport_getContainer(imp).img) + +#define wbImport_setKind(imp, val) (wbImport_getKind(imp) = val) +#define wbImport_setRaw(imp, val) (wbImport_getRaw(imp) = val) +#define wbImport_setCSV(imp, val) (wbImport_getCSV(imp) = val) +#define wbImport_setText(imp, val) (wbImport_getText(imp) = val) +#define wbImport_setImage(imp, val) (wbImport_getImage(imp) = val) + +EXTERN_C void *wbImport(const char *file, int *rows); +void *wbImport(const char *file, int *rows, int *columns); +void *wbImport(const char *file, int *rows, const char *type); +void *wbImport(const char *file, int *resRows, int *resColumns, + const char *type); +wbImage_t wbImport(const char *file); +int wbImport_flag(const char *file); + +#endif /* __WB_IMPORT_H__ */ diff --git a/CUDA_BasicMatrixMultiplication/libwb/wbInit.cpp b/CUDA_BasicMatrixMultiplication/libwb/wbInit.cpp new file mode 100644 index 0000000..96ebcf3 --- /dev/null +++ b/CUDA_BasicMatrixMultiplication/libwb/wbInit.cpp @@ -0,0 +1,85 @@ + +#include "wb.h" + +#define MB (1 << 20) +#ifndef WB_DEFAULT_HEAP_SIZE +#define WB_DEFAULT_HEAP_SIZE (1024 * MB) +#endif /* WB_DEFAULT_HEAP_SIZE */ + +static bool _initializedQ = wbFalse; + +#ifndef WB_USE_WINDOWS +__attribute__((__constructor__)) +#endif /* WB_USE_WINDOWS */ +void wb_init(int * +#ifdef WB_USE_MPI + argc +#endif /* WB_USE_MPI */ + , + char *** +#ifdef WB_USE_MPI + argv +#endif /* WB_USE_MPI */ + ) { + if (_initializedQ == wbTrue) { + return; + } +#ifdef WB_USE_MPI + wbMPI_Init(argc, argv); +#endif /* WB_USE_MPI */ + +#ifdef WB_USE_CUDA + CUresult err = cuInit(0); + +/* Select a random GPU */ + +#ifdef WB_USE_MPI + if (rankCount() > 1) { + int deviceCount; + cudaGetDeviceCount(&deviceCount); + srand(time(NULL)); + cudaSetDevice(wbMPI_getRank() % deviceCount); + } else { + int deviceCount; + cudaGetDeviceCount(&deviceCount); + + srand(time(NULL)); + cudaSetDevice(rand() % deviceCount); + } +#else + { + int deviceCount; + cudaGetDeviceCount(&deviceCount); + + srand(time(NULL)); + cudaSetDevice(rand() % deviceCount); + } +#endif /* WB_USE_MPI */ + + cudaDeviceSetLimit(cudaLimitPrintfFifoSize, 1 * MB); + cudaDeviceSetLimit(cudaLimitMallocHeapSize, WB_DEFAULT_HEAP_SIZE); + + cudaDeviceSynchronize(); + +#endif /* WB_USE_CUDA */ + +#ifdef WB_USE_WINDOWS + QueryPerformanceFrequency((LARGE_INTEGER *)&_hrtime_frequency); +#endif /* _MSC_VER */ + + _hrtime(); + + _timer = wbTimer_new(); + _logger = wbLogger_new(); + _initializedQ = wbTrue; + + wbFile_init(); + + solutionJSON = NULL; + +#ifdef WB_USE_MPI + atexit(wbMPI_Exit); +#else /* WB_USE_MPI */ + atexit(wb_atExit); +#endif /* WB_USE_MPI */ +} diff --git a/CUDA_BasicMatrixMultiplication/libwb/wbInit.h b/CUDA_BasicMatrixMultiplication/libwb/wbInit.h new file mode 100644 index 0000000..40e8e1c --- /dev/null +++ b/CUDA_BasicMatrixMultiplication/libwb/wbInit.h @@ -0,0 +1,11 @@ + + +#ifndef __WB_INIT_H__ +#define __WB_INIT_H__ + +#ifndef _MSC_VER +__attribute__((__constructor__)) +#endif /* _MSC_VER */ +void wb_init(int *argc, char ***argv); + +#endif /* __WB_INIT_H__ */ diff --git a/CUDA_BasicMatrixMultiplication/libwb/wbLogger.cpp b/CUDA_BasicMatrixMultiplication/libwb/wbLogger.cpp new file mode 100644 index 0000000..c2e2e17 --- /dev/null +++ b/CUDA_BasicMatrixMultiplication/libwb/wbLogger.cpp @@ -0,0 +1,310 @@ + +#include "wb.h" + +wbLogger_t _logger = NULL; + +static inline wbBool wbLogEntry_hasNext(wbLogEntry_t elem) { + return wbLogEntry_getNext(elem) != NULL; +} + +static inline wbLogEntry_t wbLogEntry_new() { + wbLogEntry_t elem; + + elem = wbNew(struct st_wbLogEntry_t); + + wbLogEntry_setMessage(elem, NULL); + wbLogEntry_setMPIRank(elem, wbMPI_getRank()); + wbLogEntry_setTime(elem, _hrtime()); + + wbLogEntry_setLevel(elem, wbLogLevel_TRACE); + + wbLogEntry_setNext(elem, NULL); + + wbLogEntry_setLine(elem, -1); + wbLogEntry_setFile(elem, NULL); + wbLogEntry_setFunction(elem, NULL); + + return elem; +} + +static inline wbLogEntry_t +wbLogEntry_initialize(wbLogLevel_t level, string msg, const char *file, + const char *fun, int line) { + wbLogEntry_t elem; + + elem = wbLogEntry_new(); + + wbLogEntry_setLevel(elem, level); + + wbLogEntry_setMessage(elem, wbString_duplicate(msg)); + + wbLogEntry_setLine(elem, line); + wbLogEntry_setFile(elem, file); + wbLogEntry_setFunction(elem, fun); + + return elem; +} + +static inline void wbLogEntry_delete(wbLogEntry_t elem) { + if (elem != NULL) { + if (wbLogEntry_getMessage(elem) != NULL) { + wbFree(wbLogEntry_getMessage(elem)); + } + wbDelete(elem); + } + return; +} + +static inline const char *getLevelName(wbLogLevel_t level) { + switch (level) { + case wbLogLevel_unknown: + return "Unknown"; + case wbLogLevel_OFF: + return "Off"; + case wbLogLevel_FATAL: + return "Fatal"; + case wbLogLevel_ERROR: + return "Error"; + case wbLogLevel_WARN: + return "Warn"; + case wbLogLevel_INFO: + return "Info"; + case wbLogLevel_DEBUG: + return "Debug"; + case wbLogLevel_TRACE: + return "Trace"; + } + return NULL; +} + +static inline json11::Json wbLogEntry_toJSONObject(wbLogEntry_t elem) { + json11::Json json = json11::Json::object{ + {"mpi_rank", wbLogEntry_getMPIRank(elem)}, + {"level", getLevelName(wbLogEntry_getLevel(elem))}, + {"file", wbLogEntry_getFile(elem)}, + {"function", wbLogEntry_getFunction(elem)}, + {"line", wbLogEntry_getLine(elem)}, + {"time", wbLogEntry_getTime(elem)}, + {"message", wbLogEntry_getMessage(elem)}, + }; + return json; +} + +static inline string wbLogEntry_toJSON(wbLogEntry_t elem) { + if (elem == NULL) { + return ""; + } else if (WB_USE_JSON11) { + json11::Json json = wbLogEntry_toJSONObject(elem); + return json.string_value(); + } else { + stringstream ss; + + ss << "{\n"; + ss << wbString_quote("mpi_rank") << ":" + << wbString(wbLogEntry_getMPIRank(elem)) << ",\n"; + ss << wbString_quote("level") << ":" + << wbString_quote(getLevelName(wbLogEntry_getLevel(elem))) << ",\n"; + ss << wbString_quote("message") << ":" + << wbString_quote(wbLogEntry_getMessage(elem)) << ",\n"; + ss << wbString_quote("file") << ":" + << wbString_quote(wbLogEntry_getFile(elem)) << ",\n"; + ss << wbString_quote("function") << ":" + << wbString_quote(wbLogEntry_getFunction(elem)) << ",\n"; + ss << wbString_quote("line") << ":" << wbLogEntry_getLine(elem) + << ",\n"; + ss << wbString_quote("time") << ":" << wbLogEntry_getTime(elem) + << "\n"; + ss << "}"; + + return ss.str(); + } + return ""; +} + +static inline string wbLogEntry_toXML(wbLogEntry_t elem) { + if (elem != NULL) { + stringstream ss; + + ss << "\n"; + ss << "" + << "LoggerElement" + << "\n"; + ss << "" << wbLogEntry_getLevel(elem) << "\n"; + ss << "" << wbLogEntry_getMessage(elem) << "\n"; + ss << "" << wbLogEntry_getFile(elem) << "\n"; + ss << "" << wbLogEntry_getFunction(elem) << "\n"; + ss << "" << wbLogEntry_getLine(elem) << "\n"; + ss << "\n"; + ss << "\n"; + + return ss.str(); + } + return ""; +} + +wbLogger_t wbLogger_new() { + wbLogger_t logger; + + logger = wbNew(struct st_wbLogger_t); + + wbLogger_setLength(logger, 0); + wbLogger_setHead(logger, NULL); + + wbLogger_getLevel(logger) = wbLogLevel_TRACE; + + return logger; +} + +static inline void _wbLogger_setLevel(wbLogger_t logger, + wbLogLevel_t level) { + wbLogger_getLevel(logger) = level; +} + +static inline void _wbLogger_setLevel(wbLogLevel_t level) { + _wbLogger_setLevel(_logger, level); +} + +#define wbLogger_setLevel(level) _wbLogger_setLevel(wbLogLevel_##level) + +void wbLogger_clear(wbLogger_t logger) { + if (logger != NULL) { + wbLogEntry_t tmp; + wbLogEntry_t iter; + + iter = wbLogger_getHead(logger); + while (iter != NULL) { + tmp = wbLogEntry_getNext(iter); + wbLogEntry_delete(iter); + iter = tmp; + } + + wbLogger_setLength(logger, 0); + wbLogger_setHead(logger, NULL); + } +} + +void wbLogger_delete(wbLogger_t logger) { + if (logger != NULL) { + wbLogger_clear(logger); + wbDelete(logger); + } + return; +} + +void wbLogger_append(wbLogLevel_t level, string msg, const char *file, + const char *fun, int line) { + wbLogEntry_t elem; + wbLogger_t logger; + + wb_init(NULL, NULL); + + logger = _logger; + + if (wbLogger_getLevel(logger) < level) { + return; + } + + elem = wbLogEntry_initialize(level, msg, file, fun, line); + +#ifdef wbLogger_printOnLog + if (wbLogger_printOnLog) { + if (level <= wbLogger_getLevel(logger) && elem) { + json11::Json json = json11::Json::object{ +#ifndef _MSC_VER //PMO + { "type", "logger" }, { "data", wbLogEntry_toJSONObject(elem) }}; +#else + { "data", wbLogEntry_toJSONObject(elem) }, { "type", "logger" }}; +#endif + std::cout << json.dump() << std::endl; + } + } +#endif /* wbLogger_printOnLog */ + + if (wbLogger_getHead(logger) == NULL) { + wbLogger_setHead(logger, elem); + } else { + wbLogEntry_t prev = wbLogger_getHead(logger); + + while (wbLogEntry_hasNext(prev)) { + prev = wbLogEntry_getNext(prev); + } + wbLogEntry_setNext(prev, elem); + } + +#if 0 + if (level <= wbLogger_getLevel(logger) && elem) { + const char *levelName = getLevelName(level); + + fprintf(stderr, "= LOG: %s: %s (In %s:%s on line %d). =\n", levelName, + wbLogEntry_getMessage(elem), wbLogEntry_getFile(elem), + wbLogEntry_getFunction(elem), wbLogEntry_getLine(elem)); + } +#endif + + wbLogger_incrementLength(logger); + + return; +} + +string wbLogger_toJSON() { + return wbLogger_toJSON(_logger); +} + +static json11::Json wbLogger_toJSONObject(wbLogger_t logger) { + std::vector elems{}; + + if (logger != NULL) { + wbLogEntry_t iter; + stringstream ss; + + for (iter = wbLogger_getHead(logger); iter != NULL; + iter = wbLogEntry_getNext(iter)) { + elems.push_back(wbLogEntry_toJSONObject(iter)); + } + } + return json11::Json(elems); +} + +string wbLogger_toJSON(wbLogger_t logger) { + if (logger != NULL) { + wbLogEntry_t iter; + stringstream ss; + + for (iter = wbLogger_getHead(logger); iter != NULL; + iter = wbLogEntry_getNext(iter)) { + ss << wbLogEntry_toJSON(iter); + if (wbLogEntry_getNext(iter) != NULL) { + ss << ",\n"; + } + } + + return ss.str(); + } + return ""; +} + +string wbLogger_toXML() { + return wbLogger_toXML(_logger); +} + +string wbLogger_toXML(wbLogger_t logger) { + if (logger != NULL) { + wbLogEntry_t iter; + stringstream ss; + + ss << "\n"; + ss << "" + << "Logger" + << "\n"; + ss << "\n"; + for (iter = wbLogger_getHead(logger); iter != NULL; + iter = wbLogEntry_getNext(iter)) { + ss << wbLogEntry_toXML(iter); + } + ss << "\n"; + ss << "\n"; + + return ss.str(); + } + return ""; +} diff --git a/CUDA_BasicMatrixMultiplication/libwb/wbLogger.h b/CUDA_BasicMatrixMultiplication/libwb/wbLogger.h new file mode 100644 index 0000000..b852592 --- /dev/null +++ b/CUDA_BasicMatrixMultiplication/libwb/wbLogger.h @@ -0,0 +1,87 @@ + +#ifndef __WB_LOGGER_H__ +#define __WB_LOGGER_H__ + +#include + +typedef enum en_wbLogLevel_t { + wbLogLevel_unknown = -1, + wbLogLevel_OFF = 0, + wbLogLevel_FATAL, + wbLogLevel_ERROR, + wbLogLevel_WARN, + wbLogLevel_INFO, + wbLogLevel_DEBUG, + wbLogLevel_TRACE +} wbLogLevel_t; + +struct st_wbLogEntry_t { + int line; + int mpiRank; + char *msg; + uint64_t time; + const char *fun; + const char *file; + wbLogLevel_t level; + wbLogEntry_t next; +}; + +struct st_wbLogger_t { + int length; + wbLogEntry_t head; + wbLogLevel_t level; +}; + +#define wbLogEntry_getMessage(elem) ((elem)->msg) +#define wbLogEntry_getMPIRank(elem) ((elem)->mpiRank) +#define wbLogEntry_getTime(elem) ((elem)->time) +#define wbLogEntry_getLevel(elem) ((elem)->level) +#define wbLogEntry_getNext(elem) ((elem)->next) +#define wbLogEntry_getLine(elem) ((elem)->line) +#define wbLogEntry_getFunction(elem) ((elem)->fun) +#define wbLogEntry_getFile(elem) ((elem)->file) + +#define wbLogEntry_setMessage(elem, val) \ + (wbLogEntry_getMessage(elem) = val) +#define wbLogEntry_setMPIRank(elem, val) \ + (wbLogEntry_getMPIRank(elem) = val) +#define wbLogEntry_setTime(elem, val) (wbLogEntry_getTime(elem) = val) +#define wbLogEntry_setLevel(elem, val) (wbLogEntry_getLevel(elem) = val) +#define wbLogEntry_setNext(elem, val) (wbLogEntry_getNext(elem) = val) +#define wbLogEntry_setLine(elem, val) (wbLogEntry_getLine(elem) = val) +#define wbLogEntry_setFunction(elem, val) \ + (wbLogEntry_getFunction(elem) = val) +#define wbLogEntry_setFile(elem, val) (wbLogEntry_getFile(elem) = val) + +#define wbLogger_getLength(log) ((log)->length) +#define wbLogger_getHead(log) ((log)->head) +#define wbLogger_getLevel(log) ((log)->level) + +#define wbLogger_setLength(log, val) (wbLogger_getLength(log) = val) +#define wbLogger_setHead(log, val) (wbLogger_getHead(log) = val) + +#define wbLogger_incrementLength(log) (wbLogger_getLength(log)++) +#define wbLogger_decrementLength(log) (wbLogger_getLength(log)--) + +#define wbLog(level, ...) \ + wbLogger_append(wbLogLevel_##level, wbString(__VA_ARGS__), wbFile, \ + wbFunction, wbLine) + +extern wbLogger_t _logger; + +wbLogger_t wbLogger_new(); + +void wbLogger_clear(wbLogger_t logger); + +void wbLogger_delete(wbLogger_t logger); + +void wbLogger_append(wbLogLevel_t level, string msg, const char *file, + const char *fun, int line); + +string wbLogger_toXML(wbLogger_t logger); +string wbLogger_toXML(); + +string wbLogger_toJSON(wbLogger_t logger); +string wbLogger_toJSON(); + +#endif /* __WB_LOGGER_H__ */ diff --git a/CUDA_BasicMatrixMultiplication/libwb/wbMD5.h b/CUDA_BasicMatrixMultiplication/libwb/wbMD5.h new file mode 100644 index 0000000..e83a8ef --- /dev/null +++ b/CUDA_BasicMatrixMultiplication/libwb/wbMD5.h @@ -0,0 +1,311 @@ + +/* + * This code implements the MD5 message-digest algorithm. + * The algorithm is due to Ron Rivest. This code was + * written by Colin Plumb in 1993, no copyright is claimed. + * This code is in the public domain; do with it what you wish. + * + * Equivalent code is available from RSA Data Security, Inc. + * This code has been tested against that, and is equivalent, + * except that you don't need to include two pages of legalese + * with every copy. + * + * To compute the message digest of a chunk of bytes, declare an + * MD5Context structure, pass it to MD5Init, call MD5Update as + * needed on buffers full of bytes, and then call MD5Final, which + * will fill a supplied 16-byte array with the digest. + * + * Changed so as no longer to depend on Colin Plumb's `usual.h' header + * definitions; now uses stuff from dpkg's config.h. + * - Ian Jackson . + * Still in the public domain. + */ + +#ifndef __WB_MD5_H__ +#define __WB_MD5_H__ + +#include /* for memcpy() */ +#include /* for stupid systems */ + +#define UWORD32 unsigned int + +#define md5byte unsigned char + +struct MD5Context { + UWORD32 buf[4]; + UWORD32 bytes[2]; + UWORD32 in[16]; +}; + +static void MD5Transform(UWORD32 buf[4], UWORD32 const in[16]); + +static int g_bigEndian = 0; +static int g_endianessDetected = 0; + +static void detectEndianess() { + int nl = 0x12345678; + short ns = 0x1234; + + unsigned char *p = (unsigned char *)(&nl); + unsigned char *sp = (unsigned char *)(&ns); + + if (g_endianessDetected) + return; + if (p[0] == 0x12 && p[1] == 0x34 && p[2] == 0x56 && p[3] == 0x78) { + g_bigEndian = 1; + } else if (p[0] == 0x78 && p[1] == 0x56 && p[2] == 0x34 && + p[3] == 0x12) { + g_bigEndian = 0; + } else { + g_bigEndian = *sp != 0x12; + } + + g_endianessDetected = 1; +} + +static void byteSwap(UWORD32 *buf, unsigned words) { + md5byte *p; + + if (!g_bigEndian) + return; + + p = (md5byte *)buf; + + do { + *buf++ = (UWORD32)((unsigned)p[3] << 8 | p[2]) << 16 | + ((unsigned)p[1] << 8 | p[0]); + p += 4; + } while (--words); +} + +/* + * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious + * initialization constants. + */ +static void MD5Init(struct MD5Context *ctx) { + detectEndianess(); + + ctx->buf[0] = 0x67452301; + ctx->buf[1] = 0xefcdab89; + ctx->buf[2] = 0x98badcfe; + ctx->buf[3] = 0x10325476; + + ctx->bytes[0] = 0; + ctx->bytes[1] = 0; +} + +/* + * Update context to reflect the concatenation of another buffer full + * of bytes. + */ +static void MD5Update(struct MD5Context *ctx, md5byte const *buf, + unsigned len) { + UWORD32 t; + + /* Update byte count */ + + t = ctx->bytes[0]; + if ((ctx->bytes[0] = t + len) < t) + ctx->bytes[1]++; /* Carry from low to high */ + + t = 64 - (t & 0x3f); /* Space available in ctx->in (at least 1) */ + if (t > len) { + memcpy((md5byte *)ctx->in + 64 - t, buf, len); + return; + } + /* First chunk is an odd size */ + memcpy((md5byte *)ctx->in + 64 - t, buf, t); + byteSwap(ctx->in, 16); + MD5Transform(ctx->buf, ctx->in); + buf += t; + len -= t; + + /* Process data in 64-byte chunks */ + while (len >= 64) { + memcpy(ctx->in, buf, 64); + byteSwap(ctx->in, 16); + MD5Transform(ctx->buf, ctx->in); + buf += 64; + len -= 64; + } + + /* Handle any remaining bytes of data. */ + memcpy(ctx->in, buf, len); +} + +/* + * Final wrapup - pad to 64-byte boundary with the bit pattern + * 1 0* (64-bit count of bits processed, MSB-first) + */ +static void MD5Final(md5byte digest[16], struct MD5Context *ctx) { + int count = ctx->bytes[0] & 0x3f; /* Number of bytes in ctx->in */ + md5byte *p = (md5byte *)ctx->in + count; + + /* Set the first char of padding to 0x80. There is always room. */ + *p++ = 0x80; + + /* Bytes of padding needed to make 56 bytes (-8..55) */ + count = 56 - 1 - count; + + if (count < 0) { /* Padding forces an extra block */ + memset(p, 0, count + 8); + byteSwap(ctx->in, 16); + MD5Transform(ctx->buf, ctx->in); + p = (md5byte *)ctx->in; + count = 56; + } + memset(p, 0, count); + byteSwap(ctx->in, 14); + + /* Append length in bits and transform */ + ctx->in[14] = ctx->bytes[0] << 3; + ctx->in[15] = ctx->bytes[1] << 3 | ctx->bytes[0] >> 29; + MD5Transform(ctx->buf, ctx->in); + + byteSwap(ctx->buf, 4); + memcpy(digest, ctx->buf, 16); + memset(&ctx, 0, sizeof(ctx)); /* In case it's sensitive */ +} + +#ifndef ASM_MD5 + +/* The four core functions - F1 is optimized somewhat */ + +/* #define F1(x, y, z) (x & y | ~x & z) */ +#define F1(x, y, z) (z ^ (x & (y ^ z))) +#define F2(x, y, z) F1(z, x, y) +#define F3(x, y, z) (x ^ y ^ z) +#define F4(x, y, z) (y ^ (x | ~z)) + +/* This is the central step in the MD5 algorithm. */ +#define MD5STEP(f, w, x, y, z, in, s) \ + (w += f(x, y, z) + in, w = (w << s | w >> (32 - s)) + x) + +/* + * The core of the MD5 algorithm, this alters an existing MD5 hash to + * reflect the addition of 16 longwords of new data. MD5Update blocks + * the data and converts bytes into longwords for this routine. + */ +static void MD5Transform(UWORD32 buf[4], UWORD32 const in[16]) { + UWORD32 a, b, c, d; + + a = buf[0]; + b = buf[1]; + c = buf[2]; + d = buf[3]; + + MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); + MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); + MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); + MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); + MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); + MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); + MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); + MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); + MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); + MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); + MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); + MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); + MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); + MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); + MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); + MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); + + MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); + MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); + MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); + MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); + MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); + MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); + MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); + MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); + MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); + MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); + MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); + MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); + MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); + MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); + MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); + MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); + + MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); + MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); + MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); + MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); + MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); + MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); + MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); + MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); + MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); + MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); + MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); + MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); + MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); + MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); + MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); + MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); + + MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); + MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); + MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); + MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); + MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); + MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); + MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); + MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); + MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); + MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); + MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); + MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); + MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); + MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); + MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); + MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} + +#endif + +static void MD5_buffer(const unsigned char *buf, unsigned int len, + unsigned char sig[16]) { + struct MD5Context md5; + MD5Init(&md5); + MD5Update(&md5, buf, len); + MD5Final(sig, &md5); +} + +#define wbMD5 MD5_buffer + +#define HEX_STRING "0123456789abcdef" /* to convert to hex */ + +static void wbMD5_sigToString(unsigned char signature[16], char *str, + int len) { + unsigned char *sig_p; + char *str_p, *max_p; + unsigned int high, low; + + str_p = str; + max_p = str + len; + + for (sig_p = (unsigned char *)signature; + sig_p < (unsigned char *)signature + 16; sig_p++) { + high = *sig_p / 16; + low = *sig_p % 16; + /* account for 2 chars */ + if (str_p + 1 >= max_p) { + break; + } + *str_p++ = HEX_STRING[high]; + *str_p++ = HEX_STRING[low]; + } + /* account for 2 chars */ + if (str_p < max_p) { + *str_p++ = '\0'; + } +} + +#endif /* __WB_MD5_H__ */ diff --git a/CUDA_BasicMatrixMultiplication/libwb/wbMPI.cpp b/CUDA_BasicMatrixMultiplication/libwb/wbMPI.cpp new file mode 100644 index 0000000..546c1ed --- /dev/null +++ b/CUDA_BasicMatrixMultiplication/libwb/wbMPI.cpp @@ -0,0 +1,75 @@ + +#ifdef WB_USE_MPI + +#include +#include +#include +#include "wb.h" + +static int rank = -1; + +int wbMPI_getRank() { + if (rank != -1) { + return rank; + } + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + return rank; +} + +int rankCount() { + int nRanks; + MPI_Comm_size(MPI_COMM_WORLD, &nRanks); + return nRanks; +} + +const char *wbMPI_getStringFromRank(int rank, int tag) { + if (isMasterQ) { + char *buf; + int bufSize; + MPI_Recv(&bufSize, 1, MPI_INT, rank, tag, MPI_COMM_WORLD, + MPI_STATUS_IGNORE); + buf = (char *)calloc(bufSize, sizeof(char)); + MPI_Recv(buf, bufSize, MPI_CHAR, rank, tag, MPI_COMM_WORLD, + MPI_STATUS_IGNORE); + return buf; + } + + return NULL; +} +void wbMPI_sendStringToMaster(const char *str, int tag) { + if (!isMasterQ) { + // we are going to send the string to the master + int len = (int)strlen(str) + 1; + MPI_Send(&len, 1, MPI_INT, 0, tag, MPI_COMM_WORLD); + MPI_Send((void *)str, len, MPI_CHAR, 0, tag, MPI_COMM_WORLD); + } + + return; +} + +int wbMPI_Init(int *argc, char ***argv) { + int err = MPI_SUCCESS; + err = MPI_Init(argc, argv); + // printf("argc = %d\n", *argc); + // err = MPI_Init(NULL, NULL); + // printf("rank = %d is master = %d\n", wbMPI_getRank(), isMasterQ); + // MPI_Barrier(MPI_COMM_WORLD); + return err; +} + +bool finalizedQ = false; + +extern "C" int wbMPI_Finalize(void) { + if (finalizedQ) { + return MPI_SUCCESS; + } + finalizedQ = true; + wb_atExit(); + return MPI_Finalize(); +} +extern "C" void wbMPI_Exit(void) { + wbMPI_Finalize(); + return; +} + +#endif /* WB_USE_MPI */ diff --git a/CUDA_BasicMatrixMultiplication/libwb/wbMPI.h b/CUDA_BasicMatrixMultiplication/libwb/wbMPI.h new file mode 100644 index 0000000..6275eaf --- /dev/null +++ b/CUDA_BasicMatrixMultiplication/libwb/wbMPI.h @@ -0,0 +1,37 @@ + +#ifndef __WB_MPI_H__ +#define __WB_MPI_H__ + +#ifdef WB_USE_MPI + +#include +#include +#include + +#define isMasterQ ((wbMPI_getRank()) == 0) + +extern int wbMPI_getRank(); + +extern int rankCount(); + +extern const char *wbMPI_getStringFromRank(int rank, int tag); +extern void wbMPI_sendStringToMaster(const char *str, int tag); + +extern int wbMPI_Init(int *argc, char ***argv); + +extern bool finalizedQ; + +extern "C" int wbMPI_Finalize(void); +extern "C" void wbMPI_Exit(void); + +#define MPI_Finalize wbMPI_Finalize + +#else /* WB_USE_MPI */ +static inline int rankCount() { + return 1; +} +static inline int wbMPI_getRank() { + return 0; +} +#endif /* WB_USE_MPI */ +#endif /* __WB_MPI_H__ */ diff --git a/CUDA_BasicMatrixMultiplication/libwb/wbMalloc.h b/CUDA_BasicMatrixMultiplication/libwb/wbMalloc.h new file mode 100644 index 0000000..5d74be4 --- /dev/null +++ b/CUDA_BasicMatrixMultiplication/libwb/wbMalloc.h @@ -0,0 +1,140 @@ + + +#ifndef __WB_MALLOC_H__ +#define __WB_MALLOC_H__ + +#ifdef WB_USE_CUSTOM_MALLOC +#ifdef __linux__ +#define THROW __THROW +#else +#define THROW +#endif + +static inline void *_malloc(size_t size) THROW { + if (size == 0) { + return NULL; + } else { + int err; + void *res = memmgr_alloc((ulong)size, &err); + if (err) { + fprintf(stderr, "<>:: Memory allocation failed\n"); + exit(1); + } else { + size_t ii = 0; + unsigned char *p = (unsigned char *)res; + while (ii++ < size) { + *p++ = 0; + } + return res; + } + } +} + +static inline void _free(void *ptr) THROW { + if (ptr != NULL) { + memmgr_free(ptr); + } +} + +static inline void *_calloc(size_t nmemb, size_t size) THROW { + return _malloc(nmemb * size); +} + +static inline void *_realloc(void *ptr, size_t size) THROW { + if (size == 0) { + free(ptr); + return NULL; + } else if (ptr == NULL) { + return malloc(size); + } else { + void *buf; + unsigned char *dst; + unsigned char *src; + size_t alloc_size, to_copy, i = 0; + + // Allocate new buffer + buf = malloc(size); + + if (buf != 0) { + // Find original allocation size + alloc_size = (size_t)memmgr_get_block_size(ptr); + to_copy = alloc_size; + if (to_copy > size) { + to_copy = size; + } + + // Copy data to new buffer + dst = (unsigned char *)buf; + src = (unsigned char *)ptr; + while (i++ < to_copy) { + *dst++ = *src++; + } + + // Free the old buffer + free(ptr); + } + + return buf; + } +} + +#define wbNew(type) ((type *)_malloc(sizeof(type))) +#define wbNewArray(type, len) ((type *)_malloc((len) * sizeof(type))) +#define wbMalloc(sz) _malloc(sz) +#define wbDelete(var) \ + _free(var); \ + var = NULL +#define wbFree(var) \ + _free(var); \ + var = NULL +#define wbRealloc(var, newSize) _realloc(var, newSize) +#define wbReallocArray(t, m, n) ((t *)_realloc(m, n * sizeof(t))) + +#define free _free +#define malloc _malloc +#define calloc _calloc +#define realloc _realloc + +#else /* WB_USE_CUSTOM_MALLOC */ + +static inline void *xMalloc(size_t sz) { + void *mem = NULL; + if (sz != 0) { + mem = malloc(sz); + } + return mem; +} + +static inline void xFree(void *mem) { + if (mem != NULL) { + free(mem); + } + return; +} + +static inline void *xRealloc(void *mem, size_t sz) { + if (mem == NULL) { + return NULL; + } else if (sz == 0) { + xFree(mem); + return NULL; + } else { + void *res = realloc(mem, sz); + wbAssert(res != NULL); + return res; + } +} + +#define wbNew(type) ((type *)wbMalloc(sizeof(type))) +#define wbNewArray(type, len) ((type *)wbMalloc((len) * sizeof(type))) +#define wbMalloc(sz) xMalloc(sz) +#define wbDelete(var) wbFree(var) +#define wbFree(var) \ + xFree(var); \ + var = NULL +#define wbRealloc(var, newSize) xRealloc(var, newSize) +#define wbReallocArray(t, m, n) ((t *)xRealloc(m, n * sizeof(t))) + +#endif /* WB_USE_CUSTOM_MALLOC */ + +#endif /* __WB_MALLOC_H__ */ diff --git a/CUDA_BasicMatrixMultiplication/libwb/wbPPM.cpp b/CUDA_BasicMatrixMultiplication/libwb/wbPPM.cpp new file mode 100644 index 0000000..86ab208 --- /dev/null +++ b/CUDA_BasicMatrixMultiplication/libwb/wbPPM.cpp @@ -0,0 +1,199 @@ + +#include +#include "wb.h" + +static inline float _min(float x, float y) { + return x < y ? x : y; +} + +static inline float _max(float x, float y) { + return x > y ? x : y; +} + +static inline float _clamp(float x, float start, float end) { + return _min(_max(x, start), end); +} + +static const char *skipSpaces(const char *line) { + while (*line == ' ' || *line == '\t') { + line++; + if (*line == '\0') { + break; + } + } + return line; +} + +static char nextNonSpaceChar(const char *line0) { + const char *line = skipSpaces(line0); + return *line; +} + +static wbBool isComment(const char *line) { + char nextChar = nextNonSpaceChar(line); + if (nextChar == '\0') { + return wbTrue; + } else { + return nextChar == '#'; + } +} + +static void parseDimensions(const char *line0, int *width, int *height) { + const char *line = skipSpaces(line0); + sscanf(line, "%d %d", width, height); +} + +static void parseDimensions(const char *line0, int *width, int *height, + int *channels) { + const char *line = skipSpaces(line0); + sscanf(line, "%d %d %d", width, height, channels); +} + +static void parseDepth(const char *line0, int *depth) { + const char *line = skipSpaces(line0); + sscanf(line, "%d", depth); +} + +static char *nextLine(wbFile_t file) { + char *line = NULL; + while ((line = wbFile_readLine(file)) != NULL) { + if (!isComment(line)) { + break; + } + } + return line; +} + +wbImage_t wbPPM_import(const char *filename) { + wbImage_t img; + wbFile_t file; + char *header; + char *line; + int ii, jj, kk, channels; + int width, height, depth; + unsigned char *charData, *charIter; + float *imgData, *floatIter; + float scale; + + img = NULL; + + file = wbFile_open(filename, "rb"); + if (file == NULL) { + printf("Could not open %s\n", filename); + goto cleanup; + } + + header = wbFile_readLine(file); + if (header == NULL) { + printf("Could not read from %s\n", filename); + goto cleanup; + } else if (strcmp(header, "P6") != 0 && strcmp(header, "P6\n") != 0 && + strcmp(header, "P5") != 0 && strcmp(header, "P5\n") != 0 && + strcmp(header, "S6") != 0 && strcmp(header, "S6\n") != 0) { + printf("Could find magic number for %s\n", filename); + goto cleanup; + } + + // P5 are monochrome while P6/S6 are rgb + // S6 needs to parse number of channels out of file + if (strcmp(header, "P5") == 0 || strcmp(header, "P5\n") == 0) { + channels = 1; + line = nextLine(file); + parseDimensions(line, &width, &height); + } else if (strcmp(header, "P6") == 0 || strcmp(header, "P6\n") == 0) { + channels = 3; + line = nextLine(file); + parseDimensions(line, &width, &height); + } else { + line = nextLine(file); + parseDimensions(line, &width, &height, &channels); + } + + // the line now contains the depth information + line = nextLine(file); + parseDepth(line, &depth); + + // the rest of the lines contain the data in binary format + charData = (unsigned char *)wbFile_read( + file, width * channels * sizeof(unsigned char), height); + + img = wbImage_new(width, height, channels); + + imgData = wbImage_getData(img); + + charIter = charData; + floatIter = imgData; + + scale = 1.0f / ((float)depth); + + for (ii = 0; ii < height; ii++) { + for (jj = 0; jj < width; jj++) { + for (kk = 0; kk < channels; kk++) { + *floatIter = ((float)*charIter) * scale; + floatIter++; + charIter++; + } + } + } + +#ifdef LAZY_FILE_LOAD + wbDelete(charData); +#endif + +cleanup: + wbFile_close(file); + return img; +} + +void wbPPM_export(const char *filename, wbImage_t img) { + int ii; + int jj; + int kk; + int depth; + int width; + int height; + int channels; + wbFile_t file; + float *floatIter; + unsigned char *charData; + unsigned char *charIter; + + file = wbFile_open(filename, "wb+"); + + width = wbImage_getWidth(img); + height = wbImage_getHeight(img); + channels = wbImage_getChannels(img); + depth = 255; + + if (channels == 1) { + wbFile_writeLine(file, "P5"); + } else { + wbFile_writeLine(file, "P6"); + } + wbFile_writeLine(file, "#Created via wbPPM Export"); + wbFile_writeLine(file, wbString(width, " ", height)); + wbFile_writeLine(file, wbString(depth)); + + charData = wbNewArray(unsigned char, width *height *channels); + + charIter = charData; + floatIter = wbImage_getData(img); + + for (ii = 0; ii < height; ii++) { + for (jj = 0; jj < width; jj++) { + for (kk = 0; kk < channels; kk++) { + *charIter = (unsigned char)ceil(_clamp(*floatIter, 0, 1) * depth); + floatIter++; + charIter++; + } + } + } + + wbFile_write(file, charData, width * channels * sizeof(unsigned char), + height); + + wbDelete(charData); + wbFile_delete(file); + + return; +} diff --git a/CUDA_BasicMatrixMultiplication/libwb/wbPPM.h b/CUDA_BasicMatrixMultiplication/libwb/wbPPM.h new file mode 100644 index 0000000..d589b36 --- /dev/null +++ b/CUDA_BasicMatrixMultiplication/libwb/wbPPM.h @@ -0,0 +1,11 @@ + + +#ifndef __wbPPM_H__ +#define __wbPPM_H__ + +START_EXTERN_C +wbImage_t wbPPM_import(const char *filename); +void wbPPM_export(const char *filename, wbImage_t img); +END_EXTERN_C + +#endif /* __wbPPM_H__ */ diff --git a/CUDA_BasicMatrixMultiplication/libwb/wbPath.cpp b/CUDA_BasicMatrixMultiplication/libwb/wbPath.cpp new file mode 100644 index 0000000..0d93e2b --- /dev/null +++ b/CUDA_BasicMatrixMultiplication/libwb/wbPath.cpp @@ -0,0 +1,42 @@ +#include "wb.h" + +char *wbPath_join(const char *p1, const char *p2) { + size_t s1 = strlen(p1); + size_t s2 = strlen(p2); + char *res = + wbNewArray(char, s1 + 1 /* seperator */ + s2 + 1 /* terminator */); + memcpy(res, p1, s1); + char *iter = res + s1; + *iter++ = wbDirectorySeperator; + memcpy(iter, p2, s2); + iter += s2; + *iter = '\0'; + return res; +} + +char *wbPath_join(const char *p1, const char *p2, const char *p3) { + char *p12 = wbPath_join(p1, p2); + char *res = wbPath_join(p12, p3); + wbDelete(p12); + return res; +} + +char *wbPath_join(const char *p1, const char *p2, const char *p3, + const char *p4) { + char *p123 = wbPath_join(p1, p2, p3); + char *res = wbPath_join(p123, p4); + wbDelete(p123); + return res; +} + +char *wbPath_join(const std::string &p1, const std::string &p2) { + return wbPath_join(p1.c_str(), p2.c_str()); +} +char *wbPath_join(const std::string &p1, const std::string &p2, + const std::string &p3) { + return wbPath_join(p1.c_str(), p2.c_str(), p3.c_str()); +} +char *wbPath_join(const std::string &p1, const std::string &p2, + const std::string &p3, const std::string &p4) { + return wbPath_join(p1.c_str(), p2.c_str(), p3.c_str(), p4.c_str()); +} \ No newline at end of file diff --git a/CUDA_BasicMatrixMultiplication/libwb/wbPath.h b/CUDA_BasicMatrixMultiplication/libwb/wbPath.h new file mode 100644 index 0000000..0dd3187 --- /dev/null +++ b/CUDA_BasicMatrixMultiplication/libwb/wbPath.h @@ -0,0 +1,30 @@ +#ifndef __WB_PATH_H__ +#define __WB_PATH_H__ + +char *wbPath_join(const char *p1, const char *p2); +char *wbPath_join(const char *p1, const char *p2, const char *p3); +char *wbPath_join(const char *p1, const char *p2, const char *p3, + const char *p4); + +char *wbPath_join(const std::string &p1, const std::string &p2); +char *wbPath_join(const std::string &p1, const std::string &p2, + const std::string &p3); +char *wbPath_join(const std::string &p1, const std::string &p2, + const std::string &p3, const std::string &p4); + +template +static char *wbPath_join(const T1 &p1, const T2 &p2) { + return wbPath_join(wbString(p1), wbString(p2)); +} +template +static char *wbPath_join(const T1 &p1, const T2 &p2, const T3 &p3) { + return wbPath_join(wbString(p1), wbString(p2), wbString(p3)); +} +template +static char *wbPath_join(const T1 &p1, const T2 &p2, const T3 &p3, + const T4 &p4) { + return wbPath_join(wbString(p1), wbString(p2), wbString(p3), + wbString(p4)); +} + +#endif /* __WB_PATH_H__ */ diff --git a/CUDA_BasicMatrixMultiplication/libwb/wbSolution.cpp b/CUDA_BasicMatrixMultiplication/libwb/wbSolution.cpp new file mode 100644 index 0000000..703f410 --- /dev/null +++ b/CUDA_BasicMatrixMultiplication/libwb/wbSolution.cpp @@ -0,0 +1,271 @@ + +#include "wb.h" + +char *solutionJSON = NULL; +static string _solution_correctQ(""); + +static void _onUnsameImageFunction(string str) { + _solution_correctQ = str; +} + +template +static wbBool wbSolution_listCorrectQ(const char *expectedOutputFile, + wbSolution_t sol, const char *type) { + wbBool res; + T *expectedData; + int expectedRows, expectedColumns; + + expectedData = (T *)wbImport(expectedOutputFile, &expectedRows, + &expectedColumns, type); + + if (expectedData == NULL) { + _solution_correctQ = "Failed to open expected output file."; + res = wbFalse; + } else if (expectedRows != wbSolution_getRows(sol)) { + wbLog(TRACE, "Number of rows in the solution is ", + wbSolution_getRows(sol), ". Expected number of rows is ", + expectedRows, "."); + _solution_correctQ = + "The number of rows in the solution did not match " + "that of the expected results."; + res = wbFalse; + } else if (expectedColumns != wbSolution_getColumns(sol)) { + wbLog(TRACE, "Number of columns in the solution is ", + wbSolution_getColumns(sol), ". Expected number of columns is ", + expectedColumns, "."); + _solution_correctQ = "The number of columns in the solution did not " + "match that of the expected results."; + res = wbFalse; + } else { + int ii, jj, idx; + T *solutionData; + + solutionData = (T *)wbSolution_getData(sol); + + for (ii = 0; ii < expectedRows; ii++) { + for (jj = 0; jj < expectedColumns; jj++) { + idx = ii * expectedColumns + jj; + if (wbUnequalQ(expectedData[idx], solutionData[idx])) { + string str; + if (expectedColumns == 1) { + str = wbString( + "The solution did not match the expected results at row ", + ii, ". Expecting ", expectedData[idx], " but got ", + solutionData[idx], "."); + } else { + str = wbString("The solution did not match the expected " + "results at column ", + jj, " and row ", ii, ". Expecting ", + expectedData[idx], " but got ", + solutionData[idx], "."); + } + _solution_correctQ = str; + res = wbFalse; + goto matrixCleanup; + } + } + } + + res = wbTrue; + matrixCleanup: + if (expectedData != NULL) { + wbFree(expectedData); + } + } + return res; +} + +static wbBool wbSolution_correctQ(char *expectedOutputFile, + wbSolution_t sol) { + if (expectedOutputFile == NULL) { + _solution_correctQ = "Failed to determined the expected output file."; + return wbFalse; + } else if (!wbFile_existsQ(expectedOutputFile)) { + _solution_correctQ = + wbString("The file ", expectedOutputFile, " does not exist."); + return wbFalse; + } else if (wbString_sameQ(wbSolution_getType(sol), "image")) { + wbBool res; + wbImage_t solutionImage = NULL; + wbImage_t expectedImage = wbImport(expectedOutputFile); + if (expectedImage == NULL) { + _solution_correctQ = "Failed to open expected output file."; + res = wbFalse; + } else if (wbImage_getWidth(expectedImage) != + wbSolution_getWidth(sol)) { + _solution_correctQ = + "The image width of the expected image does not " + "match that of the solution."; + res = wbFalse; + } else if (wbImage_getHeight(expectedImage) != + wbSolution_getHeight(sol)) { + _solution_correctQ = + "The image height of the expected image does not " + "match that of the solution."; + res = wbFalse; + } else if (wbImage_getChannels(expectedImage) != + wbSolution_getChannels(sol)) { + _solution_correctQ = + "The image channels of the expected image does not " + "match that of the solution."; + res = wbFalse; + } else { + solutionImage = (wbImage_t)wbSolution_getData(sol); + wbAssert(solutionImage != NULL); + res = wbImage_sameQ(solutionImage, expectedImage, + _onUnsameImageFunction); + } + if (expectedImage != NULL) { + wbImage_delete(expectedImage); + } + return res; + } else if (wbString_sameQ(wbSolution_getType(sol), "histogram")) { + return wbSolution_listCorrectQ(expectedOutputFile, sol, + "Integer"); + } else if (wbString_sameQ(wbSolution_getType(sol), "integral_vector")) { + return wbSolution_listCorrectQ(expectedOutputFile, sol, + "Integer"); + } else if (wbString_sameQ(wbSolution_getType(sol), "vector") || + wbString_sameQ(wbSolution_getType(sol), "matrix")) { + return wbSolution_listCorrectQ(expectedOutputFile, sol, + "Real"); + } else { + wbAssert(wbFalse); + return wbFalse; + } +} + +wbBool wbSolution(char *expectedOutputFile, char *outputFile, char *type0, + void *data, int rows, int columns, int depth) { + char *type; + wbBool res; + wbSolution_t sol; + + if (expectedOutputFile == NULL || data == NULL || type0 == NULL) { + wbLog(ERROR, "Failed to grade solution"); + return wbFalse; + } + + type = wbString_toLower(type0); + + if (_solution_correctQ != "") { + _solution_correctQ = ""; + } + + wbSolution_setOutputFile(sol, outputFile); + wbSolution_setType(sol, type); + wbSolution_setData(sol, data); + wbSolution_setRows(sol, rows); + wbSolution_setColumns(sol, columns); + wbSolution_setDepth(sol, depth); + + res = wbSolution_correctQ(expectedOutputFile, sol); + + if (outputFile != NULL) { + if (wbString_sameQ(type, "image")) { + wbImage_t inputImage = (wbImage_t)data; + wbImage_t img = wbImage_new(wbImage_getWidth(inputImage), + wbImage_getHeight(inputImage), + wbImage_getChannels(inputImage)); + memcpy(wbImage_getData(img), wbImage_getData(inputImage), + rows * columns * wbImage_channels * sizeof(wbReal_t)); + wbExport(outputFile, img); + wbImage_delete(img); + } else if (wbString_sameQ(type, "integral_vector")) { + wbExport(outputFile, (int *)data, rows, columns); + } else if (wbString_sameQ(type, "vector") || + wbString_sameQ(type, "matrix")) { + wbExport(outputFile, (wbReal_t *)data, rows, columns); + } else if (wbString_sameQ(type, "histogram")) { + wbExport(outputFile, (unsigned char *)data, rows, columns); + } else if (wbString_sameQ(type, "text")) { + wbExport_text(outputFile, (unsigned char *)data, rows * columns); + } + } + + wbFree(type); + + return res; +} + +wbBool wbSolution(char *expectedOutputFile, char *outputFile, char *type0, + void *data, int rows, int columns) { + return wbSolution(expectedOutputFile, outputFile, type0, data, rows, + columns, 1); +} + +wbBool wbSolution(wbArg_t arg, void *data, int rows, int columns, + int depth) { + char *type; + wbBool res; + char *expectedOutputFile; + char *outputFile; + stringstream ss; + + expectedOutputFile = wbArg_getExpectedOutputFile(arg); + outputFile = wbArg_getOutputFile(arg); + type = wbArg_getType(arg); + + wbAssert(type != NULL); + wbAssert(expectedOutputFile != NULL); + wbAssert(outputFile != NULL); + + res = wbSolution(expectedOutputFile, outputFile, type, data, rows, + columns, depth); + + if (WB_USE_JSON11) { + json11::Json json; + if (res) { + json = json11::Json::object{{"correctq", true}, + {"message", "The solution is correct"}}; + } else { + json = json11::Json::object{{"correctq", false}, + {"message", _solution_correctQ}}; + } + +#ifdef wbLogger_printOnLog + if (wbLogger_printOnLog) { + json11::Json e = +//PMO +#ifndef _MSC_VER + json11::Json::object{{"type", "solution"}, {"data", json}}; +#else + json11::Json::object{{"data", json }, {"type", "solution" }}; +#endif + std::cout << e.dump() << std::endl; + } +#endif /* wbLogger_printOnLog */ + + solutionJSON = wbString_duplicate(json.string_value()); + } else { + if (res) { + ss << "{\n"; + ss << wbString_quote("correctq") << ": true,\n"; + ss << wbString_quote("message") << ": " + << wbString_quote("Solution is correct.") << "\n"; + ss << "}"; + } else { + ss << "{\n"; + ss << wbString_quote("correctq") << ": false,\n"; + ss << wbString_quote("message") << ": " + << wbString_quote(_solution_correctQ) << "\n"; + ss << "}"; + } + solutionJSON = wbString_duplicate(ss.str()); + } + + return res; +} + +wbBool wbSolution(wbArg_t arg, void *data, int rows, int columns) { + return wbSolution(arg, data, rows, columns, 1); +} + +EXTERN_C wbBool wbSolution(wbArg_t arg, void *data, int rows) { + return wbSolution(arg, data, rows, 1); +} + +wbBool wbSolution(wbArg_t arg, wbImage_t img) { + return wbSolution(arg, img, wbImage_getHeight(img), + wbImage_getWidth(img), wbImage_getChannels(img)); +} diff --git a/CUDA_BasicMatrixMultiplication/libwb/wbSolution.h b/CUDA_BasicMatrixMultiplication/libwb/wbSolution.h new file mode 100644 index 0000000..f18d07d --- /dev/null +++ b/CUDA_BasicMatrixMultiplication/libwb/wbSolution.h @@ -0,0 +1,40 @@ + + +#ifndef __WB_SOLUTION_H__ +#define __WB_SOLUTION_H__ + +typedef struct st_wbSolution_t { + char *type; + char *outputFile; + void *data; + int rows; + int columns; + int depth; +} wbSolution_t; + +#define wbSolution_getType(sol) ((sol).type) +#define wbSolution_getOutputFile(sol) ((sol).outputFile) +#define wbSolution_getData(sol) ((sol).data) +#define wbSolution_getRows(sol) ((sol).rows) +#define wbSolution_getColumns(sol) ((sol).columns) +#define wbSolution_getDepth(sol) ((sol).depth) + +#define wbSolution_getHeight wbSolution_getRows +#define wbSolution_getWidth wbSolution_getColumns +#define wbSolution_getChannels wbSolution_getDepth + +#define wbSolution_setType(sol, val) (wbSolution_getType(sol) = val) +#define wbSolution_setOutputFile(sol, val) \ + (wbSolution_getOutputFile(sol) = val) +#define wbSolution_setData(sol, val) (wbSolution_getData(sol) = val) +#define wbSolution_setRows(sol, val) (wbSolution_getRows(sol) = val) +#define wbSolution_setColumns(sol, val) (wbSolution_getColumns(sol) = val) +#define wbSolution_setDepth(sol, val) (wbSolution_getDepth(sol) = val) + +wbBool wbSolution(char *expectedOutputFile, char *outputFile, char *type0, + void *data, int rows, int columns); +wbBool wbSolution(wbArg_t arg, void *data, int rows, int columns); +EXTERN_C wbBool wbSolution(wbArg_t arg, void *data, int rows); +wbBool wbSolution(wbArg_t arg, wbImage_t img); + +#endif /* __WB_SOLUTION_H__ */ diff --git a/CUDA_BasicMatrixMultiplication/libwb/wbSparse.cpp b/CUDA_BasicMatrixMultiplication/libwb/wbSparse.cpp new file mode 100644 index 0000000..9cdcba3 --- /dev/null +++ b/CUDA_BasicMatrixMultiplication/libwb/wbSparse.cpp @@ -0,0 +1,82 @@ + +#include "wb.h" + +static void sort(int *data, int *key, int start, int end) { + if ((end - start + 1) > 1) { + int left = start, right = end; + int pivot = key[right]; + while (left <= right) { + while (key[left] > pivot) { + left = left + 1; + } + while (key[right] < pivot) { + right = right - 1; + } + if (left <= right) { + int tmp = key[left]; + key[left] = key[right]; + key[right] = tmp; + tmp = data[left]; + data[left] = data[right]; + data[right] = tmp; + left = left + 1; + right = right - 1; + } + } + sort(data, key, start, right); + sort(data, key, left, end); + } +} + +EXTERN_C void CSRToJDS(int dim, int *csrRowPtr, int *csrColIdx, + float *csrData, int **jdsRowPerm, int **jdsRowNNZ, + int **jdsColStartIdx, int **jdsColIdx, + float **jdsData) { + // Row Permutation Vector + *jdsRowPerm = (int *)malloc(sizeof(int) * dim); + for (int rowIdx = 0; rowIdx < dim; ++rowIdx) { + (*jdsRowPerm)[rowIdx] = rowIdx; + } + + // Number of non-zeros per row + *jdsRowNNZ = (int *)malloc(sizeof(int) * dim); + for (int rowIdx = 0; rowIdx < dim; ++rowIdx) { + (*jdsRowNNZ)[rowIdx] = csrRowPtr[rowIdx + 1] - csrRowPtr[rowIdx]; + } + + // Sort rows by number of non-zeros + sort(*jdsRowPerm, *jdsRowNNZ, 0, dim - 1); + + // Starting point of each compressed column + int maxRowNNZ = (*jdsRowNNZ)[0]; // Largest number of non-zeros per row + DEBUG(printf("jdsRowNNZ = %d\n", maxRowNNZ)); + *jdsColStartIdx = (int *)malloc(sizeof(int) * maxRowNNZ); + (*jdsColStartIdx)[0] = 0; // First column starts at 0 + for (int col = 0; col < maxRowNNZ - 1; ++col) { + // Count the number of rows with entries in this column + int count = 0; + for (int idx = 0; idx < dim; ++idx) { + if ((*jdsRowNNZ)[idx] > col) { + ++count; + } + } + (*jdsColStartIdx)[col + 1] = (*jdsColStartIdx)[col] + count; + } + + // Sort the column indexes and data + const int NNZ = csrRowPtr[dim]; + DEBUG(printf("NNZ = %d\n", NNZ)); + *jdsColIdx = (int *)malloc(sizeof(int) * NNZ); + DEBUG(printf("dim = %d\n", dim)); + *jdsData = (float *)malloc(sizeof(float) * NNZ); + for (int idx = 0; idx < dim; ++idx) { // For every row + int row = (*jdsRowPerm)[idx]; + int rowNNZ = (*jdsRowNNZ)[idx]; + for (int nnzIdx = 0; nnzIdx < rowNNZ; ++nnzIdx) { + int jdsPos = (*jdsColStartIdx)[nnzIdx] + idx; + int csrPos = csrRowPtr[row] + nnzIdx; + (*jdsColIdx)[jdsPos] = csrColIdx[csrPos]; + (*jdsData)[jdsPos] = csrData[csrPos]; + } + } +} diff --git a/CUDA_BasicMatrixMultiplication/libwb/wbSparse.h b/CUDA_BasicMatrixMultiplication/libwb/wbSparse.h new file mode 100644 index 0000000..c04a857 --- /dev/null +++ b/CUDA_BasicMatrixMultiplication/libwb/wbSparse.h @@ -0,0 +1,10 @@ + +#ifndef __WB_SPARSE_H__ +#define __WB_SPARSE_H__ + +EXTERN_C void CSRToJDS(int dim, int *csrRowPtr, int *csrColIdx, + float *csrData, int **jdsRowPerm, int **jdsRowNNZ, + int **jdsColStartIdx, int **jdsColIdx, + float **jdsData); + +#endif /* __WB_SPARSE_H__ */ diff --git a/CUDA_BasicMatrixMultiplication/libwb/wbString.h b/CUDA_BasicMatrixMultiplication/libwb/wbString.h new file mode 100644 index 0000000..65e52f8 --- /dev/null +++ b/CUDA_BasicMatrixMultiplication/libwb/wbString.h @@ -0,0 +1,324 @@ + + +#ifndef __WB_STRING_H__ +#define __WB_STRING_H__ + +#include +#include +#include +#include +#include +#include +#include "wb.h" + +using std::string; +using std::vector; +using std::stringstream; +using std::exception; + +template +static inline string wbString(const T &x); + +static inline void wbString_replace(string &value, string const &search, + string const &replace) { + for (string::size_type next = value.find(search); next != string::npos; + next = value.find(search, next)) { + value.replace(next, search.length(), replace); + next += replace.length(); + } +} + +static inline string wbString_quote(string str) { + string s = str; + wbString_replace(s, "\\", "\\\\"); + s = "\"" + s + "\""; + return s; +} + +static inline string wbString_quote(const char *str) { + if (str == NULL) { + return wbString_quote(""); + } else { + return wbString_quote(string(str)); + } +} + +static inline char *wbString_duplicate(const char *str) { + if (str == NULL) { + return NULL; + } else { + char *newstr; + size_t len = strlen(str); + newstr = wbNewArray(char, len + 1); + memcpy(newstr, str, len * sizeof(char)); + newstr[len] = '\0'; + return newstr; + } +} + +static inline char *wbString_duplicate(std::string str) { + return wbString_duplicate(str.c_str()); +} + +static inline string wbString(void) { + string s = ""; + return s; +} + +template +static inline string wbString(const T &x) { + try { + stringstream ss; + ss << x; + return ss.str(); + } catch (exception &e) { + return string(); + } +} + +template <> +inline string wbString(const bool &x) { + return x ? "True" : "False"; +} + +template <> +inline string wbString(const vector &x) { + stringstream ss; + ss << "{"; + for (size_t ii = 0; ii < x.size(); ii++) { + ss << wbString_quote(x[ii]); + if (ii != x.size() - 1) { + ss << ", "; + } + } + ss << "}"; + + return ss.str(); +} + +template <> +inline string wbString(const vector &x) { + stringstream ss; + ss << "{"; + for (size_t ii = 0; ii < x.size(); ii++) { + ss << x[ii]; + if (ii != x.size() - 1) { + ss << ", "; + } + } + ss << "}"; + + return ss.str(); +} + +template <> +inline string wbString(const vector &x) { + stringstream ss; + ss << "{"; + for (size_t ii = 0; ii < x.size(); ii++) { + ss << x[ii]; + if (ii != x.size() - 1) { + ss << ", "; + } + } + ss << "}"; + + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1) { + stringstream ss; + ss << wbString(x0) << wbString(x1); + + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1, const T2 &x2) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2); + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1, const T2 &x2, + const T3 &x3) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2) << wbString(x3); + + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1, const T2 &x2, + const T3 &x3, const T4 &x4) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2) << wbString(x3) + << wbString(x4); + + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1, const T2 &x2, + const T3 &x3, const T4 &x4, const T5 &x5) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2) << wbString(x3) + << wbString(x4) << wbString(x5); + + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1, const T2 &x2, + const T3 &x3, const T4 &x4, const T5 &x5, + const T6 &x6) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2) << wbString(x3) + << wbString(x4) << wbString(x5) << wbString(x6); + + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1, const T2 &x2, + const T3 &x3, const T4 &x4, const T5 &x5, + const T6 &x6, const T7 &x7) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2) << wbString(x3) + << wbString(x4) << wbString(x5) << wbString(x6) << wbString(x7); + + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1, const T2 &x2, + const T3 &x3, const T4 &x4, const T5 &x5, + const T6 &x6, const T7 &x7, const T8 &x8) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2) << wbString(x3) + << wbString(x4) << wbString(x5) << wbString(x6) << wbString(x7) + << wbString(x8); + + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1, const T2 &x2, + const T3 &x3, const T4 &x4, const T5 &x5, + const T6 &x6, const T7 &x7, const T8 &x8, + const T9 &x9) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2) << wbString(x3) + << wbString(x4) << wbString(x5) << wbString(x6) << wbString(x7) + << wbString(x8) << wbString(x9); + + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1, const T2 &x2, + const T3 &x3, const T4 &x4, const T5 &x5, + const T6 &x6, const T7 &x7, const T8 &x8, + const T9 &x9, const T10 &x10) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2) << wbString(x3) + << wbString(x4) << wbString(x5) << wbString(x6) << wbString(x7) + << wbString(x8) << wbString(x9) << wbString(x10); + + return ss.str(); +} + +template +static inline string +wbString(const T0 &x0, const T1 &x1, const T2 &x2, const T3 &x3, + const T4 &x4, const T5 &x5, const T6 &x6, const T7 &x7, + const T8 &x8, const T9 &x9, const T10 &x10, const T11 &x11) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2) << wbString(x3) + << wbString(x4) << wbString(x5) << wbString(x6) << wbString(x7) + << wbString(x8) << wbString(x9) << wbString(x10) << wbString(x11); + + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1, const T2 &x2, + const T3 &x3, const T4 &x4, const T5 &x5, + const T6 &x6, const T7 &x7, const T8 &x8, + const T9 &x9, const T10 &x10, const T11 &x11, + const T12 &x12) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2) << wbString(x3) + << wbString(x4) << wbString(x5) << wbString(x6) << wbString(x7) + << wbString(x8) << wbString(x9) << wbString(x10) << wbString(x11) + << wbString(x12); + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1, const T2 &x2, + const T3 &x3, const T4 &x4, const T5 &x5, + const T6 &x6, const T7 &x7, const T8 &x8, + const T9 &x9, const T10 &x10, const T11 &x11, + const T12 &x12, const T13 &x13) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2) << wbString(x3) + << wbString(x4) << wbString(x5) << wbString(x6) << wbString(x7) + << wbString(x8) << wbString(x9) << wbString(x10) << wbString(x11) + << wbString(x12) << wbString(x13); + return ss.str(); +} + +template +static inline wbBool wbString_sameQ(const X &x, const Y &y) { + string xs = wbString(x); + string ys = wbString(y); + return strcmp(xs.c_str(), ys.c_str()) == 0; +} + +static inline wbBool wbString_sameQ(const string &x, const string &y) { + return x.compare(y) == 0; +} + +static inline char *wbString_toLower(const char *str) { + if (str == NULL) { + return NULL; + } else { + char *res, *iter; + + res = iter = wbString_duplicate(str); + while (*iter != '\0') { + *iter++ = tolower(*str++); + } + return res; + } +} + +static inline wbBool wbString_startsWith(const char *str, + const char *prefix) { + while (*prefix != '\0') { + if (*str == '\0' || *str != *prefix) { + return wbFalse; + } + str++; + prefix++; + } + return wbTrue; +} + +#endif /* __WB_STRING_H__ */ diff --git a/CUDA_BasicMatrixMultiplication/libwb/wbThrust.h b/CUDA_BasicMatrixMultiplication/libwb/wbThrust.h new file mode 100644 index 0000000..e2d3160 --- /dev/null +++ b/CUDA_BasicMatrixMultiplication/libwb/wbThrust.h @@ -0,0 +1,15 @@ + +#ifndef __WB_THRUST_H__ +#define __WB_THRUST_H__ + +#ifdef WB_USE_CUDA +#include +#include +#include +#include +#include +#include + +#endif /* WB_USE_CUDA */ + +#endif /* __WB_THRUST_H__ */ diff --git a/CUDA_BasicMatrixMultiplication/libwb/wbTimer.cpp b/CUDA_BasicMatrixMultiplication/libwb/wbTimer.cpp new file mode 100644 index 0000000..c9fbdb8 --- /dev/null +++ b/CUDA_BasicMatrixMultiplication/libwb/wbTimer.cpp @@ -0,0 +1,493 @@ +#include "wb.h" + +#ifdef WB_USE_WINDOWS +uint64_t _hrtime_frequency = 0; +#endif /* WB_USE_WINDOWS */ +wbTimer_t _timer = NULL; + +#ifdef WB_USE_DARWIN +static double o_timebase = 0; +static uint64_t o_timestart = 0; +#endif /* WB_USE_DARWIN */ + +uint64_t _hrtime(void) { +#define NANOSEC ((uint64_t)1e9) +#ifdef WB_USE_WINDOWS + LARGE_INTEGER counter; + if (!QueryPerformanceCounter(&counter)) { + return 0; + } + return ((uint64_t)counter.LowPart * NANOSEC / _hrtime_frequency) + + (((uint64_t)counter.HighPart * NANOSEC / _hrtime_frequency) + << 32); +#else + struct timespec ts; +#ifdef WB_USE_DARWIN +#define O_NANOSEC (+1.0E-9) +#define O_GIGA UINT64_C(1000000000) + if (!o_timestart) { + mach_timebase_info_data_t tb{}; + mach_timebase_info(&tb); + o_timebase = tb.numer; + o_timebase /= tb.denom; + o_timestart = mach_absolute_time(); + } + double diff = (mach_absolute_time() - o_timestart) * o_timebase; + ts.tv_sec = diff * O_NANOSEC; + ts.tv_nsec = diff - (ts.tv_sec * O_GIGA); +#undef O_NANOSEC +#undef O_GIGA +#else /* WB_USE_DARWIN */ + clock_gettime(CLOCK_MONOTONIC, &ts); +#endif /* WB_USE_DARWIN */ + return (((uint64_t)ts.tv_sec) * NANOSEC + ts.tv_nsec); +#endif /* WB_USE_WINDOWS */ +#undef NANOSEC +} + +static inline uint64_t getTime(void) { +#ifdef WB_USE_CUDA + cudaDeviceSynchronize(); +#endif /* WB_USE_CUDA */ + return _hrtime(); +} + +static inline wbTimerNode_t wbTimerNode_new(int id, wbTimerKind_t kind, + const char *file, + const char *fun, + int startLine) { + wbTimerNode_t node = wbNew(struct st_wbTimerNode_t); + wbTimerNode_setId(node, id); + wbTimerNode_setMPIRank(node, wbMPI_getRank()); + wbTimerNode_setLevel(node, 0); + wbTimerNode_setStoppedQ(node, wbFalse); + wbTimerNode_setKind(node, kind); + wbTimerNode_setStartTime(node, 0); + wbTimerNode_setEndTime(node, 0); + wbTimerNode_setElapsedTime(node, 0); + wbTimerNode_setStartLine(node, startLine); + wbTimerNode_setEndLine(node, 0); + wbTimerNode_setStartFunction(node, fun); + wbTimerNode_setEndFunction(node, NULL); + wbTimerNode_setStartFile(node, file); + wbTimerNode_setEndFile(node, NULL); + wbTimerNode_setNext(node, NULL); + wbTimerNode_setPrevious(node, NULL); + wbTimerNode_setParent(node, NULL); + wbTimerNode_setMessage(node, NULL); + return node; +} + +static inline void wbTimerNode_delete(wbTimerNode_t node) { + if (node != NULL) { + if (wbTimerNode_getMessage(node)) { + wbDelete(wbTimerNode_getMessage(node)); + } + wbDelete(node); + } +} + +static inline const char *_nodeKind(wbTimerKind_t kind) { + switch (kind) { + case wbTimerKind_Generic: + return "Generic"; + case wbTimerKind_IO: + return "IO"; + case wbTimerKind_GPU: + return "GPU"; + case wbTimerKind_Copy: + return "Copy"; + case wbTimerKind_Driver: + return "Driver"; + case wbTimerKind_CopyAsync: + return "CopyAsync"; + case wbTimerKind_Compute: + return "Compute"; + case wbTimerKind_CPUGPUOverlap: + return "CPUGPUOverlap"; + } + return "Undefined"; +} + +static inline json11::Json wbTimerNode_toJSONObject(wbTimerNode_t node) { + json11::Json json = json11::Json::object{ + {"id", wbTimerNode_getId(node)}, + {"mpi_rank", wbTimerNode_getMPIRank(node)}, + {"stopped", wbTimerNode_stoppedQ(node)}, + {"kind", _nodeKind(wbTimerNode_getKind(node))}, + {"start_time", wbTimerNode_getStartTime(node)}, + {"end_time", wbTimerNode_getEndTime(node)}, + {"elapsed_time", wbTimerNode_getElapsedTime(node)}, + {"start_line", wbTimerNode_getStartLine(node)}, + {"end_line", wbTimerNode_getEndLine(node)}, + {"start_function", wbTimerNode_getStartFunction(node)}, + {"end_function", wbTimerNode_getEndFunction(node)}, + {"start_file", wbTimerNode_getStartFile(node)}, + {"end_file", wbTimerNode_getEndFile(node)}, + {"parent_id", wbTimerNode_hasParent(node) + ? wbTimerNode_getId(wbTimerNode_getParent(node)) + : -1}, + {"message", wbTimerNode_getMessage(node)}, + }; + return json; +} + +static inline string wbTimerNode_toJSON(wbTimerNode_t node) { + if (node == NULL) { + return ""; + } else if (WB_USE_JSON11) { + json11::Json json = wbTimerNode_toJSONObject(node); + return json.string_value(); + } else { + stringstream ss; + + ss << "{\n"; + ss << wbString_quote("id") << ":" << wbTimerNode_getId(node) << ",\n"; + ss << wbString_quote("mpi_rank") << ":" << wbTimerNode_getMPIRank(node) + << ",\n"; + ss << wbString_quote("stopped") << ":" + << wbString(wbTimerNode_stoppedQ(node) ? "true" : "false") << ",\n"; + ss << wbString_quote("kind") << ":" + << wbString_quote(_nodeKind(wbTimerNode_getKind(node))) << ",\n"; + ss << wbString_quote("start_time") << ":" + << wbTimerNode_getStartTime(node) << ",\n"; + ss << wbString_quote("end_time") << ":" << wbTimerNode_getEndTime(node) + << ",\n"; + ss << wbString_quote("elapsed_time") << ":" + << wbTimerNode_getElapsedTime(node) << ",\n"; + ss << wbString_quote("start_line") << ":" + << wbTimerNode_getStartLine(node) << ",\n"; + ss << wbString_quote("end_line") << ":" << wbTimerNode_getEndLine(node) + << ",\n"; + ss << wbString_quote("start_function") << ":" + << wbString_quote(wbTimerNode_getStartFunction(node)) << ",\n"; + ss << wbString_quote("end_function") << ":" + << wbString_quote(wbTimerNode_getEndFunction(node)) << ",\n"; + ss << wbString_quote("start_file") << ":" + << wbString_quote(wbTimerNode_getStartFile(node)) << ",\n"; + ss << wbString_quote("end_file") << ":" + << wbString_quote(wbTimerNode_getEndFile(node)) << ",\n"; + ss << wbString_quote("parent_id") << ":" + << wbString(wbTimerNode_hasParent(node) + ? wbTimerNode_getId(wbTimerNode_getParent(node)) + : -1) + << ",\n"; + ss << wbString_quote("message") << ":" + << wbString_quote(wbTimerNode_getMessage(node)) << "\n"; + ss << "}"; + + return ss.str(); + } +} + +static inline string wbTimerNode_toXML(wbTimerNode_t node) { + if (node == NULL) { + return ""; + } else { + stringstream ss; + + ss << "\n"; + ss << "" << wbTimerNode_getId(node) << "\n"; + ss << "" + << wbString(wbTimerNode_stoppedQ(node) ? "true" : "false") + << "\n"; + ss << "" << _nodeKind(wbTimerNode_getKind(node)) << "\n"; + ss << "" << wbTimerNode_getStartTime(node) + << "\n"; + ss << "" << wbTimerNode_getEndTime(node) << "\n"; + ss << "" << wbTimerNode_getElapsedTime(node) + << "\n"; + ss << "" << wbTimerNode_getStartLine(node) + << "\n"; + ss << "" << wbTimerNode_getEndLine(node) << "\n"; + ss << "" << wbTimerNode_getStartFunction(node) + << "\n"; + ss << "" << wbTimerNode_getEndFunction(node) + << "\n"; + ss << "" << wbTimerNode_getStartFile(node) + << "\n"; + ss << "" << wbTimerNode_getEndFile(node) << "\n"; + ss << "" + << wbString(wbTimerNode_hasParent(node) + ? wbTimerNode_getId(wbTimerNode_getParent(node)) + : -1) + << "\n"; + ss << "" << wbTimerNode_getMessage(node) << "\n"; + ss << "\n"; + + return ss.str(); + } +} + +#define wbTimer_getLength(timer) ((timer)->length) +#define wbTimer_getHead(timer) ((timer)->head) +#define wbTimer_getTail(timer) ((timer)->tail) +#define wbTimer_getStartTime(timer) ((timer)->startTime) +#define wbTimer_getEndTime(timer) ((timer)->endTime) +#define wbTimer_getElapsedTime(timer) ((timer)->elapsedTime) + +#define wbTimer_setLength(timer, val) (wbTimer_getLength(timer) = val) +#define wbTimer_setHead(timer, val) (wbTimer_getHead(timer) = val) +#define wbTimer_setTail(timer, val) (wbTimer_getTail(timer) = val) +#define wbTimer_setStartTime(node, val) (wbTimer_getStartTime(node) = val) +#define wbTimer_setEndTime(node, val) (wbTimer_getEndTime(node) = val) +#define wbTimer_setElapsedTime(node, val) \ + (wbTimer_getElapsedTime(node) = val) + +#define wbTimer_incrementLength(timer) (wbTimer_getLength(timer)++) +#define wbTimer_decrementLength(timer) (wbTimer_getLength(timer)--) + +#define wbTimer_emptyQ(timer) (wbTimer_getLength(timer) == 0) + +void wbTimer_delete(wbTimer_t timer) { + if (timer != NULL) { + wbTimerNode_t tmp, iter; + + iter = wbTimer_getHead(timer); + while (iter) { + tmp = wbTimerNode_getNext(iter); + wbTimerNode_delete(iter); + iter = tmp; + } + + wbDelete(timer); + } +} + +static json11::Json wbTimer_toJSONObject(wbTimer_t timer) { + + stringstream ss; + wbTimerNode_t iter; + uint64_t currentTime; + std::vector elems; + + currentTime = getTime(); + + wbTimer_setEndTime(timer, currentTime); + wbTimer_setElapsedTime(timer, currentTime - wbTimer_getStartTime(timer)); + + for (iter = wbTimer_getHead(timer); iter != NULL; + iter = wbTimerNode_getNext(iter)) { + if (!wbTimerNode_stoppedQ(iter)) { + wbTimerNode_setEndTime(iter, currentTime); + wbTimerNode_setElapsedTime(iter, currentTime - + wbTimerNode_getStartTime(iter)); + } + elems.push_back(wbTimerNode_toJSONObject(iter)); + } + return json11::Json(elems); +} + +string wbTimer_toJSON(wbTimer_t timer) { + if (timer == NULL) { + return ""; + } else if (WB_USE_JSON11) { + json11::Json json = wbTimer_toJSONObject(timer); + return json.string_value(); + } else { + stringstream ss; + wbTimerNode_t iter; + uint64_t currentTime; + + currentTime = getTime(); + + wbTimer_setEndTime(timer, currentTime); + wbTimer_setElapsedTime(timer, + currentTime - wbTimer_getStartTime(timer)); + + for (iter = wbTimer_getHead(timer); iter != NULL; + iter = wbTimerNode_getNext(iter)) { + if (!wbTimerNode_stoppedQ(iter)) { + wbTimerNode_setEndTime(iter, currentTime); + wbTimerNode_setElapsedTime( + iter, currentTime - wbTimerNode_getStartTime(iter)); + } + ss << wbTimerNode_toJSON(iter); + if (wbTimerNode_getNext(iter) != NULL) { + ss << ",\n"; + } + } + + return ss.str(); + } +} + +string wbTimer_toJSON() { + return wbTimer_toJSON(_timer); +} + +string wbTimer_toXML(wbTimer_t timer) { + if (timer == NULL) { + return ""; + } else { + stringstream ss; + wbTimerNode_t iter; + uint64_t currentTime; + + currentTime = getTime(); + + wbTimer_setEndTime(timer, currentTime); + wbTimer_setElapsedTime(timer, + currentTime - wbTimer_getStartTime(timer)); + + ss << "\n"; + ss << "" << wbTimer_getStartTime(timer) + << "\n"; + ss << "" << wbTimer_getEndTime(timer) << "\n"; + ss << "" << wbTimer_getElapsedTime(timer) + << "\n"; + ss << "\n"; + for (iter = wbTimer_getHead(timer); iter != NULL; + iter = wbTimerNode_getNext(iter)) { + if (!wbTimerNode_stoppedQ(iter)) { + wbTimerNode_setEndTime(iter, currentTime); + wbTimerNode_setElapsedTime( + iter, currentTime - wbTimerNode_getStartTime(iter)); + } + ss << wbTimerNode_toXML(iter); + } + ss << "\n"; + ss << "\n"; + + return ss.str(); + } +} + +string wbTimer_toXML() { + return wbTimer_toXML(_timer); +} + +wbTimer_t wbTimer_new(void) { + wbTimer_t timer = wbNew(struct st_wbTimer_t); + wbTimer_setLength(timer, 0); + wbTimer_setHead(timer, NULL); + wbTimer_setTail(timer, NULL); + wbTimer_setStartTime(timer, getTime()); + wbTimer_setEndTime(timer, 0); + wbTimer_setElapsedTime(timer, 0); + + return timer; +} + +static inline wbTimerNode_t _findParent(wbTimer_t timer) { + wbTimerNode_t iter; + + for (iter = wbTimer_getTail(timer); iter != NULL; + iter = wbTimerNode_getPrevious(iter)) { + if (!wbTimerNode_stoppedQ(iter)) { + return iter; + } + } + return NULL; +} + +static inline void _insertIntoList(wbTimer_t timer, wbTimerNode_t node) { + if (wbTimer_emptyQ(timer)) { + wbTimer_setHead(timer, node); + wbTimer_setTail(timer, node); + } else { + wbTimerNode_t end = wbTimer_getTail(timer); + wbTimer_setTail(timer, node); + wbTimerNode_setNext(end, node); + wbTimerNode_setPrevious(node, end); + } + wbTimer_incrementLength(timer); +} + +wbTimerNode_t wbTimer_start(wbTimerKind_t kind, const char *file, + const char *fun, int line) { + int id; + uint64_t currentTime; + wbTimerNode_t node; + wbTimerNode_t parent; + + wb_init(NULL, NULL); + + currentTime = getTime(); + + id = wbTimer_getLength(_timer); + + node = wbTimerNode_new(id, kind, file, fun, line); + + parent = _findParent(_timer); + _insertIntoList(_timer, node); + + wbTimerNode_setStartTime(node, currentTime); + wbTimerNode_setParent(node, parent); + if (parent != NULL) { + wbTimerNode_setLevel(node, wbTimerNode_getLevel(parent) + 1); + } + + return node; +} + +wbTimerNode_t wbTimer_start(wbTimerKind_t kind, string msg, + const char *file, const char *fun, int line) { + wbTimerNode_t node = wbTimer_start(kind, file, fun, line); + wbTimerNode_setMessage(node, wbString_duplicate(msg)); + return node; +} + +static inline wbTimerNode_t _findNode(wbTimer_t timer, wbTimerKind_t kind, + string msg) { + wbTimerNode_t iter; + + for (iter = wbTimer_getTail(timer); iter != NULL; + iter = wbTimerNode_getPrevious(iter)) { + if (msg == "") { + if (!wbTimerNode_stoppedQ(iter) && + wbTimerNode_getKind(iter) == kind) { + return iter; + } + } else { + if (!wbTimerNode_stoppedQ(iter) && + wbTimerNode_getKind(iter) == kind && + msg == wbTimerNode_getMessage(iter)) { + return iter; + } + } + } + return NULL; +} + +void wbTimer_stop(wbTimerKind_t kind, string msg, const char *file, + const char *fun, int line) { + uint64_t currentTime; + wbTimerNode_t node; + + currentTime = getTime(); + + node = _findNode(_timer, kind, msg); + + wbAssert(node != NULL); + if (node == NULL) { + return; + } + + wbTimerNode_setEndTime(node, currentTime); + wbTimerNode_setElapsedTime(node, + currentTime - wbTimerNode_getStartTime(node)); + wbTimerNode_setEndLine(node, line); + wbTimerNode_setEndFunction(node, fun); + wbTimerNode_setEndFile(node, file); + wbTimerNode_setStoppedQ(node, wbTrue); + +#ifdef wbLogger_printOnLog + if (wbLogger_printOnLog) { + json11::Json json = json11::Json::object{ +//PMO +#ifndef _MSC_VER + { "type", "timer" }, { "data", wbTimerNode_toJSONObject(node) }}; +#else + { "data", wbTimerNode_toJSONObject(node) }, { "type", "timer" }}; +#endif + std::cout << json.dump() << std::endl; + } +#endif /* wbLogger_printOnLog */ + return; +} + +void wbTimer_stop(wbTimerKind_t kind, const char *file, const char *fun, + int line) { + wbTimer_stop(kind, "", file, fun, line); +} diff --git a/CUDA_BasicMatrixMultiplication/libwb/wbTimer.h b/CUDA_BasicMatrixMultiplication/libwb/wbTimer.h new file mode 100644 index 0000000..133b58f --- /dev/null +++ b/CUDA_BasicMatrixMultiplication/libwb/wbTimer.h @@ -0,0 +1,139 @@ + + +#ifndef __WB_TIMER_H__ +#define __WB_TIMER_H__ + +#ifdef WB_USE_WINDOWS +extern uint64_t _hrtime_frequency; +#endif /* _WIN32 */ + +extern wbTimer_t _timer; + +typedef enum en_wbTimerKind_t { + wbTimerKind_Generic, + wbTimerKind_IO, + wbTimerKind_GPU, + wbTimerKind_Copy, + wbTimerKind_Driver, + wbTimerKind_CopyAsync, + wbTimerKind_Compute, + wbTimerKind_CPUGPUOverlap, +} wbTimerKind_t; + +struct st_wbTimerNode_t { + int id; + int mpiRank; + int level; + wbBool stoppedQ; + wbTimerKind_t kind; + uint64_t startTime; + uint64_t endTime; + uint64_t elapsedTime; + int startLine; + int endLine; + const char *startFunction; + const char *endFunction; + const char *startFile; + const char *endFile; + wbTimerNode_t next; + wbTimerNode_t prev; + wbTimerNode_t parent; + char *msg; +}; + +struct st_wbTimer_t { + size_t length; + wbTimerNode_t head; + wbTimerNode_t tail; + uint64_t startTime; + uint64_t endTime; + uint64_t elapsedTime; +}; + +#define wbTimerNode_getId(node) ((node)->id) +#define wbTimerNode_getMPIRank(node) ((node)->mpiRank) +#define wbTimerNode_getLevel(node) ((node)->level) +#define wbTimerNode_getStoppedQ(node) ((node)->stoppedQ) +#define wbTimerNode_getKind(node) ((node)->kind) +#define wbTimerNode_getStartTime(node) ((node)->startTime) +#define wbTimerNode_getEndTime(node) ((node)->endTime) +#define wbTimerNode_getElapsedTime(node) ((node)->elapsedTime) +#define wbTimerNode_getStartLine(node) ((node)->startLine) +#define wbTimerNode_getEndLine(node) ((node)->endLine) +#define wbTimerNode_getStartFunction(node) ((node)->startFunction) +#define wbTimerNode_getEndFunction(node) ((node)->endFunction) +#define wbTimerNode_getStartFile(node) ((node)->startFile) +#define wbTimerNode_getEndFile(node) ((node)->endFile) +#define wbTimerNode_getNext(node) ((node)->next) +#define wbTimerNode_getPrevious(node) ((node)->prev) +#define wbTimerNode_getParent(node) ((node)->parent) +#define wbTimerNode_getMessage(node) ((node)->msg) + +#define wbTimerNode_setId(node, val) (wbTimerNode_getId(node) = val) +#define wbTimerNode_setMPIRank(node, val) \ + (wbTimerNode_getMPIRank(node) = val) +#define wbTimerNode_setLevel(node, val) (wbTimerNode_getLevel(node) = val) +#define wbTimerNode_setStoppedQ(node, val) \ + (wbTimerNode_getStoppedQ(node) = val) +#define wbTimerNode_setKind(node, val) (wbTimerNode_getKind(node) = val) +#define wbTimerNode_setStartTime(node, val) \ + (wbTimerNode_getStartTime(node) = val) +#define wbTimerNode_setEndTime(node, val) \ + (wbTimerNode_getEndTime(node) = val) +#define wbTimerNode_setElapsedTime(node, val) \ + (wbTimerNode_getElapsedTime(node) = val) +#define wbTimerNode_setStartLine(node, val) \ + (wbTimerNode_getStartLine(node) = val) +#define wbTimerNode_setEndLine(node, val) \ + (wbTimerNode_getEndLine(node) = val) +#define wbTimerNode_setStartFunction(node, val) \ + (wbTimerNode_getStartFunction(node) = val) +#define wbTimerNode_setEndFunction(node, val) \ + (wbTimerNode_getEndFunction(node) = val) +#define wbTimerNode_setStartFile(node, val) \ + (wbTimerNode_getStartFile(node) = val) +#define wbTimerNode_setEndFile(node, val) \ + (wbTimerNode_getEndFile(node) = val) +#define wbTimerNode_setNext(node, val) (wbTimerNode_getNext(node) = val) +#define wbTimerNode_setPrevious(node, val) \ + (wbTimerNode_getPrevious(node) = val) +#define wbTimerNode_setParent(node, val) \ + (wbTimerNode_getParent(node) = val) +#define wbTimerNode_setMessage(node, val) \ + (wbTimerNode_getMessage(node) = val) + +#define wbTimerNode_stoppedQ(node) \ + (wbTimerNode_getStoppedQ(node) == wbTrue) +#define wbTimerNode_hasNext(node) (wbTimerNode_getNext(node) != NULL) +#define wbTimerNode_hasPrevious(node) \ + (wbTimerNode_getPrevious(node) != NULL) +#define wbTimerNode_hasParent(node) (wbTimerNode_getParent(node) != NULL) + +uint64_t _hrtime(void); + +wbTimer_t wbTimer_new(void); +void wbTimer_delete(wbTimer_t timer); + +string wbTimer_toJSON(wbTimer_t timer); +string wbTimer_toJSON(); + +string wbTimer_toXML(wbTimer_t timer); +string wbTimer_toXML(); + +wbTimerNode_t wbTimer_start(wbTimerKind_t kind, const char *file, + const char *fun, int line); +wbTimerNode_t wbTimer_start(wbTimerKind_t kind, string msg, + const char *file, const char *fun, int line); +void wbTimer_stop(wbTimerKind_t kind, string msg, const char *file, + const char *fun, int line); +void wbTimer_stop(wbTimerKind_t kind, const char *file, const char *fun, + int line); + +#define wbTime_start(kind, ...) \ + wbTimer_start(wbTimerKind_##kind, wbString(__VA_ARGS__), wbFile, \ + wbFunction, wbLine) +#define wbTime_stop(kind, ...) \ + wbTimer_stop(wbTimerKind_##kind, wbString(__VA_ARGS__), wbFile, \ + wbFunction, wbLine) + +#endif /* __WB_TIMER_H__ */ diff --git a/CUDA_BasicMatrixMultiplication/libwb/wbTypes.h b/CUDA_BasicMatrixMultiplication/libwb/wbTypes.h new file mode 100644 index 0000000..6837792 --- /dev/null +++ b/CUDA_BasicMatrixMultiplication/libwb/wbTypes.h @@ -0,0 +1,55 @@ + + +#ifndef __WB_TYPES_H__ +#define __WB_TYPES_H__ + +#include "wbAssert.h" + +typedef bool wbBool; +typedef float wbReal_t; +typedef char wbChar_t; + +typedef struct st_wbTimerNode_t *wbTimerNode_t; +typedef struct st_wbTimer_t *wbTimer_t; +typedef struct st_wbLogEntry_t *wbLogEntry_t; +typedef struct st_wbLogger_t *wbLogger_t; +typedef struct st_wbArg_t wbArg_t; +typedef struct st_wbImage_t *wbImage_t; +typedef struct st_wbFile_t *wbFile_t; + +#define wbTrue true +#define wbFalse false + +typedef enum en_wbType_t { + wbType_unknown = -1, + wbType_ascii = 1, + wbType_bit8, + wbType_ubit8, + wbType_integer, + wbType_float, + wbType_double +} wbType_t; + +static inline size_t wbType_size(wbType_t ty) { + switch (ty) { + case wbType_unknown: + wbAssert(false && "Invalid wbType_unknown"); + return 0; + case wbType_ascii: + return sizeof(char); + case wbType_bit8: + return sizeof(char); + case wbType_ubit8: + return sizeof(unsigned char); + case wbType_integer: + return sizeof(int); + case wbType_float: + return sizeof(float); + case wbType_double: + return sizeof(double); + } + wbAssert(false && "Invalid type"); + return 0; +} + +#endif /* __WB_TYPES_H__ */ diff --git a/CUDA_BasicMatrixMultiplication/libwb/wbUtils.h b/CUDA_BasicMatrixMultiplication/libwb/wbUtils.h new file mode 100644 index 0000000..cbd1b91 --- /dev/null +++ b/CUDA_BasicMatrixMultiplication/libwb/wbUtils.h @@ -0,0 +1,10 @@ +#ifndef __WB_UTILS_H__ +#define __WB_UTILS_H__ + +#ifdef WB_DEBUG +#define DEBUG(...) __VA_ARGS__ +#else /* WB_DEBUG */ +#define DEBUG(...) +#endif /* WB_DEBUG */ + +#endif /* __WB_UTILS_H__ */ diff --git a/CUDA_BasicMatrixMultiplication/libwb/wb_test.cpp b/CUDA_BasicMatrixMultiplication/libwb/wb_test.cpp new file mode 100644 index 0000000..87883c8 --- /dev/null +++ b/CUDA_BasicMatrixMultiplication/libwb/wb_test.cpp @@ -0,0 +1,4 @@ +#define CATCH_CONFIG_MAIN + +#include "wb.h" +#include "vendor/catch.hpp" diff --git a/CUDA_Convolution/Convolution/template.cu b/CUDA_Convolution/Convolution/template.cu new file mode 100644 index 0000000..bf0dbf2 --- /dev/null +++ b/CUDA_Convolution/Convolution/template.cu @@ -0,0 +1,175 @@ +#include + +#define MASK_WIDTH 5 +#define O_TILE_WIDTH 16 +#define BLOCK_WIDTH (O_TILE_WIDTH + (MASK_WIDTH - 1)) +#define clamp(x) (min(max((x), 0.0), 1.0)) + +//implement the tiled 2D convolution kernel with adjustments for channels +//use shared memory to reduce the number of global accesses, handle the boundary conditions in when loading input list elements into the shared memory + +__global__ void convolution_2D_kernel(float *P, float *N, int imageHeight, int imageWidth, int channels, const float * __restrict__ M) { + + __shared__ float N_ds[BLOCK_WIDTH][BLOCK_WIDTH]; + + int tx = threadIdx.x; + int ty = threadIdx.y; + int bx = blockIdx.x; + int by = blockIdx.y; + int tempY = by * O_TILE_WIDTH + ty; + int tempX = bx * O_TILE_WIDTH + tx; + + for (int k = 0; k < channels; k++) { + + float accum = 0; + int offset = ty * O_TILE_WIDTH + tx; + int yOffset = offset / BLOCK_WIDTH; + int xOffset = offset % BLOCK_WIDTH; + int yIndex = by * O_TILE_WIDTH + yOffset - (MASK_WIDTH / 2); + int xIndex = bx * O_TILE_WIDTH + xOffset - (MASK_WIDTH / 2); + int index = (yIndex * imageWidth + xIndex) * channels + k; + + if (yIndex >= 0 && yIndex < imageHeight && + xIndex >= 0 && xIndex < imageWidth) { + N_ds[yOffset][xOffset] = N[index]; + } else { + N_ds[yOffset][xOffset] = 0.0f; + } + + offset = ty * O_TILE_WIDTH + tx + (O_TILE_WIDTH * O_TILE_WIDTH); + yOffset = offset / BLOCK_WIDTH; + xOffset = offset % BLOCK_WIDTH; + yIndex = by * O_TILE_WIDTH + yOffset - (MASK_WIDTH / 2); + xIndex = bx * O_TILE_WIDTH + xOffset - (MASK_WIDTH / 2); + index = (yIndex * imageWidth + xIndex) * channels + k; + + if (yOffset < BLOCK_WIDTH && xOffset < BLOCK_WIDTH) { + + if (xIndex >= 0 && xIndex < imageWidth && + yIndex >= 0 && yIndex < imageHeight) { + N_ds[yOffset][xOffset] = N[index]; + } else { + N_ds[yOffset][xOffset] = 0.0f; + } + + } else {} + + __syncthreads(); + + for (int i = 0; i < MASK_WIDTH; i++) { + + for (int j = 0; j < MASK_WIDTH; j++) { + accum += N_ds[ty + i][tx + j] * M[i * MASK_WIDTH + j]; + } + + } + + if (tempY < imageHeight && tempX < imageWidth) { + P[(tempY * imageWidth + tempX) * channels + k] = clamp(accum); + } else {} + + __syncthreads(); + + } +} + + +int main(int argc, char *argv[]) { + wbArg_t arg; + int maskRows; + int maskColumns; + int imageChannels; + int imageWidth; + int imageHeight; + char *inputImageFile; + char *inputMaskFile; + wbImage_t inputImage; + wbImage_t outputImage; + float *hostInputImageData; + float *hostOutputImageData; + float *hostMaskData; + float *deviceInputImageData; + float *deviceOutputImageData; + float *deviceMaskData; + + arg = wbArg_read(argc, argv); /* parse the input arguments */ + + inputImageFile = wbArg_getInputFile(arg, 0); + inputMaskFile = wbArg_getInputFile(arg, 1); + + inputImage = wbImport(inputImageFile); + hostMaskData = (float *)wbImport(inputMaskFile, &maskRows, &maskColumns); + + assert(maskRows == MASK_WIDTH); /* mask height is fixed to 5 */ + assert(maskColumns == MASK_WIDTH); /* mask width is fixed to 5 */ + + imageWidth = wbImage_getWidth(inputImage); + imageHeight = wbImage_getHeight(inputImage); + imageChannels = wbImage_getChannels(inputImage); + + outputImage = wbImage_new(imageWidth, imageHeight, imageChannels); + + hostInputImageData = wbImage_getData(inputImage); + hostOutputImageData = wbImage_getData(outputImage); + + wbTime_start(GPU, "Doing GPU Computation (memory + compute)"); + + wbTime_start(GPU, "Doing GPU memory allocation"); + //allocate device memory + + + cudaMalloc((void **) &deviceInputImageData, imageWidth * imageHeight * imageChannels * sizeof(float)); + cudaMalloc((void **) &deviceOutputImageData, imageWidth * imageHeight * imageChannels * sizeof(float)); + cudaMalloc((void **) &deviceMaskData, maskRows * maskColumns * sizeof(float)); + + + wbTime_stop(GPU, "Doing GPU memory allocation"); + + wbTime_start(Copy, "Copying data to the GPU"); + //copy host memory to device + + + cudaMemcpy(deviceInputImageData, hostInputImageData, imageWidth * imageHeight * imageChannels * sizeof(float), cudaMemcpyHostToDevice); + cudaMemcpy(deviceMaskData, hostMaskData, maskRows * maskColumns * sizeof(float), cudaMemcpyHostToDevice); + + + wbTime_stop(Copy, "Copying data to the GPU"); + + wbTime_start(Compute, "Doing the computation on the GPU"); + //initialize thread block and kernel grid dimensions + //invoke CUDA kernel + + + dim3 dimBlock(O_TILE_WIDTH, O_TILE_WIDTH, 1); + + dim3 dimGrid(((imageWidth - 1) / O_TILE_WIDTH) + 1, ((imageHeight - 1) / O_TILE_WIDTH) + 1, 1); + + convolution_2D_kernel<<>>(deviceOutputImageData, deviceInputImageData, imageHeight, imageWidth, imageChannels, deviceMaskData); + + + wbTime_stop(Compute, "Doing the computation on the GPU"); + + wbTime_start(Copy, "Copying data from the GPU"); + //copy results from device to host + + cudaMemcpy(hostOutputImageData, deviceOutputImageData, imageWidth * imageHeight * imageChannels * sizeof(float), cudaMemcpyDeviceToHost); + + wbTime_stop(Copy, "Copying data from the GPU"); + + wbTime_stop(GPU, "Doing GPU Computation (memory + compute)"); + + wbSolution(arg, outputImage); + + //deallocate device memory + + cudaFree(deviceInputImageData); + cudaFree(deviceOutputImageData); + cudaFree(deviceMaskData); + + + free(hostMaskData); + wbImage_delete(outputImage); + wbImage_delete(inputImage); + + return 0; +} diff --git a/CUDA_Convolution/libwb/.clang-format b/CUDA_Convolution/libwb/.clang-format new file mode 100644 index 0000000..4757ed4 --- /dev/null +++ b/CUDA_Convolution/libwb/.clang-format @@ -0,0 +1,21 @@ +--- +Language: Cpp +BasedOnStyle: LLVM +ColumnLimit: 75 +AccessModifierOffset: -2 +BreakBeforeBraces: Attach +AlignTrailingComments: true +AlignEscapedNewlinesLeft: false +AlignConsecutiveAssignments: true +AlignOperands: true +AllowShortFunctionsOnASingleLine: false +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AlwaysBreakTemplateDeclarations: true +IndentCaseLabels: true +SpacesBeforeTrailingComments: 1 +Standard: Cpp11 +TabWidth: 4 +UseTab: Never +SortIncludes: false +... diff --git a/CUDA_Convolution/libwb/.travis.yml b/CUDA_Convolution/libwb/.travis.yml new file mode 100644 index 0000000..e32c621 --- /dev/null +++ b/CUDA_Convolution/libwb/.travis.yml @@ -0,0 +1,65 @@ +# Use new trusty images, should yield newer compilers and packages +sudo: required +dist: precise +language: cpp + +matrix: + include: + - compiler: gcc + addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - g++-4.9 + env: COMPILER=g++-4.9 + - compiler: gcc + addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - g++-5 + env: COMPILER=g++-5 + - compiler: clang + addons: + apt: + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-precise-3.6 + packages: + - clang-3.6 + env: COMPILER=clang++-3.6 + - compiler: clang + addons: + apt: + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-precise-3.7 + packages: + - clang-3.7 + env: COMPILER=clang++-3.7 +# - compiler: gcc +# addons: +# apt: +# sources: +# - ubuntu-toolchain-r-test +# packages: +# - g++-6 +# env: COMPILER=g++-6 + # - compiler: clang + # addons: + # apt: + # sources: + # - ubuntu-toolchain-r-test + # - llvm-toolchain-precise-3.8 + # packages: + # - clang-3.8 + # env: COMPILER=clang++-3.8 + +before_install: + - sudo apt-get update -qq +script: + - $COMPILER --version + - make CXX=$COMPILER test + - ./test diff --git a/CUDA_Convolution/libwb/CMakeLists.txt b/CUDA_Convolution/libwb/CMakeLists.txt new file mode 100644 index 0000000..f732c32 --- /dev/null +++ b/CUDA_Convolution/libwb/CMakeLists.txt @@ -0,0 +1,34 @@ +cmake_minimum_required(VERSION 2.8 FATAL_ERROR) + +set(CMAKE_BUILD_TYPE Release) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) +set(CMAKE_COLOR_MAKEFILE ON) +set(VERBOSE_BUILD ON) +set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) +set(CMAKE_MACOSX_RPATH TRUE) +set_property(GLOBAL PROPERTY USE_FOLDERS ON) + + +project(wb) + +set(current_dir "${CMAKE_CURRENT_SOURCE_DIR}") + +if(NOT EXISTS "${CMAKE_CURRENT_BINARY_DIR}/cotire.cmake") + file(DOWNLOAD "https://raw.githubusercontent.com/sakra/cotire/master/CMake/cotire.cmake" "${CMAKE_CURRENT_BINARY_DIR}/cotire.cmake") +endif() + + + +include(${current_dir}/sources.cmake) + +set(WBLIB_STATIC ${WBLIB}) +set(WBLIB_SHARED lib${WBLIB}) + +add_library(${WBLIB_STATIC} STATIC ${LIBWB_SOURCE_FILES} ) +add_library(${WBLIB_SHARED} SHARED ${LIBWB_SOURCE_FILES} ) +set_property(TARGET ${WBLIB_STATIC} PROPERTY CXX_STANDARD 11) +set_property(TARGET ${WBLIB_SHARED} PROPERTY CXX_STANDARD 11) +if (UNIX) + set_target_properties(${WBLIB_SHARED} PROPERTIES OUTPUT_NAME ${WBLIB_STATIC}) +endif (UNIX) +set_property(TARGET ${WBLIB} PROPERTY CXX_STANDARD 11) diff --git a/CUDA_Convolution/libwb/LICENSE.TXT b/CUDA_Convolution/libwb/LICENSE.TXT new file mode 100644 index 0000000..8df244d --- /dev/null +++ b/CUDA_Convolution/libwb/LICENSE.TXT @@ -0,0 +1,36 @@ +Copyright (c) 2016, Abdul Dakkak All rights reserved. + +Developed by: Abdul Dakkak + IMPACT Group + University of Illinois, Urbana-Champaign + impact.crhc.illinois.edu + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal with the +Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, +sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +Redistributions of source code must retain the above +copyright notice, this list of conditions and the following +disclaimers. +Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following +disclaimers in the documentation and/or other materials +provided with the distribution. +Neither the names of Abdul Dakkak, Impact Group, nor the +names of its contributors may be used to endorse or promote +products derived from this Software without specific prior +written permission. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +WITH THE SOFTWARE. diff --git a/CUDA_Convolution/libwb/Makefile b/CUDA_Convolution/libwb/Makefile new file mode 100644 index 0000000..b8a72d7 --- /dev/null +++ b/CUDA_Convolution/libwb/Makefile @@ -0,0 +1,56 @@ +########################################## +# Options +########################################## +WB_LIB_PATH=$(CURDIR)/lib +WB_SRC_PATH=$(CURDIR) + +########################################## +########################################## + +DEFINES= +CXX_FLAGS=-fPIC -Wno-unused-function -x c++ -O3 -g -std=c++11 -Wall -Wno-unused-function -pedantic -I . -I $(WB_SRC_PATH) $(DEFINES) +LIBS=-lm -lstdc++ + +########################################## +########################################## + +UNAME_S := $(shell uname -s) +ifeq ($(UNAME_S),Linux) + LIBS += -lrt +endif + +########################################## +########################################## + +SOURCES := $(shell find $(WB_SRC_PATH) ! -name "*_test.cpp" -name "*.cpp") +TESTS := $(shell find $(WB_SRC_PATH) -name "*_test.cpp") + +OBJECTS = $(SOURCES:.cpp=.o) +TESTOBJECTS = $(TESTS:.cpp=.o) + +############################################## +# OUTPUT +############################################## + +.PHONY: all +.SUFFIXES: .o .cpp +all: libwb.so + +.cpp.o: + $(CXX) $(DEFINES) $(CXX_FLAGS) -c -o $@ $< + +libwb.so: $(OBJECTS) + mkdir -p $(WB_LIB_PATH) + $(CXX) -fPIC -shared -o $(WB_LIB_PATH)/$@ $(OBJECTS) $(LIBS) + +libwb.a: $(OBJECTS) + mkdir -p $(WB_LIB_PATH) + ar rcs -o $(WB_LIB_PATH)/$@ $(OBJECTS) + +test: $(TESTOBJECTS) $(OBJECTS) + $(CXX) -fPIC -o $@ $(TESTOBJECTS) $(OBJECTS) $(LIBS) + + +clean: + rm -fr $(ARCH) + -rm -f $(EXES) *.o *~ \ No newline at end of file diff --git a/CUDA_Convolution/libwb/README.md b/CUDA_Convolution/libwb/README.md new file mode 100644 index 0000000..0486f93 --- /dev/null +++ b/CUDA_Convolution/libwb/README.md @@ -0,0 +1,7 @@ + +# libWB + +[![Travis Build Status](https://travis-ci.org/abduld/libwb.svg?branch=master)](https://travis-ci.org/abduld/libwb) +[![AppVeyor status](https://ci.appveyor.com/api/projects/status/0nx5ie7gn5c0e6ai/branch/master?svg=true)](https://ci.appveyor.com/project/abduld/libwb/branch/master) + \ No newline at end of file diff --git a/CUDA_Convolution/libwb/appveyor.yml b/CUDA_Convolution/libwb/appveyor.yml new file mode 100644 index 0000000..e7a6c95 --- /dev/null +++ b/CUDA_Convolution/libwb/appveyor.yml @@ -0,0 +1,54 @@ + + +# Operating system (build VM template) +os: + - Visual Studio 2015 + + +# scripts that are called at very beginning, before repo cloning +init: + - echo init step + - git config --global core.autocrlf input + - cmake --version + - C:\"Program Files (x86)"\"Microsoft Visual Studio 14.0"\VC\vcvarsall.bat %PLATFORM% + +# clone directory +clone_folder: c:\projects\libwb +# fetch repository as zip archive +shallow_clone: true # default is "false" + +# branches to build +branches: + # whitelist + only: + - master + +platform: + - x64 +configuration: + - Release + +environment: + P: "c:/projects/libs" + + +install: + # by default, all script lines are interpreted as batch + +build: + project: ALL_BUILD.vcxproj # path to Visual Studio solution or project + +# scripts to run before build +before_build: + - echo Running cmake... + - cd c:\projects\libwb + - cmake -G "Visual Studio 14 2015 Win64" -DCMAKE_INSTALL_PREFIX=%P% + +# after_build: +# - echo after_build step + + +# on_finish always executes regardless of passed or failed builds +# on_finish: +# - echo on_finish step +# - ps: ls \ No newline at end of file diff --git a/CUDA_Convolution/libwb/sources.cmake b/CUDA_Convolution/libwb/sources.cmake new file mode 100644 index 0000000..4ac1b10 --- /dev/null +++ b/CUDA_Convolution/libwb/sources.cmake @@ -0,0 +1,31 @@ + +set(WBLIB "wb") + +include_directories(${CMAKE_CURRENT_LIST_DIR}) + +file(GLOB THESE_CPP_FILES + ${CMAKE_CURRENT_LIST_DIR}/*.cpp +) + +file(GLOB THESE_TEST_FILES + ${CMAKE_CURRENT_LIST_DIR}/*_test.cpp +) + +list(REMOVE_ITEM THESE_CPP_FILES ${THESE_TEST_FILES}) + +file(GLOB THESE_HEADER_FILES + ${CMAKE_CURRENT_LIST_DIR}/*.h +) + +list(APPEND LIBWB_HEADER_FILES + ${THESE_HEADER_FILES} +) + +list(APPEND LIBWB_SOURCE_FILES + ${THESE_CPP_FILES} + ${CMAKE_CURRENT_LIST_DIR}/vendor/json11.cpp +) + +list(APPEND LIBWB_TEST_FILES + ${THESE_TEST_FILES} +) diff --git a/CUDA_Convolution/libwb/vendor/catch.hpp b/CUDA_Convolution/libwb/vendor/catch.hpp new file mode 100644 index 0000000..f52eebd --- /dev/null +++ b/CUDA_Convolution/libwb/vendor/catch.hpp @@ -0,0 +1,10414 @@ +/* + * Catch v1.3.6 + * Generated: 2016-03-11 18:30:42.852700 + * ---------------------------------------------------------- + * This file has been merged from multiple headers. Please don't edit it directly + * Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved. + * + * Distributed under the Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + */ +#ifndef TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED +#define TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED + +#define TWOBLUECUBES_CATCH_HPP_INCLUDED + +#ifdef __clang__ +# pragma clang system_header +#elif defined __GNUC__ +# pragma GCC system_header +#endif + +// #included from: internal/catch_suppress_warnings.h + +#ifdef __clang__ +# ifdef __ICC // icpc defines the __clang__ macro +# pragma warning(push) +# pragma warning(disable: 161 1682) +# else // __ICC +# pragma clang diagnostic ignored "-Wglobal-constructors" +# pragma clang diagnostic ignored "-Wvariadic-macros" +# pragma clang diagnostic ignored "-Wc99-extensions" +# pragma clang diagnostic ignored "-Wunused-variable" +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wpadded" +# pragma clang diagnostic ignored "-Wc++98-compat" +# pragma clang diagnostic ignored "-Wc++98-compat-pedantic" +# pragma clang diagnostic ignored "-Wswitch-enum" +# pragma clang diagnostic ignored "-Wcovered-switch-default" +# endif +#elif defined __GNUC__ +# pragma GCC diagnostic ignored "-Wvariadic-macros" +# pragma GCC diagnostic ignored "-Wunused-variable" +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wpadded" +#endif +#if defined(CATCH_CONFIG_MAIN) || defined(CATCH_CONFIG_RUNNER) +# define CATCH_IMPL +#endif + +#ifdef CATCH_IMPL +# ifndef CLARA_CONFIG_MAIN +# define CLARA_CONFIG_MAIN_NOT_DEFINED +# define CLARA_CONFIG_MAIN +# endif +#endif + +// #included from: internal/catch_notimplemented_exception.h +#define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_H_INCLUDED + +// #included from: catch_common.h +#define TWOBLUECUBES_CATCH_COMMON_H_INCLUDED + +#define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line +#define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) +#define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ ) + +#define INTERNAL_CATCH_STRINGIFY2( expr ) #expr +#define INTERNAL_CATCH_STRINGIFY( expr ) INTERNAL_CATCH_STRINGIFY2( expr ) + +#include +#include +#include + +// #included from: catch_compiler_capabilities.h +#define TWOBLUECUBES_CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED + +// Detect a number of compiler features - mostly C++11/14 conformance - by compiler +// The following features are defined: +// +// CATCH_CONFIG_CPP11_NULLPTR : is nullptr supported? +// CATCH_CONFIG_CPP11_NOEXCEPT : is noexcept supported? +// CATCH_CONFIG_CPP11_GENERATED_METHODS : The delete and default keywords for compiler generated methods +// CATCH_CONFIG_CPP11_IS_ENUM : std::is_enum is supported? +// CATCH_CONFIG_CPP11_TUPLE : std::tuple is supported +// CATCH_CONFIG_CPP11_LONG_LONG : is long long supported? +// CATCH_CONFIG_CPP11_OVERRIDE : is override supported? +// CATCH_CONFIG_CPP11_UNIQUE_PTR : is unique_ptr supported (otherwise use auto_ptr) + +// CATCH_CONFIG_CPP11_OR_GREATER : Is C++11 supported? + +// CATCH_CONFIG_VARIADIC_MACROS : are variadic macros supported? + +// **************** +// Note to maintainers: if new toggles are added please document them +// in configuration.md, too +// **************** + +// In general each macro has a _NO_ form +// (e.g. CATCH_CONFIG_CPP11_NO_NULLPTR) which disables the feature. +// Many features, at point of detection, define an _INTERNAL_ macro, so they +// can be combined, en-mass, with the _NO_ forms later. + +// All the C++11 features can be disabled with CATCH_CONFIG_NO_CPP11 + +#if defined(__cplusplus) && __cplusplus >= 201103L +# define CATCH_CPP11_OR_GREATER +#endif + +#ifdef __clang__ + +# if __has_feature(cxx_nullptr) +# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR +# endif + +# if __has_feature(cxx_noexcept) +# define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT +# endif + +# if defined(CATCH_CPP11_OR_GREATER) +# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS _Pragma( "clang diagnostic ignored \"-Wparentheses\"" ) +# endif + +#endif // __clang__ + +//////////////////////////////////////////////////////////////////////////////// +// Borland +#ifdef __BORLANDC__ + +#endif // __BORLANDC__ + +//////////////////////////////////////////////////////////////////////////////// +// EDG +#ifdef __EDG_VERSION__ + +#endif // __EDG_VERSION__ + +//////////////////////////////////////////////////////////////////////////////// +// Digital Mars +#ifdef __DMC__ + +#endif // __DMC__ + +//////////////////////////////////////////////////////////////////////////////// +// GCC +#ifdef __GNUC__ + +# if __GNUC__ == 4 && __GNUC_MINOR__ >= 6 && defined(__GXX_EXPERIMENTAL_CXX0X__) +# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR +# endif + +# if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS) && defined(CATCH_CPP11_OR_GREATER) +# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS _Pragma( "GCC diagnostic ignored \"-Wparentheses\"" ) +# endif + +// - otherwise more recent versions define __cplusplus >= 201103L +// and will get picked up below + +#endif // __GNUC__ + +//////////////////////////////////////////////////////////////////////////////// +// Visual C++ +#ifdef _MSC_VER + +#if (_MSC_VER >= 1600) +# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR +# define CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR +#endif + +#if (_MSC_VER >= 1900 ) // (VC++ 13 (VS2015)) +#define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT +#define CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS +#endif + +#endif // _MSC_VER + +//////////////////////////////////////////////////////////////////////////////// + +// Use variadic macros if the compiler supports them +#if ( defined _MSC_VER && _MSC_VER > 1400 && !defined __EDGE__) || \ + ( defined __WAVE__ && __WAVE_HAS_VARIADICS ) || \ + ( defined __GNUC__ && __GNUC__ >= 3 ) || \ + ( !defined __cplusplus && __STDC_VERSION__ >= 199901L || __cplusplus >= 201103L ) + +#define CATCH_INTERNAL_CONFIG_VARIADIC_MACROS + +#endif + +//////////////////////////////////////////////////////////////////////////////// +// C++ language feature support + +// catch all support for C++11 +#if defined(CATCH_CPP11_OR_GREATER) + +# if !defined(CATCH_INTERNAL_CONFIG_CPP11_NULLPTR) +# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR +# endif + +# ifndef CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT +# define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT +# endif + +# ifndef CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS +# define CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS +# endif + +# ifndef CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM +# define CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM +# endif + +# ifndef CATCH_INTERNAL_CONFIG_CPP11_TUPLE +# define CATCH_INTERNAL_CONFIG_CPP11_TUPLE +# endif + +# ifndef CATCH_INTERNAL_CONFIG_VARIADIC_MACROS +# define CATCH_INTERNAL_CONFIG_VARIADIC_MACROS +# endif + +# if !defined(CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG) +# define CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG +# endif + +# if !defined(CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE) +# define CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE +# endif +# if !defined(CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) +# define CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR +# endif + +#endif // __cplusplus >= 201103L + +// Now set the actual defines based on the above + anything the user has configured +#if defined(CATCH_INTERNAL_CONFIG_CPP11_NULLPTR) && !defined(CATCH_CONFIG_CPP11_NO_NULLPTR) && !defined(CATCH_CONFIG_CPP11_NULLPTR) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_NULLPTR +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_CONFIG_CPP11_NO_NOEXCEPT) && !defined(CATCH_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_NOEXCEPT +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS) && !defined(CATCH_CONFIG_CPP11_NO_GENERATED_METHODS) && !defined(CATCH_CONFIG_CPP11_GENERATED_METHODS) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_GENERATED_METHODS +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM) && !defined(CATCH_CONFIG_CPP11_NO_IS_ENUM) && !defined(CATCH_CONFIG_CPP11_IS_ENUM) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_IS_ENUM +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_TUPLE) && !defined(CATCH_CONFIG_CPP11_NO_TUPLE) && !defined(CATCH_CONFIG_CPP11_TUPLE) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_TUPLE +#endif +#if defined(CATCH_INTERNAL_CONFIG_VARIADIC_MACROS) && !defined(CATCH_CONFIG_NO_VARIADIC_MACROS) && !defined(CATCH_CONFIG_VARIADIC_MACROS) +# define CATCH_CONFIG_VARIADIC_MACROS +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG) && !defined(CATCH_CONFIG_NO_LONG_LONG) && !defined(CATCH_CONFIG_CPP11_LONG_LONG) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_LONG_LONG +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE) && !defined(CATCH_CONFIG_NO_OVERRIDE) && !defined(CATCH_CONFIG_CPP11_OVERRIDE) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_OVERRIDE +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) && !defined(CATCH_CONFIG_NO_UNIQUE_PTR) && !defined(CATCH_CONFIG_CPP11_UNIQUE_PTR) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_UNIQUE_PTR +#endif + +#if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS) +# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS +#endif + +// noexcept support: +#if defined(CATCH_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_NOEXCEPT) +# define CATCH_NOEXCEPT noexcept +# define CATCH_NOEXCEPT_IS(x) noexcept(x) +#else +# define CATCH_NOEXCEPT throw() +# define CATCH_NOEXCEPT_IS(x) +#endif + +// nullptr support +#ifdef CATCH_CONFIG_CPP11_NULLPTR +# define CATCH_NULL nullptr +#else +# define CATCH_NULL NULL +#endif + +// override support +#ifdef CATCH_CONFIG_CPP11_OVERRIDE +# define CATCH_OVERRIDE override +#else +# define CATCH_OVERRIDE +#endif + +// unique_ptr support +#ifdef CATCH_CONFIG_CPP11_UNIQUE_PTR +# define CATCH_AUTO_PTR( T ) std::unique_ptr +#else +# define CATCH_AUTO_PTR( T ) std::auto_ptr +#endif + +namespace Catch { + + struct IConfig; + + struct CaseSensitive { enum Choice { + Yes, + No + }; }; + + class NonCopyable { +#ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + NonCopyable( NonCopyable const& ) = delete; + NonCopyable( NonCopyable && ) = delete; + NonCopyable& operator = ( NonCopyable const& ) = delete; + NonCopyable& operator = ( NonCopyable && ) = delete; +#else + NonCopyable( NonCopyable const& info ); + NonCopyable& operator = ( NonCopyable const& ); +#endif + + protected: + NonCopyable() {} + virtual ~NonCopyable(); + }; + + class SafeBool { + public: + typedef void (SafeBool::*type)() const; + + static type makeSafe( bool value ) { + return value ? &SafeBool::trueValue : 0; + } + private: + void trueValue() const {} + }; + + template + inline void deleteAll( ContainerT& container ) { + typename ContainerT::const_iterator it = container.begin(); + typename ContainerT::const_iterator itEnd = container.end(); + for(; it != itEnd; ++it ) + delete *it; + } + template + inline void deleteAllValues( AssociativeContainerT& container ) { + typename AssociativeContainerT::const_iterator it = container.begin(); + typename AssociativeContainerT::const_iterator itEnd = container.end(); + for(; it != itEnd; ++it ) + delete it->second; + } + + bool startsWith( std::string const& s, std::string const& prefix ); + bool endsWith( std::string const& s, std::string const& suffix ); + bool contains( std::string const& s, std::string const& infix ); + void toLowerInPlace( std::string& s ); + std::string toLower( std::string const& s ); + std::string trim( std::string const& str ); + bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ); + + struct pluralise { + pluralise( std::size_t count, std::string const& label ); + + friend std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ); + + std::size_t m_count; + std::string m_label; + }; + + struct SourceLineInfo { + + SourceLineInfo(); + SourceLineInfo( char const* _file, std::size_t _line ); + SourceLineInfo( SourceLineInfo const& other ); +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + SourceLineInfo( SourceLineInfo && ) = default; + SourceLineInfo& operator = ( SourceLineInfo const& ) = default; + SourceLineInfo& operator = ( SourceLineInfo && ) = default; +# endif + bool empty() const; + bool operator == ( SourceLineInfo const& other ) const; + bool operator < ( SourceLineInfo const& other ) const; + + std::string file; + std::size_t line; + }; + + std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ); + + // This is just here to avoid compiler warnings with macro constants and boolean literals + inline bool isTrue( bool value ){ return value; } + inline bool alwaysTrue() { return true; } + inline bool alwaysFalse() { return false; } + + void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo ); + + void seedRng( IConfig const& config ); + unsigned int rngSeed(); + + // Use this in variadic streaming macros to allow + // >> +StreamEndStop + // as well as + // >> stuff +StreamEndStop + struct StreamEndStop { + std::string operator+() { + return std::string(); + } + }; + template + T const& operator + ( T const& value, StreamEndStop ) { + return value; + } +} + +#define CATCH_INTERNAL_LINEINFO ::Catch::SourceLineInfo( __FILE__, static_cast( __LINE__ ) ) +#define CATCH_INTERNAL_ERROR( msg ) ::Catch::throwLogicError( msg, CATCH_INTERNAL_LINEINFO ); + +#include + +namespace Catch { + + class NotImplementedException : public std::exception + { + public: + NotImplementedException( SourceLineInfo const& lineInfo ); + NotImplementedException( NotImplementedException const& ) {} + + virtual ~NotImplementedException() CATCH_NOEXCEPT {} + + virtual const char* what() const CATCH_NOEXCEPT; + + private: + std::string m_what; + SourceLineInfo m_lineInfo; + }; + +} // end namespace Catch + +/////////////////////////////////////////////////////////////////////////////// +#define CATCH_NOT_IMPLEMENTED throw Catch::NotImplementedException( CATCH_INTERNAL_LINEINFO ) + +// #included from: internal/catch_context.h +#define TWOBLUECUBES_CATCH_CONTEXT_H_INCLUDED + +// #included from: catch_interfaces_generators.h +#define TWOBLUECUBES_CATCH_INTERFACES_GENERATORS_H_INCLUDED + +#include + +namespace Catch { + + struct IGeneratorInfo { + virtual ~IGeneratorInfo(); + virtual bool moveNext() = 0; + virtual std::size_t getCurrentIndex() const = 0; + }; + + struct IGeneratorsForTest { + virtual ~IGeneratorsForTest(); + + virtual IGeneratorInfo& getGeneratorInfo( std::string const& fileInfo, std::size_t size ) = 0; + virtual bool moveNext() = 0; + }; + + IGeneratorsForTest* createGeneratorsForTest(); + +} // end namespace Catch + +// #included from: catch_ptr.hpp +#define TWOBLUECUBES_CATCH_PTR_HPP_INCLUDED + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpadded" +#endif + +namespace Catch { + + // An intrusive reference counting smart pointer. + // T must implement addRef() and release() methods + // typically implementing the IShared interface + template + class Ptr { + public: + Ptr() : m_p( CATCH_NULL ){} + Ptr( T* p ) : m_p( p ){ + if( m_p ) + m_p->addRef(); + } + Ptr( Ptr const& other ) : m_p( other.m_p ){ + if( m_p ) + m_p->addRef(); + } + ~Ptr(){ + if( m_p ) + m_p->release(); + } + void reset() { + if( m_p ) + m_p->release(); + m_p = CATCH_NULL; + } + Ptr& operator = ( T* p ){ + Ptr temp( p ); + swap( temp ); + return *this; + } + Ptr& operator = ( Ptr const& other ){ + Ptr temp( other ); + swap( temp ); + return *this; + } + void swap( Ptr& other ) { std::swap( m_p, other.m_p ); } + T* get() const{ return m_p; } + T& operator*() const { return *m_p; } + T* operator->() const { return m_p; } + bool operator !() const { return m_p == CATCH_NULL; } + operator SafeBool::type() const { return SafeBool::makeSafe( m_p != CATCH_NULL ); } + + private: + T* m_p; + }; + + struct IShared : NonCopyable { + virtual ~IShared(); + virtual void addRef() const = 0; + virtual void release() const = 0; + }; + + template + struct SharedImpl : T { + + SharedImpl() : m_rc( 0 ){} + + virtual void addRef() const { + ++m_rc; + } + virtual void release() const { + if( --m_rc == 0 ) + delete this; + } + + mutable unsigned int m_rc; + }; + +} // end namespace Catch + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +#include +#include +#include + +namespace Catch { + + class TestCase; + class Stream; + struct IResultCapture; + struct IRunner; + struct IGeneratorsForTest; + struct IConfig; + + struct IContext + { + virtual ~IContext(); + + virtual IResultCapture* getResultCapture() = 0; + virtual IRunner* getRunner() = 0; + virtual size_t getGeneratorIndex( std::string const& fileInfo, size_t totalSize ) = 0; + virtual bool advanceGeneratorsForCurrentTest() = 0; + virtual Ptr getConfig() const = 0; + }; + + struct IMutableContext : IContext + { + virtual ~IMutableContext(); + virtual void setResultCapture( IResultCapture* resultCapture ) = 0; + virtual void setRunner( IRunner* runner ) = 0; + virtual void setConfig( Ptr const& config ) = 0; + }; + + IContext& getCurrentContext(); + IMutableContext& getCurrentMutableContext(); + void cleanUpContext(); + Stream createStream( std::string const& streamName ); + +} + +// #included from: internal/catch_test_registry.hpp +#define TWOBLUECUBES_CATCH_TEST_REGISTRY_HPP_INCLUDED + +// #included from: catch_interfaces_testcase.h +#define TWOBLUECUBES_CATCH_INTERFACES_TESTCASE_H_INCLUDED + +#include + +namespace Catch { + + class TestSpec; + + struct ITestCase : IShared { + virtual void invoke () const = 0; + protected: + virtual ~ITestCase(); + }; + + class TestCase; + struct IConfig; + + struct ITestCaseRegistry { + virtual ~ITestCaseRegistry(); + virtual std::vector const& getAllTests() const = 0; + virtual std::vector const& getAllTestsSorted( IConfig const& config ) const = 0; + }; + + bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ); + std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ); + std::vector const& getAllTestCasesSorted( IConfig const& config ); + +} + +namespace Catch { + +template +class MethodTestCase : public SharedImpl { + +public: + MethodTestCase( void (C::*method)() ) : m_method( method ) {} + + virtual void invoke() const { + C obj; + (obj.*m_method)(); + } + +private: + virtual ~MethodTestCase() {} + + void (C::*m_method)(); +}; + +typedef void(*TestFunction)(); + +struct NameAndDesc { + NameAndDesc( const char* _name = "", const char* _description= "" ) + : name( _name ), description( _description ) + {} + + const char* name; + const char* description; +}; + +void registerTestCase + ( ITestCase* testCase, + char const* className, + NameAndDesc const& nameAndDesc, + SourceLineInfo const& lineInfo ); + +struct AutoReg { + + AutoReg + ( TestFunction function, + SourceLineInfo const& lineInfo, + NameAndDesc const& nameAndDesc ); + + template + AutoReg + ( void (C::*method)(), + char const* className, + NameAndDesc const& nameAndDesc, + SourceLineInfo const& lineInfo ) { + + registerTestCase + ( new MethodTestCase( method ), + className, + nameAndDesc, + lineInfo ); + } + + ~AutoReg(); + +private: + AutoReg( AutoReg const& ); + void operator= ( AutoReg const& ); +}; + +void registerTestCaseFunction + ( TestFunction function, + SourceLineInfo const& lineInfo, + NameAndDesc const& nameAndDesc ); + +} // end namespace Catch + +#ifdef CATCH_CONFIG_VARIADIC_MACROS + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_TESTCASE( ... ) \ + static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )(); \ + namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( __VA_ARGS__ ) ); }\ + static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )() + + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \ + namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); } + + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, ... )\ + namespace{ \ + struct INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ) : ClassName{ \ + void test(); \ + }; \ + Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test, #ClassName, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); \ + } \ + void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test() + + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, ... ) \ + Catch::AutoReg( Function, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( __VA_ARGS__ ) ); + +#else + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_TESTCASE( Name, Desc ) \ + static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )(); \ + namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( Name, Desc ) ); }\ + static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )() + + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, Name, Desc ) \ + namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( Name, Desc ), CATCH_INTERNAL_LINEINFO ); } + + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, TestName, Desc )\ + namespace{ \ + struct INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ) : ClassName{ \ + void test(); \ + }; \ + Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test, #ClassName, Catch::NameAndDesc( TestName, Desc ), CATCH_INTERNAL_LINEINFO ); \ + } \ + void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test() + + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, Name, Desc ) \ + Catch::AutoReg( Function, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( Name, Desc ) ); +#endif + +// #included from: internal/catch_capture.hpp +#define TWOBLUECUBES_CATCH_CAPTURE_HPP_INCLUDED + +// #included from: catch_result_builder.h +#define TWOBLUECUBES_CATCH_RESULT_BUILDER_H_INCLUDED + +// #included from: catch_result_type.h +#define TWOBLUECUBES_CATCH_RESULT_TYPE_H_INCLUDED + +namespace Catch { + + // ResultWas::OfType enum + struct ResultWas { enum OfType { + Unknown = -1, + Ok = 0, + Info = 1, + Warning = 2, + + FailureBit = 0x10, + + ExpressionFailed = FailureBit | 1, + ExplicitFailure = FailureBit | 2, + + Exception = 0x100 | FailureBit, + + ThrewException = Exception | 1, + DidntThrowException = Exception | 2, + + FatalErrorCondition = 0x200 | FailureBit + + }; }; + + inline bool isOk( ResultWas::OfType resultType ) { + return ( resultType & ResultWas::FailureBit ) == 0; + } + inline bool isJustInfo( int flags ) { + return flags == ResultWas::Info; + } + + // ResultDisposition::Flags enum + struct ResultDisposition { enum Flags { + Normal = 0x01, + + ContinueOnFailure = 0x02, // Failures fail test, but execution continues + FalseTest = 0x04, // Prefix expression with ! + SuppressFail = 0x08 // Failures are reported but do not fail the test + }; }; + + inline ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs ) { + return static_cast( static_cast( lhs ) | static_cast( rhs ) ); + } + + inline bool shouldContinueOnFailure( int flags ) { return ( flags & ResultDisposition::ContinueOnFailure ) != 0; } + inline bool isFalseTest( int flags ) { return ( flags & ResultDisposition::FalseTest ) != 0; } + inline bool shouldSuppressFailure( int flags ) { return ( flags & ResultDisposition::SuppressFail ) != 0; } + +} // end namespace Catch + +// #included from: catch_assertionresult.h +#define TWOBLUECUBES_CATCH_ASSERTIONRESULT_H_INCLUDED + +#include + +namespace Catch { + + struct AssertionInfo + { + AssertionInfo() {} + AssertionInfo( std::string const& _macroName, + SourceLineInfo const& _lineInfo, + std::string const& _capturedExpression, + ResultDisposition::Flags _resultDisposition ); + + std::string macroName; + SourceLineInfo lineInfo; + std::string capturedExpression; + ResultDisposition::Flags resultDisposition; + }; + + struct AssertionResultData + { + AssertionResultData() : resultType( ResultWas::Unknown ) {} + + std::string reconstructedExpression; + std::string message; + ResultWas::OfType resultType; + }; + + class AssertionResult { + public: + AssertionResult(); + AssertionResult( AssertionInfo const& info, AssertionResultData const& data ); + ~AssertionResult(); +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + AssertionResult( AssertionResult const& ) = default; + AssertionResult( AssertionResult && ) = default; + AssertionResult& operator = ( AssertionResult const& ) = default; + AssertionResult& operator = ( AssertionResult && ) = default; +# endif + + bool isOk() const; + bool succeeded() const; + ResultWas::OfType getResultType() const; + bool hasExpression() const; + bool hasMessage() const; + std::string getExpression() const; + std::string getExpressionInMacro() const; + bool hasExpandedExpression() const; + std::string getExpandedExpression() const; + std::string getMessage() const; + SourceLineInfo getSourceInfo() const; + std::string getTestMacroName() const; + + protected: + AssertionInfo m_info; + AssertionResultData m_resultData; + }; + +} // end namespace Catch + +// #included from: catch_matchers.hpp +#define TWOBLUECUBES_CATCH_MATCHERS_HPP_INCLUDED + +namespace Catch { +namespace Matchers { + namespace Impl { + + namespace Generic { + template class AllOf; + template class AnyOf; + template class Not; + } + + template + struct Matcher : SharedImpl + { + typedef ExpressionT ExpressionType; + + virtual ~Matcher() {} + virtual Ptr clone() const = 0; + virtual bool match( ExpressionT const& expr ) const = 0; + virtual std::string toString() const = 0; + + Generic::AllOf operator && ( Matcher const& other ) const; + Generic::AnyOf operator || ( Matcher const& other ) const; + Generic::Not operator ! () const; + }; + + template + struct MatcherImpl : Matcher { + + virtual Ptr > clone() const { + return Ptr >( new DerivedT( static_cast( *this ) ) ); + } + }; + + namespace Generic { + template + class Not : public MatcherImpl, ExpressionT> { + public: + explicit Not( Matcher const& matcher ) : m_matcher(matcher.clone()) {} + Not( Not const& other ) : m_matcher( other.m_matcher ) {} + + virtual bool match( ExpressionT const& expr ) const CATCH_OVERRIDE { + return !m_matcher->match( expr ); + } + + virtual std::string toString() const CATCH_OVERRIDE { + return "not " + m_matcher->toString(); + } + private: + Ptr< Matcher > m_matcher; + }; + + template + class AllOf : public MatcherImpl, ExpressionT> { + public: + + AllOf() {} + AllOf( AllOf const& other ) : m_matchers( other.m_matchers ) {} + + AllOf& add( Matcher const& matcher ) { + m_matchers.push_back( matcher.clone() ); + return *this; + } + virtual bool match( ExpressionT const& expr ) const + { + for( std::size_t i = 0; i < m_matchers.size(); ++i ) + if( !m_matchers[i]->match( expr ) ) + return false; + return true; + } + virtual std::string toString() const { + std::ostringstream oss; + oss << "( "; + for( std::size_t i = 0; i < m_matchers.size(); ++i ) { + if( i != 0 ) + oss << " and "; + oss << m_matchers[i]->toString(); + } + oss << " )"; + return oss.str(); + } + + AllOf operator && ( Matcher const& other ) const { + AllOf allOfExpr( *this ); + allOfExpr.add( other ); + return allOfExpr; + } + + private: + std::vector > > m_matchers; + }; + + template + class AnyOf : public MatcherImpl, ExpressionT> { + public: + + AnyOf() {} + AnyOf( AnyOf const& other ) : m_matchers( other.m_matchers ) {} + + AnyOf& add( Matcher const& matcher ) { + m_matchers.push_back( matcher.clone() ); + return *this; + } + virtual bool match( ExpressionT const& expr ) const + { + for( std::size_t i = 0; i < m_matchers.size(); ++i ) + if( m_matchers[i]->match( expr ) ) + return true; + return false; + } + virtual std::string toString() const { + std::ostringstream oss; + oss << "( "; + for( std::size_t i = 0; i < m_matchers.size(); ++i ) { + if( i != 0 ) + oss << " or "; + oss << m_matchers[i]->toString(); + } + oss << " )"; + return oss.str(); + } + + AnyOf operator || ( Matcher const& other ) const { + AnyOf anyOfExpr( *this ); + anyOfExpr.add( other ); + return anyOfExpr; + } + + private: + std::vector > > m_matchers; + }; + + } // namespace Generic + + template + Generic::AllOf Matcher::operator && ( Matcher const& other ) const { + Generic::AllOf allOfExpr; + allOfExpr.add( *this ); + allOfExpr.add( other ); + return allOfExpr; + } + + template + Generic::AnyOf Matcher::operator || ( Matcher const& other ) const { + Generic::AnyOf anyOfExpr; + anyOfExpr.add( *this ); + anyOfExpr.add( other ); + return anyOfExpr; + } + + template + Generic::Not Matcher::operator ! () const { + return Generic::Not( *this ); + } + + namespace StdString { + + inline std::string makeString( std::string const& str ) { return str; } + inline std::string makeString( const char* str ) { return str ? std::string( str ) : std::string(); } + + struct CasedString + { + CasedString( std::string const& str, CaseSensitive::Choice caseSensitivity ) + : m_caseSensitivity( caseSensitivity ), + m_str( adjustString( str ) ) + {} + std::string adjustString( std::string const& str ) const { + return m_caseSensitivity == CaseSensitive::No + ? toLower( str ) + : str; + + } + std::string toStringSuffix() const + { + return m_caseSensitivity == CaseSensitive::No + ? " (case insensitive)" + : ""; + } + CaseSensitive::Choice m_caseSensitivity; + std::string m_str; + }; + + struct Equals : MatcherImpl { + Equals( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) + : m_data( str, caseSensitivity ) + {} + Equals( Equals const& other ) : m_data( other.m_data ){} + + virtual ~Equals(); + + virtual bool match( std::string const& expr ) const { + return m_data.m_str == m_data.adjustString( expr );; + } + virtual std::string toString() const { + return "equals: \"" + m_data.m_str + "\"" + m_data.toStringSuffix(); + } + + CasedString m_data; + }; + + struct Contains : MatcherImpl { + Contains( std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) + : m_data( substr, caseSensitivity ){} + Contains( Contains const& other ) : m_data( other.m_data ){} + + virtual ~Contains(); + + virtual bool match( std::string const& expr ) const { + return m_data.adjustString( expr ).find( m_data.m_str ) != std::string::npos; + } + virtual std::string toString() const { + return "contains: \"" + m_data.m_str + "\"" + m_data.toStringSuffix(); + } + + CasedString m_data; + }; + + struct StartsWith : MatcherImpl { + StartsWith( std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) + : m_data( substr, caseSensitivity ){} + + StartsWith( StartsWith const& other ) : m_data( other.m_data ){} + + virtual ~StartsWith(); + + virtual bool match( std::string const& expr ) const { + return startsWith( m_data.adjustString( expr ), m_data.m_str ); + } + virtual std::string toString() const { + return "starts with: \"" + m_data.m_str + "\"" + m_data.toStringSuffix(); + } + + CasedString m_data; + }; + + struct EndsWith : MatcherImpl { + EndsWith( std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) + : m_data( substr, caseSensitivity ){} + EndsWith( EndsWith const& other ) : m_data( other.m_data ){} + + virtual ~EndsWith(); + + virtual bool match( std::string const& expr ) const { + return endsWith( m_data.adjustString( expr ), m_data.m_str ); + } + virtual std::string toString() const { + return "ends with: \"" + m_data.m_str + "\"" + m_data.toStringSuffix(); + } + + CasedString m_data; + }; + } // namespace StdString + } // namespace Impl + + // The following functions create the actual matcher objects. + // This allows the types to be inferred + template + inline Impl::Generic::Not Not( Impl::Matcher const& m ) { + return Impl::Generic::Not( m ); + } + + template + inline Impl::Generic::AllOf AllOf( Impl::Matcher const& m1, + Impl::Matcher const& m2 ) { + return Impl::Generic::AllOf().add( m1 ).add( m2 ); + } + template + inline Impl::Generic::AllOf AllOf( Impl::Matcher const& m1, + Impl::Matcher const& m2, + Impl::Matcher const& m3 ) { + return Impl::Generic::AllOf().add( m1 ).add( m2 ).add( m3 ); + } + template + inline Impl::Generic::AnyOf AnyOf( Impl::Matcher const& m1, + Impl::Matcher const& m2 ) { + return Impl::Generic::AnyOf().add( m1 ).add( m2 ); + } + template + inline Impl::Generic::AnyOf AnyOf( Impl::Matcher const& m1, + Impl::Matcher const& m2, + Impl::Matcher const& m3 ) { + return Impl::Generic::AnyOf().add( m1 ).add( m2 ).add( m3 ); + } + + inline Impl::StdString::Equals Equals( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) { + return Impl::StdString::Equals( str, caseSensitivity ); + } + inline Impl::StdString::Equals Equals( const char* str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) { + return Impl::StdString::Equals( Impl::StdString::makeString( str ), caseSensitivity ); + } + inline Impl::StdString::Contains Contains( std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) { + return Impl::StdString::Contains( substr, caseSensitivity ); + } + inline Impl::StdString::Contains Contains( const char* substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) { + return Impl::StdString::Contains( Impl::StdString::makeString( substr ), caseSensitivity ); + } + inline Impl::StdString::StartsWith StartsWith( std::string const& substr ) { + return Impl::StdString::StartsWith( substr ); + } + inline Impl::StdString::StartsWith StartsWith( const char* substr ) { + return Impl::StdString::StartsWith( Impl::StdString::makeString( substr ) ); + } + inline Impl::StdString::EndsWith EndsWith( std::string const& substr ) { + return Impl::StdString::EndsWith( substr ); + } + inline Impl::StdString::EndsWith EndsWith( const char* substr ) { + return Impl::StdString::EndsWith( Impl::StdString::makeString( substr ) ); + } + +} // namespace Matchers + +using namespace Matchers; + +} // namespace Catch + +namespace Catch { + + struct TestFailureException{}; + + template class ExpressionLhs; + + struct STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison; + + struct CopyableStream { + CopyableStream() {} + CopyableStream( CopyableStream const& other ) { + oss << other.oss.str(); + } + CopyableStream& operator=( CopyableStream const& other ) { + oss.str(""); + oss << other.oss.str(); + return *this; + } + std::ostringstream oss; + }; + + class ResultBuilder { + public: + ResultBuilder( char const* macroName, + SourceLineInfo const& lineInfo, + char const* capturedExpression, + ResultDisposition::Flags resultDisposition, + char const* secondArg = "" ); + + template + ExpressionLhs operator <= ( T const& operand ); + ExpressionLhs operator <= ( bool value ); + + template + ResultBuilder& operator << ( T const& value ) { + m_stream.oss << value; + return *this; + } + + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( RhsT const& ); + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || ( RhsT const& ); + + ResultBuilder& setResultType( ResultWas::OfType result ); + ResultBuilder& setResultType( bool result ); + ResultBuilder& setLhs( std::string const& lhs ); + ResultBuilder& setRhs( std::string const& rhs ); + ResultBuilder& setOp( std::string const& op ); + + void endExpression(); + + std::string reconstructExpression() const; + AssertionResult build() const; + + void useActiveException( ResultDisposition::Flags resultDisposition = ResultDisposition::Normal ); + void captureResult( ResultWas::OfType resultType ); + void captureExpression(); + void captureExpectedException( std::string const& expectedMessage ); + void captureExpectedException( Matchers::Impl::Matcher const& matcher ); + void handleResult( AssertionResult const& result ); + void react(); + bool shouldDebugBreak() const; + bool allowThrows() const; + + private: + AssertionInfo m_assertionInfo; + AssertionResultData m_data; + struct ExprComponents { + ExprComponents() : testFalse( false ) {} + bool testFalse; + std::string lhs, rhs, op; + } m_exprComponents; + CopyableStream m_stream; + + bool m_shouldDebugBreak; + bool m_shouldThrow; + }; + +} // namespace Catch + +// Include after due to circular dependency: +// #included from: catch_expression_lhs.hpp +#define TWOBLUECUBES_CATCH_EXPRESSION_LHS_HPP_INCLUDED + +// #included from: catch_evaluate.hpp +#define TWOBLUECUBES_CATCH_EVALUATE_HPP_INCLUDED + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable:4389) // '==' : signed/unsigned mismatch +#endif + +#include + +namespace Catch { +namespace Internal { + + enum Operator { + IsEqualTo, + IsNotEqualTo, + IsLessThan, + IsGreaterThan, + IsLessThanOrEqualTo, + IsGreaterThanOrEqualTo + }; + + template struct OperatorTraits { static const char* getName(){ return "*error*"; } }; + template<> struct OperatorTraits { static const char* getName(){ return "=="; } }; + template<> struct OperatorTraits { static const char* getName(){ return "!="; } }; + template<> struct OperatorTraits { static const char* getName(){ return "<"; } }; + template<> struct OperatorTraits { static const char* getName(){ return ">"; } }; + template<> struct OperatorTraits { static const char* getName(){ return "<="; } }; + template<> struct OperatorTraits{ static const char* getName(){ return ">="; } }; + + template + inline T& opCast(T const& t) { return const_cast(t); } + +// nullptr_t support based on pull request #154 from Konstantin Baumann +#ifdef CATCH_CONFIG_CPP11_NULLPTR + inline std::nullptr_t opCast(std::nullptr_t) { return nullptr; } +#endif // CATCH_CONFIG_CPP11_NULLPTR + + // So the compare overloads can be operator agnostic we convey the operator as a template + // enum, which is used to specialise an Evaluator for doing the comparison. + template + class Evaluator{}; + + template + struct Evaluator { + static bool evaluate( T1 const& lhs, T2 const& rhs) { + return bool( opCast( lhs ) == opCast( rhs ) ); + } + }; + template + struct Evaluator { + static bool evaluate( T1 const& lhs, T2 const& rhs ) { + return bool( opCast( lhs ) != opCast( rhs ) ); + } + }; + template + struct Evaluator { + static bool evaluate( T1 const& lhs, T2 const& rhs ) { + return bool( opCast( lhs ) < opCast( rhs ) ); + } + }; + template + struct Evaluator { + static bool evaluate( T1 const& lhs, T2 const& rhs ) { + return bool( opCast( lhs ) > opCast( rhs ) ); + } + }; + template + struct Evaluator { + static bool evaluate( T1 const& lhs, T2 const& rhs ) { + return bool( opCast( lhs ) >= opCast( rhs ) ); + } + }; + template + struct Evaluator { + static bool evaluate( T1 const& lhs, T2 const& rhs ) { + return bool( opCast( lhs ) <= opCast( rhs ) ); + } + }; + + template + bool applyEvaluator( T1 const& lhs, T2 const& rhs ) { + return Evaluator::evaluate( lhs, rhs ); + } + + // This level of indirection allows us to specialise for integer types + // to avoid signed/ unsigned warnings + + // "base" overload + template + bool compare( T1 const& lhs, T2 const& rhs ) { + return Evaluator::evaluate( lhs, rhs ); + } + + // unsigned X to int + template bool compare( unsigned int lhs, int rhs ) { + return applyEvaluator( lhs, static_cast( rhs ) ); + } + template bool compare( unsigned long lhs, int rhs ) { + return applyEvaluator( lhs, static_cast( rhs ) ); + } + template bool compare( unsigned char lhs, int rhs ) { + return applyEvaluator( lhs, static_cast( rhs ) ); + } + + // unsigned X to long + template bool compare( unsigned int lhs, long rhs ) { + return applyEvaluator( lhs, static_cast( rhs ) ); + } + template bool compare( unsigned long lhs, long rhs ) { + return applyEvaluator( lhs, static_cast( rhs ) ); + } + template bool compare( unsigned char lhs, long rhs ) { + return applyEvaluator( lhs, static_cast( rhs ) ); + } + + // int to unsigned X + template bool compare( int lhs, unsigned int rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( int lhs, unsigned long rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( int lhs, unsigned char rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + + // long to unsigned X + template bool compare( long lhs, unsigned int rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( long lhs, unsigned long rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( long lhs, unsigned char rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + + // pointer to long (when comparing against NULL) + template bool compare( long lhs, T* rhs ) { + return Evaluator::evaluate( reinterpret_cast( lhs ), rhs ); + } + template bool compare( T* lhs, long rhs ) { + return Evaluator::evaluate( lhs, reinterpret_cast( rhs ) ); + } + + // pointer to int (when comparing against NULL) + template bool compare( int lhs, T* rhs ) { + return Evaluator::evaluate( reinterpret_cast( lhs ), rhs ); + } + template bool compare( T* lhs, int rhs ) { + return Evaluator::evaluate( lhs, reinterpret_cast( rhs ) ); + } + +#ifdef CATCH_CONFIG_CPP11_LONG_LONG + // long long to unsigned X + template bool compare( long long lhs, unsigned int rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( long long lhs, unsigned long rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( long long lhs, unsigned long long rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( long long lhs, unsigned char rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + + // unsigned long long to X + template bool compare( unsigned long long lhs, int rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( unsigned long long lhs, long rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( unsigned long long lhs, long long rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( unsigned long long lhs, char rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + + // pointer to long long (when comparing against NULL) + template bool compare( long long lhs, T* rhs ) { + return Evaluator::evaluate( reinterpret_cast( lhs ), rhs ); + } + template bool compare( T* lhs, long long rhs ) { + return Evaluator::evaluate( lhs, reinterpret_cast( rhs ) ); + } +#endif // CATCH_CONFIG_CPP11_LONG_LONG + +#ifdef CATCH_CONFIG_CPP11_NULLPTR + // pointer to nullptr_t (when comparing against nullptr) + template bool compare( std::nullptr_t, T* rhs ) { + return Evaluator::evaluate( nullptr, rhs ); + } + template bool compare( T* lhs, std::nullptr_t ) { + return Evaluator::evaluate( lhs, nullptr ); + } +#endif // CATCH_CONFIG_CPP11_NULLPTR + +} // end of namespace Internal +} // end of namespace Catch + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +// #included from: catch_tostring.h +#define TWOBLUECUBES_CATCH_TOSTRING_H_INCLUDED + +#include +#include +#include +#include +#include + +#ifdef __OBJC__ +// #included from: catch_objc_arc.hpp +#define TWOBLUECUBES_CATCH_OBJC_ARC_HPP_INCLUDED + +#import + +#ifdef __has_feature +#define CATCH_ARC_ENABLED __has_feature(objc_arc) +#else +#define CATCH_ARC_ENABLED 0 +#endif + +void arcSafeRelease( NSObject* obj ); +id performOptionalSelector( id obj, SEL sel ); + +#if !CATCH_ARC_ENABLED +inline void arcSafeRelease( NSObject* obj ) { + [obj release]; +} +inline id performOptionalSelector( id obj, SEL sel ) { + if( [obj respondsToSelector: sel] ) + return [obj performSelector: sel]; + return nil; +} +#define CATCH_UNSAFE_UNRETAINED +#define CATCH_ARC_STRONG +#else +inline void arcSafeRelease( NSObject* ){} +inline id performOptionalSelector( id obj, SEL sel ) { +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Warc-performSelector-leaks" +#endif + if( [obj respondsToSelector: sel] ) + return [obj performSelector: sel]; +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + return nil; +} +#define CATCH_UNSAFE_UNRETAINED __unsafe_unretained +#define CATCH_ARC_STRONG __strong +#endif + +#endif + +#ifdef CATCH_CONFIG_CPP11_TUPLE +#include +#endif + +#ifdef CATCH_CONFIG_CPP11_IS_ENUM +#include +#endif + +namespace Catch { + +// Why we're here. +template +std::string toString( T const& value ); + +// Built in overloads + +std::string toString( std::string const& value ); +std::string toString( std::wstring const& value ); +std::string toString( const char* const value ); +std::string toString( char* const value ); +std::string toString( const wchar_t* const value ); +std::string toString( wchar_t* const value ); +std::string toString( int value ); +std::string toString( unsigned long value ); +std::string toString( unsigned int value ); +std::string toString( const double value ); +std::string toString( const float value ); +std::string toString( bool value ); +std::string toString( char value ); +std::string toString( signed char value ); +std::string toString( unsigned char value ); + +#ifdef CATCH_CONFIG_CPP11_LONG_LONG +std::string toString( long long value ); +std::string toString( unsigned long long value ); +#endif + +#ifdef CATCH_CONFIG_CPP11_NULLPTR +std::string toString( std::nullptr_t ); +#endif + +#ifdef __OBJC__ + std::string toString( NSString const * const& nsstring ); + std::string toString( NSString * CATCH_ARC_STRONG const& nsstring ); + std::string toString( NSObject* const& nsObject ); +#endif + +namespace Detail { + + extern const std::string unprintableString; + + struct BorgType { + template BorgType( T const& ); + }; + + struct TrueType { char sizer[1]; }; + struct FalseType { char sizer[2]; }; + + TrueType& testStreamable( std::ostream& ); + FalseType testStreamable( FalseType ); + + FalseType operator<<( std::ostream const&, BorgType const& ); + + template + struct IsStreamInsertable { + static std::ostream &s; + static T const&t; + enum { value = sizeof( testStreamable(s << t) ) == sizeof( TrueType ) }; + }; + +#if defined(CATCH_CONFIG_CPP11_IS_ENUM) + template::value + > + struct EnumStringMaker + { + static std::string convert( T const& ) { return unprintableString; } + }; + + template + struct EnumStringMaker + { + static std::string convert( T const& v ) + { + return ::Catch::toString( + static_cast::type>(v) + ); + } + }; +#endif + template + struct StringMakerBase { +#if defined(CATCH_CONFIG_CPP11_IS_ENUM) + template + static std::string convert( T const& v ) + { + return EnumStringMaker::convert( v ); + } +#else + template + static std::string convert( T const& ) { return unprintableString; } +#endif + }; + + template<> + struct StringMakerBase { + template + static std::string convert( T const& _value ) { + std::ostringstream oss; + oss << _value; + return oss.str(); + } + }; + + std::string rawMemoryToString( const void *object, std::size_t size ); + + template + inline std::string rawMemoryToString( const T& object ) { + return rawMemoryToString( &object, sizeof(object) ); + } + +} // end namespace Detail + +template +struct StringMaker : + Detail::StringMakerBase::value> {}; + +template +struct StringMaker { + template + static std::string convert( U* p ) { + if( !p ) + return "NULL"; + else + return Detail::rawMemoryToString( p ); + } +}; + +template +struct StringMaker { + static std::string convert( R C::* p ) { + if( !p ) + return "NULL"; + else + return Detail::rawMemoryToString( p ); + } +}; + +namespace Detail { + template + std::string rangeToString( InputIterator first, InputIterator last ); +} + +//template +//struct StringMaker > { +// static std::string convert( std::vector const& v ) { +// return Detail::rangeToString( v.begin(), v.end() ); +// } +//}; + +template +std::string toString( std::vector const& v ) { + return Detail::rangeToString( v.begin(), v.end() ); +} + +#ifdef CATCH_CONFIG_CPP11_TUPLE + +// toString for tuples +namespace TupleDetail { + template< + typename Tuple, + std::size_t N = 0, + bool = (N < std::tuple_size::value) + > + struct ElementPrinter { + static void print( const Tuple& tuple, std::ostream& os ) + { + os << ( N ? ", " : " " ) + << Catch::toString(std::get(tuple)); + ElementPrinter::print(tuple,os); + } + }; + + template< + typename Tuple, + std::size_t N + > + struct ElementPrinter { + static void print( const Tuple&, std::ostream& ) {} + }; + +} + +template +struct StringMaker> { + + static std::string convert( const std::tuple& tuple ) + { + std::ostringstream os; + os << '{'; + TupleDetail::ElementPrinter>::print( tuple, os ); + os << " }"; + return os.str(); + } +}; +#endif // CATCH_CONFIG_CPP11_TUPLE + +namespace Detail { + template + std::string makeString( T const& value ) { + return StringMaker::convert( value ); + } +} // end namespace Detail + +/// \brief converts any type to a string +/// +/// The default template forwards on to ostringstream - except when an +/// ostringstream overload does not exist - in which case it attempts to detect +/// that and writes {?}. +/// Overload (not specialise) this template for custom typs that you don't want +/// to provide an ostream overload for. +template +std::string toString( T const& value ) { + return StringMaker::convert( value ); +} + + namespace Detail { + template + std::string rangeToString( InputIterator first, InputIterator last ) { + std::ostringstream oss; + oss << "{ "; + if( first != last ) { + oss << Catch::toString( *first ); + for( ++first ; first != last ; ++first ) + oss << ", " << Catch::toString( *first ); + } + oss << " }"; + return oss.str(); + } +} + +} // end namespace Catch + +namespace Catch { + +// Wraps the LHS of an expression and captures the operator and RHS (if any) - +// wrapping them all in a ResultBuilder object +template +class ExpressionLhs { + ExpressionLhs& operator = ( ExpressionLhs const& ); +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + ExpressionLhs& operator = ( ExpressionLhs && ) = delete; +# endif + +public: + ExpressionLhs( ResultBuilder& rb, T lhs ) : m_rb( rb ), m_lhs( lhs ) {} +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + ExpressionLhs( ExpressionLhs const& ) = default; + ExpressionLhs( ExpressionLhs && ) = default; +# endif + + template + ResultBuilder& operator == ( RhsT const& rhs ) { + return captureExpression( rhs ); + } + + template + ResultBuilder& operator != ( RhsT const& rhs ) { + return captureExpression( rhs ); + } + + template + ResultBuilder& operator < ( RhsT const& rhs ) { + return captureExpression( rhs ); + } + + template + ResultBuilder& operator > ( RhsT const& rhs ) { + return captureExpression( rhs ); + } + + template + ResultBuilder& operator <= ( RhsT const& rhs ) { + return captureExpression( rhs ); + } + + template + ResultBuilder& operator >= ( RhsT const& rhs ) { + return captureExpression( rhs ); + } + + ResultBuilder& operator == ( bool rhs ) { + return captureExpression( rhs ); + } + + ResultBuilder& operator != ( bool rhs ) { + return captureExpression( rhs ); + } + + void endExpression() { + bool value = m_lhs ? true : false; + m_rb + .setLhs( Catch::toString( value ) ) + .setResultType( value ) + .endExpression(); + } + + // Only simple binary expressions are allowed on the LHS. + // If more complex compositions are required then place the sub expression in parentheses + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator + ( RhsT const& ); + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator - ( RhsT const& ); + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator / ( RhsT const& ); + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator * ( RhsT const& ); + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( RhsT const& ); + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || ( RhsT const& ); + +private: + template + ResultBuilder& captureExpression( RhsT const& rhs ) { + return m_rb + .setResultType( Internal::compare( m_lhs, rhs ) ) + .setLhs( Catch::toString( m_lhs ) ) + .setRhs( Catch::toString( rhs ) ) + .setOp( Internal::OperatorTraits::getName() ); + } + +private: + ResultBuilder& m_rb; + T m_lhs; +}; + +} // end namespace Catch + + +namespace Catch { + + template + inline ExpressionLhs ResultBuilder::operator <= ( T const& operand ) { + return ExpressionLhs( *this, operand ); + } + + inline ExpressionLhs ResultBuilder::operator <= ( bool value ) { + return ExpressionLhs( *this, value ); + } + +} // namespace Catch + +// #included from: catch_message.h +#define TWOBLUECUBES_CATCH_MESSAGE_H_INCLUDED + +#include + +namespace Catch { + + struct MessageInfo { + MessageInfo( std::string const& _macroName, + SourceLineInfo const& _lineInfo, + ResultWas::OfType _type ); + + std::string macroName; + SourceLineInfo lineInfo; + ResultWas::OfType type; + std::string message; + unsigned int sequence; + + bool operator == ( MessageInfo const& other ) const { + return sequence == other.sequence; + } + bool operator < ( MessageInfo const& other ) const { + return sequence < other.sequence; + } + private: + static unsigned int globalCount; + }; + + struct MessageBuilder { + MessageBuilder( std::string const& macroName, + SourceLineInfo const& lineInfo, + ResultWas::OfType type ) + : m_info( macroName, lineInfo, type ) + {} + + template + MessageBuilder& operator << ( T const& value ) { + m_stream << value; + return *this; + } + + MessageInfo m_info; + std::ostringstream m_stream; + }; + + class ScopedMessage { + public: + ScopedMessage( MessageBuilder const& builder ); + ScopedMessage( ScopedMessage const& other ); + ~ScopedMessage(); + + MessageInfo m_info; + }; + +} // end namespace Catch + +// #included from: catch_interfaces_capture.h +#define TWOBLUECUBES_CATCH_INTERFACES_CAPTURE_H_INCLUDED + +#include + +namespace Catch { + + class TestCase; + class AssertionResult; + struct AssertionInfo; + struct SectionInfo; + struct SectionEndInfo; + struct MessageInfo; + class ScopedMessageBuilder; + struct Counts; + + struct IResultCapture { + + virtual ~IResultCapture(); + + virtual void assertionEnded( AssertionResult const& result ) = 0; + virtual bool sectionStarted( SectionInfo const& sectionInfo, + Counts& assertions ) = 0; + virtual void sectionEnded( SectionEndInfo const& endInfo ) = 0; + virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) = 0; + virtual void pushScopedMessage( MessageInfo const& message ) = 0; + virtual void popScopedMessage( MessageInfo const& message ) = 0; + + virtual std::string getCurrentTestName() const = 0; + virtual const AssertionResult* getLastResult() const = 0; + + virtual void handleFatalErrorCondition( std::string const& message ) = 0; + }; + + IResultCapture& getResultCapture(); +} + +// #included from: catch_debugger.h +#define TWOBLUECUBES_CATCH_DEBUGGER_H_INCLUDED + +// #included from: catch_platform.h +#define TWOBLUECUBES_CATCH_PLATFORM_H_INCLUDED + +#if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) +#define CATCH_PLATFORM_MAC +#elif defined(__IPHONE_OS_VERSION_MIN_REQUIRED) +#define CATCH_PLATFORM_IPHONE +#elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) +#define CATCH_PLATFORM_WINDOWS +#endif + +#include + +namespace Catch{ + + bool isDebuggerActive(); + void writeToDebugConsole( std::string const& text ); +} + +#ifdef CATCH_PLATFORM_MAC + + // The following code snippet based on: + // http://cocoawithlove.com/2008/03/break-into-debugger.html + #ifdef DEBUG + #if defined(__ppc64__) || defined(__ppc__) + #define CATCH_BREAK_INTO_DEBUGGER() \ + if( Catch::isDebuggerActive() ) { \ + __asm__("li r0, 20\nsc\nnop\nli r0, 37\nli r4, 2\nsc\nnop\n" \ + : : : "memory","r0","r3","r4" ); \ + } + #else + #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) {__asm__("int $3\n" : : );} + #endif + #endif + +#elif defined(_MSC_VER) + #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { __debugbreak(); } +#elif defined(__MINGW32__) + extern "C" __declspec(dllimport) void __stdcall DebugBreak(); + #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { DebugBreak(); } +#endif + +#ifndef CATCH_BREAK_INTO_DEBUGGER +#define CATCH_BREAK_INTO_DEBUGGER() Catch::alwaysTrue(); +#endif + +// #included from: catch_interfaces_runner.h +#define TWOBLUECUBES_CATCH_INTERFACES_RUNNER_H_INCLUDED + +namespace Catch { + class TestCase; + + struct IRunner { + virtual ~IRunner(); + virtual bool aborting() const = 0; + }; +} + +/////////////////////////////////////////////////////////////////////////////// +// In the event of a failure works out if the debugger needs to be invoked +// and/or an exception thrown and takes appropriate action. +// This needs to be done as a macro so the debugger will stop in the user +// source code rather than in Catch library code +#define INTERNAL_CATCH_REACT( resultBuilder ) \ + if( resultBuilder.shouldDebugBreak() ) CATCH_BREAK_INTO_DEBUGGER(); \ + resultBuilder.react(); + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \ + try { \ + CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ + ( __catchResult <= expr ).endExpression(); \ + } \ + catch( ... ) { \ + __catchResult.useActiveException( Catch::ResultDisposition::Normal ); \ + } \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::isTrue( false && static_cast(expr) ) ) // expr here is never evaluated at runtime but it forces the compiler to give it a look + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_IF( expr, resultDisposition, macroName ) \ + INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ); \ + if( Catch::getResultCapture().getLastResult()->succeeded() ) + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_ELSE( expr, resultDisposition, macroName ) \ + INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ); \ + if( !Catch::getResultCapture().getLastResult()->succeeded() ) + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_NO_THROW( expr, resultDisposition, macroName ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \ + try { \ + expr; \ + __catchResult.captureResult( Catch::ResultWas::Ok ); \ + } \ + catch( ... ) { \ + __catchResult.useActiveException( resultDisposition ); \ + } \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::alwaysFalse() ) + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_THROWS( expr, resultDisposition, matcher, macroName ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition, #matcher ); \ + if( __catchResult.allowThrows() ) \ + try { \ + expr; \ + __catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \ + } \ + catch( ... ) { \ + __catchResult.captureExpectedException( matcher ); \ + } \ + else \ + __catchResult.captureResult( Catch::ResultWas::Ok ); \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::alwaysFalse() ) + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_THROWS_AS( expr, exceptionType, resultDisposition, macroName ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \ + if( __catchResult.allowThrows() ) \ + try { \ + expr; \ + __catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \ + } \ + catch( exceptionType ) { \ + __catchResult.captureResult( Catch::ResultWas::Ok ); \ + } \ + catch( ... ) { \ + __catchResult.useActiveException( resultDisposition ); \ + } \ + else \ + __catchResult.captureResult( Catch::ResultWas::Ok ); \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::alwaysFalse() ) + +/////////////////////////////////////////////////////////////////////////////// +#ifdef CATCH_CONFIG_VARIADIC_MACROS + #define INTERNAL_CATCH_MSG( messageType, resultDisposition, macroName, ... ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \ + __catchResult << __VA_ARGS__ + ::Catch::StreamEndStop(); \ + __catchResult.captureResult( messageType ); \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::alwaysFalse() ) +#else + #define INTERNAL_CATCH_MSG( messageType, resultDisposition, macroName, log ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \ + __catchResult << log + ::Catch::StreamEndStop(); \ + __catchResult.captureResult( messageType ); \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::alwaysFalse() ) +#endif + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_INFO( log, macroName ) \ + Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME( scopedMessage ) = Catch::MessageBuilder( macroName, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log; + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CHECK_THAT( arg, matcher, resultDisposition, macroName ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #arg ", " #matcher, resultDisposition ); \ + try { \ + std::string matcherAsString = (matcher).toString(); \ + __catchResult \ + .setLhs( Catch::toString( arg ) ) \ + .setRhs( matcherAsString == Catch::Detail::unprintableString ? #matcher : matcherAsString ) \ + .setOp( "matches" ) \ + .setResultType( (matcher).match( arg ) ); \ + __catchResult.captureExpression(); \ + } catch( ... ) { \ + __catchResult.useActiveException( resultDisposition | Catch::ResultDisposition::ContinueOnFailure ); \ + } \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::alwaysFalse() ) + +// #included from: internal/catch_section.h +#define TWOBLUECUBES_CATCH_SECTION_H_INCLUDED + +// #included from: catch_section_info.h +#define TWOBLUECUBES_CATCH_SECTION_INFO_H_INCLUDED + +// #included from: catch_totals.hpp +#define TWOBLUECUBES_CATCH_TOTALS_HPP_INCLUDED + +#include + +namespace Catch { + + struct Counts { + Counts() : passed( 0 ), failed( 0 ), failedButOk( 0 ) {} + + Counts operator - ( Counts const& other ) const { + Counts diff; + diff.passed = passed - other.passed; + diff.failed = failed - other.failed; + diff.failedButOk = failedButOk - other.failedButOk; + return diff; + } + Counts& operator += ( Counts const& other ) { + passed += other.passed; + failed += other.failed; + failedButOk += other.failedButOk; + return *this; + } + + std::size_t total() const { + return passed + failed + failedButOk; + } + bool allPassed() const { + return failed == 0 && failedButOk == 0; + } + bool allOk() const { + return failed == 0; + } + + std::size_t passed; + std::size_t failed; + std::size_t failedButOk; + }; + + struct Totals { + + Totals operator - ( Totals const& other ) const { + Totals diff; + diff.assertions = assertions - other.assertions; + diff.testCases = testCases - other.testCases; + return diff; + } + + Totals delta( Totals const& prevTotals ) const { + Totals diff = *this - prevTotals; + if( diff.assertions.failed > 0 ) + ++diff.testCases.failed; + else if( diff.assertions.failedButOk > 0 ) + ++diff.testCases.failedButOk; + else + ++diff.testCases.passed; + return diff; + } + + Totals& operator += ( Totals const& other ) { + assertions += other.assertions; + testCases += other.testCases; + return *this; + } + + Counts assertions; + Counts testCases; + }; +} + +namespace Catch { + + struct SectionInfo { + SectionInfo + ( SourceLineInfo const& _lineInfo, + std::string const& _name, + std::string const& _description = std::string() ); + + std::string name; + std::string description; + SourceLineInfo lineInfo; + }; + + struct SectionEndInfo { + SectionEndInfo( SectionInfo const& _sectionInfo, Counts const& _prevAssertions, double _durationInSeconds ) + : sectionInfo( _sectionInfo ), prevAssertions( _prevAssertions ), durationInSeconds( _durationInSeconds ) + {} + + SectionInfo sectionInfo; + Counts prevAssertions; + double durationInSeconds; + }; + +} // end namespace Catch + +// #included from: catch_timer.h +#define TWOBLUECUBES_CATCH_TIMER_H_INCLUDED + +#ifdef CATCH_PLATFORM_WINDOWS +typedef unsigned long long uint64_t; +#else +#include +#endif + +namespace Catch { + + class Timer { + public: + Timer() : m_ticks( 0 ) {} + void start(); + unsigned int getElapsedMicroseconds() const; + unsigned int getElapsedMilliseconds() const; + double getElapsedSeconds() const; + + private: + uint64_t m_ticks; + }; + +} // namespace Catch + +#include + +namespace Catch { + + class Section : NonCopyable { + public: + Section( SectionInfo const& info ); + ~Section(); + + // This indicates whether the section should be executed or not + operator bool() const; + + private: + SectionInfo m_info; + + std::string m_name; + Counts m_assertions; + bool m_sectionIncluded; + Timer m_timer; + }; + +} // end namespace Catch + +#ifdef CATCH_CONFIG_VARIADIC_MACROS + #define INTERNAL_CATCH_SECTION( ... ) \ + if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) ) +#else + #define INTERNAL_CATCH_SECTION( name, desc ) \ + if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, name, desc ) ) +#endif + +// #included from: internal/catch_generators.hpp +#define TWOBLUECUBES_CATCH_GENERATORS_HPP_INCLUDED + +#include +#include +#include +#include + +namespace Catch { + +template +struct IGenerator { + virtual ~IGenerator() {} + virtual T getValue( std::size_t index ) const = 0; + virtual std::size_t size () const = 0; +}; + +template +class BetweenGenerator : public IGenerator { +public: + BetweenGenerator( T from, T to ) : m_from( from ), m_to( to ){} + + virtual T getValue( std::size_t index ) const { + return m_from+static_cast( index ); + } + + virtual std::size_t size() const { + return static_cast( 1+m_to-m_from ); + } + +private: + + T m_from; + T m_to; +}; + +template +class ValuesGenerator : public IGenerator { +public: + ValuesGenerator(){} + + void add( T value ) { + m_values.push_back( value ); + } + + virtual T getValue( std::size_t index ) const { + return m_values[index]; + } + + virtual std::size_t size() const { + return m_values.size(); + } + +private: + std::vector m_values; +}; + +template +class CompositeGenerator { +public: + CompositeGenerator() : m_totalSize( 0 ) {} + + // *** Move semantics, similar to auto_ptr *** + CompositeGenerator( CompositeGenerator& other ) + : m_fileInfo( other.m_fileInfo ), + m_totalSize( 0 ) + { + move( other ); + } + + CompositeGenerator& setFileInfo( const char* fileInfo ) { + m_fileInfo = fileInfo; + return *this; + } + + ~CompositeGenerator() { + deleteAll( m_composed ); + } + + operator T () const { + size_t overallIndex = getCurrentContext().getGeneratorIndex( m_fileInfo, m_totalSize ); + + typename std::vector*>::const_iterator it = m_composed.begin(); + typename std::vector*>::const_iterator itEnd = m_composed.end(); + for( size_t index = 0; it != itEnd; ++it ) + { + const IGenerator* generator = *it; + if( overallIndex >= index && overallIndex < index + generator->size() ) + { + return generator->getValue( overallIndex-index ); + } + index += generator->size(); + } + CATCH_INTERNAL_ERROR( "Indexed past end of generated range" ); + return T(); // Suppress spurious "not all control paths return a value" warning in Visual Studio - if you know how to fix this please do so + } + + void add( const IGenerator* generator ) { + m_totalSize += generator->size(); + m_composed.push_back( generator ); + } + + CompositeGenerator& then( CompositeGenerator& other ) { + move( other ); + return *this; + } + + CompositeGenerator& then( T value ) { + ValuesGenerator* valuesGen = new ValuesGenerator(); + valuesGen->add( value ); + add( valuesGen ); + return *this; + } + +private: + + void move( CompositeGenerator& other ) { + std::copy( other.m_composed.begin(), other.m_composed.end(), std::back_inserter( m_composed ) ); + m_totalSize += other.m_totalSize; + other.m_composed.clear(); + } + + std::vector*> m_composed; + std::string m_fileInfo; + size_t m_totalSize; +}; + +namespace Generators +{ + template + CompositeGenerator between( T from, T to ) { + CompositeGenerator generators; + generators.add( new BetweenGenerator( from, to ) ); + return generators; + } + + template + CompositeGenerator values( T val1, T val2 ) { + CompositeGenerator generators; + ValuesGenerator* valuesGen = new ValuesGenerator(); + valuesGen->add( val1 ); + valuesGen->add( val2 ); + generators.add( valuesGen ); + return generators; + } + + template + CompositeGenerator values( T val1, T val2, T val3 ){ + CompositeGenerator generators; + ValuesGenerator* valuesGen = new ValuesGenerator(); + valuesGen->add( val1 ); + valuesGen->add( val2 ); + valuesGen->add( val3 ); + generators.add( valuesGen ); + return generators; + } + + template + CompositeGenerator values( T val1, T val2, T val3, T val4 ) { + CompositeGenerator generators; + ValuesGenerator* valuesGen = new ValuesGenerator(); + valuesGen->add( val1 ); + valuesGen->add( val2 ); + valuesGen->add( val3 ); + valuesGen->add( val4 ); + generators.add( valuesGen ); + return generators; + } + +} // end namespace Generators + +using namespace Generators; + +} // end namespace Catch + +#define INTERNAL_CATCH_LINESTR2( line ) #line +#define INTERNAL_CATCH_LINESTR( line ) INTERNAL_CATCH_LINESTR2( line ) + +#define INTERNAL_CATCH_GENERATE( expr ) expr.setFileInfo( __FILE__ "(" INTERNAL_CATCH_LINESTR( __LINE__ ) ")" ) + +// #included from: internal/catch_interfaces_exception.h +#define TWOBLUECUBES_CATCH_INTERFACES_EXCEPTION_H_INCLUDED + +#include +#include + +// #included from: catch_interfaces_registry_hub.h +#define TWOBLUECUBES_CATCH_INTERFACES_REGISTRY_HUB_H_INCLUDED + +#include + +namespace Catch { + + class TestCase; + struct ITestCaseRegistry; + struct IExceptionTranslatorRegistry; + struct IExceptionTranslator; + struct IReporterRegistry; + struct IReporterFactory; + + struct IRegistryHub { + virtual ~IRegistryHub(); + + virtual IReporterRegistry const& getReporterRegistry() const = 0; + virtual ITestCaseRegistry const& getTestCaseRegistry() const = 0; + virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() = 0; + }; + + struct IMutableRegistryHub { + virtual ~IMutableRegistryHub(); + virtual void registerReporter( std::string const& name, Ptr const& factory ) = 0; + virtual void registerListener( Ptr const& factory ) = 0; + virtual void registerTest( TestCase const& testInfo ) = 0; + virtual void registerTranslator( const IExceptionTranslator* translator ) = 0; + }; + + IRegistryHub& getRegistryHub(); + IMutableRegistryHub& getMutableRegistryHub(); + void cleanUp(); + std::string translateActiveException(); + +} + +namespace Catch { + + typedef std::string(*exceptionTranslateFunction)(); + + struct IExceptionTranslator; + typedef std::vector ExceptionTranslators; + + struct IExceptionTranslator { + virtual ~IExceptionTranslator(); + virtual std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const = 0; + }; + + struct IExceptionTranslatorRegistry { + virtual ~IExceptionTranslatorRegistry(); + + virtual std::string translateActiveException() const = 0; + }; + + class ExceptionTranslatorRegistrar { + template + class ExceptionTranslator : public IExceptionTranslator { + public: + + ExceptionTranslator( std::string(*translateFunction)( T& ) ) + : m_translateFunction( translateFunction ) + {} + + virtual std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const CATCH_OVERRIDE { + try { + if( it == itEnd ) + throw; + else + return (*it)->translate( it+1, itEnd ); + } + catch( T& ex ) { + return m_translateFunction( ex ); + } + } + + protected: + std::string(*m_translateFunction)( T& ); + }; + + public: + template + ExceptionTranslatorRegistrar( std::string(*translateFunction)( T& ) ) { + getMutableRegistryHub().registerTranslator + ( new ExceptionTranslator( translateFunction ) ); + } + }; +} + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) \ + static std::string INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator )( signature ); \ + namespace{ Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ) ); }\ + static std::string INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator )( signature ) + +// #included from: internal/catch_approx.hpp +#define TWOBLUECUBES_CATCH_APPROX_HPP_INCLUDED + +#include +#include + +namespace Catch { +namespace Detail { + + class Approx { + public: + explicit Approx ( double value ) + : m_epsilon( std::numeric_limits::epsilon()*100 ), + m_scale( 1.0 ), + m_value( value ) + {} + + Approx( Approx const& other ) + : m_epsilon( other.m_epsilon ), + m_scale( other.m_scale ), + m_value( other.m_value ) + {} + + static Approx custom() { + return Approx( 0 ); + } + + Approx operator()( double value ) { + Approx approx( value ); + approx.epsilon( m_epsilon ); + approx.scale( m_scale ); + return approx; + } + + friend bool operator == ( double lhs, Approx const& rhs ) { + // Thanks to Richard Harris for his help refining this formula + return fabs( lhs - rhs.m_value ) < rhs.m_epsilon * (rhs.m_scale + (std::max)( fabs(lhs), fabs(rhs.m_value) ) ); + } + + friend bool operator == ( Approx const& lhs, double rhs ) { + return operator==( rhs, lhs ); + } + + friend bool operator != ( double lhs, Approx const& rhs ) { + return !operator==( lhs, rhs ); + } + + friend bool operator != ( Approx const& lhs, double rhs ) { + return !operator==( rhs, lhs ); + } + + Approx& epsilon( double newEpsilon ) { + m_epsilon = newEpsilon; + return *this; + } + + Approx& scale( double newScale ) { + m_scale = newScale; + return *this; + } + + std::string toString() const { + std::ostringstream oss; + oss << "Approx( " << Catch::toString( m_value ) << " )"; + return oss.str(); + } + + private: + double m_epsilon; + double m_scale; + double m_value; + }; +} + +template<> +inline std::string toString( Detail::Approx const& value ) { + return value.toString(); +} + +} // end namespace Catch + +// #included from: internal/catch_interfaces_tag_alias_registry.h +#define TWOBLUECUBES_CATCH_INTERFACES_TAG_ALIAS_REGISTRY_H_INCLUDED + +// #included from: catch_tag_alias.h +#define TWOBLUECUBES_CATCH_TAG_ALIAS_H_INCLUDED + +#include + +namespace Catch { + + struct TagAlias { + TagAlias( std::string _tag, SourceLineInfo _lineInfo ) : tag( _tag ), lineInfo( _lineInfo ) {} + + std::string tag; + SourceLineInfo lineInfo; + }; + + struct RegistrarForTagAliases { + RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ); + }; + +} // end namespace Catch + +#define CATCH_REGISTER_TAG_ALIAS( alias, spec ) namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); } +// #included from: catch_option.hpp +#define TWOBLUECUBES_CATCH_OPTION_HPP_INCLUDED + +namespace Catch { + + // An optional type + template + class Option { + public: + Option() : nullableValue( CATCH_NULL ) {} + Option( T const& _value ) + : nullableValue( new( storage ) T( _value ) ) + {} + Option( Option const& _other ) + : nullableValue( _other ? new( storage ) T( *_other ) : CATCH_NULL ) + {} + + ~Option() { + reset(); + } + + Option& operator= ( Option const& _other ) { + if( &_other != this ) { + reset(); + if( _other ) + nullableValue = new( storage ) T( *_other ); + } + return *this; + } + Option& operator = ( T const& _value ) { + reset(); + nullableValue = new( storage ) T( _value ); + return *this; + } + + void reset() { + if( nullableValue ) + nullableValue->~T(); + nullableValue = CATCH_NULL; + } + + T& operator*() { return *nullableValue; } + T const& operator*() const { return *nullableValue; } + T* operator->() { return nullableValue; } + const T* operator->() const { return nullableValue; } + + T valueOr( T const& defaultValue ) const { + return nullableValue ? *nullableValue : defaultValue; + } + + bool some() const { return nullableValue != CATCH_NULL; } + bool none() const { return nullableValue == CATCH_NULL; } + + bool operator !() const { return nullableValue == CATCH_NULL; } + operator SafeBool::type() const { + return SafeBool::makeSafe( some() ); + } + + private: + T* nullableValue; + char storage[sizeof(T)]; + }; + +} // end namespace Catch + +namespace Catch { + + struct ITagAliasRegistry { + virtual ~ITagAliasRegistry(); + virtual Option find( std::string const& alias ) const = 0; + virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const = 0; + + static ITagAliasRegistry const& get(); + }; + +} // end namespace Catch + +// These files are included here so the single_include script doesn't put them +// in the conditionally compiled sections +// #included from: internal/catch_test_case_info.h +#define TWOBLUECUBES_CATCH_TEST_CASE_INFO_H_INCLUDED + +#include +#include + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpadded" +#endif + +namespace Catch { + + struct ITestCase; + + struct TestCaseInfo { + enum SpecialProperties{ + None = 0, + IsHidden = 1 << 1, + ShouldFail = 1 << 2, + MayFail = 1 << 3, + Throws = 1 << 4 + }; + + TestCaseInfo( std::string const& _name, + std::string const& _className, + std::string const& _description, + std::set const& _tags, + SourceLineInfo const& _lineInfo ); + + TestCaseInfo( TestCaseInfo const& other ); + + friend void setTags( TestCaseInfo& testCaseInfo, std::set const& tags ); + + bool isHidden() const; + bool throws() const; + bool okToFail() const; + bool expectedToFail() const; + + std::string name; + std::string className; + std::string description; + std::set tags; + std::set lcaseTags; + std::string tagsAsString; + SourceLineInfo lineInfo; + SpecialProperties properties; + }; + + class TestCase : public TestCaseInfo { + public: + + TestCase( ITestCase* testCase, TestCaseInfo const& info ); + TestCase( TestCase const& other ); + + TestCase withName( std::string const& _newName ) const; + + void invoke() const; + + TestCaseInfo const& getTestCaseInfo() const; + + void swap( TestCase& other ); + bool operator == ( TestCase const& other ) const; + bool operator < ( TestCase const& other ) const; + TestCase& operator = ( TestCase const& other ); + + private: + Ptr test; + }; + + TestCase makeTestCase( ITestCase* testCase, + std::string const& className, + std::string const& name, + std::string const& description, + SourceLineInfo const& lineInfo ); +} + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + + +#ifdef __OBJC__ +// #included from: internal/catch_objc.hpp +#define TWOBLUECUBES_CATCH_OBJC_HPP_INCLUDED + +#import + +#include + +// NB. Any general catch headers included here must be included +// in catch.hpp first to make sure they are included by the single +// header for non obj-usage + +/////////////////////////////////////////////////////////////////////////////// +// This protocol is really only here for (self) documenting purposes, since +// all its methods are optional. +@protocol OcFixture + +@optional + +-(void) setUp; +-(void) tearDown; + +@end + +namespace Catch { + + class OcMethod : public SharedImpl { + + public: + OcMethod( Class cls, SEL sel ) : m_cls( cls ), m_sel( sel ) {} + + virtual void invoke() const { + id obj = [[m_cls alloc] init]; + + performOptionalSelector( obj, @selector(setUp) ); + performOptionalSelector( obj, m_sel ); + performOptionalSelector( obj, @selector(tearDown) ); + + arcSafeRelease( obj ); + } + private: + virtual ~OcMethod() {} + + Class m_cls; + SEL m_sel; + }; + + namespace Detail{ + + inline std::string getAnnotation( Class cls, + std::string const& annotationName, + std::string const& testCaseName ) { + NSString* selStr = [[NSString alloc] initWithFormat:@"Catch_%s_%s", annotationName.c_str(), testCaseName.c_str()]; + SEL sel = NSSelectorFromString( selStr ); + arcSafeRelease( selStr ); + id value = performOptionalSelector( cls, sel ); + if( value ) + return [(NSString*)value UTF8String]; + return ""; + } + } + + inline size_t registerTestMethods() { + size_t noTestMethods = 0; + int noClasses = objc_getClassList( CATCH_NULL, 0 ); + + Class* classes = (CATCH_UNSAFE_UNRETAINED Class *)malloc( sizeof(Class) * noClasses); + objc_getClassList( classes, noClasses ); + + for( int c = 0; c < noClasses; c++ ) { + Class cls = classes[c]; + { + u_int count; + Method* methods = class_copyMethodList( cls, &count ); + for( u_int m = 0; m < count ; m++ ) { + SEL selector = method_getName(methods[m]); + std::string methodName = sel_getName(selector); + if( startsWith( methodName, "Catch_TestCase_" ) ) { + std::string testCaseName = methodName.substr( 15 ); + std::string name = Detail::getAnnotation( cls, "Name", testCaseName ); + std::string desc = Detail::getAnnotation( cls, "Description", testCaseName ); + const char* className = class_getName( cls ); + + getMutableRegistryHub().registerTest( makeTestCase( new OcMethod( cls, selector ), className, name.c_str(), desc.c_str(), SourceLineInfo() ) ); + noTestMethods++; + } + } + free(methods); + } + } + return noTestMethods; + } + + namespace Matchers { + namespace Impl { + namespace NSStringMatchers { + + template + struct StringHolder : MatcherImpl{ + StringHolder( NSString* substr ) : m_substr( [substr copy] ){} + StringHolder( StringHolder const& other ) : m_substr( [other.m_substr copy] ){} + StringHolder() { + arcSafeRelease( m_substr ); + } + + NSString* m_substr; + }; + + struct Equals : StringHolder { + Equals( NSString* substr ) : StringHolder( substr ){} + + virtual bool match( ExpressionType const& str ) const { + return (str != nil || m_substr == nil ) && + [str isEqualToString:m_substr]; + } + + virtual std::string toString() const { + return "equals string: " + Catch::toString( m_substr ); + } + }; + + struct Contains : StringHolder { + Contains( NSString* substr ) : StringHolder( substr ){} + + virtual bool match( ExpressionType const& str ) const { + return (str != nil || m_substr == nil ) && + [str rangeOfString:m_substr].location != NSNotFound; + } + + virtual std::string toString() const { + return "contains string: " + Catch::toString( m_substr ); + } + }; + + struct StartsWith : StringHolder { + StartsWith( NSString* substr ) : StringHolder( substr ){} + + virtual bool match( ExpressionType const& str ) const { + return (str != nil || m_substr == nil ) && + [str rangeOfString:m_substr].location == 0; + } + + virtual std::string toString() const { + return "starts with: " + Catch::toString( m_substr ); + } + }; + struct EndsWith : StringHolder { + EndsWith( NSString* substr ) : StringHolder( substr ){} + + virtual bool match( ExpressionType const& str ) const { + return (str != nil || m_substr == nil ) && + [str rangeOfString:m_substr].location == [str length] - [m_substr length]; + } + + virtual std::string toString() const { + return "ends with: " + Catch::toString( m_substr ); + } + }; + + } // namespace NSStringMatchers + } // namespace Impl + + inline Impl::NSStringMatchers::Equals + Equals( NSString* substr ){ return Impl::NSStringMatchers::Equals( substr ); } + + inline Impl::NSStringMatchers::Contains + Contains( NSString* substr ){ return Impl::NSStringMatchers::Contains( substr ); } + + inline Impl::NSStringMatchers::StartsWith + StartsWith( NSString* substr ){ return Impl::NSStringMatchers::StartsWith( substr ); } + + inline Impl::NSStringMatchers::EndsWith + EndsWith( NSString* substr ){ return Impl::NSStringMatchers::EndsWith( substr ); } + + } // namespace Matchers + + using namespace Matchers; + +} // namespace Catch + +/////////////////////////////////////////////////////////////////////////////// +#define OC_TEST_CASE( name, desc )\ ++(NSString*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Name_test ) \ +{\ +return @ name; \ +}\ ++(NSString*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Description_test ) \ +{ \ +return @ desc; \ +} \ +-(void) INTERNAL_CATCH_UNIQUE_NAME( Catch_TestCase_test ) + +#endif + +#ifdef CATCH_IMPL +// #included from: internal/catch_impl.hpp +#define TWOBLUECUBES_CATCH_IMPL_HPP_INCLUDED + +// Collect all the implementation files together here +// These are the equivalent of what would usually be cpp files + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wweak-vtables" +#endif + +// #included from: ../catch_session.hpp +#define TWOBLUECUBES_CATCH_RUNNER_HPP_INCLUDED + +// #included from: internal/catch_commandline.hpp +#define TWOBLUECUBES_CATCH_COMMANDLINE_HPP_INCLUDED + +// #included from: catch_config.hpp +#define TWOBLUECUBES_CATCH_CONFIG_HPP_INCLUDED + +// #included from: catch_test_spec_parser.hpp +#define TWOBLUECUBES_CATCH_TEST_SPEC_PARSER_HPP_INCLUDED + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpadded" +#endif + +// #included from: catch_test_spec.hpp +#define TWOBLUECUBES_CATCH_TEST_SPEC_HPP_INCLUDED + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpadded" +#endif + +// #included from: catch_wildcard_pattern.hpp +#define TWOBLUECUBES_CATCH_WILDCARD_PATTERN_HPP_INCLUDED + +namespace Catch +{ + class WildcardPattern { + enum WildcardPosition { + NoWildcard = 0, + WildcardAtStart = 1, + WildcardAtEnd = 2, + WildcardAtBothEnds = WildcardAtStart | WildcardAtEnd + }; + + public: + + WildcardPattern( std::string const& pattern, CaseSensitive::Choice caseSensitivity ) + : m_caseSensitivity( caseSensitivity ), + m_wildcard( NoWildcard ), + m_pattern( adjustCase( pattern ) ) + { + if( startsWith( m_pattern, "*" ) ) { + m_pattern = m_pattern.substr( 1 ); + m_wildcard = WildcardAtStart; + } + if( endsWith( m_pattern, "*" ) ) { + m_pattern = m_pattern.substr( 0, m_pattern.size()-1 ); + m_wildcard = static_cast( m_wildcard | WildcardAtEnd ); + } + } + virtual ~WildcardPattern(); + virtual bool matches( std::string const& str ) const { + switch( m_wildcard ) { + case NoWildcard: + return m_pattern == adjustCase( str ); + case WildcardAtStart: + return endsWith( adjustCase( str ), m_pattern ); + case WildcardAtEnd: + return startsWith( adjustCase( str ), m_pattern ); + case WildcardAtBothEnds: + return contains( adjustCase( str ), m_pattern ); + } + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunreachable-code" +#endif + throw std::logic_error( "Unknown enum" ); +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + } + private: + std::string adjustCase( std::string const& str ) const { + return m_caseSensitivity == CaseSensitive::No ? toLower( str ) : str; + } + CaseSensitive::Choice m_caseSensitivity; + WildcardPosition m_wildcard; + std::string m_pattern; + }; +} + +#include +#include + +namespace Catch { + + class TestSpec { + struct Pattern : SharedImpl<> { + virtual ~Pattern(); + virtual bool matches( TestCaseInfo const& testCase ) const = 0; + }; + class NamePattern : public Pattern { + public: + NamePattern( std::string const& name ) + : m_wildcardPattern( toLower( name ), CaseSensitive::No ) + {} + virtual ~NamePattern(); + virtual bool matches( TestCaseInfo const& testCase ) const { + return m_wildcardPattern.matches( toLower( testCase.name ) ); + } + private: + WildcardPattern m_wildcardPattern; + }; + + class TagPattern : public Pattern { + public: + TagPattern( std::string const& tag ) : m_tag( toLower( tag ) ) {} + virtual ~TagPattern(); + virtual bool matches( TestCaseInfo const& testCase ) const { + return testCase.lcaseTags.find( m_tag ) != testCase.lcaseTags.end(); + } + private: + std::string m_tag; + }; + + class ExcludedPattern : public Pattern { + public: + ExcludedPattern( Ptr const& underlyingPattern ) : m_underlyingPattern( underlyingPattern ) {} + virtual ~ExcludedPattern(); + virtual bool matches( TestCaseInfo const& testCase ) const { return !m_underlyingPattern->matches( testCase ); } + private: + Ptr m_underlyingPattern; + }; + + struct Filter { + std::vector > m_patterns; + + bool matches( TestCaseInfo const& testCase ) const { + // All patterns in a filter must match for the filter to be a match + for( std::vector >::const_iterator it = m_patterns.begin(), itEnd = m_patterns.end(); it != itEnd; ++it ) + if( !(*it)->matches( testCase ) ) + return false; + return true; + } + }; + + public: + bool hasFilters() const { + return !m_filters.empty(); + } + bool matches( TestCaseInfo const& testCase ) const { + // A TestSpec matches if any filter matches + for( std::vector::const_iterator it = m_filters.begin(), itEnd = m_filters.end(); it != itEnd; ++it ) + if( it->matches( testCase ) ) + return true; + return false; + } + + private: + std::vector m_filters; + + friend class TestSpecParser; + }; +} + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +namespace Catch { + + class TestSpecParser { + enum Mode{ None, Name, QuotedName, Tag }; + Mode m_mode; + bool m_exclusion; + std::size_t m_start, m_pos; + std::string m_arg; + TestSpec::Filter m_currentFilter; + TestSpec m_testSpec; + ITagAliasRegistry const* m_tagAliases; + + public: + TestSpecParser( ITagAliasRegistry const& tagAliases ) : m_tagAliases( &tagAliases ) {} + + TestSpecParser& parse( std::string const& arg ) { + m_mode = None; + m_exclusion = false; + m_start = std::string::npos; + m_arg = m_tagAliases->expandAliases( arg ); + for( m_pos = 0; m_pos < m_arg.size(); ++m_pos ) + visitChar( m_arg[m_pos] ); + if( m_mode == Name ) + addPattern(); + return *this; + } + TestSpec testSpec() { + addFilter(); + return m_testSpec; + } + private: + void visitChar( char c ) { + if( m_mode == None ) { + switch( c ) { + case ' ': return; + case '~': m_exclusion = true; return; + case '[': return startNewMode( Tag, ++m_pos ); + case '"': return startNewMode( QuotedName, ++m_pos ); + default: startNewMode( Name, m_pos ); break; + } + } + if( m_mode == Name ) { + if( c == ',' ) { + addPattern(); + addFilter(); + } + else if( c == '[' ) { + if( subString() == "exclude:" ) + m_exclusion = true; + else + addPattern(); + startNewMode( Tag, ++m_pos ); + } + } + else if( m_mode == QuotedName && c == '"' ) + addPattern(); + else if( m_mode == Tag && c == ']' ) + addPattern(); + } + void startNewMode( Mode mode, std::size_t start ) { + m_mode = mode; + m_start = start; + } + std::string subString() const { return m_arg.substr( m_start, m_pos - m_start ); } + template + void addPattern() { + std::string token = subString(); + if( startsWith( token, "exclude:" ) ) { + m_exclusion = true; + token = token.substr( 8 ); + } + if( !token.empty() ) { + Ptr pattern = new T( token ); + if( m_exclusion ) + pattern = new TestSpec::ExcludedPattern( pattern ); + m_currentFilter.m_patterns.push_back( pattern ); + } + m_exclusion = false; + m_mode = None; + } + void addFilter() { + if( !m_currentFilter.m_patterns.empty() ) { + m_testSpec.m_filters.push_back( m_currentFilter ); + m_currentFilter = TestSpec::Filter(); + } + } + }; + inline TestSpec parseTestSpec( std::string const& arg ) { + return TestSpecParser( ITagAliasRegistry::get() ).parse( arg ).testSpec(); + } + +} // namespace Catch + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +// #included from: catch_interfaces_config.h +#define TWOBLUECUBES_CATCH_INTERFACES_CONFIG_H_INCLUDED + +#include +#include +#include + +namespace Catch { + + struct Verbosity { enum Level { + NoOutput = 0, + Quiet, + Normal + }; }; + + struct WarnAbout { enum What { + Nothing = 0x00, + NoAssertions = 0x01 + }; }; + + struct ShowDurations { enum OrNot { + DefaultForReporter, + Always, + Never + }; }; + struct RunTests { enum InWhatOrder { + InDeclarationOrder, + InLexicographicalOrder, + InRandomOrder + }; }; + struct UseColour { enum YesOrNo { + Auto, + Yes, + No + }; }; + + class TestSpec; + + struct IConfig : IShared { + + virtual ~IConfig(); + + virtual bool allowThrows() const = 0; + virtual std::ostream& stream() const = 0; + virtual std::string name() const = 0; + virtual bool includeSuccessfulResults() const = 0; + virtual bool shouldDebugBreak() const = 0; + virtual bool warnAboutMissingAssertions() const = 0; + virtual int abortAfter() const = 0; + virtual bool showInvisibles() const = 0; + virtual ShowDurations::OrNot showDurations() const = 0; + virtual TestSpec const& testSpec() const = 0; + virtual RunTests::InWhatOrder runOrder() const = 0; + virtual unsigned int rngSeed() const = 0; + virtual UseColour::YesOrNo useColour() const = 0; + }; +} + +// #included from: catch_stream.h +#define TWOBLUECUBES_CATCH_STREAM_H_INCLUDED + +// #included from: catch_streambuf.h +#define TWOBLUECUBES_CATCH_STREAMBUF_H_INCLUDED + +#include + +namespace Catch { + + class StreamBufBase : public std::streambuf { + public: + virtual ~StreamBufBase() CATCH_NOEXCEPT; + }; +} + +#include +#include +#include + +namespace Catch { + + std::ostream& cout(); + std::ostream& cerr(); + + struct IStream { + virtual ~IStream() CATCH_NOEXCEPT; + virtual std::ostream& stream() const = 0; + }; + + class FileStream : public IStream { + mutable std::ofstream m_ofs; + public: + FileStream( std::string const& filename ); + virtual ~FileStream() CATCH_NOEXCEPT; + public: // IStream + virtual std::ostream& stream() const CATCH_OVERRIDE; + }; + + class CoutStream : public IStream { + mutable std::ostream m_os; + public: + CoutStream(); + virtual ~CoutStream() CATCH_NOEXCEPT; + + public: // IStream + virtual std::ostream& stream() const CATCH_OVERRIDE; + }; + + class DebugOutStream : public IStream { + std::auto_ptr m_streamBuf; + mutable std::ostream m_os; + public: + DebugOutStream(); + virtual ~DebugOutStream() CATCH_NOEXCEPT; + + public: // IStream + virtual std::ostream& stream() const CATCH_OVERRIDE; + }; +} + +#include +#include +#include +#include +#include + +#ifndef CATCH_CONFIG_CONSOLE_WIDTH +#define CATCH_CONFIG_CONSOLE_WIDTH 80 +#endif + +namespace Catch { + + struct ConfigData { + + ConfigData() + : listTests( false ), + listTags( false ), + listReporters( false ), + listTestNamesOnly( false ), + showSuccessfulTests( false ), + shouldDebugBreak( false ), + noThrow( false ), + showHelp( false ), + showInvisibles( false ), + filenamesAsTags( false ), + abortAfter( -1 ), + rngSeed( 0 ), + verbosity( Verbosity::Normal ), + warnings( WarnAbout::Nothing ), + showDurations( ShowDurations::DefaultForReporter ), + runOrder( RunTests::InDeclarationOrder ), + useColour( UseColour::Auto ) + {} + + bool listTests; + bool listTags; + bool listReporters; + bool listTestNamesOnly; + + bool showSuccessfulTests; + bool shouldDebugBreak; + bool noThrow; + bool showHelp; + bool showInvisibles; + bool filenamesAsTags; + + int abortAfter; + unsigned int rngSeed; + + Verbosity::Level verbosity; + WarnAbout::What warnings; + ShowDurations::OrNot showDurations; + RunTests::InWhatOrder runOrder; + UseColour::YesOrNo useColour; + + std::string outputFilename; + std::string name; + std::string processName; + + std::vector reporterNames; + std::vector testsOrTags; + }; + + class Config : public SharedImpl { + private: + Config( Config const& other ); + Config& operator = ( Config const& other ); + virtual void dummy(); + public: + + Config() + {} + + Config( ConfigData const& data ) + : m_data( data ), + m_stream( openStream() ) + { + if( !data.testsOrTags.empty() ) { + TestSpecParser parser( ITagAliasRegistry::get() ); + for( std::size_t i = 0; i < data.testsOrTags.size(); ++i ) + parser.parse( data.testsOrTags[i] ); + m_testSpec = parser.testSpec(); + } + } + + virtual ~Config() { + } + + std::string const& getFilename() const { + return m_data.outputFilename ; + } + + bool listTests() const { return m_data.listTests; } + bool listTestNamesOnly() const { return m_data.listTestNamesOnly; } + bool listTags() const { return m_data.listTags; } + bool listReporters() const { return m_data.listReporters; } + + std::string getProcessName() const { return m_data.processName; } + + bool shouldDebugBreak() const { return m_data.shouldDebugBreak; } + + std::vector getReporterNames() const { return m_data.reporterNames; } + + int abortAfter() const { return m_data.abortAfter; } + + TestSpec const& testSpec() const { return m_testSpec; } + + bool showHelp() const { return m_data.showHelp; } + bool showInvisibles() const { return m_data.showInvisibles; } + + // IConfig interface + virtual bool allowThrows() const { return !m_data.noThrow; } + virtual std::ostream& stream() const { return m_stream->stream(); } + virtual std::string name() const { return m_data.name.empty() ? m_data.processName : m_data.name; } + virtual bool includeSuccessfulResults() const { return m_data.showSuccessfulTests; } + virtual bool warnAboutMissingAssertions() const { return m_data.warnings & WarnAbout::NoAssertions; } + virtual ShowDurations::OrNot showDurations() const { return m_data.showDurations; } + virtual RunTests::InWhatOrder runOrder() const { return m_data.runOrder; } + virtual unsigned int rngSeed() const { return m_data.rngSeed; } + virtual UseColour::YesOrNo useColour() const { return m_data.useColour; } + + private: + + IStream const* openStream() { + if( m_data.outputFilename.empty() ) + return new CoutStream(); + else if( m_data.outputFilename[0] == '%' ) { + if( m_data.outputFilename == "%debug" ) + return new DebugOutStream(); + else + throw std::domain_error( "Unrecognised stream: " + m_data.outputFilename ); + } + else + return new FileStream( m_data.outputFilename ); + } + ConfigData m_data; + + std::auto_ptr m_stream; + TestSpec m_testSpec; + }; + +} // end namespace Catch + +// #included from: catch_clara.h +#define TWOBLUECUBES_CATCH_CLARA_H_INCLUDED + +// Use Catch's value for console width (store Clara's off to the side, if present) +#ifdef CLARA_CONFIG_CONSOLE_WIDTH +#define CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH CLARA_CONFIG_CONSOLE_WIDTH +#undef CLARA_CONFIG_CONSOLE_WIDTH +#endif +#define CLARA_CONFIG_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH + +// Declare Clara inside the Catch namespace +#define STITCH_CLARA_OPEN_NAMESPACE namespace Catch { +// #included from: ../external/clara.h + +// Version 0.0.1.1 + +// Only use header guard if we are not using an outer namespace +#if !defined(TWOBLUECUBES_CLARA_H_INCLUDED) || defined(STITCH_CLARA_OPEN_NAMESPACE) + +#ifndef STITCH_CLARA_OPEN_NAMESPACE +#define TWOBLUECUBES_CLARA_H_INCLUDED +#define STITCH_CLARA_OPEN_NAMESPACE +#define STITCH_CLARA_CLOSE_NAMESPACE +#else +#define STITCH_CLARA_CLOSE_NAMESPACE } +#endif + +#define STITCH_TBC_TEXT_FORMAT_OPEN_NAMESPACE STITCH_CLARA_OPEN_NAMESPACE + +// ----------- #included from tbc_text_format.h ----------- + +// Only use header guard if we are not using an outer namespace +#if !defined(TBC_TEXT_FORMAT_H_INCLUDED) || defined(STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE) +#ifndef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE +#define TBC_TEXT_FORMAT_H_INCLUDED +#endif + +#include +#include +#include +#include + +// Use optional outer namespace +#ifdef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE +namespace STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE { +#endif + +namespace Tbc { + +#ifdef TBC_TEXT_FORMAT_CONSOLE_WIDTH + const unsigned int consoleWidth = TBC_TEXT_FORMAT_CONSOLE_WIDTH; +#else + const unsigned int consoleWidth = 80; +#endif + + struct TextAttributes { + TextAttributes() + : initialIndent( std::string::npos ), + indent( 0 ), + width( consoleWidth-1 ), + tabChar( '\t' ) + {} + + TextAttributes& setInitialIndent( std::size_t _value ) { initialIndent = _value; return *this; } + TextAttributes& setIndent( std::size_t _value ) { indent = _value; return *this; } + TextAttributes& setWidth( std::size_t _value ) { width = _value; return *this; } + TextAttributes& setTabChar( char _value ) { tabChar = _value; return *this; } + + std::size_t initialIndent; // indent of first line, or npos + std::size_t indent; // indent of subsequent lines, or all if initialIndent is npos + std::size_t width; // maximum width of text, including indent. Longer text will wrap + char tabChar; // If this char is seen the indent is changed to current pos + }; + + class Text { + public: + Text( std::string const& _str, TextAttributes const& _attr = TextAttributes() ) + : attr( _attr ) + { + std::string wrappableChars = " [({.,/|\\-"; + std::size_t indent = _attr.initialIndent != std::string::npos + ? _attr.initialIndent + : _attr.indent; + std::string remainder = _str; + + while( !remainder.empty() ) { + if( lines.size() >= 1000 ) { + lines.push_back( "... message truncated due to excessive size" ); + return; + } + std::size_t tabPos = std::string::npos; + std::size_t width = (std::min)( remainder.size(), _attr.width - indent ); + std::size_t pos = remainder.find_first_of( '\n' ); + if( pos <= width ) { + width = pos; + } + pos = remainder.find_last_of( _attr.tabChar, width ); + if( pos != std::string::npos ) { + tabPos = pos; + if( remainder[width] == '\n' ) + width--; + remainder = remainder.substr( 0, tabPos ) + remainder.substr( tabPos+1 ); + } + + if( width == remainder.size() ) { + spliceLine( indent, remainder, width ); + } + else if( remainder[width] == '\n' ) { + spliceLine( indent, remainder, width ); + if( width <= 1 || remainder.size() != 1 ) + remainder = remainder.substr( 1 ); + indent = _attr.indent; + } + else { + pos = remainder.find_last_of( wrappableChars, width ); + if( pos != std::string::npos && pos > 0 ) { + spliceLine( indent, remainder, pos ); + if( remainder[0] == ' ' ) + remainder = remainder.substr( 1 ); + } + else { + spliceLine( indent, remainder, width-1 ); + lines.back() += "-"; + } + if( lines.size() == 1 ) + indent = _attr.indent; + if( tabPos != std::string::npos ) + indent += tabPos; + } + } + } + + void spliceLine( std::size_t _indent, std::string& _remainder, std::size_t _pos ) { + lines.push_back( std::string( _indent, ' ' ) + _remainder.substr( 0, _pos ) ); + _remainder = _remainder.substr( _pos ); + } + + typedef std::vector::const_iterator const_iterator; + + const_iterator begin() const { return lines.begin(); } + const_iterator end() const { return lines.end(); } + std::string const& last() const { return lines.back(); } + std::size_t size() const { return lines.size(); } + std::string const& operator[]( std::size_t _index ) const { return lines[_index]; } + std::string toString() const { + std::ostringstream oss; + oss << *this; + return oss.str(); + } + + inline friend std::ostream& operator << ( std::ostream& _stream, Text const& _text ) { + for( Text::const_iterator it = _text.begin(), itEnd = _text.end(); + it != itEnd; ++it ) { + if( it != _text.begin() ) + _stream << "\n"; + _stream << *it; + } + return _stream; + } + + private: + std::string str; + TextAttributes attr; + std::vector lines; + }; + +} // end namespace Tbc + +#ifdef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE +} // end outer namespace +#endif + +#endif // TBC_TEXT_FORMAT_H_INCLUDED + +// ----------- end of #include from tbc_text_format.h ----------- +// ........... back in clara.h + +#undef STITCH_TBC_TEXT_FORMAT_OPEN_NAMESPACE + +// ----------- #included from clara_compilers.h ----------- + +#ifndef TWOBLUECUBES_CLARA_COMPILERS_H_INCLUDED +#define TWOBLUECUBES_CLARA_COMPILERS_H_INCLUDED + +// Detect a number of compiler features - mostly C++11/14 conformance - by compiler +// The following features are defined: +// +// CLARA_CONFIG_CPP11_NULLPTR : is nullptr supported? +// CLARA_CONFIG_CPP11_NOEXCEPT : is noexcept supported? +// CLARA_CONFIG_CPP11_GENERATED_METHODS : The delete and default keywords for compiler generated methods +// CLARA_CONFIG_CPP11_OVERRIDE : is override supported? +// CLARA_CONFIG_CPP11_UNIQUE_PTR : is unique_ptr supported (otherwise use auto_ptr) + +// CLARA_CONFIG_CPP11_OR_GREATER : Is C++11 supported? + +// CLARA_CONFIG_VARIADIC_MACROS : are variadic macros supported? + +// In general each macro has a _NO_ form +// (e.g. CLARA_CONFIG_CPP11_NO_NULLPTR) which disables the feature. +// Many features, at point of detection, define an _INTERNAL_ macro, so they +// can be combined, en-mass, with the _NO_ forms later. + +// All the C++11 features can be disabled with CLARA_CONFIG_NO_CPP11 + +#ifdef __clang__ + +#if __has_feature(cxx_nullptr) +#define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR +#endif + +#if __has_feature(cxx_noexcept) +#define CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT +#endif + +#endif // __clang__ + +//////////////////////////////////////////////////////////////////////////////// +// GCC +#ifdef __GNUC__ + +#if __GNUC__ == 4 && __GNUC_MINOR__ >= 6 && defined(__GXX_EXPERIMENTAL_CXX0X__) +#define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR +#endif + +// - otherwise more recent versions define __cplusplus >= 201103L +// and will get picked up below + +#endif // __GNUC__ + +//////////////////////////////////////////////////////////////////////////////// +// Visual C++ +#ifdef _MSC_VER + +#if (_MSC_VER >= 1600) +#define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR +#define CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR +#endif + +#if (_MSC_VER >= 1900 ) // (VC++ 13 (VS2015)) +#define CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT +#define CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS +#endif + +#endif // _MSC_VER + +//////////////////////////////////////////////////////////////////////////////// +// C++ language feature support + +// catch all support for C++11 +#if defined(__cplusplus) && __cplusplus >= 201103L + +#define CLARA_CPP11_OR_GREATER + +#if !defined(CLARA_INTERNAL_CONFIG_CPP11_NULLPTR) +#define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR +#endif + +#ifndef CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT +#define CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT +#endif + +#ifndef CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS +#define CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS +#endif + +#if !defined(CLARA_INTERNAL_CONFIG_CPP11_OVERRIDE) +#define CLARA_INTERNAL_CONFIG_CPP11_OVERRIDE +#endif +#if !defined(CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) +#define CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR +#endif + +#endif // __cplusplus >= 201103L + +// Now set the actual defines based on the above + anything the user has configured +#if defined(CLARA_INTERNAL_CONFIG_CPP11_NULLPTR) && !defined(CLARA_CONFIG_CPP11_NO_NULLPTR) && !defined(CLARA_CONFIG_CPP11_NULLPTR) && !defined(CLARA_CONFIG_NO_CPP11) +#define CLARA_CONFIG_CPP11_NULLPTR +#endif +#if defined(CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT) && !defined(CLARA_CONFIG_CPP11_NO_NOEXCEPT) && !defined(CLARA_CONFIG_CPP11_NOEXCEPT) && !defined(CLARA_CONFIG_NO_CPP11) +#define CLARA_CONFIG_CPP11_NOEXCEPT +#endif +#if defined(CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS) && !defined(CLARA_CONFIG_CPP11_NO_GENERATED_METHODS) && !defined(CLARA_CONFIG_CPP11_GENERATED_METHODS) && !defined(CLARA_CONFIG_NO_CPP11) +#define CLARA_CONFIG_CPP11_GENERATED_METHODS +#endif +#if defined(CLARA_INTERNAL_CONFIG_CPP11_OVERRIDE) && !defined(CLARA_CONFIG_NO_OVERRIDE) && !defined(CLARA_CONFIG_CPP11_OVERRIDE) && !defined(CLARA_CONFIG_NO_CPP11) +#define CLARA_CONFIG_CPP11_OVERRIDE +#endif +#if defined(CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) && !defined(CLARA_CONFIG_NO_UNIQUE_PTR) && !defined(CLARA_CONFIG_CPP11_UNIQUE_PTR) && !defined(CLARA_CONFIG_NO_CPP11) +#define CLARA_CONFIG_CPP11_UNIQUE_PTR +#endif + +// noexcept support: +#if defined(CLARA_CONFIG_CPP11_NOEXCEPT) && !defined(CLARA_NOEXCEPT) +#define CLARA_NOEXCEPT noexcept +# define CLARA_NOEXCEPT_IS(x) noexcept(x) +#else +#define CLARA_NOEXCEPT throw() +# define CLARA_NOEXCEPT_IS(x) +#endif + +// nullptr support +#ifdef CLARA_CONFIG_CPP11_NULLPTR +#define CLARA_NULL nullptr +#else +#define CLARA_NULL NULL +#endif + +// override support +#ifdef CLARA_CONFIG_CPP11_OVERRIDE +#define CLARA_OVERRIDE override +#else +#define CLARA_OVERRIDE +#endif + +// unique_ptr support +#ifdef CLARA_CONFIG_CPP11_UNIQUE_PTR +# define CLARA_AUTO_PTR( T ) std::unique_ptr +#else +# define CLARA_AUTO_PTR( T ) std::auto_ptr +#endif + +#endif // TWOBLUECUBES_CLARA_COMPILERS_H_INCLUDED + +// ----------- end of #include from clara_compilers.h ----------- +// ........... back in clara.h + +#include +#include +#include + +// Use optional outer namespace +#ifdef STITCH_CLARA_OPEN_NAMESPACE +STITCH_CLARA_OPEN_NAMESPACE +#endif + +namespace Clara { + + struct UnpositionalTag {}; + + extern UnpositionalTag _; + +#ifdef CLARA_CONFIG_MAIN + UnpositionalTag _; +#endif + + namespace Detail { + +#ifdef CLARA_CONSOLE_WIDTH + const unsigned int consoleWidth = CLARA_CONFIG_CONSOLE_WIDTH; +#else + const unsigned int consoleWidth = 80; +#endif + + // Use this to try and stop compiler from warning about unreachable code + inline bool isTrue( bool value ) { return value; } + + using namespace Tbc; + + inline bool startsWith( std::string const& str, std::string const& prefix ) { + return str.size() >= prefix.size() && str.substr( 0, prefix.size() ) == prefix; + } + + template struct RemoveConstRef{ typedef T type; }; + template struct RemoveConstRef{ typedef T type; }; + template struct RemoveConstRef{ typedef T type; }; + template struct RemoveConstRef{ typedef T type; }; + + template struct IsBool { static const bool value = false; }; + template<> struct IsBool { static const bool value = true; }; + + template + void convertInto( std::string const& _source, T& _dest ) { + std::stringstream ss; + ss << _source; + ss >> _dest; + if( ss.fail() ) + throw std::runtime_error( "Unable to convert " + _source + " to destination type" ); + } + inline void convertInto( std::string const& _source, std::string& _dest ) { + _dest = _source; + } + inline void convertInto( std::string const& _source, bool& _dest ) { + std::string sourceLC = _source; + std::transform( sourceLC.begin(), sourceLC.end(), sourceLC.begin(), ::tolower ); + if( sourceLC == "y" || sourceLC == "1" || sourceLC == "true" || sourceLC == "yes" || sourceLC == "on" ) + _dest = true; + else if( sourceLC == "n" || sourceLC == "0" || sourceLC == "false" || sourceLC == "no" || sourceLC == "off" ) + _dest = false; + else + throw std::runtime_error( "Expected a boolean value but did not recognise:\n '" + _source + "'" ); + } + inline void convertInto( bool _source, bool& _dest ) { + _dest = _source; + } + template + inline void convertInto( bool, T& ) { + if( isTrue( true ) ) + throw std::runtime_error( "Invalid conversion" ); + } + + template + struct IArgFunction { + virtual ~IArgFunction() {} +#ifdef CLARA_CONFIG_CPP11_GENERATED_METHODS + IArgFunction() = default; + IArgFunction( IArgFunction const& ) = default; +#endif + virtual void set( ConfigT& config, std::string const& value ) const = 0; + virtual void setFlag( ConfigT& config ) const = 0; + virtual bool takesArg() const = 0; + virtual IArgFunction* clone() const = 0; + }; + + template + class BoundArgFunction { + public: + BoundArgFunction() : functionObj( CLARA_NULL ) {} + BoundArgFunction( IArgFunction* _functionObj ) : functionObj( _functionObj ) {} + BoundArgFunction( BoundArgFunction const& other ) : functionObj( other.functionObj ? other.functionObj->clone() : CLARA_NULL ) {} + BoundArgFunction& operator = ( BoundArgFunction const& other ) { + IArgFunction* newFunctionObj = other.functionObj ? other.functionObj->clone() : CLARA_NULL; + delete functionObj; + functionObj = newFunctionObj; + return *this; + } + ~BoundArgFunction() { delete functionObj; } + + void set( ConfigT& config, std::string const& value ) const { + functionObj->set( config, value ); + } + void setFlag( ConfigT& config ) const { + functionObj->setFlag( config ); + } + bool takesArg() const { return functionObj->takesArg(); } + + bool isSet() const { + return functionObj != CLARA_NULL; + } + private: + IArgFunction* functionObj; + }; + + template + struct NullBinder : IArgFunction{ + virtual void set( C&, std::string const& ) const {} + virtual void setFlag( C& ) const {} + virtual bool takesArg() const { return true; } + virtual IArgFunction* clone() const { return new NullBinder( *this ); } + }; + + template + struct BoundDataMember : IArgFunction{ + BoundDataMember( M C::* _member ) : member( _member ) {} + virtual void set( C& p, std::string const& stringValue ) const { + convertInto( stringValue, p.*member ); + } + virtual void setFlag( C& p ) const { + convertInto( true, p.*member ); + } + virtual bool takesArg() const { return !IsBool::value; } + virtual IArgFunction* clone() const { return new BoundDataMember( *this ); } + M C::* member; + }; + template + struct BoundUnaryMethod : IArgFunction{ + BoundUnaryMethod( void (C::*_member)( M ) ) : member( _member ) {} + virtual void set( C& p, std::string const& stringValue ) const { + typename RemoveConstRef::type value; + convertInto( stringValue, value ); + (p.*member)( value ); + } + virtual void setFlag( C& p ) const { + typename RemoveConstRef::type value; + convertInto( true, value ); + (p.*member)( value ); + } + virtual bool takesArg() const { return !IsBool::value; } + virtual IArgFunction* clone() const { return new BoundUnaryMethod( *this ); } + void (C::*member)( M ); + }; + template + struct BoundNullaryMethod : IArgFunction{ + BoundNullaryMethod( void (C::*_member)() ) : member( _member ) {} + virtual void set( C& p, std::string const& stringValue ) const { + bool value; + convertInto( stringValue, value ); + if( value ) + (p.*member)(); + } + virtual void setFlag( C& p ) const { + (p.*member)(); + } + virtual bool takesArg() const { return false; } + virtual IArgFunction* clone() const { return new BoundNullaryMethod( *this ); } + void (C::*member)(); + }; + + template + struct BoundUnaryFunction : IArgFunction{ + BoundUnaryFunction( void (*_function)( C& ) ) : function( _function ) {} + virtual void set( C& obj, std::string const& stringValue ) const { + bool value; + convertInto( stringValue, value ); + if( value ) + function( obj ); + } + virtual void setFlag( C& p ) const { + function( p ); + } + virtual bool takesArg() const { return false; } + virtual IArgFunction* clone() const { return new BoundUnaryFunction( *this ); } + void (*function)( C& ); + }; + + template + struct BoundBinaryFunction : IArgFunction{ + BoundBinaryFunction( void (*_function)( C&, T ) ) : function( _function ) {} + virtual void set( C& obj, std::string const& stringValue ) const { + typename RemoveConstRef::type value; + convertInto( stringValue, value ); + function( obj, value ); + } + virtual void setFlag( C& obj ) const { + typename RemoveConstRef::type value; + convertInto( true, value ); + function( obj, value ); + } + virtual bool takesArg() const { return !IsBool::value; } + virtual IArgFunction* clone() const { return new BoundBinaryFunction( *this ); } + void (*function)( C&, T ); + }; + + } // namespace Detail + + struct Parser { + Parser() : separators( " \t=:" ) {} + + struct Token { + enum Type { Positional, ShortOpt, LongOpt }; + Token( Type _type, std::string const& _data ) : type( _type ), data( _data ) {} + Type type; + std::string data; + }; + + void parseIntoTokens( int argc, char const* const argv[], std::vector& tokens ) const { + const std::string doubleDash = "--"; + for( int i = 1; i < argc && argv[i] != doubleDash; ++i ) + parseIntoTokens( argv[i] , tokens); + } + void parseIntoTokens( std::string arg, std::vector& tokens ) const { + while( !arg.empty() ) { + Parser::Token token( Parser::Token::Positional, arg ); + arg = ""; + if( token.data[0] == '-' ) { + if( token.data.size() > 1 && token.data[1] == '-' ) { + token = Parser::Token( Parser::Token::LongOpt, token.data.substr( 2 ) ); + } + else { + token = Parser::Token( Parser::Token::ShortOpt, token.data.substr( 1 ) ); + if( token.data.size() > 1 && separators.find( token.data[1] ) == std::string::npos ) { + arg = "-" + token.data.substr( 1 ); + token.data = token.data.substr( 0, 1 ); + } + } + } + if( token.type != Parser::Token::Positional ) { + std::size_t pos = token.data.find_first_of( separators ); + if( pos != std::string::npos ) { + arg = token.data.substr( pos+1 ); + token.data = token.data.substr( 0, pos ); + } + } + tokens.push_back( token ); + } + } + std::string separators; + }; + + template + struct CommonArgProperties { + CommonArgProperties() {} + CommonArgProperties( Detail::BoundArgFunction const& _boundField ) : boundField( _boundField ) {} + + Detail::BoundArgFunction boundField; + std::string description; + std::string detail; + std::string placeholder; // Only value if boundField takes an arg + + bool takesArg() const { + return !placeholder.empty(); + } + void validate() const { + if( !boundField.isSet() ) + throw std::logic_error( "option not bound" ); + } + }; + struct OptionArgProperties { + std::vector shortNames; + std::string longName; + + bool hasShortName( std::string const& shortName ) const { + return std::find( shortNames.begin(), shortNames.end(), shortName ) != shortNames.end(); + } + bool hasLongName( std::string const& _longName ) const { + return _longName == longName; + } + }; + struct PositionalArgProperties { + PositionalArgProperties() : position( -1 ) {} + int position; // -1 means non-positional (floating) + + bool isFixedPositional() const { + return position != -1; + } + }; + + template + class CommandLine { + + struct Arg : CommonArgProperties, OptionArgProperties, PositionalArgProperties { + Arg() {} + Arg( Detail::BoundArgFunction const& _boundField ) : CommonArgProperties( _boundField ) {} + + using CommonArgProperties::placeholder; // !TBD + + std::string dbgName() const { + if( !longName.empty() ) + return "--" + longName; + if( !shortNames.empty() ) + return "-" + shortNames[0]; + return "positional args"; + } + std::string commands() const { + std::ostringstream oss; + bool first = true; + std::vector::const_iterator it = shortNames.begin(), itEnd = shortNames.end(); + for(; it != itEnd; ++it ) { + if( first ) + first = false; + else + oss << ", "; + oss << "-" << *it; + } + if( !longName.empty() ) { + if( !first ) + oss << ", "; + oss << "--" << longName; + } + if( !placeholder.empty() ) + oss << " <" << placeholder << ">"; + return oss.str(); + } + }; + + typedef CLARA_AUTO_PTR( Arg ) ArgAutoPtr; + + friend void addOptName( Arg& arg, std::string const& optName ) + { + if( optName.empty() ) + return; + if( Detail::startsWith( optName, "--" ) ) { + if( !arg.longName.empty() ) + throw std::logic_error( "Only one long opt may be specified. '" + + arg.longName + + "' already specified, now attempting to add '" + + optName + "'" ); + arg.longName = optName.substr( 2 ); + } + else if( Detail::startsWith( optName, "-" ) ) + arg.shortNames.push_back( optName.substr( 1 ) ); + else + throw std::logic_error( "option must begin with - or --. Option was: '" + optName + "'" ); + } + friend void setPositionalArg( Arg& arg, int position ) + { + arg.position = position; + } + + class ArgBuilder { + public: + ArgBuilder( Arg* arg ) : m_arg( arg ) {} + + // Bind a non-boolean data member (requires placeholder string) + template + void bind( M C::* field, std::string const& placeholder ) { + m_arg->boundField = new Detail::BoundDataMember( field ); + m_arg->placeholder = placeholder; + } + // Bind a boolean data member (no placeholder required) + template + void bind( bool C::* field ) { + m_arg->boundField = new Detail::BoundDataMember( field ); + } + + // Bind a method taking a single, non-boolean argument (requires a placeholder string) + template + void bind( void (C::* unaryMethod)( M ), std::string const& placeholder ) { + m_arg->boundField = new Detail::BoundUnaryMethod( unaryMethod ); + m_arg->placeholder = placeholder; + } + + // Bind a method taking a single, boolean argument (no placeholder string required) + template + void bind( void (C::* unaryMethod)( bool ) ) { + m_arg->boundField = new Detail::BoundUnaryMethod( unaryMethod ); + } + + // Bind a method that takes no arguments (will be called if opt is present) + template + void bind( void (C::* nullaryMethod)() ) { + m_arg->boundField = new Detail::BoundNullaryMethod( nullaryMethod ); + } + + // Bind a free function taking a single argument - the object to operate on (no placeholder string required) + template + void bind( void (* unaryFunction)( C& ) ) { + m_arg->boundField = new Detail::BoundUnaryFunction( unaryFunction ); + } + + // Bind a free function taking a single argument - the object to operate on (requires a placeholder string) + template + void bind( void (* binaryFunction)( C&, T ), std::string const& placeholder ) { + m_arg->boundField = new Detail::BoundBinaryFunction( binaryFunction ); + m_arg->placeholder = placeholder; + } + + ArgBuilder& describe( std::string const& description ) { + m_arg->description = description; + return *this; + } + ArgBuilder& detail( std::string const& detail ) { + m_arg->detail = detail; + return *this; + } + + protected: + Arg* m_arg; + }; + + class OptBuilder : public ArgBuilder { + public: + OptBuilder( Arg* arg ) : ArgBuilder( arg ) {} + OptBuilder( OptBuilder& other ) : ArgBuilder( other ) {} + + OptBuilder& operator[]( std::string const& optName ) { + addOptName( *ArgBuilder::m_arg, optName ); + return *this; + } + }; + + public: + + CommandLine() + : m_boundProcessName( new Detail::NullBinder() ), + m_highestSpecifiedArgPosition( 0 ), + m_throwOnUnrecognisedTokens( false ) + {} + CommandLine( CommandLine const& other ) + : m_boundProcessName( other.m_boundProcessName ), + m_options ( other.m_options ), + m_positionalArgs( other.m_positionalArgs ), + m_highestSpecifiedArgPosition( other.m_highestSpecifiedArgPosition ), + m_throwOnUnrecognisedTokens( other.m_throwOnUnrecognisedTokens ) + { + if( other.m_floatingArg.get() ) + m_floatingArg.reset( new Arg( *other.m_floatingArg ) ); + } + + CommandLine& setThrowOnUnrecognisedTokens( bool shouldThrow = true ) { + m_throwOnUnrecognisedTokens = shouldThrow; + return *this; + } + + OptBuilder operator[]( std::string const& optName ) { + m_options.push_back( Arg() ); + addOptName( m_options.back(), optName ); + OptBuilder builder( &m_options.back() ); + return builder; + } + + ArgBuilder operator[]( int position ) { + m_positionalArgs.insert( std::make_pair( position, Arg() ) ); + if( position > m_highestSpecifiedArgPosition ) + m_highestSpecifiedArgPosition = position; + setPositionalArg( m_positionalArgs[position], position ); + ArgBuilder builder( &m_positionalArgs[position] ); + return builder; + } + + // Invoke this with the _ instance + ArgBuilder operator[]( UnpositionalTag ) { + if( m_floatingArg.get() ) + throw std::logic_error( "Only one unpositional argument can be added" ); + m_floatingArg.reset( new Arg() ); + ArgBuilder builder( m_floatingArg.get() ); + return builder; + } + + template + void bindProcessName( M C::* field ) { + m_boundProcessName = new Detail::BoundDataMember( field ); + } + template + void bindProcessName( void (C::*_unaryMethod)( M ) ) { + m_boundProcessName = new Detail::BoundUnaryMethod( _unaryMethod ); + } + + void optUsage( std::ostream& os, std::size_t indent = 0, std::size_t width = Detail::consoleWidth ) const { + typename std::vector::const_iterator itBegin = m_options.begin(), itEnd = m_options.end(), it; + std::size_t maxWidth = 0; + for( it = itBegin; it != itEnd; ++it ) + maxWidth = (std::max)( maxWidth, it->commands().size() ); + + for( it = itBegin; it != itEnd; ++it ) { + Detail::Text usage( it->commands(), Detail::TextAttributes() + .setWidth( maxWidth+indent ) + .setIndent( indent ) ); + Detail::Text desc( it->description, Detail::TextAttributes() + .setWidth( width - maxWidth - 3 ) ); + + for( std::size_t i = 0; i < (std::max)( usage.size(), desc.size() ); ++i ) { + std::string usageCol = i < usage.size() ? usage[i] : ""; + os << usageCol; + + if( i < desc.size() && !desc[i].empty() ) + os << std::string( indent + 2 + maxWidth - usageCol.size(), ' ' ) + << desc[i]; + os << "\n"; + } + } + } + std::string optUsage() const { + std::ostringstream oss; + optUsage( oss ); + return oss.str(); + } + + void argSynopsis( std::ostream& os ) const { + for( int i = 1; i <= m_highestSpecifiedArgPosition; ++i ) { + if( i > 1 ) + os << " "; + typename std::map::const_iterator it = m_positionalArgs.find( i ); + if( it != m_positionalArgs.end() ) + os << "<" << it->second.placeholder << ">"; + else if( m_floatingArg.get() ) + os << "<" << m_floatingArg->placeholder << ">"; + else + throw std::logic_error( "non consecutive positional arguments with no floating args" ); + } + // !TBD No indication of mandatory args + if( m_floatingArg.get() ) { + if( m_highestSpecifiedArgPosition > 1 ) + os << " "; + os << "[<" << m_floatingArg->placeholder << "> ...]"; + } + } + std::string argSynopsis() const { + std::ostringstream oss; + argSynopsis( oss ); + return oss.str(); + } + + void usage( std::ostream& os, std::string const& procName ) const { + validate(); + os << "usage:\n " << procName << " "; + argSynopsis( os ); + if( !m_options.empty() ) { + os << " [options]\n\nwhere options are: \n"; + optUsage( os, 2 ); + } + os << "\n"; + } + std::string usage( std::string const& procName ) const { + std::ostringstream oss; + usage( oss, procName ); + return oss.str(); + } + + ConfigT parse( int argc, char const* const argv[] ) const { + ConfigT config; + parseInto( argc, argv, config ); + return config; + } + + std::vector parseInto( int argc, char const* argv[], ConfigT& config ) const { + std::string processName = argv[0]; + std::size_t lastSlash = processName.find_last_of( "/\\" ); + if( lastSlash != std::string::npos ) + processName = processName.substr( lastSlash+1 ); + m_boundProcessName.set( config, processName ); + std::vector tokens; + Parser parser; + parser.parseIntoTokens( argc, argv, tokens ); + return populate( tokens, config ); + } + + std::vector populate( std::vector const& tokens, ConfigT& config ) const { + validate(); + std::vector unusedTokens = populateOptions( tokens, config ); + unusedTokens = populateFixedArgs( unusedTokens, config ); + unusedTokens = populateFloatingArgs( unusedTokens, config ); + return unusedTokens; + } + + std::vector populateOptions( std::vector const& tokens, ConfigT& config ) const { + std::vector unusedTokens; + std::vector errors; + for( std::size_t i = 0; i < tokens.size(); ++i ) { + Parser::Token const& token = tokens[i]; + typename std::vector::const_iterator it = m_options.begin(), itEnd = m_options.end(); + for(; it != itEnd; ++it ) { + Arg const& arg = *it; + + try { + if( ( token.type == Parser::Token::ShortOpt && arg.hasShortName( token.data ) ) || + ( token.type == Parser::Token::LongOpt && arg.hasLongName( token.data ) ) ) { + if( arg.takesArg() ) { + if( i == tokens.size()-1 || tokens[i+1].type != Parser::Token::Positional ) + errors.push_back( "Expected argument to option: " + token.data ); + else + arg.boundField.set( config, tokens[++i].data ); + } + else { + arg.boundField.setFlag( config ); + } + break; + } + } + catch( std::exception& ex ) { + errors.push_back( std::string( ex.what() ) + "\n- while parsing: (" + arg.commands() + ")" ); + } + } + if( it == itEnd ) { + if( token.type == Parser::Token::Positional || !m_throwOnUnrecognisedTokens ) + unusedTokens.push_back( token ); + else if( errors.empty() && m_throwOnUnrecognisedTokens ) + errors.push_back( "unrecognised option: " + token.data ); + } + } + if( !errors.empty() ) { + std::ostringstream oss; + for( std::vector::const_iterator it = errors.begin(), itEnd = errors.end(); + it != itEnd; + ++it ) { + if( it != errors.begin() ) + oss << "\n"; + oss << *it; + } + throw std::runtime_error( oss.str() ); + } + return unusedTokens; + } + std::vector populateFixedArgs( std::vector const& tokens, ConfigT& config ) const { + std::vector unusedTokens; + int position = 1; + for( std::size_t i = 0; i < tokens.size(); ++i ) { + Parser::Token const& token = tokens[i]; + typename std::map::const_iterator it = m_positionalArgs.find( position ); + if( it != m_positionalArgs.end() ) + it->second.boundField.set( config, token.data ); + else + unusedTokens.push_back( token ); + if( token.type == Parser::Token::Positional ) + position++; + } + return unusedTokens; + } + std::vector populateFloatingArgs( std::vector const& tokens, ConfigT& config ) const { + if( !m_floatingArg.get() ) + return tokens; + std::vector unusedTokens; + for( std::size_t i = 0; i < tokens.size(); ++i ) { + Parser::Token const& token = tokens[i]; + if( token.type == Parser::Token::Positional ) + m_floatingArg->boundField.set( config, token.data ); + else + unusedTokens.push_back( token ); + } + return unusedTokens; + } + + void validate() const + { + if( m_options.empty() && m_positionalArgs.empty() && !m_floatingArg.get() ) + throw std::logic_error( "No options or arguments specified" ); + + for( typename std::vector::const_iterator it = m_options.begin(), + itEnd = m_options.end(); + it != itEnd; ++it ) + it->validate(); + } + + private: + Detail::BoundArgFunction m_boundProcessName; + std::vector m_options; + std::map m_positionalArgs; + ArgAutoPtr m_floatingArg; + int m_highestSpecifiedArgPosition; + bool m_throwOnUnrecognisedTokens; + }; + +} // end namespace Clara + +STITCH_CLARA_CLOSE_NAMESPACE +#undef STITCH_CLARA_OPEN_NAMESPACE +#undef STITCH_CLARA_CLOSE_NAMESPACE + +#endif // TWOBLUECUBES_CLARA_H_INCLUDED +#undef STITCH_CLARA_OPEN_NAMESPACE + +// Restore Clara's value for console width, if present +#ifdef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH +#define CLARA_CONFIG_CONSOLE_WIDTH CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH +#undef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH +#endif + +#include + +namespace Catch { + + inline void abortAfterFirst( ConfigData& config ) { config.abortAfter = 1; } + inline void abortAfterX( ConfigData& config, int x ) { + if( x < 1 ) + throw std::runtime_error( "Value after -x or --abortAfter must be greater than zero" ); + config.abortAfter = x; + } + inline void addTestOrTags( ConfigData& config, std::string const& _testSpec ) { config.testsOrTags.push_back( _testSpec ); } + inline void addReporterName( ConfigData& config, std::string const& _reporterName ) { config.reporterNames.push_back( _reporterName ); } + + inline void addWarning( ConfigData& config, std::string const& _warning ) { + if( _warning == "NoAssertions" ) + config.warnings = static_cast( config.warnings | WarnAbout::NoAssertions ); + else + throw std::runtime_error( "Unrecognised warning: '" + _warning + "'" ); + } + inline void setOrder( ConfigData& config, std::string const& order ) { + if( startsWith( "declared", order ) ) + config.runOrder = RunTests::InDeclarationOrder; + else if( startsWith( "lexical", order ) ) + config.runOrder = RunTests::InLexicographicalOrder; + else if( startsWith( "random", order ) ) + config.runOrder = RunTests::InRandomOrder; + else + throw std::runtime_error( "Unrecognised ordering: '" + order + "'" ); + } + inline void setRngSeed( ConfigData& config, std::string const& seed ) { + if( seed == "time" ) { + config.rngSeed = static_cast( std::time(0) ); + } + else { + std::stringstream ss; + ss << seed; + ss >> config.rngSeed; + if( ss.fail() ) + throw std::runtime_error( "Argment to --rng-seed should be the word 'time' or a number" ); + } + } + inline void setVerbosity( ConfigData& config, int level ) { + // !TBD: accept strings? + config.verbosity = static_cast( level ); + } + inline void setShowDurations( ConfigData& config, bool _showDurations ) { + config.showDurations = _showDurations + ? ShowDurations::Always + : ShowDurations::Never; + } + inline void setUseColour( ConfigData& config, std::string const& value ) { + std::string mode = toLower( value ); + + if( mode == "yes" ) + config.useColour = UseColour::Yes; + else if( mode == "no" ) + config.useColour = UseColour::No; + else if( mode == "auto" ) + config.useColour = UseColour::Auto; + else + throw std::runtime_error( "colour mode must be one of: auto, yes or no" ); + } + inline void forceColour( ConfigData& config ) { + config.useColour = UseColour::Yes; + } + inline void loadTestNamesFromFile( ConfigData& config, std::string const& _filename ) { + std::ifstream f( _filename.c_str() ); + if( !f.is_open() ) + throw std::domain_error( "Unable to load input file: " + _filename ); + + std::string line; + while( std::getline( f, line ) ) { + line = trim(line); + if( !line.empty() && !startsWith( line, "#" ) ) + addTestOrTags( config, "\"" + line + "\"," ); + } + } + + inline Clara::CommandLine makeCommandLineParser() { + + using namespace Clara; + CommandLine cli; + + cli.bindProcessName( &ConfigData::processName ); + + cli["-?"]["-h"]["--help"] + .describe( "display usage information" ) + .bind( &ConfigData::showHelp ); + + cli["-l"]["--list-tests"] + .describe( "list all/matching test cases" ) + .bind( &ConfigData::listTests ); + + cli["-t"]["--list-tags"] + .describe( "list all/matching tags" ) + .bind( &ConfigData::listTags ); + + cli["-s"]["--success"] + .describe( "include successful tests in output" ) + .bind( &ConfigData::showSuccessfulTests ); + + cli["-b"]["--break"] + .describe( "break into debugger on failure" ) + .bind( &ConfigData::shouldDebugBreak ); + + cli["-e"]["--nothrow"] + .describe( "skip exception tests" ) + .bind( &ConfigData::noThrow ); + + cli["-i"]["--invisibles"] + .describe( "show invisibles (tabs, newlines)" ) + .bind( &ConfigData::showInvisibles ); + + cli["-o"]["--out"] + .describe( "output filename" ) + .bind( &ConfigData::outputFilename, "filename" ); + + cli["-r"]["--reporter"] +// .placeholder( "name[:filename]" ) + .describe( "reporter to use (defaults to console)" ) + .bind( &addReporterName, "name" ); + + cli["-n"]["--name"] + .describe( "suite name" ) + .bind( &ConfigData::name, "name" ); + + cli["-a"]["--abort"] + .describe( "abort at first failure" ) + .bind( &abortAfterFirst ); + + cli["-x"]["--abortx"] + .describe( "abort after x failures" ) + .bind( &abortAfterX, "no. failures" ); + + cli["-w"]["--warn"] + .describe( "enable warnings" ) + .bind( &addWarning, "warning name" ); + +// - needs updating if reinstated +// cli.into( &setVerbosity ) +// .describe( "level of verbosity (0=no output)" ) +// .shortOpt( "v") +// .longOpt( "verbosity" ) +// .placeholder( "level" ); + + cli[_] + .describe( "which test or tests to use" ) + .bind( &addTestOrTags, "test name, pattern or tags" ); + + cli["-d"]["--durations"] + .describe( "show test durations" ) + .bind( &setShowDurations, "yes|no" ); + + cli["-f"]["--input-file"] + .describe( "load test names to run from a file" ) + .bind( &loadTestNamesFromFile, "filename" ); + + cli["-#"]["--filenames-as-tags"] + .describe( "adds a tag for the filename" ) + .bind( &ConfigData::filenamesAsTags ); + + // Less common commands which don't have a short form + cli["--list-test-names-only"] + .describe( "list all/matching test cases names only" ) + .bind( &ConfigData::listTestNamesOnly ); + + cli["--list-reporters"] + .describe( "list all reporters" ) + .bind( &ConfigData::listReporters ); + + cli["--order"] + .describe( "test case order (defaults to decl)" ) + .bind( &setOrder, "decl|lex|rand" ); + + cli["--rng-seed"] + .describe( "set a specific seed for random numbers" ) + .bind( &setRngSeed, "'time'|number" ); + + cli["--force-colour"] + .describe( "force colourised output (deprecated)" ) + .bind( &forceColour ); + + cli["--use-colour"] + .describe( "should output be colourised" ) + .bind( &setUseColour, "yes|no" ); + + return cli; + } + +} // end namespace Catch + +// #included from: internal/catch_list.hpp +#define TWOBLUECUBES_CATCH_LIST_HPP_INCLUDED + +// #included from: catch_text.h +#define TWOBLUECUBES_CATCH_TEXT_H_INCLUDED + +#define TBC_TEXT_FORMAT_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH + +#define CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE Catch +// #included from: ../external/tbc_text_format.h +// Only use header guard if we are not using an outer namespace +#ifndef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE +# ifdef TWOBLUECUBES_TEXT_FORMAT_H_INCLUDED +# ifndef TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED +# define TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED +# endif +# else +# define TWOBLUECUBES_TEXT_FORMAT_H_INCLUDED +# endif +#endif +#ifndef TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED +#include +#include +#include + +// Use optional outer namespace +#ifdef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE +namespace CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE { +#endif + +namespace Tbc { + +#ifdef TBC_TEXT_FORMAT_CONSOLE_WIDTH + const unsigned int consoleWidth = TBC_TEXT_FORMAT_CONSOLE_WIDTH; +#else + const unsigned int consoleWidth = 80; +#endif + + struct TextAttributes { + TextAttributes() + : initialIndent( std::string::npos ), + indent( 0 ), + width( consoleWidth-1 ), + tabChar( '\t' ) + {} + + TextAttributes& setInitialIndent( std::size_t _value ) { initialIndent = _value; return *this; } + TextAttributes& setIndent( std::size_t _value ) { indent = _value; return *this; } + TextAttributes& setWidth( std::size_t _value ) { width = _value; return *this; } + TextAttributes& setTabChar( char _value ) { tabChar = _value; return *this; } + + std::size_t initialIndent; // indent of first line, or npos + std::size_t indent; // indent of subsequent lines, or all if initialIndent is npos + std::size_t width; // maximum width of text, including indent. Longer text will wrap + char tabChar; // If this char is seen the indent is changed to current pos + }; + + class Text { + public: + Text( std::string const& _str, TextAttributes const& _attr = TextAttributes() ) + : attr( _attr ) + { + std::string wrappableChars = " [({.,/|\\-"; + std::size_t indent = _attr.initialIndent != std::string::npos + ? _attr.initialIndent + : _attr.indent; + std::string remainder = _str; + + while( !remainder.empty() ) { + if( lines.size() >= 1000 ) { + lines.push_back( "... message truncated due to excessive size" ); + return; + } + std::size_t tabPos = std::string::npos; + std::size_t width = (std::min)( remainder.size(), _attr.width - indent ); + std::size_t pos = remainder.find_first_of( '\n' ); + if( pos <= width ) { + width = pos; + } + pos = remainder.find_last_of( _attr.tabChar, width ); + if( pos != std::string::npos ) { + tabPos = pos; + if( remainder[width] == '\n' ) + width--; + remainder = remainder.substr( 0, tabPos ) + remainder.substr( tabPos+1 ); + } + + if( width == remainder.size() ) { + spliceLine( indent, remainder, width ); + } + else if( remainder[width] == '\n' ) { + spliceLine( indent, remainder, width ); + if( width <= 1 || remainder.size() != 1 ) + remainder = remainder.substr( 1 ); + indent = _attr.indent; + } + else { + pos = remainder.find_last_of( wrappableChars, width ); + if( pos != std::string::npos && pos > 0 ) { + spliceLine( indent, remainder, pos ); + if( remainder[0] == ' ' ) + remainder = remainder.substr( 1 ); + } + else { + spliceLine( indent, remainder, width-1 ); + lines.back() += "-"; + } + if( lines.size() == 1 ) + indent = _attr.indent; + if( tabPos != std::string::npos ) + indent += tabPos; + } + } + } + + void spliceLine( std::size_t _indent, std::string& _remainder, std::size_t _pos ) { + lines.push_back( std::string( _indent, ' ' ) + _remainder.substr( 0, _pos ) ); + _remainder = _remainder.substr( _pos ); + } + + typedef std::vector::const_iterator const_iterator; + + const_iterator begin() const { return lines.begin(); } + const_iterator end() const { return lines.end(); } + std::string const& last() const { return lines.back(); } + std::size_t size() const { return lines.size(); } + std::string const& operator[]( std::size_t _index ) const { return lines[_index]; } + std::string toString() const { + std::ostringstream oss; + oss << *this; + return oss.str(); + } + + inline friend std::ostream& operator << ( std::ostream& _stream, Text const& _text ) { + for( Text::const_iterator it = _text.begin(), itEnd = _text.end(); + it != itEnd; ++it ) { + if( it != _text.begin() ) + _stream << "\n"; + _stream << *it; + } + return _stream; + } + + private: + std::string str; + TextAttributes attr; + std::vector lines; + }; + +} // end namespace Tbc + +#ifdef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE +} // end outer namespace +#endif + +#endif // TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED +#undef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE + +namespace Catch { + using Tbc::Text; + using Tbc::TextAttributes; +} + +// #included from: catch_console_colour.hpp +#define TWOBLUECUBES_CATCH_CONSOLE_COLOUR_HPP_INCLUDED + +namespace Catch { + + struct Colour { + enum Code { + None = 0, + + White, + Red, + Green, + Blue, + Cyan, + Yellow, + Grey, + + Bright = 0x10, + + BrightRed = Bright | Red, + BrightGreen = Bright | Green, + LightGrey = Bright | Grey, + BrightWhite = Bright | White, + + // By intention + FileName = LightGrey, + Warning = Yellow, + ResultError = BrightRed, + ResultSuccess = BrightGreen, + ResultExpectedFailure = Warning, + + Error = BrightRed, + Success = Green, + + OriginalExpression = Cyan, + ReconstructedExpression = Yellow, + + SecondaryText = LightGrey, + Headers = White + }; + + // Use constructed object for RAII guard + Colour( Code _colourCode ); + Colour( Colour const& other ); + ~Colour(); + + // Use static method for one-shot changes + static void use( Code _colourCode ); + + private: + bool m_moved; + }; + + inline std::ostream& operator << ( std::ostream& os, Colour const& ) { return os; } + +} // end namespace Catch + +// #included from: catch_interfaces_reporter.h +#define TWOBLUECUBES_CATCH_INTERFACES_REPORTER_H_INCLUDED + +#include +#include +#include +#include + +namespace Catch +{ + struct ReporterConfig { + explicit ReporterConfig( Ptr const& _fullConfig ) + : m_stream( &_fullConfig->stream() ), m_fullConfig( _fullConfig ) {} + + ReporterConfig( Ptr const& _fullConfig, std::ostream& _stream ) + : m_stream( &_stream ), m_fullConfig( _fullConfig ) {} + + std::ostream& stream() const { return *m_stream; } + Ptr fullConfig() const { return m_fullConfig; } + + private: + std::ostream* m_stream; + Ptr m_fullConfig; + }; + + struct ReporterPreferences { + ReporterPreferences() + : shouldRedirectStdOut( false ) + {} + + bool shouldRedirectStdOut; + }; + + template + struct LazyStat : Option { + LazyStat() : used( false ) {} + LazyStat& operator=( T const& _value ) { + Option::operator=( _value ); + used = false; + return *this; + } + void reset() { + Option::reset(); + used = false; + } + bool used; + }; + + struct TestRunInfo { + TestRunInfo( std::string const& _name ) : name( _name ) {} + std::string name; + }; + struct GroupInfo { + GroupInfo( std::string const& _name, + std::size_t _groupIndex, + std::size_t _groupsCount ) + : name( _name ), + groupIndex( _groupIndex ), + groupsCounts( _groupsCount ) + {} + + std::string name; + std::size_t groupIndex; + std::size_t groupsCounts; + }; + + struct AssertionStats { + AssertionStats( AssertionResult const& _assertionResult, + std::vector const& _infoMessages, + Totals const& _totals ) + : assertionResult( _assertionResult ), + infoMessages( _infoMessages ), + totals( _totals ) + { + if( assertionResult.hasMessage() ) { + // Copy message into messages list. + // !TBD This should have been done earlier, somewhere + MessageBuilder builder( assertionResult.getTestMacroName(), assertionResult.getSourceInfo(), assertionResult.getResultType() ); + builder << assertionResult.getMessage(); + builder.m_info.message = builder.m_stream.str(); + + infoMessages.push_back( builder.m_info ); + } + } + virtual ~AssertionStats(); + +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + AssertionStats( AssertionStats const& ) = default; + AssertionStats( AssertionStats && ) = default; + AssertionStats& operator = ( AssertionStats const& ) = default; + AssertionStats& operator = ( AssertionStats && ) = default; +# endif + + AssertionResult assertionResult; + std::vector infoMessages; + Totals totals; + }; + + struct SectionStats { + SectionStats( SectionInfo const& _sectionInfo, + Counts const& _assertions, + double _durationInSeconds, + bool _missingAssertions ) + : sectionInfo( _sectionInfo ), + assertions( _assertions ), + durationInSeconds( _durationInSeconds ), + missingAssertions( _missingAssertions ) + {} + virtual ~SectionStats(); +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + SectionStats( SectionStats const& ) = default; + SectionStats( SectionStats && ) = default; + SectionStats& operator = ( SectionStats const& ) = default; + SectionStats& operator = ( SectionStats && ) = default; +# endif + + SectionInfo sectionInfo; + Counts assertions; + double durationInSeconds; + bool missingAssertions; + }; + + struct TestCaseStats { + TestCaseStats( TestCaseInfo const& _testInfo, + Totals const& _totals, + std::string const& _stdOut, + std::string const& _stdErr, + bool _aborting ) + : testInfo( _testInfo ), + totals( _totals ), + stdOut( _stdOut ), + stdErr( _stdErr ), + aborting( _aborting ) + {} + virtual ~TestCaseStats(); + +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + TestCaseStats( TestCaseStats const& ) = default; + TestCaseStats( TestCaseStats && ) = default; + TestCaseStats& operator = ( TestCaseStats const& ) = default; + TestCaseStats& operator = ( TestCaseStats && ) = default; +# endif + + TestCaseInfo testInfo; + Totals totals; + std::string stdOut; + std::string stdErr; + bool aborting; + }; + + struct TestGroupStats { + TestGroupStats( GroupInfo const& _groupInfo, + Totals const& _totals, + bool _aborting ) + : groupInfo( _groupInfo ), + totals( _totals ), + aborting( _aborting ) + {} + TestGroupStats( GroupInfo const& _groupInfo ) + : groupInfo( _groupInfo ), + aborting( false ) + {} + virtual ~TestGroupStats(); + +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + TestGroupStats( TestGroupStats const& ) = default; + TestGroupStats( TestGroupStats && ) = default; + TestGroupStats& operator = ( TestGroupStats const& ) = default; + TestGroupStats& operator = ( TestGroupStats && ) = default; +# endif + + GroupInfo groupInfo; + Totals totals; + bool aborting; + }; + + struct TestRunStats { + TestRunStats( TestRunInfo const& _runInfo, + Totals const& _totals, + bool _aborting ) + : runInfo( _runInfo ), + totals( _totals ), + aborting( _aborting ) + {} + virtual ~TestRunStats(); + +# ifndef CATCH_CONFIG_CPP11_GENERATED_METHODS + TestRunStats( TestRunStats const& _other ) + : runInfo( _other.runInfo ), + totals( _other.totals ), + aborting( _other.aborting ) + {} +# else + TestRunStats( TestRunStats const& ) = default; + TestRunStats( TestRunStats && ) = default; + TestRunStats& operator = ( TestRunStats const& ) = default; + TestRunStats& operator = ( TestRunStats && ) = default; +# endif + + TestRunInfo runInfo; + Totals totals; + bool aborting; + }; + + struct IStreamingReporter : IShared { + virtual ~IStreamingReporter(); + + // Implementing class must also provide the following static method: + // static std::string getDescription(); + + virtual ReporterPreferences getPreferences() const = 0; + + virtual void noMatchingTestCases( std::string const& spec ) = 0; + + virtual void testRunStarting( TestRunInfo const& testRunInfo ) = 0; + virtual void testGroupStarting( GroupInfo const& groupInfo ) = 0; + + virtual void testCaseStarting( TestCaseInfo const& testInfo ) = 0; + virtual void sectionStarting( SectionInfo const& sectionInfo ) = 0; + + virtual void assertionStarting( AssertionInfo const& assertionInfo ) = 0; + + // The return value indicates if the messages buffer should be cleared: + virtual bool assertionEnded( AssertionStats const& assertionStats ) = 0; + + virtual void sectionEnded( SectionStats const& sectionStats ) = 0; + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) = 0; + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) = 0; + virtual void testRunEnded( TestRunStats const& testRunStats ) = 0; + + virtual void skipTest( TestCaseInfo const& testInfo ) = 0; + }; + + struct IReporterFactory : IShared { + virtual ~IReporterFactory(); + virtual IStreamingReporter* create( ReporterConfig const& config ) const = 0; + virtual std::string getDescription() const = 0; + }; + + struct IReporterRegistry { + typedef std::map > FactoryMap; + typedef std::vector > Listeners; + + virtual ~IReporterRegistry(); + virtual IStreamingReporter* create( std::string const& name, Ptr const& config ) const = 0; + virtual FactoryMap const& getFactories() const = 0; + virtual Listeners const& getListeners() const = 0; + }; + + Ptr addReporter( Ptr const& existingReporter, Ptr const& additionalReporter ); + +} + +#include +#include + +namespace Catch { + + inline std::size_t listTests( Config const& config ) { + + TestSpec testSpec = config.testSpec(); + if( config.testSpec().hasFilters() ) + Catch::cout() << "Matching test cases:\n"; + else { + Catch::cout() << "All available test cases:\n"; + testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); + } + + std::size_t matchedTests = 0; + TextAttributes nameAttr, tagsAttr; + nameAttr.setInitialIndent( 2 ).setIndent( 4 ); + tagsAttr.setIndent( 6 ); + + std::vector matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); + for( std::vector::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); + it != itEnd; + ++it ) { + matchedTests++; + TestCaseInfo const& testCaseInfo = it->getTestCaseInfo(); + Colour::Code colour = testCaseInfo.isHidden() + ? Colour::SecondaryText + : Colour::None; + Colour colourGuard( colour ); + + Catch::cout() << Text( testCaseInfo.name, nameAttr ) << std::endl; + if( !testCaseInfo.tags.empty() ) + Catch::cout() << Text( testCaseInfo.tagsAsString, tagsAttr ) << std::endl; + } + + if( !config.testSpec().hasFilters() ) + Catch::cout() << pluralise( matchedTests, "test case" ) << "\n" << std::endl; + else + Catch::cout() << pluralise( matchedTests, "matching test case" ) << "\n" << std::endl; + return matchedTests; + } + + inline std::size_t listTestsNamesOnly( Config const& config ) { + TestSpec testSpec = config.testSpec(); + if( !config.testSpec().hasFilters() ) + testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); + std::size_t matchedTests = 0; + std::vector matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); + for( std::vector::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); + it != itEnd; + ++it ) { + matchedTests++; + TestCaseInfo const& testCaseInfo = it->getTestCaseInfo(); + Catch::cout() << testCaseInfo.name << std::endl; + } + return matchedTests; + } + + struct TagInfo { + TagInfo() : count ( 0 ) {} + void add( std::string const& spelling ) { + ++count; + spellings.insert( spelling ); + } + std::string all() const { + std::string out; + for( std::set::const_iterator it = spellings.begin(), itEnd = spellings.end(); + it != itEnd; + ++it ) + out += "[" + *it + "]"; + return out; + } + std::set spellings; + std::size_t count; + }; + + inline std::size_t listTags( Config const& config ) { + TestSpec testSpec = config.testSpec(); + if( config.testSpec().hasFilters() ) + Catch::cout() << "Tags for matching test cases:\n"; + else { + Catch::cout() << "All available tags:\n"; + testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); + } + + std::map tagCounts; + + std::vector matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); + for( std::vector::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); + it != itEnd; + ++it ) { + for( std::set::const_iterator tagIt = it->getTestCaseInfo().tags.begin(), + tagItEnd = it->getTestCaseInfo().tags.end(); + tagIt != tagItEnd; + ++tagIt ) { + std::string tagName = *tagIt; + std::string lcaseTagName = toLower( tagName ); + std::map::iterator countIt = tagCounts.find( lcaseTagName ); + if( countIt == tagCounts.end() ) + countIt = tagCounts.insert( std::make_pair( lcaseTagName, TagInfo() ) ).first; + countIt->second.add( tagName ); + } + } + + for( std::map::const_iterator countIt = tagCounts.begin(), + countItEnd = tagCounts.end(); + countIt != countItEnd; + ++countIt ) { + std::ostringstream oss; + oss << " " << std::setw(2) << countIt->second.count << " "; + Text wrapper( countIt->second.all(), TextAttributes() + .setInitialIndent( 0 ) + .setIndent( oss.str().size() ) + .setWidth( CATCH_CONFIG_CONSOLE_WIDTH-10 ) ); + Catch::cout() << oss.str() << wrapper << "\n"; + } + Catch::cout() << pluralise( tagCounts.size(), "tag" ) << "\n" << std::endl; + return tagCounts.size(); + } + + inline std::size_t listReporters( Config const& /*config*/ ) { + Catch::cout() << "Available reporters:\n"; + IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories(); + IReporterRegistry::FactoryMap::const_iterator itBegin = factories.begin(), itEnd = factories.end(), it; + std::size_t maxNameLen = 0; + for(it = itBegin; it != itEnd; ++it ) + maxNameLen = (std::max)( maxNameLen, it->first.size() ); + + for(it = itBegin; it != itEnd; ++it ) { + Text wrapper( it->second->getDescription(), TextAttributes() + .setInitialIndent( 0 ) + .setIndent( 7+maxNameLen ) + .setWidth( CATCH_CONFIG_CONSOLE_WIDTH - maxNameLen-8 ) ); + Catch::cout() << " " + << it->first + << ":" + << std::string( maxNameLen - it->first.size() + 2, ' ' ) + << wrapper << "\n"; + } + Catch::cout() << std::endl; + return factories.size(); + } + + inline Option list( Config const& config ) { + Option listedCount; + if( config.listTests() ) + listedCount = listedCount.valueOr(0) + listTests( config ); + if( config.listTestNamesOnly() ) + listedCount = listedCount.valueOr(0) + listTestsNamesOnly( config ); + if( config.listTags() ) + listedCount = listedCount.valueOr(0) + listTags( config ); + if( config.listReporters() ) + listedCount = listedCount.valueOr(0) + listReporters( config ); + return listedCount; + } + +} // end namespace Catch + +// #included from: internal/catch_run_context.hpp +#define TWOBLUECUBES_CATCH_RUNNER_IMPL_HPP_INCLUDED + +// #included from: catch_test_case_tracker.hpp +#define TWOBLUECUBES_CATCH_TEST_CASE_TRACKER_HPP_INCLUDED + +#include +#include +#include +#include + +namespace Catch { +namespace TestCaseTracking { + + struct ITracker : SharedImpl<> { + virtual ~ITracker(); + + // static queries + virtual std::string name() const = 0; + + // dynamic queries + virtual bool isComplete() const = 0; // Successfully completed or failed + virtual bool isSuccessfullyCompleted() const = 0; + virtual bool isOpen() const = 0; // Started but not complete + virtual bool hasChildren() const = 0; + + virtual ITracker& parent() = 0; + + // actions + virtual void close() = 0; // Successfully complete + virtual void fail() = 0; + virtual void markAsNeedingAnotherRun() = 0; + + virtual void addChild( Ptr const& child ) = 0; + virtual ITracker* findChild( std::string const& name ) = 0; + virtual void openChild() = 0; + }; + + class TrackerContext { + + enum RunState { + NotStarted, + Executing, + CompletedCycle + }; + + Ptr m_rootTracker; + ITracker* m_currentTracker; + RunState m_runState; + + public: + + static TrackerContext& instance() { + static TrackerContext s_instance; + return s_instance; + } + + TrackerContext() + : m_currentTracker( CATCH_NULL ), + m_runState( NotStarted ) + {} + + ITracker& startRun(); + + void endRun() { + m_rootTracker.reset(); + m_currentTracker = CATCH_NULL; + m_runState = NotStarted; + } + + void startCycle() { + m_currentTracker = m_rootTracker.get(); + m_runState = Executing; + } + void completeCycle() { + m_runState = CompletedCycle; + } + + bool completedCycle() const { + return m_runState == CompletedCycle; + } + ITracker& currentTracker() { + return *m_currentTracker; + } + void setCurrentTracker( ITracker* tracker ) { + m_currentTracker = tracker; + } + }; + + class TrackerBase : public ITracker { + protected: + enum CycleState { + NotStarted, + Executing, + ExecutingChildren, + NeedsAnotherRun, + CompletedSuccessfully, + Failed + }; + class TrackerHasName { + std::string m_name; + public: + TrackerHasName( std::string const& name ) : m_name( name ) {} + bool operator ()( Ptr const& tracker ) { + return tracker->name() == m_name; + } + }; + typedef std::vector > Children; + std::string m_name; + TrackerContext& m_ctx; + ITracker* m_parent; + Children m_children; + CycleState m_runState; + public: + TrackerBase( std::string const& name, TrackerContext& ctx, ITracker* parent ) + : m_name( name ), + m_ctx( ctx ), + m_parent( parent ), + m_runState( NotStarted ) + {} + virtual ~TrackerBase(); + + virtual std::string name() const CATCH_OVERRIDE { + return m_name; + } + virtual bool isComplete() const CATCH_OVERRIDE { + return m_runState == CompletedSuccessfully || m_runState == Failed; + } + virtual bool isSuccessfullyCompleted() const CATCH_OVERRIDE { + return m_runState == CompletedSuccessfully; + } + virtual bool isOpen() const CATCH_OVERRIDE { + return m_runState != NotStarted && !isComplete(); + } + virtual bool hasChildren() const CATCH_OVERRIDE { + return !m_children.empty(); + } + + virtual void addChild( Ptr const& child ) CATCH_OVERRIDE { + m_children.push_back( child ); + } + + virtual ITracker* findChild( std::string const& name ) CATCH_OVERRIDE { + Children::const_iterator it = std::find_if( m_children.begin(), m_children.end(), TrackerHasName( name ) ); + return( it != m_children.end() ) + ? it->get() + : CATCH_NULL; + } + virtual ITracker& parent() CATCH_OVERRIDE { + assert( m_parent ); // Should always be non-null except for root + return *m_parent; + } + + virtual void openChild() CATCH_OVERRIDE { + if( m_runState != ExecutingChildren ) { + m_runState = ExecutingChildren; + if( m_parent ) + m_parent->openChild(); + } + } + void open() { + m_runState = Executing; + moveToThis(); + if( m_parent ) + m_parent->openChild(); + } + + virtual void close() CATCH_OVERRIDE { + + // Close any still open children (e.g. generators) + while( &m_ctx.currentTracker() != this ) + m_ctx.currentTracker().close(); + + switch( m_runState ) { + case NotStarted: + case CompletedSuccessfully: + case Failed: + throw std::logic_error( "Illogical state" ); + + case NeedsAnotherRun: + break;; + + case Executing: + m_runState = CompletedSuccessfully; + break; + case ExecutingChildren: + if( m_children.empty() || m_children.back()->isComplete() ) + m_runState = CompletedSuccessfully; + break; + + default: + throw std::logic_error( "Unexpected state" ); + } + moveToParent(); + m_ctx.completeCycle(); + } + virtual void fail() CATCH_OVERRIDE { + m_runState = Failed; + if( m_parent ) + m_parent->markAsNeedingAnotherRun(); + moveToParent(); + m_ctx.completeCycle(); + } + virtual void markAsNeedingAnotherRun() CATCH_OVERRIDE { + m_runState = NeedsAnotherRun; + } + private: + void moveToParent() { + assert( m_parent ); + m_ctx.setCurrentTracker( m_parent ); + } + void moveToThis() { + m_ctx.setCurrentTracker( this ); + } + }; + + class SectionTracker : public TrackerBase { + public: + SectionTracker( std::string const& name, TrackerContext& ctx, ITracker* parent ) + : TrackerBase( name, ctx, parent ) + {} + virtual ~SectionTracker(); + + static SectionTracker& acquire( TrackerContext& ctx, std::string const& name ) { + SectionTracker* section = CATCH_NULL; + + ITracker& currentTracker = ctx.currentTracker(); + if( ITracker* childTracker = currentTracker.findChild( name ) ) { + section = dynamic_cast( childTracker ); + assert( section ); + } + else { + section = new SectionTracker( name, ctx, ¤tTracker ); + currentTracker.addChild( section ); + } + if( !ctx.completedCycle() && !section->isComplete() ) { + + section->open(); + } + return *section; + } + }; + + class IndexTracker : public TrackerBase { + int m_size; + int m_index; + public: + IndexTracker( std::string const& name, TrackerContext& ctx, ITracker* parent, int size ) + : TrackerBase( name, ctx, parent ), + m_size( size ), + m_index( -1 ) + {} + virtual ~IndexTracker(); + + static IndexTracker& acquire( TrackerContext& ctx, std::string const& name, int size ) { + IndexTracker* tracker = CATCH_NULL; + + ITracker& currentTracker = ctx.currentTracker(); + if( ITracker* childTracker = currentTracker.findChild( name ) ) { + tracker = dynamic_cast( childTracker ); + assert( tracker ); + } + else { + tracker = new IndexTracker( name, ctx, ¤tTracker, size ); + currentTracker.addChild( tracker ); + } + + if( !ctx.completedCycle() && !tracker->isComplete() ) { + if( tracker->m_runState != ExecutingChildren && tracker->m_runState != NeedsAnotherRun ) + tracker->moveNext(); + tracker->open(); + } + + return *tracker; + } + + int index() const { return m_index; } + + void moveNext() { + m_index++; + m_children.clear(); + } + + virtual void close() CATCH_OVERRIDE { + TrackerBase::close(); + if( m_runState == CompletedSuccessfully && m_index < m_size-1 ) + m_runState = Executing; + } + }; + + inline ITracker& TrackerContext::startRun() { + m_rootTracker = new SectionTracker( "{root}", *this, CATCH_NULL ); + m_currentTracker = CATCH_NULL; + m_runState = Executing; + return *m_rootTracker; + } + +} // namespace TestCaseTracking + +using TestCaseTracking::ITracker; +using TestCaseTracking::TrackerContext; +using TestCaseTracking::SectionTracker; +using TestCaseTracking::IndexTracker; + +} // namespace Catch + +// #included from: catch_fatal_condition.hpp +#define TWOBLUECUBES_CATCH_FATAL_CONDITION_H_INCLUDED + +namespace Catch { + + // Report the error condition then exit the process + inline void fatal( std::string const& message, int exitCode ) { + IContext& context = Catch::getCurrentContext(); + IResultCapture* resultCapture = context.getResultCapture(); + resultCapture->handleFatalErrorCondition( message ); + + if( Catch::alwaysTrue() ) // avoids "no return" warnings + exit( exitCode ); + } + +} // namespace Catch + +#if defined ( CATCH_PLATFORM_WINDOWS ) ///////////////////////////////////////// + +namespace Catch { + + struct FatalConditionHandler { + void reset() {} + }; + +} // namespace Catch + +#else // Not Windows - assumed to be POSIX compatible ////////////////////////// + +#include + +namespace Catch { + + struct SignalDefs { int id; const char* name; }; + extern SignalDefs signalDefs[]; + SignalDefs signalDefs[] = { + { SIGINT, "SIGINT - Terminal interrupt signal" }, + { SIGILL, "SIGILL - Illegal instruction signal" }, + { SIGFPE, "SIGFPE - Floating point error signal" }, + { SIGSEGV, "SIGSEGV - Segmentation violation signal" }, + { SIGTERM, "SIGTERM - Termination request signal" }, + { SIGABRT, "SIGABRT - Abort (abnormal termination) signal" } + }; + + struct FatalConditionHandler { + + static void handleSignal( int sig ) { + for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) + if( sig == signalDefs[i].id ) + fatal( signalDefs[i].name, -sig ); + fatal( "", -sig ); + } + + FatalConditionHandler() : m_isSet( true ) { + for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) + signal( signalDefs[i].id, handleSignal ); + } + ~FatalConditionHandler() { + reset(); + } + void reset() { + if( m_isSet ) { + for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) + signal( signalDefs[i].id, SIG_DFL ); + m_isSet = false; + } + } + + bool m_isSet; + }; + +} // namespace Catch + +#endif // not Windows + +#include +#include + +namespace Catch { + + class StreamRedirect { + + public: + StreamRedirect( std::ostream& stream, std::string& targetString ) + : m_stream( stream ), + m_prevBuf( stream.rdbuf() ), + m_targetString( targetString ) + { + stream.rdbuf( m_oss.rdbuf() ); + } + + ~StreamRedirect() { + m_targetString += m_oss.str(); + m_stream.rdbuf( m_prevBuf ); + } + + private: + std::ostream& m_stream; + std::streambuf* m_prevBuf; + std::ostringstream m_oss; + std::string& m_targetString; + }; + + /////////////////////////////////////////////////////////////////////////// + + class RunContext : public IResultCapture, public IRunner { + + RunContext( RunContext const& ); + void operator =( RunContext const& ); + + public: + + explicit RunContext( Ptr const& _config, Ptr const& reporter ) + : m_runInfo( _config->name() ), + m_context( getCurrentMutableContext() ), + m_activeTestCase( CATCH_NULL ), + m_config( _config ), + m_reporter( reporter ) + { + m_context.setRunner( this ); + m_context.setConfig( m_config ); + m_context.setResultCapture( this ); + m_reporter->testRunStarting( m_runInfo ); + } + + virtual ~RunContext() { + m_reporter->testRunEnded( TestRunStats( m_runInfo, m_totals, aborting() ) ); + } + + void testGroupStarting( std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount ) { + m_reporter->testGroupStarting( GroupInfo( testSpec, groupIndex, groupsCount ) ); + } + void testGroupEnded( std::string const& testSpec, Totals const& totals, std::size_t groupIndex, std::size_t groupsCount ) { + m_reporter->testGroupEnded( TestGroupStats( GroupInfo( testSpec, groupIndex, groupsCount ), totals, aborting() ) ); + } + + Totals runTest( TestCase const& testCase ) { + Totals prevTotals = m_totals; + + std::string redirectedCout; + std::string redirectedCerr; + + TestCaseInfo testInfo = testCase.getTestCaseInfo(); + + m_reporter->testCaseStarting( testInfo ); + + m_activeTestCase = &testCase; + + do { + m_trackerContext.startRun(); + do { + m_trackerContext.startCycle(); + m_testCaseTracker = &SectionTracker::acquire( m_trackerContext, testInfo.name ); + runCurrentTest( redirectedCout, redirectedCerr ); + } + while( !m_testCaseTracker->isSuccessfullyCompleted() && !aborting() ); + } + // !TBD: deprecated - this will be replaced by indexed trackers + while( getCurrentContext().advanceGeneratorsForCurrentTest() && !aborting() ); + + Totals deltaTotals = m_totals.delta( prevTotals ); + m_totals.testCases += deltaTotals.testCases; + m_reporter->testCaseEnded( TestCaseStats( testInfo, + deltaTotals, + redirectedCout, + redirectedCerr, + aborting() ) ); + + m_activeTestCase = CATCH_NULL; + m_testCaseTracker = CATCH_NULL; + + return deltaTotals; + } + + Ptr config() const { + return m_config; + } + + private: // IResultCapture + + virtual void assertionEnded( AssertionResult const& result ) { + if( result.getResultType() == ResultWas::Ok ) { + m_totals.assertions.passed++; + } + else if( !result.isOk() ) { + m_totals.assertions.failed++; + } + + if( m_reporter->assertionEnded( AssertionStats( result, m_messages, m_totals ) ) ) + m_messages.clear(); + + // Reset working state + m_lastAssertionInfo = AssertionInfo( "", m_lastAssertionInfo.lineInfo, "{Unknown expression after the reported line}" , m_lastAssertionInfo.resultDisposition ); + m_lastResult = result; + } + + virtual bool sectionStarted ( + SectionInfo const& sectionInfo, + Counts& assertions + ) + { + std::ostringstream oss; + oss << sectionInfo.name << "@" << sectionInfo.lineInfo; + + ITracker& sectionTracker = SectionTracker::acquire( m_trackerContext, oss.str() ); + if( !sectionTracker.isOpen() ) + return false; + m_activeSections.push_back( §ionTracker ); + + m_lastAssertionInfo.lineInfo = sectionInfo.lineInfo; + + m_reporter->sectionStarting( sectionInfo ); + + assertions = m_totals.assertions; + + return true; + } + bool testForMissingAssertions( Counts& assertions ) { + if( assertions.total() != 0 ) + return false; + if( !m_config->warnAboutMissingAssertions() ) + return false; + if( m_trackerContext.currentTracker().hasChildren() ) + return false; + m_totals.assertions.failed++; + assertions.failed++; + return true; + } + + virtual void sectionEnded( SectionEndInfo const& endInfo ) { + Counts assertions = m_totals.assertions - endInfo.prevAssertions; + bool missingAssertions = testForMissingAssertions( assertions ); + + if( !m_activeSections.empty() ) { + m_activeSections.back()->close(); + m_activeSections.pop_back(); + } + + m_reporter->sectionEnded( SectionStats( endInfo.sectionInfo, assertions, endInfo.durationInSeconds, missingAssertions ) ); + m_messages.clear(); + } + + virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) { + if( m_unfinishedSections.empty() ) + m_activeSections.back()->fail(); + else + m_activeSections.back()->close(); + m_activeSections.pop_back(); + + m_unfinishedSections.push_back( endInfo ); + } + + virtual void pushScopedMessage( MessageInfo const& message ) { + m_messages.push_back( message ); + } + + virtual void popScopedMessage( MessageInfo const& message ) { + m_messages.erase( std::remove( m_messages.begin(), m_messages.end(), message ), m_messages.end() ); + } + + virtual std::string getCurrentTestName() const { + return m_activeTestCase + ? m_activeTestCase->getTestCaseInfo().name + : ""; + } + + virtual const AssertionResult* getLastResult() const { + return &m_lastResult; + } + + virtual void handleFatalErrorCondition( std::string const& message ) { + ResultBuilder resultBuilder = makeUnexpectedResultBuilder(); + resultBuilder.setResultType( ResultWas::FatalErrorCondition ); + resultBuilder << message; + resultBuilder.captureExpression(); + + handleUnfinishedSections(); + + // Recreate section for test case (as we will lose the one that was in scope) + TestCaseInfo const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); + SectionInfo testCaseSection( testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description ); + + Counts assertions; + assertions.failed = 1; + SectionStats testCaseSectionStats( testCaseSection, assertions, 0, false ); + m_reporter->sectionEnded( testCaseSectionStats ); + + TestCaseInfo testInfo = m_activeTestCase->getTestCaseInfo(); + + Totals deltaTotals; + deltaTotals.testCases.failed = 1; + m_reporter->testCaseEnded( TestCaseStats( testInfo, + deltaTotals, + "", + "", + false ) ); + m_totals.testCases.failed++; + testGroupEnded( "", m_totals, 1, 1 ); + m_reporter->testRunEnded( TestRunStats( m_runInfo, m_totals, false ) ); + } + + public: + // !TBD We need to do this another way! + bool aborting() const { + return m_totals.assertions.failed == static_cast( m_config->abortAfter() ); + } + + private: + + void runCurrentTest( std::string& redirectedCout, std::string& redirectedCerr ) { + TestCaseInfo const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); + SectionInfo testCaseSection( testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description ); + m_reporter->sectionStarting( testCaseSection ); + Counts prevAssertions = m_totals.assertions; + double duration = 0; + try { + m_lastAssertionInfo = AssertionInfo( "TEST_CASE", testCaseInfo.lineInfo, "", ResultDisposition::Normal ); + + seedRng( *m_config ); + + Timer timer; + timer.start(); + if( m_reporter->getPreferences().shouldRedirectStdOut ) { + StreamRedirect coutRedir( Catch::cout(), redirectedCout ); + StreamRedirect cerrRedir( Catch::cerr(), redirectedCerr ); + invokeActiveTestCase(); + } + else { + invokeActiveTestCase(); + } + duration = timer.getElapsedSeconds(); + } + catch( TestFailureException& ) { + // This just means the test was aborted due to failure + } + catch(...) { + makeUnexpectedResultBuilder().useActiveException(); + } + m_testCaseTracker->close(); + handleUnfinishedSections(); + m_messages.clear(); + + Counts assertions = m_totals.assertions - prevAssertions; + bool missingAssertions = testForMissingAssertions( assertions ); + + if( testCaseInfo.okToFail() ) { + std::swap( assertions.failedButOk, assertions.failed ); + m_totals.assertions.failed -= assertions.failedButOk; + m_totals.assertions.failedButOk += assertions.failedButOk; + } + + SectionStats testCaseSectionStats( testCaseSection, assertions, duration, missingAssertions ); + m_reporter->sectionEnded( testCaseSectionStats ); + } + + void invokeActiveTestCase() { + FatalConditionHandler fatalConditionHandler; // Handle signals + m_activeTestCase->invoke(); + fatalConditionHandler.reset(); + } + + private: + + ResultBuilder makeUnexpectedResultBuilder() const { + return ResultBuilder( m_lastAssertionInfo.macroName.c_str(), + m_lastAssertionInfo.lineInfo, + m_lastAssertionInfo.capturedExpression.c_str(), + m_lastAssertionInfo.resultDisposition ); + } + + void handleUnfinishedSections() { + // If sections ended prematurely due to an exception we stored their + // infos here so we can tear them down outside the unwind process. + for( std::vector::const_reverse_iterator it = m_unfinishedSections.rbegin(), + itEnd = m_unfinishedSections.rend(); + it != itEnd; + ++it ) + sectionEnded( *it ); + m_unfinishedSections.clear(); + } + + TestRunInfo m_runInfo; + IMutableContext& m_context; + TestCase const* m_activeTestCase; + ITracker* m_testCaseTracker; + ITracker* m_currentSectionTracker; + AssertionResult m_lastResult; + + Ptr m_config; + Totals m_totals; + Ptr m_reporter; + std::vector m_messages; + AssertionInfo m_lastAssertionInfo; + std::vector m_unfinishedSections; + std::vector m_activeSections; + TrackerContext m_trackerContext; + }; + + IResultCapture& getResultCapture() { + if( IResultCapture* capture = getCurrentContext().getResultCapture() ) + return *capture; + else + throw std::logic_error( "No result capture instance" ); + } + +} // end namespace Catch + +// #included from: internal/catch_version.h +#define TWOBLUECUBES_CATCH_VERSION_H_INCLUDED + +namespace Catch { + + // Versioning information + struct Version { + Version( unsigned int _majorVersion, + unsigned int _minorVersion, + unsigned int _patchNumber, + std::string const& _branchName, + unsigned int _buildNumber ); + + unsigned int const majorVersion; + unsigned int const minorVersion; + unsigned int const patchNumber; + + // buildNumber is only used if branchName is not null + std::string const branchName; + unsigned int const buildNumber; + + friend std::ostream& operator << ( std::ostream& os, Version const& version ); + + private: + void operator=( Version const& ); + }; + + extern Version libraryVersion; +} + +#include +#include +#include + +namespace Catch { + + Ptr createReporter( std::string const& reporterName, Ptr const& config ) { + Ptr reporter = getRegistryHub().getReporterRegistry().create( reporterName, config.get() ); + if( !reporter ) { + std::ostringstream oss; + oss << "No reporter registered with name: '" << reporterName << "'"; + throw std::domain_error( oss.str() ); + } + return reporter; + } + + Ptr makeReporter( Ptr const& config ) { + std::vector reporters = config->getReporterNames(); + if( reporters.empty() ) + reporters.push_back( "console" ); + + Ptr reporter; + for( std::vector::const_iterator it = reporters.begin(), itEnd = reporters.end(); + it != itEnd; + ++it ) + reporter = addReporter( reporter, createReporter( *it, config ) ); + return reporter; + } + Ptr addListeners( Ptr const& config, Ptr reporters ) { + IReporterRegistry::Listeners listeners = getRegistryHub().getReporterRegistry().getListeners(); + for( IReporterRegistry::Listeners::const_iterator it = listeners.begin(), itEnd = listeners.end(); + it != itEnd; + ++it ) + reporters = addReporter(reporters, (*it)->create( ReporterConfig( config ) ) ); + return reporters; + } + + Totals runTests( Ptr const& config ) { + + Ptr iconfig = config.get(); + + Ptr reporter = makeReporter( config ); + reporter = addListeners( iconfig, reporter ); + + RunContext context( iconfig, reporter ); + + Totals totals; + + context.testGroupStarting( config->name(), 1, 1 ); + + TestSpec testSpec = config->testSpec(); + if( !testSpec.hasFilters() ) + testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "~[.]" ).testSpec(); // All not hidden tests + + std::vector const& allTestCases = getAllTestCasesSorted( *iconfig ); + for( std::vector::const_iterator it = allTestCases.begin(), itEnd = allTestCases.end(); + it != itEnd; + ++it ) { + if( !context.aborting() && matchTest( *it, testSpec, *iconfig ) ) + totals += context.runTest( *it ); + else + reporter->skipTest( *it ); + } + + context.testGroupEnded( iconfig->name(), totals, 1, 1 ); + return totals; + } + + void applyFilenamesAsTags( IConfig const& config ) { + std::vector const& tests = getAllTestCasesSorted( config ); + for(std::size_t i = 0; i < tests.size(); ++i ) { + TestCase& test = const_cast( tests[i] ); + std::set tags = test.tags; + + std::string filename = test.lineInfo.file; + std::string::size_type lastSlash = filename.find_last_of( "\\/" ); + if( lastSlash != std::string::npos ) + filename = filename.substr( lastSlash+1 ); + + std::string::size_type lastDot = filename.find_last_of( "." ); + if( lastDot != std::string::npos ) + filename = filename.substr( 0, lastDot ); + + tags.insert( "#" + filename ); + setTags( test, tags ); + } + } + + class Session : NonCopyable { + static bool alreadyInstantiated; + + public: + + struct OnUnusedOptions { enum DoWhat { Ignore, Fail }; }; + + Session() + : m_cli( makeCommandLineParser() ) { + if( alreadyInstantiated ) { + std::string msg = "Only one instance of Catch::Session can ever be used"; + Catch::cerr() << msg << std::endl; + throw std::logic_error( msg ); + } + alreadyInstantiated = true; + } + ~Session() { + Catch::cleanUp(); + } + + void showHelp( std::string const& processName ) { + Catch::cout() << "\nCatch v" << libraryVersion << "\n"; + + m_cli.usage( Catch::cout(), processName ); + Catch::cout() << "For more detail usage please see the project docs\n" << std::endl; + } + + int applyCommandLine( int argc, char const* argv[], OnUnusedOptions::DoWhat unusedOptionBehaviour = OnUnusedOptions::Fail ) { + try { + m_cli.setThrowOnUnrecognisedTokens( unusedOptionBehaviour == OnUnusedOptions::Fail ); + m_unusedTokens = m_cli.parseInto( argc, argv, m_configData ); + if( m_configData.showHelp ) + showHelp( m_configData.processName ); + m_config.reset(); + } + catch( std::exception& ex ) { + { + Colour colourGuard( Colour::Red ); + Catch::cerr() + << "\nError(s) in input:\n" + << Text( ex.what(), TextAttributes().setIndent(2) ) + << "\n\n"; + } + m_cli.usage( Catch::cout(), m_configData.processName ); + return (std::numeric_limits::max)(); + } + return 0; + } + + void useConfigData( ConfigData const& _configData ) { + m_configData = _configData; + m_config.reset(); + } + + int run( int argc, char const* argv[] ) { + + int returnCode = applyCommandLine( argc, argv ); + if( returnCode == 0 ) + returnCode = run(); + return returnCode; + } + int run( int argc, char* argv[] ) { + return run( argc, const_cast( argv ) ); + } + + int run() { + if( m_configData.showHelp ) + return 0; + + try + { + config(); // Force config to be constructed + + seedRng( *m_config ); + + if( m_configData.filenamesAsTags ) + applyFilenamesAsTags( *m_config ); + + // Handle list request + if( Option listed = list( config() ) ) + return static_cast( *listed ); + + return static_cast( runTests( m_config ).assertions.failed ); + } + catch( std::exception& ex ) { + Catch::cerr() << ex.what() << std::endl; + return (std::numeric_limits::max)(); + } + } + + Clara::CommandLine const& cli() const { + return m_cli; + } + std::vector const& unusedTokens() const { + return m_unusedTokens; + } + ConfigData& configData() { + return m_configData; + } + Config& config() { + if( !m_config ) + m_config = new Config( m_configData ); + return *m_config; + } + private: + Clara::CommandLine m_cli; + std::vector m_unusedTokens; + ConfigData m_configData; + Ptr m_config; + }; + + bool Session::alreadyInstantiated = false; + +} // end namespace Catch + +// #included from: catch_registry_hub.hpp +#define TWOBLUECUBES_CATCH_REGISTRY_HUB_HPP_INCLUDED + +// #included from: catch_test_case_registry_impl.hpp +#define TWOBLUECUBES_CATCH_TEST_CASE_REGISTRY_IMPL_HPP_INCLUDED + +#include +#include +#include +#include +#include + +namespace Catch { + + struct LexSort { + bool operator() (TestCase i,TestCase j) const { return (i sortTests( IConfig const& config, std::vector const& unsortedTestCases ) { + + std::vector sorted = unsortedTestCases; + + switch( config.runOrder() ) { + case RunTests::InLexicographicalOrder: + std::sort( sorted.begin(), sorted.end(), LexSort() ); + break; + case RunTests::InRandomOrder: + { + seedRng( config ); + + RandomNumberGenerator rng; + std::random_shuffle( sorted.begin(), sorted.end(), rng ); + } + break; + case RunTests::InDeclarationOrder: + // already in declaration order + break; + } + return sorted; + } + bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ) { + return testSpec.matches( testCase ) && ( config.allowThrows() || !testCase.throws() ); + } + + void enforceNoDuplicateTestCases( std::vector const& functions ) { + std::set seenFunctions; + for( std::vector::const_iterator it = functions.begin(), itEnd = functions.end(); + it != itEnd; + ++it ) { + std::pair::const_iterator, bool> prev = seenFunctions.insert( *it ); + if( !prev.second ){ + Catch::cerr() + << Colour( Colour::Red ) + << "error: TEST_CASE( \"" << it->name << "\" ) already defined.\n" + << "\tFirst seen at " << prev.first->getTestCaseInfo().lineInfo << "\n" + << "\tRedefined at " << it->getTestCaseInfo().lineInfo << std::endl; + exit(1); + } + } + } + + std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ) { + std::vector filtered; + filtered.reserve( testCases.size() ); + for( std::vector::const_iterator it = testCases.begin(), itEnd = testCases.end(); + it != itEnd; + ++it ) + if( matchTest( *it, testSpec, config ) ) + filtered.push_back( *it ); + return filtered; + } + std::vector const& getAllTestCasesSorted( IConfig const& config ) { + return getRegistryHub().getTestCaseRegistry().getAllTestsSorted( config ); + } + + class TestRegistry : public ITestCaseRegistry { + public: + TestRegistry() + : m_currentSortOrder( RunTests::InDeclarationOrder ), + m_unnamedCount( 0 ) + {} + virtual ~TestRegistry(); + + virtual void registerTest( TestCase const& testCase ) { + std::string name = testCase.getTestCaseInfo().name; + if( name == "" ) { + std::ostringstream oss; + oss << "Anonymous test case " << ++m_unnamedCount; + return registerTest( testCase.withName( oss.str() ) ); + } + m_functions.push_back( testCase ); + } + + virtual std::vector const& getAllTests() const { + return m_functions; + } + virtual std::vector const& getAllTestsSorted( IConfig const& config ) const { + if( m_sortedFunctions.empty() ) + enforceNoDuplicateTestCases( m_functions ); + + if( m_currentSortOrder != config.runOrder() || m_sortedFunctions.empty() ) { + m_sortedFunctions = sortTests( config, m_functions ); + m_currentSortOrder = config.runOrder(); + } + return m_sortedFunctions; + } + + private: + std::vector m_functions; + mutable RunTests::InWhatOrder m_currentSortOrder; + mutable std::vector m_sortedFunctions; + size_t m_unnamedCount; + std::ios_base::Init m_ostreamInit; // Forces cout/ cerr to be initialised + }; + + /////////////////////////////////////////////////////////////////////////// + + class FreeFunctionTestCase : public SharedImpl { + public: + + FreeFunctionTestCase( TestFunction fun ) : m_fun( fun ) {} + + virtual void invoke() const { + m_fun(); + } + + private: + virtual ~FreeFunctionTestCase(); + + TestFunction m_fun; + }; + + inline std::string extractClassName( std::string const& classOrQualifiedMethodName ) { + std::string className = classOrQualifiedMethodName; + if( startsWith( className, "&" ) ) + { + std::size_t lastColons = className.rfind( "::" ); + std::size_t penultimateColons = className.rfind( "::", lastColons-1 ); + if( penultimateColons == std::string::npos ) + penultimateColons = 1; + className = className.substr( penultimateColons, lastColons-penultimateColons ); + } + return className; + } + + void registerTestCase + ( ITestCase* testCase, + char const* classOrQualifiedMethodName, + NameAndDesc const& nameAndDesc, + SourceLineInfo const& lineInfo ) { + + getMutableRegistryHub().registerTest + ( makeTestCase + ( testCase, + extractClassName( classOrQualifiedMethodName ), + nameAndDesc.name, + nameAndDesc.description, + lineInfo ) ); + } + void registerTestCaseFunction + ( TestFunction function, + SourceLineInfo const& lineInfo, + NameAndDesc const& nameAndDesc ) { + registerTestCase( new FreeFunctionTestCase( function ), "", nameAndDesc, lineInfo ); + } + + /////////////////////////////////////////////////////////////////////////// + + AutoReg::AutoReg + ( TestFunction function, + SourceLineInfo const& lineInfo, + NameAndDesc const& nameAndDesc ) { + registerTestCaseFunction( function, lineInfo, nameAndDesc ); + } + + AutoReg::~AutoReg() {} + +} // end namespace Catch + +// #included from: catch_reporter_registry.hpp +#define TWOBLUECUBES_CATCH_REPORTER_REGISTRY_HPP_INCLUDED + +#include + +namespace Catch { + + class ReporterRegistry : public IReporterRegistry { + + public: + + virtual ~ReporterRegistry() CATCH_OVERRIDE {} + + virtual IStreamingReporter* create( std::string const& name, Ptr const& config ) const CATCH_OVERRIDE { + FactoryMap::const_iterator it = m_factories.find( name ); + if( it == m_factories.end() ) + return CATCH_NULL; + return it->second->create( ReporterConfig( config ) ); + } + + void registerReporter( std::string const& name, Ptr const& factory ) { + m_factories.insert( std::make_pair( name, factory ) ); + } + void registerListener( Ptr const& factory ) { + m_listeners.push_back( factory ); + } + + virtual FactoryMap const& getFactories() const CATCH_OVERRIDE { + return m_factories; + } + virtual Listeners const& getListeners() const CATCH_OVERRIDE { + return m_listeners; + } + + private: + FactoryMap m_factories; + Listeners m_listeners; + }; +} + +// #included from: catch_exception_translator_registry.hpp +#define TWOBLUECUBES_CATCH_EXCEPTION_TRANSLATOR_REGISTRY_HPP_INCLUDED + +#ifdef __OBJC__ +#import "Foundation/Foundation.h" +#endif + +namespace Catch { + + class ExceptionTranslatorRegistry : public IExceptionTranslatorRegistry { + public: + ~ExceptionTranslatorRegistry() { + deleteAll( m_translators ); + } + + virtual void registerTranslator( const IExceptionTranslator* translator ) { + m_translators.push_back( translator ); + } + + virtual std::string translateActiveException() const { + try { +#ifdef __OBJC__ + // In Objective-C try objective-c exceptions first + @try { + return tryTranslators(); + } + @catch (NSException *exception) { + return Catch::toString( [exception description] ); + } +#else + return tryTranslators(); +#endif + } + catch( TestFailureException& ) { + throw; + } + catch( std::exception& ex ) { + return ex.what(); + } + catch( std::string& msg ) { + return msg; + } + catch( const char* msg ) { + return msg; + } + catch(...) { + return "Unknown exception"; + } + } + + std::string tryTranslators() const { + if( m_translators.empty() ) + throw; + else + return m_translators[0]->translate( m_translators.begin()+1, m_translators.end() ); + } + + private: + std::vector m_translators; + }; +} + +namespace Catch { + + namespace { + + class RegistryHub : public IRegistryHub, public IMutableRegistryHub { + + RegistryHub( RegistryHub const& ); + void operator=( RegistryHub const& ); + + public: // IRegistryHub + RegistryHub() { + } + virtual IReporterRegistry const& getReporterRegistry() const CATCH_OVERRIDE { + return m_reporterRegistry; + } + virtual ITestCaseRegistry const& getTestCaseRegistry() const CATCH_OVERRIDE { + return m_testCaseRegistry; + } + virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() CATCH_OVERRIDE { + return m_exceptionTranslatorRegistry; + } + + public: // IMutableRegistryHub + virtual void registerReporter( std::string const& name, Ptr const& factory ) CATCH_OVERRIDE { + m_reporterRegistry.registerReporter( name, factory ); + } + virtual void registerListener( Ptr const& factory ) CATCH_OVERRIDE { + m_reporterRegistry.registerListener( factory ); + } + virtual void registerTest( TestCase const& testInfo ) CATCH_OVERRIDE { + m_testCaseRegistry.registerTest( testInfo ); + } + virtual void registerTranslator( const IExceptionTranslator* translator ) CATCH_OVERRIDE { + m_exceptionTranslatorRegistry.registerTranslator( translator ); + } + + private: + TestRegistry m_testCaseRegistry; + ReporterRegistry m_reporterRegistry; + ExceptionTranslatorRegistry m_exceptionTranslatorRegistry; + }; + + // Single, global, instance + inline RegistryHub*& getTheRegistryHub() { + static RegistryHub* theRegistryHub = CATCH_NULL; + if( !theRegistryHub ) + theRegistryHub = new RegistryHub(); + return theRegistryHub; + } + } + + IRegistryHub& getRegistryHub() { + return *getTheRegistryHub(); + } + IMutableRegistryHub& getMutableRegistryHub() { + return *getTheRegistryHub(); + } + void cleanUp() { + delete getTheRegistryHub(); + getTheRegistryHub() = CATCH_NULL; + cleanUpContext(); + } + std::string translateActiveException() { + return getRegistryHub().getExceptionTranslatorRegistry().translateActiveException(); + } + +} // end namespace Catch + +// #included from: catch_notimplemented_exception.hpp +#define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_HPP_INCLUDED + +#include + +namespace Catch { + + NotImplementedException::NotImplementedException( SourceLineInfo const& lineInfo ) + : m_lineInfo( lineInfo ) { + std::ostringstream oss; + oss << lineInfo << ": function "; + oss << "not implemented"; + m_what = oss.str(); + } + + const char* NotImplementedException::what() const CATCH_NOEXCEPT { + return m_what.c_str(); + } + +} // end namespace Catch + +// #included from: catch_context_impl.hpp +#define TWOBLUECUBES_CATCH_CONTEXT_IMPL_HPP_INCLUDED + +// #included from: catch_stream.hpp +#define TWOBLUECUBES_CATCH_STREAM_HPP_INCLUDED + +#include +#include +#include + +namespace Catch { + + template + class StreamBufImpl : public StreamBufBase { + char data[bufferSize]; + WriterF m_writer; + + public: + StreamBufImpl() { + setp( data, data + sizeof(data) ); + } + + ~StreamBufImpl() CATCH_NOEXCEPT { + sync(); + } + + private: + int overflow( int c ) { + sync(); + + if( c != EOF ) { + if( pbase() == epptr() ) + m_writer( std::string( 1, static_cast( c ) ) ); + else + sputc( static_cast( c ) ); + } + return 0; + } + + int sync() { + if( pbase() != pptr() ) { + m_writer( std::string( pbase(), static_cast( pptr() - pbase() ) ) ); + setp( pbase(), epptr() ); + } + return 0; + } + }; + + /////////////////////////////////////////////////////////////////////////// + + FileStream::FileStream( std::string const& filename ) { + m_ofs.open( filename.c_str() ); + if( m_ofs.fail() ) { + std::ostringstream oss; + oss << "Unable to open file: '" << filename << "'"; + throw std::domain_error( oss.str() ); + } + } + + std::ostream& FileStream::stream() const { + return m_ofs; + } + + struct OutputDebugWriter { + + void operator()( std::string const&str ) { + writeToDebugConsole( str ); + } + }; + + DebugOutStream::DebugOutStream() + : m_streamBuf( new StreamBufImpl() ), + m_os( m_streamBuf.get() ) + {} + + std::ostream& DebugOutStream::stream() const { + return m_os; + } + + // Store the streambuf from cout up-front because + // cout may get redirected when running tests + CoutStream::CoutStream() + : m_os( Catch::cout().rdbuf() ) + {} + + std::ostream& CoutStream::stream() const { + return m_os; + } + +#ifndef CATCH_CONFIG_NOSTDOUT // If you #define this you must implement these functions + std::ostream& cout() { + return std::cout; + } + std::ostream& cerr() { + return std::cerr; + } +#endif +} + +namespace Catch { + + class Context : public IMutableContext { + + Context() : m_config( CATCH_NULL ), m_runner( CATCH_NULL ), m_resultCapture( CATCH_NULL ) {} + Context( Context const& ); + void operator=( Context const& ); + + public: // IContext + virtual IResultCapture* getResultCapture() { + return m_resultCapture; + } + virtual IRunner* getRunner() { + return m_runner; + } + virtual size_t getGeneratorIndex( std::string const& fileInfo, size_t totalSize ) { + return getGeneratorsForCurrentTest() + .getGeneratorInfo( fileInfo, totalSize ) + .getCurrentIndex(); + } + virtual bool advanceGeneratorsForCurrentTest() { + IGeneratorsForTest* generators = findGeneratorsForCurrentTest(); + return generators && generators->moveNext(); + } + + virtual Ptr getConfig() const { + return m_config; + } + + public: // IMutableContext + virtual void setResultCapture( IResultCapture* resultCapture ) { + m_resultCapture = resultCapture; + } + virtual void setRunner( IRunner* runner ) { + m_runner = runner; + } + virtual void setConfig( Ptr const& config ) { + m_config = config; + } + + friend IMutableContext& getCurrentMutableContext(); + + private: + IGeneratorsForTest* findGeneratorsForCurrentTest() { + std::string testName = getResultCapture()->getCurrentTestName(); + + std::map::const_iterator it = + m_generatorsByTestName.find( testName ); + return it != m_generatorsByTestName.end() + ? it->second + : CATCH_NULL; + } + + IGeneratorsForTest& getGeneratorsForCurrentTest() { + IGeneratorsForTest* generators = findGeneratorsForCurrentTest(); + if( !generators ) { + std::string testName = getResultCapture()->getCurrentTestName(); + generators = createGeneratorsForTest(); + m_generatorsByTestName.insert( std::make_pair( testName, generators ) ); + } + return *generators; + } + + private: + Ptr m_config; + IRunner* m_runner; + IResultCapture* m_resultCapture; + std::map m_generatorsByTestName; + }; + + namespace { + Context* currentContext = CATCH_NULL; + } + IMutableContext& getCurrentMutableContext() { + if( !currentContext ) + currentContext = new Context(); + return *currentContext; + } + IContext& getCurrentContext() { + return getCurrentMutableContext(); + } + + void cleanUpContext() { + delete currentContext; + currentContext = CATCH_NULL; + } +} + +// #included from: catch_console_colour_impl.hpp +#define TWOBLUECUBES_CATCH_CONSOLE_COLOUR_IMPL_HPP_INCLUDED + +namespace Catch { + namespace { + + struct IColourImpl { + virtual ~IColourImpl() {} + virtual void use( Colour::Code _colourCode ) = 0; + }; + + struct NoColourImpl : IColourImpl { + void use( Colour::Code ) {} + + static IColourImpl* instance() { + static NoColourImpl s_instance; + return &s_instance; + } + }; + + } // anon namespace +} // namespace Catch + +#if !defined( CATCH_CONFIG_COLOUR_NONE ) && !defined( CATCH_CONFIG_COLOUR_WINDOWS ) && !defined( CATCH_CONFIG_COLOUR_ANSI ) +# ifdef CATCH_PLATFORM_WINDOWS +# define CATCH_CONFIG_COLOUR_WINDOWS +# else +# define CATCH_CONFIG_COLOUR_ANSI +# endif +#endif + +#if defined ( CATCH_CONFIG_COLOUR_WINDOWS ) ///////////////////////////////////////// + +#ifndef NOMINMAX +#define NOMINMAX +#endif + +#ifdef __AFXDLL +#include +#else +#include +#endif + +namespace Catch { +namespace { + + class Win32ColourImpl : public IColourImpl { + public: + Win32ColourImpl() : stdoutHandle( GetStdHandle(STD_OUTPUT_HANDLE) ) + { + CONSOLE_SCREEN_BUFFER_INFO csbiInfo; + GetConsoleScreenBufferInfo( stdoutHandle, &csbiInfo ); + originalForegroundAttributes = csbiInfo.wAttributes & ~( BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_BLUE | BACKGROUND_INTENSITY ); + originalBackgroundAttributes = csbiInfo.wAttributes & ~( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY ); + } + + virtual void use( Colour::Code _colourCode ) { + switch( _colourCode ) { + case Colour::None: return setTextAttribute( originalForegroundAttributes ); + case Colour::White: return setTextAttribute( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE ); + case Colour::Red: return setTextAttribute( FOREGROUND_RED ); + case Colour::Green: return setTextAttribute( FOREGROUND_GREEN ); + case Colour::Blue: return setTextAttribute( FOREGROUND_BLUE ); + case Colour::Cyan: return setTextAttribute( FOREGROUND_BLUE | FOREGROUND_GREEN ); + case Colour::Yellow: return setTextAttribute( FOREGROUND_RED | FOREGROUND_GREEN ); + case Colour::Grey: return setTextAttribute( 0 ); + + case Colour::LightGrey: return setTextAttribute( FOREGROUND_INTENSITY ); + case Colour::BrightRed: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED ); + case Colour::BrightGreen: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN ); + case Colour::BrightWhite: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE ); + + case Colour::Bright: throw std::logic_error( "not a colour" ); + } + } + + private: + void setTextAttribute( WORD _textAttribute ) { + SetConsoleTextAttribute( stdoutHandle, _textAttribute | originalBackgroundAttributes ); + } + HANDLE stdoutHandle; + WORD originalForegroundAttributes; + WORD originalBackgroundAttributes; + }; + + IColourImpl* platformColourInstance() { + static Win32ColourImpl s_instance; + + Ptr config = getCurrentContext().getConfig(); + UseColour::YesOrNo colourMode = config + ? config->useColour() + : UseColour::Auto; + if( colourMode == UseColour::Auto ) + colourMode = !isDebuggerActive() + ? UseColour::Yes + : UseColour::No; + return colourMode == UseColour::Yes + ? &s_instance + : NoColourImpl::instance(); + } + +} // end anon namespace +} // end namespace Catch + +#elif defined( CATCH_CONFIG_COLOUR_ANSI ) ////////////////////////////////////// + +#include + +namespace Catch { +namespace { + + // use POSIX/ ANSI console terminal codes + // Thanks to Adam Strzelecki for original contribution + // (http://github.com/nanoant) + // https://github.com/philsquared/Catch/pull/131 + class PosixColourImpl : public IColourImpl { + public: + virtual void use( Colour::Code _colourCode ) { + switch( _colourCode ) { + case Colour::None: + case Colour::White: return setColour( "[0m" ); + case Colour::Red: return setColour( "[0;31m" ); + case Colour::Green: return setColour( "[0;32m" ); + case Colour::Blue: return setColour( "[0:34m" ); + case Colour::Cyan: return setColour( "[0;36m" ); + case Colour::Yellow: return setColour( "[0;33m" ); + case Colour::Grey: return setColour( "[1;30m" ); + + case Colour::LightGrey: return setColour( "[0;37m" ); + case Colour::BrightRed: return setColour( "[1;31m" ); + case Colour::BrightGreen: return setColour( "[1;32m" ); + case Colour::BrightWhite: return setColour( "[1;37m" ); + + case Colour::Bright: throw std::logic_error( "not a colour" ); + } + } + static IColourImpl* instance() { + static PosixColourImpl s_instance; + return &s_instance; + } + + private: + void setColour( const char* _escapeCode ) { + Catch::cout() << '\033' << _escapeCode; + } + }; + + IColourImpl* platformColourInstance() { + Ptr config = getCurrentContext().getConfig(); + UseColour::YesOrNo colourMode = config + ? config->useColour() + : UseColour::Auto; + if( colourMode == UseColour::Auto ) + colourMode = (!isDebuggerActive() && isatty(STDOUT_FILENO) ) + ? UseColour::Yes + : UseColour::No; + return colourMode == UseColour::Yes + ? PosixColourImpl::instance() + : NoColourImpl::instance(); + } + +} // end anon namespace +} // end namespace Catch + +#else // not Windows or ANSI /////////////////////////////////////////////// + +namespace Catch { + + static IColourImpl* platformColourInstance() { return NoColourImpl::instance(); } + +} // end namespace Catch + +#endif // Windows/ ANSI/ None + +namespace Catch { + + Colour::Colour( Code _colourCode ) : m_moved( false ) { use( _colourCode ); } + Colour::Colour( Colour const& _other ) : m_moved( false ) { const_cast( _other ).m_moved = true; } + Colour::~Colour(){ if( !m_moved ) use( None ); } + + void Colour::use( Code _colourCode ) { + static IColourImpl* impl = platformColourInstance(); + impl->use( _colourCode ); + } + +} // end namespace Catch + +// #included from: catch_generators_impl.hpp +#define TWOBLUECUBES_CATCH_GENERATORS_IMPL_HPP_INCLUDED + +#include +#include +#include + +namespace Catch { + + struct GeneratorInfo : IGeneratorInfo { + + GeneratorInfo( std::size_t size ) + : m_size( size ), + m_currentIndex( 0 ) + {} + + bool moveNext() { + if( ++m_currentIndex == m_size ) { + m_currentIndex = 0; + return false; + } + return true; + } + + std::size_t getCurrentIndex() const { + return m_currentIndex; + } + + std::size_t m_size; + std::size_t m_currentIndex; + }; + + /////////////////////////////////////////////////////////////////////////// + + class GeneratorsForTest : public IGeneratorsForTest { + + public: + ~GeneratorsForTest() { + deleteAll( m_generatorsInOrder ); + } + + IGeneratorInfo& getGeneratorInfo( std::string const& fileInfo, std::size_t size ) { + std::map::const_iterator it = m_generatorsByName.find( fileInfo ); + if( it == m_generatorsByName.end() ) { + IGeneratorInfo* info = new GeneratorInfo( size ); + m_generatorsByName.insert( std::make_pair( fileInfo, info ) ); + m_generatorsInOrder.push_back( info ); + return *info; + } + return *it->second; + } + + bool moveNext() { + std::vector::const_iterator it = m_generatorsInOrder.begin(); + std::vector::const_iterator itEnd = m_generatorsInOrder.end(); + for(; it != itEnd; ++it ) { + if( (*it)->moveNext() ) + return true; + } + return false; + } + + private: + std::map m_generatorsByName; + std::vector m_generatorsInOrder; + }; + + IGeneratorsForTest* createGeneratorsForTest() + { + return new GeneratorsForTest(); + } + +} // end namespace Catch + +// #included from: catch_assertionresult.hpp +#define TWOBLUECUBES_CATCH_ASSERTIONRESULT_HPP_INCLUDED + +namespace Catch { + + AssertionInfo::AssertionInfo( std::string const& _macroName, + SourceLineInfo const& _lineInfo, + std::string const& _capturedExpression, + ResultDisposition::Flags _resultDisposition ) + : macroName( _macroName ), + lineInfo( _lineInfo ), + capturedExpression( _capturedExpression ), + resultDisposition( _resultDisposition ) + {} + + AssertionResult::AssertionResult() {} + + AssertionResult::AssertionResult( AssertionInfo const& info, AssertionResultData const& data ) + : m_info( info ), + m_resultData( data ) + {} + + AssertionResult::~AssertionResult() {} + + // Result was a success + bool AssertionResult::succeeded() const { + return Catch::isOk( m_resultData.resultType ); + } + + // Result was a success, or failure is suppressed + bool AssertionResult::isOk() const { + return Catch::isOk( m_resultData.resultType ) || shouldSuppressFailure( m_info.resultDisposition ); + } + + ResultWas::OfType AssertionResult::getResultType() const { + return m_resultData.resultType; + } + + bool AssertionResult::hasExpression() const { + return !m_info.capturedExpression.empty(); + } + + bool AssertionResult::hasMessage() const { + return !m_resultData.message.empty(); + } + + std::string AssertionResult::getExpression() const { + if( isFalseTest( m_info.resultDisposition ) ) + return "!" + m_info.capturedExpression; + else + return m_info.capturedExpression; + } + std::string AssertionResult::getExpressionInMacro() const { + if( m_info.macroName.empty() ) + return m_info.capturedExpression; + else + return m_info.macroName + "( " + m_info.capturedExpression + " )"; + } + + bool AssertionResult::hasExpandedExpression() const { + return hasExpression() && getExpandedExpression() != getExpression(); + } + + std::string AssertionResult::getExpandedExpression() const { + return m_resultData.reconstructedExpression; + } + + std::string AssertionResult::getMessage() const { + return m_resultData.message; + } + SourceLineInfo AssertionResult::getSourceInfo() const { + return m_info.lineInfo; + } + + std::string AssertionResult::getTestMacroName() const { + return m_info.macroName; + } + +} // end namespace Catch + +// #included from: catch_test_case_info.hpp +#define TWOBLUECUBES_CATCH_TEST_CASE_INFO_HPP_INCLUDED + +namespace Catch { + + inline TestCaseInfo::SpecialProperties parseSpecialTag( std::string const& tag ) { + if( startsWith( tag, "." ) || + tag == "hide" || + tag == "!hide" ) + return TestCaseInfo::IsHidden; + else if( tag == "!throws" ) + return TestCaseInfo::Throws; + else if( tag == "!shouldfail" ) + return TestCaseInfo::ShouldFail; + else if( tag == "!mayfail" ) + return TestCaseInfo::MayFail; + else + return TestCaseInfo::None; + } + inline bool isReservedTag( std::string const& tag ) { + return parseSpecialTag( tag ) == TestCaseInfo::None && tag.size() > 0 && !isalnum( tag[0] ); + } + inline void enforceNotReservedTag( std::string const& tag, SourceLineInfo const& _lineInfo ) { + if( isReservedTag( tag ) ) { + { + Colour colourGuard( Colour::Red ); + Catch::cerr() + << "Tag name [" << tag << "] not allowed.\n" + << "Tag names starting with non alpha-numeric characters are reserved\n"; + } + { + Colour colourGuard( Colour::FileName ); + Catch::cerr() << _lineInfo << std::endl; + } + exit(1); + } + } + + TestCase makeTestCase( ITestCase* _testCase, + std::string const& _className, + std::string const& _name, + std::string const& _descOrTags, + SourceLineInfo const& _lineInfo ) + { + bool isHidden( startsWith( _name, "./" ) ); // Legacy support + + // Parse out tags + std::set tags; + std::string desc, tag; + bool inTag = false; + for( std::size_t i = 0; i < _descOrTags.size(); ++i ) { + char c = _descOrTags[i]; + if( !inTag ) { + if( c == '[' ) + inTag = true; + else + desc += c; + } + else { + if( c == ']' ) { + TestCaseInfo::SpecialProperties prop = parseSpecialTag( tag ); + if( prop == TestCaseInfo::IsHidden ) + isHidden = true; + else if( prop == TestCaseInfo::None ) + enforceNotReservedTag( tag, _lineInfo ); + + tags.insert( tag ); + tag.clear(); + inTag = false; + } + else + tag += c; + } + } + if( isHidden ) { + tags.insert( "hide" ); + tags.insert( "." ); + } + + TestCaseInfo info( _name, _className, desc, tags, _lineInfo ); + return TestCase( _testCase, info ); + } + + void setTags( TestCaseInfo& testCaseInfo, std::set const& tags ) + { + testCaseInfo.tags = tags; + testCaseInfo.lcaseTags.clear(); + + std::ostringstream oss; + for( std::set::const_iterator it = tags.begin(), itEnd = tags.end(); it != itEnd; ++it ) { + oss << "[" << *it << "]"; + std::string lcaseTag = toLower( *it ); + testCaseInfo.properties = static_cast( testCaseInfo.properties | parseSpecialTag( lcaseTag ) ); + testCaseInfo.lcaseTags.insert( lcaseTag ); + } + testCaseInfo.tagsAsString = oss.str(); + } + + TestCaseInfo::TestCaseInfo( std::string const& _name, + std::string const& _className, + std::string const& _description, + std::set const& _tags, + SourceLineInfo const& _lineInfo ) + : name( _name ), + className( _className ), + description( _description ), + lineInfo( _lineInfo ), + properties( None ) + { + setTags( *this, _tags ); + } + + TestCaseInfo::TestCaseInfo( TestCaseInfo const& other ) + : name( other.name ), + className( other.className ), + description( other.description ), + tags( other.tags ), + lcaseTags( other.lcaseTags ), + tagsAsString( other.tagsAsString ), + lineInfo( other.lineInfo ), + properties( other.properties ) + {} + + bool TestCaseInfo::isHidden() const { + return ( properties & IsHidden ) != 0; + } + bool TestCaseInfo::throws() const { + return ( properties & Throws ) != 0; + } + bool TestCaseInfo::okToFail() const { + return ( properties & (ShouldFail | MayFail ) ) != 0; + } + bool TestCaseInfo::expectedToFail() const { + return ( properties & (ShouldFail ) ) != 0; + } + + TestCase::TestCase( ITestCase* testCase, TestCaseInfo const& info ) : TestCaseInfo( info ), test( testCase ) {} + + TestCase::TestCase( TestCase const& other ) + : TestCaseInfo( other ), + test( other.test ) + {} + + TestCase TestCase::withName( std::string const& _newName ) const { + TestCase other( *this ); + other.name = _newName; + return other; + } + + void TestCase::swap( TestCase& other ) { + test.swap( other.test ); + name.swap( other.name ); + className.swap( other.className ); + description.swap( other.description ); + tags.swap( other.tags ); + lcaseTags.swap( other.lcaseTags ); + tagsAsString.swap( other.tagsAsString ); + std::swap( TestCaseInfo::properties, static_cast( other ).properties ); + std::swap( lineInfo, other.lineInfo ); + } + + void TestCase::invoke() const { + test->invoke(); + } + + bool TestCase::operator == ( TestCase const& other ) const { + return test.get() == other.test.get() && + name == other.name && + className == other.className; + } + + bool TestCase::operator < ( TestCase const& other ) const { + return name < other.name; + } + TestCase& TestCase::operator = ( TestCase const& other ) { + TestCase temp( other ); + swap( temp ); + return *this; + } + + TestCaseInfo const& TestCase::getTestCaseInfo() const + { + return *this; + } + +} // end namespace Catch + +// #included from: catch_version.hpp +#define TWOBLUECUBES_CATCH_VERSION_HPP_INCLUDED + +namespace Catch { + + Version::Version + ( unsigned int _majorVersion, + unsigned int _minorVersion, + unsigned int _patchNumber, + std::string const& _branchName, + unsigned int _buildNumber ) + : majorVersion( _majorVersion ), + minorVersion( _minorVersion ), + patchNumber( _patchNumber ), + branchName( _branchName ), + buildNumber( _buildNumber ) + {} + + std::ostream& operator << ( std::ostream& os, Version const& version ) { + os << version.majorVersion << "." + << version.minorVersion << "." + << version.patchNumber; + + if( !version.branchName.empty() ) { + os << "-" << version.branchName + << "." << version.buildNumber; + } + return os; + } + + Version libraryVersion( 1, 3, 6, "", 0 ); + +} + +// #included from: catch_message.hpp +#define TWOBLUECUBES_CATCH_MESSAGE_HPP_INCLUDED + +namespace Catch { + + MessageInfo::MessageInfo( std::string const& _macroName, + SourceLineInfo const& _lineInfo, + ResultWas::OfType _type ) + : macroName( _macroName ), + lineInfo( _lineInfo ), + type( _type ), + sequence( ++globalCount ) + {} + + // This may need protecting if threading support is added + unsigned int MessageInfo::globalCount = 0; + + //////////////////////////////////////////////////////////////////////////// + + ScopedMessage::ScopedMessage( MessageBuilder const& builder ) + : m_info( builder.m_info ) + { + m_info.message = builder.m_stream.str(); + getResultCapture().pushScopedMessage( m_info ); + } + ScopedMessage::ScopedMessage( ScopedMessage const& other ) + : m_info( other.m_info ) + {} + + ScopedMessage::~ScopedMessage() { + getResultCapture().popScopedMessage( m_info ); + } + +} // end namespace Catch + +// #included from: catch_legacy_reporter_adapter.hpp +#define TWOBLUECUBES_CATCH_LEGACY_REPORTER_ADAPTER_HPP_INCLUDED + +// #included from: catch_legacy_reporter_adapter.h +#define TWOBLUECUBES_CATCH_LEGACY_REPORTER_ADAPTER_H_INCLUDED + +namespace Catch +{ + // Deprecated + struct IReporter : IShared { + virtual ~IReporter(); + + virtual bool shouldRedirectStdout() const = 0; + + virtual void StartTesting() = 0; + virtual void EndTesting( Totals const& totals ) = 0; + virtual void StartGroup( std::string const& groupName ) = 0; + virtual void EndGroup( std::string const& groupName, Totals const& totals ) = 0; + virtual void StartTestCase( TestCaseInfo const& testInfo ) = 0; + virtual void EndTestCase( TestCaseInfo const& testInfo, Totals const& totals, std::string const& stdOut, std::string const& stdErr ) = 0; + virtual void StartSection( std::string const& sectionName, std::string const& description ) = 0; + virtual void EndSection( std::string const& sectionName, Counts const& assertions ) = 0; + virtual void NoAssertionsInSection( std::string const& sectionName ) = 0; + virtual void NoAssertionsInTestCase( std::string const& testName ) = 0; + virtual void Aborted() = 0; + virtual void Result( AssertionResult const& result ) = 0; + }; + + class LegacyReporterAdapter : public SharedImpl + { + public: + LegacyReporterAdapter( Ptr const& legacyReporter ); + virtual ~LegacyReporterAdapter(); + + virtual ReporterPreferences getPreferences() const; + virtual void noMatchingTestCases( std::string const& ); + virtual void testRunStarting( TestRunInfo const& ); + virtual void testGroupStarting( GroupInfo const& groupInfo ); + virtual void testCaseStarting( TestCaseInfo const& testInfo ); + virtual void sectionStarting( SectionInfo const& sectionInfo ); + virtual void assertionStarting( AssertionInfo const& ); + virtual bool assertionEnded( AssertionStats const& assertionStats ); + virtual void sectionEnded( SectionStats const& sectionStats ); + virtual void testCaseEnded( TestCaseStats const& testCaseStats ); + virtual void testGroupEnded( TestGroupStats const& testGroupStats ); + virtual void testRunEnded( TestRunStats const& testRunStats ); + virtual void skipTest( TestCaseInfo const& ); + + private: + Ptr m_legacyReporter; + }; +} + +namespace Catch +{ + LegacyReporterAdapter::LegacyReporterAdapter( Ptr const& legacyReporter ) + : m_legacyReporter( legacyReporter ) + {} + LegacyReporterAdapter::~LegacyReporterAdapter() {} + + ReporterPreferences LegacyReporterAdapter::getPreferences() const { + ReporterPreferences prefs; + prefs.shouldRedirectStdOut = m_legacyReporter->shouldRedirectStdout(); + return prefs; + } + + void LegacyReporterAdapter::noMatchingTestCases( std::string const& ) {} + void LegacyReporterAdapter::testRunStarting( TestRunInfo const& ) { + m_legacyReporter->StartTesting(); + } + void LegacyReporterAdapter::testGroupStarting( GroupInfo const& groupInfo ) { + m_legacyReporter->StartGroup( groupInfo.name ); + } + void LegacyReporterAdapter::testCaseStarting( TestCaseInfo const& testInfo ) { + m_legacyReporter->StartTestCase( testInfo ); + } + void LegacyReporterAdapter::sectionStarting( SectionInfo const& sectionInfo ) { + m_legacyReporter->StartSection( sectionInfo.name, sectionInfo.description ); + } + void LegacyReporterAdapter::assertionStarting( AssertionInfo const& ) { + // Not on legacy interface + } + + bool LegacyReporterAdapter::assertionEnded( AssertionStats const& assertionStats ) { + if( assertionStats.assertionResult.getResultType() != ResultWas::Ok ) { + for( std::vector::const_iterator it = assertionStats.infoMessages.begin(), itEnd = assertionStats.infoMessages.end(); + it != itEnd; + ++it ) { + if( it->type == ResultWas::Info ) { + ResultBuilder rb( it->macroName.c_str(), it->lineInfo, "", ResultDisposition::Normal ); + rb << it->message; + rb.setResultType( ResultWas::Info ); + AssertionResult result = rb.build(); + m_legacyReporter->Result( result ); + } + } + } + m_legacyReporter->Result( assertionStats.assertionResult ); + return true; + } + void LegacyReporterAdapter::sectionEnded( SectionStats const& sectionStats ) { + if( sectionStats.missingAssertions ) + m_legacyReporter->NoAssertionsInSection( sectionStats.sectionInfo.name ); + m_legacyReporter->EndSection( sectionStats.sectionInfo.name, sectionStats.assertions ); + } + void LegacyReporterAdapter::testCaseEnded( TestCaseStats const& testCaseStats ) { + m_legacyReporter->EndTestCase + ( testCaseStats.testInfo, + testCaseStats.totals, + testCaseStats.stdOut, + testCaseStats.stdErr ); + } + void LegacyReporterAdapter::testGroupEnded( TestGroupStats const& testGroupStats ) { + if( testGroupStats.aborting ) + m_legacyReporter->Aborted(); + m_legacyReporter->EndGroup( testGroupStats.groupInfo.name, testGroupStats.totals ); + } + void LegacyReporterAdapter::testRunEnded( TestRunStats const& testRunStats ) { + m_legacyReporter->EndTesting( testRunStats.totals ); + } + void LegacyReporterAdapter::skipTest( TestCaseInfo const& ) { + } +} + +// #included from: catch_timer.hpp + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wc++11-long-long" +#endif + +#ifdef CATCH_PLATFORM_WINDOWS +#include +#else +#include +#endif + +namespace Catch { + + namespace { +#ifdef CATCH_PLATFORM_WINDOWS + uint64_t getCurrentTicks() { + static uint64_t hz=0, hzo=0; + if (!hz) { + QueryPerformanceFrequency( reinterpret_cast( &hz ) ); + QueryPerformanceCounter( reinterpret_cast( &hzo ) ); + } + uint64_t t; + QueryPerformanceCounter( reinterpret_cast( &t ) ); + return ((t-hzo)*1000000)/hz; + } +#else + uint64_t getCurrentTicks() { + timeval t; + gettimeofday(&t,CATCH_NULL); + return static_cast( t.tv_sec ) * 1000000ull + static_cast( t.tv_usec ); + } +#endif + } + + void Timer::start() { + m_ticks = getCurrentTicks(); + } + unsigned int Timer::getElapsedMicroseconds() const { + return static_cast(getCurrentTicks() - m_ticks); + } + unsigned int Timer::getElapsedMilliseconds() const { + return static_cast(getElapsedMicroseconds()/1000); + } + double Timer::getElapsedSeconds() const { + return getElapsedMicroseconds()/1000000.0; + } + +} // namespace Catch + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif +// #included from: catch_common.hpp +#define TWOBLUECUBES_CATCH_COMMON_HPP_INCLUDED + +namespace Catch { + + bool startsWith( std::string const& s, std::string const& prefix ) { + return s.size() >= prefix.size() && s.substr( 0, prefix.size() ) == prefix; + } + bool endsWith( std::string const& s, std::string const& suffix ) { + return s.size() >= suffix.size() && s.substr( s.size()-suffix.size(), suffix.size() ) == suffix; + } + bool contains( std::string const& s, std::string const& infix ) { + return s.find( infix ) != std::string::npos; + } + void toLowerInPlace( std::string& s ) { + std::transform( s.begin(), s.end(), s.begin(), ::tolower ); + } + std::string toLower( std::string const& s ) { + std::string lc = s; + toLowerInPlace( lc ); + return lc; + } + std::string trim( std::string const& str ) { + static char const* whitespaceChars = "\n\r\t "; + std::string::size_type start = str.find_first_not_of( whitespaceChars ); + std::string::size_type end = str.find_last_not_of( whitespaceChars ); + + return start != std::string::npos ? str.substr( start, 1+end-start ) : ""; + } + + bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ) { + bool replaced = false; + std::size_t i = str.find( replaceThis ); + while( i != std::string::npos ) { + replaced = true; + str = str.substr( 0, i ) + withThis + str.substr( i+replaceThis.size() ); + if( i < str.size()-withThis.size() ) + i = str.find( replaceThis, i+withThis.size() ); + else + i = std::string::npos; + } + return replaced; + } + + pluralise::pluralise( std::size_t count, std::string const& label ) + : m_count( count ), + m_label( label ) + {} + + std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ) { + os << pluraliser.m_count << " " << pluraliser.m_label; + if( pluraliser.m_count != 1 ) + os << "s"; + return os; + } + + SourceLineInfo::SourceLineInfo() : line( 0 ){} + SourceLineInfo::SourceLineInfo( char const* _file, std::size_t _line ) + : file( _file ), + line( _line ) + {} + SourceLineInfo::SourceLineInfo( SourceLineInfo const& other ) + : file( other.file ), + line( other.line ) + {} + bool SourceLineInfo::empty() const { + return file.empty(); + } + bool SourceLineInfo::operator == ( SourceLineInfo const& other ) const { + return line == other.line && file == other.file; + } + bool SourceLineInfo::operator < ( SourceLineInfo const& other ) const { + return line < other.line || ( line == other.line && file < other.file ); + } + + void seedRng( IConfig const& config ) { + if( config.rngSeed() != 0 ) + std::srand( config.rngSeed() ); + } + unsigned int rngSeed() { + return getCurrentContext().getConfig()->rngSeed(); + } + + std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ) { +#ifndef __GNUG__ + os << info.file << "(" << info.line << ")"; +#else + os << info.file << ":" << info.line; +#endif + return os; + } + + void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo ) { + std::ostringstream oss; + oss << locationInfo << ": Internal Catch error: '" << message << "'"; + if( alwaysTrue() ) + throw std::logic_error( oss.str() ); + } +} + +// #included from: catch_section.hpp +#define TWOBLUECUBES_CATCH_SECTION_HPP_INCLUDED + +namespace Catch { + + SectionInfo::SectionInfo + ( SourceLineInfo const& _lineInfo, + std::string const& _name, + std::string const& _description ) + : name( _name ), + description( _description ), + lineInfo( _lineInfo ) + {} + + Section::Section( SectionInfo const& info ) + : m_info( info ), + m_sectionIncluded( getResultCapture().sectionStarted( m_info, m_assertions ) ) + { + m_timer.start(); + } + + Section::~Section() { + if( m_sectionIncluded ) { + SectionEndInfo endInfo( m_info, m_assertions, m_timer.getElapsedSeconds() ); + if( std::uncaught_exception() ) + getResultCapture().sectionEndedEarly( endInfo ); + else + getResultCapture().sectionEnded( endInfo ); + } + } + + // This indicates whether the section should be executed or not + Section::operator bool() const { + return m_sectionIncluded; + } + +} // end namespace Catch + +// #included from: catch_debugger.hpp +#define TWOBLUECUBES_CATCH_DEBUGGER_HPP_INCLUDED + +#include + +#ifdef CATCH_PLATFORM_MAC + + #include + #include + #include + #include + #include + + namespace Catch{ + + // The following function is taken directly from the following technical note: + // http://developer.apple.com/library/mac/#qa/qa2004/qa1361.html + + // Returns true if the current process is being debugged (either + // running under the debugger or has a debugger attached post facto). + bool isDebuggerActive(){ + + int mib[4]; + struct kinfo_proc info; + size_t size; + + // Initialize the flags so that, if sysctl fails for some bizarre + // reason, we get a predictable result. + + info.kp_proc.p_flag = 0; + + // Initialize mib, which tells sysctl the info we want, in this case + // we're looking for information about a specific process ID. + + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PID; + mib[3] = getpid(); + + // Call sysctl. + + size = sizeof(info); + if( sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, CATCH_NULL, 0) != 0 ) { + Catch::cerr() << "\n** Call to sysctl failed - unable to determine if debugger is active **\n" << std::endl; + return false; + } + + // We're being debugged if the P_TRACED flag is set. + + return ( (info.kp_proc.p_flag & P_TRACED) != 0 ); + } + } // namespace Catch + +#elif defined(_MSC_VER) + extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); + namespace Catch { + bool isDebuggerActive() { + return IsDebuggerPresent() != 0; + } + } +#elif defined(__MINGW32__) + extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); + namespace Catch { + bool isDebuggerActive() { + return IsDebuggerPresent() != 0; + } + } +#else + namespace Catch { + inline bool isDebuggerActive() { return false; } + } +#endif // Platform + +#ifdef CATCH_PLATFORM_WINDOWS + extern "C" __declspec(dllimport) void __stdcall OutputDebugStringA( const char* ); + namespace Catch { + void writeToDebugConsole( std::string const& text ) { + ::OutputDebugStringA( text.c_str() ); + } + } +#else + namespace Catch { + void writeToDebugConsole( std::string const& text ) { + // !TBD: Need a version for Mac/ XCode and other IDEs + Catch::cout() << text; + } + } +#endif // Platform + +// #included from: catch_tostring.hpp +#define TWOBLUECUBES_CATCH_TOSTRING_HPP_INCLUDED + +namespace Catch { + +namespace Detail { + + const std::string unprintableString = "{?}"; + + namespace { + const int hexThreshold = 255; + + struct Endianness { + enum Arch { Big, Little }; + + static Arch which() { + union _{ + int asInt; + char asChar[sizeof (int)]; + } u; + + u.asInt = 1; + return ( u.asChar[sizeof(int)-1] == 1 ) ? Big : Little; + } + }; + } + + std::string rawMemoryToString( const void *object, std::size_t size ) + { + // Reverse order for little endian architectures + int i = 0, end = static_cast( size ), inc = 1; + if( Endianness::which() == Endianness::Little ) { + i = end-1; + end = inc = -1; + } + + unsigned char const *bytes = static_cast(object); + std::ostringstream os; + os << "0x" << std::setfill('0') << std::hex; + for( ; i != end; i += inc ) + os << std::setw(2) << static_cast(bytes[i]); + return os.str(); + } +} + +std::string toString( std::string const& value ) { + std::string s = value; + if( getCurrentContext().getConfig()->showInvisibles() ) { + for(size_t i = 0; i < s.size(); ++i ) { + std::string subs; + switch( s[i] ) { + case '\n': subs = "\\n"; break; + case '\t': subs = "\\t"; break; + default: break; + } + if( !subs.empty() ) { + s = s.substr( 0, i ) + subs + s.substr( i+1 ); + ++i; + } + } + } + return "\"" + s + "\""; +} +std::string toString( std::wstring const& value ) { + + std::string s; + s.reserve( value.size() ); + for(size_t i = 0; i < value.size(); ++i ) + s += value[i] <= 0xff ? static_cast( value[i] ) : '?'; + return Catch::toString( s ); +} + +std::string toString( const char* const value ) { + return value ? Catch::toString( std::string( value ) ) : std::string( "{null string}" ); +} + +std::string toString( char* const value ) { + return Catch::toString( static_cast( value ) ); +} + +std::string toString( const wchar_t* const value ) +{ + return value ? Catch::toString( std::wstring(value) ) : std::string( "{null string}" ); +} + +std::string toString( wchar_t* const value ) +{ + return Catch::toString( static_cast( value ) ); +} + +std::string toString( int value ) { + std::ostringstream oss; + oss << value; + if( value > Detail::hexThreshold ) + oss << " (0x" << std::hex << value << ")"; + return oss.str(); +} + +std::string toString( unsigned long value ) { + std::ostringstream oss; + oss << value; + if( value > Detail::hexThreshold ) + oss << " (0x" << std::hex << value << ")"; + return oss.str(); +} + +std::string toString( unsigned int value ) { + return Catch::toString( static_cast( value ) ); +} + +template +std::string fpToString( T value, int precision ) { + std::ostringstream oss; + oss << std::setprecision( precision ) + << std::fixed + << value; + std::string d = oss.str(); + std::size_t i = d.find_last_not_of( '0' ); + if( i != std::string::npos && i != d.size()-1 ) { + if( d[i] == '.' ) + i++; + d = d.substr( 0, i+1 ); + } + return d; +} + +std::string toString( const double value ) { + return fpToString( value, 10 ); +} +std::string toString( const float value ) { + return fpToString( value, 5 ) + "f"; +} + +std::string toString( bool value ) { + return value ? "true" : "false"; +} + +std::string toString( char value ) { + return value < ' ' + ? toString( static_cast( value ) ) + : Detail::makeString( value ); +} + +std::string toString( signed char value ) { + return toString( static_cast( value ) ); +} + +std::string toString( unsigned char value ) { + return toString( static_cast( value ) ); +} + +#ifdef CATCH_CONFIG_CPP11_LONG_LONG +std::string toString( long long value ) { + std::ostringstream oss; + oss << value; + if( value > Detail::hexThreshold ) + oss << " (0x" << std::hex << value << ")"; + return oss.str(); +} +std::string toString( unsigned long long value ) { + std::ostringstream oss; + oss << value; + if( value > Detail::hexThreshold ) + oss << " (0x" << std::hex << value << ")"; + return oss.str(); +} +#endif + +#ifdef CATCH_CONFIG_CPP11_NULLPTR +std::string toString( std::nullptr_t ) { + return "nullptr"; +} +#endif + +#ifdef __OBJC__ + std::string toString( NSString const * const& nsstring ) { + if( !nsstring ) + return "nil"; + return "@" + toString([nsstring UTF8String]); + } + std::string toString( NSString * CATCH_ARC_STRONG const& nsstring ) { + if( !nsstring ) + return "nil"; + return "@" + toString([nsstring UTF8String]); + } + std::string toString( NSObject* const& nsObject ) { + return toString( [nsObject description] ); + } +#endif + +} // end namespace Catch + +// #included from: catch_result_builder.hpp +#define TWOBLUECUBES_CATCH_RESULT_BUILDER_HPP_INCLUDED + +namespace Catch { + + std::string capturedExpressionWithSecondArgument( std::string const& capturedExpression, std::string const& secondArg ) { + return secondArg.empty() || secondArg == "\"\"" + ? capturedExpression + : capturedExpression + ", " + secondArg; + } + ResultBuilder::ResultBuilder( char const* macroName, + SourceLineInfo const& lineInfo, + char const* capturedExpression, + ResultDisposition::Flags resultDisposition, + char const* secondArg ) + : m_assertionInfo( macroName, lineInfo, capturedExpressionWithSecondArgument( capturedExpression, secondArg ), resultDisposition ), + m_shouldDebugBreak( false ), + m_shouldThrow( false ) + {} + + ResultBuilder& ResultBuilder::setResultType( ResultWas::OfType result ) { + m_data.resultType = result; + return *this; + } + ResultBuilder& ResultBuilder::setResultType( bool result ) { + m_data.resultType = result ? ResultWas::Ok : ResultWas::ExpressionFailed; + return *this; + } + ResultBuilder& ResultBuilder::setLhs( std::string const& lhs ) { + m_exprComponents.lhs = lhs; + return *this; + } + ResultBuilder& ResultBuilder::setRhs( std::string const& rhs ) { + m_exprComponents.rhs = rhs; + return *this; + } + ResultBuilder& ResultBuilder::setOp( std::string const& op ) { + m_exprComponents.op = op; + return *this; + } + + void ResultBuilder::endExpression() { + m_exprComponents.testFalse = isFalseTest( m_assertionInfo.resultDisposition ); + captureExpression(); + } + + void ResultBuilder::useActiveException( ResultDisposition::Flags resultDisposition ) { + m_assertionInfo.resultDisposition = resultDisposition; + m_stream.oss << Catch::translateActiveException(); + captureResult( ResultWas::ThrewException ); + } + + void ResultBuilder::captureResult( ResultWas::OfType resultType ) { + setResultType( resultType ); + captureExpression(); + } + void ResultBuilder::captureExpectedException( std::string const& expectedMessage ) { + if( expectedMessage.empty() ) + captureExpectedException( Matchers::Impl::Generic::AllOf() ); + else + captureExpectedException( Matchers::Equals( expectedMessage ) ); + } + + void ResultBuilder::captureExpectedException( Matchers::Impl::Matcher const& matcher ) { + + assert( m_exprComponents.testFalse == false ); + AssertionResultData data = m_data; + data.resultType = ResultWas::Ok; + data.reconstructedExpression = m_assertionInfo.capturedExpression; + + std::string actualMessage = Catch::translateActiveException(); + if( !matcher.match( actualMessage ) ) { + data.resultType = ResultWas::ExpressionFailed; + data.reconstructedExpression = actualMessage; + } + AssertionResult result( m_assertionInfo, data ); + handleResult( result ); + } + + void ResultBuilder::captureExpression() { + AssertionResult result = build(); + handleResult( result ); + } + void ResultBuilder::handleResult( AssertionResult const& result ) + { + getResultCapture().assertionEnded( result ); + + if( !result.isOk() ) { + if( getCurrentContext().getConfig()->shouldDebugBreak() ) + m_shouldDebugBreak = true; + if( getCurrentContext().getRunner()->aborting() || (m_assertionInfo.resultDisposition & ResultDisposition::Normal) ) + m_shouldThrow = true; + } + } + void ResultBuilder::react() { + if( m_shouldThrow ) + throw Catch::TestFailureException(); + } + + bool ResultBuilder::shouldDebugBreak() const { return m_shouldDebugBreak; } + bool ResultBuilder::allowThrows() const { return getCurrentContext().getConfig()->allowThrows(); } + + AssertionResult ResultBuilder::build() const + { + assert( m_data.resultType != ResultWas::Unknown ); + + AssertionResultData data = m_data; + + // Flip bool results if testFalse is set + if( m_exprComponents.testFalse ) { + if( data.resultType == ResultWas::Ok ) + data.resultType = ResultWas::ExpressionFailed; + else if( data.resultType == ResultWas::ExpressionFailed ) + data.resultType = ResultWas::Ok; + } + + data.message = m_stream.oss.str(); + data.reconstructedExpression = reconstructExpression(); + if( m_exprComponents.testFalse ) { + if( m_exprComponents.op == "" ) + data.reconstructedExpression = "!" + data.reconstructedExpression; + else + data.reconstructedExpression = "!(" + data.reconstructedExpression + ")"; + } + return AssertionResult( m_assertionInfo, data ); + } + std::string ResultBuilder::reconstructExpression() const { + if( m_exprComponents.op == "" ) + return m_exprComponents.lhs.empty() ? m_assertionInfo.capturedExpression : m_exprComponents.op + m_exprComponents.lhs; + else if( m_exprComponents.op == "matches" ) + return m_exprComponents.lhs + " " + m_exprComponents.rhs; + else if( m_exprComponents.op != "!" ) { + if( m_exprComponents.lhs.size() + m_exprComponents.rhs.size() < 40 && + m_exprComponents.lhs.find("\n") == std::string::npos && + m_exprComponents.rhs.find("\n") == std::string::npos ) + return m_exprComponents.lhs + " " + m_exprComponents.op + " " + m_exprComponents.rhs; + else + return m_exprComponents.lhs + "\n" + m_exprComponents.op + "\n" + m_exprComponents.rhs; + } + else + return "{can't expand - use " + m_assertionInfo.macroName + "_FALSE( " + m_assertionInfo.capturedExpression.substr(1) + " ) instead of " + m_assertionInfo.macroName + "( " + m_assertionInfo.capturedExpression + " ) for better diagnostics}"; + } + +} // end namespace Catch + +// #included from: catch_tag_alias_registry.hpp +#define TWOBLUECUBES_CATCH_TAG_ALIAS_REGISTRY_HPP_INCLUDED + +// #included from: catch_tag_alias_registry.h +#define TWOBLUECUBES_CATCH_TAG_ALIAS_REGISTRY_H_INCLUDED + +#include + +namespace Catch { + + class TagAliasRegistry : public ITagAliasRegistry { + public: + virtual ~TagAliasRegistry(); + virtual Option find( std::string const& alias ) const; + virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const; + void add( char const* alias, char const* tag, SourceLineInfo const& lineInfo ); + static TagAliasRegistry& get(); + + private: + std::map m_registry; + }; + +} // end namespace Catch + +#include +#include + +namespace Catch { + + TagAliasRegistry::~TagAliasRegistry() {} + + Option TagAliasRegistry::find( std::string const& alias ) const { + std::map::const_iterator it = m_registry.find( alias ); + if( it != m_registry.end() ) + return it->second; + else + return Option(); + } + + std::string TagAliasRegistry::expandAliases( std::string const& unexpandedTestSpec ) const { + std::string expandedTestSpec = unexpandedTestSpec; + for( std::map::const_iterator it = m_registry.begin(), itEnd = m_registry.end(); + it != itEnd; + ++it ) { + std::size_t pos = expandedTestSpec.find( it->first ); + if( pos != std::string::npos ) { + expandedTestSpec = expandedTestSpec.substr( 0, pos ) + + it->second.tag + + expandedTestSpec.substr( pos + it->first.size() ); + } + } + return expandedTestSpec; + } + + void TagAliasRegistry::add( char const* alias, char const* tag, SourceLineInfo const& lineInfo ) { + + if( !startsWith( alias, "[@" ) || !endsWith( alias, "]" ) ) { + std::ostringstream oss; + oss << "error: tag alias, \"" << alias << "\" is not of the form [@alias name].\n" << lineInfo; + throw std::domain_error( oss.str().c_str() ); + } + if( !m_registry.insert( std::make_pair( alias, TagAlias( tag, lineInfo ) ) ).second ) { + std::ostringstream oss; + oss << "error: tag alias, \"" << alias << "\" already registered.\n" + << "\tFirst seen at " << find(alias)->lineInfo << "\n" + << "\tRedefined at " << lineInfo; + throw std::domain_error( oss.str().c_str() ); + } + } + + TagAliasRegistry& TagAliasRegistry::get() { + static TagAliasRegistry instance; + return instance; + + } + + ITagAliasRegistry::~ITagAliasRegistry() {} + ITagAliasRegistry const& ITagAliasRegistry::get() { return TagAliasRegistry::get(); } + + RegistrarForTagAliases::RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ) { + try { + TagAliasRegistry::get().add( alias, tag, lineInfo ); + } + catch( std::exception& ex ) { + Colour colourGuard( Colour::Red ); + Catch::cerr() << ex.what() << std::endl; + exit(1); + } + } + +} // end namespace Catch + +// #included from: ../reporters/catch_reporter_multi.hpp +#define TWOBLUECUBES_CATCH_REPORTER_MULTI_HPP_INCLUDED + +namespace Catch { + +class MultipleReporters : public SharedImpl { + typedef std::vector > Reporters; + Reporters m_reporters; + +public: + void add( Ptr const& reporter ) { + m_reporters.push_back( reporter ); + } + +public: // IStreamingReporter + + virtual ReporterPreferences getPreferences() const CATCH_OVERRIDE { + return m_reporters[0]->getPreferences(); + } + + virtual void noMatchingTestCases( std::string const& spec ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->noMatchingTestCases( spec ); + } + + virtual void testRunStarting( TestRunInfo const& testRunInfo ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->testRunStarting( testRunInfo ); + } + + virtual void testGroupStarting( GroupInfo const& groupInfo ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->testGroupStarting( groupInfo ); + } + + virtual void testCaseStarting( TestCaseInfo const& testInfo ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->testCaseStarting( testInfo ); + } + + virtual void sectionStarting( SectionInfo const& sectionInfo ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->sectionStarting( sectionInfo ); + } + + virtual void assertionStarting( AssertionInfo const& assertionInfo ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->assertionStarting( assertionInfo ); + } + + // The return value indicates if the messages buffer should be cleared: + virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE { + bool clearBuffer = false; + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + clearBuffer |= (*it)->assertionEnded( assertionStats ); + return clearBuffer; + } + + virtual void sectionEnded( SectionStats const& sectionStats ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->sectionEnded( sectionStats ); + } + + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->testCaseEnded( testCaseStats ); + } + + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->testGroupEnded( testGroupStats ); + } + + virtual void testRunEnded( TestRunStats const& testRunStats ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->testRunEnded( testRunStats ); + } + + virtual void skipTest( TestCaseInfo const& testInfo ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->skipTest( testInfo ); + } +}; + +Ptr addReporter( Ptr const& existingReporter, Ptr const& additionalReporter ) { + Ptr resultingReporter; + + if( existingReporter ) { + MultipleReporters* multi = dynamic_cast( existingReporter.get() ); + if( !multi ) { + multi = new MultipleReporters; + resultingReporter = Ptr( multi ); + if( existingReporter ) + multi->add( existingReporter ); + } + else + resultingReporter = existingReporter; + multi->add( additionalReporter ); + } + else + resultingReporter = additionalReporter; + + return resultingReporter; +} + +} // end namespace Catch + +// #included from: ../reporters/catch_reporter_xml.hpp +#define TWOBLUECUBES_CATCH_REPORTER_XML_HPP_INCLUDED + +// #included from: catch_reporter_bases.hpp +#define TWOBLUECUBES_CATCH_REPORTER_BASES_HPP_INCLUDED + +#include + +namespace Catch { + + struct StreamingReporterBase : SharedImpl { + + StreamingReporterBase( ReporterConfig const& _config ) + : m_config( _config.fullConfig() ), + stream( _config.stream() ) + { + m_reporterPrefs.shouldRedirectStdOut = false; + } + + virtual ReporterPreferences getPreferences() const CATCH_OVERRIDE { + return m_reporterPrefs; + } + + virtual ~StreamingReporterBase() CATCH_OVERRIDE; + + virtual void noMatchingTestCases( std::string const& ) CATCH_OVERRIDE {} + + virtual void testRunStarting( TestRunInfo const& _testRunInfo ) CATCH_OVERRIDE { + currentTestRunInfo = _testRunInfo; + } + virtual void testGroupStarting( GroupInfo const& _groupInfo ) CATCH_OVERRIDE { + currentGroupInfo = _groupInfo; + } + + virtual void testCaseStarting( TestCaseInfo const& _testInfo ) CATCH_OVERRIDE { + currentTestCaseInfo = _testInfo; + } + virtual void sectionStarting( SectionInfo const& _sectionInfo ) CATCH_OVERRIDE { + m_sectionStack.push_back( _sectionInfo ); + } + + virtual void sectionEnded( SectionStats const& /* _sectionStats */ ) CATCH_OVERRIDE { + m_sectionStack.pop_back(); + } + virtual void testCaseEnded( TestCaseStats const& /* _testCaseStats */ ) CATCH_OVERRIDE { + currentTestCaseInfo.reset(); + } + virtual void testGroupEnded( TestGroupStats const& /* _testGroupStats */ ) CATCH_OVERRIDE { + currentGroupInfo.reset(); + } + virtual void testRunEnded( TestRunStats const& /* _testRunStats */ ) CATCH_OVERRIDE { + currentTestCaseInfo.reset(); + currentGroupInfo.reset(); + currentTestRunInfo.reset(); + } + + virtual void skipTest( TestCaseInfo const& ) CATCH_OVERRIDE { + // Don't do anything with this by default. + // It can optionally be overridden in the derived class. + } + + Ptr m_config; + std::ostream& stream; + + LazyStat currentTestRunInfo; + LazyStat currentGroupInfo; + LazyStat currentTestCaseInfo; + + std::vector m_sectionStack; + ReporterPreferences m_reporterPrefs; + }; + + struct CumulativeReporterBase : SharedImpl { + template + struct Node : SharedImpl<> { + explicit Node( T const& _value ) : value( _value ) {} + virtual ~Node() {} + + typedef std::vector > ChildNodes; + T value; + ChildNodes children; + }; + struct SectionNode : SharedImpl<> { + explicit SectionNode( SectionStats const& _stats ) : stats( _stats ) {} + virtual ~SectionNode(); + + bool operator == ( SectionNode const& other ) const { + return stats.sectionInfo.lineInfo == other.stats.sectionInfo.lineInfo; + } + bool operator == ( Ptr const& other ) const { + return operator==( *other ); + } + + SectionStats stats; + typedef std::vector > ChildSections; + typedef std::vector Assertions; + ChildSections childSections; + Assertions assertions; + std::string stdOut; + std::string stdErr; + }; + + struct BySectionInfo { + BySectionInfo( SectionInfo const& other ) : m_other( other ) {} + BySectionInfo( BySectionInfo const& other ) : m_other( other.m_other ) {} + bool operator() ( Ptr const& node ) const { + return node->stats.sectionInfo.lineInfo == m_other.lineInfo; + } + private: + void operator=( BySectionInfo const& ); + SectionInfo const& m_other; + }; + + typedef Node TestCaseNode; + typedef Node TestGroupNode; + typedef Node TestRunNode; + + CumulativeReporterBase( ReporterConfig const& _config ) + : m_config( _config.fullConfig() ), + stream( _config.stream() ) + { + m_reporterPrefs.shouldRedirectStdOut = false; + } + ~CumulativeReporterBase(); + + virtual ReporterPreferences getPreferences() const CATCH_OVERRIDE { + return m_reporterPrefs; + } + + virtual void testRunStarting( TestRunInfo const& ) CATCH_OVERRIDE {} + virtual void testGroupStarting( GroupInfo const& ) CATCH_OVERRIDE {} + + virtual void testCaseStarting( TestCaseInfo const& ) CATCH_OVERRIDE {} + + virtual void sectionStarting( SectionInfo const& sectionInfo ) CATCH_OVERRIDE { + SectionStats incompleteStats( sectionInfo, Counts(), 0, false ); + Ptr node; + if( m_sectionStack.empty() ) { + if( !m_rootSection ) + m_rootSection = new SectionNode( incompleteStats ); + node = m_rootSection; + } + else { + SectionNode& parentNode = *m_sectionStack.back(); + SectionNode::ChildSections::const_iterator it = + std::find_if( parentNode.childSections.begin(), + parentNode.childSections.end(), + BySectionInfo( sectionInfo ) ); + if( it == parentNode.childSections.end() ) { + node = new SectionNode( incompleteStats ); + parentNode.childSections.push_back( node ); + } + else + node = *it; + } + m_sectionStack.push_back( node ); + m_deepestSection = node; + } + + virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE {} + + virtual bool assertionEnded( AssertionStats const& assertionStats ) { + assert( !m_sectionStack.empty() ); + SectionNode& sectionNode = *m_sectionStack.back(); + sectionNode.assertions.push_back( assertionStats ); + return true; + } + virtual void sectionEnded( SectionStats const& sectionStats ) CATCH_OVERRIDE { + assert( !m_sectionStack.empty() ); + SectionNode& node = *m_sectionStack.back(); + node.stats = sectionStats; + m_sectionStack.pop_back(); + } + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE { + Ptr node = new TestCaseNode( testCaseStats ); + assert( m_sectionStack.size() == 0 ); + node->children.push_back( m_rootSection ); + m_testCases.push_back( node ); + m_rootSection.reset(); + + assert( m_deepestSection ); + m_deepestSection->stdOut = testCaseStats.stdOut; + m_deepestSection->stdErr = testCaseStats.stdErr; + } + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE { + Ptr node = new TestGroupNode( testGroupStats ); + node->children.swap( m_testCases ); + m_testGroups.push_back( node ); + } + virtual void testRunEnded( TestRunStats const& testRunStats ) CATCH_OVERRIDE { + Ptr node = new TestRunNode( testRunStats ); + node->children.swap( m_testGroups ); + m_testRuns.push_back( node ); + testRunEndedCumulative(); + } + virtual void testRunEndedCumulative() = 0; + + virtual void skipTest( TestCaseInfo const& ) CATCH_OVERRIDE {} + + Ptr m_config; + std::ostream& stream; + std::vector m_assertions; + std::vector > > m_sections; + std::vector > m_testCases; + std::vector > m_testGroups; + + std::vector > m_testRuns; + + Ptr m_rootSection; + Ptr m_deepestSection; + std::vector > m_sectionStack; + ReporterPreferences m_reporterPrefs; + + }; + + template + char const* getLineOfChars() { + static char line[CATCH_CONFIG_CONSOLE_WIDTH] = {0}; + if( !*line ) { + memset( line, C, CATCH_CONFIG_CONSOLE_WIDTH-1 ); + line[CATCH_CONFIG_CONSOLE_WIDTH-1] = 0; + } + return line; + } + + struct TestEventListenerBase : StreamingReporterBase { + TestEventListenerBase( ReporterConfig const& _config ) + : StreamingReporterBase( _config ) + {} + + virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE {} + virtual bool assertionEnded( AssertionStats const& ) CATCH_OVERRIDE { + return false; + } + }; + +} // end namespace Catch + +// #included from: ../internal/catch_reporter_registrars.hpp +#define TWOBLUECUBES_CATCH_REPORTER_REGISTRARS_HPP_INCLUDED + +namespace Catch { + + template + class LegacyReporterRegistrar { + + class ReporterFactory : public IReporterFactory { + virtual IStreamingReporter* create( ReporterConfig const& config ) const { + return new LegacyReporterAdapter( new T( config ) ); + } + + virtual std::string getDescription() const { + return T::getDescription(); + } + }; + + public: + + LegacyReporterRegistrar( std::string const& name ) { + getMutableRegistryHub().registerReporter( name, new ReporterFactory() ); + } + }; + + template + class ReporterRegistrar { + + class ReporterFactory : public SharedImpl { + + // *** Please Note ***: + // - If you end up here looking at a compiler error because it's trying to register + // your custom reporter class be aware that the native reporter interface has changed + // to IStreamingReporter. The "legacy" interface, IReporter, is still supported via + // an adapter. Just use REGISTER_LEGACY_REPORTER to take advantage of the adapter. + // However please consider updating to the new interface as the old one is now + // deprecated and will probably be removed quite soon! + // Please contact me via github if you have any questions at all about this. + // In fact, ideally, please contact me anyway to let me know you've hit this - as I have + // no idea who is actually using custom reporters at all (possibly no-one!). + // The new interface is designed to minimise exposure to interface changes in the future. + virtual IStreamingReporter* create( ReporterConfig const& config ) const { + return new T( config ); + } + + virtual std::string getDescription() const { + return T::getDescription(); + } + }; + + public: + + ReporterRegistrar( std::string const& name ) { + getMutableRegistryHub().registerReporter( name, new ReporterFactory() ); + } + }; + + template + class ListenerRegistrar { + + class ListenerFactory : public SharedImpl { + + virtual IStreamingReporter* create( ReporterConfig const& config ) const { + return new T( config ); + } + virtual std::string getDescription() const { + return ""; + } + }; + + public: + + ListenerRegistrar() { + getMutableRegistryHub().registerListener( new ListenerFactory() ); + } + }; +} + +#define INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) \ + namespace{ Catch::LegacyReporterRegistrar catch_internal_RegistrarFor##reporterType( name ); } + +#define INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) \ + namespace{ Catch::ReporterRegistrar catch_internal_RegistrarFor##reporterType( name ); } + +#define INTERNAL_CATCH_REGISTER_LISTENER( listenerType ) \ + namespace{ Catch::ListenerRegistrar catch_internal_RegistrarFor##listenerType; } + +// #included from: ../internal/catch_xmlwriter.hpp +#define TWOBLUECUBES_CATCH_XMLWRITER_HPP_INCLUDED + +#include +#include +#include +#include + +namespace Catch { + + class XmlEncode { + public: + enum ForWhat { ForTextNodes, ForAttributes }; + + XmlEncode( std::string const& str, ForWhat forWhat = ForTextNodes ) + : m_str( str ), + m_forWhat( forWhat ) + {} + + void encodeTo( std::ostream& os ) const { + + // Apostrophe escaping not necessary if we always use " to write attributes + // (see: http://www.w3.org/TR/xml/#syntax) + + for( std::size_t i = 0; i < m_str.size(); ++ i ) { + char c = m_str[i]; + switch( c ) { + case '<': os << "<"; break; + case '&': os << "&"; break; + + case '>': + // See: http://www.w3.org/TR/xml/#syntax + if( i > 2 && m_str[i-1] == ']' && m_str[i-2] == ']' ) + os << ">"; + else + os << c; + break; + + case '\"': + if( m_forWhat == ForAttributes ) + os << """; + else + os << c; + break; + + default: + // Escape control chars - based on contribution by @espenalb in PR #465 + if ( ( c < '\x09' ) || ( c > '\x0D' && c < '\x20') || c=='\x7F' ) + os << "&#x" << std::uppercase << std::hex << static_cast( c ); + else + os << c; + } + } + } + + friend std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ) { + xmlEncode.encodeTo( os ); + return os; + } + + private: + std::string m_str; + ForWhat m_forWhat; + }; + + class XmlWriter { + public: + + class ScopedElement { + public: + ScopedElement( XmlWriter* writer ) + : m_writer( writer ) + {} + + ScopedElement( ScopedElement const& other ) + : m_writer( other.m_writer ){ + other.m_writer = CATCH_NULL; + } + + ~ScopedElement() { + if( m_writer ) + m_writer->endElement(); + } + + ScopedElement& writeText( std::string const& text, bool indent = true ) { + m_writer->writeText( text, indent ); + return *this; + } + + template + ScopedElement& writeAttribute( std::string const& name, T const& attribute ) { + m_writer->writeAttribute( name, attribute ); + return *this; + } + + private: + mutable XmlWriter* m_writer; + }; + + XmlWriter() + : m_tagIsOpen( false ), + m_needsNewline( false ), + m_os( &Catch::cout() ) + {} + + XmlWriter( std::ostream& os ) + : m_tagIsOpen( false ), + m_needsNewline( false ), + m_os( &os ) + {} + + ~XmlWriter() { + while( !m_tags.empty() ) + endElement(); + } + + XmlWriter& startElement( std::string const& name ) { + ensureTagClosed(); + newlineIfNecessary(); + stream() << m_indent << "<" << name; + m_tags.push_back( name ); + m_indent += " "; + m_tagIsOpen = true; + return *this; + } + + ScopedElement scopedElement( std::string const& name ) { + ScopedElement scoped( this ); + startElement( name ); + return scoped; + } + + XmlWriter& endElement() { + newlineIfNecessary(); + m_indent = m_indent.substr( 0, m_indent.size()-2 ); + if( m_tagIsOpen ) { + stream() << "/>\n"; + m_tagIsOpen = false; + } + else { + stream() << m_indent << "\n"; + } + m_tags.pop_back(); + return *this; + } + + XmlWriter& writeAttribute( std::string const& name, std::string const& attribute ) { + if( !name.empty() && !attribute.empty() ) + stream() << " " << name << "=\"" << XmlEncode( attribute, XmlEncode::ForAttributes ) << "\""; + return *this; + } + + XmlWriter& writeAttribute( std::string const& name, bool attribute ) { + stream() << " " << name << "=\"" << ( attribute ? "true" : "false" ) << "\""; + return *this; + } + + template + XmlWriter& writeAttribute( std::string const& name, T const& attribute ) { + std::ostringstream oss; + oss << attribute; + return writeAttribute( name, oss.str() ); + } + + XmlWriter& writeText( std::string const& text, bool indent = true ) { + if( !text.empty() ){ + bool tagWasOpen = m_tagIsOpen; + ensureTagClosed(); + if( tagWasOpen && indent ) + stream() << m_indent; + stream() << XmlEncode( text ); + m_needsNewline = true; + } + return *this; + } + + XmlWriter& writeComment( std::string const& text ) { + ensureTagClosed(); + stream() << m_indent << ""; + m_needsNewline = true; + return *this; + } + + XmlWriter& writeBlankLine() { + ensureTagClosed(); + stream() << "\n"; + return *this; + } + + void setStream( std::ostream& os ) { + m_os = &os; + } + + private: + XmlWriter( XmlWriter const& ); + void operator=( XmlWriter const& ); + + std::ostream& stream() { + return *m_os; + } + + void ensureTagClosed() { + if( m_tagIsOpen ) { + stream() << ">\n"; + m_tagIsOpen = false; + } + } + + void newlineIfNecessary() { + if( m_needsNewline ) { + stream() << "\n"; + m_needsNewline = false; + } + } + + bool m_tagIsOpen; + bool m_needsNewline; + std::vector m_tags; + std::string m_indent; + std::ostream* m_os; + }; + +} +// #included from: catch_reenable_warnings.h + +#define TWOBLUECUBES_CATCH_REENABLE_WARNINGS_H_INCLUDED + +#ifdef __clang__ +# ifdef __ICC // icpc defines the __clang__ macro +# pragma warning(pop) +# else +# pragma clang diagnostic pop +# endif +#elif defined __GNUC__ +# pragma GCC diagnostic pop +#endif + + +namespace Catch { + class XmlReporter : public StreamingReporterBase { + public: + XmlReporter( ReporterConfig const& _config ) + : StreamingReporterBase( _config ), + m_sectionDepth( 0 ) + { + m_reporterPrefs.shouldRedirectStdOut = true; + } + + virtual ~XmlReporter() CATCH_OVERRIDE; + + static std::string getDescription() { + return "Reports test results as an XML document"; + } + + public: // StreamingReporterBase + + virtual void noMatchingTestCases( std::string const& s ) CATCH_OVERRIDE { + StreamingReporterBase::noMatchingTestCases( s ); + } + + virtual void testRunStarting( TestRunInfo const& testInfo ) CATCH_OVERRIDE { + StreamingReporterBase::testRunStarting( testInfo ); + m_xml.setStream( stream ); + m_xml.startElement( "Catch" ); + if( !m_config->name().empty() ) + m_xml.writeAttribute( "name", m_config->name() ); + } + + virtual void testGroupStarting( GroupInfo const& groupInfo ) CATCH_OVERRIDE { + StreamingReporterBase::testGroupStarting( groupInfo ); + m_xml.startElement( "Group" ) + .writeAttribute( "name", groupInfo.name ); + } + + virtual void testCaseStarting( TestCaseInfo const& testInfo ) CATCH_OVERRIDE { + StreamingReporterBase::testCaseStarting(testInfo); + m_xml.startElement( "TestCase" ).writeAttribute( "name", trim( testInfo.name ) ); + + if ( m_config->showDurations() == ShowDurations::Always ) + m_testCaseTimer.start(); + } + + virtual void sectionStarting( SectionInfo const& sectionInfo ) CATCH_OVERRIDE { + StreamingReporterBase::sectionStarting( sectionInfo ); + if( m_sectionDepth++ > 0 ) { + m_xml.startElement( "Section" ) + .writeAttribute( "name", trim( sectionInfo.name ) ) + .writeAttribute( "description", sectionInfo.description ); + } + } + + virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE { } + + virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE { + const AssertionResult& assertionResult = assertionStats.assertionResult; + + // Print any info messages in tags. + if( assertionStats.assertionResult.getResultType() != ResultWas::Ok ) { + for( std::vector::const_iterator it = assertionStats.infoMessages.begin(), itEnd = assertionStats.infoMessages.end(); + it != itEnd; + ++it ) { + if( it->type == ResultWas::Info ) { + m_xml.scopedElement( "Info" ) + .writeText( it->message ); + } else if ( it->type == ResultWas::Warning ) { + m_xml.scopedElement( "Warning" ) + .writeText( it->message ); + } + } + } + + // Drop out if result was successful but we're not printing them. + if( !m_config->includeSuccessfulResults() && isOk(assertionResult.getResultType()) ) + return true; + + // Print the expression if there is one. + if( assertionResult.hasExpression() ) { + m_xml.startElement( "Expression" ) + .writeAttribute( "success", assertionResult.succeeded() ) + .writeAttribute( "type", assertionResult.getTestMacroName() ) + .writeAttribute( "filename", assertionResult.getSourceInfo().file ) + .writeAttribute( "line", assertionResult.getSourceInfo().line ); + + m_xml.scopedElement( "Original" ) + .writeText( assertionResult.getExpression() ); + m_xml.scopedElement( "Expanded" ) + .writeText( assertionResult.getExpandedExpression() ); + } + + // And... Print a result applicable to each result type. + switch( assertionResult.getResultType() ) { + case ResultWas::ThrewException: + m_xml.scopedElement( "Exception" ) + .writeAttribute( "filename", assertionResult.getSourceInfo().file ) + .writeAttribute( "line", assertionResult.getSourceInfo().line ) + .writeText( assertionResult.getMessage() ); + break; + case ResultWas::FatalErrorCondition: + m_xml.scopedElement( "Fatal Error Condition" ) + .writeAttribute( "filename", assertionResult.getSourceInfo().file ) + .writeAttribute( "line", assertionResult.getSourceInfo().line ) + .writeText( assertionResult.getMessage() ); + break; + case ResultWas::Info: + m_xml.scopedElement( "Info" ) + .writeText( assertionResult.getMessage() ); + break; + case ResultWas::Warning: + // Warning will already have been written + break; + case ResultWas::ExplicitFailure: + m_xml.scopedElement( "Failure" ) + .writeText( assertionResult.getMessage() ); + break; + default: + break; + } + + if( assertionResult.hasExpression() ) + m_xml.endElement(); + + return true; + } + + virtual void sectionEnded( SectionStats const& sectionStats ) CATCH_OVERRIDE { + StreamingReporterBase::sectionEnded( sectionStats ); + if( --m_sectionDepth > 0 ) { + XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResults" ); + e.writeAttribute( "successes", sectionStats.assertions.passed ); + e.writeAttribute( "failures", sectionStats.assertions.failed ); + e.writeAttribute( "expectedFailures", sectionStats.assertions.failedButOk ); + + if ( m_config->showDurations() == ShowDurations::Always ) + e.writeAttribute( "durationInSeconds", sectionStats.durationInSeconds ); + + m_xml.endElement(); + } + } + + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE { + StreamingReporterBase::testCaseEnded( testCaseStats ); + XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResult" ); + e.writeAttribute( "success", testCaseStats.totals.assertions.allOk() ); + + if ( m_config->showDurations() == ShowDurations::Always ) + e.writeAttribute( "durationInSeconds", m_testCaseTimer.getElapsedSeconds() ); + + m_xml.endElement(); + } + + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE { + StreamingReporterBase::testGroupEnded( testGroupStats ); + // TODO: Check testGroupStats.aborting and act accordingly. + m_xml.scopedElement( "OverallResults" ) + .writeAttribute( "successes", testGroupStats.totals.assertions.passed ) + .writeAttribute( "failures", testGroupStats.totals.assertions.failed ) + .writeAttribute( "expectedFailures", testGroupStats.totals.assertions.failedButOk ); + m_xml.endElement(); + } + + virtual void testRunEnded( TestRunStats const& testRunStats ) CATCH_OVERRIDE { + StreamingReporterBase::testRunEnded( testRunStats ); + m_xml.scopedElement( "OverallResults" ) + .writeAttribute( "successes", testRunStats.totals.assertions.passed ) + .writeAttribute( "failures", testRunStats.totals.assertions.failed ) + .writeAttribute( "expectedFailures", testRunStats.totals.assertions.failedButOk ); + m_xml.endElement(); + } + + private: + Timer m_testCaseTimer; + XmlWriter m_xml; + int m_sectionDepth; + }; + + INTERNAL_CATCH_REGISTER_REPORTER( "xml", XmlReporter ) + +} // end namespace Catch + +// #included from: ../reporters/catch_reporter_junit.hpp +#define TWOBLUECUBES_CATCH_REPORTER_JUNIT_HPP_INCLUDED + +#include + +namespace Catch { + + class JunitReporter : public CumulativeReporterBase { + public: + JunitReporter( ReporterConfig const& _config ) + : CumulativeReporterBase( _config ), + xml( _config.stream() ) + { + m_reporterPrefs.shouldRedirectStdOut = true; + } + + virtual ~JunitReporter() CATCH_OVERRIDE; + + static std::string getDescription() { + return "Reports test results in an XML format that looks like Ant's junitreport target"; + } + + virtual void noMatchingTestCases( std::string const& /*spec*/ ) CATCH_OVERRIDE {} + + virtual void testRunStarting( TestRunInfo const& runInfo ) CATCH_OVERRIDE { + CumulativeReporterBase::testRunStarting( runInfo ); + xml.startElement( "testsuites" ); + } + + virtual void testGroupStarting( GroupInfo const& groupInfo ) CATCH_OVERRIDE { + suiteTimer.start(); + stdOutForSuite.str(""); + stdErrForSuite.str(""); + unexpectedExceptions = 0; + CumulativeReporterBase::testGroupStarting( groupInfo ); + } + + virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE { + if( assertionStats.assertionResult.getResultType() == ResultWas::ThrewException ) + unexpectedExceptions++; + return CumulativeReporterBase::assertionEnded( assertionStats ); + } + + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE { + stdOutForSuite << testCaseStats.stdOut; + stdErrForSuite << testCaseStats.stdErr; + CumulativeReporterBase::testCaseEnded( testCaseStats ); + } + + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE { + double suiteTime = suiteTimer.getElapsedSeconds(); + CumulativeReporterBase::testGroupEnded( testGroupStats ); + writeGroup( *m_testGroups.back(), suiteTime ); + } + + virtual void testRunEndedCumulative() CATCH_OVERRIDE { + xml.endElement(); + } + + void writeGroup( TestGroupNode const& groupNode, double suiteTime ) { + XmlWriter::ScopedElement e = xml.scopedElement( "testsuite" ); + TestGroupStats const& stats = groupNode.value; + xml.writeAttribute( "name", stats.groupInfo.name ); + xml.writeAttribute( "errors", unexpectedExceptions ); + xml.writeAttribute( "failures", stats.totals.assertions.failed-unexpectedExceptions ); + xml.writeAttribute( "tests", stats.totals.assertions.total() ); + xml.writeAttribute( "hostname", "tbd" ); // !TBD + if( m_config->showDurations() == ShowDurations::Never ) + xml.writeAttribute( "time", "" ); + else + xml.writeAttribute( "time", suiteTime ); + xml.writeAttribute( "timestamp", "tbd" ); // !TBD + + // Write test cases + for( TestGroupNode::ChildNodes::const_iterator + it = groupNode.children.begin(), itEnd = groupNode.children.end(); + it != itEnd; + ++it ) + writeTestCase( **it ); + + xml.scopedElement( "system-out" ).writeText( trim( stdOutForSuite.str() ), false ); + xml.scopedElement( "system-err" ).writeText( trim( stdErrForSuite.str() ), false ); + } + + void writeTestCase( TestCaseNode const& testCaseNode ) { + TestCaseStats const& stats = testCaseNode.value; + + // All test cases have exactly one section - which represents the + // test case itself. That section may have 0-n nested sections + assert( testCaseNode.children.size() == 1 ); + SectionNode const& rootSection = *testCaseNode.children.front(); + + std::string className = stats.testInfo.className; + + if( className.empty() ) { + if( rootSection.childSections.empty() ) + className = "global"; + } + writeSection( className, "", rootSection ); + } + + void writeSection( std::string const& className, + std::string const& rootName, + SectionNode const& sectionNode ) { + std::string name = trim( sectionNode.stats.sectionInfo.name ); + if( !rootName.empty() ) + name = rootName + "/" + name; + + if( !sectionNode.assertions.empty() || + !sectionNode.stdOut.empty() || + !sectionNode.stdErr.empty() ) { + XmlWriter::ScopedElement e = xml.scopedElement( "testcase" ); + if( className.empty() ) { + xml.writeAttribute( "classname", name ); + xml.writeAttribute( "name", "root" ); + } + else { + xml.writeAttribute( "classname", className ); + xml.writeAttribute( "name", name ); + } + xml.writeAttribute( "time", Catch::toString( sectionNode.stats.durationInSeconds ) ); + + writeAssertions( sectionNode ); + + if( !sectionNode.stdOut.empty() ) + xml.scopedElement( "system-out" ).writeText( trim( sectionNode.stdOut ), false ); + if( !sectionNode.stdErr.empty() ) + xml.scopedElement( "system-err" ).writeText( trim( sectionNode.stdErr ), false ); + } + for( SectionNode::ChildSections::const_iterator + it = sectionNode.childSections.begin(), + itEnd = sectionNode.childSections.end(); + it != itEnd; + ++it ) + if( className.empty() ) + writeSection( name, "", **it ); + else + writeSection( className, name, **it ); + } + + void writeAssertions( SectionNode const& sectionNode ) { + for( SectionNode::Assertions::const_iterator + it = sectionNode.assertions.begin(), itEnd = sectionNode.assertions.end(); + it != itEnd; + ++it ) + writeAssertion( *it ); + } + void writeAssertion( AssertionStats const& stats ) { + AssertionResult const& result = stats.assertionResult; + if( !result.isOk() ) { + std::string elementName; + switch( result.getResultType() ) { + case ResultWas::ThrewException: + case ResultWas::FatalErrorCondition: + elementName = "error"; + break; + case ResultWas::ExplicitFailure: + elementName = "failure"; + break; + case ResultWas::ExpressionFailed: + elementName = "failure"; + break; + case ResultWas::DidntThrowException: + elementName = "failure"; + break; + + // We should never see these here: + case ResultWas::Info: + case ResultWas::Warning: + case ResultWas::Ok: + case ResultWas::Unknown: + case ResultWas::FailureBit: + case ResultWas::Exception: + elementName = "internalError"; + break; + } + + XmlWriter::ScopedElement e = xml.scopedElement( elementName ); + + xml.writeAttribute( "message", result.getExpandedExpression() ); + xml.writeAttribute( "type", result.getTestMacroName() ); + + std::ostringstream oss; + if( !result.getMessage().empty() ) + oss << result.getMessage() << "\n"; + for( std::vector::const_iterator + it = stats.infoMessages.begin(), + itEnd = stats.infoMessages.end(); + it != itEnd; + ++it ) + if( it->type == ResultWas::Info ) + oss << it->message << "\n"; + + oss << "at " << result.getSourceInfo(); + xml.writeText( oss.str(), false ); + } + } + + XmlWriter xml; + Timer suiteTimer; + std::ostringstream stdOutForSuite; + std::ostringstream stdErrForSuite; + unsigned int unexpectedExceptions; + }; + + INTERNAL_CATCH_REGISTER_REPORTER( "junit", JunitReporter ) + +} // end namespace Catch + +// #included from: ../reporters/catch_reporter_console.hpp +#define TWOBLUECUBES_CATCH_REPORTER_CONSOLE_HPP_INCLUDED + +namespace Catch { + + struct ConsoleReporter : StreamingReporterBase { + ConsoleReporter( ReporterConfig const& _config ) + : StreamingReporterBase( _config ), + m_headerPrinted( false ) + {} + + virtual ~ConsoleReporter() CATCH_OVERRIDE; + static std::string getDescription() { + return "Reports test results as plain lines of text"; + } + + virtual void noMatchingTestCases( std::string const& spec ) CATCH_OVERRIDE { + stream << "No test cases matched '" << spec << "'" << std::endl; + } + + virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE { + } + + virtual bool assertionEnded( AssertionStats const& _assertionStats ) CATCH_OVERRIDE { + AssertionResult const& result = _assertionStats.assertionResult; + + bool printInfoMessages = true; + + // Drop out if result was successful and we're not printing those + if( !m_config->includeSuccessfulResults() && result.isOk() ) { + if( result.getResultType() != ResultWas::Warning ) + return false; + printInfoMessages = false; + } + + lazyPrint(); + + AssertionPrinter printer( stream, _assertionStats, printInfoMessages ); + printer.print(); + stream << std::endl; + return true; + } + + virtual void sectionStarting( SectionInfo const& _sectionInfo ) CATCH_OVERRIDE { + m_headerPrinted = false; + StreamingReporterBase::sectionStarting( _sectionInfo ); + } + virtual void sectionEnded( SectionStats const& _sectionStats ) CATCH_OVERRIDE { + if( _sectionStats.missingAssertions ) { + lazyPrint(); + Colour colour( Colour::ResultError ); + if( m_sectionStack.size() > 1 ) + stream << "\nNo assertions in section"; + else + stream << "\nNo assertions in test case"; + stream << " '" << _sectionStats.sectionInfo.name << "'\n" << std::endl; + } + if( m_headerPrinted ) { + if( m_config->showDurations() == ShowDurations::Always ) + stream << "Completed in " << _sectionStats.durationInSeconds << "s" << std::endl; + m_headerPrinted = false; + } + else { + if( m_config->showDurations() == ShowDurations::Always ) + stream << _sectionStats.sectionInfo.name << " completed in " << _sectionStats.durationInSeconds << "s" << std::endl; + } + StreamingReporterBase::sectionEnded( _sectionStats ); + } + + virtual void testCaseEnded( TestCaseStats const& _testCaseStats ) CATCH_OVERRIDE { + StreamingReporterBase::testCaseEnded( _testCaseStats ); + m_headerPrinted = false; + } + virtual void testGroupEnded( TestGroupStats const& _testGroupStats ) CATCH_OVERRIDE { + if( currentGroupInfo.used ) { + printSummaryDivider(); + stream << "Summary for group '" << _testGroupStats.groupInfo.name << "':\n"; + printTotals( _testGroupStats.totals ); + stream << "\n" << std::endl; + } + StreamingReporterBase::testGroupEnded( _testGroupStats ); + } + virtual void testRunEnded( TestRunStats const& _testRunStats ) CATCH_OVERRIDE { + printTotalsDivider( _testRunStats.totals ); + printTotals( _testRunStats.totals ); + stream << std::endl; + StreamingReporterBase::testRunEnded( _testRunStats ); + } + + private: + + class AssertionPrinter { + void operator= ( AssertionPrinter const& ); + public: + AssertionPrinter( std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages ) + : stream( _stream ), + stats( _stats ), + result( _stats.assertionResult ), + colour( Colour::None ), + message( result.getMessage() ), + messages( _stats.infoMessages ), + printInfoMessages( _printInfoMessages ) + { + switch( result.getResultType() ) { + case ResultWas::Ok: + colour = Colour::Success; + passOrFail = "PASSED"; + //if( result.hasMessage() ) + if( _stats.infoMessages.size() == 1 ) + messageLabel = "with message"; + if( _stats.infoMessages.size() > 1 ) + messageLabel = "with messages"; + break; + case ResultWas::ExpressionFailed: + if( result.isOk() ) { + colour = Colour::Success; + passOrFail = "FAILED - but was ok"; + } + else { + colour = Colour::Error; + passOrFail = "FAILED"; + } + if( _stats.infoMessages.size() == 1 ) + messageLabel = "with message"; + if( _stats.infoMessages.size() > 1 ) + messageLabel = "with messages"; + break; + case ResultWas::ThrewException: + colour = Colour::Error; + passOrFail = "FAILED"; + messageLabel = "due to unexpected exception with message"; + break; + case ResultWas::FatalErrorCondition: + colour = Colour::Error; + passOrFail = "FAILED"; + messageLabel = "due to a fatal error condition"; + break; + case ResultWas::DidntThrowException: + colour = Colour::Error; + passOrFail = "FAILED"; + messageLabel = "because no exception was thrown where one was expected"; + break; + case ResultWas::Info: + messageLabel = "info"; + break; + case ResultWas::Warning: + messageLabel = "warning"; + break; + case ResultWas::ExplicitFailure: + passOrFail = "FAILED"; + colour = Colour::Error; + if( _stats.infoMessages.size() == 1 ) + messageLabel = "explicitly with message"; + if( _stats.infoMessages.size() > 1 ) + messageLabel = "explicitly with messages"; + break; + // These cases are here to prevent compiler warnings + case ResultWas::Unknown: + case ResultWas::FailureBit: + case ResultWas::Exception: + passOrFail = "** internal error **"; + colour = Colour::Error; + break; + } + } + + void print() const { + printSourceInfo(); + if( stats.totals.assertions.total() > 0 ) { + if( result.isOk() ) + stream << "\n"; + printResultType(); + printOriginalExpression(); + printReconstructedExpression(); + } + else { + stream << "\n"; + } + printMessage(); + } + + private: + void printResultType() const { + if( !passOrFail.empty() ) { + Colour colourGuard( colour ); + stream << passOrFail << ":\n"; + } + } + void printOriginalExpression() const { + if( result.hasExpression() ) { + Colour colourGuard( Colour::OriginalExpression ); + stream << " "; + stream << result.getExpressionInMacro(); + stream << "\n"; + } + } + void printReconstructedExpression() const { + if( result.hasExpandedExpression() ) { + stream << "with expansion:\n"; + Colour colourGuard( Colour::ReconstructedExpression ); + stream << Text( result.getExpandedExpression(), TextAttributes().setIndent(2) ) << "\n"; + } + } + void printMessage() const { + if( !messageLabel.empty() ) + stream << messageLabel << ":" << "\n"; + for( std::vector::const_iterator it = messages.begin(), itEnd = messages.end(); + it != itEnd; + ++it ) { + // If this assertion is a warning ignore any INFO messages + if( printInfoMessages || it->type != ResultWas::Info ) + stream << Text( it->message, TextAttributes().setIndent(2) ) << "\n"; + } + } + void printSourceInfo() const { + Colour colourGuard( Colour::FileName ); + stream << result.getSourceInfo() << ": "; + } + + std::ostream& stream; + AssertionStats const& stats; + AssertionResult const& result; + Colour::Code colour; + std::string passOrFail; + std::string messageLabel; + std::string message; + std::vector messages; + bool printInfoMessages; + }; + + void lazyPrint() { + + if( !currentTestRunInfo.used ) + lazyPrintRunInfo(); + if( !currentGroupInfo.used ) + lazyPrintGroupInfo(); + + if( !m_headerPrinted ) { + printTestCaseAndSectionHeader(); + m_headerPrinted = true; + } + } + void lazyPrintRunInfo() { + stream << "\n" << getLineOfChars<'~'>() << "\n"; + Colour colour( Colour::SecondaryText ); + stream << currentTestRunInfo->name + << " is a Catch v" << libraryVersion << " host application.\n" + << "Run with -? for options\n\n"; + + if( m_config->rngSeed() != 0 ) + stream << "Randomness seeded to: " << m_config->rngSeed() << "\n\n"; + + currentTestRunInfo.used = true; + } + void lazyPrintGroupInfo() { + if( !currentGroupInfo->name.empty() && currentGroupInfo->groupsCounts > 1 ) { + printClosedHeader( "Group: " + currentGroupInfo->name ); + currentGroupInfo.used = true; + } + } + void printTestCaseAndSectionHeader() { + assert( !m_sectionStack.empty() ); + printOpenHeader( currentTestCaseInfo->name ); + + if( m_sectionStack.size() > 1 ) { + Colour colourGuard( Colour::Headers ); + + std::vector::const_iterator + it = m_sectionStack.begin()+1, // Skip first section (test case) + itEnd = m_sectionStack.end(); + for( ; it != itEnd; ++it ) + printHeaderString( it->name, 2 ); + } + + SourceLineInfo lineInfo = m_sectionStack.front().lineInfo; + + if( !lineInfo.empty() ){ + stream << getLineOfChars<'-'>() << "\n"; + Colour colourGuard( Colour::FileName ); + stream << lineInfo << "\n"; + } + stream << getLineOfChars<'.'>() << "\n" << std::endl; + } + + void printClosedHeader( std::string const& _name ) { + printOpenHeader( _name ); + stream << getLineOfChars<'.'>() << "\n"; + } + void printOpenHeader( std::string const& _name ) { + stream << getLineOfChars<'-'>() << "\n"; + { + Colour colourGuard( Colour::Headers ); + printHeaderString( _name ); + } + } + + // if string has a : in first line will set indent to follow it on + // subsequent lines + void printHeaderString( std::string const& _string, std::size_t indent = 0 ) { + std::size_t i = _string.find( ": " ); + if( i != std::string::npos ) + i+=2; + else + i = 0; + stream << Text( _string, TextAttributes() + .setIndent( indent+i) + .setInitialIndent( indent ) ) << "\n"; + } + + struct SummaryColumn { + + SummaryColumn( std::string const& _label, Colour::Code _colour ) + : label( _label ), + colour( _colour ) + {} + SummaryColumn addRow( std::size_t count ) { + std::ostringstream oss; + oss << count; + std::string row = oss.str(); + for( std::vector::iterator it = rows.begin(); it != rows.end(); ++it ) { + while( it->size() < row.size() ) + *it = " " + *it; + while( it->size() > row.size() ) + row = " " + row; + } + rows.push_back( row ); + return *this; + } + + std::string label; + Colour::Code colour; + std::vector rows; + + }; + + void printTotals( Totals const& totals ) { + if( totals.testCases.total() == 0 ) { + stream << Colour( Colour::Warning ) << "No tests ran\n"; + } + else if( totals.assertions.total() > 0 && totals.assertions.allPassed() ) { + stream << Colour( Colour::ResultSuccess ) << "All tests passed"; + stream << " (" + << pluralise( totals.assertions.passed, "assertion" ) << " in " + << pluralise( totals.testCases.passed, "test case" ) << ")" + << "\n"; + } + else { + + std::vector columns; + columns.push_back( SummaryColumn( "", Colour::None ) + .addRow( totals.testCases.total() ) + .addRow( totals.assertions.total() ) ); + columns.push_back( SummaryColumn( "passed", Colour::Success ) + .addRow( totals.testCases.passed ) + .addRow( totals.assertions.passed ) ); + columns.push_back( SummaryColumn( "failed", Colour::ResultError ) + .addRow( totals.testCases.failed ) + .addRow( totals.assertions.failed ) ); + columns.push_back( SummaryColumn( "failed as expected", Colour::ResultExpectedFailure ) + .addRow( totals.testCases.failedButOk ) + .addRow( totals.assertions.failedButOk ) ); + + printSummaryRow( "test cases", columns, 0 ); + printSummaryRow( "assertions", columns, 1 ); + } + } + void printSummaryRow( std::string const& label, std::vector const& cols, std::size_t row ) { + for( std::vector::const_iterator it = cols.begin(); it != cols.end(); ++it ) { + std::string value = it->rows[row]; + if( it->label.empty() ) { + stream << label << ": "; + if( value != "0" ) + stream << value; + else + stream << Colour( Colour::Warning ) << "- none -"; + } + else if( value != "0" ) { + stream << Colour( Colour::LightGrey ) << " | "; + stream << Colour( it->colour ) + << value << " " << it->label; + } + } + stream << "\n"; + } + + static std::size_t makeRatio( std::size_t number, std::size_t total ) { + std::size_t ratio = total > 0 ? CATCH_CONFIG_CONSOLE_WIDTH * number/ total : 0; + return ( ratio == 0 && number > 0 ) ? 1 : ratio; + } + static std::size_t& findMax( std::size_t& i, std::size_t& j, std::size_t& k ) { + if( i > j && i > k ) + return i; + else if( j > k ) + return j; + else + return k; + } + + void printTotalsDivider( Totals const& totals ) { + if( totals.testCases.total() > 0 ) { + std::size_t failedRatio = makeRatio( totals.testCases.failed, totals.testCases.total() ); + std::size_t failedButOkRatio = makeRatio( totals.testCases.failedButOk, totals.testCases.total() ); + std::size_t passedRatio = makeRatio( totals.testCases.passed, totals.testCases.total() ); + while( failedRatio + failedButOkRatio + passedRatio < CATCH_CONFIG_CONSOLE_WIDTH-1 ) + findMax( failedRatio, failedButOkRatio, passedRatio )++; + while( failedRatio + failedButOkRatio + passedRatio > CATCH_CONFIG_CONSOLE_WIDTH-1 ) + findMax( failedRatio, failedButOkRatio, passedRatio )--; + + stream << Colour( Colour::Error ) << std::string( failedRatio, '=' ); + stream << Colour( Colour::ResultExpectedFailure ) << std::string( failedButOkRatio, '=' ); + if( totals.testCases.allPassed() ) + stream << Colour( Colour::ResultSuccess ) << std::string( passedRatio, '=' ); + else + stream << Colour( Colour::Success ) << std::string( passedRatio, '=' ); + } + else { + stream << Colour( Colour::Warning ) << std::string( CATCH_CONFIG_CONSOLE_WIDTH-1, '=' ); + } + stream << "\n"; + } + void printSummaryDivider() { + stream << getLineOfChars<'-'>() << "\n"; + } + + private: + bool m_headerPrinted; + }; + + INTERNAL_CATCH_REGISTER_REPORTER( "console", ConsoleReporter ) + +} // end namespace Catch + +// #included from: ../reporters/catch_reporter_compact.hpp +#define TWOBLUECUBES_CATCH_REPORTER_COMPACT_HPP_INCLUDED + +namespace Catch { + + struct CompactReporter : StreamingReporterBase { + + CompactReporter( ReporterConfig const& _config ) + : StreamingReporterBase( _config ) + {} + + virtual ~CompactReporter(); + + static std::string getDescription() { + return "Reports test results on a single line, suitable for IDEs"; + } + + virtual ReporterPreferences getPreferences() const { + ReporterPreferences prefs; + prefs.shouldRedirectStdOut = false; + return prefs; + } + + virtual void noMatchingTestCases( std::string const& spec ) { + stream << "No test cases matched '" << spec << "'" << std::endl; + } + + virtual void assertionStarting( AssertionInfo const& ) { + } + + virtual bool assertionEnded( AssertionStats const& _assertionStats ) { + AssertionResult const& result = _assertionStats.assertionResult; + + bool printInfoMessages = true; + + // Drop out if result was successful and we're not printing those + if( !m_config->includeSuccessfulResults() && result.isOk() ) { + if( result.getResultType() != ResultWas::Warning ) + return false; + printInfoMessages = false; + } + + AssertionPrinter printer( stream, _assertionStats, printInfoMessages ); + printer.print(); + + stream << std::endl; + return true; + } + + virtual void testRunEnded( TestRunStats const& _testRunStats ) { + printTotals( _testRunStats.totals ); + stream << "\n" << std::endl; + StreamingReporterBase::testRunEnded( _testRunStats ); + } + + private: + class AssertionPrinter { + void operator= ( AssertionPrinter const& ); + public: + AssertionPrinter( std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages ) + : stream( _stream ) + , stats( _stats ) + , result( _stats.assertionResult ) + , messages( _stats.infoMessages ) + , itMessage( _stats.infoMessages.begin() ) + , printInfoMessages( _printInfoMessages ) + {} + + void print() { + printSourceInfo(); + + itMessage = messages.begin(); + + switch( result.getResultType() ) { + case ResultWas::Ok: + printResultType( Colour::ResultSuccess, passedString() ); + printOriginalExpression(); + printReconstructedExpression(); + if ( ! result.hasExpression() ) + printRemainingMessages( Colour::None ); + else + printRemainingMessages(); + break; + case ResultWas::ExpressionFailed: + if( result.isOk() ) + printResultType( Colour::ResultSuccess, failedString() + std::string( " - but was ok" ) ); + else + printResultType( Colour::Error, failedString() ); + printOriginalExpression(); + printReconstructedExpression(); + printRemainingMessages(); + break; + case ResultWas::ThrewException: + printResultType( Colour::Error, failedString() ); + printIssue( "unexpected exception with message:" ); + printMessage(); + printExpressionWas(); + printRemainingMessages(); + break; + case ResultWas::FatalErrorCondition: + printResultType( Colour::Error, failedString() ); + printIssue( "fatal error condition with message:" ); + printMessage(); + printExpressionWas(); + printRemainingMessages(); + break; + case ResultWas::DidntThrowException: + printResultType( Colour::Error, failedString() ); + printIssue( "expected exception, got none" ); + printExpressionWas(); + printRemainingMessages(); + break; + case ResultWas::Info: + printResultType( Colour::None, "info" ); + printMessage(); + printRemainingMessages(); + break; + case ResultWas::Warning: + printResultType( Colour::None, "warning" ); + printMessage(); + printRemainingMessages(); + break; + case ResultWas::ExplicitFailure: + printResultType( Colour::Error, failedString() ); + printIssue( "explicitly" ); + printRemainingMessages( Colour::None ); + break; + // These cases are here to prevent compiler warnings + case ResultWas::Unknown: + case ResultWas::FailureBit: + case ResultWas::Exception: + printResultType( Colour::Error, "** internal error **" ); + break; + } + } + + private: + // Colour::LightGrey + + static Colour::Code dimColour() { return Colour::FileName; } + +#ifdef CATCH_PLATFORM_MAC + static const char* failedString() { return "FAILED"; } + static const char* passedString() { return "PASSED"; } +#else + static const char* failedString() { return "failed"; } + static const char* passedString() { return "passed"; } +#endif + + void printSourceInfo() const { + Colour colourGuard( Colour::FileName ); + stream << result.getSourceInfo() << ":"; + } + + void printResultType( Colour::Code colour, std::string passOrFail ) const { + if( !passOrFail.empty() ) { + { + Colour colourGuard( colour ); + stream << " " << passOrFail; + } + stream << ":"; + } + } + + void printIssue( std::string issue ) const { + stream << " " << issue; + } + + void printExpressionWas() { + if( result.hasExpression() ) { + stream << ";"; + { + Colour colour( dimColour() ); + stream << " expression was:"; + } + printOriginalExpression(); + } + } + + void printOriginalExpression() const { + if( result.hasExpression() ) { + stream << " " << result.getExpression(); + } + } + + void printReconstructedExpression() const { + if( result.hasExpandedExpression() ) { + { + Colour colour( dimColour() ); + stream << " for: "; + } + stream << result.getExpandedExpression(); + } + } + + void printMessage() { + if ( itMessage != messages.end() ) { + stream << " '" << itMessage->message << "'"; + ++itMessage; + } + } + + void printRemainingMessages( Colour::Code colour = dimColour() ) { + if ( itMessage == messages.end() ) + return; + + // using messages.end() directly yields compilation error: + std::vector::const_iterator itEnd = messages.end(); + const std::size_t N = static_cast( std::distance( itMessage, itEnd ) ); + + { + Colour colourGuard( colour ); + stream << " with " << pluralise( N, "message" ) << ":"; + } + + for(; itMessage != itEnd; ) { + // If this assertion is a warning ignore any INFO messages + if( printInfoMessages || itMessage->type != ResultWas::Info ) { + stream << " '" << itMessage->message << "'"; + if ( ++itMessage != itEnd ) { + Colour colourGuard( dimColour() ); + stream << " and"; + } + } + } + } + + private: + std::ostream& stream; + AssertionStats const& stats; + AssertionResult const& result; + std::vector messages; + std::vector::const_iterator itMessage; + bool printInfoMessages; + }; + + // Colour, message variants: + // - white: No tests ran. + // - red: Failed [both/all] N test cases, failed [both/all] M assertions. + // - white: Passed [both/all] N test cases (no assertions). + // - red: Failed N tests cases, failed M assertions. + // - green: Passed [both/all] N tests cases with M assertions. + + std::string bothOrAll( std::size_t count ) const { + return count == 1 ? "" : count == 2 ? "both " : "all " ; + } + + void printTotals( const Totals& totals ) const { + if( totals.testCases.total() == 0 ) { + stream << "No tests ran."; + } + else if( totals.testCases.failed == totals.testCases.total() ) { + Colour colour( Colour::ResultError ); + const std::string qualify_assertions_failed = + totals.assertions.failed == totals.assertions.total() ? + bothOrAll( totals.assertions.failed ) : ""; + stream << + "Failed " << bothOrAll( totals.testCases.failed ) + << pluralise( totals.testCases.failed, "test case" ) << ", " + "failed " << qualify_assertions_failed << + pluralise( totals.assertions.failed, "assertion" ) << "."; + } + else if( totals.assertions.total() == 0 ) { + stream << + "Passed " << bothOrAll( totals.testCases.total() ) + << pluralise( totals.testCases.total(), "test case" ) + << " (no assertions)."; + } + else if( totals.assertions.failed ) { + Colour colour( Colour::ResultError ); + stream << + "Failed " << pluralise( totals.testCases.failed, "test case" ) << ", " + "failed " << pluralise( totals.assertions.failed, "assertion" ) << "."; + } + else { + Colour colour( Colour::ResultSuccess ); + stream << + "Passed " << bothOrAll( totals.testCases.passed ) + << pluralise( totals.testCases.passed, "test case" ) << + " with " << pluralise( totals.assertions.passed, "assertion" ) << "."; + } + } + }; + + INTERNAL_CATCH_REGISTER_REPORTER( "compact", CompactReporter ) + +} // end namespace Catch + +namespace Catch { + // These are all here to avoid warnings about not having any out of line + // virtual methods + NonCopyable::~NonCopyable() {} + IShared::~IShared() {} + IStream::~IStream() CATCH_NOEXCEPT {} + FileStream::~FileStream() CATCH_NOEXCEPT {} + CoutStream::~CoutStream() CATCH_NOEXCEPT {} + DebugOutStream::~DebugOutStream() CATCH_NOEXCEPT {} + StreamBufBase::~StreamBufBase() CATCH_NOEXCEPT {} + IContext::~IContext() {} + IResultCapture::~IResultCapture() {} + ITestCase::~ITestCase() {} + ITestCaseRegistry::~ITestCaseRegistry() {} + IRegistryHub::~IRegistryHub() {} + IMutableRegistryHub::~IMutableRegistryHub() {} + IExceptionTranslator::~IExceptionTranslator() {} + IExceptionTranslatorRegistry::~IExceptionTranslatorRegistry() {} + IReporter::~IReporter() {} + IReporterFactory::~IReporterFactory() {} + IReporterRegistry::~IReporterRegistry() {} + IStreamingReporter::~IStreamingReporter() {} + AssertionStats::~AssertionStats() {} + SectionStats::~SectionStats() {} + TestCaseStats::~TestCaseStats() {} + TestGroupStats::~TestGroupStats() {} + TestRunStats::~TestRunStats() {} + CumulativeReporterBase::SectionNode::~SectionNode() {} + CumulativeReporterBase::~CumulativeReporterBase() {} + + StreamingReporterBase::~StreamingReporterBase() {} + ConsoleReporter::~ConsoleReporter() {} + CompactReporter::~CompactReporter() {} + IRunner::~IRunner() {} + IMutableContext::~IMutableContext() {} + IConfig::~IConfig() {} + XmlReporter::~XmlReporter() {} + JunitReporter::~JunitReporter() {} + TestRegistry::~TestRegistry() {} + FreeFunctionTestCase::~FreeFunctionTestCase() {} + IGeneratorInfo::~IGeneratorInfo() {} + IGeneratorsForTest::~IGeneratorsForTest() {} + WildcardPattern::~WildcardPattern() {} + TestSpec::Pattern::~Pattern() {} + TestSpec::NamePattern::~NamePattern() {} + TestSpec::TagPattern::~TagPattern() {} + TestSpec::ExcludedPattern::~ExcludedPattern() {} + + Matchers::Impl::StdString::Equals::~Equals() {} + Matchers::Impl::StdString::Contains::~Contains() {} + Matchers::Impl::StdString::StartsWith::~StartsWith() {} + Matchers::Impl::StdString::EndsWith::~EndsWith() {} + + void Config::dummy() {} + + namespace TestCaseTracking { + ITracker::~ITracker() {} + TrackerBase::~TrackerBase() {} + SectionTracker::~SectionTracker() {} + IndexTracker::~IndexTracker() {} + } +} + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +#endif + +#ifdef CATCH_CONFIG_MAIN +// #included from: internal/catch_default_main.hpp +#define TWOBLUECUBES_CATCH_DEFAULT_MAIN_HPP_INCLUDED + +#ifndef __OBJC__ + +// Standard C/C++ main entry point +int main (int argc, char * argv[]) { + return Catch::Session().run( argc, argv ); +} + +#else // __OBJC__ + +// Objective-C entry point +int main (int argc, char * const argv[]) { +#if !CATCH_ARC_ENABLED + NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; +#endif + + Catch::registerTestMethods(); + int result = Catch::Session().run( argc, (char* const*)argv ); + +#if !CATCH_ARC_ENABLED + [pool drain]; +#endif + + return result; +} + +#endif // __OBJC__ + +#endif + +#ifdef CLARA_CONFIG_MAIN_NOT_DEFINED +# undef CLARA_CONFIG_MAIN +#endif + +////// + +// If this config identifier is defined then all CATCH macros are prefixed with CATCH_ +#ifdef CATCH_CONFIG_PREFIX_ALL + +#define CATCH_REQUIRE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE" ) +#define CATCH_REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, "CATCH_REQUIRE_FALSE" ) + +#define CATCH_REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, "", "CATCH_REQUIRE_THROWS" ) +#define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THROWS_AS" ) +#define CATCH_REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, matcher, "CATCH_REQUIRE_THROWS_WITH" ) +#define CATCH_REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_NOTHROW" ) + +#define CATCH_CHECK( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK" ) +#define CATCH_CHECK_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, "CATCH_CHECK_FALSE" ) +#define CATCH_CHECKED_IF( expr ) INTERNAL_CATCH_IF( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECKED_IF" ) +#define CATCH_CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECKED_ELSE" ) +#define CATCH_CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, "CATCH_CHECK_NOFAIL" ) + +#define CATCH_CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THROWS" ) +#define CATCH_CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THROWS_AS" ) +#define CATCH_CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, matcher, "CATCH_CHECK_THROWS_WITH" ) +#define CATCH_CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_NOTHROW" ) + +#define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THAT" ) +#define CATCH_REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THAT" ) + +#define CATCH_INFO( msg ) INTERNAL_CATCH_INFO( msg, "CATCH_INFO" ) +#define CATCH_WARN( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, "CATCH_WARN", msg ) +#define CATCH_SCOPED_INFO( msg ) INTERNAL_CATCH_INFO( msg, "CATCH_INFO" ) +#define CATCH_CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CATCH_CAPTURE" ) +#define CATCH_SCOPED_CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CATCH_CAPTURE" ) + +#ifdef CATCH_CONFIG_VARIADIC_MACROS + #define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ ) + #define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ ) + #define CATCH_METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ ) + #define CATCH_REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ ) + #define CATCH_SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) + #define CATCH_FAIL( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "CATCH_FAIL", __VA_ARGS__ ) + #define CATCH_SUCCEED( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "CATCH_SUCCEED", __VA_ARGS__ ) +#else + #define CATCH_TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description ) + #define CATCH_TEST_CASE_METHOD( className, name, description ) INTERNAL_CATCH_TEST_CASE_METHOD( className, name, description ) + #define CATCH_METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description ) + #define CATCH_REGISTER_TEST_CASE( function, name, description ) INTERNAL_CATCH_REGISTER_TESTCASE( function, name, description ) + #define CATCH_SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description ) + #define CATCH_FAIL( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "CATCH_FAIL", msg ) + #define CATCH_SUCCEED( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "CATCH_SUCCEED", msg ) +#endif +#define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE( "", "" ) + +#define CATCH_REGISTER_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) +#define CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) + +#define CATCH_GENERATE( expr) INTERNAL_CATCH_GENERATE( expr ) + +// "BDD-style" convenience wrappers +#ifdef CATCH_CONFIG_VARIADIC_MACROS +#define CATCH_SCENARIO( ... ) CATCH_TEST_CASE( "Scenario: " __VA_ARGS__ ) +#define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ ) +#else +#define CATCH_SCENARIO( name, tags ) CATCH_TEST_CASE( "Scenario: " name, tags ) +#define CATCH_SCENARIO_METHOD( className, name, tags ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " name, tags ) +#endif +#define CATCH_GIVEN( desc ) CATCH_SECTION( std::string( "Given: ") + desc, "" ) +#define CATCH_WHEN( desc ) CATCH_SECTION( std::string( " When: ") + desc, "" ) +#define CATCH_AND_WHEN( desc ) CATCH_SECTION( std::string( " And: ") + desc, "" ) +#define CATCH_THEN( desc ) CATCH_SECTION( std::string( " Then: ") + desc, "" ) +#define CATCH_AND_THEN( desc ) CATCH_SECTION( std::string( " And: ") + desc, "" ) + +// If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required +#else + +#define REQUIRE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal, "REQUIRE" ) +#define REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, "REQUIRE_FALSE" ) + +#define REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, "", "REQUIRE_THROWS" ) +#define REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::Normal, "REQUIRE_THROWS_AS" ) +#define REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, matcher, "REQUIRE_THROWS_WITH" ) +#define REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::Normal, "REQUIRE_NOTHROW" ) + +#define CHECK( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK" ) +#define CHECK_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, "CHECK_FALSE" ) +#define CHECKED_IF( expr ) INTERNAL_CATCH_IF( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECKED_IF" ) +#define CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECKED_ELSE" ) +#define CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, "CHECK_NOFAIL" ) + +#define CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, "", "CHECK_THROWS" ) +#define CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THROWS_AS" ) +#define CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, matcher, "CHECK_THROWS_WITH" ) +#define CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK_NOTHROW" ) + +#define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THAT" ) +#define REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::Normal, "REQUIRE_THAT" ) + +#define INFO( msg ) INTERNAL_CATCH_INFO( msg, "INFO" ) +#define WARN( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, "WARN", msg ) +#define SCOPED_INFO( msg ) INTERNAL_CATCH_INFO( msg, "INFO" ) +#define CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CAPTURE" ) +#define SCOPED_CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CAPTURE" ) + +#ifdef CATCH_CONFIG_VARIADIC_MACROS + #define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ ) + #define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ ) + #define METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ ) + #define REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ ) + #define SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) + #define FAIL( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "FAIL", __VA_ARGS__ ) + #define SUCCEED( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "SUCCEED", __VA_ARGS__ ) +#else + #define TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description ) + #define TEST_CASE_METHOD( className, name, description ) INTERNAL_CATCH_TEST_CASE_METHOD( className, name, description ) + #define METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description ) + #define REGISTER_TEST_CASE( method, name, description ) INTERNAL_CATCH_REGISTER_TESTCASE( method, name, description ) + #define SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description ) + #define FAIL( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "FAIL", msg ) + #define SUCCEED( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "SUCCEED", msg ) +#endif +#define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE( "", "" ) + +#define REGISTER_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) +#define REGISTER_LEGACY_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) + +#define GENERATE( expr) INTERNAL_CATCH_GENERATE( expr ) + +#endif + +#define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) + +// "BDD-style" convenience wrappers +#ifdef CATCH_CONFIG_VARIADIC_MACROS +#define SCENARIO( ... ) TEST_CASE( "Scenario: " __VA_ARGS__ ) +#define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ ) +#else +#define SCENARIO( name, tags ) TEST_CASE( "Scenario: " name, tags ) +#define SCENARIO_METHOD( className, name, tags ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " name, tags ) +#endif +#define GIVEN( desc ) SECTION( std::string(" Given: ") + desc, "" ) +#define WHEN( desc ) SECTION( std::string(" When: ") + desc, "" ) +#define AND_WHEN( desc ) SECTION( std::string("And when: ") + desc, "" ) +#define THEN( desc ) SECTION( std::string(" Then: ") + desc, "" ) +#define AND_THEN( desc ) SECTION( std::string(" And: ") + desc, "" ) + +using Catch::Detail::Approx; + +#endif // TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED + diff --git a/CUDA_Convolution/libwb/vendor/json11.cpp b/CUDA_Convolution/libwb/vendor/json11.cpp new file mode 100644 index 0000000..f401c26 --- /dev/null +++ b/CUDA_Convolution/libwb/vendor/json11.cpp @@ -0,0 +1,1013 @@ +/* Copyright (c) 2013 Dropbox, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy + * of this software and associated documentation files (the "Software"), to + * deal + * in the Software without restriction, including without limitation the + * rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN + * THE SOFTWARE. + */ + +#include "json11.hpp" +#include +#include +#include +#include +#include +#include + +namespace json11 { + +static const int max_depth = 200; + +using std::string; +using std::vector; +using std::map; +using std::make_shared; +using std::initializer_list; +using std::move; + +/* * * * * * * * * * * * * * * * * * * * + * Serialization + */ + +static void dump(std::nullptr_t, string &out) { + out += "null"; +} + +static void dump(double value, string &out) { + if (std::isfinite(value)) { + char buf[32]; +//PMO +#ifndef _MSC_VER + snprintf(buf, sizeof buf, "%.17g", value); +#else + _snprintf_s(buf, sizeof buf, "%.17g", value); +#endif + out += buf; + } else { + out += "null"; + } +} + +static void dump(int value, string &out) { + char buf[32]; +//PMO +#ifndef _MSC_VER + snprintf(buf, sizeof buf, "%d", value); +#else + _snprintf_s(buf, sizeof buf, "%d", value); +#endif + out += buf; +} + +static void dump(int64_t value, string &out) { + char buf[64]; +//PMO +#ifndef _MSC_VER + snprintf(buf, sizeof buf, "%" PRId64, value); +#else + _snprintf_s(buf, sizeof buf, "%" PRId64, value); +#endif + out += buf; +} + +static void dump(uint64_t value, string &out) { + char buf[128]; +//PMO +#ifndef _MSC_VER + snprintf(buf, sizeof buf, "%" PRIu64, value); +#else + _snprintf_s(buf, sizeof buf, "%" PRIu64, value); +#endif + out += buf; +} + +static void dump(bool value, string &out) { + out += value ? "true" : "false"; +} + +static void dump(const string &value, string &out) { + out += '"'; + for (size_t i = 0; i < value.length(); i++) { + const char ch = value[i]; + if (ch == '\\') { + out += "\\\\"; + } else if (ch == '"') { + out += "\\\""; + } else if (ch == '\b') { + out += "\\b"; + } else if (ch == '\f') { + out += "\\f"; + } else if (ch == '\n') { + out += "\\n"; + } else if (ch == '\r') { + out += "\\r"; + } else if (ch == '\t') { + out += "\\t"; + } else if (static_cast(ch) <= 0x1f) { + char buf[8]; +//PMO +#ifndef _MSC_VER + snprintf(buf, sizeof buf, "\\u%04x", ch); +#else + _snprintf_s(buf, sizeof buf, "\\u%04x", ch); +#endif + out += buf; + } else if (static_cast(ch) == 0xe2 && + static_cast(value[i + 1]) == 0x80 && + static_cast(value[i + 2]) == 0xa8) { + out += "\\u2028"; + i += 2; + } else if (static_cast(ch) == 0xe2 && + static_cast(value[i + 1]) == 0x80 && + static_cast(value[i + 2]) == 0xa9) { + out += "\\u2029"; + i += 2; + } else { + out += ch; + } + } + out += '"'; +} + +static void dump(const Json::array &values, string &out) { + bool first = true; + out += "["; + for (const auto &value : values) { + if (!first) + out += ", "; + value.dump(out); + first = false; + } + out += "]"; +} + +static void dump(const Json::object &values, string &out) { + bool first = true; + out += "{"; + for (const auto &kv : values) { + if (!first) + out += ", "; + dump(kv.first, out); + out += ": "; + kv.second.dump(out); + first = false; + } + out += "}"; +} + +void Json::dump(string &out) const { + m_ptr->dump(out); +} + +/* * * * * * * * * * * * * * * * * * * * + * Value wrappers + */ + +template +class Value : public JsonValue { +protected: + // Constructors + explicit Value(const T &value) : m_value(value) { + } + explicit Value(T &&value) : m_value(move(value)) { + } + + // Get type tag + Json::Type type() const override { + return tag; + } + + // Comparisons + bool equals(const JsonValue *other) const override { + return m_value == static_cast *>(other)->m_value; + } + bool less(const JsonValue *other) const override { + return m_value < static_cast *>(other)->m_value; + } + + const T m_value; + void dump(string &out) const override { + json11::dump(m_value, out); + } +}; + +class JsonDouble final : public Value { + double number_value() const override { + return m_value; + } + int int_value() const override { + return static_cast(m_value); + } + int64_t int64_value() const override { + return (int64_t)m_value; + } + uint64_t uint64_value() const override { + return (uint64_t)m_value; + } + bool equals(const JsonValue *other) const override { + return m_value == other->number_value(); + } + bool less(const JsonValue *other) const override { + return m_value < other->number_value(); + } + +public: + explicit JsonDouble(double value) : Value(value) { + } +}; + +class JsonInt final : public Value { + double number_value() const override { + return m_value; + } + int int_value() const override { + return m_value; + } + int64_t int64_value() const override { + return m_value; + } + uint64_t uint64_value() const override { + return m_value; + } + bool equals(const JsonValue *other) const override { + return m_value == other->number_value(); + } + bool less(const JsonValue *other) const override { + return m_value < other->number_value(); + } + +public: + explicit JsonInt(int value) : Value(value) { + } +}; + +class JsonInt64 final : public Value { + double number_value() const override { + return m_value; + } + int int_value() const override { + return (int)m_value; + } + int64_t int64_value() const override { + return m_value; + } + uint64_t uint64_value() const override { + return (uint64_t)m_value; + } + bool equals(const JsonValue *other) const override { + return m_value == other->number_value(); + } + bool less(const JsonValue *other) const override { + return m_value < other->number_value(); + } + +public: + explicit JsonInt64(int64_t value) : Value(value) { + } +}; + +class JsonUInt64 final : public Value { + double number_value() const override { + return m_value; + } + int int_value() const override { + return (int)m_value; + } + int64_t int64_value() const override { + return (int64_t)m_value; + } + uint64_t uint64_value() const override { + return m_value; + } + bool equals(const JsonValue *other) const override { + return m_value == other->number_value(); + } + bool less(const JsonValue *other) const override { + return m_value < other->number_value(); + } + +public: + explicit JsonUInt64(uint64_t value) : Value(value) { + } +}; + +class JsonBoolean final : public Value { + bool bool_value() const override { + return m_value; + } + +public: + explicit JsonBoolean(bool value) : Value(value) { + } +}; + +class JsonString final : public Value { + const string &string_value() const override { + return m_value; + } + +public: + explicit JsonString(const string &value) : Value(value) { + } + explicit JsonString(string &&value) : Value(move(value)) { + } +}; + +class JsonArray final : public Value { + const Json::array &array_items() const override { + return m_value; + } + const Json &operator[](size_t i) const override; + +public: + explicit JsonArray(const Json::array &value) : Value(value) { + } + explicit JsonArray(Json::array &&value) : Value(move(value)) { + } +}; + +class JsonObject final : public Value { + const Json::object &object_items() const override { + return m_value; + } + const Json &operator[](const string &key) const override; + +public: + explicit JsonObject(const Json::object &value) : Value(value) { + } + explicit JsonObject(Json::object &&value) : Value(move(value)) { + } +}; + +class JsonNull final : public Value { +public: + JsonNull() : Value(nullptr) { + } +}; + +/* * * * * * * * * * * * * * * * * * * * + * Static globals - static-init-safe + */ +struct Statics { + const std::shared_ptr null = make_shared(); + const std::shared_ptr t = make_shared(true); + const std::shared_ptr f = make_shared(false); + const string empty_string; + const vector empty_vector; + const map empty_map; + Statics() { + } +}; + +static const Statics &statics() { + static const Statics s{}; + return s; +} + +static const Json &static_null() { + // This has to be separate, not in Statics, because Json() accesses + // statics().null. + static const Json json_null; + return json_null; +} + +/* * * * * * * * * * * * * * * * * * * * + * Constructors + */ + +Json::Json() NOEXCEPT : m_ptr(statics().null) { +} +Json::Json(std::nullptr_t) NOEXCEPT : m_ptr(statics().null) { +} +Json::Json(double value) : m_ptr(make_shared(value)) { +} +Json::Json(int value) : m_ptr(make_shared(value)) { +} +Json::Json(int64_t value) : m_ptr(make_shared(value)) { +} +Json::Json(uint64_t value) : m_ptr(make_shared(value)) { +} +Json::Json(bool value) : m_ptr(value ? statics().t : statics().f) { +} +Json::Json(const string &value) : m_ptr(make_shared(value)) { +} +Json::Json(string &&value) : m_ptr(make_shared(move(value))) { +} +Json::Json(const char *value) : m_ptr(make_shared(value)) { +} +Json::Json(const Json::array &values) + : m_ptr(make_shared(values)) { +} +Json::Json(Json::array &&values) + : m_ptr(make_shared(move(values))) { +} +Json::Json(const Json::object &values) + : m_ptr(make_shared(values)) { +} +Json::Json(Json::object &&values) + : m_ptr(make_shared(move(values))) { +} + +/* * * * * * * * * * * * * * * * * * * * + * Accessors + */ + +Json::Type Json::type() const { + return m_ptr->type(); +} +double Json::number_value() const { + return m_ptr->number_value(); +} +int Json::int_value() const { + return m_ptr->int_value(); +} +int64_t Json::int64_value() const { + return m_ptr->int64_value(); +} +uint64_t Json::uint64_value() const { + return m_ptr->uint64_value(); +} +bool Json::bool_value() const { + return m_ptr->bool_value(); +} +const string &Json::string_value() const { + return m_ptr->string_value(); +} +const vector &Json::array_items() const { + return m_ptr->array_items(); +} +const map &Json::object_items() const { + return m_ptr->object_items(); +} +const Json &Json::operator[](size_t i) const { + return (*m_ptr)[i]; +} +const Json &Json::operator[](const string &key) const { + return (*m_ptr)[key]; +} + +double JsonValue::number_value() const { + return 0; +} +int JsonValue::int_value() const { + return 0; +} +int64_t JsonValue::int64_value() const { + return 0; +} +uint64_t JsonValue::uint64_value() const { + return 0; +} +bool JsonValue::bool_value() const { + return false; +} +const string &JsonValue::string_value() const { + return statics().empty_string; +} +const vector &JsonValue::array_items() const { + return statics().empty_vector; +} +const map &JsonValue::object_items() const { + return statics().empty_map; +} +const Json &JsonValue::operator[](size_t) const { + return static_null(); +} +const Json &JsonValue::operator[](const string &) const { + return static_null(); +} + +const Json &JsonObject::operator[](const string &key) const { + auto iter = m_value.find(key); + return (iter == m_value.end()) ? static_null() : iter->second; +} +const Json &JsonArray::operator[](size_t i) const { + if (i >= m_value.size()) + return static_null(); + else + return m_value[i]; +} + +/* * * * * * * * * * * * * * * * * * * * + * Comparison + */ + +bool Json::operator==(const Json &other) const { + if (m_ptr->type() != other.m_ptr->type()) + return false; + + return m_ptr->equals(other.m_ptr.get()); +} + +bool Json::operator<(const Json &other) const { + if (m_ptr->type() != other.m_ptr->type()) + return m_ptr->type() < other.m_ptr->type(); + + return m_ptr->less(other.m_ptr.get()); +} + +/* * * * * * * * * * * * * * * * * * * * + * Parsing + */ + +/* esc(c) + * + * Format char c suitable for printing in an error message. + */ +static inline string esc(char c) { + char buf[12]; + if (static_cast(c) >= 0x20 && static_cast(c) <= 0x7f) { +//PMO +#ifndef _MSC_VER + snprintf(buf, sizeof buf, "'%c' (%d)", c, c); +#else + _snprintf_s(buf, sizeof buf, "'%c' (%d)", c, c); +#endif + } else { +//PMO +#ifndef _MSC_VER + snprintf(buf, sizeof buf, "(%d)", c); +#else + _snprintf_s(buf, sizeof buf, "(%d)", c); +#endif + } + return string(buf); +} + +static inline bool in_range(long x, long lower, long upper) { + return (x >= lower && x <= upper); +} + +/* JsonParser + * + * Object that tracks all state of an in-progress parse. + */ +struct JsonParser { + + /* State + */ + const string &str; + size_t i; + string &err; + bool failed; + const JsonParse strategy; + + /* fail(msg, err_ret = Json()) + * + * Mark this parse as failed. + */ + Json fail(string &&msg) { + return fail(move(msg), Json()); + } + + template + T fail(string &&msg, const T err_ret) { + if (!failed) + err = std::move(msg); + failed = true; + return err_ret; + } + + /* consume_whitespace() + * + * Advance until the current character is non-whitespace. + */ + void consume_whitespace() { + while (str[i] == ' ' || str[i] == '\r' || str[i] == '\n' || + str[i] == '\t') + i++; + } + + /* consume_comment() + * + * Advance comments (c-style inline and multiline). + */ + bool consume_comment() { + bool comment_found = false; + if (str[i] == '/') { + i++; + if (i == str.size()) + return fail("unexpected end of input inside comment", 0); + if (str[i] == '/') { // inline comment + i++; + if (i == str.size()) + return fail("unexpected end of input inside inline comment", 0); + // advance until next line + while (str[i] != '\n') { + i++; + if (i == str.size()) + return fail("unexpected end of input inside inline comment", + 0); + } + comment_found = true; + } else if (str[i] == '*') { // multiline comment + i++; + if (i > str.size() - 2) + return fail("unexpected end of input inside multi-line comment", + 0); + // advance until closing tokens + while (!(str[i] == '*' && str[i + 1] == '/')) { + i++; + if (i > str.size() - 2) + return fail( + "unexpected end of input inside multi-line comment", 0); + } + i += 2; + if (i == str.size()) + return fail("unexpected end of input inside multi-line comment", + 0); + comment_found = true; + } else + return fail("malformed comment", 0); + } + return comment_found; + } + + /* consume_garbage() + * + * Advance until the current character is non-whitespace and non-comment. + */ + void consume_garbage() { + consume_whitespace(); + if (strategy == JsonParse::COMMENTS) { + bool comment_found = false; + do { + comment_found = consume_comment(); + consume_whitespace(); + } while (comment_found); + } + } + + /* get_next_token() + * + * Return the next non-whitespace character. If the end of the input is + * reached, + * flag an error and return 0. + */ + char get_next_token() { + consume_garbage(); + if (i == str.size()) + return fail("unexpected end of input", 0); + + return str[i++]; + } + + /* encode_utf8(pt, out) + * + * Encode pt as UTF-8 and add it to out. + */ + void encode_utf8(long pt, string &out) { + if (pt < 0) + return; + + if (pt < 0x80) { + out += static_cast(pt); + } else if (pt < 0x800) { + out += static_cast((pt >> 6) | 0xC0); + out += static_cast((pt & 0x3F) | 0x80); + } else if (pt < 0x10000) { + out += static_cast((pt >> 12) | 0xE0); + out += static_cast(((pt >> 6) & 0x3F) | 0x80); + out += static_cast((pt & 0x3F) | 0x80); + } else { + out += static_cast((pt >> 18) | 0xF0); + out += static_cast(((pt >> 12) & 0x3F) | 0x80); + out += static_cast(((pt >> 6) & 0x3F) | 0x80); + out += static_cast((pt & 0x3F) | 0x80); + } + } + + /* parse_string() + * + * Parse a string, starting at the current position. + */ + string parse_string() { + string out; + long last_escaped_codepoint = -1; + while (true) { + if (i == str.size()) + return fail("unexpected end of input in string", ""); + + char ch = str[i++]; + + if (ch == '"') { + encode_utf8(last_escaped_codepoint, out); + return out; + } + + if (in_range(ch, 0, 0x1f)) + return fail("unescaped " + esc(ch) + " in string", ""); + + // The usual case: non-escaped characters + if (ch != '\\') { + encode_utf8(last_escaped_codepoint, out); + last_escaped_codepoint = -1; + out += ch; + continue; + } + + // Handle escapes + if (i == str.size()) + return fail("unexpected end of input in string", ""); + + ch = str[i++]; + + if (ch == 'u') { + // Extract 4-byte escape sequence + string esc = str.substr(i, 4); + // Explicitly check length of the substring. The following loop + // relies on std::string returning the terminating NUL when + // accessing str[length]. Checking here reduces brittleness. + if (esc.length() < 4) { + return fail("bad \\u escape: " + esc, ""); + } + for (int j = 0; j < 4; j++) { + if (!in_range(esc[j], 'a', 'f') && !in_range(esc[j], 'A', 'F') && + !in_range(esc[j], '0', '9')) + return fail("bad \\u escape: " + esc, ""); + } + + long codepoint = strtol(esc.data(), nullptr, 16); + + // JSON specifies that characters outside the BMP shall be encoded + // as a pair + // of 4-hex-digit \u escapes encoding their surrogate pair + // components. Check + // whether we're in the middle of such a beast: the previous + // codepoint was an + // escaped lead (high) surrogate, and this is a trail (low) + // surrogate. + if (in_range(last_escaped_codepoint, 0xD800, 0xDBFF) && + in_range(codepoint, 0xDC00, 0xDFFF)) { + // Reassemble the two surrogate pairs into one astral-plane + // character, per + // the UTF-16 algorithm. + encode_utf8((((last_escaped_codepoint - 0xD800) << 10) | + (codepoint - 0xDC00)) + + 0x10000, + out); + last_escaped_codepoint = -1; + } else { + encode_utf8(last_escaped_codepoint, out); + last_escaped_codepoint = codepoint; + } + + i += 4; + continue; + } + + encode_utf8(last_escaped_codepoint, out); + last_escaped_codepoint = -1; + + if (ch == 'b') { + out += '\b'; + } else if (ch == 'f') { + out += '\f'; + } else if (ch == 'n') { + out += '\n'; + } else if (ch == 'r') { + out += '\r'; + } else if (ch == 't') { + out += '\t'; + } else if (ch == '"' || ch == '\\' || ch == '/') { + out += ch; + } else { + return fail("invalid escape character " + esc(ch), ""); + } + } + } + + /* parse_number() + * + * Parse a double. + */ + Json parse_number() { + size_t start_pos = i; + + if (str[i] == '-') + i++; + + // Integer part + if (str[i] == '0') { + i++; + if (in_range(str[i], '0', '9')) + return fail("leading 0s not permitted in numbers"); + } else if (in_range(str[i], '1', '9')) { + i++; + while (in_range(str[i], '0', '9')) + i++; + } else { + return fail("invalid " + esc(str[i]) + " in number"); + } + + if (str[i] != '.' && str[i] != 'e' && str[i] != 'E' && + (i - start_pos) <= + static_cast(std::numeric_limits::digits10)) { + return std::atoi(str.c_str() + start_pos); + } + + // Decimal part + if (str[i] == '.') { + i++; + if (!in_range(str[i], '0', '9')) + return fail("at least one digit required in fractional part"); + + while (in_range(str[i], '0', '9')) + i++; + } + + // Exponent part + if (str[i] == 'e' || str[i] == 'E') { + i++; + + if (str[i] == '+' || str[i] == '-') + i++; + + if (!in_range(str[i], '0', '9')) + return fail("at least one digit required in exponent"); + + while (in_range(str[i], '0', '9')) + i++; + } + + return std::strtod(str.c_str() + start_pos, nullptr); + } + + /* expect(str, res) + * + * Expect that 'str' starts at the character that was just read. If it + * does, advance + * the input and return res. If not, flag an error. + */ + Json expect(const string &expected, Json res) { + assert(i != 0); + i--; + if (str.compare(i, expected.length(), expected) == 0) { + i += expected.length(); + return res; + } else { + return fail("parse error: expected " + expected + ", got " + + str.substr(i, expected.length())); + } + } + + /* parse_json() + * + * Parse a JSON object. + */ + Json parse_json(int depth) { + if (depth > max_depth) { + return fail("exceeded maximum nesting depth"); + } + + char ch = get_next_token(); + if (failed) + return Json(); + + if (ch == '-' || (ch >= '0' && ch <= '9')) { + i--; + return parse_number(); + } + + if (ch == 't') + return expect("true", true); + + if (ch == 'f') + return expect("false", false); + + if (ch == 'n') + return expect("null", Json()); + + if (ch == '"') + return parse_string(); + + if (ch == '{') { + map data; + ch = get_next_token(); + if (ch == '}') + return data; + + while (1) { + if (ch != '"') + return fail("expected '\"' in object, got " + esc(ch)); + + string key = parse_string(); + if (failed) + return Json(); + + ch = get_next_token(); + if (ch != ':') + return fail("expected ':' in object, got " + esc(ch)); + + data[std::move(key)] = parse_json(depth + 1); + if (failed) + return Json(); + + ch = get_next_token(); + if (ch == '}') + break; + if (ch != ',') + return fail("expected ',' in object, got " + esc(ch)); + + ch = get_next_token(); + } + return data; + } + + if (ch == '[') { + vector data; + ch = get_next_token(); + if (ch == ']') + return data; + + while (1) { + i--; + data.push_back(parse_json(depth + 1)); + if (failed) + return Json(); + + ch = get_next_token(); + if (ch == ']') + break; + if (ch != ',') + return fail("expected ',' in list, got " + esc(ch)); + + ch = get_next_token(); + (void)ch; + } + return data; + } + + return fail("expected value, got " + esc(ch)); + } +}; + +Json Json::parse(const string &in, string &err, JsonParse strategy) { + JsonParser parser{in, 0, err, false, strategy}; + Json result = parser.parse_json(0); + + // Check for any trailing garbage + parser.consume_garbage(); + if (parser.i != in.size()) + return parser.fail("unexpected trailing " + esc(in[parser.i])); + + return result; +} + +// Documented in json11.hpp +vector Json::parse_multi(const string &in, string &err, + JsonParse strategy) { + JsonParser parser{in, 0, err, false, strategy}; + + vector json_vec; + while (parser.i != in.size() && !parser.failed) { + json_vec.push_back(parser.parse_json(0)); + // Check for another object + parser.consume_garbage(); + } + return json_vec; +} + +/* * * * * * * * * * * * * * * * * * * * + * Shape-checking + */ + +bool Json::has_shape(const shape &types, string &err) const { + if (!is_object()) { + err = "expected JSON object, got " + dump(); + return false; + } + + for (auto &item : types) { + if ((*this)[item.first].type() != item.second) { + err = "bad type for " + item.first + " in " + dump(); + return false; + } + } + + return true; +} + +} // namespace json11 diff --git a/CUDA_Convolution/libwb/vendor/json11.hpp b/CUDA_Convolution/libwb/vendor/json11.hpp new file mode 100644 index 0000000..9e0f0d9 --- /dev/null +++ b/CUDA_Convolution/libwb/vendor/json11.hpp @@ -0,0 +1,300 @@ +/* json11 + * + * json11 is a tiny JSON library for C++11, providing JSON parsing and + * serialization. + * + * The core object provided by the library is json11::Json. A Json object + * represents any JSON + * value: null, bool, number (int or double), string (std::string), array + * (std::vector), or + * object (std::map). + * + * Json objects act like values: they can be assigned, copied, moved, + * compared for equality or + * order, etc. There are also helper methods Json::dump, to serialize a + * Json to a string, and + * Json::parse (static) to parse a std::string as a Json object. + * + * Internally, the various types of Json object are represented by the + * JsonValue class + * hierarchy. + * + * A note on numbers - JSON specifies the syntax of number formatting but + * not its semantics, + * so some JSON implementations distinguish between integers and + * floating-point numbers, while + * some don't. In json11, we choose the latter. Because some JSON + * implementations (namely + * Javascript itself) treat all numbers as the same type, distinguishing + * the two leads + * to JSON that will be *silently* changed by a round-trip through those + * implementations. + * Dangerous! To avoid that risk, json11 stores all numbers as double + * internally, but also + * provides integer helpers. + * + * Fortunately, double-precision IEEE754 ('double') can precisely store any + * integer in the + * range +/-2^53, which includes every 'int' on most systems. (Timestamps + * often use int64 + * or long long to avoid the Y2038K problem; a double storing microseconds + * since some epoch + * will be exact for +/- 275 years.) + */ + +/* Copyright (c) 2013 Dropbox, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy + * of this software and associated documentation files (the "Software"), to + * deal + * in the Software without restriction, including without limitation the + * rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN + * THE SOFTWARE. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +//PMO +#ifndef _MSC_VER +#define NOEXCEPT noexcept +#else +#define NOEXCEPT _NOEXCEPT +#endif + +namespace json11 { + +enum JsonParse { STANDARD, COMMENTS }; + +class JsonValue; + +class Json final { +public: + // Types + enum Type { + NUL, + NUMBER, + NUMBER64, + UNUMBER64, + BOOL, + STRING, + ARRAY, + OBJECT + }; + + // Array and object typedefs + typedef std::vector array; + typedef std::map object; + + // Constructors for the various types of JSON value. + //PMO + //Json() noexcept; // NUL + Json() NOEXCEPT; // NUL + //Json(std::nullptr_t) noexcept; // NUL + Json(std::nullptr_t) NOEXCEPT; // NUL + Json(double value); // NUMBER + Json(int value); // NUMBER + Json(int64_t value); // NUMBER64 + Json(uint64_t value); // UNUMBER64 + Json(bool value); // BOOL + Json(const std::string &value); // STRING + Json(std::string &&value); // STRING + Json(const char *value); // STRING + Json(const array &values); // ARRAY + Json(array &&values); // ARRAY + Json(const object &values); // OBJECT + Json(object &&values); // OBJECT + + // Implicit constructor: anything with a to_json() function. + template + Json(const T &t) : Json(t.to_json()) { + } + + // Implicit constructor: map-like objects (std::map, std::unordered_map, + // etc) + template < + class M, + typename std::enable_if< + std::is_constructible::value && + std::is_constructible::value, + int>::type = 0> + Json(const M &m) : Json(object(m.begin(), m.end())) { + } + + // Implicit constructor: vector-like objects (std::list, std::vector, + // std::set, etc) + template ::value, + int>::type = 0> + Json(const V &v) : Json(array(v.begin(), v.end())) { + } + + // This prevents Json(some_pointer) from accidentally producing a bool. + // Use + // Json(bool(some_pointer)) if that behavior is desired. + Json(void *) = delete; + + // Accessors + Type type() const; + + bool is_null() const { + return type() == NUL; + } + bool is_number() const { + return type() == NUMBER; + } + bool is_number64() const { + return type() == NUMBER64; + } + bool is_unumber64() const { + return type() == UNUMBER64; + } + bool is_bool() const { + return type() == BOOL; + } + bool is_string() const { + return type() == STRING; + } + bool is_array() const { + return type() == ARRAY; + } + bool is_object() const { + return type() == OBJECT; + } + + // Return the enclosed value if this is a number, 0 otherwise. Note that + // json11 does not + // distinguish between integer and non-integer numbers - number_value() + // and int_value() + // can both be applied to a NUMBER-typed object. + double number_value() const; + int int_value() const; + int64_t int64_value() const; + uint64_t uint64_value() const; + + // Return the enclosed value if this is a boolean, false otherwise. + bool bool_value() const; + // Return the enclosed string if this is a string, "" otherwise. + const std::string &string_value() const; + // Return the enclosed std::vector if this is an array, or an empty + // vector otherwise. + const array &array_items() const; + // Return the enclosed std::map if this is an object, or an empty map + // otherwise. + const object &object_items() const; + + // Return a reference to arr[i] if this is an array, Json() otherwise. + const Json &operator[](size_t i) const; + // Return a reference to obj[key] if this is an object, Json() otherwise. + const Json &operator[](const std::string &key) const; + + // Serialize. + void dump(std::string &out) const; + std::string dump() const { + std::string out; + dump(out); + return out; + } + + // Parse. If parse fails, return Json() and assign an error message to + // err. + static Json parse(const std::string &in, std::string &err, + JsonParse strategy = JsonParse::STANDARD); + static Json parse(const char *in, std::string &err, + JsonParse strategy = JsonParse::STANDARD) { + if (in) { + return parse(std::string(in), err, strategy); + } else { + err = "null input"; + return nullptr; + } + } + // Parse multiple objects, concatenated or separated by whitespace + static std::vector + parse_multi(const std::string &in, std::string &err, + JsonParse strategy = JsonParse::STANDARD); + + bool operator==(const Json &rhs) const; + bool operator<(const Json &rhs) const; + bool operator!=(const Json &rhs) const { + return !(*this == rhs); + } + bool operator<=(const Json &rhs) const { + return !(rhs < *this); + } + bool operator>(const Json &rhs) const { + return (rhs < *this); + } + bool operator>=(const Json &rhs) const { + return !(*this < rhs); + } + + /* has_shape(types, err) + * + * Return true if this is a JSON object and, for each item in types, has + * a field of + * the given type. If not, return false and set err to a descriptive + * message. + */ + typedef std::initializer_list> shape; + bool has_shape(const shape &types, std::string &err) const; + +private: + std::shared_ptr m_ptr; +}; + +// Internal class hierarchy - JsonValue objects are not exposed to users of +// this API. +class JsonValue { +protected: + friend class Json; + friend class JsonInt; + friend class JsonInt64; + friend class JsonUInt64; + friend class JsonDouble; + virtual Json::Type type() const = 0; + virtual bool equals(const JsonValue *other) const = 0; + virtual bool less(const JsonValue *other) const = 0; + virtual void dump(std::string &out) const = 0; + virtual double number_value() const; + virtual int int_value() const; + virtual int64_t int64_value() const; + virtual uint64_t uint64_value() const; + virtual bool bool_value() const; + virtual const std::string &string_value() const; + virtual const Json::array &array_items() const; + virtual const Json &operator[](size_t i) const; + virtual const Json::object &object_items() const; + virtual const Json &operator[](const std::string &key) const; + virtual ~JsonValue() { + } +}; + +} // namespace json11 diff --git a/CUDA_Convolution/libwb/wb.h b/CUDA_Convolution/libwb/wb.h new file mode 100644 index 0000000..8f41e23 --- /dev/null +++ b/CUDA_Convolution/libwb/wb.h @@ -0,0 +1,155 @@ + + +#ifndef __WB_H__ +#define __WB_H__ + +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ + +#include +#include +#include +#include + +#ifdef _MSC_VER + +// set minimal warning level +#pragma warning(push,0) +// some warnings still occur at this level +// if necessary, disable specific warnings not covered by previous pragma +#pragma warning(disable : 4244 4056 4305 4800 4267 4996 4756 4661 4385 4101) + +#define __func__ __FUNCTION__ +#ifndef _CRT_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_WARNINGS 1 +#endif /* _CRT_SECURE_NO_WARNINGS */ +#define _CRT_SECURE_NO_DEPRECATE 1 +#define _CRT_NONSTDC_NO_DEPRECATE 1 +#include +#include +#include +#define WB_USE_WINDOWS +#else /* _MSC_VER */ +#include +#include +#include +#include +#define WB_USE_UNIX +#ifdef __APPLE__ +#include +#define WB_USE_DARWIN +#else /* __APPLE__ */ +#define WB_USE_LINUX +#endif /* __APPLE__ */ +#endif /* _MSC_VER */ + +#define wbStmt(stmt) stmt + +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ + +#define wbLine __LINE__ +#define wbFile __FILE__ +#define wbFunction __func__ + +#define wbExit() \ + wbAssert(0); \ + exit(1) + +#ifdef WB_USE_COURSERA +#define wbLogger_printOnExit 1 +#else /* WB_USE_COURSERA */ +#define wbLogger_printOnLog 1 +#endif /* WB_USE_COURSERA */ + +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ + +#ifdef __cplusplus +#define EXTERN_C extern "C" +#define START_EXTERN_C EXTERN_C { +#define END_EXTERN_C } +#else +#define EXTERN_C +#define START_EXTERN_C +#define END_EXTERN_C +#endif /* __cplusplus */ + +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ + +#include +#define WB_USE_JSON11 1 + +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ + +#define LAZY_FILE_LOAD +extern char *solutionJSON; + +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ + +#ifdef WB_USE_OPENCL +#ifdef WB_USE_DARWIN +#include +#else /* WB_USE_DARWIN */ +#include +#endif /* WB_USE_DARWIN */ +#endif /* WB_USE_OPENCL */ + +#include "wbTypes.h" + +#include "wbAssert.h" +#include "wbMalloc.h" +#include "wbString.h" +#include "wbUtils.h" + +#include "wbArg.h" +#include "wbCUDA.h" +#include "wbCast.h" +#include "wbComparator.h" +#include "wbDirectory.h" +#include "wbExit.h" +#include "wbExport.h" +#include "wbFile.h" +#include "wbImage.h" +#include "wbImport.h" +#include "wbInit.h" +#include "wbLogger.h" +#include "wbMD5.h" +#include "wbMPI.h" +#include "wbSolution.h" +#include "wbSparse.h" +#include "wbThrust.h" +#include "wbTimer.h" +#include "wbPath.h" + +#include "wbDataset.h" + +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ + +#endif /* __WB_H__ */ diff --git a/CUDA_Convolution/libwb/wbArg.cpp b/CUDA_Convolution/libwb/wbArg.cpp new file mode 100644 index 0000000..2a5c736 --- /dev/null +++ b/CUDA_Convolution/libwb/wbArg.cpp @@ -0,0 +1,105 @@ + +#include "wb.h" + +EXTERN_C wbArg_t wbArg_new(int *argc, char ***argv) { + wbArg_t arg; + + wb_init(argc, argv); + + wbArg_setInputCount(arg, 0); + wbArg_setInputFiles(arg, NULL); + wbArg_setOutputFile(arg, NULL); + wbArg_setType(arg, NULL); + wbArg_setExpectedOutputFile(arg, NULL); + return arg; +} + +EXTERN_C void wbArg_delete(wbArg_t arg) { + if (wbArg_getInputCount(arg) > 0 && wbArg_getInputFiles(arg) != NULL) { + int ii; + for (ii = 0; ii < wbArg_getInputCount(arg); ii++) { + wbDelete(wbArg_getInputFile(arg, ii)); + } + wbDelete(wbArg_getInputFiles(arg)); + wbArg_setInputCount(arg, 0); + wbArg_setInputFiles(arg, NULL); + } + if (wbArg_getOutputFile(arg)) { + wbDelete(wbArg_getOutputFile(arg)); + wbArg_setOutputFile(arg, NULL); + } + if (wbArg_getExpectedOutputFile(arg)) { + wbDelete(wbArg_getExpectedOutputFile(arg)); + wbArg_setExpectedOutputFile(arg, NULL); + } + if (wbArg_getType(arg)) { + wbDelete(wbArg_getType(arg)); + wbArg_setType(arg, NULL); + } + return; +} + +static int getInputFileCount(char *arg) { + int count = 1; + while (*arg != '\0' && *arg != '-') { + if (*arg == ',') { + count++; + } + arg++; + } + return count; +} + +static char **parseInputFiles(char *arg, int *resCount) { + int count; + int ii = 0; + char **files; + char *token; + + count = getInputFileCount(arg); + + files = wbNewArray(char *, count); + + token = strtok(arg, ","); + while (token != NULL) { + files[ii++] = wbString_duplicate(token); + token = strtok(NULL, ","); + } + *resCount = ii; + return files; +} + +static char *parseString(char *arg) { + return wbString_duplicate(arg); +} + +EXTERN_C wbArg_t wbArg_read(int argc, char **argv) { + int ii; + wbArg_t arg; + + arg = wbArg_new(&argc, &argv); + for (ii = 0; ii < argc; ii++) { + if (wbString_startsWith(argv[ii], "-i")) { + int fileCount; + char **files; + + files = parseInputFiles(argv[ii + 1], &fileCount); + + wbArg_setInputCount(arg, fileCount); + wbArg_setInputFiles(arg, files); + } else if (wbString_startsWith(argv[ii], "-o")) { + char *file = parseString(argv[ii + 1]); + wbArg_setOutputFile(arg, file); + } else if (wbString_startsWith(argv[ii], "-e")) { + char *file = parseString(argv[ii + 1]); + wbArg_setExpectedOutputFile(arg, file); + } else if (wbString_startsWith(argv[ii], "-t")) { + char *type = parseString(argv[ii + 1]); + wbArg_setType(arg, type); + } else if (argv[ii][0] == '-') { + wbLog(ERROR, "Unexpected program option ", argv[ii]); + } + } + + return arg; +} diff --git a/CUDA_Convolution/libwb/wbArg.h b/CUDA_Convolution/libwb/wbArg.h new file mode 100644 index 0000000..c98bcf7 --- /dev/null +++ b/CUDA_Convolution/libwb/wbArg.h @@ -0,0 +1,33 @@ + + +#ifndef __WB_ARG_H__ +#define __WB_ARG_H__ + +struct st_wbArg_t { + int inputCount; + char **inputFiles; + char *outputFile; + char *expectedOutput; + char *type; +}; + +#define wbArg_getInputCount(wa) ((wa).inputCount) +#define wbArg_getInputFiles(wa) ((wa).inputFiles) +#define wbArg_getInputFile(wa, ii) (wbArg_getInputFiles(wa)[ii]) +#define wbArg_getOutputFile(wa) ((wa).outputFile) +#define wbArg_getExpectedOutputFile(wa) ((wa).expectedOutput) +#define wbArg_getType(wa) ((wa).type) + +#define wbArg_setInputCount(wa, val) (wbArg_getInputCount(wa) = val) +#define wbArg_setInputFiles(wa, val) (wbArg_getInputFiles(wa) = val) +#define wbArg_setInputFile(wa, ii, val) (wbArg_getInputFile(wa, ii) = val) +#define wbArg_setOutputFile(wa, val) (wbArg_getOutputFile(wa) = val) +#define wbArg_setExpectedOutputFile(wa, val) \ + (wbArg_getExpectedOutputFile(wa) = val) +#define wbArg_setType(wa, val) (wbArg_getType(wa) = val) + +EXTERN_C wbArg_t wbArg_new(int *argc, char ***argv); +EXTERN_C void wbArg_delete(wbArg_t arg); +EXTERN_C wbArg_t wbArg_read(int argc, char **argv); + +#endif /* __WB_ARG_H__ */ diff --git a/CUDA_Convolution/libwb/wbAssert.h b/CUDA_Convolution/libwb/wbAssert.h new file mode 100644 index 0000000..b8ed669 --- /dev/null +++ b/CUDA_Convolution/libwb/wbAssert.h @@ -0,0 +1,24 @@ + + +#ifndef __WB_ASSERT_H__ +#define __WB_ASSERT_H__ + +#include + +#ifdef WB_DEBUG +#define wbAssert(cond) assert(cond) +#define wbAssertMessage(msg, cond) \ + do { \ + if (!(cond)) { \ + wbPrint(msg); \ + wbAssert(cond); \ + } \ + } while (0) +#else /* WB_DEBUG */ +#define wbAssert(...) +#define wbAssertMessage(...) +#endif /* WB_DEBUG */ + +#define wbTodo(msg) wbAssertMessage(msg, false) + +#endif /* __WB_ASSERT_H__ */ diff --git a/CUDA_Convolution/libwb/wbCUDA.cpp b/CUDA_Convolution/libwb/wbCUDA.cpp new file mode 100644 index 0000000..cb26895 --- /dev/null +++ b/CUDA_Convolution/libwb/wbCUDA.cpp @@ -0,0 +1,25 @@ + +#include "wb.h" +#ifdef WB_USE_CUDA + +int _cudaMemoryListIdx = 0; + +size_t _cudaMallocSize = 0; + +wbCUDAMemory_t _cudaMemoryList[_cudaMemoryListSize]; + +char *wbRandom_list(size_t sz) { + size_t ii; + char *rands = wbNewArray(char, sz); + int *irands = (int *)rands; + for (ii = 0; ii < sz / sizeof(int); ii++) { + irands[ii] = rand(); + } + while (ii < sz) { + rands[ii] = (char)(rand() % 255); + ii++; + } + return rands; +} + +#endif /* WB_USE_CUDA */ diff --git a/CUDA_Convolution/libwb/wbCUDA.h b/CUDA_Convolution/libwb/wbCUDA.h new file mode 100644 index 0000000..658ff39 --- /dev/null +++ b/CUDA_Convolution/libwb/wbCUDA.h @@ -0,0 +1,77 @@ + +#ifndef __WB_CUDA_H__ +#define __WB_CUDA_H__ + +#ifdef WB_USE_CUDA +#ifdef __PGI +#define __GNUC__ 4 +#endif /* __PGI */ +#include +#include + +typedef struct st_wbCUDAMemory_t { + void *mem; + size_t sz; +} wbCUDAMemory_t; + +#define _cudaMemoryListSize 1024 + +extern size_t _cudaMallocSize; +extern wbCUDAMemory_t _cudaMemoryList[]; +extern int _cudaMemoryListIdx; + +char *wbRandom_list(size_t sz); + +static inline cudaError_t wbCUDAMalloc(void **devPtr, size_t sz) { + int idx = _cudaMemoryListIdx; + + cudaError_t err = cudaMalloc(devPtr, sz); + + if (idx == 0) { + srand(time(NULL)); + memset(_cudaMemoryList, 0, + sizeof(wbCUDAMemory_t) * _cudaMemoryListSize); + } + + if (err == cudaSuccess) { +#if 0 + char * rands = wbRandom_list(sz); + // can use curand here, but do not want to invoke a kernel + err = cudaMemcpy(*devPtr, rands, sz, cudaMemcpyHostToDevice); + wbFree(rands); +#else + err = cudaMemset(*devPtr, 0, sz); +#endif + } + + _cudaMallocSize += sz; + _cudaMemoryList[idx].mem = *devPtr; + _cudaMemoryList[idx].sz = sz; + _cudaMemoryListIdx++; + return err; +} + +static inline cudaError_t wbCUDAFree(void *mem) { + int idx = _cudaMemoryListIdx; + if (idx == 0) { + memset(_cudaMemoryList, 0, + sizeof(wbCUDAMemory_t) * _cudaMemoryListSize); + } + for (int ii = 0; ii < idx; ii++) { + if (_cudaMemoryList[ii].mem != NULL && + _cudaMemoryList[ii].mem == mem) { + cudaError_t err = cudaFree(mem); + _cudaMallocSize -= _cudaMemoryList[ii].sz; + _cudaMemoryList[ii].mem = NULL; + return err; + } + } + return cudaErrorMemoryAllocation; +} + +#define cudaMalloc(elem, err) wbCUDAMalloc((void **)elem, err) +#define cudaFree wbCUDAFree + +#endif /* WB_USE_CUDA */ + +#endif /* __WB_CUDA_H__ */ diff --git a/CUDA_Convolution/libwb/wbCast.h b/CUDA_Convolution/libwb/wbCast.h new file mode 100644 index 0000000..01e8387 --- /dev/null +++ b/CUDA_Convolution/libwb/wbCast.h @@ -0,0 +1,29 @@ + + +#ifndef __WB_CAST_H__ +#define __WB_CAST_H__ + +template +static inline void wbCast(X &x, const Y &y, size_t len) { + size_t ii; + + for (ii = 0; ii < len; ii++) { + x[ii] = (X)y[ii]; + } + + return; +} + +template +static inline X *wbCast(const Y &y, size_t len) { + size_t ii; + X *x = wbNewArray(X, len); + + for (ii = 0; ii < len; ii++) { + x[ii] = (X)y[ii]; + } + + return x; +} + +#endif /* __WB_CAST_H__ */ diff --git a/CUDA_Convolution/libwb/wbComparator.h b/CUDA_Convolution/libwb/wbComparator.h new file mode 100644 index 0000000..26fd0cb --- /dev/null +++ b/CUDA_Convolution/libwb/wbComparator.h @@ -0,0 +1,187 @@ + + +#ifndef __WB_COMPARATOR_H__ +#define __WB_COMPARATOR_H__ + +#include "wb.h" + +template +static inline T _abs(const T &a) { + return a < 0 ? -a : a; +} + +static inline wbBool _almostEqual(double A, double B, double eps) { + if (A == 0) { + return _abs(B) < eps; + } else if (B == 0) { + return _abs(A) < eps; + } else { +#if 0 + double d = max(_abs(A), _abs(B)); + double g = (_abs(A - B) / d); +#else + double g = _abs(A - B); +#endif + if (g <= eps) { + return wbTrue; + } else { + return wbFalse; + } + } +} + +static inline wbBool _almostEqual(float A, float B, float eps) { + if (A == 0) { + return _abs(B) < eps; + } else if (B == 0) { + return _abs(A) < eps; + } else { +#if 0 + float d = max(_abs(A), _abs(B)); + float g = (_abs(A - B) / d); +#else + float g = _abs(A - B); +#endif + if (g <= eps) { + return wbTrue; + } else { + return wbFalse; + } + } +} + +static inline wbBool _almostEqual(double A, double B) { + return _almostEqual(A, B, 0.2); +} + +static inline wbBool _almostEqual(float A, float B) { + return _almostEqual(A, B, 0.2f); +} + +static inline wbBool _almostEqual2sComplement(float A, float B, + int maxUlps) { + // Make sure maxUlps is non-negative and small enough that the + // default NAN won't compare as equal to anything. + + int aInt, bInt, intDiff; + + wbAssert(maxUlps > 0 && maxUlps < 4 * 1024 * 1024); + + int *tmp = reinterpret_cast(&A); + aInt = *tmp; + + // Make aInt lexicographically ordered as a twos-complement int + if (aInt < 0) { + aInt = 0x80000000 - aInt; + } + // Make bInt lexicographically ordered as a twos-complement int + tmp = reinterpret_cast(&B); + bInt = *tmp; + if (bInt < 0) { + bInt = 0x80000000 - bInt; + } + intDiff = _abs(aInt - bInt); + if (intDiff <= maxUlps) { + return wbTrue; + } + return wbFalse; +} + +static inline wbBool _almostEqual2sComplement(float A, float B) { + return _almostEqual2sComplement(A, B, 4); +} + +static inline wbBool _almostEqual2sComplement(double A, double B, + int maxUlps) { + // Make sure maxUlps is non-negative and small enough that the + // default NAN won't compare as equal to anything. + + int64_t aInt, bInt, intDiff; + + wbAssert(maxUlps > 0 && maxUlps < 4 * 1024 * 1024); + + int64_t *tmp = reinterpret_cast(&A); + aInt = *tmp; + + // Make aInt lexicographically ordered as a twos-complement int + if (aInt < 0) { + aInt = 0x80000000 - aInt; + } + // Make bInt lexicographically ordered as a twos-complement int + tmp = reinterpret_cast(&B); + bInt = *tmp; + if (bInt < 0) { + bInt = 0x80000000 - bInt; + } + intDiff = _abs(aInt - bInt); + if (intDiff <= maxUlps) { + return wbTrue; + } + return wbFalse; +} + +static inline wbBool _almostEqual2sComplement(double A, double B) { + return _almostEqual2sComplement(A, B, 4); +} + +template +static inline int wbCompare(const T &a, const T &b) { + if (a == b) { + return 0; + } else if (a < b) { + return -1; + } else { + return 1; + } +} + +template <> +inline int wbCompare(const double &a, const double &b) { + if (_almostEqual(a, b)) { + return 0; + } else if (a < b) { + return -1; + } else { + return 1; + } +} + +template <> +inline int wbCompare(const float &a, const float &b) { + if (_almostEqual(a, b)) { + return 0; + } else if (a < b) { + return -1; + } else { + return 1; + } +} + +template +static inline wbBool wbEqualQ(const T &a, const T &b) { + return wbCompare(a, b) == 0; +} + +template +static inline wbBool wbUnequalQ(const T &a, const T &b) { + return wbCompare(a, b) != 0; +} + +template +static inline wbBool wbEqualQ(const T *a, const T *b, size_t n) { + size_t ii; + + for (ii = 0; ii < n; ii++) { + if (wbUnequalQ(a[ii], b[ii])) { + return wbFalse; + } + } + return wbTrue; +} + +template +static inline wbBool wbUnequalQ(const T *a, const T *b, size_t n) { + return !wbEqualQ(a, b, n); +} + +#endif /* __WB_COMPARATOR_H__ */ diff --git a/CUDA_Convolution/libwb/wbDataset.cpp b/CUDA_Convolution/libwb/wbDataset.cpp new file mode 100644 index 0000000..a11f064 --- /dev/null +++ b/CUDA_Convolution/libwb/wbDataset.cpp @@ -0,0 +1,177 @@ +#include "wb.h" + +template +static inline T _min(const T &x, const T &y) { + return x < y ? x : y; +} + +template +static inline T _max(const T &x, const T &y) { + return x > y ? x : y; +} + +template +inline T lerp(const double &x, const T &start, const T &end) { + return (1 - x) * start + x * end; +} + +static inline void genRandom(void *trgt, wbType_t type, double minVal, + double maxVal) { + const int span = maxVal - minVal; + const int r = rand(); + const double rf = ((double)r) / ((double)RAND_MAX); + switch (type) { + case wbType_ascii: + *((char *)trgt) = (r % span) + minVal; // random printable character; + break; + case wbType_bit8: + *((char *)trgt) = lerp(rf, minVal, maxVal); + break; + case wbType_ubit8: + *((unsigned char *)trgt) = lerp(rf, minVal, maxVal); + break; + case wbType_integer: + *((int *)trgt) = lerp(rf, minVal, maxVal); + break; + case wbType_float: { + *((float *)trgt) = lerp(rf, minVal, maxVal); + break; + } + case wbType_double: { + *((double *)trgt) = lerp(rf, minVal, maxVal); + break; + } + case wbType_unknown: + wbAssert(false && "Invalid wbType_unknown"); + break; + } + return; +} + +static inline void *genRandomList(wbType_t type, size_t len, double minVal, + double maxVal) { + size_t ii; + void *data = wbNewArray(char, wbType_size(type) * len); + switch (type) { + case wbType_ascii: + case wbType_bit8: { + char *iter = (char *)data; + for (ii = 0; ii < len; ii++) { + genRandom(iter++, type, minVal, maxVal); + } + break; + } + case wbType_ubit8: { + unsigned char *iter = (unsigned char *)data; + for (ii = 0; ii < len; ii++) { + genRandom(iter++, type, minVal, maxVal); + } + break; + } + case wbType_integer: { + int *iter = (int *)data; + for (ii = 0; ii < len; ii++) { + genRandom(iter++, type, minVal, maxVal); + } + break; + } + case wbType_float: { + float *iter = (float *)data; + for (ii = 0; ii < len; ii++) { + genRandom(iter++, type, minVal, maxVal); + } + break; + } + case wbType_double: { + double *iter = (double *)data; + for (ii = 0; ii < len; ii++) { + genRandom(iter++, type, minVal, maxVal); + } + break; + } + case wbType_unknown: + wbAssert(false && "Invalid wbType_unknown"); + break; + } + return data; +} + +static void genRaw(const char *path, wbRaw_GenerateParams_t params) { + int rows = _max(1, params.rows); + int cols = _max(1, params.cols); + double minVal = params.minVal; + double maxVal = params.maxVal; + wbType_t type = params.type; + void *data = genRandomList(type, rows * cols, minVal, maxVal); + wbExport(path, wbExportKind_raw, data, rows, cols, type); + wbDelete(data); +} + +static void genCSV(const char *path, wbCSV_GenerateParams_t params) { + int rows = _max(1, params.rows); + int cols = _max(1, params.cols); + double minVal = params.minVal; + double maxVal = params.maxVal; + wbType_t type = params.type; + void *data = genRandomList(type, rows * cols, minVal, maxVal); + wbExport(path, wbExportKind_csv, data, rows, cols, type); + wbDelete(data); +} + +static void genTSV(const char *path, wbTSV_GenerateParams_t params) { + int rows = _max(1, params.rows); + int cols = _max(1, params.cols); + double minVal = params.minVal; + double maxVal = params.maxVal; + wbType_t type = params.type; + void *data = genRandomList(type, rows * cols, minVal, maxVal); + wbExport(path, wbExportKind_tsv, data, rows, cols, type); + wbDelete(data); +} + +static void genText(const char *path, wbText_GenerateParams_t params) { + int length = _max(1, params.length); + wbType_t type = wbType_ascii; + void *data = genRandomList(type, length, 32, 128); + wbExport(path, wbExportKind_text, data, length, 1, type); + wbDelete(data); +} + +static void genPPM(const char *path, wbPPM_GenerateParams_t params) { + int width = _max(1, params.width); + int height = _max(1, params.height); + int channels = _max(1, params.channels); + double minVal = params.minVal; + double maxVal = params.maxVal; + wbType_t type = wbType_float; + float *data = (float *)genRandomList(type, width * height * channels, + minVal, maxVal); + wbImage_t img = wbImage_new(width, height, channels, data); + wbExport(path, img); + wbImage_delete(img); +} + +EXTERN_C void wbDataset_generate(const char *path, wbExportKind_t kind, + wbGenerateParams_t params) { + wbDirectory_create(wbDirectory_name(path)); + + switch (kind) { + case wbExportKind_raw: + genRaw(path, params.raw); + break; + case wbExportKind_csv: + genCSV(path, params.csv); + break; + case wbExportKind_tsv: + genTSV(path, params.tsv); + break; + case wbExportKind_ppm: + genPPM(path, params.ppm); + break; + case wbExportKind_text: + genText(path, params.text); + break; + default: + wbAssert(false && "Invalid Export kind"); + } +} diff --git a/CUDA_Convolution/libwb/wbDataset.h b/CUDA_Convolution/libwb/wbDataset.h new file mode 100644 index 0000000..ce81c28 --- /dev/null +++ b/CUDA_Convolution/libwb/wbDataset.h @@ -0,0 +1,52 @@ +#ifndef __WB_DATASET_H__ +#define __WB_DATASET_H__ + +#include "wbImport.h" +#include "wbTypes.h" + +typedef struct { + int rows; + int cols; + wbType_t type; + double minVal; + double maxVal; +} wbCSV_GenerateParams_t; + +typedef struct { + int rows; + int cols; + wbType_t type; + double minVal; + double maxVal; +} wbTSV_GenerateParams_t; + +typedef struct { + int rows; + int cols; + double minVal; + double maxVal; + wbType_t type; +} wbRaw_GenerateParams_t; + +typedef struct { + int width; + int height; + int channels; + double minVal; + double maxVal; +} wbPPM_GenerateParams_t; + +typedef struct { int length; } wbText_GenerateParams_t; + +typedef union { + wbCSV_GenerateParams_t csv; + wbRaw_GenerateParams_t raw; + wbTSV_GenerateParams_t tsv; + wbPPM_GenerateParams_t ppm; + wbText_GenerateParams_t text; +} wbGenerateParams_t; + +EXTERN_C void wbDataset_generate(const char *path, wbExportKind_t kind, + wbGenerateParams_t params); + +#endif /* __WB_DATASET_H__ */ diff --git a/CUDA_Convolution/libwb/wbDataset_test.cpp b/CUDA_Convolution/libwb/wbDataset_test.cpp new file mode 100644 index 0000000..4f08042 --- /dev/null +++ b/CUDA_Convolution/libwb/wbDataset_test.cpp @@ -0,0 +1,23 @@ + +#include "wb.h" +#include "vendor/catch.hpp" + +TEST_CASE("Can create Raw dataset", "[DataGenerator]") { + wbGenerateParams_t params; + params.raw.rows = 2; + params.raw.cols = 300; + params.raw.minVal = 0; + params.raw.maxVal = 30; + params.raw.type = wbType_integer; + wbDataset_generate( + wbPath_join(wbDirectory_current(), "test-dataset", "test.raw"), + wbExportKind_raw, params); +} + +TEST_CASE("Can create Text dataset", "[DataGenerator]") { + wbGenerateParams_t params; + params.text.length = 2000; + wbDataset_generate( + wbPath_join(wbDirectory_current(), "test-dataset", "test.txt"), + wbExportKind_text, params); +} diff --git a/CUDA_Convolution/libwb/wbDirectory.cpp b/CUDA_Convolution/libwb/wbDirectory.cpp new file mode 100644 index 0000000..10dc8c5 --- /dev/null +++ b/CUDA_Convolution/libwb/wbDirectory.cpp @@ -0,0 +1,88 @@ +#include "wb.h" + +#ifndef PATH_MAX +#ifdef FILENAME_MAX +#define PATH_MAX FILENAME_MAX +#else /* FILENAME_MAX */ +#define PATH_MAX 4096 +#endif /* FILENAME_MAX */ +#endif /* PATH_MAX */ + +#ifdef WB_USE_UNIX +const char wbDirectorySeperator = '/'; +static char *getcwd_(char *buf, int maxLen) { + return getcwd(buf, maxLen); +} +static void mkdir_(const char *dir) { + mkdir(dir, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); +} +#else /* WB_USE_LINUX */ +const char wbDirectorySeperator = '\\'; +static char *getcwd_(char *buf, int maxLen) { + return _getcwd(buf, maxLen); +} +static void mkdir_(const char *dir) { + _mkdir(dir); +} +#endif /* WB_USE_LINUX */ + +EXTERN_C const char * wbDirectory_create(const char *dir) { + char tmp[PATH_MAX]; + char *p = NULL; + size_t len; +//PMO +#ifndef _MSC_VER + snprintf(tmp, sizeof(tmp), "%s", dir); +#else + _snprintf_s(tmp, sizeof(tmp), "%s", dir); +#endif + len = strlen(tmp); + if (tmp[len - 1] == wbDirectorySeperator) { + tmp[len - 1] = 0; + } + for (p = tmp + 1; *p; p++) { + if (*p == wbDirectorySeperator) { + *p = 0; + mkdir_(tmp); + *p = wbDirectorySeperator; + } + } + mkdir_(tmp); + return dir; +} + +EXTERN_C char *wbDirectory_name(const char *pth0) { + char *pth = wbString_duplicate(pth0); + char *p = strrchr(pth, wbDirectorySeperator); + if (p) { + p[0] = 0; + } + return pth; +} + +EXTERN_C char *wbDirectory_current() { + char *tmp = wbNewArray(char, PATH_MAX + 1); + if (getcwd_(tmp, PATH_MAX)) { + return tmp; + } + + wbDelete(tmp); + + int error = errno; + switch (error) { + case EACCES: + std::cerr + << "Cannot get current directory :: access denied. exiting..." + << std::endl; + exit(-1); + case ENOMEM: + std::cerr << "Cannot get current directory :: insufficient storage. " + "exiting..." + << std::endl; + exit(-1); + default: + std::cerr << "Cannot get current directory :: unrecognised error " + << error << std::endl; + exit(-1); + } +} \ No newline at end of file diff --git a/CUDA_Convolution/libwb/wbDirectory.h b/CUDA_Convolution/libwb/wbDirectory.h new file mode 100644 index 0000000..cb14f81 --- /dev/null +++ b/CUDA_Convolution/libwb/wbDirectory.h @@ -0,0 +1,9 @@ +#ifndef __WB_DIRECTORY__ +#define __WB_DIRECTORY__ + +extern const char wbDirectorySeperator; +EXTERN_C char *wbDirectory_name(const char *pth); +EXTERN_C const char * wbDirectory_create(const char *dir); +EXTERN_C char *wbDirectory_current(); + +#endif /* __WB_DIRECTORY__ */ diff --git a/CUDA_Convolution/libwb/wbExit.cpp b/CUDA_Convolution/libwb/wbExit.cpp new file mode 100644 index 0000000..a7edc3a --- /dev/null +++ b/CUDA_Convolution/libwb/wbExit.cpp @@ -0,0 +1,119 @@ + +#include "wb.h" + +enum { + wbMPI_timerTag = 2, + wbMPI_loggerTag = 4, + wbMPI_solutionExistsTag = 8, + wbMPI_solutionTag = 16 +}; + +void wb_atExit(void) { + using std::cout; + using std::endl; + +#ifdef WB_USE_CUDA + cudaDeviceSynchronize(); +#endif /* WB_USE_CUDA */ + + int nranks = rankCount(); + if (nranks > 1) { +#ifdef WB_USE_MPI + if (isMasterQ) { +#ifdef wbLogger_printOnExit + cout << "==$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$" << endl; + + cout << "{\n"; + cout << wbString_quote("timer") << ":"; + cout << "[\n"; + for (int ii = 0; ii < nranks; ii++) { + if (ii == 0) { + cout << wbTimer_toJSON(); + } else { + const char *msg = wbMPI_getStringFromRank(ii, wbMPI_timerTag); + if (msg != NULL && strlen(msg) != 0) { + cout << ",\n"; + cout << msg; + // free(msg); + } + } + } + cout << "]" << endl; // close timer + + cout << "," << endl; // start logger + cout << wbString_quote("logger") << ":"; + cout << "[\n"; + for (int ii = 0; ii < nranks; ii++) { + if (ii == 0) { + cout << wbLogger_toJSON(); + } else { + const char *msg = wbMPI_getStringFromRank(ii, wbMPI_loggerTag); + if (msg != NULL && strlen(msg) != 0) { + cout << ",\n"; + cout << msg; + // free(msg); + } + } + } + cout << "]" << endl; // close logger + + cout << "," << endl; // start solutionExists + cout << wbString_quote("cuda_memory") << ":" << _cudaMallocSize + << ",\n"; + + if (solutionJSON) { + cout << wbString_quote("solution_exists") << ": true,\n"; + cout << wbString_quote("solution") << ":" << solutionJSON << "\n"; + } else { + cout << wbString_quote("solution_exists") << ": false\n"; + } + cout << "}" << endl; // close json + + } else { + wbMPI_sendStringToMaster(wbTimer_toJSON().c_str(), wbMPI_timerTag); + wbMPI_sendStringToMaster(wbLogger_toJSON().c_str(), wbMPI_loggerTag); + } +#endif /* wbLogger_printOnExit */ + +#endif /* WB_USE_MPI */ + } else { +#ifdef wbLogger_printOnExit + cout << "==$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$" << endl; + + cout << "{\n" << wbString_quote("timer") << ":[" << wbTimer_toJSON() + << "],\n" << wbString_quote("logger") << ":[" << wbLogger_toJSON() + << "],\n"; + +#ifdef WB_USE_CUDA + cout << wbString_quote("cuda_memory") << ":" << _cudaMallocSize + << ",\n"; +#endif /* WB_USE_CUDA */ + + if (solutionJSON) { + cout << wbString_quote("solution_exists") << ": true,\n"; + cout << wbString_quote("solution") << ":" << solutionJSON << "\n"; + } else { + cout << wbString_quote("solution_exists") << ": false\n"; + } + cout << "}" << endl; +#endif /* wbLogger_printOnExit */ + } + + // wbTimer_delete(_timer); + // wbLogger_delete(_logger); + + _timer = NULL; + _logger = NULL; + +// wbFile_atExit(); + +#ifdef WB_USE_CUDA + cudaDeviceReset(); +#endif + + exit(0); + + // assert(0); + + return; +} diff --git a/CUDA_Convolution/libwb/wbExit.h b/CUDA_Convolution/libwb/wbExit.h new file mode 100644 index 0000000..4400108 --- /dev/null +++ b/CUDA_Convolution/libwb/wbExit.h @@ -0,0 +1,7 @@ + +#ifndef __WB_EXIT_H__ +#define __WB_EXIT_H__ + +void wb_atExit(void); + +#endif /* __WB_EXIT_H__ */ diff --git a/CUDA_Convolution/libwb/wbExport.cpp b/CUDA_Convolution/libwb/wbExport.cpp new file mode 100644 index 0000000..59b7a33 --- /dev/null +++ b/CUDA_Convolution/libwb/wbExport.cpp @@ -0,0 +1,510 @@ + +#include "wb.h" + +static inline void wbExportText_setFile(wbExportText_t text, + const char *path) { + if (text != NULL) { + if (wbExportText_getFile(text) != NULL) { + wbFile_delete(wbExportText_getFile(text)); + } + if (path != NULL) { + wbExportText_getFile(text) = wbFile_open(path, "w+"); + } else { + wbExportText_getFile(text) = NULL; + } + } + + return; +} + +static inline wbExportText_t wbExportText_new(void) { + wbExportText_t text; + + text = wbNew(struct st_wbExportText_t); + + wbExportText_getFile(text) = NULL; + wbExportText_setLength(text, -1); + + return text; +} + +static inline void wbExportText_delete(wbExportText_t text) { + if (text != NULL) { + wbExportText_setFile(text, NULL); + wbDelete(text); + } + return; +} + +static inline void wbExportText_write(wbExportText_t text, + const char *data, int length) { + int ii; + FILE *handle; + wbFile_t file; + + if (text == NULL || wbExportText_getFile(text) == NULL) { + return; + } + + file = wbExportText_getFile(text); + + handle = wbFile_getFileHandle(file); + + if (handle == NULL) { + return; + } + + for (ii = 0; ii < length; ii++) { + fprintf(handle, "%c", data[ii]); + } + + return; +} + +static inline void wbExportRaw_setFile(wbExportRaw_t raw, + const char *path) { + if (raw != NULL) { + if (wbExportRaw_getFile(raw) != NULL) { + wbFile_delete(wbExportRaw_getFile(raw)); + } + if (path != NULL) { + wbExportRaw_getFile(raw) = wbFile_open(path, "w+"); + } else { + wbExportRaw_getFile(raw) = NULL; + } + } + + return; +} + +static inline wbExportRaw_t wbExportRaw_new(void) { + wbExportRaw_t raw; + + raw = wbNew(struct st_wbExportRaw_t); + + wbExportRaw_getFile(raw) = NULL; + wbExportRaw_setRowCount(raw, -1); + wbExportRaw_setColumnCount(raw, -1); + + return raw; +} + +static inline void wbExportRaw_delete(wbExportRaw_t raw) { + if (raw != NULL) { + wbExportRaw_setFile(raw, NULL); + wbDelete(raw); + } + return; +} + +static inline void wbExportRaw_write(wbExportRaw_t raw, void *data, + int rows, int columns, + wbType_t type) { + int ii, jj; + FILE *handle; + wbFile_t file; + + if (raw == NULL || wbExportRaw_getFile(raw) == NULL) { + return; + } + + file = wbExportRaw_getFile(raw); + + handle = wbFile_getFileHandle(file); + + if (handle == NULL) { + return; + } + + if (columns == 1) { + fprintf(handle, "%d\n", rows); + } else { + fprintf(handle, "%d %d\n", rows, columns); + } + + for (ii = 0; ii < rows; ii++) { + for (jj = 0; jj < columns; jj++) { + if (type == wbType_integer) { + int elem = ((int *)data)[ii * columns + jj]; + fprintf(handle, "%d", elem); + } else if (type == wbType_ubit8) { + int elem = ((unsigned char *)data)[ii * columns + jj]; + fprintf(handle, "%d", elem); + } else { + wbReal_t elem = ((wbReal_t *)data)[ii * columns + jj]; + fprintf(handle, "%f", elem); + } + if (jj == columns - 1) { + fprintf(handle, "\n"); + } else { + fprintf(handle, " "); + } + } + } + + return; +} + +static inline void wbExportCSV_setFile(wbExportCSV_t csv, + const char *path) { + if (csv != NULL) { + if (wbExportCSV_getFile(csv) != NULL) { + wbFile_delete(wbExportCSV_getFile(csv)); + } + if (path != NULL) { + wbExportCSV_getFile(csv) = wbFile_open(path, "w+"); + } else { + wbExportCSV_getFile(csv) = NULL; + } + } + + return; +} + +static inline wbExportCSV_t wbExportCSV_new(void) { + wbExportCSV_t csv; + + csv = wbNew(struct st_wbExportCSV_t); + + wbExportCSV_getFile(csv) = NULL; + wbExportCSV_setColumnCount(csv, -1); + wbExportCSV_setRowCount(csv, -1); + wbExportCSV_setSeperator(csv, '\0'); + + return csv; +} + +static inline void wbExportCSV_delete(wbExportCSV_t csv) { + if (csv != NULL) { + wbExportCSV_setFile(csv, NULL); + wbDelete(csv); + } +} + +static inline void wbExportCSV_write(wbExportCSV_t csv, void *data, + int rows, int columns, char sep, + wbType_t type) { + int ii, jj; + wbFile_t file; + FILE *handle; + char seperator[2]; + + if (csv == NULL || wbExportCSV_getFile(csv) == NULL) { + return; + } + + file = wbExportCSV_getFile(csv); + + handle = wbFile_getFileHandle(file); + + if (handle == NULL) { + return; + } + + if (sep == '\0') { + seperator[0] = ','; + } else { + seperator[0] = sep; + } + seperator[1] = '\0'; + + for (ii = 0; ii < rows; ii++) { + for (jj = 0; jj < columns; jj++) { + if (type == wbType_integer) { + int elem = ((int *)data)[ii * columns + jj]; + fprintf(handle, "%d", elem); + } else if (type == wbType_ubit8) { + int elem = ((unsigned char *)data)[ii * columns + jj]; + fprintf(handle, "%d", elem); + } else { + wbReal_t elem = ((wbReal_t *)data)[ii * columns + jj]; + fprintf(handle, "%f", elem); + } + if (jj == columns - 1) { + fprintf(handle, "\n"); + } else { + fprintf(handle, "%s", seperator); + } + } + } + + return; +} + +static inline wbExport_t wbExport_open(const char *file, + wbExportKind_t kind) { + wbExport_t exprt; + + if (file == NULL) { + wbLog(ERROR, "Go NULL for file value."); + wbExit(); + } + + wbExport_setFile(exprt, NULL); + wbExport_setKind(exprt, kind); + + if (kind == wbExportKind_raw) { + wbExportRaw_t raw = wbExportRaw_new(); + wbExportRaw_setFile(raw, file); + wbExport_setRaw(exprt, raw); + } else if (kind == wbExportKind_text) { + wbExportText_t txt = wbExportText_new(); + wbExportText_setFile(txt, file); + wbExport_setText(exprt, txt); + } else if (kind == wbExportKind_tsv || kind == wbExportKind_csv) { + wbExportCSV_t csv = wbExportCSV_new(); + if (kind == wbExportKind_csv) { + wbExportCSV_setSeperator(csv, ','); + } else { + wbExportCSV_setSeperator(csv, '\t'); + } + wbExportCSV_setFile(csv, file); + wbExport_setCSV(exprt, csv); + } else if (kind == wbExportKind_ppm) { + wbExport_setFile(exprt, wbString_duplicate(file)); + } else { + wbLog(ERROR, "Invalid export type."); + wbExit(); + } + + return exprt; +} + +static inline wbExport_t wbExport_open(const char *file, + const char *type0) { + wbExport_t exprt; + wbExportKind_t kind; + char *type; + + type = wbString_toLower(type0); + + if (wbString_sameQ(type, "csv")) { + kind = wbExportKind_csv; + } else if (wbString_sameQ(type, "tsv")) { + kind = wbExportKind_tsv; + } else if (wbString_sameQ(type, "raw") || wbString_sameQ(type, "dat")) { + kind = wbExportKind_raw; + } else if (wbString_sameQ(type, "ppm") || wbString_sameQ(type, "pbm")) { + kind = wbExportKind_ppm; + } else if (wbString_sameQ(type, "txt") || wbString_sameQ(type, "text")) { + kind = wbExportKind_text; + } else { + wbLog(ERROR, "Invalid export type ", type0); + wbExit(); + } + + exprt = wbExport_open(file, kind); + + wbDelete(type); + + return exprt; +} + +static inline void wbExport_close(wbExport_t exprt) { + wbExportKind_t kind; + + kind = wbExport_getKind(exprt); + + if (wbExport_getFile(exprt)) { + wbDelete(wbExport_getFile(exprt)); + } + + if (kind == wbExportKind_tsv || kind == wbExportKind_csv) { + wbExportCSV_t csv = wbExport_getCSV(exprt); + wbExportCSV_delete(csv); + wbExport_setCSV(exprt, NULL); + } else if (kind == wbExportKind_raw) { + wbExportRaw_t raw = wbExport_getRaw(exprt); + wbExportRaw_delete(raw); + wbExport_setRaw(exprt, NULL); + } else if (kind == wbExportKind_text) { + wbExportText_t text = wbExport_getText(exprt); + wbExportText_delete(text); + wbExport_setText(exprt, NULL); + } else if (kind == wbExportKind_ppm) { + } else { + wbLog(ERROR, "Invalid export type."); + wbExit(); + } + return; +} + +static inline void wbExport_writeAsImage(wbExport_t exprt, wbImage_t img) { + wbAssert(wbExport_getKind(exprt) == wbExportKind_ppm); + + wbPPM_export(wbExport_getFile(exprt), img); + + return; +} + +static inline void wbExport_write(wbExport_t exprt, void *data, int rows, + int columns, char sep, wbType_t type) { + wbExportKind_t kind; + + kind = wbExport_getKind(exprt); + if (kind == wbExportKind_tsv || kind == wbExportKind_csv) { + wbExportCSV_t csv = wbExport_getCSV(exprt); + wbExportCSV_write(csv, data, rows, columns, sep, type); + } else if (kind == wbExportKind_raw) { + wbExportRaw_t raw = wbExport_getRaw(exprt); + wbExportRaw_write(raw, data, rows, columns, type); + } else if (kind == wbExportKind_text) { + wbExportText_t text = wbExport_getText(exprt); + if (columns == 0) { + columns = 1; + } + if (rows == 0) { + rows = 1; + } + wbExportText_write(text, (const char *)data, rows * columns); + } else { + wbLog(ERROR, "Invalid export type."); + wbExit(); + } + return; +} + +static inline void wbExport_write(wbExport_t exprt, void *data, int rows, + int columns, wbType_t type) { + wbExport_write(exprt, data, rows, columns, ',', type); +} + +static wbExportKind_t _parseExportExtension(const char *file) { + char *extension; + wbExportKind_t kind; + + extension = wbFile_extension(file); + + if (wbString_sameQ(extension, "csv")) { + kind = wbExportKind_csv; + } else if (wbString_sameQ(extension, "tsv")) { + kind = wbExportKind_tsv; + } else if (wbString_sameQ(extension, "raw") || + wbString_sameQ(extension, "dat")) { + kind = wbExportKind_raw; + } else if (wbString_sameQ(extension, "text") || + wbString_sameQ(extension, "txt")) { + kind = wbExportKind_text; + } else if (wbString_sameQ(extension, "ppm")) { + kind = wbExportKind_ppm; + } else { + kind = wbExportKind_unknown; + wbLog(ERROR, "File ", file, " does not have a compatible extension."); + } + + wbDelete(extension); + + return kind; +} + +static void wbExport(const char *file, void *data, int rows, int columns, + wbType_t type) { + wbExportKind_t kind; + wbExport_t exprt; + + if (file == NULL) { + return; + } + + kind = _parseExportExtension(file); + exprt = wbExport_open(file, kind); + + wbExport_write(exprt, data, rows, columns, type); + wbExport_close(exprt); +} + +void wbExport(const char *file, unsigned char *data, int rows) { + wbExport(file, data, rows, 1); + return; +} + +void wbExport(const char *file, int *data, int rows) { + wbExport(file, data, rows, 1); + return; +} + +void wbExport(const char *file, wbReal_t *data, int rows) { + wbExport(file, data, rows, 1); + return; +} + +void wbExport(const char *file, unsigned char *data, int rows, + int columns) { + wbExportKind_t kind; + wbExport_t exprt; + + if (file == NULL) { + return; + } + + kind = _parseExportExtension(file); + exprt = wbExport_open(file, kind); + + wbExport_write(exprt, data, rows, columns, wbType_ubit8); + wbExport_close(exprt); +} + +void wbExport(const char *file, int *data, int rows, int columns) { + wbExportKind_t kind; + wbExport_t exprt; + + if (file == NULL) { + return; + } + + kind = _parseExportExtension(file); + exprt = wbExport_open(file, kind); + + wbExport_write(exprt, data, rows, columns, wbType_integer); + wbExport_close(exprt); +} + +void wbExport(const char *file, wbReal_t *data, int rows, int columns) { + wbExportKind_t kind; + wbExport_t exprt; + + if (file == NULL) { + return; + } + + kind = _parseExportExtension(file); + exprt = wbExport_open(file, kind); + + wbExport_write(exprt, data, rows, columns, wbType_real); + wbExport_close(exprt); +} + +void wbExport(const char *file, wbExportKind_t kind, void *data, int rows, + int columns, wbType_t type) { + wbExport_t exprt; + + if (file == NULL) { + return; + } + + exprt = wbExport_open(file, kind); + + wbExport_write(exprt, data, rows, columns, type); + wbExport_close(exprt); +} + +void wbExport(const char *file, wbImage_t img) { + wbExportKind_t kind; + wbExport_t exprt; + + if (file == NULL) { + return; + } + + kind = _parseExportExtension(file); + exprt = wbExport_open(file, kind); + + wbAssert(kind == wbExportKind_ppm); + + wbExport_writeAsImage(exprt, img); + wbExport_close(exprt); +} + +void wbExport_text(const char *file, void *data, int length) { + wbExport(file, wbExportKind_text, data, 1, length, wbType_ascii); +} diff --git a/CUDA_Convolution/libwb/wbExport.h b/CUDA_Convolution/libwb/wbExport.h new file mode 100644 index 0000000..dd16b3f --- /dev/null +++ b/CUDA_Convolution/libwb/wbExport.h @@ -0,0 +1,106 @@ + + +#ifndef __WB_EXPORT_H__ +#define __WB_EXPORT_H__ + +#include "wb.h" +#include "wbFile.h" +#include "wbPPM.h" + +typedef enum en_wbExportKind_t { + wbExportKind_unknown = -1, + wbExportKind_raw = 0x1000, + wbExportKind_csv, + wbExportKind_tsv, + wbExportKind_ppm, + wbExportKind_text, +} wbExportKind_t; + +typedef struct st_wbExportText_t { + int length; + wbFile_t file; +} * wbExportText_t; + +#define wbExportText_getLength(txt) ((txt)->length) +#define wbExportText_getFile(txt) ((txt)->file) + +#define wbExportText_setLength(txt, val) \ + (wbExportText_getLength(txt) = val) + +typedef struct st_wbExportRaw_t { + int rows; + int columns; + wbFile_t file; +} * wbExportRaw_t; + +#define wbExportRaw_getColumnCount(raw) ((raw)->columns) +#define wbExportRaw_getRowCount(raw) ((raw)->rows) +#define wbExportRaw_getFile(raw) ((raw)->file) + +#define wbExportRaw_setRowCount(raw, val) \ + (wbExportRaw_getRowCount(raw) = val) +#define wbExportRaw_setColumnCount(raw, val) \ + (wbExportRaw_getColumnCount(raw) = val) + +typedef struct st_wbExportCSV_t { + int rows; + int columns; + wbFile_t file; + char seperator; +} * wbExportCSV_t; + +#define wbExportCSV_getRowCount(csv) ((csv)->rows) +#define wbExportCSV_getColumnCount(csv) ((csv)->columns) +#define wbExportCSV_getFile(csv) ((csv)->file) +#define wbExportCSV_getSeperator(csv) ((csv)->seperator) + +#define wbExportCSV_setRowCount(csv, val) \ + (wbExportCSV_getRowCount(csv) = val) +#define wbExportCSV_setColumnCount(csv, val) \ + (wbExportCSV_getColumnCount(csv) = val) +#define wbExportCSV_setSeperator(csv, val) \ + (wbExportCSV_getSeperator(csv) = val) + +typedef struct st_wbExport_t { + wbExportKind_t kind; + union { + wbExportRaw_t raw; + wbExportCSV_t csv; + wbImage_t img; + wbExportText_t text; + } container; + char *file; +} wbExport_t; + +#define wbExport_getKind(exprt) ((exprt).kind) +#define wbExport_getContainer(exprt) ((exprt).container) +#define wbExport_getRaw(exprt) (wbExport_getContainer(exprt).raw) +#define wbExport_getCSV(exprt) (wbExport_getContainer(exprt).csv) +#define wbExport_getImage(exprt) (wbExport_getContainer(exprt).img) +#define wbExport_getText(exprt) (wbExport_getContainer(exprt).text) +#define wbExport_getFile(exprt) ((exprt).file) + +#define wbExport_setKind(exprt, val) (wbExport_getKind(exprt) = val) +#define wbExport_setRaw(exprt, val) (wbExport_getRaw(exprt) = val) +#define wbExport_setCSV(exprt, val) (wbExport_getCSV(exprt) = val) +#define wbExport_setImage(exprt, val) (wbExport_getImage(exprt) = val) +#define wbExport_setText(exprt, val) (wbExport_getText(exprt) = val) +#define wbExport_setFile(exprt, val) (wbExport_getFile(exprt) = val) + +void wbExport(const char *file, int *data, int rows, int columns); +void wbExport(const char *file, int *data, int rows); +void wbExport(const char *file, unsigned char *data, int rows, + int columns); +void wbExport(const char *file, unsigned char *data, int rows); +void wbExport(const char *file, int *data, int rows, int columns); +void wbExport(const char *file, int *data, int rows); +void wbExport(const char *file, wbReal_t *data, int rows, int columns); +void wbExport(const char *file, wbReal_t *data, int rows); +void wbExport(const char *file, wbImage_t img); + +void wbExport(const char *file, wbExportKind_t kind, void *data, int rows, + int columns, wbType_t type); + +void wbExport_text(const char *file, void *data, int length); + +#endif /* __WB_EXPORT_H__ */ diff --git a/CUDA_Convolution/libwb/wbFile.cpp b/CUDA_Convolution/libwb/wbFile.cpp new file mode 100644 index 0000000..b3fdbe7 --- /dev/null +++ b/CUDA_Convolution/libwb/wbFile.cpp @@ -0,0 +1,353 @@ + + +#include "wb.h" + +#define wbFile_maxCount 256 + +static wbFile_t wbFile_handles[wbFile_maxCount]; + +static int wbFile_nextIndex(void) { + int ii; + for (ii = 0; ii < wbFile_maxCount; ii++) { + if (wbFile_handles[ii] == NULL) { + return ii; + } + } + wbLog(ERROR, "Ran out of file handles."); + wbExit(); + return -1; +} + +wbFile_t wbFile_new(void) { + int idx = wbFile_nextIndex(); + wbFile_t file = wbNew(struct st_wbFile_t); + + wbAssert(idx >= 0); + + wbFile_setIndex(file, idx); + wbFile_setFileName(file, NULL); + wbFile_setMode(file, NULL); + wbFile_setFileHandle(file, NULL); + wbFile_setData(file, NULL); + + wbFile_handles[idx] = file; + + return file; +} + +void wbFile_delete(wbFile_t file) { + if (file != NULL) { + int idx = wbFile_getIndex(file); + if (wbFile_getFileName(file) != NULL) { + wbDelete(wbFile_getFileName(file)); + } + if (wbFile_getMode(file) != NULL) { + wbDelete(wbFile_getMode(file)); + } + if (wbFile_getFileHandle(file) != NULL) { + fflush(wbFile_getFileHandle(file)); + fclose(wbFile_getFileHandle(file)); + } + if (idx >= 0) { + wbAssert(wbFile_handles[idx] == file); + wbFile_handles[idx] = NULL; + } + if (wbFile_getData(file) != NULL) { + wbDelete(wbFile_getData(file)); + } + wbDelete(file); + } +} + +void wbFile_init(void) { + int ii; + + for (ii = 0; ii < wbFile_maxCount; ii++) { + wbFile_handles[ii] = NULL; + } +} + +void wbFile_atExit(void) { + int ii; + + for (ii = 0; ii < wbFile_maxCount; ii++) { + if (wbFile_handles[ii] != NULL) { + wbFile_delete(wbFile_handles[ii]); + } + } +} + +int wbFile_count(void) { + int ii, count = 0; + + for (ii = 0; ii < wbFile_maxCount; ii++) { + if (wbFile_handles[ii] != NULL) { + count++; + } + } + return count; +} + +wbFile_t wbFile_open(const char *fileName, const char *mode) { + FILE *handle; + wbFile_t file; + + if (fileName == NULL) { + return NULL; + } + + handle = fopen(fileName, mode); + if (handle == NULL) { + wbLog(ERROR, "Failed to open ", file, " in mode ", mode); + return NULL; + } + + file = wbFile_new(); + wbFile_setFileName(file, wbString_duplicate(fileName)); + wbFile_setMode(file, wbString_duplicate(mode)); + wbFile_setFileHandle(file, handle); + + return file; +} + +wbFile_t wbFile_open(const char *fileName) { + return wbFile_open(fileName, "r"); +} + +void wbFile_close(wbFile_t file) { + wbFile_delete(file); +} + +char *wbFile_read(wbFile_t file, size_t size, size_t count) { + size_t res; + char *buffer; + size_t bufferLen; + FILE *handle; + + if (file == NULL) { + return NULL; + } +#ifndef LAZY_FILE_LOAD + if (wbFile_getData(file) != NULL) { + char *data = wbFile_getData(file) + wbFile_getDataOffset(file); + wbFile_setDataOffset(file, wbFile_getDataOffset(file) + size * count); + return data; + } +#endif /* LAZY_FILE_LOAD */ + + handle = wbFile_getFileHandle(file); + bufferLen = size * count + 1; + buffer = wbNewArray(char, bufferLen); + + res = fread(buffer, size, count, handle); + // make valid C string + buffer[size * res] = '\0'; + + return buffer; +} + +char *wbFile_read(wbFile_t file, size_t len) { + char *buffer = wbFile_read(file, sizeof(char), len); + return buffer; +} + +void wbFile_rewind(wbFile_t file) { + if (file == NULL) { + return; + } + + if (wbFile_getData(file) == NULL) { + FILE *handle; + handle = wbFile_getFileHandle(file); + wbAssert(handle != NULL); + rewind(handle); + } +#ifndef LAZY_FILE_LOAD + else { + wbFile_setDataOffset(file, 0); + } +#endif + + return; +} + +size_t wbFile_size(wbFile_t file) { + size_t len; + FILE *handle; + + if (file == NULL) { + return 0; + } +#ifndef LAZY_FILE_LOAD + if (wbFile_getData(file) != NULL) { + if (wbFile_getLength(file) == 0) { + wbFile_setLength(file, strlen(wbFile_getData(file))); + } + return wbFile_getLength(file); + } +#endif /* LAZY_FILE_LOAD */ + + handle = wbFile_getFileHandle(file); + + fseek(handle, 0, SEEK_END); + len = ftell(handle); + rewind(handle); + + return len; +} + +char *wbFile_read(wbFile_t file) { + size_t len; + + if (file == NULL) { + return NULL; + } + + len = wbFile_size(file); + + if (len == 0) { + return NULL; + } + + wbFile_setLength(file, len); + + return wbFile_read(file, len); +} + +#define MAX_CHARS_PER_LINE (1 << 17) + +static char buffer[MAX_CHARS_PER_LINE]; + +char *wbFile_readLine(wbFile_t file) { + if (file == NULL) { + return NULL; + } +#ifdef LAZY_FILE_LOAD + FILE *handle; + memset(buffer, 0, MAX_CHARS_PER_LINE); + + handle = wbFile_getFileHandle(file); + + if (fgets(buffer, MAX_CHARS_PER_LINE - 1, handle)) { + return buffer; + } else { + // wbLog(ERROR, "Was not able to read line from ", + // wbFile_getFileName(file)); + return NULL; + } +#else + size_t newOffset; + size_t lenToNewLine = 0; + const char *tmp; + + if (wbFile_getData(file) == NULL) { + wbFile_setData(file, wbFile_read(file)); + fclose(wbFile_getFileHandle(file)); + wbFile_setFileHandle(file, NULL); + wbFile_setDataOffset(file, 0); + wbFile_setLength(file, strlen(wbFile_getData(file))); + } + + memset(buffer, 0, MAX_CHARS_PER_LINE); + + if (wbFile_getDataOffset(file) >= wbFile_getLength(file)) { + return NULL; + } + + newOffset = wbFile_getDataOffset(file); + tmp = wbFile_getData(file) + wbFile_getDataOffset(file); + while (newOffset < wbFile_getLength(file) && *tmp != '\n') { + tmp++; + lenToNewLine++; + newOffset++; + } + + memcpy(buffer, wbFile_getData(file) + wbFile_getDataOffset(file), + lenToNewLine); + wbFile_setDataOffset(file, newOffset + 1); + + return buffer; +#endif +} + +void wbFile_write(wbFile_t file, const void *buffer, size_t size, + size_t count) { + size_t res; + FILE *handle; + + if (file == NULL) { + return; + } + + handle = wbFile_getFileHandle(file); + + res = fwrite(buffer, size, count, handle); + if (res != count) { + wbLog(ERROR, "Failed to write data to ", wbFile_getFileName(file)); + } + + return; +} + +void wbFile_write(wbFile_t file, const void *buffer, size_t len) { + wbFile_write(file, buffer, sizeof(char), len); + return; +} + +void wbFile_write(wbFile_t file, const char *buffer) { + size_t len; + + len = strlen(buffer); + wbFile_write(file, buffer, len); + + return; +} + +void wbFile_writeLine(wbFile_t file, const char *buffer0) { + string buffer = wbString(buffer0, "\n"); + wbFile_write(file, buffer.c_str()); +} + +void wbFile_write(wbFile_t file, string buffer) { + wbFile_write(file, buffer.c_str()); +} + +void wbFile_writeLine(wbFile_t file, string buffer0) { + string buffer = buffer0 + "\n"; + wbFile_write(file, buffer.c_str()); +} + +wbBool wbFile_existsQ(const char *path) { + if (path == NULL) { + return wbFalse; + } else { + FILE *file = fopen(path, "r"); + if (file != NULL) { + fclose(file); + return wbTrue; + } + return wbFalse; + } +} + +char *wbFile_extension(const char *file) { + char *extension; + char *extensionLower; + char *end; + size_t len; + + len = strlen(file); + end = (char *)&file[len - 1]; + while (*end != '.') { + end--; + } + if (*end == '.') { + end++; + } + + extension = wbString_duplicate(end); + extensionLower = wbString_toLower(extension); + wbDelete(extension); + + return extensionLower; +} diff --git a/CUDA_Convolution/libwb/wbFile.h b/CUDA_Convolution/libwb/wbFile.h new file mode 100644 index 0000000..ea6b0cb --- /dev/null +++ b/CUDA_Convolution/libwb/wbFile.h @@ -0,0 +1,56 @@ + + +#ifndef __WB_FILE_H__ +#define __WB_FILE_H__ + +struct st_wbFile_t { + int index; + char *file; + char *mode; + char *data; + FILE *handle; + size_t len; + size_t offset; +}; + +#define wbFile_getIndex(file) ((file)->index) +#define wbFile_getFileName(file) ((file)->file) +#define wbFile_getMode(file) ((file)->mode) +#define wbFile_getData(file) ((file)->data) +#define wbFile_getLength(file) ((file)->len) +#define wbFile_getDataOffset(file) ((file)->offset) +#define wbFile_getFileHandle(file) ((file)->handle) + +#define wbFile_setIndex(file, val) (wbFile_getIndex(file) = val) +#define wbFile_setFileName(file, val) (wbFile_getFileName(file) = val) +#define wbFile_setMode(file, val) (wbFile_getMode(file) = val) +#define wbFile_setData(file, val) (wbFile_getData(file) = val) +#define wbFile_setLength(file, val) (wbFile_getLength(file) = val) +#define wbFile_setDataOffset(file, val) (wbFile_getDataOffset(file) = val) +#define wbFile_setFileHandle(file, val) (wbFile_getFileHandle(file) = val) + +wbFile_t wbFile_new(void); +void wbFile_delete(wbFile_t file); +void wbFile_close(wbFile_t file); +void wbFile_init(void); +void wbFile_atExit(void); +int wbFile_count(void); +wbFile_t wbFile_open(const char *fileName, const char *mode); +wbFile_t wbFile_open(const char *fileName); +char *wbFile_read(wbFile_t file, size_t size, size_t count); +char *wbFile_read(wbFile_t file, size_t len); +void wbFile_rewind(wbFile_t file); +size_t wbFile_size(wbFile_t file); +char *wbFile_read(wbFile_t file); +char *wbFile_readLine(wbFile_t file); +void wbFile_write(wbFile_t file, const void *buffer, size_t size, + size_t count); +void wbFile_write(wbFile_t file, const void *buffer, size_t len); +void wbFile_write(wbFile_t file, const char *buffer); +void wbFile_writeLine(wbFile_t file, const char *buffer0); +void wbFile_write(wbFile_t file, string buffer); +void wbFile_writeLine(wbFile_t file, string buffer0); +wbBool wbFile_existsQ(const char *path); +char *wbFile_extension(const char *file); + +#endif /* __WB_FILE_H__ */ diff --git a/CUDA_Convolution/libwb/wbImage.cpp b/CUDA_Convolution/libwb/wbImage.cpp new file mode 100644 index 0000000..1d95928 --- /dev/null +++ b/CUDA_Convolution/libwb/wbImage.cpp @@ -0,0 +1,134 @@ + + +#include "wb.h" + +static inline float _min(float x, float y) { + return x < y ? x : y; +} + +static inline float _max(float x, float y) { + return x > y ? x : y; +} + +static inline float _clamp(float x, float start, float end) { + return _min(_max(x, start), end); +} + +wbImage_t wbImage_new(int width, int height, int channels, float *data) { + wbImage_t img; + + img = wbNew(struct st_wbImage_t); + + wbImage_setWidth(img, width); + wbImage_setHeight(img, height); + wbImage_setChannels(img, channels); + wbImage_setPitch(img, width * channels); + + wbImage_setData(img, data); + return img; +} + +wbImage_t wbImage_new(int width, int height, int channels) { + float *data = wbNewArray(float, width *height *channels); + return wbImage_new(width, height, channels, data); +} + +wbImage_t wbImage_new(int width, int height) { + return wbImage_new(width, height, wbImage_channels); +} + +void wbImage_delete(wbImage_t img) { + if (img != NULL) { + if (wbImage_getData(img) != NULL) { + wbDelete(wbImage_getData(img)); + } + wbDelete(img); + } +} + +static inline void wbImage_setPixel(wbImage_t img, int x, int y, int c, + float val) { + float *data = wbImage_getData(img); + int channels = wbImage_getChannels(img); + int pitch = wbImage_getPitch(img); + + data[y * pitch + x * channels + c] = val; + + return; +} + +static inline float wbImage_getPixel(wbImage_t img, int x, int y, int c) { + float *data = wbImage_getData(img); + int channels = wbImage_getChannels(img); + int pitch = wbImage_getPitch(img); + + return data[y * pitch + x * channels + c]; +} + +wbBool wbImage_sameQ(wbImage_t a, wbImage_t b, + wbImage_onSameFunction_t onUnSame) { + if (a == NULL || b == NULL) { + wbLog(ERROR, "Comparing null images."); + return wbFalse; + } else if (a == b) { + return wbTrue; + } else if (wbImage_getWidth(a) != wbImage_getWidth(b)) { + wbLog(ERROR, "Image widths do not match."); + return wbFalse; + } else if (wbImage_getHeight(a) != wbImage_getHeight(b)) { + wbLog(ERROR, "Image heights do not match."); + return wbFalse; + } else if (wbImage_getChannels(a) != wbImage_getChannels(b)) { + wbLog(ERROR, "Image channels do not match."); + return wbFalse; + } else { + float *aData, *bData; + int width, height, channels; + int ii, jj, kk; + + aData = wbImage_getData(a); + bData = wbImage_getData(b); + + wbAssert(aData != NULL); + wbAssert(bData != NULL); + + width = wbImage_getWidth(a); + height = wbImage_getHeight(a); + channels = wbImage_getChannels(a); + + for (ii = 0; ii < height; ii++) { + for (jj = 0; jj < width; jj++) { + for (kk = 0; kk < channels; kk++) { + float x, y; + if (channels <= 3) { + x = _clamp(*aData++, 0, 1); + y = _clamp(*bData++, 0, 1); + } else { + x = *aData++; + y = *bData++; + } + if (wbUnequalQ(x, y)) { + if (onUnSame != NULL) { + string str = wbString( + "Image pixels do not match at position ( row = ", + wbString(ii, ", col = ", jj, ", channel = ", kk, + ") expecting a value of "), + wbString(y, " but got a computed value of ", x)); + onUnSame(str); + } + return wbFalse; + } + } + } + } + return wbTrue; + } +} + +static void wbImage_onUnsameFunction(string str) { + wbLog(ERROR, str); +} + +wbBool wbImage_sameQ(wbImage_t a, wbImage_t b) { + return wbImage_sameQ(a, b, wbImage_onUnsameFunction); +} diff --git a/CUDA_Convolution/libwb/wbImage.h b/CUDA_Convolution/libwb/wbImage.h new file mode 100644 index 0000000..020eec5 --- /dev/null +++ b/CUDA_Convolution/libwb/wbImage.h @@ -0,0 +1,40 @@ + + +#ifndef __IMAGE_H__ +#define __IMAGE_H__ + +#include "wbTypes.h" + +struct st_wbImage_t { + int width; + int height; + int channels; + int pitch; + float *data; +}; + +#define wbImage_channels 3 + +#define wbImage_getWidth(img) ((img)->width) +#define wbImage_getHeight(img) ((img)->height) +#define wbImage_getChannels(img) ((img)->channels) +#define wbImage_getPitch(img) ((img)->pitch) +#define wbImage_getData(img) ((img)->data) + +#define wbImage_setWidth(img, val) (wbImage_getWidth(img) = val) +#define wbImage_setHeight(img, val) (wbImage_getHeight(img) = val) +#define wbImage_setChannels(img, val) (wbImage_getChannels(img) = val) +#define wbImage_setPitch(img, val) (wbImage_getPitch(img) = val) +#define wbImage_setData(img, val) (wbImage_getData(img) = val) + +typedef void (*wbImage_onSameFunction_t)(string str); + +wbImage_t wbImage_new(int width, int height, int channels, float *data); +wbImage_t wbImage_new(int width, int height, int channels); +wbImage_t wbImage_new(int width, int height); +void wbImage_delete(wbImage_t img); +wbBool wbImage_sameQ(wbImage_t a, wbImage_t b, + wbImage_onSameFunction_t onUnSame); +wbBool wbImage_sameQ(wbImage_t a, wbImage_t b); + +#endif /* __IMAGE_H__ */ diff --git a/CUDA_Convolution/libwb/wbImport.cpp b/CUDA_Convolution/libwb/wbImport.cpp new file mode 100644 index 0000000..fccc071 --- /dev/null +++ b/CUDA_Convolution/libwb/wbImport.cpp @@ -0,0 +1,711 @@ + + +#include "wb.h" + +static inline void wbImportCSV_setFile(wbImportCSV_t csv, + const char *path) { + if (csv != NULL) { + if (wbImportCSV_getFile(csv) != NULL) { + wbFile_delete(wbImportCSV_getFile(csv)); + } + if (path != NULL) { + wbImportCSV_getFile(csv) = wbFile_open(path, "r"); + } else { + wbImportCSV_getFile(csv) = NULL; + } + } + + return; +} + +static inline wbImportCSV_t wbImportCSV_new(void) { + wbImportCSV_t csv; + + csv = wbNew(struct st_wbImportCSV_t); + + wbImportCSV_setRowCount(csv, -1); + wbImportCSV_setColumnCount(csv, -1); + wbImportCSV_setData(csv, NULL); + wbImportCSV_getFile(csv) = NULL; + wbImportCSV_setSeperator(csv, '\0'); + + return csv; +} + +static inline void wbImportCSV_delete(wbImportCSV_t csv) { + if (csv != NULL) { + wbImportCSV_setFile(csv, NULL); + if (wbImportCSV_getData(csv)) { + wbDelete(wbImportCSV_getData(csv)); + } + wbDelete(csv); + } +} + +static inline wbImportCSV_t wbImportCSV_findDimensions(wbImportCSV_t csv, + int *resRows, + int *resColumns) { + int rows = 0, columns = -1; + char *line; + wbFile_t file; + char seperator[2]; + + if (csv == NULL) { + return NULL; + } + + if (wbImportCSV_getSeperator(csv) == '\0') { + seperator[0] = ','; + } else { + seperator[0] = wbImportCSV_getSeperator(csv); + } + seperator[1] = '\0'; + + file = wbImportCSV_getFile(csv); + + while ((line = wbFile_readLine(file)) != NULL) { + int currColumn = 0; + char *token = strtok(line, seperator); + while (token != NULL) { + token = strtok(NULL, seperator); + currColumn++; + } + rows++; + if (columns == -1) { + columns = currColumn; + } + if (columns != currColumn) { + wbLog(ERROR, "The csv file is not rectangular."); + } + wbAssert(columns == currColumn); + } + + wbFile_rewind(file); + + *resRows = rows; + *resColumns = columns; + + return csv; +} + +static inline int *csv_readAsInteger(wbFile_t file, char sep, int rows, + int columns) { + int ii = 0; + int *data; + char *line; + int var; + char seperator[2]; + + if (file == NULL) { + return NULL; + } + + data = wbNewArray(int, rows *columns); + + if (sep == '\0') { + seperator[0] = ','; + } else { + seperator[0] = sep; + } + seperator[1] = '\0'; + + // printf("cols = %d rows = %d\n", columns, rows); + if (columns == 1) { + while ((line = wbFile_readLine(file)) != NULL) { + sscanf(line, "%d", &var); + // printf("reading %d\n", var); + data[ii++] = var; + } + } else { + while ((line = wbFile_readLine(file)) != NULL) { + char *token = strtok(line, seperator); + while (token != NULL) { + sscanf(token, "%d", &var); + token = strtok(NULL, seperator); + data[ii++] = var; + } + } + } + + return data; +} + +static inline wbReal_t *csv_readAsReal(wbFile_t file, char sep, int rows, + int columns) { + int ii = 0; + wbReal_t *data; + char *line; + wbReal_t var; + char seperator[2]; + + if (file == NULL) { + return NULL; + } + + data = wbNewArray(wbReal_t, rows * columns); + + if (sep == '\0') { + seperator[0] = ','; + } else { + seperator[0] = sep; + } + seperator[1] = '\0'; + + if (columns == 1) { + while ((line = wbFile_readLine(file)) != NULL) { + sscanf(line, "%f", &var); + data[ii++] = var; + } + } else { + while ((line = wbFile_readLine(file)) != NULL) { + char *token = strtok(line, seperator); + while (token != NULL) { + sscanf(token, "%f", &var); + token = strtok(NULL, seperator); + data[ii++] = var; + } + } + } + + return data; +} + +static inline wbImportCSV_t wbImportCSV_read(wbImportCSV_t csv, + wbType_t type) { + void *data; + wbFile_t file; + char seperator; + int rows, columns; + + if (csv == NULL) { + return NULL; + } + + if (wbImportCSV_getRowCount(csv) == -1 || + wbImportCSV_getColumnCount(csv) == -1) { + if (wbImportCSV_findDimensions(csv, &rows, &columns) == NULL) { + wbLog(ERROR, "Failed to figure out csv dimensions."); + return NULL; + } + wbImportCSV_setRowCount(csv, rows); + wbImportCSV_setColumnCount(csv, columns); + } + + file = wbImportCSV_getFile(csv); + seperator = wbImportCSV_getSeperator(csv); + rows = wbImportCSV_getRowCount(csv); + columns = wbImportCSV_getColumnCount(csv); + + if (wbImportCSV_getData(csv) != NULL) { + wbDelete(wbImportCSV_getData(csv)); + wbImportCSV_setData(csv, NULL); + } + + if (type == wbType_integer) { + // printf("ReadXXXing as integer...\n"); + data = csv_readAsInteger(file, seperator, rows, columns); + } else { + data = csv_readAsReal(file, seperator, rows, columns); + } + + wbImportCSV_setData(csv, data); + + return csv; +} + +static inline wbImportCSV_t wbImportCSV_readAsInteger(wbImportCSV_t csv) { + return wbImportCSV_read(csv, wbType_integer); +} + +static inline wbImportCSV_t wbImportCSV_readAsReal(wbImportCSV_t csv) { + return wbImportCSV_read(csv, wbType_real); +} + +static inline void wbImportRaw_setFile(wbImportRaw_t raw, + const char *path) { + if (raw != NULL) { + if (wbImportRaw_getFile(raw) != NULL) { + wbFile_delete(wbImportRaw_getFile(raw)); + } + if (path != NULL) { + wbImportRaw_getFile(raw) = wbFile_open(path, "r"); + } else { + wbImportRaw_getFile(raw) = NULL; + } + } + + return; +} + +static inline wbImportRaw_t wbImportRaw_new(void) { + wbImportRaw_t raw; + + raw = wbNew(struct st_wbImportRaw_t); + + wbImportRaw_setRowCount(raw, -1); + wbImportRaw_setColumnCount(raw, -1); + wbImportRaw_setData(raw, NULL); + wbImportRaw_getFile(raw) = NULL; + + return raw; +} + +static inline void wbImportRaw_delete(wbImportRaw_t raw) { + if (raw != NULL) { + wbImportRaw_setFile(raw, NULL); + if (wbImportRaw_getData(raw)) { + wbDelete(wbImportRaw_getData(raw)); + } + wbDelete(raw); + } +} + +static inline wbBool lineHasSpace(const char *line) { + while (*line != '\0') { + if (*line == ' ') { + return wbTrue; + } + line++; + } + return wbFalse; +} + +static inline char *lineStrip(const char *line) { + char *sl = wbString_duplicate(line); + char *iter = sl; + size_t slen = strlen(line); + + iter += slen - 1; + while (*iter == '\0' || *iter == '\r' || *iter == '\t' || + *iter == '\n' || *iter == ' ') { + *iter-- = '\0'; + } + return sl; +} + +static inline wbBool wbImportRaw_findDimensions(wbImportRaw_t raw) { + if (raw != NULL) { + int rows; + int columns; + char *line; + wbFile_t file; + char *strippedLine; + + file = wbImportRaw_getFile(raw); + + wbFile_rewind(file); + + line = wbFile_readLine(file); + + if (line == NULL) { + return wbTrue; + } + + strippedLine = lineStrip(line); + + if (lineHasSpace(strippedLine)) { + sscanf(strippedLine, "%d %d", &rows, &columns); + } else { + columns = 1; + sscanf(strippedLine, "%d", &rows); + } + + wbImportRaw_setRowCount(raw, rows); + wbImportRaw_setColumnCount(raw, columns); + + wbDelete(strippedLine); + + return wbFalse; + } + + return wbTrue; +} + +static inline wbImportRaw_t wbImportRaw_read(wbImportRaw_t raw, + wbType_t type) { + void *data; + wbFile_t file; + char seperator; + int rows, columns; + + if (raw == NULL) { + return NULL; + } + + if (wbImportRaw_getRowCount(raw) == -1 || + wbImportRaw_getColumnCount(raw) == -1) { + if (wbImportRaw_findDimensions(raw)) { + wbLog(ERROR, "Failed to figure out raw dimensions."); + return NULL; + } + } + + file = wbImportRaw_getFile(raw); + seperator = ' '; + rows = wbImportRaw_getRowCount(raw); + columns = wbImportRaw_getColumnCount(raw); + + if (wbImportRaw_getData(raw) != NULL) { + wbDelete(wbImportRaw_getData(raw)); + wbImportRaw_setData(raw, NULL); + } + + if (type == wbType_integer) { + // printf("Rdin gas integer...\n"); + data = csv_readAsInteger(file, seperator, rows, columns); + } else { + data = csv_readAsReal(file, seperator, rows, columns); + } + + wbImportRaw_setData(raw, data); + + return raw; +} + +static inline wbImportRaw_t wbImportRaw_readAsInteger(wbImportRaw_t raw) { + return wbImportRaw_read(raw, wbType_integer); +} + +static inline wbImportRaw_t wbImportRaw_readAsReal(wbImportRaw_t raw) { + return wbImportRaw_read(raw, wbType_real); +} + +static inline wbImportText_t wbImportText_new(void) { + wbImportText_t text; + + text = wbNew(struct st_wbImportText_t); + + wbImportText_setLength(text, 0); + wbImportText_setData(text, NULL); + wbImportText_getFile(text) = NULL; + + return text; +} + +static inline void wbImportText_setFile(wbImportText_t text, + const char *path) { + if (text != NULL) { + if (wbImportText_getFile(text) != NULL) { + wbFile_delete(wbImportText_getFile(text)); + } + if (path != NULL) { + wbImportText_getFile(text) = wbFile_open(path, "r"); + } else { + wbImportText_getFile(text) = NULL; + } + } + + return; +} + +static inline void wbImportText_delete(wbImportText_t text) { + if (text != NULL) { + wbImportText_setFile(text, NULL); + if (wbImportText_getData(text)) { + wbDelete(wbImportText_getData(text)); + } + wbDelete(text); + } +} + +static inline wbImportText_t wbImportText_read(wbImportText_t text) { + char *data; + wbFile_t file; + int length; + + if (text == NULL) { + return NULL; + } + + file = wbImportText_getFile(text); + + if (wbImportText_getData(text) != NULL) { + wbDelete(wbImportText_getData(text)); + wbImportText_setData(text, NULL); + } + + length = wbFile_size(file); + data = wbFile_read(file, length); + + wbImportText_setData(text, data); + wbImportText_setLength(text, length); + + return text; +} + +static inline wbImport_t wbImport_open(const char *file, + wbImportKind_t kind) { + wbImport_t imp; + + if (file == NULL) { + wbLog(ERROR, "Go NULL for file value."); + wbExit(); + } + + if (!wbFile_existsQ(file)) { + wbLog(ERROR, "File ", file, " does not exist."); + wbExit(); + } + + wbImport_setKind(imp, kind); + + if (kind == wbImportKind_raw) { + wbImportRaw_t raw = wbImportRaw_new(); + wbImportRaw_setFile(raw, file); + wbImport_setRaw(imp, raw); + } else if (kind == wbImportKind_tsv || kind == wbImportKind_csv) { + wbImportCSV_t csv = wbImportCSV_new(); + if (kind == wbImportKind_csv) { + wbImportCSV_setSeperator(csv, ','); + } else { + wbImportCSV_setSeperator(csv, '\t'); + } + wbImportCSV_setFile(csv, file); + wbImport_setCSV(imp, csv); + } else if (kind == wbImportKind_text) { + wbImportText_t text = wbImportText_new(); + wbImportText_setFile(text, file); + wbImport_setText(imp, text); + } else if (kind == wbImportKind_ppm) { + wbImage_t img = wbPPM_import(file); + wbImport_setImage(imp, img); + } else { + wbLog(ERROR, "Invalid import type."); + wbExit(); + } + + return imp; +} + +static inline wbImport_t wbImport_open(const char *file, + const char *type0) { + wbImport_t imp; + wbImportKind_t kind; + char *type; + + type = wbString_toLower(type0); + + if (wbString_sameQ(type, "csv")) { + kind = wbImportKind_csv; + } else if (wbString_sameQ(type, "tsv")) { + kind = wbImportKind_tsv; + } else if (wbString_sameQ(type, "raw") || wbString_sameQ(type, "dat")) { + kind = wbImportKind_raw; + } else if (wbString_sameQ(type, "ppm")) { + kind = wbImportKind_ppm; + } else if (wbString_sameQ(type, "text") || wbString_sameQ(type, "txt")) { + kind = wbImportKind_text; + } else { + wbLog(ERROR, "Invalid import type ", type0); + wbExit(); + } + + imp = wbImport_open(file, kind); + + wbDelete(type); + + return imp; +} + +static inline void wbImport_close(wbImport_t imp) { + wbImportKind_t kind; + + kind = wbImport_getKind(imp); + if (kind == wbImportKind_tsv || kind == wbImportKind_csv) { + wbImportCSV_t csv = wbImport_getCSV(imp); + wbImportCSV_delete(csv); + wbImport_setCSV(imp, NULL); + } else if (kind == wbImportKind_raw) { + wbImportRaw_t raw = wbImport_getRaw(imp); + wbImportRaw_delete(raw); + wbImport_setRaw(imp, NULL); + } else if (kind == wbImportKind_text) { + wbImportText_t text = wbImport_getText(imp); + wbImportText_delete(text); + wbImport_setText(imp, NULL); + } else if (kind == wbImportKind_ppm) { + } else { + wbLog(ERROR, "Invalid import type."); + wbExit(); + } + return; +} + +static inline void *wbImport_read(wbImport_t imp, wbType_t type) { + void *data = NULL; + wbImportKind_t kind; + + kind = wbImport_getKind(imp); + if (kind == wbImportKind_tsv || kind == wbImportKind_csv) { + wbImportCSV_t csv = wbImport_getCSV(imp); + wbImportCSV_read(csv, type); + data = wbImportCSV_getData(csv); + } else if (kind == wbImportKind_raw) { + wbImportRaw_t raw = wbImport_getRaw(imp); + wbImportRaw_read(raw, type); + data = wbImportRaw_getData(raw); + } else if (wbImportKind_text == kind) { + wbImportText_t text = wbImport_getText(imp); + text = wbImportText_read(text); + data = wbImportText_getData(text); + + } else { + wbLog(ERROR, "Invalid import type."); + wbExit(); + } + return data; +} + +static inline int *wbImport_readAsInteger(wbImport_t imp) { + void *data = wbImport_read(imp, wbType_integer); + return (int *)data; +} + +static inline wbReal_t *wbImport_readAsReal(wbImport_t imp) { + void *data = wbImport_read(imp, wbType_real); + return (wbReal_t *)data; +} + +static inline wbChar_t *wbImport_readAsText(wbImport_t imp) { + void *data = wbImport_read(imp, wbType_ubit8); + return (wbChar_t *)data; +} + +static wbImportKind_t _parseImportExtension(const char *file) { + char *extension; + wbImportKind_t kind; + + extension = wbFile_extension(file); + + if (wbString_sameQ(extension, "csv")) { + kind = wbImportKind_csv; + } else if (wbString_sameQ(extension, "tsv")) { + kind = wbImportKind_tsv; + } else if (wbString_sameQ(extension, "raw") || + wbString_sameQ(extension, "dat")) { + kind = wbImportKind_raw; + } else if (wbString_sameQ(extension, "ppm") || + wbString_sameQ(extension, "pbm")) { + kind = wbImportKind_ppm; + } else if (wbString_sameQ(extension, "text") || + wbString_sameQ(extension, "txt")) { + kind = wbImportKind_text; + } else { + kind = wbImportKind_unknown; + wbLog(ERROR, "File ", file, " does not have a compatible extension."); + } + + wbDelete(extension); + + return kind; +} + +void *wbImport(const char *file, int *resRows, int *resColumns, + const char *type) { + void *data, *res; + wbImport_t imp; + size_t sz; + int columns = 0, rows = 0; + wbImportKind_t kind; + + if (file == NULL) { + fprintf(stderr, "Failed to import file.\n"); + wbExit(); + } + + kind = _parseImportExtension(file); + + wbAssert(kind != wbImportKind_unknown); + + imp = wbImport_open(file, kind); + if (wbString_sameQ(type, "Real")) { + data = wbImport_readAsReal(imp); + sz = sizeof(wbReal_t); + } else if (wbString_sameQ(type, "Text")) { + data = wbImport_readAsText(imp); + sz = sizeof(char); + } else { + // printf("Reading as integer..d\n"); + data = wbImport_readAsInteger(imp); + sz = sizeof(int); + } + + if (kind == wbImportKind_csv || kind == wbImportKind_tsv) { + rows = wbImportCSV_getRowCount(wbImport_getCSV(imp)); + columns = wbImportCSV_getColumnCount(wbImport_getCSV(imp)); + } else if (kind == wbImportKind_raw) { + rows = wbImportRaw_getRowCount(wbImport_getRaw(imp)); + columns = wbImportRaw_getColumnCount(wbImport_getRaw(imp)); + } else if (kind == wbImportKind_text) { + rows = 1; + columns = wbImportText_getLength(wbImport_getText(imp)); + } + + if (rows == 1 && columns > 0) { + rows = columns; + columns = 1; + } + + if (resRows != NULL) { + *resRows = rows; + } + + if (resColumns != NULL) { + *resColumns = columns; + } + + res = wbMalloc(sz * rows * columns); + memcpy(res, data, sz * rows * columns); + + wbImport_close(imp); + + return res; +} + +void *wbImport(const char *file, int *rows, int *columns) { + return wbImport(file, rows, columns, "Real"); +} + +EXTERN_C void *wbImport(const char *file, int *rows) { + return wbImport(file, rows, NULL, "Real"); +} + +void *wbImport(const char *file, int *res_rows, const char *type) { + int cols, rows; + void *res = wbImport(file, &rows, &cols, type); + if (rows == 1 && cols > 1) { + rows = cols; + } + *res_rows = rows; + return res; +} + +wbImage_t wbImport(const char *file) { + wbImage_t img; + wbImport_t imp; + wbImportKind_t kind; + + if (file == NULL) { + fprintf(stderr, "Failed to import file.\n"); + wbExit(); + } + + kind = _parseImportExtension(file); + + wbAssert(kind == wbImportKind_ppm); + + imp = wbImport_open(file, kind); + img = wbImport_getImage(imp); + wbImport_close(imp); + + return img; +} + +int wbImport_flag(const char *file) { + int res; + wbFile_t fh = wbFile_open(file, "r"); + const char *line = wbFile_readLine(fh); + sscanf(line, "%d", &res); + wbFile_close(fh); + return res; +} diff --git a/CUDA_Convolution/libwb/wbImport.h b/CUDA_Convolution/libwb/wbImport.h new file mode 100644 index 0000000..ce13e1b --- /dev/null +++ b/CUDA_Convolution/libwb/wbImport.h @@ -0,0 +1,103 @@ + +#ifndef __WB_IMPORT_H__ +#define __WB_IMPORT_H__ + +#include "wbImage.h" + +typedef enum en_wbImportKind_t { + wbImportKind_unknown = -1, + wbImportKind_raw = 0x1000, + wbImportKind_csv, + wbImportKind_tsv, + wbImportKind_ppm, + wbImportKind_text +} wbImportKind_t; + +#define wbType_real wbType_float + +typedef struct st_wbImportCSV_t { + int rows; + int columns; + void *data; + wbFile_t file; + char seperator; +} * wbImportCSV_t; + +#define wbImportCSV_getRowCount(csv) ((csv)->rows) +#define wbImportCSV_getColumnCount(csv) ((csv)->columns) +#define wbImportCSV_getData(csv) ((csv)->data) +#define wbImportCSV_getFile(csv) ((csv)->file) +#define wbImportCSV_getSeperator(csv) ((csv)->seperator) + +#define wbImportCSV_setRowCount(csv, val) \ + (wbImportCSV_getRowCount(csv) = val) +#define wbImportCSV_setColumnCount(csv, val) \ + (wbImportCSV_getColumnCount(csv) = val) +#define wbImportCSV_setData(csv, val) (wbImportCSV_getData(csv) = val) +#define wbImportCSV_setSeperator(csv, val) \ + (wbImportCSV_getSeperator(csv) = val) + +typedef struct st_wbImportRaw_t { + int rows; + int columns; + void *data; + wbFile_t file; +} * wbImportRaw_t; + +#define wbImportRaw_getRowCount(raw) ((raw)->rows) +#define wbImportRaw_getColumnCount(raw) ((raw)->columns) +#define wbImportRaw_getData(raw) ((raw)->data) +#define wbImportRaw_getFile(raw) ((raw)->file) + +#define wbImportRaw_setRowCount(raw, val) \ + (wbImportRaw_getRowCount(raw) = val) +#define wbImportRaw_setColumnCount(raw, val) \ + (wbImportRaw_getColumnCount(raw) = val) +#define wbImportRaw_setData(raw, val) (wbImportRaw_getData(raw) = val) + +typedef struct st_wbImportText_t { + int length; + char *data; + wbFile_t file; +} * wbImportText_t; + +#define wbImportText_getLength(txt) ((txt)->length) +#define wbImportText_getData(txt) ((txt)->data) +#define wbImportText_getFile(txt) ((txt)->file) + +#define wbImportText_setLength(txt, val) \ + (wbImportText_getLength(txt) = val) +#define wbImportText_setData(txt, val) (wbImportText_getData(txt) = val) + +typedef struct st_wbImport_t { + wbImportKind_t kind; + union { + wbImportRaw_t raw; + wbImportCSV_t csv; + wbImportText_t text; + wbImage_t img; + } container; +} wbImport_t; + +#define wbImport_getKind(imp) ((imp).kind) +#define wbImport_getContainer(imp) ((imp).container) +#define wbImport_getRaw(imp) (wbImport_getContainer(imp).raw) +#define wbImport_getCSV(imp) (wbImport_getContainer(imp).csv) +#define wbImport_getText(imp) (wbImport_getContainer(imp).text) +#define wbImport_getImage(imp) (wbImport_getContainer(imp).img) + +#define wbImport_setKind(imp, val) (wbImport_getKind(imp) = val) +#define wbImport_setRaw(imp, val) (wbImport_getRaw(imp) = val) +#define wbImport_setCSV(imp, val) (wbImport_getCSV(imp) = val) +#define wbImport_setText(imp, val) (wbImport_getText(imp) = val) +#define wbImport_setImage(imp, val) (wbImport_getImage(imp) = val) + +EXTERN_C void *wbImport(const char *file, int *rows); +void *wbImport(const char *file, int *rows, int *columns); +void *wbImport(const char *file, int *rows, const char *type); +void *wbImport(const char *file, int *resRows, int *resColumns, + const char *type); +wbImage_t wbImport(const char *file); +int wbImport_flag(const char *file); + +#endif /* __WB_IMPORT_H__ */ diff --git a/CUDA_Convolution/libwb/wbInit.cpp b/CUDA_Convolution/libwb/wbInit.cpp new file mode 100644 index 0000000..96ebcf3 --- /dev/null +++ b/CUDA_Convolution/libwb/wbInit.cpp @@ -0,0 +1,85 @@ + +#include "wb.h" + +#define MB (1 << 20) +#ifndef WB_DEFAULT_HEAP_SIZE +#define WB_DEFAULT_HEAP_SIZE (1024 * MB) +#endif /* WB_DEFAULT_HEAP_SIZE */ + +static bool _initializedQ = wbFalse; + +#ifndef WB_USE_WINDOWS +__attribute__((__constructor__)) +#endif /* WB_USE_WINDOWS */ +void wb_init(int * +#ifdef WB_USE_MPI + argc +#endif /* WB_USE_MPI */ + , + char *** +#ifdef WB_USE_MPI + argv +#endif /* WB_USE_MPI */ + ) { + if (_initializedQ == wbTrue) { + return; + } +#ifdef WB_USE_MPI + wbMPI_Init(argc, argv); +#endif /* WB_USE_MPI */ + +#ifdef WB_USE_CUDA + CUresult err = cuInit(0); + +/* Select a random GPU */ + +#ifdef WB_USE_MPI + if (rankCount() > 1) { + int deviceCount; + cudaGetDeviceCount(&deviceCount); + srand(time(NULL)); + cudaSetDevice(wbMPI_getRank() % deviceCount); + } else { + int deviceCount; + cudaGetDeviceCount(&deviceCount); + + srand(time(NULL)); + cudaSetDevice(rand() % deviceCount); + } +#else + { + int deviceCount; + cudaGetDeviceCount(&deviceCount); + + srand(time(NULL)); + cudaSetDevice(rand() % deviceCount); + } +#endif /* WB_USE_MPI */ + + cudaDeviceSetLimit(cudaLimitPrintfFifoSize, 1 * MB); + cudaDeviceSetLimit(cudaLimitMallocHeapSize, WB_DEFAULT_HEAP_SIZE); + + cudaDeviceSynchronize(); + +#endif /* WB_USE_CUDA */ + +#ifdef WB_USE_WINDOWS + QueryPerformanceFrequency((LARGE_INTEGER *)&_hrtime_frequency); +#endif /* _MSC_VER */ + + _hrtime(); + + _timer = wbTimer_new(); + _logger = wbLogger_new(); + _initializedQ = wbTrue; + + wbFile_init(); + + solutionJSON = NULL; + +#ifdef WB_USE_MPI + atexit(wbMPI_Exit); +#else /* WB_USE_MPI */ + atexit(wb_atExit); +#endif /* WB_USE_MPI */ +} diff --git a/CUDA_Convolution/libwb/wbInit.h b/CUDA_Convolution/libwb/wbInit.h new file mode 100644 index 0000000..40e8e1c --- /dev/null +++ b/CUDA_Convolution/libwb/wbInit.h @@ -0,0 +1,11 @@ + + +#ifndef __WB_INIT_H__ +#define __WB_INIT_H__ + +#ifndef _MSC_VER +__attribute__((__constructor__)) +#endif /* _MSC_VER */ +void wb_init(int *argc, char ***argv); + +#endif /* __WB_INIT_H__ */ diff --git a/CUDA_Convolution/libwb/wbLogger.cpp b/CUDA_Convolution/libwb/wbLogger.cpp new file mode 100644 index 0000000..c2e2e17 --- /dev/null +++ b/CUDA_Convolution/libwb/wbLogger.cpp @@ -0,0 +1,310 @@ + +#include "wb.h" + +wbLogger_t _logger = NULL; + +static inline wbBool wbLogEntry_hasNext(wbLogEntry_t elem) { + return wbLogEntry_getNext(elem) != NULL; +} + +static inline wbLogEntry_t wbLogEntry_new() { + wbLogEntry_t elem; + + elem = wbNew(struct st_wbLogEntry_t); + + wbLogEntry_setMessage(elem, NULL); + wbLogEntry_setMPIRank(elem, wbMPI_getRank()); + wbLogEntry_setTime(elem, _hrtime()); + + wbLogEntry_setLevel(elem, wbLogLevel_TRACE); + + wbLogEntry_setNext(elem, NULL); + + wbLogEntry_setLine(elem, -1); + wbLogEntry_setFile(elem, NULL); + wbLogEntry_setFunction(elem, NULL); + + return elem; +} + +static inline wbLogEntry_t +wbLogEntry_initialize(wbLogLevel_t level, string msg, const char *file, + const char *fun, int line) { + wbLogEntry_t elem; + + elem = wbLogEntry_new(); + + wbLogEntry_setLevel(elem, level); + + wbLogEntry_setMessage(elem, wbString_duplicate(msg)); + + wbLogEntry_setLine(elem, line); + wbLogEntry_setFile(elem, file); + wbLogEntry_setFunction(elem, fun); + + return elem; +} + +static inline void wbLogEntry_delete(wbLogEntry_t elem) { + if (elem != NULL) { + if (wbLogEntry_getMessage(elem) != NULL) { + wbFree(wbLogEntry_getMessage(elem)); + } + wbDelete(elem); + } + return; +} + +static inline const char *getLevelName(wbLogLevel_t level) { + switch (level) { + case wbLogLevel_unknown: + return "Unknown"; + case wbLogLevel_OFF: + return "Off"; + case wbLogLevel_FATAL: + return "Fatal"; + case wbLogLevel_ERROR: + return "Error"; + case wbLogLevel_WARN: + return "Warn"; + case wbLogLevel_INFO: + return "Info"; + case wbLogLevel_DEBUG: + return "Debug"; + case wbLogLevel_TRACE: + return "Trace"; + } + return NULL; +} + +static inline json11::Json wbLogEntry_toJSONObject(wbLogEntry_t elem) { + json11::Json json = json11::Json::object{ + {"mpi_rank", wbLogEntry_getMPIRank(elem)}, + {"level", getLevelName(wbLogEntry_getLevel(elem))}, + {"file", wbLogEntry_getFile(elem)}, + {"function", wbLogEntry_getFunction(elem)}, + {"line", wbLogEntry_getLine(elem)}, + {"time", wbLogEntry_getTime(elem)}, + {"message", wbLogEntry_getMessage(elem)}, + }; + return json; +} + +static inline string wbLogEntry_toJSON(wbLogEntry_t elem) { + if (elem == NULL) { + return ""; + } else if (WB_USE_JSON11) { + json11::Json json = wbLogEntry_toJSONObject(elem); + return json.string_value(); + } else { + stringstream ss; + + ss << "{\n"; + ss << wbString_quote("mpi_rank") << ":" + << wbString(wbLogEntry_getMPIRank(elem)) << ",\n"; + ss << wbString_quote("level") << ":" + << wbString_quote(getLevelName(wbLogEntry_getLevel(elem))) << ",\n"; + ss << wbString_quote("message") << ":" + << wbString_quote(wbLogEntry_getMessage(elem)) << ",\n"; + ss << wbString_quote("file") << ":" + << wbString_quote(wbLogEntry_getFile(elem)) << ",\n"; + ss << wbString_quote("function") << ":" + << wbString_quote(wbLogEntry_getFunction(elem)) << ",\n"; + ss << wbString_quote("line") << ":" << wbLogEntry_getLine(elem) + << ",\n"; + ss << wbString_quote("time") << ":" << wbLogEntry_getTime(elem) + << "\n"; + ss << "}"; + + return ss.str(); + } + return ""; +} + +static inline string wbLogEntry_toXML(wbLogEntry_t elem) { + if (elem != NULL) { + stringstream ss; + + ss << "\n"; + ss << "" + << "LoggerElement" + << "\n"; + ss << "" << wbLogEntry_getLevel(elem) << "\n"; + ss << "" << wbLogEntry_getMessage(elem) << "\n"; + ss << "" << wbLogEntry_getFile(elem) << "\n"; + ss << "" << wbLogEntry_getFunction(elem) << "\n"; + ss << "" << wbLogEntry_getLine(elem) << "\n"; + ss << "\n"; + ss << "\n"; + + return ss.str(); + } + return ""; +} + +wbLogger_t wbLogger_new() { + wbLogger_t logger; + + logger = wbNew(struct st_wbLogger_t); + + wbLogger_setLength(logger, 0); + wbLogger_setHead(logger, NULL); + + wbLogger_getLevel(logger) = wbLogLevel_TRACE; + + return logger; +} + +static inline void _wbLogger_setLevel(wbLogger_t logger, + wbLogLevel_t level) { + wbLogger_getLevel(logger) = level; +} + +static inline void _wbLogger_setLevel(wbLogLevel_t level) { + _wbLogger_setLevel(_logger, level); +} + +#define wbLogger_setLevel(level) _wbLogger_setLevel(wbLogLevel_##level) + +void wbLogger_clear(wbLogger_t logger) { + if (logger != NULL) { + wbLogEntry_t tmp; + wbLogEntry_t iter; + + iter = wbLogger_getHead(logger); + while (iter != NULL) { + tmp = wbLogEntry_getNext(iter); + wbLogEntry_delete(iter); + iter = tmp; + } + + wbLogger_setLength(logger, 0); + wbLogger_setHead(logger, NULL); + } +} + +void wbLogger_delete(wbLogger_t logger) { + if (logger != NULL) { + wbLogger_clear(logger); + wbDelete(logger); + } + return; +} + +void wbLogger_append(wbLogLevel_t level, string msg, const char *file, + const char *fun, int line) { + wbLogEntry_t elem; + wbLogger_t logger; + + wb_init(NULL, NULL); + + logger = _logger; + + if (wbLogger_getLevel(logger) < level) { + return; + } + + elem = wbLogEntry_initialize(level, msg, file, fun, line); + +#ifdef wbLogger_printOnLog + if (wbLogger_printOnLog) { + if (level <= wbLogger_getLevel(logger) && elem) { + json11::Json json = json11::Json::object{ +#ifndef _MSC_VER //PMO + { "type", "logger" }, { "data", wbLogEntry_toJSONObject(elem) }}; +#else + { "data", wbLogEntry_toJSONObject(elem) }, { "type", "logger" }}; +#endif + std::cout << json.dump() << std::endl; + } + } +#endif /* wbLogger_printOnLog */ + + if (wbLogger_getHead(logger) == NULL) { + wbLogger_setHead(logger, elem); + } else { + wbLogEntry_t prev = wbLogger_getHead(logger); + + while (wbLogEntry_hasNext(prev)) { + prev = wbLogEntry_getNext(prev); + } + wbLogEntry_setNext(prev, elem); + } + +#if 0 + if (level <= wbLogger_getLevel(logger) && elem) { + const char *levelName = getLevelName(level); + + fprintf(stderr, "= LOG: %s: %s (In %s:%s on line %d). =\n", levelName, + wbLogEntry_getMessage(elem), wbLogEntry_getFile(elem), + wbLogEntry_getFunction(elem), wbLogEntry_getLine(elem)); + } +#endif + + wbLogger_incrementLength(logger); + + return; +} + +string wbLogger_toJSON() { + return wbLogger_toJSON(_logger); +} + +static json11::Json wbLogger_toJSONObject(wbLogger_t logger) { + std::vector elems{}; + + if (logger != NULL) { + wbLogEntry_t iter; + stringstream ss; + + for (iter = wbLogger_getHead(logger); iter != NULL; + iter = wbLogEntry_getNext(iter)) { + elems.push_back(wbLogEntry_toJSONObject(iter)); + } + } + return json11::Json(elems); +} + +string wbLogger_toJSON(wbLogger_t logger) { + if (logger != NULL) { + wbLogEntry_t iter; + stringstream ss; + + for (iter = wbLogger_getHead(logger); iter != NULL; + iter = wbLogEntry_getNext(iter)) { + ss << wbLogEntry_toJSON(iter); + if (wbLogEntry_getNext(iter) != NULL) { + ss << ",\n"; + } + } + + return ss.str(); + } + return ""; +} + +string wbLogger_toXML() { + return wbLogger_toXML(_logger); +} + +string wbLogger_toXML(wbLogger_t logger) { + if (logger != NULL) { + wbLogEntry_t iter; + stringstream ss; + + ss << "\n"; + ss << "" + << "Logger" + << "\n"; + ss << "\n"; + for (iter = wbLogger_getHead(logger); iter != NULL; + iter = wbLogEntry_getNext(iter)) { + ss << wbLogEntry_toXML(iter); + } + ss << "\n"; + ss << "\n"; + + return ss.str(); + } + return ""; +} diff --git a/CUDA_Convolution/libwb/wbLogger.h b/CUDA_Convolution/libwb/wbLogger.h new file mode 100644 index 0000000..b852592 --- /dev/null +++ b/CUDA_Convolution/libwb/wbLogger.h @@ -0,0 +1,87 @@ + +#ifndef __WB_LOGGER_H__ +#define __WB_LOGGER_H__ + +#include + +typedef enum en_wbLogLevel_t { + wbLogLevel_unknown = -1, + wbLogLevel_OFF = 0, + wbLogLevel_FATAL, + wbLogLevel_ERROR, + wbLogLevel_WARN, + wbLogLevel_INFO, + wbLogLevel_DEBUG, + wbLogLevel_TRACE +} wbLogLevel_t; + +struct st_wbLogEntry_t { + int line; + int mpiRank; + char *msg; + uint64_t time; + const char *fun; + const char *file; + wbLogLevel_t level; + wbLogEntry_t next; +}; + +struct st_wbLogger_t { + int length; + wbLogEntry_t head; + wbLogLevel_t level; +}; + +#define wbLogEntry_getMessage(elem) ((elem)->msg) +#define wbLogEntry_getMPIRank(elem) ((elem)->mpiRank) +#define wbLogEntry_getTime(elem) ((elem)->time) +#define wbLogEntry_getLevel(elem) ((elem)->level) +#define wbLogEntry_getNext(elem) ((elem)->next) +#define wbLogEntry_getLine(elem) ((elem)->line) +#define wbLogEntry_getFunction(elem) ((elem)->fun) +#define wbLogEntry_getFile(elem) ((elem)->file) + +#define wbLogEntry_setMessage(elem, val) \ + (wbLogEntry_getMessage(elem) = val) +#define wbLogEntry_setMPIRank(elem, val) \ + (wbLogEntry_getMPIRank(elem) = val) +#define wbLogEntry_setTime(elem, val) (wbLogEntry_getTime(elem) = val) +#define wbLogEntry_setLevel(elem, val) (wbLogEntry_getLevel(elem) = val) +#define wbLogEntry_setNext(elem, val) (wbLogEntry_getNext(elem) = val) +#define wbLogEntry_setLine(elem, val) (wbLogEntry_getLine(elem) = val) +#define wbLogEntry_setFunction(elem, val) \ + (wbLogEntry_getFunction(elem) = val) +#define wbLogEntry_setFile(elem, val) (wbLogEntry_getFile(elem) = val) + +#define wbLogger_getLength(log) ((log)->length) +#define wbLogger_getHead(log) ((log)->head) +#define wbLogger_getLevel(log) ((log)->level) + +#define wbLogger_setLength(log, val) (wbLogger_getLength(log) = val) +#define wbLogger_setHead(log, val) (wbLogger_getHead(log) = val) + +#define wbLogger_incrementLength(log) (wbLogger_getLength(log)++) +#define wbLogger_decrementLength(log) (wbLogger_getLength(log)--) + +#define wbLog(level, ...) \ + wbLogger_append(wbLogLevel_##level, wbString(__VA_ARGS__), wbFile, \ + wbFunction, wbLine) + +extern wbLogger_t _logger; + +wbLogger_t wbLogger_new(); + +void wbLogger_clear(wbLogger_t logger); + +void wbLogger_delete(wbLogger_t logger); + +void wbLogger_append(wbLogLevel_t level, string msg, const char *file, + const char *fun, int line); + +string wbLogger_toXML(wbLogger_t logger); +string wbLogger_toXML(); + +string wbLogger_toJSON(wbLogger_t logger); +string wbLogger_toJSON(); + +#endif /* __WB_LOGGER_H__ */ diff --git a/CUDA_Convolution/libwb/wbMD5.h b/CUDA_Convolution/libwb/wbMD5.h new file mode 100644 index 0000000..e83a8ef --- /dev/null +++ b/CUDA_Convolution/libwb/wbMD5.h @@ -0,0 +1,311 @@ + +/* + * This code implements the MD5 message-digest algorithm. + * The algorithm is due to Ron Rivest. This code was + * written by Colin Plumb in 1993, no copyright is claimed. + * This code is in the public domain; do with it what you wish. + * + * Equivalent code is available from RSA Data Security, Inc. + * This code has been tested against that, and is equivalent, + * except that you don't need to include two pages of legalese + * with every copy. + * + * To compute the message digest of a chunk of bytes, declare an + * MD5Context structure, pass it to MD5Init, call MD5Update as + * needed on buffers full of bytes, and then call MD5Final, which + * will fill a supplied 16-byte array with the digest. + * + * Changed so as no longer to depend on Colin Plumb's `usual.h' header + * definitions; now uses stuff from dpkg's config.h. + * - Ian Jackson . + * Still in the public domain. + */ + +#ifndef __WB_MD5_H__ +#define __WB_MD5_H__ + +#include /* for memcpy() */ +#include /* for stupid systems */ + +#define UWORD32 unsigned int + +#define md5byte unsigned char + +struct MD5Context { + UWORD32 buf[4]; + UWORD32 bytes[2]; + UWORD32 in[16]; +}; + +static void MD5Transform(UWORD32 buf[4], UWORD32 const in[16]); + +static int g_bigEndian = 0; +static int g_endianessDetected = 0; + +static void detectEndianess() { + int nl = 0x12345678; + short ns = 0x1234; + + unsigned char *p = (unsigned char *)(&nl); + unsigned char *sp = (unsigned char *)(&ns); + + if (g_endianessDetected) + return; + if (p[0] == 0x12 && p[1] == 0x34 && p[2] == 0x56 && p[3] == 0x78) { + g_bigEndian = 1; + } else if (p[0] == 0x78 && p[1] == 0x56 && p[2] == 0x34 && + p[3] == 0x12) { + g_bigEndian = 0; + } else { + g_bigEndian = *sp != 0x12; + } + + g_endianessDetected = 1; +} + +static void byteSwap(UWORD32 *buf, unsigned words) { + md5byte *p; + + if (!g_bigEndian) + return; + + p = (md5byte *)buf; + + do { + *buf++ = (UWORD32)((unsigned)p[3] << 8 | p[2]) << 16 | + ((unsigned)p[1] << 8 | p[0]); + p += 4; + } while (--words); +} + +/* + * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious + * initialization constants. + */ +static void MD5Init(struct MD5Context *ctx) { + detectEndianess(); + + ctx->buf[0] = 0x67452301; + ctx->buf[1] = 0xefcdab89; + ctx->buf[2] = 0x98badcfe; + ctx->buf[3] = 0x10325476; + + ctx->bytes[0] = 0; + ctx->bytes[1] = 0; +} + +/* + * Update context to reflect the concatenation of another buffer full + * of bytes. + */ +static void MD5Update(struct MD5Context *ctx, md5byte const *buf, + unsigned len) { + UWORD32 t; + + /* Update byte count */ + + t = ctx->bytes[0]; + if ((ctx->bytes[0] = t + len) < t) + ctx->bytes[1]++; /* Carry from low to high */ + + t = 64 - (t & 0x3f); /* Space available in ctx->in (at least 1) */ + if (t > len) { + memcpy((md5byte *)ctx->in + 64 - t, buf, len); + return; + } + /* First chunk is an odd size */ + memcpy((md5byte *)ctx->in + 64 - t, buf, t); + byteSwap(ctx->in, 16); + MD5Transform(ctx->buf, ctx->in); + buf += t; + len -= t; + + /* Process data in 64-byte chunks */ + while (len >= 64) { + memcpy(ctx->in, buf, 64); + byteSwap(ctx->in, 16); + MD5Transform(ctx->buf, ctx->in); + buf += 64; + len -= 64; + } + + /* Handle any remaining bytes of data. */ + memcpy(ctx->in, buf, len); +} + +/* + * Final wrapup - pad to 64-byte boundary with the bit pattern + * 1 0* (64-bit count of bits processed, MSB-first) + */ +static void MD5Final(md5byte digest[16], struct MD5Context *ctx) { + int count = ctx->bytes[0] & 0x3f; /* Number of bytes in ctx->in */ + md5byte *p = (md5byte *)ctx->in + count; + + /* Set the first char of padding to 0x80. There is always room. */ + *p++ = 0x80; + + /* Bytes of padding needed to make 56 bytes (-8..55) */ + count = 56 - 1 - count; + + if (count < 0) { /* Padding forces an extra block */ + memset(p, 0, count + 8); + byteSwap(ctx->in, 16); + MD5Transform(ctx->buf, ctx->in); + p = (md5byte *)ctx->in; + count = 56; + } + memset(p, 0, count); + byteSwap(ctx->in, 14); + + /* Append length in bits and transform */ + ctx->in[14] = ctx->bytes[0] << 3; + ctx->in[15] = ctx->bytes[1] << 3 | ctx->bytes[0] >> 29; + MD5Transform(ctx->buf, ctx->in); + + byteSwap(ctx->buf, 4); + memcpy(digest, ctx->buf, 16); + memset(&ctx, 0, sizeof(ctx)); /* In case it's sensitive */ +} + +#ifndef ASM_MD5 + +/* The four core functions - F1 is optimized somewhat */ + +/* #define F1(x, y, z) (x & y | ~x & z) */ +#define F1(x, y, z) (z ^ (x & (y ^ z))) +#define F2(x, y, z) F1(z, x, y) +#define F3(x, y, z) (x ^ y ^ z) +#define F4(x, y, z) (y ^ (x | ~z)) + +/* This is the central step in the MD5 algorithm. */ +#define MD5STEP(f, w, x, y, z, in, s) \ + (w += f(x, y, z) + in, w = (w << s | w >> (32 - s)) + x) + +/* + * The core of the MD5 algorithm, this alters an existing MD5 hash to + * reflect the addition of 16 longwords of new data. MD5Update blocks + * the data and converts bytes into longwords for this routine. + */ +static void MD5Transform(UWORD32 buf[4], UWORD32 const in[16]) { + UWORD32 a, b, c, d; + + a = buf[0]; + b = buf[1]; + c = buf[2]; + d = buf[3]; + + MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); + MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); + MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); + MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); + MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); + MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); + MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); + MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); + MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); + MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); + MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); + MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); + MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); + MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); + MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); + MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); + + MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); + MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); + MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); + MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); + MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); + MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); + MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); + MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); + MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); + MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); + MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); + MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); + MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); + MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); + MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); + MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); + + MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); + MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); + MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); + MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); + MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); + MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); + MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); + MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); + MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); + MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); + MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); + MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); + MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); + MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); + MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); + MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); + + MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); + MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); + MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); + MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); + MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); + MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); + MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); + MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); + MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); + MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); + MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); + MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); + MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); + MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); + MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); + MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} + +#endif + +static void MD5_buffer(const unsigned char *buf, unsigned int len, + unsigned char sig[16]) { + struct MD5Context md5; + MD5Init(&md5); + MD5Update(&md5, buf, len); + MD5Final(sig, &md5); +} + +#define wbMD5 MD5_buffer + +#define HEX_STRING "0123456789abcdef" /* to convert to hex */ + +static void wbMD5_sigToString(unsigned char signature[16], char *str, + int len) { + unsigned char *sig_p; + char *str_p, *max_p; + unsigned int high, low; + + str_p = str; + max_p = str + len; + + for (sig_p = (unsigned char *)signature; + sig_p < (unsigned char *)signature + 16; sig_p++) { + high = *sig_p / 16; + low = *sig_p % 16; + /* account for 2 chars */ + if (str_p + 1 >= max_p) { + break; + } + *str_p++ = HEX_STRING[high]; + *str_p++ = HEX_STRING[low]; + } + /* account for 2 chars */ + if (str_p < max_p) { + *str_p++ = '\0'; + } +} + +#endif /* __WB_MD5_H__ */ diff --git a/CUDA_Convolution/libwb/wbMPI.cpp b/CUDA_Convolution/libwb/wbMPI.cpp new file mode 100644 index 0000000..546c1ed --- /dev/null +++ b/CUDA_Convolution/libwb/wbMPI.cpp @@ -0,0 +1,75 @@ + +#ifdef WB_USE_MPI + +#include +#include +#include +#include "wb.h" + +static int rank = -1; + +int wbMPI_getRank() { + if (rank != -1) { + return rank; + } + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + return rank; +} + +int rankCount() { + int nRanks; + MPI_Comm_size(MPI_COMM_WORLD, &nRanks); + return nRanks; +} + +const char *wbMPI_getStringFromRank(int rank, int tag) { + if (isMasterQ) { + char *buf; + int bufSize; + MPI_Recv(&bufSize, 1, MPI_INT, rank, tag, MPI_COMM_WORLD, + MPI_STATUS_IGNORE); + buf = (char *)calloc(bufSize, sizeof(char)); + MPI_Recv(buf, bufSize, MPI_CHAR, rank, tag, MPI_COMM_WORLD, + MPI_STATUS_IGNORE); + return buf; + } + + return NULL; +} +void wbMPI_sendStringToMaster(const char *str, int tag) { + if (!isMasterQ) { + // we are going to send the string to the master + int len = (int)strlen(str) + 1; + MPI_Send(&len, 1, MPI_INT, 0, tag, MPI_COMM_WORLD); + MPI_Send((void *)str, len, MPI_CHAR, 0, tag, MPI_COMM_WORLD); + } + + return; +} + +int wbMPI_Init(int *argc, char ***argv) { + int err = MPI_SUCCESS; + err = MPI_Init(argc, argv); + // printf("argc = %d\n", *argc); + // err = MPI_Init(NULL, NULL); + // printf("rank = %d is master = %d\n", wbMPI_getRank(), isMasterQ); + // MPI_Barrier(MPI_COMM_WORLD); + return err; +} + +bool finalizedQ = false; + +extern "C" int wbMPI_Finalize(void) { + if (finalizedQ) { + return MPI_SUCCESS; + } + finalizedQ = true; + wb_atExit(); + return MPI_Finalize(); +} +extern "C" void wbMPI_Exit(void) { + wbMPI_Finalize(); + return; +} + +#endif /* WB_USE_MPI */ diff --git a/CUDA_Convolution/libwb/wbMPI.h b/CUDA_Convolution/libwb/wbMPI.h new file mode 100644 index 0000000..6275eaf --- /dev/null +++ b/CUDA_Convolution/libwb/wbMPI.h @@ -0,0 +1,37 @@ + +#ifndef __WB_MPI_H__ +#define __WB_MPI_H__ + +#ifdef WB_USE_MPI + +#include +#include +#include + +#define isMasterQ ((wbMPI_getRank()) == 0) + +extern int wbMPI_getRank(); + +extern int rankCount(); + +extern const char *wbMPI_getStringFromRank(int rank, int tag); +extern void wbMPI_sendStringToMaster(const char *str, int tag); + +extern int wbMPI_Init(int *argc, char ***argv); + +extern bool finalizedQ; + +extern "C" int wbMPI_Finalize(void); +extern "C" void wbMPI_Exit(void); + +#define MPI_Finalize wbMPI_Finalize + +#else /* WB_USE_MPI */ +static inline int rankCount() { + return 1; +} +static inline int wbMPI_getRank() { + return 0; +} +#endif /* WB_USE_MPI */ +#endif /* __WB_MPI_H__ */ diff --git a/CUDA_Convolution/libwb/wbMalloc.h b/CUDA_Convolution/libwb/wbMalloc.h new file mode 100644 index 0000000..5d74be4 --- /dev/null +++ b/CUDA_Convolution/libwb/wbMalloc.h @@ -0,0 +1,140 @@ + + +#ifndef __WB_MALLOC_H__ +#define __WB_MALLOC_H__ + +#ifdef WB_USE_CUSTOM_MALLOC +#ifdef __linux__ +#define THROW __THROW +#else +#define THROW +#endif + +static inline void *_malloc(size_t size) THROW { + if (size == 0) { + return NULL; + } else { + int err; + void *res = memmgr_alloc((ulong)size, &err); + if (err) { + fprintf(stderr, "<>:: Memory allocation failed\n"); + exit(1); + } else { + size_t ii = 0; + unsigned char *p = (unsigned char *)res; + while (ii++ < size) { + *p++ = 0; + } + return res; + } + } +} + +static inline void _free(void *ptr) THROW { + if (ptr != NULL) { + memmgr_free(ptr); + } +} + +static inline void *_calloc(size_t nmemb, size_t size) THROW { + return _malloc(nmemb * size); +} + +static inline void *_realloc(void *ptr, size_t size) THROW { + if (size == 0) { + free(ptr); + return NULL; + } else if (ptr == NULL) { + return malloc(size); + } else { + void *buf; + unsigned char *dst; + unsigned char *src; + size_t alloc_size, to_copy, i = 0; + + // Allocate new buffer + buf = malloc(size); + + if (buf != 0) { + // Find original allocation size + alloc_size = (size_t)memmgr_get_block_size(ptr); + to_copy = alloc_size; + if (to_copy > size) { + to_copy = size; + } + + // Copy data to new buffer + dst = (unsigned char *)buf; + src = (unsigned char *)ptr; + while (i++ < to_copy) { + *dst++ = *src++; + } + + // Free the old buffer + free(ptr); + } + + return buf; + } +} + +#define wbNew(type) ((type *)_malloc(sizeof(type))) +#define wbNewArray(type, len) ((type *)_malloc((len) * sizeof(type))) +#define wbMalloc(sz) _malloc(sz) +#define wbDelete(var) \ + _free(var); \ + var = NULL +#define wbFree(var) \ + _free(var); \ + var = NULL +#define wbRealloc(var, newSize) _realloc(var, newSize) +#define wbReallocArray(t, m, n) ((t *)_realloc(m, n * sizeof(t))) + +#define free _free +#define malloc _malloc +#define calloc _calloc +#define realloc _realloc + +#else /* WB_USE_CUSTOM_MALLOC */ + +static inline void *xMalloc(size_t sz) { + void *mem = NULL; + if (sz != 0) { + mem = malloc(sz); + } + return mem; +} + +static inline void xFree(void *mem) { + if (mem != NULL) { + free(mem); + } + return; +} + +static inline void *xRealloc(void *mem, size_t sz) { + if (mem == NULL) { + return NULL; + } else if (sz == 0) { + xFree(mem); + return NULL; + } else { + void *res = realloc(mem, sz); + wbAssert(res != NULL); + return res; + } +} + +#define wbNew(type) ((type *)wbMalloc(sizeof(type))) +#define wbNewArray(type, len) ((type *)wbMalloc((len) * sizeof(type))) +#define wbMalloc(sz) xMalloc(sz) +#define wbDelete(var) wbFree(var) +#define wbFree(var) \ + xFree(var); \ + var = NULL +#define wbRealloc(var, newSize) xRealloc(var, newSize) +#define wbReallocArray(t, m, n) ((t *)xRealloc(m, n * sizeof(t))) + +#endif /* WB_USE_CUSTOM_MALLOC */ + +#endif /* __WB_MALLOC_H__ */ diff --git a/CUDA_Convolution/libwb/wbPPM.cpp b/CUDA_Convolution/libwb/wbPPM.cpp new file mode 100644 index 0000000..86ab208 --- /dev/null +++ b/CUDA_Convolution/libwb/wbPPM.cpp @@ -0,0 +1,199 @@ + +#include +#include "wb.h" + +static inline float _min(float x, float y) { + return x < y ? x : y; +} + +static inline float _max(float x, float y) { + return x > y ? x : y; +} + +static inline float _clamp(float x, float start, float end) { + return _min(_max(x, start), end); +} + +static const char *skipSpaces(const char *line) { + while (*line == ' ' || *line == '\t') { + line++; + if (*line == '\0') { + break; + } + } + return line; +} + +static char nextNonSpaceChar(const char *line0) { + const char *line = skipSpaces(line0); + return *line; +} + +static wbBool isComment(const char *line) { + char nextChar = nextNonSpaceChar(line); + if (nextChar == '\0') { + return wbTrue; + } else { + return nextChar == '#'; + } +} + +static void parseDimensions(const char *line0, int *width, int *height) { + const char *line = skipSpaces(line0); + sscanf(line, "%d %d", width, height); +} + +static void parseDimensions(const char *line0, int *width, int *height, + int *channels) { + const char *line = skipSpaces(line0); + sscanf(line, "%d %d %d", width, height, channels); +} + +static void parseDepth(const char *line0, int *depth) { + const char *line = skipSpaces(line0); + sscanf(line, "%d", depth); +} + +static char *nextLine(wbFile_t file) { + char *line = NULL; + while ((line = wbFile_readLine(file)) != NULL) { + if (!isComment(line)) { + break; + } + } + return line; +} + +wbImage_t wbPPM_import(const char *filename) { + wbImage_t img; + wbFile_t file; + char *header; + char *line; + int ii, jj, kk, channels; + int width, height, depth; + unsigned char *charData, *charIter; + float *imgData, *floatIter; + float scale; + + img = NULL; + + file = wbFile_open(filename, "rb"); + if (file == NULL) { + printf("Could not open %s\n", filename); + goto cleanup; + } + + header = wbFile_readLine(file); + if (header == NULL) { + printf("Could not read from %s\n", filename); + goto cleanup; + } else if (strcmp(header, "P6") != 0 && strcmp(header, "P6\n") != 0 && + strcmp(header, "P5") != 0 && strcmp(header, "P5\n") != 0 && + strcmp(header, "S6") != 0 && strcmp(header, "S6\n") != 0) { + printf("Could find magic number for %s\n", filename); + goto cleanup; + } + + // P5 are monochrome while P6/S6 are rgb + // S6 needs to parse number of channels out of file + if (strcmp(header, "P5") == 0 || strcmp(header, "P5\n") == 0) { + channels = 1; + line = nextLine(file); + parseDimensions(line, &width, &height); + } else if (strcmp(header, "P6") == 0 || strcmp(header, "P6\n") == 0) { + channels = 3; + line = nextLine(file); + parseDimensions(line, &width, &height); + } else { + line = nextLine(file); + parseDimensions(line, &width, &height, &channels); + } + + // the line now contains the depth information + line = nextLine(file); + parseDepth(line, &depth); + + // the rest of the lines contain the data in binary format + charData = (unsigned char *)wbFile_read( + file, width * channels * sizeof(unsigned char), height); + + img = wbImage_new(width, height, channels); + + imgData = wbImage_getData(img); + + charIter = charData; + floatIter = imgData; + + scale = 1.0f / ((float)depth); + + for (ii = 0; ii < height; ii++) { + for (jj = 0; jj < width; jj++) { + for (kk = 0; kk < channels; kk++) { + *floatIter = ((float)*charIter) * scale; + floatIter++; + charIter++; + } + } + } + +#ifdef LAZY_FILE_LOAD + wbDelete(charData); +#endif + +cleanup: + wbFile_close(file); + return img; +} + +void wbPPM_export(const char *filename, wbImage_t img) { + int ii; + int jj; + int kk; + int depth; + int width; + int height; + int channels; + wbFile_t file; + float *floatIter; + unsigned char *charData; + unsigned char *charIter; + + file = wbFile_open(filename, "wb+"); + + width = wbImage_getWidth(img); + height = wbImage_getHeight(img); + channels = wbImage_getChannels(img); + depth = 255; + + if (channels == 1) { + wbFile_writeLine(file, "P5"); + } else { + wbFile_writeLine(file, "P6"); + } + wbFile_writeLine(file, "#Created via wbPPM Export"); + wbFile_writeLine(file, wbString(width, " ", height)); + wbFile_writeLine(file, wbString(depth)); + + charData = wbNewArray(unsigned char, width *height *channels); + + charIter = charData; + floatIter = wbImage_getData(img); + + for (ii = 0; ii < height; ii++) { + for (jj = 0; jj < width; jj++) { + for (kk = 0; kk < channels; kk++) { + *charIter = (unsigned char)ceil(_clamp(*floatIter, 0, 1) * depth); + floatIter++; + charIter++; + } + } + } + + wbFile_write(file, charData, width * channels * sizeof(unsigned char), + height); + + wbDelete(charData); + wbFile_delete(file); + + return; +} diff --git a/CUDA_Convolution/libwb/wbPPM.h b/CUDA_Convolution/libwb/wbPPM.h new file mode 100644 index 0000000..d589b36 --- /dev/null +++ b/CUDA_Convolution/libwb/wbPPM.h @@ -0,0 +1,11 @@ + + +#ifndef __wbPPM_H__ +#define __wbPPM_H__ + +START_EXTERN_C +wbImage_t wbPPM_import(const char *filename); +void wbPPM_export(const char *filename, wbImage_t img); +END_EXTERN_C + +#endif /* __wbPPM_H__ */ diff --git a/CUDA_Convolution/libwb/wbPath.cpp b/CUDA_Convolution/libwb/wbPath.cpp new file mode 100644 index 0000000..0d93e2b --- /dev/null +++ b/CUDA_Convolution/libwb/wbPath.cpp @@ -0,0 +1,42 @@ +#include "wb.h" + +char *wbPath_join(const char *p1, const char *p2) { + size_t s1 = strlen(p1); + size_t s2 = strlen(p2); + char *res = + wbNewArray(char, s1 + 1 /* seperator */ + s2 + 1 /* terminator */); + memcpy(res, p1, s1); + char *iter = res + s1; + *iter++ = wbDirectorySeperator; + memcpy(iter, p2, s2); + iter += s2; + *iter = '\0'; + return res; +} + +char *wbPath_join(const char *p1, const char *p2, const char *p3) { + char *p12 = wbPath_join(p1, p2); + char *res = wbPath_join(p12, p3); + wbDelete(p12); + return res; +} + +char *wbPath_join(const char *p1, const char *p2, const char *p3, + const char *p4) { + char *p123 = wbPath_join(p1, p2, p3); + char *res = wbPath_join(p123, p4); + wbDelete(p123); + return res; +} + +char *wbPath_join(const std::string &p1, const std::string &p2) { + return wbPath_join(p1.c_str(), p2.c_str()); +} +char *wbPath_join(const std::string &p1, const std::string &p2, + const std::string &p3) { + return wbPath_join(p1.c_str(), p2.c_str(), p3.c_str()); +} +char *wbPath_join(const std::string &p1, const std::string &p2, + const std::string &p3, const std::string &p4) { + return wbPath_join(p1.c_str(), p2.c_str(), p3.c_str(), p4.c_str()); +} \ No newline at end of file diff --git a/CUDA_Convolution/libwb/wbPath.h b/CUDA_Convolution/libwb/wbPath.h new file mode 100644 index 0000000..0dd3187 --- /dev/null +++ b/CUDA_Convolution/libwb/wbPath.h @@ -0,0 +1,30 @@ +#ifndef __WB_PATH_H__ +#define __WB_PATH_H__ + +char *wbPath_join(const char *p1, const char *p2); +char *wbPath_join(const char *p1, const char *p2, const char *p3); +char *wbPath_join(const char *p1, const char *p2, const char *p3, + const char *p4); + +char *wbPath_join(const std::string &p1, const std::string &p2); +char *wbPath_join(const std::string &p1, const std::string &p2, + const std::string &p3); +char *wbPath_join(const std::string &p1, const std::string &p2, + const std::string &p3, const std::string &p4); + +template +static char *wbPath_join(const T1 &p1, const T2 &p2) { + return wbPath_join(wbString(p1), wbString(p2)); +} +template +static char *wbPath_join(const T1 &p1, const T2 &p2, const T3 &p3) { + return wbPath_join(wbString(p1), wbString(p2), wbString(p3)); +} +template +static char *wbPath_join(const T1 &p1, const T2 &p2, const T3 &p3, + const T4 &p4) { + return wbPath_join(wbString(p1), wbString(p2), wbString(p3), + wbString(p4)); +} + +#endif /* __WB_PATH_H__ */ diff --git a/CUDA_Convolution/libwb/wbSolution.cpp b/CUDA_Convolution/libwb/wbSolution.cpp new file mode 100644 index 0000000..703f410 --- /dev/null +++ b/CUDA_Convolution/libwb/wbSolution.cpp @@ -0,0 +1,271 @@ + +#include "wb.h" + +char *solutionJSON = NULL; +static string _solution_correctQ(""); + +static void _onUnsameImageFunction(string str) { + _solution_correctQ = str; +} + +template +static wbBool wbSolution_listCorrectQ(const char *expectedOutputFile, + wbSolution_t sol, const char *type) { + wbBool res; + T *expectedData; + int expectedRows, expectedColumns; + + expectedData = (T *)wbImport(expectedOutputFile, &expectedRows, + &expectedColumns, type); + + if (expectedData == NULL) { + _solution_correctQ = "Failed to open expected output file."; + res = wbFalse; + } else if (expectedRows != wbSolution_getRows(sol)) { + wbLog(TRACE, "Number of rows in the solution is ", + wbSolution_getRows(sol), ". Expected number of rows is ", + expectedRows, "."); + _solution_correctQ = + "The number of rows in the solution did not match " + "that of the expected results."; + res = wbFalse; + } else if (expectedColumns != wbSolution_getColumns(sol)) { + wbLog(TRACE, "Number of columns in the solution is ", + wbSolution_getColumns(sol), ". Expected number of columns is ", + expectedColumns, "."); + _solution_correctQ = "The number of columns in the solution did not " + "match that of the expected results."; + res = wbFalse; + } else { + int ii, jj, idx; + T *solutionData; + + solutionData = (T *)wbSolution_getData(sol); + + for (ii = 0; ii < expectedRows; ii++) { + for (jj = 0; jj < expectedColumns; jj++) { + idx = ii * expectedColumns + jj; + if (wbUnequalQ(expectedData[idx], solutionData[idx])) { + string str; + if (expectedColumns == 1) { + str = wbString( + "The solution did not match the expected results at row ", + ii, ". Expecting ", expectedData[idx], " but got ", + solutionData[idx], "."); + } else { + str = wbString("The solution did not match the expected " + "results at column ", + jj, " and row ", ii, ". Expecting ", + expectedData[idx], " but got ", + solutionData[idx], "."); + } + _solution_correctQ = str; + res = wbFalse; + goto matrixCleanup; + } + } + } + + res = wbTrue; + matrixCleanup: + if (expectedData != NULL) { + wbFree(expectedData); + } + } + return res; +} + +static wbBool wbSolution_correctQ(char *expectedOutputFile, + wbSolution_t sol) { + if (expectedOutputFile == NULL) { + _solution_correctQ = "Failed to determined the expected output file."; + return wbFalse; + } else if (!wbFile_existsQ(expectedOutputFile)) { + _solution_correctQ = + wbString("The file ", expectedOutputFile, " does not exist."); + return wbFalse; + } else if (wbString_sameQ(wbSolution_getType(sol), "image")) { + wbBool res; + wbImage_t solutionImage = NULL; + wbImage_t expectedImage = wbImport(expectedOutputFile); + if (expectedImage == NULL) { + _solution_correctQ = "Failed to open expected output file."; + res = wbFalse; + } else if (wbImage_getWidth(expectedImage) != + wbSolution_getWidth(sol)) { + _solution_correctQ = + "The image width of the expected image does not " + "match that of the solution."; + res = wbFalse; + } else if (wbImage_getHeight(expectedImage) != + wbSolution_getHeight(sol)) { + _solution_correctQ = + "The image height of the expected image does not " + "match that of the solution."; + res = wbFalse; + } else if (wbImage_getChannels(expectedImage) != + wbSolution_getChannels(sol)) { + _solution_correctQ = + "The image channels of the expected image does not " + "match that of the solution."; + res = wbFalse; + } else { + solutionImage = (wbImage_t)wbSolution_getData(sol); + wbAssert(solutionImage != NULL); + res = wbImage_sameQ(solutionImage, expectedImage, + _onUnsameImageFunction); + } + if (expectedImage != NULL) { + wbImage_delete(expectedImage); + } + return res; + } else if (wbString_sameQ(wbSolution_getType(sol), "histogram")) { + return wbSolution_listCorrectQ(expectedOutputFile, sol, + "Integer"); + } else if (wbString_sameQ(wbSolution_getType(sol), "integral_vector")) { + return wbSolution_listCorrectQ(expectedOutputFile, sol, + "Integer"); + } else if (wbString_sameQ(wbSolution_getType(sol), "vector") || + wbString_sameQ(wbSolution_getType(sol), "matrix")) { + return wbSolution_listCorrectQ(expectedOutputFile, sol, + "Real"); + } else { + wbAssert(wbFalse); + return wbFalse; + } +} + +wbBool wbSolution(char *expectedOutputFile, char *outputFile, char *type0, + void *data, int rows, int columns, int depth) { + char *type; + wbBool res; + wbSolution_t sol; + + if (expectedOutputFile == NULL || data == NULL || type0 == NULL) { + wbLog(ERROR, "Failed to grade solution"); + return wbFalse; + } + + type = wbString_toLower(type0); + + if (_solution_correctQ != "") { + _solution_correctQ = ""; + } + + wbSolution_setOutputFile(sol, outputFile); + wbSolution_setType(sol, type); + wbSolution_setData(sol, data); + wbSolution_setRows(sol, rows); + wbSolution_setColumns(sol, columns); + wbSolution_setDepth(sol, depth); + + res = wbSolution_correctQ(expectedOutputFile, sol); + + if (outputFile != NULL) { + if (wbString_sameQ(type, "image")) { + wbImage_t inputImage = (wbImage_t)data; + wbImage_t img = wbImage_new(wbImage_getWidth(inputImage), + wbImage_getHeight(inputImage), + wbImage_getChannels(inputImage)); + memcpy(wbImage_getData(img), wbImage_getData(inputImage), + rows * columns * wbImage_channels * sizeof(wbReal_t)); + wbExport(outputFile, img); + wbImage_delete(img); + } else if (wbString_sameQ(type, "integral_vector")) { + wbExport(outputFile, (int *)data, rows, columns); + } else if (wbString_sameQ(type, "vector") || + wbString_sameQ(type, "matrix")) { + wbExport(outputFile, (wbReal_t *)data, rows, columns); + } else if (wbString_sameQ(type, "histogram")) { + wbExport(outputFile, (unsigned char *)data, rows, columns); + } else if (wbString_sameQ(type, "text")) { + wbExport_text(outputFile, (unsigned char *)data, rows * columns); + } + } + + wbFree(type); + + return res; +} + +wbBool wbSolution(char *expectedOutputFile, char *outputFile, char *type0, + void *data, int rows, int columns) { + return wbSolution(expectedOutputFile, outputFile, type0, data, rows, + columns, 1); +} + +wbBool wbSolution(wbArg_t arg, void *data, int rows, int columns, + int depth) { + char *type; + wbBool res; + char *expectedOutputFile; + char *outputFile; + stringstream ss; + + expectedOutputFile = wbArg_getExpectedOutputFile(arg); + outputFile = wbArg_getOutputFile(arg); + type = wbArg_getType(arg); + + wbAssert(type != NULL); + wbAssert(expectedOutputFile != NULL); + wbAssert(outputFile != NULL); + + res = wbSolution(expectedOutputFile, outputFile, type, data, rows, + columns, depth); + + if (WB_USE_JSON11) { + json11::Json json; + if (res) { + json = json11::Json::object{{"correctq", true}, + {"message", "The solution is correct"}}; + } else { + json = json11::Json::object{{"correctq", false}, + {"message", _solution_correctQ}}; + } + +#ifdef wbLogger_printOnLog + if (wbLogger_printOnLog) { + json11::Json e = +//PMO +#ifndef _MSC_VER + json11::Json::object{{"type", "solution"}, {"data", json}}; +#else + json11::Json::object{{"data", json }, {"type", "solution" }}; +#endif + std::cout << e.dump() << std::endl; + } +#endif /* wbLogger_printOnLog */ + + solutionJSON = wbString_duplicate(json.string_value()); + } else { + if (res) { + ss << "{\n"; + ss << wbString_quote("correctq") << ": true,\n"; + ss << wbString_quote("message") << ": " + << wbString_quote("Solution is correct.") << "\n"; + ss << "}"; + } else { + ss << "{\n"; + ss << wbString_quote("correctq") << ": false,\n"; + ss << wbString_quote("message") << ": " + << wbString_quote(_solution_correctQ) << "\n"; + ss << "}"; + } + solutionJSON = wbString_duplicate(ss.str()); + } + + return res; +} + +wbBool wbSolution(wbArg_t arg, void *data, int rows, int columns) { + return wbSolution(arg, data, rows, columns, 1); +} + +EXTERN_C wbBool wbSolution(wbArg_t arg, void *data, int rows) { + return wbSolution(arg, data, rows, 1); +} + +wbBool wbSolution(wbArg_t arg, wbImage_t img) { + return wbSolution(arg, img, wbImage_getHeight(img), + wbImage_getWidth(img), wbImage_getChannels(img)); +} diff --git a/CUDA_Convolution/libwb/wbSolution.h b/CUDA_Convolution/libwb/wbSolution.h new file mode 100644 index 0000000..f18d07d --- /dev/null +++ b/CUDA_Convolution/libwb/wbSolution.h @@ -0,0 +1,40 @@ + + +#ifndef __WB_SOLUTION_H__ +#define __WB_SOLUTION_H__ + +typedef struct st_wbSolution_t { + char *type; + char *outputFile; + void *data; + int rows; + int columns; + int depth; +} wbSolution_t; + +#define wbSolution_getType(sol) ((sol).type) +#define wbSolution_getOutputFile(sol) ((sol).outputFile) +#define wbSolution_getData(sol) ((sol).data) +#define wbSolution_getRows(sol) ((sol).rows) +#define wbSolution_getColumns(sol) ((sol).columns) +#define wbSolution_getDepth(sol) ((sol).depth) + +#define wbSolution_getHeight wbSolution_getRows +#define wbSolution_getWidth wbSolution_getColumns +#define wbSolution_getChannels wbSolution_getDepth + +#define wbSolution_setType(sol, val) (wbSolution_getType(sol) = val) +#define wbSolution_setOutputFile(sol, val) \ + (wbSolution_getOutputFile(sol) = val) +#define wbSolution_setData(sol, val) (wbSolution_getData(sol) = val) +#define wbSolution_setRows(sol, val) (wbSolution_getRows(sol) = val) +#define wbSolution_setColumns(sol, val) (wbSolution_getColumns(sol) = val) +#define wbSolution_setDepth(sol, val) (wbSolution_getDepth(sol) = val) + +wbBool wbSolution(char *expectedOutputFile, char *outputFile, char *type0, + void *data, int rows, int columns); +wbBool wbSolution(wbArg_t arg, void *data, int rows, int columns); +EXTERN_C wbBool wbSolution(wbArg_t arg, void *data, int rows); +wbBool wbSolution(wbArg_t arg, wbImage_t img); + +#endif /* __WB_SOLUTION_H__ */ diff --git a/CUDA_Convolution/libwb/wbSparse.cpp b/CUDA_Convolution/libwb/wbSparse.cpp new file mode 100644 index 0000000..9cdcba3 --- /dev/null +++ b/CUDA_Convolution/libwb/wbSparse.cpp @@ -0,0 +1,82 @@ + +#include "wb.h" + +static void sort(int *data, int *key, int start, int end) { + if ((end - start + 1) > 1) { + int left = start, right = end; + int pivot = key[right]; + while (left <= right) { + while (key[left] > pivot) { + left = left + 1; + } + while (key[right] < pivot) { + right = right - 1; + } + if (left <= right) { + int tmp = key[left]; + key[left] = key[right]; + key[right] = tmp; + tmp = data[left]; + data[left] = data[right]; + data[right] = tmp; + left = left + 1; + right = right - 1; + } + } + sort(data, key, start, right); + sort(data, key, left, end); + } +} + +EXTERN_C void CSRToJDS(int dim, int *csrRowPtr, int *csrColIdx, + float *csrData, int **jdsRowPerm, int **jdsRowNNZ, + int **jdsColStartIdx, int **jdsColIdx, + float **jdsData) { + // Row Permutation Vector + *jdsRowPerm = (int *)malloc(sizeof(int) * dim); + for (int rowIdx = 0; rowIdx < dim; ++rowIdx) { + (*jdsRowPerm)[rowIdx] = rowIdx; + } + + // Number of non-zeros per row + *jdsRowNNZ = (int *)malloc(sizeof(int) * dim); + for (int rowIdx = 0; rowIdx < dim; ++rowIdx) { + (*jdsRowNNZ)[rowIdx] = csrRowPtr[rowIdx + 1] - csrRowPtr[rowIdx]; + } + + // Sort rows by number of non-zeros + sort(*jdsRowPerm, *jdsRowNNZ, 0, dim - 1); + + // Starting point of each compressed column + int maxRowNNZ = (*jdsRowNNZ)[0]; // Largest number of non-zeros per row + DEBUG(printf("jdsRowNNZ = %d\n", maxRowNNZ)); + *jdsColStartIdx = (int *)malloc(sizeof(int) * maxRowNNZ); + (*jdsColStartIdx)[0] = 0; // First column starts at 0 + for (int col = 0; col < maxRowNNZ - 1; ++col) { + // Count the number of rows with entries in this column + int count = 0; + for (int idx = 0; idx < dim; ++idx) { + if ((*jdsRowNNZ)[idx] > col) { + ++count; + } + } + (*jdsColStartIdx)[col + 1] = (*jdsColStartIdx)[col] + count; + } + + // Sort the column indexes and data + const int NNZ = csrRowPtr[dim]; + DEBUG(printf("NNZ = %d\n", NNZ)); + *jdsColIdx = (int *)malloc(sizeof(int) * NNZ); + DEBUG(printf("dim = %d\n", dim)); + *jdsData = (float *)malloc(sizeof(float) * NNZ); + for (int idx = 0; idx < dim; ++idx) { // For every row + int row = (*jdsRowPerm)[idx]; + int rowNNZ = (*jdsRowNNZ)[idx]; + for (int nnzIdx = 0; nnzIdx < rowNNZ; ++nnzIdx) { + int jdsPos = (*jdsColStartIdx)[nnzIdx] + idx; + int csrPos = csrRowPtr[row] + nnzIdx; + (*jdsColIdx)[jdsPos] = csrColIdx[csrPos]; + (*jdsData)[jdsPos] = csrData[csrPos]; + } + } +} diff --git a/CUDA_Convolution/libwb/wbSparse.h b/CUDA_Convolution/libwb/wbSparse.h new file mode 100644 index 0000000..c04a857 --- /dev/null +++ b/CUDA_Convolution/libwb/wbSparse.h @@ -0,0 +1,10 @@ + +#ifndef __WB_SPARSE_H__ +#define __WB_SPARSE_H__ + +EXTERN_C void CSRToJDS(int dim, int *csrRowPtr, int *csrColIdx, + float *csrData, int **jdsRowPerm, int **jdsRowNNZ, + int **jdsColStartIdx, int **jdsColIdx, + float **jdsData); + +#endif /* __WB_SPARSE_H__ */ diff --git a/CUDA_Convolution/libwb/wbString.h b/CUDA_Convolution/libwb/wbString.h new file mode 100644 index 0000000..65e52f8 --- /dev/null +++ b/CUDA_Convolution/libwb/wbString.h @@ -0,0 +1,324 @@ + + +#ifndef __WB_STRING_H__ +#define __WB_STRING_H__ + +#include +#include +#include +#include +#include +#include +#include "wb.h" + +using std::string; +using std::vector; +using std::stringstream; +using std::exception; + +template +static inline string wbString(const T &x); + +static inline void wbString_replace(string &value, string const &search, + string const &replace) { + for (string::size_type next = value.find(search); next != string::npos; + next = value.find(search, next)) { + value.replace(next, search.length(), replace); + next += replace.length(); + } +} + +static inline string wbString_quote(string str) { + string s = str; + wbString_replace(s, "\\", "\\\\"); + s = "\"" + s + "\""; + return s; +} + +static inline string wbString_quote(const char *str) { + if (str == NULL) { + return wbString_quote(""); + } else { + return wbString_quote(string(str)); + } +} + +static inline char *wbString_duplicate(const char *str) { + if (str == NULL) { + return NULL; + } else { + char *newstr; + size_t len = strlen(str); + newstr = wbNewArray(char, len + 1); + memcpy(newstr, str, len * sizeof(char)); + newstr[len] = '\0'; + return newstr; + } +} + +static inline char *wbString_duplicate(std::string str) { + return wbString_duplicate(str.c_str()); +} + +static inline string wbString(void) { + string s = ""; + return s; +} + +template +static inline string wbString(const T &x) { + try { + stringstream ss; + ss << x; + return ss.str(); + } catch (exception &e) { + return string(); + } +} + +template <> +inline string wbString(const bool &x) { + return x ? "True" : "False"; +} + +template <> +inline string wbString(const vector &x) { + stringstream ss; + ss << "{"; + for (size_t ii = 0; ii < x.size(); ii++) { + ss << wbString_quote(x[ii]); + if (ii != x.size() - 1) { + ss << ", "; + } + } + ss << "}"; + + return ss.str(); +} + +template <> +inline string wbString(const vector &x) { + stringstream ss; + ss << "{"; + for (size_t ii = 0; ii < x.size(); ii++) { + ss << x[ii]; + if (ii != x.size() - 1) { + ss << ", "; + } + } + ss << "}"; + + return ss.str(); +} + +template <> +inline string wbString(const vector &x) { + stringstream ss; + ss << "{"; + for (size_t ii = 0; ii < x.size(); ii++) { + ss << x[ii]; + if (ii != x.size() - 1) { + ss << ", "; + } + } + ss << "}"; + + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1) { + stringstream ss; + ss << wbString(x0) << wbString(x1); + + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1, const T2 &x2) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2); + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1, const T2 &x2, + const T3 &x3) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2) << wbString(x3); + + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1, const T2 &x2, + const T3 &x3, const T4 &x4) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2) << wbString(x3) + << wbString(x4); + + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1, const T2 &x2, + const T3 &x3, const T4 &x4, const T5 &x5) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2) << wbString(x3) + << wbString(x4) << wbString(x5); + + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1, const T2 &x2, + const T3 &x3, const T4 &x4, const T5 &x5, + const T6 &x6) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2) << wbString(x3) + << wbString(x4) << wbString(x5) << wbString(x6); + + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1, const T2 &x2, + const T3 &x3, const T4 &x4, const T5 &x5, + const T6 &x6, const T7 &x7) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2) << wbString(x3) + << wbString(x4) << wbString(x5) << wbString(x6) << wbString(x7); + + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1, const T2 &x2, + const T3 &x3, const T4 &x4, const T5 &x5, + const T6 &x6, const T7 &x7, const T8 &x8) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2) << wbString(x3) + << wbString(x4) << wbString(x5) << wbString(x6) << wbString(x7) + << wbString(x8); + + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1, const T2 &x2, + const T3 &x3, const T4 &x4, const T5 &x5, + const T6 &x6, const T7 &x7, const T8 &x8, + const T9 &x9) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2) << wbString(x3) + << wbString(x4) << wbString(x5) << wbString(x6) << wbString(x7) + << wbString(x8) << wbString(x9); + + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1, const T2 &x2, + const T3 &x3, const T4 &x4, const T5 &x5, + const T6 &x6, const T7 &x7, const T8 &x8, + const T9 &x9, const T10 &x10) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2) << wbString(x3) + << wbString(x4) << wbString(x5) << wbString(x6) << wbString(x7) + << wbString(x8) << wbString(x9) << wbString(x10); + + return ss.str(); +} + +template +static inline string +wbString(const T0 &x0, const T1 &x1, const T2 &x2, const T3 &x3, + const T4 &x4, const T5 &x5, const T6 &x6, const T7 &x7, + const T8 &x8, const T9 &x9, const T10 &x10, const T11 &x11) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2) << wbString(x3) + << wbString(x4) << wbString(x5) << wbString(x6) << wbString(x7) + << wbString(x8) << wbString(x9) << wbString(x10) << wbString(x11); + + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1, const T2 &x2, + const T3 &x3, const T4 &x4, const T5 &x5, + const T6 &x6, const T7 &x7, const T8 &x8, + const T9 &x9, const T10 &x10, const T11 &x11, + const T12 &x12) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2) << wbString(x3) + << wbString(x4) << wbString(x5) << wbString(x6) << wbString(x7) + << wbString(x8) << wbString(x9) << wbString(x10) << wbString(x11) + << wbString(x12); + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1, const T2 &x2, + const T3 &x3, const T4 &x4, const T5 &x5, + const T6 &x6, const T7 &x7, const T8 &x8, + const T9 &x9, const T10 &x10, const T11 &x11, + const T12 &x12, const T13 &x13) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2) << wbString(x3) + << wbString(x4) << wbString(x5) << wbString(x6) << wbString(x7) + << wbString(x8) << wbString(x9) << wbString(x10) << wbString(x11) + << wbString(x12) << wbString(x13); + return ss.str(); +} + +template +static inline wbBool wbString_sameQ(const X &x, const Y &y) { + string xs = wbString(x); + string ys = wbString(y); + return strcmp(xs.c_str(), ys.c_str()) == 0; +} + +static inline wbBool wbString_sameQ(const string &x, const string &y) { + return x.compare(y) == 0; +} + +static inline char *wbString_toLower(const char *str) { + if (str == NULL) { + return NULL; + } else { + char *res, *iter; + + res = iter = wbString_duplicate(str); + while (*iter != '\0') { + *iter++ = tolower(*str++); + } + return res; + } +} + +static inline wbBool wbString_startsWith(const char *str, + const char *prefix) { + while (*prefix != '\0') { + if (*str == '\0' || *str != *prefix) { + return wbFalse; + } + str++; + prefix++; + } + return wbTrue; +} + +#endif /* __WB_STRING_H__ */ diff --git a/CUDA_Convolution/libwb/wbThrust.h b/CUDA_Convolution/libwb/wbThrust.h new file mode 100644 index 0000000..e2d3160 --- /dev/null +++ b/CUDA_Convolution/libwb/wbThrust.h @@ -0,0 +1,15 @@ + +#ifndef __WB_THRUST_H__ +#define __WB_THRUST_H__ + +#ifdef WB_USE_CUDA +#include +#include +#include +#include +#include +#include + +#endif /* WB_USE_CUDA */ + +#endif /* __WB_THRUST_H__ */ diff --git a/CUDA_Convolution/libwb/wbTimer.cpp b/CUDA_Convolution/libwb/wbTimer.cpp new file mode 100644 index 0000000..c9fbdb8 --- /dev/null +++ b/CUDA_Convolution/libwb/wbTimer.cpp @@ -0,0 +1,493 @@ +#include "wb.h" + +#ifdef WB_USE_WINDOWS +uint64_t _hrtime_frequency = 0; +#endif /* WB_USE_WINDOWS */ +wbTimer_t _timer = NULL; + +#ifdef WB_USE_DARWIN +static double o_timebase = 0; +static uint64_t o_timestart = 0; +#endif /* WB_USE_DARWIN */ + +uint64_t _hrtime(void) { +#define NANOSEC ((uint64_t)1e9) +#ifdef WB_USE_WINDOWS + LARGE_INTEGER counter; + if (!QueryPerformanceCounter(&counter)) { + return 0; + } + return ((uint64_t)counter.LowPart * NANOSEC / _hrtime_frequency) + + (((uint64_t)counter.HighPart * NANOSEC / _hrtime_frequency) + << 32); +#else + struct timespec ts; +#ifdef WB_USE_DARWIN +#define O_NANOSEC (+1.0E-9) +#define O_GIGA UINT64_C(1000000000) + if (!o_timestart) { + mach_timebase_info_data_t tb{}; + mach_timebase_info(&tb); + o_timebase = tb.numer; + o_timebase /= tb.denom; + o_timestart = mach_absolute_time(); + } + double diff = (mach_absolute_time() - o_timestart) * o_timebase; + ts.tv_sec = diff * O_NANOSEC; + ts.tv_nsec = diff - (ts.tv_sec * O_GIGA); +#undef O_NANOSEC +#undef O_GIGA +#else /* WB_USE_DARWIN */ + clock_gettime(CLOCK_MONOTONIC, &ts); +#endif /* WB_USE_DARWIN */ + return (((uint64_t)ts.tv_sec) * NANOSEC + ts.tv_nsec); +#endif /* WB_USE_WINDOWS */ +#undef NANOSEC +} + +static inline uint64_t getTime(void) { +#ifdef WB_USE_CUDA + cudaDeviceSynchronize(); +#endif /* WB_USE_CUDA */ + return _hrtime(); +} + +static inline wbTimerNode_t wbTimerNode_new(int id, wbTimerKind_t kind, + const char *file, + const char *fun, + int startLine) { + wbTimerNode_t node = wbNew(struct st_wbTimerNode_t); + wbTimerNode_setId(node, id); + wbTimerNode_setMPIRank(node, wbMPI_getRank()); + wbTimerNode_setLevel(node, 0); + wbTimerNode_setStoppedQ(node, wbFalse); + wbTimerNode_setKind(node, kind); + wbTimerNode_setStartTime(node, 0); + wbTimerNode_setEndTime(node, 0); + wbTimerNode_setElapsedTime(node, 0); + wbTimerNode_setStartLine(node, startLine); + wbTimerNode_setEndLine(node, 0); + wbTimerNode_setStartFunction(node, fun); + wbTimerNode_setEndFunction(node, NULL); + wbTimerNode_setStartFile(node, file); + wbTimerNode_setEndFile(node, NULL); + wbTimerNode_setNext(node, NULL); + wbTimerNode_setPrevious(node, NULL); + wbTimerNode_setParent(node, NULL); + wbTimerNode_setMessage(node, NULL); + return node; +} + +static inline void wbTimerNode_delete(wbTimerNode_t node) { + if (node != NULL) { + if (wbTimerNode_getMessage(node)) { + wbDelete(wbTimerNode_getMessage(node)); + } + wbDelete(node); + } +} + +static inline const char *_nodeKind(wbTimerKind_t kind) { + switch (kind) { + case wbTimerKind_Generic: + return "Generic"; + case wbTimerKind_IO: + return "IO"; + case wbTimerKind_GPU: + return "GPU"; + case wbTimerKind_Copy: + return "Copy"; + case wbTimerKind_Driver: + return "Driver"; + case wbTimerKind_CopyAsync: + return "CopyAsync"; + case wbTimerKind_Compute: + return "Compute"; + case wbTimerKind_CPUGPUOverlap: + return "CPUGPUOverlap"; + } + return "Undefined"; +} + +static inline json11::Json wbTimerNode_toJSONObject(wbTimerNode_t node) { + json11::Json json = json11::Json::object{ + {"id", wbTimerNode_getId(node)}, + {"mpi_rank", wbTimerNode_getMPIRank(node)}, + {"stopped", wbTimerNode_stoppedQ(node)}, + {"kind", _nodeKind(wbTimerNode_getKind(node))}, + {"start_time", wbTimerNode_getStartTime(node)}, + {"end_time", wbTimerNode_getEndTime(node)}, + {"elapsed_time", wbTimerNode_getElapsedTime(node)}, + {"start_line", wbTimerNode_getStartLine(node)}, + {"end_line", wbTimerNode_getEndLine(node)}, + {"start_function", wbTimerNode_getStartFunction(node)}, + {"end_function", wbTimerNode_getEndFunction(node)}, + {"start_file", wbTimerNode_getStartFile(node)}, + {"end_file", wbTimerNode_getEndFile(node)}, + {"parent_id", wbTimerNode_hasParent(node) + ? wbTimerNode_getId(wbTimerNode_getParent(node)) + : -1}, + {"message", wbTimerNode_getMessage(node)}, + }; + return json; +} + +static inline string wbTimerNode_toJSON(wbTimerNode_t node) { + if (node == NULL) { + return ""; + } else if (WB_USE_JSON11) { + json11::Json json = wbTimerNode_toJSONObject(node); + return json.string_value(); + } else { + stringstream ss; + + ss << "{\n"; + ss << wbString_quote("id") << ":" << wbTimerNode_getId(node) << ",\n"; + ss << wbString_quote("mpi_rank") << ":" << wbTimerNode_getMPIRank(node) + << ",\n"; + ss << wbString_quote("stopped") << ":" + << wbString(wbTimerNode_stoppedQ(node) ? "true" : "false") << ",\n"; + ss << wbString_quote("kind") << ":" + << wbString_quote(_nodeKind(wbTimerNode_getKind(node))) << ",\n"; + ss << wbString_quote("start_time") << ":" + << wbTimerNode_getStartTime(node) << ",\n"; + ss << wbString_quote("end_time") << ":" << wbTimerNode_getEndTime(node) + << ",\n"; + ss << wbString_quote("elapsed_time") << ":" + << wbTimerNode_getElapsedTime(node) << ",\n"; + ss << wbString_quote("start_line") << ":" + << wbTimerNode_getStartLine(node) << ",\n"; + ss << wbString_quote("end_line") << ":" << wbTimerNode_getEndLine(node) + << ",\n"; + ss << wbString_quote("start_function") << ":" + << wbString_quote(wbTimerNode_getStartFunction(node)) << ",\n"; + ss << wbString_quote("end_function") << ":" + << wbString_quote(wbTimerNode_getEndFunction(node)) << ",\n"; + ss << wbString_quote("start_file") << ":" + << wbString_quote(wbTimerNode_getStartFile(node)) << ",\n"; + ss << wbString_quote("end_file") << ":" + << wbString_quote(wbTimerNode_getEndFile(node)) << ",\n"; + ss << wbString_quote("parent_id") << ":" + << wbString(wbTimerNode_hasParent(node) + ? wbTimerNode_getId(wbTimerNode_getParent(node)) + : -1) + << ",\n"; + ss << wbString_quote("message") << ":" + << wbString_quote(wbTimerNode_getMessage(node)) << "\n"; + ss << "}"; + + return ss.str(); + } +} + +static inline string wbTimerNode_toXML(wbTimerNode_t node) { + if (node == NULL) { + return ""; + } else { + stringstream ss; + + ss << "\n"; + ss << "" << wbTimerNode_getId(node) << "\n"; + ss << "" + << wbString(wbTimerNode_stoppedQ(node) ? "true" : "false") + << "\n"; + ss << "" << _nodeKind(wbTimerNode_getKind(node)) << "\n"; + ss << "" << wbTimerNode_getStartTime(node) + << "\n"; + ss << "" << wbTimerNode_getEndTime(node) << "\n"; + ss << "" << wbTimerNode_getElapsedTime(node) + << "\n"; + ss << "" << wbTimerNode_getStartLine(node) + << "\n"; + ss << "" << wbTimerNode_getEndLine(node) << "\n"; + ss << "" << wbTimerNode_getStartFunction(node) + << "\n"; + ss << "" << wbTimerNode_getEndFunction(node) + << "\n"; + ss << "" << wbTimerNode_getStartFile(node) + << "\n"; + ss << "" << wbTimerNode_getEndFile(node) << "\n"; + ss << "" + << wbString(wbTimerNode_hasParent(node) + ? wbTimerNode_getId(wbTimerNode_getParent(node)) + : -1) + << "\n"; + ss << "" << wbTimerNode_getMessage(node) << "\n"; + ss << "\n"; + + return ss.str(); + } +} + +#define wbTimer_getLength(timer) ((timer)->length) +#define wbTimer_getHead(timer) ((timer)->head) +#define wbTimer_getTail(timer) ((timer)->tail) +#define wbTimer_getStartTime(timer) ((timer)->startTime) +#define wbTimer_getEndTime(timer) ((timer)->endTime) +#define wbTimer_getElapsedTime(timer) ((timer)->elapsedTime) + +#define wbTimer_setLength(timer, val) (wbTimer_getLength(timer) = val) +#define wbTimer_setHead(timer, val) (wbTimer_getHead(timer) = val) +#define wbTimer_setTail(timer, val) (wbTimer_getTail(timer) = val) +#define wbTimer_setStartTime(node, val) (wbTimer_getStartTime(node) = val) +#define wbTimer_setEndTime(node, val) (wbTimer_getEndTime(node) = val) +#define wbTimer_setElapsedTime(node, val) \ + (wbTimer_getElapsedTime(node) = val) + +#define wbTimer_incrementLength(timer) (wbTimer_getLength(timer)++) +#define wbTimer_decrementLength(timer) (wbTimer_getLength(timer)--) + +#define wbTimer_emptyQ(timer) (wbTimer_getLength(timer) == 0) + +void wbTimer_delete(wbTimer_t timer) { + if (timer != NULL) { + wbTimerNode_t tmp, iter; + + iter = wbTimer_getHead(timer); + while (iter) { + tmp = wbTimerNode_getNext(iter); + wbTimerNode_delete(iter); + iter = tmp; + } + + wbDelete(timer); + } +} + +static json11::Json wbTimer_toJSONObject(wbTimer_t timer) { + + stringstream ss; + wbTimerNode_t iter; + uint64_t currentTime; + std::vector elems; + + currentTime = getTime(); + + wbTimer_setEndTime(timer, currentTime); + wbTimer_setElapsedTime(timer, currentTime - wbTimer_getStartTime(timer)); + + for (iter = wbTimer_getHead(timer); iter != NULL; + iter = wbTimerNode_getNext(iter)) { + if (!wbTimerNode_stoppedQ(iter)) { + wbTimerNode_setEndTime(iter, currentTime); + wbTimerNode_setElapsedTime(iter, currentTime - + wbTimerNode_getStartTime(iter)); + } + elems.push_back(wbTimerNode_toJSONObject(iter)); + } + return json11::Json(elems); +} + +string wbTimer_toJSON(wbTimer_t timer) { + if (timer == NULL) { + return ""; + } else if (WB_USE_JSON11) { + json11::Json json = wbTimer_toJSONObject(timer); + return json.string_value(); + } else { + stringstream ss; + wbTimerNode_t iter; + uint64_t currentTime; + + currentTime = getTime(); + + wbTimer_setEndTime(timer, currentTime); + wbTimer_setElapsedTime(timer, + currentTime - wbTimer_getStartTime(timer)); + + for (iter = wbTimer_getHead(timer); iter != NULL; + iter = wbTimerNode_getNext(iter)) { + if (!wbTimerNode_stoppedQ(iter)) { + wbTimerNode_setEndTime(iter, currentTime); + wbTimerNode_setElapsedTime( + iter, currentTime - wbTimerNode_getStartTime(iter)); + } + ss << wbTimerNode_toJSON(iter); + if (wbTimerNode_getNext(iter) != NULL) { + ss << ",\n"; + } + } + + return ss.str(); + } +} + +string wbTimer_toJSON() { + return wbTimer_toJSON(_timer); +} + +string wbTimer_toXML(wbTimer_t timer) { + if (timer == NULL) { + return ""; + } else { + stringstream ss; + wbTimerNode_t iter; + uint64_t currentTime; + + currentTime = getTime(); + + wbTimer_setEndTime(timer, currentTime); + wbTimer_setElapsedTime(timer, + currentTime - wbTimer_getStartTime(timer)); + + ss << "\n"; + ss << "" << wbTimer_getStartTime(timer) + << "\n"; + ss << "" << wbTimer_getEndTime(timer) << "\n"; + ss << "" << wbTimer_getElapsedTime(timer) + << "\n"; + ss << "\n"; + for (iter = wbTimer_getHead(timer); iter != NULL; + iter = wbTimerNode_getNext(iter)) { + if (!wbTimerNode_stoppedQ(iter)) { + wbTimerNode_setEndTime(iter, currentTime); + wbTimerNode_setElapsedTime( + iter, currentTime - wbTimerNode_getStartTime(iter)); + } + ss << wbTimerNode_toXML(iter); + } + ss << "\n"; + ss << "\n"; + + return ss.str(); + } +} + +string wbTimer_toXML() { + return wbTimer_toXML(_timer); +} + +wbTimer_t wbTimer_new(void) { + wbTimer_t timer = wbNew(struct st_wbTimer_t); + wbTimer_setLength(timer, 0); + wbTimer_setHead(timer, NULL); + wbTimer_setTail(timer, NULL); + wbTimer_setStartTime(timer, getTime()); + wbTimer_setEndTime(timer, 0); + wbTimer_setElapsedTime(timer, 0); + + return timer; +} + +static inline wbTimerNode_t _findParent(wbTimer_t timer) { + wbTimerNode_t iter; + + for (iter = wbTimer_getTail(timer); iter != NULL; + iter = wbTimerNode_getPrevious(iter)) { + if (!wbTimerNode_stoppedQ(iter)) { + return iter; + } + } + return NULL; +} + +static inline void _insertIntoList(wbTimer_t timer, wbTimerNode_t node) { + if (wbTimer_emptyQ(timer)) { + wbTimer_setHead(timer, node); + wbTimer_setTail(timer, node); + } else { + wbTimerNode_t end = wbTimer_getTail(timer); + wbTimer_setTail(timer, node); + wbTimerNode_setNext(end, node); + wbTimerNode_setPrevious(node, end); + } + wbTimer_incrementLength(timer); +} + +wbTimerNode_t wbTimer_start(wbTimerKind_t kind, const char *file, + const char *fun, int line) { + int id; + uint64_t currentTime; + wbTimerNode_t node; + wbTimerNode_t parent; + + wb_init(NULL, NULL); + + currentTime = getTime(); + + id = wbTimer_getLength(_timer); + + node = wbTimerNode_new(id, kind, file, fun, line); + + parent = _findParent(_timer); + _insertIntoList(_timer, node); + + wbTimerNode_setStartTime(node, currentTime); + wbTimerNode_setParent(node, parent); + if (parent != NULL) { + wbTimerNode_setLevel(node, wbTimerNode_getLevel(parent) + 1); + } + + return node; +} + +wbTimerNode_t wbTimer_start(wbTimerKind_t kind, string msg, + const char *file, const char *fun, int line) { + wbTimerNode_t node = wbTimer_start(kind, file, fun, line); + wbTimerNode_setMessage(node, wbString_duplicate(msg)); + return node; +} + +static inline wbTimerNode_t _findNode(wbTimer_t timer, wbTimerKind_t kind, + string msg) { + wbTimerNode_t iter; + + for (iter = wbTimer_getTail(timer); iter != NULL; + iter = wbTimerNode_getPrevious(iter)) { + if (msg == "") { + if (!wbTimerNode_stoppedQ(iter) && + wbTimerNode_getKind(iter) == kind) { + return iter; + } + } else { + if (!wbTimerNode_stoppedQ(iter) && + wbTimerNode_getKind(iter) == kind && + msg == wbTimerNode_getMessage(iter)) { + return iter; + } + } + } + return NULL; +} + +void wbTimer_stop(wbTimerKind_t kind, string msg, const char *file, + const char *fun, int line) { + uint64_t currentTime; + wbTimerNode_t node; + + currentTime = getTime(); + + node = _findNode(_timer, kind, msg); + + wbAssert(node != NULL); + if (node == NULL) { + return; + } + + wbTimerNode_setEndTime(node, currentTime); + wbTimerNode_setElapsedTime(node, + currentTime - wbTimerNode_getStartTime(node)); + wbTimerNode_setEndLine(node, line); + wbTimerNode_setEndFunction(node, fun); + wbTimerNode_setEndFile(node, file); + wbTimerNode_setStoppedQ(node, wbTrue); + +#ifdef wbLogger_printOnLog + if (wbLogger_printOnLog) { + json11::Json json = json11::Json::object{ +//PMO +#ifndef _MSC_VER + { "type", "timer" }, { "data", wbTimerNode_toJSONObject(node) }}; +#else + { "data", wbTimerNode_toJSONObject(node) }, { "type", "timer" }}; +#endif + std::cout << json.dump() << std::endl; + } +#endif /* wbLogger_printOnLog */ + return; +} + +void wbTimer_stop(wbTimerKind_t kind, const char *file, const char *fun, + int line) { + wbTimer_stop(kind, "", file, fun, line); +} diff --git a/CUDA_Convolution/libwb/wbTimer.h b/CUDA_Convolution/libwb/wbTimer.h new file mode 100644 index 0000000..133b58f --- /dev/null +++ b/CUDA_Convolution/libwb/wbTimer.h @@ -0,0 +1,139 @@ + + +#ifndef __WB_TIMER_H__ +#define __WB_TIMER_H__ + +#ifdef WB_USE_WINDOWS +extern uint64_t _hrtime_frequency; +#endif /* _WIN32 */ + +extern wbTimer_t _timer; + +typedef enum en_wbTimerKind_t { + wbTimerKind_Generic, + wbTimerKind_IO, + wbTimerKind_GPU, + wbTimerKind_Copy, + wbTimerKind_Driver, + wbTimerKind_CopyAsync, + wbTimerKind_Compute, + wbTimerKind_CPUGPUOverlap, +} wbTimerKind_t; + +struct st_wbTimerNode_t { + int id; + int mpiRank; + int level; + wbBool stoppedQ; + wbTimerKind_t kind; + uint64_t startTime; + uint64_t endTime; + uint64_t elapsedTime; + int startLine; + int endLine; + const char *startFunction; + const char *endFunction; + const char *startFile; + const char *endFile; + wbTimerNode_t next; + wbTimerNode_t prev; + wbTimerNode_t parent; + char *msg; +}; + +struct st_wbTimer_t { + size_t length; + wbTimerNode_t head; + wbTimerNode_t tail; + uint64_t startTime; + uint64_t endTime; + uint64_t elapsedTime; +}; + +#define wbTimerNode_getId(node) ((node)->id) +#define wbTimerNode_getMPIRank(node) ((node)->mpiRank) +#define wbTimerNode_getLevel(node) ((node)->level) +#define wbTimerNode_getStoppedQ(node) ((node)->stoppedQ) +#define wbTimerNode_getKind(node) ((node)->kind) +#define wbTimerNode_getStartTime(node) ((node)->startTime) +#define wbTimerNode_getEndTime(node) ((node)->endTime) +#define wbTimerNode_getElapsedTime(node) ((node)->elapsedTime) +#define wbTimerNode_getStartLine(node) ((node)->startLine) +#define wbTimerNode_getEndLine(node) ((node)->endLine) +#define wbTimerNode_getStartFunction(node) ((node)->startFunction) +#define wbTimerNode_getEndFunction(node) ((node)->endFunction) +#define wbTimerNode_getStartFile(node) ((node)->startFile) +#define wbTimerNode_getEndFile(node) ((node)->endFile) +#define wbTimerNode_getNext(node) ((node)->next) +#define wbTimerNode_getPrevious(node) ((node)->prev) +#define wbTimerNode_getParent(node) ((node)->parent) +#define wbTimerNode_getMessage(node) ((node)->msg) + +#define wbTimerNode_setId(node, val) (wbTimerNode_getId(node) = val) +#define wbTimerNode_setMPIRank(node, val) \ + (wbTimerNode_getMPIRank(node) = val) +#define wbTimerNode_setLevel(node, val) (wbTimerNode_getLevel(node) = val) +#define wbTimerNode_setStoppedQ(node, val) \ + (wbTimerNode_getStoppedQ(node) = val) +#define wbTimerNode_setKind(node, val) (wbTimerNode_getKind(node) = val) +#define wbTimerNode_setStartTime(node, val) \ + (wbTimerNode_getStartTime(node) = val) +#define wbTimerNode_setEndTime(node, val) \ + (wbTimerNode_getEndTime(node) = val) +#define wbTimerNode_setElapsedTime(node, val) \ + (wbTimerNode_getElapsedTime(node) = val) +#define wbTimerNode_setStartLine(node, val) \ + (wbTimerNode_getStartLine(node) = val) +#define wbTimerNode_setEndLine(node, val) \ + (wbTimerNode_getEndLine(node) = val) +#define wbTimerNode_setStartFunction(node, val) \ + (wbTimerNode_getStartFunction(node) = val) +#define wbTimerNode_setEndFunction(node, val) \ + (wbTimerNode_getEndFunction(node) = val) +#define wbTimerNode_setStartFile(node, val) \ + (wbTimerNode_getStartFile(node) = val) +#define wbTimerNode_setEndFile(node, val) \ + (wbTimerNode_getEndFile(node) = val) +#define wbTimerNode_setNext(node, val) (wbTimerNode_getNext(node) = val) +#define wbTimerNode_setPrevious(node, val) \ + (wbTimerNode_getPrevious(node) = val) +#define wbTimerNode_setParent(node, val) \ + (wbTimerNode_getParent(node) = val) +#define wbTimerNode_setMessage(node, val) \ + (wbTimerNode_getMessage(node) = val) + +#define wbTimerNode_stoppedQ(node) \ + (wbTimerNode_getStoppedQ(node) == wbTrue) +#define wbTimerNode_hasNext(node) (wbTimerNode_getNext(node) != NULL) +#define wbTimerNode_hasPrevious(node) \ + (wbTimerNode_getPrevious(node) != NULL) +#define wbTimerNode_hasParent(node) (wbTimerNode_getParent(node) != NULL) + +uint64_t _hrtime(void); + +wbTimer_t wbTimer_new(void); +void wbTimer_delete(wbTimer_t timer); + +string wbTimer_toJSON(wbTimer_t timer); +string wbTimer_toJSON(); + +string wbTimer_toXML(wbTimer_t timer); +string wbTimer_toXML(); + +wbTimerNode_t wbTimer_start(wbTimerKind_t kind, const char *file, + const char *fun, int line); +wbTimerNode_t wbTimer_start(wbTimerKind_t kind, string msg, + const char *file, const char *fun, int line); +void wbTimer_stop(wbTimerKind_t kind, string msg, const char *file, + const char *fun, int line); +void wbTimer_stop(wbTimerKind_t kind, const char *file, const char *fun, + int line); + +#define wbTime_start(kind, ...) \ + wbTimer_start(wbTimerKind_##kind, wbString(__VA_ARGS__), wbFile, \ + wbFunction, wbLine) +#define wbTime_stop(kind, ...) \ + wbTimer_stop(wbTimerKind_##kind, wbString(__VA_ARGS__), wbFile, \ + wbFunction, wbLine) + +#endif /* __WB_TIMER_H__ */ diff --git a/CUDA_Convolution/libwb/wbTypes.h b/CUDA_Convolution/libwb/wbTypes.h new file mode 100644 index 0000000..6837792 --- /dev/null +++ b/CUDA_Convolution/libwb/wbTypes.h @@ -0,0 +1,55 @@ + + +#ifndef __WB_TYPES_H__ +#define __WB_TYPES_H__ + +#include "wbAssert.h" + +typedef bool wbBool; +typedef float wbReal_t; +typedef char wbChar_t; + +typedef struct st_wbTimerNode_t *wbTimerNode_t; +typedef struct st_wbTimer_t *wbTimer_t; +typedef struct st_wbLogEntry_t *wbLogEntry_t; +typedef struct st_wbLogger_t *wbLogger_t; +typedef struct st_wbArg_t wbArg_t; +typedef struct st_wbImage_t *wbImage_t; +typedef struct st_wbFile_t *wbFile_t; + +#define wbTrue true +#define wbFalse false + +typedef enum en_wbType_t { + wbType_unknown = -1, + wbType_ascii = 1, + wbType_bit8, + wbType_ubit8, + wbType_integer, + wbType_float, + wbType_double +} wbType_t; + +static inline size_t wbType_size(wbType_t ty) { + switch (ty) { + case wbType_unknown: + wbAssert(false && "Invalid wbType_unknown"); + return 0; + case wbType_ascii: + return sizeof(char); + case wbType_bit8: + return sizeof(char); + case wbType_ubit8: + return sizeof(unsigned char); + case wbType_integer: + return sizeof(int); + case wbType_float: + return sizeof(float); + case wbType_double: + return sizeof(double); + } + wbAssert(false && "Invalid type"); + return 0; +} + +#endif /* __WB_TYPES_H__ */ diff --git a/CUDA_Convolution/libwb/wbUtils.h b/CUDA_Convolution/libwb/wbUtils.h new file mode 100644 index 0000000..cbd1b91 --- /dev/null +++ b/CUDA_Convolution/libwb/wbUtils.h @@ -0,0 +1,10 @@ +#ifndef __WB_UTILS_H__ +#define __WB_UTILS_H__ + +#ifdef WB_DEBUG +#define DEBUG(...) __VA_ARGS__ +#else /* WB_DEBUG */ +#define DEBUG(...) +#endif /* WB_DEBUG */ + +#endif /* __WB_UTILS_H__ */ diff --git a/CUDA_Convolution/libwb/wb_test.cpp b/CUDA_Convolution/libwb/wb_test.cpp new file mode 100644 index 0000000..87883c8 --- /dev/null +++ b/CUDA_Convolution/libwb/wb_test.cpp @@ -0,0 +1,4 @@ +#define CATCH_CONFIG_MAIN + +#include "wb.h" +#include "vendor/catch.hpp" diff --git a/CUDA_DeviceQuery/DeviceQuery/template.cu b/CUDA_DeviceQuery/DeviceQuery/template.cu new file mode 100644 index 0000000..d74754f --- /dev/null +++ b/CUDA_DeviceQuery/DeviceQuery/template.cu @@ -0,0 +1,54 @@ +#include + +int main(int argc, char **argv) { + int deviceCount; + + wbArg_read(argc, argv); + + cudaGetDeviceCount(&deviceCount); + + wbTime_start(GPU, "Getting GPU Data."); //@@ start a timer + + for (int dev = 0; dev < deviceCount; dev++) { + cudaDeviceProp deviceProp; + + cudaGetDeviceProperties(&deviceProp, dev); + + if (dev == 0) { + if (deviceProp.major == 9999 && deviceProp.minor == 9999) { + wbLog(TRACE, "No CUDA GPU has been detected"); + return -1; + } else if (deviceCount == 1) { + //@@ WbLog is a provided logging API (similar to Log4J). + //@@ The logging function wbLog takes a level which is either + //@@ OFF, FATAL, ERROR, WARN, INFO, DEBUG, or TRACE and a + //@@ message to be printed. + wbLog(TRACE, "There is 1 device supporting CUDA"); + } else { + wbLog(TRACE, "There are ", deviceCount, + " devices supporting CUDA"); + } + } + + wbLog(TRACE, "Device ", dev, " name: ", deviceProp.name); + wbLog(TRACE, " Computational Capabilities: ", deviceProp.major, ".", + deviceProp.minor); + wbLog(TRACE, " Maximum global memory size: ", + deviceProp.totalGlobalMem); + wbLog(TRACE, " Maximum constant memory size: ", + deviceProp.totalConstMem); + wbLog(TRACE, " Maximum shared memory size per block: ", + deviceProp.sharedMemPerBlock); + wbLog(TRACE, " Maximum block dimensions: ", + deviceProp.maxThreadsDim[0], " x ", deviceProp.maxThreadsDim[1], + " x ", deviceProp.maxThreadsDim[2]); + wbLog(TRACE, " Maximum grid dimensions: ", deviceProp.maxGridSize[0], + " x ", deviceProp.maxGridSize[1], " x ", + deviceProp.maxGridSize[2]); + wbLog(TRACE, " Warp size: ", deviceProp.warpSize); + } + + wbTime_stop(GPU, "Getting GPU Data."); //@@ stop the timer + //system("Pause"); + return 0; +} diff --git a/CUDA_DeviceQuery/libwb/.clang-format b/CUDA_DeviceQuery/libwb/.clang-format new file mode 100644 index 0000000..4757ed4 --- /dev/null +++ b/CUDA_DeviceQuery/libwb/.clang-format @@ -0,0 +1,21 @@ +--- +Language: Cpp +BasedOnStyle: LLVM +ColumnLimit: 75 +AccessModifierOffset: -2 +BreakBeforeBraces: Attach +AlignTrailingComments: true +AlignEscapedNewlinesLeft: false +AlignConsecutiveAssignments: true +AlignOperands: true +AllowShortFunctionsOnASingleLine: false +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AlwaysBreakTemplateDeclarations: true +IndentCaseLabels: true +SpacesBeforeTrailingComments: 1 +Standard: Cpp11 +TabWidth: 4 +UseTab: Never +SortIncludes: false +... diff --git a/CUDA_DeviceQuery/libwb/.travis.yml b/CUDA_DeviceQuery/libwb/.travis.yml new file mode 100644 index 0000000..e32c621 --- /dev/null +++ b/CUDA_DeviceQuery/libwb/.travis.yml @@ -0,0 +1,65 @@ +# Use new trusty images, should yield newer compilers and packages +sudo: required +dist: precise +language: cpp + +matrix: + include: + - compiler: gcc + addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - g++-4.9 + env: COMPILER=g++-4.9 + - compiler: gcc + addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - g++-5 + env: COMPILER=g++-5 + - compiler: clang + addons: + apt: + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-precise-3.6 + packages: + - clang-3.6 + env: COMPILER=clang++-3.6 + - compiler: clang + addons: + apt: + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-precise-3.7 + packages: + - clang-3.7 + env: COMPILER=clang++-3.7 +# - compiler: gcc +# addons: +# apt: +# sources: +# - ubuntu-toolchain-r-test +# packages: +# - g++-6 +# env: COMPILER=g++-6 + # - compiler: clang + # addons: + # apt: + # sources: + # - ubuntu-toolchain-r-test + # - llvm-toolchain-precise-3.8 + # packages: + # - clang-3.8 + # env: COMPILER=clang++-3.8 + +before_install: + - sudo apt-get update -qq +script: + - $COMPILER --version + - make CXX=$COMPILER test + - ./test diff --git a/CUDA_DeviceQuery/libwb/CMakeLists.txt b/CUDA_DeviceQuery/libwb/CMakeLists.txt new file mode 100644 index 0000000..f732c32 --- /dev/null +++ b/CUDA_DeviceQuery/libwb/CMakeLists.txt @@ -0,0 +1,34 @@ +cmake_minimum_required(VERSION 2.8 FATAL_ERROR) + +set(CMAKE_BUILD_TYPE Release) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) +set(CMAKE_COLOR_MAKEFILE ON) +set(VERBOSE_BUILD ON) +set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) +set(CMAKE_MACOSX_RPATH TRUE) +set_property(GLOBAL PROPERTY USE_FOLDERS ON) + + +project(wb) + +set(current_dir "${CMAKE_CURRENT_SOURCE_DIR}") + +if(NOT EXISTS "${CMAKE_CURRENT_BINARY_DIR}/cotire.cmake") + file(DOWNLOAD "https://raw.githubusercontent.com/sakra/cotire/master/CMake/cotire.cmake" "${CMAKE_CURRENT_BINARY_DIR}/cotire.cmake") +endif() + + + +include(${current_dir}/sources.cmake) + +set(WBLIB_STATIC ${WBLIB}) +set(WBLIB_SHARED lib${WBLIB}) + +add_library(${WBLIB_STATIC} STATIC ${LIBWB_SOURCE_FILES} ) +add_library(${WBLIB_SHARED} SHARED ${LIBWB_SOURCE_FILES} ) +set_property(TARGET ${WBLIB_STATIC} PROPERTY CXX_STANDARD 11) +set_property(TARGET ${WBLIB_SHARED} PROPERTY CXX_STANDARD 11) +if (UNIX) + set_target_properties(${WBLIB_SHARED} PROPERTIES OUTPUT_NAME ${WBLIB_STATIC}) +endif (UNIX) +set_property(TARGET ${WBLIB} PROPERTY CXX_STANDARD 11) diff --git a/CUDA_DeviceQuery/libwb/LICENSE.TXT b/CUDA_DeviceQuery/libwb/LICENSE.TXT new file mode 100644 index 0000000..8df244d --- /dev/null +++ b/CUDA_DeviceQuery/libwb/LICENSE.TXT @@ -0,0 +1,36 @@ +Copyright (c) 2016, Abdul Dakkak All rights reserved. + +Developed by: Abdul Dakkak + IMPACT Group + University of Illinois, Urbana-Champaign + impact.crhc.illinois.edu + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal with the +Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, +sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +Redistributions of source code must retain the above +copyright notice, this list of conditions and the following +disclaimers. +Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following +disclaimers in the documentation and/or other materials +provided with the distribution. +Neither the names of Abdul Dakkak, Impact Group, nor the +names of its contributors may be used to endorse or promote +products derived from this Software without specific prior +written permission. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +WITH THE SOFTWARE. diff --git a/CUDA_DeviceQuery/libwb/Makefile b/CUDA_DeviceQuery/libwb/Makefile new file mode 100644 index 0000000..b8a72d7 --- /dev/null +++ b/CUDA_DeviceQuery/libwb/Makefile @@ -0,0 +1,56 @@ +########################################## +# Options +########################################## +WB_LIB_PATH=$(CURDIR)/lib +WB_SRC_PATH=$(CURDIR) + +########################################## +########################################## + +DEFINES= +CXX_FLAGS=-fPIC -Wno-unused-function -x c++ -O3 -g -std=c++11 -Wall -Wno-unused-function -pedantic -I . -I $(WB_SRC_PATH) $(DEFINES) +LIBS=-lm -lstdc++ + +########################################## +########################################## + +UNAME_S := $(shell uname -s) +ifeq ($(UNAME_S),Linux) + LIBS += -lrt +endif + +########################################## +########################################## + +SOURCES := $(shell find $(WB_SRC_PATH) ! -name "*_test.cpp" -name "*.cpp") +TESTS := $(shell find $(WB_SRC_PATH) -name "*_test.cpp") + +OBJECTS = $(SOURCES:.cpp=.o) +TESTOBJECTS = $(TESTS:.cpp=.o) + +############################################## +# OUTPUT +############################################## + +.PHONY: all +.SUFFIXES: .o .cpp +all: libwb.so + +.cpp.o: + $(CXX) $(DEFINES) $(CXX_FLAGS) -c -o $@ $< + +libwb.so: $(OBJECTS) + mkdir -p $(WB_LIB_PATH) + $(CXX) -fPIC -shared -o $(WB_LIB_PATH)/$@ $(OBJECTS) $(LIBS) + +libwb.a: $(OBJECTS) + mkdir -p $(WB_LIB_PATH) + ar rcs -o $(WB_LIB_PATH)/$@ $(OBJECTS) + +test: $(TESTOBJECTS) $(OBJECTS) + $(CXX) -fPIC -o $@ $(TESTOBJECTS) $(OBJECTS) $(LIBS) + + +clean: + rm -fr $(ARCH) + -rm -f $(EXES) *.o *~ \ No newline at end of file diff --git a/CUDA_DeviceQuery/libwb/README.md b/CUDA_DeviceQuery/libwb/README.md new file mode 100644 index 0000000..0486f93 --- /dev/null +++ b/CUDA_DeviceQuery/libwb/README.md @@ -0,0 +1,7 @@ + +# libWB + +[![Travis Build Status](https://travis-ci.org/abduld/libwb.svg?branch=master)](https://travis-ci.org/abduld/libwb) +[![AppVeyor status](https://ci.appveyor.com/api/projects/status/0nx5ie7gn5c0e6ai/branch/master?svg=true)](https://ci.appveyor.com/project/abduld/libwb/branch/master) + \ No newline at end of file diff --git a/CUDA_DeviceQuery/libwb/appveyor.yml b/CUDA_DeviceQuery/libwb/appveyor.yml new file mode 100644 index 0000000..e7a6c95 --- /dev/null +++ b/CUDA_DeviceQuery/libwb/appveyor.yml @@ -0,0 +1,54 @@ + + +# Operating system (build VM template) +os: + - Visual Studio 2015 + + +# scripts that are called at very beginning, before repo cloning +init: + - echo init step + - git config --global core.autocrlf input + - cmake --version + - C:\"Program Files (x86)"\"Microsoft Visual Studio 14.0"\VC\vcvarsall.bat %PLATFORM% + +# clone directory +clone_folder: c:\projects\libwb +# fetch repository as zip archive +shallow_clone: true # default is "false" + +# branches to build +branches: + # whitelist + only: + - master + +platform: + - x64 +configuration: + - Release + +environment: + P: "c:/projects/libs" + + +install: + # by default, all script lines are interpreted as batch + +build: + project: ALL_BUILD.vcxproj # path to Visual Studio solution or project + +# scripts to run before build +before_build: + - echo Running cmake... + - cd c:\projects\libwb + - cmake -G "Visual Studio 14 2015 Win64" -DCMAKE_INSTALL_PREFIX=%P% + +# after_build: +# - echo after_build step + + +# on_finish always executes regardless of passed or failed builds +# on_finish: +# - echo on_finish step +# - ps: ls \ No newline at end of file diff --git a/CUDA_DeviceQuery/libwb/sources.cmake b/CUDA_DeviceQuery/libwb/sources.cmake new file mode 100644 index 0000000..4ac1b10 --- /dev/null +++ b/CUDA_DeviceQuery/libwb/sources.cmake @@ -0,0 +1,31 @@ + +set(WBLIB "wb") + +include_directories(${CMAKE_CURRENT_LIST_DIR}) + +file(GLOB THESE_CPP_FILES + ${CMAKE_CURRENT_LIST_DIR}/*.cpp +) + +file(GLOB THESE_TEST_FILES + ${CMAKE_CURRENT_LIST_DIR}/*_test.cpp +) + +list(REMOVE_ITEM THESE_CPP_FILES ${THESE_TEST_FILES}) + +file(GLOB THESE_HEADER_FILES + ${CMAKE_CURRENT_LIST_DIR}/*.h +) + +list(APPEND LIBWB_HEADER_FILES + ${THESE_HEADER_FILES} +) + +list(APPEND LIBWB_SOURCE_FILES + ${THESE_CPP_FILES} + ${CMAKE_CURRENT_LIST_DIR}/vendor/json11.cpp +) + +list(APPEND LIBWB_TEST_FILES + ${THESE_TEST_FILES} +) diff --git a/CUDA_DeviceQuery/libwb/vendor/catch.hpp b/CUDA_DeviceQuery/libwb/vendor/catch.hpp new file mode 100644 index 0000000..f52eebd --- /dev/null +++ b/CUDA_DeviceQuery/libwb/vendor/catch.hpp @@ -0,0 +1,10414 @@ +/* + * Catch v1.3.6 + * Generated: 2016-03-11 18:30:42.852700 + * ---------------------------------------------------------- + * This file has been merged from multiple headers. Please don't edit it directly + * Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved. + * + * Distributed under the Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + */ +#ifndef TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED +#define TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED + +#define TWOBLUECUBES_CATCH_HPP_INCLUDED + +#ifdef __clang__ +# pragma clang system_header +#elif defined __GNUC__ +# pragma GCC system_header +#endif + +// #included from: internal/catch_suppress_warnings.h + +#ifdef __clang__ +# ifdef __ICC // icpc defines the __clang__ macro +# pragma warning(push) +# pragma warning(disable: 161 1682) +# else // __ICC +# pragma clang diagnostic ignored "-Wglobal-constructors" +# pragma clang diagnostic ignored "-Wvariadic-macros" +# pragma clang diagnostic ignored "-Wc99-extensions" +# pragma clang diagnostic ignored "-Wunused-variable" +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wpadded" +# pragma clang diagnostic ignored "-Wc++98-compat" +# pragma clang diagnostic ignored "-Wc++98-compat-pedantic" +# pragma clang diagnostic ignored "-Wswitch-enum" +# pragma clang diagnostic ignored "-Wcovered-switch-default" +# endif +#elif defined __GNUC__ +# pragma GCC diagnostic ignored "-Wvariadic-macros" +# pragma GCC diagnostic ignored "-Wunused-variable" +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wpadded" +#endif +#if defined(CATCH_CONFIG_MAIN) || defined(CATCH_CONFIG_RUNNER) +# define CATCH_IMPL +#endif + +#ifdef CATCH_IMPL +# ifndef CLARA_CONFIG_MAIN +# define CLARA_CONFIG_MAIN_NOT_DEFINED +# define CLARA_CONFIG_MAIN +# endif +#endif + +// #included from: internal/catch_notimplemented_exception.h +#define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_H_INCLUDED + +// #included from: catch_common.h +#define TWOBLUECUBES_CATCH_COMMON_H_INCLUDED + +#define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line +#define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) +#define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ ) + +#define INTERNAL_CATCH_STRINGIFY2( expr ) #expr +#define INTERNAL_CATCH_STRINGIFY( expr ) INTERNAL_CATCH_STRINGIFY2( expr ) + +#include +#include +#include + +// #included from: catch_compiler_capabilities.h +#define TWOBLUECUBES_CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED + +// Detect a number of compiler features - mostly C++11/14 conformance - by compiler +// The following features are defined: +// +// CATCH_CONFIG_CPP11_NULLPTR : is nullptr supported? +// CATCH_CONFIG_CPP11_NOEXCEPT : is noexcept supported? +// CATCH_CONFIG_CPP11_GENERATED_METHODS : The delete and default keywords for compiler generated methods +// CATCH_CONFIG_CPP11_IS_ENUM : std::is_enum is supported? +// CATCH_CONFIG_CPP11_TUPLE : std::tuple is supported +// CATCH_CONFIG_CPP11_LONG_LONG : is long long supported? +// CATCH_CONFIG_CPP11_OVERRIDE : is override supported? +// CATCH_CONFIG_CPP11_UNIQUE_PTR : is unique_ptr supported (otherwise use auto_ptr) + +// CATCH_CONFIG_CPP11_OR_GREATER : Is C++11 supported? + +// CATCH_CONFIG_VARIADIC_MACROS : are variadic macros supported? + +// **************** +// Note to maintainers: if new toggles are added please document them +// in configuration.md, too +// **************** + +// In general each macro has a _NO_ form +// (e.g. CATCH_CONFIG_CPP11_NO_NULLPTR) which disables the feature. +// Many features, at point of detection, define an _INTERNAL_ macro, so they +// can be combined, en-mass, with the _NO_ forms later. + +// All the C++11 features can be disabled with CATCH_CONFIG_NO_CPP11 + +#if defined(__cplusplus) && __cplusplus >= 201103L +# define CATCH_CPP11_OR_GREATER +#endif + +#ifdef __clang__ + +# if __has_feature(cxx_nullptr) +# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR +# endif + +# if __has_feature(cxx_noexcept) +# define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT +# endif + +# if defined(CATCH_CPP11_OR_GREATER) +# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS _Pragma( "clang diagnostic ignored \"-Wparentheses\"" ) +# endif + +#endif // __clang__ + +//////////////////////////////////////////////////////////////////////////////// +// Borland +#ifdef __BORLANDC__ + +#endif // __BORLANDC__ + +//////////////////////////////////////////////////////////////////////////////// +// EDG +#ifdef __EDG_VERSION__ + +#endif // __EDG_VERSION__ + +//////////////////////////////////////////////////////////////////////////////// +// Digital Mars +#ifdef __DMC__ + +#endif // __DMC__ + +//////////////////////////////////////////////////////////////////////////////// +// GCC +#ifdef __GNUC__ + +# if __GNUC__ == 4 && __GNUC_MINOR__ >= 6 && defined(__GXX_EXPERIMENTAL_CXX0X__) +# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR +# endif + +# if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS) && defined(CATCH_CPP11_OR_GREATER) +# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS _Pragma( "GCC diagnostic ignored \"-Wparentheses\"" ) +# endif + +// - otherwise more recent versions define __cplusplus >= 201103L +// and will get picked up below + +#endif // __GNUC__ + +//////////////////////////////////////////////////////////////////////////////// +// Visual C++ +#ifdef _MSC_VER + +#if (_MSC_VER >= 1600) +# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR +# define CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR +#endif + +#if (_MSC_VER >= 1900 ) // (VC++ 13 (VS2015)) +#define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT +#define CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS +#endif + +#endif // _MSC_VER + +//////////////////////////////////////////////////////////////////////////////// + +// Use variadic macros if the compiler supports them +#if ( defined _MSC_VER && _MSC_VER > 1400 && !defined __EDGE__) || \ + ( defined __WAVE__ && __WAVE_HAS_VARIADICS ) || \ + ( defined __GNUC__ && __GNUC__ >= 3 ) || \ + ( !defined __cplusplus && __STDC_VERSION__ >= 199901L || __cplusplus >= 201103L ) + +#define CATCH_INTERNAL_CONFIG_VARIADIC_MACROS + +#endif + +//////////////////////////////////////////////////////////////////////////////// +// C++ language feature support + +// catch all support for C++11 +#if defined(CATCH_CPP11_OR_GREATER) + +# if !defined(CATCH_INTERNAL_CONFIG_CPP11_NULLPTR) +# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR +# endif + +# ifndef CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT +# define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT +# endif + +# ifndef CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS +# define CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS +# endif + +# ifndef CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM +# define CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM +# endif + +# ifndef CATCH_INTERNAL_CONFIG_CPP11_TUPLE +# define CATCH_INTERNAL_CONFIG_CPP11_TUPLE +# endif + +# ifndef CATCH_INTERNAL_CONFIG_VARIADIC_MACROS +# define CATCH_INTERNAL_CONFIG_VARIADIC_MACROS +# endif + +# if !defined(CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG) +# define CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG +# endif + +# if !defined(CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE) +# define CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE +# endif +# if !defined(CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) +# define CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR +# endif + +#endif // __cplusplus >= 201103L + +// Now set the actual defines based on the above + anything the user has configured +#if defined(CATCH_INTERNAL_CONFIG_CPP11_NULLPTR) && !defined(CATCH_CONFIG_CPP11_NO_NULLPTR) && !defined(CATCH_CONFIG_CPP11_NULLPTR) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_NULLPTR +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_CONFIG_CPP11_NO_NOEXCEPT) && !defined(CATCH_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_NOEXCEPT +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS) && !defined(CATCH_CONFIG_CPP11_NO_GENERATED_METHODS) && !defined(CATCH_CONFIG_CPP11_GENERATED_METHODS) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_GENERATED_METHODS +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM) && !defined(CATCH_CONFIG_CPP11_NO_IS_ENUM) && !defined(CATCH_CONFIG_CPP11_IS_ENUM) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_IS_ENUM +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_TUPLE) && !defined(CATCH_CONFIG_CPP11_NO_TUPLE) && !defined(CATCH_CONFIG_CPP11_TUPLE) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_TUPLE +#endif +#if defined(CATCH_INTERNAL_CONFIG_VARIADIC_MACROS) && !defined(CATCH_CONFIG_NO_VARIADIC_MACROS) && !defined(CATCH_CONFIG_VARIADIC_MACROS) +# define CATCH_CONFIG_VARIADIC_MACROS +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG) && !defined(CATCH_CONFIG_NO_LONG_LONG) && !defined(CATCH_CONFIG_CPP11_LONG_LONG) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_LONG_LONG +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE) && !defined(CATCH_CONFIG_NO_OVERRIDE) && !defined(CATCH_CONFIG_CPP11_OVERRIDE) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_OVERRIDE +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) && !defined(CATCH_CONFIG_NO_UNIQUE_PTR) && !defined(CATCH_CONFIG_CPP11_UNIQUE_PTR) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_UNIQUE_PTR +#endif + +#if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS) +# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS +#endif + +// noexcept support: +#if defined(CATCH_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_NOEXCEPT) +# define CATCH_NOEXCEPT noexcept +# define CATCH_NOEXCEPT_IS(x) noexcept(x) +#else +# define CATCH_NOEXCEPT throw() +# define CATCH_NOEXCEPT_IS(x) +#endif + +// nullptr support +#ifdef CATCH_CONFIG_CPP11_NULLPTR +# define CATCH_NULL nullptr +#else +# define CATCH_NULL NULL +#endif + +// override support +#ifdef CATCH_CONFIG_CPP11_OVERRIDE +# define CATCH_OVERRIDE override +#else +# define CATCH_OVERRIDE +#endif + +// unique_ptr support +#ifdef CATCH_CONFIG_CPP11_UNIQUE_PTR +# define CATCH_AUTO_PTR( T ) std::unique_ptr +#else +# define CATCH_AUTO_PTR( T ) std::auto_ptr +#endif + +namespace Catch { + + struct IConfig; + + struct CaseSensitive { enum Choice { + Yes, + No + }; }; + + class NonCopyable { +#ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + NonCopyable( NonCopyable const& ) = delete; + NonCopyable( NonCopyable && ) = delete; + NonCopyable& operator = ( NonCopyable const& ) = delete; + NonCopyable& operator = ( NonCopyable && ) = delete; +#else + NonCopyable( NonCopyable const& info ); + NonCopyable& operator = ( NonCopyable const& ); +#endif + + protected: + NonCopyable() {} + virtual ~NonCopyable(); + }; + + class SafeBool { + public: + typedef void (SafeBool::*type)() const; + + static type makeSafe( bool value ) { + return value ? &SafeBool::trueValue : 0; + } + private: + void trueValue() const {} + }; + + template + inline void deleteAll( ContainerT& container ) { + typename ContainerT::const_iterator it = container.begin(); + typename ContainerT::const_iterator itEnd = container.end(); + for(; it != itEnd; ++it ) + delete *it; + } + template + inline void deleteAllValues( AssociativeContainerT& container ) { + typename AssociativeContainerT::const_iterator it = container.begin(); + typename AssociativeContainerT::const_iterator itEnd = container.end(); + for(; it != itEnd; ++it ) + delete it->second; + } + + bool startsWith( std::string const& s, std::string const& prefix ); + bool endsWith( std::string const& s, std::string const& suffix ); + bool contains( std::string const& s, std::string const& infix ); + void toLowerInPlace( std::string& s ); + std::string toLower( std::string const& s ); + std::string trim( std::string const& str ); + bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ); + + struct pluralise { + pluralise( std::size_t count, std::string const& label ); + + friend std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ); + + std::size_t m_count; + std::string m_label; + }; + + struct SourceLineInfo { + + SourceLineInfo(); + SourceLineInfo( char const* _file, std::size_t _line ); + SourceLineInfo( SourceLineInfo const& other ); +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + SourceLineInfo( SourceLineInfo && ) = default; + SourceLineInfo& operator = ( SourceLineInfo const& ) = default; + SourceLineInfo& operator = ( SourceLineInfo && ) = default; +# endif + bool empty() const; + bool operator == ( SourceLineInfo const& other ) const; + bool operator < ( SourceLineInfo const& other ) const; + + std::string file; + std::size_t line; + }; + + std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ); + + // This is just here to avoid compiler warnings with macro constants and boolean literals + inline bool isTrue( bool value ){ return value; } + inline bool alwaysTrue() { return true; } + inline bool alwaysFalse() { return false; } + + void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo ); + + void seedRng( IConfig const& config ); + unsigned int rngSeed(); + + // Use this in variadic streaming macros to allow + // >> +StreamEndStop + // as well as + // >> stuff +StreamEndStop + struct StreamEndStop { + std::string operator+() { + return std::string(); + } + }; + template + T const& operator + ( T const& value, StreamEndStop ) { + return value; + } +} + +#define CATCH_INTERNAL_LINEINFO ::Catch::SourceLineInfo( __FILE__, static_cast( __LINE__ ) ) +#define CATCH_INTERNAL_ERROR( msg ) ::Catch::throwLogicError( msg, CATCH_INTERNAL_LINEINFO ); + +#include + +namespace Catch { + + class NotImplementedException : public std::exception + { + public: + NotImplementedException( SourceLineInfo const& lineInfo ); + NotImplementedException( NotImplementedException const& ) {} + + virtual ~NotImplementedException() CATCH_NOEXCEPT {} + + virtual const char* what() const CATCH_NOEXCEPT; + + private: + std::string m_what; + SourceLineInfo m_lineInfo; + }; + +} // end namespace Catch + +/////////////////////////////////////////////////////////////////////////////// +#define CATCH_NOT_IMPLEMENTED throw Catch::NotImplementedException( CATCH_INTERNAL_LINEINFO ) + +// #included from: internal/catch_context.h +#define TWOBLUECUBES_CATCH_CONTEXT_H_INCLUDED + +// #included from: catch_interfaces_generators.h +#define TWOBLUECUBES_CATCH_INTERFACES_GENERATORS_H_INCLUDED + +#include + +namespace Catch { + + struct IGeneratorInfo { + virtual ~IGeneratorInfo(); + virtual bool moveNext() = 0; + virtual std::size_t getCurrentIndex() const = 0; + }; + + struct IGeneratorsForTest { + virtual ~IGeneratorsForTest(); + + virtual IGeneratorInfo& getGeneratorInfo( std::string const& fileInfo, std::size_t size ) = 0; + virtual bool moveNext() = 0; + }; + + IGeneratorsForTest* createGeneratorsForTest(); + +} // end namespace Catch + +// #included from: catch_ptr.hpp +#define TWOBLUECUBES_CATCH_PTR_HPP_INCLUDED + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpadded" +#endif + +namespace Catch { + + // An intrusive reference counting smart pointer. + // T must implement addRef() and release() methods + // typically implementing the IShared interface + template + class Ptr { + public: + Ptr() : m_p( CATCH_NULL ){} + Ptr( T* p ) : m_p( p ){ + if( m_p ) + m_p->addRef(); + } + Ptr( Ptr const& other ) : m_p( other.m_p ){ + if( m_p ) + m_p->addRef(); + } + ~Ptr(){ + if( m_p ) + m_p->release(); + } + void reset() { + if( m_p ) + m_p->release(); + m_p = CATCH_NULL; + } + Ptr& operator = ( T* p ){ + Ptr temp( p ); + swap( temp ); + return *this; + } + Ptr& operator = ( Ptr const& other ){ + Ptr temp( other ); + swap( temp ); + return *this; + } + void swap( Ptr& other ) { std::swap( m_p, other.m_p ); } + T* get() const{ return m_p; } + T& operator*() const { return *m_p; } + T* operator->() const { return m_p; } + bool operator !() const { return m_p == CATCH_NULL; } + operator SafeBool::type() const { return SafeBool::makeSafe( m_p != CATCH_NULL ); } + + private: + T* m_p; + }; + + struct IShared : NonCopyable { + virtual ~IShared(); + virtual void addRef() const = 0; + virtual void release() const = 0; + }; + + template + struct SharedImpl : T { + + SharedImpl() : m_rc( 0 ){} + + virtual void addRef() const { + ++m_rc; + } + virtual void release() const { + if( --m_rc == 0 ) + delete this; + } + + mutable unsigned int m_rc; + }; + +} // end namespace Catch + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +#include +#include +#include + +namespace Catch { + + class TestCase; + class Stream; + struct IResultCapture; + struct IRunner; + struct IGeneratorsForTest; + struct IConfig; + + struct IContext + { + virtual ~IContext(); + + virtual IResultCapture* getResultCapture() = 0; + virtual IRunner* getRunner() = 0; + virtual size_t getGeneratorIndex( std::string const& fileInfo, size_t totalSize ) = 0; + virtual bool advanceGeneratorsForCurrentTest() = 0; + virtual Ptr getConfig() const = 0; + }; + + struct IMutableContext : IContext + { + virtual ~IMutableContext(); + virtual void setResultCapture( IResultCapture* resultCapture ) = 0; + virtual void setRunner( IRunner* runner ) = 0; + virtual void setConfig( Ptr const& config ) = 0; + }; + + IContext& getCurrentContext(); + IMutableContext& getCurrentMutableContext(); + void cleanUpContext(); + Stream createStream( std::string const& streamName ); + +} + +// #included from: internal/catch_test_registry.hpp +#define TWOBLUECUBES_CATCH_TEST_REGISTRY_HPP_INCLUDED + +// #included from: catch_interfaces_testcase.h +#define TWOBLUECUBES_CATCH_INTERFACES_TESTCASE_H_INCLUDED + +#include + +namespace Catch { + + class TestSpec; + + struct ITestCase : IShared { + virtual void invoke () const = 0; + protected: + virtual ~ITestCase(); + }; + + class TestCase; + struct IConfig; + + struct ITestCaseRegistry { + virtual ~ITestCaseRegistry(); + virtual std::vector const& getAllTests() const = 0; + virtual std::vector const& getAllTestsSorted( IConfig const& config ) const = 0; + }; + + bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ); + std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ); + std::vector const& getAllTestCasesSorted( IConfig const& config ); + +} + +namespace Catch { + +template +class MethodTestCase : public SharedImpl { + +public: + MethodTestCase( void (C::*method)() ) : m_method( method ) {} + + virtual void invoke() const { + C obj; + (obj.*m_method)(); + } + +private: + virtual ~MethodTestCase() {} + + void (C::*m_method)(); +}; + +typedef void(*TestFunction)(); + +struct NameAndDesc { + NameAndDesc( const char* _name = "", const char* _description= "" ) + : name( _name ), description( _description ) + {} + + const char* name; + const char* description; +}; + +void registerTestCase + ( ITestCase* testCase, + char const* className, + NameAndDesc const& nameAndDesc, + SourceLineInfo const& lineInfo ); + +struct AutoReg { + + AutoReg + ( TestFunction function, + SourceLineInfo const& lineInfo, + NameAndDesc const& nameAndDesc ); + + template + AutoReg + ( void (C::*method)(), + char const* className, + NameAndDesc const& nameAndDesc, + SourceLineInfo const& lineInfo ) { + + registerTestCase + ( new MethodTestCase( method ), + className, + nameAndDesc, + lineInfo ); + } + + ~AutoReg(); + +private: + AutoReg( AutoReg const& ); + void operator= ( AutoReg const& ); +}; + +void registerTestCaseFunction + ( TestFunction function, + SourceLineInfo const& lineInfo, + NameAndDesc const& nameAndDesc ); + +} // end namespace Catch + +#ifdef CATCH_CONFIG_VARIADIC_MACROS + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_TESTCASE( ... ) \ + static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )(); \ + namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( __VA_ARGS__ ) ); }\ + static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )() + + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \ + namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); } + + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, ... )\ + namespace{ \ + struct INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ) : ClassName{ \ + void test(); \ + }; \ + Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test, #ClassName, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); \ + } \ + void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test() + + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, ... ) \ + Catch::AutoReg( Function, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( __VA_ARGS__ ) ); + +#else + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_TESTCASE( Name, Desc ) \ + static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )(); \ + namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( Name, Desc ) ); }\ + static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )() + + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, Name, Desc ) \ + namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( Name, Desc ), CATCH_INTERNAL_LINEINFO ); } + + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, TestName, Desc )\ + namespace{ \ + struct INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ) : ClassName{ \ + void test(); \ + }; \ + Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test, #ClassName, Catch::NameAndDesc( TestName, Desc ), CATCH_INTERNAL_LINEINFO ); \ + } \ + void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test() + + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, Name, Desc ) \ + Catch::AutoReg( Function, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( Name, Desc ) ); +#endif + +// #included from: internal/catch_capture.hpp +#define TWOBLUECUBES_CATCH_CAPTURE_HPP_INCLUDED + +// #included from: catch_result_builder.h +#define TWOBLUECUBES_CATCH_RESULT_BUILDER_H_INCLUDED + +// #included from: catch_result_type.h +#define TWOBLUECUBES_CATCH_RESULT_TYPE_H_INCLUDED + +namespace Catch { + + // ResultWas::OfType enum + struct ResultWas { enum OfType { + Unknown = -1, + Ok = 0, + Info = 1, + Warning = 2, + + FailureBit = 0x10, + + ExpressionFailed = FailureBit | 1, + ExplicitFailure = FailureBit | 2, + + Exception = 0x100 | FailureBit, + + ThrewException = Exception | 1, + DidntThrowException = Exception | 2, + + FatalErrorCondition = 0x200 | FailureBit + + }; }; + + inline bool isOk( ResultWas::OfType resultType ) { + return ( resultType & ResultWas::FailureBit ) == 0; + } + inline bool isJustInfo( int flags ) { + return flags == ResultWas::Info; + } + + // ResultDisposition::Flags enum + struct ResultDisposition { enum Flags { + Normal = 0x01, + + ContinueOnFailure = 0x02, // Failures fail test, but execution continues + FalseTest = 0x04, // Prefix expression with ! + SuppressFail = 0x08 // Failures are reported but do not fail the test + }; }; + + inline ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs ) { + return static_cast( static_cast( lhs ) | static_cast( rhs ) ); + } + + inline bool shouldContinueOnFailure( int flags ) { return ( flags & ResultDisposition::ContinueOnFailure ) != 0; } + inline bool isFalseTest( int flags ) { return ( flags & ResultDisposition::FalseTest ) != 0; } + inline bool shouldSuppressFailure( int flags ) { return ( flags & ResultDisposition::SuppressFail ) != 0; } + +} // end namespace Catch + +// #included from: catch_assertionresult.h +#define TWOBLUECUBES_CATCH_ASSERTIONRESULT_H_INCLUDED + +#include + +namespace Catch { + + struct AssertionInfo + { + AssertionInfo() {} + AssertionInfo( std::string const& _macroName, + SourceLineInfo const& _lineInfo, + std::string const& _capturedExpression, + ResultDisposition::Flags _resultDisposition ); + + std::string macroName; + SourceLineInfo lineInfo; + std::string capturedExpression; + ResultDisposition::Flags resultDisposition; + }; + + struct AssertionResultData + { + AssertionResultData() : resultType( ResultWas::Unknown ) {} + + std::string reconstructedExpression; + std::string message; + ResultWas::OfType resultType; + }; + + class AssertionResult { + public: + AssertionResult(); + AssertionResult( AssertionInfo const& info, AssertionResultData const& data ); + ~AssertionResult(); +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + AssertionResult( AssertionResult const& ) = default; + AssertionResult( AssertionResult && ) = default; + AssertionResult& operator = ( AssertionResult const& ) = default; + AssertionResult& operator = ( AssertionResult && ) = default; +# endif + + bool isOk() const; + bool succeeded() const; + ResultWas::OfType getResultType() const; + bool hasExpression() const; + bool hasMessage() const; + std::string getExpression() const; + std::string getExpressionInMacro() const; + bool hasExpandedExpression() const; + std::string getExpandedExpression() const; + std::string getMessage() const; + SourceLineInfo getSourceInfo() const; + std::string getTestMacroName() const; + + protected: + AssertionInfo m_info; + AssertionResultData m_resultData; + }; + +} // end namespace Catch + +// #included from: catch_matchers.hpp +#define TWOBLUECUBES_CATCH_MATCHERS_HPP_INCLUDED + +namespace Catch { +namespace Matchers { + namespace Impl { + + namespace Generic { + template class AllOf; + template class AnyOf; + template class Not; + } + + template + struct Matcher : SharedImpl + { + typedef ExpressionT ExpressionType; + + virtual ~Matcher() {} + virtual Ptr clone() const = 0; + virtual bool match( ExpressionT const& expr ) const = 0; + virtual std::string toString() const = 0; + + Generic::AllOf operator && ( Matcher const& other ) const; + Generic::AnyOf operator || ( Matcher const& other ) const; + Generic::Not operator ! () const; + }; + + template + struct MatcherImpl : Matcher { + + virtual Ptr > clone() const { + return Ptr >( new DerivedT( static_cast( *this ) ) ); + } + }; + + namespace Generic { + template + class Not : public MatcherImpl, ExpressionT> { + public: + explicit Not( Matcher const& matcher ) : m_matcher(matcher.clone()) {} + Not( Not const& other ) : m_matcher( other.m_matcher ) {} + + virtual bool match( ExpressionT const& expr ) const CATCH_OVERRIDE { + return !m_matcher->match( expr ); + } + + virtual std::string toString() const CATCH_OVERRIDE { + return "not " + m_matcher->toString(); + } + private: + Ptr< Matcher > m_matcher; + }; + + template + class AllOf : public MatcherImpl, ExpressionT> { + public: + + AllOf() {} + AllOf( AllOf const& other ) : m_matchers( other.m_matchers ) {} + + AllOf& add( Matcher const& matcher ) { + m_matchers.push_back( matcher.clone() ); + return *this; + } + virtual bool match( ExpressionT const& expr ) const + { + for( std::size_t i = 0; i < m_matchers.size(); ++i ) + if( !m_matchers[i]->match( expr ) ) + return false; + return true; + } + virtual std::string toString() const { + std::ostringstream oss; + oss << "( "; + for( std::size_t i = 0; i < m_matchers.size(); ++i ) { + if( i != 0 ) + oss << " and "; + oss << m_matchers[i]->toString(); + } + oss << " )"; + return oss.str(); + } + + AllOf operator && ( Matcher const& other ) const { + AllOf allOfExpr( *this ); + allOfExpr.add( other ); + return allOfExpr; + } + + private: + std::vector > > m_matchers; + }; + + template + class AnyOf : public MatcherImpl, ExpressionT> { + public: + + AnyOf() {} + AnyOf( AnyOf const& other ) : m_matchers( other.m_matchers ) {} + + AnyOf& add( Matcher const& matcher ) { + m_matchers.push_back( matcher.clone() ); + return *this; + } + virtual bool match( ExpressionT const& expr ) const + { + for( std::size_t i = 0; i < m_matchers.size(); ++i ) + if( m_matchers[i]->match( expr ) ) + return true; + return false; + } + virtual std::string toString() const { + std::ostringstream oss; + oss << "( "; + for( std::size_t i = 0; i < m_matchers.size(); ++i ) { + if( i != 0 ) + oss << " or "; + oss << m_matchers[i]->toString(); + } + oss << " )"; + return oss.str(); + } + + AnyOf operator || ( Matcher const& other ) const { + AnyOf anyOfExpr( *this ); + anyOfExpr.add( other ); + return anyOfExpr; + } + + private: + std::vector > > m_matchers; + }; + + } // namespace Generic + + template + Generic::AllOf Matcher::operator && ( Matcher const& other ) const { + Generic::AllOf allOfExpr; + allOfExpr.add( *this ); + allOfExpr.add( other ); + return allOfExpr; + } + + template + Generic::AnyOf Matcher::operator || ( Matcher const& other ) const { + Generic::AnyOf anyOfExpr; + anyOfExpr.add( *this ); + anyOfExpr.add( other ); + return anyOfExpr; + } + + template + Generic::Not Matcher::operator ! () const { + return Generic::Not( *this ); + } + + namespace StdString { + + inline std::string makeString( std::string const& str ) { return str; } + inline std::string makeString( const char* str ) { return str ? std::string( str ) : std::string(); } + + struct CasedString + { + CasedString( std::string const& str, CaseSensitive::Choice caseSensitivity ) + : m_caseSensitivity( caseSensitivity ), + m_str( adjustString( str ) ) + {} + std::string adjustString( std::string const& str ) const { + return m_caseSensitivity == CaseSensitive::No + ? toLower( str ) + : str; + + } + std::string toStringSuffix() const + { + return m_caseSensitivity == CaseSensitive::No + ? " (case insensitive)" + : ""; + } + CaseSensitive::Choice m_caseSensitivity; + std::string m_str; + }; + + struct Equals : MatcherImpl { + Equals( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) + : m_data( str, caseSensitivity ) + {} + Equals( Equals const& other ) : m_data( other.m_data ){} + + virtual ~Equals(); + + virtual bool match( std::string const& expr ) const { + return m_data.m_str == m_data.adjustString( expr );; + } + virtual std::string toString() const { + return "equals: \"" + m_data.m_str + "\"" + m_data.toStringSuffix(); + } + + CasedString m_data; + }; + + struct Contains : MatcherImpl { + Contains( std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) + : m_data( substr, caseSensitivity ){} + Contains( Contains const& other ) : m_data( other.m_data ){} + + virtual ~Contains(); + + virtual bool match( std::string const& expr ) const { + return m_data.adjustString( expr ).find( m_data.m_str ) != std::string::npos; + } + virtual std::string toString() const { + return "contains: \"" + m_data.m_str + "\"" + m_data.toStringSuffix(); + } + + CasedString m_data; + }; + + struct StartsWith : MatcherImpl { + StartsWith( std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) + : m_data( substr, caseSensitivity ){} + + StartsWith( StartsWith const& other ) : m_data( other.m_data ){} + + virtual ~StartsWith(); + + virtual bool match( std::string const& expr ) const { + return startsWith( m_data.adjustString( expr ), m_data.m_str ); + } + virtual std::string toString() const { + return "starts with: \"" + m_data.m_str + "\"" + m_data.toStringSuffix(); + } + + CasedString m_data; + }; + + struct EndsWith : MatcherImpl { + EndsWith( std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) + : m_data( substr, caseSensitivity ){} + EndsWith( EndsWith const& other ) : m_data( other.m_data ){} + + virtual ~EndsWith(); + + virtual bool match( std::string const& expr ) const { + return endsWith( m_data.adjustString( expr ), m_data.m_str ); + } + virtual std::string toString() const { + return "ends with: \"" + m_data.m_str + "\"" + m_data.toStringSuffix(); + } + + CasedString m_data; + }; + } // namespace StdString + } // namespace Impl + + // The following functions create the actual matcher objects. + // This allows the types to be inferred + template + inline Impl::Generic::Not Not( Impl::Matcher const& m ) { + return Impl::Generic::Not( m ); + } + + template + inline Impl::Generic::AllOf AllOf( Impl::Matcher const& m1, + Impl::Matcher const& m2 ) { + return Impl::Generic::AllOf().add( m1 ).add( m2 ); + } + template + inline Impl::Generic::AllOf AllOf( Impl::Matcher const& m1, + Impl::Matcher const& m2, + Impl::Matcher const& m3 ) { + return Impl::Generic::AllOf().add( m1 ).add( m2 ).add( m3 ); + } + template + inline Impl::Generic::AnyOf AnyOf( Impl::Matcher const& m1, + Impl::Matcher const& m2 ) { + return Impl::Generic::AnyOf().add( m1 ).add( m2 ); + } + template + inline Impl::Generic::AnyOf AnyOf( Impl::Matcher const& m1, + Impl::Matcher const& m2, + Impl::Matcher const& m3 ) { + return Impl::Generic::AnyOf().add( m1 ).add( m2 ).add( m3 ); + } + + inline Impl::StdString::Equals Equals( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) { + return Impl::StdString::Equals( str, caseSensitivity ); + } + inline Impl::StdString::Equals Equals( const char* str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) { + return Impl::StdString::Equals( Impl::StdString::makeString( str ), caseSensitivity ); + } + inline Impl::StdString::Contains Contains( std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) { + return Impl::StdString::Contains( substr, caseSensitivity ); + } + inline Impl::StdString::Contains Contains( const char* substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) { + return Impl::StdString::Contains( Impl::StdString::makeString( substr ), caseSensitivity ); + } + inline Impl::StdString::StartsWith StartsWith( std::string const& substr ) { + return Impl::StdString::StartsWith( substr ); + } + inline Impl::StdString::StartsWith StartsWith( const char* substr ) { + return Impl::StdString::StartsWith( Impl::StdString::makeString( substr ) ); + } + inline Impl::StdString::EndsWith EndsWith( std::string const& substr ) { + return Impl::StdString::EndsWith( substr ); + } + inline Impl::StdString::EndsWith EndsWith( const char* substr ) { + return Impl::StdString::EndsWith( Impl::StdString::makeString( substr ) ); + } + +} // namespace Matchers + +using namespace Matchers; + +} // namespace Catch + +namespace Catch { + + struct TestFailureException{}; + + template class ExpressionLhs; + + struct STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison; + + struct CopyableStream { + CopyableStream() {} + CopyableStream( CopyableStream const& other ) { + oss << other.oss.str(); + } + CopyableStream& operator=( CopyableStream const& other ) { + oss.str(""); + oss << other.oss.str(); + return *this; + } + std::ostringstream oss; + }; + + class ResultBuilder { + public: + ResultBuilder( char const* macroName, + SourceLineInfo const& lineInfo, + char const* capturedExpression, + ResultDisposition::Flags resultDisposition, + char const* secondArg = "" ); + + template + ExpressionLhs operator <= ( T const& operand ); + ExpressionLhs operator <= ( bool value ); + + template + ResultBuilder& operator << ( T const& value ) { + m_stream.oss << value; + return *this; + } + + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( RhsT const& ); + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || ( RhsT const& ); + + ResultBuilder& setResultType( ResultWas::OfType result ); + ResultBuilder& setResultType( bool result ); + ResultBuilder& setLhs( std::string const& lhs ); + ResultBuilder& setRhs( std::string const& rhs ); + ResultBuilder& setOp( std::string const& op ); + + void endExpression(); + + std::string reconstructExpression() const; + AssertionResult build() const; + + void useActiveException( ResultDisposition::Flags resultDisposition = ResultDisposition::Normal ); + void captureResult( ResultWas::OfType resultType ); + void captureExpression(); + void captureExpectedException( std::string const& expectedMessage ); + void captureExpectedException( Matchers::Impl::Matcher const& matcher ); + void handleResult( AssertionResult const& result ); + void react(); + bool shouldDebugBreak() const; + bool allowThrows() const; + + private: + AssertionInfo m_assertionInfo; + AssertionResultData m_data; + struct ExprComponents { + ExprComponents() : testFalse( false ) {} + bool testFalse; + std::string lhs, rhs, op; + } m_exprComponents; + CopyableStream m_stream; + + bool m_shouldDebugBreak; + bool m_shouldThrow; + }; + +} // namespace Catch + +// Include after due to circular dependency: +// #included from: catch_expression_lhs.hpp +#define TWOBLUECUBES_CATCH_EXPRESSION_LHS_HPP_INCLUDED + +// #included from: catch_evaluate.hpp +#define TWOBLUECUBES_CATCH_EVALUATE_HPP_INCLUDED + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable:4389) // '==' : signed/unsigned mismatch +#endif + +#include + +namespace Catch { +namespace Internal { + + enum Operator { + IsEqualTo, + IsNotEqualTo, + IsLessThan, + IsGreaterThan, + IsLessThanOrEqualTo, + IsGreaterThanOrEqualTo + }; + + template struct OperatorTraits { static const char* getName(){ return "*error*"; } }; + template<> struct OperatorTraits { static const char* getName(){ return "=="; } }; + template<> struct OperatorTraits { static const char* getName(){ return "!="; } }; + template<> struct OperatorTraits { static const char* getName(){ return "<"; } }; + template<> struct OperatorTraits { static const char* getName(){ return ">"; } }; + template<> struct OperatorTraits { static const char* getName(){ return "<="; } }; + template<> struct OperatorTraits{ static const char* getName(){ return ">="; } }; + + template + inline T& opCast(T const& t) { return const_cast(t); } + +// nullptr_t support based on pull request #154 from Konstantin Baumann +#ifdef CATCH_CONFIG_CPP11_NULLPTR + inline std::nullptr_t opCast(std::nullptr_t) { return nullptr; } +#endif // CATCH_CONFIG_CPP11_NULLPTR + + // So the compare overloads can be operator agnostic we convey the operator as a template + // enum, which is used to specialise an Evaluator for doing the comparison. + template + class Evaluator{}; + + template + struct Evaluator { + static bool evaluate( T1 const& lhs, T2 const& rhs) { + return bool( opCast( lhs ) == opCast( rhs ) ); + } + }; + template + struct Evaluator { + static bool evaluate( T1 const& lhs, T2 const& rhs ) { + return bool( opCast( lhs ) != opCast( rhs ) ); + } + }; + template + struct Evaluator { + static bool evaluate( T1 const& lhs, T2 const& rhs ) { + return bool( opCast( lhs ) < opCast( rhs ) ); + } + }; + template + struct Evaluator { + static bool evaluate( T1 const& lhs, T2 const& rhs ) { + return bool( opCast( lhs ) > opCast( rhs ) ); + } + }; + template + struct Evaluator { + static bool evaluate( T1 const& lhs, T2 const& rhs ) { + return bool( opCast( lhs ) >= opCast( rhs ) ); + } + }; + template + struct Evaluator { + static bool evaluate( T1 const& lhs, T2 const& rhs ) { + return bool( opCast( lhs ) <= opCast( rhs ) ); + } + }; + + template + bool applyEvaluator( T1 const& lhs, T2 const& rhs ) { + return Evaluator::evaluate( lhs, rhs ); + } + + // This level of indirection allows us to specialise for integer types + // to avoid signed/ unsigned warnings + + // "base" overload + template + bool compare( T1 const& lhs, T2 const& rhs ) { + return Evaluator::evaluate( lhs, rhs ); + } + + // unsigned X to int + template bool compare( unsigned int lhs, int rhs ) { + return applyEvaluator( lhs, static_cast( rhs ) ); + } + template bool compare( unsigned long lhs, int rhs ) { + return applyEvaluator( lhs, static_cast( rhs ) ); + } + template bool compare( unsigned char lhs, int rhs ) { + return applyEvaluator( lhs, static_cast( rhs ) ); + } + + // unsigned X to long + template bool compare( unsigned int lhs, long rhs ) { + return applyEvaluator( lhs, static_cast( rhs ) ); + } + template bool compare( unsigned long lhs, long rhs ) { + return applyEvaluator( lhs, static_cast( rhs ) ); + } + template bool compare( unsigned char lhs, long rhs ) { + return applyEvaluator( lhs, static_cast( rhs ) ); + } + + // int to unsigned X + template bool compare( int lhs, unsigned int rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( int lhs, unsigned long rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( int lhs, unsigned char rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + + // long to unsigned X + template bool compare( long lhs, unsigned int rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( long lhs, unsigned long rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( long lhs, unsigned char rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + + // pointer to long (when comparing against NULL) + template bool compare( long lhs, T* rhs ) { + return Evaluator::evaluate( reinterpret_cast( lhs ), rhs ); + } + template bool compare( T* lhs, long rhs ) { + return Evaluator::evaluate( lhs, reinterpret_cast( rhs ) ); + } + + // pointer to int (when comparing against NULL) + template bool compare( int lhs, T* rhs ) { + return Evaluator::evaluate( reinterpret_cast( lhs ), rhs ); + } + template bool compare( T* lhs, int rhs ) { + return Evaluator::evaluate( lhs, reinterpret_cast( rhs ) ); + } + +#ifdef CATCH_CONFIG_CPP11_LONG_LONG + // long long to unsigned X + template bool compare( long long lhs, unsigned int rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( long long lhs, unsigned long rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( long long lhs, unsigned long long rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( long long lhs, unsigned char rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + + // unsigned long long to X + template bool compare( unsigned long long lhs, int rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( unsigned long long lhs, long rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( unsigned long long lhs, long long rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( unsigned long long lhs, char rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + + // pointer to long long (when comparing against NULL) + template bool compare( long long lhs, T* rhs ) { + return Evaluator::evaluate( reinterpret_cast( lhs ), rhs ); + } + template bool compare( T* lhs, long long rhs ) { + return Evaluator::evaluate( lhs, reinterpret_cast( rhs ) ); + } +#endif // CATCH_CONFIG_CPP11_LONG_LONG + +#ifdef CATCH_CONFIG_CPP11_NULLPTR + // pointer to nullptr_t (when comparing against nullptr) + template bool compare( std::nullptr_t, T* rhs ) { + return Evaluator::evaluate( nullptr, rhs ); + } + template bool compare( T* lhs, std::nullptr_t ) { + return Evaluator::evaluate( lhs, nullptr ); + } +#endif // CATCH_CONFIG_CPP11_NULLPTR + +} // end of namespace Internal +} // end of namespace Catch + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +// #included from: catch_tostring.h +#define TWOBLUECUBES_CATCH_TOSTRING_H_INCLUDED + +#include +#include +#include +#include +#include + +#ifdef __OBJC__ +// #included from: catch_objc_arc.hpp +#define TWOBLUECUBES_CATCH_OBJC_ARC_HPP_INCLUDED + +#import + +#ifdef __has_feature +#define CATCH_ARC_ENABLED __has_feature(objc_arc) +#else +#define CATCH_ARC_ENABLED 0 +#endif + +void arcSafeRelease( NSObject* obj ); +id performOptionalSelector( id obj, SEL sel ); + +#if !CATCH_ARC_ENABLED +inline void arcSafeRelease( NSObject* obj ) { + [obj release]; +} +inline id performOptionalSelector( id obj, SEL sel ) { + if( [obj respondsToSelector: sel] ) + return [obj performSelector: sel]; + return nil; +} +#define CATCH_UNSAFE_UNRETAINED +#define CATCH_ARC_STRONG +#else +inline void arcSafeRelease( NSObject* ){} +inline id performOptionalSelector( id obj, SEL sel ) { +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Warc-performSelector-leaks" +#endif + if( [obj respondsToSelector: sel] ) + return [obj performSelector: sel]; +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + return nil; +} +#define CATCH_UNSAFE_UNRETAINED __unsafe_unretained +#define CATCH_ARC_STRONG __strong +#endif + +#endif + +#ifdef CATCH_CONFIG_CPP11_TUPLE +#include +#endif + +#ifdef CATCH_CONFIG_CPP11_IS_ENUM +#include +#endif + +namespace Catch { + +// Why we're here. +template +std::string toString( T const& value ); + +// Built in overloads + +std::string toString( std::string const& value ); +std::string toString( std::wstring const& value ); +std::string toString( const char* const value ); +std::string toString( char* const value ); +std::string toString( const wchar_t* const value ); +std::string toString( wchar_t* const value ); +std::string toString( int value ); +std::string toString( unsigned long value ); +std::string toString( unsigned int value ); +std::string toString( const double value ); +std::string toString( const float value ); +std::string toString( bool value ); +std::string toString( char value ); +std::string toString( signed char value ); +std::string toString( unsigned char value ); + +#ifdef CATCH_CONFIG_CPP11_LONG_LONG +std::string toString( long long value ); +std::string toString( unsigned long long value ); +#endif + +#ifdef CATCH_CONFIG_CPP11_NULLPTR +std::string toString( std::nullptr_t ); +#endif + +#ifdef __OBJC__ + std::string toString( NSString const * const& nsstring ); + std::string toString( NSString * CATCH_ARC_STRONG const& nsstring ); + std::string toString( NSObject* const& nsObject ); +#endif + +namespace Detail { + + extern const std::string unprintableString; + + struct BorgType { + template BorgType( T const& ); + }; + + struct TrueType { char sizer[1]; }; + struct FalseType { char sizer[2]; }; + + TrueType& testStreamable( std::ostream& ); + FalseType testStreamable( FalseType ); + + FalseType operator<<( std::ostream const&, BorgType const& ); + + template + struct IsStreamInsertable { + static std::ostream &s; + static T const&t; + enum { value = sizeof( testStreamable(s << t) ) == sizeof( TrueType ) }; + }; + +#if defined(CATCH_CONFIG_CPP11_IS_ENUM) + template::value + > + struct EnumStringMaker + { + static std::string convert( T const& ) { return unprintableString; } + }; + + template + struct EnumStringMaker + { + static std::string convert( T const& v ) + { + return ::Catch::toString( + static_cast::type>(v) + ); + } + }; +#endif + template + struct StringMakerBase { +#if defined(CATCH_CONFIG_CPP11_IS_ENUM) + template + static std::string convert( T const& v ) + { + return EnumStringMaker::convert( v ); + } +#else + template + static std::string convert( T const& ) { return unprintableString; } +#endif + }; + + template<> + struct StringMakerBase { + template + static std::string convert( T const& _value ) { + std::ostringstream oss; + oss << _value; + return oss.str(); + } + }; + + std::string rawMemoryToString( const void *object, std::size_t size ); + + template + inline std::string rawMemoryToString( const T& object ) { + return rawMemoryToString( &object, sizeof(object) ); + } + +} // end namespace Detail + +template +struct StringMaker : + Detail::StringMakerBase::value> {}; + +template +struct StringMaker { + template + static std::string convert( U* p ) { + if( !p ) + return "NULL"; + else + return Detail::rawMemoryToString( p ); + } +}; + +template +struct StringMaker { + static std::string convert( R C::* p ) { + if( !p ) + return "NULL"; + else + return Detail::rawMemoryToString( p ); + } +}; + +namespace Detail { + template + std::string rangeToString( InputIterator first, InputIterator last ); +} + +//template +//struct StringMaker > { +// static std::string convert( std::vector const& v ) { +// return Detail::rangeToString( v.begin(), v.end() ); +// } +//}; + +template +std::string toString( std::vector const& v ) { + return Detail::rangeToString( v.begin(), v.end() ); +} + +#ifdef CATCH_CONFIG_CPP11_TUPLE + +// toString for tuples +namespace TupleDetail { + template< + typename Tuple, + std::size_t N = 0, + bool = (N < std::tuple_size::value) + > + struct ElementPrinter { + static void print( const Tuple& tuple, std::ostream& os ) + { + os << ( N ? ", " : " " ) + << Catch::toString(std::get(tuple)); + ElementPrinter::print(tuple,os); + } + }; + + template< + typename Tuple, + std::size_t N + > + struct ElementPrinter { + static void print( const Tuple&, std::ostream& ) {} + }; + +} + +template +struct StringMaker> { + + static std::string convert( const std::tuple& tuple ) + { + std::ostringstream os; + os << '{'; + TupleDetail::ElementPrinter>::print( tuple, os ); + os << " }"; + return os.str(); + } +}; +#endif // CATCH_CONFIG_CPP11_TUPLE + +namespace Detail { + template + std::string makeString( T const& value ) { + return StringMaker::convert( value ); + } +} // end namespace Detail + +/// \brief converts any type to a string +/// +/// The default template forwards on to ostringstream - except when an +/// ostringstream overload does not exist - in which case it attempts to detect +/// that and writes {?}. +/// Overload (not specialise) this template for custom typs that you don't want +/// to provide an ostream overload for. +template +std::string toString( T const& value ) { + return StringMaker::convert( value ); +} + + namespace Detail { + template + std::string rangeToString( InputIterator first, InputIterator last ) { + std::ostringstream oss; + oss << "{ "; + if( first != last ) { + oss << Catch::toString( *first ); + for( ++first ; first != last ; ++first ) + oss << ", " << Catch::toString( *first ); + } + oss << " }"; + return oss.str(); + } +} + +} // end namespace Catch + +namespace Catch { + +// Wraps the LHS of an expression and captures the operator and RHS (if any) - +// wrapping them all in a ResultBuilder object +template +class ExpressionLhs { + ExpressionLhs& operator = ( ExpressionLhs const& ); +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + ExpressionLhs& operator = ( ExpressionLhs && ) = delete; +# endif + +public: + ExpressionLhs( ResultBuilder& rb, T lhs ) : m_rb( rb ), m_lhs( lhs ) {} +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + ExpressionLhs( ExpressionLhs const& ) = default; + ExpressionLhs( ExpressionLhs && ) = default; +# endif + + template + ResultBuilder& operator == ( RhsT const& rhs ) { + return captureExpression( rhs ); + } + + template + ResultBuilder& operator != ( RhsT const& rhs ) { + return captureExpression( rhs ); + } + + template + ResultBuilder& operator < ( RhsT const& rhs ) { + return captureExpression( rhs ); + } + + template + ResultBuilder& operator > ( RhsT const& rhs ) { + return captureExpression( rhs ); + } + + template + ResultBuilder& operator <= ( RhsT const& rhs ) { + return captureExpression( rhs ); + } + + template + ResultBuilder& operator >= ( RhsT const& rhs ) { + return captureExpression( rhs ); + } + + ResultBuilder& operator == ( bool rhs ) { + return captureExpression( rhs ); + } + + ResultBuilder& operator != ( bool rhs ) { + return captureExpression( rhs ); + } + + void endExpression() { + bool value = m_lhs ? true : false; + m_rb + .setLhs( Catch::toString( value ) ) + .setResultType( value ) + .endExpression(); + } + + // Only simple binary expressions are allowed on the LHS. + // If more complex compositions are required then place the sub expression in parentheses + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator + ( RhsT const& ); + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator - ( RhsT const& ); + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator / ( RhsT const& ); + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator * ( RhsT const& ); + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( RhsT const& ); + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || ( RhsT const& ); + +private: + template + ResultBuilder& captureExpression( RhsT const& rhs ) { + return m_rb + .setResultType( Internal::compare( m_lhs, rhs ) ) + .setLhs( Catch::toString( m_lhs ) ) + .setRhs( Catch::toString( rhs ) ) + .setOp( Internal::OperatorTraits::getName() ); + } + +private: + ResultBuilder& m_rb; + T m_lhs; +}; + +} // end namespace Catch + + +namespace Catch { + + template + inline ExpressionLhs ResultBuilder::operator <= ( T const& operand ) { + return ExpressionLhs( *this, operand ); + } + + inline ExpressionLhs ResultBuilder::operator <= ( bool value ) { + return ExpressionLhs( *this, value ); + } + +} // namespace Catch + +// #included from: catch_message.h +#define TWOBLUECUBES_CATCH_MESSAGE_H_INCLUDED + +#include + +namespace Catch { + + struct MessageInfo { + MessageInfo( std::string const& _macroName, + SourceLineInfo const& _lineInfo, + ResultWas::OfType _type ); + + std::string macroName; + SourceLineInfo lineInfo; + ResultWas::OfType type; + std::string message; + unsigned int sequence; + + bool operator == ( MessageInfo const& other ) const { + return sequence == other.sequence; + } + bool operator < ( MessageInfo const& other ) const { + return sequence < other.sequence; + } + private: + static unsigned int globalCount; + }; + + struct MessageBuilder { + MessageBuilder( std::string const& macroName, + SourceLineInfo const& lineInfo, + ResultWas::OfType type ) + : m_info( macroName, lineInfo, type ) + {} + + template + MessageBuilder& operator << ( T const& value ) { + m_stream << value; + return *this; + } + + MessageInfo m_info; + std::ostringstream m_stream; + }; + + class ScopedMessage { + public: + ScopedMessage( MessageBuilder const& builder ); + ScopedMessage( ScopedMessage const& other ); + ~ScopedMessage(); + + MessageInfo m_info; + }; + +} // end namespace Catch + +// #included from: catch_interfaces_capture.h +#define TWOBLUECUBES_CATCH_INTERFACES_CAPTURE_H_INCLUDED + +#include + +namespace Catch { + + class TestCase; + class AssertionResult; + struct AssertionInfo; + struct SectionInfo; + struct SectionEndInfo; + struct MessageInfo; + class ScopedMessageBuilder; + struct Counts; + + struct IResultCapture { + + virtual ~IResultCapture(); + + virtual void assertionEnded( AssertionResult const& result ) = 0; + virtual bool sectionStarted( SectionInfo const& sectionInfo, + Counts& assertions ) = 0; + virtual void sectionEnded( SectionEndInfo const& endInfo ) = 0; + virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) = 0; + virtual void pushScopedMessage( MessageInfo const& message ) = 0; + virtual void popScopedMessage( MessageInfo const& message ) = 0; + + virtual std::string getCurrentTestName() const = 0; + virtual const AssertionResult* getLastResult() const = 0; + + virtual void handleFatalErrorCondition( std::string const& message ) = 0; + }; + + IResultCapture& getResultCapture(); +} + +// #included from: catch_debugger.h +#define TWOBLUECUBES_CATCH_DEBUGGER_H_INCLUDED + +// #included from: catch_platform.h +#define TWOBLUECUBES_CATCH_PLATFORM_H_INCLUDED + +#if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) +#define CATCH_PLATFORM_MAC +#elif defined(__IPHONE_OS_VERSION_MIN_REQUIRED) +#define CATCH_PLATFORM_IPHONE +#elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) +#define CATCH_PLATFORM_WINDOWS +#endif + +#include + +namespace Catch{ + + bool isDebuggerActive(); + void writeToDebugConsole( std::string const& text ); +} + +#ifdef CATCH_PLATFORM_MAC + + // The following code snippet based on: + // http://cocoawithlove.com/2008/03/break-into-debugger.html + #ifdef DEBUG + #if defined(__ppc64__) || defined(__ppc__) + #define CATCH_BREAK_INTO_DEBUGGER() \ + if( Catch::isDebuggerActive() ) { \ + __asm__("li r0, 20\nsc\nnop\nli r0, 37\nli r4, 2\nsc\nnop\n" \ + : : : "memory","r0","r3","r4" ); \ + } + #else + #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) {__asm__("int $3\n" : : );} + #endif + #endif + +#elif defined(_MSC_VER) + #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { __debugbreak(); } +#elif defined(__MINGW32__) + extern "C" __declspec(dllimport) void __stdcall DebugBreak(); + #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { DebugBreak(); } +#endif + +#ifndef CATCH_BREAK_INTO_DEBUGGER +#define CATCH_BREAK_INTO_DEBUGGER() Catch::alwaysTrue(); +#endif + +// #included from: catch_interfaces_runner.h +#define TWOBLUECUBES_CATCH_INTERFACES_RUNNER_H_INCLUDED + +namespace Catch { + class TestCase; + + struct IRunner { + virtual ~IRunner(); + virtual bool aborting() const = 0; + }; +} + +/////////////////////////////////////////////////////////////////////////////// +// In the event of a failure works out if the debugger needs to be invoked +// and/or an exception thrown and takes appropriate action. +// This needs to be done as a macro so the debugger will stop in the user +// source code rather than in Catch library code +#define INTERNAL_CATCH_REACT( resultBuilder ) \ + if( resultBuilder.shouldDebugBreak() ) CATCH_BREAK_INTO_DEBUGGER(); \ + resultBuilder.react(); + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \ + try { \ + CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ + ( __catchResult <= expr ).endExpression(); \ + } \ + catch( ... ) { \ + __catchResult.useActiveException( Catch::ResultDisposition::Normal ); \ + } \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::isTrue( false && static_cast(expr) ) ) // expr here is never evaluated at runtime but it forces the compiler to give it a look + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_IF( expr, resultDisposition, macroName ) \ + INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ); \ + if( Catch::getResultCapture().getLastResult()->succeeded() ) + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_ELSE( expr, resultDisposition, macroName ) \ + INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ); \ + if( !Catch::getResultCapture().getLastResult()->succeeded() ) + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_NO_THROW( expr, resultDisposition, macroName ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \ + try { \ + expr; \ + __catchResult.captureResult( Catch::ResultWas::Ok ); \ + } \ + catch( ... ) { \ + __catchResult.useActiveException( resultDisposition ); \ + } \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::alwaysFalse() ) + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_THROWS( expr, resultDisposition, matcher, macroName ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition, #matcher ); \ + if( __catchResult.allowThrows() ) \ + try { \ + expr; \ + __catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \ + } \ + catch( ... ) { \ + __catchResult.captureExpectedException( matcher ); \ + } \ + else \ + __catchResult.captureResult( Catch::ResultWas::Ok ); \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::alwaysFalse() ) + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_THROWS_AS( expr, exceptionType, resultDisposition, macroName ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \ + if( __catchResult.allowThrows() ) \ + try { \ + expr; \ + __catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \ + } \ + catch( exceptionType ) { \ + __catchResult.captureResult( Catch::ResultWas::Ok ); \ + } \ + catch( ... ) { \ + __catchResult.useActiveException( resultDisposition ); \ + } \ + else \ + __catchResult.captureResult( Catch::ResultWas::Ok ); \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::alwaysFalse() ) + +/////////////////////////////////////////////////////////////////////////////// +#ifdef CATCH_CONFIG_VARIADIC_MACROS + #define INTERNAL_CATCH_MSG( messageType, resultDisposition, macroName, ... ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \ + __catchResult << __VA_ARGS__ + ::Catch::StreamEndStop(); \ + __catchResult.captureResult( messageType ); \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::alwaysFalse() ) +#else + #define INTERNAL_CATCH_MSG( messageType, resultDisposition, macroName, log ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \ + __catchResult << log + ::Catch::StreamEndStop(); \ + __catchResult.captureResult( messageType ); \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::alwaysFalse() ) +#endif + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_INFO( log, macroName ) \ + Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME( scopedMessage ) = Catch::MessageBuilder( macroName, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log; + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CHECK_THAT( arg, matcher, resultDisposition, macroName ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #arg ", " #matcher, resultDisposition ); \ + try { \ + std::string matcherAsString = (matcher).toString(); \ + __catchResult \ + .setLhs( Catch::toString( arg ) ) \ + .setRhs( matcherAsString == Catch::Detail::unprintableString ? #matcher : matcherAsString ) \ + .setOp( "matches" ) \ + .setResultType( (matcher).match( arg ) ); \ + __catchResult.captureExpression(); \ + } catch( ... ) { \ + __catchResult.useActiveException( resultDisposition | Catch::ResultDisposition::ContinueOnFailure ); \ + } \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::alwaysFalse() ) + +// #included from: internal/catch_section.h +#define TWOBLUECUBES_CATCH_SECTION_H_INCLUDED + +// #included from: catch_section_info.h +#define TWOBLUECUBES_CATCH_SECTION_INFO_H_INCLUDED + +// #included from: catch_totals.hpp +#define TWOBLUECUBES_CATCH_TOTALS_HPP_INCLUDED + +#include + +namespace Catch { + + struct Counts { + Counts() : passed( 0 ), failed( 0 ), failedButOk( 0 ) {} + + Counts operator - ( Counts const& other ) const { + Counts diff; + diff.passed = passed - other.passed; + diff.failed = failed - other.failed; + diff.failedButOk = failedButOk - other.failedButOk; + return diff; + } + Counts& operator += ( Counts const& other ) { + passed += other.passed; + failed += other.failed; + failedButOk += other.failedButOk; + return *this; + } + + std::size_t total() const { + return passed + failed + failedButOk; + } + bool allPassed() const { + return failed == 0 && failedButOk == 0; + } + bool allOk() const { + return failed == 0; + } + + std::size_t passed; + std::size_t failed; + std::size_t failedButOk; + }; + + struct Totals { + + Totals operator - ( Totals const& other ) const { + Totals diff; + diff.assertions = assertions - other.assertions; + diff.testCases = testCases - other.testCases; + return diff; + } + + Totals delta( Totals const& prevTotals ) const { + Totals diff = *this - prevTotals; + if( diff.assertions.failed > 0 ) + ++diff.testCases.failed; + else if( diff.assertions.failedButOk > 0 ) + ++diff.testCases.failedButOk; + else + ++diff.testCases.passed; + return diff; + } + + Totals& operator += ( Totals const& other ) { + assertions += other.assertions; + testCases += other.testCases; + return *this; + } + + Counts assertions; + Counts testCases; + }; +} + +namespace Catch { + + struct SectionInfo { + SectionInfo + ( SourceLineInfo const& _lineInfo, + std::string const& _name, + std::string const& _description = std::string() ); + + std::string name; + std::string description; + SourceLineInfo lineInfo; + }; + + struct SectionEndInfo { + SectionEndInfo( SectionInfo const& _sectionInfo, Counts const& _prevAssertions, double _durationInSeconds ) + : sectionInfo( _sectionInfo ), prevAssertions( _prevAssertions ), durationInSeconds( _durationInSeconds ) + {} + + SectionInfo sectionInfo; + Counts prevAssertions; + double durationInSeconds; + }; + +} // end namespace Catch + +// #included from: catch_timer.h +#define TWOBLUECUBES_CATCH_TIMER_H_INCLUDED + +#ifdef CATCH_PLATFORM_WINDOWS +typedef unsigned long long uint64_t; +#else +#include +#endif + +namespace Catch { + + class Timer { + public: + Timer() : m_ticks( 0 ) {} + void start(); + unsigned int getElapsedMicroseconds() const; + unsigned int getElapsedMilliseconds() const; + double getElapsedSeconds() const; + + private: + uint64_t m_ticks; + }; + +} // namespace Catch + +#include + +namespace Catch { + + class Section : NonCopyable { + public: + Section( SectionInfo const& info ); + ~Section(); + + // This indicates whether the section should be executed or not + operator bool() const; + + private: + SectionInfo m_info; + + std::string m_name; + Counts m_assertions; + bool m_sectionIncluded; + Timer m_timer; + }; + +} // end namespace Catch + +#ifdef CATCH_CONFIG_VARIADIC_MACROS + #define INTERNAL_CATCH_SECTION( ... ) \ + if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) ) +#else + #define INTERNAL_CATCH_SECTION( name, desc ) \ + if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, name, desc ) ) +#endif + +// #included from: internal/catch_generators.hpp +#define TWOBLUECUBES_CATCH_GENERATORS_HPP_INCLUDED + +#include +#include +#include +#include + +namespace Catch { + +template +struct IGenerator { + virtual ~IGenerator() {} + virtual T getValue( std::size_t index ) const = 0; + virtual std::size_t size () const = 0; +}; + +template +class BetweenGenerator : public IGenerator { +public: + BetweenGenerator( T from, T to ) : m_from( from ), m_to( to ){} + + virtual T getValue( std::size_t index ) const { + return m_from+static_cast( index ); + } + + virtual std::size_t size() const { + return static_cast( 1+m_to-m_from ); + } + +private: + + T m_from; + T m_to; +}; + +template +class ValuesGenerator : public IGenerator { +public: + ValuesGenerator(){} + + void add( T value ) { + m_values.push_back( value ); + } + + virtual T getValue( std::size_t index ) const { + return m_values[index]; + } + + virtual std::size_t size() const { + return m_values.size(); + } + +private: + std::vector m_values; +}; + +template +class CompositeGenerator { +public: + CompositeGenerator() : m_totalSize( 0 ) {} + + // *** Move semantics, similar to auto_ptr *** + CompositeGenerator( CompositeGenerator& other ) + : m_fileInfo( other.m_fileInfo ), + m_totalSize( 0 ) + { + move( other ); + } + + CompositeGenerator& setFileInfo( const char* fileInfo ) { + m_fileInfo = fileInfo; + return *this; + } + + ~CompositeGenerator() { + deleteAll( m_composed ); + } + + operator T () const { + size_t overallIndex = getCurrentContext().getGeneratorIndex( m_fileInfo, m_totalSize ); + + typename std::vector*>::const_iterator it = m_composed.begin(); + typename std::vector*>::const_iterator itEnd = m_composed.end(); + for( size_t index = 0; it != itEnd; ++it ) + { + const IGenerator* generator = *it; + if( overallIndex >= index && overallIndex < index + generator->size() ) + { + return generator->getValue( overallIndex-index ); + } + index += generator->size(); + } + CATCH_INTERNAL_ERROR( "Indexed past end of generated range" ); + return T(); // Suppress spurious "not all control paths return a value" warning in Visual Studio - if you know how to fix this please do so + } + + void add( const IGenerator* generator ) { + m_totalSize += generator->size(); + m_composed.push_back( generator ); + } + + CompositeGenerator& then( CompositeGenerator& other ) { + move( other ); + return *this; + } + + CompositeGenerator& then( T value ) { + ValuesGenerator* valuesGen = new ValuesGenerator(); + valuesGen->add( value ); + add( valuesGen ); + return *this; + } + +private: + + void move( CompositeGenerator& other ) { + std::copy( other.m_composed.begin(), other.m_composed.end(), std::back_inserter( m_composed ) ); + m_totalSize += other.m_totalSize; + other.m_composed.clear(); + } + + std::vector*> m_composed; + std::string m_fileInfo; + size_t m_totalSize; +}; + +namespace Generators +{ + template + CompositeGenerator between( T from, T to ) { + CompositeGenerator generators; + generators.add( new BetweenGenerator( from, to ) ); + return generators; + } + + template + CompositeGenerator values( T val1, T val2 ) { + CompositeGenerator generators; + ValuesGenerator* valuesGen = new ValuesGenerator(); + valuesGen->add( val1 ); + valuesGen->add( val2 ); + generators.add( valuesGen ); + return generators; + } + + template + CompositeGenerator values( T val1, T val2, T val3 ){ + CompositeGenerator generators; + ValuesGenerator* valuesGen = new ValuesGenerator(); + valuesGen->add( val1 ); + valuesGen->add( val2 ); + valuesGen->add( val3 ); + generators.add( valuesGen ); + return generators; + } + + template + CompositeGenerator values( T val1, T val2, T val3, T val4 ) { + CompositeGenerator generators; + ValuesGenerator* valuesGen = new ValuesGenerator(); + valuesGen->add( val1 ); + valuesGen->add( val2 ); + valuesGen->add( val3 ); + valuesGen->add( val4 ); + generators.add( valuesGen ); + return generators; + } + +} // end namespace Generators + +using namespace Generators; + +} // end namespace Catch + +#define INTERNAL_CATCH_LINESTR2( line ) #line +#define INTERNAL_CATCH_LINESTR( line ) INTERNAL_CATCH_LINESTR2( line ) + +#define INTERNAL_CATCH_GENERATE( expr ) expr.setFileInfo( __FILE__ "(" INTERNAL_CATCH_LINESTR( __LINE__ ) ")" ) + +// #included from: internal/catch_interfaces_exception.h +#define TWOBLUECUBES_CATCH_INTERFACES_EXCEPTION_H_INCLUDED + +#include +#include + +// #included from: catch_interfaces_registry_hub.h +#define TWOBLUECUBES_CATCH_INTERFACES_REGISTRY_HUB_H_INCLUDED + +#include + +namespace Catch { + + class TestCase; + struct ITestCaseRegistry; + struct IExceptionTranslatorRegistry; + struct IExceptionTranslator; + struct IReporterRegistry; + struct IReporterFactory; + + struct IRegistryHub { + virtual ~IRegistryHub(); + + virtual IReporterRegistry const& getReporterRegistry() const = 0; + virtual ITestCaseRegistry const& getTestCaseRegistry() const = 0; + virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() = 0; + }; + + struct IMutableRegistryHub { + virtual ~IMutableRegistryHub(); + virtual void registerReporter( std::string const& name, Ptr const& factory ) = 0; + virtual void registerListener( Ptr const& factory ) = 0; + virtual void registerTest( TestCase const& testInfo ) = 0; + virtual void registerTranslator( const IExceptionTranslator* translator ) = 0; + }; + + IRegistryHub& getRegistryHub(); + IMutableRegistryHub& getMutableRegistryHub(); + void cleanUp(); + std::string translateActiveException(); + +} + +namespace Catch { + + typedef std::string(*exceptionTranslateFunction)(); + + struct IExceptionTranslator; + typedef std::vector ExceptionTranslators; + + struct IExceptionTranslator { + virtual ~IExceptionTranslator(); + virtual std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const = 0; + }; + + struct IExceptionTranslatorRegistry { + virtual ~IExceptionTranslatorRegistry(); + + virtual std::string translateActiveException() const = 0; + }; + + class ExceptionTranslatorRegistrar { + template + class ExceptionTranslator : public IExceptionTranslator { + public: + + ExceptionTranslator( std::string(*translateFunction)( T& ) ) + : m_translateFunction( translateFunction ) + {} + + virtual std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const CATCH_OVERRIDE { + try { + if( it == itEnd ) + throw; + else + return (*it)->translate( it+1, itEnd ); + } + catch( T& ex ) { + return m_translateFunction( ex ); + } + } + + protected: + std::string(*m_translateFunction)( T& ); + }; + + public: + template + ExceptionTranslatorRegistrar( std::string(*translateFunction)( T& ) ) { + getMutableRegistryHub().registerTranslator + ( new ExceptionTranslator( translateFunction ) ); + } + }; +} + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) \ + static std::string INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator )( signature ); \ + namespace{ Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ) ); }\ + static std::string INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator )( signature ) + +// #included from: internal/catch_approx.hpp +#define TWOBLUECUBES_CATCH_APPROX_HPP_INCLUDED + +#include +#include + +namespace Catch { +namespace Detail { + + class Approx { + public: + explicit Approx ( double value ) + : m_epsilon( std::numeric_limits::epsilon()*100 ), + m_scale( 1.0 ), + m_value( value ) + {} + + Approx( Approx const& other ) + : m_epsilon( other.m_epsilon ), + m_scale( other.m_scale ), + m_value( other.m_value ) + {} + + static Approx custom() { + return Approx( 0 ); + } + + Approx operator()( double value ) { + Approx approx( value ); + approx.epsilon( m_epsilon ); + approx.scale( m_scale ); + return approx; + } + + friend bool operator == ( double lhs, Approx const& rhs ) { + // Thanks to Richard Harris for his help refining this formula + return fabs( lhs - rhs.m_value ) < rhs.m_epsilon * (rhs.m_scale + (std::max)( fabs(lhs), fabs(rhs.m_value) ) ); + } + + friend bool operator == ( Approx const& lhs, double rhs ) { + return operator==( rhs, lhs ); + } + + friend bool operator != ( double lhs, Approx const& rhs ) { + return !operator==( lhs, rhs ); + } + + friend bool operator != ( Approx const& lhs, double rhs ) { + return !operator==( rhs, lhs ); + } + + Approx& epsilon( double newEpsilon ) { + m_epsilon = newEpsilon; + return *this; + } + + Approx& scale( double newScale ) { + m_scale = newScale; + return *this; + } + + std::string toString() const { + std::ostringstream oss; + oss << "Approx( " << Catch::toString( m_value ) << " )"; + return oss.str(); + } + + private: + double m_epsilon; + double m_scale; + double m_value; + }; +} + +template<> +inline std::string toString( Detail::Approx const& value ) { + return value.toString(); +} + +} // end namespace Catch + +// #included from: internal/catch_interfaces_tag_alias_registry.h +#define TWOBLUECUBES_CATCH_INTERFACES_TAG_ALIAS_REGISTRY_H_INCLUDED + +// #included from: catch_tag_alias.h +#define TWOBLUECUBES_CATCH_TAG_ALIAS_H_INCLUDED + +#include + +namespace Catch { + + struct TagAlias { + TagAlias( std::string _tag, SourceLineInfo _lineInfo ) : tag( _tag ), lineInfo( _lineInfo ) {} + + std::string tag; + SourceLineInfo lineInfo; + }; + + struct RegistrarForTagAliases { + RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ); + }; + +} // end namespace Catch + +#define CATCH_REGISTER_TAG_ALIAS( alias, spec ) namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); } +// #included from: catch_option.hpp +#define TWOBLUECUBES_CATCH_OPTION_HPP_INCLUDED + +namespace Catch { + + // An optional type + template + class Option { + public: + Option() : nullableValue( CATCH_NULL ) {} + Option( T const& _value ) + : nullableValue( new( storage ) T( _value ) ) + {} + Option( Option const& _other ) + : nullableValue( _other ? new( storage ) T( *_other ) : CATCH_NULL ) + {} + + ~Option() { + reset(); + } + + Option& operator= ( Option const& _other ) { + if( &_other != this ) { + reset(); + if( _other ) + nullableValue = new( storage ) T( *_other ); + } + return *this; + } + Option& operator = ( T const& _value ) { + reset(); + nullableValue = new( storage ) T( _value ); + return *this; + } + + void reset() { + if( nullableValue ) + nullableValue->~T(); + nullableValue = CATCH_NULL; + } + + T& operator*() { return *nullableValue; } + T const& operator*() const { return *nullableValue; } + T* operator->() { return nullableValue; } + const T* operator->() const { return nullableValue; } + + T valueOr( T const& defaultValue ) const { + return nullableValue ? *nullableValue : defaultValue; + } + + bool some() const { return nullableValue != CATCH_NULL; } + bool none() const { return nullableValue == CATCH_NULL; } + + bool operator !() const { return nullableValue == CATCH_NULL; } + operator SafeBool::type() const { + return SafeBool::makeSafe( some() ); + } + + private: + T* nullableValue; + char storage[sizeof(T)]; + }; + +} // end namespace Catch + +namespace Catch { + + struct ITagAliasRegistry { + virtual ~ITagAliasRegistry(); + virtual Option find( std::string const& alias ) const = 0; + virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const = 0; + + static ITagAliasRegistry const& get(); + }; + +} // end namespace Catch + +// These files are included here so the single_include script doesn't put them +// in the conditionally compiled sections +// #included from: internal/catch_test_case_info.h +#define TWOBLUECUBES_CATCH_TEST_CASE_INFO_H_INCLUDED + +#include +#include + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpadded" +#endif + +namespace Catch { + + struct ITestCase; + + struct TestCaseInfo { + enum SpecialProperties{ + None = 0, + IsHidden = 1 << 1, + ShouldFail = 1 << 2, + MayFail = 1 << 3, + Throws = 1 << 4 + }; + + TestCaseInfo( std::string const& _name, + std::string const& _className, + std::string const& _description, + std::set const& _tags, + SourceLineInfo const& _lineInfo ); + + TestCaseInfo( TestCaseInfo const& other ); + + friend void setTags( TestCaseInfo& testCaseInfo, std::set const& tags ); + + bool isHidden() const; + bool throws() const; + bool okToFail() const; + bool expectedToFail() const; + + std::string name; + std::string className; + std::string description; + std::set tags; + std::set lcaseTags; + std::string tagsAsString; + SourceLineInfo lineInfo; + SpecialProperties properties; + }; + + class TestCase : public TestCaseInfo { + public: + + TestCase( ITestCase* testCase, TestCaseInfo const& info ); + TestCase( TestCase const& other ); + + TestCase withName( std::string const& _newName ) const; + + void invoke() const; + + TestCaseInfo const& getTestCaseInfo() const; + + void swap( TestCase& other ); + bool operator == ( TestCase const& other ) const; + bool operator < ( TestCase const& other ) const; + TestCase& operator = ( TestCase const& other ); + + private: + Ptr test; + }; + + TestCase makeTestCase( ITestCase* testCase, + std::string const& className, + std::string const& name, + std::string const& description, + SourceLineInfo const& lineInfo ); +} + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + + +#ifdef __OBJC__ +// #included from: internal/catch_objc.hpp +#define TWOBLUECUBES_CATCH_OBJC_HPP_INCLUDED + +#import + +#include + +// NB. Any general catch headers included here must be included +// in catch.hpp first to make sure they are included by the single +// header for non obj-usage + +/////////////////////////////////////////////////////////////////////////////// +// This protocol is really only here for (self) documenting purposes, since +// all its methods are optional. +@protocol OcFixture + +@optional + +-(void) setUp; +-(void) tearDown; + +@end + +namespace Catch { + + class OcMethod : public SharedImpl { + + public: + OcMethod( Class cls, SEL sel ) : m_cls( cls ), m_sel( sel ) {} + + virtual void invoke() const { + id obj = [[m_cls alloc] init]; + + performOptionalSelector( obj, @selector(setUp) ); + performOptionalSelector( obj, m_sel ); + performOptionalSelector( obj, @selector(tearDown) ); + + arcSafeRelease( obj ); + } + private: + virtual ~OcMethod() {} + + Class m_cls; + SEL m_sel; + }; + + namespace Detail{ + + inline std::string getAnnotation( Class cls, + std::string const& annotationName, + std::string const& testCaseName ) { + NSString* selStr = [[NSString alloc] initWithFormat:@"Catch_%s_%s", annotationName.c_str(), testCaseName.c_str()]; + SEL sel = NSSelectorFromString( selStr ); + arcSafeRelease( selStr ); + id value = performOptionalSelector( cls, sel ); + if( value ) + return [(NSString*)value UTF8String]; + return ""; + } + } + + inline size_t registerTestMethods() { + size_t noTestMethods = 0; + int noClasses = objc_getClassList( CATCH_NULL, 0 ); + + Class* classes = (CATCH_UNSAFE_UNRETAINED Class *)malloc( sizeof(Class) * noClasses); + objc_getClassList( classes, noClasses ); + + for( int c = 0; c < noClasses; c++ ) { + Class cls = classes[c]; + { + u_int count; + Method* methods = class_copyMethodList( cls, &count ); + for( u_int m = 0; m < count ; m++ ) { + SEL selector = method_getName(methods[m]); + std::string methodName = sel_getName(selector); + if( startsWith( methodName, "Catch_TestCase_" ) ) { + std::string testCaseName = methodName.substr( 15 ); + std::string name = Detail::getAnnotation( cls, "Name", testCaseName ); + std::string desc = Detail::getAnnotation( cls, "Description", testCaseName ); + const char* className = class_getName( cls ); + + getMutableRegistryHub().registerTest( makeTestCase( new OcMethod( cls, selector ), className, name.c_str(), desc.c_str(), SourceLineInfo() ) ); + noTestMethods++; + } + } + free(methods); + } + } + return noTestMethods; + } + + namespace Matchers { + namespace Impl { + namespace NSStringMatchers { + + template + struct StringHolder : MatcherImpl{ + StringHolder( NSString* substr ) : m_substr( [substr copy] ){} + StringHolder( StringHolder const& other ) : m_substr( [other.m_substr copy] ){} + StringHolder() { + arcSafeRelease( m_substr ); + } + + NSString* m_substr; + }; + + struct Equals : StringHolder { + Equals( NSString* substr ) : StringHolder( substr ){} + + virtual bool match( ExpressionType const& str ) const { + return (str != nil || m_substr == nil ) && + [str isEqualToString:m_substr]; + } + + virtual std::string toString() const { + return "equals string: " + Catch::toString( m_substr ); + } + }; + + struct Contains : StringHolder { + Contains( NSString* substr ) : StringHolder( substr ){} + + virtual bool match( ExpressionType const& str ) const { + return (str != nil || m_substr == nil ) && + [str rangeOfString:m_substr].location != NSNotFound; + } + + virtual std::string toString() const { + return "contains string: " + Catch::toString( m_substr ); + } + }; + + struct StartsWith : StringHolder { + StartsWith( NSString* substr ) : StringHolder( substr ){} + + virtual bool match( ExpressionType const& str ) const { + return (str != nil || m_substr == nil ) && + [str rangeOfString:m_substr].location == 0; + } + + virtual std::string toString() const { + return "starts with: " + Catch::toString( m_substr ); + } + }; + struct EndsWith : StringHolder { + EndsWith( NSString* substr ) : StringHolder( substr ){} + + virtual bool match( ExpressionType const& str ) const { + return (str != nil || m_substr == nil ) && + [str rangeOfString:m_substr].location == [str length] - [m_substr length]; + } + + virtual std::string toString() const { + return "ends with: " + Catch::toString( m_substr ); + } + }; + + } // namespace NSStringMatchers + } // namespace Impl + + inline Impl::NSStringMatchers::Equals + Equals( NSString* substr ){ return Impl::NSStringMatchers::Equals( substr ); } + + inline Impl::NSStringMatchers::Contains + Contains( NSString* substr ){ return Impl::NSStringMatchers::Contains( substr ); } + + inline Impl::NSStringMatchers::StartsWith + StartsWith( NSString* substr ){ return Impl::NSStringMatchers::StartsWith( substr ); } + + inline Impl::NSStringMatchers::EndsWith + EndsWith( NSString* substr ){ return Impl::NSStringMatchers::EndsWith( substr ); } + + } // namespace Matchers + + using namespace Matchers; + +} // namespace Catch + +/////////////////////////////////////////////////////////////////////////////// +#define OC_TEST_CASE( name, desc )\ ++(NSString*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Name_test ) \ +{\ +return @ name; \ +}\ ++(NSString*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Description_test ) \ +{ \ +return @ desc; \ +} \ +-(void) INTERNAL_CATCH_UNIQUE_NAME( Catch_TestCase_test ) + +#endif + +#ifdef CATCH_IMPL +// #included from: internal/catch_impl.hpp +#define TWOBLUECUBES_CATCH_IMPL_HPP_INCLUDED + +// Collect all the implementation files together here +// These are the equivalent of what would usually be cpp files + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wweak-vtables" +#endif + +// #included from: ../catch_session.hpp +#define TWOBLUECUBES_CATCH_RUNNER_HPP_INCLUDED + +// #included from: internal/catch_commandline.hpp +#define TWOBLUECUBES_CATCH_COMMANDLINE_HPP_INCLUDED + +// #included from: catch_config.hpp +#define TWOBLUECUBES_CATCH_CONFIG_HPP_INCLUDED + +// #included from: catch_test_spec_parser.hpp +#define TWOBLUECUBES_CATCH_TEST_SPEC_PARSER_HPP_INCLUDED + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpadded" +#endif + +// #included from: catch_test_spec.hpp +#define TWOBLUECUBES_CATCH_TEST_SPEC_HPP_INCLUDED + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpadded" +#endif + +// #included from: catch_wildcard_pattern.hpp +#define TWOBLUECUBES_CATCH_WILDCARD_PATTERN_HPP_INCLUDED + +namespace Catch +{ + class WildcardPattern { + enum WildcardPosition { + NoWildcard = 0, + WildcardAtStart = 1, + WildcardAtEnd = 2, + WildcardAtBothEnds = WildcardAtStart | WildcardAtEnd + }; + + public: + + WildcardPattern( std::string const& pattern, CaseSensitive::Choice caseSensitivity ) + : m_caseSensitivity( caseSensitivity ), + m_wildcard( NoWildcard ), + m_pattern( adjustCase( pattern ) ) + { + if( startsWith( m_pattern, "*" ) ) { + m_pattern = m_pattern.substr( 1 ); + m_wildcard = WildcardAtStart; + } + if( endsWith( m_pattern, "*" ) ) { + m_pattern = m_pattern.substr( 0, m_pattern.size()-1 ); + m_wildcard = static_cast( m_wildcard | WildcardAtEnd ); + } + } + virtual ~WildcardPattern(); + virtual bool matches( std::string const& str ) const { + switch( m_wildcard ) { + case NoWildcard: + return m_pattern == adjustCase( str ); + case WildcardAtStart: + return endsWith( adjustCase( str ), m_pattern ); + case WildcardAtEnd: + return startsWith( adjustCase( str ), m_pattern ); + case WildcardAtBothEnds: + return contains( adjustCase( str ), m_pattern ); + } + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunreachable-code" +#endif + throw std::logic_error( "Unknown enum" ); +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + } + private: + std::string adjustCase( std::string const& str ) const { + return m_caseSensitivity == CaseSensitive::No ? toLower( str ) : str; + } + CaseSensitive::Choice m_caseSensitivity; + WildcardPosition m_wildcard; + std::string m_pattern; + }; +} + +#include +#include + +namespace Catch { + + class TestSpec { + struct Pattern : SharedImpl<> { + virtual ~Pattern(); + virtual bool matches( TestCaseInfo const& testCase ) const = 0; + }; + class NamePattern : public Pattern { + public: + NamePattern( std::string const& name ) + : m_wildcardPattern( toLower( name ), CaseSensitive::No ) + {} + virtual ~NamePattern(); + virtual bool matches( TestCaseInfo const& testCase ) const { + return m_wildcardPattern.matches( toLower( testCase.name ) ); + } + private: + WildcardPattern m_wildcardPattern; + }; + + class TagPattern : public Pattern { + public: + TagPattern( std::string const& tag ) : m_tag( toLower( tag ) ) {} + virtual ~TagPattern(); + virtual bool matches( TestCaseInfo const& testCase ) const { + return testCase.lcaseTags.find( m_tag ) != testCase.lcaseTags.end(); + } + private: + std::string m_tag; + }; + + class ExcludedPattern : public Pattern { + public: + ExcludedPattern( Ptr const& underlyingPattern ) : m_underlyingPattern( underlyingPattern ) {} + virtual ~ExcludedPattern(); + virtual bool matches( TestCaseInfo const& testCase ) const { return !m_underlyingPattern->matches( testCase ); } + private: + Ptr m_underlyingPattern; + }; + + struct Filter { + std::vector > m_patterns; + + bool matches( TestCaseInfo const& testCase ) const { + // All patterns in a filter must match for the filter to be a match + for( std::vector >::const_iterator it = m_patterns.begin(), itEnd = m_patterns.end(); it != itEnd; ++it ) + if( !(*it)->matches( testCase ) ) + return false; + return true; + } + }; + + public: + bool hasFilters() const { + return !m_filters.empty(); + } + bool matches( TestCaseInfo const& testCase ) const { + // A TestSpec matches if any filter matches + for( std::vector::const_iterator it = m_filters.begin(), itEnd = m_filters.end(); it != itEnd; ++it ) + if( it->matches( testCase ) ) + return true; + return false; + } + + private: + std::vector m_filters; + + friend class TestSpecParser; + }; +} + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +namespace Catch { + + class TestSpecParser { + enum Mode{ None, Name, QuotedName, Tag }; + Mode m_mode; + bool m_exclusion; + std::size_t m_start, m_pos; + std::string m_arg; + TestSpec::Filter m_currentFilter; + TestSpec m_testSpec; + ITagAliasRegistry const* m_tagAliases; + + public: + TestSpecParser( ITagAliasRegistry const& tagAliases ) : m_tagAliases( &tagAliases ) {} + + TestSpecParser& parse( std::string const& arg ) { + m_mode = None; + m_exclusion = false; + m_start = std::string::npos; + m_arg = m_tagAliases->expandAliases( arg ); + for( m_pos = 0; m_pos < m_arg.size(); ++m_pos ) + visitChar( m_arg[m_pos] ); + if( m_mode == Name ) + addPattern(); + return *this; + } + TestSpec testSpec() { + addFilter(); + return m_testSpec; + } + private: + void visitChar( char c ) { + if( m_mode == None ) { + switch( c ) { + case ' ': return; + case '~': m_exclusion = true; return; + case '[': return startNewMode( Tag, ++m_pos ); + case '"': return startNewMode( QuotedName, ++m_pos ); + default: startNewMode( Name, m_pos ); break; + } + } + if( m_mode == Name ) { + if( c == ',' ) { + addPattern(); + addFilter(); + } + else if( c == '[' ) { + if( subString() == "exclude:" ) + m_exclusion = true; + else + addPattern(); + startNewMode( Tag, ++m_pos ); + } + } + else if( m_mode == QuotedName && c == '"' ) + addPattern(); + else if( m_mode == Tag && c == ']' ) + addPattern(); + } + void startNewMode( Mode mode, std::size_t start ) { + m_mode = mode; + m_start = start; + } + std::string subString() const { return m_arg.substr( m_start, m_pos - m_start ); } + template + void addPattern() { + std::string token = subString(); + if( startsWith( token, "exclude:" ) ) { + m_exclusion = true; + token = token.substr( 8 ); + } + if( !token.empty() ) { + Ptr pattern = new T( token ); + if( m_exclusion ) + pattern = new TestSpec::ExcludedPattern( pattern ); + m_currentFilter.m_patterns.push_back( pattern ); + } + m_exclusion = false; + m_mode = None; + } + void addFilter() { + if( !m_currentFilter.m_patterns.empty() ) { + m_testSpec.m_filters.push_back( m_currentFilter ); + m_currentFilter = TestSpec::Filter(); + } + } + }; + inline TestSpec parseTestSpec( std::string const& arg ) { + return TestSpecParser( ITagAliasRegistry::get() ).parse( arg ).testSpec(); + } + +} // namespace Catch + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +// #included from: catch_interfaces_config.h +#define TWOBLUECUBES_CATCH_INTERFACES_CONFIG_H_INCLUDED + +#include +#include +#include + +namespace Catch { + + struct Verbosity { enum Level { + NoOutput = 0, + Quiet, + Normal + }; }; + + struct WarnAbout { enum What { + Nothing = 0x00, + NoAssertions = 0x01 + }; }; + + struct ShowDurations { enum OrNot { + DefaultForReporter, + Always, + Never + }; }; + struct RunTests { enum InWhatOrder { + InDeclarationOrder, + InLexicographicalOrder, + InRandomOrder + }; }; + struct UseColour { enum YesOrNo { + Auto, + Yes, + No + }; }; + + class TestSpec; + + struct IConfig : IShared { + + virtual ~IConfig(); + + virtual bool allowThrows() const = 0; + virtual std::ostream& stream() const = 0; + virtual std::string name() const = 0; + virtual bool includeSuccessfulResults() const = 0; + virtual bool shouldDebugBreak() const = 0; + virtual bool warnAboutMissingAssertions() const = 0; + virtual int abortAfter() const = 0; + virtual bool showInvisibles() const = 0; + virtual ShowDurations::OrNot showDurations() const = 0; + virtual TestSpec const& testSpec() const = 0; + virtual RunTests::InWhatOrder runOrder() const = 0; + virtual unsigned int rngSeed() const = 0; + virtual UseColour::YesOrNo useColour() const = 0; + }; +} + +// #included from: catch_stream.h +#define TWOBLUECUBES_CATCH_STREAM_H_INCLUDED + +// #included from: catch_streambuf.h +#define TWOBLUECUBES_CATCH_STREAMBUF_H_INCLUDED + +#include + +namespace Catch { + + class StreamBufBase : public std::streambuf { + public: + virtual ~StreamBufBase() CATCH_NOEXCEPT; + }; +} + +#include +#include +#include + +namespace Catch { + + std::ostream& cout(); + std::ostream& cerr(); + + struct IStream { + virtual ~IStream() CATCH_NOEXCEPT; + virtual std::ostream& stream() const = 0; + }; + + class FileStream : public IStream { + mutable std::ofstream m_ofs; + public: + FileStream( std::string const& filename ); + virtual ~FileStream() CATCH_NOEXCEPT; + public: // IStream + virtual std::ostream& stream() const CATCH_OVERRIDE; + }; + + class CoutStream : public IStream { + mutable std::ostream m_os; + public: + CoutStream(); + virtual ~CoutStream() CATCH_NOEXCEPT; + + public: // IStream + virtual std::ostream& stream() const CATCH_OVERRIDE; + }; + + class DebugOutStream : public IStream { + std::auto_ptr m_streamBuf; + mutable std::ostream m_os; + public: + DebugOutStream(); + virtual ~DebugOutStream() CATCH_NOEXCEPT; + + public: // IStream + virtual std::ostream& stream() const CATCH_OVERRIDE; + }; +} + +#include +#include +#include +#include +#include + +#ifndef CATCH_CONFIG_CONSOLE_WIDTH +#define CATCH_CONFIG_CONSOLE_WIDTH 80 +#endif + +namespace Catch { + + struct ConfigData { + + ConfigData() + : listTests( false ), + listTags( false ), + listReporters( false ), + listTestNamesOnly( false ), + showSuccessfulTests( false ), + shouldDebugBreak( false ), + noThrow( false ), + showHelp( false ), + showInvisibles( false ), + filenamesAsTags( false ), + abortAfter( -1 ), + rngSeed( 0 ), + verbosity( Verbosity::Normal ), + warnings( WarnAbout::Nothing ), + showDurations( ShowDurations::DefaultForReporter ), + runOrder( RunTests::InDeclarationOrder ), + useColour( UseColour::Auto ) + {} + + bool listTests; + bool listTags; + bool listReporters; + bool listTestNamesOnly; + + bool showSuccessfulTests; + bool shouldDebugBreak; + bool noThrow; + bool showHelp; + bool showInvisibles; + bool filenamesAsTags; + + int abortAfter; + unsigned int rngSeed; + + Verbosity::Level verbosity; + WarnAbout::What warnings; + ShowDurations::OrNot showDurations; + RunTests::InWhatOrder runOrder; + UseColour::YesOrNo useColour; + + std::string outputFilename; + std::string name; + std::string processName; + + std::vector reporterNames; + std::vector testsOrTags; + }; + + class Config : public SharedImpl { + private: + Config( Config const& other ); + Config& operator = ( Config const& other ); + virtual void dummy(); + public: + + Config() + {} + + Config( ConfigData const& data ) + : m_data( data ), + m_stream( openStream() ) + { + if( !data.testsOrTags.empty() ) { + TestSpecParser parser( ITagAliasRegistry::get() ); + for( std::size_t i = 0; i < data.testsOrTags.size(); ++i ) + parser.parse( data.testsOrTags[i] ); + m_testSpec = parser.testSpec(); + } + } + + virtual ~Config() { + } + + std::string const& getFilename() const { + return m_data.outputFilename ; + } + + bool listTests() const { return m_data.listTests; } + bool listTestNamesOnly() const { return m_data.listTestNamesOnly; } + bool listTags() const { return m_data.listTags; } + bool listReporters() const { return m_data.listReporters; } + + std::string getProcessName() const { return m_data.processName; } + + bool shouldDebugBreak() const { return m_data.shouldDebugBreak; } + + std::vector getReporterNames() const { return m_data.reporterNames; } + + int abortAfter() const { return m_data.abortAfter; } + + TestSpec const& testSpec() const { return m_testSpec; } + + bool showHelp() const { return m_data.showHelp; } + bool showInvisibles() const { return m_data.showInvisibles; } + + // IConfig interface + virtual bool allowThrows() const { return !m_data.noThrow; } + virtual std::ostream& stream() const { return m_stream->stream(); } + virtual std::string name() const { return m_data.name.empty() ? m_data.processName : m_data.name; } + virtual bool includeSuccessfulResults() const { return m_data.showSuccessfulTests; } + virtual bool warnAboutMissingAssertions() const { return m_data.warnings & WarnAbout::NoAssertions; } + virtual ShowDurations::OrNot showDurations() const { return m_data.showDurations; } + virtual RunTests::InWhatOrder runOrder() const { return m_data.runOrder; } + virtual unsigned int rngSeed() const { return m_data.rngSeed; } + virtual UseColour::YesOrNo useColour() const { return m_data.useColour; } + + private: + + IStream const* openStream() { + if( m_data.outputFilename.empty() ) + return new CoutStream(); + else if( m_data.outputFilename[0] == '%' ) { + if( m_data.outputFilename == "%debug" ) + return new DebugOutStream(); + else + throw std::domain_error( "Unrecognised stream: " + m_data.outputFilename ); + } + else + return new FileStream( m_data.outputFilename ); + } + ConfigData m_data; + + std::auto_ptr m_stream; + TestSpec m_testSpec; + }; + +} // end namespace Catch + +// #included from: catch_clara.h +#define TWOBLUECUBES_CATCH_CLARA_H_INCLUDED + +// Use Catch's value for console width (store Clara's off to the side, if present) +#ifdef CLARA_CONFIG_CONSOLE_WIDTH +#define CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH CLARA_CONFIG_CONSOLE_WIDTH +#undef CLARA_CONFIG_CONSOLE_WIDTH +#endif +#define CLARA_CONFIG_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH + +// Declare Clara inside the Catch namespace +#define STITCH_CLARA_OPEN_NAMESPACE namespace Catch { +// #included from: ../external/clara.h + +// Version 0.0.1.1 + +// Only use header guard if we are not using an outer namespace +#if !defined(TWOBLUECUBES_CLARA_H_INCLUDED) || defined(STITCH_CLARA_OPEN_NAMESPACE) + +#ifndef STITCH_CLARA_OPEN_NAMESPACE +#define TWOBLUECUBES_CLARA_H_INCLUDED +#define STITCH_CLARA_OPEN_NAMESPACE +#define STITCH_CLARA_CLOSE_NAMESPACE +#else +#define STITCH_CLARA_CLOSE_NAMESPACE } +#endif + +#define STITCH_TBC_TEXT_FORMAT_OPEN_NAMESPACE STITCH_CLARA_OPEN_NAMESPACE + +// ----------- #included from tbc_text_format.h ----------- + +// Only use header guard if we are not using an outer namespace +#if !defined(TBC_TEXT_FORMAT_H_INCLUDED) || defined(STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE) +#ifndef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE +#define TBC_TEXT_FORMAT_H_INCLUDED +#endif + +#include +#include +#include +#include + +// Use optional outer namespace +#ifdef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE +namespace STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE { +#endif + +namespace Tbc { + +#ifdef TBC_TEXT_FORMAT_CONSOLE_WIDTH + const unsigned int consoleWidth = TBC_TEXT_FORMAT_CONSOLE_WIDTH; +#else + const unsigned int consoleWidth = 80; +#endif + + struct TextAttributes { + TextAttributes() + : initialIndent( std::string::npos ), + indent( 0 ), + width( consoleWidth-1 ), + tabChar( '\t' ) + {} + + TextAttributes& setInitialIndent( std::size_t _value ) { initialIndent = _value; return *this; } + TextAttributes& setIndent( std::size_t _value ) { indent = _value; return *this; } + TextAttributes& setWidth( std::size_t _value ) { width = _value; return *this; } + TextAttributes& setTabChar( char _value ) { tabChar = _value; return *this; } + + std::size_t initialIndent; // indent of first line, or npos + std::size_t indent; // indent of subsequent lines, or all if initialIndent is npos + std::size_t width; // maximum width of text, including indent. Longer text will wrap + char tabChar; // If this char is seen the indent is changed to current pos + }; + + class Text { + public: + Text( std::string const& _str, TextAttributes const& _attr = TextAttributes() ) + : attr( _attr ) + { + std::string wrappableChars = " [({.,/|\\-"; + std::size_t indent = _attr.initialIndent != std::string::npos + ? _attr.initialIndent + : _attr.indent; + std::string remainder = _str; + + while( !remainder.empty() ) { + if( lines.size() >= 1000 ) { + lines.push_back( "... message truncated due to excessive size" ); + return; + } + std::size_t tabPos = std::string::npos; + std::size_t width = (std::min)( remainder.size(), _attr.width - indent ); + std::size_t pos = remainder.find_first_of( '\n' ); + if( pos <= width ) { + width = pos; + } + pos = remainder.find_last_of( _attr.tabChar, width ); + if( pos != std::string::npos ) { + tabPos = pos; + if( remainder[width] == '\n' ) + width--; + remainder = remainder.substr( 0, tabPos ) + remainder.substr( tabPos+1 ); + } + + if( width == remainder.size() ) { + spliceLine( indent, remainder, width ); + } + else if( remainder[width] == '\n' ) { + spliceLine( indent, remainder, width ); + if( width <= 1 || remainder.size() != 1 ) + remainder = remainder.substr( 1 ); + indent = _attr.indent; + } + else { + pos = remainder.find_last_of( wrappableChars, width ); + if( pos != std::string::npos && pos > 0 ) { + spliceLine( indent, remainder, pos ); + if( remainder[0] == ' ' ) + remainder = remainder.substr( 1 ); + } + else { + spliceLine( indent, remainder, width-1 ); + lines.back() += "-"; + } + if( lines.size() == 1 ) + indent = _attr.indent; + if( tabPos != std::string::npos ) + indent += tabPos; + } + } + } + + void spliceLine( std::size_t _indent, std::string& _remainder, std::size_t _pos ) { + lines.push_back( std::string( _indent, ' ' ) + _remainder.substr( 0, _pos ) ); + _remainder = _remainder.substr( _pos ); + } + + typedef std::vector::const_iterator const_iterator; + + const_iterator begin() const { return lines.begin(); } + const_iterator end() const { return lines.end(); } + std::string const& last() const { return lines.back(); } + std::size_t size() const { return lines.size(); } + std::string const& operator[]( std::size_t _index ) const { return lines[_index]; } + std::string toString() const { + std::ostringstream oss; + oss << *this; + return oss.str(); + } + + inline friend std::ostream& operator << ( std::ostream& _stream, Text const& _text ) { + for( Text::const_iterator it = _text.begin(), itEnd = _text.end(); + it != itEnd; ++it ) { + if( it != _text.begin() ) + _stream << "\n"; + _stream << *it; + } + return _stream; + } + + private: + std::string str; + TextAttributes attr; + std::vector lines; + }; + +} // end namespace Tbc + +#ifdef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE +} // end outer namespace +#endif + +#endif // TBC_TEXT_FORMAT_H_INCLUDED + +// ----------- end of #include from tbc_text_format.h ----------- +// ........... back in clara.h + +#undef STITCH_TBC_TEXT_FORMAT_OPEN_NAMESPACE + +// ----------- #included from clara_compilers.h ----------- + +#ifndef TWOBLUECUBES_CLARA_COMPILERS_H_INCLUDED +#define TWOBLUECUBES_CLARA_COMPILERS_H_INCLUDED + +// Detect a number of compiler features - mostly C++11/14 conformance - by compiler +// The following features are defined: +// +// CLARA_CONFIG_CPP11_NULLPTR : is nullptr supported? +// CLARA_CONFIG_CPP11_NOEXCEPT : is noexcept supported? +// CLARA_CONFIG_CPP11_GENERATED_METHODS : The delete and default keywords for compiler generated methods +// CLARA_CONFIG_CPP11_OVERRIDE : is override supported? +// CLARA_CONFIG_CPP11_UNIQUE_PTR : is unique_ptr supported (otherwise use auto_ptr) + +// CLARA_CONFIG_CPP11_OR_GREATER : Is C++11 supported? + +// CLARA_CONFIG_VARIADIC_MACROS : are variadic macros supported? + +// In general each macro has a _NO_ form +// (e.g. CLARA_CONFIG_CPP11_NO_NULLPTR) which disables the feature. +// Many features, at point of detection, define an _INTERNAL_ macro, so they +// can be combined, en-mass, with the _NO_ forms later. + +// All the C++11 features can be disabled with CLARA_CONFIG_NO_CPP11 + +#ifdef __clang__ + +#if __has_feature(cxx_nullptr) +#define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR +#endif + +#if __has_feature(cxx_noexcept) +#define CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT +#endif + +#endif // __clang__ + +//////////////////////////////////////////////////////////////////////////////// +// GCC +#ifdef __GNUC__ + +#if __GNUC__ == 4 && __GNUC_MINOR__ >= 6 && defined(__GXX_EXPERIMENTAL_CXX0X__) +#define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR +#endif + +// - otherwise more recent versions define __cplusplus >= 201103L +// and will get picked up below + +#endif // __GNUC__ + +//////////////////////////////////////////////////////////////////////////////// +// Visual C++ +#ifdef _MSC_VER + +#if (_MSC_VER >= 1600) +#define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR +#define CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR +#endif + +#if (_MSC_VER >= 1900 ) // (VC++ 13 (VS2015)) +#define CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT +#define CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS +#endif + +#endif // _MSC_VER + +//////////////////////////////////////////////////////////////////////////////// +// C++ language feature support + +// catch all support for C++11 +#if defined(__cplusplus) && __cplusplus >= 201103L + +#define CLARA_CPP11_OR_GREATER + +#if !defined(CLARA_INTERNAL_CONFIG_CPP11_NULLPTR) +#define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR +#endif + +#ifndef CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT +#define CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT +#endif + +#ifndef CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS +#define CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS +#endif + +#if !defined(CLARA_INTERNAL_CONFIG_CPP11_OVERRIDE) +#define CLARA_INTERNAL_CONFIG_CPP11_OVERRIDE +#endif +#if !defined(CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) +#define CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR +#endif + +#endif // __cplusplus >= 201103L + +// Now set the actual defines based on the above + anything the user has configured +#if defined(CLARA_INTERNAL_CONFIG_CPP11_NULLPTR) && !defined(CLARA_CONFIG_CPP11_NO_NULLPTR) && !defined(CLARA_CONFIG_CPP11_NULLPTR) && !defined(CLARA_CONFIG_NO_CPP11) +#define CLARA_CONFIG_CPP11_NULLPTR +#endif +#if defined(CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT) && !defined(CLARA_CONFIG_CPP11_NO_NOEXCEPT) && !defined(CLARA_CONFIG_CPP11_NOEXCEPT) && !defined(CLARA_CONFIG_NO_CPP11) +#define CLARA_CONFIG_CPP11_NOEXCEPT +#endif +#if defined(CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS) && !defined(CLARA_CONFIG_CPP11_NO_GENERATED_METHODS) && !defined(CLARA_CONFIG_CPP11_GENERATED_METHODS) && !defined(CLARA_CONFIG_NO_CPP11) +#define CLARA_CONFIG_CPP11_GENERATED_METHODS +#endif +#if defined(CLARA_INTERNAL_CONFIG_CPP11_OVERRIDE) && !defined(CLARA_CONFIG_NO_OVERRIDE) && !defined(CLARA_CONFIG_CPP11_OVERRIDE) && !defined(CLARA_CONFIG_NO_CPP11) +#define CLARA_CONFIG_CPP11_OVERRIDE +#endif +#if defined(CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) && !defined(CLARA_CONFIG_NO_UNIQUE_PTR) && !defined(CLARA_CONFIG_CPP11_UNIQUE_PTR) && !defined(CLARA_CONFIG_NO_CPP11) +#define CLARA_CONFIG_CPP11_UNIQUE_PTR +#endif + +// noexcept support: +#if defined(CLARA_CONFIG_CPP11_NOEXCEPT) && !defined(CLARA_NOEXCEPT) +#define CLARA_NOEXCEPT noexcept +# define CLARA_NOEXCEPT_IS(x) noexcept(x) +#else +#define CLARA_NOEXCEPT throw() +# define CLARA_NOEXCEPT_IS(x) +#endif + +// nullptr support +#ifdef CLARA_CONFIG_CPP11_NULLPTR +#define CLARA_NULL nullptr +#else +#define CLARA_NULL NULL +#endif + +// override support +#ifdef CLARA_CONFIG_CPP11_OVERRIDE +#define CLARA_OVERRIDE override +#else +#define CLARA_OVERRIDE +#endif + +// unique_ptr support +#ifdef CLARA_CONFIG_CPP11_UNIQUE_PTR +# define CLARA_AUTO_PTR( T ) std::unique_ptr +#else +# define CLARA_AUTO_PTR( T ) std::auto_ptr +#endif + +#endif // TWOBLUECUBES_CLARA_COMPILERS_H_INCLUDED + +// ----------- end of #include from clara_compilers.h ----------- +// ........... back in clara.h + +#include +#include +#include + +// Use optional outer namespace +#ifdef STITCH_CLARA_OPEN_NAMESPACE +STITCH_CLARA_OPEN_NAMESPACE +#endif + +namespace Clara { + + struct UnpositionalTag {}; + + extern UnpositionalTag _; + +#ifdef CLARA_CONFIG_MAIN + UnpositionalTag _; +#endif + + namespace Detail { + +#ifdef CLARA_CONSOLE_WIDTH + const unsigned int consoleWidth = CLARA_CONFIG_CONSOLE_WIDTH; +#else + const unsigned int consoleWidth = 80; +#endif + + // Use this to try and stop compiler from warning about unreachable code + inline bool isTrue( bool value ) { return value; } + + using namespace Tbc; + + inline bool startsWith( std::string const& str, std::string const& prefix ) { + return str.size() >= prefix.size() && str.substr( 0, prefix.size() ) == prefix; + } + + template struct RemoveConstRef{ typedef T type; }; + template struct RemoveConstRef{ typedef T type; }; + template struct RemoveConstRef{ typedef T type; }; + template struct RemoveConstRef{ typedef T type; }; + + template struct IsBool { static const bool value = false; }; + template<> struct IsBool { static const bool value = true; }; + + template + void convertInto( std::string const& _source, T& _dest ) { + std::stringstream ss; + ss << _source; + ss >> _dest; + if( ss.fail() ) + throw std::runtime_error( "Unable to convert " + _source + " to destination type" ); + } + inline void convertInto( std::string const& _source, std::string& _dest ) { + _dest = _source; + } + inline void convertInto( std::string const& _source, bool& _dest ) { + std::string sourceLC = _source; + std::transform( sourceLC.begin(), sourceLC.end(), sourceLC.begin(), ::tolower ); + if( sourceLC == "y" || sourceLC == "1" || sourceLC == "true" || sourceLC == "yes" || sourceLC == "on" ) + _dest = true; + else if( sourceLC == "n" || sourceLC == "0" || sourceLC == "false" || sourceLC == "no" || sourceLC == "off" ) + _dest = false; + else + throw std::runtime_error( "Expected a boolean value but did not recognise:\n '" + _source + "'" ); + } + inline void convertInto( bool _source, bool& _dest ) { + _dest = _source; + } + template + inline void convertInto( bool, T& ) { + if( isTrue( true ) ) + throw std::runtime_error( "Invalid conversion" ); + } + + template + struct IArgFunction { + virtual ~IArgFunction() {} +#ifdef CLARA_CONFIG_CPP11_GENERATED_METHODS + IArgFunction() = default; + IArgFunction( IArgFunction const& ) = default; +#endif + virtual void set( ConfigT& config, std::string const& value ) const = 0; + virtual void setFlag( ConfigT& config ) const = 0; + virtual bool takesArg() const = 0; + virtual IArgFunction* clone() const = 0; + }; + + template + class BoundArgFunction { + public: + BoundArgFunction() : functionObj( CLARA_NULL ) {} + BoundArgFunction( IArgFunction* _functionObj ) : functionObj( _functionObj ) {} + BoundArgFunction( BoundArgFunction const& other ) : functionObj( other.functionObj ? other.functionObj->clone() : CLARA_NULL ) {} + BoundArgFunction& operator = ( BoundArgFunction const& other ) { + IArgFunction* newFunctionObj = other.functionObj ? other.functionObj->clone() : CLARA_NULL; + delete functionObj; + functionObj = newFunctionObj; + return *this; + } + ~BoundArgFunction() { delete functionObj; } + + void set( ConfigT& config, std::string const& value ) const { + functionObj->set( config, value ); + } + void setFlag( ConfigT& config ) const { + functionObj->setFlag( config ); + } + bool takesArg() const { return functionObj->takesArg(); } + + bool isSet() const { + return functionObj != CLARA_NULL; + } + private: + IArgFunction* functionObj; + }; + + template + struct NullBinder : IArgFunction{ + virtual void set( C&, std::string const& ) const {} + virtual void setFlag( C& ) const {} + virtual bool takesArg() const { return true; } + virtual IArgFunction* clone() const { return new NullBinder( *this ); } + }; + + template + struct BoundDataMember : IArgFunction{ + BoundDataMember( M C::* _member ) : member( _member ) {} + virtual void set( C& p, std::string const& stringValue ) const { + convertInto( stringValue, p.*member ); + } + virtual void setFlag( C& p ) const { + convertInto( true, p.*member ); + } + virtual bool takesArg() const { return !IsBool::value; } + virtual IArgFunction* clone() const { return new BoundDataMember( *this ); } + M C::* member; + }; + template + struct BoundUnaryMethod : IArgFunction{ + BoundUnaryMethod( void (C::*_member)( M ) ) : member( _member ) {} + virtual void set( C& p, std::string const& stringValue ) const { + typename RemoveConstRef::type value; + convertInto( stringValue, value ); + (p.*member)( value ); + } + virtual void setFlag( C& p ) const { + typename RemoveConstRef::type value; + convertInto( true, value ); + (p.*member)( value ); + } + virtual bool takesArg() const { return !IsBool::value; } + virtual IArgFunction* clone() const { return new BoundUnaryMethod( *this ); } + void (C::*member)( M ); + }; + template + struct BoundNullaryMethod : IArgFunction{ + BoundNullaryMethod( void (C::*_member)() ) : member( _member ) {} + virtual void set( C& p, std::string const& stringValue ) const { + bool value; + convertInto( stringValue, value ); + if( value ) + (p.*member)(); + } + virtual void setFlag( C& p ) const { + (p.*member)(); + } + virtual bool takesArg() const { return false; } + virtual IArgFunction* clone() const { return new BoundNullaryMethod( *this ); } + void (C::*member)(); + }; + + template + struct BoundUnaryFunction : IArgFunction{ + BoundUnaryFunction( void (*_function)( C& ) ) : function( _function ) {} + virtual void set( C& obj, std::string const& stringValue ) const { + bool value; + convertInto( stringValue, value ); + if( value ) + function( obj ); + } + virtual void setFlag( C& p ) const { + function( p ); + } + virtual bool takesArg() const { return false; } + virtual IArgFunction* clone() const { return new BoundUnaryFunction( *this ); } + void (*function)( C& ); + }; + + template + struct BoundBinaryFunction : IArgFunction{ + BoundBinaryFunction( void (*_function)( C&, T ) ) : function( _function ) {} + virtual void set( C& obj, std::string const& stringValue ) const { + typename RemoveConstRef::type value; + convertInto( stringValue, value ); + function( obj, value ); + } + virtual void setFlag( C& obj ) const { + typename RemoveConstRef::type value; + convertInto( true, value ); + function( obj, value ); + } + virtual bool takesArg() const { return !IsBool::value; } + virtual IArgFunction* clone() const { return new BoundBinaryFunction( *this ); } + void (*function)( C&, T ); + }; + + } // namespace Detail + + struct Parser { + Parser() : separators( " \t=:" ) {} + + struct Token { + enum Type { Positional, ShortOpt, LongOpt }; + Token( Type _type, std::string const& _data ) : type( _type ), data( _data ) {} + Type type; + std::string data; + }; + + void parseIntoTokens( int argc, char const* const argv[], std::vector& tokens ) const { + const std::string doubleDash = "--"; + for( int i = 1; i < argc && argv[i] != doubleDash; ++i ) + parseIntoTokens( argv[i] , tokens); + } + void parseIntoTokens( std::string arg, std::vector& tokens ) const { + while( !arg.empty() ) { + Parser::Token token( Parser::Token::Positional, arg ); + arg = ""; + if( token.data[0] == '-' ) { + if( token.data.size() > 1 && token.data[1] == '-' ) { + token = Parser::Token( Parser::Token::LongOpt, token.data.substr( 2 ) ); + } + else { + token = Parser::Token( Parser::Token::ShortOpt, token.data.substr( 1 ) ); + if( token.data.size() > 1 && separators.find( token.data[1] ) == std::string::npos ) { + arg = "-" + token.data.substr( 1 ); + token.data = token.data.substr( 0, 1 ); + } + } + } + if( token.type != Parser::Token::Positional ) { + std::size_t pos = token.data.find_first_of( separators ); + if( pos != std::string::npos ) { + arg = token.data.substr( pos+1 ); + token.data = token.data.substr( 0, pos ); + } + } + tokens.push_back( token ); + } + } + std::string separators; + }; + + template + struct CommonArgProperties { + CommonArgProperties() {} + CommonArgProperties( Detail::BoundArgFunction const& _boundField ) : boundField( _boundField ) {} + + Detail::BoundArgFunction boundField; + std::string description; + std::string detail; + std::string placeholder; // Only value if boundField takes an arg + + bool takesArg() const { + return !placeholder.empty(); + } + void validate() const { + if( !boundField.isSet() ) + throw std::logic_error( "option not bound" ); + } + }; + struct OptionArgProperties { + std::vector shortNames; + std::string longName; + + bool hasShortName( std::string const& shortName ) const { + return std::find( shortNames.begin(), shortNames.end(), shortName ) != shortNames.end(); + } + bool hasLongName( std::string const& _longName ) const { + return _longName == longName; + } + }; + struct PositionalArgProperties { + PositionalArgProperties() : position( -1 ) {} + int position; // -1 means non-positional (floating) + + bool isFixedPositional() const { + return position != -1; + } + }; + + template + class CommandLine { + + struct Arg : CommonArgProperties, OptionArgProperties, PositionalArgProperties { + Arg() {} + Arg( Detail::BoundArgFunction const& _boundField ) : CommonArgProperties( _boundField ) {} + + using CommonArgProperties::placeholder; // !TBD + + std::string dbgName() const { + if( !longName.empty() ) + return "--" + longName; + if( !shortNames.empty() ) + return "-" + shortNames[0]; + return "positional args"; + } + std::string commands() const { + std::ostringstream oss; + bool first = true; + std::vector::const_iterator it = shortNames.begin(), itEnd = shortNames.end(); + for(; it != itEnd; ++it ) { + if( first ) + first = false; + else + oss << ", "; + oss << "-" << *it; + } + if( !longName.empty() ) { + if( !first ) + oss << ", "; + oss << "--" << longName; + } + if( !placeholder.empty() ) + oss << " <" << placeholder << ">"; + return oss.str(); + } + }; + + typedef CLARA_AUTO_PTR( Arg ) ArgAutoPtr; + + friend void addOptName( Arg& arg, std::string const& optName ) + { + if( optName.empty() ) + return; + if( Detail::startsWith( optName, "--" ) ) { + if( !arg.longName.empty() ) + throw std::logic_error( "Only one long opt may be specified. '" + + arg.longName + + "' already specified, now attempting to add '" + + optName + "'" ); + arg.longName = optName.substr( 2 ); + } + else if( Detail::startsWith( optName, "-" ) ) + arg.shortNames.push_back( optName.substr( 1 ) ); + else + throw std::logic_error( "option must begin with - or --. Option was: '" + optName + "'" ); + } + friend void setPositionalArg( Arg& arg, int position ) + { + arg.position = position; + } + + class ArgBuilder { + public: + ArgBuilder( Arg* arg ) : m_arg( arg ) {} + + // Bind a non-boolean data member (requires placeholder string) + template + void bind( M C::* field, std::string const& placeholder ) { + m_arg->boundField = new Detail::BoundDataMember( field ); + m_arg->placeholder = placeholder; + } + // Bind a boolean data member (no placeholder required) + template + void bind( bool C::* field ) { + m_arg->boundField = new Detail::BoundDataMember( field ); + } + + // Bind a method taking a single, non-boolean argument (requires a placeholder string) + template + void bind( void (C::* unaryMethod)( M ), std::string const& placeholder ) { + m_arg->boundField = new Detail::BoundUnaryMethod( unaryMethod ); + m_arg->placeholder = placeholder; + } + + // Bind a method taking a single, boolean argument (no placeholder string required) + template + void bind( void (C::* unaryMethod)( bool ) ) { + m_arg->boundField = new Detail::BoundUnaryMethod( unaryMethod ); + } + + // Bind a method that takes no arguments (will be called if opt is present) + template + void bind( void (C::* nullaryMethod)() ) { + m_arg->boundField = new Detail::BoundNullaryMethod( nullaryMethod ); + } + + // Bind a free function taking a single argument - the object to operate on (no placeholder string required) + template + void bind( void (* unaryFunction)( C& ) ) { + m_arg->boundField = new Detail::BoundUnaryFunction( unaryFunction ); + } + + // Bind a free function taking a single argument - the object to operate on (requires a placeholder string) + template + void bind( void (* binaryFunction)( C&, T ), std::string const& placeholder ) { + m_arg->boundField = new Detail::BoundBinaryFunction( binaryFunction ); + m_arg->placeholder = placeholder; + } + + ArgBuilder& describe( std::string const& description ) { + m_arg->description = description; + return *this; + } + ArgBuilder& detail( std::string const& detail ) { + m_arg->detail = detail; + return *this; + } + + protected: + Arg* m_arg; + }; + + class OptBuilder : public ArgBuilder { + public: + OptBuilder( Arg* arg ) : ArgBuilder( arg ) {} + OptBuilder( OptBuilder& other ) : ArgBuilder( other ) {} + + OptBuilder& operator[]( std::string const& optName ) { + addOptName( *ArgBuilder::m_arg, optName ); + return *this; + } + }; + + public: + + CommandLine() + : m_boundProcessName( new Detail::NullBinder() ), + m_highestSpecifiedArgPosition( 0 ), + m_throwOnUnrecognisedTokens( false ) + {} + CommandLine( CommandLine const& other ) + : m_boundProcessName( other.m_boundProcessName ), + m_options ( other.m_options ), + m_positionalArgs( other.m_positionalArgs ), + m_highestSpecifiedArgPosition( other.m_highestSpecifiedArgPosition ), + m_throwOnUnrecognisedTokens( other.m_throwOnUnrecognisedTokens ) + { + if( other.m_floatingArg.get() ) + m_floatingArg.reset( new Arg( *other.m_floatingArg ) ); + } + + CommandLine& setThrowOnUnrecognisedTokens( bool shouldThrow = true ) { + m_throwOnUnrecognisedTokens = shouldThrow; + return *this; + } + + OptBuilder operator[]( std::string const& optName ) { + m_options.push_back( Arg() ); + addOptName( m_options.back(), optName ); + OptBuilder builder( &m_options.back() ); + return builder; + } + + ArgBuilder operator[]( int position ) { + m_positionalArgs.insert( std::make_pair( position, Arg() ) ); + if( position > m_highestSpecifiedArgPosition ) + m_highestSpecifiedArgPosition = position; + setPositionalArg( m_positionalArgs[position], position ); + ArgBuilder builder( &m_positionalArgs[position] ); + return builder; + } + + // Invoke this with the _ instance + ArgBuilder operator[]( UnpositionalTag ) { + if( m_floatingArg.get() ) + throw std::logic_error( "Only one unpositional argument can be added" ); + m_floatingArg.reset( new Arg() ); + ArgBuilder builder( m_floatingArg.get() ); + return builder; + } + + template + void bindProcessName( M C::* field ) { + m_boundProcessName = new Detail::BoundDataMember( field ); + } + template + void bindProcessName( void (C::*_unaryMethod)( M ) ) { + m_boundProcessName = new Detail::BoundUnaryMethod( _unaryMethod ); + } + + void optUsage( std::ostream& os, std::size_t indent = 0, std::size_t width = Detail::consoleWidth ) const { + typename std::vector::const_iterator itBegin = m_options.begin(), itEnd = m_options.end(), it; + std::size_t maxWidth = 0; + for( it = itBegin; it != itEnd; ++it ) + maxWidth = (std::max)( maxWidth, it->commands().size() ); + + for( it = itBegin; it != itEnd; ++it ) { + Detail::Text usage( it->commands(), Detail::TextAttributes() + .setWidth( maxWidth+indent ) + .setIndent( indent ) ); + Detail::Text desc( it->description, Detail::TextAttributes() + .setWidth( width - maxWidth - 3 ) ); + + for( std::size_t i = 0; i < (std::max)( usage.size(), desc.size() ); ++i ) { + std::string usageCol = i < usage.size() ? usage[i] : ""; + os << usageCol; + + if( i < desc.size() && !desc[i].empty() ) + os << std::string( indent + 2 + maxWidth - usageCol.size(), ' ' ) + << desc[i]; + os << "\n"; + } + } + } + std::string optUsage() const { + std::ostringstream oss; + optUsage( oss ); + return oss.str(); + } + + void argSynopsis( std::ostream& os ) const { + for( int i = 1; i <= m_highestSpecifiedArgPosition; ++i ) { + if( i > 1 ) + os << " "; + typename std::map::const_iterator it = m_positionalArgs.find( i ); + if( it != m_positionalArgs.end() ) + os << "<" << it->second.placeholder << ">"; + else if( m_floatingArg.get() ) + os << "<" << m_floatingArg->placeholder << ">"; + else + throw std::logic_error( "non consecutive positional arguments with no floating args" ); + } + // !TBD No indication of mandatory args + if( m_floatingArg.get() ) { + if( m_highestSpecifiedArgPosition > 1 ) + os << " "; + os << "[<" << m_floatingArg->placeholder << "> ...]"; + } + } + std::string argSynopsis() const { + std::ostringstream oss; + argSynopsis( oss ); + return oss.str(); + } + + void usage( std::ostream& os, std::string const& procName ) const { + validate(); + os << "usage:\n " << procName << " "; + argSynopsis( os ); + if( !m_options.empty() ) { + os << " [options]\n\nwhere options are: \n"; + optUsage( os, 2 ); + } + os << "\n"; + } + std::string usage( std::string const& procName ) const { + std::ostringstream oss; + usage( oss, procName ); + return oss.str(); + } + + ConfigT parse( int argc, char const* const argv[] ) const { + ConfigT config; + parseInto( argc, argv, config ); + return config; + } + + std::vector parseInto( int argc, char const* argv[], ConfigT& config ) const { + std::string processName = argv[0]; + std::size_t lastSlash = processName.find_last_of( "/\\" ); + if( lastSlash != std::string::npos ) + processName = processName.substr( lastSlash+1 ); + m_boundProcessName.set( config, processName ); + std::vector tokens; + Parser parser; + parser.parseIntoTokens( argc, argv, tokens ); + return populate( tokens, config ); + } + + std::vector populate( std::vector const& tokens, ConfigT& config ) const { + validate(); + std::vector unusedTokens = populateOptions( tokens, config ); + unusedTokens = populateFixedArgs( unusedTokens, config ); + unusedTokens = populateFloatingArgs( unusedTokens, config ); + return unusedTokens; + } + + std::vector populateOptions( std::vector const& tokens, ConfigT& config ) const { + std::vector unusedTokens; + std::vector errors; + for( std::size_t i = 0; i < tokens.size(); ++i ) { + Parser::Token const& token = tokens[i]; + typename std::vector::const_iterator it = m_options.begin(), itEnd = m_options.end(); + for(; it != itEnd; ++it ) { + Arg const& arg = *it; + + try { + if( ( token.type == Parser::Token::ShortOpt && arg.hasShortName( token.data ) ) || + ( token.type == Parser::Token::LongOpt && arg.hasLongName( token.data ) ) ) { + if( arg.takesArg() ) { + if( i == tokens.size()-1 || tokens[i+1].type != Parser::Token::Positional ) + errors.push_back( "Expected argument to option: " + token.data ); + else + arg.boundField.set( config, tokens[++i].data ); + } + else { + arg.boundField.setFlag( config ); + } + break; + } + } + catch( std::exception& ex ) { + errors.push_back( std::string( ex.what() ) + "\n- while parsing: (" + arg.commands() + ")" ); + } + } + if( it == itEnd ) { + if( token.type == Parser::Token::Positional || !m_throwOnUnrecognisedTokens ) + unusedTokens.push_back( token ); + else if( errors.empty() && m_throwOnUnrecognisedTokens ) + errors.push_back( "unrecognised option: " + token.data ); + } + } + if( !errors.empty() ) { + std::ostringstream oss; + for( std::vector::const_iterator it = errors.begin(), itEnd = errors.end(); + it != itEnd; + ++it ) { + if( it != errors.begin() ) + oss << "\n"; + oss << *it; + } + throw std::runtime_error( oss.str() ); + } + return unusedTokens; + } + std::vector populateFixedArgs( std::vector const& tokens, ConfigT& config ) const { + std::vector unusedTokens; + int position = 1; + for( std::size_t i = 0; i < tokens.size(); ++i ) { + Parser::Token const& token = tokens[i]; + typename std::map::const_iterator it = m_positionalArgs.find( position ); + if( it != m_positionalArgs.end() ) + it->second.boundField.set( config, token.data ); + else + unusedTokens.push_back( token ); + if( token.type == Parser::Token::Positional ) + position++; + } + return unusedTokens; + } + std::vector populateFloatingArgs( std::vector const& tokens, ConfigT& config ) const { + if( !m_floatingArg.get() ) + return tokens; + std::vector unusedTokens; + for( std::size_t i = 0; i < tokens.size(); ++i ) { + Parser::Token const& token = tokens[i]; + if( token.type == Parser::Token::Positional ) + m_floatingArg->boundField.set( config, token.data ); + else + unusedTokens.push_back( token ); + } + return unusedTokens; + } + + void validate() const + { + if( m_options.empty() && m_positionalArgs.empty() && !m_floatingArg.get() ) + throw std::logic_error( "No options or arguments specified" ); + + for( typename std::vector::const_iterator it = m_options.begin(), + itEnd = m_options.end(); + it != itEnd; ++it ) + it->validate(); + } + + private: + Detail::BoundArgFunction m_boundProcessName; + std::vector m_options; + std::map m_positionalArgs; + ArgAutoPtr m_floatingArg; + int m_highestSpecifiedArgPosition; + bool m_throwOnUnrecognisedTokens; + }; + +} // end namespace Clara + +STITCH_CLARA_CLOSE_NAMESPACE +#undef STITCH_CLARA_OPEN_NAMESPACE +#undef STITCH_CLARA_CLOSE_NAMESPACE + +#endif // TWOBLUECUBES_CLARA_H_INCLUDED +#undef STITCH_CLARA_OPEN_NAMESPACE + +// Restore Clara's value for console width, if present +#ifdef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH +#define CLARA_CONFIG_CONSOLE_WIDTH CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH +#undef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH +#endif + +#include + +namespace Catch { + + inline void abortAfterFirst( ConfigData& config ) { config.abortAfter = 1; } + inline void abortAfterX( ConfigData& config, int x ) { + if( x < 1 ) + throw std::runtime_error( "Value after -x or --abortAfter must be greater than zero" ); + config.abortAfter = x; + } + inline void addTestOrTags( ConfigData& config, std::string const& _testSpec ) { config.testsOrTags.push_back( _testSpec ); } + inline void addReporterName( ConfigData& config, std::string const& _reporterName ) { config.reporterNames.push_back( _reporterName ); } + + inline void addWarning( ConfigData& config, std::string const& _warning ) { + if( _warning == "NoAssertions" ) + config.warnings = static_cast( config.warnings | WarnAbout::NoAssertions ); + else + throw std::runtime_error( "Unrecognised warning: '" + _warning + "'" ); + } + inline void setOrder( ConfigData& config, std::string const& order ) { + if( startsWith( "declared", order ) ) + config.runOrder = RunTests::InDeclarationOrder; + else if( startsWith( "lexical", order ) ) + config.runOrder = RunTests::InLexicographicalOrder; + else if( startsWith( "random", order ) ) + config.runOrder = RunTests::InRandomOrder; + else + throw std::runtime_error( "Unrecognised ordering: '" + order + "'" ); + } + inline void setRngSeed( ConfigData& config, std::string const& seed ) { + if( seed == "time" ) { + config.rngSeed = static_cast( std::time(0) ); + } + else { + std::stringstream ss; + ss << seed; + ss >> config.rngSeed; + if( ss.fail() ) + throw std::runtime_error( "Argment to --rng-seed should be the word 'time' or a number" ); + } + } + inline void setVerbosity( ConfigData& config, int level ) { + // !TBD: accept strings? + config.verbosity = static_cast( level ); + } + inline void setShowDurations( ConfigData& config, bool _showDurations ) { + config.showDurations = _showDurations + ? ShowDurations::Always + : ShowDurations::Never; + } + inline void setUseColour( ConfigData& config, std::string const& value ) { + std::string mode = toLower( value ); + + if( mode == "yes" ) + config.useColour = UseColour::Yes; + else if( mode == "no" ) + config.useColour = UseColour::No; + else if( mode == "auto" ) + config.useColour = UseColour::Auto; + else + throw std::runtime_error( "colour mode must be one of: auto, yes or no" ); + } + inline void forceColour( ConfigData& config ) { + config.useColour = UseColour::Yes; + } + inline void loadTestNamesFromFile( ConfigData& config, std::string const& _filename ) { + std::ifstream f( _filename.c_str() ); + if( !f.is_open() ) + throw std::domain_error( "Unable to load input file: " + _filename ); + + std::string line; + while( std::getline( f, line ) ) { + line = trim(line); + if( !line.empty() && !startsWith( line, "#" ) ) + addTestOrTags( config, "\"" + line + "\"," ); + } + } + + inline Clara::CommandLine makeCommandLineParser() { + + using namespace Clara; + CommandLine cli; + + cli.bindProcessName( &ConfigData::processName ); + + cli["-?"]["-h"]["--help"] + .describe( "display usage information" ) + .bind( &ConfigData::showHelp ); + + cli["-l"]["--list-tests"] + .describe( "list all/matching test cases" ) + .bind( &ConfigData::listTests ); + + cli["-t"]["--list-tags"] + .describe( "list all/matching tags" ) + .bind( &ConfigData::listTags ); + + cli["-s"]["--success"] + .describe( "include successful tests in output" ) + .bind( &ConfigData::showSuccessfulTests ); + + cli["-b"]["--break"] + .describe( "break into debugger on failure" ) + .bind( &ConfigData::shouldDebugBreak ); + + cli["-e"]["--nothrow"] + .describe( "skip exception tests" ) + .bind( &ConfigData::noThrow ); + + cli["-i"]["--invisibles"] + .describe( "show invisibles (tabs, newlines)" ) + .bind( &ConfigData::showInvisibles ); + + cli["-o"]["--out"] + .describe( "output filename" ) + .bind( &ConfigData::outputFilename, "filename" ); + + cli["-r"]["--reporter"] +// .placeholder( "name[:filename]" ) + .describe( "reporter to use (defaults to console)" ) + .bind( &addReporterName, "name" ); + + cli["-n"]["--name"] + .describe( "suite name" ) + .bind( &ConfigData::name, "name" ); + + cli["-a"]["--abort"] + .describe( "abort at first failure" ) + .bind( &abortAfterFirst ); + + cli["-x"]["--abortx"] + .describe( "abort after x failures" ) + .bind( &abortAfterX, "no. failures" ); + + cli["-w"]["--warn"] + .describe( "enable warnings" ) + .bind( &addWarning, "warning name" ); + +// - needs updating if reinstated +// cli.into( &setVerbosity ) +// .describe( "level of verbosity (0=no output)" ) +// .shortOpt( "v") +// .longOpt( "verbosity" ) +// .placeholder( "level" ); + + cli[_] + .describe( "which test or tests to use" ) + .bind( &addTestOrTags, "test name, pattern or tags" ); + + cli["-d"]["--durations"] + .describe( "show test durations" ) + .bind( &setShowDurations, "yes|no" ); + + cli["-f"]["--input-file"] + .describe( "load test names to run from a file" ) + .bind( &loadTestNamesFromFile, "filename" ); + + cli["-#"]["--filenames-as-tags"] + .describe( "adds a tag for the filename" ) + .bind( &ConfigData::filenamesAsTags ); + + // Less common commands which don't have a short form + cli["--list-test-names-only"] + .describe( "list all/matching test cases names only" ) + .bind( &ConfigData::listTestNamesOnly ); + + cli["--list-reporters"] + .describe( "list all reporters" ) + .bind( &ConfigData::listReporters ); + + cli["--order"] + .describe( "test case order (defaults to decl)" ) + .bind( &setOrder, "decl|lex|rand" ); + + cli["--rng-seed"] + .describe( "set a specific seed for random numbers" ) + .bind( &setRngSeed, "'time'|number" ); + + cli["--force-colour"] + .describe( "force colourised output (deprecated)" ) + .bind( &forceColour ); + + cli["--use-colour"] + .describe( "should output be colourised" ) + .bind( &setUseColour, "yes|no" ); + + return cli; + } + +} // end namespace Catch + +// #included from: internal/catch_list.hpp +#define TWOBLUECUBES_CATCH_LIST_HPP_INCLUDED + +// #included from: catch_text.h +#define TWOBLUECUBES_CATCH_TEXT_H_INCLUDED + +#define TBC_TEXT_FORMAT_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH + +#define CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE Catch +// #included from: ../external/tbc_text_format.h +// Only use header guard if we are not using an outer namespace +#ifndef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE +# ifdef TWOBLUECUBES_TEXT_FORMAT_H_INCLUDED +# ifndef TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED +# define TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED +# endif +# else +# define TWOBLUECUBES_TEXT_FORMAT_H_INCLUDED +# endif +#endif +#ifndef TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED +#include +#include +#include + +// Use optional outer namespace +#ifdef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE +namespace CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE { +#endif + +namespace Tbc { + +#ifdef TBC_TEXT_FORMAT_CONSOLE_WIDTH + const unsigned int consoleWidth = TBC_TEXT_FORMAT_CONSOLE_WIDTH; +#else + const unsigned int consoleWidth = 80; +#endif + + struct TextAttributes { + TextAttributes() + : initialIndent( std::string::npos ), + indent( 0 ), + width( consoleWidth-1 ), + tabChar( '\t' ) + {} + + TextAttributes& setInitialIndent( std::size_t _value ) { initialIndent = _value; return *this; } + TextAttributes& setIndent( std::size_t _value ) { indent = _value; return *this; } + TextAttributes& setWidth( std::size_t _value ) { width = _value; return *this; } + TextAttributes& setTabChar( char _value ) { tabChar = _value; return *this; } + + std::size_t initialIndent; // indent of first line, or npos + std::size_t indent; // indent of subsequent lines, or all if initialIndent is npos + std::size_t width; // maximum width of text, including indent. Longer text will wrap + char tabChar; // If this char is seen the indent is changed to current pos + }; + + class Text { + public: + Text( std::string const& _str, TextAttributes const& _attr = TextAttributes() ) + : attr( _attr ) + { + std::string wrappableChars = " [({.,/|\\-"; + std::size_t indent = _attr.initialIndent != std::string::npos + ? _attr.initialIndent + : _attr.indent; + std::string remainder = _str; + + while( !remainder.empty() ) { + if( lines.size() >= 1000 ) { + lines.push_back( "... message truncated due to excessive size" ); + return; + } + std::size_t tabPos = std::string::npos; + std::size_t width = (std::min)( remainder.size(), _attr.width - indent ); + std::size_t pos = remainder.find_first_of( '\n' ); + if( pos <= width ) { + width = pos; + } + pos = remainder.find_last_of( _attr.tabChar, width ); + if( pos != std::string::npos ) { + tabPos = pos; + if( remainder[width] == '\n' ) + width--; + remainder = remainder.substr( 0, tabPos ) + remainder.substr( tabPos+1 ); + } + + if( width == remainder.size() ) { + spliceLine( indent, remainder, width ); + } + else if( remainder[width] == '\n' ) { + spliceLine( indent, remainder, width ); + if( width <= 1 || remainder.size() != 1 ) + remainder = remainder.substr( 1 ); + indent = _attr.indent; + } + else { + pos = remainder.find_last_of( wrappableChars, width ); + if( pos != std::string::npos && pos > 0 ) { + spliceLine( indent, remainder, pos ); + if( remainder[0] == ' ' ) + remainder = remainder.substr( 1 ); + } + else { + spliceLine( indent, remainder, width-1 ); + lines.back() += "-"; + } + if( lines.size() == 1 ) + indent = _attr.indent; + if( tabPos != std::string::npos ) + indent += tabPos; + } + } + } + + void spliceLine( std::size_t _indent, std::string& _remainder, std::size_t _pos ) { + lines.push_back( std::string( _indent, ' ' ) + _remainder.substr( 0, _pos ) ); + _remainder = _remainder.substr( _pos ); + } + + typedef std::vector::const_iterator const_iterator; + + const_iterator begin() const { return lines.begin(); } + const_iterator end() const { return lines.end(); } + std::string const& last() const { return lines.back(); } + std::size_t size() const { return lines.size(); } + std::string const& operator[]( std::size_t _index ) const { return lines[_index]; } + std::string toString() const { + std::ostringstream oss; + oss << *this; + return oss.str(); + } + + inline friend std::ostream& operator << ( std::ostream& _stream, Text const& _text ) { + for( Text::const_iterator it = _text.begin(), itEnd = _text.end(); + it != itEnd; ++it ) { + if( it != _text.begin() ) + _stream << "\n"; + _stream << *it; + } + return _stream; + } + + private: + std::string str; + TextAttributes attr; + std::vector lines; + }; + +} // end namespace Tbc + +#ifdef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE +} // end outer namespace +#endif + +#endif // TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED +#undef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE + +namespace Catch { + using Tbc::Text; + using Tbc::TextAttributes; +} + +// #included from: catch_console_colour.hpp +#define TWOBLUECUBES_CATCH_CONSOLE_COLOUR_HPP_INCLUDED + +namespace Catch { + + struct Colour { + enum Code { + None = 0, + + White, + Red, + Green, + Blue, + Cyan, + Yellow, + Grey, + + Bright = 0x10, + + BrightRed = Bright | Red, + BrightGreen = Bright | Green, + LightGrey = Bright | Grey, + BrightWhite = Bright | White, + + // By intention + FileName = LightGrey, + Warning = Yellow, + ResultError = BrightRed, + ResultSuccess = BrightGreen, + ResultExpectedFailure = Warning, + + Error = BrightRed, + Success = Green, + + OriginalExpression = Cyan, + ReconstructedExpression = Yellow, + + SecondaryText = LightGrey, + Headers = White + }; + + // Use constructed object for RAII guard + Colour( Code _colourCode ); + Colour( Colour const& other ); + ~Colour(); + + // Use static method for one-shot changes + static void use( Code _colourCode ); + + private: + bool m_moved; + }; + + inline std::ostream& operator << ( std::ostream& os, Colour const& ) { return os; } + +} // end namespace Catch + +// #included from: catch_interfaces_reporter.h +#define TWOBLUECUBES_CATCH_INTERFACES_REPORTER_H_INCLUDED + +#include +#include +#include +#include + +namespace Catch +{ + struct ReporterConfig { + explicit ReporterConfig( Ptr const& _fullConfig ) + : m_stream( &_fullConfig->stream() ), m_fullConfig( _fullConfig ) {} + + ReporterConfig( Ptr const& _fullConfig, std::ostream& _stream ) + : m_stream( &_stream ), m_fullConfig( _fullConfig ) {} + + std::ostream& stream() const { return *m_stream; } + Ptr fullConfig() const { return m_fullConfig; } + + private: + std::ostream* m_stream; + Ptr m_fullConfig; + }; + + struct ReporterPreferences { + ReporterPreferences() + : shouldRedirectStdOut( false ) + {} + + bool shouldRedirectStdOut; + }; + + template + struct LazyStat : Option { + LazyStat() : used( false ) {} + LazyStat& operator=( T const& _value ) { + Option::operator=( _value ); + used = false; + return *this; + } + void reset() { + Option::reset(); + used = false; + } + bool used; + }; + + struct TestRunInfo { + TestRunInfo( std::string const& _name ) : name( _name ) {} + std::string name; + }; + struct GroupInfo { + GroupInfo( std::string const& _name, + std::size_t _groupIndex, + std::size_t _groupsCount ) + : name( _name ), + groupIndex( _groupIndex ), + groupsCounts( _groupsCount ) + {} + + std::string name; + std::size_t groupIndex; + std::size_t groupsCounts; + }; + + struct AssertionStats { + AssertionStats( AssertionResult const& _assertionResult, + std::vector const& _infoMessages, + Totals const& _totals ) + : assertionResult( _assertionResult ), + infoMessages( _infoMessages ), + totals( _totals ) + { + if( assertionResult.hasMessage() ) { + // Copy message into messages list. + // !TBD This should have been done earlier, somewhere + MessageBuilder builder( assertionResult.getTestMacroName(), assertionResult.getSourceInfo(), assertionResult.getResultType() ); + builder << assertionResult.getMessage(); + builder.m_info.message = builder.m_stream.str(); + + infoMessages.push_back( builder.m_info ); + } + } + virtual ~AssertionStats(); + +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + AssertionStats( AssertionStats const& ) = default; + AssertionStats( AssertionStats && ) = default; + AssertionStats& operator = ( AssertionStats const& ) = default; + AssertionStats& operator = ( AssertionStats && ) = default; +# endif + + AssertionResult assertionResult; + std::vector infoMessages; + Totals totals; + }; + + struct SectionStats { + SectionStats( SectionInfo const& _sectionInfo, + Counts const& _assertions, + double _durationInSeconds, + bool _missingAssertions ) + : sectionInfo( _sectionInfo ), + assertions( _assertions ), + durationInSeconds( _durationInSeconds ), + missingAssertions( _missingAssertions ) + {} + virtual ~SectionStats(); +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + SectionStats( SectionStats const& ) = default; + SectionStats( SectionStats && ) = default; + SectionStats& operator = ( SectionStats const& ) = default; + SectionStats& operator = ( SectionStats && ) = default; +# endif + + SectionInfo sectionInfo; + Counts assertions; + double durationInSeconds; + bool missingAssertions; + }; + + struct TestCaseStats { + TestCaseStats( TestCaseInfo const& _testInfo, + Totals const& _totals, + std::string const& _stdOut, + std::string const& _stdErr, + bool _aborting ) + : testInfo( _testInfo ), + totals( _totals ), + stdOut( _stdOut ), + stdErr( _stdErr ), + aborting( _aborting ) + {} + virtual ~TestCaseStats(); + +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + TestCaseStats( TestCaseStats const& ) = default; + TestCaseStats( TestCaseStats && ) = default; + TestCaseStats& operator = ( TestCaseStats const& ) = default; + TestCaseStats& operator = ( TestCaseStats && ) = default; +# endif + + TestCaseInfo testInfo; + Totals totals; + std::string stdOut; + std::string stdErr; + bool aborting; + }; + + struct TestGroupStats { + TestGroupStats( GroupInfo const& _groupInfo, + Totals const& _totals, + bool _aborting ) + : groupInfo( _groupInfo ), + totals( _totals ), + aborting( _aborting ) + {} + TestGroupStats( GroupInfo const& _groupInfo ) + : groupInfo( _groupInfo ), + aborting( false ) + {} + virtual ~TestGroupStats(); + +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + TestGroupStats( TestGroupStats const& ) = default; + TestGroupStats( TestGroupStats && ) = default; + TestGroupStats& operator = ( TestGroupStats const& ) = default; + TestGroupStats& operator = ( TestGroupStats && ) = default; +# endif + + GroupInfo groupInfo; + Totals totals; + bool aborting; + }; + + struct TestRunStats { + TestRunStats( TestRunInfo const& _runInfo, + Totals const& _totals, + bool _aborting ) + : runInfo( _runInfo ), + totals( _totals ), + aborting( _aborting ) + {} + virtual ~TestRunStats(); + +# ifndef CATCH_CONFIG_CPP11_GENERATED_METHODS + TestRunStats( TestRunStats const& _other ) + : runInfo( _other.runInfo ), + totals( _other.totals ), + aborting( _other.aborting ) + {} +# else + TestRunStats( TestRunStats const& ) = default; + TestRunStats( TestRunStats && ) = default; + TestRunStats& operator = ( TestRunStats const& ) = default; + TestRunStats& operator = ( TestRunStats && ) = default; +# endif + + TestRunInfo runInfo; + Totals totals; + bool aborting; + }; + + struct IStreamingReporter : IShared { + virtual ~IStreamingReporter(); + + // Implementing class must also provide the following static method: + // static std::string getDescription(); + + virtual ReporterPreferences getPreferences() const = 0; + + virtual void noMatchingTestCases( std::string const& spec ) = 0; + + virtual void testRunStarting( TestRunInfo const& testRunInfo ) = 0; + virtual void testGroupStarting( GroupInfo const& groupInfo ) = 0; + + virtual void testCaseStarting( TestCaseInfo const& testInfo ) = 0; + virtual void sectionStarting( SectionInfo const& sectionInfo ) = 0; + + virtual void assertionStarting( AssertionInfo const& assertionInfo ) = 0; + + // The return value indicates if the messages buffer should be cleared: + virtual bool assertionEnded( AssertionStats const& assertionStats ) = 0; + + virtual void sectionEnded( SectionStats const& sectionStats ) = 0; + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) = 0; + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) = 0; + virtual void testRunEnded( TestRunStats const& testRunStats ) = 0; + + virtual void skipTest( TestCaseInfo const& testInfo ) = 0; + }; + + struct IReporterFactory : IShared { + virtual ~IReporterFactory(); + virtual IStreamingReporter* create( ReporterConfig const& config ) const = 0; + virtual std::string getDescription() const = 0; + }; + + struct IReporterRegistry { + typedef std::map > FactoryMap; + typedef std::vector > Listeners; + + virtual ~IReporterRegistry(); + virtual IStreamingReporter* create( std::string const& name, Ptr const& config ) const = 0; + virtual FactoryMap const& getFactories() const = 0; + virtual Listeners const& getListeners() const = 0; + }; + + Ptr addReporter( Ptr const& existingReporter, Ptr const& additionalReporter ); + +} + +#include +#include + +namespace Catch { + + inline std::size_t listTests( Config const& config ) { + + TestSpec testSpec = config.testSpec(); + if( config.testSpec().hasFilters() ) + Catch::cout() << "Matching test cases:\n"; + else { + Catch::cout() << "All available test cases:\n"; + testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); + } + + std::size_t matchedTests = 0; + TextAttributes nameAttr, tagsAttr; + nameAttr.setInitialIndent( 2 ).setIndent( 4 ); + tagsAttr.setIndent( 6 ); + + std::vector matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); + for( std::vector::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); + it != itEnd; + ++it ) { + matchedTests++; + TestCaseInfo const& testCaseInfo = it->getTestCaseInfo(); + Colour::Code colour = testCaseInfo.isHidden() + ? Colour::SecondaryText + : Colour::None; + Colour colourGuard( colour ); + + Catch::cout() << Text( testCaseInfo.name, nameAttr ) << std::endl; + if( !testCaseInfo.tags.empty() ) + Catch::cout() << Text( testCaseInfo.tagsAsString, tagsAttr ) << std::endl; + } + + if( !config.testSpec().hasFilters() ) + Catch::cout() << pluralise( matchedTests, "test case" ) << "\n" << std::endl; + else + Catch::cout() << pluralise( matchedTests, "matching test case" ) << "\n" << std::endl; + return matchedTests; + } + + inline std::size_t listTestsNamesOnly( Config const& config ) { + TestSpec testSpec = config.testSpec(); + if( !config.testSpec().hasFilters() ) + testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); + std::size_t matchedTests = 0; + std::vector matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); + for( std::vector::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); + it != itEnd; + ++it ) { + matchedTests++; + TestCaseInfo const& testCaseInfo = it->getTestCaseInfo(); + Catch::cout() << testCaseInfo.name << std::endl; + } + return matchedTests; + } + + struct TagInfo { + TagInfo() : count ( 0 ) {} + void add( std::string const& spelling ) { + ++count; + spellings.insert( spelling ); + } + std::string all() const { + std::string out; + for( std::set::const_iterator it = spellings.begin(), itEnd = spellings.end(); + it != itEnd; + ++it ) + out += "[" + *it + "]"; + return out; + } + std::set spellings; + std::size_t count; + }; + + inline std::size_t listTags( Config const& config ) { + TestSpec testSpec = config.testSpec(); + if( config.testSpec().hasFilters() ) + Catch::cout() << "Tags for matching test cases:\n"; + else { + Catch::cout() << "All available tags:\n"; + testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); + } + + std::map tagCounts; + + std::vector matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); + for( std::vector::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); + it != itEnd; + ++it ) { + for( std::set::const_iterator tagIt = it->getTestCaseInfo().tags.begin(), + tagItEnd = it->getTestCaseInfo().tags.end(); + tagIt != tagItEnd; + ++tagIt ) { + std::string tagName = *tagIt; + std::string lcaseTagName = toLower( tagName ); + std::map::iterator countIt = tagCounts.find( lcaseTagName ); + if( countIt == tagCounts.end() ) + countIt = tagCounts.insert( std::make_pair( lcaseTagName, TagInfo() ) ).first; + countIt->second.add( tagName ); + } + } + + for( std::map::const_iterator countIt = tagCounts.begin(), + countItEnd = tagCounts.end(); + countIt != countItEnd; + ++countIt ) { + std::ostringstream oss; + oss << " " << std::setw(2) << countIt->second.count << " "; + Text wrapper( countIt->second.all(), TextAttributes() + .setInitialIndent( 0 ) + .setIndent( oss.str().size() ) + .setWidth( CATCH_CONFIG_CONSOLE_WIDTH-10 ) ); + Catch::cout() << oss.str() << wrapper << "\n"; + } + Catch::cout() << pluralise( tagCounts.size(), "tag" ) << "\n" << std::endl; + return tagCounts.size(); + } + + inline std::size_t listReporters( Config const& /*config*/ ) { + Catch::cout() << "Available reporters:\n"; + IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories(); + IReporterRegistry::FactoryMap::const_iterator itBegin = factories.begin(), itEnd = factories.end(), it; + std::size_t maxNameLen = 0; + for(it = itBegin; it != itEnd; ++it ) + maxNameLen = (std::max)( maxNameLen, it->first.size() ); + + for(it = itBegin; it != itEnd; ++it ) { + Text wrapper( it->second->getDescription(), TextAttributes() + .setInitialIndent( 0 ) + .setIndent( 7+maxNameLen ) + .setWidth( CATCH_CONFIG_CONSOLE_WIDTH - maxNameLen-8 ) ); + Catch::cout() << " " + << it->first + << ":" + << std::string( maxNameLen - it->first.size() + 2, ' ' ) + << wrapper << "\n"; + } + Catch::cout() << std::endl; + return factories.size(); + } + + inline Option list( Config const& config ) { + Option listedCount; + if( config.listTests() ) + listedCount = listedCount.valueOr(0) + listTests( config ); + if( config.listTestNamesOnly() ) + listedCount = listedCount.valueOr(0) + listTestsNamesOnly( config ); + if( config.listTags() ) + listedCount = listedCount.valueOr(0) + listTags( config ); + if( config.listReporters() ) + listedCount = listedCount.valueOr(0) + listReporters( config ); + return listedCount; + } + +} // end namespace Catch + +// #included from: internal/catch_run_context.hpp +#define TWOBLUECUBES_CATCH_RUNNER_IMPL_HPP_INCLUDED + +// #included from: catch_test_case_tracker.hpp +#define TWOBLUECUBES_CATCH_TEST_CASE_TRACKER_HPP_INCLUDED + +#include +#include +#include +#include + +namespace Catch { +namespace TestCaseTracking { + + struct ITracker : SharedImpl<> { + virtual ~ITracker(); + + // static queries + virtual std::string name() const = 0; + + // dynamic queries + virtual bool isComplete() const = 0; // Successfully completed or failed + virtual bool isSuccessfullyCompleted() const = 0; + virtual bool isOpen() const = 0; // Started but not complete + virtual bool hasChildren() const = 0; + + virtual ITracker& parent() = 0; + + // actions + virtual void close() = 0; // Successfully complete + virtual void fail() = 0; + virtual void markAsNeedingAnotherRun() = 0; + + virtual void addChild( Ptr const& child ) = 0; + virtual ITracker* findChild( std::string const& name ) = 0; + virtual void openChild() = 0; + }; + + class TrackerContext { + + enum RunState { + NotStarted, + Executing, + CompletedCycle + }; + + Ptr m_rootTracker; + ITracker* m_currentTracker; + RunState m_runState; + + public: + + static TrackerContext& instance() { + static TrackerContext s_instance; + return s_instance; + } + + TrackerContext() + : m_currentTracker( CATCH_NULL ), + m_runState( NotStarted ) + {} + + ITracker& startRun(); + + void endRun() { + m_rootTracker.reset(); + m_currentTracker = CATCH_NULL; + m_runState = NotStarted; + } + + void startCycle() { + m_currentTracker = m_rootTracker.get(); + m_runState = Executing; + } + void completeCycle() { + m_runState = CompletedCycle; + } + + bool completedCycle() const { + return m_runState == CompletedCycle; + } + ITracker& currentTracker() { + return *m_currentTracker; + } + void setCurrentTracker( ITracker* tracker ) { + m_currentTracker = tracker; + } + }; + + class TrackerBase : public ITracker { + protected: + enum CycleState { + NotStarted, + Executing, + ExecutingChildren, + NeedsAnotherRun, + CompletedSuccessfully, + Failed + }; + class TrackerHasName { + std::string m_name; + public: + TrackerHasName( std::string const& name ) : m_name( name ) {} + bool operator ()( Ptr const& tracker ) { + return tracker->name() == m_name; + } + }; + typedef std::vector > Children; + std::string m_name; + TrackerContext& m_ctx; + ITracker* m_parent; + Children m_children; + CycleState m_runState; + public: + TrackerBase( std::string const& name, TrackerContext& ctx, ITracker* parent ) + : m_name( name ), + m_ctx( ctx ), + m_parent( parent ), + m_runState( NotStarted ) + {} + virtual ~TrackerBase(); + + virtual std::string name() const CATCH_OVERRIDE { + return m_name; + } + virtual bool isComplete() const CATCH_OVERRIDE { + return m_runState == CompletedSuccessfully || m_runState == Failed; + } + virtual bool isSuccessfullyCompleted() const CATCH_OVERRIDE { + return m_runState == CompletedSuccessfully; + } + virtual bool isOpen() const CATCH_OVERRIDE { + return m_runState != NotStarted && !isComplete(); + } + virtual bool hasChildren() const CATCH_OVERRIDE { + return !m_children.empty(); + } + + virtual void addChild( Ptr const& child ) CATCH_OVERRIDE { + m_children.push_back( child ); + } + + virtual ITracker* findChild( std::string const& name ) CATCH_OVERRIDE { + Children::const_iterator it = std::find_if( m_children.begin(), m_children.end(), TrackerHasName( name ) ); + return( it != m_children.end() ) + ? it->get() + : CATCH_NULL; + } + virtual ITracker& parent() CATCH_OVERRIDE { + assert( m_parent ); // Should always be non-null except for root + return *m_parent; + } + + virtual void openChild() CATCH_OVERRIDE { + if( m_runState != ExecutingChildren ) { + m_runState = ExecutingChildren; + if( m_parent ) + m_parent->openChild(); + } + } + void open() { + m_runState = Executing; + moveToThis(); + if( m_parent ) + m_parent->openChild(); + } + + virtual void close() CATCH_OVERRIDE { + + // Close any still open children (e.g. generators) + while( &m_ctx.currentTracker() != this ) + m_ctx.currentTracker().close(); + + switch( m_runState ) { + case NotStarted: + case CompletedSuccessfully: + case Failed: + throw std::logic_error( "Illogical state" ); + + case NeedsAnotherRun: + break;; + + case Executing: + m_runState = CompletedSuccessfully; + break; + case ExecutingChildren: + if( m_children.empty() || m_children.back()->isComplete() ) + m_runState = CompletedSuccessfully; + break; + + default: + throw std::logic_error( "Unexpected state" ); + } + moveToParent(); + m_ctx.completeCycle(); + } + virtual void fail() CATCH_OVERRIDE { + m_runState = Failed; + if( m_parent ) + m_parent->markAsNeedingAnotherRun(); + moveToParent(); + m_ctx.completeCycle(); + } + virtual void markAsNeedingAnotherRun() CATCH_OVERRIDE { + m_runState = NeedsAnotherRun; + } + private: + void moveToParent() { + assert( m_parent ); + m_ctx.setCurrentTracker( m_parent ); + } + void moveToThis() { + m_ctx.setCurrentTracker( this ); + } + }; + + class SectionTracker : public TrackerBase { + public: + SectionTracker( std::string const& name, TrackerContext& ctx, ITracker* parent ) + : TrackerBase( name, ctx, parent ) + {} + virtual ~SectionTracker(); + + static SectionTracker& acquire( TrackerContext& ctx, std::string const& name ) { + SectionTracker* section = CATCH_NULL; + + ITracker& currentTracker = ctx.currentTracker(); + if( ITracker* childTracker = currentTracker.findChild( name ) ) { + section = dynamic_cast( childTracker ); + assert( section ); + } + else { + section = new SectionTracker( name, ctx, ¤tTracker ); + currentTracker.addChild( section ); + } + if( !ctx.completedCycle() && !section->isComplete() ) { + + section->open(); + } + return *section; + } + }; + + class IndexTracker : public TrackerBase { + int m_size; + int m_index; + public: + IndexTracker( std::string const& name, TrackerContext& ctx, ITracker* parent, int size ) + : TrackerBase( name, ctx, parent ), + m_size( size ), + m_index( -1 ) + {} + virtual ~IndexTracker(); + + static IndexTracker& acquire( TrackerContext& ctx, std::string const& name, int size ) { + IndexTracker* tracker = CATCH_NULL; + + ITracker& currentTracker = ctx.currentTracker(); + if( ITracker* childTracker = currentTracker.findChild( name ) ) { + tracker = dynamic_cast( childTracker ); + assert( tracker ); + } + else { + tracker = new IndexTracker( name, ctx, ¤tTracker, size ); + currentTracker.addChild( tracker ); + } + + if( !ctx.completedCycle() && !tracker->isComplete() ) { + if( tracker->m_runState != ExecutingChildren && tracker->m_runState != NeedsAnotherRun ) + tracker->moveNext(); + tracker->open(); + } + + return *tracker; + } + + int index() const { return m_index; } + + void moveNext() { + m_index++; + m_children.clear(); + } + + virtual void close() CATCH_OVERRIDE { + TrackerBase::close(); + if( m_runState == CompletedSuccessfully && m_index < m_size-1 ) + m_runState = Executing; + } + }; + + inline ITracker& TrackerContext::startRun() { + m_rootTracker = new SectionTracker( "{root}", *this, CATCH_NULL ); + m_currentTracker = CATCH_NULL; + m_runState = Executing; + return *m_rootTracker; + } + +} // namespace TestCaseTracking + +using TestCaseTracking::ITracker; +using TestCaseTracking::TrackerContext; +using TestCaseTracking::SectionTracker; +using TestCaseTracking::IndexTracker; + +} // namespace Catch + +// #included from: catch_fatal_condition.hpp +#define TWOBLUECUBES_CATCH_FATAL_CONDITION_H_INCLUDED + +namespace Catch { + + // Report the error condition then exit the process + inline void fatal( std::string const& message, int exitCode ) { + IContext& context = Catch::getCurrentContext(); + IResultCapture* resultCapture = context.getResultCapture(); + resultCapture->handleFatalErrorCondition( message ); + + if( Catch::alwaysTrue() ) // avoids "no return" warnings + exit( exitCode ); + } + +} // namespace Catch + +#if defined ( CATCH_PLATFORM_WINDOWS ) ///////////////////////////////////////// + +namespace Catch { + + struct FatalConditionHandler { + void reset() {} + }; + +} // namespace Catch + +#else // Not Windows - assumed to be POSIX compatible ////////////////////////// + +#include + +namespace Catch { + + struct SignalDefs { int id; const char* name; }; + extern SignalDefs signalDefs[]; + SignalDefs signalDefs[] = { + { SIGINT, "SIGINT - Terminal interrupt signal" }, + { SIGILL, "SIGILL - Illegal instruction signal" }, + { SIGFPE, "SIGFPE - Floating point error signal" }, + { SIGSEGV, "SIGSEGV - Segmentation violation signal" }, + { SIGTERM, "SIGTERM - Termination request signal" }, + { SIGABRT, "SIGABRT - Abort (abnormal termination) signal" } + }; + + struct FatalConditionHandler { + + static void handleSignal( int sig ) { + for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) + if( sig == signalDefs[i].id ) + fatal( signalDefs[i].name, -sig ); + fatal( "", -sig ); + } + + FatalConditionHandler() : m_isSet( true ) { + for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) + signal( signalDefs[i].id, handleSignal ); + } + ~FatalConditionHandler() { + reset(); + } + void reset() { + if( m_isSet ) { + for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) + signal( signalDefs[i].id, SIG_DFL ); + m_isSet = false; + } + } + + bool m_isSet; + }; + +} // namespace Catch + +#endif // not Windows + +#include +#include + +namespace Catch { + + class StreamRedirect { + + public: + StreamRedirect( std::ostream& stream, std::string& targetString ) + : m_stream( stream ), + m_prevBuf( stream.rdbuf() ), + m_targetString( targetString ) + { + stream.rdbuf( m_oss.rdbuf() ); + } + + ~StreamRedirect() { + m_targetString += m_oss.str(); + m_stream.rdbuf( m_prevBuf ); + } + + private: + std::ostream& m_stream; + std::streambuf* m_prevBuf; + std::ostringstream m_oss; + std::string& m_targetString; + }; + + /////////////////////////////////////////////////////////////////////////// + + class RunContext : public IResultCapture, public IRunner { + + RunContext( RunContext const& ); + void operator =( RunContext const& ); + + public: + + explicit RunContext( Ptr const& _config, Ptr const& reporter ) + : m_runInfo( _config->name() ), + m_context( getCurrentMutableContext() ), + m_activeTestCase( CATCH_NULL ), + m_config( _config ), + m_reporter( reporter ) + { + m_context.setRunner( this ); + m_context.setConfig( m_config ); + m_context.setResultCapture( this ); + m_reporter->testRunStarting( m_runInfo ); + } + + virtual ~RunContext() { + m_reporter->testRunEnded( TestRunStats( m_runInfo, m_totals, aborting() ) ); + } + + void testGroupStarting( std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount ) { + m_reporter->testGroupStarting( GroupInfo( testSpec, groupIndex, groupsCount ) ); + } + void testGroupEnded( std::string const& testSpec, Totals const& totals, std::size_t groupIndex, std::size_t groupsCount ) { + m_reporter->testGroupEnded( TestGroupStats( GroupInfo( testSpec, groupIndex, groupsCount ), totals, aborting() ) ); + } + + Totals runTest( TestCase const& testCase ) { + Totals prevTotals = m_totals; + + std::string redirectedCout; + std::string redirectedCerr; + + TestCaseInfo testInfo = testCase.getTestCaseInfo(); + + m_reporter->testCaseStarting( testInfo ); + + m_activeTestCase = &testCase; + + do { + m_trackerContext.startRun(); + do { + m_trackerContext.startCycle(); + m_testCaseTracker = &SectionTracker::acquire( m_trackerContext, testInfo.name ); + runCurrentTest( redirectedCout, redirectedCerr ); + } + while( !m_testCaseTracker->isSuccessfullyCompleted() && !aborting() ); + } + // !TBD: deprecated - this will be replaced by indexed trackers + while( getCurrentContext().advanceGeneratorsForCurrentTest() && !aborting() ); + + Totals deltaTotals = m_totals.delta( prevTotals ); + m_totals.testCases += deltaTotals.testCases; + m_reporter->testCaseEnded( TestCaseStats( testInfo, + deltaTotals, + redirectedCout, + redirectedCerr, + aborting() ) ); + + m_activeTestCase = CATCH_NULL; + m_testCaseTracker = CATCH_NULL; + + return deltaTotals; + } + + Ptr config() const { + return m_config; + } + + private: // IResultCapture + + virtual void assertionEnded( AssertionResult const& result ) { + if( result.getResultType() == ResultWas::Ok ) { + m_totals.assertions.passed++; + } + else if( !result.isOk() ) { + m_totals.assertions.failed++; + } + + if( m_reporter->assertionEnded( AssertionStats( result, m_messages, m_totals ) ) ) + m_messages.clear(); + + // Reset working state + m_lastAssertionInfo = AssertionInfo( "", m_lastAssertionInfo.lineInfo, "{Unknown expression after the reported line}" , m_lastAssertionInfo.resultDisposition ); + m_lastResult = result; + } + + virtual bool sectionStarted ( + SectionInfo const& sectionInfo, + Counts& assertions + ) + { + std::ostringstream oss; + oss << sectionInfo.name << "@" << sectionInfo.lineInfo; + + ITracker& sectionTracker = SectionTracker::acquire( m_trackerContext, oss.str() ); + if( !sectionTracker.isOpen() ) + return false; + m_activeSections.push_back( §ionTracker ); + + m_lastAssertionInfo.lineInfo = sectionInfo.lineInfo; + + m_reporter->sectionStarting( sectionInfo ); + + assertions = m_totals.assertions; + + return true; + } + bool testForMissingAssertions( Counts& assertions ) { + if( assertions.total() != 0 ) + return false; + if( !m_config->warnAboutMissingAssertions() ) + return false; + if( m_trackerContext.currentTracker().hasChildren() ) + return false; + m_totals.assertions.failed++; + assertions.failed++; + return true; + } + + virtual void sectionEnded( SectionEndInfo const& endInfo ) { + Counts assertions = m_totals.assertions - endInfo.prevAssertions; + bool missingAssertions = testForMissingAssertions( assertions ); + + if( !m_activeSections.empty() ) { + m_activeSections.back()->close(); + m_activeSections.pop_back(); + } + + m_reporter->sectionEnded( SectionStats( endInfo.sectionInfo, assertions, endInfo.durationInSeconds, missingAssertions ) ); + m_messages.clear(); + } + + virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) { + if( m_unfinishedSections.empty() ) + m_activeSections.back()->fail(); + else + m_activeSections.back()->close(); + m_activeSections.pop_back(); + + m_unfinishedSections.push_back( endInfo ); + } + + virtual void pushScopedMessage( MessageInfo const& message ) { + m_messages.push_back( message ); + } + + virtual void popScopedMessage( MessageInfo const& message ) { + m_messages.erase( std::remove( m_messages.begin(), m_messages.end(), message ), m_messages.end() ); + } + + virtual std::string getCurrentTestName() const { + return m_activeTestCase + ? m_activeTestCase->getTestCaseInfo().name + : ""; + } + + virtual const AssertionResult* getLastResult() const { + return &m_lastResult; + } + + virtual void handleFatalErrorCondition( std::string const& message ) { + ResultBuilder resultBuilder = makeUnexpectedResultBuilder(); + resultBuilder.setResultType( ResultWas::FatalErrorCondition ); + resultBuilder << message; + resultBuilder.captureExpression(); + + handleUnfinishedSections(); + + // Recreate section for test case (as we will lose the one that was in scope) + TestCaseInfo const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); + SectionInfo testCaseSection( testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description ); + + Counts assertions; + assertions.failed = 1; + SectionStats testCaseSectionStats( testCaseSection, assertions, 0, false ); + m_reporter->sectionEnded( testCaseSectionStats ); + + TestCaseInfo testInfo = m_activeTestCase->getTestCaseInfo(); + + Totals deltaTotals; + deltaTotals.testCases.failed = 1; + m_reporter->testCaseEnded( TestCaseStats( testInfo, + deltaTotals, + "", + "", + false ) ); + m_totals.testCases.failed++; + testGroupEnded( "", m_totals, 1, 1 ); + m_reporter->testRunEnded( TestRunStats( m_runInfo, m_totals, false ) ); + } + + public: + // !TBD We need to do this another way! + bool aborting() const { + return m_totals.assertions.failed == static_cast( m_config->abortAfter() ); + } + + private: + + void runCurrentTest( std::string& redirectedCout, std::string& redirectedCerr ) { + TestCaseInfo const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); + SectionInfo testCaseSection( testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description ); + m_reporter->sectionStarting( testCaseSection ); + Counts prevAssertions = m_totals.assertions; + double duration = 0; + try { + m_lastAssertionInfo = AssertionInfo( "TEST_CASE", testCaseInfo.lineInfo, "", ResultDisposition::Normal ); + + seedRng( *m_config ); + + Timer timer; + timer.start(); + if( m_reporter->getPreferences().shouldRedirectStdOut ) { + StreamRedirect coutRedir( Catch::cout(), redirectedCout ); + StreamRedirect cerrRedir( Catch::cerr(), redirectedCerr ); + invokeActiveTestCase(); + } + else { + invokeActiveTestCase(); + } + duration = timer.getElapsedSeconds(); + } + catch( TestFailureException& ) { + // This just means the test was aborted due to failure + } + catch(...) { + makeUnexpectedResultBuilder().useActiveException(); + } + m_testCaseTracker->close(); + handleUnfinishedSections(); + m_messages.clear(); + + Counts assertions = m_totals.assertions - prevAssertions; + bool missingAssertions = testForMissingAssertions( assertions ); + + if( testCaseInfo.okToFail() ) { + std::swap( assertions.failedButOk, assertions.failed ); + m_totals.assertions.failed -= assertions.failedButOk; + m_totals.assertions.failedButOk += assertions.failedButOk; + } + + SectionStats testCaseSectionStats( testCaseSection, assertions, duration, missingAssertions ); + m_reporter->sectionEnded( testCaseSectionStats ); + } + + void invokeActiveTestCase() { + FatalConditionHandler fatalConditionHandler; // Handle signals + m_activeTestCase->invoke(); + fatalConditionHandler.reset(); + } + + private: + + ResultBuilder makeUnexpectedResultBuilder() const { + return ResultBuilder( m_lastAssertionInfo.macroName.c_str(), + m_lastAssertionInfo.lineInfo, + m_lastAssertionInfo.capturedExpression.c_str(), + m_lastAssertionInfo.resultDisposition ); + } + + void handleUnfinishedSections() { + // If sections ended prematurely due to an exception we stored their + // infos here so we can tear them down outside the unwind process. + for( std::vector::const_reverse_iterator it = m_unfinishedSections.rbegin(), + itEnd = m_unfinishedSections.rend(); + it != itEnd; + ++it ) + sectionEnded( *it ); + m_unfinishedSections.clear(); + } + + TestRunInfo m_runInfo; + IMutableContext& m_context; + TestCase const* m_activeTestCase; + ITracker* m_testCaseTracker; + ITracker* m_currentSectionTracker; + AssertionResult m_lastResult; + + Ptr m_config; + Totals m_totals; + Ptr m_reporter; + std::vector m_messages; + AssertionInfo m_lastAssertionInfo; + std::vector m_unfinishedSections; + std::vector m_activeSections; + TrackerContext m_trackerContext; + }; + + IResultCapture& getResultCapture() { + if( IResultCapture* capture = getCurrentContext().getResultCapture() ) + return *capture; + else + throw std::logic_error( "No result capture instance" ); + } + +} // end namespace Catch + +// #included from: internal/catch_version.h +#define TWOBLUECUBES_CATCH_VERSION_H_INCLUDED + +namespace Catch { + + // Versioning information + struct Version { + Version( unsigned int _majorVersion, + unsigned int _minorVersion, + unsigned int _patchNumber, + std::string const& _branchName, + unsigned int _buildNumber ); + + unsigned int const majorVersion; + unsigned int const minorVersion; + unsigned int const patchNumber; + + // buildNumber is only used if branchName is not null + std::string const branchName; + unsigned int const buildNumber; + + friend std::ostream& operator << ( std::ostream& os, Version const& version ); + + private: + void operator=( Version const& ); + }; + + extern Version libraryVersion; +} + +#include +#include +#include + +namespace Catch { + + Ptr createReporter( std::string const& reporterName, Ptr const& config ) { + Ptr reporter = getRegistryHub().getReporterRegistry().create( reporterName, config.get() ); + if( !reporter ) { + std::ostringstream oss; + oss << "No reporter registered with name: '" << reporterName << "'"; + throw std::domain_error( oss.str() ); + } + return reporter; + } + + Ptr makeReporter( Ptr const& config ) { + std::vector reporters = config->getReporterNames(); + if( reporters.empty() ) + reporters.push_back( "console" ); + + Ptr reporter; + for( std::vector::const_iterator it = reporters.begin(), itEnd = reporters.end(); + it != itEnd; + ++it ) + reporter = addReporter( reporter, createReporter( *it, config ) ); + return reporter; + } + Ptr addListeners( Ptr const& config, Ptr reporters ) { + IReporterRegistry::Listeners listeners = getRegistryHub().getReporterRegistry().getListeners(); + for( IReporterRegistry::Listeners::const_iterator it = listeners.begin(), itEnd = listeners.end(); + it != itEnd; + ++it ) + reporters = addReporter(reporters, (*it)->create( ReporterConfig( config ) ) ); + return reporters; + } + + Totals runTests( Ptr const& config ) { + + Ptr iconfig = config.get(); + + Ptr reporter = makeReporter( config ); + reporter = addListeners( iconfig, reporter ); + + RunContext context( iconfig, reporter ); + + Totals totals; + + context.testGroupStarting( config->name(), 1, 1 ); + + TestSpec testSpec = config->testSpec(); + if( !testSpec.hasFilters() ) + testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "~[.]" ).testSpec(); // All not hidden tests + + std::vector const& allTestCases = getAllTestCasesSorted( *iconfig ); + for( std::vector::const_iterator it = allTestCases.begin(), itEnd = allTestCases.end(); + it != itEnd; + ++it ) { + if( !context.aborting() && matchTest( *it, testSpec, *iconfig ) ) + totals += context.runTest( *it ); + else + reporter->skipTest( *it ); + } + + context.testGroupEnded( iconfig->name(), totals, 1, 1 ); + return totals; + } + + void applyFilenamesAsTags( IConfig const& config ) { + std::vector const& tests = getAllTestCasesSorted( config ); + for(std::size_t i = 0; i < tests.size(); ++i ) { + TestCase& test = const_cast( tests[i] ); + std::set tags = test.tags; + + std::string filename = test.lineInfo.file; + std::string::size_type lastSlash = filename.find_last_of( "\\/" ); + if( lastSlash != std::string::npos ) + filename = filename.substr( lastSlash+1 ); + + std::string::size_type lastDot = filename.find_last_of( "." ); + if( lastDot != std::string::npos ) + filename = filename.substr( 0, lastDot ); + + tags.insert( "#" + filename ); + setTags( test, tags ); + } + } + + class Session : NonCopyable { + static bool alreadyInstantiated; + + public: + + struct OnUnusedOptions { enum DoWhat { Ignore, Fail }; }; + + Session() + : m_cli( makeCommandLineParser() ) { + if( alreadyInstantiated ) { + std::string msg = "Only one instance of Catch::Session can ever be used"; + Catch::cerr() << msg << std::endl; + throw std::logic_error( msg ); + } + alreadyInstantiated = true; + } + ~Session() { + Catch::cleanUp(); + } + + void showHelp( std::string const& processName ) { + Catch::cout() << "\nCatch v" << libraryVersion << "\n"; + + m_cli.usage( Catch::cout(), processName ); + Catch::cout() << "For more detail usage please see the project docs\n" << std::endl; + } + + int applyCommandLine( int argc, char const* argv[], OnUnusedOptions::DoWhat unusedOptionBehaviour = OnUnusedOptions::Fail ) { + try { + m_cli.setThrowOnUnrecognisedTokens( unusedOptionBehaviour == OnUnusedOptions::Fail ); + m_unusedTokens = m_cli.parseInto( argc, argv, m_configData ); + if( m_configData.showHelp ) + showHelp( m_configData.processName ); + m_config.reset(); + } + catch( std::exception& ex ) { + { + Colour colourGuard( Colour::Red ); + Catch::cerr() + << "\nError(s) in input:\n" + << Text( ex.what(), TextAttributes().setIndent(2) ) + << "\n\n"; + } + m_cli.usage( Catch::cout(), m_configData.processName ); + return (std::numeric_limits::max)(); + } + return 0; + } + + void useConfigData( ConfigData const& _configData ) { + m_configData = _configData; + m_config.reset(); + } + + int run( int argc, char const* argv[] ) { + + int returnCode = applyCommandLine( argc, argv ); + if( returnCode == 0 ) + returnCode = run(); + return returnCode; + } + int run( int argc, char* argv[] ) { + return run( argc, const_cast( argv ) ); + } + + int run() { + if( m_configData.showHelp ) + return 0; + + try + { + config(); // Force config to be constructed + + seedRng( *m_config ); + + if( m_configData.filenamesAsTags ) + applyFilenamesAsTags( *m_config ); + + // Handle list request + if( Option listed = list( config() ) ) + return static_cast( *listed ); + + return static_cast( runTests( m_config ).assertions.failed ); + } + catch( std::exception& ex ) { + Catch::cerr() << ex.what() << std::endl; + return (std::numeric_limits::max)(); + } + } + + Clara::CommandLine const& cli() const { + return m_cli; + } + std::vector const& unusedTokens() const { + return m_unusedTokens; + } + ConfigData& configData() { + return m_configData; + } + Config& config() { + if( !m_config ) + m_config = new Config( m_configData ); + return *m_config; + } + private: + Clara::CommandLine m_cli; + std::vector m_unusedTokens; + ConfigData m_configData; + Ptr m_config; + }; + + bool Session::alreadyInstantiated = false; + +} // end namespace Catch + +// #included from: catch_registry_hub.hpp +#define TWOBLUECUBES_CATCH_REGISTRY_HUB_HPP_INCLUDED + +// #included from: catch_test_case_registry_impl.hpp +#define TWOBLUECUBES_CATCH_TEST_CASE_REGISTRY_IMPL_HPP_INCLUDED + +#include +#include +#include +#include +#include + +namespace Catch { + + struct LexSort { + bool operator() (TestCase i,TestCase j) const { return (i sortTests( IConfig const& config, std::vector const& unsortedTestCases ) { + + std::vector sorted = unsortedTestCases; + + switch( config.runOrder() ) { + case RunTests::InLexicographicalOrder: + std::sort( sorted.begin(), sorted.end(), LexSort() ); + break; + case RunTests::InRandomOrder: + { + seedRng( config ); + + RandomNumberGenerator rng; + std::random_shuffle( sorted.begin(), sorted.end(), rng ); + } + break; + case RunTests::InDeclarationOrder: + // already in declaration order + break; + } + return sorted; + } + bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ) { + return testSpec.matches( testCase ) && ( config.allowThrows() || !testCase.throws() ); + } + + void enforceNoDuplicateTestCases( std::vector const& functions ) { + std::set seenFunctions; + for( std::vector::const_iterator it = functions.begin(), itEnd = functions.end(); + it != itEnd; + ++it ) { + std::pair::const_iterator, bool> prev = seenFunctions.insert( *it ); + if( !prev.second ){ + Catch::cerr() + << Colour( Colour::Red ) + << "error: TEST_CASE( \"" << it->name << "\" ) already defined.\n" + << "\tFirst seen at " << prev.first->getTestCaseInfo().lineInfo << "\n" + << "\tRedefined at " << it->getTestCaseInfo().lineInfo << std::endl; + exit(1); + } + } + } + + std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ) { + std::vector filtered; + filtered.reserve( testCases.size() ); + for( std::vector::const_iterator it = testCases.begin(), itEnd = testCases.end(); + it != itEnd; + ++it ) + if( matchTest( *it, testSpec, config ) ) + filtered.push_back( *it ); + return filtered; + } + std::vector const& getAllTestCasesSorted( IConfig const& config ) { + return getRegistryHub().getTestCaseRegistry().getAllTestsSorted( config ); + } + + class TestRegistry : public ITestCaseRegistry { + public: + TestRegistry() + : m_currentSortOrder( RunTests::InDeclarationOrder ), + m_unnamedCount( 0 ) + {} + virtual ~TestRegistry(); + + virtual void registerTest( TestCase const& testCase ) { + std::string name = testCase.getTestCaseInfo().name; + if( name == "" ) { + std::ostringstream oss; + oss << "Anonymous test case " << ++m_unnamedCount; + return registerTest( testCase.withName( oss.str() ) ); + } + m_functions.push_back( testCase ); + } + + virtual std::vector const& getAllTests() const { + return m_functions; + } + virtual std::vector const& getAllTestsSorted( IConfig const& config ) const { + if( m_sortedFunctions.empty() ) + enforceNoDuplicateTestCases( m_functions ); + + if( m_currentSortOrder != config.runOrder() || m_sortedFunctions.empty() ) { + m_sortedFunctions = sortTests( config, m_functions ); + m_currentSortOrder = config.runOrder(); + } + return m_sortedFunctions; + } + + private: + std::vector m_functions; + mutable RunTests::InWhatOrder m_currentSortOrder; + mutable std::vector m_sortedFunctions; + size_t m_unnamedCount; + std::ios_base::Init m_ostreamInit; // Forces cout/ cerr to be initialised + }; + + /////////////////////////////////////////////////////////////////////////// + + class FreeFunctionTestCase : public SharedImpl { + public: + + FreeFunctionTestCase( TestFunction fun ) : m_fun( fun ) {} + + virtual void invoke() const { + m_fun(); + } + + private: + virtual ~FreeFunctionTestCase(); + + TestFunction m_fun; + }; + + inline std::string extractClassName( std::string const& classOrQualifiedMethodName ) { + std::string className = classOrQualifiedMethodName; + if( startsWith( className, "&" ) ) + { + std::size_t lastColons = className.rfind( "::" ); + std::size_t penultimateColons = className.rfind( "::", lastColons-1 ); + if( penultimateColons == std::string::npos ) + penultimateColons = 1; + className = className.substr( penultimateColons, lastColons-penultimateColons ); + } + return className; + } + + void registerTestCase + ( ITestCase* testCase, + char const* classOrQualifiedMethodName, + NameAndDesc const& nameAndDesc, + SourceLineInfo const& lineInfo ) { + + getMutableRegistryHub().registerTest + ( makeTestCase + ( testCase, + extractClassName( classOrQualifiedMethodName ), + nameAndDesc.name, + nameAndDesc.description, + lineInfo ) ); + } + void registerTestCaseFunction + ( TestFunction function, + SourceLineInfo const& lineInfo, + NameAndDesc const& nameAndDesc ) { + registerTestCase( new FreeFunctionTestCase( function ), "", nameAndDesc, lineInfo ); + } + + /////////////////////////////////////////////////////////////////////////// + + AutoReg::AutoReg + ( TestFunction function, + SourceLineInfo const& lineInfo, + NameAndDesc const& nameAndDesc ) { + registerTestCaseFunction( function, lineInfo, nameAndDesc ); + } + + AutoReg::~AutoReg() {} + +} // end namespace Catch + +// #included from: catch_reporter_registry.hpp +#define TWOBLUECUBES_CATCH_REPORTER_REGISTRY_HPP_INCLUDED + +#include + +namespace Catch { + + class ReporterRegistry : public IReporterRegistry { + + public: + + virtual ~ReporterRegistry() CATCH_OVERRIDE {} + + virtual IStreamingReporter* create( std::string const& name, Ptr const& config ) const CATCH_OVERRIDE { + FactoryMap::const_iterator it = m_factories.find( name ); + if( it == m_factories.end() ) + return CATCH_NULL; + return it->second->create( ReporterConfig( config ) ); + } + + void registerReporter( std::string const& name, Ptr const& factory ) { + m_factories.insert( std::make_pair( name, factory ) ); + } + void registerListener( Ptr const& factory ) { + m_listeners.push_back( factory ); + } + + virtual FactoryMap const& getFactories() const CATCH_OVERRIDE { + return m_factories; + } + virtual Listeners const& getListeners() const CATCH_OVERRIDE { + return m_listeners; + } + + private: + FactoryMap m_factories; + Listeners m_listeners; + }; +} + +// #included from: catch_exception_translator_registry.hpp +#define TWOBLUECUBES_CATCH_EXCEPTION_TRANSLATOR_REGISTRY_HPP_INCLUDED + +#ifdef __OBJC__ +#import "Foundation/Foundation.h" +#endif + +namespace Catch { + + class ExceptionTranslatorRegistry : public IExceptionTranslatorRegistry { + public: + ~ExceptionTranslatorRegistry() { + deleteAll( m_translators ); + } + + virtual void registerTranslator( const IExceptionTranslator* translator ) { + m_translators.push_back( translator ); + } + + virtual std::string translateActiveException() const { + try { +#ifdef __OBJC__ + // In Objective-C try objective-c exceptions first + @try { + return tryTranslators(); + } + @catch (NSException *exception) { + return Catch::toString( [exception description] ); + } +#else + return tryTranslators(); +#endif + } + catch( TestFailureException& ) { + throw; + } + catch( std::exception& ex ) { + return ex.what(); + } + catch( std::string& msg ) { + return msg; + } + catch( const char* msg ) { + return msg; + } + catch(...) { + return "Unknown exception"; + } + } + + std::string tryTranslators() const { + if( m_translators.empty() ) + throw; + else + return m_translators[0]->translate( m_translators.begin()+1, m_translators.end() ); + } + + private: + std::vector m_translators; + }; +} + +namespace Catch { + + namespace { + + class RegistryHub : public IRegistryHub, public IMutableRegistryHub { + + RegistryHub( RegistryHub const& ); + void operator=( RegistryHub const& ); + + public: // IRegistryHub + RegistryHub() { + } + virtual IReporterRegistry const& getReporterRegistry() const CATCH_OVERRIDE { + return m_reporterRegistry; + } + virtual ITestCaseRegistry const& getTestCaseRegistry() const CATCH_OVERRIDE { + return m_testCaseRegistry; + } + virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() CATCH_OVERRIDE { + return m_exceptionTranslatorRegistry; + } + + public: // IMutableRegistryHub + virtual void registerReporter( std::string const& name, Ptr const& factory ) CATCH_OVERRIDE { + m_reporterRegistry.registerReporter( name, factory ); + } + virtual void registerListener( Ptr const& factory ) CATCH_OVERRIDE { + m_reporterRegistry.registerListener( factory ); + } + virtual void registerTest( TestCase const& testInfo ) CATCH_OVERRIDE { + m_testCaseRegistry.registerTest( testInfo ); + } + virtual void registerTranslator( const IExceptionTranslator* translator ) CATCH_OVERRIDE { + m_exceptionTranslatorRegistry.registerTranslator( translator ); + } + + private: + TestRegistry m_testCaseRegistry; + ReporterRegistry m_reporterRegistry; + ExceptionTranslatorRegistry m_exceptionTranslatorRegistry; + }; + + // Single, global, instance + inline RegistryHub*& getTheRegistryHub() { + static RegistryHub* theRegistryHub = CATCH_NULL; + if( !theRegistryHub ) + theRegistryHub = new RegistryHub(); + return theRegistryHub; + } + } + + IRegistryHub& getRegistryHub() { + return *getTheRegistryHub(); + } + IMutableRegistryHub& getMutableRegistryHub() { + return *getTheRegistryHub(); + } + void cleanUp() { + delete getTheRegistryHub(); + getTheRegistryHub() = CATCH_NULL; + cleanUpContext(); + } + std::string translateActiveException() { + return getRegistryHub().getExceptionTranslatorRegistry().translateActiveException(); + } + +} // end namespace Catch + +// #included from: catch_notimplemented_exception.hpp +#define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_HPP_INCLUDED + +#include + +namespace Catch { + + NotImplementedException::NotImplementedException( SourceLineInfo const& lineInfo ) + : m_lineInfo( lineInfo ) { + std::ostringstream oss; + oss << lineInfo << ": function "; + oss << "not implemented"; + m_what = oss.str(); + } + + const char* NotImplementedException::what() const CATCH_NOEXCEPT { + return m_what.c_str(); + } + +} // end namespace Catch + +// #included from: catch_context_impl.hpp +#define TWOBLUECUBES_CATCH_CONTEXT_IMPL_HPP_INCLUDED + +// #included from: catch_stream.hpp +#define TWOBLUECUBES_CATCH_STREAM_HPP_INCLUDED + +#include +#include +#include + +namespace Catch { + + template + class StreamBufImpl : public StreamBufBase { + char data[bufferSize]; + WriterF m_writer; + + public: + StreamBufImpl() { + setp( data, data + sizeof(data) ); + } + + ~StreamBufImpl() CATCH_NOEXCEPT { + sync(); + } + + private: + int overflow( int c ) { + sync(); + + if( c != EOF ) { + if( pbase() == epptr() ) + m_writer( std::string( 1, static_cast( c ) ) ); + else + sputc( static_cast( c ) ); + } + return 0; + } + + int sync() { + if( pbase() != pptr() ) { + m_writer( std::string( pbase(), static_cast( pptr() - pbase() ) ) ); + setp( pbase(), epptr() ); + } + return 0; + } + }; + + /////////////////////////////////////////////////////////////////////////// + + FileStream::FileStream( std::string const& filename ) { + m_ofs.open( filename.c_str() ); + if( m_ofs.fail() ) { + std::ostringstream oss; + oss << "Unable to open file: '" << filename << "'"; + throw std::domain_error( oss.str() ); + } + } + + std::ostream& FileStream::stream() const { + return m_ofs; + } + + struct OutputDebugWriter { + + void operator()( std::string const&str ) { + writeToDebugConsole( str ); + } + }; + + DebugOutStream::DebugOutStream() + : m_streamBuf( new StreamBufImpl() ), + m_os( m_streamBuf.get() ) + {} + + std::ostream& DebugOutStream::stream() const { + return m_os; + } + + // Store the streambuf from cout up-front because + // cout may get redirected when running tests + CoutStream::CoutStream() + : m_os( Catch::cout().rdbuf() ) + {} + + std::ostream& CoutStream::stream() const { + return m_os; + } + +#ifndef CATCH_CONFIG_NOSTDOUT // If you #define this you must implement these functions + std::ostream& cout() { + return std::cout; + } + std::ostream& cerr() { + return std::cerr; + } +#endif +} + +namespace Catch { + + class Context : public IMutableContext { + + Context() : m_config( CATCH_NULL ), m_runner( CATCH_NULL ), m_resultCapture( CATCH_NULL ) {} + Context( Context const& ); + void operator=( Context const& ); + + public: // IContext + virtual IResultCapture* getResultCapture() { + return m_resultCapture; + } + virtual IRunner* getRunner() { + return m_runner; + } + virtual size_t getGeneratorIndex( std::string const& fileInfo, size_t totalSize ) { + return getGeneratorsForCurrentTest() + .getGeneratorInfo( fileInfo, totalSize ) + .getCurrentIndex(); + } + virtual bool advanceGeneratorsForCurrentTest() { + IGeneratorsForTest* generators = findGeneratorsForCurrentTest(); + return generators && generators->moveNext(); + } + + virtual Ptr getConfig() const { + return m_config; + } + + public: // IMutableContext + virtual void setResultCapture( IResultCapture* resultCapture ) { + m_resultCapture = resultCapture; + } + virtual void setRunner( IRunner* runner ) { + m_runner = runner; + } + virtual void setConfig( Ptr const& config ) { + m_config = config; + } + + friend IMutableContext& getCurrentMutableContext(); + + private: + IGeneratorsForTest* findGeneratorsForCurrentTest() { + std::string testName = getResultCapture()->getCurrentTestName(); + + std::map::const_iterator it = + m_generatorsByTestName.find( testName ); + return it != m_generatorsByTestName.end() + ? it->second + : CATCH_NULL; + } + + IGeneratorsForTest& getGeneratorsForCurrentTest() { + IGeneratorsForTest* generators = findGeneratorsForCurrentTest(); + if( !generators ) { + std::string testName = getResultCapture()->getCurrentTestName(); + generators = createGeneratorsForTest(); + m_generatorsByTestName.insert( std::make_pair( testName, generators ) ); + } + return *generators; + } + + private: + Ptr m_config; + IRunner* m_runner; + IResultCapture* m_resultCapture; + std::map m_generatorsByTestName; + }; + + namespace { + Context* currentContext = CATCH_NULL; + } + IMutableContext& getCurrentMutableContext() { + if( !currentContext ) + currentContext = new Context(); + return *currentContext; + } + IContext& getCurrentContext() { + return getCurrentMutableContext(); + } + + void cleanUpContext() { + delete currentContext; + currentContext = CATCH_NULL; + } +} + +// #included from: catch_console_colour_impl.hpp +#define TWOBLUECUBES_CATCH_CONSOLE_COLOUR_IMPL_HPP_INCLUDED + +namespace Catch { + namespace { + + struct IColourImpl { + virtual ~IColourImpl() {} + virtual void use( Colour::Code _colourCode ) = 0; + }; + + struct NoColourImpl : IColourImpl { + void use( Colour::Code ) {} + + static IColourImpl* instance() { + static NoColourImpl s_instance; + return &s_instance; + } + }; + + } // anon namespace +} // namespace Catch + +#if !defined( CATCH_CONFIG_COLOUR_NONE ) && !defined( CATCH_CONFIG_COLOUR_WINDOWS ) && !defined( CATCH_CONFIG_COLOUR_ANSI ) +# ifdef CATCH_PLATFORM_WINDOWS +# define CATCH_CONFIG_COLOUR_WINDOWS +# else +# define CATCH_CONFIG_COLOUR_ANSI +# endif +#endif + +#if defined ( CATCH_CONFIG_COLOUR_WINDOWS ) ///////////////////////////////////////// + +#ifndef NOMINMAX +#define NOMINMAX +#endif + +#ifdef __AFXDLL +#include +#else +#include +#endif + +namespace Catch { +namespace { + + class Win32ColourImpl : public IColourImpl { + public: + Win32ColourImpl() : stdoutHandle( GetStdHandle(STD_OUTPUT_HANDLE) ) + { + CONSOLE_SCREEN_BUFFER_INFO csbiInfo; + GetConsoleScreenBufferInfo( stdoutHandle, &csbiInfo ); + originalForegroundAttributes = csbiInfo.wAttributes & ~( BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_BLUE | BACKGROUND_INTENSITY ); + originalBackgroundAttributes = csbiInfo.wAttributes & ~( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY ); + } + + virtual void use( Colour::Code _colourCode ) { + switch( _colourCode ) { + case Colour::None: return setTextAttribute( originalForegroundAttributes ); + case Colour::White: return setTextAttribute( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE ); + case Colour::Red: return setTextAttribute( FOREGROUND_RED ); + case Colour::Green: return setTextAttribute( FOREGROUND_GREEN ); + case Colour::Blue: return setTextAttribute( FOREGROUND_BLUE ); + case Colour::Cyan: return setTextAttribute( FOREGROUND_BLUE | FOREGROUND_GREEN ); + case Colour::Yellow: return setTextAttribute( FOREGROUND_RED | FOREGROUND_GREEN ); + case Colour::Grey: return setTextAttribute( 0 ); + + case Colour::LightGrey: return setTextAttribute( FOREGROUND_INTENSITY ); + case Colour::BrightRed: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED ); + case Colour::BrightGreen: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN ); + case Colour::BrightWhite: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE ); + + case Colour::Bright: throw std::logic_error( "not a colour" ); + } + } + + private: + void setTextAttribute( WORD _textAttribute ) { + SetConsoleTextAttribute( stdoutHandle, _textAttribute | originalBackgroundAttributes ); + } + HANDLE stdoutHandle; + WORD originalForegroundAttributes; + WORD originalBackgroundAttributes; + }; + + IColourImpl* platformColourInstance() { + static Win32ColourImpl s_instance; + + Ptr config = getCurrentContext().getConfig(); + UseColour::YesOrNo colourMode = config + ? config->useColour() + : UseColour::Auto; + if( colourMode == UseColour::Auto ) + colourMode = !isDebuggerActive() + ? UseColour::Yes + : UseColour::No; + return colourMode == UseColour::Yes + ? &s_instance + : NoColourImpl::instance(); + } + +} // end anon namespace +} // end namespace Catch + +#elif defined( CATCH_CONFIG_COLOUR_ANSI ) ////////////////////////////////////// + +#include + +namespace Catch { +namespace { + + // use POSIX/ ANSI console terminal codes + // Thanks to Adam Strzelecki for original contribution + // (http://github.com/nanoant) + // https://github.com/philsquared/Catch/pull/131 + class PosixColourImpl : public IColourImpl { + public: + virtual void use( Colour::Code _colourCode ) { + switch( _colourCode ) { + case Colour::None: + case Colour::White: return setColour( "[0m" ); + case Colour::Red: return setColour( "[0;31m" ); + case Colour::Green: return setColour( "[0;32m" ); + case Colour::Blue: return setColour( "[0:34m" ); + case Colour::Cyan: return setColour( "[0;36m" ); + case Colour::Yellow: return setColour( "[0;33m" ); + case Colour::Grey: return setColour( "[1;30m" ); + + case Colour::LightGrey: return setColour( "[0;37m" ); + case Colour::BrightRed: return setColour( "[1;31m" ); + case Colour::BrightGreen: return setColour( "[1;32m" ); + case Colour::BrightWhite: return setColour( "[1;37m" ); + + case Colour::Bright: throw std::logic_error( "not a colour" ); + } + } + static IColourImpl* instance() { + static PosixColourImpl s_instance; + return &s_instance; + } + + private: + void setColour( const char* _escapeCode ) { + Catch::cout() << '\033' << _escapeCode; + } + }; + + IColourImpl* platformColourInstance() { + Ptr config = getCurrentContext().getConfig(); + UseColour::YesOrNo colourMode = config + ? config->useColour() + : UseColour::Auto; + if( colourMode == UseColour::Auto ) + colourMode = (!isDebuggerActive() && isatty(STDOUT_FILENO) ) + ? UseColour::Yes + : UseColour::No; + return colourMode == UseColour::Yes + ? PosixColourImpl::instance() + : NoColourImpl::instance(); + } + +} // end anon namespace +} // end namespace Catch + +#else // not Windows or ANSI /////////////////////////////////////////////// + +namespace Catch { + + static IColourImpl* platformColourInstance() { return NoColourImpl::instance(); } + +} // end namespace Catch + +#endif // Windows/ ANSI/ None + +namespace Catch { + + Colour::Colour( Code _colourCode ) : m_moved( false ) { use( _colourCode ); } + Colour::Colour( Colour const& _other ) : m_moved( false ) { const_cast( _other ).m_moved = true; } + Colour::~Colour(){ if( !m_moved ) use( None ); } + + void Colour::use( Code _colourCode ) { + static IColourImpl* impl = platformColourInstance(); + impl->use( _colourCode ); + } + +} // end namespace Catch + +// #included from: catch_generators_impl.hpp +#define TWOBLUECUBES_CATCH_GENERATORS_IMPL_HPP_INCLUDED + +#include +#include +#include + +namespace Catch { + + struct GeneratorInfo : IGeneratorInfo { + + GeneratorInfo( std::size_t size ) + : m_size( size ), + m_currentIndex( 0 ) + {} + + bool moveNext() { + if( ++m_currentIndex == m_size ) { + m_currentIndex = 0; + return false; + } + return true; + } + + std::size_t getCurrentIndex() const { + return m_currentIndex; + } + + std::size_t m_size; + std::size_t m_currentIndex; + }; + + /////////////////////////////////////////////////////////////////////////// + + class GeneratorsForTest : public IGeneratorsForTest { + + public: + ~GeneratorsForTest() { + deleteAll( m_generatorsInOrder ); + } + + IGeneratorInfo& getGeneratorInfo( std::string const& fileInfo, std::size_t size ) { + std::map::const_iterator it = m_generatorsByName.find( fileInfo ); + if( it == m_generatorsByName.end() ) { + IGeneratorInfo* info = new GeneratorInfo( size ); + m_generatorsByName.insert( std::make_pair( fileInfo, info ) ); + m_generatorsInOrder.push_back( info ); + return *info; + } + return *it->second; + } + + bool moveNext() { + std::vector::const_iterator it = m_generatorsInOrder.begin(); + std::vector::const_iterator itEnd = m_generatorsInOrder.end(); + for(; it != itEnd; ++it ) { + if( (*it)->moveNext() ) + return true; + } + return false; + } + + private: + std::map m_generatorsByName; + std::vector m_generatorsInOrder; + }; + + IGeneratorsForTest* createGeneratorsForTest() + { + return new GeneratorsForTest(); + } + +} // end namespace Catch + +// #included from: catch_assertionresult.hpp +#define TWOBLUECUBES_CATCH_ASSERTIONRESULT_HPP_INCLUDED + +namespace Catch { + + AssertionInfo::AssertionInfo( std::string const& _macroName, + SourceLineInfo const& _lineInfo, + std::string const& _capturedExpression, + ResultDisposition::Flags _resultDisposition ) + : macroName( _macroName ), + lineInfo( _lineInfo ), + capturedExpression( _capturedExpression ), + resultDisposition( _resultDisposition ) + {} + + AssertionResult::AssertionResult() {} + + AssertionResult::AssertionResult( AssertionInfo const& info, AssertionResultData const& data ) + : m_info( info ), + m_resultData( data ) + {} + + AssertionResult::~AssertionResult() {} + + // Result was a success + bool AssertionResult::succeeded() const { + return Catch::isOk( m_resultData.resultType ); + } + + // Result was a success, or failure is suppressed + bool AssertionResult::isOk() const { + return Catch::isOk( m_resultData.resultType ) || shouldSuppressFailure( m_info.resultDisposition ); + } + + ResultWas::OfType AssertionResult::getResultType() const { + return m_resultData.resultType; + } + + bool AssertionResult::hasExpression() const { + return !m_info.capturedExpression.empty(); + } + + bool AssertionResult::hasMessage() const { + return !m_resultData.message.empty(); + } + + std::string AssertionResult::getExpression() const { + if( isFalseTest( m_info.resultDisposition ) ) + return "!" + m_info.capturedExpression; + else + return m_info.capturedExpression; + } + std::string AssertionResult::getExpressionInMacro() const { + if( m_info.macroName.empty() ) + return m_info.capturedExpression; + else + return m_info.macroName + "( " + m_info.capturedExpression + " )"; + } + + bool AssertionResult::hasExpandedExpression() const { + return hasExpression() && getExpandedExpression() != getExpression(); + } + + std::string AssertionResult::getExpandedExpression() const { + return m_resultData.reconstructedExpression; + } + + std::string AssertionResult::getMessage() const { + return m_resultData.message; + } + SourceLineInfo AssertionResult::getSourceInfo() const { + return m_info.lineInfo; + } + + std::string AssertionResult::getTestMacroName() const { + return m_info.macroName; + } + +} // end namespace Catch + +// #included from: catch_test_case_info.hpp +#define TWOBLUECUBES_CATCH_TEST_CASE_INFO_HPP_INCLUDED + +namespace Catch { + + inline TestCaseInfo::SpecialProperties parseSpecialTag( std::string const& tag ) { + if( startsWith( tag, "." ) || + tag == "hide" || + tag == "!hide" ) + return TestCaseInfo::IsHidden; + else if( tag == "!throws" ) + return TestCaseInfo::Throws; + else if( tag == "!shouldfail" ) + return TestCaseInfo::ShouldFail; + else if( tag == "!mayfail" ) + return TestCaseInfo::MayFail; + else + return TestCaseInfo::None; + } + inline bool isReservedTag( std::string const& tag ) { + return parseSpecialTag( tag ) == TestCaseInfo::None && tag.size() > 0 && !isalnum( tag[0] ); + } + inline void enforceNotReservedTag( std::string const& tag, SourceLineInfo const& _lineInfo ) { + if( isReservedTag( tag ) ) { + { + Colour colourGuard( Colour::Red ); + Catch::cerr() + << "Tag name [" << tag << "] not allowed.\n" + << "Tag names starting with non alpha-numeric characters are reserved\n"; + } + { + Colour colourGuard( Colour::FileName ); + Catch::cerr() << _lineInfo << std::endl; + } + exit(1); + } + } + + TestCase makeTestCase( ITestCase* _testCase, + std::string const& _className, + std::string const& _name, + std::string const& _descOrTags, + SourceLineInfo const& _lineInfo ) + { + bool isHidden( startsWith( _name, "./" ) ); // Legacy support + + // Parse out tags + std::set tags; + std::string desc, tag; + bool inTag = false; + for( std::size_t i = 0; i < _descOrTags.size(); ++i ) { + char c = _descOrTags[i]; + if( !inTag ) { + if( c == '[' ) + inTag = true; + else + desc += c; + } + else { + if( c == ']' ) { + TestCaseInfo::SpecialProperties prop = parseSpecialTag( tag ); + if( prop == TestCaseInfo::IsHidden ) + isHidden = true; + else if( prop == TestCaseInfo::None ) + enforceNotReservedTag( tag, _lineInfo ); + + tags.insert( tag ); + tag.clear(); + inTag = false; + } + else + tag += c; + } + } + if( isHidden ) { + tags.insert( "hide" ); + tags.insert( "." ); + } + + TestCaseInfo info( _name, _className, desc, tags, _lineInfo ); + return TestCase( _testCase, info ); + } + + void setTags( TestCaseInfo& testCaseInfo, std::set const& tags ) + { + testCaseInfo.tags = tags; + testCaseInfo.lcaseTags.clear(); + + std::ostringstream oss; + for( std::set::const_iterator it = tags.begin(), itEnd = tags.end(); it != itEnd; ++it ) { + oss << "[" << *it << "]"; + std::string lcaseTag = toLower( *it ); + testCaseInfo.properties = static_cast( testCaseInfo.properties | parseSpecialTag( lcaseTag ) ); + testCaseInfo.lcaseTags.insert( lcaseTag ); + } + testCaseInfo.tagsAsString = oss.str(); + } + + TestCaseInfo::TestCaseInfo( std::string const& _name, + std::string const& _className, + std::string const& _description, + std::set const& _tags, + SourceLineInfo const& _lineInfo ) + : name( _name ), + className( _className ), + description( _description ), + lineInfo( _lineInfo ), + properties( None ) + { + setTags( *this, _tags ); + } + + TestCaseInfo::TestCaseInfo( TestCaseInfo const& other ) + : name( other.name ), + className( other.className ), + description( other.description ), + tags( other.tags ), + lcaseTags( other.lcaseTags ), + tagsAsString( other.tagsAsString ), + lineInfo( other.lineInfo ), + properties( other.properties ) + {} + + bool TestCaseInfo::isHidden() const { + return ( properties & IsHidden ) != 0; + } + bool TestCaseInfo::throws() const { + return ( properties & Throws ) != 0; + } + bool TestCaseInfo::okToFail() const { + return ( properties & (ShouldFail | MayFail ) ) != 0; + } + bool TestCaseInfo::expectedToFail() const { + return ( properties & (ShouldFail ) ) != 0; + } + + TestCase::TestCase( ITestCase* testCase, TestCaseInfo const& info ) : TestCaseInfo( info ), test( testCase ) {} + + TestCase::TestCase( TestCase const& other ) + : TestCaseInfo( other ), + test( other.test ) + {} + + TestCase TestCase::withName( std::string const& _newName ) const { + TestCase other( *this ); + other.name = _newName; + return other; + } + + void TestCase::swap( TestCase& other ) { + test.swap( other.test ); + name.swap( other.name ); + className.swap( other.className ); + description.swap( other.description ); + tags.swap( other.tags ); + lcaseTags.swap( other.lcaseTags ); + tagsAsString.swap( other.tagsAsString ); + std::swap( TestCaseInfo::properties, static_cast( other ).properties ); + std::swap( lineInfo, other.lineInfo ); + } + + void TestCase::invoke() const { + test->invoke(); + } + + bool TestCase::operator == ( TestCase const& other ) const { + return test.get() == other.test.get() && + name == other.name && + className == other.className; + } + + bool TestCase::operator < ( TestCase const& other ) const { + return name < other.name; + } + TestCase& TestCase::operator = ( TestCase const& other ) { + TestCase temp( other ); + swap( temp ); + return *this; + } + + TestCaseInfo const& TestCase::getTestCaseInfo() const + { + return *this; + } + +} // end namespace Catch + +// #included from: catch_version.hpp +#define TWOBLUECUBES_CATCH_VERSION_HPP_INCLUDED + +namespace Catch { + + Version::Version + ( unsigned int _majorVersion, + unsigned int _minorVersion, + unsigned int _patchNumber, + std::string const& _branchName, + unsigned int _buildNumber ) + : majorVersion( _majorVersion ), + minorVersion( _minorVersion ), + patchNumber( _patchNumber ), + branchName( _branchName ), + buildNumber( _buildNumber ) + {} + + std::ostream& operator << ( std::ostream& os, Version const& version ) { + os << version.majorVersion << "." + << version.minorVersion << "." + << version.patchNumber; + + if( !version.branchName.empty() ) { + os << "-" << version.branchName + << "." << version.buildNumber; + } + return os; + } + + Version libraryVersion( 1, 3, 6, "", 0 ); + +} + +// #included from: catch_message.hpp +#define TWOBLUECUBES_CATCH_MESSAGE_HPP_INCLUDED + +namespace Catch { + + MessageInfo::MessageInfo( std::string const& _macroName, + SourceLineInfo const& _lineInfo, + ResultWas::OfType _type ) + : macroName( _macroName ), + lineInfo( _lineInfo ), + type( _type ), + sequence( ++globalCount ) + {} + + // This may need protecting if threading support is added + unsigned int MessageInfo::globalCount = 0; + + //////////////////////////////////////////////////////////////////////////// + + ScopedMessage::ScopedMessage( MessageBuilder const& builder ) + : m_info( builder.m_info ) + { + m_info.message = builder.m_stream.str(); + getResultCapture().pushScopedMessage( m_info ); + } + ScopedMessage::ScopedMessage( ScopedMessage const& other ) + : m_info( other.m_info ) + {} + + ScopedMessage::~ScopedMessage() { + getResultCapture().popScopedMessage( m_info ); + } + +} // end namespace Catch + +// #included from: catch_legacy_reporter_adapter.hpp +#define TWOBLUECUBES_CATCH_LEGACY_REPORTER_ADAPTER_HPP_INCLUDED + +// #included from: catch_legacy_reporter_adapter.h +#define TWOBLUECUBES_CATCH_LEGACY_REPORTER_ADAPTER_H_INCLUDED + +namespace Catch +{ + // Deprecated + struct IReporter : IShared { + virtual ~IReporter(); + + virtual bool shouldRedirectStdout() const = 0; + + virtual void StartTesting() = 0; + virtual void EndTesting( Totals const& totals ) = 0; + virtual void StartGroup( std::string const& groupName ) = 0; + virtual void EndGroup( std::string const& groupName, Totals const& totals ) = 0; + virtual void StartTestCase( TestCaseInfo const& testInfo ) = 0; + virtual void EndTestCase( TestCaseInfo const& testInfo, Totals const& totals, std::string const& stdOut, std::string const& stdErr ) = 0; + virtual void StartSection( std::string const& sectionName, std::string const& description ) = 0; + virtual void EndSection( std::string const& sectionName, Counts const& assertions ) = 0; + virtual void NoAssertionsInSection( std::string const& sectionName ) = 0; + virtual void NoAssertionsInTestCase( std::string const& testName ) = 0; + virtual void Aborted() = 0; + virtual void Result( AssertionResult const& result ) = 0; + }; + + class LegacyReporterAdapter : public SharedImpl + { + public: + LegacyReporterAdapter( Ptr const& legacyReporter ); + virtual ~LegacyReporterAdapter(); + + virtual ReporterPreferences getPreferences() const; + virtual void noMatchingTestCases( std::string const& ); + virtual void testRunStarting( TestRunInfo const& ); + virtual void testGroupStarting( GroupInfo const& groupInfo ); + virtual void testCaseStarting( TestCaseInfo const& testInfo ); + virtual void sectionStarting( SectionInfo const& sectionInfo ); + virtual void assertionStarting( AssertionInfo const& ); + virtual bool assertionEnded( AssertionStats const& assertionStats ); + virtual void sectionEnded( SectionStats const& sectionStats ); + virtual void testCaseEnded( TestCaseStats const& testCaseStats ); + virtual void testGroupEnded( TestGroupStats const& testGroupStats ); + virtual void testRunEnded( TestRunStats const& testRunStats ); + virtual void skipTest( TestCaseInfo const& ); + + private: + Ptr m_legacyReporter; + }; +} + +namespace Catch +{ + LegacyReporterAdapter::LegacyReporterAdapter( Ptr const& legacyReporter ) + : m_legacyReporter( legacyReporter ) + {} + LegacyReporterAdapter::~LegacyReporterAdapter() {} + + ReporterPreferences LegacyReporterAdapter::getPreferences() const { + ReporterPreferences prefs; + prefs.shouldRedirectStdOut = m_legacyReporter->shouldRedirectStdout(); + return prefs; + } + + void LegacyReporterAdapter::noMatchingTestCases( std::string const& ) {} + void LegacyReporterAdapter::testRunStarting( TestRunInfo const& ) { + m_legacyReporter->StartTesting(); + } + void LegacyReporterAdapter::testGroupStarting( GroupInfo const& groupInfo ) { + m_legacyReporter->StartGroup( groupInfo.name ); + } + void LegacyReporterAdapter::testCaseStarting( TestCaseInfo const& testInfo ) { + m_legacyReporter->StartTestCase( testInfo ); + } + void LegacyReporterAdapter::sectionStarting( SectionInfo const& sectionInfo ) { + m_legacyReporter->StartSection( sectionInfo.name, sectionInfo.description ); + } + void LegacyReporterAdapter::assertionStarting( AssertionInfo const& ) { + // Not on legacy interface + } + + bool LegacyReporterAdapter::assertionEnded( AssertionStats const& assertionStats ) { + if( assertionStats.assertionResult.getResultType() != ResultWas::Ok ) { + for( std::vector::const_iterator it = assertionStats.infoMessages.begin(), itEnd = assertionStats.infoMessages.end(); + it != itEnd; + ++it ) { + if( it->type == ResultWas::Info ) { + ResultBuilder rb( it->macroName.c_str(), it->lineInfo, "", ResultDisposition::Normal ); + rb << it->message; + rb.setResultType( ResultWas::Info ); + AssertionResult result = rb.build(); + m_legacyReporter->Result( result ); + } + } + } + m_legacyReporter->Result( assertionStats.assertionResult ); + return true; + } + void LegacyReporterAdapter::sectionEnded( SectionStats const& sectionStats ) { + if( sectionStats.missingAssertions ) + m_legacyReporter->NoAssertionsInSection( sectionStats.sectionInfo.name ); + m_legacyReporter->EndSection( sectionStats.sectionInfo.name, sectionStats.assertions ); + } + void LegacyReporterAdapter::testCaseEnded( TestCaseStats const& testCaseStats ) { + m_legacyReporter->EndTestCase + ( testCaseStats.testInfo, + testCaseStats.totals, + testCaseStats.stdOut, + testCaseStats.stdErr ); + } + void LegacyReporterAdapter::testGroupEnded( TestGroupStats const& testGroupStats ) { + if( testGroupStats.aborting ) + m_legacyReporter->Aborted(); + m_legacyReporter->EndGroup( testGroupStats.groupInfo.name, testGroupStats.totals ); + } + void LegacyReporterAdapter::testRunEnded( TestRunStats const& testRunStats ) { + m_legacyReporter->EndTesting( testRunStats.totals ); + } + void LegacyReporterAdapter::skipTest( TestCaseInfo const& ) { + } +} + +// #included from: catch_timer.hpp + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wc++11-long-long" +#endif + +#ifdef CATCH_PLATFORM_WINDOWS +#include +#else +#include +#endif + +namespace Catch { + + namespace { +#ifdef CATCH_PLATFORM_WINDOWS + uint64_t getCurrentTicks() { + static uint64_t hz=0, hzo=0; + if (!hz) { + QueryPerformanceFrequency( reinterpret_cast( &hz ) ); + QueryPerformanceCounter( reinterpret_cast( &hzo ) ); + } + uint64_t t; + QueryPerformanceCounter( reinterpret_cast( &t ) ); + return ((t-hzo)*1000000)/hz; + } +#else + uint64_t getCurrentTicks() { + timeval t; + gettimeofday(&t,CATCH_NULL); + return static_cast( t.tv_sec ) * 1000000ull + static_cast( t.tv_usec ); + } +#endif + } + + void Timer::start() { + m_ticks = getCurrentTicks(); + } + unsigned int Timer::getElapsedMicroseconds() const { + return static_cast(getCurrentTicks() - m_ticks); + } + unsigned int Timer::getElapsedMilliseconds() const { + return static_cast(getElapsedMicroseconds()/1000); + } + double Timer::getElapsedSeconds() const { + return getElapsedMicroseconds()/1000000.0; + } + +} // namespace Catch + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif +// #included from: catch_common.hpp +#define TWOBLUECUBES_CATCH_COMMON_HPP_INCLUDED + +namespace Catch { + + bool startsWith( std::string const& s, std::string const& prefix ) { + return s.size() >= prefix.size() && s.substr( 0, prefix.size() ) == prefix; + } + bool endsWith( std::string const& s, std::string const& suffix ) { + return s.size() >= suffix.size() && s.substr( s.size()-suffix.size(), suffix.size() ) == suffix; + } + bool contains( std::string const& s, std::string const& infix ) { + return s.find( infix ) != std::string::npos; + } + void toLowerInPlace( std::string& s ) { + std::transform( s.begin(), s.end(), s.begin(), ::tolower ); + } + std::string toLower( std::string const& s ) { + std::string lc = s; + toLowerInPlace( lc ); + return lc; + } + std::string trim( std::string const& str ) { + static char const* whitespaceChars = "\n\r\t "; + std::string::size_type start = str.find_first_not_of( whitespaceChars ); + std::string::size_type end = str.find_last_not_of( whitespaceChars ); + + return start != std::string::npos ? str.substr( start, 1+end-start ) : ""; + } + + bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ) { + bool replaced = false; + std::size_t i = str.find( replaceThis ); + while( i != std::string::npos ) { + replaced = true; + str = str.substr( 0, i ) + withThis + str.substr( i+replaceThis.size() ); + if( i < str.size()-withThis.size() ) + i = str.find( replaceThis, i+withThis.size() ); + else + i = std::string::npos; + } + return replaced; + } + + pluralise::pluralise( std::size_t count, std::string const& label ) + : m_count( count ), + m_label( label ) + {} + + std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ) { + os << pluraliser.m_count << " " << pluraliser.m_label; + if( pluraliser.m_count != 1 ) + os << "s"; + return os; + } + + SourceLineInfo::SourceLineInfo() : line( 0 ){} + SourceLineInfo::SourceLineInfo( char const* _file, std::size_t _line ) + : file( _file ), + line( _line ) + {} + SourceLineInfo::SourceLineInfo( SourceLineInfo const& other ) + : file( other.file ), + line( other.line ) + {} + bool SourceLineInfo::empty() const { + return file.empty(); + } + bool SourceLineInfo::operator == ( SourceLineInfo const& other ) const { + return line == other.line && file == other.file; + } + bool SourceLineInfo::operator < ( SourceLineInfo const& other ) const { + return line < other.line || ( line == other.line && file < other.file ); + } + + void seedRng( IConfig const& config ) { + if( config.rngSeed() != 0 ) + std::srand( config.rngSeed() ); + } + unsigned int rngSeed() { + return getCurrentContext().getConfig()->rngSeed(); + } + + std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ) { +#ifndef __GNUG__ + os << info.file << "(" << info.line << ")"; +#else + os << info.file << ":" << info.line; +#endif + return os; + } + + void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo ) { + std::ostringstream oss; + oss << locationInfo << ": Internal Catch error: '" << message << "'"; + if( alwaysTrue() ) + throw std::logic_error( oss.str() ); + } +} + +// #included from: catch_section.hpp +#define TWOBLUECUBES_CATCH_SECTION_HPP_INCLUDED + +namespace Catch { + + SectionInfo::SectionInfo + ( SourceLineInfo const& _lineInfo, + std::string const& _name, + std::string const& _description ) + : name( _name ), + description( _description ), + lineInfo( _lineInfo ) + {} + + Section::Section( SectionInfo const& info ) + : m_info( info ), + m_sectionIncluded( getResultCapture().sectionStarted( m_info, m_assertions ) ) + { + m_timer.start(); + } + + Section::~Section() { + if( m_sectionIncluded ) { + SectionEndInfo endInfo( m_info, m_assertions, m_timer.getElapsedSeconds() ); + if( std::uncaught_exception() ) + getResultCapture().sectionEndedEarly( endInfo ); + else + getResultCapture().sectionEnded( endInfo ); + } + } + + // This indicates whether the section should be executed or not + Section::operator bool() const { + return m_sectionIncluded; + } + +} // end namespace Catch + +// #included from: catch_debugger.hpp +#define TWOBLUECUBES_CATCH_DEBUGGER_HPP_INCLUDED + +#include + +#ifdef CATCH_PLATFORM_MAC + + #include + #include + #include + #include + #include + + namespace Catch{ + + // The following function is taken directly from the following technical note: + // http://developer.apple.com/library/mac/#qa/qa2004/qa1361.html + + // Returns true if the current process is being debugged (either + // running under the debugger or has a debugger attached post facto). + bool isDebuggerActive(){ + + int mib[4]; + struct kinfo_proc info; + size_t size; + + // Initialize the flags so that, if sysctl fails for some bizarre + // reason, we get a predictable result. + + info.kp_proc.p_flag = 0; + + // Initialize mib, which tells sysctl the info we want, in this case + // we're looking for information about a specific process ID. + + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PID; + mib[3] = getpid(); + + // Call sysctl. + + size = sizeof(info); + if( sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, CATCH_NULL, 0) != 0 ) { + Catch::cerr() << "\n** Call to sysctl failed - unable to determine if debugger is active **\n" << std::endl; + return false; + } + + // We're being debugged if the P_TRACED flag is set. + + return ( (info.kp_proc.p_flag & P_TRACED) != 0 ); + } + } // namespace Catch + +#elif defined(_MSC_VER) + extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); + namespace Catch { + bool isDebuggerActive() { + return IsDebuggerPresent() != 0; + } + } +#elif defined(__MINGW32__) + extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); + namespace Catch { + bool isDebuggerActive() { + return IsDebuggerPresent() != 0; + } + } +#else + namespace Catch { + inline bool isDebuggerActive() { return false; } + } +#endif // Platform + +#ifdef CATCH_PLATFORM_WINDOWS + extern "C" __declspec(dllimport) void __stdcall OutputDebugStringA( const char* ); + namespace Catch { + void writeToDebugConsole( std::string const& text ) { + ::OutputDebugStringA( text.c_str() ); + } + } +#else + namespace Catch { + void writeToDebugConsole( std::string const& text ) { + // !TBD: Need a version for Mac/ XCode and other IDEs + Catch::cout() << text; + } + } +#endif // Platform + +// #included from: catch_tostring.hpp +#define TWOBLUECUBES_CATCH_TOSTRING_HPP_INCLUDED + +namespace Catch { + +namespace Detail { + + const std::string unprintableString = "{?}"; + + namespace { + const int hexThreshold = 255; + + struct Endianness { + enum Arch { Big, Little }; + + static Arch which() { + union _{ + int asInt; + char asChar[sizeof (int)]; + } u; + + u.asInt = 1; + return ( u.asChar[sizeof(int)-1] == 1 ) ? Big : Little; + } + }; + } + + std::string rawMemoryToString( const void *object, std::size_t size ) + { + // Reverse order for little endian architectures + int i = 0, end = static_cast( size ), inc = 1; + if( Endianness::which() == Endianness::Little ) { + i = end-1; + end = inc = -1; + } + + unsigned char const *bytes = static_cast(object); + std::ostringstream os; + os << "0x" << std::setfill('0') << std::hex; + for( ; i != end; i += inc ) + os << std::setw(2) << static_cast(bytes[i]); + return os.str(); + } +} + +std::string toString( std::string const& value ) { + std::string s = value; + if( getCurrentContext().getConfig()->showInvisibles() ) { + for(size_t i = 0; i < s.size(); ++i ) { + std::string subs; + switch( s[i] ) { + case '\n': subs = "\\n"; break; + case '\t': subs = "\\t"; break; + default: break; + } + if( !subs.empty() ) { + s = s.substr( 0, i ) + subs + s.substr( i+1 ); + ++i; + } + } + } + return "\"" + s + "\""; +} +std::string toString( std::wstring const& value ) { + + std::string s; + s.reserve( value.size() ); + for(size_t i = 0; i < value.size(); ++i ) + s += value[i] <= 0xff ? static_cast( value[i] ) : '?'; + return Catch::toString( s ); +} + +std::string toString( const char* const value ) { + return value ? Catch::toString( std::string( value ) ) : std::string( "{null string}" ); +} + +std::string toString( char* const value ) { + return Catch::toString( static_cast( value ) ); +} + +std::string toString( const wchar_t* const value ) +{ + return value ? Catch::toString( std::wstring(value) ) : std::string( "{null string}" ); +} + +std::string toString( wchar_t* const value ) +{ + return Catch::toString( static_cast( value ) ); +} + +std::string toString( int value ) { + std::ostringstream oss; + oss << value; + if( value > Detail::hexThreshold ) + oss << " (0x" << std::hex << value << ")"; + return oss.str(); +} + +std::string toString( unsigned long value ) { + std::ostringstream oss; + oss << value; + if( value > Detail::hexThreshold ) + oss << " (0x" << std::hex << value << ")"; + return oss.str(); +} + +std::string toString( unsigned int value ) { + return Catch::toString( static_cast( value ) ); +} + +template +std::string fpToString( T value, int precision ) { + std::ostringstream oss; + oss << std::setprecision( precision ) + << std::fixed + << value; + std::string d = oss.str(); + std::size_t i = d.find_last_not_of( '0' ); + if( i != std::string::npos && i != d.size()-1 ) { + if( d[i] == '.' ) + i++; + d = d.substr( 0, i+1 ); + } + return d; +} + +std::string toString( const double value ) { + return fpToString( value, 10 ); +} +std::string toString( const float value ) { + return fpToString( value, 5 ) + "f"; +} + +std::string toString( bool value ) { + return value ? "true" : "false"; +} + +std::string toString( char value ) { + return value < ' ' + ? toString( static_cast( value ) ) + : Detail::makeString( value ); +} + +std::string toString( signed char value ) { + return toString( static_cast( value ) ); +} + +std::string toString( unsigned char value ) { + return toString( static_cast( value ) ); +} + +#ifdef CATCH_CONFIG_CPP11_LONG_LONG +std::string toString( long long value ) { + std::ostringstream oss; + oss << value; + if( value > Detail::hexThreshold ) + oss << " (0x" << std::hex << value << ")"; + return oss.str(); +} +std::string toString( unsigned long long value ) { + std::ostringstream oss; + oss << value; + if( value > Detail::hexThreshold ) + oss << " (0x" << std::hex << value << ")"; + return oss.str(); +} +#endif + +#ifdef CATCH_CONFIG_CPP11_NULLPTR +std::string toString( std::nullptr_t ) { + return "nullptr"; +} +#endif + +#ifdef __OBJC__ + std::string toString( NSString const * const& nsstring ) { + if( !nsstring ) + return "nil"; + return "@" + toString([nsstring UTF8String]); + } + std::string toString( NSString * CATCH_ARC_STRONG const& nsstring ) { + if( !nsstring ) + return "nil"; + return "@" + toString([nsstring UTF8String]); + } + std::string toString( NSObject* const& nsObject ) { + return toString( [nsObject description] ); + } +#endif + +} // end namespace Catch + +// #included from: catch_result_builder.hpp +#define TWOBLUECUBES_CATCH_RESULT_BUILDER_HPP_INCLUDED + +namespace Catch { + + std::string capturedExpressionWithSecondArgument( std::string const& capturedExpression, std::string const& secondArg ) { + return secondArg.empty() || secondArg == "\"\"" + ? capturedExpression + : capturedExpression + ", " + secondArg; + } + ResultBuilder::ResultBuilder( char const* macroName, + SourceLineInfo const& lineInfo, + char const* capturedExpression, + ResultDisposition::Flags resultDisposition, + char const* secondArg ) + : m_assertionInfo( macroName, lineInfo, capturedExpressionWithSecondArgument( capturedExpression, secondArg ), resultDisposition ), + m_shouldDebugBreak( false ), + m_shouldThrow( false ) + {} + + ResultBuilder& ResultBuilder::setResultType( ResultWas::OfType result ) { + m_data.resultType = result; + return *this; + } + ResultBuilder& ResultBuilder::setResultType( bool result ) { + m_data.resultType = result ? ResultWas::Ok : ResultWas::ExpressionFailed; + return *this; + } + ResultBuilder& ResultBuilder::setLhs( std::string const& lhs ) { + m_exprComponents.lhs = lhs; + return *this; + } + ResultBuilder& ResultBuilder::setRhs( std::string const& rhs ) { + m_exprComponents.rhs = rhs; + return *this; + } + ResultBuilder& ResultBuilder::setOp( std::string const& op ) { + m_exprComponents.op = op; + return *this; + } + + void ResultBuilder::endExpression() { + m_exprComponents.testFalse = isFalseTest( m_assertionInfo.resultDisposition ); + captureExpression(); + } + + void ResultBuilder::useActiveException( ResultDisposition::Flags resultDisposition ) { + m_assertionInfo.resultDisposition = resultDisposition; + m_stream.oss << Catch::translateActiveException(); + captureResult( ResultWas::ThrewException ); + } + + void ResultBuilder::captureResult( ResultWas::OfType resultType ) { + setResultType( resultType ); + captureExpression(); + } + void ResultBuilder::captureExpectedException( std::string const& expectedMessage ) { + if( expectedMessage.empty() ) + captureExpectedException( Matchers::Impl::Generic::AllOf() ); + else + captureExpectedException( Matchers::Equals( expectedMessage ) ); + } + + void ResultBuilder::captureExpectedException( Matchers::Impl::Matcher const& matcher ) { + + assert( m_exprComponents.testFalse == false ); + AssertionResultData data = m_data; + data.resultType = ResultWas::Ok; + data.reconstructedExpression = m_assertionInfo.capturedExpression; + + std::string actualMessage = Catch::translateActiveException(); + if( !matcher.match( actualMessage ) ) { + data.resultType = ResultWas::ExpressionFailed; + data.reconstructedExpression = actualMessage; + } + AssertionResult result( m_assertionInfo, data ); + handleResult( result ); + } + + void ResultBuilder::captureExpression() { + AssertionResult result = build(); + handleResult( result ); + } + void ResultBuilder::handleResult( AssertionResult const& result ) + { + getResultCapture().assertionEnded( result ); + + if( !result.isOk() ) { + if( getCurrentContext().getConfig()->shouldDebugBreak() ) + m_shouldDebugBreak = true; + if( getCurrentContext().getRunner()->aborting() || (m_assertionInfo.resultDisposition & ResultDisposition::Normal) ) + m_shouldThrow = true; + } + } + void ResultBuilder::react() { + if( m_shouldThrow ) + throw Catch::TestFailureException(); + } + + bool ResultBuilder::shouldDebugBreak() const { return m_shouldDebugBreak; } + bool ResultBuilder::allowThrows() const { return getCurrentContext().getConfig()->allowThrows(); } + + AssertionResult ResultBuilder::build() const + { + assert( m_data.resultType != ResultWas::Unknown ); + + AssertionResultData data = m_data; + + // Flip bool results if testFalse is set + if( m_exprComponents.testFalse ) { + if( data.resultType == ResultWas::Ok ) + data.resultType = ResultWas::ExpressionFailed; + else if( data.resultType == ResultWas::ExpressionFailed ) + data.resultType = ResultWas::Ok; + } + + data.message = m_stream.oss.str(); + data.reconstructedExpression = reconstructExpression(); + if( m_exprComponents.testFalse ) { + if( m_exprComponents.op == "" ) + data.reconstructedExpression = "!" + data.reconstructedExpression; + else + data.reconstructedExpression = "!(" + data.reconstructedExpression + ")"; + } + return AssertionResult( m_assertionInfo, data ); + } + std::string ResultBuilder::reconstructExpression() const { + if( m_exprComponents.op == "" ) + return m_exprComponents.lhs.empty() ? m_assertionInfo.capturedExpression : m_exprComponents.op + m_exprComponents.lhs; + else if( m_exprComponents.op == "matches" ) + return m_exprComponents.lhs + " " + m_exprComponents.rhs; + else if( m_exprComponents.op != "!" ) { + if( m_exprComponents.lhs.size() + m_exprComponents.rhs.size() < 40 && + m_exprComponents.lhs.find("\n") == std::string::npos && + m_exprComponents.rhs.find("\n") == std::string::npos ) + return m_exprComponents.lhs + " " + m_exprComponents.op + " " + m_exprComponents.rhs; + else + return m_exprComponents.lhs + "\n" + m_exprComponents.op + "\n" + m_exprComponents.rhs; + } + else + return "{can't expand - use " + m_assertionInfo.macroName + "_FALSE( " + m_assertionInfo.capturedExpression.substr(1) + " ) instead of " + m_assertionInfo.macroName + "( " + m_assertionInfo.capturedExpression + " ) for better diagnostics}"; + } + +} // end namespace Catch + +// #included from: catch_tag_alias_registry.hpp +#define TWOBLUECUBES_CATCH_TAG_ALIAS_REGISTRY_HPP_INCLUDED + +// #included from: catch_tag_alias_registry.h +#define TWOBLUECUBES_CATCH_TAG_ALIAS_REGISTRY_H_INCLUDED + +#include + +namespace Catch { + + class TagAliasRegistry : public ITagAliasRegistry { + public: + virtual ~TagAliasRegistry(); + virtual Option find( std::string const& alias ) const; + virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const; + void add( char const* alias, char const* tag, SourceLineInfo const& lineInfo ); + static TagAliasRegistry& get(); + + private: + std::map m_registry; + }; + +} // end namespace Catch + +#include +#include + +namespace Catch { + + TagAliasRegistry::~TagAliasRegistry() {} + + Option TagAliasRegistry::find( std::string const& alias ) const { + std::map::const_iterator it = m_registry.find( alias ); + if( it != m_registry.end() ) + return it->second; + else + return Option(); + } + + std::string TagAliasRegistry::expandAliases( std::string const& unexpandedTestSpec ) const { + std::string expandedTestSpec = unexpandedTestSpec; + for( std::map::const_iterator it = m_registry.begin(), itEnd = m_registry.end(); + it != itEnd; + ++it ) { + std::size_t pos = expandedTestSpec.find( it->first ); + if( pos != std::string::npos ) { + expandedTestSpec = expandedTestSpec.substr( 0, pos ) + + it->second.tag + + expandedTestSpec.substr( pos + it->first.size() ); + } + } + return expandedTestSpec; + } + + void TagAliasRegistry::add( char const* alias, char const* tag, SourceLineInfo const& lineInfo ) { + + if( !startsWith( alias, "[@" ) || !endsWith( alias, "]" ) ) { + std::ostringstream oss; + oss << "error: tag alias, \"" << alias << "\" is not of the form [@alias name].\n" << lineInfo; + throw std::domain_error( oss.str().c_str() ); + } + if( !m_registry.insert( std::make_pair( alias, TagAlias( tag, lineInfo ) ) ).second ) { + std::ostringstream oss; + oss << "error: tag alias, \"" << alias << "\" already registered.\n" + << "\tFirst seen at " << find(alias)->lineInfo << "\n" + << "\tRedefined at " << lineInfo; + throw std::domain_error( oss.str().c_str() ); + } + } + + TagAliasRegistry& TagAliasRegistry::get() { + static TagAliasRegistry instance; + return instance; + + } + + ITagAliasRegistry::~ITagAliasRegistry() {} + ITagAliasRegistry const& ITagAliasRegistry::get() { return TagAliasRegistry::get(); } + + RegistrarForTagAliases::RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ) { + try { + TagAliasRegistry::get().add( alias, tag, lineInfo ); + } + catch( std::exception& ex ) { + Colour colourGuard( Colour::Red ); + Catch::cerr() << ex.what() << std::endl; + exit(1); + } + } + +} // end namespace Catch + +// #included from: ../reporters/catch_reporter_multi.hpp +#define TWOBLUECUBES_CATCH_REPORTER_MULTI_HPP_INCLUDED + +namespace Catch { + +class MultipleReporters : public SharedImpl { + typedef std::vector > Reporters; + Reporters m_reporters; + +public: + void add( Ptr const& reporter ) { + m_reporters.push_back( reporter ); + } + +public: // IStreamingReporter + + virtual ReporterPreferences getPreferences() const CATCH_OVERRIDE { + return m_reporters[0]->getPreferences(); + } + + virtual void noMatchingTestCases( std::string const& spec ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->noMatchingTestCases( spec ); + } + + virtual void testRunStarting( TestRunInfo const& testRunInfo ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->testRunStarting( testRunInfo ); + } + + virtual void testGroupStarting( GroupInfo const& groupInfo ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->testGroupStarting( groupInfo ); + } + + virtual void testCaseStarting( TestCaseInfo const& testInfo ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->testCaseStarting( testInfo ); + } + + virtual void sectionStarting( SectionInfo const& sectionInfo ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->sectionStarting( sectionInfo ); + } + + virtual void assertionStarting( AssertionInfo const& assertionInfo ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->assertionStarting( assertionInfo ); + } + + // The return value indicates if the messages buffer should be cleared: + virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE { + bool clearBuffer = false; + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + clearBuffer |= (*it)->assertionEnded( assertionStats ); + return clearBuffer; + } + + virtual void sectionEnded( SectionStats const& sectionStats ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->sectionEnded( sectionStats ); + } + + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->testCaseEnded( testCaseStats ); + } + + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->testGroupEnded( testGroupStats ); + } + + virtual void testRunEnded( TestRunStats const& testRunStats ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->testRunEnded( testRunStats ); + } + + virtual void skipTest( TestCaseInfo const& testInfo ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->skipTest( testInfo ); + } +}; + +Ptr addReporter( Ptr const& existingReporter, Ptr const& additionalReporter ) { + Ptr resultingReporter; + + if( existingReporter ) { + MultipleReporters* multi = dynamic_cast( existingReporter.get() ); + if( !multi ) { + multi = new MultipleReporters; + resultingReporter = Ptr( multi ); + if( existingReporter ) + multi->add( existingReporter ); + } + else + resultingReporter = existingReporter; + multi->add( additionalReporter ); + } + else + resultingReporter = additionalReporter; + + return resultingReporter; +} + +} // end namespace Catch + +// #included from: ../reporters/catch_reporter_xml.hpp +#define TWOBLUECUBES_CATCH_REPORTER_XML_HPP_INCLUDED + +// #included from: catch_reporter_bases.hpp +#define TWOBLUECUBES_CATCH_REPORTER_BASES_HPP_INCLUDED + +#include + +namespace Catch { + + struct StreamingReporterBase : SharedImpl { + + StreamingReporterBase( ReporterConfig const& _config ) + : m_config( _config.fullConfig() ), + stream( _config.stream() ) + { + m_reporterPrefs.shouldRedirectStdOut = false; + } + + virtual ReporterPreferences getPreferences() const CATCH_OVERRIDE { + return m_reporterPrefs; + } + + virtual ~StreamingReporterBase() CATCH_OVERRIDE; + + virtual void noMatchingTestCases( std::string const& ) CATCH_OVERRIDE {} + + virtual void testRunStarting( TestRunInfo const& _testRunInfo ) CATCH_OVERRIDE { + currentTestRunInfo = _testRunInfo; + } + virtual void testGroupStarting( GroupInfo const& _groupInfo ) CATCH_OVERRIDE { + currentGroupInfo = _groupInfo; + } + + virtual void testCaseStarting( TestCaseInfo const& _testInfo ) CATCH_OVERRIDE { + currentTestCaseInfo = _testInfo; + } + virtual void sectionStarting( SectionInfo const& _sectionInfo ) CATCH_OVERRIDE { + m_sectionStack.push_back( _sectionInfo ); + } + + virtual void sectionEnded( SectionStats const& /* _sectionStats */ ) CATCH_OVERRIDE { + m_sectionStack.pop_back(); + } + virtual void testCaseEnded( TestCaseStats const& /* _testCaseStats */ ) CATCH_OVERRIDE { + currentTestCaseInfo.reset(); + } + virtual void testGroupEnded( TestGroupStats const& /* _testGroupStats */ ) CATCH_OVERRIDE { + currentGroupInfo.reset(); + } + virtual void testRunEnded( TestRunStats const& /* _testRunStats */ ) CATCH_OVERRIDE { + currentTestCaseInfo.reset(); + currentGroupInfo.reset(); + currentTestRunInfo.reset(); + } + + virtual void skipTest( TestCaseInfo const& ) CATCH_OVERRIDE { + // Don't do anything with this by default. + // It can optionally be overridden in the derived class. + } + + Ptr m_config; + std::ostream& stream; + + LazyStat currentTestRunInfo; + LazyStat currentGroupInfo; + LazyStat currentTestCaseInfo; + + std::vector m_sectionStack; + ReporterPreferences m_reporterPrefs; + }; + + struct CumulativeReporterBase : SharedImpl { + template + struct Node : SharedImpl<> { + explicit Node( T const& _value ) : value( _value ) {} + virtual ~Node() {} + + typedef std::vector > ChildNodes; + T value; + ChildNodes children; + }; + struct SectionNode : SharedImpl<> { + explicit SectionNode( SectionStats const& _stats ) : stats( _stats ) {} + virtual ~SectionNode(); + + bool operator == ( SectionNode const& other ) const { + return stats.sectionInfo.lineInfo == other.stats.sectionInfo.lineInfo; + } + bool operator == ( Ptr const& other ) const { + return operator==( *other ); + } + + SectionStats stats; + typedef std::vector > ChildSections; + typedef std::vector Assertions; + ChildSections childSections; + Assertions assertions; + std::string stdOut; + std::string stdErr; + }; + + struct BySectionInfo { + BySectionInfo( SectionInfo const& other ) : m_other( other ) {} + BySectionInfo( BySectionInfo const& other ) : m_other( other.m_other ) {} + bool operator() ( Ptr const& node ) const { + return node->stats.sectionInfo.lineInfo == m_other.lineInfo; + } + private: + void operator=( BySectionInfo const& ); + SectionInfo const& m_other; + }; + + typedef Node TestCaseNode; + typedef Node TestGroupNode; + typedef Node TestRunNode; + + CumulativeReporterBase( ReporterConfig const& _config ) + : m_config( _config.fullConfig() ), + stream( _config.stream() ) + { + m_reporterPrefs.shouldRedirectStdOut = false; + } + ~CumulativeReporterBase(); + + virtual ReporterPreferences getPreferences() const CATCH_OVERRIDE { + return m_reporterPrefs; + } + + virtual void testRunStarting( TestRunInfo const& ) CATCH_OVERRIDE {} + virtual void testGroupStarting( GroupInfo const& ) CATCH_OVERRIDE {} + + virtual void testCaseStarting( TestCaseInfo const& ) CATCH_OVERRIDE {} + + virtual void sectionStarting( SectionInfo const& sectionInfo ) CATCH_OVERRIDE { + SectionStats incompleteStats( sectionInfo, Counts(), 0, false ); + Ptr node; + if( m_sectionStack.empty() ) { + if( !m_rootSection ) + m_rootSection = new SectionNode( incompleteStats ); + node = m_rootSection; + } + else { + SectionNode& parentNode = *m_sectionStack.back(); + SectionNode::ChildSections::const_iterator it = + std::find_if( parentNode.childSections.begin(), + parentNode.childSections.end(), + BySectionInfo( sectionInfo ) ); + if( it == parentNode.childSections.end() ) { + node = new SectionNode( incompleteStats ); + parentNode.childSections.push_back( node ); + } + else + node = *it; + } + m_sectionStack.push_back( node ); + m_deepestSection = node; + } + + virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE {} + + virtual bool assertionEnded( AssertionStats const& assertionStats ) { + assert( !m_sectionStack.empty() ); + SectionNode& sectionNode = *m_sectionStack.back(); + sectionNode.assertions.push_back( assertionStats ); + return true; + } + virtual void sectionEnded( SectionStats const& sectionStats ) CATCH_OVERRIDE { + assert( !m_sectionStack.empty() ); + SectionNode& node = *m_sectionStack.back(); + node.stats = sectionStats; + m_sectionStack.pop_back(); + } + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE { + Ptr node = new TestCaseNode( testCaseStats ); + assert( m_sectionStack.size() == 0 ); + node->children.push_back( m_rootSection ); + m_testCases.push_back( node ); + m_rootSection.reset(); + + assert( m_deepestSection ); + m_deepestSection->stdOut = testCaseStats.stdOut; + m_deepestSection->stdErr = testCaseStats.stdErr; + } + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE { + Ptr node = new TestGroupNode( testGroupStats ); + node->children.swap( m_testCases ); + m_testGroups.push_back( node ); + } + virtual void testRunEnded( TestRunStats const& testRunStats ) CATCH_OVERRIDE { + Ptr node = new TestRunNode( testRunStats ); + node->children.swap( m_testGroups ); + m_testRuns.push_back( node ); + testRunEndedCumulative(); + } + virtual void testRunEndedCumulative() = 0; + + virtual void skipTest( TestCaseInfo const& ) CATCH_OVERRIDE {} + + Ptr m_config; + std::ostream& stream; + std::vector m_assertions; + std::vector > > m_sections; + std::vector > m_testCases; + std::vector > m_testGroups; + + std::vector > m_testRuns; + + Ptr m_rootSection; + Ptr m_deepestSection; + std::vector > m_sectionStack; + ReporterPreferences m_reporterPrefs; + + }; + + template + char const* getLineOfChars() { + static char line[CATCH_CONFIG_CONSOLE_WIDTH] = {0}; + if( !*line ) { + memset( line, C, CATCH_CONFIG_CONSOLE_WIDTH-1 ); + line[CATCH_CONFIG_CONSOLE_WIDTH-1] = 0; + } + return line; + } + + struct TestEventListenerBase : StreamingReporterBase { + TestEventListenerBase( ReporterConfig const& _config ) + : StreamingReporterBase( _config ) + {} + + virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE {} + virtual bool assertionEnded( AssertionStats const& ) CATCH_OVERRIDE { + return false; + } + }; + +} // end namespace Catch + +// #included from: ../internal/catch_reporter_registrars.hpp +#define TWOBLUECUBES_CATCH_REPORTER_REGISTRARS_HPP_INCLUDED + +namespace Catch { + + template + class LegacyReporterRegistrar { + + class ReporterFactory : public IReporterFactory { + virtual IStreamingReporter* create( ReporterConfig const& config ) const { + return new LegacyReporterAdapter( new T( config ) ); + } + + virtual std::string getDescription() const { + return T::getDescription(); + } + }; + + public: + + LegacyReporterRegistrar( std::string const& name ) { + getMutableRegistryHub().registerReporter( name, new ReporterFactory() ); + } + }; + + template + class ReporterRegistrar { + + class ReporterFactory : public SharedImpl { + + // *** Please Note ***: + // - If you end up here looking at a compiler error because it's trying to register + // your custom reporter class be aware that the native reporter interface has changed + // to IStreamingReporter. The "legacy" interface, IReporter, is still supported via + // an adapter. Just use REGISTER_LEGACY_REPORTER to take advantage of the adapter. + // However please consider updating to the new interface as the old one is now + // deprecated and will probably be removed quite soon! + // Please contact me via github if you have any questions at all about this. + // In fact, ideally, please contact me anyway to let me know you've hit this - as I have + // no idea who is actually using custom reporters at all (possibly no-one!). + // The new interface is designed to minimise exposure to interface changes in the future. + virtual IStreamingReporter* create( ReporterConfig const& config ) const { + return new T( config ); + } + + virtual std::string getDescription() const { + return T::getDescription(); + } + }; + + public: + + ReporterRegistrar( std::string const& name ) { + getMutableRegistryHub().registerReporter( name, new ReporterFactory() ); + } + }; + + template + class ListenerRegistrar { + + class ListenerFactory : public SharedImpl { + + virtual IStreamingReporter* create( ReporterConfig const& config ) const { + return new T( config ); + } + virtual std::string getDescription() const { + return ""; + } + }; + + public: + + ListenerRegistrar() { + getMutableRegistryHub().registerListener( new ListenerFactory() ); + } + }; +} + +#define INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) \ + namespace{ Catch::LegacyReporterRegistrar catch_internal_RegistrarFor##reporterType( name ); } + +#define INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) \ + namespace{ Catch::ReporterRegistrar catch_internal_RegistrarFor##reporterType( name ); } + +#define INTERNAL_CATCH_REGISTER_LISTENER( listenerType ) \ + namespace{ Catch::ListenerRegistrar catch_internal_RegistrarFor##listenerType; } + +// #included from: ../internal/catch_xmlwriter.hpp +#define TWOBLUECUBES_CATCH_XMLWRITER_HPP_INCLUDED + +#include +#include +#include +#include + +namespace Catch { + + class XmlEncode { + public: + enum ForWhat { ForTextNodes, ForAttributes }; + + XmlEncode( std::string const& str, ForWhat forWhat = ForTextNodes ) + : m_str( str ), + m_forWhat( forWhat ) + {} + + void encodeTo( std::ostream& os ) const { + + // Apostrophe escaping not necessary if we always use " to write attributes + // (see: http://www.w3.org/TR/xml/#syntax) + + for( std::size_t i = 0; i < m_str.size(); ++ i ) { + char c = m_str[i]; + switch( c ) { + case '<': os << "<"; break; + case '&': os << "&"; break; + + case '>': + // See: http://www.w3.org/TR/xml/#syntax + if( i > 2 && m_str[i-1] == ']' && m_str[i-2] == ']' ) + os << ">"; + else + os << c; + break; + + case '\"': + if( m_forWhat == ForAttributes ) + os << """; + else + os << c; + break; + + default: + // Escape control chars - based on contribution by @espenalb in PR #465 + if ( ( c < '\x09' ) || ( c > '\x0D' && c < '\x20') || c=='\x7F' ) + os << "&#x" << std::uppercase << std::hex << static_cast( c ); + else + os << c; + } + } + } + + friend std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ) { + xmlEncode.encodeTo( os ); + return os; + } + + private: + std::string m_str; + ForWhat m_forWhat; + }; + + class XmlWriter { + public: + + class ScopedElement { + public: + ScopedElement( XmlWriter* writer ) + : m_writer( writer ) + {} + + ScopedElement( ScopedElement const& other ) + : m_writer( other.m_writer ){ + other.m_writer = CATCH_NULL; + } + + ~ScopedElement() { + if( m_writer ) + m_writer->endElement(); + } + + ScopedElement& writeText( std::string const& text, bool indent = true ) { + m_writer->writeText( text, indent ); + return *this; + } + + template + ScopedElement& writeAttribute( std::string const& name, T const& attribute ) { + m_writer->writeAttribute( name, attribute ); + return *this; + } + + private: + mutable XmlWriter* m_writer; + }; + + XmlWriter() + : m_tagIsOpen( false ), + m_needsNewline( false ), + m_os( &Catch::cout() ) + {} + + XmlWriter( std::ostream& os ) + : m_tagIsOpen( false ), + m_needsNewline( false ), + m_os( &os ) + {} + + ~XmlWriter() { + while( !m_tags.empty() ) + endElement(); + } + + XmlWriter& startElement( std::string const& name ) { + ensureTagClosed(); + newlineIfNecessary(); + stream() << m_indent << "<" << name; + m_tags.push_back( name ); + m_indent += " "; + m_tagIsOpen = true; + return *this; + } + + ScopedElement scopedElement( std::string const& name ) { + ScopedElement scoped( this ); + startElement( name ); + return scoped; + } + + XmlWriter& endElement() { + newlineIfNecessary(); + m_indent = m_indent.substr( 0, m_indent.size()-2 ); + if( m_tagIsOpen ) { + stream() << "/>\n"; + m_tagIsOpen = false; + } + else { + stream() << m_indent << "\n"; + } + m_tags.pop_back(); + return *this; + } + + XmlWriter& writeAttribute( std::string const& name, std::string const& attribute ) { + if( !name.empty() && !attribute.empty() ) + stream() << " " << name << "=\"" << XmlEncode( attribute, XmlEncode::ForAttributes ) << "\""; + return *this; + } + + XmlWriter& writeAttribute( std::string const& name, bool attribute ) { + stream() << " " << name << "=\"" << ( attribute ? "true" : "false" ) << "\""; + return *this; + } + + template + XmlWriter& writeAttribute( std::string const& name, T const& attribute ) { + std::ostringstream oss; + oss << attribute; + return writeAttribute( name, oss.str() ); + } + + XmlWriter& writeText( std::string const& text, bool indent = true ) { + if( !text.empty() ){ + bool tagWasOpen = m_tagIsOpen; + ensureTagClosed(); + if( tagWasOpen && indent ) + stream() << m_indent; + stream() << XmlEncode( text ); + m_needsNewline = true; + } + return *this; + } + + XmlWriter& writeComment( std::string const& text ) { + ensureTagClosed(); + stream() << m_indent << ""; + m_needsNewline = true; + return *this; + } + + XmlWriter& writeBlankLine() { + ensureTagClosed(); + stream() << "\n"; + return *this; + } + + void setStream( std::ostream& os ) { + m_os = &os; + } + + private: + XmlWriter( XmlWriter const& ); + void operator=( XmlWriter const& ); + + std::ostream& stream() { + return *m_os; + } + + void ensureTagClosed() { + if( m_tagIsOpen ) { + stream() << ">\n"; + m_tagIsOpen = false; + } + } + + void newlineIfNecessary() { + if( m_needsNewline ) { + stream() << "\n"; + m_needsNewline = false; + } + } + + bool m_tagIsOpen; + bool m_needsNewline; + std::vector m_tags; + std::string m_indent; + std::ostream* m_os; + }; + +} +// #included from: catch_reenable_warnings.h + +#define TWOBLUECUBES_CATCH_REENABLE_WARNINGS_H_INCLUDED + +#ifdef __clang__ +# ifdef __ICC // icpc defines the __clang__ macro +# pragma warning(pop) +# else +# pragma clang diagnostic pop +# endif +#elif defined __GNUC__ +# pragma GCC diagnostic pop +#endif + + +namespace Catch { + class XmlReporter : public StreamingReporterBase { + public: + XmlReporter( ReporterConfig const& _config ) + : StreamingReporterBase( _config ), + m_sectionDepth( 0 ) + { + m_reporterPrefs.shouldRedirectStdOut = true; + } + + virtual ~XmlReporter() CATCH_OVERRIDE; + + static std::string getDescription() { + return "Reports test results as an XML document"; + } + + public: // StreamingReporterBase + + virtual void noMatchingTestCases( std::string const& s ) CATCH_OVERRIDE { + StreamingReporterBase::noMatchingTestCases( s ); + } + + virtual void testRunStarting( TestRunInfo const& testInfo ) CATCH_OVERRIDE { + StreamingReporterBase::testRunStarting( testInfo ); + m_xml.setStream( stream ); + m_xml.startElement( "Catch" ); + if( !m_config->name().empty() ) + m_xml.writeAttribute( "name", m_config->name() ); + } + + virtual void testGroupStarting( GroupInfo const& groupInfo ) CATCH_OVERRIDE { + StreamingReporterBase::testGroupStarting( groupInfo ); + m_xml.startElement( "Group" ) + .writeAttribute( "name", groupInfo.name ); + } + + virtual void testCaseStarting( TestCaseInfo const& testInfo ) CATCH_OVERRIDE { + StreamingReporterBase::testCaseStarting(testInfo); + m_xml.startElement( "TestCase" ).writeAttribute( "name", trim( testInfo.name ) ); + + if ( m_config->showDurations() == ShowDurations::Always ) + m_testCaseTimer.start(); + } + + virtual void sectionStarting( SectionInfo const& sectionInfo ) CATCH_OVERRIDE { + StreamingReporterBase::sectionStarting( sectionInfo ); + if( m_sectionDepth++ > 0 ) { + m_xml.startElement( "Section" ) + .writeAttribute( "name", trim( sectionInfo.name ) ) + .writeAttribute( "description", sectionInfo.description ); + } + } + + virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE { } + + virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE { + const AssertionResult& assertionResult = assertionStats.assertionResult; + + // Print any info messages in tags. + if( assertionStats.assertionResult.getResultType() != ResultWas::Ok ) { + for( std::vector::const_iterator it = assertionStats.infoMessages.begin(), itEnd = assertionStats.infoMessages.end(); + it != itEnd; + ++it ) { + if( it->type == ResultWas::Info ) { + m_xml.scopedElement( "Info" ) + .writeText( it->message ); + } else if ( it->type == ResultWas::Warning ) { + m_xml.scopedElement( "Warning" ) + .writeText( it->message ); + } + } + } + + // Drop out if result was successful but we're not printing them. + if( !m_config->includeSuccessfulResults() && isOk(assertionResult.getResultType()) ) + return true; + + // Print the expression if there is one. + if( assertionResult.hasExpression() ) { + m_xml.startElement( "Expression" ) + .writeAttribute( "success", assertionResult.succeeded() ) + .writeAttribute( "type", assertionResult.getTestMacroName() ) + .writeAttribute( "filename", assertionResult.getSourceInfo().file ) + .writeAttribute( "line", assertionResult.getSourceInfo().line ); + + m_xml.scopedElement( "Original" ) + .writeText( assertionResult.getExpression() ); + m_xml.scopedElement( "Expanded" ) + .writeText( assertionResult.getExpandedExpression() ); + } + + // And... Print a result applicable to each result type. + switch( assertionResult.getResultType() ) { + case ResultWas::ThrewException: + m_xml.scopedElement( "Exception" ) + .writeAttribute( "filename", assertionResult.getSourceInfo().file ) + .writeAttribute( "line", assertionResult.getSourceInfo().line ) + .writeText( assertionResult.getMessage() ); + break; + case ResultWas::FatalErrorCondition: + m_xml.scopedElement( "Fatal Error Condition" ) + .writeAttribute( "filename", assertionResult.getSourceInfo().file ) + .writeAttribute( "line", assertionResult.getSourceInfo().line ) + .writeText( assertionResult.getMessage() ); + break; + case ResultWas::Info: + m_xml.scopedElement( "Info" ) + .writeText( assertionResult.getMessage() ); + break; + case ResultWas::Warning: + // Warning will already have been written + break; + case ResultWas::ExplicitFailure: + m_xml.scopedElement( "Failure" ) + .writeText( assertionResult.getMessage() ); + break; + default: + break; + } + + if( assertionResult.hasExpression() ) + m_xml.endElement(); + + return true; + } + + virtual void sectionEnded( SectionStats const& sectionStats ) CATCH_OVERRIDE { + StreamingReporterBase::sectionEnded( sectionStats ); + if( --m_sectionDepth > 0 ) { + XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResults" ); + e.writeAttribute( "successes", sectionStats.assertions.passed ); + e.writeAttribute( "failures", sectionStats.assertions.failed ); + e.writeAttribute( "expectedFailures", sectionStats.assertions.failedButOk ); + + if ( m_config->showDurations() == ShowDurations::Always ) + e.writeAttribute( "durationInSeconds", sectionStats.durationInSeconds ); + + m_xml.endElement(); + } + } + + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE { + StreamingReporterBase::testCaseEnded( testCaseStats ); + XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResult" ); + e.writeAttribute( "success", testCaseStats.totals.assertions.allOk() ); + + if ( m_config->showDurations() == ShowDurations::Always ) + e.writeAttribute( "durationInSeconds", m_testCaseTimer.getElapsedSeconds() ); + + m_xml.endElement(); + } + + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE { + StreamingReporterBase::testGroupEnded( testGroupStats ); + // TODO: Check testGroupStats.aborting and act accordingly. + m_xml.scopedElement( "OverallResults" ) + .writeAttribute( "successes", testGroupStats.totals.assertions.passed ) + .writeAttribute( "failures", testGroupStats.totals.assertions.failed ) + .writeAttribute( "expectedFailures", testGroupStats.totals.assertions.failedButOk ); + m_xml.endElement(); + } + + virtual void testRunEnded( TestRunStats const& testRunStats ) CATCH_OVERRIDE { + StreamingReporterBase::testRunEnded( testRunStats ); + m_xml.scopedElement( "OverallResults" ) + .writeAttribute( "successes", testRunStats.totals.assertions.passed ) + .writeAttribute( "failures", testRunStats.totals.assertions.failed ) + .writeAttribute( "expectedFailures", testRunStats.totals.assertions.failedButOk ); + m_xml.endElement(); + } + + private: + Timer m_testCaseTimer; + XmlWriter m_xml; + int m_sectionDepth; + }; + + INTERNAL_CATCH_REGISTER_REPORTER( "xml", XmlReporter ) + +} // end namespace Catch + +// #included from: ../reporters/catch_reporter_junit.hpp +#define TWOBLUECUBES_CATCH_REPORTER_JUNIT_HPP_INCLUDED + +#include + +namespace Catch { + + class JunitReporter : public CumulativeReporterBase { + public: + JunitReporter( ReporterConfig const& _config ) + : CumulativeReporterBase( _config ), + xml( _config.stream() ) + { + m_reporterPrefs.shouldRedirectStdOut = true; + } + + virtual ~JunitReporter() CATCH_OVERRIDE; + + static std::string getDescription() { + return "Reports test results in an XML format that looks like Ant's junitreport target"; + } + + virtual void noMatchingTestCases( std::string const& /*spec*/ ) CATCH_OVERRIDE {} + + virtual void testRunStarting( TestRunInfo const& runInfo ) CATCH_OVERRIDE { + CumulativeReporterBase::testRunStarting( runInfo ); + xml.startElement( "testsuites" ); + } + + virtual void testGroupStarting( GroupInfo const& groupInfo ) CATCH_OVERRIDE { + suiteTimer.start(); + stdOutForSuite.str(""); + stdErrForSuite.str(""); + unexpectedExceptions = 0; + CumulativeReporterBase::testGroupStarting( groupInfo ); + } + + virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE { + if( assertionStats.assertionResult.getResultType() == ResultWas::ThrewException ) + unexpectedExceptions++; + return CumulativeReporterBase::assertionEnded( assertionStats ); + } + + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE { + stdOutForSuite << testCaseStats.stdOut; + stdErrForSuite << testCaseStats.stdErr; + CumulativeReporterBase::testCaseEnded( testCaseStats ); + } + + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE { + double suiteTime = suiteTimer.getElapsedSeconds(); + CumulativeReporterBase::testGroupEnded( testGroupStats ); + writeGroup( *m_testGroups.back(), suiteTime ); + } + + virtual void testRunEndedCumulative() CATCH_OVERRIDE { + xml.endElement(); + } + + void writeGroup( TestGroupNode const& groupNode, double suiteTime ) { + XmlWriter::ScopedElement e = xml.scopedElement( "testsuite" ); + TestGroupStats const& stats = groupNode.value; + xml.writeAttribute( "name", stats.groupInfo.name ); + xml.writeAttribute( "errors", unexpectedExceptions ); + xml.writeAttribute( "failures", stats.totals.assertions.failed-unexpectedExceptions ); + xml.writeAttribute( "tests", stats.totals.assertions.total() ); + xml.writeAttribute( "hostname", "tbd" ); // !TBD + if( m_config->showDurations() == ShowDurations::Never ) + xml.writeAttribute( "time", "" ); + else + xml.writeAttribute( "time", suiteTime ); + xml.writeAttribute( "timestamp", "tbd" ); // !TBD + + // Write test cases + for( TestGroupNode::ChildNodes::const_iterator + it = groupNode.children.begin(), itEnd = groupNode.children.end(); + it != itEnd; + ++it ) + writeTestCase( **it ); + + xml.scopedElement( "system-out" ).writeText( trim( stdOutForSuite.str() ), false ); + xml.scopedElement( "system-err" ).writeText( trim( stdErrForSuite.str() ), false ); + } + + void writeTestCase( TestCaseNode const& testCaseNode ) { + TestCaseStats const& stats = testCaseNode.value; + + // All test cases have exactly one section - which represents the + // test case itself. That section may have 0-n nested sections + assert( testCaseNode.children.size() == 1 ); + SectionNode const& rootSection = *testCaseNode.children.front(); + + std::string className = stats.testInfo.className; + + if( className.empty() ) { + if( rootSection.childSections.empty() ) + className = "global"; + } + writeSection( className, "", rootSection ); + } + + void writeSection( std::string const& className, + std::string const& rootName, + SectionNode const& sectionNode ) { + std::string name = trim( sectionNode.stats.sectionInfo.name ); + if( !rootName.empty() ) + name = rootName + "/" + name; + + if( !sectionNode.assertions.empty() || + !sectionNode.stdOut.empty() || + !sectionNode.stdErr.empty() ) { + XmlWriter::ScopedElement e = xml.scopedElement( "testcase" ); + if( className.empty() ) { + xml.writeAttribute( "classname", name ); + xml.writeAttribute( "name", "root" ); + } + else { + xml.writeAttribute( "classname", className ); + xml.writeAttribute( "name", name ); + } + xml.writeAttribute( "time", Catch::toString( sectionNode.stats.durationInSeconds ) ); + + writeAssertions( sectionNode ); + + if( !sectionNode.stdOut.empty() ) + xml.scopedElement( "system-out" ).writeText( trim( sectionNode.stdOut ), false ); + if( !sectionNode.stdErr.empty() ) + xml.scopedElement( "system-err" ).writeText( trim( sectionNode.stdErr ), false ); + } + for( SectionNode::ChildSections::const_iterator + it = sectionNode.childSections.begin(), + itEnd = sectionNode.childSections.end(); + it != itEnd; + ++it ) + if( className.empty() ) + writeSection( name, "", **it ); + else + writeSection( className, name, **it ); + } + + void writeAssertions( SectionNode const& sectionNode ) { + for( SectionNode::Assertions::const_iterator + it = sectionNode.assertions.begin(), itEnd = sectionNode.assertions.end(); + it != itEnd; + ++it ) + writeAssertion( *it ); + } + void writeAssertion( AssertionStats const& stats ) { + AssertionResult const& result = stats.assertionResult; + if( !result.isOk() ) { + std::string elementName; + switch( result.getResultType() ) { + case ResultWas::ThrewException: + case ResultWas::FatalErrorCondition: + elementName = "error"; + break; + case ResultWas::ExplicitFailure: + elementName = "failure"; + break; + case ResultWas::ExpressionFailed: + elementName = "failure"; + break; + case ResultWas::DidntThrowException: + elementName = "failure"; + break; + + // We should never see these here: + case ResultWas::Info: + case ResultWas::Warning: + case ResultWas::Ok: + case ResultWas::Unknown: + case ResultWas::FailureBit: + case ResultWas::Exception: + elementName = "internalError"; + break; + } + + XmlWriter::ScopedElement e = xml.scopedElement( elementName ); + + xml.writeAttribute( "message", result.getExpandedExpression() ); + xml.writeAttribute( "type", result.getTestMacroName() ); + + std::ostringstream oss; + if( !result.getMessage().empty() ) + oss << result.getMessage() << "\n"; + for( std::vector::const_iterator + it = stats.infoMessages.begin(), + itEnd = stats.infoMessages.end(); + it != itEnd; + ++it ) + if( it->type == ResultWas::Info ) + oss << it->message << "\n"; + + oss << "at " << result.getSourceInfo(); + xml.writeText( oss.str(), false ); + } + } + + XmlWriter xml; + Timer suiteTimer; + std::ostringstream stdOutForSuite; + std::ostringstream stdErrForSuite; + unsigned int unexpectedExceptions; + }; + + INTERNAL_CATCH_REGISTER_REPORTER( "junit", JunitReporter ) + +} // end namespace Catch + +// #included from: ../reporters/catch_reporter_console.hpp +#define TWOBLUECUBES_CATCH_REPORTER_CONSOLE_HPP_INCLUDED + +namespace Catch { + + struct ConsoleReporter : StreamingReporterBase { + ConsoleReporter( ReporterConfig const& _config ) + : StreamingReporterBase( _config ), + m_headerPrinted( false ) + {} + + virtual ~ConsoleReporter() CATCH_OVERRIDE; + static std::string getDescription() { + return "Reports test results as plain lines of text"; + } + + virtual void noMatchingTestCases( std::string const& spec ) CATCH_OVERRIDE { + stream << "No test cases matched '" << spec << "'" << std::endl; + } + + virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE { + } + + virtual bool assertionEnded( AssertionStats const& _assertionStats ) CATCH_OVERRIDE { + AssertionResult const& result = _assertionStats.assertionResult; + + bool printInfoMessages = true; + + // Drop out if result was successful and we're not printing those + if( !m_config->includeSuccessfulResults() && result.isOk() ) { + if( result.getResultType() != ResultWas::Warning ) + return false; + printInfoMessages = false; + } + + lazyPrint(); + + AssertionPrinter printer( stream, _assertionStats, printInfoMessages ); + printer.print(); + stream << std::endl; + return true; + } + + virtual void sectionStarting( SectionInfo const& _sectionInfo ) CATCH_OVERRIDE { + m_headerPrinted = false; + StreamingReporterBase::sectionStarting( _sectionInfo ); + } + virtual void sectionEnded( SectionStats const& _sectionStats ) CATCH_OVERRIDE { + if( _sectionStats.missingAssertions ) { + lazyPrint(); + Colour colour( Colour::ResultError ); + if( m_sectionStack.size() > 1 ) + stream << "\nNo assertions in section"; + else + stream << "\nNo assertions in test case"; + stream << " '" << _sectionStats.sectionInfo.name << "'\n" << std::endl; + } + if( m_headerPrinted ) { + if( m_config->showDurations() == ShowDurations::Always ) + stream << "Completed in " << _sectionStats.durationInSeconds << "s" << std::endl; + m_headerPrinted = false; + } + else { + if( m_config->showDurations() == ShowDurations::Always ) + stream << _sectionStats.sectionInfo.name << " completed in " << _sectionStats.durationInSeconds << "s" << std::endl; + } + StreamingReporterBase::sectionEnded( _sectionStats ); + } + + virtual void testCaseEnded( TestCaseStats const& _testCaseStats ) CATCH_OVERRIDE { + StreamingReporterBase::testCaseEnded( _testCaseStats ); + m_headerPrinted = false; + } + virtual void testGroupEnded( TestGroupStats const& _testGroupStats ) CATCH_OVERRIDE { + if( currentGroupInfo.used ) { + printSummaryDivider(); + stream << "Summary for group '" << _testGroupStats.groupInfo.name << "':\n"; + printTotals( _testGroupStats.totals ); + stream << "\n" << std::endl; + } + StreamingReporterBase::testGroupEnded( _testGroupStats ); + } + virtual void testRunEnded( TestRunStats const& _testRunStats ) CATCH_OVERRIDE { + printTotalsDivider( _testRunStats.totals ); + printTotals( _testRunStats.totals ); + stream << std::endl; + StreamingReporterBase::testRunEnded( _testRunStats ); + } + + private: + + class AssertionPrinter { + void operator= ( AssertionPrinter const& ); + public: + AssertionPrinter( std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages ) + : stream( _stream ), + stats( _stats ), + result( _stats.assertionResult ), + colour( Colour::None ), + message( result.getMessage() ), + messages( _stats.infoMessages ), + printInfoMessages( _printInfoMessages ) + { + switch( result.getResultType() ) { + case ResultWas::Ok: + colour = Colour::Success; + passOrFail = "PASSED"; + //if( result.hasMessage() ) + if( _stats.infoMessages.size() == 1 ) + messageLabel = "with message"; + if( _stats.infoMessages.size() > 1 ) + messageLabel = "with messages"; + break; + case ResultWas::ExpressionFailed: + if( result.isOk() ) { + colour = Colour::Success; + passOrFail = "FAILED - but was ok"; + } + else { + colour = Colour::Error; + passOrFail = "FAILED"; + } + if( _stats.infoMessages.size() == 1 ) + messageLabel = "with message"; + if( _stats.infoMessages.size() > 1 ) + messageLabel = "with messages"; + break; + case ResultWas::ThrewException: + colour = Colour::Error; + passOrFail = "FAILED"; + messageLabel = "due to unexpected exception with message"; + break; + case ResultWas::FatalErrorCondition: + colour = Colour::Error; + passOrFail = "FAILED"; + messageLabel = "due to a fatal error condition"; + break; + case ResultWas::DidntThrowException: + colour = Colour::Error; + passOrFail = "FAILED"; + messageLabel = "because no exception was thrown where one was expected"; + break; + case ResultWas::Info: + messageLabel = "info"; + break; + case ResultWas::Warning: + messageLabel = "warning"; + break; + case ResultWas::ExplicitFailure: + passOrFail = "FAILED"; + colour = Colour::Error; + if( _stats.infoMessages.size() == 1 ) + messageLabel = "explicitly with message"; + if( _stats.infoMessages.size() > 1 ) + messageLabel = "explicitly with messages"; + break; + // These cases are here to prevent compiler warnings + case ResultWas::Unknown: + case ResultWas::FailureBit: + case ResultWas::Exception: + passOrFail = "** internal error **"; + colour = Colour::Error; + break; + } + } + + void print() const { + printSourceInfo(); + if( stats.totals.assertions.total() > 0 ) { + if( result.isOk() ) + stream << "\n"; + printResultType(); + printOriginalExpression(); + printReconstructedExpression(); + } + else { + stream << "\n"; + } + printMessage(); + } + + private: + void printResultType() const { + if( !passOrFail.empty() ) { + Colour colourGuard( colour ); + stream << passOrFail << ":\n"; + } + } + void printOriginalExpression() const { + if( result.hasExpression() ) { + Colour colourGuard( Colour::OriginalExpression ); + stream << " "; + stream << result.getExpressionInMacro(); + stream << "\n"; + } + } + void printReconstructedExpression() const { + if( result.hasExpandedExpression() ) { + stream << "with expansion:\n"; + Colour colourGuard( Colour::ReconstructedExpression ); + stream << Text( result.getExpandedExpression(), TextAttributes().setIndent(2) ) << "\n"; + } + } + void printMessage() const { + if( !messageLabel.empty() ) + stream << messageLabel << ":" << "\n"; + for( std::vector::const_iterator it = messages.begin(), itEnd = messages.end(); + it != itEnd; + ++it ) { + // If this assertion is a warning ignore any INFO messages + if( printInfoMessages || it->type != ResultWas::Info ) + stream << Text( it->message, TextAttributes().setIndent(2) ) << "\n"; + } + } + void printSourceInfo() const { + Colour colourGuard( Colour::FileName ); + stream << result.getSourceInfo() << ": "; + } + + std::ostream& stream; + AssertionStats const& stats; + AssertionResult const& result; + Colour::Code colour; + std::string passOrFail; + std::string messageLabel; + std::string message; + std::vector messages; + bool printInfoMessages; + }; + + void lazyPrint() { + + if( !currentTestRunInfo.used ) + lazyPrintRunInfo(); + if( !currentGroupInfo.used ) + lazyPrintGroupInfo(); + + if( !m_headerPrinted ) { + printTestCaseAndSectionHeader(); + m_headerPrinted = true; + } + } + void lazyPrintRunInfo() { + stream << "\n" << getLineOfChars<'~'>() << "\n"; + Colour colour( Colour::SecondaryText ); + stream << currentTestRunInfo->name + << " is a Catch v" << libraryVersion << " host application.\n" + << "Run with -? for options\n\n"; + + if( m_config->rngSeed() != 0 ) + stream << "Randomness seeded to: " << m_config->rngSeed() << "\n\n"; + + currentTestRunInfo.used = true; + } + void lazyPrintGroupInfo() { + if( !currentGroupInfo->name.empty() && currentGroupInfo->groupsCounts > 1 ) { + printClosedHeader( "Group: " + currentGroupInfo->name ); + currentGroupInfo.used = true; + } + } + void printTestCaseAndSectionHeader() { + assert( !m_sectionStack.empty() ); + printOpenHeader( currentTestCaseInfo->name ); + + if( m_sectionStack.size() > 1 ) { + Colour colourGuard( Colour::Headers ); + + std::vector::const_iterator + it = m_sectionStack.begin()+1, // Skip first section (test case) + itEnd = m_sectionStack.end(); + for( ; it != itEnd; ++it ) + printHeaderString( it->name, 2 ); + } + + SourceLineInfo lineInfo = m_sectionStack.front().lineInfo; + + if( !lineInfo.empty() ){ + stream << getLineOfChars<'-'>() << "\n"; + Colour colourGuard( Colour::FileName ); + stream << lineInfo << "\n"; + } + stream << getLineOfChars<'.'>() << "\n" << std::endl; + } + + void printClosedHeader( std::string const& _name ) { + printOpenHeader( _name ); + stream << getLineOfChars<'.'>() << "\n"; + } + void printOpenHeader( std::string const& _name ) { + stream << getLineOfChars<'-'>() << "\n"; + { + Colour colourGuard( Colour::Headers ); + printHeaderString( _name ); + } + } + + // if string has a : in first line will set indent to follow it on + // subsequent lines + void printHeaderString( std::string const& _string, std::size_t indent = 0 ) { + std::size_t i = _string.find( ": " ); + if( i != std::string::npos ) + i+=2; + else + i = 0; + stream << Text( _string, TextAttributes() + .setIndent( indent+i) + .setInitialIndent( indent ) ) << "\n"; + } + + struct SummaryColumn { + + SummaryColumn( std::string const& _label, Colour::Code _colour ) + : label( _label ), + colour( _colour ) + {} + SummaryColumn addRow( std::size_t count ) { + std::ostringstream oss; + oss << count; + std::string row = oss.str(); + for( std::vector::iterator it = rows.begin(); it != rows.end(); ++it ) { + while( it->size() < row.size() ) + *it = " " + *it; + while( it->size() > row.size() ) + row = " " + row; + } + rows.push_back( row ); + return *this; + } + + std::string label; + Colour::Code colour; + std::vector rows; + + }; + + void printTotals( Totals const& totals ) { + if( totals.testCases.total() == 0 ) { + stream << Colour( Colour::Warning ) << "No tests ran\n"; + } + else if( totals.assertions.total() > 0 && totals.assertions.allPassed() ) { + stream << Colour( Colour::ResultSuccess ) << "All tests passed"; + stream << " (" + << pluralise( totals.assertions.passed, "assertion" ) << " in " + << pluralise( totals.testCases.passed, "test case" ) << ")" + << "\n"; + } + else { + + std::vector columns; + columns.push_back( SummaryColumn( "", Colour::None ) + .addRow( totals.testCases.total() ) + .addRow( totals.assertions.total() ) ); + columns.push_back( SummaryColumn( "passed", Colour::Success ) + .addRow( totals.testCases.passed ) + .addRow( totals.assertions.passed ) ); + columns.push_back( SummaryColumn( "failed", Colour::ResultError ) + .addRow( totals.testCases.failed ) + .addRow( totals.assertions.failed ) ); + columns.push_back( SummaryColumn( "failed as expected", Colour::ResultExpectedFailure ) + .addRow( totals.testCases.failedButOk ) + .addRow( totals.assertions.failedButOk ) ); + + printSummaryRow( "test cases", columns, 0 ); + printSummaryRow( "assertions", columns, 1 ); + } + } + void printSummaryRow( std::string const& label, std::vector const& cols, std::size_t row ) { + for( std::vector::const_iterator it = cols.begin(); it != cols.end(); ++it ) { + std::string value = it->rows[row]; + if( it->label.empty() ) { + stream << label << ": "; + if( value != "0" ) + stream << value; + else + stream << Colour( Colour::Warning ) << "- none -"; + } + else if( value != "0" ) { + stream << Colour( Colour::LightGrey ) << " | "; + stream << Colour( it->colour ) + << value << " " << it->label; + } + } + stream << "\n"; + } + + static std::size_t makeRatio( std::size_t number, std::size_t total ) { + std::size_t ratio = total > 0 ? CATCH_CONFIG_CONSOLE_WIDTH * number/ total : 0; + return ( ratio == 0 && number > 0 ) ? 1 : ratio; + } + static std::size_t& findMax( std::size_t& i, std::size_t& j, std::size_t& k ) { + if( i > j && i > k ) + return i; + else if( j > k ) + return j; + else + return k; + } + + void printTotalsDivider( Totals const& totals ) { + if( totals.testCases.total() > 0 ) { + std::size_t failedRatio = makeRatio( totals.testCases.failed, totals.testCases.total() ); + std::size_t failedButOkRatio = makeRatio( totals.testCases.failedButOk, totals.testCases.total() ); + std::size_t passedRatio = makeRatio( totals.testCases.passed, totals.testCases.total() ); + while( failedRatio + failedButOkRatio + passedRatio < CATCH_CONFIG_CONSOLE_WIDTH-1 ) + findMax( failedRatio, failedButOkRatio, passedRatio )++; + while( failedRatio + failedButOkRatio + passedRatio > CATCH_CONFIG_CONSOLE_WIDTH-1 ) + findMax( failedRatio, failedButOkRatio, passedRatio )--; + + stream << Colour( Colour::Error ) << std::string( failedRatio, '=' ); + stream << Colour( Colour::ResultExpectedFailure ) << std::string( failedButOkRatio, '=' ); + if( totals.testCases.allPassed() ) + stream << Colour( Colour::ResultSuccess ) << std::string( passedRatio, '=' ); + else + stream << Colour( Colour::Success ) << std::string( passedRatio, '=' ); + } + else { + stream << Colour( Colour::Warning ) << std::string( CATCH_CONFIG_CONSOLE_WIDTH-1, '=' ); + } + stream << "\n"; + } + void printSummaryDivider() { + stream << getLineOfChars<'-'>() << "\n"; + } + + private: + bool m_headerPrinted; + }; + + INTERNAL_CATCH_REGISTER_REPORTER( "console", ConsoleReporter ) + +} // end namespace Catch + +// #included from: ../reporters/catch_reporter_compact.hpp +#define TWOBLUECUBES_CATCH_REPORTER_COMPACT_HPP_INCLUDED + +namespace Catch { + + struct CompactReporter : StreamingReporterBase { + + CompactReporter( ReporterConfig const& _config ) + : StreamingReporterBase( _config ) + {} + + virtual ~CompactReporter(); + + static std::string getDescription() { + return "Reports test results on a single line, suitable for IDEs"; + } + + virtual ReporterPreferences getPreferences() const { + ReporterPreferences prefs; + prefs.shouldRedirectStdOut = false; + return prefs; + } + + virtual void noMatchingTestCases( std::string const& spec ) { + stream << "No test cases matched '" << spec << "'" << std::endl; + } + + virtual void assertionStarting( AssertionInfo const& ) { + } + + virtual bool assertionEnded( AssertionStats const& _assertionStats ) { + AssertionResult const& result = _assertionStats.assertionResult; + + bool printInfoMessages = true; + + // Drop out if result was successful and we're not printing those + if( !m_config->includeSuccessfulResults() && result.isOk() ) { + if( result.getResultType() != ResultWas::Warning ) + return false; + printInfoMessages = false; + } + + AssertionPrinter printer( stream, _assertionStats, printInfoMessages ); + printer.print(); + + stream << std::endl; + return true; + } + + virtual void testRunEnded( TestRunStats const& _testRunStats ) { + printTotals( _testRunStats.totals ); + stream << "\n" << std::endl; + StreamingReporterBase::testRunEnded( _testRunStats ); + } + + private: + class AssertionPrinter { + void operator= ( AssertionPrinter const& ); + public: + AssertionPrinter( std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages ) + : stream( _stream ) + , stats( _stats ) + , result( _stats.assertionResult ) + , messages( _stats.infoMessages ) + , itMessage( _stats.infoMessages.begin() ) + , printInfoMessages( _printInfoMessages ) + {} + + void print() { + printSourceInfo(); + + itMessage = messages.begin(); + + switch( result.getResultType() ) { + case ResultWas::Ok: + printResultType( Colour::ResultSuccess, passedString() ); + printOriginalExpression(); + printReconstructedExpression(); + if ( ! result.hasExpression() ) + printRemainingMessages( Colour::None ); + else + printRemainingMessages(); + break; + case ResultWas::ExpressionFailed: + if( result.isOk() ) + printResultType( Colour::ResultSuccess, failedString() + std::string( " - but was ok" ) ); + else + printResultType( Colour::Error, failedString() ); + printOriginalExpression(); + printReconstructedExpression(); + printRemainingMessages(); + break; + case ResultWas::ThrewException: + printResultType( Colour::Error, failedString() ); + printIssue( "unexpected exception with message:" ); + printMessage(); + printExpressionWas(); + printRemainingMessages(); + break; + case ResultWas::FatalErrorCondition: + printResultType( Colour::Error, failedString() ); + printIssue( "fatal error condition with message:" ); + printMessage(); + printExpressionWas(); + printRemainingMessages(); + break; + case ResultWas::DidntThrowException: + printResultType( Colour::Error, failedString() ); + printIssue( "expected exception, got none" ); + printExpressionWas(); + printRemainingMessages(); + break; + case ResultWas::Info: + printResultType( Colour::None, "info" ); + printMessage(); + printRemainingMessages(); + break; + case ResultWas::Warning: + printResultType( Colour::None, "warning" ); + printMessage(); + printRemainingMessages(); + break; + case ResultWas::ExplicitFailure: + printResultType( Colour::Error, failedString() ); + printIssue( "explicitly" ); + printRemainingMessages( Colour::None ); + break; + // These cases are here to prevent compiler warnings + case ResultWas::Unknown: + case ResultWas::FailureBit: + case ResultWas::Exception: + printResultType( Colour::Error, "** internal error **" ); + break; + } + } + + private: + // Colour::LightGrey + + static Colour::Code dimColour() { return Colour::FileName; } + +#ifdef CATCH_PLATFORM_MAC + static const char* failedString() { return "FAILED"; } + static const char* passedString() { return "PASSED"; } +#else + static const char* failedString() { return "failed"; } + static const char* passedString() { return "passed"; } +#endif + + void printSourceInfo() const { + Colour colourGuard( Colour::FileName ); + stream << result.getSourceInfo() << ":"; + } + + void printResultType( Colour::Code colour, std::string passOrFail ) const { + if( !passOrFail.empty() ) { + { + Colour colourGuard( colour ); + stream << " " << passOrFail; + } + stream << ":"; + } + } + + void printIssue( std::string issue ) const { + stream << " " << issue; + } + + void printExpressionWas() { + if( result.hasExpression() ) { + stream << ";"; + { + Colour colour( dimColour() ); + stream << " expression was:"; + } + printOriginalExpression(); + } + } + + void printOriginalExpression() const { + if( result.hasExpression() ) { + stream << " " << result.getExpression(); + } + } + + void printReconstructedExpression() const { + if( result.hasExpandedExpression() ) { + { + Colour colour( dimColour() ); + stream << " for: "; + } + stream << result.getExpandedExpression(); + } + } + + void printMessage() { + if ( itMessage != messages.end() ) { + stream << " '" << itMessage->message << "'"; + ++itMessage; + } + } + + void printRemainingMessages( Colour::Code colour = dimColour() ) { + if ( itMessage == messages.end() ) + return; + + // using messages.end() directly yields compilation error: + std::vector::const_iterator itEnd = messages.end(); + const std::size_t N = static_cast( std::distance( itMessage, itEnd ) ); + + { + Colour colourGuard( colour ); + stream << " with " << pluralise( N, "message" ) << ":"; + } + + for(; itMessage != itEnd; ) { + // If this assertion is a warning ignore any INFO messages + if( printInfoMessages || itMessage->type != ResultWas::Info ) { + stream << " '" << itMessage->message << "'"; + if ( ++itMessage != itEnd ) { + Colour colourGuard( dimColour() ); + stream << " and"; + } + } + } + } + + private: + std::ostream& stream; + AssertionStats const& stats; + AssertionResult const& result; + std::vector messages; + std::vector::const_iterator itMessage; + bool printInfoMessages; + }; + + // Colour, message variants: + // - white: No tests ran. + // - red: Failed [both/all] N test cases, failed [both/all] M assertions. + // - white: Passed [both/all] N test cases (no assertions). + // - red: Failed N tests cases, failed M assertions. + // - green: Passed [both/all] N tests cases with M assertions. + + std::string bothOrAll( std::size_t count ) const { + return count == 1 ? "" : count == 2 ? "both " : "all " ; + } + + void printTotals( const Totals& totals ) const { + if( totals.testCases.total() == 0 ) { + stream << "No tests ran."; + } + else if( totals.testCases.failed == totals.testCases.total() ) { + Colour colour( Colour::ResultError ); + const std::string qualify_assertions_failed = + totals.assertions.failed == totals.assertions.total() ? + bothOrAll( totals.assertions.failed ) : ""; + stream << + "Failed " << bothOrAll( totals.testCases.failed ) + << pluralise( totals.testCases.failed, "test case" ) << ", " + "failed " << qualify_assertions_failed << + pluralise( totals.assertions.failed, "assertion" ) << "."; + } + else if( totals.assertions.total() == 0 ) { + stream << + "Passed " << bothOrAll( totals.testCases.total() ) + << pluralise( totals.testCases.total(), "test case" ) + << " (no assertions)."; + } + else if( totals.assertions.failed ) { + Colour colour( Colour::ResultError ); + stream << + "Failed " << pluralise( totals.testCases.failed, "test case" ) << ", " + "failed " << pluralise( totals.assertions.failed, "assertion" ) << "."; + } + else { + Colour colour( Colour::ResultSuccess ); + stream << + "Passed " << bothOrAll( totals.testCases.passed ) + << pluralise( totals.testCases.passed, "test case" ) << + " with " << pluralise( totals.assertions.passed, "assertion" ) << "."; + } + } + }; + + INTERNAL_CATCH_REGISTER_REPORTER( "compact", CompactReporter ) + +} // end namespace Catch + +namespace Catch { + // These are all here to avoid warnings about not having any out of line + // virtual methods + NonCopyable::~NonCopyable() {} + IShared::~IShared() {} + IStream::~IStream() CATCH_NOEXCEPT {} + FileStream::~FileStream() CATCH_NOEXCEPT {} + CoutStream::~CoutStream() CATCH_NOEXCEPT {} + DebugOutStream::~DebugOutStream() CATCH_NOEXCEPT {} + StreamBufBase::~StreamBufBase() CATCH_NOEXCEPT {} + IContext::~IContext() {} + IResultCapture::~IResultCapture() {} + ITestCase::~ITestCase() {} + ITestCaseRegistry::~ITestCaseRegistry() {} + IRegistryHub::~IRegistryHub() {} + IMutableRegistryHub::~IMutableRegistryHub() {} + IExceptionTranslator::~IExceptionTranslator() {} + IExceptionTranslatorRegistry::~IExceptionTranslatorRegistry() {} + IReporter::~IReporter() {} + IReporterFactory::~IReporterFactory() {} + IReporterRegistry::~IReporterRegistry() {} + IStreamingReporter::~IStreamingReporter() {} + AssertionStats::~AssertionStats() {} + SectionStats::~SectionStats() {} + TestCaseStats::~TestCaseStats() {} + TestGroupStats::~TestGroupStats() {} + TestRunStats::~TestRunStats() {} + CumulativeReporterBase::SectionNode::~SectionNode() {} + CumulativeReporterBase::~CumulativeReporterBase() {} + + StreamingReporterBase::~StreamingReporterBase() {} + ConsoleReporter::~ConsoleReporter() {} + CompactReporter::~CompactReporter() {} + IRunner::~IRunner() {} + IMutableContext::~IMutableContext() {} + IConfig::~IConfig() {} + XmlReporter::~XmlReporter() {} + JunitReporter::~JunitReporter() {} + TestRegistry::~TestRegistry() {} + FreeFunctionTestCase::~FreeFunctionTestCase() {} + IGeneratorInfo::~IGeneratorInfo() {} + IGeneratorsForTest::~IGeneratorsForTest() {} + WildcardPattern::~WildcardPattern() {} + TestSpec::Pattern::~Pattern() {} + TestSpec::NamePattern::~NamePattern() {} + TestSpec::TagPattern::~TagPattern() {} + TestSpec::ExcludedPattern::~ExcludedPattern() {} + + Matchers::Impl::StdString::Equals::~Equals() {} + Matchers::Impl::StdString::Contains::~Contains() {} + Matchers::Impl::StdString::StartsWith::~StartsWith() {} + Matchers::Impl::StdString::EndsWith::~EndsWith() {} + + void Config::dummy() {} + + namespace TestCaseTracking { + ITracker::~ITracker() {} + TrackerBase::~TrackerBase() {} + SectionTracker::~SectionTracker() {} + IndexTracker::~IndexTracker() {} + } +} + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +#endif + +#ifdef CATCH_CONFIG_MAIN +// #included from: internal/catch_default_main.hpp +#define TWOBLUECUBES_CATCH_DEFAULT_MAIN_HPP_INCLUDED + +#ifndef __OBJC__ + +// Standard C/C++ main entry point +int main (int argc, char * argv[]) { + return Catch::Session().run( argc, argv ); +} + +#else // __OBJC__ + +// Objective-C entry point +int main (int argc, char * const argv[]) { +#if !CATCH_ARC_ENABLED + NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; +#endif + + Catch::registerTestMethods(); + int result = Catch::Session().run( argc, (char* const*)argv ); + +#if !CATCH_ARC_ENABLED + [pool drain]; +#endif + + return result; +} + +#endif // __OBJC__ + +#endif + +#ifdef CLARA_CONFIG_MAIN_NOT_DEFINED +# undef CLARA_CONFIG_MAIN +#endif + +////// + +// If this config identifier is defined then all CATCH macros are prefixed with CATCH_ +#ifdef CATCH_CONFIG_PREFIX_ALL + +#define CATCH_REQUIRE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE" ) +#define CATCH_REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, "CATCH_REQUIRE_FALSE" ) + +#define CATCH_REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, "", "CATCH_REQUIRE_THROWS" ) +#define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THROWS_AS" ) +#define CATCH_REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, matcher, "CATCH_REQUIRE_THROWS_WITH" ) +#define CATCH_REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_NOTHROW" ) + +#define CATCH_CHECK( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK" ) +#define CATCH_CHECK_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, "CATCH_CHECK_FALSE" ) +#define CATCH_CHECKED_IF( expr ) INTERNAL_CATCH_IF( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECKED_IF" ) +#define CATCH_CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECKED_ELSE" ) +#define CATCH_CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, "CATCH_CHECK_NOFAIL" ) + +#define CATCH_CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THROWS" ) +#define CATCH_CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THROWS_AS" ) +#define CATCH_CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, matcher, "CATCH_CHECK_THROWS_WITH" ) +#define CATCH_CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_NOTHROW" ) + +#define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THAT" ) +#define CATCH_REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THAT" ) + +#define CATCH_INFO( msg ) INTERNAL_CATCH_INFO( msg, "CATCH_INFO" ) +#define CATCH_WARN( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, "CATCH_WARN", msg ) +#define CATCH_SCOPED_INFO( msg ) INTERNAL_CATCH_INFO( msg, "CATCH_INFO" ) +#define CATCH_CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CATCH_CAPTURE" ) +#define CATCH_SCOPED_CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CATCH_CAPTURE" ) + +#ifdef CATCH_CONFIG_VARIADIC_MACROS + #define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ ) + #define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ ) + #define CATCH_METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ ) + #define CATCH_REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ ) + #define CATCH_SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) + #define CATCH_FAIL( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "CATCH_FAIL", __VA_ARGS__ ) + #define CATCH_SUCCEED( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "CATCH_SUCCEED", __VA_ARGS__ ) +#else + #define CATCH_TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description ) + #define CATCH_TEST_CASE_METHOD( className, name, description ) INTERNAL_CATCH_TEST_CASE_METHOD( className, name, description ) + #define CATCH_METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description ) + #define CATCH_REGISTER_TEST_CASE( function, name, description ) INTERNAL_CATCH_REGISTER_TESTCASE( function, name, description ) + #define CATCH_SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description ) + #define CATCH_FAIL( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "CATCH_FAIL", msg ) + #define CATCH_SUCCEED( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "CATCH_SUCCEED", msg ) +#endif +#define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE( "", "" ) + +#define CATCH_REGISTER_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) +#define CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) + +#define CATCH_GENERATE( expr) INTERNAL_CATCH_GENERATE( expr ) + +// "BDD-style" convenience wrappers +#ifdef CATCH_CONFIG_VARIADIC_MACROS +#define CATCH_SCENARIO( ... ) CATCH_TEST_CASE( "Scenario: " __VA_ARGS__ ) +#define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ ) +#else +#define CATCH_SCENARIO( name, tags ) CATCH_TEST_CASE( "Scenario: " name, tags ) +#define CATCH_SCENARIO_METHOD( className, name, tags ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " name, tags ) +#endif +#define CATCH_GIVEN( desc ) CATCH_SECTION( std::string( "Given: ") + desc, "" ) +#define CATCH_WHEN( desc ) CATCH_SECTION( std::string( " When: ") + desc, "" ) +#define CATCH_AND_WHEN( desc ) CATCH_SECTION( std::string( " And: ") + desc, "" ) +#define CATCH_THEN( desc ) CATCH_SECTION( std::string( " Then: ") + desc, "" ) +#define CATCH_AND_THEN( desc ) CATCH_SECTION( std::string( " And: ") + desc, "" ) + +// If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required +#else + +#define REQUIRE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal, "REQUIRE" ) +#define REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, "REQUIRE_FALSE" ) + +#define REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, "", "REQUIRE_THROWS" ) +#define REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::Normal, "REQUIRE_THROWS_AS" ) +#define REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, matcher, "REQUIRE_THROWS_WITH" ) +#define REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::Normal, "REQUIRE_NOTHROW" ) + +#define CHECK( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK" ) +#define CHECK_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, "CHECK_FALSE" ) +#define CHECKED_IF( expr ) INTERNAL_CATCH_IF( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECKED_IF" ) +#define CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECKED_ELSE" ) +#define CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, "CHECK_NOFAIL" ) + +#define CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, "", "CHECK_THROWS" ) +#define CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THROWS_AS" ) +#define CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, matcher, "CHECK_THROWS_WITH" ) +#define CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK_NOTHROW" ) + +#define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THAT" ) +#define REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::Normal, "REQUIRE_THAT" ) + +#define INFO( msg ) INTERNAL_CATCH_INFO( msg, "INFO" ) +#define WARN( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, "WARN", msg ) +#define SCOPED_INFO( msg ) INTERNAL_CATCH_INFO( msg, "INFO" ) +#define CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CAPTURE" ) +#define SCOPED_CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CAPTURE" ) + +#ifdef CATCH_CONFIG_VARIADIC_MACROS + #define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ ) + #define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ ) + #define METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ ) + #define REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ ) + #define SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) + #define FAIL( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "FAIL", __VA_ARGS__ ) + #define SUCCEED( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "SUCCEED", __VA_ARGS__ ) +#else + #define TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description ) + #define TEST_CASE_METHOD( className, name, description ) INTERNAL_CATCH_TEST_CASE_METHOD( className, name, description ) + #define METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description ) + #define REGISTER_TEST_CASE( method, name, description ) INTERNAL_CATCH_REGISTER_TESTCASE( method, name, description ) + #define SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description ) + #define FAIL( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "FAIL", msg ) + #define SUCCEED( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "SUCCEED", msg ) +#endif +#define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE( "", "" ) + +#define REGISTER_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) +#define REGISTER_LEGACY_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) + +#define GENERATE( expr) INTERNAL_CATCH_GENERATE( expr ) + +#endif + +#define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) + +// "BDD-style" convenience wrappers +#ifdef CATCH_CONFIG_VARIADIC_MACROS +#define SCENARIO( ... ) TEST_CASE( "Scenario: " __VA_ARGS__ ) +#define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ ) +#else +#define SCENARIO( name, tags ) TEST_CASE( "Scenario: " name, tags ) +#define SCENARIO_METHOD( className, name, tags ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " name, tags ) +#endif +#define GIVEN( desc ) SECTION( std::string(" Given: ") + desc, "" ) +#define WHEN( desc ) SECTION( std::string(" When: ") + desc, "" ) +#define AND_WHEN( desc ) SECTION( std::string("And when: ") + desc, "" ) +#define THEN( desc ) SECTION( std::string(" Then: ") + desc, "" ) +#define AND_THEN( desc ) SECTION( std::string(" And: ") + desc, "" ) + +using Catch::Detail::Approx; + +#endif // TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED + diff --git a/CUDA_DeviceQuery/libwb/vendor/json11.cpp b/CUDA_DeviceQuery/libwb/vendor/json11.cpp new file mode 100644 index 0000000..f401c26 --- /dev/null +++ b/CUDA_DeviceQuery/libwb/vendor/json11.cpp @@ -0,0 +1,1013 @@ +/* Copyright (c) 2013 Dropbox, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy + * of this software and associated documentation files (the "Software"), to + * deal + * in the Software without restriction, including without limitation the + * rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN + * THE SOFTWARE. + */ + +#include "json11.hpp" +#include +#include +#include +#include +#include +#include + +namespace json11 { + +static const int max_depth = 200; + +using std::string; +using std::vector; +using std::map; +using std::make_shared; +using std::initializer_list; +using std::move; + +/* * * * * * * * * * * * * * * * * * * * + * Serialization + */ + +static void dump(std::nullptr_t, string &out) { + out += "null"; +} + +static void dump(double value, string &out) { + if (std::isfinite(value)) { + char buf[32]; +//PMO +#ifndef _MSC_VER + snprintf(buf, sizeof buf, "%.17g", value); +#else + _snprintf_s(buf, sizeof buf, "%.17g", value); +#endif + out += buf; + } else { + out += "null"; + } +} + +static void dump(int value, string &out) { + char buf[32]; +//PMO +#ifndef _MSC_VER + snprintf(buf, sizeof buf, "%d", value); +#else + _snprintf_s(buf, sizeof buf, "%d", value); +#endif + out += buf; +} + +static void dump(int64_t value, string &out) { + char buf[64]; +//PMO +#ifndef _MSC_VER + snprintf(buf, sizeof buf, "%" PRId64, value); +#else + _snprintf_s(buf, sizeof buf, "%" PRId64, value); +#endif + out += buf; +} + +static void dump(uint64_t value, string &out) { + char buf[128]; +//PMO +#ifndef _MSC_VER + snprintf(buf, sizeof buf, "%" PRIu64, value); +#else + _snprintf_s(buf, sizeof buf, "%" PRIu64, value); +#endif + out += buf; +} + +static void dump(bool value, string &out) { + out += value ? "true" : "false"; +} + +static void dump(const string &value, string &out) { + out += '"'; + for (size_t i = 0; i < value.length(); i++) { + const char ch = value[i]; + if (ch == '\\') { + out += "\\\\"; + } else if (ch == '"') { + out += "\\\""; + } else if (ch == '\b') { + out += "\\b"; + } else if (ch == '\f') { + out += "\\f"; + } else if (ch == '\n') { + out += "\\n"; + } else if (ch == '\r') { + out += "\\r"; + } else if (ch == '\t') { + out += "\\t"; + } else if (static_cast(ch) <= 0x1f) { + char buf[8]; +//PMO +#ifndef _MSC_VER + snprintf(buf, sizeof buf, "\\u%04x", ch); +#else + _snprintf_s(buf, sizeof buf, "\\u%04x", ch); +#endif + out += buf; + } else if (static_cast(ch) == 0xe2 && + static_cast(value[i + 1]) == 0x80 && + static_cast(value[i + 2]) == 0xa8) { + out += "\\u2028"; + i += 2; + } else if (static_cast(ch) == 0xe2 && + static_cast(value[i + 1]) == 0x80 && + static_cast(value[i + 2]) == 0xa9) { + out += "\\u2029"; + i += 2; + } else { + out += ch; + } + } + out += '"'; +} + +static void dump(const Json::array &values, string &out) { + bool first = true; + out += "["; + for (const auto &value : values) { + if (!first) + out += ", "; + value.dump(out); + first = false; + } + out += "]"; +} + +static void dump(const Json::object &values, string &out) { + bool first = true; + out += "{"; + for (const auto &kv : values) { + if (!first) + out += ", "; + dump(kv.first, out); + out += ": "; + kv.second.dump(out); + first = false; + } + out += "}"; +} + +void Json::dump(string &out) const { + m_ptr->dump(out); +} + +/* * * * * * * * * * * * * * * * * * * * + * Value wrappers + */ + +template +class Value : public JsonValue { +protected: + // Constructors + explicit Value(const T &value) : m_value(value) { + } + explicit Value(T &&value) : m_value(move(value)) { + } + + // Get type tag + Json::Type type() const override { + return tag; + } + + // Comparisons + bool equals(const JsonValue *other) const override { + return m_value == static_cast *>(other)->m_value; + } + bool less(const JsonValue *other) const override { + return m_value < static_cast *>(other)->m_value; + } + + const T m_value; + void dump(string &out) const override { + json11::dump(m_value, out); + } +}; + +class JsonDouble final : public Value { + double number_value() const override { + return m_value; + } + int int_value() const override { + return static_cast(m_value); + } + int64_t int64_value() const override { + return (int64_t)m_value; + } + uint64_t uint64_value() const override { + return (uint64_t)m_value; + } + bool equals(const JsonValue *other) const override { + return m_value == other->number_value(); + } + bool less(const JsonValue *other) const override { + return m_value < other->number_value(); + } + +public: + explicit JsonDouble(double value) : Value(value) { + } +}; + +class JsonInt final : public Value { + double number_value() const override { + return m_value; + } + int int_value() const override { + return m_value; + } + int64_t int64_value() const override { + return m_value; + } + uint64_t uint64_value() const override { + return m_value; + } + bool equals(const JsonValue *other) const override { + return m_value == other->number_value(); + } + bool less(const JsonValue *other) const override { + return m_value < other->number_value(); + } + +public: + explicit JsonInt(int value) : Value(value) { + } +}; + +class JsonInt64 final : public Value { + double number_value() const override { + return m_value; + } + int int_value() const override { + return (int)m_value; + } + int64_t int64_value() const override { + return m_value; + } + uint64_t uint64_value() const override { + return (uint64_t)m_value; + } + bool equals(const JsonValue *other) const override { + return m_value == other->number_value(); + } + bool less(const JsonValue *other) const override { + return m_value < other->number_value(); + } + +public: + explicit JsonInt64(int64_t value) : Value(value) { + } +}; + +class JsonUInt64 final : public Value { + double number_value() const override { + return m_value; + } + int int_value() const override { + return (int)m_value; + } + int64_t int64_value() const override { + return (int64_t)m_value; + } + uint64_t uint64_value() const override { + return m_value; + } + bool equals(const JsonValue *other) const override { + return m_value == other->number_value(); + } + bool less(const JsonValue *other) const override { + return m_value < other->number_value(); + } + +public: + explicit JsonUInt64(uint64_t value) : Value(value) { + } +}; + +class JsonBoolean final : public Value { + bool bool_value() const override { + return m_value; + } + +public: + explicit JsonBoolean(bool value) : Value(value) { + } +}; + +class JsonString final : public Value { + const string &string_value() const override { + return m_value; + } + +public: + explicit JsonString(const string &value) : Value(value) { + } + explicit JsonString(string &&value) : Value(move(value)) { + } +}; + +class JsonArray final : public Value { + const Json::array &array_items() const override { + return m_value; + } + const Json &operator[](size_t i) const override; + +public: + explicit JsonArray(const Json::array &value) : Value(value) { + } + explicit JsonArray(Json::array &&value) : Value(move(value)) { + } +}; + +class JsonObject final : public Value { + const Json::object &object_items() const override { + return m_value; + } + const Json &operator[](const string &key) const override; + +public: + explicit JsonObject(const Json::object &value) : Value(value) { + } + explicit JsonObject(Json::object &&value) : Value(move(value)) { + } +}; + +class JsonNull final : public Value { +public: + JsonNull() : Value(nullptr) { + } +}; + +/* * * * * * * * * * * * * * * * * * * * + * Static globals - static-init-safe + */ +struct Statics { + const std::shared_ptr null = make_shared(); + const std::shared_ptr t = make_shared(true); + const std::shared_ptr f = make_shared(false); + const string empty_string; + const vector empty_vector; + const map empty_map; + Statics() { + } +}; + +static const Statics &statics() { + static const Statics s{}; + return s; +} + +static const Json &static_null() { + // This has to be separate, not in Statics, because Json() accesses + // statics().null. + static const Json json_null; + return json_null; +} + +/* * * * * * * * * * * * * * * * * * * * + * Constructors + */ + +Json::Json() NOEXCEPT : m_ptr(statics().null) { +} +Json::Json(std::nullptr_t) NOEXCEPT : m_ptr(statics().null) { +} +Json::Json(double value) : m_ptr(make_shared(value)) { +} +Json::Json(int value) : m_ptr(make_shared(value)) { +} +Json::Json(int64_t value) : m_ptr(make_shared(value)) { +} +Json::Json(uint64_t value) : m_ptr(make_shared(value)) { +} +Json::Json(bool value) : m_ptr(value ? statics().t : statics().f) { +} +Json::Json(const string &value) : m_ptr(make_shared(value)) { +} +Json::Json(string &&value) : m_ptr(make_shared(move(value))) { +} +Json::Json(const char *value) : m_ptr(make_shared(value)) { +} +Json::Json(const Json::array &values) + : m_ptr(make_shared(values)) { +} +Json::Json(Json::array &&values) + : m_ptr(make_shared(move(values))) { +} +Json::Json(const Json::object &values) + : m_ptr(make_shared(values)) { +} +Json::Json(Json::object &&values) + : m_ptr(make_shared(move(values))) { +} + +/* * * * * * * * * * * * * * * * * * * * + * Accessors + */ + +Json::Type Json::type() const { + return m_ptr->type(); +} +double Json::number_value() const { + return m_ptr->number_value(); +} +int Json::int_value() const { + return m_ptr->int_value(); +} +int64_t Json::int64_value() const { + return m_ptr->int64_value(); +} +uint64_t Json::uint64_value() const { + return m_ptr->uint64_value(); +} +bool Json::bool_value() const { + return m_ptr->bool_value(); +} +const string &Json::string_value() const { + return m_ptr->string_value(); +} +const vector &Json::array_items() const { + return m_ptr->array_items(); +} +const map &Json::object_items() const { + return m_ptr->object_items(); +} +const Json &Json::operator[](size_t i) const { + return (*m_ptr)[i]; +} +const Json &Json::operator[](const string &key) const { + return (*m_ptr)[key]; +} + +double JsonValue::number_value() const { + return 0; +} +int JsonValue::int_value() const { + return 0; +} +int64_t JsonValue::int64_value() const { + return 0; +} +uint64_t JsonValue::uint64_value() const { + return 0; +} +bool JsonValue::bool_value() const { + return false; +} +const string &JsonValue::string_value() const { + return statics().empty_string; +} +const vector &JsonValue::array_items() const { + return statics().empty_vector; +} +const map &JsonValue::object_items() const { + return statics().empty_map; +} +const Json &JsonValue::operator[](size_t) const { + return static_null(); +} +const Json &JsonValue::operator[](const string &) const { + return static_null(); +} + +const Json &JsonObject::operator[](const string &key) const { + auto iter = m_value.find(key); + return (iter == m_value.end()) ? static_null() : iter->second; +} +const Json &JsonArray::operator[](size_t i) const { + if (i >= m_value.size()) + return static_null(); + else + return m_value[i]; +} + +/* * * * * * * * * * * * * * * * * * * * + * Comparison + */ + +bool Json::operator==(const Json &other) const { + if (m_ptr->type() != other.m_ptr->type()) + return false; + + return m_ptr->equals(other.m_ptr.get()); +} + +bool Json::operator<(const Json &other) const { + if (m_ptr->type() != other.m_ptr->type()) + return m_ptr->type() < other.m_ptr->type(); + + return m_ptr->less(other.m_ptr.get()); +} + +/* * * * * * * * * * * * * * * * * * * * + * Parsing + */ + +/* esc(c) + * + * Format char c suitable for printing in an error message. + */ +static inline string esc(char c) { + char buf[12]; + if (static_cast(c) >= 0x20 && static_cast(c) <= 0x7f) { +//PMO +#ifndef _MSC_VER + snprintf(buf, sizeof buf, "'%c' (%d)", c, c); +#else + _snprintf_s(buf, sizeof buf, "'%c' (%d)", c, c); +#endif + } else { +//PMO +#ifndef _MSC_VER + snprintf(buf, sizeof buf, "(%d)", c); +#else + _snprintf_s(buf, sizeof buf, "(%d)", c); +#endif + } + return string(buf); +} + +static inline bool in_range(long x, long lower, long upper) { + return (x >= lower && x <= upper); +} + +/* JsonParser + * + * Object that tracks all state of an in-progress parse. + */ +struct JsonParser { + + /* State + */ + const string &str; + size_t i; + string &err; + bool failed; + const JsonParse strategy; + + /* fail(msg, err_ret = Json()) + * + * Mark this parse as failed. + */ + Json fail(string &&msg) { + return fail(move(msg), Json()); + } + + template + T fail(string &&msg, const T err_ret) { + if (!failed) + err = std::move(msg); + failed = true; + return err_ret; + } + + /* consume_whitespace() + * + * Advance until the current character is non-whitespace. + */ + void consume_whitespace() { + while (str[i] == ' ' || str[i] == '\r' || str[i] == '\n' || + str[i] == '\t') + i++; + } + + /* consume_comment() + * + * Advance comments (c-style inline and multiline). + */ + bool consume_comment() { + bool comment_found = false; + if (str[i] == '/') { + i++; + if (i == str.size()) + return fail("unexpected end of input inside comment", 0); + if (str[i] == '/') { // inline comment + i++; + if (i == str.size()) + return fail("unexpected end of input inside inline comment", 0); + // advance until next line + while (str[i] != '\n') { + i++; + if (i == str.size()) + return fail("unexpected end of input inside inline comment", + 0); + } + comment_found = true; + } else if (str[i] == '*') { // multiline comment + i++; + if (i > str.size() - 2) + return fail("unexpected end of input inside multi-line comment", + 0); + // advance until closing tokens + while (!(str[i] == '*' && str[i + 1] == '/')) { + i++; + if (i > str.size() - 2) + return fail( + "unexpected end of input inside multi-line comment", 0); + } + i += 2; + if (i == str.size()) + return fail("unexpected end of input inside multi-line comment", + 0); + comment_found = true; + } else + return fail("malformed comment", 0); + } + return comment_found; + } + + /* consume_garbage() + * + * Advance until the current character is non-whitespace and non-comment. + */ + void consume_garbage() { + consume_whitespace(); + if (strategy == JsonParse::COMMENTS) { + bool comment_found = false; + do { + comment_found = consume_comment(); + consume_whitespace(); + } while (comment_found); + } + } + + /* get_next_token() + * + * Return the next non-whitespace character. If the end of the input is + * reached, + * flag an error and return 0. + */ + char get_next_token() { + consume_garbage(); + if (i == str.size()) + return fail("unexpected end of input", 0); + + return str[i++]; + } + + /* encode_utf8(pt, out) + * + * Encode pt as UTF-8 and add it to out. + */ + void encode_utf8(long pt, string &out) { + if (pt < 0) + return; + + if (pt < 0x80) { + out += static_cast(pt); + } else if (pt < 0x800) { + out += static_cast((pt >> 6) | 0xC0); + out += static_cast((pt & 0x3F) | 0x80); + } else if (pt < 0x10000) { + out += static_cast((pt >> 12) | 0xE0); + out += static_cast(((pt >> 6) & 0x3F) | 0x80); + out += static_cast((pt & 0x3F) | 0x80); + } else { + out += static_cast((pt >> 18) | 0xF0); + out += static_cast(((pt >> 12) & 0x3F) | 0x80); + out += static_cast(((pt >> 6) & 0x3F) | 0x80); + out += static_cast((pt & 0x3F) | 0x80); + } + } + + /* parse_string() + * + * Parse a string, starting at the current position. + */ + string parse_string() { + string out; + long last_escaped_codepoint = -1; + while (true) { + if (i == str.size()) + return fail("unexpected end of input in string", ""); + + char ch = str[i++]; + + if (ch == '"') { + encode_utf8(last_escaped_codepoint, out); + return out; + } + + if (in_range(ch, 0, 0x1f)) + return fail("unescaped " + esc(ch) + " in string", ""); + + // The usual case: non-escaped characters + if (ch != '\\') { + encode_utf8(last_escaped_codepoint, out); + last_escaped_codepoint = -1; + out += ch; + continue; + } + + // Handle escapes + if (i == str.size()) + return fail("unexpected end of input in string", ""); + + ch = str[i++]; + + if (ch == 'u') { + // Extract 4-byte escape sequence + string esc = str.substr(i, 4); + // Explicitly check length of the substring. The following loop + // relies on std::string returning the terminating NUL when + // accessing str[length]. Checking here reduces brittleness. + if (esc.length() < 4) { + return fail("bad \\u escape: " + esc, ""); + } + for (int j = 0; j < 4; j++) { + if (!in_range(esc[j], 'a', 'f') && !in_range(esc[j], 'A', 'F') && + !in_range(esc[j], '0', '9')) + return fail("bad \\u escape: " + esc, ""); + } + + long codepoint = strtol(esc.data(), nullptr, 16); + + // JSON specifies that characters outside the BMP shall be encoded + // as a pair + // of 4-hex-digit \u escapes encoding their surrogate pair + // components. Check + // whether we're in the middle of such a beast: the previous + // codepoint was an + // escaped lead (high) surrogate, and this is a trail (low) + // surrogate. + if (in_range(last_escaped_codepoint, 0xD800, 0xDBFF) && + in_range(codepoint, 0xDC00, 0xDFFF)) { + // Reassemble the two surrogate pairs into one astral-plane + // character, per + // the UTF-16 algorithm. + encode_utf8((((last_escaped_codepoint - 0xD800) << 10) | + (codepoint - 0xDC00)) + + 0x10000, + out); + last_escaped_codepoint = -1; + } else { + encode_utf8(last_escaped_codepoint, out); + last_escaped_codepoint = codepoint; + } + + i += 4; + continue; + } + + encode_utf8(last_escaped_codepoint, out); + last_escaped_codepoint = -1; + + if (ch == 'b') { + out += '\b'; + } else if (ch == 'f') { + out += '\f'; + } else if (ch == 'n') { + out += '\n'; + } else if (ch == 'r') { + out += '\r'; + } else if (ch == 't') { + out += '\t'; + } else if (ch == '"' || ch == '\\' || ch == '/') { + out += ch; + } else { + return fail("invalid escape character " + esc(ch), ""); + } + } + } + + /* parse_number() + * + * Parse a double. + */ + Json parse_number() { + size_t start_pos = i; + + if (str[i] == '-') + i++; + + // Integer part + if (str[i] == '0') { + i++; + if (in_range(str[i], '0', '9')) + return fail("leading 0s not permitted in numbers"); + } else if (in_range(str[i], '1', '9')) { + i++; + while (in_range(str[i], '0', '9')) + i++; + } else { + return fail("invalid " + esc(str[i]) + " in number"); + } + + if (str[i] != '.' && str[i] != 'e' && str[i] != 'E' && + (i - start_pos) <= + static_cast(std::numeric_limits::digits10)) { + return std::atoi(str.c_str() + start_pos); + } + + // Decimal part + if (str[i] == '.') { + i++; + if (!in_range(str[i], '0', '9')) + return fail("at least one digit required in fractional part"); + + while (in_range(str[i], '0', '9')) + i++; + } + + // Exponent part + if (str[i] == 'e' || str[i] == 'E') { + i++; + + if (str[i] == '+' || str[i] == '-') + i++; + + if (!in_range(str[i], '0', '9')) + return fail("at least one digit required in exponent"); + + while (in_range(str[i], '0', '9')) + i++; + } + + return std::strtod(str.c_str() + start_pos, nullptr); + } + + /* expect(str, res) + * + * Expect that 'str' starts at the character that was just read. If it + * does, advance + * the input and return res. If not, flag an error. + */ + Json expect(const string &expected, Json res) { + assert(i != 0); + i--; + if (str.compare(i, expected.length(), expected) == 0) { + i += expected.length(); + return res; + } else { + return fail("parse error: expected " + expected + ", got " + + str.substr(i, expected.length())); + } + } + + /* parse_json() + * + * Parse a JSON object. + */ + Json parse_json(int depth) { + if (depth > max_depth) { + return fail("exceeded maximum nesting depth"); + } + + char ch = get_next_token(); + if (failed) + return Json(); + + if (ch == '-' || (ch >= '0' && ch <= '9')) { + i--; + return parse_number(); + } + + if (ch == 't') + return expect("true", true); + + if (ch == 'f') + return expect("false", false); + + if (ch == 'n') + return expect("null", Json()); + + if (ch == '"') + return parse_string(); + + if (ch == '{') { + map data; + ch = get_next_token(); + if (ch == '}') + return data; + + while (1) { + if (ch != '"') + return fail("expected '\"' in object, got " + esc(ch)); + + string key = parse_string(); + if (failed) + return Json(); + + ch = get_next_token(); + if (ch != ':') + return fail("expected ':' in object, got " + esc(ch)); + + data[std::move(key)] = parse_json(depth + 1); + if (failed) + return Json(); + + ch = get_next_token(); + if (ch == '}') + break; + if (ch != ',') + return fail("expected ',' in object, got " + esc(ch)); + + ch = get_next_token(); + } + return data; + } + + if (ch == '[') { + vector data; + ch = get_next_token(); + if (ch == ']') + return data; + + while (1) { + i--; + data.push_back(parse_json(depth + 1)); + if (failed) + return Json(); + + ch = get_next_token(); + if (ch == ']') + break; + if (ch != ',') + return fail("expected ',' in list, got " + esc(ch)); + + ch = get_next_token(); + (void)ch; + } + return data; + } + + return fail("expected value, got " + esc(ch)); + } +}; + +Json Json::parse(const string &in, string &err, JsonParse strategy) { + JsonParser parser{in, 0, err, false, strategy}; + Json result = parser.parse_json(0); + + // Check for any trailing garbage + parser.consume_garbage(); + if (parser.i != in.size()) + return parser.fail("unexpected trailing " + esc(in[parser.i])); + + return result; +} + +// Documented in json11.hpp +vector Json::parse_multi(const string &in, string &err, + JsonParse strategy) { + JsonParser parser{in, 0, err, false, strategy}; + + vector json_vec; + while (parser.i != in.size() && !parser.failed) { + json_vec.push_back(parser.parse_json(0)); + // Check for another object + parser.consume_garbage(); + } + return json_vec; +} + +/* * * * * * * * * * * * * * * * * * * * + * Shape-checking + */ + +bool Json::has_shape(const shape &types, string &err) const { + if (!is_object()) { + err = "expected JSON object, got " + dump(); + return false; + } + + for (auto &item : types) { + if ((*this)[item.first].type() != item.second) { + err = "bad type for " + item.first + " in " + dump(); + return false; + } + } + + return true; +} + +} // namespace json11 diff --git a/CUDA_DeviceQuery/libwb/vendor/json11.hpp b/CUDA_DeviceQuery/libwb/vendor/json11.hpp new file mode 100644 index 0000000..9e0f0d9 --- /dev/null +++ b/CUDA_DeviceQuery/libwb/vendor/json11.hpp @@ -0,0 +1,300 @@ +/* json11 + * + * json11 is a tiny JSON library for C++11, providing JSON parsing and + * serialization. + * + * The core object provided by the library is json11::Json. A Json object + * represents any JSON + * value: null, bool, number (int or double), string (std::string), array + * (std::vector), or + * object (std::map). + * + * Json objects act like values: they can be assigned, copied, moved, + * compared for equality or + * order, etc. There are also helper methods Json::dump, to serialize a + * Json to a string, and + * Json::parse (static) to parse a std::string as a Json object. + * + * Internally, the various types of Json object are represented by the + * JsonValue class + * hierarchy. + * + * A note on numbers - JSON specifies the syntax of number formatting but + * not its semantics, + * so some JSON implementations distinguish between integers and + * floating-point numbers, while + * some don't. In json11, we choose the latter. Because some JSON + * implementations (namely + * Javascript itself) treat all numbers as the same type, distinguishing + * the two leads + * to JSON that will be *silently* changed by a round-trip through those + * implementations. + * Dangerous! To avoid that risk, json11 stores all numbers as double + * internally, but also + * provides integer helpers. + * + * Fortunately, double-precision IEEE754 ('double') can precisely store any + * integer in the + * range +/-2^53, which includes every 'int' on most systems. (Timestamps + * often use int64 + * or long long to avoid the Y2038K problem; a double storing microseconds + * since some epoch + * will be exact for +/- 275 years.) + */ + +/* Copyright (c) 2013 Dropbox, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy + * of this software and associated documentation files (the "Software"), to + * deal + * in the Software without restriction, including without limitation the + * rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN + * THE SOFTWARE. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +//PMO +#ifndef _MSC_VER +#define NOEXCEPT noexcept +#else +#define NOEXCEPT _NOEXCEPT +#endif + +namespace json11 { + +enum JsonParse { STANDARD, COMMENTS }; + +class JsonValue; + +class Json final { +public: + // Types + enum Type { + NUL, + NUMBER, + NUMBER64, + UNUMBER64, + BOOL, + STRING, + ARRAY, + OBJECT + }; + + // Array and object typedefs + typedef std::vector array; + typedef std::map object; + + // Constructors for the various types of JSON value. + //PMO + //Json() noexcept; // NUL + Json() NOEXCEPT; // NUL + //Json(std::nullptr_t) noexcept; // NUL + Json(std::nullptr_t) NOEXCEPT; // NUL + Json(double value); // NUMBER + Json(int value); // NUMBER + Json(int64_t value); // NUMBER64 + Json(uint64_t value); // UNUMBER64 + Json(bool value); // BOOL + Json(const std::string &value); // STRING + Json(std::string &&value); // STRING + Json(const char *value); // STRING + Json(const array &values); // ARRAY + Json(array &&values); // ARRAY + Json(const object &values); // OBJECT + Json(object &&values); // OBJECT + + // Implicit constructor: anything with a to_json() function. + template + Json(const T &t) : Json(t.to_json()) { + } + + // Implicit constructor: map-like objects (std::map, std::unordered_map, + // etc) + template < + class M, + typename std::enable_if< + std::is_constructible::value && + std::is_constructible::value, + int>::type = 0> + Json(const M &m) : Json(object(m.begin(), m.end())) { + } + + // Implicit constructor: vector-like objects (std::list, std::vector, + // std::set, etc) + template ::value, + int>::type = 0> + Json(const V &v) : Json(array(v.begin(), v.end())) { + } + + // This prevents Json(some_pointer) from accidentally producing a bool. + // Use + // Json(bool(some_pointer)) if that behavior is desired. + Json(void *) = delete; + + // Accessors + Type type() const; + + bool is_null() const { + return type() == NUL; + } + bool is_number() const { + return type() == NUMBER; + } + bool is_number64() const { + return type() == NUMBER64; + } + bool is_unumber64() const { + return type() == UNUMBER64; + } + bool is_bool() const { + return type() == BOOL; + } + bool is_string() const { + return type() == STRING; + } + bool is_array() const { + return type() == ARRAY; + } + bool is_object() const { + return type() == OBJECT; + } + + // Return the enclosed value if this is a number, 0 otherwise. Note that + // json11 does not + // distinguish between integer and non-integer numbers - number_value() + // and int_value() + // can both be applied to a NUMBER-typed object. + double number_value() const; + int int_value() const; + int64_t int64_value() const; + uint64_t uint64_value() const; + + // Return the enclosed value if this is a boolean, false otherwise. + bool bool_value() const; + // Return the enclosed string if this is a string, "" otherwise. + const std::string &string_value() const; + // Return the enclosed std::vector if this is an array, or an empty + // vector otherwise. + const array &array_items() const; + // Return the enclosed std::map if this is an object, or an empty map + // otherwise. + const object &object_items() const; + + // Return a reference to arr[i] if this is an array, Json() otherwise. + const Json &operator[](size_t i) const; + // Return a reference to obj[key] if this is an object, Json() otherwise. + const Json &operator[](const std::string &key) const; + + // Serialize. + void dump(std::string &out) const; + std::string dump() const { + std::string out; + dump(out); + return out; + } + + // Parse. If parse fails, return Json() and assign an error message to + // err. + static Json parse(const std::string &in, std::string &err, + JsonParse strategy = JsonParse::STANDARD); + static Json parse(const char *in, std::string &err, + JsonParse strategy = JsonParse::STANDARD) { + if (in) { + return parse(std::string(in), err, strategy); + } else { + err = "null input"; + return nullptr; + } + } + // Parse multiple objects, concatenated or separated by whitespace + static std::vector + parse_multi(const std::string &in, std::string &err, + JsonParse strategy = JsonParse::STANDARD); + + bool operator==(const Json &rhs) const; + bool operator<(const Json &rhs) const; + bool operator!=(const Json &rhs) const { + return !(*this == rhs); + } + bool operator<=(const Json &rhs) const { + return !(rhs < *this); + } + bool operator>(const Json &rhs) const { + return (rhs < *this); + } + bool operator>=(const Json &rhs) const { + return !(*this < rhs); + } + + /* has_shape(types, err) + * + * Return true if this is a JSON object and, for each item in types, has + * a field of + * the given type. If not, return false and set err to a descriptive + * message. + */ + typedef std::initializer_list> shape; + bool has_shape(const shape &types, std::string &err) const; + +private: + std::shared_ptr m_ptr; +}; + +// Internal class hierarchy - JsonValue objects are not exposed to users of +// this API. +class JsonValue { +protected: + friend class Json; + friend class JsonInt; + friend class JsonInt64; + friend class JsonUInt64; + friend class JsonDouble; + virtual Json::Type type() const = 0; + virtual bool equals(const JsonValue *other) const = 0; + virtual bool less(const JsonValue *other) const = 0; + virtual void dump(std::string &out) const = 0; + virtual double number_value() const; + virtual int int_value() const; + virtual int64_t int64_value() const; + virtual uint64_t uint64_value() const; + virtual bool bool_value() const; + virtual const std::string &string_value() const; + virtual const Json::array &array_items() const; + virtual const Json &operator[](size_t i) const; + virtual const Json::object &object_items() const; + virtual const Json &operator[](const std::string &key) const; + virtual ~JsonValue() { + } +}; + +} // namespace json11 diff --git a/CUDA_DeviceQuery/libwb/wb.h b/CUDA_DeviceQuery/libwb/wb.h new file mode 100644 index 0000000..8f41e23 --- /dev/null +++ b/CUDA_DeviceQuery/libwb/wb.h @@ -0,0 +1,155 @@ + + +#ifndef __WB_H__ +#define __WB_H__ + +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ + +#include +#include +#include +#include + +#ifdef _MSC_VER + +// set minimal warning level +#pragma warning(push,0) +// some warnings still occur at this level +// if necessary, disable specific warnings not covered by previous pragma +#pragma warning(disable : 4244 4056 4305 4800 4267 4996 4756 4661 4385 4101) + +#define __func__ __FUNCTION__ +#ifndef _CRT_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_WARNINGS 1 +#endif /* _CRT_SECURE_NO_WARNINGS */ +#define _CRT_SECURE_NO_DEPRECATE 1 +#define _CRT_NONSTDC_NO_DEPRECATE 1 +#include +#include +#include +#define WB_USE_WINDOWS +#else /* _MSC_VER */ +#include +#include +#include +#include +#define WB_USE_UNIX +#ifdef __APPLE__ +#include +#define WB_USE_DARWIN +#else /* __APPLE__ */ +#define WB_USE_LINUX +#endif /* __APPLE__ */ +#endif /* _MSC_VER */ + +#define wbStmt(stmt) stmt + +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ + +#define wbLine __LINE__ +#define wbFile __FILE__ +#define wbFunction __func__ + +#define wbExit() \ + wbAssert(0); \ + exit(1) + +#ifdef WB_USE_COURSERA +#define wbLogger_printOnExit 1 +#else /* WB_USE_COURSERA */ +#define wbLogger_printOnLog 1 +#endif /* WB_USE_COURSERA */ + +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ + +#ifdef __cplusplus +#define EXTERN_C extern "C" +#define START_EXTERN_C EXTERN_C { +#define END_EXTERN_C } +#else +#define EXTERN_C +#define START_EXTERN_C +#define END_EXTERN_C +#endif /* __cplusplus */ + +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ + +#include +#define WB_USE_JSON11 1 + +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ + +#define LAZY_FILE_LOAD +extern char *solutionJSON; + +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ + +#ifdef WB_USE_OPENCL +#ifdef WB_USE_DARWIN +#include +#else /* WB_USE_DARWIN */ +#include +#endif /* WB_USE_DARWIN */ +#endif /* WB_USE_OPENCL */ + +#include "wbTypes.h" + +#include "wbAssert.h" +#include "wbMalloc.h" +#include "wbString.h" +#include "wbUtils.h" + +#include "wbArg.h" +#include "wbCUDA.h" +#include "wbCast.h" +#include "wbComparator.h" +#include "wbDirectory.h" +#include "wbExit.h" +#include "wbExport.h" +#include "wbFile.h" +#include "wbImage.h" +#include "wbImport.h" +#include "wbInit.h" +#include "wbLogger.h" +#include "wbMD5.h" +#include "wbMPI.h" +#include "wbSolution.h" +#include "wbSparse.h" +#include "wbThrust.h" +#include "wbTimer.h" +#include "wbPath.h" + +#include "wbDataset.h" + +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ + +#endif /* __WB_H__ */ diff --git a/CUDA_DeviceQuery/libwb/wbArg.cpp b/CUDA_DeviceQuery/libwb/wbArg.cpp new file mode 100644 index 0000000..2a5c736 --- /dev/null +++ b/CUDA_DeviceQuery/libwb/wbArg.cpp @@ -0,0 +1,105 @@ + +#include "wb.h" + +EXTERN_C wbArg_t wbArg_new(int *argc, char ***argv) { + wbArg_t arg; + + wb_init(argc, argv); + + wbArg_setInputCount(arg, 0); + wbArg_setInputFiles(arg, NULL); + wbArg_setOutputFile(arg, NULL); + wbArg_setType(arg, NULL); + wbArg_setExpectedOutputFile(arg, NULL); + return arg; +} + +EXTERN_C void wbArg_delete(wbArg_t arg) { + if (wbArg_getInputCount(arg) > 0 && wbArg_getInputFiles(arg) != NULL) { + int ii; + for (ii = 0; ii < wbArg_getInputCount(arg); ii++) { + wbDelete(wbArg_getInputFile(arg, ii)); + } + wbDelete(wbArg_getInputFiles(arg)); + wbArg_setInputCount(arg, 0); + wbArg_setInputFiles(arg, NULL); + } + if (wbArg_getOutputFile(arg)) { + wbDelete(wbArg_getOutputFile(arg)); + wbArg_setOutputFile(arg, NULL); + } + if (wbArg_getExpectedOutputFile(arg)) { + wbDelete(wbArg_getExpectedOutputFile(arg)); + wbArg_setExpectedOutputFile(arg, NULL); + } + if (wbArg_getType(arg)) { + wbDelete(wbArg_getType(arg)); + wbArg_setType(arg, NULL); + } + return; +} + +static int getInputFileCount(char *arg) { + int count = 1; + while (*arg != '\0' && *arg != '-') { + if (*arg == ',') { + count++; + } + arg++; + } + return count; +} + +static char **parseInputFiles(char *arg, int *resCount) { + int count; + int ii = 0; + char **files; + char *token; + + count = getInputFileCount(arg); + + files = wbNewArray(char *, count); + + token = strtok(arg, ","); + while (token != NULL) { + files[ii++] = wbString_duplicate(token); + token = strtok(NULL, ","); + } + *resCount = ii; + return files; +} + +static char *parseString(char *arg) { + return wbString_duplicate(arg); +} + +EXTERN_C wbArg_t wbArg_read(int argc, char **argv) { + int ii; + wbArg_t arg; + + arg = wbArg_new(&argc, &argv); + for (ii = 0; ii < argc; ii++) { + if (wbString_startsWith(argv[ii], "-i")) { + int fileCount; + char **files; + + files = parseInputFiles(argv[ii + 1], &fileCount); + + wbArg_setInputCount(arg, fileCount); + wbArg_setInputFiles(arg, files); + } else if (wbString_startsWith(argv[ii], "-o")) { + char *file = parseString(argv[ii + 1]); + wbArg_setOutputFile(arg, file); + } else if (wbString_startsWith(argv[ii], "-e")) { + char *file = parseString(argv[ii + 1]); + wbArg_setExpectedOutputFile(arg, file); + } else if (wbString_startsWith(argv[ii], "-t")) { + char *type = parseString(argv[ii + 1]); + wbArg_setType(arg, type); + } else if (argv[ii][0] == '-') { + wbLog(ERROR, "Unexpected program option ", argv[ii]); + } + } + + return arg; +} diff --git a/CUDA_DeviceQuery/libwb/wbArg.h b/CUDA_DeviceQuery/libwb/wbArg.h new file mode 100644 index 0000000..c98bcf7 --- /dev/null +++ b/CUDA_DeviceQuery/libwb/wbArg.h @@ -0,0 +1,33 @@ + + +#ifndef __WB_ARG_H__ +#define __WB_ARG_H__ + +struct st_wbArg_t { + int inputCount; + char **inputFiles; + char *outputFile; + char *expectedOutput; + char *type; +}; + +#define wbArg_getInputCount(wa) ((wa).inputCount) +#define wbArg_getInputFiles(wa) ((wa).inputFiles) +#define wbArg_getInputFile(wa, ii) (wbArg_getInputFiles(wa)[ii]) +#define wbArg_getOutputFile(wa) ((wa).outputFile) +#define wbArg_getExpectedOutputFile(wa) ((wa).expectedOutput) +#define wbArg_getType(wa) ((wa).type) + +#define wbArg_setInputCount(wa, val) (wbArg_getInputCount(wa) = val) +#define wbArg_setInputFiles(wa, val) (wbArg_getInputFiles(wa) = val) +#define wbArg_setInputFile(wa, ii, val) (wbArg_getInputFile(wa, ii) = val) +#define wbArg_setOutputFile(wa, val) (wbArg_getOutputFile(wa) = val) +#define wbArg_setExpectedOutputFile(wa, val) \ + (wbArg_getExpectedOutputFile(wa) = val) +#define wbArg_setType(wa, val) (wbArg_getType(wa) = val) + +EXTERN_C wbArg_t wbArg_new(int *argc, char ***argv); +EXTERN_C void wbArg_delete(wbArg_t arg); +EXTERN_C wbArg_t wbArg_read(int argc, char **argv); + +#endif /* __WB_ARG_H__ */ diff --git a/CUDA_DeviceQuery/libwb/wbAssert.h b/CUDA_DeviceQuery/libwb/wbAssert.h new file mode 100644 index 0000000..b8ed669 --- /dev/null +++ b/CUDA_DeviceQuery/libwb/wbAssert.h @@ -0,0 +1,24 @@ + + +#ifndef __WB_ASSERT_H__ +#define __WB_ASSERT_H__ + +#include + +#ifdef WB_DEBUG +#define wbAssert(cond) assert(cond) +#define wbAssertMessage(msg, cond) \ + do { \ + if (!(cond)) { \ + wbPrint(msg); \ + wbAssert(cond); \ + } \ + } while (0) +#else /* WB_DEBUG */ +#define wbAssert(...) +#define wbAssertMessage(...) +#endif /* WB_DEBUG */ + +#define wbTodo(msg) wbAssertMessage(msg, false) + +#endif /* __WB_ASSERT_H__ */ diff --git a/CUDA_DeviceQuery/libwb/wbCUDA.cpp b/CUDA_DeviceQuery/libwb/wbCUDA.cpp new file mode 100644 index 0000000..cb26895 --- /dev/null +++ b/CUDA_DeviceQuery/libwb/wbCUDA.cpp @@ -0,0 +1,25 @@ + +#include "wb.h" +#ifdef WB_USE_CUDA + +int _cudaMemoryListIdx = 0; + +size_t _cudaMallocSize = 0; + +wbCUDAMemory_t _cudaMemoryList[_cudaMemoryListSize]; + +char *wbRandom_list(size_t sz) { + size_t ii; + char *rands = wbNewArray(char, sz); + int *irands = (int *)rands; + for (ii = 0; ii < sz / sizeof(int); ii++) { + irands[ii] = rand(); + } + while (ii < sz) { + rands[ii] = (char)(rand() % 255); + ii++; + } + return rands; +} + +#endif /* WB_USE_CUDA */ diff --git a/CUDA_DeviceQuery/libwb/wbCUDA.h b/CUDA_DeviceQuery/libwb/wbCUDA.h new file mode 100644 index 0000000..658ff39 --- /dev/null +++ b/CUDA_DeviceQuery/libwb/wbCUDA.h @@ -0,0 +1,77 @@ + +#ifndef __WB_CUDA_H__ +#define __WB_CUDA_H__ + +#ifdef WB_USE_CUDA +#ifdef __PGI +#define __GNUC__ 4 +#endif /* __PGI */ +#include +#include + +typedef struct st_wbCUDAMemory_t { + void *mem; + size_t sz; +} wbCUDAMemory_t; + +#define _cudaMemoryListSize 1024 + +extern size_t _cudaMallocSize; +extern wbCUDAMemory_t _cudaMemoryList[]; +extern int _cudaMemoryListIdx; + +char *wbRandom_list(size_t sz); + +static inline cudaError_t wbCUDAMalloc(void **devPtr, size_t sz) { + int idx = _cudaMemoryListIdx; + + cudaError_t err = cudaMalloc(devPtr, sz); + + if (idx == 0) { + srand(time(NULL)); + memset(_cudaMemoryList, 0, + sizeof(wbCUDAMemory_t) * _cudaMemoryListSize); + } + + if (err == cudaSuccess) { +#if 0 + char * rands = wbRandom_list(sz); + // can use curand here, but do not want to invoke a kernel + err = cudaMemcpy(*devPtr, rands, sz, cudaMemcpyHostToDevice); + wbFree(rands); +#else + err = cudaMemset(*devPtr, 0, sz); +#endif + } + + _cudaMallocSize += sz; + _cudaMemoryList[idx].mem = *devPtr; + _cudaMemoryList[idx].sz = sz; + _cudaMemoryListIdx++; + return err; +} + +static inline cudaError_t wbCUDAFree(void *mem) { + int idx = _cudaMemoryListIdx; + if (idx == 0) { + memset(_cudaMemoryList, 0, + sizeof(wbCUDAMemory_t) * _cudaMemoryListSize); + } + for (int ii = 0; ii < idx; ii++) { + if (_cudaMemoryList[ii].mem != NULL && + _cudaMemoryList[ii].mem == mem) { + cudaError_t err = cudaFree(mem); + _cudaMallocSize -= _cudaMemoryList[ii].sz; + _cudaMemoryList[ii].mem = NULL; + return err; + } + } + return cudaErrorMemoryAllocation; +} + +#define cudaMalloc(elem, err) wbCUDAMalloc((void **)elem, err) +#define cudaFree wbCUDAFree + +#endif /* WB_USE_CUDA */ + +#endif /* __WB_CUDA_H__ */ diff --git a/CUDA_DeviceQuery/libwb/wbCast.h b/CUDA_DeviceQuery/libwb/wbCast.h new file mode 100644 index 0000000..01e8387 --- /dev/null +++ b/CUDA_DeviceQuery/libwb/wbCast.h @@ -0,0 +1,29 @@ + + +#ifndef __WB_CAST_H__ +#define __WB_CAST_H__ + +template +static inline void wbCast(X &x, const Y &y, size_t len) { + size_t ii; + + for (ii = 0; ii < len; ii++) { + x[ii] = (X)y[ii]; + } + + return; +} + +template +static inline X *wbCast(const Y &y, size_t len) { + size_t ii; + X *x = wbNewArray(X, len); + + for (ii = 0; ii < len; ii++) { + x[ii] = (X)y[ii]; + } + + return x; +} + +#endif /* __WB_CAST_H__ */ diff --git a/CUDA_DeviceQuery/libwb/wbComparator.h b/CUDA_DeviceQuery/libwb/wbComparator.h new file mode 100644 index 0000000..26fd0cb --- /dev/null +++ b/CUDA_DeviceQuery/libwb/wbComparator.h @@ -0,0 +1,187 @@ + + +#ifndef __WB_COMPARATOR_H__ +#define __WB_COMPARATOR_H__ + +#include "wb.h" + +template +static inline T _abs(const T &a) { + return a < 0 ? -a : a; +} + +static inline wbBool _almostEqual(double A, double B, double eps) { + if (A == 0) { + return _abs(B) < eps; + } else if (B == 0) { + return _abs(A) < eps; + } else { +#if 0 + double d = max(_abs(A), _abs(B)); + double g = (_abs(A - B) / d); +#else + double g = _abs(A - B); +#endif + if (g <= eps) { + return wbTrue; + } else { + return wbFalse; + } + } +} + +static inline wbBool _almostEqual(float A, float B, float eps) { + if (A == 0) { + return _abs(B) < eps; + } else if (B == 0) { + return _abs(A) < eps; + } else { +#if 0 + float d = max(_abs(A), _abs(B)); + float g = (_abs(A - B) / d); +#else + float g = _abs(A - B); +#endif + if (g <= eps) { + return wbTrue; + } else { + return wbFalse; + } + } +} + +static inline wbBool _almostEqual(double A, double B) { + return _almostEqual(A, B, 0.2); +} + +static inline wbBool _almostEqual(float A, float B) { + return _almostEqual(A, B, 0.2f); +} + +static inline wbBool _almostEqual2sComplement(float A, float B, + int maxUlps) { + // Make sure maxUlps is non-negative and small enough that the + // default NAN won't compare as equal to anything. + + int aInt, bInt, intDiff; + + wbAssert(maxUlps > 0 && maxUlps < 4 * 1024 * 1024); + + int *tmp = reinterpret_cast(&A); + aInt = *tmp; + + // Make aInt lexicographically ordered as a twos-complement int + if (aInt < 0) { + aInt = 0x80000000 - aInt; + } + // Make bInt lexicographically ordered as a twos-complement int + tmp = reinterpret_cast(&B); + bInt = *tmp; + if (bInt < 0) { + bInt = 0x80000000 - bInt; + } + intDiff = _abs(aInt - bInt); + if (intDiff <= maxUlps) { + return wbTrue; + } + return wbFalse; +} + +static inline wbBool _almostEqual2sComplement(float A, float B) { + return _almostEqual2sComplement(A, B, 4); +} + +static inline wbBool _almostEqual2sComplement(double A, double B, + int maxUlps) { + // Make sure maxUlps is non-negative and small enough that the + // default NAN won't compare as equal to anything. + + int64_t aInt, bInt, intDiff; + + wbAssert(maxUlps > 0 && maxUlps < 4 * 1024 * 1024); + + int64_t *tmp = reinterpret_cast(&A); + aInt = *tmp; + + // Make aInt lexicographically ordered as a twos-complement int + if (aInt < 0) { + aInt = 0x80000000 - aInt; + } + // Make bInt lexicographically ordered as a twos-complement int + tmp = reinterpret_cast(&B); + bInt = *tmp; + if (bInt < 0) { + bInt = 0x80000000 - bInt; + } + intDiff = _abs(aInt - bInt); + if (intDiff <= maxUlps) { + return wbTrue; + } + return wbFalse; +} + +static inline wbBool _almostEqual2sComplement(double A, double B) { + return _almostEqual2sComplement(A, B, 4); +} + +template +static inline int wbCompare(const T &a, const T &b) { + if (a == b) { + return 0; + } else if (a < b) { + return -1; + } else { + return 1; + } +} + +template <> +inline int wbCompare(const double &a, const double &b) { + if (_almostEqual(a, b)) { + return 0; + } else if (a < b) { + return -1; + } else { + return 1; + } +} + +template <> +inline int wbCompare(const float &a, const float &b) { + if (_almostEqual(a, b)) { + return 0; + } else if (a < b) { + return -1; + } else { + return 1; + } +} + +template +static inline wbBool wbEqualQ(const T &a, const T &b) { + return wbCompare(a, b) == 0; +} + +template +static inline wbBool wbUnequalQ(const T &a, const T &b) { + return wbCompare(a, b) != 0; +} + +template +static inline wbBool wbEqualQ(const T *a, const T *b, size_t n) { + size_t ii; + + for (ii = 0; ii < n; ii++) { + if (wbUnequalQ(a[ii], b[ii])) { + return wbFalse; + } + } + return wbTrue; +} + +template +static inline wbBool wbUnequalQ(const T *a, const T *b, size_t n) { + return !wbEqualQ(a, b, n); +} + +#endif /* __WB_COMPARATOR_H__ */ diff --git a/CUDA_DeviceQuery/libwb/wbDataset.cpp b/CUDA_DeviceQuery/libwb/wbDataset.cpp new file mode 100644 index 0000000..a11f064 --- /dev/null +++ b/CUDA_DeviceQuery/libwb/wbDataset.cpp @@ -0,0 +1,177 @@ +#include "wb.h" + +template +static inline T _min(const T &x, const T &y) { + return x < y ? x : y; +} + +template +static inline T _max(const T &x, const T &y) { + return x > y ? x : y; +} + +template +inline T lerp(const double &x, const T &start, const T &end) { + return (1 - x) * start + x * end; +} + +static inline void genRandom(void *trgt, wbType_t type, double minVal, + double maxVal) { + const int span = maxVal - minVal; + const int r = rand(); + const double rf = ((double)r) / ((double)RAND_MAX); + switch (type) { + case wbType_ascii: + *((char *)trgt) = (r % span) + minVal; // random printable character; + break; + case wbType_bit8: + *((char *)trgt) = lerp(rf, minVal, maxVal); + break; + case wbType_ubit8: + *((unsigned char *)trgt) = lerp(rf, minVal, maxVal); + break; + case wbType_integer: + *((int *)trgt) = lerp(rf, minVal, maxVal); + break; + case wbType_float: { + *((float *)trgt) = lerp(rf, minVal, maxVal); + break; + } + case wbType_double: { + *((double *)trgt) = lerp(rf, minVal, maxVal); + break; + } + case wbType_unknown: + wbAssert(false && "Invalid wbType_unknown"); + break; + } + return; +} + +static inline void *genRandomList(wbType_t type, size_t len, double minVal, + double maxVal) { + size_t ii; + void *data = wbNewArray(char, wbType_size(type) * len); + switch (type) { + case wbType_ascii: + case wbType_bit8: { + char *iter = (char *)data; + for (ii = 0; ii < len; ii++) { + genRandom(iter++, type, minVal, maxVal); + } + break; + } + case wbType_ubit8: { + unsigned char *iter = (unsigned char *)data; + for (ii = 0; ii < len; ii++) { + genRandom(iter++, type, minVal, maxVal); + } + break; + } + case wbType_integer: { + int *iter = (int *)data; + for (ii = 0; ii < len; ii++) { + genRandom(iter++, type, minVal, maxVal); + } + break; + } + case wbType_float: { + float *iter = (float *)data; + for (ii = 0; ii < len; ii++) { + genRandom(iter++, type, minVal, maxVal); + } + break; + } + case wbType_double: { + double *iter = (double *)data; + for (ii = 0; ii < len; ii++) { + genRandom(iter++, type, minVal, maxVal); + } + break; + } + case wbType_unknown: + wbAssert(false && "Invalid wbType_unknown"); + break; + } + return data; +} + +static void genRaw(const char *path, wbRaw_GenerateParams_t params) { + int rows = _max(1, params.rows); + int cols = _max(1, params.cols); + double minVal = params.minVal; + double maxVal = params.maxVal; + wbType_t type = params.type; + void *data = genRandomList(type, rows * cols, minVal, maxVal); + wbExport(path, wbExportKind_raw, data, rows, cols, type); + wbDelete(data); +} + +static void genCSV(const char *path, wbCSV_GenerateParams_t params) { + int rows = _max(1, params.rows); + int cols = _max(1, params.cols); + double minVal = params.minVal; + double maxVal = params.maxVal; + wbType_t type = params.type; + void *data = genRandomList(type, rows * cols, minVal, maxVal); + wbExport(path, wbExportKind_csv, data, rows, cols, type); + wbDelete(data); +} + +static void genTSV(const char *path, wbTSV_GenerateParams_t params) { + int rows = _max(1, params.rows); + int cols = _max(1, params.cols); + double minVal = params.minVal; + double maxVal = params.maxVal; + wbType_t type = params.type; + void *data = genRandomList(type, rows * cols, minVal, maxVal); + wbExport(path, wbExportKind_tsv, data, rows, cols, type); + wbDelete(data); +} + +static void genText(const char *path, wbText_GenerateParams_t params) { + int length = _max(1, params.length); + wbType_t type = wbType_ascii; + void *data = genRandomList(type, length, 32, 128); + wbExport(path, wbExportKind_text, data, length, 1, type); + wbDelete(data); +} + +static void genPPM(const char *path, wbPPM_GenerateParams_t params) { + int width = _max(1, params.width); + int height = _max(1, params.height); + int channels = _max(1, params.channels); + double minVal = params.minVal; + double maxVal = params.maxVal; + wbType_t type = wbType_float; + float *data = (float *)genRandomList(type, width * height * channels, + minVal, maxVal); + wbImage_t img = wbImage_new(width, height, channels, data); + wbExport(path, img); + wbImage_delete(img); +} + +EXTERN_C void wbDataset_generate(const char *path, wbExportKind_t kind, + wbGenerateParams_t params) { + wbDirectory_create(wbDirectory_name(path)); + + switch (kind) { + case wbExportKind_raw: + genRaw(path, params.raw); + break; + case wbExportKind_csv: + genCSV(path, params.csv); + break; + case wbExportKind_tsv: + genTSV(path, params.tsv); + break; + case wbExportKind_ppm: + genPPM(path, params.ppm); + break; + case wbExportKind_text: + genText(path, params.text); + break; + default: + wbAssert(false && "Invalid Export kind"); + } +} diff --git a/CUDA_DeviceQuery/libwb/wbDataset.h b/CUDA_DeviceQuery/libwb/wbDataset.h new file mode 100644 index 0000000..ce81c28 --- /dev/null +++ b/CUDA_DeviceQuery/libwb/wbDataset.h @@ -0,0 +1,52 @@ +#ifndef __WB_DATASET_H__ +#define __WB_DATASET_H__ + +#include "wbImport.h" +#include "wbTypes.h" + +typedef struct { + int rows; + int cols; + wbType_t type; + double minVal; + double maxVal; +} wbCSV_GenerateParams_t; + +typedef struct { + int rows; + int cols; + wbType_t type; + double minVal; + double maxVal; +} wbTSV_GenerateParams_t; + +typedef struct { + int rows; + int cols; + double minVal; + double maxVal; + wbType_t type; +} wbRaw_GenerateParams_t; + +typedef struct { + int width; + int height; + int channels; + double minVal; + double maxVal; +} wbPPM_GenerateParams_t; + +typedef struct { int length; } wbText_GenerateParams_t; + +typedef union { + wbCSV_GenerateParams_t csv; + wbRaw_GenerateParams_t raw; + wbTSV_GenerateParams_t tsv; + wbPPM_GenerateParams_t ppm; + wbText_GenerateParams_t text; +} wbGenerateParams_t; + +EXTERN_C void wbDataset_generate(const char *path, wbExportKind_t kind, + wbGenerateParams_t params); + +#endif /* __WB_DATASET_H__ */ diff --git a/CUDA_DeviceQuery/libwb/wbDataset_test.cpp b/CUDA_DeviceQuery/libwb/wbDataset_test.cpp new file mode 100644 index 0000000..4f08042 --- /dev/null +++ b/CUDA_DeviceQuery/libwb/wbDataset_test.cpp @@ -0,0 +1,23 @@ + +#include "wb.h" +#include "vendor/catch.hpp" + +TEST_CASE("Can create Raw dataset", "[DataGenerator]") { + wbGenerateParams_t params; + params.raw.rows = 2; + params.raw.cols = 300; + params.raw.minVal = 0; + params.raw.maxVal = 30; + params.raw.type = wbType_integer; + wbDataset_generate( + wbPath_join(wbDirectory_current(), "test-dataset", "test.raw"), + wbExportKind_raw, params); +} + +TEST_CASE("Can create Text dataset", "[DataGenerator]") { + wbGenerateParams_t params; + params.text.length = 2000; + wbDataset_generate( + wbPath_join(wbDirectory_current(), "test-dataset", "test.txt"), + wbExportKind_text, params); +} diff --git a/CUDA_DeviceQuery/libwb/wbDirectory.cpp b/CUDA_DeviceQuery/libwb/wbDirectory.cpp new file mode 100644 index 0000000..10dc8c5 --- /dev/null +++ b/CUDA_DeviceQuery/libwb/wbDirectory.cpp @@ -0,0 +1,88 @@ +#include "wb.h" + +#ifndef PATH_MAX +#ifdef FILENAME_MAX +#define PATH_MAX FILENAME_MAX +#else /* FILENAME_MAX */ +#define PATH_MAX 4096 +#endif /* FILENAME_MAX */ +#endif /* PATH_MAX */ + +#ifdef WB_USE_UNIX +const char wbDirectorySeperator = '/'; +static char *getcwd_(char *buf, int maxLen) { + return getcwd(buf, maxLen); +} +static void mkdir_(const char *dir) { + mkdir(dir, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); +} +#else /* WB_USE_LINUX */ +const char wbDirectorySeperator = '\\'; +static char *getcwd_(char *buf, int maxLen) { + return _getcwd(buf, maxLen); +} +static void mkdir_(const char *dir) { + _mkdir(dir); +} +#endif /* WB_USE_LINUX */ + +EXTERN_C const char * wbDirectory_create(const char *dir) { + char tmp[PATH_MAX]; + char *p = NULL; + size_t len; +//PMO +#ifndef _MSC_VER + snprintf(tmp, sizeof(tmp), "%s", dir); +#else + _snprintf_s(tmp, sizeof(tmp), "%s", dir); +#endif + len = strlen(tmp); + if (tmp[len - 1] == wbDirectorySeperator) { + tmp[len - 1] = 0; + } + for (p = tmp + 1; *p; p++) { + if (*p == wbDirectorySeperator) { + *p = 0; + mkdir_(tmp); + *p = wbDirectorySeperator; + } + } + mkdir_(tmp); + return dir; +} + +EXTERN_C char *wbDirectory_name(const char *pth0) { + char *pth = wbString_duplicate(pth0); + char *p = strrchr(pth, wbDirectorySeperator); + if (p) { + p[0] = 0; + } + return pth; +} + +EXTERN_C char *wbDirectory_current() { + char *tmp = wbNewArray(char, PATH_MAX + 1); + if (getcwd_(tmp, PATH_MAX)) { + return tmp; + } + + wbDelete(tmp); + + int error = errno; + switch (error) { + case EACCES: + std::cerr + << "Cannot get current directory :: access denied. exiting..." + << std::endl; + exit(-1); + case ENOMEM: + std::cerr << "Cannot get current directory :: insufficient storage. " + "exiting..." + << std::endl; + exit(-1); + default: + std::cerr << "Cannot get current directory :: unrecognised error " + << error << std::endl; + exit(-1); + } +} \ No newline at end of file diff --git a/CUDA_DeviceQuery/libwb/wbDirectory.h b/CUDA_DeviceQuery/libwb/wbDirectory.h new file mode 100644 index 0000000..cb14f81 --- /dev/null +++ b/CUDA_DeviceQuery/libwb/wbDirectory.h @@ -0,0 +1,9 @@ +#ifndef __WB_DIRECTORY__ +#define __WB_DIRECTORY__ + +extern const char wbDirectorySeperator; +EXTERN_C char *wbDirectory_name(const char *pth); +EXTERN_C const char * wbDirectory_create(const char *dir); +EXTERN_C char *wbDirectory_current(); + +#endif /* __WB_DIRECTORY__ */ diff --git a/CUDA_DeviceQuery/libwb/wbExit.cpp b/CUDA_DeviceQuery/libwb/wbExit.cpp new file mode 100644 index 0000000..a7edc3a --- /dev/null +++ b/CUDA_DeviceQuery/libwb/wbExit.cpp @@ -0,0 +1,119 @@ + +#include "wb.h" + +enum { + wbMPI_timerTag = 2, + wbMPI_loggerTag = 4, + wbMPI_solutionExistsTag = 8, + wbMPI_solutionTag = 16 +}; + +void wb_atExit(void) { + using std::cout; + using std::endl; + +#ifdef WB_USE_CUDA + cudaDeviceSynchronize(); +#endif /* WB_USE_CUDA */ + + int nranks = rankCount(); + if (nranks > 1) { +#ifdef WB_USE_MPI + if (isMasterQ) { +#ifdef wbLogger_printOnExit + cout << "==$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$" << endl; + + cout << "{\n"; + cout << wbString_quote("timer") << ":"; + cout << "[\n"; + for (int ii = 0; ii < nranks; ii++) { + if (ii == 0) { + cout << wbTimer_toJSON(); + } else { + const char *msg = wbMPI_getStringFromRank(ii, wbMPI_timerTag); + if (msg != NULL && strlen(msg) != 0) { + cout << ",\n"; + cout << msg; + // free(msg); + } + } + } + cout << "]" << endl; // close timer + + cout << "," << endl; // start logger + cout << wbString_quote("logger") << ":"; + cout << "[\n"; + for (int ii = 0; ii < nranks; ii++) { + if (ii == 0) { + cout << wbLogger_toJSON(); + } else { + const char *msg = wbMPI_getStringFromRank(ii, wbMPI_loggerTag); + if (msg != NULL && strlen(msg) != 0) { + cout << ",\n"; + cout << msg; + // free(msg); + } + } + } + cout << "]" << endl; // close logger + + cout << "," << endl; // start solutionExists + cout << wbString_quote("cuda_memory") << ":" << _cudaMallocSize + << ",\n"; + + if (solutionJSON) { + cout << wbString_quote("solution_exists") << ": true,\n"; + cout << wbString_quote("solution") << ":" << solutionJSON << "\n"; + } else { + cout << wbString_quote("solution_exists") << ": false\n"; + } + cout << "}" << endl; // close json + + } else { + wbMPI_sendStringToMaster(wbTimer_toJSON().c_str(), wbMPI_timerTag); + wbMPI_sendStringToMaster(wbLogger_toJSON().c_str(), wbMPI_loggerTag); + } +#endif /* wbLogger_printOnExit */ + +#endif /* WB_USE_MPI */ + } else { +#ifdef wbLogger_printOnExit + cout << "==$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$" << endl; + + cout << "{\n" << wbString_quote("timer") << ":[" << wbTimer_toJSON() + << "],\n" << wbString_quote("logger") << ":[" << wbLogger_toJSON() + << "],\n"; + +#ifdef WB_USE_CUDA + cout << wbString_quote("cuda_memory") << ":" << _cudaMallocSize + << ",\n"; +#endif /* WB_USE_CUDA */ + + if (solutionJSON) { + cout << wbString_quote("solution_exists") << ": true,\n"; + cout << wbString_quote("solution") << ":" << solutionJSON << "\n"; + } else { + cout << wbString_quote("solution_exists") << ": false\n"; + } + cout << "}" << endl; +#endif /* wbLogger_printOnExit */ + } + + // wbTimer_delete(_timer); + // wbLogger_delete(_logger); + + _timer = NULL; + _logger = NULL; + +// wbFile_atExit(); + +#ifdef WB_USE_CUDA + cudaDeviceReset(); +#endif + + exit(0); + + // assert(0); + + return; +} diff --git a/CUDA_DeviceQuery/libwb/wbExit.h b/CUDA_DeviceQuery/libwb/wbExit.h new file mode 100644 index 0000000..4400108 --- /dev/null +++ b/CUDA_DeviceQuery/libwb/wbExit.h @@ -0,0 +1,7 @@ + +#ifndef __WB_EXIT_H__ +#define __WB_EXIT_H__ + +void wb_atExit(void); + +#endif /* __WB_EXIT_H__ */ diff --git a/CUDA_DeviceQuery/libwb/wbExport.cpp b/CUDA_DeviceQuery/libwb/wbExport.cpp new file mode 100644 index 0000000..59b7a33 --- /dev/null +++ b/CUDA_DeviceQuery/libwb/wbExport.cpp @@ -0,0 +1,510 @@ + +#include "wb.h" + +static inline void wbExportText_setFile(wbExportText_t text, + const char *path) { + if (text != NULL) { + if (wbExportText_getFile(text) != NULL) { + wbFile_delete(wbExportText_getFile(text)); + } + if (path != NULL) { + wbExportText_getFile(text) = wbFile_open(path, "w+"); + } else { + wbExportText_getFile(text) = NULL; + } + } + + return; +} + +static inline wbExportText_t wbExportText_new(void) { + wbExportText_t text; + + text = wbNew(struct st_wbExportText_t); + + wbExportText_getFile(text) = NULL; + wbExportText_setLength(text, -1); + + return text; +} + +static inline void wbExportText_delete(wbExportText_t text) { + if (text != NULL) { + wbExportText_setFile(text, NULL); + wbDelete(text); + } + return; +} + +static inline void wbExportText_write(wbExportText_t text, + const char *data, int length) { + int ii; + FILE *handle; + wbFile_t file; + + if (text == NULL || wbExportText_getFile(text) == NULL) { + return; + } + + file = wbExportText_getFile(text); + + handle = wbFile_getFileHandle(file); + + if (handle == NULL) { + return; + } + + for (ii = 0; ii < length; ii++) { + fprintf(handle, "%c", data[ii]); + } + + return; +} + +static inline void wbExportRaw_setFile(wbExportRaw_t raw, + const char *path) { + if (raw != NULL) { + if (wbExportRaw_getFile(raw) != NULL) { + wbFile_delete(wbExportRaw_getFile(raw)); + } + if (path != NULL) { + wbExportRaw_getFile(raw) = wbFile_open(path, "w+"); + } else { + wbExportRaw_getFile(raw) = NULL; + } + } + + return; +} + +static inline wbExportRaw_t wbExportRaw_new(void) { + wbExportRaw_t raw; + + raw = wbNew(struct st_wbExportRaw_t); + + wbExportRaw_getFile(raw) = NULL; + wbExportRaw_setRowCount(raw, -1); + wbExportRaw_setColumnCount(raw, -1); + + return raw; +} + +static inline void wbExportRaw_delete(wbExportRaw_t raw) { + if (raw != NULL) { + wbExportRaw_setFile(raw, NULL); + wbDelete(raw); + } + return; +} + +static inline void wbExportRaw_write(wbExportRaw_t raw, void *data, + int rows, int columns, + wbType_t type) { + int ii, jj; + FILE *handle; + wbFile_t file; + + if (raw == NULL || wbExportRaw_getFile(raw) == NULL) { + return; + } + + file = wbExportRaw_getFile(raw); + + handle = wbFile_getFileHandle(file); + + if (handle == NULL) { + return; + } + + if (columns == 1) { + fprintf(handle, "%d\n", rows); + } else { + fprintf(handle, "%d %d\n", rows, columns); + } + + for (ii = 0; ii < rows; ii++) { + for (jj = 0; jj < columns; jj++) { + if (type == wbType_integer) { + int elem = ((int *)data)[ii * columns + jj]; + fprintf(handle, "%d", elem); + } else if (type == wbType_ubit8) { + int elem = ((unsigned char *)data)[ii * columns + jj]; + fprintf(handle, "%d", elem); + } else { + wbReal_t elem = ((wbReal_t *)data)[ii * columns + jj]; + fprintf(handle, "%f", elem); + } + if (jj == columns - 1) { + fprintf(handle, "\n"); + } else { + fprintf(handle, " "); + } + } + } + + return; +} + +static inline void wbExportCSV_setFile(wbExportCSV_t csv, + const char *path) { + if (csv != NULL) { + if (wbExportCSV_getFile(csv) != NULL) { + wbFile_delete(wbExportCSV_getFile(csv)); + } + if (path != NULL) { + wbExportCSV_getFile(csv) = wbFile_open(path, "w+"); + } else { + wbExportCSV_getFile(csv) = NULL; + } + } + + return; +} + +static inline wbExportCSV_t wbExportCSV_new(void) { + wbExportCSV_t csv; + + csv = wbNew(struct st_wbExportCSV_t); + + wbExportCSV_getFile(csv) = NULL; + wbExportCSV_setColumnCount(csv, -1); + wbExportCSV_setRowCount(csv, -1); + wbExportCSV_setSeperator(csv, '\0'); + + return csv; +} + +static inline void wbExportCSV_delete(wbExportCSV_t csv) { + if (csv != NULL) { + wbExportCSV_setFile(csv, NULL); + wbDelete(csv); + } +} + +static inline void wbExportCSV_write(wbExportCSV_t csv, void *data, + int rows, int columns, char sep, + wbType_t type) { + int ii, jj; + wbFile_t file; + FILE *handle; + char seperator[2]; + + if (csv == NULL || wbExportCSV_getFile(csv) == NULL) { + return; + } + + file = wbExportCSV_getFile(csv); + + handle = wbFile_getFileHandle(file); + + if (handle == NULL) { + return; + } + + if (sep == '\0') { + seperator[0] = ','; + } else { + seperator[0] = sep; + } + seperator[1] = '\0'; + + for (ii = 0; ii < rows; ii++) { + for (jj = 0; jj < columns; jj++) { + if (type == wbType_integer) { + int elem = ((int *)data)[ii * columns + jj]; + fprintf(handle, "%d", elem); + } else if (type == wbType_ubit8) { + int elem = ((unsigned char *)data)[ii * columns + jj]; + fprintf(handle, "%d", elem); + } else { + wbReal_t elem = ((wbReal_t *)data)[ii * columns + jj]; + fprintf(handle, "%f", elem); + } + if (jj == columns - 1) { + fprintf(handle, "\n"); + } else { + fprintf(handle, "%s", seperator); + } + } + } + + return; +} + +static inline wbExport_t wbExport_open(const char *file, + wbExportKind_t kind) { + wbExport_t exprt; + + if (file == NULL) { + wbLog(ERROR, "Go NULL for file value."); + wbExit(); + } + + wbExport_setFile(exprt, NULL); + wbExport_setKind(exprt, kind); + + if (kind == wbExportKind_raw) { + wbExportRaw_t raw = wbExportRaw_new(); + wbExportRaw_setFile(raw, file); + wbExport_setRaw(exprt, raw); + } else if (kind == wbExportKind_text) { + wbExportText_t txt = wbExportText_new(); + wbExportText_setFile(txt, file); + wbExport_setText(exprt, txt); + } else if (kind == wbExportKind_tsv || kind == wbExportKind_csv) { + wbExportCSV_t csv = wbExportCSV_new(); + if (kind == wbExportKind_csv) { + wbExportCSV_setSeperator(csv, ','); + } else { + wbExportCSV_setSeperator(csv, '\t'); + } + wbExportCSV_setFile(csv, file); + wbExport_setCSV(exprt, csv); + } else if (kind == wbExportKind_ppm) { + wbExport_setFile(exprt, wbString_duplicate(file)); + } else { + wbLog(ERROR, "Invalid export type."); + wbExit(); + } + + return exprt; +} + +static inline wbExport_t wbExport_open(const char *file, + const char *type0) { + wbExport_t exprt; + wbExportKind_t kind; + char *type; + + type = wbString_toLower(type0); + + if (wbString_sameQ(type, "csv")) { + kind = wbExportKind_csv; + } else if (wbString_sameQ(type, "tsv")) { + kind = wbExportKind_tsv; + } else if (wbString_sameQ(type, "raw") || wbString_sameQ(type, "dat")) { + kind = wbExportKind_raw; + } else if (wbString_sameQ(type, "ppm") || wbString_sameQ(type, "pbm")) { + kind = wbExportKind_ppm; + } else if (wbString_sameQ(type, "txt") || wbString_sameQ(type, "text")) { + kind = wbExportKind_text; + } else { + wbLog(ERROR, "Invalid export type ", type0); + wbExit(); + } + + exprt = wbExport_open(file, kind); + + wbDelete(type); + + return exprt; +} + +static inline void wbExport_close(wbExport_t exprt) { + wbExportKind_t kind; + + kind = wbExport_getKind(exprt); + + if (wbExport_getFile(exprt)) { + wbDelete(wbExport_getFile(exprt)); + } + + if (kind == wbExportKind_tsv || kind == wbExportKind_csv) { + wbExportCSV_t csv = wbExport_getCSV(exprt); + wbExportCSV_delete(csv); + wbExport_setCSV(exprt, NULL); + } else if (kind == wbExportKind_raw) { + wbExportRaw_t raw = wbExport_getRaw(exprt); + wbExportRaw_delete(raw); + wbExport_setRaw(exprt, NULL); + } else if (kind == wbExportKind_text) { + wbExportText_t text = wbExport_getText(exprt); + wbExportText_delete(text); + wbExport_setText(exprt, NULL); + } else if (kind == wbExportKind_ppm) { + } else { + wbLog(ERROR, "Invalid export type."); + wbExit(); + } + return; +} + +static inline void wbExport_writeAsImage(wbExport_t exprt, wbImage_t img) { + wbAssert(wbExport_getKind(exprt) == wbExportKind_ppm); + + wbPPM_export(wbExport_getFile(exprt), img); + + return; +} + +static inline void wbExport_write(wbExport_t exprt, void *data, int rows, + int columns, char sep, wbType_t type) { + wbExportKind_t kind; + + kind = wbExport_getKind(exprt); + if (kind == wbExportKind_tsv || kind == wbExportKind_csv) { + wbExportCSV_t csv = wbExport_getCSV(exprt); + wbExportCSV_write(csv, data, rows, columns, sep, type); + } else if (kind == wbExportKind_raw) { + wbExportRaw_t raw = wbExport_getRaw(exprt); + wbExportRaw_write(raw, data, rows, columns, type); + } else if (kind == wbExportKind_text) { + wbExportText_t text = wbExport_getText(exprt); + if (columns == 0) { + columns = 1; + } + if (rows == 0) { + rows = 1; + } + wbExportText_write(text, (const char *)data, rows * columns); + } else { + wbLog(ERROR, "Invalid export type."); + wbExit(); + } + return; +} + +static inline void wbExport_write(wbExport_t exprt, void *data, int rows, + int columns, wbType_t type) { + wbExport_write(exprt, data, rows, columns, ',', type); +} + +static wbExportKind_t _parseExportExtension(const char *file) { + char *extension; + wbExportKind_t kind; + + extension = wbFile_extension(file); + + if (wbString_sameQ(extension, "csv")) { + kind = wbExportKind_csv; + } else if (wbString_sameQ(extension, "tsv")) { + kind = wbExportKind_tsv; + } else if (wbString_sameQ(extension, "raw") || + wbString_sameQ(extension, "dat")) { + kind = wbExportKind_raw; + } else if (wbString_sameQ(extension, "text") || + wbString_sameQ(extension, "txt")) { + kind = wbExportKind_text; + } else if (wbString_sameQ(extension, "ppm")) { + kind = wbExportKind_ppm; + } else { + kind = wbExportKind_unknown; + wbLog(ERROR, "File ", file, " does not have a compatible extension."); + } + + wbDelete(extension); + + return kind; +} + +static void wbExport(const char *file, void *data, int rows, int columns, + wbType_t type) { + wbExportKind_t kind; + wbExport_t exprt; + + if (file == NULL) { + return; + } + + kind = _parseExportExtension(file); + exprt = wbExport_open(file, kind); + + wbExport_write(exprt, data, rows, columns, type); + wbExport_close(exprt); +} + +void wbExport(const char *file, unsigned char *data, int rows) { + wbExport(file, data, rows, 1); + return; +} + +void wbExport(const char *file, int *data, int rows) { + wbExport(file, data, rows, 1); + return; +} + +void wbExport(const char *file, wbReal_t *data, int rows) { + wbExport(file, data, rows, 1); + return; +} + +void wbExport(const char *file, unsigned char *data, int rows, + int columns) { + wbExportKind_t kind; + wbExport_t exprt; + + if (file == NULL) { + return; + } + + kind = _parseExportExtension(file); + exprt = wbExport_open(file, kind); + + wbExport_write(exprt, data, rows, columns, wbType_ubit8); + wbExport_close(exprt); +} + +void wbExport(const char *file, int *data, int rows, int columns) { + wbExportKind_t kind; + wbExport_t exprt; + + if (file == NULL) { + return; + } + + kind = _parseExportExtension(file); + exprt = wbExport_open(file, kind); + + wbExport_write(exprt, data, rows, columns, wbType_integer); + wbExport_close(exprt); +} + +void wbExport(const char *file, wbReal_t *data, int rows, int columns) { + wbExportKind_t kind; + wbExport_t exprt; + + if (file == NULL) { + return; + } + + kind = _parseExportExtension(file); + exprt = wbExport_open(file, kind); + + wbExport_write(exprt, data, rows, columns, wbType_real); + wbExport_close(exprt); +} + +void wbExport(const char *file, wbExportKind_t kind, void *data, int rows, + int columns, wbType_t type) { + wbExport_t exprt; + + if (file == NULL) { + return; + } + + exprt = wbExport_open(file, kind); + + wbExport_write(exprt, data, rows, columns, type); + wbExport_close(exprt); +} + +void wbExport(const char *file, wbImage_t img) { + wbExportKind_t kind; + wbExport_t exprt; + + if (file == NULL) { + return; + } + + kind = _parseExportExtension(file); + exprt = wbExport_open(file, kind); + + wbAssert(kind == wbExportKind_ppm); + + wbExport_writeAsImage(exprt, img); + wbExport_close(exprt); +} + +void wbExport_text(const char *file, void *data, int length) { + wbExport(file, wbExportKind_text, data, 1, length, wbType_ascii); +} diff --git a/CUDA_DeviceQuery/libwb/wbExport.h b/CUDA_DeviceQuery/libwb/wbExport.h new file mode 100644 index 0000000..dd16b3f --- /dev/null +++ b/CUDA_DeviceQuery/libwb/wbExport.h @@ -0,0 +1,106 @@ + + +#ifndef __WB_EXPORT_H__ +#define __WB_EXPORT_H__ + +#include "wb.h" +#include "wbFile.h" +#include "wbPPM.h" + +typedef enum en_wbExportKind_t { + wbExportKind_unknown = -1, + wbExportKind_raw = 0x1000, + wbExportKind_csv, + wbExportKind_tsv, + wbExportKind_ppm, + wbExportKind_text, +} wbExportKind_t; + +typedef struct st_wbExportText_t { + int length; + wbFile_t file; +} * wbExportText_t; + +#define wbExportText_getLength(txt) ((txt)->length) +#define wbExportText_getFile(txt) ((txt)->file) + +#define wbExportText_setLength(txt, val) \ + (wbExportText_getLength(txt) = val) + +typedef struct st_wbExportRaw_t { + int rows; + int columns; + wbFile_t file; +} * wbExportRaw_t; + +#define wbExportRaw_getColumnCount(raw) ((raw)->columns) +#define wbExportRaw_getRowCount(raw) ((raw)->rows) +#define wbExportRaw_getFile(raw) ((raw)->file) + +#define wbExportRaw_setRowCount(raw, val) \ + (wbExportRaw_getRowCount(raw) = val) +#define wbExportRaw_setColumnCount(raw, val) \ + (wbExportRaw_getColumnCount(raw) = val) + +typedef struct st_wbExportCSV_t { + int rows; + int columns; + wbFile_t file; + char seperator; +} * wbExportCSV_t; + +#define wbExportCSV_getRowCount(csv) ((csv)->rows) +#define wbExportCSV_getColumnCount(csv) ((csv)->columns) +#define wbExportCSV_getFile(csv) ((csv)->file) +#define wbExportCSV_getSeperator(csv) ((csv)->seperator) + +#define wbExportCSV_setRowCount(csv, val) \ + (wbExportCSV_getRowCount(csv) = val) +#define wbExportCSV_setColumnCount(csv, val) \ + (wbExportCSV_getColumnCount(csv) = val) +#define wbExportCSV_setSeperator(csv, val) \ + (wbExportCSV_getSeperator(csv) = val) + +typedef struct st_wbExport_t { + wbExportKind_t kind; + union { + wbExportRaw_t raw; + wbExportCSV_t csv; + wbImage_t img; + wbExportText_t text; + } container; + char *file; +} wbExport_t; + +#define wbExport_getKind(exprt) ((exprt).kind) +#define wbExport_getContainer(exprt) ((exprt).container) +#define wbExport_getRaw(exprt) (wbExport_getContainer(exprt).raw) +#define wbExport_getCSV(exprt) (wbExport_getContainer(exprt).csv) +#define wbExport_getImage(exprt) (wbExport_getContainer(exprt).img) +#define wbExport_getText(exprt) (wbExport_getContainer(exprt).text) +#define wbExport_getFile(exprt) ((exprt).file) + +#define wbExport_setKind(exprt, val) (wbExport_getKind(exprt) = val) +#define wbExport_setRaw(exprt, val) (wbExport_getRaw(exprt) = val) +#define wbExport_setCSV(exprt, val) (wbExport_getCSV(exprt) = val) +#define wbExport_setImage(exprt, val) (wbExport_getImage(exprt) = val) +#define wbExport_setText(exprt, val) (wbExport_getText(exprt) = val) +#define wbExport_setFile(exprt, val) (wbExport_getFile(exprt) = val) + +void wbExport(const char *file, int *data, int rows, int columns); +void wbExport(const char *file, int *data, int rows); +void wbExport(const char *file, unsigned char *data, int rows, + int columns); +void wbExport(const char *file, unsigned char *data, int rows); +void wbExport(const char *file, int *data, int rows, int columns); +void wbExport(const char *file, int *data, int rows); +void wbExport(const char *file, wbReal_t *data, int rows, int columns); +void wbExport(const char *file, wbReal_t *data, int rows); +void wbExport(const char *file, wbImage_t img); + +void wbExport(const char *file, wbExportKind_t kind, void *data, int rows, + int columns, wbType_t type); + +void wbExport_text(const char *file, void *data, int length); + +#endif /* __WB_EXPORT_H__ */ diff --git a/CUDA_DeviceQuery/libwb/wbFile.cpp b/CUDA_DeviceQuery/libwb/wbFile.cpp new file mode 100644 index 0000000..b3fdbe7 --- /dev/null +++ b/CUDA_DeviceQuery/libwb/wbFile.cpp @@ -0,0 +1,353 @@ + + +#include "wb.h" + +#define wbFile_maxCount 256 + +static wbFile_t wbFile_handles[wbFile_maxCount]; + +static int wbFile_nextIndex(void) { + int ii; + for (ii = 0; ii < wbFile_maxCount; ii++) { + if (wbFile_handles[ii] == NULL) { + return ii; + } + } + wbLog(ERROR, "Ran out of file handles."); + wbExit(); + return -1; +} + +wbFile_t wbFile_new(void) { + int idx = wbFile_nextIndex(); + wbFile_t file = wbNew(struct st_wbFile_t); + + wbAssert(idx >= 0); + + wbFile_setIndex(file, idx); + wbFile_setFileName(file, NULL); + wbFile_setMode(file, NULL); + wbFile_setFileHandle(file, NULL); + wbFile_setData(file, NULL); + + wbFile_handles[idx] = file; + + return file; +} + +void wbFile_delete(wbFile_t file) { + if (file != NULL) { + int idx = wbFile_getIndex(file); + if (wbFile_getFileName(file) != NULL) { + wbDelete(wbFile_getFileName(file)); + } + if (wbFile_getMode(file) != NULL) { + wbDelete(wbFile_getMode(file)); + } + if (wbFile_getFileHandle(file) != NULL) { + fflush(wbFile_getFileHandle(file)); + fclose(wbFile_getFileHandle(file)); + } + if (idx >= 0) { + wbAssert(wbFile_handles[idx] == file); + wbFile_handles[idx] = NULL; + } + if (wbFile_getData(file) != NULL) { + wbDelete(wbFile_getData(file)); + } + wbDelete(file); + } +} + +void wbFile_init(void) { + int ii; + + for (ii = 0; ii < wbFile_maxCount; ii++) { + wbFile_handles[ii] = NULL; + } +} + +void wbFile_atExit(void) { + int ii; + + for (ii = 0; ii < wbFile_maxCount; ii++) { + if (wbFile_handles[ii] != NULL) { + wbFile_delete(wbFile_handles[ii]); + } + } +} + +int wbFile_count(void) { + int ii, count = 0; + + for (ii = 0; ii < wbFile_maxCount; ii++) { + if (wbFile_handles[ii] != NULL) { + count++; + } + } + return count; +} + +wbFile_t wbFile_open(const char *fileName, const char *mode) { + FILE *handle; + wbFile_t file; + + if (fileName == NULL) { + return NULL; + } + + handle = fopen(fileName, mode); + if (handle == NULL) { + wbLog(ERROR, "Failed to open ", file, " in mode ", mode); + return NULL; + } + + file = wbFile_new(); + wbFile_setFileName(file, wbString_duplicate(fileName)); + wbFile_setMode(file, wbString_duplicate(mode)); + wbFile_setFileHandle(file, handle); + + return file; +} + +wbFile_t wbFile_open(const char *fileName) { + return wbFile_open(fileName, "r"); +} + +void wbFile_close(wbFile_t file) { + wbFile_delete(file); +} + +char *wbFile_read(wbFile_t file, size_t size, size_t count) { + size_t res; + char *buffer; + size_t bufferLen; + FILE *handle; + + if (file == NULL) { + return NULL; + } +#ifndef LAZY_FILE_LOAD + if (wbFile_getData(file) != NULL) { + char *data = wbFile_getData(file) + wbFile_getDataOffset(file); + wbFile_setDataOffset(file, wbFile_getDataOffset(file) + size * count); + return data; + } +#endif /* LAZY_FILE_LOAD */ + + handle = wbFile_getFileHandle(file); + bufferLen = size * count + 1; + buffer = wbNewArray(char, bufferLen); + + res = fread(buffer, size, count, handle); + // make valid C string + buffer[size * res] = '\0'; + + return buffer; +} + +char *wbFile_read(wbFile_t file, size_t len) { + char *buffer = wbFile_read(file, sizeof(char), len); + return buffer; +} + +void wbFile_rewind(wbFile_t file) { + if (file == NULL) { + return; + } + + if (wbFile_getData(file) == NULL) { + FILE *handle; + handle = wbFile_getFileHandle(file); + wbAssert(handle != NULL); + rewind(handle); + } +#ifndef LAZY_FILE_LOAD + else { + wbFile_setDataOffset(file, 0); + } +#endif + + return; +} + +size_t wbFile_size(wbFile_t file) { + size_t len; + FILE *handle; + + if (file == NULL) { + return 0; + } +#ifndef LAZY_FILE_LOAD + if (wbFile_getData(file) != NULL) { + if (wbFile_getLength(file) == 0) { + wbFile_setLength(file, strlen(wbFile_getData(file))); + } + return wbFile_getLength(file); + } +#endif /* LAZY_FILE_LOAD */ + + handle = wbFile_getFileHandle(file); + + fseek(handle, 0, SEEK_END); + len = ftell(handle); + rewind(handle); + + return len; +} + +char *wbFile_read(wbFile_t file) { + size_t len; + + if (file == NULL) { + return NULL; + } + + len = wbFile_size(file); + + if (len == 0) { + return NULL; + } + + wbFile_setLength(file, len); + + return wbFile_read(file, len); +} + +#define MAX_CHARS_PER_LINE (1 << 17) + +static char buffer[MAX_CHARS_PER_LINE]; + +char *wbFile_readLine(wbFile_t file) { + if (file == NULL) { + return NULL; + } +#ifdef LAZY_FILE_LOAD + FILE *handle; + memset(buffer, 0, MAX_CHARS_PER_LINE); + + handle = wbFile_getFileHandle(file); + + if (fgets(buffer, MAX_CHARS_PER_LINE - 1, handle)) { + return buffer; + } else { + // wbLog(ERROR, "Was not able to read line from ", + // wbFile_getFileName(file)); + return NULL; + } +#else + size_t newOffset; + size_t lenToNewLine = 0; + const char *tmp; + + if (wbFile_getData(file) == NULL) { + wbFile_setData(file, wbFile_read(file)); + fclose(wbFile_getFileHandle(file)); + wbFile_setFileHandle(file, NULL); + wbFile_setDataOffset(file, 0); + wbFile_setLength(file, strlen(wbFile_getData(file))); + } + + memset(buffer, 0, MAX_CHARS_PER_LINE); + + if (wbFile_getDataOffset(file) >= wbFile_getLength(file)) { + return NULL; + } + + newOffset = wbFile_getDataOffset(file); + tmp = wbFile_getData(file) + wbFile_getDataOffset(file); + while (newOffset < wbFile_getLength(file) && *tmp != '\n') { + tmp++; + lenToNewLine++; + newOffset++; + } + + memcpy(buffer, wbFile_getData(file) + wbFile_getDataOffset(file), + lenToNewLine); + wbFile_setDataOffset(file, newOffset + 1); + + return buffer; +#endif +} + +void wbFile_write(wbFile_t file, const void *buffer, size_t size, + size_t count) { + size_t res; + FILE *handle; + + if (file == NULL) { + return; + } + + handle = wbFile_getFileHandle(file); + + res = fwrite(buffer, size, count, handle); + if (res != count) { + wbLog(ERROR, "Failed to write data to ", wbFile_getFileName(file)); + } + + return; +} + +void wbFile_write(wbFile_t file, const void *buffer, size_t len) { + wbFile_write(file, buffer, sizeof(char), len); + return; +} + +void wbFile_write(wbFile_t file, const char *buffer) { + size_t len; + + len = strlen(buffer); + wbFile_write(file, buffer, len); + + return; +} + +void wbFile_writeLine(wbFile_t file, const char *buffer0) { + string buffer = wbString(buffer0, "\n"); + wbFile_write(file, buffer.c_str()); +} + +void wbFile_write(wbFile_t file, string buffer) { + wbFile_write(file, buffer.c_str()); +} + +void wbFile_writeLine(wbFile_t file, string buffer0) { + string buffer = buffer0 + "\n"; + wbFile_write(file, buffer.c_str()); +} + +wbBool wbFile_existsQ(const char *path) { + if (path == NULL) { + return wbFalse; + } else { + FILE *file = fopen(path, "r"); + if (file != NULL) { + fclose(file); + return wbTrue; + } + return wbFalse; + } +} + +char *wbFile_extension(const char *file) { + char *extension; + char *extensionLower; + char *end; + size_t len; + + len = strlen(file); + end = (char *)&file[len - 1]; + while (*end != '.') { + end--; + } + if (*end == '.') { + end++; + } + + extension = wbString_duplicate(end); + extensionLower = wbString_toLower(extension); + wbDelete(extension); + + return extensionLower; +} diff --git a/CUDA_DeviceQuery/libwb/wbFile.h b/CUDA_DeviceQuery/libwb/wbFile.h new file mode 100644 index 0000000..ea6b0cb --- /dev/null +++ b/CUDA_DeviceQuery/libwb/wbFile.h @@ -0,0 +1,56 @@ + + +#ifndef __WB_FILE_H__ +#define __WB_FILE_H__ + +struct st_wbFile_t { + int index; + char *file; + char *mode; + char *data; + FILE *handle; + size_t len; + size_t offset; +}; + +#define wbFile_getIndex(file) ((file)->index) +#define wbFile_getFileName(file) ((file)->file) +#define wbFile_getMode(file) ((file)->mode) +#define wbFile_getData(file) ((file)->data) +#define wbFile_getLength(file) ((file)->len) +#define wbFile_getDataOffset(file) ((file)->offset) +#define wbFile_getFileHandle(file) ((file)->handle) + +#define wbFile_setIndex(file, val) (wbFile_getIndex(file) = val) +#define wbFile_setFileName(file, val) (wbFile_getFileName(file) = val) +#define wbFile_setMode(file, val) (wbFile_getMode(file) = val) +#define wbFile_setData(file, val) (wbFile_getData(file) = val) +#define wbFile_setLength(file, val) (wbFile_getLength(file) = val) +#define wbFile_setDataOffset(file, val) (wbFile_getDataOffset(file) = val) +#define wbFile_setFileHandle(file, val) (wbFile_getFileHandle(file) = val) + +wbFile_t wbFile_new(void); +void wbFile_delete(wbFile_t file); +void wbFile_close(wbFile_t file); +void wbFile_init(void); +void wbFile_atExit(void); +int wbFile_count(void); +wbFile_t wbFile_open(const char *fileName, const char *mode); +wbFile_t wbFile_open(const char *fileName); +char *wbFile_read(wbFile_t file, size_t size, size_t count); +char *wbFile_read(wbFile_t file, size_t len); +void wbFile_rewind(wbFile_t file); +size_t wbFile_size(wbFile_t file); +char *wbFile_read(wbFile_t file); +char *wbFile_readLine(wbFile_t file); +void wbFile_write(wbFile_t file, const void *buffer, size_t size, + size_t count); +void wbFile_write(wbFile_t file, const void *buffer, size_t len); +void wbFile_write(wbFile_t file, const char *buffer); +void wbFile_writeLine(wbFile_t file, const char *buffer0); +void wbFile_write(wbFile_t file, string buffer); +void wbFile_writeLine(wbFile_t file, string buffer0); +wbBool wbFile_existsQ(const char *path); +char *wbFile_extension(const char *file); + +#endif /* __WB_FILE_H__ */ diff --git a/CUDA_DeviceQuery/libwb/wbImage.cpp b/CUDA_DeviceQuery/libwb/wbImage.cpp new file mode 100644 index 0000000..1d95928 --- /dev/null +++ b/CUDA_DeviceQuery/libwb/wbImage.cpp @@ -0,0 +1,134 @@ + + +#include "wb.h" + +static inline float _min(float x, float y) { + return x < y ? x : y; +} + +static inline float _max(float x, float y) { + return x > y ? x : y; +} + +static inline float _clamp(float x, float start, float end) { + return _min(_max(x, start), end); +} + +wbImage_t wbImage_new(int width, int height, int channels, float *data) { + wbImage_t img; + + img = wbNew(struct st_wbImage_t); + + wbImage_setWidth(img, width); + wbImage_setHeight(img, height); + wbImage_setChannels(img, channels); + wbImage_setPitch(img, width * channels); + + wbImage_setData(img, data); + return img; +} + +wbImage_t wbImage_new(int width, int height, int channels) { + float *data = wbNewArray(float, width *height *channels); + return wbImage_new(width, height, channels, data); +} + +wbImage_t wbImage_new(int width, int height) { + return wbImage_new(width, height, wbImage_channels); +} + +void wbImage_delete(wbImage_t img) { + if (img != NULL) { + if (wbImage_getData(img) != NULL) { + wbDelete(wbImage_getData(img)); + } + wbDelete(img); + } +} + +static inline void wbImage_setPixel(wbImage_t img, int x, int y, int c, + float val) { + float *data = wbImage_getData(img); + int channels = wbImage_getChannels(img); + int pitch = wbImage_getPitch(img); + + data[y * pitch + x * channels + c] = val; + + return; +} + +static inline float wbImage_getPixel(wbImage_t img, int x, int y, int c) { + float *data = wbImage_getData(img); + int channels = wbImage_getChannels(img); + int pitch = wbImage_getPitch(img); + + return data[y * pitch + x * channels + c]; +} + +wbBool wbImage_sameQ(wbImage_t a, wbImage_t b, + wbImage_onSameFunction_t onUnSame) { + if (a == NULL || b == NULL) { + wbLog(ERROR, "Comparing null images."); + return wbFalse; + } else if (a == b) { + return wbTrue; + } else if (wbImage_getWidth(a) != wbImage_getWidth(b)) { + wbLog(ERROR, "Image widths do not match."); + return wbFalse; + } else if (wbImage_getHeight(a) != wbImage_getHeight(b)) { + wbLog(ERROR, "Image heights do not match."); + return wbFalse; + } else if (wbImage_getChannels(a) != wbImage_getChannels(b)) { + wbLog(ERROR, "Image channels do not match."); + return wbFalse; + } else { + float *aData, *bData; + int width, height, channels; + int ii, jj, kk; + + aData = wbImage_getData(a); + bData = wbImage_getData(b); + + wbAssert(aData != NULL); + wbAssert(bData != NULL); + + width = wbImage_getWidth(a); + height = wbImage_getHeight(a); + channels = wbImage_getChannels(a); + + for (ii = 0; ii < height; ii++) { + for (jj = 0; jj < width; jj++) { + for (kk = 0; kk < channels; kk++) { + float x, y; + if (channels <= 3) { + x = _clamp(*aData++, 0, 1); + y = _clamp(*bData++, 0, 1); + } else { + x = *aData++; + y = *bData++; + } + if (wbUnequalQ(x, y)) { + if (onUnSame != NULL) { + string str = wbString( + "Image pixels do not match at position ( row = ", + wbString(ii, ", col = ", jj, ", channel = ", kk, + ") expecting a value of "), + wbString(y, " but got a computed value of ", x)); + onUnSame(str); + } + return wbFalse; + } + } + } + } + return wbTrue; + } +} + +static void wbImage_onUnsameFunction(string str) { + wbLog(ERROR, str); +} + +wbBool wbImage_sameQ(wbImage_t a, wbImage_t b) { + return wbImage_sameQ(a, b, wbImage_onUnsameFunction); +} diff --git a/CUDA_DeviceQuery/libwb/wbImage.h b/CUDA_DeviceQuery/libwb/wbImage.h new file mode 100644 index 0000000..020eec5 --- /dev/null +++ b/CUDA_DeviceQuery/libwb/wbImage.h @@ -0,0 +1,40 @@ + + +#ifndef __IMAGE_H__ +#define __IMAGE_H__ + +#include "wbTypes.h" + +struct st_wbImage_t { + int width; + int height; + int channels; + int pitch; + float *data; +}; + +#define wbImage_channels 3 + +#define wbImage_getWidth(img) ((img)->width) +#define wbImage_getHeight(img) ((img)->height) +#define wbImage_getChannels(img) ((img)->channels) +#define wbImage_getPitch(img) ((img)->pitch) +#define wbImage_getData(img) ((img)->data) + +#define wbImage_setWidth(img, val) (wbImage_getWidth(img) = val) +#define wbImage_setHeight(img, val) (wbImage_getHeight(img) = val) +#define wbImage_setChannels(img, val) (wbImage_getChannels(img) = val) +#define wbImage_setPitch(img, val) (wbImage_getPitch(img) = val) +#define wbImage_setData(img, val) (wbImage_getData(img) = val) + +typedef void (*wbImage_onSameFunction_t)(string str); + +wbImage_t wbImage_new(int width, int height, int channels, float *data); +wbImage_t wbImage_new(int width, int height, int channels); +wbImage_t wbImage_new(int width, int height); +void wbImage_delete(wbImage_t img); +wbBool wbImage_sameQ(wbImage_t a, wbImage_t b, + wbImage_onSameFunction_t onUnSame); +wbBool wbImage_sameQ(wbImage_t a, wbImage_t b); + +#endif /* __IMAGE_H__ */ diff --git a/CUDA_DeviceQuery/libwb/wbImport.cpp b/CUDA_DeviceQuery/libwb/wbImport.cpp new file mode 100644 index 0000000..fccc071 --- /dev/null +++ b/CUDA_DeviceQuery/libwb/wbImport.cpp @@ -0,0 +1,711 @@ + + +#include "wb.h" + +static inline void wbImportCSV_setFile(wbImportCSV_t csv, + const char *path) { + if (csv != NULL) { + if (wbImportCSV_getFile(csv) != NULL) { + wbFile_delete(wbImportCSV_getFile(csv)); + } + if (path != NULL) { + wbImportCSV_getFile(csv) = wbFile_open(path, "r"); + } else { + wbImportCSV_getFile(csv) = NULL; + } + } + + return; +} + +static inline wbImportCSV_t wbImportCSV_new(void) { + wbImportCSV_t csv; + + csv = wbNew(struct st_wbImportCSV_t); + + wbImportCSV_setRowCount(csv, -1); + wbImportCSV_setColumnCount(csv, -1); + wbImportCSV_setData(csv, NULL); + wbImportCSV_getFile(csv) = NULL; + wbImportCSV_setSeperator(csv, '\0'); + + return csv; +} + +static inline void wbImportCSV_delete(wbImportCSV_t csv) { + if (csv != NULL) { + wbImportCSV_setFile(csv, NULL); + if (wbImportCSV_getData(csv)) { + wbDelete(wbImportCSV_getData(csv)); + } + wbDelete(csv); + } +} + +static inline wbImportCSV_t wbImportCSV_findDimensions(wbImportCSV_t csv, + int *resRows, + int *resColumns) { + int rows = 0, columns = -1; + char *line; + wbFile_t file; + char seperator[2]; + + if (csv == NULL) { + return NULL; + } + + if (wbImportCSV_getSeperator(csv) == '\0') { + seperator[0] = ','; + } else { + seperator[0] = wbImportCSV_getSeperator(csv); + } + seperator[1] = '\0'; + + file = wbImportCSV_getFile(csv); + + while ((line = wbFile_readLine(file)) != NULL) { + int currColumn = 0; + char *token = strtok(line, seperator); + while (token != NULL) { + token = strtok(NULL, seperator); + currColumn++; + } + rows++; + if (columns == -1) { + columns = currColumn; + } + if (columns != currColumn) { + wbLog(ERROR, "The csv file is not rectangular."); + } + wbAssert(columns == currColumn); + } + + wbFile_rewind(file); + + *resRows = rows; + *resColumns = columns; + + return csv; +} + +static inline int *csv_readAsInteger(wbFile_t file, char sep, int rows, + int columns) { + int ii = 0; + int *data; + char *line; + int var; + char seperator[2]; + + if (file == NULL) { + return NULL; + } + + data = wbNewArray(int, rows *columns); + + if (sep == '\0') { + seperator[0] = ','; + } else { + seperator[0] = sep; + } + seperator[1] = '\0'; + + // printf("cols = %d rows = %d\n", columns, rows); + if (columns == 1) { + while ((line = wbFile_readLine(file)) != NULL) { + sscanf(line, "%d", &var); + // printf("reading %d\n", var); + data[ii++] = var; + } + } else { + while ((line = wbFile_readLine(file)) != NULL) { + char *token = strtok(line, seperator); + while (token != NULL) { + sscanf(token, "%d", &var); + token = strtok(NULL, seperator); + data[ii++] = var; + } + } + } + + return data; +} + +static inline wbReal_t *csv_readAsReal(wbFile_t file, char sep, int rows, + int columns) { + int ii = 0; + wbReal_t *data; + char *line; + wbReal_t var; + char seperator[2]; + + if (file == NULL) { + return NULL; + } + + data = wbNewArray(wbReal_t, rows * columns); + + if (sep == '\0') { + seperator[0] = ','; + } else { + seperator[0] = sep; + } + seperator[1] = '\0'; + + if (columns == 1) { + while ((line = wbFile_readLine(file)) != NULL) { + sscanf(line, "%f", &var); + data[ii++] = var; + } + } else { + while ((line = wbFile_readLine(file)) != NULL) { + char *token = strtok(line, seperator); + while (token != NULL) { + sscanf(token, "%f", &var); + token = strtok(NULL, seperator); + data[ii++] = var; + } + } + } + + return data; +} + +static inline wbImportCSV_t wbImportCSV_read(wbImportCSV_t csv, + wbType_t type) { + void *data; + wbFile_t file; + char seperator; + int rows, columns; + + if (csv == NULL) { + return NULL; + } + + if (wbImportCSV_getRowCount(csv) == -1 || + wbImportCSV_getColumnCount(csv) == -1) { + if (wbImportCSV_findDimensions(csv, &rows, &columns) == NULL) { + wbLog(ERROR, "Failed to figure out csv dimensions."); + return NULL; + } + wbImportCSV_setRowCount(csv, rows); + wbImportCSV_setColumnCount(csv, columns); + } + + file = wbImportCSV_getFile(csv); + seperator = wbImportCSV_getSeperator(csv); + rows = wbImportCSV_getRowCount(csv); + columns = wbImportCSV_getColumnCount(csv); + + if (wbImportCSV_getData(csv) != NULL) { + wbDelete(wbImportCSV_getData(csv)); + wbImportCSV_setData(csv, NULL); + } + + if (type == wbType_integer) { + // printf("ReadXXXing as integer...\n"); + data = csv_readAsInteger(file, seperator, rows, columns); + } else { + data = csv_readAsReal(file, seperator, rows, columns); + } + + wbImportCSV_setData(csv, data); + + return csv; +} + +static inline wbImportCSV_t wbImportCSV_readAsInteger(wbImportCSV_t csv) { + return wbImportCSV_read(csv, wbType_integer); +} + +static inline wbImportCSV_t wbImportCSV_readAsReal(wbImportCSV_t csv) { + return wbImportCSV_read(csv, wbType_real); +} + +static inline void wbImportRaw_setFile(wbImportRaw_t raw, + const char *path) { + if (raw != NULL) { + if (wbImportRaw_getFile(raw) != NULL) { + wbFile_delete(wbImportRaw_getFile(raw)); + } + if (path != NULL) { + wbImportRaw_getFile(raw) = wbFile_open(path, "r"); + } else { + wbImportRaw_getFile(raw) = NULL; + } + } + + return; +} + +static inline wbImportRaw_t wbImportRaw_new(void) { + wbImportRaw_t raw; + + raw = wbNew(struct st_wbImportRaw_t); + + wbImportRaw_setRowCount(raw, -1); + wbImportRaw_setColumnCount(raw, -1); + wbImportRaw_setData(raw, NULL); + wbImportRaw_getFile(raw) = NULL; + + return raw; +} + +static inline void wbImportRaw_delete(wbImportRaw_t raw) { + if (raw != NULL) { + wbImportRaw_setFile(raw, NULL); + if (wbImportRaw_getData(raw)) { + wbDelete(wbImportRaw_getData(raw)); + } + wbDelete(raw); + } +} + +static inline wbBool lineHasSpace(const char *line) { + while (*line != '\0') { + if (*line == ' ') { + return wbTrue; + } + line++; + } + return wbFalse; +} + +static inline char *lineStrip(const char *line) { + char *sl = wbString_duplicate(line); + char *iter = sl; + size_t slen = strlen(line); + + iter += slen - 1; + while (*iter == '\0' || *iter == '\r' || *iter == '\t' || + *iter == '\n' || *iter == ' ') { + *iter-- = '\0'; + } + return sl; +} + +static inline wbBool wbImportRaw_findDimensions(wbImportRaw_t raw) { + if (raw != NULL) { + int rows; + int columns; + char *line; + wbFile_t file; + char *strippedLine; + + file = wbImportRaw_getFile(raw); + + wbFile_rewind(file); + + line = wbFile_readLine(file); + + if (line == NULL) { + return wbTrue; + } + + strippedLine = lineStrip(line); + + if (lineHasSpace(strippedLine)) { + sscanf(strippedLine, "%d %d", &rows, &columns); + } else { + columns = 1; + sscanf(strippedLine, "%d", &rows); + } + + wbImportRaw_setRowCount(raw, rows); + wbImportRaw_setColumnCount(raw, columns); + + wbDelete(strippedLine); + + return wbFalse; + } + + return wbTrue; +} + +static inline wbImportRaw_t wbImportRaw_read(wbImportRaw_t raw, + wbType_t type) { + void *data; + wbFile_t file; + char seperator; + int rows, columns; + + if (raw == NULL) { + return NULL; + } + + if (wbImportRaw_getRowCount(raw) == -1 || + wbImportRaw_getColumnCount(raw) == -1) { + if (wbImportRaw_findDimensions(raw)) { + wbLog(ERROR, "Failed to figure out raw dimensions."); + return NULL; + } + } + + file = wbImportRaw_getFile(raw); + seperator = ' '; + rows = wbImportRaw_getRowCount(raw); + columns = wbImportRaw_getColumnCount(raw); + + if (wbImportRaw_getData(raw) != NULL) { + wbDelete(wbImportRaw_getData(raw)); + wbImportRaw_setData(raw, NULL); + } + + if (type == wbType_integer) { + // printf("Rdin gas integer...\n"); + data = csv_readAsInteger(file, seperator, rows, columns); + } else { + data = csv_readAsReal(file, seperator, rows, columns); + } + + wbImportRaw_setData(raw, data); + + return raw; +} + +static inline wbImportRaw_t wbImportRaw_readAsInteger(wbImportRaw_t raw) { + return wbImportRaw_read(raw, wbType_integer); +} + +static inline wbImportRaw_t wbImportRaw_readAsReal(wbImportRaw_t raw) { + return wbImportRaw_read(raw, wbType_real); +} + +static inline wbImportText_t wbImportText_new(void) { + wbImportText_t text; + + text = wbNew(struct st_wbImportText_t); + + wbImportText_setLength(text, 0); + wbImportText_setData(text, NULL); + wbImportText_getFile(text) = NULL; + + return text; +} + +static inline void wbImportText_setFile(wbImportText_t text, + const char *path) { + if (text != NULL) { + if (wbImportText_getFile(text) != NULL) { + wbFile_delete(wbImportText_getFile(text)); + } + if (path != NULL) { + wbImportText_getFile(text) = wbFile_open(path, "r"); + } else { + wbImportText_getFile(text) = NULL; + } + } + + return; +} + +static inline void wbImportText_delete(wbImportText_t text) { + if (text != NULL) { + wbImportText_setFile(text, NULL); + if (wbImportText_getData(text)) { + wbDelete(wbImportText_getData(text)); + } + wbDelete(text); + } +} + +static inline wbImportText_t wbImportText_read(wbImportText_t text) { + char *data; + wbFile_t file; + int length; + + if (text == NULL) { + return NULL; + } + + file = wbImportText_getFile(text); + + if (wbImportText_getData(text) != NULL) { + wbDelete(wbImportText_getData(text)); + wbImportText_setData(text, NULL); + } + + length = wbFile_size(file); + data = wbFile_read(file, length); + + wbImportText_setData(text, data); + wbImportText_setLength(text, length); + + return text; +} + +static inline wbImport_t wbImport_open(const char *file, + wbImportKind_t kind) { + wbImport_t imp; + + if (file == NULL) { + wbLog(ERROR, "Go NULL for file value."); + wbExit(); + } + + if (!wbFile_existsQ(file)) { + wbLog(ERROR, "File ", file, " does not exist."); + wbExit(); + } + + wbImport_setKind(imp, kind); + + if (kind == wbImportKind_raw) { + wbImportRaw_t raw = wbImportRaw_new(); + wbImportRaw_setFile(raw, file); + wbImport_setRaw(imp, raw); + } else if (kind == wbImportKind_tsv || kind == wbImportKind_csv) { + wbImportCSV_t csv = wbImportCSV_new(); + if (kind == wbImportKind_csv) { + wbImportCSV_setSeperator(csv, ','); + } else { + wbImportCSV_setSeperator(csv, '\t'); + } + wbImportCSV_setFile(csv, file); + wbImport_setCSV(imp, csv); + } else if (kind == wbImportKind_text) { + wbImportText_t text = wbImportText_new(); + wbImportText_setFile(text, file); + wbImport_setText(imp, text); + } else if (kind == wbImportKind_ppm) { + wbImage_t img = wbPPM_import(file); + wbImport_setImage(imp, img); + } else { + wbLog(ERROR, "Invalid import type."); + wbExit(); + } + + return imp; +} + +static inline wbImport_t wbImport_open(const char *file, + const char *type0) { + wbImport_t imp; + wbImportKind_t kind; + char *type; + + type = wbString_toLower(type0); + + if (wbString_sameQ(type, "csv")) { + kind = wbImportKind_csv; + } else if (wbString_sameQ(type, "tsv")) { + kind = wbImportKind_tsv; + } else if (wbString_sameQ(type, "raw") || wbString_sameQ(type, "dat")) { + kind = wbImportKind_raw; + } else if (wbString_sameQ(type, "ppm")) { + kind = wbImportKind_ppm; + } else if (wbString_sameQ(type, "text") || wbString_sameQ(type, "txt")) { + kind = wbImportKind_text; + } else { + wbLog(ERROR, "Invalid import type ", type0); + wbExit(); + } + + imp = wbImport_open(file, kind); + + wbDelete(type); + + return imp; +} + +static inline void wbImport_close(wbImport_t imp) { + wbImportKind_t kind; + + kind = wbImport_getKind(imp); + if (kind == wbImportKind_tsv || kind == wbImportKind_csv) { + wbImportCSV_t csv = wbImport_getCSV(imp); + wbImportCSV_delete(csv); + wbImport_setCSV(imp, NULL); + } else if (kind == wbImportKind_raw) { + wbImportRaw_t raw = wbImport_getRaw(imp); + wbImportRaw_delete(raw); + wbImport_setRaw(imp, NULL); + } else if (kind == wbImportKind_text) { + wbImportText_t text = wbImport_getText(imp); + wbImportText_delete(text); + wbImport_setText(imp, NULL); + } else if (kind == wbImportKind_ppm) { + } else { + wbLog(ERROR, "Invalid import type."); + wbExit(); + } + return; +} + +static inline void *wbImport_read(wbImport_t imp, wbType_t type) { + void *data = NULL; + wbImportKind_t kind; + + kind = wbImport_getKind(imp); + if (kind == wbImportKind_tsv || kind == wbImportKind_csv) { + wbImportCSV_t csv = wbImport_getCSV(imp); + wbImportCSV_read(csv, type); + data = wbImportCSV_getData(csv); + } else if (kind == wbImportKind_raw) { + wbImportRaw_t raw = wbImport_getRaw(imp); + wbImportRaw_read(raw, type); + data = wbImportRaw_getData(raw); + } else if (wbImportKind_text == kind) { + wbImportText_t text = wbImport_getText(imp); + text = wbImportText_read(text); + data = wbImportText_getData(text); + + } else { + wbLog(ERROR, "Invalid import type."); + wbExit(); + } + return data; +} + +static inline int *wbImport_readAsInteger(wbImport_t imp) { + void *data = wbImport_read(imp, wbType_integer); + return (int *)data; +} + +static inline wbReal_t *wbImport_readAsReal(wbImport_t imp) { + void *data = wbImport_read(imp, wbType_real); + return (wbReal_t *)data; +} + +static inline wbChar_t *wbImport_readAsText(wbImport_t imp) { + void *data = wbImport_read(imp, wbType_ubit8); + return (wbChar_t *)data; +} + +static wbImportKind_t _parseImportExtension(const char *file) { + char *extension; + wbImportKind_t kind; + + extension = wbFile_extension(file); + + if (wbString_sameQ(extension, "csv")) { + kind = wbImportKind_csv; + } else if (wbString_sameQ(extension, "tsv")) { + kind = wbImportKind_tsv; + } else if (wbString_sameQ(extension, "raw") || + wbString_sameQ(extension, "dat")) { + kind = wbImportKind_raw; + } else if (wbString_sameQ(extension, "ppm") || + wbString_sameQ(extension, "pbm")) { + kind = wbImportKind_ppm; + } else if (wbString_sameQ(extension, "text") || + wbString_sameQ(extension, "txt")) { + kind = wbImportKind_text; + } else { + kind = wbImportKind_unknown; + wbLog(ERROR, "File ", file, " does not have a compatible extension."); + } + + wbDelete(extension); + + return kind; +} + +void *wbImport(const char *file, int *resRows, int *resColumns, + const char *type) { + void *data, *res; + wbImport_t imp; + size_t sz; + int columns = 0, rows = 0; + wbImportKind_t kind; + + if (file == NULL) { + fprintf(stderr, "Failed to import file.\n"); + wbExit(); + } + + kind = _parseImportExtension(file); + + wbAssert(kind != wbImportKind_unknown); + + imp = wbImport_open(file, kind); + if (wbString_sameQ(type, "Real")) { + data = wbImport_readAsReal(imp); + sz = sizeof(wbReal_t); + } else if (wbString_sameQ(type, "Text")) { + data = wbImport_readAsText(imp); + sz = sizeof(char); + } else { + // printf("Reading as integer..d\n"); + data = wbImport_readAsInteger(imp); + sz = sizeof(int); + } + + if (kind == wbImportKind_csv || kind == wbImportKind_tsv) { + rows = wbImportCSV_getRowCount(wbImport_getCSV(imp)); + columns = wbImportCSV_getColumnCount(wbImport_getCSV(imp)); + } else if (kind == wbImportKind_raw) { + rows = wbImportRaw_getRowCount(wbImport_getRaw(imp)); + columns = wbImportRaw_getColumnCount(wbImport_getRaw(imp)); + } else if (kind == wbImportKind_text) { + rows = 1; + columns = wbImportText_getLength(wbImport_getText(imp)); + } + + if (rows == 1 && columns > 0) { + rows = columns; + columns = 1; + } + + if (resRows != NULL) { + *resRows = rows; + } + + if (resColumns != NULL) { + *resColumns = columns; + } + + res = wbMalloc(sz * rows * columns); + memcpy(res, data, sz * rows * columns); + + wbImport_close(imp); + + return res; +} + +void *wbImport(const char *file, int *rows, int *columns) { + return wbImport(file, rows, columns, "Real"); +} + +EXTERN_C void *wbImport(const char *file, int *rows) { + return wbImport(file, rows, NULL, "Real"); +} + +void *wbImport(const char *file, int *res_rows, const char *type) { + int cols, rows; + void *res = wbImport(file, &rows, &cols, type); + if (rows == 1 && cols > 1) { + rows = cols; + } + *res_rows = rows; + return res; +} + +wbImage_t wbImport(const char *file) { + wbImage_t img; + wbImport_t imp; + wbImportKind_t kind; + + if (file == NULL) { + fprintf(stderr, "Failed to import file.\n"); + wbExit(); + } + + kind = _parseImportExtension(file); + + wbAssert(kind == wbImportKind_ppm); + + imp = wbImport_open(file, kind); + img = wbImport_getImage(imp); + wbImport_close(imp); + + return img; +} + +int wbImport_flag(const char *file) { + int res; + wbFile_t fh = wbFile_open(file, "r"); + const char *line = wbFile_readLine(fh); + sscanf(line, "%d", &res); + wbFile_close(fh); + return res; +} diff --git a/CUDA_DeviceQuery/libwb/wbImport.h b/CUDA_DeviceQuery/libwb/wbImport.h new file mode 100644 index 0000000..ce13e1b --- /dev/null +++ b/CUDA_DeviceQuery/libwb/wbImport.h @@ -0,0 +1,103 @@ + +#ifndef __WB_IMPORT_H__ +#define __WB_IMPORT_H__ + +#include "wbImage.h" + +typedef enum en_wbImportKind_t { + wbImportKind_unknown = -1, + wbImportKind_raw = 0x1000, + wbImportKind_csv, + wbImportKind_tsv, + wbImportKind_ppm, + wbImportKind_text +} wbImportKind_t; + +#define wbType_real wbType_float + +typedef struct st_wbImportCSV_t { + int rows; + int columns; + void *data; + wbFile_t file; + char seperator; +} * wbImportCSV_t; + +#define wbImportCSV_getRowCount(csv) ((csv)->rows) +#define wbImportCSV_getColumnCount(csv) ((csv)->columns) +#define wbImportCSV_getData(csv) ((csv)->data) +#define wbImportCSV_getFile(csv) ((csv)->file) +#define wbImportCSV_getSeperator(csv) ((csv)->seperator) + +#define wbImportCSV_setRowCount(csv, val) \ + (wbImportCSV_getRowCount(csv) = val) +#define wbImportCSV_setColumnCount(csv, val) \ + (wbImportCSV_getColumnCount(csv) = val) +#define wbImportCSV_setData(csv, val) (wbImportCSV_getData(csv) = val) +#define wbImportCSV_setSeperator(csv, val) \ + (wbImportCSV_getSeperator(csv) = val) + +typedef struct st_wbImportRaw_t { + int rows; + int columns; + void *data; + wbFile_t file; +} * wbImportRaw_t; + +#define wbImportRaw_getRowCount(raw) ((raw)->rows) +#define wbImportRaw_getColumnCount(raw) ((raw)->columns) +#define wbImportRaw_getData(raw) ((raw)->data) +#define wbImportRaw_getFile(raw) ((raw)->file) + +#define wbImportRaw_setRowCount(raw, val) \ + (wbImportRaw_getRowCount(raw) = val) +#define wbImportRaw_setColumnCount(raw, val) \ + (wbImportRaw_getColumnCount(raw) = val) +#define wbImportRaw_setData(raw, val) (wbImportRaw_getData(raw) = val) + +typedef struct st_wbImportText_t { + int length; + char *data; + wbFile_t file; +} * wbImportText_t; + +#define wbImportText_getLength(txt) ((txt)->length) +#define wbImportText_getData(txt) ((txt)->data) +#define wbImportText_getFile(txt) ((txt)->file) + +#define wbImportText_setLength(txt, val) \ + (wbImportText_getLength(txt) = val) +#define wbImportText_setData(txt, val) (wbImportText_getData(txt) = val) + +typedef struct st_wbImport_t { + wbImportKind_t kind; + union { + wbImportRaw_t raw; + wbImportCSV_t csv; + wbImportText_t text; + wbImage_t img; + } container; +} wbImport_t; + +#define wbImport_getKind(imp) ((imp).kind) +#define wbImport_getContainer(imp) ((imp).container) +#define wbImport_getRaw(imp) (wbImport_getContainer(imp).raw) +#define wbImport_getCSV(imp) (wbImport_getContainer(imp).csv) +#define wbImport_getText(imp) (wbImport_getContainer(imp).text) +#define wbImport_getImage(imp) (wbImport_getContainer(imp).img) + +#define wbImport_setKind(imp, val) (wbImport_getKind(imp) = val) +#define wbImport_setRaw(imp, val) (wbImport_getRaw(imp) = val) +#define wbImport_setCSV(imp, val) (wbImport_getCSV(imp) = val) +#define wbImport_setText(imp, val) (wbImport_getText(imp) = val) +#define wbImport_setImage(imp, val) (wbImport_getImage(imp) = val) + +EXTERN_C void *wbImport(const char *file, int *rows); +void *wbImport(const char *file, int *rows, int *columns); +void *wbImport(const char *file, int *rows, const char *type); +void *wbImport(const char *file, int *resRows, int *resColumns, + const char *type); +wbImage_t wbImport(const char *file); +int wbImport_flag(const char *file); + +#endif /* __WB_IMPORT_H__ */ diff --git a/CUDA_DeviceQuery/libwb/wbInit.cpp b/CUDA_DeviceQuery/libwb/wbInit.cpp new file mode 100644 index 0000000..96ebcf3 --- /dev/null +++ b/CUDA_DeviceQuery/libwb/wbInit.cpp @@ -0,0 +1,85 @@ + +#include "wb.h" + +#define MB (1 << 20) +#ifndef WB_DEFAULT_HEAP_SIZE +#define WB_DEFAULT_HEAP_SIZE (1024 * MB) +#endif /* WB_DEFAULT_HEAP_SIZE */ + +static bool _initializedQ = wbFalse; + +#ifndef WB_USE_WINDOWS +__attribute__((__constructor__)) +#endif /* WB_USE_WINDOWS */ +void wb_init(int * +#ifdef WB_USE_MPI + argc +#endif /* WB_USE_MPI */ + , + char *** +#ifdef WB_USE_MPI + argv +#endif /* WB_USE_MPI */ + ) { + if (_initializedQ == wbTrue) { + return; + } +#ifdef WB_USE_MPI + wbMPI_Init(argc, argv); +#endif /* WB_USE_MPI */ + +#ifdef WB_USE_CUDA + CUresult err = cuInit(0); + +/* Select a random GPU */ + +#ifdef WB_USE_MPI + if (rankCount() > 1) { + int deviceCount; + cudaGetDeviceCount(&deviceCount); + srand(time(NULL)); + cudaSetDevice(wbMPI_getRank() % deviceCount); + } else { + int deviceCount; + cudaGetDeviceCount(&deviceCount); + + srand(time(NULL)); + cudaSetDevice(rand() % deviceCount); + } +#else + { + int deviceCount; + cudaGetDeviceCount(&deviceCount); + + srand(time(NULL)); + cudaSetDevice(rand() % deviceCount); + } +#endif /* WB_USE_MPI */ + + cudaDeviceSetLimit(cudaLimitPrintfFifoSize, 1 * MB); + cudaDeviceSetLimit(cudaLimitMallocHeapSize, WB_DEFAULT_HEAP_SIZE); + + cudaDeviceSynchronize(); + +#endif /* WB_USE_CUDA */ + +#ifdef WB_USE_WINDOWS + QueryPerformanceFrequency((LARGE_INTEGER *)&_hrtime_frequency); +#endif /* _MSC_VER */ + + _hrtime(); + + _timer = wbTimer_new(); + _logger = wbLogger_new(); + _initializedQ = wbTrue; + + wbFile_init(); + + solutionJSON = NULL; + +#ifdef WB_USE_MPI + atexit(wbMPI_Exit); +#else /* WB_USE_MPI */ + atexit(wb_atExit); +#endif /* WB_USE_MPI */ +} diff --git a/CUDA_DeviceQuery/libwb/wbInit.h b/CUDA_DeviceQuery/libwb/wbInit.h new file mode 100644 index 0000000..40e8e1c --- /dev/null +++ b/CUDA_DeviceQuery/libwb/wbInit.h @@ -0,0 +1,11 @@ + + +#ifndef __WB_INIT_H__ +#define __WB_INIT_H__ + +#ifndef _MSC_VER +__attribute__((__constructor__)) +#endif /* _MSC_VER */ +void wb_init(int *argc, char ***argv); + +#endif /* __WB_INIT_H__ */ diff --git a/CUDA_DeviceQuery/libwb/wbLogger.cpp b/CUDA_DeviceQuery/libwb/wbLogger.cpp new file mode 100644 index 0000000..c2e2e17 --- /dev/null +++ b/CUDA_DeviceQuery/libwb/wbLogger.cpp @@ -0,0 +1,310 @@ + +#include "wb.h" + +wbLogger_t _logger = NULL; + +static inline wbBool wbLogEntry_hasNext(wbLogEntry_t elem) { + return wbLogEntry_getNext(elem) != NULL; +} + +static inline wbLogEntry_t wbLogEntry_new() { + wbLogEntry_t elem; + + elem = wbNew(struct st_wbLogEntry_t); + + wbLogEntry_setMessage(elem, NULL); + wbLogEntry_setMPIRank(elem, wbMPI_getRank()); + wbLogEntry_setTime(elem, _hrtime()); + + wbLogEntry_setLevel(elem, wbLogLevel_TRACE); + + wbLogEntry_setNext(elem, NULL); + + wbLogEntry_setLine(elem, -1); + wbLogEntry_setFile(elem, NULL); + wbLogEntry_setFunction(elem, NULL); + + return elem; +} + +static inline wbLogEntry_t +wbLogEntry_initialize(wbLogLevel_t level, string msg, const char *file, + const char *fun, int line) { + wbLogEntry_t elem; + + elem = wbLogEntry_new(); + + wbLogEntry_setLevel(elem, level); + + wbLogEntry_setMessage(elem, wbString_duplicate(msg)); + + wbLogEntry_setLine(elem, line); + wbLogEntry_setFile(elem, file); + wbLogEntry_setFunction(elem, fun); + + return elem; +} + +static inline void wbLogEntry_delete(wbLogEntry_t elem) { + if (elem != NULL) { + if (wbLogEntry_getMessage(elem) != NULL) { + wbFree(wbLogEntry_getMessage(elem)); + } + wbDelete(elem); + } + return; +} + +static inline const char *getLevelName(wbLogLevel_t level) { + switch (level) { + case wbLogLevel_unknown: + return "Unknown"; + case wbLogLevel_OFF: + return "Off"; + case wbLogLevel_FATAL: + return "Fatal"; + case wbLogLevel_ERROR: + return "Error"; + case wbLogLevel_WARN: + return "Warn"; + case wbLogLevel_INFO: + return "Info"; + case wbLogLevel_DEBUG: + return "Debug"; + case wbLogLevel_TRACE: + return "Trace"; + } + return NULL; +} + +static inline json11::Json wbLogEntry_toJSONObject(wbLogEntry_t elem) { + json11::Json json = json11::Json::object{ + {"mpi_rank", wbLogEntry_getMPIRank(elem)}, + {"level", getLevelName(wbLogEntry_getLevel(elem))}, + {"file", wbLogEntry_getFile(elem)}, + {"function", wbLogEntry_getFunction(elem)}, + {"line", wbLogEntry_getLine(elem)}, + {"time", wbLogEntry_getTime(elem)}, + {"message", wbLogEntry_getMessage(elem)}, + }; + return json; +} + +static inline string wbLogEntry_toJSON(wbLogEntry_t elem) { + if (elem == NULL) { + return ""; + } else if (WB_USE_JSON11) { + json11::Json json = wbLogEntry_toJSONObject(elem); + return json.string_value(); + } else { + stringstream ss; + + ss << "{\n"; + ss << wbString_quote("mpi_rank") << ":" + << wbString(wbLogEntry_getMPIRank(elem)) << ",\n"; + ss << wbString_quote("level") << ":" + << wbString_quote(getLevelName(wbLogEntry_getLevel(elem))) << ",\n"; + ss << wbString_quote("message") << ":" + << wbString_quote(wbLogEntry_getMessage(elem)) << ",\n"; + ss << wbString_quote("file") << ":" + << wbString_quote(wbLogEntry_getFile(elem)) << ",\n"; + ss << wbString_quote("function") << ":" + << wbString_quote(wbLogEntry_getFunction(elem)) << ",\n"; + ss << wbString_quote("line") << ":" << wbLogEntry_getLine(elem) + << ",\n"; + ss << wbString_quote("time") << ":" << wbLogEntry_getTime(elem) + << "\n"; + ss << "}"; + + return ss.str(); + } + return ""; +} + +static inline string wbLogEntry_toXML(wbLogEntry_t elem) { + if (elem != NULL) { + stringstream ss; + + ss << "\n"; + ss << "" + << "LoggerElement" + << "\n"; + ss << "" << wbLogEntry_getLevel(elem) << "\n"; + ss << "" << wbLogEntry_getMessage(elem) << "\n"; + ss << "" << wbLogEntry_getFile(elem) << "\n"; + ss << "" << wbLogEntry_getFunction(elem) << "\n"; + ss << "" << wbLogEntry_getLine(elem) << "\n"; + ss << "\n"; + ss << "\n"; + + return ss.str(); + } + return ""; +} + +wbLogger_t wbLogger_new() { + wbLogger_t logger; + + logger = wbNew(struct st_wbLogger_t); + + wbLogger_setLength(logger, 0); + wbLogger_setHead(logger, NULL); + + wbLogger_getLevel(logger) = wbLogLevel_TRACE; + + return logger; +} + +static inline void _wbLogger_setLevel(wbLogger_t logger, + wbLogLevel_t level) { + wbLogger_getLevel(logger) = level; +} + +static inline void _wbLogger_setLevel(wbLogLevel_t level) { + _wbLogger_setLevel(_logger, level); +} + +#define wbLogger_setLevel(level) _wbLogger_setLevel(wbLogLevel_##level) + +void wbLogger_clear(wbLogger_t logger) { + if (logger != NULL) { + wbLogEntry_t tmp; + wbLogEntry_t iter; + + iter = wbLogger_getHead(logger); + while (iter != NULL) { + tmp = wbLogEntry_getNext(iter); + wbLogEntry_delete(iter); + iter = tmp; + } + + wbLogger_setLength(logger, 0); + wbLogger_setHead(logger, NULL); + } +} + +void wbLogger_delete(wbLogger_t logger) { + if (logger != NULL) { + wbLogger_clear(logger); + wbDelete(logger); + } + return; +} + +void wbLogger_append(wbLogLevel_t level, string msg, const char *file, + const char *fun, int line) { + wbLogEntry_t elem; + wbLogger_t logger; + + wb_init(NULL, NULL); + + logger = _logger; + + if (wbLogger_getLevel(logger) < level) { + return; + } + + elem = wbLogEntry_initialize(level, msg, file, fun, line); + +#ifdef wbLogger_printOnLog + if (wbLogger_printOnLog) { + if (level <= wbLogger_getLevel(logger) && elem) { + json11::Json json = json11::Json::object{ +#ifndef _MSC_VER //PMO + { "type", "logger" }, { "data", wbLogEntry_toJSONObject(elem) }}; +#else + { "data", wbLogEntry_toJSONObject(elem) }, { "type", "logger" }}; +#endif + std::cout << json.dump() << std::endl; + } + } +#endif /* wbLogger_printOnLog */ + + if (wbLogger_getHead(logger) == NULL) { + wbLogger_setHead(logger, elem); + } else { + wbLogEntry_t prev = wbLogger_getHead(logger); + + while (wbLogEntry_hasNext(prev)) { + prev = wbLogEntry_getNext(prev); + } + wbLogEntry_setNext(prev, elem); + } + +#if 0 + if (level <= wbLogger_getLevel(logger) && elem) { + const char *levelName = getLevelName(level); + + fprintf(stderr, "= LOG: %s: %s (In %s:%s on line %d). =\n", levelName, + wbLogEntry_getMessage(elem), wbLogEntry_getFile(elem), + wbLogEntry_getFunction(elem), wbLogEntry_getLine(elem)); + } +#endif + + wbLogger_incrementLength(logger); + + return; +} + +string wbLogger_toJSON() { + return wbLogger_toJSON(_logger); +} + +static json11::Json wbLogger_toJSONObject(wbLogger_t logger) { + std::vector elems{}; + + if (logger != NULL) { + wbLogEntry_t iter; + stringstream ss; + + for (iter = wbLogger_getHead(logger); iter != NULL; + iter = wbLogEntry_getNext(iter)) { + elems.push_back(wbLogEntry_toJSONObject(iter)); + } + } + return json11::Json(elems); +} + +string wbLogger_toJSON(wbLogger_t logger) { + if (logger != NULL) { + wbLogEntry_t iter; + stringstream ss; + + for (iter = wbLogger_getHead(logger); iter != NULL; + iter = wbLogEntry_getNext(iter)) { + ss << wbLogEntry_toJSON(iter); + if (wbLogEntry_getNext(iter) != NULL) { + ss << ",\n"; + } + } + + return ss.str(); + } + return ""; +} + +string wbLogger_toXML() { + return wbLogger_toXML(_logger); +} + +string wbLogger_toXML(wbLogger_t logger) { + if (logger != NULL) { + wbLogEntry_t iter; + stringstream ss; + + ss << "\n"; + ss << "" + << "Logger" + << "\n"; + ss << "\n"; + for (iter = wbLogger_getHead(logger); iter != NULL; + iter = wbLogEntry_getNext(iter)) { + ss << wbLogEntry_toXML(iter); + } + ss << "\n"; + ss << "\n"; + + return ss.str(); + } + return ""; +} diff --git a/CUDA_DeviceQuery/libwb/wbLogger.h b/CUDA_DeviceQuery/libwb/wbLogger.h new file mode 100644 index 0000000..b852592 --- /dev/null +++ b/CUDA_DeviceQuery/libwb/wbLogger.h @@ -0,0 +1,87 @@ + +#ifndef __WB_LOGGER_H__ +#define __WB_LOGGER_H__ + +#include + +typedef enum en_wbLogLevel_t { + wbLogLevel_unknown = -1, + wbLogLevel_OFF = 0, + wbLogLevel_FATAL, + wbLogLevel_ERROR, + wbLogLevel_WARN, + wbLogLevel_INFO, + wbLogLevel_DEBUG, + wbLogLevel_TRACE +} wbLogLevel_t; + +struct st_wbLogEntry_t { + int line; + int mpiRank; + char *msg; + uint64_t time; + const char *fun; + const char *file; + wbLogLevel_t level; + wbLogEntry_t next; +}; + +struct st_wbLogger_t { + int length; + wbLogEntry_t head; + wbLogLevel_t level; +}; + +#define wbLogEntry_getMessage(elem) ((elem)->msg) +#define wbLogEntry_getMPIRank(elem) ((elem)->mpiRank) +#define wbLogEntry_getTime(elem) ((elem)->time) +#define wbLogEntry_getLevel(elem) ((elem)->level) +#define wbLogEntry_getNext(elem) ((elem)->next) +#define wbLogEntry_getLine(elem) ((elem)->line) +#define wbLogEntry_getFunction(elem) ((elem)->fun) +#define wbLogEntry_getFile(elem) ((elem)->file) + +#define wbLogEntry_setMessage(elem, val) \ + (wbLogEntry_getMessage(elem) = val) +#define wbLogEntry_setMPIRank(elem, val) \ + (wbLogEntry_getMPIRank(elem) = val) +#define wbLogEntry_setTime(elem, val) (wbLogEntry_getTime(elem) = val) +#define wbLogEntry_setLevel(elem, val) (wbLogEntry_getLevel(elem) = val) +#define wbLogEntry_setNext(elem, val) (wbLogEntry_getNext(elem) = val) +#define wbLogEntry_setLine(elem, val) (wbLogEntry_getLine(elem) = val) +#define wbLogEntry_setFunction(elem, val) \ + (wbLogEntry_getFunction(elem) = val) +#define wbLogEntry_setFile(elem, val) (wbLogEntry_getFile(elem) = val) + +#define wbLogger_getLength(log) ((log)->length) +#define wbLogger_getHead(log) ((log)->head) +#define wbLogger_getLevel(log) ((log)->level) + +#define wbLogger_setLength(log, val) (wbLogger_getLength(log) = val) +#define wbLogger_setHead(log, val) (wbLogger_getHead(log) = val) + +#define wbLogger_incrementLength(log) (wbLogger_getLength(log)++) +#define wbLogger_decrementLength(log) (wbLogger_getLength(log)--) + +#define wbLog(level, ...) \ + wbLogger_append(wbLogLevel_##level, wbString(__VA_ARGS__), wbFile, \ + wbFunction, wbLine) + +extern wbLogger_t _logger; + +wbLogger_t wbLogger_new(); + +void wbLogger_clear(wbLogger_t logger); + +void wbLogger_delete(wbLogger_t logger); + +void wbLogger_append(wbLogLevel_t level, string msg, const char *file, + const char *fun, int line); + +string wbLogger_toXML(wbLogger_t logger); +string wbLogger_toXML(); + +string wbLogger_toJSON(wbLogger_t logger); +string wbLogger_toJSON(); + +#endif /* __WB_LOGGER_H__ */ diff --git a/CUDA_DeviceQuery/libwb/wbMD5.h b/CUDA_DeviceQuery/libwb/wbMD5.h new file mode 100644 index 0000000..e83a8ef --- /dev/null +++ b/CUDA_DeviceQuery/libwb/wbMD5.h @@ -0,0 +1,311 @@ + +/* + * This code implements the MD5 message-digest algorithm. + * The algorithm is due to Ron Rivest. This code was + * written by Colin Plumb in 1993, no copyright is claimed. + * This code is in the public domain; do with it what you wish. + * + * Equivalent code is available from RSA Data Security, Inc. + * This code has been tested against that, and is equivalent, + * except that you don't need to include two pages of legalese + * with every copy. + * + * To compute the message digest of a chunk of bytes, declare an + * MD5Context structure, pass it to MD5Init, call MD5Update as + * needed on buffers full of bytes, and then call MD5Final, which + * will fill a supplied 16-byte array with the digest. + * + * Changed so as no longer to depend on Colin Plumb's `usual.h' header + * definitions; now uses stuff from dpkg's config.h. + * - Ian Jackson . + * Still in the public domain. + */ + +#ifndef __WB_MD5_H__ +#define __WB_MD5_H__ + +#include /* for memcpy() */ +#include /* for stupid systems */ + +#define UWORD32 unsigned int + +#define md5byte unsigned char + +struct MD5Context { + UWORD32 buf[4]; + UWORD32 bytes[2]; + UWORD32 in[16]; +}; + +static void MD5Transform(UWORD32 buf[4], UWORD32 const in[16]); + +static int g_bigEndian = 0; +static int g_endianessDetected = 0; + +static void detectEndianess() { + int nl = 0x12345678; + short ns = 0x1234; + + unsigned char *p = (unsigned char *)(&nl); + unsigned char *sp = (unsigned char *)(&ns); + + if (g_endianessDetected) + return; + if (p[0] == 0x12 && p[1] == 0x34 && p[2] == 0x56 && p[3] == 0x78) { + g_bigEndian = 1; + } else if (p[0] == 0x78 && p[1] == 0x56 && p[2] == 0x34 && + p[3] == 0x12) { + g_bigEndian = 0; + } else { + g_bigEndian = *sp != 0x12; + } + + g_endianessDetected = 1; +} + +static void byteSwap(UWORD32 *buf, unsigned words) { + md5byte *p; + + if (!g_bigEndian) + return; + + p = (md5byte *)buf; + + do { + *buf++ = (UWORD32)((unsigned)p[3] << 8 | p[2]) << 16 | + ((unsigned)p[1] << 8 | p[0]); + p += 4; + } while (--words); +} + +/* + * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious + * initialization constants. + */ +static void MD5Init(struct MD5Context *ctx) { + detectEndianess(); + + ctx->buf[0] = 0x67452301; + ctx->buf[1] = 0xefcdab89; + ctx->buf[2] = 0x98badcfe; + ctx->buf[3] = 0x10325476; + + ctx->bytes[0] = 0; + ctx->bytes[1] = 0; +} + +/* + * Update context to reflect the concatenation of another buffer full + * of bytes. + */ +static void MD5Update(struct MD5Context *ctx, md5byte const *buf, + unsigned len) { + UWORD32 t; + + /* Update byte count */ + + t = ctx->bytes[0]; + if ((ctx->bytes[0] = t + len) < t) + ctx->bytes[1]++; /* Carry from low to high */ + + t = 64 - (t & 0x3f); /* Space available in ctx->in (at least 1) */ + if (t > len) { + memcpy((md5byte *)ctx->in + 64 - t, buf, len); + return; + } + /* First chunk is an odd size */ + memcpy((md5byte *)ctx->in + 64 - t, buf, t); + byteSwap(ctx->in, 16); + MD5Transform(ctx->buf, ctx->in); + buf += t; + len -= t; + + /* Process data in 64-byte chunks */ + while (len >= 64) { + memcpy(ctx->in, buf, 64); + byteSwap(ctx->in, 16); + MD5Transform(ctx->buf, ctx->in); + buf += 64; + len -= 64; + } + + /* Handle any remaining bytes of data. */ + memcpy(ctx->in, buf, len); +} + +/* + * Final wrapup - pad to 64-byte boundary with the bit pattern + * 1 0* (64-bit count of bits processed, MSB-first) + */ +static void MD5Final(md5byte digest[16], struct MD5Context *ctx) { + int count = ctx->bytes[0] & 0x3f; /* Number of bytes in ctx->in */ + md5byte *p = (md5byte *)ctx->in + count; + + /* Set the first char of padding to 0x80. There is always room. */ + *p++ = 0x80; + + /* Bytes of padding needed to make 56 bytes (-8..55) */ + count = 56 - 1 - count; + + if (count < 0) { /* Padding forces an extra block */ + memset(p, 0, count + 8); + byteSwap(ctx->in, 16); + MD5Transform(ctx->buf, ctx->in); + p = (md5byte *)ctx->in; + count = 56; + } + memset(p, 0, count); + byteSwap(ctx->in, 14); + + /* Append length in bits and transform */ + ctx->in[14] = ctx->bytes[0] << 3; + ctx->in[15] = ctx->bytes[1] << 3 | ctx->bytes[0] >> 29; + MD5Transform(ctx->buf, ctx->in); + + byteSwap(ctx->buf, 4); + memcpy(digest, ctx->buf, 16); + memset(&ctx, 0, sizeof(ctx)); /* In case it's sensitive */ +} + +#ifndef ASM_MD5 + +/* The four core functions - F1 is optimized somewhat */ + +/* #define F1(x, y, z) (x & y | ~x & z) */ +#define F1(x, y, z) (z ^ (x & (y ^ z))) +#define F2(x, y, z) F1(z, x, y) +#define F3(x, y, z) (x ^ y ^ z) +#define F4(x, y, z) (y ^ (x | ~z)) + +/* This is the central step in the MD5 algorithm. */ +#define MD5STEP(f, w, x, y, z, in, s) \ + (w += f(x, y, z) + in, w = (w << s | w >> (32 - s)) + x) + +/* + * The core of the MD5 algorithm, this alters an existing MD5 hash to + * reflect the addition of 16 longwords of new data. MD5Update blocks + * the data and converts bytes into longwords for this routine. + */ +static void MD5Transform(UWORD32 buf[4], UWORD32 const in[16]) { + UWORD32 a, b, c, d; + + a = buf[0]; + b = buf[1]; + c = buf[2]; + d = buf[3]; + + MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); + MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); + MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); + MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); + MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); + MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); + MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); + MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); + MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); + MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); + MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); + MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); + MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); + MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); + MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); + MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); + + MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); + MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); + MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); + MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); + MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); + MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); + MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); + MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); + MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); + MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); + MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); + MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); + MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); + MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); + MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); + MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); + + MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); + MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); + MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); + MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); + MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); + MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); + MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); + MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); + MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); + MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); + MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); + MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); + MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); + MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); + MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); + MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); + + MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); + MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); + MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); + MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); + MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); + MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); + MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); + MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); + MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); + MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); + MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); + MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); + MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); + MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); + MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); + MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} + +#endif + +static void MD5_buffer(const unsigned char *buf, unsigned int len, + unsigned char sig[16]) { + struct MD5Context md5; + MD5Init(&md5); + MD5Update(&md5, buf, len); + MD5Final(sig, &md5); +} + +#define wbMD5 MD5_buffer + +#define HEX_STRING "0123456789abcdef" /* to convert to hex */ + +static void wbMD5_sigToString(unsigned char signature[16], char *str, + int len) { + unsigned char *sig_p; + char *str_p, *max_p; + unsigned int high, low; + + str_p = str; + max_p = str + len; + + for (sig_p = (unsigned char *)signature; + sig_p < (unsigned char *)signature + 16; sig_p++) { + high = *sig_p / 16; + low = *sig_p % 16; + /* account for 2 chars */ + if (str_p + 1 >= max_p) { + break; + } + *str_p++ = HEX_STRING[high]; + *str_p++ = HEX_STRING[low]; + } + /* account for 2 chars */ + if (str_p < max_p) { + *str_p++ = '\0'; + } +} + +#endif /* __WB_MD5_H__ */ diff --git a/CUDA_DeviceQuery/libwb/wbMPI.cpp b/CUDA_DeviceQuery/libwb/wbMPI.cpp new file mode 100644 index 0000000..546c1ed --- /dev/null +++ b/CUDA_DeviceQuery/libwb/wbMPI.cpp @@ -0,0 +1,75 @@ + +#ifdef WB_USE_MPI + +#include +#include +#include +#include "wb.h" + +static int rank = -1; + +int wbMPI_getRank() { + if (rank != -1) { + return rank; + } + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + return rank; +} + +int rankCount() { + int nRanks; + MPI_Comm_size(MPI_COMM_WORLD, &nRanks); + return nRanks; +} + +const char *wbMPI_getStringFromRank(int rank, int tag) { + if (isMasterQ) { + char *buf; + int bufSize; + MPI_Recv(&bufSize, 1, MPI_INT, rank, tag, MPI_COMM_WORLD, + MPI_STATUS_IGNORE); + buf = (char *)calloc(bufSize, sizeof(char)); + MPI_Recv(buf, bufSize, MPI_CHAR, rank, tag, MPI_COMM_WORLD, + MPI_STATUS_IGNORE); + return buf; + } + + return NULL; +} +void wbMPI_sendStringToMaster(const char *str, int tag) { + if (!isMasterQ) { + // we are going to send the string to the master + int len = (int)strlen(str) + 1; + MPI_Send(&len, 1, MPI_INT, 0, tag, MPI_COMM_WORLD); + MPI_Send((void *)str, len, MPI_CHAR, 0, tag, MPI_COMM_WORLD); + } + + return; +} + +int wbMPI_Init(int *argc, char ***argv) { + int err = MPI_SUCCESS; + err = MPI_Init(argc, argv); + // printf("argc = %d\n", *argc); + // err = MPI_Init(NULL, NULL); + // printf("rank = %d is master = %d\n", wbMPI_getRank(), isMasterQ); + // MPI_Barrier(MPI_COMM_WORLD); + return err; +} + +bool finalizedQ = false; + +extern "C" int wbMPI_Finalize(void) { + if (finalizedQ) { + return MPI_SUCCESS; + } + finalizedQ = true; + wb_atExit(); + return MPI_Finalize(); +} +extern "C" void wbMPI_Exit(void) { + wbMPI_Finalize(); + return; +} + +#endif /* WB_USE_MPI */ diff --git a/CUDA_DeviceQuery/libwb/wbMPI.h b/CUDA_DeviceQuery/libwb/wbMPI.h new file mode 100644 index 0000000..6275eaf --- /dev/null +++ b/CUDA_DeviceQuery/libwb/wbMPI.h @@ -0,0 +1,37 @@ + +#ifndef __WB_MPI_H__ +#define __WB_MPI_H__ + +#ifdef WB_USE_MPI + +#include +#include +#include + +#define isMasterQ ((wbMPI_getRank()) == 0) + +extern int wbMPI_getRank(); + +extern int rankCount(); + +extern const char *wbMPI_getStringFromRank(int rank, int tag); +extern void wbMPI_sendStringToMaster(const char *str, int tag); + +extern int wbMPI_Init(int *argc, char ***argv); + +extern bool finalizedQ; + +extern "C" int wbMPI_Finalize(void); +extern "C" void wbMPI_Exit(void); + +#define MPI_Finalize wbMPI_Finalize + +#else /* WB_USE_MPI */ +static inline int rankCount() { + return 1; +} +static inline int wbMPI_getRank() { + return 0; +} +#endif /* WB_USE_MPI */ +#endif /* __WB_MPI_H__ */ diff --git a/CUDA_DeviceQuery/libwb/wbMalloc.h b/CUDA_DeviceQuery/libwb/wbMalloc.h new file mode 100644 index 0000000..5d74be4 --- /dev/null +++ b/CUDA_DeviceQuery/libwb/wbMalloc.h @@ -0,0 +1,140 @@ + + +#ifndef __WB_MALLOC_H__ +#define __WB_MALLOC_H__ + +#ifdef WB_USE_CUSTOM_MALLOC +#ifdef __linux__ +#define THROW __THROW +#else +#define THROW +#endif + +static inline void *_malloc(size_t size) THROW { + if (size == 0) { + return NULL; + } else { + int err; + void *res = memmgr_alloc((ulong)size, &err); + if (err) { + fprintf(stderr, "<>:: Memory allocation failed\n"); + exit(1); + } else { + size_t ii = 0; + unsigned char *p = (unsigned char *)res; + while (ii++ < size) { + *p++ = 0; + } + return res; + } + } +} + +static inline void _free(void *ptr) THROW { + if (ptr != NULL) { + memmgr_free(ptr); + } +} + +static inline void *_calloc(size_t nmemb, size_t size) THROW { + return _malloc(nmemb * size); +} + +static inline void *_realloc(void *ptr, size_t size) THROW { + if (size == 0) { + free(ptr); + return NULL; + } else if (ptr == NULL) { + return malloc(size); + } else { + void *buf; + unsigned char *dst; + unsigned char *src; + size_t alloc_size, to_copy, i = 0; + + // Allocate new buffer + buf = malloc(size); + + if (buf != 0) { + // Find original allocation size + alloc_size = (size_t)memmgr_get_block_size(ptr); + to_copy = alloc_size; + if (to_copy > size) { + to_copy = size; + } + + // Copy data to new buffer + dst = (unsigned char *)buf; + src = (unsigned char *)ptr; + while (i++ < to_copy) { + *dst++ = *src++; + } + + // Free the old buffer + free(ptr); + } + + return buf; + } +} + +#define wbNew(type) ((type *)_malloc(sizeof(type))) +#define wbNewArray(type, len) ((type *)_malloc((len) * sizeof(type))) +#define wbMalloc(sz) _malloc(sz) +#define wbDelete(var) \ + _free(var); \ + var = NULL +#define wbFree(var) \ + _free(var); \ + var = NULL +#define wbRealloc(var, newSize) _realloc(var, newSize) +#define wbReallocArray(t, m, n) ((t *)_realloc(m, n * sizeof(t))) + +#define free _free +#define malloc _malloc +#define calloc _calloc +#define realloc _realloc + +#else /* WB_USE_CUSTOM_MALLOC */ + +static inline void *xMalloc(size_t sz) { + void *mem = NULL; + if (sz != 0) { + mem = malloc(sz); + } + return mem; +} + +static inline void xFree(void *mem) { + if (mem != NULL) { + free(mem); + } + return; +} + +static inline void *xRealloc(void *mem, size_t sz) { + if (mem == NULL) { + return NULL; + } else if (sz == 0) { + xFree(mem); + return NULL; + } else { + void *res = realloc(mem, sz); + wbAssert(res != NULL); + return res; + } +} + +#define wbNew(type) ((type *)wbMalloc(sizeof(type))) +#define wbNewArray(type, len) ((type *)wbMalloc((len) * sizeof(type))) +#define wbMalloc(sz) xMalloc(sz) +#define wbDelete(var) wbFree(var) +#define wbFree(var) \ + xFree(var); \ + var = NULL +#define wbRealloc(var, newSize) xRealloc(var, newSize) +#define wbReallocArray(t, m, n) ((t *)xRealloc(m, n * sizeof(t))) + +#endif /* WB_USE_CUSTOM_MALLOC */ + +#endif /* __WB_MALLOC_H__ */ diff --git a/CUDA_DeviceQuery/libwb/wbPPM.cpp b/CUDA_DeviceQuery/libwb/wbPPM.cpp new file mode 100644 index 0000000..86ab208 --- /dev/null +++ b/CUDA_DeviceQuery/libwb/wbPPM.cpp @@ -0,0 +1,199 @@ + +#include +#include "wb.h" + +static inline float _min(float x, float y) { + return x < y ? x : y; +} + +static inline float _max(float x, float y) { + return x > y ? x : y; +} + +static inline float _clamp(float x, float start, float end) { + return _min(_max(x, start), end); +} + +static const char *skipSpaces(const char *line) { + while (*line == ' ' || *line == '\t') { + line++; + if (*line == '\0') { + break; + } + } + return line; +} + +static char nextNonSpaceChar(const char *line0) { + const char *line = skipSpaces(line0); + return *line; +} + +static wbBool isComment(const char *line) { + char nextChar = nextNonSpaceChar(line); + if (nextChar == '\0') { + return wbTrue; + } else { + return nextChar == '#'; + } +} + +static void parseDimensions(const char *line0, int *width, int *height) { + const char *line = skipSpaces(line0); + sscanf(line, "%d %d", width, height); +} + +static void parseDimensions(const char *line0, int *width, int *height, + int *channels) { + const char *line = skipSpaces(line0); + sscanf(line, "%d %d %d", width, height, channels); +} + +static void parseDepth(const char *line0, int *depth) { + const char *line = skipSpaces(line0); + sscanf(line, "%d", depth); +} + +static char *nextLine(wbFile_t file) { + char *line = NULL; + while ((line = wbFile_readLine(file)) != NULL) { + if (!isComment(line)) { + break; + } + } + return line; +} + +wbImage_t wbPPM_import(const char *filename) { + wbImage_t img; + wbFile_t file; + char *header; + char *line; + int ii, jj, kk, channels; + int width, height, depth; + unsigned char *charData, *charIter; + float *imgData, *floatIter; + float scale; + + img = NULL; + + file = wbFile_open(filename, "rb"); + if (file == NULL) { + printf("Could not open %s\n", filename); + goto cleanup; + } + + header = wbFile_readLine(file); + if (header == NULL) { + printf("Could not read from %s\n", filename); + goto cleanup; + } else if (strcmp(header, "P6") != 0 && strcmp(header, "P6\n") != 0 && + strcmp(header, "P5") != 0 && strcmp(header, "P5\n") != 0 && + strcmp(header, "S6") != 0 && strcmp(header, "S6\n") != 0) { + printf("Could find magic number for %s\n", filename); + goto cleanup; + } + + // P5 are monochrome while P6/S6 are rgb + // S6 needs to parse number of channels out of file + if (strcmp(header, "P5") == 0 || strcmp(header, "P5\n") == 0) { + channels = 1; + line = nextLine(file); + parseDimensions(line, &width, &height); + } else if (strcmp(header, "P6") == 0 || strcmp(header, "P6\n") == 0) { + channels = 3; + line = nextLine(file); + parseDimensions(line, &width, &height); + } else { + line = nextLine(file); + parseDimensions(line, &width, &height, &channels); + } + + // the line now contains the depth information + line = nextLine(file); + parseDepth(line, &depth); + + // the rest of the lines contain the data in binary format + charData = (unsigned char *)wbFile_read( + file, width * channels * sizeof(unsigned char), height); + + img = wbImage_new(width, height, channels); + + imgData = wbImage_getData(img); + + charIter = charData; + floatIter = imgData; + + scale = 1.0f / ((float)depth); + + for (ii = 0; ii < height; ii++) { + for (jj = 0; jj < width; jj++) { + for (kk = 0; kk < channels; kk++) { + *floatIter = ((float)*charIter) * scale; + floatIter++; + charIter++; + } + } + } + +#ifdef LAZY_FILE_LOAD + wbDelete(charData); +#endif + +cleanup: + wbFile_close(file); + return img; +} + +void wbPPM_export(const char *filename, wbImage_t img) { + int ii; + int jj; + int kk; + int depth; + int width; + int height; + int channels; + wbFile_t file; + float *floatIter; + unsigned char *charData; + unsigned char *charIter; + + file = wbFile_open(filename, "wb+"); + + width = wbImage_getWidth(img); + height = wbImage_getHeight(img); + channels = wbImage_getChannels(img); + depth = 255; + + if (channels == 1) { + wbFile_writeLine(file, "P5"); + } else { + wbFile_writeLine(file, "P6"); + } + wbFile_writeLine(file, "#Created via wbPPM Export"); + wbFile_writeLine(file, wbString(width, " ", height)); + wbFile_writeLine(file, wbString(depth)); + + charData = wbNewArray(unsigned char, width *height *channels); + + charIter = charData; + floatIter = wbImage_getData(img); + + for (ii = 0; ii < height; ii++) { + for (jj = 0; jj < width; jj++) { + for (kk = 0; kk < channels; kk++) { + *charIter = (unsigned char)ceil(_clamp(*floatIter, 0, 1) * depth); + floatIter++; + charIter++; + } + } + } + + wbFile_write(file, charData, width * channels * sizeof(unsigned char), + height); + + wbDelete(charData); + wbFile_delete(file); + + return; +} diff --git a/CUDA_DeviceQuery/libwb/wbPPM.h b/CUDA_DeviceQuery/libwb/wbPPM.h new file mode 100644 index 0000000..d589b36 --- /dev/null +++ b/CUDA_DeviceQuery/libwb/wbPPM.h @@ -0,0 +1,11 @@ + + +#ifndef __wbPPM_H__ +#define __wbPPM_H__ + +START_EXTERN_C +wbImage_t wbPPM_import(const char *filename); +void wbPPM_export(const char *filename, wbImage_t img); +END_EXTERN_C + +#endif /* __wbPPM_H__ */ diff --git a/CUDA_DeviceQuery/libwb/wbPath.cpp b/CUDA_DeviceQuery/libwb/wbPath.cpp new file mode 100644 index 0000000..0d93e2b --- /dev/null +++ b/CUDA_DeviceQuery/libwb/wbPath.cpp @@ -0,0 +1,42 @@ +#include "wb.h" + +char *wbPath_join(const char *p1, const char *p2) { + size_t s1 = strlen(p1); + size_t s2 = strlen(p2); + char *res = + wbNewArray(char, s1 + 1 /* seperator */ + s2 + 1 /* terminator */); + memcpy(res, p1, s1); + char *iter = res + s1; + *iter++ = wbDirectorySeperator; + memcpy(iter, p2, s2); + iter += s2; + *iter = '\0'; + return res; +} + +char *wbPath_join(const char *p1, const char *p2, const char *p3) { + char *p12 = wbPath_join(p1, p2); + char *res = wbPath_join(p12, p3); + wbDelete(p12); + return res; +} + +char *wbPath_join(const char *p1, const char *p2, const char *p3, + const char *p4) { + char *p123 = wbPath_join(p1, p2, p3); + char *res = wbPath_join(p123, p4); + wbDelete(p123); + return res; +} + +char *wbPath_join(const std::string &p1, const std::string &p2) { + return wbPath_join(p1.c_str(), p2.c_str()); +} +char *wbPath_join(const std::string &p1, const std::string &p2, + const std::string &p3) { + return wbPath_join(p1.c_str(), p2.c_str(), p3.c_str()); +} +char *wbPath_join(const std::string &p1, const std::string &p2, + const std::string &p3, const std::string &p4) { + return wbPath_join(p1.c_str(), p2.c_str(), p3.c_str(), p4.c_str()); +} \ No newline at end of file diff --git a/CUDA_DeviceQuery/libwb/wbPath.h b/CUDA_DeviceQuery/libwb/wbPath.h new file mode 100644 index 0000000..0dd3187 --- /dev/null +++ b/CUDA_DeviceQuery/libwb/wbPath.h @@ -0,0 +1,30 @@ +#ifndef __WB_PATH_H__ +#define __WB_PATH_H__ + +char *wbPath_join(const char *p1, const char *p2); +char *wbPath_join(const char *p1, const char *p2, const char *p3); +char *wbPath_join(const char *p1, const char *p2, const char *p3, + const char *p4); + +char *wbPath_join(const std::string &p1, const std::string &p2); +char *wbPath_join(const std::string &p1, const std::string &p2, + const std::string &p3); +char *wbPath_join(const std::string &p1, const std::string &p2, + const std::string &p3, const std::string &p4); + +template +static char *wbPath_join(const T1 &p1, const T2 &p2) { + return wbPath_join(wbString(p1), wbString(p2)); +} +template +static char *wbPath_join(const T1 &p1, const T2 &p2, const T3 &p3) { + return wbPath_join(wbString(p1), wbString(p2), wbString(p3)); +} +template +static char *wbPath_join(const T1 &p1, const T2 &p2, const T3 &p3, + const T4 &p4) { + return wbPath_join(wbString(p1), wbString(p2), wbString(p3), + wbString(p4)); +} + +#endif /* __WB_PATH_H__ */ diff --git a/CUDA_DeviceQuery/libwb/wbSolution.cpp b/CUDA_DeviceQuery/libwb/wbSolution.cpp new file mode 100644 index 0000000..703f410 --- /dev/null +++ b/CUDA_DeviceQuery/libwb/wbSolution.cpp @@ -0,0 +1,271 @@ + +#include "wb.h" + +char *solutionJSON = NULL; +static string _solution_correctQ(""); + +static void _onUnsameImageFunction(string str) { + _solution_correctQ = str; +} + +template +static wbBool wbSolution_listCorrectQ(const char *expectedOutputFile, + wbSolution_t sol, const char *type) { + wbBool res; + T *expectedData; + int expectedRows, expectedColumns; + + expectedData = (T *)wbImport(expectedOutputFile, &expectedRows, + &expectedColumns, type); + + if (expectedData == NULL) { + _solution_correctQ = "Failed to open expected output file."; + res = wbFalse; + } else if (expectedRows != wbSolution_getRows(sol)) { + wbLog(TRACE, "Number of rows in the solution is ", + wbSolution_getRows(sol), ". Expected number of rows is ", + expectedRows, "."); + _solution_correctQ = + "The number of rows in the solution did not match " + "that of the expected results."; + res = wbFalse; + } else if (expectedColumns != wbSolution_getColumns(sol)) { + wbLog(TRACE, "Number of columns in the solution is ", + wbSolution_getColumns(sol), ". Expected number of columns is ", + expectedColumns, "."); + _solution_correctQ = "The number of columns in the solution did not " + "match that of the expected results."; + res = wbFalse; + } else { + int ii, jj, idx; + T *solutionData; + + solutionData = (T *)wbSolution_getData(sol); + + for (ii = 0; ii < expectedRows; ii++) { + for (jj = 0; jj < expectedColumns; jj++) { + idx = ii * expectedColumns + jj; + if (wbUnequalQ(expectedData[idx], solutionData[idx])) { + string str; + if (expectedColumns == 1) { + str = wbString( + "The solution did not match the expected results at row ", + ii, ". Expecting ", expectedData[idx], " but got ", + solutionData[idx], "."); + } else { + str = wbString("The solution did not match the expected " + "results at column ", + jj, " and row ", ii, ". Expecting ", + expectedData[idx], " but got ", + solutionData[idx], "."); + } + _solution_correctQ = str; + res = wbFalse; + goto matrixCleanup; + } + } + } + + res = wbTrue; + matrixCleanup: + if (expectedData != NULL) { + wbFree(expectedData); + } + } + return res; +} + +static wbBool wbSolution_correctQ(char *expectedOutputFile, + wbSolution_t sol) { + if (expectedOutputFile == NULL) { + _solution_correctQ = "Failed to determined the expected output file."; + return wbFalse; + } else if (!wbFile_existsQ(expectedOutputFile)) { + _solution_correctQ = + wbString("The file ", expectedOutputFile, " does not exist."); + return wbFalse; + } else if (wbString_sameQ(wbSolution_getType(sol), "image")) { + wbBool res; + wbImage_t solutionImage = NULL; + wbImage_t expectedImage = wbImport(expectedOutputFile); + if (expectedImage == NULL) { + _solution_correctQ = "Failed to open expected output file."; + res = wbFalse; + } else if (wbImage_getWidth(expectedImage) != + wbSolution_getWidth(sol)) { + _solution_correctQ = + "The image width of the expected image does not " + "match that of the solution."; + res = wbFalse; + } else if (wbImage_getHeight(expectedImage) != + wbSolution_getHeight(sol)) { + _solution_correctQ = + "The image height of the expected image does not " + "match that of the solution."; + res = wbFalse; + } else if (wbImage_getChannels(expectedImage) != + wbSolution_getChannels(sol)) { + _solution_correctQ = + "The image channels of the expected image does not " + "match that of the solution."; + res = wbFalse; + } else { + solutionImage = (wbImage_t)wbSolution_getData(sol); + wbAssert(solutionImage != NULL); + res = wbImage_sameQ(solutionImage, expectedImage, + _onUnsameImageFunction); + } + if (expectedImage != NULL) { + wbImage_delete(expectedImage); + } + return res; + } else if (wbString_sameQ(wbSolution_getType(sol), "histogram")) { + return wbSolution_listCorrectQ(expectedOutputFile, sol, + "Integer"); + } else if (wbString_sameQ(wbSolution_getType(sol), "integral_vector")) { + return wbSolution_listCorrectQ(expectedOutputFile, sol, + "Integer"); + } else if (wbString_sameQ(wbSolution_getType(sol), "vector") || + wbString_sameQ(wbSolution_getType(sol), "matrix")) { + return wbSolution_listCorrectQ(expectedOutputFile, sol, + "Real"); + } else { + wbAssert(wbFalse); + return wbFalse; + } +} + +wbBool wbSolution(char *expectedOutputFile, char *outputFile, char *type0, + void *data, int rows, int columns, int depth) { + char *type; + wbBool res; + wbSolution_t sol; + + if (expectedOutputFile == NULL || data == NULL || type0 == NULL) { + wbLog(ERROR, "Failed to grade solution"); + return wbFalse; + } + + type = wbString_toLower(type0); + + if (_solution_correctQ != "") { + _solution_correctQ = ""; + } + + wbSolution_setOutputFile(sol, outputFile); + wbSolution_setType(sol, type); + wbSolution_setData(sol, data); + wbSolution_setRows(sol, rows); + wbSolution_setColumns(sol, columns); + wbSolution_setDepth(sol, depth); + + res = wbSolution_correctQ(expectedOutputFile, sol); + + if (outputFile != NULL) { + if (wbString_sameQ(type, "image")) { + wbImage_t inputImage = (wbImage_t)data; + wbImage_t img = wbImage_new(wbImage_getWidth(inputImage), + wbImage_getHeight(inputImage), + wbImage_getChannels(inputImage)); + memcpy(wbImage_getData(img), wbImage_getData(inputImage), + rows * columns * wbImage_channels * sizeof(wbReal_t)); + wbExport(outputFile, img); + wbImage_delete(img); + } else if (wbString_sameQ(type, "integral_vector")) { + wbExport(outputFile, (int *)data, rows, columns); + } else if (wbString_sameQ(type, "vector") || + wbString_sameQ(type, "matrix")) { + wbExport(outputFile, (wbReal_t *)data, rows, columns); + } else if (wbString_sameQ(type, "histogram")) { + wbExport(outputFile, (unsigned char *)data, rows, columns); + } else if (wbString_sameQ(type, "text")) { + wbExport_text(outputFile, (unsigned char *)data, rows * columns); + } + } + + wbFree(type); + + return res; +} + +wbBool wbSolution(char *expectedOutputFile, char *outputFile, char *type0, + void *data, int rows, int columns) { + return wbSolution(expectedOutputFile, outputFile, type0, data, rows, + columns, 1); +} + +wbBool wbSolution(wbArg_t arg, void *data, int rows, int columns, + int depth) { + char *type; + wbBool res; + char *expectedOutputFile; + char *outputFile; + stringstream ss; + + expectedOutputFile = wbArg_getExpectedOutputFile(arg); + outputFile = wbArg_getOutputFile(arg); + type = wbArg_getType(arg); + + wbAssert(type != NULL); + wbAssert(expectedOutputFile != NULL); + wbAssert(outputFile != NULL); + + res = wbSolution(expectedOutputFile, outputFile, type, data, rows, + columns, depth); + + if (WB_USE_JSON11) { + json11::Json json; + if (res) { + json = json11::Json::object{{"correctq", true}, + {"message", "The solution is correct"}}; + } else { + json = json11::Json::object{{"correctq", false}, + {"message", _solution_correctQ}}; + } + +#ifdef wbLogger_printOnLog + if (wbLogger_printOnLog) { + json11::Json e = +//PMO +#ifndef _MSC_VER + json11::Json::object{{"type", "solution"}, {"data", json}}; +#else + json11::Json::object{{"data", json }, {"type", "solution" }}; +#endif + std::cout << e.dump() << std::endl; + } +#endif /* wbLogger_printOnLog */ + + solutionJSON = wbString_duplicate(json.string_value()); + } else { + if (res) { + ss << "{\n"; + ss << wbString_quote("correctq") << ": true,\n"; + ss << wbString_quote("message") << ": " + << wbString_quote("Solution is correct.") << "\n"; + ss << "}"; + } else { + ss << "{\n"; + ss << wbString_quote("correctq") << ": false,\n"; + ss << wbString_quote("message") << ": " + << wbString_quote(_solution_correctQ) << "\n"; + ss << "}"; + } + solutionJSON = wbString_duplicate(ss.str()); + } + + return res; +} + +wbBool wbSolution(wbArg_t arg, void *data, int rows, int columns) { + return wbSolution(arg, data, rows, columns, 1); +} + +EXTERN_C wbBool wbSolution(wbArg_t arg, void *data, int rows) { + return wbSolution(arg, data, rows, 1); +} + +wbBool wbSolution(wbArg_t arg, wbImage_t img) { + return wbSolution(arg, img, wbImage_getHeight(img), + wbImage_getWidth(img), wbImage_getChannels(img)); +} diff --git a/CUDA_DeviceQuery/libwb/wbSolution.h b/CUDA_DeviceQuery/libwb/wbSolution.h new file mode 100644 index 0000000..f18d07d --- /dev/null +++ b/CUDA_DeviceQuery/libwb/wbSolution.h @@ -0,0 +1,40 @@ + + +#ifndef __WB_SOLUTION_H__ +#define __WB_SOLUTION_H__ + +typedef struct st_wbSolution_t { + char *type; + char *outputFile; + void *data; + int rows; + int columns; + int depth; +} wbSolution_t; + +#define wbSolution_getType(sol) ((sol).type) +#define wbSolution_getOutputFile(sol) ((sol).outputFile) +#define wbSolution_getData(sol) ((sol).data) +#define wbSolution_getRows(sol) ((sol).rows) +#define wbSolution_getColumns(sol) ((sol).columns) +#define wbSolution_getDepth(sol) ((sol).depth) + +#define wbSolution_getHeight wbSolution_getRows +#define wbSolution_getWidth wbSolution_getColumns +#define wbSolution_getChannels wbSolution_getDepth + +#define wbSolution_setType(sol, val) (wbSolution_getType(sol) = val) +#define wbSolution_setOutputFile(sol, val) \ + (wbSolution_getOutputFile(sol) = val) +#define wbSolution_setData(sol, val) (wbSolution_getData(sol) = val) +#define wbSolution_setRows(sol, val) (wbSolution_getRows(sol) = val) +#define wbSolution_setColumns(sol, val) (wbSolution_getColumns(sol) = val) +#define wbSolution_setDepth(sol, val) (wbSolution_getDepth(sol) = val) + +wbBool wbSolution(char *expectedOutputFile, char *outputFile, char *type0, + void *data, int rows, int columns); +wbBool wbSolution(wbArg_t arg, void *data, int rows, int columns); +EXTERN_C wbBool wbSolution(wbArg_t arg, void *data, int rows); +wbBool wbSolution(wbArg_t arg, wbImage_t img); + +#endif /* __WB_SOLUTION_H__ */ diff --git a/CUDA_DeviceQuery/libwb/wbSparse.cpp b/CUDA_DeviceQuery/libwb/wbSparse.cpp new file mode 100644 index 0000000..9cdcba3 --- /dev/null +++ b/CUDA_DeviceQuery/libwb/wbSparse.cpp @@ -0,0 +1,82 @@ + +#include "wb.h" + +static void sort(int *data, int *key, int start, int end) { + if ((end - start + 1) > 1) { + int left = start, right = end; + int pivot = key[right]; + while (left <= right) { + while (key[left] > pivot) { + left = left + 1; + } + while (key[right] < pivot) { + right = right - 1; + } + if (left <= right) { + int tmp = key[left]; + key[left] = key[right]; + key[right] = tmp; + tmp = data[left]; + data[left] = data[right]; + data[right] = tmp; + left = left + 1; + right = right - 1; + } + } + sort(data, key, start, right); + sort(data, key, left, end); + } +} + +EXTERN_C void CSRToJDS(int dim, int *csrRowPtr, int *csrColIdx, + float *csrData, int **jdsRowPerm, int **jdsRowNNZ, + int **jdsColStartIdx, int **jdsColIdx, + float **jdsData) { + // Row Permutation Vector + *jdsRowPerm = (int *)malloc(sizeof(int) * dim); + for (int rowIdx = 0; rowIdx < dim; ++rowIdx) { + (*jdsRowPerm)[rowIdx] = rowIdx; + } + + // Number of non-zeros per row + *jdsRowNNZ = (int *)malloc(sizeof(int) * dim); + for (int rowIdx = 0; rowIdx < dim; ++rowIdx) { + (*jdsRowNNZ)[rowIdx] = csrRowPtr[rowIdx + 1] - csrRowPtr[rowIdx]; + } + + // Sort rows by number of non-zeros + sort(*jdsRowPerm, *jdsRowNNZ, 0, dim - 1); + + // Starting point of each compressed column + int maxRowNNZ = (*jdsRowNNZ)[0]; // Largest number of non-zeros per row + DEBUG(printf("jdsRowNNZ = %d\n", maxRowNNZ)); + *jdsColStartIdx = (int *)malloc(sizeof(int) * maxRowNNZ); + (*jdsColStartIdx)[0] = 0; // First column starts at 0 + for (int col = 0; col < maxRowNNZ - 1; ++col) { + // Count the number of rows with entries in this column + int count = 0; + for (int idx = 0; idx < dim; ++idx) { + if ((*jdsRowNNZ)[idx] > col) { + ++count; + } + } + (*jdsColStartIdx)[col + 1] = (*jdsColStartIdx)[col] + count; + } + + // Sort the column indexes and data + const int NNZ = csrRowPtr[dim]; + DEBUG(printf("NNZ = %d\n", NNZ)); + *jdsColIdx = (int *)malloc(sizeof(int) * NNZ); + DEBUG(printf("dim = %d\n", dim)); + *jdsData = (float *)malloc(sizeof(float) * NNZ); + for (int idx = 0; idx < dim; ++idx) { // For every row + int row = (*jdsRowPerm)[idx]; + int rowNNZ = (*jdsRowNNZ)[idx]; + for (int nnzIdx = 0; nnzIdx < rowNNZ; ++nnzIdx) { + int jdsPos = (*jdsColStartIdx)[nnzIdx] + idx; + int csrPos = csrRowPtr[row] + nnzIdx; + (*jdsColIdx)[jdsPos] = csrColIdx[csrPos]; + (*jdsData)[jdsPos] = csrData[csrPos]; + } + } +} diff --git a/CUDA_DeviceQuery/libwb/wbSparse.h b/CUDA_DeviceQuery/libwb/wbSparse.h new file mode 100644 index 0000000..c04a857 --- /dev/null +++ b/CUDA_DeviceQuery/libwb/wbSparse.h @@ -0,0 +1,10 @@ + +#ifndef __WB_SPARSE_H__ +#define __WB_SPARSE_H__ + +EXTERN_C void CSRToJDS(int dim, int *csrRowPtr, int *csrColIdx, + float *csrData, int **jdsRowPerm, int **jdsRowNNZ, + int **jdsColStartIdx, int **jdsColIdx, + float **jdsData); + +#endif /* __WB_SPARSE_H__ */ diff --git a/CUDA_DeviceQuery/libwb/wbString.h b/CUDA_DeviceQuery/libwb/wbString.h new file mode 100644 index 0000000..65e52f8 --- /dev/null +++ b/CUDA_DeviceQuery/libwb/wbString.h @@ -0,0 +1,324 @@ + + +#ifndef __WB_STRING_H__ +#define __WB_STRING_H__ + +#include +#include +#include +#include +#include +#include +#include "wb.h" + +using std::string; +using std::vector; +using std::stringstream; +using std::exception; + +template +static inline string wbString(const T &x); + +static inline void wbString_replace(string &value, string const &search, + string const &replace) { + for (string::size_type next = value.find(search); next != string::npos; + next = value.find(search, next)) { + value.replace(next, search.length(), replace); + next += replace.length(); + } +} + +static inline string wbString_quote(string str) { + string s = str; + wbString_replace(s, "\\", "\\\\"); + s = "\"" + s + "\""; + return s; +} + +static inline string wbString_quote(const char *str) { + if (str == NULL) { + return wbString_quote(""); + } else { + return wbString_quote(string(str)); + } +} + +static inline char *wbString_duplicate(const char *str) { + if (str == NULL) { + return NULL; + } else { + char *newstr; + size_t len = strlen(str); + newstr = wbNewArray(char, len + 1); + memcpy(newstr, str, len * sizeof(char)); + newstr[len] = '\0'; + return newstr; + } +} + +static inline char *wbString_duplicate(std::string str) { + return wbString_duplicate(str.c_str()); +} + +static inline string wbString(void) { + string s = ""; + return s; +} + +template +static inline string wbString(const T &x) { + try { + stringstream ss; + ss << x; + return ss.str(); + } catch (exception &e) { + return string(); + } +} + +template <> +inline string wbString(const bool &x) { + return x ? "True" : "False"; +} + +template <> +inline string wbString(const vector &x) { + stringstream ss; + ss << "{"; + for (size_t ii = 0; ii < x.size(); ii++) { + ss << wbString_quote(x[ii]); + if (ii != x.size() - 1) { + ss << ", "; + } + } + ss << "}"; + + return ss.str(); +} + +template <> +inline string wbString(const vector &x) { + stringstream ss; + ss << "{"; + for (size_t ii = 0; ii < x.size(); ii++) { + ss << x[ii]; + if (ii != x.size() - 1) { + ss << ", "; + } + } + ss << "}"; + + return ss.str(); +} + +template <> +inline string wbString(const vector &x) { + stringstream ss; + ss << "{"; + for (size_t ii = 0; ii < x.size(); ii++) { + ss << x[ii]; + if (ii != x.size() - 1) { + ss << ", "; + } + } + ss << "}"; + + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1) { + stringstream ss; + ss << wbString(x0) << wbString(x1); + + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1, const T2 &x2) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2); + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1, const T2 &x2, + const T3 &x3) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2) << wbString(x3); + + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1, const T2 &x2, + const T3 &x3, const T4 &x4) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2) << wbString(x3) + << wbString(x4); + + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1, const T2 &x2, + const T3 &x3, const T4 &x4, const T5 &x5) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2) << wbString(x3) + << wbString(x4) << wbString(x5); + + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1, const T2 &x2, + const T3 &x3, const T4 &x4, const T5 &x5, + const T6 &x6) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2) << wbString(x3) + << wbString(x4) << wbString(x5) << wbString(x6); + + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1, const T2 &x2, + const T3 &x3, const T4 &x4, const T5 &x5, + const T6 &x6, const T7 &x7) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2) << wbString(x3) + << wbString(x4) << wbString(x5) << wbString(x6) << wbString(x7); + + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1, const T2 &x2, + const T3 &x3, const T4 &x4, const T5 &x5, + const T6 &x6, const T7 &x7, const T8 &x8) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2) << wbString(x3) + << wbString(x4) << wbString(x5) << wbString(x6) << wbString(x7) + << wbString(x8); + + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1, const T2 &x2, + const T3 &x3, const T4 &x4, const T5 &x5, + const T6 &x6, const T7 &x7, const T8 &x8, + const T9 &x9) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2) << wbString(x3) + << wbString(x4) << wbString(x5) << wbString(x6) << wbString(x7) + << wbString(x8) << wbString(x9); + + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1, const T2 &x2, + const T3 &x3, const T4 &x4, const T5 &x5, + const T6 &x6, const T7 &x7, const T8 &x8, + const T9 &x9, const T10 &x10) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2) << wbString(x3) + << wbString(x4) << wbString(x5) << wbString(x6) << wbString(x7) + << wbString(x8) << wbString(x9) << wbString(x10); + + return ss.str(); +} + +template +static inline string +wbString(const T0 &x0, const T1 &x1, const T2 &x2, const T3 &x3, + const T4 &x4, const T5 &x5, const T6 &x6, const T7 &x7, + const T8 &x8, const T9 &x9, const T10 &x10, const T11 &x11) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2) << wbString(x3) + << wbString(x4) << wbString(x5) << wbString(x6) << wbString(x7) + << wbString(x8) << wbString(x9) << wbString(x10) << wbString(x11); + + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1, const T2 &x2, + const T3 &x3, const T4 &x4, const T5 &x5, + const T6 &x6, const T7 &x7, const T8 &x8, + const T9 &x9, const T10 &x10, const T11 &x11, + const T12 &x12) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2) << wbString(x3) + << wbString(x4) << wbString(x5) << wbString(x6) << wbString(x7) + << wbString(x8) << wbString(x9) << wbString(x10) << wbString(x11) + << wbString(x12); + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1, const T2 &x2, + const T3 &x3, const T4 &x4, const T5 &x5, + const T6 &x6, const T7 &x7, const T8 &x8, + const T9 &x9, const T10 &x10, const T11 &x11, + const T12 &x12, const T13 &x13) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2) << wbString(x3) + << wbString(x4) << wbString(x5) << wbString(x6) << wbString(x7) + << wbString(x8) << wbString(x9) << wbString(x10) << wbString(x11) + << wbString(x12) << wbString(x13); + return ss.str(); +} + +template +static inline wbBool wbString_sameQ(const X &x, const Y &y) { + string xs = wbString(x); + string ys = wbString(y); + return strcmp(xs.c_str(), ys.c_str()) == 0; +} + +static inline wbBool wbString_sameQ(const string &x, const string &y) { + return x.compare(y) == 0; +} + +static inline char *wbString_toLower(const char *str) { + if (str == NULL) { + return NULL; + } else { + char *res, *iter; + + res = iter = wbString_duplicate(str); + while (*iter != '\0') { + *iter++ = tolower(*str++); + } + return res; + } +} + +static inline wbBool wbString_startsWith(const char *str, + const char *prefix) { + while (*prefix != '\0') { + if (*str == '\0' || *str != *prefix) { + return wbFalse; + } + str++; + prefix++; + } + return wbTrue; +} + +#endif /* __WB_STRING_H__ */ diff --git a/CUDA_DeviceQuery/libwb/wbThrust.h b/CUDA_DeviceQuery/libwb/wbThrust.h new file mode 100644 index 0000000..e2d3160 --- /dev/null +++ b/CUDA_DeviceQuery/libwb/wbThrust.h @@ -0,0 +1,15 @@ + +#ifndef __WB_THRUST_H__ +#define __WB_THRUST_H__ + +#ifdef WB_USE_CUDA +#include +#include +#include +#include +#include +#include + +#endif /* WB_USE_CUDA */ + +#endif /* __WB_THRUST_H__ */ diff --git a/CUDA_DeviceQuery/libwb/wbTimer.cpp b/CUDA_DeviceQuery/libwb/wbTimer.cpp new file mode 100644 index 0000000..c9fbdb8 --- /dev/null +++ b/CUDA_DeviceQuery/libwb/wbTimer.cpp @@ -0,0 +1,493 @@ +#include "wb.h" + +#ifdef WB_USE_WINDOWS +uint64_t _hrtime_frequency = 0; +#endif /* WB_USE_WINDOWS */ +wbTimer_t _timer = NULL; + +#ifdef WB_USE_DARWIN +static double o_timebase = 0; +static uint64_t o_timestart = 0; +#endif /* WB_USE_DARWIN */ + +uint64_t _hrtime(void) { +#define NANOSEC ((uint64_t)1e9) +#ifdef WB_USE_WINDOWS + LARGE_INTEGER counter; + if (!QueryPerformanceCounter(&counter)) { + return 0; + } + return ((uint64_t)counter.LowPart * NANOSEC / _hrtime_frequency) + + (((uint64_t)counter.HighPart * NANOSEC / _hrtime_frequency) + << 32); +#else + struct timespec ts; +#ifdef WB_USE_DARWIN +#define O_NANOSEC (+1.0E-9) +#define O_GIGA UINT64_C(1000000000) + if (!o_timestart) { + mach_timebase_info_data_t tb{}; + mach_timebase_info(&tb); + o_timebase = tb.numer; + o_timebase /= tb.denom; + o_timestart = mach_absolute_time(); + } + double diff = (mach_absolute_time() - o_timestart) * o_timebase; + ts.tv_sec = diff * O_NANOSEC; + ts.tv_nsec = diff - (ts.tv_sec * O_GIGA); +#undef O_NANOSEC +#undef O_GIGA +#else /* WB_USE_DARWIN */ + clock_gettime(CLOCK_MONOTONIC, &ts); +#endif /* WB_USE_DARWIN */ + return (((uint64_t)ts.tv_sec) * NANOSEC + ts.tv_nsec); +#endif /* WB_USE_WINDOWS */ +#undef NANOSEC +} + +static inline uint64_t getTime(void) { +#ifdef WB_USE_CUDA + cudaDeviceSynchronize(); +#endif /* WB_USE_CUDA */ + return _hrtime(); +} + +static inline wbTimerNode_t wbTimerNode_new(int id, wbTimerKind_t kind, + const char *file, + const char *fun, + int startLine) { + wbTimerNode_t node = wbNew(struct st_wbTimerNode_t); + wbTimerNode_setId(node, id); + wbTimerNode_setMPIRank(node, wbMPI_getRank()); + wbTimerNode_setLevel(node, 0); + wbTimerNode_setStoppedQ(node, wbFalse); + wbTimerNode_setKind(node, kind); + wbTimerNode_setStartTime(node, 0); + wbTimerNode_setEndTime(node, 0); + wbTimerNode_setElapsedTime(node, 0); + wbTimerNode_setStartLine(node, startLine); + wbTimerNode_setEndLine(node, 0); + wbTimerNode_setStartFunction(node, fun); + wbTimerNode_setEndFunction(node, NULL); + wbTimerNode_setStartFile(node, file); + wbTimerNode_setEndFile(node, NULL); + wbTimerNode_setNext(node, NULL); + wbTimerNode_setPrevious(node, NULL); + wbTimerNode_setParent(node, NULL); + wbTimerNode_setMessage(node, NULL); + return node; +} + +static inline void wbTimerNode_delete(wbTimerNode_t node) { + if (node != NULL) { + if (wbTimerNode_getMessage(node)) { + wbDelete(wbTimerNode_getMessage(node)); + } + wbDelete(node); + } +} + +static inline const char *_nodeKind(wbTimerKind_t kind) { + switch (kind) { + case wbTimerKind_Generic: + return "Generic"; + case wbTimerKind_IO: + return "IO"; + case wbTimerKind_GPU: + return "GPU"; + case wbTimerKind_Copy: + return "Copy"; + case wbTimerKind_Driver: + return "Driver"; + case wbTimerKind_CopyAsync: + return "CopyAsync"; + case wbTimerKind_Compute: + return "Compute"; + case wbTimerKind_CPUGPUOverlap: + return "CPUGPUOverlap"; + } + return "Undefined"; +} + +static inline json11::Json wbTimerNode_toJSONObject(wbTimerNode_t node) { + json11::Json json = json11::Json::object{ + {"id", wbTimerNode_getId(node)}, + {"mpi_rank", wbTimerNode_getMPIRank(node)}, + {"stopped", wbTimerNode_stoppedQ(node)}, + {"kind", _nodeKind(wbTimerNode_getKind(node))}, + {"start_time", wbTimerNode_getStartTime(node)}, + {"end_time", wbTimerNode_getEndTime(node)}, + {"elapsed_time", wbTimerNode_getElapsedTime(node)}, + {"start_line", wbTimerNode_getStartLine(node)}, + {"end_line", wbTimerNode_getEndLine(node)}, + {"start_function", wbTimerNode_getStartFunction(node)}, + {"end_function", wbTimerNode_getEndFunction(node)}, + {"start_file", wbTimerNode_getStartFile(node)}, + {"end_file", wbTimerNode_getEndFile(node)}, + {"parent_id", wbTimerNode_hasParent(node) + ? wbTimerNode_getId(wbTimerNode_getParent(node)) + : -1}, + {"message", wbTimerNode_getMessage(node)}, + }; + return json; +} + +static inline string wbTimerNode_toJSON(wbTimerNode_t node) { + if (node == NULL) { + return ""; + } else if (WB_USE_JSON11) { + json11::Json json = wbTimerNode_toJSONObject(node); + return json.string_value(); + } else { + stringstream ss; + + ss << "{\n"; + ss << wbString_quote("id") << ":" << wbTimerNode_getId(node) << ",\n"; + ss << wbString_quote("mpi_rank") << ":" << wbTimerNode_getMPIRank(node) + << ",\n"; + ss << wbString_quote("stopped") << ":" + << wbString(wbTimerNode_stoppedQ(node) ? "true" : "false") << ",\n"; + ss << wbString_quote("kind") << ":" + << wbString_quote(_nodeKind(wbTimerNode_getKind(node))) << ",\n"; + ss << wbString_quote("start_time") << ":" + << wbTimerNode_getStartTime(node) << ",\n"; + ss << wbString_quote("end_time") << ":" << wbTimerNode_getEndTime(node) + << ",\n"; + ss << wbString_quote("elapsed_time") << ":" + << wbTimerNode_getElapsedTime(node) << ",\n"; + ss << wbString_quote("start_line") << ":" + << wbTimerNode_getStartLine(node) << ",\n"; + ss << wbString_quote("end_line") << ":" << wbTimerNode_getEndLine(node) + << ",\n"; + ss << wbString_quote("start_function") << ":" + << wbString_quote(wbTimerNode_getStartFunction(node)) << ",\n"; + ss << wbString_quote("end_function") << ":" + << wbString_quote(wbTimerNode_getEndFunction(node)) << ",\n"; + ss << wbString_quote("start_file") << ":" + << wbString_quote(wbTimerNode_getStartFile(node)) << ",\n"; + ss << wbString_quote("end_file") << ":" + << wbString_quote(wbTimerNode_getEndFile(node)) << ",\n"; + ss << wbString_quote("parent_id") << ":" + << wbString(wbTimerNode_hasParent(node) + ? wbTimerNode_getId(wbTimerNode_getParent(node)) + : -1) + << ",\n"; + ss << wbString_quote("message") << ":" + << wbString_quote(wbTimerNode_getMessage(node)) << "\n"; + ss << "}"; + + return ss.str(); + } +} + +static inline string wbTimerNode_toXML(wbTimerNode_t node) { + if (node == NULL) { + return ""; + } else { + stringstream ss; + + ss << "\n"; + ss << "" << wbTimerNode_getId(node) << "\n"; + ss << "" + << wbString(wbTimerNode_stoppedQ(node) ? "true" : "false") + << "\n"; + ss << "" << _nodeKind(wbTimerNode_getKind(node)) << "\n"; + ss << "" << wbTimerNode_getStartTime(node) + << "\n"; + ss << "" << wbTimerNode_getEndTime(node) << "\n"; + ss << "" << wbTimerNode_getElapsedTime(node) + << "\n"; + ss << "" << wbTimerNode_getStartLine(node) + << "\n"; + ss << "" << wbTimerNode_getEndLine(node) << "\n"; + ss << "" << wbTimerNode_getStartFunction(node) + << "\n"; + ss << "" << wbTimerNode_getEndFunction(node) + << "\n"; + ss << "" << wbTimerNode_getStartFile(node) + << "\n"; + ss << "" << wbTimerNode_getEndFile(node) << "\n"; + ss << "" + << wbString(wbTimerNode_hasParent(node) + ? wbTimerNode_getId(wbTimerNode_getParent(node)) + : -1) + << "\n"; + ss << "" << wbTimerNode_getMessage(node) << "\n"; + ss << "\n"; + + return ss.str(); + } +} + +#define wbTimer_getLength(timer) ((timer)->length) +#define wbTimer_getHead(timer) ((timer)->head) +#define wbTimer_getTail(timer) ((timer)->tail) +#define wbTimer_getStartTime(timer) ((timer)->startTime) +#define wbTimer_getEndTime(timer) ((timer)->endTime) +#define wbTimer_getElapsedTime(timer) ((timer)->elapsedTime) + +#define wbTimer_setLength(timer, val) (wbTimer_getLength(timer) = val) +#define wbTimer_setHead(timer, val) (wbTimer_getHead(timer) = val) +#define wbTimer_setTail(timer, val) (wbTimer_getTail(timer) = val) +#define wbTimer_setStartTime(node, val) (wbTimer_getStartTime(node) = val) +#define wbTimer_setEndTime(node, val) (wbTimer_getEndTime(node) = val) +#define wbTimer_setElapsedTime(node, val) \ + (wbTimer_getElapsedTime(node) = val) + +#define wbTimer_incrementLength(timer) (wbTimer_getLength(timer)++) +#define wbTimer_decrementLength(timer) (wbTimer_getLength(timer)--) + +#define wbTimer_emptyQ(timer) (wbTimer_getLength(timer) == 0) + +void wbTimer_delete(wbTimer_t timer) { + if (timer != NULL) { + wbTimerNode_t tmp, iter; + + iter = wbTimer_getHead(timer); + while (iter) { + tmp = wbTimerNode_getNext(iter); + wbTimerNode_delete(iter); + iter = tmp; + } + + wbDelete(timer); + } +} + +static json11::Json wbTimer_toJSONObject(wbTimer_t timer) { + + stringstream ss; + wbTimerNode_t iter; + uint64_t currentTime; + std::vector elems; + + currentTime = getTime(); + + wbTimer_setEndTime(timer, currentTime); + wbTimer_setElapsedTime(timer, currentTime - wbTimer_getStartTime(timer)); + + for (iter = wbTimer_getHead(timer); iter != NULL; + iter = wbTimerNode_getNext(iter)) { + if (!wbTimerNode_stoppedQ(iter)) { + wbTimerNode_setEndTime(iter, currentTime); + wbTimerNode_setElapsedTime(iter, currentTime - + wbTimerNode_getStartTime(iter)); + } + elems.push_back(wbTimerNode_toJSONObject(iter)); + } + return json11::Json(elems); +} + +string wbTimer_toJSON(wbTimer_t timer) { + if (timer == NULL) { + return ""; + } else if (WB_USE_JSON11) { + json11::Json json = wbTimer_toJSONObject(timer); + return json.string_value(); + } else { + stringstream ss; + wbTimerNode_t iter; + uint64_t currentTime; + + currentTime = getTime(); + + wbTimer_setEndTime(timer, currentTime); + wbTimer_setElapsedTime(timer, + currentTime - wbTimer_getStartTime(timer)); + + for (iter = wbTimer_getHead(timer); iter != NULL; + iter = wbTimerNode_getNext(iter)) { + if (!wbTimerNode_stoppedQ(iter)) { + wbTimerNode_setEndTime(iter, currentTime); + wbTimerNode_setElapsedTime( + iter, currentTime - wbTimerNode_getStartTime(iter)); + } + ss << wbTimerNode_toJSON(iter); + if (wbTimerNode_getNext(iter) != NULL) { + ss << ",\n"; + } + } + + return ss.str(); + } +} + +string wbTimer_toJSON() { + return wbTimer_toJSON(_timer); +} + +string wbTimer_toXML(wbTimer_t timer) { + if (timer == NULL) { + return ""; + } else { + stringstream ss; + wbTimerNode_t iter; + uint64_t currentTime; + + currentTime = getTime(); + + wbTimer_setEndTime(timer, currentTime); + wbTimer_setElapsedTime(timer, + currentTime - wbTimer_getStartTime(timer)); + + ss << "\n"; + ss << "" << wbTimer_getStartTime(timer) + << "\n"; + ss << "" << wbTimer_getEndTime(timer) << "\n"; + ss << "" << wbTimer_getElapsedTime(timer) + << "\n"; + ss << "\n"; + for (iter = wbTimer_getHead(timer); iter != NULL; + iter = wbTimerNode_getNext(iter)) { + if (!wbTimerNode_stoppedQ(iter)) { + wbTimerNode_setEndTime(iter, currentTime); + wbTimerNode_setElapsedTime( + iter, currentTime - wbTimerNode_getStartTime(iter)); + } + ss << wbTimerNode_toXML(iter); + } + ss << "\n"; + ss << "\n"; + + return ss.str(); + } +} + +string wbTimer_toXML() { + return wbTimer_toXML(_timer); +} + +wbTimer_t wbTimer_new(void) { + wbTimer_t timer = wbNew(struct st_wbTimer_t); + wbTimer_setLength(timer, 0); + wbTimer_setHead(timer, NULL); + wbTimer_setTail(timer, NULL); + wbTimer_setStartTime(timer, getTime()); + wbTimer_setEndTime(timer, 0); + wbTimer_setElapsedTime(timer, 0); + + return timer; +} + +static inline wbTimerNode_t _findParent(wbTimer_t timer) { + wbTimerNode_t iter; + + for (iter = wbTimer_getTail(timer); iter != NULL; + iter = wbTimerNode_getPrevious(iter)) { + if (!wbTimerNode_stoppedQ(iter)) { + return iter; + } + } + return NULL; +} + +static inline void _insertIntoList(wbTimer_t timer, wbTimerNode_t node) { + if (wbTimer_emptyQ(timer)) { + wbTimer_setHead(timer, node); + wbTimer_setTail(timer, node); + } else { + wbTimerNode_t end = wbTimer_getTail(timer); + wbTimer_setTail(timer, node); + wbTimerNode_setNext(end, node); + wbTimerNode_setPrevious(node, end); + } + wbTimer_incrementLength(timer); +} + +wbTimerNode_t wbTimer_start(wbTimerKind_t kind, const char *file, + const char *fun, int line) { + int id; + uint64_t currentTime; + wbTimerNode_t node; + wbTimerNode_t parent; + + wb_init(NULL, NULL); + + currentTime = getTime(); + + id = wbTimer_getLength(_timer); + + node = wbTimerNode_new(id, kind, file, fun, line); + + parent = _findParent(_timer); + _insertIntoList(_timer, node); + + wbTimerNode_setStartTime(node, currentTime); + wbTimerNode_setParent(node, parent); + if (parent != NULL) { + wbTimerNode_setLevel(node, wbTimerNode_getLevel(parent) + 1); + } + + return node; +} + +wbTimerNode_t wbTimer_start(wbTimerKind_t kind, string msg, + const char *file, const char *fun, int line) { + wbTimerNode_t node = wbTimer_start(kind, file, fun, line); + wbTimerNode_setMessage(node, wbString_duplicate(msg)); + return node; +} + +static inline wbTimerNode_t _findNode(wbTimer_t timer, wbTimerKind_t kind, + string msg) { + wbTimerNode_t iter; + + for (iter = wbTimer_getTail(timer); iter != NULL; + iter = wbTimerNode_getPrevious(iter)) { + if (msg == "") { + if (!wbTimerNode_stoppedQ(iter) && + wbTimerNode_getKind(iter) == kind) { + return iter; + } + } else { + if (!wbTimerNode_stoppedQ(iter) && + wbTimerNode_getKind(iter) == kind && + msg == wbTimerNode_getMessage(iter)) { + return iter; + } + } + } + return NULL; +} + +void wbTimer_stop(wbTimerKind_t kind, string msg, const char *file, + const char *fun, int line) { + uint64_t currentTime; + wbTimerNode_t node; + + currentTime = getTime(); + + node = _findNode(_timer, kind, msg); + + wbAssert(node != NULL); + if (node == NULL) { + return; + } + + wbTimerNode_setEndTime(node, currentTime); + wbTimerNode_setElapsedTime(node, + currentTime - wbTimerNode_getStartTime(node)); + wbTimerNode_setEndLine(node, line); + wbTimerNode_setEndFunction(node, fun); + wbTimerNode_setEndFile(node, file); + wbTimerNode_setStoppedQ(node, wbTrue); + +#ifdef wbLogger_printOnLog + if (wbLogger_printOnLog) { + json11::Json json = json11::Json::object{ +//PMO +#ifndef _MSC_VER + { "type", "timer" }, { "data", wbTimerNode_toJSONObject(node) }}; +#else + { "data", wbTimerNode_toJSONObject(node) }, { "type", "timer" }}; +#endif + std::cout << json.dump() << std::endl; + } +#endif /* wbLogger_printOnLog */ + return; +} + +void wbTimer_stop(wbTimerKind_t kind, const char *file, const char *fun, + int line) { + wbTimer_stop(kind, "", file, fun, line); +} diff --git a/CUDA_DeviceQuery/libwb/wbTimer.h b/CUDA_DeviceQuery/libwb/wbTimer.h new file mode 100644 index 0000000..133b58f --- /dev/null +++ b/CUDA_DeviceQuery/libwb/wbTimer.h @@ -0,0 +1,139 @@ + + +#ifndef __WB_TIMER_H__ +#define __WB_TIMER_H__ + +#ifdef WB_USE_WINDOWS +extern uint64_t _hrtime_frequency; +#endif /* _WIN32 */ + +extern wbTimer_t _timer; + +typedef enum en_wbTimerKind_t { + wbTimerKind_Generic, + wbTimerKind_IO, + wbTimerKind_GPU, + wbTimerKind_Copy, + wbTimerKind_Driver, + wbTimerKind_CopyAsync, + wbTimerKind_Compute, + wbTimerKind_CPUGPUOverlap, +} wbTimerKind_t; + +struct st_wbTimerNode_t { + int id; + int mpiRank; + int level; + wbBool stoppedQ; + wbTimerKind_t kind; + uint64_t startTime; + uint64_t endTime; + uint64_t elapsedTime; + int startLine; + int endLine; + const char *startFunction; + const char *endFunction; + const char *startFile; + const char *endFile; + wbTimerNode_t next; + wbTimerNode_t prev; + wbTimerNode_t parent; + char *msg; +}; + +struct st_wbTimer_t { + size_t length; + wbTimerNode_t head; + wbTimerNode_t tail; + uint64_t startTime; + uint64_t endTime; + uint64_t elapsedTime; +}; + +#define wbTimerNode_getId(node) ((node)->id) +#define wbTimerNode_getMPIRank(node) ((node)->mpiRank) +#define wbTimerNode_getLevel(node) ((node)->level) +#define wbTimerNode_getStoppedQ(node) ((node)->stoppedQ) +#define wbTimerNode_getKind(node) ((node)->kind) +#define wbTimerNode_getStartTime(node) ((node)->startTime) +#define wbTimerNode_getEndTime(node) ((node)->endTime) +#define wbTimerNode_getElapsedTime(node) ((node)->elapsedTime) +#define wbTimerNode_getStartLine(node) ((node)->startLine) +#define wbTimerNode_getEndLine(node) ((node)->endLine) +#define wbTimerNode_getStartFunction(node) ((node)->startFunction) +#define wbTimerNode_getEndFunction(node) ((node)->endFunction) +#define wbTimerNode_getStartFile(node) ((node)->startFile) +#define wbTimerNode_getEndFile(node) ((node)->endFile) +#define wbTimerNode_getNext(node) ((node)->next) +#define wbTimerNode_getPrevious(node) ((node)->prev) +#define wbTimerNode_getParent(node) ((node)->parent) +#define wbTimerNode_getMessage(node) ((node)->msg) + +#define wbTimerNode_setId(node, val) (wbTimerNode_getId(node) = val) +#define wbTimerNode_setMPIRank(node, val) \ + (wbTimerNode_getMPIRank(node) = val) +#define wbTimerNode_setLevel(node, val) (wbTimerNode_getLevel(node) = val) +#define wbTimerNode_setStoppedQ(node, val) \ + (wbTimerNode_getStoppedQ(node) = val) +#define wbTimerNode_setKind(node, val) (wbTimerNode_getKind(node) = val) +#define wbTimerNode_setStartTime(node, val) \ + (wbTimerNode_getStartTime(node) = val) +#define wbTimerNode_setEndTime(node, val) \ + (wbTimerNode_getEndTime(node) = val) +#define wbTimerNode_setElapsedTime(node, val) \ + (wbTimerNode_getElapsedTime(node) = val) +#define wbTimerNode_setStartLine(node, val) \ + (wbTimerNode_getStartLine(node) = val) +#define wbTimerNode_setEndLine(node, val) \ + (wbTimerNode_getEndLine(node) = val) +#define wbTimerNode_setStartFunction(node, val) \ + (wbTimerNode_getStartFunction(node) = val) +#define wbTimerNode_setEndFunction(node, val) \ + (wbTimerNode_getEndFunction(node) = val) +#define wbTimerNode_setStartFile(node, val) \ + (wbTimerNode_getStartFile(node) = val) +#define wbTimerNode_setEndFile(node, val) \ + (wbTimerNode_getEndFile(node) = val) +#define wbTimerNode_setNext(node, val) (wbTimerNode_getNext(node) = val) +#define wbTimerNode_setPrevious(node, val) \ + (wbTimerNode_getPrevious(node) = val) +#define wbTimerNode_setParent(node, val) \ + (wbTimerNode_getParent(node) = val) +#define wbTimerNode_setMessage(node, val) \ + (wbTimerNode_getMessage(node) = val) + +#define wbTimerNode_stoppedQ(node) \ + (wbTimerNode_getStoppedQ(node) == wbTrue) +#define wbTimerNode_hasNext(node) (wbTimerNode_getNext(node) != NULL) +#define wbTimerNode_hasPrevious(node) \ + (wbTimerNode_getPrevious(node) != NULL) +#define wbTimerNode_hasParent(node) (wbTimerNode_getParent(node) != NULL) + +uint64_t _hrtime(void); + +wbTimer_t wbTimer_new(void); +void wbTimer_delete(wbTimer_t timer); + +string wbTimer_toJSON(wbTimer_t timer); +string wbTimer_toJSON(); + +string wbTimer_toXML(wbTimer_t timer); +string wbTimer_toXML(); + +wbTimerNode_t wbTimer_start(wbTimerKind_t kind, const char *file, + const char *fun, int line); +wbTimerNode_t wbTimer_start(wbTimerKind_t kind, string msg, + const char *file, const char *fun, int line); +void wbTimer_stop(wbTimerKind_t kind, string msg, const char *file, + const char *fun, int line); +void wbTimer_stop(wbTimerKind_t kind, const char *file, const char *fun, + int line); + +#define wbTime_start(kind, ...) \ + wbTimer_start(wbTimerKind_##kind, wbString(__VA_ARGS__), wbFile, \ + wbFunction, wbLine) +#define wbTime_stop(kind, ...) \ + wbTimer_stop(wbTimerKind_##kind, wbString(__VA_ARGS__), wbFile, \ + wbFunction, wbLine) + +#endif /* __WB_TIMER_H__ */ diff --git a/CUDA_DeviceQuery/libwb/wbTypes.h b/CUDA_DeviceQuery/libwb/wbTypes.h new file mode 100644 index 0000000..6837792 --- /dev/null +++ b/CUDA_DeviceQuery/libwb/wbTypes.h @@ -0,0 +1,55 @@ + + +#ifndef __WB_TYPES_H__ +#define __WB_TYPES_H__ + +#include "wbAssert.h" + +typedef bool wbBool; +typedef float wbReal_t; +typedef char wbChar_t; + +typedef struct st_wbTimerNode_t *wbTimerNode_t; +typedef struct st_wbTimer_t *wbTimer_t; +typedef struct st_wbLogEntry_t *wbLogEntry_t; +typedef struct st_wbLogger_t *wbLogger_t; +typedef struct st_wbArg_t wbArg_t; +typedef struct st_wbImage_t *wbImage_t; +typedef struct st_wbFile_t *wbFile_t; + +#define wbTrue true +#define wbFalse false + +typedef enum en_wbType_t { + wbType_unknown = -1, + wbType_ascii = 1, + wbType_bit8, + wbType_ubit8, + wbType_integer, + wbType_float, + wbType_double +} wbType_t; + +static inline size_t wbType_size(wbType_t ty) { + switch (ty) { + case wbType_unknown: + wbAssert(false && "Invalid wbType_unknown"); + return 0; + case wbType_ascii: + return sizeof(char); + case wbType_bit8: + return sizeof(char); + case wbType_ubit8: + return sizeof(unsigned char); + case wbType_integer: + return sizeof(int); + case wbType_float: + return sizeof(float); + case wbType_double: + return sizeof(double); + } + wbAssert(false && "Invalid type"); + return 0; +} + +#endif /* __WB_TYPES_H__ */ diff --git a/CUDA_DeviceQuery/libwb/wbUtils.h b/CUDA_DeviceQuery/libwb/wbUtils.h new file mode 100644 index 0000000..cbd1b91 --- /dev/null +++ b/CUDA_DeviceQuery/libwb/wbUtils.h @@ -0,0 +1,10 @@ +#ifndef __WB_UTILS_H__ +#define __WB_UTILS_H__ + +#ifdef WB_DEBUG +#define DEBUG(...) __VA_ARGS__ +#else /* WB_DEBUG */ +#define DEBUG(...) +#endif /* WB_DEBUG */ + +#endif /* __WB_UTILS_H__ */ diff --git a/CUDA_DeviceQuery/libwb/wb_test.cpp b/CUDA_DeviceQuery/libwb/wb_test.cpp new file mode 100644 index 0000000..87883c8 --- /dev/null +++ b/CUDA_DeviceQuery/libwb/wb_test.cpp @@ -0,0 +1,4 @@ +#define CATCH_CONFIG_MAIN + +#include "wb.h" +#include "vendor/catch.hpp" diff --git a/CUDA_Histogram/Histogram/template.cu b/CUDA_Histogram/Histogram/template.cu new file mode 100644 index 0000000..882e53b --- /dev/null +++ b/CUDA_Histogram/Histogram/template.cu @@ -0,0 +1,188 @@ +#include + +#define NUM_BINS 4096 +#define BLOCK_SIZE 512 + +#define CUDA_CHECK(ans) \ + { gpuAssert((ans), __FILE__, __LINE__); } +inline void gpuAssert(cudaError_t code, const char *file, int line, + bool abort = true) { + if (code != cudaSuccess) { + fprintf(stderr, "GPUassert: %s %s %d\n", cudaGetErrorString(code), + file, line); + if (abort) + exit(code); + } +} + +__global__ void histogram(unsigned int *input, unsigned int *bins, + unsigned int num_elements, + unsigned int num_bins) { + //@@ privitization technique + + __shared__ unsigned int histo_private[NUM_BINS]; + + int i = threadIdx.x + blockIdx.x * blockDim.x; // global thread id + // total number of threads + int stride = blockDim.x * gridDim.x; + + if (threadIdx.x < num_bins) { + histo_private[threadIdx.x] = 0; + } + + __syncthreads(); + + // compute block's histogram + + while (i < num_elements) { + int temp = input[i]; + atomicAdd(&(histo_private[temp]), 1); + i += stride; + } + // wait for all other threads in the block to finish + __syncthreads(); + + // store to global histogram + + if (threadIdx.x < num_bins) { + //int t = histo_private[threadIdx.x]; + atomicAdd(&(bins[threadIdx.x]), histo_private[threadIdx.x]); + } + + + /* + for (int pos = threadIdx.x; pos < NUM_BINS; pos += blockDim.x) { + histo_private[pos] = 0; + } + __syncthreads(); + for (int pos = i; pos < num_elements; pos += stride) { + atomicAdd(&(histo_private[input[i]]), 1); + } + __syncthreads(); + for (int pos = threadIdx; pos < NUM_BINS; pos += blockDim.x) { + atomicAdd(&(bins[threadIdx.x]), histo_private[threadIdx.x]); + } + */ + + /* + histo_private[threadIdx.x] = 0; + __syncthreads(); + while (i < num_elements) { + atomicAdd(&histo_private[input[i]], 1); + i += stride; + } + __syncthreads(); + atomicAdd(&bins[threadIdx.x], histo_private[threadIdx.x]); + */ +} + +__global__ void saturate(unsigned int *bins, unsigned int num_bins) { + //@@ counters are saturated at 127 + + int i = threadIdx.x + blockIdx.x * blockDim.x; + + if (i < num_bins) { + if (bins[i] > 127) { // || bins[i] == 0 + bins[i] = 127; + } + } + +} + +int main(int argc, char *argv[]) { + wbArg_t args; + int inputLength; + unsigned int *hostInput; + unsigned int *hostBins; + unsigned int *deviceInput; + unsigned int *deviceBins; + + args = wbArg_read(argc, argv); + + wbTime_start(Generic, "Importing data and creating memory on host"); + hostInput = (unsigned int *)wbImport(wbArg_getInputFile(args, 0), + &inputLength, "Integer"); + hostBins = (unsigned int *)malloc(NUM_BINS * sizeof(unsigned int)); + wbTime_stop(Generic, "Importing data and creating memory on host"); + + wbLog(TRACE, "The input length is ", inputLength); + wbLog(TRACE, "The number of bins is ", NUM_BINS); + + wbTime_start(GPU, "Allocating GPU memory."); + //@@ Allocate GPU memory + + //------------------------------------------------------------------- + cudaMalloc((void**)&deviceInput, inputLength * sizeof(unsigned int)); + cudaMalloc((void**)&deviceBins, NUM_BINS * sizeof(unsigned int)); + //------------------------------------------------------------------- + + CUDA_CHECK(cudaDeviceSynchronize()); + wbTime_stop(GPU, "Allocating GPU memory."); + + wbTime_start(GPU, "Copying input memory to the GPU."); + //@@ Copy memory to the GPU + + //------------------------------------------------------------------- + cudaMemcpy(deviceInput, hostInput, inputLength * sizeof(unsigned int), cudaMemcpyHostToDevice); + //cudaMemcpy(deviceBins, hostBins, NUM_BINS * sizeof(unsigned int), cudaMemcpyHostToDevice); + //------------------------------------------------------------------- + + CUDA_CHECK(cudaDeviceSynchronize()); + wbTime_stop(GPU, "Copying input memory to the GPU."); + + wbTime_start(GPU, "Clearing the bins."); + //@@ zero out the deviceBins + + //------------------------------------------------------------------- + cudaMemset(deviceBins, 0, NUM_BINS * sizeof(unsigned int)); + //------------------------------------------------------------------- + + wbTime_stop(GPU, "Clearing the bins."); + + //@@ Initialize the grid and block dimensions + + //------------------------------------------------------------------- + // (NUM_BINS / BLOCK_SIZE) + //ceil((float)inputLength / BLOCK_SIZE) + dim3 dimGrid(ceil((float) (inputLength) / (BLOCK_SIZE)), 1, 1); + dim3 dimBlock(BLOCK_SIZE*2, 1, 1); + + //------------------------------------------------------------------- + + wbLog(TRACE, "Launching kernel"); + wbTime_start(Compute, "Performing CUDA computation"); + //@@ Perform kernel computations + + //------------------------------------------------------------------- + histogram <<>>(deviceInput, deviceBins, inputLength, NUM_BINS); + saturate <<>>(deviceBins, NUM_BINS); + //------------------------------------------------------------------- + + wbTime_stop(Compute, "Performing CUDA computation"); + + wbTime_start(Copy, "Copying output memory to the CPU"); + //@@ Copy the GPU memory back to the CPU + + //------------------------------------------------------------------- + cudaMemcpy(hostBins, deviceBins, NUM_BINS * sizeof(unsigned int), cudaMemcpyDeviceToHost); + //------------------------------------------------------------------- + + CUDA_CHECK(cudaDeviceSynchronize()); + wbTime_stop(Copy, "Copying output memory to the CPU"); + + wbTime_start(GPU, "Freeing GPU Memory"); + //@@ Free the GPU memory + + //------------------------------------------------------------------- + cudaFree(deviceInput); + cudaFree(deviceBins); + //------------------------------------------------------------------- + + wbTime_stop(GPU, "Freeing GPU Memory"); + + wbSolution(args, hostBins, NUM_BINS); + + free(hostBins); + free(hostInput); + return 0; +} diff --git a/CUDA_Histogram/libwb/.clang-format b/CUDA_Histogram/libwb/.clang-format new file mode 100644 index 0000000..4757ed4 --- /dev/null +++ b/CUDA_Histogram/libwb/.clang-format @@ -0,0 +1,21 @@ +--- +Language: Cpp +BasedOnStyle: LLVM +ColumnLimit: 75 +AccessModifierOffset: -2 +BreakBeforeBraces: Attach +AlignTrailingComments: true +AlignEscapedNewlinesLeft: false +AlignConsecutiveAssignments: true +AlignOperands: true +AllowShortFunctionsOnASingleLine: false +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AlwaysBreakTemplateDeclarations: true +IndentCaseLabels: true +SpacesBeforeTrailingComments: 1 +Standard: Cpp11 +TabWidth: 4 +UseTab: Never +SortIncludes: false +... diff --git a/CUDA_Histogram/libwb/.travis.yml b/CUDA_Histogram/libwb/.travis.yml new file mode 100644 index 0000000..e32c621 --- /dev/null +++ b/CUDA_Histogram/libwb/.travis.yml @@ -0,0 +1,65 @@ +# Use new trusty images, should yield newer compilers and packages +sudo: required +dist: precise +language: cpp + +matrix: + include: + - compiler: gcc + addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - g++-4.9 + env: COMPILER=g++-4.9 + - compiler: gcc + addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - g++-5 + env: COMPILER=g++-5 + - compiler: clang + addons: + apt: + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-precise-3.6 + packages: + - clang-3.6 + env: COMPILER=clang++-3.6 + - compiler: clang + addons: + apt: + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-precise-3.7 + packages: + - clang-3.7 + env: COMPILER=clang++-3.7 +# - compiler: gcc +# addons: +# apt: +# sources: +# - ubuntu-toolchain-r-test +# packages: +# - g++-6 +# env: COMPILER=g++-6 + # - compiler: clang + # addons: + # apt: + # sources: + # - ubuntu-toolchain-r-test + # - llvm-toolchain-precise-3.8 + # packages: + # - clang-3.8 + # env: COMPILER=clang++-3.8 + +before_install: + - sudo apt-get update -qq +script: + - $COMPILER --version + - make CXX=$COMPILER test + - ./test diff --git a/CUDA_Histogram/libwb/CMakeLists.txt b/CUDA_Histogram/libwb/CMakeLists.txt new file mode 100644 index 0000000..f732c32 --- /dev/null +++ b/CUDA_Histogram/libwb/CMakeLists.txt @@ -0,0 +1,34 @@ +cmake_minimum_required(VERSION 2.8 FATAL_ERROR) + +set(CMAKE_BUILD_TYPE Release) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) +set(CMAKE_COLOR_MAKEFILE ON) +set(VERBOSE_BUILD ON) +set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) +set(CMAKE_MACOSX_RPATH TRUE) +set_property(GLOBAL PROPERTY USE_FOLDERS ON) + + +project(wb) + +set(current_dir "${CMAKE_CURRENT_SOURCE_DIR}") + +if(NOT EXISTS "${CMAKE_CURRENT_BINARY_DIR}/cotire.cmake") + file(DOWNLOAD "https://raw.githubusercontent.com/sakra/cotire/master/CMake/cotire.cmake" "${CMAKE_CURRENT_BINARY_DIR}/cotire.cmake") +endif() + + + +include(${current_dir}/sources.cmake) + +set(WBLIB_STATIC ${WBLIB}) +set(WBLIB_SHARED lib${WBLIB}) + +add_library(${WBLIB_STATIC} STATIC ${LIBWB_SOURCE_FILES} ) +add_library(${WBLIB_SHARED} SHARED ${LIBWB_SOURCE_FILES} ) +set_property(TARGET ${WBLIB_STATIC} PROPERTY CXX_STANDARD 11) +set_property(TARGET ${WBLIB_SHARED} PROPERTY CXX_STANDARD 11) +if (UNIX) + set_target_properties(${WBLIB_SHARED} PROPERTIES OUTPUT_NAME ${WBLIB_STATIC}) +endif (UNIX) +set_property(TARGET ${WBLIB} PROPERTY CXX_STANDARD 11) diff --git a/CUDA_Histogram/libwb/LICENSE.TXT b/CUDA_Histogram/libwb/LICENSE.TXT new file mode 100644 index 0000000..8df244d --- /dev/null +++ b/CUDA_Histogram/libwb/LICENSE.TXT @@ -0,0 +1,36 @@ +Copyright (c) 2016, Abdul Dakkak All rights reserved. + +Developed by: Abdul Dakkak + IMPACT Group + University of Illinois, Urbana-Champaign + impact.crhc.illinois.edu + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal with the +Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, +sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +Redistributions of source code must retain the above +copyright notice, this list of conditions and the following +disclaimers. +Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following +disclaimers in the documentation and/or other materials +provided with the distribution. +Neither the names of Abdul Dakkak, Impact Group, nor the +names of its contributors may be used to endorse or promote +products derived from this Software without specific prior +written permission. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +WITH THE SOFTWARE. diff --git a/CUDA_Histogram/libwb/Makefile b/CUDA_Histogram/libwb/Makefile new file mode 100644 index 0000000..b8a72d7 --- /dev/null +++ b/CUDA_Histogram/libwb/Makefile @@ -0,0 +1,56 @@ +########################################## +# Options +########################################## +WB_LIB_PATH=$(CURDIR)/lib +WB_SRC_PATH=$(CURDIR) + +########################################## +########################################## + +DEFINES= +CXX_FLAGS=-fPIC -Wno-unused-function -x c++ -O3 -g -std=c++11 -Wall -Wno-unused-function -pedantic -I . -I $(WB_SRC_PATH) $(DEFINES) +LIBS=-lm -lstdc++ + +########################################## +########################################## + +UNAME_S := $(shell uname -s) +ifeq ($(UNAME_S),Linux) + LIBS += -lrt +endif + +########################################## +########################################## + +SOURCES := $(shell find $(WB_SRC_PATH) ! -name "*_test.cpp" -name "*.cpp") +TESTS := $(shell find $(WB_SRC_PATH) -name "*_test.cpp") + +OBJECTS = $(SOURCES:.cpp=.o) +TESTOBJECTS = $(TESTS:.cpp=.o) + +############################################## +# OUTPUT +############################################## + +.PHONY: all +.SUFFIXES: .o .cpp +all: libwb.so + +.cpp.o: + $(CXX) $(DEFINES) $(CXX_FLAGS) -c -o $@ $< + +libwb.so: $(OBJECTS) + mkdir -p $(WB_LIB_PATH) + $(CXX) -fPIC -shared -o $(WB_LIB_PATH)/$@ $(OBJECTS) $(LIBS) + +libwb.a: $(OBJECTS) + mkdir -p $(WB_LIB_PATH) + ar rcs -o $(WB_LIB_PATH)/$@ $(OBJECTS) + +test: $(TESTOBJECTS) $(OBJECTS) + $(CXX) -fPIC -o $@ $(TESTOBJECTS) $(OBJECTS) $(LIBS) + + +clean: + rm -fr $(ARCH) + -rm -f $(EXES) *.o *~ \ No newline at end of file diff --git a/CUDA_Histogram/libwb/README.md b/CUDA_Histogram/libwb/README.md new file mode 100644 index 0000000..0486f93 --- /dev/null +++ b/CUDA_Histogram/libwb/README.md @@ -0,0 +1,7 @@ + +# libWB + +[![Travis Build Status](https://travis-ci.org/abduld/libwb.svg?branch=master)](https://travis-ci.org/abduld/libwb) +[![AppVeyor status](https://ci.appveyor.com/api/projects/status/0nx5ie7gn5c0e6ai/branch/master?svg=true)](https://ci.appveyor.com/project/abduld/libwb/branch/master) + \ No newline at end of file diff --git a/CUDA_Histogram/libwb/appveyor.yml b/CUDA_Histogram/libwb/appveyor.yml new file mode 100644 index 0000000..e7a6c95 --- /dev/null +++ b/CUDA_Histogram/libwb/appveyor.yml @@ -0,0 +1,54 @@ + + +# Operating system (build VM template) +os: + - Visual Studio 2015 + + +# scripts that are called at very beginning, before repo cloning +init: + - echo init step + - git config --global core.autocrlf input + - cmake --version + - C:\"Program Files (x86)"\"Microsoft Visual Studio 14.0"\VC\vcvarsall.bat %PLATFORM% + +# clone directory +clone_folder: c:\projects\libwb +# fetch repository as zip archive +shallow_clone: true # default is "false" + +# branches to build +branches: + # whitelist + only: + - master + +platform: + - x64 +configuration: + - Release + +environment: + P: "c:/projects/libs" + + +install: + # by default, all script lines are interpreted as batch + +build: + project: ALL_BUILD.vcxproj # path to Visual Studio solution or project + +# scripts to run before build +before_build: + - echo Running cmake... + - cd c:\projects\libwb + - cmake -G "Visual Studio 14 2015 Win64" -DCMAKE_INSTALL_PREFIX=%P% + +# after_build: +# - echo after_build step + + +# on_finish always executes regardless of passed or failed builds +# on_finish: +# - echo on_finish step +# - ps: ls \ No newline at end of file diff --git a/CUDA_Histogram/libwb/sources.cmake b/CUDA_Histogram/libwb/sources.cmake new file mode 100644 index 0000000..4ac1b10 --- /dev/null +++ b/CUDA_Histogram/libwb/sources.cmake @@ -0,0 +1,31 @@ + +set(WBLIB "wb") + +include_directories(${CMAKE_CURRENT_LIST_DIR}) + +file(GLOB THESE_CPP_FILES + ${CMAKE_CURRENT_LIST_DIR}/*.cpp +) + +file(GLOB THESE_TEST_FILES + ${CMAKE_CURRENT_LIST_DIR}/*_test.cpp +) + +list(REMOVE_ITEM THESE_CPP_FILES ${THESE_TEST_FILES}) + +file(GLOB THESE_HEADER_FILES + ${CMAKE_CURRENT_LIST_DIR}/*.h +) + +list(APPEND LIBWB_HEADER_FILES + ${THESE_HEADER_FILES} +) + +list(APPEND LIBWB_SOURCE_FILES + ${THESE_CPP_FILES} + ${CMAKE_CURRENT_LIST_DIR}/vendor/json11.cpp +) + +list(APPEND LIBWB_TEST_FILES + ${THESE_TEST_FILES} +) diff --git a/CUDA_Histogram/libwb/vendor/catch.hpp b/CUDA_Histogram/libwb/vendor/catch.hpp new file mode 100644 index 0000000..f52eebd --- /dev/null +++ b/CUDA_Histogram/libwb/vendor/catch.hpp @@ -0,0 +1,10414 @@ +/* + * Catch v1.3.6 + * Generated: 2016-03-11 18:30:42.852700 + * ---------------------------------------------------------- + * This file has been merged from multiple headers. Please don't edit it directly + * Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved. + * + * Distributed under the Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + */ +#ifndef TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED +#define TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED + +#define TWOBLUECUBES_CATCH_HPP_INCLUDED + +#ifdef __clang__ +# pragma clang system_header +#elif defined __GNUC__ +# pragma GCC system_header +#endif + +// #included from: internal/catch_suppress_warnings.h + +#ifdef __clang__ +# ifdef __ICC // icpc defines the __clang__ macro +# pragma warning(push) +# pragma warning(disable: 161 1682) +# else // __ICC +# pragma clang diagnostic ignored "-Wglobal-constructors" +# pragma clang diagnostic ignored "-Wvariadic-macros" +# pragma clang diagnostic ignored "-Wc99-extensions" +# pragma clang diagnostic ignored "-Wunused-variable" +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wpadded" +# pragma clang diagnostic ignored "-Wc++98-compat" +# pragma clang diagnostic ignored "-Wc++98-compat-pedantic" +# pragma clang diagnostic ignored "-Wswitch-enum" +# pragma clang diagnostic ignored "-Wcovered-switch-default" +# endif +#elif defined __GNUC__ +# pragma GCC diagnostic ignored "-Wvariadic-macros" +# pragma GCC diagnostic ignored "-Wunused-variable" +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wpadded" +#endif +#if defined(CATCH_CONFIG_MAIN) || defined(CATCH_CONFIG_RUNNER) +# define CATCH_IMPL +#endif + +#ifdef CATCH_IMPL +# ifndef CLARA_CONFIG_MAIN +# define CLARA_CONFIG_MAIN_NOT_DEFINED +# define CLARA_CONFIG_MAIN +# endif +#endif + +// #included from: internal/catch_notimplemented_exception.h +#define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_H_INCLUDED + +// #included from: catch_common.h +#define TWOBLUECUBES_CATCH_COMMON_H_INCLUDED + +#define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line +#define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) +#define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ ) + +#define INTERNAL_CATCH_STRINGIFY2( expr ) #expr +#define INTERNAL_CATCH_STRINGIFY( expr ) INTERNAL_CATCH_STRINGIFY2( expr ) + +#include +#include +#include + +// #included from: catch_compiler_capabilities.h +#define TWOBLUECUBES_CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED + +// Detect a number of compiler features - mostly C++11/14 conformance - by compiler +// The following features are defined: +// +// CATCH_CONFIG_CPP11_NULLPTR : is nullptr supported? +// CATCH_CONFIG_CPP11_NOEXCEPT : is noexcept supported? +// CATCH_CONFIG_CPP11_GENERATED_METHODS : The delete and default keywords for compiler generated methods +// CATCH_CONFIG_CPP11_IS_ENUM : std::is_enum is supported? +// CATCH_CONFIG_CPP11_TUPLE : std::tuple is supported +// CATCH_CONFIG_CPP11_LONG_LONG : is long long supported? +// CATCH_CONFIG_CPP11_OVERRIDE : is override supported? +// CATCH_CONFIG_CPP11_UNIQUE_PTR : is unique_ptr supported (otherwise use auto_ptr) + +// CATCH_CONFIG_CPP11_OR_GREATER : Is C++11 supported? + +// CATCH_CONFIG_VARIADIC_MACROS : are variadic macros supported? + +// **************** +// Note to maintainers: if new toggles are added please document them +// in configuration.md, too +// **************** + +// In general each macro has a _NO_ form +// (e.g. CATCH_CONFIG_CPP11_NO_NULLPTR) which disables the feature. +// Many features, at point of detection, define an _INTERNAL_ macro, so they +// can be combined, en-mass, with the _NO_ forms later. + +// All the C++11 features can be disabled with CATCH_CONFIG_NO_CPP11 + +#if defined(__cplusplus) && __cplusplus >= 201103L +# define CATCH_CPP11_OR_GREATER +#endif + +#ifdef __clang__ + +# if __has_feature(cxx_nullptr) +# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR +# endif + +# if __has_feature(cxx_noexcept) +# define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT +# endif + +# if defined(CATCH_CPP11_OR_GREATER) +# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS _Pragma( "clang diagnostic ignored \"-Wparentheses\"" ) +# endif + +#endif // __clang__ + +//////////////////////////////////////////////////////////////////////////////// +// Borland +#ifdef __BORLANDC__ + +#endif // __BORLANDC__ + +//////////////////////////////////////////////////////////////////////////////// +// EDG +#ifdef __EDG_VERSION__ + +#endif // __EDG_VERSION__ + +//////////////////////////////////////////////////////////////////////////////// +// Digital Mars +#ifdef __DMC__ + +#endif // __DMC__ + +//////////////////////////////////////////////////////////////////////////////// +// GCC +#ifdef __GNUC__ + +# if __GNUC__ == 4 && __GNUC_MINOR__ >= 6 && defined(__GXX_EXPERIMENTAL_CXX0X__) +# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR +# endif + +# if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS) && defined(CATCH_CPP11_OR_GREATER) +# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS _Pragma( "GCC diagnostic ignored \"-Wparentheses\"" ) +# endif + +// - otherwise more recent versions define __cplusplus >= 201103L +// and will get picked up below + +#endif // __GNUC__ + +//////////////////////////////////////////////////////////////////////////////// +// Visual C++ +#ifdef _MSC_VER + +#if (_MSC_VER >= 1600) +# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR +# define CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR +#endif + +#if (_MSC_VER >= 1900 ) // (VC++ 13 (VS2015)) +#define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT +#define CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS +#endif + +#endif // _MSC_VER + +//////////////////////////////////////////////////////////////////////////////// + +// Use variadic macros if the compiler supports them +#if ( defined _MSC_VER && _MSC_VER > 1400 && !defined __EDGE__) || \ + ( defined __WAVE__ && __WAVE_HAS_VARIADICS ) || \ + ( defined __GNUC__ && __GNUC__ >= 3 ) || \ + ( !defined __cplusplus && __STDC_VERSION__ >= 199901L || __cplusplus >= 201103L ) + +#define CATCH_INTERNAL_CONFIG_VARIADIC_MACROS + +#endif + +//////////////////////////////////////////////////////////////////////////////// +// C++ language feature support + +// catch all support for C++11 +#if defined(CATCH_CPP11_OR_GREATER) + +# if !defined(CATCH_INTERNAL_CONFIG_CPP11_NULLPTR) +# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR +# endif + +# ifndef CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT +# define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT +# endif + +# ifndef CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS +# define CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS +# endif + +# ifndef CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM +# define CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM +# endif + +# ifndef CATCH_INTERNAL_CONFIG_CPP11_TUPLE +# define CATCH_INTERNAL_CONFIG_CPP11_TUPLE +# endif + +# ifndef CATCH_INTERNAL_CONFIG_VARIADIC_MACROS +# define CATCH_INTERNAL_CONFIG_VARIADIC_MACROS +# endif + +# if !defined(CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG) +# define CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG +# endif + +# if !defined(CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE) +# define CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE +# endif +# if !defined(CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) +# define CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR +# endif + +#endif // __cplusplus >= 201103L + +// Now set the actual defines based on the above + anything the user has configured +#if defined(CATCH_INTERNAL_CONFIG_CPP11_NULLPTR) && !defined(CATCH_CONFIG_CPP11_NO_NULLPTR) && !defined(CATCH_CONFIG_CPP11_NULLPTR) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_NULLPTR +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_CONFIG_CPP11_NO_NOEXCEPT) && !defined(CATCH_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_NOEXCEPT +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS) && !defined(CATCH_CONFIG_CPP11_NO_GENERATED_METHODS) && !defined(CATCH_CONFIG_CPP11_GENERATED_METHODS) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_GENERATED_METHODS +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM) && !defined(CATCH_CONFIG_CPP11_NO_IS_ENUM) && !defined(CATCH_CONFIG_CPP11_IS_ENUM) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_IS_ENUM +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_TUPLE) && !defined(CATCH_CONFIG_CPP11_NO_TUPLE) && !defined(CATCH_CONFIG_CPP11_TUPLE) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_TUPLE +#endif +#if defined(CATCH_INTERNAL_CONFIG_VARIADIC_MACROS) && !defined(CATCH_CONFIG_NO_VARIADIC_MACROS) && !defined(CATCH_CONFIG_VARIADIC_MACROS) +# define CATCH_CONFIG_VARIADIC_MACROS +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG) && !defined(CATCH_CONFIG_NO_LONG_LONG) && !defined(CATCH_CONFIG_CPP11_LONG_LONG) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_LONG_LONG +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE) && !defined(CATCH_CONFIG_NO_OVERRIDE) && !defined(CATCH_CONFIG_CPP11_OVERRIDE) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_OVERRIDE +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) && !defined(CATCH_CONFIG_NO_UNIQUE_PTR) && !defined(CATCH_CONFIG_CPP11_UNIQUE_PTR) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_UNIQUE_PTR +#endif + +#if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS) +# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS +#endif + +// noexcept support: +#if defined(CATCH_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_NOEXCEPT) +# define CATCH_NOEXCEPT noexcept +# define CATCH_NOEXCEPT_IS(x) noexcept(x) +#else +# define CATCH_NOEXCEPT throw() +# define CATCH_NOEXCEPT_IS(x) +#endif + +// nullptr support +#ifdef CATCH_CONFIG_CPP11_NULLPTR +# define CATCH_NULL nullptr +#else +# define CATCH_NULL NULL +#endif + +// override support +#ifdef CATCH_CONFIG_CPP11_OVERRIDE +# define CATCH_OVERRIDE override +#else +# define CATCH_OVERRIDE +#endif + +// unique_ptr support +#ifdef CATCH_CONFIG_CPP11_UNIQUE_PTR +# define CATCH_AUTO_PTR( T ) std::unique_ptr +#else +# define CATCH_AUTO_PTR( T ) std::auto_ptr +#endif + +namespace Catch { + + struct IConfig; + + struct CaseSensitive { enum Choice { + Yes, + No + }; }; + + class NonCopyable { +#ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + NonCopyable( NonCopyable const& ) = delete; + NonCopyable( NonCopyable && ) = delete; + NonCopyable& operator = ( NonCopyable const& ) = delete; + NonCopyable& operator = ( NonCopyable && ) = delete; +#else + NonCopyable( NonCopyable const& info ); + NonCopyable& operator = ( NonCopyable const& ); +#endif + + protected: + NonCopyable() {} + virtual ~NonCopyable(); + }; + + class SafeBool { + public: + typedef void (SafeBool::*type)() const; + + static type makeSafe( bool value ) { + return value ? &SafeBool::trueValue : 0; + } + private: + void trueValue() const {} + }; + + template + inline void deleteAll( ContainerT& container ) { + typename ContainerT::const_iterator it = container.begin(); + typename ContainerT::const_iterator itEnd = container.end(); + for(; it != itEnd; ++it ) + delete *it; + } + template + inline void deleteAllValues( AssociativeContainerT& container ) { + typename AssociativeContainerT::const_iterator it = container.begin(); + typename AssociativeContainerT::const_iterator itEnd = container.end(); + for(; it != itEnd; ++it ) + delete it->second; + } + + bool startsWith( std::string const& s, std::string const& prefix ); + bool endsWith( std::string const& s, std::string const& suffix ); + bool contains( std::string const& s, std::string const& infix ); + void toLowerInPlace( std::string& s ); + std::string toLower( std::string const& s ); + std::string trim( std::string const& str ); + bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ); + + struct pluralise { + pluralise( std::size_t count, std::string const& label ); + + friend std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ); + + std::size_t m_count; + std::string m_label; + }; + + struct SourceLineInfo { + + SourceLineInfo(); + SourceLineInfo( char const* _file, std::size_t _line ); + SourceLineInfo( SourceLineInfo const& other ); +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + SourceLineInfo( SourceLineInfo && ) = default; + SourceLineInfo& operator = ( SourceLineInfo const& ) = default; + SourceLineInfo& operator = ( SourceLineInfo && ) = default; +# endif + bool empty() const; + bool operator == ( SourceLineInfo const& other ) const; + bool operator < ( SourceLineInfo const& other ) const; + + std::string file; + std::size_t line; + }; + + std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ); + + // This is just here to avoid compiler warnings with macro constants and boolean literals + inline bool isTrue( bool value ){ return value; } + inline bool alwaysTrue() { return true; } + inline bool alwaysFalse() { return false; } + + void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo ); + + void seedRng( IConfig const& config ); + unsigned int rngSeed(); + + // Use this in variadic streaming macros to allow + // >> +StreamEndStop + // as well as + // >> stuff +StreamEndStop + struct StreamEndStop { + std::string operator+() { + return std::string(); + } + }; + template + T const& operator + ( T const& value, StreamEndStop ) { + return value; + } +} + +#define CATCH_INTERNAL_LINEINFO ::Catch::SourceLineInfo( __FILE__, static_cast( __LINE__ ) ) +#define CATCH_INTERNAL_ERROR( msg ) ::Catch::throwLogicError( msg, CATCH_INTERNAL_LINEINFO ); + +#include + +namespace Catch { + + class NotImplementedException : public std::exception + { + public: + NotImplementedException( SourceLineInfo const& lineInfo ); + NotImplementedException( NotImplementedException const& ) {} + + virtual ~NotImplementedException() CATCH_NOEXCEPT {} + + virtual const char* what() const CATCH_NOEXCEPT; + + private: + std::string m_what; + SourceLineInfo m_lineInfo; + }; + +} // end namespace Catch + +/////////////////////////////////////////////////////////////////////////////// +#define CATCH_NOT_IMPLEMENTED throw Catch::NotImplementedException( CATCH_INTERNAL_LINEINFO ) + +// #included from: internal/catch_context.h +#define TWOBLUECUBES_CATCH_CONTEXT_H_INCLUDED + +// #included from: catch_interfaces_generators.h +#define TWOBLUECUBES_CATCH_INTERFACES_GENERATORS_H_INCLUDED + +#include + +namespace Catch { + + struct IGeneratorInfo { + virtual ~IGeneratorInfo(); + virtual bool moveNext() = 0; + virtual std::size_t getCurrentIndex() const = 0; + }; + + struct IGeneratorsForTest { + virtual ~IGeneratorsForTest(); + + virtual IGeneratorInfo& getGeneratorInfo( std::string const& fileInfo, std::size_t size ) = 0; + virtual bool moveNext() = 0; + }; + + IGeneratorsForTest* createGeneratorsForTest(); + +} // end namespace Catch + +// #included from: catch_ptr.hpp +#define TWOBLUECUBES_CATCH_PTR_HPP_INCLUDED + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpadded" +#endif + +namespace Catch { + + // An intrusive reference counting smart pointer. + // T must implement addRef() and release() methods + // typically implementing the IShared interface + template + class Ptr { + public: + Ptr() : m_p( CATCH_NULL ){} + Ptr( T* p ) : m_p( p ){ + if( m_p ) + m_p->addRef(); + } + Ptr( Ptr const& other ) : m_p( other.m_p ){ + if( m_p ) + m_p->addRef(); + } + ~Ptr(){ + if( m_p ) + m_p->release(); + } + void reset() { + if( m_p ) + m_p->release(); + m_p = CATCH_NULL; + } + Ptr& operator = ( T* p ){ + Ptr temp( p ); + swap( temp ); + return *this; + } + Ptr& operator = ( Ptr const& other ){ + Ptr temp( other ); + swap( temp ); + return *this; + } + void swap( Ptr& other ) { std::swap( m_p, other.m_p ); } + T* get() const{ return m_p; } + T& operator*() const { return *m_p; } + T* operator->() const { return m_p; } + bool operator !() const { return m_p == CATCH_NULL; } + operator SafeBool::type() const { return SafeBool::makeSafe( m_p != CATCH_NULL ); } + + private: + T* m_p; + }; + + struct IShared : NonCopyable { + virtual ~IShared(); + virtual void addRef() const = 0; + virtual void release() const = 0; + }; + + template + struct SharedImpl : T { + + SharedImpl() : m_rc( 0 ){} + + virtual void addRef() const { + ++m_rc; + } + virtual void release() const { + if( --m_rc == 0 ) + delete this; + } + + mutable unsigned int m_rc; + }; + +} // end namespace Catch + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +#include +#include +#include + +namespace Catch { + + class TestCase; + class Stream; + struct IResultCapture; + struct IRunner; + struct IGeneratorsForTest; + struct IConfig; + + struct IContext + { + virtual ~IContext(); + + virtual IResultCapture* getResultCapture() = 0; + virtual IRunner* getRunner() = 0; + virtual size_t getGeneratorIndex( std::string const& fileInfo, size_t totalSize ) = 0; + virtual bool advanceGeneratorsForCurrentTest() = 0; + virtual Ptr getConfig() const = 0; + }; + + struct IMutableContext : IContext + { + virtual ~IMutableContext(); + virtual void setResultCapture( IResultCapture* resultCapture ) = 0; + virtual void setRunner( IRunner* runner ) = 0; + virtual void setConfig( Ptr const& config ) = 0; + }; + + IContext& getCurrentContext(); + IMutableContext& getCurrentMutableContext(); + void cleanUpContext(); + Stream createStream( std::string const& streamName ); + +} + +// #included from: internal/catch_test_registry.hpp +#define TWOBLUECUBES_CATCH_TEST_REGISTRY_HPP_INCLUDED + +// #included from: catch_interfaces_testcase.h +#define TWOBLUECUBES_CATCH_INTERFACES_TESTCASE_H_INCLUDED + +#include + +namespace Catch { + + class TestSpec; + + struct ITestCase : IShared { + virtual void invoke () const = 0; + protected: + virtual ~ITestCase(); + }; + + class TestCase; + struct IConfig; + + struct ITestCaseRegistry { + virtual ~ITestCaseRegistry(); + virtual std::vector const& getAllTests() const = 0; + virtual std::vector const& getAllTestsSorted( IConfig const& config ) const = 0; + }; + + bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ); + std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ); + std::vector const& getAllTestCasesSorted( IConfig const& config ); + +} + +namespace Catch { + +template +class MethodTestCase : public SharedImpl { + +public: + MethodTestCase( void (C::*method)() ) : m_method( method ) {} + + virtual void invoke() const { + C obj; + (obj.*m_method)(); + } + +private: + virtual ~MethodTestCase() {} + + void (C::*m_method)(); +}; + +typedef void(*TestFunction)(); + +struct NameAndDesc { + NameAndDesc( const char* _name = "", const char* _description= "" ) + : name( _name ), description( _description ) + {} + + const char* name; + const char* description; +}; + +void registerTestCase + ( ITestCase* testCase, + char const* className, + NameAndDesc const& nameAndDesc, + SourceLineInfo const& lineInfo ); + +struct AutoReg { + + AutoReg + ( TestFunction function, + SourceLineInfo const& lineInfo, + NameAndDesc const& nameAndDesc ); + + template + AutoReg + ( void (C::*method)(), + char const* className, + NameAndDesc const& nameAndDesc, + SourceLineInfo const& lineInfo ) { + + registerTestCase + ( new MethodTestCase( method ), + className, + nameAndDesc, + lineInfo ); + } + + ~AutoReg(); + +private: + AutoReg( AutoReg const& ); + void operator= ( AutoReg const& ); +}; + +void registerTestCaseFunction + ( TestFunction function, + SourceLineInfo const& lineInfo, + NameAndDesc const& nameAndDesc ); + +} // end namespace Catch + +#ifdef CATCH_CONFIG_VARIADIC_MACROS + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_TESTCASE( ... ) \ + static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )(); \ + namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( __VA_ARGS__ ) ); }\ + static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )() + + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \ + namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); } + + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, ... )\ + namespace{ \ + struct INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ) : ClassName{ \ + void test(); \ + }; \ + Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test, #ClassName, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); \ + } \ + void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test() + + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, ... ) \ + Catch::AutoReg( Function, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( __VA_ARGS__ ) ); + +#else + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_TESTCASE( Name, Desc ) \ + static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )(); \ + namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( Name, Desc ) ); }\ + static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )() + + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, Name, Desc ) \ + namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( Name, Desc ), CATCH_INTERNAL_LINEINFO ); } + + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, TestName, Desc )\ + namespace{ \ + struct INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ) : ClassName{ \ + void test(); \ + }; \ + Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test, #ClassName, Catch::NameAndDesc( TestName, Desc ), CATCH_INTERNAL_LINEINFO ); \ + } \ + void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test() + + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, Name, Desc ) \ + Catch::AutoReg( Function, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( Name, Desc ) ); +#endif + +// #included from: internal/catch_capture.hpp +#define TWOBLUECUBES_CATCH_CAPTURE_HPP_INCLUDED + +// #included from: catch_result_builder.h +#define TWOBLUECUBES_CATCH_RESULT_BUILDER_H_INCLUDED + +// #included from: catch_result_type.h +#define TWOBLUECUBES_CATCH_RESULT_TYPE_H_INCLUDED + +namespace Catch { + + // ResultWas::OfType enum + struct ResultWas { enum OfType { + Unknown = -1, + Ok = 0, + Info = 1, + Warning = 2, + + FailureBit = 0x10, + + ExpressionFailed = FailureBit | 1, + ExplicitFailure = FailureBit | 2, + + Exception = 0x100 | FailureBit, + + ThrewException = Exception | 1, + DidntThrowException = Exception | 2, + + FatalErrorCondition = 0x200 | FailureBit + + }; }; + + inline bool isOk( ResultWas::OfType resultType ) { + return ( resultType & ResultWas::FailureBit ) == 0; + } + inline bool isJustInfo( int flags ) { + return flags == ResultWas::Info; + } + + // ResultDisposition::Flags enum + struct ResultDisposition { enum Flags { + Normal = 0x01, + + ContinueOnFailure = 0x02, // Failures fail test, but execution continues + FalseTest = 0x04, // Prefix expression with ! + SuppressFail = 0x08 // Failures are reported but do not fail the test + }; }; + + inline ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs ) { + return static_cast( static_cast( lhs ) | static_cast( rhs ) ); + } + + inline bool shouldContinueOnFailure( int flags ) { return ( flags & ResultDisposition::ContinueOnFailure ) != 0; } + inline bool isFalseTest( int flags ) { return ( flags & ResultDisposition::FalseTest ) != 0; } + inline bool shouldSuppressFailure( int flags ) { return ( flags & ResultDisposition::SuppressFail ) != 0; } + +} // end namespace Catch + +// #included from: catch_assertionresult.h +#define TWOBLUECUBES_CATCH_ASSERTIONRESULT_H_INCLUDED + +#include + +namespace Catch { + + struct AssertionInfo + { + AssertionInfo() {} + AssertionInfo( std::string const& _macroName, + SourceLineInfo const& _lineInfo, + std::string const& _capturedExpression, + ResultDisposition::Flags _resultDisposition ); + + std::string macroName; + SourceLineInfo lineInfo; + std::string capturedExpression; + ResultDisposition::Flags resultDisposition; + }; + + struct AssertionResultData + { + AssertionResultData() : resultType( ResultWas::Unknown ) {} + + std::string reconstructedExpression; + std::string message; + ResultWas::OfType resultType; + }; + + class AssertionResult { + public: + AssertionResult(); + AssertionResult( AssertionInfo const& info, AssertionResultData const& data ); + ~AssertionResult(); +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + AssertionResult( AssertionResult const& ) = default; + AssertionResult( AssertionResult && ) = default; + AssertionResult& operator = ( AssertionResult const& ) = default; + AssertionResult& operator = ( AssertionResult && ) = default; +# endif + + bool isOk() const; + bool succeeded() const; + ResultWas::OfType getResultType() const; + bool hasExpression() const; + bool hasMessage() const; + std::string getExpression() const; + std::string getExpressionInMacro() const; + bool hasExpandedExpression() const; + std::string getExpandedExpression() const; + std::string getMessage() const; + SourceLineInfo getSourceInfo() const; + std::string getTestMacroName() const; + + protected: + AssertionInfo m_info; + AssertionResultData m_resultData; + }; + +} // end namespace Catch + +// #included from: catch_matchers.hpp +#define TWOBLUECUBES_CATCH_MATCHERS_HPP_INCLUDED + +namespace Catch { +namespace Matchers { + namespace Impl { + + namespace Generic { + template class AllOf; + template class AnyOf; + template class Not; + } + + template + struct Matcher : SharedImpl + { + typedef ExpressionT ExpressionType; + + virtual ~Matcher() {} + virtual Ptr clone() const = 0; + virtual bool match( ExpressionT const& expr ) const = 0; + virtual std::string toString() const = 0; + + Generic::AllOf operator && ( Matcher const& other ) const; + Generic::AnyOf operator || ( Matcher const& other ) const; + Generic::Not operator ! () const; + }; + + template + struct MatcherImpl : Matcher { + + virtual Ptr > clone() const { + return Ptr >( new DerivedT( static_cast( *this ) ) ); + } + }; + + namespace Generic { + template + class Not : public MatcherImpl, ExpressionT> { + public: + explicit Not( Matcher const& matcher ) : m_matcher(matcher.clone()) {} + Not( Not const& other ) : m_matcher( other.m_matcher ) {} + + virtual bool match( ExpressionT const& expr ) const CATCH_OVERRIDE { + return !m_matcher->match( expr ); + } + + virtual std::string toString() const CATCH_OVERRIDE { + return "not " + m_matcher->toString(); + } + private: + Ptr< Matcher > m_matcher; + }; + + template + class AllOf : public MatcherImpl, ExpressionT> { + public: + + AllOf() {} + AllOf( AllOf const& other ) : m_matchers( other.m_matchers ) {} + + AllOf& add( Matcher const& matcher ) { + m_matchers.push_back( matcher.clone() ); + return *this; + } + virtual bool match( ExpressionT const& expr ) const + { + for( std::size_t i = 0; i < m_matchers.size(); ++i ) + if( !m_matchers[i]->match( expr ) ) + return false; + return true; + } + virtual std::string toString() const { + std::ostringstream oss; + oss << "( "; + for( std::size_t i = 0; i < m_matchers.size(); ++i ) { + if( i != 0 ) + oss << " and "; + oss << m_matchers[i]->toString(); + } + oss << " )"; + return oss.str(); + } + + AllOf operator && ( Matcher const& other ) const { + AllOf allOfExpr( *this ); + allOfExpr.add( other ); + return allOfExpr; + } + + private: + std::vector > > m_matchers; + }; + + template + class AnyOf : public MatcherImpl, ExpressionT> { + public: + + AnyOf() {} + AnyOf( AnyOf const& other ) : m_matchers( other.m_matchers ) {} + + AnyOf& add( Matcher const& matcher ) { + m_matchers.push_back( matcher.clone() ); + return *this; + } + virtual bool match( ExpressionT const& expr ) const + { + for( std::size_t i = 0; i < m_matchers.size(); ++i ) + if( m_matchers[i]->match( expr ) ) + return true; + return false; + } + virtual std::string toString() const { + std::ostringstream oss; + oss << "( "; + for( std::size_t i = 0; i < m_matchers.size(); ++i ) { + if( i != 0 ) + oss << " or "; + oss << m_matchers[i]->toString(); + } + oss << " )"; + return oss.str(); + } + + AnyOf operator || ( Matcher const& other ) const { + AnyOf anyOfExpr( *this ); + anyOfExpr.add( other ); + return anyOfExpr; + } + + private: + std::vector > > m_matchers; + }; + + } // namespace Generic + + template + Generic::AllOf Matcher::operator && ( Matcher const& other ) const { + Generic::AllOf allOfExpr; + allOfExpr.add( *this ); + allOfExpr.add( other ); + return allOfExpr; + } + + template + Generic::AnyOf Matcher::operator || ( Matcher const& other ) const { + Generic::AnyOf anyOfExpr; + anyOfExpr.add( *this ); + anyOfExpr.add( other ); + return anyOfExpr; + } + + template + Generic::Not Matcher::operator ! () const { + return Generic::Not( *this ); + } + + namespace StdString { + + inline std::string makeString( std::string const& str ) { return str; } + inline std::string makeString( const char* str ) { return str ? std::string( str ) : std::string(); } + + struct CasedString + { + CasedString( std::string const& str, CaseSensitive::Choice caseSensitivity ) + : m_caseSensitivity( caseSensitivity ), + m_str( adjustString( str ) ) + {} + std::string adjustString( std::string const& str ) const { + return m_caseSensitivity == CaseSensitive::No + ? toLower( str ) + : str; + + } + std::string toStringSuffix() const + { + return m_caseSensitivity == CaseSensitive::No + ? " (case insensitive)" + : ""; + } + CaseSensitive::Choice m_caseSensitivity; + std::string m_str; + }; + + struct Equals : MatcherImpl { + Equals( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) + : m_data( str, caseSensitivity ) + {} + Equals( Equals const& other ) : m_data( other.m_data ){} + + virtual ~Equals(); + + virtual bool match( std::string const& expr ) const { + return m_data.m_str == m_data.adjustString( expr );; + } + virtual std::string toString() const { + return "equals: \"" + m_data.m_str + "\"" + m_data.toStringSuffix(); + } + + CasedString m_data; + }; + + struct Contains : MatcherImpl { + Contains( std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) + : m_data( substr, caseSensitivity ){} + Contains( Contains const& other ) : m_data( other.m_data ){} + + virtual ~Contains(); + + virtual bool match( std::string const& expr ) const { + return m_data.adjustString( expr ).find( m_data.m_str ) != std::string::npos; + } + virtual std::string toString() const { + return "contains: \"" + m_data.m_str + "\"" + m_data.toStringSuffix(); + } + + CasedString m_data; + }; + + struct StartsWith : MatcherImpl { + StartsWith( std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) + : m_data( substr, caseSensitivity ){} + + StartsWith( StartsWith const& other ) : m_data( other.m_data ){} + + virtual ~StartsWith(); + + virtual bool match( std::string const& expr ) const { + return startsWith( m_data.adjustString( expr ), m_data.m_str ); + } + virtual std::string toString() const { + return "starts with: \"" + m_data.m_str + "\"" + m_data.toStringSuffix(); + } + + CasedString m_data; + }; + + struct EndsWith : MatcherImpl { + EndsWith( std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) + : m_data( substr, caseSensitivity ){} + EndsWith( EndsWith const& other ) : m_data( other.m_data ){} + + virtual ~EndsWith(); + + virtual bool match( std::string const& expr ) const { + return endsWith( m_data.adjustString( expr ), m_data.m_str ); + } + virtual std::string toString() const { + return "ends with: \"" + m_data.m_str + "\"" + m_data.toStringSuffix(); + } + + CasedString m_data; + }; + } // namespace StdString + } // namespace Impl + + // The following functions create the actual matcher objects. + // This allows the types to be inferred + template + inline Impl::Generic::Not Not( Impl::Matcher const& m ) { + return Impl::Generic::Not( m ); + } + + template + inline Impl::Generic::AllOf AllOf( Impl::Matcher const& m1, + Impl::Matcher const& m2 ) { + return Impl::Generic::AllOf().add( m1 ).add( m2 ); + } + template + inline Impl::Generic::AllOf AllOf( Impl::Matcher const& m1, + Impl::Matcher const& m2, + Impl::Matcher const& m3 ) { + return Impl::Generic::AllOf().add( m1 ).add( m2 ).add( m3 ); + } + template + inline Impl::Generic::AnyOf AnyOf( Impl::Matcher const& m1, + Impl::Matcher const& m2 ) { + return Impl::Generic::AnyOf().add( m1 ).add( m2 ); + } + template + inline Impl::Generic::AnyOf AnyOf( Impl::Matcher const& m1, + Impl::Matcher const& m2, + Impl::Matcher const& m3 ) { + return Impl::Generic::AnyOf().add( m1 ).add( m2 ).add( m3 ); + } + + inline Impl::StdString::Equals Equals( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) { + return Impl::StdString::Equals( str, caseSensitivity ); + } + inline Impl::StdString::Equals Equals( const char* str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) { + return Impl::StdString::Equals( Impl::StdString::makeString( str ), caseSensitivity ); + } + inline Impl::StdString::Contains Contains( std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) { + return Impl::StdString::Contains( substr, caseSensitivity ); + } + inline Impl::StdString::Contains Contains( const char* substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) { + return Impl::StdString::Contains( Impl::StdString::makeString( substr ), caseSensitivity ); + } + inline Impl::StdString::StartsWith StartsWith( std::string const& substr ) { + return Impl::StdString::StartsWith( substr ); + } + inline Impl::StdString::StartsWith StartsWith( const char* substr ) { + return Impl::StdString::StartsWith( Impl::StdString::makeString( substr ) ); + } + inline Impl::StdString::EndsWith EndsWith( std::string const& substr ) { + return Impl::StdString::EndsWith( substr ); + } + inline Impl::StdString::EndsWith EndsWith( const char* substr ) { + return Impl::StdString::EndsWith( Impl::StdString::makeString( substr ) ); + } + +} // namespace Matchers + +using namespace Matchers; + +} // namespace Catch + +namespace Catch { + + struct TestFailureException{}; + + template class ExpressionLhs; + + struct STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison; + + struct CopyableStream { + CopyableStream() {} + CopyableStream( CopyableStream const& other ) { + oss << other.oss.str(); + } + CopyableStream& operator=( CopyableStream const& other ) { + oss.str(""); + oss << other.oss.str(); + return *this; + } + std::ostringstream oss; + }; + + class ResultBuilder { + public: + ResultBuilder( char const* macroName, + SourceLineInfo const& lineInfo, + char const* capturedExpression, + ResultDisposition::Flags resultDisposition, + char const* secondArg = "" ); + + template + ExpressionLhs operator <= ( T const& operand ); + ExpressionLhs operator <= ( bool value ); + + template + ResultBuilder& operator << ( T const& value ) { + m_stream.oss << value; + return *this; + } + + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( RhsT const& ); + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || ( RhsT const& ); + + ResultBuilder& setResultType( ResultWas::OfType result ); + ResultBuilder& setResultType( bool result ); + ResultBuilder& setLhs( std::string const& lhs ); + ResultBuilder& setRhs( std::string const& rhs ); + ResultBuilder& setOp( std::string const& op ); + + void endExpression(); + + std::string reconstructExpression() const; + AssertionResult build() const; + + void useActiveException( ResultDisposition::Flags resultDisposition = ResultDisposition::Normal ); + void captureResult( ResultWas::OfType resultType ); + void captureExpression(); + void captureExpectedException( std::string const& expectedMessage ); + void captureExpectedException( Matchers::Impl::Matcher const& matcher ); + void handleResult( AssertionResult const& result ); + void react(); + bool shouldDebugBreak() const; + bool allowThrows() const; + + private: + AssertionInfo m_assertionInfo; + AssertionResultData m_data; + struct ExprComponents { + ExprComponents() : testFalse( false ) {} + bool testFalse; + std::string lhs, rhs, op; + } m_exprComponents; + CopyableStream m_stream; + + bool m_shouldDebugBreak; + bool m_shouldThrow; + }; + +} // namespace Catch + +// Include after due to circular dependency: +// #included from: catch_expression_lhs.hpp +#define TWOBLUECUBES_CATCH_EXPRESSION_LHS_HPP_INCLUDED + +// #included from: catch_evaluate.hpp +#define TWOBLUECUBES_CATCH_EVALUATE_HPP_INCLUDED + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable:4389) // '==' : signed/unsigned mismatch +#endif + +#include + +namespace Catch { +namespace Internal { + + enum Operator { + IsEqualTo, + IsNotEqualTo, + IsLessThan, + IsGreaterThan, + IsLessThanOrEqualTo, + IsGreaterThanOrEqualTo + }; + + template struct OperatorTraits { static const char* getName(){ return "*error*"; } }; + template<> struct OperatorTraits { static const char* getName(){ return "=="; } }; + template<> struct OperatorTraits { static const char* getName(){ return "!="; } }; + template<> struct OperatorTraits { static const char* getName(){ return "<"; } }; + template<> struct OperatorTraits { static const char* getName(){ return ">"; } }; + template<> struct OperatorTraits { static const char* getName(){ return "<="; } }; + template<> struct OperatorTraits{ static const char* getName(){ return ">="; } }; + + template + inline T& opCast(T const& t) { return const_cast(t); } + +// nullptr_t support based on pull request #154 from Konstantin Baumann +#ifdef CATCH_CONFIG_CPP11_NULLPTR + inline std::nullptr_t opCast(std::nullptr_t) { return nullptr; } +#endif // CATCH_CONFIG_CPP11_NULLPTR + + // So the compare overloads can be operator agnostic we convey the operator as a template + // enum, which is used to specialise an Evaluator for doing the comparison. + template + class Evaluator{}; + + template + struct Evaluator { + static bool evaluate( T1 const& lhs, T2 const& rhs) { + return bool( opCast( lhs ) == opCast( rhs ) ); + } + }; + template + struct Evaluator { + static bool evaluate( T1 const& lhs, T2 const& rhs ) { + return bool( opCast( lhs ) != opCast( rhs ) ); + } + }; + template + struct Evaluator { + static bool evaluate( T1 const& lhs, T2 const& rhs ) { + return bool( opCast( lhs ) < opCast( rhs ) ); + } + }; + template + struct Evaluator { + static bool evaluate( T1 const& lhs, T2 const& rhs ) { + return bool( opCast( lhs ) > opCast( rhs ) ); + } + }; + template + struct Evaluator { + static bool evaluate( T1 const& lhs, T2 const& rhs ) { + return bool( opCast( lhs ) >= opCast( rhs ) ); + } + }; + template + struct Evaluator { + static bool evaluate( T1 const& lhs, T2 const& rhs ) { + return bool( opCast( lhs ) <= opCast( rhs ) ); + } + }; + + template + bool applyEvaluator( T1 const& lhs, T2 const& rhs ) { + return Evaluator::evaluate( lhs, rhs ); + } + + // This level of indirection allows us to specialise for integer types + // to avoid signed/ unsigned warnings + + // "base" overload + template + bool compare( T1 const& lhs, T2 const& rhs ) { + return Evaluator::evaluate( lhs, rhs ); + } + + // unsigned X to int + template bool compare( unsigned int lhs, int rhs ) { + return applyEvaluator( lhs, static_cast( rhs ) ); + } + template bool compare( unsigned long lhs, int rhs ) { + return applyEvaluator( lhs, static_cast( rhs ) ); + } + template bool compare( unsigned char lhs, int rhs ) { + return applyEvaluator( lhs, static_cast( rhs ) ); + } + + // unsigned X to long + template bool compare( unsigned int lhs, long rhs ) { + return applyEvaluator( lhs, static_cast( rhs ) ); + } + template bool compare( unsigned long lhs, long rhs ) { + return applyEvaluator( lhs, static_cast( rhs ) ); + } + template bool compare( unsigned char lhs, long rhs ) { + return applyEvaluator( lhs, static_cast( rhs ) ); + } + + // int to unsigned X + template bool compare( int lhs, unsigned int rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( int lhs, unsigned long rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( int lhs, unsigned char rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + + // long to unsigned X + template bool compare( long lhs, unsigned int rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( long lhs, unsigned long rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( long lhs, unsigned char rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + + // pointer to long (when comparing against NULL) + template bool compare( long lhs, T* rhs ) { + return Evaluator::evaluate( reinterpret_cast( lhs ), rhs ); + } + template bool compare( T* lhs, long rhs ) { + return Evaluator::evaluate( lhs, reinterpret_cast( rhs ) ); + } + + // pointer to int (when comparing against NULL) + template bool compare( int lhs, T* rhs ) { + return Evaluator::evaluate( reinterpret_cast( lhs ), rhs ); + } + template bool compare( T* lhs, int rhs ) { + return Evaluator::evaluate( lhs, reinterpret_cast( rhs ) ); + } + +#ifdef CATCH_CONFIG_CPP11_LONG_LONG + // long long to unsigned X + template bool compare( long long lhs, unsigned int rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( long long lhs, unsigned long rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( long long lhs, unsigned long long rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( long long lhs, unsigned char rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + + // unsigned long long to X + template bool compare( unsigned long long lhs, int rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( unsigned long long lhs, long rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( unsigned long long lhs, long long rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( unsigned long long lhs, char rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + + // pointer to long long (when comparing against NULL) + template bool compare( long long lhs, T* rhs ) { + return Evaluator::evaluate( reinterpret_cast( lhs ), rhs ); + } + template bool compare( T* lhs, long long rhs ) { + return Evaluator::evaluate( lhs, reinterpret_cast( rhs ) ); + } +#endif // CATCH_CONFIG_CPP11_LONG_LONG + +#ifdef CATCH_CONFIG_CPP11_NULLPTR + // pointer to nullptr_t (when comparing against nullptr) + template bool compare( std::nullptr_t, T* rhs ) { + return Evaluator::evaluate( nullptr, rhs ); + } + template bool compare( T* lhs, std::nullptr_t ) { + return Evaluator::evaluate( lhs, nullptr ); + } +#endif // CATCH_CONFIG_CPP11_NULLPTR + +} // end of namespace Internal +} // end of namespace Catch + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +// #included from: catch_tostring.h +#define TWOBLUECUBES_CATCH_TOSTRING_H_INCLUDED + +#include +#include +#include +#include +#include + +#ifdef __OBJC__ +// #included from: catch_objc_arc.hpp +#define TWOBLUECUBES_CATCH_OBJC_ARC_HPP_INCLUDED + +#import + +#ifdef __has_feature +#define CATCH_ARC_ENABLED __has_feature(objc_arc) +#else +#define CATCH_ARC_ENABLED 0 +#endif + +void arcSafeRelease( NSObject* obj ); +id performOptionalSelector( id obj, SEL sel ); + +#if !CATCH_ARC_ENABLED +inline void arcSafeRelease( NSObject* obj ) { + [obj release]; +} +inline id performOptionalSelector( id obj, SEL sel ) { + if( [obj respondsToSelector: sel] ) + return [obj performSelector: sel]; + return nil; +} +#define CATCH_UNSAFE_UNRETAINED +#define CATCH_ARC_STRONG +#else +inline void arcSafeRelease( NSObject* ){} +inline id performOptionalSelector( id obj, SEL sel ) { +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Warc-performSelector-leaks" +#endif + if( [obj respondsToSelector: sel] ) + return [obj performSelector: sel]; +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + return nil; +} +#define CATCH_UNSAFE_UNRETAINED __unsafe_unretained +#define CATCH_ARC_STRONG __strong +#endif + +#endif + +#ifdef CATCH_CONFIG_CPP11_TUPLE +#include +#endif + +#ifdef CATCH_CONFIG_CPP11_IS_ENUM +#include +#endif + +namespace Catch { + +// Why we're here. +template +std::string toString( T const& value ); + +// Built in overloads + +std::string toString( std::string const& value ); +std::string toString( std::wstring const& value ); +std::string toString( const char* const value ); +std::string toString( char* const value ); +std::string toString( const wchar_t* const value ); +std::string toString( wchar_t* const value ); +std::string toString( int value ); +std::string toString( unsigned long value ); +std::string toString( unsigned int value ); +std::string toString( const double value ); +std::string toString( const float value ); +std::string toString( bool value ); +std::string toString( char value ); +std::string toString( signed char value ); +std::string toString( unsigned char value ); + +#ifdef CATCH_CONFIG_CPP11_LONG_LONG +std::string toString( long long value ); +std::string toString( unsigned long long value ); +#endif + +#ifdef CATCH_CONFIG_CPP11_NULLPTR +std::string toString( std::nullptr_t ); +#endif + +#ifdef __OBJC__ + std::string toString( NSString const * const& nsstring ); + std::string toString( NSString * CATCH_ARC_STRONG const& nsstring ); + std::string toString( NSObject* const& nsObject ); +#endif + +namespace Detail { + + extern const std::string unprintableString; + + struct BorgType { + template BorgType( T const& ); + }; + + struct TrueType { char sizer[1]; }; + struct FalseType { char sizer[2]; }; + + TrueType& testStreamable( std::ostream& ); + FalseType testStreamable( FalseType ); + + FalseType operator<<( std::ostream const&, BorgType const& ); + + template + struct IsStreamInsertable { + static std::ostream &s; + static T const&t; + enum { value = sizeof( testStreamable(s << t) ) == sizeof( TrueType ) }; + }; + +#if defined(CATCH_CONFIG_CPP11_IS_ENUM) + template::value + > + struct EnumStringMaker + { + static std::string convert( T const& ) { return unprintableString; } + }; + + template + struct EnumStringMaker + { + static std::string convert( T const& v ) + { + return ::Catch::toString( + static_cast::type>(v) + ); + } + }; +#endif + template + struct StringMakerBase { +#if defined(CATCH_CONFIG_CPP11_IS_ENUM) + template + static std::string convert( T const& v ) + { + return EnumStringMaker::convert( v ); + } +#else + template + static std::string convert( T const& ) { return unprintableString; } +#endif + }; + + template<> + struct StringMakerBase { + template + static std::string convert( T const& _value ) { + std::ostringstream oss; + oss << _value; + return oss.str(); + } + }; + + std::string rawMemoryToString( const void *object, std::size_t size ); + + template + inline std::string rawMemoryToString( const T& object ) { + return rawMemoryToString( &object, sizeof(object) ); + } + +} // end namespace Detail + +template +struct StringMaker : + Detail::StringMakerBase::value> {}; + +template +struct StringMaker { + template + static std::string convert( U* p ) { + if( !p ) + return "NULL"; + else + return Detail::rawMemoryToString( p ); + } +}; + +template +struct StringMaker { + static std::string convert( R C::* p ) { + if( !p ) + return "NULL"; + else + return Detail::rawMemoryToString( p ); + } +}; + +namespace Detail { + template + std::string rangeToString( InputIterator first, InputIterator last ); +} + +//template +//struct StringMaker > { +// static std::string convert( std::vector const& v ) { +// return Detail::rangeToString( v.begin(), v.end() ); +// } +//}; + +template +std::string toString( std::vector const& v ) { + return Detail::rangeToString( v.begin(), v.end() ); +} + +#ifdef CATCH_CONFIG_CPP11_TUPLE + +// toString for tuples +namespace TupleDetail { + template< + typename Tuple, + std::size_t N = 0, + bool = (N < std::tuple_size::value) + > + struct ElementPrinter { + static void print( const Tuple& tuple, std::ostream& os ) + { + os << ( N ? ", " : " " ) + << Catch::toString(std::get(tuple)); + ElementPrinter::print(tuple,os); + } + }; + + template< + typename Tuple, + std::size_t N + > + struct ElementPrinter { + static void print( const Tuple&, std::ostream& ) {} + }; + +} + +template +struct StringMaker> { + + static std::string convert( const std::tuple& tuple ) + { + std::ostringstream os; + os << '{'; + TupleDetail::ElementPrinter>::print( tuple, os ); + os << " }"; + return os.str(); + } +}; +#endif // CATCH_CONFIG_CPP11_TUPLE + +namespace Detail { + template + std::string makeString( T const& value ) { + return StringMaker::convert( value ); + } +} // end namespace Detail + +/// \brief converts any type to a string +/// +/// The default template forwards on to ostringstream - except when an +/// ostringstream overload does not exist - in which case it attempts to detect +/// that and writes {?}. +/// Overload (not specialise) this template for custom typs that you don't want +/// to provide an ostream overload for. +template +std::string toString( T const& value ) { + return StringMaker::convert( value ); +} + + namespace Detail { + template + std::string rangeToString( InputIterator first, InputIterator last ) { + std::ostringstream oss; + oss << "{ "; + if( first != last ) { + oss << Catch::toString( *first ); + for( ++first ; first != last ; ++first ) + oss << ", " << Catch::toString( *first ); + } + oss << " }"; + return oss.str(); + } +} + +} // end namespace Catch + +namespace Catch { + +// Wraps the LHS of an expression and captures the operator and RHS (if any) - +// wrapping them all in a ResultBuilder object +template +class ExpressionLhs { + ExpressionLhs& operator = ( ExpressionLhs const& ); +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + ExpressionLhs& operator = ( ExpressionLhs && ) = delete; +# endif + +public: + ExpressionLhs( ResultBuilder& rb, T lhs ) : m_rb( rb ), m_lhs( lhs ) {} +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + ExpressionLhs( ExpressionLhs const& ) = default; + ExpressionLhs( ExpressionLhs && ) = default; +# endif + + template + ResultBuilder& operator == ( RhsT const& rhs ) { + return captureExpression( rhs ); + } + + template + ResultBuilder& operator != ( RhsT const& rhs ) { + return captureExpression( rhs ); + } + + template + ResultBuilder& operator < ( RhsT const& rhs ) { + return captureExpression( rhs ); + } + + template + ResultBuilder& operator > ( RhsT const& rhs ) { + return captureExpression( rhs ); + } + + template + ResultBuilder& operator <= ( RhsT const& rhs ) { + return captureExpression( rhs ); + } + + template + ResultBuilder& operator >= ( RhsT const& rhs ) { + return captureExpression( rhs ); + } + + ResultBuilder& operator == ( bool rhs ) { + return captureExpression( rhs ); + } + + ResultBuilder& operator != ( bool rhs ) { + return captureExpression( rhs ); + } + + void endExpression() { + bool value = m_lhs ? true : false; + m_rb + .setLhs( Catch::toString( value ) ) + .setResultType( value ) + .endExpression(); + } + + // Only simple binary expressions are allowed on the LHS. + // If more complex compositions are required then place the sub expression in parentheses + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator + ( RhsT const& ); + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator - ( RhsT const& ); + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator / ( RhsT const& ); + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator * ( RhsT const& ); + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( RhsT const& ); + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || ( RhsT const& ); + +private: + template + ResultBuilder& captureExpression( RhsT const& rhs ) { + return m_rb + .setResultType( Internal::compare( m_lhs, rhs ) ) + .setLhs( Catch::toString( m_lhs ) ) + .setRhs( Catch::toString( rhs ) ) + .setOp( Internal::OperatorTraits::getName() ); + } + +private: + ResultBuilder& m_rb; + T m_lhs; +}; + +} // end namespace Catch + + +namespace Catch { + + template + inline ExpressionLhs ResultBuilder::operator <= ( T const& operand ) { + return ExpressionLhs( *this, operand ); + } + + inline ExpressionLhs ResultBuilder::operator <= ( bool value ) { + return ExpressionLhs( *this, value ); + } + +} // namespace Catch + +// #included from: catch_message.h +#define TWOBLUECUBES_CATCH_MESSAGE_H_INCLUDED + +#include + +namespace Catch { + + struct MessageInfo { + MessageInfo( std::string const& _macroName, + SourceLineInfo const& _lineInfo, + ResultWas::OfType _type ); + + std::string macroName; + SourceLineInfo lineInfo; + ResultWas::OfType type; + std::string message; + unsigned int sequence; + + bool operator == ( MessageInfo const& other ) const { + return sequence == other.sequence; + } + bool operator < ( MessageInfo const& other ) const { + return sequence < other.sequence; + } + private: + static unsigned int globalCount; + }; + + struct MessageBuilder { + MessageBuilder( std::string const& macroName, + SourceLineInfo const& lineInfo, + ResultWas::OfType type ) + : m_info( macroName, lineInfo, type ) + {} + + template + MessageBuilder& operator << ( T const& value ) { + m_stream << value; + return *this; + } + + MessageInfo m_info; + std::ostringstream m_stream; + }; + + class ScopedMessage { + public: + ScopedMessage( MessageBuilder const& builder ); + ScopedMessage( ScopedMessage const& other ); + ~ScopedMessage(); + + MessageInfo m_info; + }; + +} // end namespace Catch + +// #included from: catch_interfaces_capture.h +#define TWOBLUECUBES_CATCH_INTERFACES_CAPTURE_H_INCLUDED + +#include + +namespace Catch { + + class TestCase; + class AssertionResult; + struct AssertionInfo; + struct SectionInfo; + struct SectionEndInfo; + struct MessageInfo; + class ScopedMessageBuilder; + struct Counts; + + struct IResultCapture { + + virtual ~IResultCapture(); + + virtual void assertionEnded( AssertionResult const& result ) = 0; + virtual bool sectionStarted( SectionInfo const& sectionInfo, + Counts& assertions ) = 0; + virtual void sectionEnded( SectionEndInfo const& endInfo ) = 0; + virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) = 0; + virtual void pushScopedMessage( MessageInfo const& message ) = 0; + virtual void popScopedMessage( MessageInfo const& message ) = 0; + + virtual std::string getCurrentTestName() const = 0; + virtual const AssertionResult* getLastResult() const = 0; + + virtual void handleFatalErrorCondition( std::string const& message ) = 0; + }; + + IResultCapture& getResultCapture(); +} + +// #included from: catch_debugger.h +#define TWOBLUECUBES_CATCH_DEBUGGER_H_INCLUDED + +// #included from: catch_platform.h +#define TWOBLUECUBES_CATCH_PLATFORM_H_INCLUDED + +#if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) +#define CATCH_PLATFORM_MAC +#elif defined(__IPHONE_OS_VERSION_MIN_REQUIRED) +#define CATCH_PLATFORM_IPHONE +#elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) +#define CATCH_PLATFORM_WINDOWS +#endif + +#include + +namespace Catch{ + + bool isDebuggerActive(); + void writeToDebugConsole( std::string const& text ); +} + +#ifdef CATCH_PLATFORM_MAC + + // The following code snippet based on: + // http://cocoawithlove.com/2008/03/break-into-debugger.html + #ifdef DEBUG + #if defined(__ppc64__) || defined(__ppc__) + #define CATCH_BREAK_INTO_DEBUGGER() \ + if( Catch::isDebuggerActive() ) { \ + __asm__("li r0, 20\nsc\nnop\nli r0, 37\nli r4, 2\nsc\nnop\n" \ + : : : "memory","r0","r3","r4" ); \ + } + #else + #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) {__asm__("int $3\n" : : );} + #endif + #endif + +#elif defined(_MSC_VER) + #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { __debugbreak(); } +#elif defined(__MINGW32__) + extern "C" __declspec(dllimport) void __stdcall DebugBreak(); + #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { DebugBreak(); } +#endif + +#ifndef CATCH_BREAK_INTO_DEBUGGER +#define CATCH_BREAK_INTO_DEBUGGER() Catch::alwaysTrue(); +#endif + +// #included from: catch_interfaces_runner.h +#define TWOBLUECUBES_CATCH_INTERFACES_RUNNER_H_INCLUDED + +namespace Catch { + class TestCase; + + struct IRunner { + virtual ~IRunner(); + virtual bool aborting() const = 0; + }; +} + +/////////////////////////////////////////////////////////////////////////////// +// In the event of a failure works out if the debugger needs to be invoked +// and/or an exception thrown and takes appropriate action. +// This needs to be done as a macro so the debugger will stop in the user +// source code rather than in Catch library code +#define INTERNAL_CATCH_REACT( resultBuilder ) \ + if( resultBuilder.shouldDebugBreak() ) CATCH_BREAK_INTO_DEBUGGER(); \ + resultBuilder.react(); + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \ + try { \ + CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ + ( __catchResult <= expr ).endExpression(); \ + } \ + catch( ... ) { \ + __catchResult.useActiveException( Catch::ResultDisposition::Normal ); \ + } \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::isTrue( false && static_cast(expr) ) ) // expr here is never evaluated at runtime but it forces the compiler to give it a look + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_IF( expr, resultDisposition, macroName ) \ + INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ); \ + if( Catch::getResultCapture().getLastResult()->succeeded() ) + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_ELSE( expr, resultDisposition, macroName ) \ + INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ); \ + if( !Catch::getResultCapture().getLastResult()->succeeded() ) + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_NO_THROW( expr, resultDisposition, macroName ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \ + try { \ + expr; \ + __catchResult.captureResult( Catch::ResultWas::Ok ); \ + } \ + catch( ... ) { \ + __catchResult.useActiveException( resultDisposition ); \ + } \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::alwaysFalse() ) + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_THROWS( expr, resultDisposition, matcher, macroName ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition, #matcher ); \ + if( __catchResult.allowThrows() ) \ + try { \ + expr; \ + __catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \ + } \ + catch( ... ) { \ + __catchResult.captureExpectedException( matcher ); \ + } \ + else \ + __catchResult.captureResult( Catch::ResultWas::Ok ); \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::alwaysFalse() ) + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_THROWS_AS( expr, exceptionType, resultDisposition, macroName ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \ + if( __catchResult.allowThrows() ) \ + try { \ + expr; \ + __catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \ + } \ + catch( exceptionType ) { \ + __catchResult.captureResult( Catch::ResultWas::Ok ); \ + } \ + catch( ... ) { \ + __catchResult.useActiveException( resultDisposition ); \ + } \ + else \ + __catchResult.captureResult( Catch::ResultWas::Ok ); \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::alwaysFalse() ) + +/////////////////////////////////////////////////////////////////////////////// +#ifdef CATCH_CONFIG_VARIADIC_MACROS + #define INTERNAL_CATCH_MSG( messageType, resultDisposition, macroName, ... ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \ + __catchResult << __VA_ARGS__ + ::Catch::StreamEndStop(); \ + __catchResult.captureResult( messageType ); \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::alwaysFalse() ) +#else + #define INTERNAL_CATCH_MSG( messageType, resultDisposition, macroName, log ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \ + __catchResult << log + ::Catch::StreamEndStop(); \ + __catchResult.captureResult( messageType ); \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::alwaysFalse() ) +#endif + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_INFO( log, macroName ) \ + Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME( scopedMessage ) = Catch::MessageBuilder( macroName, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log; + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CHECK_THAT( arg, matcher, resultDisposition, macroName ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #arg ", " #matcher, resultDisposition ); \ + try { \ + std::string matcherAsString = (matcher).toString(); \ + __catchResult \ + .setLhs( Catch::toString( arg ) ) \ + .setRhs( matcherAsString == Catch::Detail::unprintableString ? #matcher : matcherAsString ) \ + .setOp( "matches" ) \ + .setResultType( (matcher).match( arg ) ); \ + __catchResult.captureExpression(); \ + } catch( ... ) { \ + __catchResult.useActiveException( resultDisposition | Catch::ResultDisposition::ContinueOnFailure ); \ + } \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::alwaysFalse() ) + +// #included from: internal/catch_section.h +#define TWOBLUECUBES_CATCH_SECTION_H_INCLUDED + +// #included from: catch_section_info.h +#define TWOBLUECUBES_CATCH_SECTION_INFO_H_INCLUDED + +// #included from: catch_totals.hpp +#define TWOBLUECUBES_CATCH_TOTALS_HPP_INCLUDED + +#include + +namespace Catch { + + struct Counts { + Counts() : passed( 0 ), failed( 0 ), failedButOk( 0 ) {} + + Counts operator - ( Counts const& other ) const { + Counts diff; + diff.passed = passed - other.passed; + diff.failed = failed - other.failed; + diff.failedButOk = failedButOk - other.failedButOk; + return diff; + } + Counts& operator += ( Counts const& other ) { + passed += other.passed; + failed += other.failed; + failedButOk += other.failedButOk; + return *this; + } + + std::size_t total() const { + return passed + failed + failedButOk; + } + bool allPassed() const { + return failed == 0 && failedButOk == 0; + } + bool allOk() const { + return failed == 0; + } + + std::size_t passed; + std::size_t failed; + std::size_t failedButOk; + }; + + struct Totals { + + Totals operator - ( Totals const& other ) const { + Totals diff; + diff.assertions = assertions - other.assertions; + diff.testCases = testCases - other.testCases; + return diff; + } + + Totals delta( Totals const& prevTotals ) const { + Totals diff = *this - prevTotals; + if( diff.assertions.failed > 0 ) + ++diff.testCases.failed; + else if( diff.assertions.failedButOk > 0 ) + ++diff.testCases.failedButOk; + else + ++diff.testCases.passed; + return diff; + } + + Totals& operator += ( Totals const& other ) { + assertions += other.assertions; + testCases += other.testCases; + return *this; + } + + Counts assertions; + Counts testCases; + }; +} + +namespace Catch { + + struct SectionInfo { + SectionInfo + ( SourceLineInfo const& _lineInfo, + std::string const& _name, + std::string const& _description = std::string() ); + + std::string name; + std::string description; + SourceLineInfo lineInfo; + }; + + struct SectionEndInfo { + SectionEndInfo( SectionInfo const& _sectionInfo, Counts const& _prevAssertions, double _durationInSeconds ) + : sectionInfo( _sectionInfo ), prevAssertions( _prevAssertions ), durationInSeconds( _durationInSeconds ) + {} + + SectionInfo sectionInfo; + Counts prevAssertions; + double durationInSeconds; + }; + +} // end namespace Catch + +// #included from: catch_timer.h +#define TWOBLUECUBES_CATCH_TIMER_H_INCLUDED + +#ifdef CATCH_PLATFORM_WINDOWS +typedef unsigned long long uint64_t; +#else +#include +#endif + +namespace Catch { + + class Timer { + public: + Timer() : m_ticks( 0 ) {} + void start(); + unsigned int getElapsedMicroseconds() const; + unsigned int getElapsedMilliseconds() const; + double getElapsedSeconds() const; + + private: + uint64_t m_ticks; + }; + +} // namespace Catch + +#include + +namespace Catch { + + class Section : NonCopyable { + public: + Section( SectionInfo const& info ); + ~Section(); + + // This indicates whether the section should be executed or not + operator bool() const; + + private: + SectionInfo m_info; + + std::string m_name; + Counts m_assertions; + bool m_sectionIncluded; + Timer m_timer; + }; + +} // end namespace Catch + +#ifdef CATCH_CONFIG_VARIADIC_MACROS + #define INTERNAL_CATCH_SECTION( ... ) \ + if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) ) +#else + #define INTERNAL_CATCH_SECTION( name, desc ) \ + if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, name, desc ) ) +#endif + +// #included from: internal/catch_generators.hpp +#define TWOBLUECUBES_CATCH_GENERATORS_HPP_INCLUDED + +#include +#include +#include +#include + +namespace Catch { + +template +struct IGenerator { + virtual ~IGenerator() {} + virtual T getValue( std::size_t index ) const = 0; + virtual std::size_t size () const = 0; +}; + +template +class BetweenGenerator : public IGenerator { +public: + BetweenGenerator( T from, T to ) : m_from( from ), m_to( to ){} + + virtual T getValue( std::size_t index ) const { + return m_from+static_cast( index ); + } + + virtual std::size_t size() const { + return static_cast( 1+m_to-m_from ); + } + +private: + + T m_from; + T m_to; +}; + +template +class ValuesGenerator : public IGenerator { +public: + ValuesGenerator(){} + + void add( T value ) { + m_values.push_back( value ); + } + + virtual T getValue( std::size_t index ) const { + return m_values[index]; + } + + virtual std::size_t size() const { + return m_values.size(); + } + +private: + std::vector m_values; +}; + +template +class CompositeGenerator { +public: + CompositeGenerator() : m_totalSize( 0 ) {} + + // *** Move semantics, similar to auto_ptr *** + CompositeGenerator( CompositeGenerator& other ) + : m_fileInfo( other.m_fileInfo ), + m_totalSize( 0 ) + { + move( other ); + } + + CompositeGenerator& setFileInfo( const char* fileInfo ) { + m_fileInfo = fileInfo; + return *this; + } + + ~CompositeGenerator() { + deleteAll( m_composed ); + } + + operator T () const { + size_t overallIndex = getCurrentContext().getGeneratorIndex( m_fileInfo, m_totalSize ); + + typename std::vector*>::const_iterator it = m_composed.begin(); + typename std::vector*>::const_iterator itEnd = m_composed.end(); + for( size_t index = 0; it != itEnd; ++it ) + { + const IGenerator* generator = *it; + if( overallIndex >= index && overallIndex < index + generator->size() ) + { + return generator->getValue( overallIndex-index ); + } + index += generator->size(); + } + CATCH_INTERNAL_ERROR( "Indexed past end of generated range" ); + return T(); // Suppress spurious "not all control paths return a value" warning in Visual Studio - if you know how to fix this please do so + } + + void add( const IGenerator* generator ) { + m_totalSize += generator->size(); + m_composed.push_back( generator ); + } + + CompositeGenerator& then( CompositeGenerator& other ) { + move( other ); + return *this; + } + + CompositeGenerator& then( T value ) { + ValuesGenerator* valuesGen = new ValuesGenerator(); + valuesGen->add( value ); + add( valuesGen ); + return *this; + } + +private: + + void move( CompositeGenerator& other ) { + std::copy( other.m_composed.begin(), other.m_composed.end(), std::back_inserter( m_composed ) ); + m_totalSize += other.m_totalSize; + other.m_composed.clear(); + } + + std::vector*> m_composed; + std::string m_fileInfo; + size_t m_totalSize; +}; + +namespace Generators +{ + template + CompositeGenerator between( T from, T to ) { + CompositeGenerator generators; + generators.add( new BetweenGenerator( from, to ) ); + return generators; + } + + template + CompositeGenerator values( T val1, T val2 ) { + CompositeGenerator generators; + ValuesGenerator* valuesGen = new ValuesGenerator(); + valuesGen->add( val1 ); + valuesGen->add( val2 ); + generators.add( valuesGen ); + return generators; + } + + template + CompositeGenerator values( T val1, T val2, T val3 ){ + CompositeGenerator generators; + ValuesGenerator* valuesGen = new ValuesGenerator(); + valuesGen->add( val1 ); + valuesGen->add( val2 ); + valuesGen->add( val3 ); + generators.add( valuesGen ); + return generators; + } + + template + CompositeGenerator values( T val1, T val2, T val3, T val4 ) { + CompositeGenerator generators; + ValuesGenerator* valuesGen = new ValuesGenerator(); + valuesGen->add( val1 ); + valuesGen->add( val2 ); + valuesGen->add( val3 ); + valuesGen->add( val4 ); + generators.add( valuesGen ); + return generators; + } + +} // end namespace Generators + +using namespace Generators; + +} // end namespace Catch + +#define INTERNAL_CATCH_LINESTR2( line ) #line +#define INTERNAL_CATCH_LINESTR( line ) INTERNAL_CATCH_LINESTR2( line ) + +#define INTERNAL_CATCH_GENERATE( expr ) expr.setFileInfo( __FILE__ "(" INTERNAL_CATCH_LINESTR( __LINE__ ) ")" ) + +// #included from: internal/catch_interfaces_exception.h +#define TWOBLUECUBES_CATCH_INTERFACES_EXCEPTION_H_INCLUDED + +#include +#include + +// #included from: catch_interfaces_registry_hub.h +#define TWOBLUECUBES_CATCH_INTERFACES_REGISTRY_HUB_H_INCLUDED + +#include + +namespace Catch { + + class TestCase; + struct ITestCaseRegistry; + struct IExceptionTranslatorRegistry; + struct IExceptionTranslator; + struct IReporterRegistry; + struct IReporterFactory; + + struct IRegistryHub { + virtual ~IRegistryHub(); + + virtual IReporterRegistry const& getReporterRegistry() const = 0; + virtual ITestCaseRegistry const& getTestCaseRegistry() const = 0; + virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() = 0; + }; + + struct IMutableRegistryHub { + virtual ~IMutableRegistryHub(); + virtual void registerReporter( std::string const& name, Ptr const& factory ) = 0; + virtual void registerListener( Ptr const& factory ) = 0; + virtual void registerTest( TestCase const& testInfo ) = 0; + virtual void registerTranslator( const IExceptionTranslator* translator ) = 0; + }; + + IRegistryHub& getRegistryHub(); + IMutableRegistryHub& getMutableRegistryHub(); + void cleanUp(); + std::string translateActiveException(); + +} + +namespace Catch { + + typedef std::string(*exceptionTranslateFunction)(); + + struct IExceptionTranslator; + typedef std::vector ExceptionTranslators; + + struct IExceptionTranslator { + virtual ~IExceptionTranslator(); + virtual std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const = 0; + }; + + struct IExceptionTranslatorRegistry { + virtual ~IExceptionTranslatorRegistry(); + + virtual std::string translateActiveException() const = 0; + }; + + class ExceptionTranslatorRegistrar { + template + class ExceptionTranslator : public IExceptionTranslator { + public: + + ExceptionTranslator( std::string(*translateFunction)( T& ) ) + : m_translateFunction( translateFunction ) + {} + + virtual std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const CATCH_OVERRIDE { + try { + if( it == itEnd ) + throw; + else + return (*it)->translate( it+1, itEnd ); + } + catch( T& ex ) { + return m_translateFunction( ex ); + } + } + + protected: + std::string(*m_translateFunction)( T& ); + }; + + public: + template + ExceptionTranslatorRegistrar( std::string(*translateFunction)( T& ) ) { + getMutableRegistryHub().registerTranslator + ( new ExceptionTranslator( translateFunction ) ); + } + }; +} + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) \ + static std::string INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator )( signature ); \ + namespace{ Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ) ); }\ + static std::string INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator )( signature ) + +// #included from: internal/catch_approx.hpp +#define TWOBLUECUBES_CATCH_APPROX_HPP_INCLUDED + +#include +#include + +namespace Catch { +namespace Detail { + + class Approx { + public: + explicit Approx ( double value ) + : m_epsilon( std::numeric_limits::epsilon()*100 ), + m_scale( 1.0 ), + m_value( value ) + {} + + Approx( Approx const& other ) + : m_epsilon( other.m_epsilon ), + m_scale( other.m_scale ), + m_value( other.m_value ) + {} + + static Approx custom() { + return Approx( 0 ); + } + + Approx operator()( double value ) { + Approx approx( value ); + approx.epsilon( m_epsilon ); + approx.scale( m_scale ); + return approx; + } + + friend bool operator == ( double lhs, Approx const& rhs ) { + // Thanks to Richard Harris for his help refining this formula + return fabs( lhs - rhs.m_value ) < rhs.m_epsilon * (rhs.m_scale + (std::max)( fabs(lhs), fabs(rhs.m_value) ) ); + } + + friend bool operator == ( Approx const& lhs, double rhs ) { + return operator==( rhs, lhs ); + } + + friend bool operator != ( double lhs, Approx const& rhs ) { + return !operator==( lhs, rhs ); + } + + friend bool operator != ( Approx const& lhs, double rhs ) { + return !operator==( rhs, lhs ); + } + + Approx& epsilon( double newEpsilon ) { + m_epsilon = newEpsilon; + return *this; + } + + Approx& scale( double newScale ) { + m_scale = newScale; + return *this; + } + + std::string toString() const { + std::ostringstream oss; + oss << "Approx( " << Catch::toString( m_value ) << " )"; + return oss.str(); + } + + private: + double m_epsilon; + double m_scale; + double m_value; + }; +} + +template<> +inline std::string toString( Detail::Approx const& value ) { + return value.toString(); +} + +} // end namespace Catch + +// #included from: internal/catch_interfaces_tag_alias_registry.h +#define TWOBLUECUBES_CATCH_INTERFACES_TAG_ALIAS_REGISTRY_H_INCLUDED + +// #included from: catch_tag_alias.h +#define TWOBLUECUBES_CATCH_TAG_ALIAS_H_INCLUDED + +#include + +namespace Catch { + + struct TagAlias { + TagAlias( std::string _tag, SourceLineInfo _lineInfo ) : tag( _tag ), lineInfo( _lineInfo ) {} + + std::string tag; + SourceLineInfo lineInfo; + }; + + struct RegistrarForTagAliases { + RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ); + }; + +} // end namespace Catch + +#define CATCH_REGISTER_TAG_ALIAS( alias, spec ) namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); } +// #included from: catch_option.hpp +#define TWOBLUECUBES_CATCH_OPTION_HPP_INCLUDED + +namespace Catch { + + // An optional type + template + class Option { + public: + Option() : nullableValue( CATCH_NULL ) {} + Option( T const& _value ) + : nullableValue( new( storage ) T( _value ) ) + {} + Option( Option const& _other ) + : nullableValue( _other ? new( storage ) T( *_other ) : CATCH_NULL ) + {} + + ~Option() { + reset(); + } + + Option& operator= ( Option const& _other ) { + if( &_other != this ) { + reset(); + if( _other ) + nullableValue = new( storage ) T( *_other ); + } + return *this; + } + Option& operator = ( T const& _value ) { + reset(); + nullableValue = new( storage ) T( _value ); + return *this; + } + + void reset() { + if( nullableValue ) + nullableValue->~T(); + nullableValue = CATCH_NULL; + } + + T& operator*() { return *nullableValue; } + T const& operator*() const { return *nullableValue; } + T* operator->() { return nullableValue; } + const T* operator->() const { return nullableValue; } + + T valueOr( T const& defaultValue ) const { + return nullableValue ? *nullableValue : defaultValue; + } + + bool some() const { return nullableValue != CATCH_NULL; } + bool none() const { return nullableValue == CATCH_NULL; } + + bool operator !() const { return nullableValue == CATCH_NULL; } + operator SafeBool::type() const { + return SafeBool::makeSafe( some() ); + } + + private: + T* nullableValue; + char storage[sizeof(T)]; + }; + +} // end namespace Catch + +namespace Catch { + + struct ITagAliasRegistry { + virtual ~ITagAliasRegistry(); + virtual Option find( std::string const& alias ) const = 0; + virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const = 0; + + static ITagAliasRegistry const& get(); + }; + +} // end namespace Catch + +// These files are included here so the single_include script doesn't put them +// in the conditionally compiled sections +// #included from: internal/catch_test_case_info.h +#define TWOBLUECUBES_CATCH_TEST_CASE_INFO_H_INCLUDED + +#include +#include + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpadded" +#endif + +namespace Catch { + + struct ITestCase; + + struct TestCaseInfo { + enum SpecialProperties{ + None = 0, + IsHidden = 1 << 1, + ShouldFail = 1 << 2, + MayFail = 1 << 3, + Throws = 1 << 4 + }; + + TestCaseInfo( std::string const& _name, + std::string const& _className, + std::string const& _description, + std::set const& _tags, + SourceLineInfo const& _lineInfo ); + + TestCaseInfo( TestCaseInfo const& other ); + + friend void setTags( TestCaseInfo& testCaseInfo, std::set const& tags ); + + bool isHidden() const; + bool throws() const; + bool okToFail() const; + bool expectedToFail() const; + + std::string name; + std::string className; + std::string description; + std::set tags; + std::set lcaseTags; + std::string tagsAsString; + SourceLineInfo lineInfo; + SpecialProperties properties; + }; + + class TestCase : public TestCaseInfo { + public: + + TestCase( ITestCase* testCase, TestCaseInfo const& info ); + TestCase( TestCase const& other ); + + TestCase withName( std::string const& _newName ) const; + + void invoke() const; + + TestCaseInfo const& getTestCaseInfo() const; + + void swap( TestCase& other ); + bool operator == ( TestCase const& other ) const; + bool operator < ( TestCase const& other ) const; + TestCase& operator = ( TestCase const& other ); + + private: + Ptr test; + }; + + TestCase makeTestCase( ITestCase* testCase, + std::string const& className, + std::string const& name, + std::string const& description, + SourceLineInfo const& lineInfo ); +} + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + + +#ifdef __OBJC__ +// #included from: internal/catch_objc.hpp +#define TWOBLUECUBES_CATCH_OBJC_HPP_INCLUDED + +#import + +#include + +// NB. Any general catch headers included here must be included +// in catch.hpp first to make sure they are included by the single +// header for non obj-usage + +/////////////////////////////////////////////////////////////////////////////// +// This protocol is really only here for (self) documenting purposes, since +// all its methods are optional. +@protocol OcFixture + +@optional + +-(void) setUp; +-(void) tearDown; + +@end + +namespace Catch { + + class OcMethod : public SharedImpl { + + public: + OcMethod( Class cls, SEL sel ) : m_cls( cls ), m_sel( sel ) {} + + virtual void invoke() const { + id obj = [[m_cls alloc] init]; + + performOptionalSelector( obj, @selector(setUp) ); + performOptionalSelector( obj, m_sel ); + performOptionalSelector( obj, @selector(tearDown) ); + + arcSafeRelease( obj ); + } + private: + virtual ~OcMethod() {} + + Class m_cls; + SEL m_sel; + }; + + namespace Detail{ + + inline std::string getAnnotation( Class cls, + std::string const& annotationName, + std::string const& testCaseName ) { + NSString* selStr = [[NSString alloc] initWithFormat:@"Catch_%s_%s", annotationName.c_str(), testCaseName.c_str()]; + SEL sel = NSSelectorFromString( selStr ); + arcSafeRelease( selStr ); + id value = performOptionalSelector( cls, sel ); + if( value ) + return [(NSString*)value UTF8String]; + return ""; + } + } + + inline size_t registerTestMethods() { + size_t noTestMethods = 0; + int noClasses = objc_getClassList( CATCH_NULL, 0 ); + + Class* classes = (CATCH_UNSAFE_UNRETAINED Class *)malloc( sizeof(Class) * noClasses); + objc_getClassList( classes, noClasses ); + + for( int c = 0; c < noClasses; c++ ) { + Class cls = classes[c]; + { + u_int count; + Method* methods = class_copyMethodList( cls, &count ); + for( u_int m = 0; m < count ; m++ ) { + SEL selector = method_getName(methods[m]); + std::string methodName = sel_getName(selector); + if( startsWith( methodName, "Catch_TestCase_" ) ) { + std::string testCaseName = methodName.substr( 15 ); + std::string name = Detail::getAnnotation( cls, "Name", testCaseName ); + std::string desc = Detail::getAnnotation( cls, "Description", testCaseName ); + const char* className = class_getName( cls ); + + getMutableRegistryHub().registerTest( makeTestCase( new OcMethod( cls, selector ), className, name.c_str(), desc.c_str(), SourceLineInfo() ) ); + noTestMethods++; + } + } + free(methods); + } + } + return noTestMethods; + } + + namespace Matchers { + namespace Impl { + namespace NSStringMatchers { + + template + struct StringHolder : MatcherImpl{ + StringHolder( NSString* substr ) : m_substr( [substr copy] ){} + StringHolder( StringHolder const& other ) : m_substr( [other.m_substr copy] ){} + StringHolder() { + arcSafeRelease( m_substr ); + } + + NSString* m_substr; + }; + + struct Equals : StringHolder { + Equals( NSString* substr ) : StringHolder( substr ){} + + virtual bool match( ExpressionType const& str ) const { + return (str != nil || m_substr == nil ) && + [str isEqualToString:m_substr]; + } + + virtual std::string toString() const { + return "equals string: " + Catch::toString( m_substr ); + } + }; + + struct Contains : StringHolder { + Contains( NSString* substr ) : StringHolder( substr ){} + + virtual bool match( ExpressionType const& str ) const { + return (str != nil || m_substr == nil ) && + [str rangeOfString:m_substr].location != NSNotFound; + } + + virtual std::string toString() const { + return "contains string: " + Catch::toString( m_substr ); + } + }; + + struct StartsWith : StringHolder { + StartsWith( NSString* substr ) : StringHolder( substr ){} + + virtual bool match( ExpressionType const& str ) const { + return (str != nil || m_substr == nil ) && + [str rangeOfString:m_substr].location == 0; + } + + virtual std::string toString() const { + return "starts with: " + Catch::toString( m_substr ); + } + }; + struct EndsWith : StringHolder { + EndsWith( NSString* substr ) : StringHolder( substr ){} + + virtual bool match( ExpressionType const& str ) const { + return (str != nil || m_substr == nil ) && + [str rangeOfString:m_substr].location == [str length] - [m_substr length]; + } + + virtual std::string toString() const { + return "ends with: " + Catch::toString( m_substr ); + } + }; + + } // namespace NSStringMatchers + } // namespace Impl + + inline Impl::NSStringMatchers::Equals + Equals( NSString* substr ){ return Impl::NSStringMatchers::Equals( substr ); } + + inline Impl::NSStringMatchers::Contains + Contains( NSString* substr ){ return Impl::NSStringMatchers::Contains( substr ); } + + inline Impl::NSStringMatchers::StartsWith + StartsWith( NSString* substr ){ return Impl::NSStringMatchers::StartsWith( substr ); } + + inline Impl::NSStringMatchers::EndsWith + EndsWith( NSString* substr ){ return Impl::NSStringMatchers::EndsWith( substr ); } + + } // namespace Matchers + + using namespace Matchers; + +} // namespace Catch + +/////////////////////////////////////////////////////////////////////////////// +#define OC_TEST_CASE( name, desc )\ ++(NSString*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Name_test ) \ +{\ +return @ name; \ +}\ ++(NSString*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Description_test ) \ +{ \ +return @ desc; \ +} \ +-(void) INTERNAL_CATCH_UNIQUE_NAME( Catch_TestCase_test ) + +#endif + +#ifdef CATCH_IMPL +// #included from: internal/catch_impl.hpp +#define TWOBLUECUBES_CATCH_IMPL_HPP_INCLUDED + +// Collect all the implementation files together here +// These are the equivalent of what would usually be cpp files + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wweak-vtables" +#endif + +// #included from: ../catch_session.hpp +#define TWOBLUECUBES_CATCH_RUNNER_HPP_INCLUDED + +// #included from: internal/catch_commandline.hpp +#define TWOBLUECUBES_CATCH_COMMANDLINE_HPP_INCLUDED + +// #included from: catch_config.hpp +#define TWOBLUECUBES_CATCH_CONFIG_HPP_INCLUDED + +// #included from: catch_test_spec_parser.hpp +#define TWOBLUECUBES_CATCH_TEST_SPEC_PARSER_HPP_INCLUDED + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpadded" +#endif + +// #included from: catch_test_spec.hpp +#define TWOBLUECUBES_CATCH_TEST_SPEC_HPP_INCLUDED + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpadded" +#endif + +// #included from: catch_wildcard_pattern.hpp +#define TWOBLUECUBES_CATCH_WILDCARD_PATTERN_HPP_INCLUDED + +namespace Catch +{ + class WildcardPattern { + enum WildcardPosition { + NoWildcard = 0, + WildcardAtStart = 1, + WildcardAtEnd = 2, + WildcardAtBothEnds = WildcardAtStart | WildcardAtEnd + }; + + public: + + WildcardPattern( std::string const& pattern, CaseSensitive::Choice caseSensitivity ) + : m_caseSensitivity( caseSensitivity ), + m_wildcard( NoWildcard ), + m_pattern( adjustCase( pattern ) ) + { + if( startsWith( m_pattern, "*" ) ) { + m_pattern = m_pattern.substr( 1 ); + m_wildcard = WildcardAtStart; + } + if( endsWith( m_pattern, "*" ) ) { + m_pattern = m_pattern.substr( 0, m_pattern.size()-1 ); + m_wildcard = static_cast( m_wildcard | WildcardAtEnd ); + } + } + virtual ~WildcardPattern(); + virtual bool matches( std::string const& str ) const { + switch( m_wildcard ) { + case NoWildcard: + return m_pattern == adjustCase( str ); + case WildcardAtStart: + return endsWith( adjustCase( str ), m_pattern ); + case WildcardAtEnd: + return startsWith( adjustCase( str ), m_pattern ); + case WildcardAtBothEnds: + return contains( adjustCase( str ), m_pattern ); + } + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunreachable-code" +#endif + throw std::logic_error( "Unknown enum" ); +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + } + private: + std::string adjustCase( std::string const& str ) const { + return m_caseSensitivity == CaseSensitive::No ? toLower( str ) : str; + } + CaseSensitive::Choice m_caseSensitivity; + WildcardPosition m_wildcard; + std::string m_pattern; + }; +} + +#include +#include + +namespace Catch { + + class TestSpec { + struct Pattern : SharedImpl<> { + virtual ~Pattern(); + virtual bool matches( TestCaseInfo const& testCase ) const = 0; + }; + class NamePattern : public Pattern { + public: + NamePattern( std::string const& name ) + : m_wildcardPattern( toLower( name ), CaseSensitive::No ) + {} + virtual ~NamePattern(); + virtual bool matches( TestCaseInfo const& testCase ) const { + return m_wildcardPattern.matches( toLower( testCase.name ) ); + } + private: + WildcardPattern m_wildcardPattern; + }; + + class TagPattern : public Pattern { + public: + TagPattern( std::string const& tag ) : m_tag( toLower( tag ) ) {} + virtual ~TagPattern(); + virtual bool matches( TestCaseInfo const& testCase ) const { + return testCase.lcaseTags.find( m_tag ) != testCase.lcaseTags.end(); + } + private: + std::string m_tag; + }; + + class ExcludedPattern : public Pattern { + public: + ExcludedPattern( Ptr const& underlyingPattern ) : m_underlyingPattern( underlyingPattern ) {} + virtual ~ExcludedPattern(); + virtual bool matches( TestCaseInfo const& testCase ) const { return !m_underlyingPattern->matches( testCase ); } + private: + Ptr m_underlyingPattern; + }; + + struct Filter { + std::vector > m_patterns; + + bool matches( TestCaseInfo const& testCase ) const { + // All patterns in a filter must match for the filter to be a match + for( std::vector >::const_iterator it = m_patterns.begin(), itEnd = m_patterns.end(); it != itEnd; ++it ) + if( !(*it)->matches( testCase ) ) + return false; + return true; + } + }; + + public: + bool hasFilters() const { + return !m_filters.empty(); + } + bool matches( TestCaseInfo const& testCase ) const { + // A TestSpec matches if any filter matches + for( std::vector::const_iterator it = m_filters.begin(), itEnd = m_filters.end(); it != itEnd; ++it ) + if( it->matches( testCase ) ) + return true; + return false; + } + + private: + std::vector m_filters; + + friend class TestSpecParser; + }; +} + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +namespace Catch { + + class TestSpecParser { + enum Mode{ None, Name, QuotedName, Tag }; + Mode m_mode; + bool m_exclusion; + std::size_t m_start, m_pos; + std::string m_arg; + TestSpec::Filter m_currentFilter; + TestSpec m_testSpec; + ITagAliasRegistry const* m_tagAliases; + + public: + TestSpecParser( ITagAliasRegistry const& tagAliases ) : m_tagAliases( &tagAliases ) {} + + TestSpecParser& parse( std::string const& arg ) { + m_mode = None; + m_exclusion = false; + m_start = std::string::npos; + m_arg = m_tagAliases->expandAliases( arg ); + for( m_pos = 0; m_pos < m_arg.size(); ++m_pos ) + visitChar( m_arg[m_pos] ); + if( m_mode == Name ) + addPattern(); + return *this; + } + TestSpec testSpec() { + addFilter(); + return m_testSpec; + } + private: + void visitChar( char c ) { + if( m_mode == None ) { + switch( c ) { + case ' ': return; + case '~': m_exclusion = true; return; + case '[': return startNewMode( Tag, ++m_pos ); + case '"': return startNewMode( QuotedName, ++m_pos ); + default: startNewMode( Name, m_pos ); break; + } + } + if( m_mode == Name ) { + if( c == ',' ) { + addPattern(); + addFilter(); + } + else if( c == '[' ) { + if( subString() == "exclude:" ) + m_exclusion = true; + else + addPattern(); + startNewMode( Tag, ++m_pos ); + } + } + else if( m_mode == QuotedName && c == '"' ) + addPattern(); + else if( m_mode == Tag && c == ']' ) + addPattern(); + } + void startNewMode( Mode mode, std::size_t start ) { + m_mode = mode; + m_start = start; + } + std::string subString() const { return m_arg.substr( m_start, m_pos - m_start ); } + template + void addPattern() { + std::string token = subString(); + if( startsWith( token, "exclude:" ) ) { + m_exclusion = true; + token = token.substr( 8 ); + } + if( !token.empty() ) { + Ptr pattern = new T( token ); + if( m_exclusion ) + pattern = new TestSpec::ExcludedPattern( pattern ); + m_currentFilter.m_patterns.push_back( pattern ); + } + m_exclusion = false; + m_mode = None; + } + void addFilter() { + if( !m_currentFilter.m_patterns.empty() ) { + m_testSpec.m_filters.push_back( m_currentFilter ); + m_currentFilter = TestSpec::Filter(); + } + } + }; + inline TestSpec parseTestSpec( std::string const& arg ) { + return TestSpecParser( ITagAliasRegistry::get() ).parse( arg ).testSpec(); + } + +} // namespace Catch + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +// #included from: catch_interfaces_config.h +#define TWOBLUECUBES_CATCH_INTERFACES_CONFIG_H_INCLUDED + +#include +#include +#include + +namespace Catch { + + struct Verbosity { enum Level { + NoOutput = 0, + Quiet, + Normal + }; }; + + struct WarnAbout { enum What { + Nothing = 0x00, + NoAssertions = 0x01 + }; }; + + struct ShowDurations { enum OrNot { + DefaultForReporter, + Always, + Never + }; }; + struct RunTests { enum InWhatOrder { + InDeclarationOrder, + InLexicographicalOrder, + InRandomOrder + }; }; + struct UseColour { enum YesOrNo { + Auto, + Yes, + No + }; }; + + class TestSpec; + + struct IConfig : IShared { + + virtual ~IConfig(); + + virtual bool allowThrows() const = 0; + virtual std::ostream& stream() const = 0; + virtual std::string name() const = 0; + virtual bool includeSuccessfulResults() const = 0; + virtual bool shouldDebugBreak() const = 0; + virtual bool warnAboutMissingAssertions() const = 0; + virtual int abortAfter() const = 0; + virtual bool showInvisibles() const = 0; + virtual ShowDurations::OrNot showDurations() const = 0; + virtual TestSpec const& testSpec() const = 0; + virtual RunTests::InWhatOrder runOrder() const = 0; + virtual unsigned int rngSeed() const = 0; + virtual UseColour::YesOrNo useColour() const = 0; + }; +} + +// #included from: catch_stream.h +#define TWOBLUECUBES_CATCH_STREAM_H_INCLUDED + +// #included from: catch_streambuf.h +#define TWOBLUECUBES_CATCH_STREAMBUF_H_INCLUDED + +#include + +namespace Catch { + + class StreamBufBase : public std::streambuf { + public: + virtual ~StreamBufBase() CATCH_NOEXCEPT; + }; +} + +#include +#include +#include + +namespace Catch { + + std::ostream& cout(); + std::ostream& cerr(); + + struct IStream { + virtual ~IStream() CATCH_NOEXCEPT; + virtual std::ostream& stream() const = 0; + }; + + class FileStream : public IStream { + mutable std::ofstream m_ofs; + public: + FileStream( std::string const& filename ); + virtual ~FileStream() CATCH_NOEXCEPT; + public: // IStream + virtual std::ostream& stream() const CATCH_OVERRIDE; + }; + + class CoutStream : public IStream { + mutable std::ostream m_os; + public: + CoutStream(); + virtual ~CoutStream() CATCH_NOEXCEPT; + + public: // IStream + virtual std::ostream& stream() const CATCH_OVERRIDE; + }; + + class DebugOutStream : public IStream { + std::auto_ptr m_streamBuf; + mutable std::ostream m_os; + public: + DebugOutStream(); + virtual ~DebugOutStream() CATCH_NOEXCEPT; + + public: // IStream + virtual std::ostream& stream() const CATCH_OVERRIDE; + }; +} + +#include +#include +#include +#include +#include + +#ifndef CATCH_CONFIG_CONSOLE_WIDTH +#define CATCH_CONFIG_CONSOLE_WIDTH 80 +#endif + +namespace Catch { + + struct ConfigData { + + ConfigData() + : listTests( false ), + listTags( false ), + listReporters( false ), + listTestNamesOnly( false ), + showSuccessfulTests( false ), + shouldDebugBreak( false ), + noThrow( false ), + showHelp( false ), + showInvisibles( false ), + filenamesAsTags( false ), + abortAfter( -1 ), + rngSeed( 0 ), + verbosity( Verbosity::Normal ), + warnings( WarnAbout::Nothing ), + showDurations( ShowDurations::DefaultForReporter ), + runOrder( RunTests::InDeclarationOrder ), + useColour( UseColour::Auto ) + {} + + bool listTests; + bool listTags; + bool listReporters; + bool listTestNamesOnly; + + bool showSuccessfulTests; + bool shouldDebugBreak; + bool noThrow; + bool showHelp; + bool showInvisibles; + bool filenamesAsTags; + + int abortAfter; + unsigned int rngSeed; + + Verbosity::Level verbosity; + WarnAbout::What warnings; + ShowDurations::OrNot showDurations; + RunTests::InWhatOrder runOrder; + UseColour::YesOrNo useColour; + + std::string outputFilename; + std::string name; + std::string processName; + + std::vector reporterNames; + std::vector testsOrTags; + }; + + class Config : public SharedImpl { + private: + Config( Config const& other ); + Config& operator = ( Config const& other ); + virtual void dummy(); + public: + + Config() + {} + + Config( ConfigData const& data ) + : m_data( data ), + m_stream( openStream() ) + { + if( !data.testsOrTags.empty() ) { + TestSpecParser parser( ITagAliasRegistry::get() ); + for( std::size_t i = 0; i < data.testsOrTags.size(); ++i ) + parser.parse( data.testsOrTags[i] ); + m_testSpec = parser.testSpec(); + } + } + + virtual ~Config() { + } + + std::string const& getFilename() const { + return m_data.outputFilename ; + } + + bool listTests() const { return m_data.listTests; } + bool listTestNamesOnly() const { return m_data.listTestNamesOnly; } + bool listTags() const { return m_data.listTags; } + bool listReporters() const { return m_data.listReporters; } + + std::string getProcessName() const { return m_data.processName; } + + bool shouldDebugBreak() const { return m_data.shouldDebugBreak; } + + std::vector getReporterNames() const { return m_data.reporterNames; } + + int abortAfter() const { return m_data.abortAfter; } + + TestSpec const& testSpec() const { return m_testSpec; } + + bool showHelp() const { return m_data.showHelp; } + bool showInvisibles() const { return m_data.showInvisibles; } + + // IConfig interface + virtual bool allowThrows() const { return !m_data.noThrow; } + virtual std::ostream& stream() const { return m_stream->stream(); } + virtual std::string name() const { return m_data.name.empty() ? m_data.processName : m_data.name; } + virtual bool includeSuccessfulResults() const { return m_data.showSuccessfulTests; } + virtual bool warnAboutMissingAssertions() const { return m_data.warnings & WarnAbout::NoAssertions; } + virtual ShowDurations::OrNot showDurations() const { return m_data.showDurations; } + virtual RunTests::InWhatOrder runOrder() const { return m_data.runOrder; } + virtual unsigned int rngSeed() const { return m_data.rngSeed; } + virtual UseColour::YesOrNo useColour() const { return m_data.useColour; } + + private: + + IStream const* openStream() { + if( m_data.outputFilename.empty() ) + return new CoutStream(); + else if( m_data.outputFilename[0] == '%' ) { + if( m_data.outputFilename == "%debug" ) + return new DebugOutStream(); + else + throw std::domain_error( "Unrecognised stream: " + m_data.outputFilename ); + } + else + return new FileStream( m_data.outputFilename ); + } + ConfigData m_data; + + std::auto_ptr m_stream; + TestSpec m_testSpec; + }; + +} // end namespace Catch + +// #included from: catch_clara.h +#define TWOBLUECUBES_CATCH_CLARA_H_INCLUDED + +// Use Catch's value for console width (store Clara's off to the side, if present) +#ifdef CLARA_CONFIG_CONSOLE_WIDTH +#define CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH CLARA_CONFIG_CONSOLE_WIDTH +#undef CLARA_CONFIG_CONSOLE_WIDTH +#endif +#define CLARA_CONFIG_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH + +// Declare Clara inside the Catch namespace +#define STITCH_CLARA_OPEN_NAMESPACE namespace Catch { +// #included from: ../external/clara.h + +// Version 0.0.1.1 + +// Only use header guard if we are not using an outer namespace +#if !defined(TWOBLUECUBES_CLARA_H_INCLUDED) || defined(STITCH_CLARA_OPEN_NAMESPACE) + +#ifndef STITCH_CLARA_OPEN_NAMESPACE +#define TWOBLUECUBES_CLARA_H_INCLUDED +#define STITCH_CLARA_OPEN_NAMESPACE +#define STITCH_CLARA_CLOSE_NAMESPACE +#else +#define STITCH_CLARA_CLOSE_NAMESPACE } +#endif + +#define STITCH_TBC_TEXT_FORMAT_OPEN_NAMESPACE STITCH_CLARA_OPEN_NAMESPACE + +// ----------- #included from tbc_text_format.h ----------- + +// Only use header guard if we are not using an outer namespace +#if !defined(TBC_TEXT_FORMAT_H_INCLUDED) || defined(STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE) +#ifndef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE +#define TBC_TEXT_FORMAT_H_INCLUDED +#endif + +#include +#include +#include +#include + +// Use optional outer namespace +#ifdef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE +namespace STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE { +#endif + +namespace Tbc { + +#ifdef TBC_TEXT_FORMAT_CONSOLE_WIDTH + const unsigned int consoleWidth = TBC_TEXT_FORMAT_CONSOLE_WIDTH; +#else + const unsigned int consoleWidth = 80; +#endif + + struct TextAttributes { + TextAttributes() + : initialIndent( std::string::npos ), + indent( 0 ), + width( consoleWidth-1 ), + tabChar( '\t' ) + {} + + TextAttributes& setInitialIndent( std::size_t _value ) { initialIndent = _value; return *this; } + TextAttributes& setIndent( std::size_t _value ) { indent = _value; return *this; } + TextAttributes& setWidth( std::size_t _value ) { width = _value; return *this; } + TextAttributes& setTabChar( char _value ) { tabChar = _value; return *this; } + + std::size_t initialIndent; // indent of first line, or npos + std::size_t indent; // indent of subsequent lines, or all if initialIndent is npos + std::size_t width; // maximum width of text, including indent. Longer text will wrap + char tabChar; // If this char is seen the indent is changed to current pos + }; + + class Text { + public: + Text( std::string const& _str, TextAttributes const& _attr = TextAttributes() ) + : attr( _attr ) + { + std::string wrappableChars = " [({.,/|\\-"; + std::size_t indent = _attr.initialIndent != std::string::npos + ? _attr.initialIndent + : _attr.indent; + std::string remainder = _str; + + while( !remainder.empty() ) { + if( lines.size() >= 1000 ) { + lines.push_back( "... message truncated due to excessive size" ); + return; + } + std::size_t tabPos = std::string::npos; + std::size_t width = (std::min)( remainder.size(), _attr.width - indent ); + std::size_t pos = remainder.find_first_of( '\n' ); + if( pos <= width ) { + width = pos; + } + pos = remainder.find_last_of( _attr.tabChar, width ); + if( pos != std::string::npos ) { + tabPos = pos; + if( remainder[width] == '\n' ) + width--; + remainder = remainder.substr( 0, tabPos ) + remainder.substr( tabPos+1 ); + } + + if( width == remainder.size() ) { + spliceLine( indent, remainder, width ); + } + else if( remainder[width] == '\n' ) { + spliceLine( indent, remainder, width ); + if( width <= 1 || remainder.size() != 1 ) + remainder = remainder.substr( 1 ); + indent = _attr.indent; + } + else { + pos = remainder.find_last_of( wrappableChars, width ); + if( pos != std::string::npos && pos > 0 ) { + spliceLine( indent, remainder, pos ); + if( remainder[0] == ' ' ) + remainder = remainder.substr( 1 ); + } + else { + spliceLine( indent, remainder, width-1 ); + lines.back() += "-"; + } + if( lines.size() == 1 ) + indent = _attr.indent; + if( tabPos != std::string::npos ) + indent += tabPos; + } + } + } + + void spliceLine( std::size_t _indent, std::string& _remainder, std::size_t _pos ) { + lines.push_back( std::string( _indent, ' ' ) + _remainder.substr( 0, _pos ) ); + _remainder = _remainder.substr( _pos ); + } + + typedef std::vector::const_iterator const_iterator; + + const_iterator begin() const { return lines.begin(); } + const_iterator end() const { return lines.end(); } + std::string const& last() const { return lines.back(); } + std::size_t size() const { return lines.size(); } + std::string const& operator[]( std::size_t _index ) const { return lines[_index]; } + std::string toString() const { + std::ostringstream oss; + oss << *this; + return oss.str(); + } + + inline friend std::ostream& operator << ( std::ostream& _stream, Text const& _text ) { + for( Text::const_iterator it = _text.begin(), itEnd = _text.end(); + it != itEnd; ++it ) { + if( it != _text.begin() ) + _stream << "\n"; + _stream << *it; + } + return _stream; + } + + private: + std::string str; + TextAttributes attr; + std::vector lines; + }; + +} // end namespace Tbc + +#ifdef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE +} // end outer namespace +#endif + +#endif // TBC_TEXT_FORMAT_H_INCLUDED + +// ----------- end of #include from tbc_text_format.h ----------- +// ........... back in clara.h + +#undef STITCH_TBC_TEXT_FORMAT_OPEN_NAMESPACE + +// ----------- #included from clara_compilers.h ----------- + +#ifndef TWOBLUECUBES_CLARA_COMPILERS_H_INCLUDED +#define TWOBLUECUBES_CLARA_COMPILERS_H_INCLUDED + +// Detect a number of compiler features - mostly C++11/14 conformance - by compiler +// The following features are defined: +// +// CLARA_CONFIG_CPP11_NULLPTR : is nullptr supported? +// CLARA_CONFIG_CPP11_NOEXCEPT : is noexcept supported? +// CLARA_CONFIG_CPP11_GENERATED_METHODS : The delete and default keywords for compiler generated methods +// CLARA_CONFIG_CPP11_OVERRIDE : is override supported? +// CLARA_CONFIG_CPP11_UNIQUE_PTR : is unique_ptr supported (otherwise use auto_ptr) + +// CLARA_CONFIG_CPP11_OR_GREATER : Is C++11 supported? + +// CLARA_CONFIG_VARIADIC_MACROS : are variadic macros supported? + +// In general each macro has a _NO_ form +// (e.g. CLARA_CONFIG_CPP11_NO_NULLPTR) which disables the feature. +// Many features, at point of detection, define an _INTERNAL_ macro, so they +// can be combined, en-mass, with the _NO_ forms later. + +// All the C++11 features can be disabled with CLARA_CONFIG_NO_CPP11 + +#ifdef __clang__ + +#if __has_feature(cxx_nullptr) +#define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR +#endif + +#if __has_feature(cxx_noexcept) +#define CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT +#endif + +#endif // __clang__ + +//////////////////////////////////////////////////////////////////////////////// +// GCC +#ifdef __GNUC__ + +#if __GNUC__ == 4 && __GNUC_MINOR__ >= 6 && defined(__GXX_EXPERIMENTAL_CXX0X__) +#define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR +#endif + +// - otherwise more recent versions define __cplusplus >= 201103L +// and will get picked up below + +#endif // __GNUC__ + +//////////////////////////////////////////////////////////////////////////////// +// Visual C++ +#ifdef _MSC_VER + +#if (_MSC_VER >= 1600) +#define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR +#define CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR +#endif + +#if (_MSC_VER >= 1900 ) // (VC++ 13 (VS2015)) +#define CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT +#define CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS +#endif + +#endif // _MSC_VER + +//////////////////////////////////////////////////////////////////////////////// +// C++ language feature support + +// catch all support for C++11 +#if defined(__cplusplus) && __cplusplus >= 201103L + +#define CLARA_CPP11_OR_GREATER + +#if !defined(CLARA_INTERNAL_CONFIG_CPP11_NULLPTR) +#define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR +#endif + +#ifndef CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT +#define CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT +#endif + +#ifndef CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS +#define CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS +#endif + +#if !defined(CLARA_INTERNAL_CONFIG_CPP11_OVERRIDE) +#define CLARA_INTERNAL_CONFIG_CPP11_OVERRIDE +#endif +#if !defined(CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) +#define CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR +#endif + +#endif // __cplusplus >= 201103L + +// Now set the actual defines based on the above + anything the user has configured +#if defined(CLARA_INTERNAL_CONFIG_CPP11_NULLPTR) && !defined(CLARA_CONFIG_CPP11_NO_NULLPTR) && !defined(CLARA_CONFIG_CPP11_NULLPTR) && !defined(CLARA_CONFIG_NO_CPP11) +#define CLARA_CONFIG_CPP11_NULLPTR +#endif +#if defined(CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT) && !defined(CLARA_CONFIG_CPP11_NO_NOEXCEPT) && !defined(CLARA_CONFIG_CPP11_NOEXCEPT) && !defined(CLARA_CONFIG_NO_CPP11) +#define CLARA_CONFIG_CPP11_NOEXCEPT +#endif +#if defined(CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS) && !defined(CLARA_CONFIG_CPP11_NO_GENERATED_METHODS) && !defined(CLARA_CONFIG_CPP11_GENERATED_METHODS) && !defined(CLARA_CONFIG_NO_CPP11) +#define CLARA_CONFIG_CPP11_GENERATED_METHODS +#endif +#if defined(CLARA_INTERNAL_CONFIG_CPP11_OVERRIDE) && !defined(CLARA_CONFIG_NO_OVERRIDE) && !defined(CLARA_CONFIG_CPP11_OVERRIDE) && !defined(CLARA_CONFIG_NO_CPP11) +#define CLARA_CONFIG_CPP11_OVERRIDE +#endif +#if defined(CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) && !defined(CLARA_CONFIG_NO_UNIQUE_PTR) && !defined(CLARA_CONFIG_CPP11_UNIQUE_PTR) && !defined(CLARA_CONFIG_NO_CPP11) +#define CLARA_CONFIG_CPP11_UNIQUE_PTR +#endif + +// noexcept support: +#if defined(CLARA_CONFIG_CPP11_NOEXCEPT) && !defined(CLARA_NOEXCEPT) +#define CLARA_NOEXCEPT noexcept +# define CLARA_NOEXCEPT_IS(x) noexcept(x) +#else +#define CLARA_NOEXCEPT throw() +# define CLARA_NOEXCEPT_IS(x) +#endif + +// nullptr support +#ifdef CLARA_CONFIG_CPP11_NULLPTR +#define CLARA_NULL nullptr +#else +#define CLARA_NULL NULL +#endif + +// override support +#ifdef CLARA_CONFIG_CPP11_OVERRIDE +#define CLARA_OVERRIDE override +#else +#define CLARA_OVERRIDE +#endif + +// unique_ptr support +#ifdef CLARA_CONFIG_CPP11_UNIQUE_PTR +# define CLARA_AUTO_PTR( T ) std::unique_ptr +#else +# define CLARA_AUTO_PTR( T ) std::auto_ptr +#endif + +#endif // TWOBLUECUBES_CLARA_COMPILERS_H_INCLUDED + +// ----------- end of #include from clara_compilers.h ----------- +// ........... back in clara.h + +#include +#include +#include + +// Use optional outer namespace +#ifdef STITCH_CLARA_OPEN_NAMESPACE +STITCH_CLARA_OPEN_NAMESPACE +#endif + +namespace Clara { + + struct UnpositionalTag {}; + + extern UnpositionalTag _; + +#ifdef CLARA_CONFIG_MAIN + UnpositionalTag _; +#endif + + namespace Detail { + +#ifdef CLARA_CONSOLE_WIDTH + const unsigned int consoleWidth = CLARA_CONFIG_CONSOLE_WIDTH; +#else + const unsigned int consoleWidth = 80; +#endif + + // Use this to try and stop compiler from warning about unreachable code + inline bool isTrue( bool value ) { return value; } + + using namespace Tbc; + + inline bool startsWith( std::string const& str, std::string const& prefix ) { + return str.size() >= prefix.size() && str.substr( 0, prefix.size() ) == prefix; + } + + template struct RemoveConstRef{ typedef T type; }; + template struct RemoveConstRef{ typedef T type; }; + template struct RemoveConstRef{ typedef T type; }; + template struct RemoveConstRef{ typedef T type; }; + + template struct IsBool { static const bool value = false; }; + template<> struct IsBool { static const bool value = true; }; + + template + void convertInto( std::string const& _source, T& _dest ) { + std::stringstream ss; + ss << _source; + ss >> _dest; + if( ss.fail() ) + throw std::runtime_error( "Unable to convert " + _source + " to destination type" ); + } + inline void convertInto( std::string const& _source, std::string& _dest ) { + _dest = _source; + } + inline void convertInto( std::string const& _source, bool& _dest ) { + std::string sourceLC = _source; + std::transform( sourceLC.begin(), sourceLC.end(), sourceLC.begin(), ::tolower ); + if( sourceLC == "y" || sourceLC == "1" || sourceLC == "true" || sourceLC == "yes" || sourceLC == "on" ) + _dest = true; + else if( sourceLC == "n" || sourceLC == "0" || sourceLC == "false" || sourceLC == "no" || sourceLC == "off" ) + _dest = false; + else + throw std::runtime_error( "Expected a boolean value but did not recognise:\n '" + _source + "'" ); + } + inline void convertInto( bool _source, bool& _dest ) { + _dest = _source; + } + template + inline void convertInto( bool, T& ) { + if( isTrue( true ) ) + throw std::runtime_error( "Invalid conversion" ); + } + + template + struct IArgFunction { + virtual ~IArgFunction() {} +#ifdef CLARA_CONFIG_CPP11_GENERATED_METHODS + IArgFunction() = default; + IArgFunction( IArgFunction const& ) = default; +#endif + virtual void set( ConfigT& config, std::string const& value ) const = 0; + virtual void setFlag( ConfigT& config ) const = 0; + virtual bool takesArg() const = 0; + virtual IArgFunction* clone() const = 0; + }; + + template + class BoundArgFunction { + public: + BoundArgFunction() : functionObj( CLARA_NULL ) {} + BoundArgFunction( IArgFunction* _functionObj ) : functionObj( _functionObj ) {} + BoundArgFunction( BoundArgFunction const& other ) : functionObj( other.functionObj ? other.functionObj->clone() : CLARA_NULL ) {} + BoundArgFunction& operator = ( BoundArgFunction const& other ) { + IArgFunction* newFunctionObj = other.functionObj ? other.functionObj->clone() : CLARA_NULL; + delete functionObj; + functionObj = newFunctionObj; + return *this; + } + ~BoundArgFunction() { delete functionObj; } + + void set( ConfigT& config, std::string const& value ) const { + functionObj->set( config, value ); + } + void setFlag( ConfigT& config ) const { + functionObj->setFlag( config ); + } + bool takesArg() const { return functionObj->takesArg(); } + + bool isSet() const { + return functionObj != CLARA_NULL; + } + private: + IArgFunction* functionObj; + }; + + template + struct NullBinder : IArgFunction{ + virtual void set( C&, std::string const& ) const {} + virtual void setFlag( C& ) const {} + virtual bool takesArg() const { return true; } + virtual IArgFunction* clone() const { return new NullBinder( *this ); } + }; + + template + struct BoundDataMember : IArgFunction{ + BoundDataMember( M C::* _member ) : member( _member ) {} + virtual void set( C& p, std::string const& stringValue ) const { + convertInto( stringValue, p.*member ); + } + virtual void setFlag( C& p ) const { + convertInto( true, p.*member ); + } + virtual bool takesArg() const { return !IsBool::value; } + virtual IArgFunction* clone() const { return new BoundDataMember( *this ); } + M C::* member; + }; + template + struct BoundUnaryMethod : IArgFunction{ + BoundUnaryMethod( void (C::*_member)( M ) ) : member( _member ) {} + virtual void set( C& p, std::string const& stringValue ) const { + typename RemoveConstRef::type value; + convertInto( stringValue, value ); + (p.*member)( value ); + } + virtual void setFlag( C& p ) const { + typename RemoveConstRef::type value; + convertInto( true, value ); + (p.*member)( value ); + } + virtual bool takesArg() const { return !IsBool::value; } + virtual IArgFunction* clone() const { return new BoundUnaryMethod( *this ); } + void (C::*member)( M ); + }; + template + struct BoundNullaryMethod : IArgFunction{ + BoundNullaryMethod( void (C::*_member)() ) : member( _member ) {} + virtual void set( C& p, std::string const& stringValue ) const { + bool value; + convertInto( stringValue, value ); + if( value ) + (p.*member)(); + } + virtual void setFlag( C& p ) const { + (p.*member)(); + } + virtual bool takesArg() const { return false; } + virtual IArgFunction* clone() const { return new BoundNullaryMethod( *this ); } + void (C::*member)(); + }; + + template + struct BoundUnaryFunction : IArgFunction{ + BoundUnaryFunction( void (*_function)( C& ) ) : function( _function ) {} + virtual void set( C& obj, std::string const& stringValue ) const { + bool value; + convertInto( stringValue, value ); + if( value ) + function( obj ); + } + virtual void setFlag( C& p ) const { + function( p ); + } + virtual bool takesArg() const { return false; } + virtual IArgFunction* clone() const { return new BoundUnaryFunction( *this ); } + void (*function)( C& ); + }; + + template + struct BoundBinaryFunction : IArgFunction{ + BoundBinaryFunction( void (*_function)( C&, T ) ) : function( _function ) {} + virtual void set( C& obj, std::string const& stringValue ) const { + typename RemoveConstRef::type value; + convertInto( stringValue, value ); + function( obj, value ); + } + virtual void setFlag( C& obj ) const { + typename RemoveConstRef::type value; + convertInto( true, value ); + function( obj, value ); + } + virtual bool takesArg() const { return !IsBool::value; } + virtual IArgFunction* clone() const { return new BoundBinaryFunction( *this ); } + void (*function)( C&, T ); + }; + + } // namespace Detail + + struct Parser { + Parser() : separators( " \t=:" ) {} + + struct Token { + enum Type { Positional, ShortOpt, LongOpt }; + Token( Type _type, std::string const& _data ) : type( _type ), data( _data ) {} + Type type; + std::string data; + }; + + void parseIntoTokens( int argc, char const* const argv[], std::vector& tokens ) const { + const std::string doubleDash = "--"; + for( int i = 1; i < argc && argv[i] != doubleDash; ++i ) + parseIntoTokens( argv[i] , tokens); + } + void parseIntoTokens( std::string arg, std::vector& tokens ) const { + while( !arg.empty() ) { + Parser::Token token( Parser::Token::Positional, arg ); + arg = ""; + if( token.data[0] == '-' ) { + if( token.data.size() > 1 && token.data[1] == '-' ) { + token = Parser::Token( Parser::Token::LongOpt, token.data.substr( 2 ) ); + } + else { + token = Parser::Token( Parser::Token::ShortOpt, token.data.substr( 1 ) ); + if( token.data.size() > 1 && separators.find( token.data[1] ) == std::string::npos ) { + arg = "-" + token.data.substr( 1 ); + token.data = token.data.substr( 0, 1 ); + } + } + } + if( token.type != Parser::Token::Positional ) { + std::size_t pos = token.data.find_first_of( separators ); + if( pos != std::string::npos ) { + arg = token.data.substr( pos+1 ); + token.data = token.data.substr( 0, pos ); + } + } + tokens.push_back( token ); + } + } + std::string separators; + }; + + template + struct CommonArgProperties { + CommonArgProperties() {} + CommonArgProperties( Detail::BoundArgFunction const& _boundField ) : boundField( _boundField ) {} + + Detail::BoundArgFunction boundField; + std::string description; + std::string detail; + std::string placeholder; // Only value if boundField takes an arg + + bool takesArg() const { + return !placeholder.empty(); + } + void validate() const { + if( !boundField.isSet() ) + throw std::logic_error( "option not bound" ); + } + }; + struct OptionArgProperties { + std::vector shortNames; + std::string longName; + + bool hasShortName( std::string const& shortName ) const { + return std::find( shortNames.begin(), shortNames.end(), shortName ) != shortNames.end(); + } + bool hasLongName( std::string const& _longName ) const { + return _longName == longName; + } + }; + struct PositionalArgProperties { + PositionalArgProperties() : position( -1 ) {} + int position; // -1 means non-positional (floating) + + bool isFixedPositional() const { + return position != -1; + } + }; + + template + class CommandLine { + + struct Arg : CommonArgProperties, OptionArgProperties, PositionalArgProperties { + Arg() {} + Arg( Detail::BoundArgFunction const& _boundField ) : CommonArgProperties( _boundField ) {} + + using CommonArgProperties::placeholder; // !TBD + + std::string dbgName() const { + if( !longName.empty() ) + return "--" + longName; + if( !shortNames.empty() ) + return "-" + shortNames[0]; + return "positional args"; + } + std::string commands() const { + std::ostringstream oss; + bool first = true; + std::vector::const_iterator it = shortNames.begin(), itEnd = shortNames.end(); + for(; it != itEnd; ++it ) { + if( first ) + first = false; + else + oss << ", "; + oss << "-" << *it; + } + if( !longName.empty() ) { + if( !first ) + oss << ", "; + oss << "--" << longName; + } + if( !placeholder.empty() ) + oss << " <" << placeholder << ">"; + return oss.str(); + } + }; + + typedef CLARA_AUTO_PTR( Arg ) ArgAutoPtr; + + friend void addOptName( Arg& arg, std::string const& optName ) + { + if( optName.empty() ) + return; + if( Detail::startsWith( optName, "--" ) ) { + if( !arg.longName.empty() ) + throw std::logic_error( "Only one long opt may be specified. '" + + arg.longName + + "' already specified, now attempting to add '" + + optName + "'" ); + arg.longName = optName.substr( 2 ); + } + else if( Detail::startsWith( optName, "-" ) ) + arg.shortNames.push_back( optName.substr( 1 ) ); + else + throw std::logic_error( "option must begin with - or --. Option was: '" + optName + "'" ); + } + friend void setPositionalArg( Arg& arg, int position ) + { + arg.position = position; + } + + class ArgBuilder { + public: + ArgBuilder( Arg* arg ) : m_arg( arg ) {} + + // Bind a non-boolean data member (requires placeholder string) + template + void bind( M C::* field, std::string const& placeholder ) { + m_arg->boundField = new Detail::BoundDataMember( field ); + m_arg->placeholder = placeholder; + } + // Bind a boolean data member (no placeholder required) + template + void bind( bool C::* field ) { + m_arg->boundField = new Detail::BoundDataMember( field ); + } + + // Bind a method taking a single, non-boolean argument (requires a placeholder string) + template + void bind( void (C::* unaryMethod)( M ), std::string const& placeholder ) { + m_arg->boundField = new Detail::BoundUnaryMethod( unaryMethod ); + m_arg->placeholder = placeholder; + } + + // Bind a method taking a single, boolean argument (no placeholder string required) + template + void bind( void (C::* unaryMethod)( bool ) ) { + m_arg->boundField = new Detail::BoundUnaryMethod( unaryMethod ); + } + + // Bind a method that takes no arguments (will be called if opt is present) + template + void bind( void (C::* nullaryMethod)() ) { + m_arg->boundField = new Detail::BoundNullaryMethod( nullaryMethod ); + } + + // Bind a free function taking a single argument - the object to operate on (no placeholder string required) + template + void bind( void (* unaryFunction)( C& ) ) { + m_arg->boundField = new Detail::BoundUnaryFunction( unaryFunction ); + } + + // Bind a free function taking a single argument - the object to operate on (requires a placeholder string) + template + void bind( void (* binaryFunction)( C&, T ), std::string const& placeholder ) { + m_arg->boundField = new Detail::BoundBinaryFunction( binaryFunction ); + m_arg->placeholder = placeholder; + } + + ArgBuilder& describe( std::string const& description ) { + m_arg->description = description; + return *this; + } + ArgBuilder& detail( std::string const& detail ) { + m_arg->detail = detail; + return *this; + } + + protected: + Arg* m_arg; + }; + + class OptBuilder : public ArgBuilder { + public: + OptBuilder( Arg* arg ) : ArgBuilder( arg ) {} + OptBuilder( OptBuilder& other ) : ArgBuilder( other ) {} + + OptBuilder& operator[]( std::string const& optName ) { + addOptName( *ArgBuilder::m_arg, optName ); + return *this; + } + }; + + public: + + CommandLine() + : m_boundProcessName( new Detail::NullBinder() ), + m_highestSpecifiedArgPosition( 0 ), + m_throwOnUnrecognisedTokens( false ) + {} + CommandLine( CommandLine const& other ) + : m_boundProcessName( other.m_boundProcessName ), + m_options ( other.m_options ), + m_positionalArgs( other.m_positionalArgs ), + m_highestSpecifiedArgPosition( other.m_highestSpecifiedArgPosition ), + m_throwOnUnrecognisedTokens( other.m_throwOnUnrecognisedTokens ) + { + if( other.m_floatingArg.get() ) + m_floatingArg.reset( new Arg( *other.m_floatingArg ) ); + } + + CommandLine& setThrowOnUnrecognisedTokens( bool shouldThrow = true ) { + m_throwOnUnrecognisedTokens = shouldThrow; + return *this; + } + + OptBuilder operator[]( std::string const& optName ) { + m_options.push_back( Arg() ); + addOptName( m_options.back(), optName ); + OptBuilder builder( &m_options.back() ); + return builder; + } + + ArgBuilder operator[]( int position ) { + m_positionalArgs.insert( std::make_pair( position, Arg() ) ); + if( position > m_highestSpecifiedArgPosition ) + m_highestSpecifiedArgPosition = position; + setPositionalArg( m_positionalArgs[position], position ); + ArgBuilder builder( &m_positionalArgs[position] ); + return builder; + } + + // Invoke this with the _ instance + ArgBuilder operator[]( UnpositionalTag ) { + if( m_floatingArg.get() ) + throw std::logic_error( "Only one unpositional argument can be added" ); + m_floatingArg.reset( new Arg() ); + ArgBuilder builder( m_floatingArg.get() ); + return builder; + } + + template + void bindProcessName( M C::* field ) { + m_boundProcessName = new Detail::BoundDataMember( field ); + } + template + void bindProcessName( void (C::*_unaryMethod)( M ) ) { + m_boundProcessName = new Detail::BoundUnaryMethod( _unaryMethod ); + } + + void optUsage( std::ostream& os, std::size_t indent = 0, std::size_t width = Detail::consoleWidth ) const { + typename std::vector::const_iterator itBegin = m_options.begin(), itEnd = m_options.end(), it; + std::size_t maxWidth = 0; + for( it = itBegin; it != itEnd; ++it ) + maxWidth = (std::max)( maxWidth, it->commands().size() ); + + for( it = itBegin; it != itEnd; ++it ) { + Detail::Text usage( it->commands(), Detail::TextAttributes() + .setWidth( maxWidth+indent ) + .setIndent( indent ) ); + Detail::Text desc( it->description, Detail::TextAttributes() + .setWidth( width - maxWidth - 3 ) ); + + for( std::size_t i = 0; i < (std::max)( usage.size(), desc.size() ); ++i ) { + std::string usageCol = i < usage.size() ? usage[i] : ""; + os << usageCol; + + if( i < desc.size() && !desc[i].empty() ) + os << std::string( indent + 2 + maxWidth - usageCol.size(), ' ' ) + << desc[i]; + os << "\n"; + } + } + } + std::string optUsage() const { + std::ostringstream oss; + optUsage( oss ); + return oss.str(); + } + + void argSynopsis( std::ostream& os ) const { + for( int i = 1; i <= m_highestSpecifiedArgPosition; ++i ) { + if( i > 1 ) + os << " "; + typename std::map::const_iterator it = m_positionalArgs.find( i ); + if( it != m_positionalArgs.end() ) + os << "<" << it->second.placeholder << ">"; + else if( m_floatingArg.get() ) + os << "<" << m_floatingArg->placeholder << ">"; + else + throw std::logic_error( "non consecutive positional arguments with no floating args" ); + } + // !TBD No indication of mandatory args + if( m_floatingArg.get() ) { + if( m_highestSpecifiedArgPosition > 1 ) + os << " "; + os << "[<" << m_floatingArg->placeholder << "> ...]"; + } + } + std::string argSynopsis() const { + std::ostringstream oss; + argSynopsis( oss ); + return oss.str(); + } + + void usage( std::ostream& os, std::string const& procName ) const { + validate(); + os << "usage:\n " << procName << " "; + argSynopsis( os ); + if( !m_options.empty() ) { + os << " [options]\n\nwhere options are: \n"; + optUsage( os, 2 ); + } + os << "\n"; + } + std::string usage( std::string const& procName ) const { + std::ostringstream oss; + usage( oss, procName ); + return oss.str(); + } + + ConfigT parse( int argc, char const* const argv[] ) const { + ConfigT config; + parseInto( argc, argv, config ); + return config; + } + + std::vector parseInto( int argc, char const* argv[], ConfigT& config ) const { + std::string processName = argv[0]; + std::size_t lastSlash = processName.find_last_of( "/\\" ); + if( lastSlash != std::string::npos ) + processName = processName.substr( lastSlash+1 ); + m_boundProcessName.set( config, processName ); + std::vector tokens; + Parser parser; + parser.parseIntoTokens( argc, argv, tokens ); + return populate( tokens, config ); + } + + std::vector populate( std::vector const& tokens, ConfigT& config ) const { + validate(); + std::vector unusedTokens = populateOptions( tokens, config ); + unusedTokens = populateFixedArgs( unusedTokens, config ); + unusedTokens = populateFloatingArgs( unusedTokens, config ); + return unusedTokens; + } + + std::vector populateOptions( std::vector const& tokens, ConfigT& config ) const { + std::vector unusedTokens; + std::vector errors; + for( std::size_t i = 0; i < tokens.size(); ++i ) { + Parser::Token const& token = tokens[i]; + typename std::vector::const_iterator it = m_options.begin(), itEnd = m_options.end(); + for(; it != itEnd; ++it ) { + Arg const& arg = *it; + + try { + if( ( token.type == Parser::Token::ShortOpt && arg.hasShortName( token.data ) ) || + ( token.type == Parser::Token::LongOpt && arg.hasLongName( token.data ) ) ) { + if( arg.takesArg() ) { + if( i == tokens.size()-1 || tokens[i+1].type != Parser::Token::Positional ) + errors.push_back( "Expected argument to option: " + token.data ); + else + arg.boundField.set( config, tokens[++i].data ); + } + else { + arg.boundField.setFlag( config ); + } + break; + } + } + catch( std::exception& ex ) { + errors.push_back( std::string( ex.what() ) + "\n- while parsing: (" + arg.commands() + ")" ); + } + } + if( it == itEnd ) { + if( token.type == Parser::Token::Positional || !m_throwOnUnrecognisedTokens ) + unusedTokens.push_back( token ); + else if( errors.empty() && m_throwOnUnrecognisedTokens ) + errors.push_back( "unrecognised option: " + token.data ); + } + } + if( !errors.empty() ) { + std::ostringstream oss; + for( std::vector::const_iterator it = errors.begin(), itEnd = errors.end(); + it != itEnd; + ++it ) { + if( it != errors.begin() ) + oss << "\n"; + oss << *it; + } + throw std::runtime_error( oss.str() ); + } + return unusedTokens; + } + std::vector populateFixedArgs( std::vector const& tokens, ConfigT& config ) const { + std::vector unusedTokens; + int position = 1; + for( std::size_t i = 0; i < tokens.size(); ++i ) { + Parser::Token const& token = tokens[i]; + typename std::map::const_iterator it = m_positionalArgs.find( position ); + if( it != m_positionalArgs.end() ) + it->second.boundField.set( config, token.data ); + else + unusedTokens.push_back( token ); + if( token.type == Parser::Token::Positional ) + position++; + } + return unusedTokens; + } + std::vector populateFloatingArgs( std::vector const& tokens, ConfigT& config ) const { + if( !m_floatingArg.get() ) + return tokens; + std::vector unusedTokens; + for( std::size_t i = 0; i < tokens.size(); ++i ) { + Parser::Token const& token = tokens[i]; + if( token.type == Parser::Token::Positional ) + m_floatingArg->boundField.set( config, token.data ); + else + unusedTokens.push_back( token ); + } + return unusedTokens; + } + + void validate() const + { + if( m_options.empty() && m_positionalArgs.empty() && !m_floatingArg.get() ) + throw std::logic_error( "No options or arguments specified" ); + + for( typename std::vector::const_iterator it = m_options.begin(), + itEnd = m_options.end(); + it != itEnd; ++it ) + it->validate(); + } + + private: + Detail::BoundArgFunction m_boundProcessName; + std::vector m_options; + std::map m_positionalArgs; + ArgAutoPtr m_floatingArg; + int m_highestSpecifiedArgPosition; + bool m_throwOnUnrecognisedTokens; + }; + +} // end namespace Clara + +STITCH_CLARA_CLOSE_NAMESPACE +#undef STITCH_CLARA_OPEN_NAMESPACE +#undef STITCH_CLARA_CLOSE_NAMESPACE + +#endif // TWOBLUECUBES_CLARA_H_INCLUDED +#undef STITCH_CLARA_OPEN_NAMESPACE + +// Restore Clara's value for console width, if present +#ifdef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH +#define CLARA_CONFIG_CONSOLE_WIDTH CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH +#undef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH +#endif + +#include + +namespace Catch { + + inline void abortAfterFirst( ConfigData& config ) { config.abortAfter = 1; } + inline void abortAfterX( ConfigData& config, int x ) { + if( x < 1 ) + throw std::runtime_error( "Value after -x or --abortAfter must be greater than zero" ); + config.abortAfter = x; + } + inline void addTestOrTags( ConfigData& config, std::string const& _testSpec ) { config.testsOrTags.push_back( _testSpec ); } + inline void addReporterName( ConfigData& config, std::string const& _reporterName ) { config.reporterNames.push_back( _reporterName ); } + + inline void addWarning( ConfigData& config, std::string const& _warning ) { + if( _warning == "NoAssertions" ) + config.warnings = static_cast( config.warnings | WarnAbout::NoAssertions ); + else + throw std::runtime_error( "Unrecognised warning: '" + _warning + "'" ); + } + inline void setOrder( ConfigData& config, std::string const& order ) { + if( startsWith( "declared", order ) ) + config.runOrder = RunTests::InDeclarationOrder; + else if( startsWith( "lexical", order ) ) + config.runOrder = RunTests::InLexicographicalOrder; + else if( startsWith( "random", order ) ) + config.runOrder = RunTests::InRandomOrder; + else + throw std::runtime_error( "Unrecognised ordering: '" + order + "'" ); + } + inline void setRngSeed( ConfigData& config, std::string const& seed ) { + if( seed == "time" ) { + config.rngSeed = static_cast( std::time(0) ); + } + else { + std::stringstream ss; + ss << seed; + ss >> config.rngSeed; + if( ss.fail() ) + throw std::runtime_error( "Argment to --rng-seed should be the word 'time' or a number" ); + } + } + inline void setVerbosity( ConfigData& config, int level ) { + // !TBD: accept strings? + config.verbosity = static_cast( level ); + } + inline void setShowDurations( ConfigData& config, bool _showDurations ) { + config.showDurations = _showDurations + ? ShowDurations::Always + : ShowDurations::Never; + } + inline void setUseColour( ConfigData& config, std::string const& value ) { + std::string mode = toLower( value ); + + if( mode == "yes" ) + config.useColour = UseColour::Yes; + else if( mode == "no" ) + config.useColour = UseColour::No; + else if( mode == "auto" ) + config.useColour = UseColour::Auto; + else + throw std::runtime_error( "colour mode must be one of: auto, yes or no" ); + } + inline void forceColour( ConfigData& config ) { + config.useColour = UseColour::Yes; + } + inline void loadTestNamesFromFile( ConfigData& config, std::string const& _filename ) { + std::ifstream f( _filename.c_str() ); + if( !f.is_open() ) + throw std::domain_error( "Unable to load input file: " + _filename ); + + std::string line; + while( std::getline( f, line ) ) { + line = trim(line); + if( !line.empty() && !startsWith( line, "#" ) ) + addTestOrTags( config, "\"" + line + "\"," ); + } + } + + inline Clara::CommandLine makeCommandLineParser() { + + using namespace Clara; + CommandLine cli; + + cli.bindProcessName( &ConfigData::processName ); + + cli["-?"]["-h"]["--help"] + .describe( "display usage information" ) + .bind( &ConfigData::showHelp ); + + cli["-l"]["--list-tests"] + .describe( "list all/matching test cases" ) + .bind( &ConfigData::listTests ); + + cli["-t"]["--list-tags"] + .describe( "list all/matching tags" ) + .bind( &ConfigData::listTags ); + + cli["-s"]["--success"] + .describe( "include successful tests in output" ) + .bind( &ConfigData::showSuccessfulTests ); + + cli["-b"]["--break"] + .describe( "break into debugger on failure" ) + .bind( &ConfigData::shouldDebugBreak ); + + cli["-e"]["--nothrow"] + .describe( "skip exception tests" ) + .bind( &ConfigData::noThrow ); + + cli["-i"]["--invisibles"] + .describe( "show invisibles (tabs, newlines)" ) + .bind( &ConfigData::showInvisibles ); + + cli["-o"]["--out"] + .describe( "output filename" ) + .bind( &ConfigData::outputFilename, "filename" ); + + cli["-r"]["--reporter"] +// .placeholder( "name[:filename]" ) + .describe( "reporter to use (defaults to console)" ) + .bind( &addReporterName, "name" ); + + cli["-n"]["--name"] + .describe( "suite name" ) + .bind( &ConfigData::name, "name" ); + + cli["-a"]["--abort"] + .describe( "abort at first failure" ) + .bind( &abortAfterFirst ); + + cli["-x"]["--abortx"] + .describe( "abort after x failures" ) + .bind( &abortAfterX, "no. failures" ); + + cli["-w"]["--warn"] + .describe( "enable warnings" ) + .bind( &addWarning, "warning name" ); + +// - needs updating if reinstated +// cli.into( &setVerbosity ) +// .describe( "level of verbosity (0=no output)" ) +// .shortOpt( "v") +// .longOpt( "verbosity" ) +// .placeholder( "level" ); + + cli[_] + .describe( "which test or tests to use" ) + .bind( &addTestOrTags, "test name, pattern or tags" ); + + cli["-d"]["--durations"] + .describe( "show test durations" ) + .bind( &setShowDurations, "yes|no" ); + + cli["-f"]["--input-file"] + .describe( "load test names to run from a file" ) + .bind( &loadTestNamesFromFile, "filename" ); + + cli["-#"]["--filenames-as-tags"] + .describe( "adds a tag for the filename" ) + .bind( &ConfigData::filenamesAsTags ); + + // Less common commands which don't have a short form + cli["--list-test-names-only"] + .describe( "list all/matching test cases names only" ) + .bind( &ConfigData::listTestNamesOnly ); + + cli["--list-reporters"] + .describe( "list all reporters" ) + .bind( &ConfigData::listReporters ); + + cli["--order"] + .describe( "test case order (defaults to decl)" ) + .bind( &setOrder, "decl|lex|rand" ); + + cli["--rng-seed"] + .describe( "set a specific seed for random numbers" ) + .bind( &setRngSeed, "'time'|number" ); + + cli["--force-colour"] + .describe( "force colourised output (deprecated)" ) + .bind( &forceColour ); + + cli["--use-colour"] + .describe( "should output be colourised" ) + .bind( &setUseColour, "yes|no" ); + + return cli; + } + +} // end namespace Catch + +// #included from: internal/catch_list.hpp +#define TWOBLUECUBES_CATCH_LIST_HPP_INCLUDED + +// #included from: catch_text.h +#define TWOBLUECUBES_CATCH_TEXT_H_INCLUDED + +#define TBC_TEXT_FORMAT_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH + +#define CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE Catch +// #included from: ../external/tbc_text_format.h +// Only use header guard if we are not using an outer namespace +#ifndef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE +# ifdef TWOBLUECUBES_TEXT_FORMAT_H_INCLUDED +# ifndef TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED +# define TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED +# endif +# else +# define TWOBLUECUBES_TEXT_FORMAT_H_INCLUDED +# endif +#endif +#ifndef TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED +#include +#include +#include + +// Use optional outer namespace +#ifdef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE +namespace CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE { +#endif + +namespace Tbc { + +#ifdef TBC_TEXT_FORMAT_CONSOLE_WIDTH + const unsigned int consoleWidth = TBC_TEXT_FORMAT_CONSOLE_WIDTH; +#else + const unsigned int consoleWidth = 80; +#endif + + struct TextAttributes { + TextAttributes() + : initialIndent( std::string::npos ), + indent( 0 ), + width( consoleWidth-1 ), + tabChar( '\t' ) + {} + + TextAttributes& setInitialIndent( std::size_t _value ) { initialIndent = _value; return *this; } + TextAttributes& setIndent( std::size_t _value ) { indent = _value; return *this; } + TextAttributes& setWidth( std::size_t _value ) { width = _value; return *this; } + TextAttributes& setTabChar( char _value ) { tabChar = _value; return *this; } + + std::size_t initialIndent; // indent of first line, or npos + std::size_t indent; // indent of subsequent lines, or all if initialIndent is npos + std::size_t width; // maximum width of text, including indent. Longer text will wrap + char tabChar; // If this char is seen the indent is changed to current pos + }; + + class Text { + public: + Text( std::string const& _str, TextAttributes const& _attr = TextAttributes() ) + : attr( _attr ) + { + std::string wrappableChars = " [({.,/|\\-"; + std::size_t indent = _attr.initialIndent != std::string::npos + ? _attr.initialIndent + : _attr.indent; + std::string remainder = _str; + + while( !remainder.empty() ) { + if( lines.size() >= 1000 ) { + lines.push_back( "... message truncated due to excessive size" ); + return; + } + std::size_t tabPos = std::string::npos; + std::size_t width = (std::min)( remainder.size(), _attr.width - indent ); + std::size_t pos = remainder.find_first_of( '\n' ); + if( pos <= width ) { + width = pos; + } + pos = remainder.find_last_of( _attr.tabChar, width ); + if( pos != std::string::npos ) { + tabPos = pos; + if( remainder[width] == '\n' ) + width--; + remainder = remainder.substr( 0, tabPos ) + remainder.substr( tabPos+1 ); + } + + if( width == remainder.size() ) { + spliceLine( indent, remainder, width ); + } + else if( remainder[width] == '\n' ) { + spliceLine( indent, remainder, width ); + if( width <= 1 || remainder.size() != 1 ) + remainder = remainder.substr( 1 ); + indent = _attr.indent; + } + else { + pos = remainder.find_last_of( wrappableChars, width ); + if( pos != std::string::npos && pos > 0 ) { + spliceLine( indent, remainder, pos ); + if( remainder[0] == ' ' ) + remainder = remainder.substr( 1 ); + } + else { + spliceLine( indent, remainder, width-1 ); + lines.back() += "-"; + } + if( lines.size() == 1 ) + indent = _attr.indent; + if( tabPos != std::string::npos ) + indent += tabPos; + } + } + } + + void spliceLine( std::size_t _indent, std::string& _remainder, std::size_t _pos ) { + lines.push_back( std::string( _indent, ' ' ) + _remainder.substr( 0, _pos ) ); + _remainder = _remainder.substr( _pos ); + } + + typedef std::vector::const_iterator const_iterator; + + const_iterator begin() const { return lines.begin(); } + const_iterator end() const { return lines.end(); } + std::string const& last() const { return lines.back(); } + std::size_t size() const { return lines.size(); } + std::string const& operator[]( std::size_t _index ) const { return lines[_index]; } + std::string toString() const { + std::ostringstream oss; + oss << *this; + return oss.str(); + } + + inline friend std::ostream& operator << ( std::ostream& _stream, Text const& _text ) { + for( Text::const_iterator it = _text.begin(), itEnd = _text.end(); + it != itEnd; ++it ) { + if( it != _text.begin() ) + _stream << "\n"; + _stream << *it; + } + return _stream; + } + + private: + std::string str; + TextAttributes attr; + std::vector lines; + }; + +} // end namespace Tbc + +#ifdef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE +} // end outer namespace +#endif + +#endif // TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED +#undef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE + +namespace Catch { + using Tbc::Text; + using Tbc::TextAttributes; +} + +// #included from: catch_console_colour.hpp +#define TWOBLUECUBES_CATCH_CONSOLE_COLOUR_HPP_INCLUDED + +namespace Catch { + + struct Colour { + enum Code { + None = 0, + + White, + Red, + Green, + Blue, + Cyan, + Yellow, + Grey, + + Bright = 0x10, + + BrightRed = Bright | Red, + BrightGreen = Bright | Green, + LightGrey = Bright | Grey, + BrightWhite = Bright | White, + + // By intention + FileName = LightGrey, + Warning = Yellow, + ResultError = BrightRed, + ResultSuccess = BrightGreen, + ResultExpectedFailure = Warning, + + Error = BrightRed, + Success = Green, + + OriginalExpression = Cyan, + ReconstructedExpression = Yellow, + + SecondaryText = LightGrey, + Headers = White + }; + + // Use constructed object for RAII guard + Colour( Code _colourCode ); + Colour( Colour const& other ); + ~Colour(); + + // Use static method for one-shot changes + static void use( Code _colourCode ); + + private: + bool m_moved; + }; + + inline std::ostream& operator << ( std::ostream& os, Colour const& ) { return os; } + +} // end namespace Catch + +// #included from: catch_interfaces_reporter.h +#define TWOBLUECUBES_CATCH_INTERFACES_REPORTER_H_INCLUDED + +#include +#include +#include +#include + +namespace Catch +{ + struct ReporterConfig { + explicit ReporterConfig( Ptr const& _fullConfig ) + : m_stream( &_fullConfig->stream() ), m_fullConfig( _fullConfig ) {} + + ReporterConfig( Ptr const& _fullConfig, std::ostream& _stream ) + : m_stream( &_stream ), m_fullConfig( _fullConfig ) {} + + std::ostream& stream() const { return *m_stream; } + Ptr fullConfig() const { return m_fullConfig; } + + private: + std::ostream* m_stream; + Ptr m_fullConfig; + }; + + struct ReporterPreferences { + ReporterPreferences() + : shouldRedirectStdOut( false ) + {} + + bool shouldRedirectStdOut; + }; + + template + struct LazyStat : Option { + LazyStat() : used( false ) {} + LazyStat& operator=( T const& _value ) { + Option::operator=( _value ); + used = false; + return *this; + } + void reset() { + Option::reset(); + used = false; + } + bool used; + }; + + struct TestRunInfo { + TestRunInfo( std::string const& _name ) : name( _name ) {} + std::string name; + }; + struct GroupInfo { + GroupInfo( std::string const& _name, + std::size_t _groupIndex, + std::size_t _groupsCount ) + : name( _name ), + groupIndex( _groupIndex ), + groupsCounts( _groupsCount ) + {} + + std::string name; + std::size_t groupIndex; + std::size_t groupsCounts; + }; + + struct AssertionStats { + AssertionStats( AssertionResult const& _assertionResult, + std::vector const& _infoMessages, + Totals const& _totals ) + : assertionResult( _assertionResult ), + infoMessages( _infoMessages ), + totals( _totals ) + { + if( assertionResult.hasMessage() ) { + // Copy message into messages list. + // !TBD This should have been done earlier, somewhere + MessageBuilder builder( assertionResult.getTestMacroName(), assertionResult.getSourceInfo(), assertionResult.getResultType() ); + builder << assertionResult.getMessage(); + builder.m_info.message = builder.m_stream.str(); + + infoMessages.push_back( builder.m_info ); + } + } + virtual ~AssertionStats(); + +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + AssertionStats( AssertionStats const& ) = default; + AssertionStats( AssertionStats && ) = default; + AssertionStats& operator = ( AssertionStats const& ) = default; + AssertionStats& operator = ( AssertionStats && ) = default; +# endif + + AssertionResult assertionResult; + std::vector infoMessages; + Totals totals; + }; + + struct SectionStats { + SectionStats( SectionInfo const& _sectionInfo, + Counts const& _assertions, + double _durationInSeconds, + bool _missingAssertions ) + : sectionInfo( _sectionInfo ), + assertions( _assertions ), + durationInSeconds( _durationInSeconds ), + missingAssertions( _missingAssertions ) + {} + virtual ~SectionStats(); +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + SectionStats( SectionStats const& ) = default; + SectionStats( SectionStats && ) = default; + SectionStats& operator = ( SectionStats const& ) = default; + SectionStats& operator = ( SectionStats && ) = default; +# endif + + SectionInfo sectionInfo; + Counts assertions; + double durationInSeconds; + bool missingAssertions; + }; + + struct TestCaseStats { + TestCaseStats( TestCaseInfo const& _testInfo, + Totals const& _totals, + std::string const& _stdOut, + std::string const& _stdErr, + bool _aborting ) + : testInfo( _testInfo ), + totals( _totals ), + stdOut( _stdOut ), + stdErr( _stdErr ), + aborting( _aborting ) + {} + virtual ~TestCaseStats(); + +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + TestCaseStats( TestCaseStats const& ) = default; + TestCaseStats( TestCaseStats && ) = default; + TestCaseStats& operator = ( TestCaseStats const& ) = default; + TestCaseStats& operator = ( TestCaseStats && ) = default; +# endif + + TestCaseInfo testInfo; + Totals totals; + std::string stdOut; + std::string stdErr; + bool aborting; + }; + + struct TestGroupStats { + TestGroupStats( GroupInfo const& _groupInfo, + Totals const& _totals, + bool _aborting ) + : groupInfo( _groupInfo ), + totals( _totals ), + aborting( _aborting ) + {} + TestGroupStats( GroupInfo const& _groupInfo ) + : groupInfo( _groupInfo ), + aborting( false ) + {} + virtual ~TestGroupStats(); + +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + TestGroupStats( TestGroupStats const& ) = default; + TestGroupStats( TestGroupStats && ) = default; + TestGroupStats& operator = ( TestGroupStats const& ) = default; + TestGroupStats& operator = ( TestGroupStats && ) = default; +# endif + + GroupInfo groupInfo; + Totals totals; + bool aborting; + }; + + struct TestRunStats { + TestRunStats( TestRunInfo const& _runInfo, + Totals const& _totals, + bool _aborting ) + : runInfo( _runInfo ), + totals( _totals ), + aborting( _aborting ) + {} + virtual ~TestRunStats(); + +# ifndef CATCH_CONFIG_CPP11_GENERATED_METHODS + TestRunStats( TestRunStats const& _other ) + : runInfo( _other.runInfo ), + totals( _other.totals ), + aborting( _other.aborting ) + {} +# else + TestRunStats( TestRunStats const& ) = default; + TestRunStats( TestRunStats && ) = default; + TestRunStats& operator = ( TestRunStats const& ) = default; + TestRunStats& operator = ( TestRunStats && ) = default; +# endif + + TestRunInfo runInfo; + Totals totals; + bool aborting; + }; + + struct IStreamingReporter : IShared { + virtual ~IStreamingReporter(); + + // Implementing class must also provide the following static method: + // static std::string getDescription(); + + virtual ReporterPreferences getPreferences() const = 0; + + virtual void noMatchingTestCases( std::string const& spec ) = 0; + + virtual void testRunStarting( TestRunInfo const& testRunInfo ) = 0; + virtual void testGroupStarting( GroupInfo const& groupInfo ) = 0; + + virtual void testCaseStarting( TestCaseInfo const& testInfo ) = 0; + virtual void sectionStarting( SectionInfo const& sectionInfo ) = 0; + + virtual void assertionStarting( AssertionInfo const& assertionInfo ) = 0; + + // The return value indicates if the messages buffer should be cleared: + virtual bool assertionEnded( AssertionStats const& assertionStats ) = 0; + + virtual void sectionEnded( SectionStats const& sectionStats ) = 0; + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) = 0; + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) = 0; + virtual void testRunEnded( TestRunStats const& testRunStats ) = 0; + + virtual void skipTest( TestCaseInfo const& testInfo ) = 0; + }; + + struct IReporterFactory : IShared { + virtual ~IReporterFactory(); + virtual IStreamingReporter* create( ReporterConfig const& config ) const = 0; + virtual std::string getDescription() const = 0; + }; + + struct IReporterRegistry { + typedef std::map > FactoryMap; + typedef std::vector > Listeners; + + virtual ~IReporterRegistry(); + virtual IStreamingReporter* create( std::string const& name, Ptr const& config ) const = 0; + virtual FactoryMap const& getFactories() const = 0; + virtual Listeners const& getListeners() const = 0; + }; + + Ptr addReporter( Ptr const& existingReporter, Ptr const& additionalReporter ); + +} + +#include +#include + +namespace Catch { + + inline std::size_t listTests( Config const& config ) { + + TestSpec testSpec = config.testSpec(); + if( config.testSpec().hasFilters() ) + Catch::cout() << "Matching test cases:\n"; + else { + Catch::cout() << "All available test cases:\n"; + testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); + } + + std::size_t matchedTests = 0; + TextAttributes nameAttr, tagsAttr; + nameAttr.setInitialIndent( 2 ).setIndent( 4 ); + tagsAttr.setIndent( 6 ); + + std::vector matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); + for( std::vector::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); + it != itEnd; + ++it ) { + matchedTests++; + TestCaseInfo const& testCaseInfo = it->getTestCaseInfo(); + Colour::Code colour = testCaseInfo.isHidden() + ? Colour::SecondaryText + : Colour::None; + Colour colourGuard( colour ); + + Catch::cout() << Text( testCaseInfo.name, nameAttr ) << std::endl; + if( !testCaseInfo.tags.empty() ) + Catch::cout() << Text( testCaseInfo.tagsAsString, tagsAttr ) << std::endl; + } + + if( !config.testSpec().hasFilters() ) + Catch::cout() << pluralise( matchedTests, "test case" ) << "\n" << std::endl; + else + Catch::cout() << pluralise( matchedTests, "matching test case" ) << "\n" << std::endl; + return matchedTests; + } + + inline std::size_t listTestsNamesOnly( Config const& config ) { + TestSpec testSpec = config.testSpec(); + if( !config.testSpec().hasFilters() ) + testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); + std::size_t matchedTests = 0; + std::vector matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); + for( std::vector::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); + it != itEnd; + ++it ) { + matchedTests++; + TestCaseInfo const& testCaseInfo = it->getTestCaseInfo(); + Catch::cout() << testCaseInfo.name << std::endl; + } + return matchedTests; + } + + struct TagInfo { + TagInfo() : count ( 0 ) {} + void add( std::string const& spelling ) { + ++count; + spellings.insert( spelling ); + } + std::string all() const { + std::string out; + for( std::set::const_iterator it = spellings.begin(), itEnd = spellings.end(); + it != itEnd; + ++it ) + out += "[" + *it + "]"; + return out; + } + std::set spellings; + std::size_t count; + }; + + inline std::size_t listTags( Config const& config ) { + TestSpec testSpec = config.testSpec(); + if( config.testSpec().hasFilters() ) + Catch::cout() << "Tags for matching test cases:\n"; + else { + Catch::cout() << "All available tags:\n"; + testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); + } + + std::map tagCounts; + + std::vector matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); + for( std::vector::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); + it != itEnd; + ++it ) { + for( std::set::const_iterator tagIt = it->getTestCaseInfo().tags.begin(), + tagItEnd = it->getTestCaseInfo().tags.end(); + tagIt != tagItEnd; + ++tagIt ) { + std::string tagName = *tagIt; + std::string lcaseTagName = toLower( tagName ); + std::map::iterator countIt = tagCounts.find( lcaseTagName ); + if( countIt == tagCounts.end() ) + countIt = tagCounts.insert( std::make_pair( lcaseTagName, TagInfo() ) ).first; + countIt->second.add( tagName ); + } + } + + for( std::map::const_iterator countIt = tagCounts.begin(), + countItEnd = tagCounts.end(); + countIt != countItEnd; + ++countIt ) { + std::ostringstream oss; + oss << " " << std::setw(2) << countIt->second.count << " "; + Text wrapper( countIt->second.all(), TextAttributes() + .setInitialIndent( 0 ) + .setIndent( oss.str().size() ) + .setWidth( CATCH_CONFIG_CONSOLE_WIDTH-10 ) ); + Catch::cout() << oss.str() << wrapper << "\n"; + } + Catch::cout() << pluralise( tagCounts.size(), "tag" ) << "\n" << std::endl; + return tagCounts.size(); + } + + inline std::size_t listReporters( Config const& /*config*/ ) { + Catch::cout() << "Available reporters:\n"; + IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories(); + IReporterRegistry::FactoryMap::const_iterator itBegin = factories.begin(), itEnd = factories.end(), it; + std::size_t maxNameLen = 0; + for(it = itBegin; it != itEnd; ++it ) + maxNameLen = (std::max)( maxNameLen, it->first.size() ); + + for(it = itBegin; it != itEnd; ++it ) { + Text wrapper( it->second->getDescription(), TextAttributes() + .setInitialIndent( 0 ) + .setIndent( 7+maxNameLen ) + .setWidth( CATCH_CONFIG_CONSOLE_WIDTH - maxNameLen-8 ) ); + Catch::cout() << " " + << it->first + << ":" + << std::string( maxNameLen - it->first.size() + 2, ' ' ) + << wrapper << "\n"; + } + Catch::cout() << std::endl; + return factories.size(); + } + + inline Option list( Config const& config ) { + Option listedCount; + if( config.listTests() ) + listedCount = listedCount.valueOr(0) + listTests( config ); + if( config.listTestNamesOnly() ) + listedCount = listedCount.valueOr(0) + listTestsNamesOnly( config ); + if( config.listTags() ) + listedCount = listedCount.valueOr(0) + listTags( config ); + if( config.listReporters() ) + listedCount = listedCount.valueOr(0) + listReporters( config ); + return listedCount; + } + +} // end namespace Catch + +// #included from: internal/catch_run_context.hpp +#define TWOBLUECUBES_CATCH_RUNNER_IMPL_HPP_INCLUDED + +// #included from: catch_test_case_tracker.hpp +#define TWOBLUECUBES_CATCH_TEST_CASE_TRACKER_HPP_INCLUDED + +#include +#include +#include +#include + +namespace Catch { +namespace TestCaseTracking { + + struct ITracker : SharedImpl<> { + virtual ~ITracker(); + + // static queries + virtual std::string name() const = 0; + + // dynamic queries + virtual bool isComplete() const = 0; // Successfully completed or failed + virtual bool isSuccessfullyCompleted() const = 0; + virtual bool isOpen() const = 0; // Started but not complete + virtual bool hasChildren() const = 0; + + virtual ITracker& parent() = 0; + + // actions + virtual void close() = 0; // Successfully complete + virtual void fail() = 0; + virtual void markAsNeedingAnotherRun() = 0; + + virtual void addChild( Ptr const& child ) = 0; + virtual ITracker* findChild( std::string const& name ) = 0; + virtual void openChild() = 0; + }; + + class TrackerContext { + + enum RunState { + NotStarted, + Executing, + CompletedCycle + }; + + Ptr m_rootTracker; + ITracker* m_currentTracker; + RunState m_runState; + + public: + + static TrackerContext& instance() { + static TrackerContext s_instance; + return s_instance; + } + + TrackerContext() + : m_currentTracker( CATCH_NULL ), + m_runState( NotStarted ) + {} + + ITracker& startRun(); + + void endRun() { + m_rootTracker.reset(); + m_currentTracker = CATCH_NULL; + m_runState = NotStarted; + } + + void startCycle() { + m_currentTracker = m_rootTracker.get(); + m_runState = Executing; + } + void completeCycle() { + m_runState = CompletedCycle; + } + + bool completedCycle() const { + return m_runState == CompletedCycle; + } + ITracker& currentTracker() { + return *m_currentTracker; + } + void setCurrentTracker( ITracker* tracker ) { + m_currentTracker = tracker; + } + }; + + class TrackerBase : public ITracker { + protected: + enum CycleState { + NotStarted, + Executing, + ExecutingChildren, + NeedsAnotherRun, + CompletedSuccessfully, + Failed + }; + class TrackerHasName { + std::string m_name; + public: + TrackerHasName( std::string const& name ) : m_name( name ) {} + bool operator ()( Ptr const& tracker ) { + return tracker->name() == m_name; + } + }; + typedef std::vector > Children; + std::string m_name; + TrackerContext& m_ctx; + ITracker* m_parent; + Children m_children; + CycleState m_runState; + public: + TrackerBase( std::string const& name, TrackerContext& ctx, ITracker* parent ) + : m_name( name ), + m_ctx( ctx ), + m_parent( parent ), + m_runState( NotStarted ) + {} + virtual ~TrackerBase(); + + virtual std::string name() const CATCH_OVERRIDE { + return m_name; + } + virtual bool isComplete() const CATCH_OVERRIDE { + return m_runState == CompletedSuccessfully || m_runState == Failed; + } + virtual bool isSuccessfullyCompleted() const CATCH_OVERRIDE { + return m_runState == CompletedSuccessfully; + } + virtual bool isOpen() const CATCH_OVERRIDE { + return m_runState != NotStarted && !isComplete(); + } + virtual bool hasChildren() const CATCH_OVERRIDE { + return !m_children.empty(); + } + + virtual void addChild( Ptr const& child ) CATCH_OVERRIDE { + m_children.push_back( child ); + } + + virtual ITracker* findChild( std::string const& name ) CATCH_OVERRIDE { + Children::const_iterator it = std::find_if( m_children.begin(), m_children.end(), TrackerHasName( name ) ); + return( it != m_children.end() ) + ? it->get() + : CATCH_NULL; + } + virtual ITracker& parent() CATCH_OVERRIDE { + assert( m_parent ); // Should always be non-null except for root + return *m_parent; + } + + virtual void openChild() CATCH_OVERRIDE { + if( m_runState != ExecutingChildren ) { + m_runState = ExecutingChildren; + if( m_parent ) + m_parent->openChild(); + } + } + void open() { + m_runState = Executing; + moveToThis(); + if( m_parent ) + m_parent->openChild(); + } + + virtual void close() CATCH_OVERRIDE { + + // Close any still open children (e.g. generators) + while( &m_ctx.currentTracker() != this ) + m_ctx.currentTracker().close(); + + switch( m_runState ) { + case NotStarted: + case CompletedSuccessfully: + case Failed: + throw std::logic_error( "Illogical state" ); + + case NeedsAnotherRun: + break;; + + case Executing: + m_runState = CompletedSuccessfully; + break; + case ExecutingChildren: + if( m_children.empty() || m_children.back()->isComplete() ) + m_runState = CompletedSuccessfully; + break; + + default: + throw std::logic_error( "Unexpected state" ); + } + moveToParent(); + m_ctx.completeCycle(); + } + virtual void fail() CATCH_OVERRIDE { + m_runState = Failed; + if( m_parent ) + m_parent->markAsNeedingAnotherRun(); + moveToParent(); + m_ctx.completeCycle(); + } + virtual void markAsNeedingAnotherRun() CATCH_OVERRIDE { + m_runState = NeedsAnotherRun; + } + private: + void moveToParent() { + assert( m_parent ); + m_ctx.setCurrentTracker( m_parent ); + } + void moveToThis() { + m_ctx.setCurrentTracker( this ); + } + }; + + class SectionTracker : public TrackerBase { + public: + SectionTracker( std::string const& name, TrackerContext& ctx, ITracker* parent ) + : TrackerBase( name, ctx, parent ) + {} + virtual ~SectionTracker(); + + static SectionTracker& acquire( TrackerContext& ctx, std::string const& name ) { + SectionTracker* section = CATCH_NULL; + + ITracker& currentTracker = ctx.currentTracker(); + if( ITracker* childTracker = currentTracker.findChild( name ) ) { + section = dynamic_cast( childTracker ); + assert( section ); + } + else { + section = new SectionTracker( name, ctx, ¤tTracker ); + currentTracker.addChild( section ); + } + if( !ctx.completedCycle() && !section->isComplete() ) { + + section->open(); + } + return *section; + } + }; + + class IndexTracker : public TrackerBase { + int m_size; + int m_index; + public: + IndexTracker( std::string const& name, TrackerContext& ctx, ITracker* parent, int size ) + : TrackerBase( name, ctx, parent ), + m_size( size ), + m_index( -1 ) + {} + virtual ~IndexTracker(); + + static IndexTracker& acquire( TrackerContext& ctx, std::string const& name, int size ) { + IndexTracker* tracker = CATCH_NULL; + + ITracker& currentTracker = ctx.currentTracker(); + if( ITracker* childTracker = currentTracker.findChild( name ) ) { + tracker = dynamic_cast( childTracker ); + assert( tracker ); + } + else { + tracker = new IndexTracker( name, ctx, ¤tTracker, size ); + currentTracker.addChild( tracker ); + } + + if( !ctx.completedCycle() && !tracker->isComplete() ) { + if( tracker->m_runState != ExecutingChildren && tracker->m_runState != NeedsAnotherRun ) + tracker->moveNext(); + tracker->open(); + } + + return *tracker; + } + + int index() const { return m_index; } + + void moveNext() { + m_index++; + m_children.clear(); + } + + virtual void close() CATCH_OVERRIDE { + TrackerBase::close(); + if( m_runState == CompletedSuccessfully && m_index < m_size-1 ) + m_runState = Executing; + } + }; + + inline ITracker& TrackerContext::startRun() { + m_rootTracker = new SectionTracker( "{root}", *this, CATCH_NULL ); + m_currentTracker = CATCH_NULL; + m_runState = Executing; + return *m_rootTracker; + } + +} // namespace TestCaseTracking + +using TestCaseTracking::ITracker; +using TestCaseTracking::TrackerContext; +using TestCaseTracking::SectionTracker; +using TestCaseTracking::IndexTracker; + +} // namespace Catch + +// #included from: catch_fatal_condition.hpp +#define TWOBLUECUBES_CATCH_FATAL_CONDITION_H_INCLUDED + +namespace Catch { + + // Report the error condition then exit the process + inline void fatal( std::string const& message, int exitCode ) { + IContext& context = Catch::getCurrentContext(); + IResultCapture* resultCapture = context.getResultCapture(); + resultCapture->handleFatalErrorCondition( message ); + + if( Catch::alwaysTrue() ) // avoids "no return" warnings + exit( exitCode ); + } + +} // namespace Catch + +#if defined ( CATCH_PLATFORM_WINDOWS ) ///////////////////////////////////////// + +namespace Catch { + + struct FatalConditionHandler { + void reset() {} + }; + +} // namespace Catch + +#else // Not Windows - assumed to be POSIX compatible ////////////////////////// + +#include + +namespace Catch { + + struct SignalDefs { int id; const char* name; }; + extern SignalDefs signalDefs[]; + SignalDefs signalDefs[] = { + { SIGINT, "SIGINT - Terminal interrupt signal" }, + { SIGILL, "SIGILL - Illegal instruction signal" }, + { SIGFPE, "SIGFPE - Floating point error signal" }, + { SIGSEGV, "SIGSEGV - Segmentation violation signal" }, + { SIGTERM, "SIGTERM - Termination request signal" }, + { SIGABRT, "SIGABRT - Abort (abnormal termination) signal" } + }; + + struct FatalConditionHandler { + + static void handleSignal( int sig ) { + for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) + if( sig == signalDefs[i].id ) + fatal( signalDefs[i].name, -sig ); + fatal( "", -sig ); + } + + FatalConditionHandler() : m_isSet( true ) { + for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) + signal( signalDefs[i].id, handleSignal ); + } + ~FatalConditionHandler() { + reset(); + } + void reset() { + if( m_isSet ) { + for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) + signal( signalDefs[i].id, SIG_DFL ); + m_isSet = false; + } + } + + bool m_isSet; + }; + +} // namespace Catch + +#endif // not Windows + +#include +#include + +namespace Catch { + + class StreamRedirect { + + public: + StreamRedirect( std::ostream& stream, std::string& targetString ) + : m_stream( stream ), + m_prevBuf( stream.rdbuf() ), + m_targetString( targetString ) + { + stream.rdbuf( m_oss.rdbuf() ); + } + + ~StreamRedirect() { + m_targetString += m_oss.str(); + m_stream.rdbuf( m_prevBuf ); + } + + private: + std::ostream& m_stream; + std::streambuf* m_prevBuf; + std::ostringstream m_oss; + std::string& m_targetString; + }; + + /////////////////////////////////////////////////////////////////////////// + + class RunContext : public IResultCapture, public IRunner { + + RunContext( RunContext const& ); + void operator =( RunContext const& ); + + public: + + explicit RunContext( Ptr const& _config, Ptr const& reporter ) + : m_runInfo( _config->name() ), + m_context( getCurrentMutableContext() ), + m_activeTestCase( CATCH_NULL ), + m_config( _config ), + m_reporter( reporter ) + { + m_context.setRunner( this ); + m_context.setConfig( m_config ); + m_context.setResultCapture( this ); + m_reporter->testRunStarting( m_runInfo ); + } + + virtual ~RunContext() { + m_reporter->testRunEnded( TestRunStats( m_runInfo, m_totals, aborting() ) ); + } + + void testGroupStarting( std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount ) { + m_reporter->testGroupStarting( GroupInfo( testSpec, groupIndex, groupsCount ) ); + } + void testGroupEnded( std::string const& testSpec, Totals const& totals, std::size_t groupIndex, std::size_t groupsCount ) { + m_reporter->testGroupEnded( TestGroupStats( GroupInfo( testSpec, groupIndex, groupsCount ), totals, aborting() ) ); + } + + Totals runTest( TestCase const& testCase ) { + Totals prevTotals = m_totals; + + std::string redirectedCout; + std::string redirectedCerr; + + TestCaseInfo testInfo = testCase.getTestCaseInfo(); + + m_reporter->testCaseStarting( testInfo ); + + m_activeTestCase = &testCase; + + do { + m_trackerContext.startRun(); + do { + m_trackerContext.startCycle(); + m_testCaseTracker = &SectionTracker::acquire( m_trackerContext, testInfo.name ); + runCurrentTest( redirectedCout, redirectedCerr ); + } + while( !m_testCaseTracker->isSuccessfullyCompleted() && !aborting() ); + } + // !TBD: deprecated - this will be replaced by indexed trackers + while( getCurrentContext().advanceGeneratorsForCurrentTest() && !aborting() ); + + Totals deltaTotals = m_totals.delta( prevTotals ); + m_totals.testCases += deltaTotals.testCases; + m_reporter->testCaseEnded( TestCaseStats( testInfo, + deltaTotals, + redirectedCout, + redirectedCerr, + aborting() ) ); + + m_activeTestCase = CATCH_NULL; + m_testCaseTracker = CATCH_NULL; + + return deltaTotals; + } + + Ptr config() const { + return m_config; + } + + private: // IResultCapture + + virtual void assertionEnded( AssertionResult const& result ) { + if( result.getResultType() == ResultWas::Ok ) { + m_totals.assertions.passed++; + } + else if( !result.isOk() ) { + m_totals.assertions.failed++; + } + + if( m_reporter->assertionEnded( AssertionStats( result, m_messages, m_totals ) ) ) + m_messages.clear(); + + // Reset working state + m_lastAssertionInfo = AssertionInfo( "", m_lastAssertionInfo.lineInfo, "{Unknown expression after the reported line}" , m_lastAssertionInfo.resultDisposition ); + m_lastResult = result; + } + + virtual bool sectionStarted ( + SectionInfo const& sectionInfo, + Counts& assertions + ) + { + std::ostringstream oss; + oss << sectionInfo.name << "@" << sectionInfo.lineInfo; + + ITracker& sectionTracker = SectionTracker::acquire( m_trackerContext, oss.str() ); + if( !sectionTracker.isOpen() ) + return false; + m_activeSections.push_back( §ionTracker ); + + m_lastAssertionInfo.lineInfo = sectionInfo.lineInfo; + + m_reporter->sectionStarting( sectionInfo ); + + assertions = m_totals.assertions; + + return true; + } + bool testForMissingAssertions( Counts& assertions ) { + if( assertions.total() != 0 ) + return false; + if( !m_config->warnAboutMissingAssertions() ) + return false; + if( m_trackerContext.currentTracker().hasChildren() ) + return false; + m_totals.assertions.failed++; + assertions.failed++; + return true; + } + + virtual void sectionEnded( SectionEndInfo const& endInfo ) { + Counts assertions = m_totals.assertions - endInfo.prevAssertions; + bool missingAssertions = testForMissingAssertions( assertions ); + + if( !m_activeSections.empty() ) { + m_activeSections.back()->close(); + m_activeSections.pop_back(); + } + + m_reporter->sectionEnded( SectionStats( endInfo.sectionInfo, assertions, endInfo.durationInSeconds, missingAssertions ) ); + m_messages.clear(); + } + + virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) { + if( m_unfinishedSections.empty() ) + m_activeSections.back()->fail(); + else + m_activeSections.back()->close(); + m_activeSections.pop_back(); + + m_unfinishedSections.push_back( endInfo ); + } + + virtual void pushScopedMessage( MessageInfo const& message ) { + m_messages.push_back( message ); + } + + virtual void popScopedMessage( MessageInfo const& message ) { + m_messages.erase( std::remove( m_messages.begin(), m_messages.end(), message ), m_messages.end() ); + } + + virtual std::string getCurrentTestName() const { + return m_activeTestCase + ? m_activeTestCase->getTestCaseInfo().name + : ""; + } + + virtual const AssertionResult* getLastResult() const { + return &m_lastResult; + } + + virtual void handleFatalErrorCondition( std::string const& message ) { + ResultBuilder resultBuilder = makeUnexpectedResultBuilder(); + resultBuilder.setResultType( ResultWas::FatalErrorCondition ); + resultBuilder << message; + resultBuilder.captureExpression(); + + handleUnfinishedSections(); + + // Recreate section for test case (as we will lose the one that was in scope) + TestCaseInfo const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); + SectionInfo testCaseSection( testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description ); + + Counts assertions; + assertions.failed = 1; + SectionStats testCaseSectionStats( testCaseSection, assertions, 0, false ); + m_reporter->sectionEnded( testCaseSectionStats ); + + TestCaseInfo testInfo = m_activeTestCase->getTestCaseInfo(); + + Totals deltaTotals; + deltaTotals.testCases.failed = 1; + m_reporter->testCaseEnded( TestCaseStats( testInfo, + deltaTotals, + "", + "", + false ) ); + m_totals.testCases.failed++; + testGroupEnded( "", m_totals, 1, 1 ); + m_reporter->testRunEnded( TestRunStats( m_runInfo, m_totals, false ) ); + } + + public: + // !TBD We need to do this another way! + bool aborting() const { + return m_totals.assertions.failed == static_cast( m_config->abortAfter() ); + } + + private: + + void runCurrentTest( std::string& redirectedCout, std::string& redirectedCerr ) { + TestCaseInfo const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); + SectionInfo testCaseSection( testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description ); + m_reporter->sectionStarting( testCaseSection ); + Counts prevAssertions = m_totals.assertions; + double duration = 0; + try { + m_lastAssertionInfo = AssertionInfo( "TEST_CASE", testCaseInfo.lineInfo, "", ResultDisposition::Normal ); + + seedRng( *m_config ); + + Timer timer; + timer.start(); + if( m_reporter->getPreferences().shouldRedirectStdOut ) { + StreamRedirect coutRedir( Catch::cout(), redirectedCout ); + StreamRedirect cerrRedir( Catch::cerr(), redirectedCerr ); + invokeActiveTestCase(); + } + else { + invokeActiveTestCase(); + } + duration = timer.getElapsedSeconds(); + } + catch( TestFailureException& ) { + // This just means the test was aborted due to failure + } + catch(...) { + makeUnexpectedResultBuilder().useActiveException(); + } + m_testCaseTracker->close(); + handleUnfinishedSections(); + m_messages.clear(); + + Counts assertions = m_totals.assertions - prevAssertions; + bool missingAssertions = testForMissingAssertions( assertions ); + + if( testCaseInfo.okToFail() ) { + std::swap( assertions.failedButOk, assertions.failed ); + m_totals.assertions.failed -= assertions.failedButOk; + m_totals.assertions.failedButOk += assertions.failedButOk; + } + + SectionStats testCaseSectionStats( testCaseSection, assertions, duration, missingAssertions ); + m_reporter->sectionEnded( testCaseSectionStats ); + } + + void invokeActiveTestCase() { + FatalConditionHandler fatalConditionHandler; // Handle signals + m_activeTestCase->invoke(); + fatalConditionHandler.reset(); + } + + private: + + ResultBuilder makeUnexpectedResultBuilder() const { + return ResultBuilder( m_lastAssertionInfo.macroName.c_str(), + m_lastAssertionInfo.lineInfo, + m_lastAssertionInfo.capturedExpression.c_str(), + m_lastAssertionInfo.resultDisposition ); + } + + void handleUnfinishedSections() { + // If sections ended prematurely due to an exception we stored their + // infos here so we can tear them down outside the unwind process. + for( std::vector::const_reverse_iterator it = m_unfinishedSections.rbegin(), + itEnd = m_unfinishedSections.rend(); + it != itEnd; + ++it ) + sectionEnded( *it ); + m_unfinishedSections.clear(); + } + + TestRunInfo m_runInfo; + IMutableContext& m_context; + TestCase const* m_activeTestCase; + ITracker* m_testCaseTracker; + ITracker* m_currentSectionTracker; + AssertionResult m_lastResult; + + Ptr m_config; + Totals m_totals; + Ptr m_reporter; + std::vector m_messages; + AssertionInfo m_lastAssertionInfo; + std::vector m_unfinishedSections; + std::vector m_activeSections; + TrackerContext m_trackerContext; + }; + + IResultCapture& getResultCapture() { + if( IResultCapture* capture = getCurrentContext().getResultCapture() ) + return *capture; + else + throw std::logic_error( "No result capture instance" ); + } + +} // end namespace Catch + +// #included from: internal/catch_version.h +#define TWOBLUECUBES_CATCH_VERSION_H_INCLUDED + +namespace Catch { + + // Versioning information + struct Version { + Version( unsigned int _majorVersion, + unsigned int _minorVersion, + unsigned int _patchNumber, + std::string const& _branchName, + unsigned int _buildNumber ); + + unsigned int const majorVersion; + unsigned int const minorVersion; + unsigned int const patchNumber; + + // buildNumber is only used if branchName is not null + std::string const branchName; + unsigned int const buildNumber; + + friend std::ostream& operator << ( std::ostream& os, Version const& version ); + + private: + void operator=( Version const& ); + }; + + extern Version libraryVersion; +} + +#include +#include +#include + +namespace Catch { + + Ptr createReporter( std::string const& reporterName, Ptr const& config ) { + Ptr reporter = getRegistryHub().getReporterRegistry().create( reporterName, config.get() ); + if( !reporter ) { + std::ostringstream oss; + oss << "No reporter registered with name: '" << reporterName << "'"; + throw std::domain_error( oss.str() ); + } + return reporter; + } + + Ptr makeReporter( Ptr const& config ) { + std::vector reporters = config->getReporterNames(); + if( reporters.empty() ) + reporters.push_back( "console" ); + + Ptr reporter; + for( std::vector::const_iterator it = reporters.begin(), itEnd = reporters.end(); + it != itEnd; + ++it ) + reporter = addReporter( reporter, createReporter( *it, config ) ); + return reporter; + } + Ptr addListeners( Ptr const& config, Ptr reporters ) { + IReporterRegistry::Listeners listeners = getRegistryHub().getReporterRegistry().getListeners(); + for( IReporterRegistry::Listeners::const_iterator it = listeners.begin(), itEnd = listeners.end(); + it != itEnd; + ++it ) + reporters = addReporter(reporters, (*it)->create( ReporterConfig( config ) ) ); + return reporters; + } + + Totals runTests( Ptr const& config ) { + + Ptr iconfig = config.get(); + + Ptr reporter = makeReporter( config ); + reporter = addListeners( iconfig, reporter ); + + RunContext context( iconfig, reporter ); + + Totals totals; + + context.testGroupStarting( config->name(), 1, 1 ); + + TestSpec testSpec = config->testSpec(); + if( !testSpec.hasFilters() ) + testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "~[.]" ).testSpec(); // All not hidden tests + + std::vector const& allTestCases = getAllTestCasesSorted( *iconfig ); + for( std::vector::const_iterator it = allTestCases.begin(), itEnd = allTestCases.end(); + it != itEnd; + ++it ) { + if( !context.aborting() && matchTest( *it, testSpec, *iconfig ) ) + totals += context.runTest( *it ); + else + reporter->skipTest( *it ); + } + + context.testGroupEnded( iconfig->name(), totals, 1, 1 ); + return totals; + } + + void applyFilenamesAsTags( IConfig const& config ) { + std::vector const& tests = getAllTestCasesSorted( config ); + for(std::size_t i = 0; i < tests.size(); ++i ) { + TestCase& test = const_cast( tests[i] ); + std::set tags = test.tags; + + std::string filename = test.lineInfo.file; + std::string::size_type lastSlash = filename.find_last_of( "\\/" ); + if( lastSlash != std::string::npos ) + filename = filename.substr( lastSlash+1 ); + + std::string::size_type lastDot = filename.find_last_of( "." ); + if( lastDot != std::string::npos ) + filename = filename.substr( 0, lastDot ); + + tags.insert( "#" + filename ); + setTags( test, tags ); + } + } + + class Session : NonCopyable { + static bool alreadyInstantiated; + + public: + + struct OnUnusedOptions { enum DoWhat { Ignore, Fail }; }; + + Session() + : m_cli( makeCommandLineParser() ) { + if( alreadyInstantiated ) { + std::string msg = "Only one instance of Catch::Session can ever be used"; + Catch::cerr() << msg << std::endl; + throw std::logic_error( msg ); + } + alreadyInstantiated = true; + } + ~Session() { + Catch::cleanUp(); + } + + void showHelp( std::string const& processName ) { + Catch::cout() << "\nCatch v" << libraryVersion << "\n"; + + m_cli.usage( Catch::cout(), processName ); + Catch::cout() << "For more detail usage please see the project docs\n" << std::endl; + } + + int applyCommandLine( int argc, char const* argv[], OnUnusedOptions::DoWhat unusedOptionBehaviour = OnUnusedOptions::Fail ) { + try { + m_cli.setThrowOnUnrecognisedTokens( unusedOptionBehaviour == OnUnusedOptions::Fail ); + m_unusedTokens = m_cli.parseInto( argc, argv, m_configData ); + if( m_configData.showHelp ) + showHelp( m_configData.processName ); + m_config.reset(); + } + catch( std::exception& ex ) { + { + Colour colourGuard( Colour::Red ); + Catch::cerr() + << "\nError(s) in input:\n" + << Text( ex.what(), TextAttributes().setIndent(2) ) + << "\n\n"; + } + m_cli.usage( Catch::cout(), m_configData.processName ); + return (std::numeric_limits::max)(); + } + return 0; + } + + void useConfigData( ConfigData const& _configData ) { + m_configData = _configData; + m_config.reset(); + } + + int run( int argc, char const* argv[] ) { + + int returnCode = applyCommandLine( argc, argv ); + if( returnCode == 0 ) + returnCode = run(); + return returnCode; + } + int run( int argc, char* argv[] ) { + return run( argc, const_cast( argv ) ); + } + + int run() { + if( m_configData.showHelp ) + return 0; + + try + { + config(); // Force config to be constructed + + seedRng( *m_config ); + + if( m_configData.filenamesAsTags ) + applyFilenamesAsTags( *m_config ); + + // Handle list request + if( Option listed = list( config() ) ) + return static_cast( *listed ); + + return static_cast( runTests( m_config ).assertions.failed ); + } + catch( std::exception& ex ) { + Catch::cerr() << ex.what() << std::endl; + return (std::numeric_limits::max)(); + } + } + + Clara::CommandLine const& cli() const { + return m_cli; + } + std::vector const& unusedTokens() const { + return m_unusedTokens; + } + ConfigData& configData() { + return m_configData; + } + Config& config() { + if( !m_config ) + m_config = new Config( m_configData ); + return *m_config; + } + private: + Clara::CommandLine m_cli; + std::vector m_unusedTokens; + ConfigData m_configData; + Ptr m_config; + }; + + bool Session::alreadyInstantiated = false; + +} // end namespace Catch + +// #included from: catch_registry_hub.hpp +#define TWOBLUECUBES_CATCH_REGISTRY_HUB_HPP_INCLUDED + +// #included from: catch_test_case_registry_impl.hpp +#define TWOBLUECUBES_CATCH_TEST_CASE_REGISTRY_IMPL_HPP_INCLUDED + +#include +#include +#include +#include +#include + +namespace Catch { + + struct LexSort { + bool operator() (TestCase i,TestCase j) const { return (i sortTests( IConfig const& config, std::vector const& unsortedTestCases ) { + + std::vector sorted = unsortedTestCases; + + switch( config.runOrder() ) { + case RunTests::InLexicographicalOrder: + std::sort( sorted.begin(), sorted.end(), LexSort() ); + break; + case RunTests::InRandomOrder: + { + seedRng( config ); + + RandomNumberGenerator rng; + std::random_shuffle( sorted.begin(), sorted.end(), rng ); + } + break; + case RunTests::InDeclarationOrder: + // already in declaration order + break; + } + return sorted; + } + bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ) { + return testSpec.matches( testCase ) && ( config.allowThrows() || !testCase.throws() ); + } + + void enforceNoDuplicateTestCases( std::vector const& functions ) { + std::set seenFunctions; + for( std::vector::const_iterator it = functions.begin(), itEnd = functions.end(); + it != itEnd; + ++it ) { + std::pair::const_iterator, bool> prev = seenFunctions.insert( *it ); + if( !prev.second ){ + Catch::cerr() + << Colour( Colour::Red ) + << "error: TEST_CASE( \"" << it->name << "\" ) already defined.\n" + << "\tFirst seen at " << prev.first->getTestCaseInfo().lineInfo << "\n" + << "\tRedefined at " << it->getTestCaseInfo().lineInfo << std::endl; + exit(1); + } + } + } + + std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ) { + std::vector filtered; + filtered.reserve( testCases.size() ); + for( std::vector::const_iterator it = testCases.begin(), itEnd = testCases.end(); + it != itEnd; + ++it ) + if( matchTest( *it, testSpec, config ) ) + filtered.push_back( *it ); + return filtered; + } + std::vector const& getAllTestCasesSorted( IConfig const& config ) { + return getRegistryHub().getTestCaseRegistry().getAllTestsSorted( config ); + } + + class TestRegistry : public ITestCaseRegistry { + public: + TestRegistry() + : m_currentSortOrder( RunTests::InDeclarationOrder ), + m_unnamedCount( 0 ) + {} + virtual ~TestRegistry(); + + virtual void registerTest( TestCase const& testCase ) { + std::string name = testCase.getTestCaseInfo().name; + if( name == "" ) { + std::ostringstream oss; + oss << "Anonymous test case " << ++m_unnamedCount; + return registerTest( testCase.withName( oss.str() ) ); + } + m_functions.push_back( testCase ); + } + + virtual std::vector const& getAllTests() const { + return m_functions; + } + virtual std::vector const& getAllTestsSorted( IConfig const& config ) const { + if( m_sortedFunctions.empty() ) + enforceNoDuplicateTestCases( m_functions ); + + if( m_currentSortOrder != config.runOrder() || m_sortedFunctions.empty() ) { + m_sortedFunctions = sortTests( config, m_functions ); + m_currentSortOrder = config.runOrder(); + } + return m_sortedFunctions; + } + + private: + std::vector m_functions; + mutable RunTests::InWhatOrder m_currentSortOrder; + mutable std::vector m_sortedFunctions; + size_t m_unnamedCount; + std::ios_base::Init m_ostreamInit; // Forces cout/ cerr to be initialised + }; + + /////////////////////////////////////////////////////////////////////////// + + class FreeFunctionTestCase : public SharedImpl { + public: + + FreeFunctionTestCase( TestFunction fun ) : m_fun( fun ) {} + + virtual void invoke() const { + m_fun(); + } + + private: + virtual ~FreeFunctionTestCase(); + + TestFunction m_fun; + }; + + inline std::string extractClassName( std::string const& classOrQualifiedMethodName ) { + std::string className = classOrQualifiedMethodName; + if( startsWith( className, "&" ) ) + { + std::size_t lastColons = className.rfind( "::" ); + std::size_t penultimateColons = className.rfind( "::", lastColons-1 ); + if( penultimateColons == std::string::npos ) + penultimateColons = 1; + className = className.substr( penultimateColons, lastColons-penultimateColons ); + } + return className; + } + + void registerTestCase + ( ITestCase* testCase, + char const* classOrQualifiedMethodName, + NameAndDesc const& nameAndDesc, + SourceLineInfo const& lineInfo ) { + + getMutableRegistryHub().registerTest + ( makeTestCase + ( testCase, + extractClassName( classOrQualifiedMethodName ), + nameAndDesc.name, + nameAndDesc.description, + lineInfo ) ); + } + void registerTestCaseFunction + ( TestFunction function, + SourceLineInfo const& lineInfo, + NameAndDesc const& nameAndDesc ) { + registerTestCase( new FreeFunctionTestCase( function ), "", nameAndDesc, lineInfo ); + } + + /////////////////////////////////////////////////////////////////////////// + + AutoReg::AutoReg + ( TestFunction function, + SourceLineInfo const& lineInfo, + NameAndDesc const& nameAndDesc ) { + registerTestCaseFunction( function, lineInfo, nameAndDesc ); + } + + AutoReg::~AutoReg() {} + +} // end namespace Catch + +// #included from: catch_reporter_registry.hpp +#define TWOBLUECUBES_CATCH_REPORTER_REGISTRY_HPP_INCLUDED + +#include + +namespace Catch { + + class ReporterRegistry : public IReporterRegistry { + + public: + + virtual ~ReporterRegistry() CATCH_OVERRIDE {} + + virtual IStreamingReporter* create( std::string const& name, Ptr const& config ) const CATCH_OVERRIDE { + FactoryMap::const_iterator it = m_factories.find( name ); + if( it == m_factories.end() ) + return CATCH_NULL; + return it->second->create( ReporterConfig( config ) ); + } + + void registerReporter( std::string const& name, Ptr const& factory ) { + m_factories.insert( std::make_pair( name, factory ) ); + } + void registerListener( Ptr const& factory ) { + m_listeners.push_back( factory ); + } + + virtual FactoryMap const& getFactories() const CATCH_OVERRIDE { + return m_factories; + } + virtual Listeners const& getListeners() const CATCH_OVERRIDE { + return m_listeners; + } + + private: + FactoryMap m_factories; + Listeners m_listeners; + }; +} + +// #included from: catch_exception_translator_registry.hpp +#define TWOBLUECUBES_CATCH_EXCEPTION_TRANSLATOR_REGISTRY_HPP_INCLUDED + +#ifdef __OBJC__ +#import "Foundation/Foundation.h" +#endif + +namespace Catch { + + class ExceptionTranslatorRegistry : public IExceptionTranslatorRegistry { + public: + ~ExceptionTranslatorRegistry() { + deleteAll( m_translators ); + } + + virtual void registerTranslator( const IExceptionTranslator* translator ) { + m_translators.push_back( translator ); + } + + virtual std::string translateActiveException() const { + try { +#ifdef __OBJC__ + // In Objective-C try objective-c exceptions first + @try { + return tryTranslators(); + } + @catch (NSException *exception) { + return Catch::toString( [exception description] ); + } +#else + return tryTranslators(); +#endif + } + catch( TestFailureException& ) { + throw; + } + catch( std::exception& ex ) { + return ex.what(); + } + catch( std::string& msg ) { + return msg; + } + catch( const char* msg ) { + return msg; + } + catch(...) { + return "Unknown exception"; + } + } + + std::string tryTranslators() const { + if( m_translators.empty() ) + throw; + else + return m_translators[0]->translate( m_translators.begin()+1, m_translators.end() ); + } + + private: + std::vector m_translators; + }; +} + +namespace Catch { + + namespace { + + class RegistryHub : public IRegistryHub, public IMutableRegistryHub { + + RegistryHub( RegistryHub const& ); + void operator=( RegistryHub const& ); + + public: // IRegistryHub + RegistryHub() { + } + virtual IReporterRegistry const& getReporterRegistry() const CATCH_OVERRIDE { + return m_reporterRegistry; + } + virtual ITestCaseRegistry const& getTestCaseRegistry() const CATCH_OVERRIDE { + return m_testCaseRegistry; + } + virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() CATCH_OVERRIDE { + return m_exceptionTranslatorRegistry; + } + + public: // IMutableRegistryHub + virtual void registerReporter( std::string const& name, Ptr const& factory ) CATCH_OVERRIDE { + m_reporterRegistry.registerReporter( name, factory ); + } + virtual void registerListener( Ptr const& factory ) CATCH_OVERRIDE { + m_reporterRegistry.registerListener( factory ); + } + virtual void registerTest( TestCase const& testInfo ) CATCH_OVERRIDE { + m_testCaseRegistry.registerTest( testInfo ); + } + virtual void registerTranslator( const IExceptionTranslator* translator ) CATCH_OVERRIDE { + m_exceptionTranslatorRegistry.registerTranslator( translator ); + } + + private: + TestRegistry m_testCaseRegistry; + ReporterRegistry m_reporterRegistry; + ExceptionTranslatorRegistry m_exceptionTranslatorRegistry; + }; + + // Single, global, instance + inline RegistryHub*& getTheRegistryHub() { + static RegistryHub* theRegistryHub = CATCH_NULL; + if( !theRegistryHub ) + theRegistryHub = new RegistryHub(); + return theRegistryHub; + } + } + + IRegistryHub& getRegistryHub() { + return *getTheRegistryHub(); + } + IMutableRegistryHub& getMutableRegistryHub() { + return *getTheRegistryHub(); + } + void cleanUp() { + delete getTheRegistryHub(); + getTheRegistryHub() = CATCH_NULL; + cleanUpContext(); + } + std::string translateActiveException() { + return getRegistryHub().getExceptionTranslatorRegistry().translateActiveException(); + } + +} // end namespace Catch + +// #included from: catch_notimplemented_exception.hpp +#define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_HPP_INCLUDED + +#include + +namespace Catch { + + NotImplementedException::NotImplementedException( SourceLineInfo const& lineInfo ) + : m_lineInfo( lineInfo ) { + std::ostringstream oss; + oss << lineInfo << ": function "; + oss << "not implemented"; + m_what = oss.str(); + } + + const char* NotImplementedException::what() const CATCH_NOEXCEPT { + return m_what.c_str(); + } + +} // end namespace Catch + +// #included from: catch_context_impl.hpp +#define TWOBLUECUBES_CATCH_CONTEXT_IMPL_HPP_INCLUDED + +// #included from: catch_stream.hpp +#define TWOBLUECUBES_CATCH_STREAM_HPP_INCLUDED + +#include +#include +#include + +namespace Catch { + + template + class StreamBufImpl : public StreamBufBase { + char data[bufferSize]; + WriterF m_writer; + + public: + StreamBufImpl() { + setp( data, data + sizeof(data) ); + } + + ~StreamBufImpl() CATCH_NOEXCEPT { + sync(); + } + + private: + int overflow( int c ) { + sync(); + + if( c != EOF ) { + if( pbase() == epptr() ) + m_writer( std::string( 1, static_cast( c ) ) ); + else + sputc( static_cast( c ) ); + } + return 0; + } + + int sync() { + if( pbase() != pptr() ) { + m_writer( std::string( pbase(), static_cast( pptr() - pbase() ) ) ); + setp( pbase(), epptr() ); + } + return 0; + } + }; + + /////////////////////////////////////////////////////////////////////////// + + FileStream::FileStream( std::string const& filename ) { + m_ofs.open( filename.c_str() ); + if( m_ofs.fail() ) { + std::ostringstream oss; + oss << "Unable to open file: '" << filename << "'"; + throw std::domain_error( oss.str() ); + } + } + + std::ostream& FileStream::stream() const { + return m_ofs; + } + + struct OutputDebugWriter { + + void operator()( std::string const&str ) { + writeToDebugConsole( str ); + } + }; + + DebugOutStream::DebugOutStream() + : m_streamBuf( new StreamBufImpl() ), + m_os( m_streamBuf.get() ) + {} + + std::ostream& DebugOutStream::stream() const { + return m_os; + } + + // Store the streambuf from cout up-front because + // cout may get redirected when running tests + CoutStream::CoutStream() + : m_os( Catch::cout().rdbuf() ) + {} + + std::ostream& CoutStream::stream() const { + return m_os; + } + +#ifndef CATCH_CONFIG_NOSTDOUT // If you #define this you must implement these functions + std::ostream& cout() { + return std::cout; + } + std::ostream& cerr() { + return std::cerr; + } +#endif +} + +namespace Catch { + + class Context : public IMutableContext { + + Context() : m_config( CATCH_NULL ), m_runner( CATCH_NULL ), m_resultCapture( CATCH_NULL ) {} + Context( Context const& ); + void operator=( Context const& ); + + public: // IContext + virtual IResultCapture* getResultCapture() { + return m_resultCapture; + } + virtual IRunner* getRunner() { + return m_runner; + } + virtual size_t getGeneratorIndex( std::string const& fileInfo, size_t totalSize ) { + return getGeneratorsForCurrentTest() + .getGeneratorInfo( fileInfo, totalSize ) + .getCurrentIndex(); + } + virtual bool advanceGeneratorsForCurrentTest() { + IGeneratorsForTest* generators = findGeneratorsForCurrentTest(); + return generators && generators->moveNext(); + } + + virtual Ptr getConfig() const { + return m_config; + } + + public: // IMutableContext + virtual void setResultCapture( IResultCapture* resultCapture ) { + m_resultCapture = resultCapture; + } + virtual void setRunner( IRunner* runner ) { + m_runner = runner; + } + virtual void setConfig( Ptr const& config ) { + m_config = config; + } + + friend IMutableContext& getCurrentMutableContext(); + + private: + IGeneratorsForTest* findGeneratorsForCurrentTest() { + std::string testName = getResultCapture()->getCurrentTestName(); + + std::map::const_iterator it = + m_generatorsByTestName.find( testName ); + return it != m_generatorsByTestName.end() + ? it->second + : CATCH_NULL; + } + + IGeneratorsForTest& getGeneratorsForCurrentTest() { + IGeneratorsForTest* generators = findGeneratorsForCurrentTest(); + if( !generators ) { + std::string testName = getResultCapture()->getCurrentTestName(); + generators = createGeneratorsForTest(); + m_generatorsByTestName.insert( std::make_pair( testName, generators ) ); + } + return *generators; + } + + private: + Ptr m_config; + IRunner* m_runner; + IResultCapture* m_resultCapture; + std::map m_generatorsByTestName; + }; + + namespace { + Context* currentContext = CATCH_NULL; + } + IMutableContext& getCurrentMutableContext() { + if( !currentContext ) + currentContext = new Context(); + return *currentContext; + } + IContext& getCurrentContext() { + return getCurrentMutableContext(); + } + + void cleanUpContext() { + delete currentContext; + currentContext = CATCH_NULL; + } +} + +// #included from: catch_console_colour_impl.hpp +#define TWOBLUECUBES_CATCH_CONSOLE_COLOUR_IMPL_HPP_INCLUDED + +namespace Catch { + namespace { + + struct IColourImpl { + virtual ~IColourImpl() {} + virtual void use( Colour::Code _colourCode ) = 0; + }; + + struct NoColourImpl : IColourImpl { + void use( Colour::Code ) {} + + static IColourImpl* instance() { + static NoColourImpl s_instance; + return &s_instance; + } + }; + + } // anon namespace +} // namespace Catch + +#if !defined( CATCH_CONFIG_COLOUR_NONE ) && !defined( CATCH_CONFIG_COLOUR_WINDOWS ) && !defined( CATCH_CONFIG_COLOUR_ANSI ) +# ifdef CATCH_PLATFORM_WINDOWS +# define CATCH_CONFIG_COLOUR_WINDOWS +# else +# define CATCH_CONFIG_COLOUR_ANSI +# endif +#endif + +#if defined ( CATCH_CONFIG_COLOUR_WINDOWS ) ///////////////////////////////////////// + +#ifndef NOMINMAX +#define NOMINMAX +#endif + +#ifdef __AFXDLL +#include +#else +#include +#endif + +namespace Catch { +namespace { + + class Win32ColourImpl : public IColourImpl { + public: + Win32ColourImpl() : stdoutHandle( GetStdHandle(STD_OUTPUT_HANDLE) ) + { + CONSOLE_SCREEN_BUFFER_INFO csbiInfo; + GetConsoleScreenBufferInfo( stdoutHandle, &csbiInfo ); + originalForegroundAttributes = csbiInfo.wAttributes & ~( BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_BLUE | BACKGROUND_INTENSITY ); + originalBackgroundAttributes = csbiInfo.wAttributes & ~( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY ); + } + + virtual void use( Colour::Code _colourCode ) { + switch( _colourCode ) { + case Colour::None: return setTextAttribute( originalForegroundAttributes ); + case Colour::White: return setTextAttribute( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE ); + case Colour::Red: return setTextAttribute( FOREGROUND_RED ); + case Colour::Green: return setTextAttribute( FOREGROUND_GREEN ); + case Colour::Blue: return setTextAttribute( FOREGROUND_BLUE ); + case Colour::Cyan: return setTextAttribute( FOREGROUND_BLUE | FOREGROUND_GREEN ); + case Colour::Yellow: return setTextAttribute( FOREGROUND_RED | FOREGROUND_GREEN ); + case Colour::Grey: return setTextAttribute( 0 ); + + case Colour::LightGrey: return setTextAttribute( FOREGROUND_INTENSITY ); + case Colour::BrightRed: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED ); + case Colour::BrightGreen: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN ); + case Colour::BrightWhite: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE ); + + case Colour::Bright: throw std::logic_error( "not a colour" ); + } + } + + private: + void setTextAttribute( WORD _textAttribute ) { + SetConsoleTextAttribute( stdoutHandle, _textAttribute | originalBackgroundAttributes ); + } + HANDLE stdoutHandle; + WORD originalForegroundAttributes; + WORD originalBackgroundAttributes; + }; + + IColourImpl* platformColourInstance() { + static Win32ColourImpl s_instance; + + Ptr config = getCurrentContext().getConfig(); + UseColour::YesOrNo colourMode = config + ? config->useColour() + : UseColour::Auto; + if( colourMode == UseColour::Auto ) + colourMode = !isDebuggerActive() + ? UseColour::Yes + : UseColour::No; + return colourMode == UseColour::Yes + ? &s_instance + : NoColourImpl::instance(); + } + +} // end anon namespace +} // end namespace Catch + +#elif defined( CATCH_CONFIG_COLOUR_ANSI ) ////////////////////////////////////// + +#include + +namespace Catch { +namespace { + + // use POSIX/ ANSI console terminal codes + // Thanks to Adam Strzelecki for original contribution + // (http://github.com/nanoant) + // https://github.com/philsquared/Catch/pull/131 + class PosixColourImpl : public IColourImpl { + public: + virtual void use( Colour::Code _colourCode ) { + switch( _colourCode ) { + case Colour::None: + case Colour::White: return setColour( "[0m" ); + case Colour::Red: return setColour( "[0;31m" ); + case Colour::Green: return setColour( "[0;32m" ); + case Colour::Blue: return setColour( "[0:34m" ); + case Colour::Cyan: return setColour( "[0;36m" ); + case Colour::Yellow: return setColour( "[0;33m" ); + case Colour::Grey: return setColour( "[1;30m" ); + + case Colour::LightGrey: return setColour( "[0;37m" ); + case Colour::BrightRed: return setColour( "[1;31m" ); + case Colour::BrightGreen: return setColour( "[1;32m" ); + case Colour::BrightWhite: return setColour( "[1;37m" ); + + case Colour::Bright: throw std::logic_error( "not a colour" ); + } + } + static IColourImpl* instance() { + static PosixColourImpl s_instance; + return &s_instance; + } + + private: + void setColour( const char* _escapeCode ) { + Catch::cout() << '\033' << _escapeCode; + } + }; + + IColourImpl* platformColourInstance() { + Ptr config = getCurrentContext().getConfig(); + UseColour::YesOrNo colourMode = config + ? config->useColour() + : UseColour::Auto; + if( colourMode == UseColour::Auto ) + colourMode = (!isDebuggerActive() && isatty(STDOUT_FILENO) ) + ? UseColour::Yes + : UseColour::No; + return colourMode == UseColour::Yes + ? PosixColourImpl::instance() + : NoColourImpl::instance(); + } + +} // end anon namespace +} // end namespace Catch + +#else // not Windows or ANSI /////////////////////////////////////////////// + +namespace Catch { + + static IColourImpl* platformColourInstance() { return NoColourImpl::instance(); } + +} // end namespace Catch + +#endif // Windows/ ANSI/ None + +namespace Catch { + + Colour::Colour( Code _colourCode ) : m_moved( false ) { use( _colourCode ); } + Colour::Colour( Colour const& _other ) : m_moved( false ) { const_cast( _other ).m_moved = true; } + Colour::~Colour(){ if( !m_moved ) use( None ); } + + void Colour::use( Code _colourCode ) { + static IColourImpl* impl = platformColourInstance(); + impl->use( _colourCode ); + } + +} // end namespace Catch + +// #included from: catch_generators_impl.hpp +#define TWOBLUECUBES_CATCH_GENERATORS_IMPL_HPP_INCLUDED + +#include +#include +#include + +namespace Catch { + + struct GeneratorInfo : IGeneratorInfo { + + GeneratorInfo( std::size_t size ) + : m_size( size ), + m_currentIndex( 0 ) + {} + + bool moveNext() { + if( ++m_currentIndex == m_size ) { + m_currentIndex = 0; + return false; + } + return true; + } + + std::size_t getCurrentIndex() const { + return m_currentIndex; + } + + std::size_t m_size; + std::size_t m_currentIndex; + }; + + /////////////////////////////////////////////////////////////////////////// + + class GeneratorsForTest : public IGeneratorsForTest { + + public: + ~GeneratorsForTest() { + deleteAll( m_generatorsInOrder ); + } + + IGeneratorInfo& getGeneratorInfo( std::string const& fileInfo, std::size_t size ) { + std::map::const_iterator it = m_generatorsByName.find( fileInfo ); + if( it == m_generatorsByName.end() ) { + IGeneratorInfo* info = new GeneratorInfo( size ); + m_generatorsByName.insert( std::make_pair( fileInfo, info ) ); + m_generatorsInOrder.push_back( info ); + return *info; + } + return *it->second; + } + + bool moveNext() { + std::vector::const_iterator it = m_generatorsInOrder.begin(); + std::vector::const_iterator itEnd = m_generatorsInOrder.end(); + for(; it != itEnd; ++it ) { + if( (*it)->moveNext() ) + return true; + } + return false; + } + + private: + std::map m_generatorsByName; + std::vector m_generatorsInOrder; + }; + + IGeneratorsForTest* createGeneratorsForTest() + { + return new GeneratorsForTest(); + } + +} // end namespace Catch + +// #included from: catch_assertionresult.hpp +#define TWOBLUECUBES_CATCH_ASSERTIONRESULT_HPP_INCLUDED + +namespace Catch { + + AssertionInfo::AssertionInfo( std::string const& _macroName, + SourceLineInfo const& _lineInfo, + std::string const& _capturedExpression, + ResultDisposition::Flags _resultDisposition ) + : macroName( _macroName ), + lineInfo( _lineInfo ), + capturedExpression( _capturedExpression ), + resultDisposition( _resultDisposition ) + {} + + AssertionResult::AssertionResult() {} + + AssertionResult::AssertionResult( AssertionInfo const& info, AssertionResultData const& data ) + : m_info( info ), + m_resultData( data ) + {} + + AssertionResult::~AssertionResult() {} + + // Result was a success + bool AssertionResult::succeeded() const { + return Catch::isOk( m_resultData.resultType ); + } + + // Result was a success, or failure is suppressed + bool AssertionResult::isOk() const { + return Catch::isOk( m_resultData.resultType ) || shouldSuppressFailure( m_info.resultDisposition ); + } + + ResultWas::OfType AssertionResult::getResultType() const { + return m_resultData.resultType; + } + + bool AssertionResult::hasExpression() const { + return !m_info.capturedExpression.empty(); + } + + bool AssertionResult::hasMessage() const { + return !m_resultData.message.empty(); + } + + std::string AssertionResult::getExpression() const { + if( isFalseTest( m_info.resultDisposition ) ) + return "!" + m_info.capturedExpression; + else + return m_info.capturedExpression; + } + std::string AssertionResult::getExpressionInMacro() const { + if( m_info.macroName.empty() ) + return m_info.capturedExpression; + else + return m_info.macroName + "( " + m_info.capturedExpression + " )"; + } + + bool AssertionResult::hasExpandedExpression() const { + return hasExpression() && getExpandedExpression() != getExpression(); + } + + std::string AssertionResult::getExpandedExpression() const { + return m_resultData.reconstructedExpression; + } + + std::string AssertionResult::getMessage() const { + return m_resultData.message; + } + SourceLineInfo AssertionResult::getSourceInfo() const { + return m_info.lineInfo; + } + + std::string AssertionResult::getTestMacroName() const { + return m_info.macroName; + } + +} // end namespace Catch + +// #included from: catch_test_case_info.hpp +#define TWOBLUECUBES_CATCH_TEST_CASE_INFO_HPP_INCLUDED + +namespace Catch { + + inline TestCaseInfo::SpecialProperties parseSpecialTag( std::string const& tag ) { + if( startsWith( tag, "." ) || + tag == "hide" || + tag == "!hide" ) + return TestCaseInfo::IsHidden; + else if( tag == "!throws" ) + return TestCaseInfo::Throws; + else if( tag == "!shouldfail" ) + return TestCaseInfo::ShouldFail; + else if( tag == "!mayfail" ) + return TestCaseInfo::MayFail; + else + return TestCaseInfo::None; + } + inline bool isReservedTag( std::string const& tag ) { + return parseSpecialTag( tag ) == TestCaseInfo::None && tag.size() > 0 && !isalnum( tag[0] ); + } + inline void enforceNotReservedTag( std::string const& tag, SourceLineInfo const& _lineInfo ) { + if( isReservedTag( tag ) ) { + { + Colour colourGuard( Colour::Red ); + Catch::cerr() + << "Tag name [" << tag << "] not allowed.\n" + << "Tag names starting with non alpha-numeric characters are reserved\n"; + } + { + Colour colourGuard( Colour::FileName ); + Catch::cerr() << _lineInfo << std::endl; + } + exit(1); + } + } + + TestCase makeTestCase( ITestCase* _testCase, + std::string const& _className, + std::string const& _name, + std::string const& _descOrTags, + SourceLineInfo const& _lineInfo ) + { + bool isHidden( startsWith( _name, "./" ) ); // Legacy support + + // Parse out tags + std::set tags; + std::string desc, tag; + bool inTag = false; + for( std::size_t i = 0; i < _descOrTags.size(); ++i ) { + char c = _descOrTags[i]; + if( !inTag ) { + if( c == '[' ) + inTag = true; + else + desc += c; + } + else { + if( c == ']' ) { + TestCaseInfo::SpecialProperties prop = parseSpecialTag( tag ); + if( prop == TestCaseInfo::IsHidden ) + isHidden = true; + else if( prop == TestCaseInfo::None ) + enforceNotReservedTag( tag, _lineInfo ); + + tags.insert( tag ); + tag.clear(); + inTag = false; + } + else + tag += c; + } + } + if( isHidden ) { + tags.insert( "hide" ); + tags.insert( "." ); + } + + TestCaseInfo info( _name, _className, desc, tags, _lineInfo ); + return TestCase( _testCase, info ); + } + + void setTags( TestCaseInfo& testCaseInfo, std::set const& tags ) + { + testCaseInfo.tags = tags; + testCaseInfo.lcaseTags.clear(); + + std::ostringstream oss; + for( std::set::const_iterator it = tags.begin(), itEnd = tags.end(); it != itEnd; ++it ) { + oss << "[" << *it << "]"; + std::string lcaseTag = toLower( *it ); + testCaseInfo.properties = static_cast( testCaseInfo.properties | parseSpecialTag( lcaseTag ) ); + testCaseInfo.lcaseTags.insert( lcaseTag ); + } + testCaseInfo.tagsAsString = oss.str(); + } + + TestCaseInfo::TestCaseInfo( std::string const& _name, + std::string const& _className, + std::string const& _description, + std::set const& _tags, + SourceLineInfo const& _lineInfo ) + : name( _name ), + className( _className ), + description( _description ), + lineInfo( _lineInfo ), + properties( None ) + { + setTags( *this, _tags ); + } + + TestCaseInfo::TestCaseInfo( TestCaseInfo const& other ) + : name( other.name ), + className( other.className ), + description( other.description ), + tags( other.tags ), + lcaseTags( other.lcaseTags ), + tagsAsString( other.tagsAsString ), + lineInfo( other.lineInfo ), + properties( other.properties ) + {} + + bool TestCaseInfo::isHidden() const { + return ( properties & IsHidden ) != 0; + } + bool TestCaseInfo::throws() const { + return ( properties & Throws ) != 0; + } + bool TestCaseInfo::okToFail() const { + return ( properties & (ShouldFail | MayFail ) ) != 0; + } + bool TestCaseInfo::expectedToFail() const { + return ( properties & (ShouldFail ) ) != 0; + } + + TestCase::TestCase( ITestCase* testCase, TestCaseInfo const& info ) : TestCaseInfo( info ), test( testCase ) {} + + TestCase::TestCase( TestCase const& other ) + : TestCaseInfo( other ), + test( other.test ) + {} + + TestCase TestCase::withName( std::string const& _newName ) const { + TestCase other( *this ); + other.name = _newName; + return other; + } + + void TestCase::swap( TestCase& other ) { + test.swap( other.test ); + name.swap( other.name ); + className.swap( other.className ); + description.swap( other.description ); + tags.swap( other.tags ); + lcaseTags.swap( other.lcaseTags ); + tagsAsString.swap( other.tagsAsString ); + std::swap( TestCaseInfo::properties, static_cast( other ).properties ); + std::swap( lineInfo, other.lineInfo ); + } + + void TestCase::invoke() const { + test->invoke(); + } + + bool TestCase::operator == ( TestCase const& other ) const { + return test.get() == other.test.get() && + name == other.name && + className == other.className; + } + + bool TestCase::operator < ( TestCase const& other ) const { + return name < other.name; + } + TestCase& TestCase::operator = ( TestCase const& other ) { + TestCase temp( other ); + swap( temp ); + return *this; + } + + TestCaseInfo const& TestCase::getTestCaseInfo() const + { + return *this; + } + +} // end namespace Catch + +// #included from: catch_version.hpp +#define TWOBLUECUBES_CATCH_VERSION_HPP_INCLUDED + +namespace Catch { + + Version::Version + ( unsigned int _majorVersion, + unsigned int _minorVersion, + unsigned int _patchNumber, + std::string const& _branchName, + unsigned int _buildNumber ) + : majorVersion( _majorVersion ), + minorVersion( _minorVersion ), + patchNumber( _patchNumber ), + branchName( _branchName ), + buildNumber( _buildNumber ) + {} + + std::ostream& operator << ( std::ostream& os, Version const& version ) { + os << version.majorVersion << "." + << version.minorVersion << "." + << version.patchNumber; + + if( !version.branchName.empty() ) { + os << "-" << version.branchName + << "." << version.buildNumber; + } + return os; + } + + Version libraryVersion( 1, 3, 6, "", 0 ); + +} + +// #included from: catch_message.hpp +#define TWOBLUECUBES_CATCH_MESSAGE_HPP_INCLUDED + +namespace Catch { + + MessageInfo::MessageInfo( std::string const& _macroName, + SourceLineInfo const& _lineInfo, + ResultWas::OfType _type ) + : macroName( _macroName ), + lineInfo( _lineInfo ), + type( _type ), + sequence( ++globalCount ) + {} + + // This may need protecting if threading support is added + unsigned int MessageInfo::globalCount = 0; + + //////////////////////////////////////////////////////////////////////////// + + ScopedMessage::ScopedMessage( MessageBuilder const& builder ) + : m_info( builder.m_info ) + { + m_info.message = builder.m_stream.str(); + getResultCapture().pushScopedMessage( m_info ); + } + ScopedMessage::ScopedMessage( ScopedMessage const& other ) + : m_info( other.m_info ) + {} + + ScopedMessage::~ScopedMessage() { + getResultCapture().popScopedMessage( m_info ); + } + +} // end namespace Catch + +// #included from: catch_legacy_reporter_adapter.hpp +#define TWOBLUECUBES_CATCH_LEGACY_REPORTER_ADAPTER_HPP_INCLUDED + +// #included from: catch_legacy_reporter_adapter.h +#define TWOBLUECUBES_CATCH_LEGACY_REPORTER_ADAPTER_H_INCLUDED + +namespace Catch +{ + // Deprecated + struct IReporter : IShared { + virtual ~IReporter(); + + virtual bool shouldRedirectStdout() const = 0; + + virtual void StartTesting() = 0; + virtual void EndTesting( Totals const& totals ) = 0; + virtual void StartGroup( std::string const& groupName ) = 0; + virtual void EndGroup( std::string const& groupName, Totals const& totals ) = 0; + virtual void StartTestCase( TestCaseInfo const& testInfo ) = 0; + virtual void EndTestCase( TestCaseInfo const& testInfo, Totals const& totals, std::string const& stdOut, std::string const& stdErr ) = 0; + virtual void StartSection( std::string const& sectionName, std::string const& description ) = 0; + virtual void EndSection( std::string const& sectionName, Counts const& assertions ) = 0; + virtual void NoAssertionsInSection( std::string const& sectionName ) = 0; + virtual void NoAssertionsInTestCase( std::string const& testName ) = 0; + virtual void Aborted() = 0; + virtual void Result( AssertionResult const& result ) = 0; + }; + + class LegacyReporterAdapter : public SharedImpl + { + public: + LegacyReporterAdapter( Ptr const& legacyReporter ); + virtual ~LegacyReporterAdapter(); + + virtual ReporterPreferences getPreferences() const; + virtual void noMatchingTestCases( std::string const& ); + virtual void testRunStarting( TestRunInfo const& ); + virtual void testGroupStarting( GroupInfo const& groupInfo ); + virtual void testCaseStarting( TestCaseInfo const& testInfo ); + virtual void sectionStarting( SectionInfo const& sectionInfo ); + virtual void assertionStarting( AssertionInfo const& ); + virtual bool assertionEnded( AssertionStats const& assertionStats ); + virtual void sectionEnded( SectionStats const& sectionStats ); + virtual void testCaseEnded( TestCaseStats const& testCaseStats ); + virtual void testGroupEnded( TestGroupStats const& testGroupStats ); + virtual void testRunEnded( TestRunStats const& testRunStats ); + virtual void skipTest( TestCaseInfo const& ); + + private: + Ptr m_legacyReporter; + }; +} + +namespace Catch +{ + LegacyReporterAdapter::LegacyReporterAdapter( Ptr const& legacyReporter ) + : m_legacyReporter( legacyReporter ) + {} + LegacyReporterAdapter::~LegacyReporterAdapter() {} + + ReporterPreferences LegacyReporterAdapter::getPreferences() const { + ReporterPreferences prefs; + prefs.shouldRedirectStdOut = m_legacyReporter->shouldRedirectStdout(); + return prefs; + } + + void LegacyReporterAdapter::noMatchingTestCases( std::string const& ) {} + void LegacyReporterAdapter::testRunStarting( TestRunInfo const& ) { + m_legacyReporter->StartTesting(); + } + void LegacyReporterAdapter::testGroupStarting( GroupInfo const& groupInfo ) { + m_legacyReporter->StartGroup( groupInfo.name ); + } + void LegacyReporterAdapter::testCaseStarting( TestCaseInfo const& testInfo ) { + m_legacyReporter->StartTestCase( testInfo ); + } + void LegacyReporterAdapter::sectionStarting( SectionInfo const& sectionInfo ) { + m_legacyReporter->StartSection( sectionInfo.name, sectionInfo.description ); + } + void LegacyReporterAdapter::assertionStarting( AssertionInfo const& ) { + // Not on legacy interface + } + + bool LegacyReporterAdapter::assertionEnded( AssertionStats const& assertionStats ) { + if( assertionStats.assertionResult.getResultType() != ResultWas::Ok ) { + for( std::vector::const_iterator it = assertionStats.infoMessages.begin(), itEnd = assertionStats.infoMessages.end(); + it != itEnd; + ++it ) { + if( it->type == ResultWas::Info ) { + ResultBuilder rb( it->macroName.c_str(), it->lineInfo, "", ResultDisposition::Normal ); + rb << it->message; + rb.setResultType( ResultWas::Info ); + AssertionResult result = rb.build(); + m_legacyReporter->Result( result ); + } + } + } + m_legacyReporter->Result( assertionStats.assertionResult ); + return true; + } + void LegacyReporterAdapter::sectionEnded( SectionStats const& sectionStats ) { + if( sectionStats.missingAssertions ) + m_legacyReporter->NoAssertionsInSection( sectionStats.sectionInfo.name ); + m_legacyReporter->EndSection( sectionStats.sectionInfo.name, sectionStats.assertions ); + } + void LegacyReporterAdapter::testCaseEnded( TestCaseStats const& testCaseStats ) { + m_legacyReporter->EndTestCase + ( testCaseStats.testInfo, + testCaseStats.totals, + testCaseStats.stdOut, + testCaseStats.stdErr ); + } + void LegacyReporterAdapter::testGroupEnded( TestGroupStats const& testGroupStats ) { + if( testGroupStats.aborting ) + m_legacyReporter->Aborted(); + m_legacyReporter->EndGroup( testGroupStats.groupInfo.name, testGroupStats.totals ); + } + void LegacyReporterAdapter::testRunEnded( TestRunStats const& testRunStats ) { + m_legacyReporter->EndTesting( testRunStats.totals ); + } + void LegacyReporterAdapter::skipTest( TestCaseInfo const& ) { + } +} + +// #included from: catch_timer.hpp + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wc++11-long-long" +#endif + +#ifdef CATCH_PLATFORM_WINDOWS +#include +#else +#include +#endif + +namespace Catch { + + namespace { +#ifdef CATCH_PLATFORM_WINDOWS + uint64_t getCurrentTicks() { + static uint64_t hz=0, hzo=0; + if (!hz) { + QueryPerformanceFrequency( reinterpret_cast( &hz ) ); + QueryPerformanceCounter( reinterpret_cast( &hzo ) ); + } + uint64_t t; + QueryPerformanceCounter( reinterpret_cast( &t ) ); + return ((t-hzo)*1000000)/hz; + } +#else + uint64_t getCurrentTicks() { + timeval t; + gettimeofday(&t,CATCH_NULL); + return static_cast( t.tv_sec ) * 1000000ull + static_cast( t.tv_usec ); + } +#endif + } + + void Timer::start() { + m_ticks = getCurrentTicks(); + } + unsigned int Timer::getElapsedMicroseconds() const { + return static_cast(getCurrentTicks() - m_ticks); + } + unsigned int Timer::getElapsedMilliseconds() const { + return static_cast(getElapsedMicroseconds()/1000); + } + double Timer::getElapsedSeconds() const { + return getElapsedMicroseconds()/1000000.0; + } + +} // namespace Catch + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif +// #included from: catch_common.hpp +#define TWOBLUECUBES_CATCH_COMMON_HPP_INCLUDED + +namespace Catch { + + bool startsWith( std::string const& s, std::string const& prefix ) { + return s.size() >= prefix.size() && s.substr( 0, prefix.size() ) == prefix; + } + bool endsWith( std::string const& s, std::string const& suffix ) { + return s.size() >= suffix.size() && s.substr( s.size()-suffix.size(), suffix.size() ) == suffix; + } + bool contains( std::string const& s, std::string const& infix ) { + return s.find( infix ) != std::string::npos; + } + void toLowerInPlace( std::string& s ) { + std::transform( s.begin(), s.end(), s.begin(), ::tolower ); + } + std::string toLower( std::string const& s ) { + std::string lc = s; + toLowerInPlace( lc ); + return lc; + } + std::string trim( std::string const& str ) { + static char const* whitespaceChars = "\n\r\t "; + std::string::size_type start = str.find_first_not_of( whitespaceChars ); + std::string::size_type end = str.find_last_not_of( whitespaceChars ); + + return start != std::string::npos ? str.substr( start, 1+end-start ) : ""; + } + + bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ) { + bool replaced = false; + std::size_t i = str.find( replaceThis ); + while( i != std::string::npos ) { + replaced = true; + str = str.substr( 0, i ) + withThis + str.substr( i+replaceThis.size() ); + if( i < str.size()-withThis.size() ) + i = str.find( replaceThis, i+withThis.size() ); + else + i = std::string::npos; + } + return replaced; + } + + pluralise::pluralise( std::size_t count, std::string const& label ) + : m_count( count ), + m_label( label ) + {} + + std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ) { + os << pluraliser.m_count << " " << pluraliser.m_label; + if( pluraliser.m_count != 1 ) + os << "s"; + return os; + } + + SourceLineInfo::SourceLineInfo() : line( 0 ){} + SourceLineInfo::SourceLineInfo( char const* _file, std::size_t _line ) + : file( _file ), + line( _line ) + {} + SourceLineInfo::SourceLineInfo( SourceLineInfo const& other ) + : file( other.file ), + line( other.line ) + {} + bool SourceLineInfo::empty() const { + return file.empty(); + } + bool SourceLineInfo::operator == ( SourceLineInfo const& other ) const { + return line == other.line && file == other.file; + } + bool SourceLineInfo::operator < ( SourceLineInfo const& other ) const { + return line < other.line || ( line == other.line && file < other.file ); + } + + void seedRng( IConfig const& config ) { + if( config.rngSeed() != 0 ) + std::srand( config.rngSeed() ); + } + unsigned int rngSeed() { + return getCurrentContext().getConfig()->rngSeed(); + } + + std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ) { +#ifndef __GNUG__ + os << info.file << "(" << info.line << ")"; +#else + os << info.file << ":" << info.line; +#endif + return os; + } + + void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo ) { + std::ostringstream oss; + oss << locationInfo << ": Internal Catch error: '" << message << "'"; + if( alwaysTrue() ) + throw std::logic_error( oss.str() ); + } +} + +// #included from: catch_section.hpp +#define TWOBLUECUBES_CATCH_SECTION_HPP_INCLUDED + +namespace Catch { + + SectionInfo::SectionInfo + ( SourceLineInfo const& _lineInfo, + std::string const& _name, + std::string const& _description ) + : name( _name ), + description( _description ), + lineInfo( _lineInfo ) + {} + + Section::Section( SectionInfo const& info ) + : m_info( info ), + m_sectionIncluded( getResultCapture().sectionStarted( m_info, m_assertions ) ) + { + m_timer.start(); + } + + Section::~Section() { + if( m_sectionIncluded ) { + SectionEndInfo endInfo( m_info, m_assertions, m_timer.getElapsedSeconds() ); + if( std::uncaught_exception() ) + getResultCapture().sectionEndedEarly( endInfo ); + else + getResultCapture().sectionEnded( endInfo ); + } + } + + // This indicates whether the section should be executed or not + Section::operator bool() const { + return m_sectionIncluded; + } + +} // end namespace Catch + +// #included from: catch_debugger.hpp +#define TWOBLUECUBES_CATCH_DEBUGGER_HPP_INCLUDED + +#include + +#ifdef CATCH_PLATFORM_MAC + + #include + #include + #include + #include + #include + + namespace Catch{ + + // The following function is taken directly from the following technical note: + // http://developer.apple.com/library/mac/#qa/qa2004/qa1361.html + + // Returns true if the current process is being debugged (either + // running under the debugger or has a debugger attached post facto). + bool isDebuggerActive(){ + + int mib[4]; + struct kinfo_proc info; + size_t size; + + // Initialize the flags so that, if sysctl fails for some bizarre + // reason, we get a predictable result. + + info.kp_proc.p_flag = 0; + + // Initialize mib, which tells sysctl the info we want, in this case + // we're looking for information about a specific process ID. + + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PID; + mib[3] = getpid(); + + // Call sysctl. + + size = sizeof(info); + if( sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, CATCH_NULL, 0) != 0 ) { + Catch::cerr() << "\n** Call to sysctl failed - unable to determine if debugger is active **\n" << std::endl; + return false; + } + + // We're being debugged if the P_TRACED flag is set. + + return ( (info.kp_proc.p_flag & P_TRACED) != 0 ); + } + } // namespace Catch + +#elif defined(_MSC_VER) + extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); + namespace Catch { + bool isDebuggerActive() { + return IsDebuggerPresent() != 0; + } + } +#elif defined(__MINGW32__) + extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); + namespace Catch { + bool isDebuggerActive() { + return IsDebuggerPresent() != 0; + } + } +#else + namespace Catch { + inline bool isDebuggerActive() { return false; } + } +#endif // Platform + +#ifdef CATCH_PLATFORM_WINDOWS + extern "C" __declspec(dllimport) void __stdcall OutputDebugStringA( const char* ); + namespace Catch { + void writeToDebugConsole( std::string const& text ) { + ::OutputDebugStringA( text.c_str() ); + } + } +#else + namespace Catch { + void writeToDebugConsole( std::string const& text ) { + // !TBD: Need a version for Mac/ XCode and other IDEs + Catch::cout() << text; + } + } +#endif // Platform + +// #included from: catch_tostring.hpp +#define TWOBLUECUBES_CATCH_TOSTRING_HPP_INCLUDED + +namespace Catch { + +namespace Detail { + + const std::string unprintableString = "{?}"; + + namespace { + const int hexThreshold = 255; + + struct Endianness { + enum Arch { Big, Little }; + + static Arch which() { + union _{ + int asInt; + char asChar[sizeof (int)]; + } u; + + u.asInt = 1; + return ( u.asChar[sizeof(int)-1] == 1 ) ? Big : Little; + } + }; + } + + std::string rawMemoryToString( const void *object, std::size_t size ) + { + // Reverse order for little endian architectures + int i = 0, end = static_cast( size ), inc = 1; + if( Endianness::which() == Endianness::Little ) { + i = end-1; + end = inc = -1; + } + + unsigned char const *bytes = static_cast(object); + std::ostringstream os; + os << "0x" << std::setfill('0') << std::hex; + for( ; i != end; i += inc ) + os << std::setw(2) << static_cast(bytes[i]); + return os.str(); + } +} + +std::string toString( std::string const& value ) { + std::string s = value; + if( getCurrentContext().getConfig()->showInvisibles() ) { + for(size_t i = 0; i < s.size(); ++i ) { + std::string subs; + switch( s[i] ) { + case '\n': subs = "\\n"; break; + case '\t': subs = "\\t"; break; + default: break; + } + if( !subs.empty() ) { + s = s.substr( 0, i ) + subs + s.substr( i+1 ); + ++i; + } + } + } + return "\"" + s + "\""; +} +std::string toString( std::wstring const& value ) { + + std::string s; + s.reserve( value.size() ); + for(size_t i = 0; i < value.size(); ++i ) + s += value[i] <= 0xff ? static_cast( value[i] ) : '?'; + return Catch::toString( s ); +} + +std::string toString( const char* const value ) { + return value ? Catch::toString( std::string( value ) ) : std::string( "{null string}" ); +} + +std::string toString( char* const value ) { + return Catch::toString( static_cast( value ) ); +} + +std::string toString( const wchar_t* const value ) +{ + return value ? Catch::toString( std::wstring(value) ) : std::string( "{null string}" ); +} + +std::string toString( wchar_t* const value ) +{ + return Catch::toString( static_cast( value ) ); +} + +std::string toString( int value ) { + std::ostringstream oss; + oss << value; + if( value > Detail::hexThreshold ) + oss << " (0x" << std::hex << value << ")"; + return oss.str(); +} + +std::string toString( unsigned long value ) { + std::ostringstream oss; + oss << value; + if( value > Detail::hexThreshold ) + oss << " (0x" << std::hex << value << ")"; + return oss.str(); +} + +std::string toString( unsigned int value ) { + return Catch::toString( static_cast( value ) ); +} + +template +std::string fpToString( T value, int precision ) { + std::ostringstream oss; + oss << std::setprecision( precision ) + << std::fixed + << value; + std::string d = oss.str(); + std::size_t i = d.find_last_not_of( '0' ); + if( i != std::string::npos && i != d.size()-1 ) { + if( d[i] == '.' ) + i++; + d = d.substr( 0, i+1 ); + } + return d; +} + +std::string toString( const double value ) { + return fpToString( value, 10 ); +} +std::string toString( const float value ) { + return fpToString( value, 5 ) + "f"; +} + +std::string toString( bool value ) { + return value ? "true" : "false"; +} + +std::string toString( char value ) { + return value < ' ' + ? toString( static_cast( value ) ) + : Detail::makeString( value ); +} + +std::string toString( signed char value ) { + return toString( static_cast( value ) ); +} + +std::string toString( unsigned char value ) { + return toString( static_cast( value ) ); +} + +#ifdef CATCH_CONFIG_CPP11_LONG_LONG +std::string toString( long long value ) { + std::ostringstream oss; + oss << value; + if( value > Detail::hexThreshold ) + oss << " (0x" << std::hex << value << ")"; + return oss.str(); +} +std::string toString( unsigned long long value ) { + std::ostringstream oss; + oss << value; + if( value > Detail::hexThreshold ) + oss << " (0x" << std::hex << value << ")"; + return oss.str(); +} +#endif + +#ifdef CATCH_CONFIG_CPP11_NULLPTR +std::string toString( std::nullptr_t ) { + return "nullptr"; +} +#endif + +#ifdef __OBJC__ + std::string toString( NSString const * const& nsstring ) { + if( !nsstring ) + return "nil"; + return "@" + toString([nsstring UTF8String]); + } + std::string toString( NSString * CATCH_ARC_STRONG const& nsstring ) { + if( !nsstring ) + return "nil"; + return "@" + toString([nsstring UTF8String]); + } + std::string toString( NSObject* const& nsObject ) { + return toString( [nsObject description] ); + } +#endif + +} // end namespace Catch + +// #included from: catch_result_builder.hpp +#define TWOBLUECUBES_CATCH_RESULT_BUILDER_HPP_INCLUDED + +namespace Catch { + + std::string capturedExpressionWithSecondArgument( std::string const& capturedExpression, std::string const& secondArg ) { + return secondArg.empty() || secondArg == "\"\"" + ? capturedExpression + : capturedExpression + ", " + secondArg; + } + ResultBuilder::ResultBuilder( char const* macroName, + SourceLineInfo const& lineInfo, + char const* capturedExpression, + ResultDisposition::Flags resultDisposition, + char const* secondArg ) + : m_assertionInfo( macroName, lineInfo, capturedExpressionWithSecondArgument( capturedExpression, secondArg ), resultDisposition ), + m_shouldDebugBreak( false ), + m_shouldThrow( false ) + {} + + ResultBuilder& ResultBuilder::setResultType( ResultWas::OfType result ) { + m_data.resultType = result; + return *this; + } + ResultBuilder& ResultBuilder::setResultType( bool result ) { + m_data.resultType = result ? ResultWas::Ok : ResultWas::ExpressionFailed; + return *this; + } + ResultBuilder& ResultBuilder::setLhs( std::string const& lhs ) { + m_exprComponents.lhs = lhs; + return *this; + } + ResultBuilder& ResultBuilder::setRhs( std::string const& rhs ) { + m_exprComponents.rhs = rhs; + return *this; + } + ResultBuilder& ResultBuilder::setOp( std::string const& op ) { + m_exprComponents.op = op; + return *this; + } + + void ResultBuilder::endExpression() { + m_exprComponents.testFalse = isFalseTest( m_assertionInfo.resultDisposition ); + captureExpression(); + } + + void ResultBuilder::useActiveException( ResultDisposition::Flags resultDisposition ) { + m_assertionInfo.resultDisposition = resultDisposition; + m_stream.oss << Catch::translateActiveException(); + captureResult( ResultWas::ThrewException ); + } + + void ResultBuilder::captureResult( ResultWas::OfType resultType ) { + setResultType( resultType ); + captureExpression(); + } + void ResultBuilder::captureExpectedException( std::string const& expectedMessage ) { + if( expectedMessage.empty() ) + captureExpectedException( Matchers::Impl::Generic::AllOf() ); + else + captureExpectedException( Matchers::Equals( expectedMessage ) ); + } + + void ResultBuilder::captureExpectedException( Matchers::Impl::Matcher const& matcher ) { + + assert( m_exprComponents.testFalse == false ); + AssertionResultData data = m_data; + data.resultType = ResultWas::Ok; + data.reconstructedExpression = m_assertionInfo.capturedExpression; + + std::string actualMessage = Catch::translateActiveException(); + if( !matcher.match( actualMessage ) ) { + data.resultType = ResultWas::ExpressionFailed; + data.reconstructedExpression = actualMessage; + } + AssertionResult result( m_assertionInfo, data ); + handleResult( result ); + } + + void ResultBuilder::captureExpression() { + AssertionResult result = build(); + handleResult( result ); + } + void ResultBuilder::handleResult( AssertionResult const& result ) + { + getResultCapture().assertionEnded( result ); + + if( !result.isOk() ) { + if( getCurrentContext().getConfig()->shouldDebugBreak() ) + m_shouldDebugBreak = true; + if( getCurrentContext().getRunner()->aborting() || (m_assertionInfo.resultDisposition & ResultDisposition::Normal) ) + m_shouldThrow = true; + } + } + void ResultBuilder::react() { + if( m_shouldThrow ) + throw Catch::TestFailureException(); + } + + bool ResultBuilder::shouldDebugBreak() const { return m_shouldDebugBreak; } + bool ResultBuilder::allowThrows() const { return getCurrentContext().getConfig()->allowThrows(); } + + AssertionResult ResultBuilder::build() const + { + assert( m_data.resultType != ResultWas::Unknown ); + + AssertionResultData data = m_data; + + // Flip bool results if testFalse is set + if( m_exprComponents.testFalse ) { + if( data.resultType == ResultWas::Ok ) + data.resultType = ResultWas::ExpressionFailed; + else if( data.resultType == ResultWas::ExpressionFailed ) + data.resultType = ResultWas::Ok; + } + + data.message = m_stream.oss.str(); + data.reconstructedExpression = reconstructExpression(); + if( m_exprComponents.testFalse ) { + if( m_exprComponents.op == "" ) + data.reconstructedExpression = "!" + data.reconstructedExpression; + else + data.reconstructedExpression = "!(" + data.reconstructedExpression + ")"; + } + return AssertionResult( m_assertionInfo, data ); + } + std::string ResultBuilder::reconstructExpression() const { + if( m_exprComponents.op == "" ) + return m_exprComponents.lhs.empty() ? m_assertionInfo.capturedExpression : m_exprComponents.op + m_exprComponents.lhs; + else if( m_exprComponents.op == "matches" ) + return m_exprComponents.lhs + " " + m_exprComponents.rhs; + else if( m_exprComponents.op != "!" ) { + if( m_exprComponents.lhs.size() + m_exprComponents.rhs.size() < 40 && + m_exprComponents.lhs.find("\n") == std::string::npos && + m_exprComponents.rhs.find("\n") == std::string::npos ) + return m_exprComponents.lhs + " " + m_exprComponents.op + " " + m_exprComponents.rhs; + else + return m_exprComponents.lhs + "\n" + m_exprComponents.op + "\n" + m_exprComponents.rhs; + } + else + return "{can't expand - use " + m_assertionInfo.macroName + "_FALSE( " + m_assertionInfo.capturedExpression.substr(1) + " ) instead of " + m_assertionInfo.macroName + "( " + m_assertionInfo.capturedExpression + " ) for better diagnostics}"; + } + +} // end namespace Catch + +// #included from: catch_tag_alias_registry.hpp +#define TWOBLUECUBES_CATCH_TAG_ALIAS_REGISTRY_HPP_INCLUDED + +// #included from: catch_tag_alias_registry.h +#define TWOBLUECUBES_CATCH_TAG_ALIAS_REGISTRY_H_INCLUDED + +#include + +namespace Catch { + + class TagAliasRegistry : public ITagAliasRegistry { + public: + virtual ~TagAliasRegistry(); + virtual Option find( std::string const& alias ) const; + virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const; + void add( char const* alias, char const* tag, SourceLineInfo const& lineInfo ); + static TagAliasRegistry& get(); + + private: + std::map m_registry; + }; + +} // end namespace Catch + +#include +#include + +namespace Catch { + + TagAliasRegistry::~TagAliasRegistry() {} + + Option TagAliasRegistry::find( std::string const& alias ) const { + std::map::const_iterator it = m_registry.find( alias ); + if( it != m_registry.end() ) + return it->second; + else + return Option(); + } + + std::string TagAliasRegistry::expandAliases( std::string const& unexpandedTestSpec ) const { + std::string expandedTestSpec = unexpandedTestSpec; + for( std::map::const_iterator it = m_registry.begin(), itEnd = m_registry.end(); + it != itEnd; + ++it ) { + std::size_t pos = expandedTestSpec.find( it->first ); + if( pos != std::string::npos ) { + expandedTestSpec = expandedTestSpec.substr( 0, pos ) + + it->second.tag + + expandedTestSpec.substr( pos + it->first.size() ); + } + } + return expandedTestSpec; + } + + void TagAliasRegistry::add( char const* alias, char const* tag, SourceLineInfo const& lineInfo ) { + + if( !startsWith( alias, "[@" ) || !endsWith( alias, "]" ) ) { + std::ostringstream oss; + oss << "error: tag alias, \"" << alias << "\" is not of the form [@alias name].\n" << lineInfo; + throw std::domain_error( oss.str().c_str() ); + } + if( !m_registry.insert( std::make_pair( alias, TagAlias( tag, lineInfo ) ) ).second ) { + std::ostringstream oss; + oss << "error: tag alias, \"" << alias << "\" already registered.\n" + << "\tFirst seen at " << find(alias)->lineInfo << "\n" + << "\tRedefined at " << lineInfo; + throw std::domain_error( oss.str().c_str() ); + } + } + + TagAliasRegistry& TagAliasRegistry::get() { + static TagAliasRegistry instance; + return instance; + + } + + ITagAliasRegistry::~ITagAliasRegistry() {} + ITagAliasRegistry const& ITagAliasRegistry::get() { return TagAliasRegistry::get(); } + + RegistrarForTagAliases::RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ) { + try { + TagAliasRegistry::get().add( alias, tag, lineInfo ); + } + catch( std::exception& ex ) { + Colour colourGuard( Colour::Red ); + Catch::cerr() << ex.what() << std::endl; + exit(1); + } + } + +} // end namespace Catch + +// #included from: ../reporters/catch_reporter_multi.hpp +#define TWOBLUECUBES_CATCH_REPORTER_MULTI_HPP_INCLUDED + +namespace Catch { + +class MultipleReporters : public SharedImpl { + typedef std::vector > Reporters; + Reporters m_reporters; + +public: + void add( Ptr const& reporter ) { + m_reporters.push_back( reporter ); + } + +public: // IStreamingReporter + + virtual ReporterPreferences getPreferences() const CATCH_OVERRIDE { + return m_reporters[0]->getPreferences(); + } + + virtual void noMatchingTestCases( std::string const& spec ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->noMatchingTestCases( spec ); + } + + virtual void testRunStarting( TestRunInfo const& testRunInfo ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->testRunStarting( testRunInfo ); + } + + virtual void testGroupStarting( GroupInfo const& groupInfo ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->testGroupStarting( groupInfo ); + } + + virtual void testCaseStarting( TestCaseInfo const& testInfo ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->testCaseStarting( testInfo ); + } + + virtual void sectionStarting( SectionInfo const& sectionInfo ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->sectionStarting( sectionInfo ); + } + + virtual void assertionStarting( AssertionInfo const& assertionInfo ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->assertionStarting( assertionInfo ); + } + + // The return value indicates if the messages buffer should be cleared: + virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE { + bool clearBuffer = false; + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + clearBuffer |= (*it)->assertionEnded( assertionStats ); + return clearBuffer; + } + + virtual void sectionEnded( SectionStats const& sectionStats ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->sectionEnded( sectionStats ); + } + + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->testCaseEnded( testCaseStats ); + } + + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->testGroupEnded( testGroupStats ); + } + + virtual void testRunEnded( TestRunStats const& testRunStats ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->testRunEnded( testRunStats ); + } + + virtual void skipTest( TestCaseInfo const& testInfo ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->skipTest( testInfo ); + } +}; + +Ptr addReporter( Ptr const& existingReporter, Ptr const& additionalReporter ) { + Ptr resultingReporter; + + if( existingReporter ) { + MultipleReporters* multi = dynamic_cast( existingReporter.get() ); + if( !multi ) { + multi = new MultipleReporters; + resultingReporter = Ptr( multi ); + if( existingReporter ) + multi->add( existingReporter ); + } + else + resultingReporter = existingReporter; + multi->add( additionalReporter ); + } + else + resultingReporter = additionalReporter; + + return resultingReporter; +} + +} // end namespace Catch + +// #included from: ../reporters/catch_reporter_xml.hpp +#define TWOBLUECUBES_CATCH_REPORTER_XML_HPP_INCLUDED + +// #included from: catch_reporter_bases.hpp +#define TWOBLUECUBES_CATCH_REPORTER_BASES_HPP_INCLUDED + +#include + +namespace Catch { + + struct StreamingReporterBase : SharedImpl { + + StreamingReporterBase( ReporterConfig const& _config ) + : m_config( _config.fullConfig() ), + stream( _config.stream() ) + { + m_reporterPrefs.shouldRedirectStdOut = false; + } + + virtual ReporterPreferences getPreferences() const CATCH_OVERRIDE { + return m_reporterPrefs; + } + + virtual ~StreamingReporterBase() CATCH_OVERRIDE; + + virtual void noMatchingTestCases( std::string const& ) CATCH_OVERRIDE {} + + virtual void testRunStarting( TestRunInfo const& _testRunInfo ) CATCH_OVERRIDE { + currentTestRunInfo = _testRunInfo; + } + virtual void testGroupStarting( GroupInfo const& _groupInfo ) CATCH_OVERRIDE { + currentGroupInfo = _groupInfo; + } + + virtual void testCaseStarting( TestCaseInfo const& _testInfo ) CATCH_OVERRIDE { + currentTestCaseInfo = _testInfo; + } + virtual void sectionStarting( SectionInfo const& _sectionInfo ) CATCH_OVERRIDE { + m_sectionStack.push_back( _sectionInfo ); + } + + virtual void sectionEnded( SectionStats const& /* _sectionStats */ ) CATCH_OVERRIDE { + m_sectionStack.pop_back(); + } + virtual void testCaseEnded( TestCaseStats const& /* _testCaseStats */ ) CATCH_OVERRIDE { + currentTestCaseInfo.reset(); + } + virtual void testGroupEnded( TestGroupStats const& /* _testGroupStats */ ) CATCH_OVERRIDE { + currentGroupInfo.reset(); + } + virtual void testRunEnded( TestRunStats const& /* _testRunStats */ ) CATCH_OVERRIDE { + currentTestCaseInfo.reset(); + currentGroupInfo.reset(); + currentTestRunInfo.reset(); + } + + virtual void skipTest( TestCaseInfo const& ) CATCH_OVERRIDE { + // Don't do anything with this by default. + // It can optionally be overridden in the derived class. + } + + Ptr m_config; + std::ostream& stream; + + LazyStat currentTestRunInfo; + LazyStat currentGroupInfo; + LazyStat currentTestCaseInfo; + + std::vector m_sectionStack; + ReporterPreferences m_reporterPrefs; + }; + + struct CumulativeReporterBase : SharedImpl { + template + struct Node : SharedImpl<> { + explicit Node( T const& _value ) : value( _value ) {} + virtual ~Node() {} + + typedef std::vector > ChildNodes; + T value; + ChildNodes children; + }; + struct SectionNode : SharedImpl<> { + explicit SectionNode( SectionStats const& _stats ) : stats( _stats ) {} + virtual ~SectionNode(); + + bool operator == ( SectionNode const& other ) const { + return stats.sectionInfo.lineInfo == other.stats.sectionInfo.lineInfo; + } + bool operator == ( Ptr const& other ) const { + return operator==( *other ); + } + + SectionStats stats; + typedef std::vector > ChildSections; + typedef std::vector Assertions; + ChildSections childSections; + Assertions assertions; + std::string stdOut; + std::string stdErr; + }; + + struct BySectionInfo { + BySectionInfo( SectionInfo const& other ) : m_other( other ) {} + BySectionInfo( BySectionInfo const& other ) : m_other( other.m_other ) {} + bool operator() ( Ptr const& node ) const { + return node->stats.sectionInfo.lineInfo == m_other.lineInfo; + } + private: + void operator=( BySectionInfo const& ); + SectionInfo const& m_other; + }; + + typedef Node TestCaseNode; + typedef Node TestGroupNode; + typedef Node TestRunNode; + + CumulativeReporterBase( ReporterConfig const& _config ) + : m_config( _config.fullConfig() ), + stream( _config.stream() ) + { + m_reporterPrefs.shouldRedirectStdOut = false; + } + ~CumulativeReporterBase(); + + virtual ReporterPreferences getPreferences() const CATCH_OVERRIDE { + return m_reporterPrefs; + } + + virtual void testRunStarting( TestRunInfo const& ) CATCH_OVERRIDE {} + virtual void testGroupStarting( GroupInfo const& ) CATCH_OVERRIDE {} + + virtual void testCaseStarting( TestCaseInfo const& ) CATCH_OVERRIDE {} + + virtual void sectionStarting( SectionInfo const& sectionInfo ) CATCH_OVERRIDE { + SectionStats incompleteStats( sectionInfo, Counts(), 0, false ); + Ptr node; + if( m_sectionStack.empty() ) { + if( !m_rootSection ) + m_rootSection = new SectionNode( incompleteStats ); + node = m_rootSection; + } + else { + SectionNode& parentNode = *m_sectionStack.back(); + SectionNode::ChildSections::const_iterator it = + std::find_if( parentNode.childSections.begin(), + parentNode.childSections.end(), + BySectionInfo( sectionInfo ) ); + if( it == parentNode.childSections.end() ) { + node = new SectionNode( incompleteStats ); + parentNode.childSections.push_back( node ); + } + else + node = *it; + } + m_sectionStack.push_back( node ); + m_deepestSection = node; + } + + virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE {} + + virtual bool assertionEnded( AssertionStats const& assertionStats ) { + assert( !m_sectionStack.empty() ); + SectionNode& sectionNode = *m_sectionStack.back(); + sectionNode.assertions.push_back( assertionStats ); + return true; + } + virtual void sectionEnded( SectionStats const& sectionStats ) CATCH_OVERRIDE { + assert( !m_sectionStack.empty() ); + SectionNode& node = *m_sectionStack.back(); + node.stats = sectionStats; + m_sectionStack.pop_back(); + } + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE { + Ptr node = new TestCaseNode( testCaseStats ); + assert( m_sectionStack.size() == 0 ); + node->children.push_back( m_rootSection ); + m_testCases.push_back( node ); + m_rootSection.reset(); + + assert( m_deepestSection ); + m_deepestSection->stdOut = testCaseStats.stdOut; + m_deepestSection->stdErr = testCaseStats.stdErr; + } + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE { + Ptr node = new TestGroupNode( testGroupStats ); + node->children.swap( m_testCases ); + m_testGroups.push_back( node ); + } + virtual void testRunEnded( TestRunStats const& testRunStats ) CATCH_OVERRIDE { + Ptr node = new TestRunNode( testRunStats ); + node->children.swap( m_testGroups ); + m_testRuns.push_back( node ); + testRunEndedCumulative(); + } + virtual void testRunEndedCumulative() = 0; + + virtual void skipTest( TestCaseInfo const& ) CATCH_OVERRIDE {} + + Ptr m_config; + std::ostream& stream; + std::vector m_assertions; + std::vector > > m_sections; + std::vector > m_testCases; + std::vector > m_testGroups; + + std::vector > m_testRuns; + + Ptr m_rootSection; + Ptr m_deepestSection; + std::vector > m_sectionStack; + ReporterPreferences m_reporterPrefs; + + }; + + template + char const* getLineOfChars() { + static char line[CATCH_CONFIG_CONSOLE_WIDTH] = {0}; + if( !*line ) { + memset( line, C, CATCH_CONFIG_CONSOLE_WIDTH-1 ); + line[CATCH_CONFIG_CONSOLE_WIDTH-1] = 0; + } + return line; + } + + struct TestEventListenerBase : StreamingReporterBase { + TestEventListenerBase( ReporterConfig const& _config ) + : StreamingReporterBase( _config ) + {} + + virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE {} + virtual bool assertionEnded( AssertionStats const& ) CATCH_OVERRIDE { + return false; + } + }; + +} // end namespace Catch + +// #included from: ../internal/catch_reporter_registrars.hpp +#define TWOBLUECUBES_CATCH_REPORTER_REGISTRARS_HPP_INCLUDED + +namespace Catch { + + template + class LegacyReporterRegistrar { + + class ReporterFactory : public IReporterFactory { + virtual IStreamingReporter* create( ReporterConfig const& config ) const { + return new LegacyReporterAdapter( new T( config ) ); + } + + virtual std::string getDescription() const { + return T::getDescription(); + } + }; + + public: + + LegacyReporterRegistrar( std::string const& name ) { + getMutableRegistryHub().registerReporter( name, new ReporterFactory() ); + } + }; + + template + class ReporterRegistrar { + + class ReporterFactory : public SharedImpl { + + // *** Please Note ***: + // - If you end up here looking at a compiler error because it's trying to register + // your custom reporter class be aware that the native reporter interface has changed + // to IStreamingReporter. The "legacy" interface, IReporter, is still supported via + // an adapter. Just use REGISTER_LEGACY_REPORTER to take advantage of the adapter. + // However please consider updating to the new interface as the old one is now + // deprecated and will probably be removed quite soon! + // Please contact me via github if you have any questions at all about this. + // In fact, ideally, please contact me anyway to let me know you've hit this - as I have + // no idea who is actually using custom reporters at all (possibly no-one!). + // The new interface is designed to minimise exposure to interface changes in the future. + virtual IStreamingReporter* create( ReporterConfig const& config ) const { + return new T( config ); + } + + virtual std::string getDescription() const { + return T::getDescription(); + } + }; + + public: + + ReporterRegistrar( std::string const& name ) { + getMutableRegistryHub().registerReporter( name, new ReporterFactory() ); + } + }; + + template + class ListenerRegistrar { + + class ListenerFactory : public SharedImpl { + + virtual IStreamingReporter* create( ReporterConfig const& config ) const { + return new T( config ); + } + virtual std::string getDescription() const { + return ""; + } + }; + + public: + + ListenerRegistrar() { + getMutableRegistryHub().registerListener( new ListenerFactory() ); + } + }; +} + +#define INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) \ + namespace{ Catch::LegacyReporterRegistrar catch_internal_RegistrarFor##reporterType( name ); } + +#define INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) \ + namespace{ Catch::ReporterRegistrar catch_internal_RegistrarFor##reporterType( name ); } + +#define INTERNAL_CATCH_REGISTER_LISTENER( listenerType ) \ + namespace{ Catch::ListenerRegistrar catch_internal_RegistrarFor##listenerType; } + +// #included from: ../internal/catch_xmlwriter.hpp +#define TWOBLUECUBES_CATCH_XMLWRITER_HPP_INCLUDED + +#include +#include +#include +#include + +namespace Catch { + + class XmlEncode { + public: + enum ForWhat { ForTextNodes, ForAttributes }; + + XmlEncode( std::string const& str, ForWhat forWhat = ForTextNodes ) + : m_str( str ), + m_forWhat( forWhat ) + {} + + void encodeTo( std::ostream& os ) const { + + // Apostrophe escaping not necessary if we always use " to write attributes + // (see: http://www.w3.org/TR/xml/#syntax) + + for( std::size_t i = 0; i < m_str.size(); ++ i ) { + char c = m_str[i]; + switch( c ) { + case '<': os << "<"; break; + case '&': os << "&"; break; + + case '>': + // See: http://www.w3.org/TR/xml/#syntax + if( i > 2 && m_str[i-1] == ']' && m_str[i-2] == ']' ) + os << ">"; + else + os << c; + break; + + case '\"': + if( m_forWhat == ForAttributes ) + os << """; + else + os << c; + break; + + default: + // Escape control chars - based on contribution by @espenalb in PR #465 + if ( ( c < '\x09' ) || ( c > '\x0D' && c < '\x20') || c=='\x7F' ) + os << "&#x" << std::uppercase << std::hex << static_cast( c ); + else + os << c; + } + } + } + + friend std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ) { + xmlEncode.encodeTo( os ); + return os; + } + + private: + std::string m_str; + ForWhat m_forWhat; + }; + + class XmlWriter { + public: + + class ScopedElement { + public: + ScopedElement( XmlWriter* writer ) + : m_writer( writer ) + {} + + ScopedElement( ScopedElement const& other ) + : m_writer( other.m_writer ){ + other.m_writer = CATCH_NULL; + } + + ~ScopedElement() { + if( m_writer ) + m_writer->endElement(); + } + + ScopedElement& writeText( std::string const& text, bool indent = true ) { + m_writer->writeText( text, indent ); + return *this; + } + + template + ScopedElement& writeAttribute( std::string const& name, T const& attribute ) { + m_writer->writeAttribute( name, attribute ); + return *this; + } + + private: + mutable XmlWriter* m_writer; + }; + + XmlWriter() + : m_tagIsOpen( false ), + m_needsNewline( false ), + m_os( &Catch::cout() ) + {} + + XmlWriter( std::ostream& os ) + : m_tagIsOpen( false ), + m_needsNewline( false ), + m_os( &os ) + {} + + ~XmlWriter() { + while( !m_tags.empty() ) + endElement(); + } + + XmlWriter& startElement( std::string const& name ) { + ensureTagClosed(); + newlineIfNecessary(); + stream() << m_indent << "<" << name; + m_tags.push_back( name ); + m_indent += " "; + m_tagIsOpen = true; + return *this; + } + + ScopedElement scopedElement( std::string const& name ) { + ScopedElement scoped( this ); + startElement( name ); + return scoped; + } + + XmlWriter& endElement() { + newlineIfNecessary(); + m_indent = m_indent.substr( 0, m_indent.size()-2 ); + if( m_tagIsOpen ) { + stream() << "/>\n"; + m_tagIsOpen = false; + } + else { + stream() << m_indent << "\n"; + } + m_tags.pop_back(); + return *this; + } + + XmlWriter& writeAttribute( std::string const& name, std::string const& attribute ) { + if( !name.empty() && !attribute.empty() ) + stream() << " " << name << "=\"" << XmlEncode( attribute, XmlEncode::ForAttributes ) << "\""; + return *this; + } + + XmlWriter& writeAttribute( std::string const& name, bool attribute ) { + stream() << " " << name << "=\"" << ( attribute ? "true" : "false" ) << "\""; + return *this; + } + + template + XmlWriter& writeAttribute( std::string const& name, T const& attribute ) { + std::ostringstream oss; + oss << attribute; + return writeAttribute( name, oss.str() ); + } + + XmlWriter& writeText( std::string const& text, bool indent = true ) { + if( !text.empty() ){ + bool tagWasOpen = m_tagIsOpen; + ensureTagClosed(); + if( tagWasOpen && indent ) + stream() << m_indent; + stream() << XmlEncode( text ); + m_needsNewline = true; + } + return *this; + } + + XmlWriter& writeComment( std::string const& text ) { + ensureTagClosed(); + stream() << m_indent << ""; + m_needsNewline = true; + return *this; + } + + XmlWriter& writeBlankLine() { + ensureTagClosed(); + stream() << "\n"; + return *this; + } + + void setStream( std::ostream& os ) { + m_os = &os; + } + + private: + XmlWriter( XmlWriter const& ); + void operator=( XmlWriter const& ); + + std::ostream& stream() { + return *m_os; + } + + void ensureTagClosed() { + if( m_tagIsOpen ) { + stream() << ">\n"; + m_tagIsOpen = false; + } + } + + void newlineIfNecessary() { + if( m_needsNewline ) { + stream() << "\n"; + m_needsNewline = false; + } + } + + bool m_tagIsOpen; + bool m_needsNewline; + std::vector m_tags; + std::string m_indent; + std::ostream* m_os; + }; + +} +// #included from: catch_reenable_warnings.h + +#define TWOBLUECUBES_CATCH_REENABLE_WARNINGS_H_INCLUDED + +#ifdef __clang__ +# ifdef __ICC // icpc defines the __clang__ macro +# pragma warning(pop) +# else +# pragma clang diagnostic pop +# endif +#elif defined __GNUC__ +# pragma GCC diagnostic pop +#endif + + +namespace Catch { + class XmlReporter : public StreamingReporterBase { + public: + XmlReporter( ReporterConfig const& _config ) + : StreamingReporterBase( _config ), + m_sectionDepth( 0 ) + { + m_reporterPrefs.shouldRedirectStdOut = true; + } + + virtual ~XmlReporter() CATCH_OVERRIDE; + + static std::string getDescription() { + return "Reports test results as an XML document"; + } + + public: // StreamingReporterBase + + virtual void noMatchingTestCases( std::string const& s ) CATCH_OVERRIDE { + StreamingReporterBase::noMatchingTestCases( s ); + } + + virtual void testRunStarting( TestRunInfo const& testInfo ) CATCH_OVERRIDE { + StreamingReporterBase::testRunStarting( testInfo ); + m_xml.setStream( stream ); + m_xml.startElement( "Catch" ); + if( !m_config->name().empty() ) + m_xml.writeAttribute( "name", m_config->name() ); + } + + virtual void testGroupStarting( GroupInfo const& groupInfo ) CATCH_OVERRIDE { + StreamingReporterBase::testGroupStarting( groupInfo ); + m_xml.startElement( "Group" ) + .writeAttribute( "name", groupInfo.name ); + } + + virtual void testCaseStarting( TestCaseInfo const& testInfo ) CATCH_OVERRIDE { + StreamingReporterBase::testCaseStarting(testInfo); + m_xml.startElement( "TestCase" ).writeAttribute( "name", trim( testInfo.name ) ); + + if ( m_config->showDurations() == ShowDurations::Always ) + m_testCaseTimer.start(); + } + + virtual void sectionStarting( SectionInfo const& sectionInfo ) CATCH_OVERRIDE { + StreamingReporterBase::sectionStarting( sectionInfo ); + if( m_sectionDepth++ > 0 ) { + m_xml.startElement( "Section" ) + .writeAttribute( "name", trim( sectionInfo.name ) ) + .writeAttribute( "description", sectionInfo.description ); + } + } + + virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE { } + + virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE { + const AssertionResult& assertionResult = assertionStats.assertionResult; + + // Print any info messages in tags. + if( assertionStats.assertionResult.getResultType() != ResultWas::Ok ) { + for( std::vector::const_iterator it = assertionStats.infoMessages.begin(), itEnd = assertionStats.infoMessages.end(); + it != itEnd; + ++it ) { + if( it->type == ResultWas::Info ) { + m_xml.scopedElement( "Info" ) + .writeText( it->message ); + } else if ( it->type == ResultWas::Warning ) { + m_xml.scopedElement( "Warning" ) + .writeText( it->message ); + } + } + } + + // Drop out if result was successful but we're not printing them. + if( !m_config->includeSuccessfulResults() && isOk(assertionResult.getResultType()) ) + return true; + + // Print the expression if there is one. + if( assertionResult.hasExpression() ) { + m_xml.startElement( "Expression" ) + .writeAttribute( "success", assertionResult.succeeded() ) + .writeAttribute( "type", assertionResult.getTestMacroName() ) + .writeAttribute( "filename", assertionResult.getSourceInfo().file ) + .writeAttribute( "line", assertionResult.getSourceInfo().line ); + + m_xml.scopedElement( "Original" ) + .writeText( assertionResult.getExpression() ); + m_xml.scopedElement( "Expanded" ) + .writeText( assertionResult.getExpandedExpression() ); + } + + // And... Print a result applicable to each result type. + switch( assertionResult.getResultType() ) { + case ResultWas::ThrewException: + m_xml.scopedElement( "Exception" ) + .writeAttribute( "filename", assertionResult.getSourceInfo().file ) + .writeAttribute( "line", assertionResult.getSourceInfo().line ) + .writeText( assertionResult.getMessage() ); + break; + case ResultWas::FatalErrorCondition: + m_xml.scopedElement( "Fatal Error Condition" ) + .writeAttribute( "filename", assertionResult.getSourceInfo().file ) + .writeAttribute( "line", assertionResult.getSourceInfo().line ) + .writeText( assertionResult.getMessage() ); + break; + case ResultWas::Info: + m_xml.scopedElement( "Info" ) + .writeText( assertionResult.getMessage() ); + break; + case ResultWas::Warning: + // Warning will already have been written + break; + case ResultWas::ExplicitFailure: + m_xml.scopedElement( "Failure" ) + .writeText( assertionResult.getMessage() ); + break; + default: + break; + } + + if( assertionResult.hasExpression() ) + m_xml.endElement(); + + return true; + } + + virtual void sectionEnded( SectionStats const& sectionStats ) CATCH_OVERRIDE { + StreamingReporterBase::sectionEnded( sectionStats ); + if( --m_sectionDepth > 0 ) { + XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResults" ); + e.writeAttribute( "successes", sectionStats.assertions.passed ); + e.writeAttribute( "failures", sectionStats.assertions.failed ); + e.writeAttribute( "expectedFailures", sectionStats.assertions.failedButOk ); + + if ( m_config->showDurations() == ShowDurations::Always ) + e.writeAttribute( "durationInSeconds", sectionStats.durationInSeconds ); + + m_xml.endElement(); + } + } + + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE { + StreamingReporterBase::testCaseEnded( testCaseStats ); + XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResult" ); + e.writeAttribute( "success", testCaseStats.totals.assertions.allOk() ); + + if ( m_config->showDurations() == ShowDurations::Always ) + e.writeAttribute( "durationInSeconds", m_testCaseTimer.getElapsedSeconds() ); + + m_xml.endElement(); + } + + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE { + StreamingReporterBase::testGroupEnded( testGroupStats ); + // TODO: Check testGroupStats.aborting and act accordingly. + m_xml.scopedElement( "OverallResults" ) + .writeAttribute( "successes", testGroupStats.totals.assertions.passed ) + .writeAttribute( "failures", testGroupStats.totals.assertions.failed ) + .writeAttribute( "expectedFailures", testGroupStats.totals.assertions.failedButOk ); + m_xml.endElement(); + } + + virtual void testRunEnded( TestRunStats const& testRunStats ) CATCH_OVERRIDE { + StreamingReporterBase::testRunEnded( testRunStats ); + m_xml.scopedElement( "OverallResults" ) + .writeAttribute( "successes", testRunStats.totals.assertions.passed ) + .writeAttribute( "failures", testRunStats.totals.assertions.failed ) + .writeAttribute( "expectedFailures", testRunStats.totals.assertions.failedButOk ); + m_xml.endElement(); + } + + private: + Timer m_testCaseTimer; + XmlWriter m_xml; + int m_sectionDepth; + }; + + INTERNAL_CATCH_REGISTER_REPORTER( "xml", XmlReporter ) + +} // end namespace Catch + +// #included from: ../reporters/catch_reporter_junit.hpp +#define TWOBLUECUBES_CATCH_REPORTER_JUNIT_HPP_INCLUDED + +#include + +namespace Catch { + + class JunitReporter : public CumulativeReporterBase { + public: + JunitReporter( ReporterConfig const& _config ) + : CumulativeReporterBase( _config ), + xml( _config.stream() ) + { + m_reporterPrefs.shouldRedirectStdOut = true; + } + + virtual ~JunitReporter() CATCH_OVERRIDE; + + static std::string getDescription() { + return "Reports test results in an XML format that looks like Ant's junitreport target"; + } + + virtual void noMatchingTestCases( std::string const& /*spec*/ ) CATCH_OVERRIDE {} + + virtual void testRunStarting( TestRunInfo const& runInfo ) CATCH_OVERRIDE { + CumulativeReporterBase::testRunStarting( runInfo ); + xml.startElement( "testsuites" ); + } + + virtual void testGroupStarting( GroupInfo const& groupInfo ) CATCH_OVERRIDE { + suiteTimer.start(); + stdOutForSuite.str(""); + stdErrForSuite.str(""); + unexpectedExceptions = 0; + CumulativeReporterBase::testGroupStarting( groupInfo ); + } + + virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE { + if( assertionStats.assertionResult.getResultType() == ResultWas::ThrewException ) + unexpectedExceptions++; + return CumulativeReporterBase::assertionEnded( assertionStats ); + } + + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE { + stdOutForSuite << testCaseStats.stdOut; + stdErrForSuite << testCaseStats.stdErr; + CumulativeReporterBase::testCaseEnded( testCaseStats ); + } + + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE { + double suiteTime = suiteTimer.getElapsedSeconds(); + CumulativeReporterBase::testGroupEnded( testGroupStats ); + writeGroup( *m_testGroups.back(), suiteTime ); + } + + virtual void testRunEndedCumulative() CATCH_OVERRIDE { + xml.endElement(); + } + + void writeGroup( TestGroupNode const& groupNode, double suiteTime ) { + XmlWriter::ScopedElement e = xml.scopedElement( "testsuite" ); + TestGroupStats const& stats = groupNode.value; + xml.writeAttribute( "name", stats.groupInfo.name ); + xml.writeAttribute( "errors", unexpectedExceptions ); + xml.writeAttribute( "failures", stats.totals.assertions.failed-unexpectedExceptions ); + xml.writeAttribute( "tests", stats.totals.assertions.total() ); + xml.writeAttribute( "hostname", "tbd" ); // !TBD + if( m_config->showDurations() == ShowDurations::Never ) + xml.writeAttribute( "time", "" ); + else + xml.writeAttribute( "time", suiteTime ); + xml.writeAttribute( "timestamp", "tbd" ); // !TBD + + // Write test cases + for( TestGroupNode::ChildNodes::const_iterator + it = groupNode.children.begin(), itEnd = groupNode.children.end(); + it != itEnd; + ++it ) + writeTestCase( **it ); + + xml.scopedElement( "system-out" ).writeText( trim( stdOutForSuite.str() ), false ); + xml.scopedElement( "system-err" ).writeText( trim( stdErrForSuite.str() ), false ); + } + + void writeTestCase( TestCaseNode const& testCaseNode ) { + TestCaseStats const& stats = testCaseNode.value; + + // All test cases have exactly one section - which represents the + // test case itself. That section may have 0-n nested sections + assert( testCaseNode.children.size() == 1 ); + SectionNode const& rootSection = *testCaseNode.children.front(); + + std::string className = stats.testInfo.className; + + if( className.empty() ) { + if( rootSection.childSections.empty() ) + className = "global"; + } + writeSection( className, "", rootSection ); + } + + void writeSection( std::string const& className, + std::string const& rootName, + SectionNode const& sectionNode ) { + std::string name = trim( sectionNode.stats.sectionInfo.name ); + if( !rootName.empty() ) + name = rootName + "/" + name; + + if( !sectionNode.assertions.empty() || + !sectionNode.stdOut.empty() || + !sectionNode.stdErr.empty() ) { + XmlWriter::ScopedElement e = xml.scopedElement( "testcase" ); + if( className.empty() ) { + xml.writeAttribute( "classname", name ); + xml.writeAttribute( "name", "root" ); + } + else { + xml.writeAttribute( "classname", className ); + xml.writeAttribute( "name", name ); + } + xml.writeAttribute( "time", Catch::toString( sectionNode.stats.durationInSeconds ) ); + + writeAssertions( sectionNode ); + + if( !sectionNode.stdOut.empty() ) + xml.scopedElement( "system-out" ).writeText( trim( sectionNode.stdOut ), false ); + if( !sectionNode.stdErr.empty() ) + xml.scopedElement( "system-err" ).writeText( trim( sectionNode.stdErr ), false ); + } + for( SectionNode::ChildSections::const_iterator + it = sectionNode.childSections.begin(), + itEnd = sectionNode.childSections.end(); + it != itEnd; + ++it ) + if( className.empty() ) + writeSection( name, "", **it ); + else + writeSection( className, name, **it ); + } + + void writeAssertions( SectionNode const& sectionNode ) { + for( SectionNode::Assertions::const_iterator + it = sectionNode.assertions.begin(), itEnd = sectionNode.assertions.end(); + it != itEnd; + ++it ) + writeAssertion( *it ); + } + void writeAssertion( AssertionStats const& stats ) { + AssertionResult const& result = stats.assertionResult; + if( !result.isOk() ) { + std::string elementName; + switch( result.getResultType() ) { + case ResultWas::ThrewException: + case ResultWas::FatalErrorCondition: + elementName = "error"; + break; + case ResultWas::ExplicitFailure: + elementName = "failure"; + break; + case ResultWas::ExpressionFailed: + elementName = "failure"; + break; + case ResultWas::DidntThrowException: + elementName = "failure"; + break; + + // We should never see these here: + case ResultWas::Info: + case ResultWas::Warning: + case ResultWas::Ok: + case ResultWas::Unknown: + case ResultWas::FailureBit: + case ResultWas::Exception: + elementName = "internalError"; + break; + } + + XmlWriter::ScopedElement e = xml.scopedElement( elementName ); + + xml.writeAttribute( "message", result.getExpandedExpression() ); + xml.writeAttribute( "type", result.getTestMacroName() ); + + std::ostringstream oss; + if( !result.getMessage().empty() ) + oss << result.getMessage() << "\n"; + for( std::vector::const_iterator + it = stats.infoMessages.begin(), + itEnd = stats.infoMessages.end(); + it != itEnd; + ++it ) + if( it->type == ResultWas::Info ) + oss << it->message << "\n"; + + oss << "at " << result.getSourceInfo(); + xml.writeText( oss.str(), false ); + } + } + + XmlWriter xml; + Timer suiteTimer; + std::ostringstream stdOutForSuite; + std::ostringstream stdErrForSuite; + unsigned int unexpectedExceptions; + }; + + INTERNAL_CATCH_REGISTER_REPORTER( "junit", JunitReporter ) + +} // end namespace Catch + +// #included from: ../reporters/catch_reporter_console.hpp +#define TWOBLUECUBES_CATCH_REPORTER_CONSOLE_HPP_INCLUDED + +namespace Catch { + + struct ConsoleReporter : StreamingReporterBase { + ConsoleReporter( ReporterConfig const& _config ) + : StreamingReporterBase( _config ), + m_headerPrinted( false ) + {} + + virtual ~ConsoleReporter() CATCH_OVERRIDE; + static std::string getDescription() { + return "Reports test results as plain lines of text"; + } + + virtual void noMatchingTestCases( std::string const& spec ) CATCH_OVERRIDE { + stream << "No test cases matched '" << spec << "'" << std::endl; + } + + virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE { + } + + virtual bool assertionEnded( AssertionStats const& _assertionStats ) CATCH_OVERRIDE { + AssertionResult const& result = _assertionStats.assertionResult; + + bool printInfoMessages = true; + + // Drop out if result was successful and we're not printing those + if( !m_config->includeSuccessfulResults() && result.isOk() ) { + if( result.getResultType() != ResultWas::Warning ) + return false; + printInfoMessages = false; + } + + lazyPrint(); + + AssertionPrinter printer( stream, _assertionStats, printInfoMessages ); + printer.print(); + stream << std::endl; + return true; + } + + virtual void sectionStarting( SectionInfo const& _sectionInfo ) CATCH_OVERRIDE { + m_headerPrinted = false; + StreamingReporterBase::sectionStarting( _sectionInfo ); + } + virtual void sectionEnded( SectionStats const& _sectionStats ) CATCH_OVERRIDE { + if( _sectionStats.missingAssertions ) { + lazyPrint(); + Colour colour( Colour::ResultError ); + if( m_sectionStack.size() > 1 ) + stream << "\nNo assertions in section"; + else + stream << "\nNo assertions in test case"; + stream << " '" << _sectionStats.sectionInfo.name << "'\n" << std::endl; + } + if( m_headerPrinted ) { + if( m_config->showDurations() == ShowDurations::Always ) + stream << "Completed in " << _sectionStats.durationInSeconds << "s" << std::endl; + m_headerPrinted = false; + } + else { + if( m_config->showDurations() == ShowDurations::Always ) + stream << _sectionStats.sectionInfo.name << " completed in " << _sectionStats.durationInSeconds << "s" << std::endl; + } + StreamingReporterBase::sectionEnded( _sectionStats ); + } + + virtual void testCaseEnded( TestCaseStats const& _testCaseStats ) CATCH_OVERRIDE { + StreamingReporterBase::testCaseEnded( _testCaseStats ); + m_headerPrinted = false; + } + virtual void testGroupEnded( TestGroupStats const& _testGroupStats ) CATCH_OVERRIDE { + if( currentGroupInfo.used ) { + printSummaryDivider(); + stream << "Summary for group '" << _testGroupStats.groupInfo.name << "':\n"; + printTotals( _testGroupStats.totals ); + stream << "\n" << std::endl; + } + StreamingReporterBase::testGroupEnded( _testGroupStats ); + } + virtual void testRunEnded( TestRunStats const& _testRunStats ) CATCH_OVERRIDE { + printTotalsDivider( _testRunStats.totals ); + printTotals( _testRunStats.totals ); + stream << std::endl; + StreamingReporterBase::testRunEnded( _testRunStats ); + } + + private: + + class AssertionPrinter { + void operator= ( AssertionPrinter const& ); + public: + AssertionPrinter( std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages ) + : stream( _stream ), + stats( _stats ), + result( _stats.assertionResult ), + colour( Colour::None ), + message( result.getMessage() ), + messages( _stats.infoMessages ), + printInfoMessages( _printInfoMessages ) + { + switch( result.getResultType() ) { + case ResultWas::Ok: + colour = Colour::Success; + passOrFail = "PASSED"; + //if( result.hasMessage() ) + if( _stats.infoMessages.size() == 1 ) + messageLabel = "with message"; + if( _stats.infoMessages.size() > 1 ) + messageLabel = "with messages"; + break; + case ResultWas::ExpressionFailed: + if( result.isOk() ) { + colour = Colour::Success; + passOrFail = "FAILED - but was ok"; + } + else { + colour = Colour::Error; + passOrFail = "FAILED"; + } + if( _stats.infoMessages.size() == 1 ) + messageLabel = "with message"; + if( _stats.infoMessages.size() > 1 ) + messageLabel = "with messages"; + break; + case ResultWas::ThrewException: + colour = Colour::Error; + passOrFail = "FAILED"; + messageLabel = "due to unexpected exception with message"; + break; + case ResultWas::FatalErrorCondition: + colour = Colour::Error; + passOrFail = "FAILED"; + messageLabel = "due to a fatal error condition"; + break; + case ResultWas::DidntThrowException: + colour = Colour::Error; + passOrFail = "FAILED"; + messageLabel = "because no exception was thrown where one was expected"; + break; + case ResultWas::Info: + messageLabel = "info"; + break; + case ResultWas::Warning: + messageLabel = "warning"; + break; + case ResultWas::ExplicitFailure: + passOrFail = "FAILED"; + colour = Colour::Error; + if( _stats.infoMessages.size() == 1 ) + messageLabel = "explicitly with message"; + if( _stats.infoMessages.size() > 1 ) + messageLabel = "explicitly with messages"; + break; + // These cases are here to prevent compiler warnings + case ResultWas::Unknown: + case ResultWas::FailureBit: + case ResultWas::Exception: + passOrFail = "** internal error **"; + colour = Colour::Error; + break; + } + } + + void print() const { + printSourceInfo(); + if( stats.totals.assertions.total() > 0 ) { + if( result.isOk() ) + stream << "\n"; + printResultType(); + printOriginalExpression(); + printReconstructedExpression(); + } + else { + stream << "\n"; + } + printMessage(); + } + + private: + void printResultType() const { + if( !passOrFail.empty() ) { + Colour colourGuard( colour ); + stream << passOrFail << ":\n"; + } + } + void printOriginalExpression() const { + if( result.hasExpression() ) { + Colour colourGuard( Colour::OriginalExpression ); + stream << " "; + stream << result.getExpressionInMacro(); + stream << "\n"; + } + } + void printReconstructedExpression() const { + if( result.hasExpandedExpression() ) { + stream << "with expansion:\n"; + Colour colourGuard( Colour::ReconstructedExpression ); + stream << Text( result.getExpandedExpression(), TextAttributes().setIndent(2) ) << "\n"; + } + } + void printMessage() const { + if( !messageLabel.empty() ) + stream << messageLabel << ":" << "\n"; + for( std::vector::const_iterator it = messages.begin(), itEnd = messages.end(); + it != itEnd; + ++it ) { + // If this assertion is a warning ignore any INFO messages + if( printInfoMessages || it->type != ResultWas::Info ) + stream << Text( it->message, TextAttributes().setIndent(2) ) << "\n"; + } + } + void printSourceInfo() const { + Colour colourGuard( Colour::FileName ); + stream << result.getSourceInfo() << ": "; + } + + std::ostream& stream; + AssertionStats const& stats; + AssertionResult const& result; + Colour::Code colour; + std::string passOrFail; + std::string messageLabel; + std::string message; + std::vector messages; + bool printInfoMessages; + }; + + void lazyPrint() { + + if( !currentTestRunInfo.used ) + lazyPrintRunInfo(); + if( !currentGroupInfo.used ) + lazyPrintGroupInfo(); + + if( !m_headerPrinted ) { + printTestCaseAndSectionHeader(); + m_headerPrinted = true; + } + } + void lazyPrintRunInfo() { + stream << "\n" << getLineOfChars<'~'>() << "\n"; + Colour colour( Colour::SecondaryText ); + stream << currentTestRunInfo->name + << " is a Catch v" << libraryVersion << " host application.\n" + << "Run with -? for options\n\n"; + + if( m_config->rngSeed() != 0 ) + stream << "Randomness seeded to: " << m_config->rngSeed() << "\n\n"; + + currentTestRunInfo.used = true; + } + void lazyPrintGroupInfo() { + if( !currentGroupInfo->name.empty() && currentGroupInfo->groupsCounts > 1 ) { + printClosedHeader( "Group: " + currentGroupInfo->name ); + currentGroupInfo.used = true; + } + } + void printTestCaseAndSectionHeader() { + assert( !m_sectionStack.empty() ); + printOpenHeader( currentTestCaseInfo->name ); + + if( m_sectionStack.size() > 1 ) { + Colour colourGuard( Colour::Headers ); + + std::vector::const_iterator + it = m_sectionStack.begin()+1, // Skip first section (test case) + itEnd = m_sectionStack.end(); + for( ; it != itEnd; ++it ) + printHeaderString( it->name, 2 ); + } + + SourceLineInfo lineInfo = m_sectionStack.front().lineInfo; + + if( !lineInfo.empty() ){ + stream << getLineOfChars<'-'>() << "\n"; + Colour colourGuard( Colour::FileName ); + stream << lineInfo << "\n"; + } + stream << getLineOfChars<'.'>() << "\n" << std::endl; + } + + void printClosedHeader( std::string const& _name ) { + printOpenHeader( _name ); + stream << getLineOfChars<'.'>() << "\n"; + } + void printOpenHeader( std::string const& _name ) { + stream << getLineOfChars<'-'>() << "\n"; + { + Colour colourGuard( Colour::Headers ); + printHeaderString( _name ); + } + } + + // if string has a : in first line will set indent to follow it on + // subsequent lines + void printHeaderString( std::string const& _string, std::size_t indent = 0 ) { + std::size_t i = _string.find( ": " ); + if( i != std::string::npos ) + i+=2; + else + i = 0; + stream << Text( _string, TextAttributes() + .setIndent( indent+i) + .setInitialIndent( indent ) ) << "\n"; + } + + struct SummaryColumn { + + SummaryColumn( std::string const& _label, Colour::Code _colour ) + : label( _label ), + colour( _colour ) + {} + SummaryColumn addRow( std::size_t count ) { + std::ostringstream oss; + oss << count; + std::string row = oss.str(); + for( std::vector::iterator it = rows.begin(); it != rows.end(); ++it ) { + while( it->size() < row.size() ) + *it = " " + *it; + while( it->size() > row.size() ) + row = " " + row; + } + rows.push_back( row ); + return *this; + } + + std::string label; + Colour::Code colour; + std::vector rows; + + }; + + void printTotals( Totals const& totals ) { + if( totals.testCases.total() == 0 ) { + stream << Colour( Colour::Warning ) << "No tests ran\n"; + } + else if( totals.assertions.total() > 0 && totals.assertions.allPassed() ) { + stream << Colour( Colour::ResultSuccess ) << "All tests passed"; + stream << " (" + << pluralise( totals.assertions.passed, "assertion" ) << " in " + << pluralise( totals.testCases.passed, "test case" ) << ")" + << "\n"; + } + else { + + std::vector columns; + columns.push_back( SummaryColumn( "", Colour::None ) + .addRow( totals.testCases.total() ) + .addRow( totals.assertions.total() ) ); + columns.push_back( SummaryColumn( "passed", Colour::Success ) + .addRow( totals.testCases.passed ) + .addRow( totals.assertions.passed ) ); + columns.push_back( SummaryColumn( "failed", Colour::ResultError ) + .addRow( totals.testCases.failed ) + .addRow( totals.assertions.failed ) ); + columns.push_back( SummaryColumn( "failed as expected", Colour::ResultExpectedFailure ) + .addRow( totals.testCases.failedButOk ) + .addRow( totals.assertions.failedButOk ) ); + + printSummaryRow( "test cases", columns, 0 ); + printSummaryRow( "assertions", columns, 1 ); + } + } + void printSummaryRow( std::string const& label, std::vector const& cols, std::size_t row ) { + for( std::vector::const_iterator it = cols.begin(); it != cols.end(); ++it ) { + std::string value = it->rows[row]; + if( it->label.empty() ) { + stream << label << ": "; + if( value != "0" ) + stream << value; + else + stream << Colour( Colour::Warning ) << "- none -"; + } + else if( value != "0" ) { + stream << Colour( Colour::LightGrey ) << " | "; + stream << Colour( it->colour ) + << value << " " << it->label; + } + } + stream << "\n"; + } + + static std::size_t makeRatio( std::size_t number, std::size_t total ) { + std::size_t ratio = total > 0 ? CATCH_CONFIG_CONSOLE_WIDTH * number/ total : 0; + return ( ratio == 0 && number > 0 ) ? 1 : ratio; + } + static std::size_t& findMax( std::size_t& i, std::size_t& j, std::size_t& k ) { + if( i > j && i > k ) + return i; + else if( j > k ) + return j; + else + return k; + } + + void printTotalsDivider( Totals const& totals ) { + if( totals.testCases.total() > 0 ) { + std::size_t failedRatio = makeRatio( totals.testCases.failed, totals.testCases.total() ); + std::size_t failedButOkRatio = makeRatio( totals.testCases.failedButOk, totals.testCases.total() ); + std::size_t passedRatio = makeRatio( totals.testCases.passed, totals.testCases.total() ); + while( failedRatio + failedButOkRatio + passedRatio < CATCH_CONFIG_CONSOLE_WIDTH-1 ) + findMax( failedRatio, failedButOkRatio, passedRatio )++; + while( failedRatio + failedButOkRatio + passedRatio > CATCH_CONFIG_CONSOLE_WIDTH-1 ) + findMax( failedRatio, failedButOkRatio, passedRatio )--; + + stream << Colour( Colour::Error ) << std::string( failedRatio, '=' ); + stream << Colour( Colour::ResultExpectedFailure ) << std::string( failedButOkRatio, '=' ); + if( totals.testCases.allPassed() ) + stream << Colour( Colour::ResultSuccess ) << std::string( passedRatio, '=' ); + else + stream << Colour( Colour::Success ) << std::string( passedRatio, '=' ); + } + else { + stream << Colour( Colour::Warning ) << std::string( CATCH_CONFIG_CONSOLE_WIDTH-1, '=' ); + } + stream << "\n"; + } + void printSummaryDivider() { + stream << getLineOfChars<'-'>() << "\n"; + } + + private: + bool m_headerPrinted; + }; + + INTERNAL_CATCH_REGISTER_REPORTER( "console", ConsoleReporter ) + +} // end namespace Catch + +// #included from: ../reporters/catch_reporter_compact.hpp +#define TWOBLUECUBES_CATCH_REPORTER_COMPACT_HPP_INCLUDED + +namespace Catch { + + struct CompactReporter : StreamingReporterBase { + + CompactReporter( ReporterConfig const& _config ) + : StreamingReporterBase( _config ) + {} + + virtual ~CompactReporter(); + + static std::string getDescription() { + return "Reports test results on a single line, suitable for IDEs"; + } + + virtual ReporterPreferences getPreferences() const { + ReporterPreferences prefs; + prefs.shouldRedirectStdOut = false; + return prefs; + } + + virtual void noMatchingTestCases( std::string const& spec ) { + stream << "No test cases matched '" << spec << "'" << std::endl; + } + + virtual void assertionStarting( AssertionInfo const& ) { + } + + virtual bool assertionEnded( AssertionStats const& _assertionStats ) { + AssertionResult const& result = _assertionStats.assertionResult; + + bool printInfoMessages = true; + + // Drop out if result was successful and we're not printing those + if( !m_config->includeSuccessfulResults() && result.isOk() ) { + if( result.getResultType() != ResultWas::Warning ) + return false; + printInfoMessages = false; + } + + AssertionPrinter printer( stream, _assertionStats, printInfoMessages ); + printer.print(); + + stream << std::endl; + return true; + } + + virtual void testRunEnded( TestRunStats const& _testRunStats ) { + printTotals( _testRunStats.totals ); + stream << "\n" << std::endl; + StreamingReporterBase::testRunEnded( _testRunStats ); + } + + private: + class AssertionPrinter { + void operator= ( AssertionPrinter const& ); + public: + AssertionPrinter( std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages ) + : stream( _stream ) + , stats( _stats ) + , result( _stats.assertionResult ) + , messages( _stats.infoMessages ) + , itMessage( _stats.infoMessages.begin() ) + , printInfoMessages( _printInfoMessages ) + {} + + void print() { + printSourceInfo(); + + itMessage = messages.begin(); + + switch( result.getResultType() ) { + case ResultWas::Ok: + printResultType( Colour::ResultSuccess, passedString() ); + printOriginalExpression(); + printReconstructedExpression(); + if ( ! result.hasExpression() ) + printRemainingMessages( Colour::None ); + else + printRemainingMessages(); + break; + case ResultWas::ExpressionFailed: + if( result.isOk() ) + printResultType( Colour::ResultSuccess, failedString() + std::string( " - but was ok" ) ); + else + printResultType( Colour::Error, failedString() ); + printOriginalExpression(); + printReconstructedExpression(); + printRemainingMessages(); + break; + case ResultWas::ThrewException: + printResultType( Colour::Error, failedString() ); + printIssue( "unexpected exception with message:" ); + printMessage(); + printExpressionWas(); + printRemainingMessages(); + break; + case ResultWas::FatalErrorCondition: + printResultType( Colour::Error, failedString() ); + printIssue( "fatal error condition with message:" ); + printMessage(); + printExpressionWas(); + printRemainingMessages(); + break; + case ResultWas::DidntThrowException: + printResultType( Colour::Error, failedString() ); + printIssue( "expected exception, got none" ); + printExpressionWas(); + printRemainingMessages(); + break; + case ResultWas::Info: + printResultType( Colour::None, "info" ); + printMessage(); + printRemainingMessages(); + break; + case ResultWas::Warning: + printResultType( Colour::None, "warning" ); + printMessage(); + printRemainingMessages(); + break; + case ResultWas::ExplicitFailure: + printResultType( Colour::Error, failedString() ); + printIssue( "explicitly" ); + printRemainingMessages( Colour::None ); + break; + // These cases are here to prevent compiler warnings + case ResultWas::Unknown: + case ResultWas::FailureBit: + case ResultWas::Exception: + printResultType( Colour::Error, "** internal error **" ); + break; + } + } + + private: + // Colour::LightGrey + + static Colour::Code dimColour() { return Colour::FileName; } + +#ifdef CATCH_PLATFORM_MAC + static const char* failedString() { return "FAILED"; } + static const char* passedString() { return "PASSED"; } +#else + static const char* failedString() { return "failed"; } + static const char* passedString() { return "passed"; } +#endif + + void printSourceInfo() const { + Colour colourGuard( Colour::FileName ); + stream << result.getSourceInfo() << ":"; + } + + void printResultType( Colour::Code colour, std::string passOrFail ) const { + if( !passOrFail.empty() ) { + { + Colour colourGuard( colour ); + stream << " " << passOrFail; + } + stream << ":"; + } + } + + void printIssue( std::string issue ) const { + stream << " " << issue; + } + + void printExpressionWas() { + if( result.hasExpression() ) { + stream << ";"; + { + Colour colour( dimColour() ); + stream << " expression was:"; + } + printOriginalExpression(); + } + } + + void printOriginalExpression() const { + if( result.hasExpression() ) { + stream << " " << result.getExpression(); + } + } + + void printReconstructedExpression() const { + if( result.hasExpandedExpression() ) { + { + Colour colour( dimColour() ); + stream << " for: "; + } + stream << result.getExpandedExpression(); + } + } + + void printMessage() { + if ( itMessage != messages.end() ) { + stream << " '" << itMessage->message << "'"; + ++itMessage; + } + } + + void printRemainingMessages( Colour::Code colour = dimColour() ) { + if ( itMessage == messages.end() ) + return; + + // using messages.end() directly yields compilation error: + std::vector::const_iterator itEnd = messages.end(); + const std::size_t N = static_cast( std::distance( itMessage, itEnd ) ); + + { + Colour colourGuard( colour ); + stream << " with " << pluralise( N, "message" ) << ":"; + } + + for(; itMessage != itEnd; ) { + // If this assertion is a warning ignore any INFO messages + if( printInfoMessages || itMessage->type != ResultWas::Info ) { + stream << " '" << itMessage->message << "'"; + if ( ++itMessage != itEnd ) { + Colour colourGuard( dimColour() ); + stream << " and"; + } + } + } + } + + private: + std::ostream& stream; + AssertionStats const& stats; + AssertionResult const& result; + std::vector messages; + std::vector::const_iterator itMessage; + bool printInfoMessages; + }; + + // Colour, message variants: + // - white: No tests ran. + // - red: Failed [both/all] N test cases, failed [both/all] M assertions. + // - white: Passed [both/all] N test cases (no assertions). + // - red: Failed N tests cases, failed M assertions. + // - green: Passed [both/all] N tests cases with M assertions. + + std::string bothOrAll( std::size_t count ) const { + return count == 1 ? "" : count == 2 ? "both " : "all " ; + } + + void printTotals( const Totals& totals ) const { + if( totals.testCases.total() == 0 ) { + stream << "No tests ran."; + } + else if( totals.testCases.failed == totals.testCases.total() ) { + Colour colour( Colour::ResultError ); + const std::string qualify_assertions_failed = + totals.assertions.failed == totals.assertions.total() ? + bothOrAll( totals.assertions.failed ) : ""; + stream << + "Failed " << bothOrAll( totals.testCases.failed ) + << pluralise( totals.testCases.failed, "test case" ) << ", " + "failed " << qualify_assertions_failed << + pluralise( totals.assertions.failed, "assertion" ) << "."; + } + else if( totals.assertions.total() == 0 ) { + stream << + "Passed " << bothOrAll( totals.testCases.total() ) + << pluralise( totals.testCases.total(), "test case" ) + << " (no assertions)."; + } + else if( totals.assertions.failed ) { + Colour colour( Colour::ResultError ); + stream << + "Failed " << pluralise( totals.testCases.failed, "test case" ) << ", " + "failed " << pluralise( totals.assertions.failed, "assertion" ) << "."; + } + else { + Colour colour( Colour::ResultSuccess ); + stream << + "Passed " << bothOrAll( totals.testCases.passed ) + << pluralise( totals.testCases.passed, "test case" ) << + " with " << pluralise( totals.assertions.passed, "assertion" ) << "."; + } + } + }; + + INTERNAL_CATCH_REGISTER_REPORTER( "compact", CompactReporter ) + +} // end namespace Catch + +namespace Catch { + // These are all here to avoid warnings about not having any out of line + // virtual methods + NonCopyable::~NonCopyable() {} + IShared::~IShared() {} + IStream::~IStream() CATCH_NOEXCEPT {} + FileStream::~FileStream() CATCH_NOEXCEPT {} + CoutStream::~CoutStream() CATCH_NOEXCEPT {} + DebugOutStream::~DebugOutStream() CATCH_NOEXCEPT {} + StreamBufBase::~StreamBufBase() CATCH_NOEXCEPT {} + IContext::~IContext() {} + IResultCapture::~IResultCapture() {} + ITestCase::~ITestCase() {} + ITestCaseRegistry::~ITestCaseRegistry() {} + IRegistryHub::~IRegistryHub() {} + IMutableRegistryHub::~IMutableRegistryHub() {} + IExceptionTranslator::~IExceptionTranslator() {} + IExceptionTranslatorRegistry::~IExceptionTranslatorRegistry() {} + IReporter::~IReporter() {} + IReporterFactory::~IReporterFactory() {} + IReporterRegistry::~IReporterRegistry() {} + IStreamingReporter::~IStreamingReporter() {} + AssertionStats::~AssertionStats() {} + SectionStats::~SectionStats() {} + TestCaseStats::~TestCaseStats() {} + TestGroupStats::~TestGroupStats() {} + TestRunStats::~TestRunStats() {} + CumulativeReporterBase::SectionNode::~SectionNode() {} + CumulativeReporterBase::~CumulativeReporterBase() {} + + StreamingReporterBase::~StreamingReporterBase() {} + ConsoleReporter::~ConsoleReporter() {} + CompactReporter::~CompactReporter() {} + IRunner::~IRunner() {} + IMutableContext::~IMutableContext() {} + IConfig::~IConfig() {} + XmlReporter::~XmlReporter() {} + JunitReporter::~JunitReporter() {} + TestRegistry::~TestRegistry() {} + FreeFunctionTestCase::~FreeFunctionTestCase() {} + IGeneratorInfo::~IGeneratorInfo() {} + IGeneratorsForTest::~IGeneratorsForTest() {} + WildcardPattern::~WildcardPattern() {} + TestSpec::Pattern::~Pattern() {} + TestSpec::NamePattern::~NamePattern() {} + TestSpec::TagPattern::~TagPattern() {} + TestSpec::ExcludedPattern::~ExcludedPattern() {} + + Matchers::Impl::StdString::Equals::~Equals() {} + Matchers::Impl::StdString::Contains::~Contains() {} + Matchers::Impl::StdString::StartsWith::~StartsWith() {} + Matchers::Impl::StdString::EndsWith::~EndsWith() {} + + void Config::dummy() {} + + namespace TestCaseTracking { + ITracker::~ITracker() {} + TrackerBase::~TrackerBase() {} + SectionTracker::~SectionTracker() {} + IndexTracker::~IndexTracker() {} + } +} + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +#endif + +#ifdef CATCH_CONFIG_MAIN +// #included from: internal/catch_default_main.hpp +#define TWOBLUECUBES_CATCH_DEFAULT_MAIN_HPP_INCLUDED + +#ifndef __OBJC__ + +// Standard C/C++ main entry point +int main (int argc, char * argv[]) { + return Catch::Session().run( argc, argv ); +} + +#else // __OBJC__ + +// Objective-C entry point +int main (int argc, char * const argv[]) { +#if !CATCH_ARC_ENABLED + NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; +#endif + + Catch::registerTestMethods(); + int result = Catch::Session().run( argc, (char* const*)argv ); + +#if !CATCH_ARC_ENABLED + [pool drain]; +#endif + + return result; +} + +#endif // __OBJC__ + +#endif + +#ifdef CLARA_CONFIG_MAIN_NOT_DEFINED +# undef CLARA_CONFIG_MAIN +#endif + +////// + +// If this config identifier is defined then all CATCH macros are prefixed with CATCH_ +#ifdef CATCH_CONFIG_PREFIX_ALL + +#define CATCH_REQUIRE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE" ) +#define CATCH_REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, "CATCH_REQUIRE_FALSE" ) + +#define CATCH_REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, "", "CATCH_REQUIRE_THROWS" ) +#define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THROWS_AS" ) +#define CATCH_REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, matcher, "CATCH_REQUIRE_THROWS_WITH" ) +#define CATCH_REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_NOTHROW" ) + +#define CATCH_CHECK( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK" ) +#define CATCH_CHECK_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, "CATCH_CHECK_FALSE" ) +#define CATCH_CHECKED_IF( expr ) INTERNAL_CATCH_IF( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECKED_IF" ) +#define CATCH_CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECKED_ELSE" ) +#define CATCH_CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, "CATCH_CHECK_NOFAIL" ) + +#define CATCH_CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THROWS" ) +#define CATCH_CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THROWS_AS" ) +#define CATCH_CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, matcher, "CATCH_CHECK_THROWS_WITH" ) +#define CATCH_CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_NOTHROW" ) + +#define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THAT" ) +#define CATCH_REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THAT" ) + +#define CATCH_INFO( msg ) INTERNAL_CATCH_INFO( msg, "CATCH_INFO" ) +#define CATCH_WARN( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, "CATCH_WARN", msg ) +#define CATCH_SCOPED_INFO( msg ) INTERNAL_CATCH_INFO( msg, "CATCH_INFO" ) +#define CATCH_CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CATCH_CAPTURE" ) +#define CATCH_SCOPED_CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CATCH_CAPTURE" ) + +#ifdef CATCH_CONFIG_VARIADIC_MACROS + #define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ ) + #define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ ) + #define CATCH_METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ ) + #define CATCH_REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ ) + #define CATCH_SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) + #define CATCH_FAIL( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "CATCH_FAIL", __VA_ARGS__ ) + #define CATCH_SUCCEED( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "CATCH_SUCCEED", __VA_ARGS__ ) +#else + #define CATCH_TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description ) + #define CATCH_TEST_CASE_METHOD( className, name, description ) INTERNAL_CATCH_TEST_CASE_METHOD( className, name, description ) + #define CATCH_METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description ) + #define CATCH_REGISTER_TEST_CASE( function, name, description ) INTERNAL_CATCH_REGISTER_TESTCASE( function, name, description ) + #define CATCH_SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description ) + #define CATCH_FAIL( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "CATCH_FAIL", msg ) + #define CATCH_SUCCEED( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "CATCH_SUCCEED", msg ) +#endif +#define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE( "", "" ) + +#define CATCH_REGISTER_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) +#define CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) + +#define CATCH_GENERATE( expr) INTERNAL_CATCH_GENERATE( expr ) + +// "BDD-style" convenience wrappers +#ifdef CATCH_CONFIG_VARIADIC_MACROS +#define CATCH_SCENARIO( ... ) CATCH_TEST_CASE( "Scenario: " __VA_ARGS__ ) +#define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ ) +#else +#define CATCH_SCENARIO( name, tags ) CATCH_TEST_CASE( "Scenario: " name, tags ) +#define CATCH_SCENARIO_METHOD( className, name, tags ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " name, tags ) +#endif +#define CATCH_GIVEN( desc ) CATCH_SECTION( std::string( "Given: ") + desc, "" ) +#define CATCH_WHEN( desc ) CATCH_SECTION( std::string( " When: ") + desc, "" ) +#define CATCH_AND_WHEN( desc ) CATCH_SECTION( std::string( " And: ") + desc, "" ) +#define CATCH_THEN( desc ) CATCH_SECTION( std::string( " Then: ") + desc, "" ) +#define CATCH_AND_THEN( desc ) CATCH_SECTION( std::string( " And: ") + desc, "" ) + +// If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required +#else + +#define REQUIRE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal, "REQUIRE" ) +#define REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, "REQUIRE_FALSE" ) + +#define REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, "", "REQUIRE_THROWS" ) +#define REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::Normal, "REQUIRE_THROWS_AS" ) +#define REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, matcher, "REQUIRE_THROWS_WITH" ) +#define REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::Normal, "REQUIRE_NOTHROW" ) + +#define CHECK( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK" ) +#define CHECK_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, "CHECK_FALSE" ) +#define CHECKED_IF( expr ) INTERNAL_CATCH_IF( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECKED_IF" ) +#define CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECKED_ELSE" ) +#define CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, "CHECK_NOFAIL" ) + +#define CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, "", "CHECK_THROWS" ) +#define CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THROWS_AS" ) +#define CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, matcher, "CHECK_THROWS_WITH" ) +#define CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK_NOTHROW" ) + +#define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THAT" ) +#define REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::Normal, "REQUIRE_THAT" ) + +#define INFO( msg ) INTERNAL_CATCH_INFO( msg, "INFO" ) +#define WARN( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, "WARN", msg ) +#define SCOPED_INFO( msg ) INTERNAL_CATCH_INFO( msg, "INFO" ) +#define CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CAPTURE" ) +#define SCOPED_CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CAPTURE" ) + +#ifdef CATCH_CONFIG_VARIADIC_MACROS + #define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ ) + #define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ ) + #define METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ ) + #define REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ ) + #define SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) + #define FAIL( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "FAIL", __VA_ARGS__ ) + #define SUCCEED( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "SUCCEED", __VA_ARGS__ ) +#else + #define TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description ) + #define TEST_CASE_METHOD( className, name, description ) INTERNAL_CATCH_TEST_CASE_METHOD( className, name, description ) + #define METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description ) + #define REGISTER_TEST_CASE( method, name, description ) INTERNAL_CATCH_REGISTER_TESTCASE( method, name, description ) + #define SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description ) + #define FAIL( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "FAIL", msg ) + #define SUCCEED( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "SUCCEED", msg ) +#endif +#define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE( "", "" ) + +#define REGISTER_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) +#define REGISTER_LEGACY_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) + +#define GENERATE( expr) INTERNAL_CATCH_GENERATE( expr ) + +#endif + +#define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) + +// "BDD-style" convenience wrappers +#ifdef CATCH_CONFIG_VARIADIC_MACROS +#define SCENARIO( ... ) TEST_CASE( "Scenario: " __VA_ARGS__ ) +#define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ ) +#else +#define SCENARIO( name, tags ) TEST_CASE( "Scenario: " name, tags ) +#define SCENARIO_METHOD( className, name, tags ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " name, tags ) +#endif +#define GIVEN( desc ) SECTION( std::string(" Given: ") + desc, "" ) +#define WHEN( desc ) SECTION( std::string(" When: ") + desc, "" ) +#define AND_WHEN( desc ) SECTION( std::string("And when: ") + desc, "" ) +#define THEN( desc ) SECTION( std::string(" Then: ") + desc, "" ) +#define AND_THEN( desc ) SECTION( std::string(" And: ") + desc, "" ) + +using Catch::Detail::Approx; + +#endif // TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED + diff --git a/CUDA_Histogram/libwb/vendor/json11.cpp b/CUDA_Histogram/libwb/vendor/json11.cpp new file mode 100644 index 0000000..f401c26 --- /dev/null +++ b/CUDA_Histogram/libwb/vendor/json11.cpp @@ -0,0 +1,1013 @@ +/* Copyright (c) 2013 Dropbox, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy + * of this software and associated documentation files (the "Software"), to + * deal + * in the Software without restriction, including without limitation the + * rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN + * THE SOFTWARE. + */ + +#include "json11.hpp" +#include +#include +#include +#include +#include +#include + +namespace json11 { + +static const int max_depth = 200; + +using std::string; +using std::vector; +using std::map; +using std::make_shared; +using std::initializer_list; +using std::move; + +/* * * * * * * * * * * * * * * * * * * * + * Serialization + */ + +static void dump(std::nullptr_t, string &out) { + out += "null"; +} + +static void dump(double value, string &out) { + if (std::isfinite(value)) { + char buf[32]; +//PMO +#ifndef _MSC_VER + snprintf(buf, sizeof buf, "%.17g", value); +#else + _snprintf_s(buf, sizeof buf, "%.17g", value); +#endif + out += buf; + } else { + out += "null"; + } +} + +static void dump(int value, string &out) { + char buf[32]; +//PMO +#ifndef _MSC_VER + snprintf(buf, sizeof buf, "%d", value); +#else + _snprintf_s(buf, sizeof buf, "%d", value); +#endif + out += buf; +} + +static void dump(int64_t value, string &out) { + char buf[64]; +//PMO +#ifndef _MSC_VER + snprintf(buf, sizeof buf, "%" PRId64, value); +#else + _snprintf_s(buf, sizeof buf, "%" PRId64, value); +#endif + out += buf; +} + +static void dump(uint64_t value, string &out) { + char buf[128]; +//PMO +#ifndef _MSC_VER + snprintf(buf, sizeof buf, "%" PRIu64, value); +#else + _snprintf_s(buf, sizeof buf, "%" PRIu64, value); +#endif + out += buf; +} + +static void dump(bool value, string &out) { + out += value ? "true" : "false"; +} + +static void dump(const string &value, string &out) { + out += '"'; + for (size_t i = 0; i < value.length(); i++) { + const char ch = value[i]; + if (ch == '\\') { + out += "\\\\"; + } else if (ch == '"') { + out += "\\\""; + } else if (ch == '\b') { + out += "\\b"; + } else if (ch == '\f') { + out += "\\f"; + } else if (ch == '\n') { + out += "\\n"; + } else if (ch == '\r') { + out += "\\r"; + } else if (ch == '\t') { + out += "\\t"; + } else if (static_cast(ch) <= 0x1f) { + char buf[8]; +//PMO +#ifndef _MSC_VER + snprintf(buf, sizeof buf, "\\u%04x", ch); +#else + _snprintf_s(buf, sizeof buf, "\\u%04x", ch); +#endif + out += buf; + } else if (static_cast(ch) == 0xe2 && + static_cast(value[i + 1]) == 0x80 && + static_cast(value[i + 2]) == 0xa8) { + out += "\\u2028"; + i += 2; + } else if (static_cast(ch) == 0xe2 && + static_cast(value[i + 1]) == 0x80 && + static_cast(value[i + 2]) == 0xa9) { + out += "\\u2029"; + i += 2; + } else { + out += ch; + } + } + out += '"'; +} + +static void dump(const Json::array &values, string &out) { + bool first = true; + out += "["; + for (const auto &value : values) { + if (!first) + out += ", "; + value.dump(out); + first = false; + } + out += "]"; +} + +static void dump(const Json::object &values, string &out) { + bool first = true; + out += "{"; + for (const auto &kv : values) { + if (!first) + out += ", "; + dump(kv.first, out); + out += ": "; + kv.second.dump(out); + first = false; + } + out += "}"; +} + +void Json::dump(string &out) const { + m_ptr->dump(out); +} + +/* * * * * * * * * * * * * * * * * * * * + * Value wrappers + */ + +template +class Value : public JsonValue { +protected: + // Constructors + explicit Value(const T &value) : m_value(value) { + } + explicit Value(T &&value) : m_value(move(value)) { + } + + // Get type tag + Json::Type type() const override { + return tag; + } + + // Comparisons + bool equals(const JsonValue *other) const override { + return m_value == static_cast *>(other)->m_value; + } + bool less(const JsonValue *other) const override { + return m_value < static_cast *>(other)->m_value; + } + + const T m_value; + void dump(string &out) const override { + json11::dump(m_value, out); + } +}; + +class JsonDouble final : public Value { + double number_value() const override { + return m_value; + } + int int_value() const override { + return static_cast(m_value); + } + int64_t int64_value() const override { + return (int64_t)m_value; + } + uint64_t uint64_value() const override { + return (uint64_t)m_value; + } + bool equals(const JsonValue *other) const override { + return m_value == other->number_value(); + } + bool less(const JsonValue *other) const override { + return m_value < other->number_value(); + } + +public: + explicit JsonDouble(double value) : Value(value) { + } +}; + +class JsonInt final : public Value { + double number_value() const override { + return m_value; + } + int int_value() const override { + return m_value; + } + int64_t int64_value() const override { + return m_value; + } + uint64_t uint64_value() const override { + return m_value; + } + bool equals(const JsonValue *other) const override { + return m_value == other->number_value(); + } + bool less(const JsonValue *other) const override { + return m_value < other->number_value(); + } + +public: + explicit JsonInt(int value) : Value(value) { + } +}; + +class JsonInt64 final : public Value { + double number_value() const override { + return m_value; + } + int int_value() const override { + return (int)m_value; + } + int64_t int64_value() const override { + return m_value; + } + uint64_t uint64_value() const override { + return (uint64_t)m_value; + } + bool equals(const JsonValue *other) const override { + return m_value == other->number_value(); + } + bool less(const JsonValue *other) const override { + return m_value < other->number_value(); + } + +public: + explicit JsonInt64(int64_t value) : Value(value) { + } +}; + +class JsonUInt64 final : public Value { + double number_value() const override { + return m_value; + } + int int_value() const override { + return (int)m_value; + } + int64_t int64_value() const override { + return (int64_t)m_value; + } + uint64_t uint64_value() const override { + return m_value; + } + bool equals(const JsonValue *other) const override { + return m_value == other->number_value(); + } + bool less(const JsonValue *other) const override { + return m_value < other->number_value(); + } + +public: + explicit JsonUInt64(uint64_t value) : Value(value) { + } +}; + +class JsonBoolean final : public Value { + bool bool_value() const override { + return m_value; + } + +public: + explicit JsonBoolean(bool value) : Value(value) { + } +}; + +class JsonString final : public Value { + const string &string_value() const override { + return m_value; + } + +public: + explicit JsonString(const string &value) : Value(value) { + } + explicit JsonString(string &&value) : Value(move(value)) { + } +}; + +class JsonArray final : public Value { + const Json::array &array_items() const override { + return m_value; + } + const Json &operator[](size_t i) const override; + +public: + explicit JsonArray(const Json::array &value) : Value(value) { + } + explicit JsonArray(Json::array &&value) : Value(move(value)) { + } +}; + +class JsonObject final : public Value { + const Json::object &object_items() const override { + return m_value; + } + const Json &operator[](const string &key) const override; + +public: + explicit JsonObject(const Json::object &value) : Value(value) { + } + explicit JsonObject(Json::object &&value) : Value(move(value)) { + } +}; + +class JsonNull final : public Value { +public: + JsonNull() : Value(nullptr) { + } +}; + +/* * * * * * * * * * * * * * * * * * * * + * Static globals - static-init-safe + */ +struct Statics { + const std::shared_ptr null = make_shared(); + const std::shared_ptr t = make_shared(true); + const std::shared_ptr f = make_shared(false); + const string empty_string; + const vector empty_vector; + const map empty_map; + Statics() { + } +}; + +static const Statics &statics() { + static const Statics s{}; + return s; +} + +static const Json &static_null() { + // This has to be separate, not in Statics, because Json() accesses + // statics().null. + static const Json json_null; + return json_null; +} + +/* * * * * * * * * * * * * * * * * * * * + * Constructors + */ + +Json::Json() NOEXCEPT : m_ptr(statics().null) { +} +Json::Json(std::nullptr_t) NOEXCEPT : m_ptr(statics().null) { +} +Json::Json(double value) : m_ptr(make_shared(value)) { +} +Json::Json(int value) : m_ptr(make_shared(value)) { +} +Json::Json(int64_t value) : m_ptr(make_shared(value)) { +} +Json::Json(uint64_t value) : m_ptr(make_shared(value)) { +} +Json::Json(bool value) : m_ptr(value ? statics().t : statics().f) { +} +Json::Json(const string &value) : m_ptr(make_shared(value)) { +} +Json::Json(string &&value) : m_ptr(make_shared(move(value))) { +} +Json::Json(const char *value) : m_ptr(make_shared(value)) { +} +Json::Json(const Json::array &values) + : m_ptr(make_shared(values)) { +} +Json::Json(Json::array &&values) + : m_ptr(make_shared(move(values))) { +} +Json::Json(const Json::object &values) + : m_ptr(make_shared(values)) { +} +Json::Json(Json::object &&values) + : m_ptr(make_shared(move(values))) { +} + +/* * * * * * * * * * * * * * * * * * * * + * Accessors + */ + +Json::Type Json::type() const { + return m_ptr->type(); +} +double Json::number_value() const { + return m_ptr->number_value(); +} +int Json::int_value() const { + return m_ptr->int_value(); +} +int64_t Json::int64_value() const { + return m_ptr->int64_value(); +} +uint64_t Json::uint64_value() const { + return m_ptr->uint64_value(); +} +bool Json::bool_value() const { + return m_ptr->bool_value(); +} +const string &Json::string_value() const { + return m_ptr->string_value(); +} +const vector &Json::array_items() const { + return m_ptr->array_items(); +} +const map &Json::object_items() const { + return m_ptr->object_items(); +} +const Json &Json::operator[](size_t i) const { + return (*m_ptr)[i]; +} +const Json &Json::operator[](const string &key) const { + return (*m_ptr)[key]; +} + +double JsonValue::number_value() const { + return 0; +} +int JsonValue::int_value() const { + return 0; +} +int64_t JsonValue::int64_value() const { + return 0; +} +uint64_t JsonValue::uint64_value() const { + return 0; +} +bool JsonValue::bool_value() const { + return false; +} +const string &JsonValue::string_value() const { + return statics().empty_string; +} +const vector &JsonValue::array_items() const { + return statics().empty_vector; +} +const map &JsonValue::object_items() const { + return statics().empty_map; +} +const Json &JsonValue::operator[](size_t) const { + return static_null(); +} +const Json &JsonValue::operator[](const string &) const { + return static_null(); +} + +const Json &JsonObject::operator[](const string &key) const { + auto iter = m_value.find(key); + return (iter == m_value.end()) ? static_null() : iter->second; +} +const Json &JsonArray::operator[](size_t i) const { + if (i >= m_value.size()) + return static_null(); + else + return m_value[i]; +} + +/* * * * * * * * * * * * * * * * * * * * + * Comparison + */ + +bool Json::operator==(const Json &other) const { + if (m_ptr->type() != other.m_ptr->type()) + return false; + + return m_ptr->equals(other.m_ptr.get()); +} + +bool Json::operator<(const Json &other) const { + if (m_ptr->type() != other.m_ptr->type()) + return m_ptr->type() < other.m_ptr->type(); + + return m_ptr->less(other.m_ptr.get()); +} + +/* * * * * * * * * * * * * * * * * * * * + * Parsing + */ + +/* esc(c) + * + * Format char c suitable for printing in an error message. + */ +static inline string esc(char c) { + char buf[12]; + if (static_cast(c) >= 0x20 && static_cast(c) <= 0x7f) { +//PMO +#ifndef _MSC_VER + snprintf(buf, sizeof buf, "'%c' (%d)", c, c); +#else + _snprintf_s(buf, sizeof buf, "'%c' (%d)", c, c); +#endif + } else { +//PMO +#ifndef _MSC_VER + snprintf(buf, sizeof buf, "(%d)", c); +#else + _snprintf_s(buf, sizeof buf, "(%d)", c); +#endif + } + return string(buf); +} + +static inline bool in_range(long x, long lower, long upper) { + return (x >= lower && x <= upper); +} + +/* JsonParser + * + * Object that tracks all state of an in-progress parse. + */ +struct JsonParser { + + /* State + */ + const string &str; + size_t i; + string &err; + bool failed; + const JsonParse strategy; + + /* fail(msg, err_ret = Json()) + * + * Mark this parse as failed. + */ + Json fail(string &&msg) { + return fail(move(msg), Json()); + } + + template + T fail(string &&msg, const T err_ret) { + if (!failed) + err = std::move(msg); + failed = true; + return err_ret; + } + + /* consume_whitespace() + * + * Advance until the current character is non-whitespace. + */ + void consume_whitespace() { + while (str[i] == ' ' || str[i] == '\r' || str[i] == '\n' || + str[i] == '\t') + i++; + } + + /* consume_comment() + * + * Advance comments (c-style inline and multiline). + */ + bool consume_comment() { + bool comment_found = false; + if (str[i] == '/') { + i++; + if (i == str.size()) + return fail("unexpected end of input inside comment", 0); + if (str[i] == '/') { // inline comment + i++; + if (i == str.size()) + return fail("unexpected end of input inside inline comment", 0); + // advance until next line + while (str[i] != '\n') { + i++; + if (i == str.size()) + return fail("unexpected end of input inside inline comment", + 0); + } + comment_found = true; + } else if (str[i] == '*') { // multiline comment + i++; + if (i > str.size() - 2) + return fail("unexpected end of input inside multi-line comment", + 0); + // advance until closing tokens + while (!(str[i] == '*' && str[i + 1] == '/')) { + i++; + if (i > str.size() - 2) + return fail( + "unexpected end of input inside multi-line comment", 0); + } + i += 2; + if (i == str.size()) + return fail("unexpected end of input inside multi-line comment", + 0); + comment_found = true; + } else + return fail("malformed comment", 0); + } + return comment_found; + } + + /* consume_garbage() + * + * Advance until the current character is non-whitespace and non-comment. + */ + void consume_garbage() { + consume_whitespace(); + if (strategy == JsonParse::COMMENTS) { + bool comment_found = false; + do { + comment_found = consume_comment(); + consume_whitespace(); + } while (comment_found); + } + } + + /* get_next_token() + * + * Return the next non-whitespace character. If the end of the input is + * reached, + * flag an error and return 0. + */ + char get_next_token() { + consume_garbage(); + if (i == str.size()) + return fail("unexpected end of input", 0); + + return str[i++]; + } + + /* encode_utf8(pt, out) + * + * Encode pt as UTF-8 and add it to out. + */ + void encode_utf8(long pt, string &out) { + if (pt < 0) + return; + + if (pt < 0x80) { + out += static_cast(pt); + } else if (pt < 0x800) { + out += static_cast((pt >> 6) | 0xC0); + out += static_cast((pt & 0x3F) | 0x80); + } else if (pt < 0x10000) { + out += static_cast((pt >> 12) | 0xE0); + out += static_cast(((pt >> 6) & 0x3F) | 0x80); + out += static_cast((pt & 0x3F) | 0x80); + } else { + out += static_cast((pt >> 18) | 0xF0); + out += static_cast(((pt >> 12) & 0x3F) | 0x80); + out += static_cast(((pt >> 6) & 0x3F) | 0x80); + out += static_cast((pt & 0x3F) | 0x80); + } + } + + /* parse_string() + * + * Parse a string, starting at the current position. + */ + string parse_string() { + string out; + long last_escaped_codepoint = -1; + while (true) { + if (i == str.size()) + return fail("unexpected end of input in string", ""); + + char ch = str[i++]; + + if (ch == '"') { + encode_utf8(last_escaped_codepoint, out); + return out; + } + + if (in_range(ch, 0, 0x1f)) + return fail("unescaped " + esc(ch) + " in string", ""); + + // The usual case: non-escaped characters + if (ch != '\\') { + encode_utf8(last_escaped_codepoint, out); + last_escaped_codepoint = -1; + out += ch; + continue; + } + + // Handle escapes + if (i == str.size()) + return fail("unexpected end of input in string", ""); + + ch = str[i++]; + + if (ch == 'u') { + // Extract 4-byte escape sequence + string esc = str.substr(i, 4); + // Explicitly check length of the substring. The following loop + // relies on std::string returning the terminating NUL when + // accessing str[length]. Checking here reduces brittleness. + if (esc.length() < 4) { + return fail("bad \\u escape: " + esc, ""); + } + for (int j = 0; j < 4; j++) { + if (!in_range(esc[j], 'a', 'f') && !in_range(esc[j], 'A', 'F') && + !in_range(esc[j], '0', '9')) + return fail("bad \\u escape: " + esc, ""); + } + + long codepoint = strtol(esc.data(), nullptr, 16); + + // JSON specifies that characters outside the BMP shall be encoded + // as a pair + // of 4-hex-digit \u escapes encoding their surrogate pair + // components. Check + // whether we're in the middle of such a beast: the previous + // codepoint was an + // escaped lead (high) surrogate, and this is a trail (low) + // surrogate. + if (in_range(last_escaped_codepoint, 0xD800, 0xDBFF) && + in_range(codepoint, 0xDC00, 0xDFFF)) { + // Reassemble the two surrogate pairs into one astral-plane + // character, per + // the UTF-16 algorithm. + encode_utf8((((last_escaped_codepoint - 0xD800) << 10) | + (codepoint - 0xDC00)) + + 0x10000, + out); + last_escaped_codepoint = -1; + } else { + encode_utf8(last_escaped_codepoint, out); + last_escaped_codepoint = codepoint; + } + + i += 4; + continue; + } + + encode_utf8(last_escaped_codepoint, out); + last_escaped_codepoint = -1; + + if (ch == 'b') { + out += '\b'; + } else if (ch == 'f') { + out += '\f'; + } else if (ch == 'n') { + out += '\n'; + } else if (ch == 'r') { + out += '\r'; + } else if (ch == 't') { + out += '\t'; + } else if (ch == '"' || ch == '\\' || ch == '/') { + out += ch; + } else { + return fail("invalid escape character " + esc(ch), ""); + } + } + } + + /* parse_number() + * + * Parse a double. + */ + Json parse_number() { + size_t start_pos = i; + + if (str[i] == '-') + i++; + + // Integer part + if (str[i] == '0') { + i++; + if (in_range(str[i], '0', '9')) + return fail("leading 0s not permitted in numbers"); + } else if (in_range(str[i], '1', '9')) { + i++; + while (in_range(str[i], '0', '9')) + i++; + } else { + return fail("invalid " + esc(str[i]) + " in number"); + } + + if (str[i] != '.' && str[i] != 'e' && str[i] != 'E' && + (i - start_pos) <= + static_cast(std::numeric_limits::digits10)) { + return std::atoi(str.c_str() + start_pos); + } + + // Decimal part + if (str[i] == '.') { + i++; + if (!in_range(str[i], '0', '9')) + return fail("at least one digit required in fractional part"); + + while (in_range(str[i], '0', '9')) + i++; + } + + // Exponent part + if (str[i] == 'e' || str[i] == 'E') { + i++; + + if (str[i] == '+' || str[i] == '-') + i++; + + if (!in_range(str[i], '0', '9')) + return fail("at least one digit required in exponent"); + + while (in_range(str[i], '0', '9')) + i++; + } + + return std::strtod(str.c_str() + start_pos, nullptr); + } + + /* expect(str, res) + * + * Expect that 'str' starts at the character that was just read. If it + * does, advance + * the input and return res. If not, flag an error. + */ + Json expect(const string &expected, Json res) { + assert(i != 0); + i--; + if (str.compare(i, expected.length(), expected) == 0) { + i += expected.length(); + return res; + } else { + return fail("parse error: expected " + expected + ", got " + + str.substr(i, expected.length())); + } + } + + /* parse_json() + * + * Parse a JSON object. + */ + Json parse_json(int depth) { + if (depth > max_depth) { + return fail("exceeded maximum nesting depth"); + } + + char ch = get_next_token(); + if (failed) + return Json(); + + if (ch == '-' || (ch >= '0' && ch <= '9')) { + i--; + return parse_number(); + } + + if (ch == 't') + return expect("true", true); + + if (ch == 'f') + return expect("false", false); + + if (ch == 'n') + return expect("null", Json()); + + if (ch == '"') + return parse_string(); + + if (ch == '{') { + map data; + ch = get_next_token(); + if (ch == '}') + return data; + + while (1) { + if (ch != '"') + return fail("expected '\"' in object, got " + esc(ch)); + + string key = parse_string(); + if (failed) + return Json(); + + ch = get_next_token(); + if (ch != ':') + return fail("expected ':' in object, got " + esc(ch)); + + data[std::move(key)] = parse_json(depth + 1); + if (failed) + return Json(); + + ch = get_next_token(); + if (ch == '}') + break; + if (ch != ',') + return fail("expected ',' in object, got " + esc(ch)); + + ch = get_next_token(); + } + return data; + } + + if (ch == '[') { + vector data; + ch = get_next_token(); + if (ch == ']') + return data; + + while (1) { + i--; + data.push_back(parse_json(depth + 1)); + if (failed) + return Json(); + + ch = get_next_token(); + if (ch == ']') + break; + if (ch != ',') + return fail("expected ',' in list, got " + esc(ch)); + + ch = get_next_token(); + (void)ch; + } + return data; + } + + return fail("expected value, got " + esc(ch)); + } +}; + +Json Json::parse(const string &in, string &err, JsonParse strategy) { + JsonParser parser{in, 0, err, false, strategy}; + Json result = parser.parse_json(0); + + // Check for any trailing garbage + parser.consume_garbage(); + if (parser.i != in.size()) + return parser.fail("unexpected trailing " + esc(in[parser.i])); + + return result; +} + +// Documented in json11.hpp +vector Json::parse_multi(const string &in, string &err, + JsonParse strategy) { + JsonParser parser{in, 0, err, false, strategy}; + + vector json_vec; + while (parser.i != in.size() && !parser.failed) { + json_vec.push_back(parser.parse_json(0)); + // Check for another object + parser.consume_garbage(); + } + return json_vec; +} + +/* * * * * * * * * * * * * * * * * * * * + * Shape-checking + */ + +bool Json::has_shape(const shape &types, string &err) const { + if (!is_object()) { + err = "expected JSON object, got " + dump(); + return false; + } + + for (auto &item : types) { + if ((*this)[item.first].type() != item.second) { + err = "bad type for " + item.first + " in " + dump(); + return false; + } + } + + return true; +} + +} // namespace json11 diff --git a/CUDA_Histogram/libwb/vendor/json11.hpp b/CUDA_Histogram/libwb/vendor/json11.hpp new file mode 100644 index 0000000..9e0f0d9 --- /dev/null +++ b/CUDA_Histogram/libwb/vendor/json11.hpp @@ -0,0 +1,300 @@ +/* json11 + * + * json11 is a tiny JSON library for C++11, providing JSON parsing and + * serialization. + * + * The core object provided by the library is json11::Json. A Json object + * represents any JSON + * value: null, bool, number (int or double), string (std::string), array + * (std::vector), or + * object (std::map). + * + * Json objects act like values: they can be assigned, copied, moved, + * compared for equality or + * order, etc. There are also helper methods Json::dump, to serialize a + * Json to a string, and + * Json::parse (static) to parse a std::string as a Json object. + * + * Internally, the various types of Json object are represented by the + * JsonValue class + * hierarchy. + * + * A note on numbers - JSON specifies the syntax of number formatting but + * not its semantics, + * so some JSON implementations distinguish between integers and + * floating-point numbers, while + * some don't. In json11, we choose the latter. Because some JSON + * implementations (namely + * Javascript itself) treat all numbers as the same type, distinguishing + * the two leads + * to JSON that will be *silently* changed by a round-trip through those + * implementations. + * Dangerous! To avoid that risk, json11 stores all numbers as double + * internally, but also + * provides integer helpers. + * + * Fortunately, double-precision IEEE754 ('double') can precisely store any + * integer in the + * range +/-2^53, which includes every 'int' on most systems. (Timestamps + * often use int64 + * or long long to avoid the Y2038K problem; a double storing microseconds + * since some epoch + * will be exact for +/- 275 years.) + */ + +/* Copyright (c) 2013 Dropbox, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy + * of this software and associated documentation files (the "Software"), to + * deal + * in the Software without restriction, including without limitation the + * rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN + * THE SOFTWARE. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +//PMO +#ifndef _MSC_VER +#define NOEXCEPT noexcept +#else +#define NOEXCEPT _NOEXCEPT +#endif + +namespace json11 { + +enum JsonParse { STANDARD, COMMENTS }; + +class JsonValue; + +class Json final { +public: + // Types + enum Type { + NUL, + NUMBER, + NUMBER64, + UNUMBER64, + BOOL, + STRING, + ARRAY, + OBJECT + }; + + // Array and object typedefs + typedef std::vector array; + typedef std::map object; + + // Constructors for the various types of JSON value. + //PMO + //Json() noexcept; // NUL + Json() NOEXCEPT; // NUL + //Json(std::nullptr_t) noexcept; // NUL + Json(std::nullptr_t) NOEXCEPT; // NUL + Json(double value); // NUMBER + Json(int value); // NUMBER + Json(int64_t value); // NUMBER64 + Json(uint64_t value); // UNUMBER64 + Json(bool value); // BOOL + Json(const std::string &value); // STRING + Json(std::string &&value); // STRING + Json(const char *value); // STRING + Json(const array &values); // ARRAY + Json(array &&values); // ARRAY + Json(const object &values); // OBJECT + Json(object &&values); // OBJECT + + // Implicit constructor: anything with a to_json() function. + template + Json(const T &t) : Json(t.to_json()) { + } + + // Implicit constructor: map-like objects (std::map, std::unordered_map, + // etc) + template < + class M, + typename std::enable_if< + std::is_constructible::value && + std::is_constructible::value, + int>::type = 0> + Json(const M &m) : Json(object(m.begin(), m.end())) { + } + + // Implicit constructor: vector-like objects (std::list, std::vector, + // std::set, etc) + template ::value, + int>::type = 0> + Json(const V &v) : Json(array(v.begin(), v.end())) { + } + + // This prevents Json(some_pointer) from accidentally producing a bool. + // Use + // Json(bool(some_pointer)) if that behavior is desired. + Json(void *) = delete; + + // Accessors + Type type() const; + + bool is_null() const { + return type() == NUL; + } + bool is_number() const { + return type() == NUMBER; + } + bool is_number64() const { + return type() == NUMBER64; + } + bool is_unumber64() const { + return type() == UNUMBER64; + } + bool is_bool() const { + return type() == BOOL; + } + bool is_string() const { + return type() == STRING; + } + bool is_array() const { + return type() == ARRAY; + } + bool is_object() const { + return type() == OBJECT; + } + + // Return the enclosed value if this is a number, 0 otherwise. Note that + // json11 does not + // distinguish between integer and non-integer numbers - number_value() + // and int_value() + // can both be applied to a NUMBER-typed object. + double number_value() const; + int int_value() const; + int64_t int64_value() const; + uint64_t uint64_value() const; + + // Return the enclosed value if this is a boolean, false otherwise. + bool bool_value() const; + // Return the enclosed string if this is a string, "" otherwise. + const std::string &string_value() const; + // Return the enclosed std::vector if this is an array, or an empty + // vector otherwise. + const array &array_items() const; + // Return the enclosed std::map if this is an object, or an empty map + // otherwise. + const object &object_items() const; + + // Return a reference to arr[i] if this is an array, Json() otherwise. + const Json &operator[](size_t i) const; + // Return a reference to obj[key] if this is an object, Json() otherwise. + const Json &operator[](const std::string &key) const; + + // Serialize. + void dump(std::string &out) const; + std::string dump() const { + std::string out; + dump(out); + return out; + } + + // Parse. If parse fails, return Json() and assign an error message to + // err. + static Json parse(const std::string &in, std::string &err, + JsonParse strategy = JsonParse::STANDARD); + static Json parse(const char *in, std::string &err, + JsonParse strategy = JsonParse::STANDARD) { + if (in) { + return parse(std::string(in), err, strategy); + } else { + err = "null input"; + return nullptr; + } + } + // Parse multiple objects, concatenated or separated by whitespace + static std::vector + parse_multi(const std::string &in, std::string &err, + JsonParse strategy = JsonParse::STANDARD); + + bool operator==(const Json &rhs) const; + bool operator<(const Json &rhs) const; + bool operator!=(const Json &rhs) const { + return !(*this == rhs); + } + bool operator<=(const Json &rhs) const { + return !(rhs < *this); + } + bool operator>(const Json &rhs) const { + return (rhs < *this); + } + bool operator>=(const Json &rhs) const { + return !(*this < rhs); + } + + /* has_shape(types, err) + * + * Return true if this is a JSON object and, for each item in types, has + * a field of + * the given type. If not, return false and set err to a descriptive + * message. + */ + typedef std::initializer_list> shape; + bool has_shape(const shape &types, std::string &err) const; + +private: + std::shared_ptr m_ptr; +}; + +// Internal class hierarchy - JsonValue objects are not exposed to users of +// this API. +class JsonValue { +protected: + friend class Json; + friend class JsonInt; + friend class JsonInt64; + friend class JsonUInt64; + friend class JsonDouble; + virtual Json::Type type() const = 0; + virtual bool equals(const JsonValue *other) const = 0; + virtual bool less(const JsonValue *other) const = 0; + virtual void dump(std::string &out) const = 0; + virtual double number_value() const; + virtual int int_value() const; + virtual int64_t int64_value() const; + virtual uint64_t uint64_value() const; + virtual bool bool_value() const; + virtual const std::string &string_value() const; + virtual const Json::array &array_items() const; + virtual const Json &operator[](size_t i) const; + virtual const Json::object &object_items() const; + virtual const Json &operator[](const std::string &key) const; + virtual ~JsonValue() { + } +}; + +} // namespace json11 diff --git a/CUDA_Histogram/libwb/wb.h b/CUDA_Histogram/libwb/wb.h new file mode 100644 index 0000000..8f41e23 --- /dev/null +++ b/CUDA_Histogram/libwb/wb.h @@ -0,0 +1,155 @@ + + +#ifndef __WB_H__ +#define __WB_H__ + +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ + +#include +#include +#include +#include + +#ifdef _MSC_VER + +// set minimal warning level +#pragma warning(push,0) +// some warnings still occur at this level +// if necessary, disable specific warnings not covered by previous pragma +#pragma warning(disable : 4244 4056 4305 4800 4267 4996 4756 4661 4385 4101) + +#define __func__ __FUNCTION__ +#ifndef _CRT_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_WARNINGS 1 +#endif /* _CRT_SECURE_NO_WARNINGS */ +#define _CRT_SECURE_NO_DEPRECATE 1 +#define _CRT_NONSTDC_NO_DEPRECATE 1 +#include +#include +#include +#define WB_USE_WINDOWS +#else /* _MSC_VER */ +#include +#include +#include +#include +#define WB_USE_UNIX +#ifdef __APPLE__ +#include +#define WB_USE_DARWIN +#else /* __APPLE__ */ +#define WB_USE_LINUX +#endif /* __APPLE__ */ +#endif /* _MSC_VER */ + +#define wbStmt(stmt) stmt + +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ + +#define wbLine __LINE__ +#define wbFile __FILE__ +#define wbFunction __func__ + +#define wbExit() \ + wbAssert(0); \ + exit(1) + +#ifdef WB_USE_COURSERA +#define wbLogger_printOnExit 1 +#else /* WB_USE_COURSERA */ +#define wbLogger_printOnLog 1 +#endif /* WB_USE_COURSERA */ + +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ + +#ifdef __cplusplus +#define EXTERN_C extern "C" +#define START_EXTERN_C EXTERN_C { +#define END_EXTERN_C } +#else +#define EXTERN_C +#define START_EXTERN_C +#define END_EXTERN_C +#endif /* __cplusplus */ + +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ + +#include +#define WB_USE_JSON11 1 + +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ + +#define LAZY_FILE_LOAD +extern char *solutionJSON; + +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ + +#ifdef WB_USE_OPENCL +#ifdef WB_USE_DARWIN +#include +#else /* WB_USE_DARWIN */ +#include +#endif /* WB_USE_DARWIN */ +#endif /* WB_USE_OPENCL */ + +#include "wbTypes.h" + +#include "wbAssert.h" +#include "wbMalloc.h" +#include "wbString.h" +#include "wbUtils.h" + +#include "wbArg.h" +#include "wbCUDA.h" +#include "wbCast.h" +#include "wbComparator.h" +#include "wbDirectory.h" +#include "wbExit.h" +#include "wbExport.h" +#include "wbFile.h" +#include "wbImage.h" +#include "wbImport.h" +#include "wbInit.h" +#include "wbLogger.h" +#include "wbMD5.h" +#include "wbMPI.h" +#include "wbSolution.h" +#include "wbSparse.h" +#include "wbThrust.h" +#include "wbTimer.h" +#include "wbPath.h" + +#include "wbDataset.h" + +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ + +#endif /* __WB_H__ */ diff --git a/CUDA_Histogram/libwb/wbArg.cpp b/CUDA_Histogram/libwb/wbArg.cpp new file mode 100644 index 0000000..2a5c736 --- /dev/null +++ b/CUDA_Histogram/libwb/wbArg.cpp @@ -0,0 +1,105 @@ + +#include "wb.h" + +EXTERN_C wbArg_t wbArg_new(int *argc, char ***argv) { + wbArg_t arg; + + wb_init(argc, argv); + + wbArg_setInputCount(arg, 0); + wbArg_setInputFiles(arg, NULL); + wbArg_setOutputFile(arg, NULL); + wbArg_setType(arg, NULL); + wbArg_setExpectedOutputFile(arg, NULL); + return arg; +} + +EXTERN_C void wbArg_delete(wbArg_t arg) { + if (wbArg_getInputCount(arg) > 0 && wbArg_getInputFiles(arg) != NULL) { + int ii; + for (ii = 0; ii < wbArg_getInputCount(arg); ii++) { + wbDelete(wbArg_getInputFile(arg, ii)); + } + wbDelete(wbArg_getInputFiles(arg)); + wbArg_setInputCount(arg, 0); + wbArg_setInputFiles(arg, NULL); + } + if (wbArg_getOutputFile(arg)) { + wbDelete(wbArg_getOutputFile(arg)); + wbArg_setOutputFile(arg, NULL); + } + if (wbArg_getExpectedOutputFile(arg)) { + wbDelete(wbArg_getExpectedOutputFile(arg)); + wbArg_setExpectedOutputFile(arg, NULL); + } + if (wbArg_getType(arg)) { + wbDelete(wbArg_getType(arg)); + wbArg_setType(arg, NULL); + } + return; +} + +static int getInputFileCount(char *arg) { + int count = 1; + while (*arg != '\0' && *arg != '-') { + if (*arg == ',') { + count++; + } + arg++; + } + return count; +} + +static char **parseInputFiles(char *arg, int *resCount) { + int count; + int ii = 0; + char **files; + char *token; + + count = getInputFileCount(arg); + + files = wbNewArray(char *, count); + + token = strtok(arg, ","); + while (token != NULL) { + files[ii++] = wbString_duplicate(token); + token = strtok(NULL, ","); + } + *resCount = ii; + return files; +} + +static char *parseString(char *arg) { + return wbString_duplicate(arg); +} + +EXTERN_C wbArg_t wbArg_read(int argc, char **argv) { + int ii; + wbArg_t arg; + + arg = wbArg_new(&argc, &argv); + for (ii = 0; ii < argc; ii++) { + if (wbString_startsWith(argv[ii], "-i")) { + int fileCount; + char **files; + + files = parseInputFiles(argv[ii + 1], &fileCount); + + wbArg_setInputCount(arg, fileCount); + wbArg_setInputFiles(arg, files); + } else if (wbString_startsWith(argv[ii], "-o")) { + char *file = parseString(argv[ii + 1]); + wbArg_setOutputFile(arg, file); + } else if (wbString_startsWith(argv[ii], "-e")) { + char *file = parseString(argv[ii + 1]); + wbArg_setExpectedOutputFile(arg, file); + } else if (wbString_startsWith(argv[ii], "-t")) { + char *type = parseString(argv[ii + 1]); + wbArg_setType(arg, type); + } else if (argv[ii][0] == '-') { + wbLog(ERROR, "Unexpected program option ", argv[ii]); + } + } + + return arg; +} diff --git a/CUDA_Histogram/libwb/wbArg.h b/CUDA_Histogram/libwb/wbArg.h new file mode 100644 index 0000000..c98bcf7 --- /dev/null +++ b/CUDA_Histogram/libwb/wbArg.h @@ -0,0 +1,33 @@ + + +#ifndef __WB_ARG_H__ +#define __WB_ARG_H__ + +struct st_wbArg_t { + int inputCount; + char **inputFiles; + char *outputFile; + char *expectedOutput; + char *type; +}; + +#define wbArg_getInputCount(wa) ((wa).inputCount) +#define wbArg_getInputFiles(wa) ((wa).inputFiles) +#define wbArg_getInputFile(wa, ii) (wbArg_getInputFiles(wa)[ii]) +#define wbArg_getOutputFile(wa) ((wa).outputFile) +#define wbArg_getExpectedOutputFile(wa) ((wa).expectedOutput) +#define wbArg_getType(wa) ((wa).type) + +#define wbArg_setInputCount(wa, val) (wbArg_getInputCount(wa) = val) +#define wbArg_setInputFiles(wa, val) (wbArg_getInputFiles(wa) = val) +#define wbArg_setInputFile(wa, ii, val) (wbArg_getInputFile(wa, ii) = val) +#define wbArg_setOutputFile(wa, val) (wbArg_getOutputFile(wa) = val) +#define wbArg_setExpectedOutputFile(wa, val) \ + (wbArg_getExpectedOutputFile(wa) = val) +#define wbArg_setType(wa, val) (wbArg_getType(wa) = val) + +EXTERN_C wbArg_t wbArg_new(int *argc, char ***argv); +EXTERN_C void wbArg_delete(wbArg_t arg); +EXTERN_C wbArg_t wbArg_read(int argc, char **argv); + +#endif /* __WB_ARG_H__ */ diff --git a/CUDA_Histogram/libwb/wbAssert.h b/CUDA_Histogram/libwb/wbAssert.h new file mode 100644 index 0000000..b8ed669 --- /dev/null +++ b/CUDA_Histogram/libwb/wbAssert.h @@ -0,0 +1,24 @@ + + +#ifndef __WB_ASSERT_H__ +#define __WB_ASSERT_H__ + +#include + +#ifdef WB_DEBUG +#define wbAssert(cond) assert(cond) +#define wbAssertMessage(msg, cond) \ + do { \ + if (!(cond)) { \ + wbPrint(msg); \ + wbAssert(cond); \ + } \ + } while (0) +#else /* WB_DEBUG */ +#define wbAssert(...) +#define wbAssertMessage(...) +#endif /* WB_DEBUG */ + +#define wbTodo(msg) wbAssertMessage(msg, false) + +#endif /* __WB_ASSERT_H__ */ diff --git a/CUDA_Histogram/libwb/wbCUDA.cpp b/CUDA_Histogram/libwb/wbCUDA.cpp new file mode 100644 index 0000000..cb26895 --- /dev/null +++ b/CUDA_Histogram/libwb/wbCUDA.cpp @@ -0,0 +1,25 @@ + +#include "wb.h" +#ifdef WB_USE_CUDA + +int _cudaMemoryListIdx = 0; + +size_t _cudaMallocSize = 0; + +wbCUDAMemory_t _cudaMemoryList[_cudaMemoryListSize]; + +char *wbRandom_list(size_t sz) { + size_t ii; + char *rands = wbNewArray(char, sz); + int *irands = (int *)rands; + for (ii = 0; ii < sz / sizeof(int); ii++) { + irands[ii] = rand(); + } + while (ii < sz) { + rands[ii] = (char)(rand() % 255); + ii++; + } + return rands; +} + +#endif /* WB_USE_CUDA */ diff --git a/CUDA_Histogram/libwb/wbCUDA.h b/CUDA_Histogram/libwb/wbCUDA.h new file mode 100644 index 0000000..658ff39 --- /dev/null +++ b/CUDA_Histogram/libwb/wbCUDA.h @@ -0,0 +1,77 @@ + +#ifndef __WB_CUDA_H__ +#define __WB_CUDA_H__ + +#ifdef WB_USE_CUDA +#ifdef __PGI +#define __GNUC__ 4 +#endif /* __PGI */ +#include +#include + +typedef struct st_wbCUDAMemory_t { + void *mem; + size_t sz; +} wbCUDAMemory_t; + +#define _cudaMemoryListSize 1024 + +extern size_t _cudaMallocSize; +extern wbCUDAMemory_t _cudaMemoryList[]; +extern int _cudaMemoryListIdx; + +char *wbRandom_list(size_t sz); + +static inline cudaError_t wbCUDAMalloc(void **devPtr, size_t sz) { + int idx = _cudaMemoryListIdx; + + cudaError_t err = cudaMalloc(devPtr, sz); + + if (idx == 0) { + srand(time(NULL)); + memset(_cudaMemoryList, 0, + sizeof(wbCUDAMemory_t) * _cudaMemoryListSize); + } + + if (err == cudaSuccess) { +#if 0 + char * rands = wbRandom_list(sz); + // can use curand here, but do not want to invoke a kernel + err = cudaMemcpy(*devPtr, rands, sz, cudaMemcpyHostToDevice); + wbFree(rands); +#else + err = cudaMemset(*devPtr, 0, sz); +#endif + } + + _cudaMallocSize += sz; + _cudaMemoryList[idx].mem = *devPtr; + _cudaMemoryList[idx].sz = sz; + _cudaMemoryListIdx++; + return err; +} + +static inline cudaError_t wbCUDAFree(void *mem) { + int idx = _cudaMemoryListIdx; + if (idx == 0) { + memset(_cudaMemoryList, 0, + sizeof(wbCUDAMemory_t) * _cudaMemoryListSize); + } + for (int ii = 0; ii < idx; ii++) { + if (_cudaMemoryList[ii].mem != NULL && + _cudaMemoryList[ii].mem == mem) { + cudaError_t err = cudaFree(mem); + _cudaMallocSize -= _cudaMemoryList[ii].sz; + _cudaMemoryList[ii].mem = NULL; + return err; + } + } + return cudaErrorMemoryAllocation; +} + +#define cudaMalloc(elem, err) wbCUDAMalloc((void **)elem, err) +#define cudaFree wbCUDAFree + +#endif /* WB_USE_CUDA */ + +#endif /* __WB_CUDA_H__ */ diff --git a/CUDA_Histogram/libwb/wbCast.h b/CUDA_Histogram/libwb/wbCast.h new file mode 100644 index 0000000..01e8387 --- /dev/null +++ b/CUDA_Histogram/libwb/wbCast.h @@ -0,0 +1,29 @@ + + +#ifndef __WB_CAST_H__ +#define __WB_CAST_H__ + +template +static inline void wbCast(X &x, const Y &y, size_t len) { + size_t ii; + + for (ii = 0; ii < len; ii++) { + x[ii] = (X)y[ii]; + } + + return; +} + +template +static inline X *wbCast(const Y &y, size_t len) { + size_t ii; + X *x = wbNewArray(X, len); + + for (ii = 0; ii < len; ii++) { + x[ii] = (X)y[ii]; + } + + return x; +} + +#endif /* __WB_CAST_H__ */ diff --git a/CUDA_Histogram/libwb/wbComparator.h b/CUDA_Histogram/libwb/wbComparator.h new file mode 100644 index 0000000..26fd0cb --- /dev/null +++ b/CUDA_Histogram/libwb/wbComparator.h @@ -0,0 +1,187 @@ + + +#ifndef __WB_COMPARATOR_H__ +#define __WB_COMPARATOR_H__ + +#include "wb.h" + +template +static inline T _abs(const T &a) { + return a < 0 ? -a : a; +} + +static inline wbBool _almostEqual(double A, double B, double eps) { + if (A == 0) { + return _abs(B) < eps; + } else if (B == 0) { + return _abs(A) < eps; + } else { +#if 0 + double d = max(_abs(A), _abs(B)); + double g = (_abs(A - B) / d); +#else + double g = _abs(A - B); +#endif + if (g <= eps) { + return wbTrue; + } else { + return wbFalse; + } + } +} + +static inline wbBool _almostEqual(float A, float B, float eps) { + if (A == 0) { + return _abs(B) < eps; + } else if (B == 0) { + return _abs(A) < eps; + } else { +#if 0 + float d = max(_abs(A), _abs(B)); + float g = (_abs(A - B) / d); +#else + float g = _abs(A - B); +#endif + if (g <= eps) { + return wbTrue; + } else { + return wbFalse; + } + } +} + +static inline wbBool _almostEqual(double A, double B) { + return _almostEqual(A, B, 0.2); +} + +static inline wbBool _almostEqual(float A, float B) { + return _almostEqual(A, B, 0.2f); +} + +static inline wbBool _almostEqual2sComplement(float A, float B, + int maxUlps) { + // Make sure maxUlps is non-negative and small enough that the + // default NAN won't compare as equal to anything. + + int aInt, bInt, intDiff; + + wbAssert(maxUlps > 0 && maxUlps < 4 * 1024 * 1024); + + int *tmp = reinterpret_cast(&A); + aInt = *tmp; + + // Make aInt lexicographically ordered as a twos-complement int + if (aInt < 0) { + aInt = 0x80000000 - aInt; + } + // Make bInt lexicographically ordered as a twos-complement int + tmp = reinterpret_cast(&B); + bInt = *tmp; + if (bInt < 0) { + bInt = 0x80000000 - bInt; + } + intDiff = _abs(aInt - bInt); + if (intDiff <= maxUlps) { + return wbTrue; + } + return wbFalse; +} + +static inline wbBool _almostEqual2sComplement(float A, float B) { + return _almostEqual2sComplement(A, B, 4); +} + +static inline wbBool _almostEqual2sComplement(double A, double B, + int maxUlps) { + // Make sure maxUlps is non-negative and small enough that the + // default NAN won't compare as equal to anything. + + int64_t aInt, bInt, intDiff; + + wbAssert(maxUlps > 0 && maxUlps < 4 * 1024 * 1024); + + int64_t *tmp = reinterpret_cast(&A); + aInt = *tmp; + + // Make aInt lexicographically ordered as a twos-complement int + if (aInt < 0) { + aInt = 0x80000000 - aInt; + } + // Make bInt lexicographically ordered as a twos-complement int + tmp = reinterpret_cast(&B); + bInt = *tmp; + if (bInt < 0) { + bInt = 0x80000000 - bInt; + } + intDiff = _abs(aInt - bInt); + if (intDiff <= maxUlps) { + return wbTrue; + } + return wbFalse; +} + +static inline wbBool _almostEqual2sComplement(double A, double B) { + return _almostEqual2sComplement(A, B, 4); +} + +template +static inline int wbCompare(const T &a, const T &b) { + if (a == b) { + return 0; + } else if (a < b) { + return -1; + } else { + return 1; + } +} + +template <> +inline int wbCompare(const double &a, const double &b) { + if (_almostEqual(a, b)) { + return 0; + } else if (a < b) { + return -1; + } else { + return 1; + } +} + +template <> +inline int wbCompare(const float &a, const float &b) { + if (_almostEqual(a, b)) { + return 0; + } else if (a < b) { + return -1; + } else { + return 1; + } +} + +template +static inline wbBool wbEqualQ(const T &a, const T &b) { + return wbCompare(a, b) == 0; +} + +template +static inline wbBool wbUnequalQ(const T &a, const T &b) { + return wbCompare(a, b) != 0; +} + +template +static inline wbBool wbEqualQ(const T *a, const T *b, size_t n) { + size_t ii; + + for (ii = 0; ii < n; ii++) { + if (wbUnequalQ(a[ii], b[ii])) { + return wbFalse; + } + } + return wbTrue; +} + +template +static inline wbBool wbUnequalQ(const T *a, const T *b, size_t n) { + return !wbEqualQ(a, b, n); +} + +#endif /* __WB_COMPARATOR_H__ */ diff --git a/CUDA_Histogram/libwb/wbDataset.cpp b/CUDA_Histogram/libwb/wbDataset.cpp new file mode 100644 index 0000000..a11f064 --- /dev/null +++ b/CUDA_Histogram/libwb/wbDataset.cpp @@ -0,0 +1,177 @@ +#include "wb.h" + +template +static inline T _min(const T &x, const T &y) { + return x < y ? x : y; +} + +template +static inline T _max(const T &x, const T &y) { + return x > y ? x : y; +} + +template +inline T lerp(const double &x, const T &start, const T &end) { + return (1 - x) * start + x * end; +} + +static inline void genRandom(void *trgt, wbType_t type, double minVal, + double maxVal) { + const int span = maxVal - minVal; + const int r = rand(); + const double rf = ((double)r) / ((double)RAND_MAX); + switch (type) { + case wbType_ascii: + *((char *)trgt) = (r % span) + minVal; // random printable character; + break; + case wbType_bit8: + *((char *)trgt) = lerp(rf, minVal, maxVal); + break; + case wbType_ubit8: + *((unsigned char *)trgt) = lerp(rf, minVal, maxVal); + break; + case wbType_integer: + *((int *)trgt) = lerp(rf, minVal, maxVal); + break; + case wbType_float: { + *((float *)trgt) = lerp(rf, minVal, maxVal); + break; + } + case wbType_double: { + *((double *)trgt) = lerp(rf, minVal, maxVal); + break; + } + case wbType_unknown: + wbAssert(false && "Invalid wbType_unknown"); + break; + } + return; +} + +static inline void *genRandomList(wbType_t type, size_t len, double minVal, + double maxVal) { + size_t ii; + void *data = wbNewArray(char, wbType_size(type) * len); + switch (type) { + case wbType_ascii: + case wbType_bit8: { + char *iter = (char *)data; + for (ii = 0; ii < len; ii++) { + genRandom(iter++, type, minVal, maxVal); + } + break; + } + case wbType_ubit8: { + unsigned char *iter = (unsigned char *)data; + for (ii = 0; ii < len; ii++) { + genRandom(iter++, type, minVal, maxVal); + } + break; + } + case wbType_integer: { + int *iter = (int *)data; + for (ii = 0; ii < len; ii++) { + genRandom(iter++, type, minVal, maxVal); + } + break; + } + case wbType_float: { + float *iter = (float *)data; + for (ii = 0; ii < len; ii++) { + genRandom(iter++, type, minVal, maxVal); + } + break; + } + case wbType_double: { + double *iter = (double *)data; + for (ii = 0; ii < len; ii++) { + genRandom(iter++, type, minVal, maxVal); + } + break; + } + case wbType_unknown: + wbAssert(false && "Invalid wbType_unknown"); + break; + } + return data; +} + +static void genRaw(const char *path, wbRaw_GenerateParams_t params) { + int rows = _max(1, params.rows); + int cols = _max(1, params.cols); + double minVal = params.minVal; + double maxVal = params.maxVal; + wbType_t type = params.type; + void *data = genRandomList(type, rows * cols, minVal, maxVal); + wbExport(path, wbExportKind_raw, data, rows, cols, type); + wbDelete(data); +} + +static void genCSV(const char *path, wbCSV_GenerateParams_t params) { + int rows = _max(1, params.rows); + int cols = _max(1, params.cols); + double minVal = params.minVal; + double maxVal = params.maxVal; + wbType_t type = params.type; + void *data = genRandomList(type, rows * cols, minVal, maxVal); + wbExport(path, wbExportKind_csv, data, rows, cols, type); + wbDelete(data); +} + +static void genTSV(const char *path, wbTSV_GenerateParams_t params) { + int rows = _max(1, params.rows); + int cols = _max(1, params.cols); + double minVal = params.minVal; + double maxVal = params.maxVal; + wbType_t type = params.type; + void *data = genRandomList(type, rows * cols, minVal, maxVal); + wbExport(path, wbExportKind_tsv, data, rows, cols, type); + wbDelete(data); +} + +static void genText(const char *path, wbText_GenerateParams_t params) { + int length = _max(1, params.length); + wbType_t type = wbType_ascii; + void *data = genRandomList(type, length, 32, 128); + wbExport(path, wbExportKind_text, data, length, 1, type); + wbDelete(data); +} + +static void genPPM(const char *path, wbPPM_GenerateParams_t params) { + int width = _max(1, params.width); + int height = _max(1, params.height); + int channels = _max(1, params.channels); + double minVal = params.minVal; + double maxVal = params.maxVal; + wbType_t type = wbType_float; + float *data = (float *)genRandomList(type, width * height * channels, + minVal, maxVal); + wbImage_t img = wbImage_new(width, height, channels, data); + wbExport(path, img); + wbImage_delete(img); +} + +EXTERN_C void wbDataset_generate(const char *path, wbExportKind_t kind, + wbGenerateParams_t params) { + wbDirectory_create(wbDirectory_name(path)); + + switch (kind) { + case wbExportKind_raw: + genRaw(path, params.raw); + break; + case wbExportKind_csv: + genCSV(path, params.csv); + break; + case wbExportKind_tsv: + genTSV(path, params.tsv); + break; + case wbExportKind_ppm: + genPPM(path, params.ppm); + break; + case wbExportKind_text: + genText(path, params.text); + break; + default: + wbAssert(false && "Invalid Export kind"); + } +} diff --git a/CUDA_Histogram/libwb/wbDataset.h b/CUDA_Histogram/libwb/wbDataset.h new file mode 100644 index 0000000..ce81c28 --- /dev/null +++ b/CUDA_Histogram/libwb/wbDataset.h @@ -0,0 +1,52 @@ +#ifndef __WB_DATASET_H__ +#define __WB_DATASET_H__ + +#include "wbImport.h" +#include "wbTypes.h" + +typedef struct { + int rows; + int cols; + wbType_t type; + double minVal; + double maxVal; +} wbCSV_GenerateParams_t; + +typedef struct { + int rows; + int cols; + wbType_t type; + double minVal; + double maxVal; +} wbTSV_GenerateParams_t; + +typedef struct { + int rows; + int cols; + double minVal; + double maxVal; + wbType_t type; +} wbRaw_GenerateParams_t; + +typedef struct { + int width; + int height; + int channels; + double minVal; + double maxVal; +} wbPPM_GenerateParams_t; + +typedef struct { int length; } wbText_GenerateParams_t; + +typedef union { + wbCSV_GenerateParams_t csv; + wbRaw_GenerateParams_t raw; + wbTSV_GenerateParams_t tsv; + wbPPM_GenerateParams_t ppm; + wbText_GenerateParams_t text; +} wbGenerateParams_t; + +EXTERN_C void wbDataset_generate(const char *path, wbExportKind_t kind, + wbGenerateParams_t params); + +#endif /* __WB_DATASET_H__ */ diff --git a/CUDA_Histogram/libwb/wbDataset_test.cpp b/CUDA_Histogram/libwb/wbDataset_test.cpp new file mode 100644 index 0000000..4f08042 --- /dev/null +++ b/CUDA_Histogram/libwb/wbDataset_test.cpp @@ -0,0 +1,23 @@ + +#include "wb.h" +#include "vendor/catch.hpp" + +TEST_CASE("Can create Raw dataset", "[DataGenerator]") { + wbGenerateParams_t params; + params.raw.rows = 2; + params.raw.cols = 300; + params.raw.minVal = 0; + params.raw.maxVal = 30; + params.raw.type = wbType_integer; + wbDataset_generate( + wbPath_join(wbDirectory_current(), "test-dataset", "test.raw"), + wbExportKind_raw, params); +} + +TEST_CASE("Can create Text dataset", "[DataGenerator]") { + wbGenerateParams_t params; + params.text.length = 2000; + wbDataset_generate( + wbPath_join(wbDirectory_current(), "test-dataset", "test.txt"), + wbExportKind_text, params); +} diff --git a/CUDA_Histogram/libwb/wbDirectory.cpp b/CUDA_Histogram/libwb/wbDirectory.cpp new file mode 100644 index 0000000..10dc8c5 --- /dev/null +++ b/CUDA_Histogram/libwb/wbDirectory.cpp @@ -0,0 +1,88 @@ +#include "wb.h" + +#ifndef PATH_MAX +#ifdef FILENAME_MAX +#define PATH_MAX FILENAME_MAX +#else /* FILENAME_MAX */ +#define PATH_MAX 4096 +#endif /* FILENAME_MAX */ +#endif /* PATH_MAX */ + +#ifdef WB_USE_UNIX +const char wbDirectorySeperator = '/'; +static char *getcwd_(char *buf, int maxLen) { + return getcwd(buf, maxLen); +} +static void mkdir_(const char *dir) { + mkdir(dir, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); +} +#else /* WB_USE_LINUX */ +const char wbDirectorySeperator = '\\'; +static char *getcwd_(char *buf, int maxLen) { + return _getcwd(buf, maxLen); +} +static void mkdir_(const char *dir) { + _mkdir(dir); +} +#endif /* WB_USE_LINUX */ + +EXTERN_C const char * wbDirectory_create(const char *dir) { + char tmp[PATH_MAX]; + char *p = NULL; + size_t len; +//PMO +#ifndef _MSC_VER + snprintf(tmp, sizeof(tmp), "%s", dir); +#else + _snprintf_s(tmp, sizeof(tmp), "%s", dir); +#endif + len = strlen(tmp); + if (tmp[len - 1] == wbDirectorySeperator) { + tmp[len - 1] = 0; + } + for (p = tmp + 1; *p; p++) { + if (*p == wbDirectorySeperator) { + *p = 0; + mkdir_(tmp); + *p = wbDirectorySeperator; + } + } + mkdir_(tmp); + return dir; +} + +EXTERN_C char *wbDirectory_name(const char *pth0) { + char *pth = wbString_duplicate(pth0); + char *p = strrchr(pth, wbDirectorySeperator); + if (p) { + p[0] = 0; + } + return pth; +} + +EXTERN_C char *wbDirectory_current() { + char *tmp = wbNewArray(char, PATH_MAX + 1); + if (getcwd_(tmp, PATH_MAX)) { + return tmp; + } + + wbDelete(tmp); + + int error = errno; + switch (error) { + case EACCES: + std::cerr + << "Cannot get current directory :: access denied. exiting..." + << std::endl; + exit(-1); + case ENOMEM: + std::cerr << "Cannot get current directory :: insufficient storage. " + "exiting..." + << std::endl; + exit(-1); + default: + std::cerr << "Cannot get current directory :: unrecognised error " + << error << std::endl; + exit(-1); + } +} \ No newline at end of file diff --git a/CUDA_Histogram/libwb/wbDirectory.h b/CUDA_Histogram/libwb/wbDirectory.h new file mode 100644 index 0000000..cb14f81 --- /dev/null +++ b/CUDA_Histogram/libwb/wbDirectory.h @@ -0,0 +1,9 @@ +#ifndef __WB_DIRECTORY__ +#define __WB_DIRECTORY__ + +extern const char wbDirectorySeperator; +EXTERN_C char *wbDirectory_name(const char *pth); +EXTERN_C const char * wbDirectory_create(const char *dir); +EXTERN_C char *wbDirectory_current(); + +#endif /* __WB_DIRECTORY__ */ diff --git a/CUDA_Histogram/libwb/wbExit.cpp b/CUDA_Histogram/libwb/wbExit.cpp new file mode 100644 index 0000000..a7edc3a --- /dev/null +++ b/CUDA_Histogram/libwb/wbExit.cpp @@ -0,0 +1,119 @@ + +#include "wb.h" + +enum { + wbMPI_timerTag = 2, + wbMPI_loggerTag = 4, + wbMPI_solutionExistsTag = 8, + wbMPI_solutionTag = 16 +}; + +void wb_atExit(void) { + using std::cout; + using std::endl; + +#ifdef WB_USE_CUDA + cudaDeviceSynchronize(); +#endif /* WB_USE_CUDA */ + + int nranks = rankCount(); + if (nranks > 1) { +#ifdef WB_USE_MPI + if (isMasterQ) { +#ifdef wbLogger_printOnExit + cout << "==$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$" << endl; + + cout << "{\n"; + cout << wbString_quote("timer") << ":"; + cout << "[\n"; + for (int ii = 0; ii < nranks; ii++) { + if (ii == 0) { + cout << wbTimer_toJSON(); + } else { + const char *msg = wbMPI_getStringFromRank(ii, wbMPI_timerTag); + if (msg != NULL && strlen(msg) != 0) { + cout << ",\n"; + cout << msg; + // free(msg); + } + } + } + cout << "]" << endl; // close timer + + cout << "," << endl; // start logger + cout << wbString_quote("logger") << ":"; + cout << "[\n"; + for (int ii = 0; ii < nranks; ii++) { + if (ii == 0) { + cout << wbLogger_toJSON(); + } else { + const char *msg = wbMPI_getStringFromRank(ii, wbMPI_loggerTag); + if (msg != NULL && strlen(msg) != 0) { + cout << ",\n"; + cout << msg; + // free(msg); + } + } + } + cout << "]" << endl; // close logger + + cout << "," << endl; // start solutionExists + cout << wbString_quote("cuda_memory") << ":" << _cudaMallocSize + << ",\n"; + + if (solutionJSON) { + cout << wbString_quote("solution_exists") << ": true,\n"; + cout << wbString_quote("solution") << ":" << solutionJSON << "\n"; + } else { + cout << wbString_quote("solution_exists") << ": false\n"; + } + cout << "}" << endl; // close json + + } else { + wbMPI_sendStringToMaster(wbTimer_toJSON().c_str(), wbMPI_timerTag); + wbMPI_sendStringToMaster(wbLogger_toJSON().c_str(), wbMPI_loggerTag); + } +#endif /* wbLogger_printOnExit */ + +#endif /* WB_USE_MPI */ + } else { +#ifdef wbLogger_printOnExit + cout << "==$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$" << endl; + + cout << "{\n" << wbString_quote("timer") << ":[" << wbTimer_toJSON() + << "],\n" << wbString_quote("logger") << ":[" << wbLogger_toJSON() + << "],\n"; + +#ifdef WB_USE_CUDA + cout << wbString_quote("cuda_memory") << ":" << _cudaMallocSize + << ",\n"; +#endif /* WB_USE_CUDA */ + + if (solutionJSON) { + cout << wbString_quote("solution_exists") << ": true,\n"; + cout << wbString_quote("solution") << ":" << solutionJSON << "\n"; + } else { + cout << wbString_quote("solution_exists") << ": false\n"; + } + cout << "}" << endl; +#endif /* wbLogger_printOnExit */ + } + + // wbTimer_delete(_timer); + // wbLogger_delete(_logger); + + _timer = NULL; + _logger = NULL; + +// wbFile_atExit(); + +#ifdef WB_USE_CUDA + cudaDeviceReset(); +#endif + + exit(0); + + // assert(0); + + return; +} diff --git a/CUDA_Histogram/libwb/wbExit.h b/CUDA_Histogram/libwb/wbExit.h new file mode 100644 index 0000000..4400108 --- /dev/null +++ b/CUDA_Histogram/libwb/wbExit.h @@ -0,0 +1,7 @@ + +#ifndef __WB_EXIT_H__ +#define __WB_EXIT_H__ + +void wb_atExit(void); + +#endif /* __WB_EXIT_H__ */ diff --git a/CUDA_Histogram/libwb/wbExport.cpp b/CUDA_Histogram/libwb/wbExport.cpp new file mode 100644 index 0000000..59b7a33 --- /dev/null +++ b/CUDA_Histogram/libwb/wbExport.cpp @@ -0,0 +1,510 @@ + +#include "wb.h" + +static inline void wbExportText_setFile(wbExportText_t text, + const char *path) { + if (text != NULL) { + if (wbExportText_getFile(text) != NULL) { + wbFile_delete(wbExportText_getFile(text)); + } + if (path != NULL) { + wbExportText_getFile(text) = wbFile_open(path, "w+"); + } else { + wbExportText_getFile(text) = NULL; + } + } + + return; +} + +static inline wbExportText_t wbExportText_new(void) { + wbExportText_t text; + + text = wbNew(struct st_wbExportText_t); + + wbExportText_getFile(text) = NULL; + wbExportText_setLength(text, -1); + + return text; +} + +static inline void wbExportText_delete(wbExportText_t text) { + if (text != NULL) { + wbExportText_setFile(text, NULL); + wbDelete(text); + } + return; +} + +static inline void wbExportText_write(wbExportText_t text, + const char *data, int length) { + int ii; + FILE *handle; + wbFile_t file; + + if (text == NULL || wbExportText_getFile(text) == NULL) { + return; + } + + file = wbExportText_getFile(text); + + handle = wbFile_getFileHandle(file); + + if (handle == NULL) { + return; + } + + for (ii = 0; ii < length; ii++) { + fprintf(handle, "%c", data[ii]); + } + + return; +} + +static inline void wbExportRaw_setFile(wbExportRaw_t raw, + const char *path) { + if (raw != NULL) { + if (wbExportRaw_getFile(raw) != NULL) { + wbFile_delete(wbExportRaw_getFile(raw)); + } + if (path != NULL) { + wbExportRaw_getFile(raw) = wbFile_open(path, "w+"); + } else { + wbExportRaw_getFile(raw) = NULL; + } + } + + return; +} + +static inline wbExportRaw_t wbExportRaw_new(void) { + wbExportRaw_t raw; + + raw = wbNew(struct st_wbExportRaw_t); + + wbExportRaw_getFile(raw) = NULL; + wbExportRaw_setRowCount(raw, -1); + wbExportRaw_setColumnCount(raw, -1); + + return raw; +} + +static inline void wbExportRaw_delete(wbExportRaw_t raw) { + if (raw != NULL) { + wbExportRaw_setFile(raw, NULL); + wbDelete(raw); + } + return; +} + +static inline void wbExportRaw_write(wbExportRaw_t raw, void *data, + int rows, int columns, + wbType_t type) { + int ii, jj; + FILE *handle; + wbFile_t file; + + if (raw == NULL || wbExportRaw_getFile(raw) == NULL) { + return; + } + + file = wbExportRaw_getFile(raw); + + handle = wbFile_getFileHandle(file); + + if (handle == NULL) { + return; + } + + if (columns == 1) { + fprintf(handle, "%d\n", rows); + } else { + fprintf(handle, "%d %d\n", rows, columns); + } + + for (ii = 0; ii < rows; ii++) { + for (jj = 0; jj < columns; jj++) { + if (type == wbType_integer) { + int elem = ((int *)data)[ii * columns + jj]; + fprintf(handle, "%d", elem); + } else if (type == wbType_ubit8) { + int elem = ((unsigned char *)data)[ii * columns + jj]; + fprintf(handle, "%d", elem); + } else { + wbReal_t elem = ((wbReal_t *)data)[ii * columns + jj]; + fprintf(handle, "%f", elem); + } + if (jj == columns - 1) { + fprintf(handle, "\n"); + } else { + fprintf(handle, " "); + } + } + } + + return; +} + +static inline void wbExportCSV_setFile(wbExportCSV_t csv, + const char *path) { + if (csv != NULL) { + if (wbExportCSV_getFile(csv) != NULL) { + wbFile_delete(wbExportCSV_getFile(csv)); + } + if (path != NULL) { + wbExportCSV_getFile(csv) = wbFile_open(path, "w+"); + } else { + wbExportCSV_getFile(csv) = NULL; + } + } + + return; +} + +static inline wbExportCSV_t wbExportCSV_new(void) { + wbExportCSV_t csv; + + csv = wbNew(struct st_wbExportCSV_t); + + wbExportCSV_getFile(csv) = NULL; + wbExportCSV_setColumnCount(csv, -1); + wbExportCSV_setRowCount(csv, -1); + wbExportCSV_setSeperator(csv, '\0'); + + return csv; +} + +static inline void wbExportCSV_delete(wbExportCSV_t csv) { + if (csv != NULL) { + wbExportCSV_setFile(csv, NULL); + wbDelete(csv); + } +} + +static inline void wbExportCSV_write(wbExportCSV_t csv, void *data, + int rows, int columns, char sep, + wbType_t type) { + int ii, jj; + wbFile_t file; + FILE *handle; + char seperator[2]; + + if (csv == NULL || wbExportCSV_getFile(csv) == NULL) { + return; + } + + file = wbExportCSV_getFile(csv); + + handle = wbFile_getFileHandle(file); + + if (handle == NULL) { + return; + } + + if (sep == '\0') { + seperator[0] = ','; + } else { + seperator[0] = sep; + } + seperator[1] = '\0'; + + for (ii = 0; ii < rows; ii++) { + for (jj = 0; jj < columns; jj++) { + if (type == wbType_integer) { + int elem = ((int *)data)[ii * columns + jj]; + fprintf(handle, "%d", elem); + } else if (type == wbType_ubit8) { + int elem = ((unsigned char *)data)[ii * columns + jj]; + fprintf(handle, "%d", elem); + } else { + wbReal_t elem = ((wbReal_t *)data)[ii * columns + jj]; + fprintf(handle, "%f", elem); + } + if (jj == columns - 1) { + fprintf(handle, "\n"); + } else { + fprintf(handle, "%s", seperator); + } + } + } + + return; +} + +static inline wbExport_t wbExport_open(const char *file, + wbExportKind_t kind) { + wbExport_t exprt; + + if (file == NULL) { + wbLog(ERROR, "Go NULL for file value."); + wbExit(); + } + + wbExport_setFile(exprt, NULL); + wbExport_setKind(exprt, kind); + + if (kind == wbExportKind_raw) { + wbExportRaw_t raw = wbExportRaw_new(); + wbExportRaw_setFile(raw, file); + wbExport_setRaw(exprt, raw); + } else if (kind == wbExportKind_text) { + wbExportText_t txt = wbExportText_new(); + wbExportText_setFile(txt, file); + wbExport_setText(exprt, txt); + } else if (kind == wbExportKind_tsv || kind == wbExportKind_csv) { + wbExportCSV_t csv = wbExportCSV_new(); + if (kind == wbExportKind_csv) { + wbExportCSV_setSeperator(csv, ','); + } else { + wbExportCSV_setSeperator(csv, '\t'); + } + wbExportCSV_setFile(csv, file); + wbExport_setCSV(exprt, csv); + } else if (kind == wbExportKind_ppm) { + wbExport_setFile(exprt, wbString_duplicate(file)); + } else { + wbLog(ERROR, "Invalid export type."); + wbExit(); + } + + return exprt; +} + +static inline wbExport_t wbExport_open(const char *file, + const char *type0) { + wbExport_t exprt; + wbExportKind_t kind; + char *type; + + type = wbString_toLower(type0); + + if (wbString_sameQ(type, "csv")) { + kind = wbExportKind_csv; + } else if (wbString_sameQ(type, "tsv")) { + kind = wbExportKind_tsv; + } else if (wbString_sameQ(type, "raw") || wbString_sameQ(type, "dat")) { + kind = wbExportKind_raw; + } else if (wbString_sameQ(type, "ppm") || wbString_sameQ(type, "pbm")) { + kind = wbExportKind_ppm; + } else if (wbString_sameQ(type, "txt") || wbString_sameQ(type, "text")) { + kind = wbExportKind_text; + } else { + wbLog(ERROR, "Invalid export type ", type0); + wbExit(); + } + + exprt = wbExport_open(file, kind); + + wbDelete(type); + + return exprt; +} + +static inline void wbExport_close(wbExport_t exprt) { + wbExportKind_t kind; + + kind = wbExport_getKind(exprt); + + if (wbExport_getFile(exprt)) { + wbDelete(wbExport_getFile(exprt)); + } + + if (kind == wbExportKind_tsv || kind == wbExportKind_csv) { + wbExportCSV_t csv = wbExport_getCSV(exprt); + wbExportCSV_delete(csv); + wbExport_setCSV(exprt, NULL); + } else if (kind == wbExportKind_raw) { + wbExportRaw_t raw = wbExport_getRaw(exprt); + wbExportRaw_delete(raw); + wbExport_setRaw(exprt, NULL); + } else if (kind == wbExportKind_text) { + wbExportText_t text = wbExport_getText(exprt); + wbExportText_delete(text); + wbExport_setText(exprt, NULL); + } else if (kind == wbExportKind_ppm) { + } else { + wbLog(ERROR, "Invalid export type."); + wbExit(); + } + return; +} + +static inline void wbExport_writeAsImage(wbExport_t exprt, wbImage_t img) { + wbAssert(wbExport_getKind(exprt) == wbExportKind_ppm); + + wbPPM_export(wbExport_getFile(exprt), img); + + return; +} + +static inline void wbExport_write(wbExport_t exprt, void *data, int rows, + int columns, char sep, wbType_t type) { + wbExportKind_t kind; + + kind = wbExport_getKind(exprt); + if (kind == wbExportKind_tsv || kind == wbExportKind_csv) { + wbExportCSV_t csv = wbExport_getCSV(exprt); + wbExportCSV_write(csv, data, rows, columns, sep, type); + } else if (kind == wbExportKind_raw) { + wbExportRaw_t raw = wbExport_getRaw(exprt); + wbExportRaw_write(raw, data, rows, columns, type); + } else if (kind == wbExportKind_text) { + wbExportText_t text = wbExport_getText(exprt); + if (columns == 0) { + columns = 1; + } + if (rows == 0) { + rows = 1; + } + wbExportText_write(text, (const char *)data, rows * columns); + } else { + wbLog(ERROR, "Invalid export type."); + wbExit(); + } + return; +} + +static inline void wbExport_write(wbExport_t exprt, void *data, int rows, + int columns, wbType_t type) { + wbExport_write(exprt, data, rows, columns, ',', type); +} + +static wbExportKind_t _parseExportExtension(const char *file) { + char *extension; + wbExportKind_t kind; + + extension = wbFile_extension(file); + + if (wbString_sameQ(extension, "csv")) { + kind = wbExportKind_csv; + } else if (wbString_sameQ(extension, "tsv")) { + kind = wbExportKind_tsv; + } else if (wbString_sameQ(extension, "raw") || + wbString_sameQ(extension, "dat")) { + kind = wbExportKind_raw; + } else if (wbString_sameQ(extension, "text") || + wbString_sameQ(extension, "txt")) { + kind = wbExportKind_text; + } else if (wbString_sameQ(extension, "ppm")) { + kind = wbExportKind_ppm; + } else { + kind = wbExportKind_unknown; + wbLog(ERROR, "File ", file, " does not have a compatible extension."); + } + + wbDelete(extension); + + return kind; +} + +static void wbExport(const char *file, void *data, int rows, int columns, + wbType_t type) { + wbExportKind_t kind; + wbExport_t exprt; + + if (file == NULL) { + return; + } + + kind = _parseExportExtension(file); + exprt = wbExport_open(file, kind); + + wbExport_write(exprt, data, rows, columns, type); + wbExport_close(exprt); +} + +void wbExport(const char *file, unsigned char *data, int rows) { + wbExport(file, data, rows, 1); + return; +} + +void wbExport(const char *file, int *data, int rows) { + wbExport(file, data, rows, 1); + return; +} + +void wbExport(const char *file, wbReal_t *data, int rows) { + wbExport(file, data, rows, 1); + return; +} + +void wbExport(const char *file, unsigned char *data, int rows, + int columns) { + wbExportKind_t kind; + wbExport_t exprt; + + if (file == NULL) { + return; + } + + kind = _parseExportExtension(file); + exprt = wbExport_open(file, kind); + + wbExport_write(exprt, data, rows, columns, wbType_ubit8); + wbExport_close(exprt); +} + +void wbExport(const char *file, int *data, int rows, int columns) { + wbExportKind_t kind; + wbExport_t exprt; + + if (file == NULL) { + return; + } + + kind = _parseExportExtension(file); + exprt = wbExport_open(file, kind); + + wbExport_write(exprt, data, rows, columns, wbType_integer); + wbExport_close(exprt); +} + +void wbExport(const char *file, wbReal_t *data, int rows, int columns) { + wbExportKind_t kind; + wbExport_t exprt; + + if (file == NULL) { + return; + } + + kind = _parseExportExtension(file); + exprt = wbExport_open(file, kind); + + wbExport_write(exprt, data, rows, columns, wbType_real); + wbExport_close(exprt); +} + +void wbExport(const char *file, wbExportKind_t kind, void *data, int rows, + int columns, wbType_t type) { + wbExport_t exprt; + + if (file == NULL) { + return; + } + + exprt = wbExport_open(file, kind); + + wbExport_write(exprt, data, rows, columns, type); + wbExport_close(exprt); +} + +void wbExport(const char *file, wbImage_t img) { + wbExportKind_t kind; + wbExport_t exprt; + + if (file == NULL) { + return; + } + + kind = _parseExportExtension(file); + exprt = wbExport_open(file, kind); + + wbAssert(kind == wbExportKind_ppm); + + wbExport_writeAsImage(exprt, img); + wbExport_close(exprt); +} + +void wbExport_text(const char *file, void *data, int length) { + wbExport(file, wbExportKind_text, data, 1, length, wbType_ascii); +} diff --git a/CUDA_Histogram/libwb/wbExport.h b/CUDA_Histogram/libwb/wbExport.h new file mode 100644 index 0000000..dd16b3f --- /dev/null +++ b/CUDA_Histogram/libwb/wbExport.h @@ -0,0 +1,106 @@ + + +#ifndef __WB_EXPORT_H__ +#define __WB_EXPORT_H__ + +#include "wb.h" +#include "wbFile.h" +#include "wbPPM.h" + +typedef enum en_wbExportKind_t { + wbExportKind_unknown = -1, + wbExportKind_raw = 0x1000, + wbExportKind_csv, + wbExportKind_tsv, + wbExportKind_ppm, + wbExportKind_text, +} wbExportKind_t; + +typedef struct st_wbExportText_t { + int length; + wbFile_t file; +} * wbExportText_t; + +#define wbExportText_getLength(txt) ((txt)->length) +#define wbExportText_getFile(txt) ((txt)->file) + +#define wbExportText_setLength(txt, val) \ + (wbExportText_getLength(txt) = val) + +typedef struct st_wbExportRaw_t { + int rows; + int columns; + wbFile_t file; +} * wbExportRaw_t; + +#define wbExportRaw_getColumnCount(raw) ((raw)->columns) +#define wbExportRaw_getRowCount(raw) ((raw)->rows) +#define wbExportRaw_getFile(raw) ((raw)->file) + +#define wbExportRaw_setRowCount(raw, val) \ + (wbExportRaw_getRowCount(raw) = val) +#define wbExportRaw_setColumnCount(raw, val) \ + (wbExportRaw_getColumnCount(raw) = val) + +typedef struct st_wbExportCSV_t { + int rows; + int columns; + wbFile_t file; + char seperator; +} * wbExportCSV_t; + +#define wbExportCSV_getRowCount(csv) ((csv)->rows) +#define wbExportCSV_getColumnCount(csv) ((csv)->columns) +#define wbExportCSV_getFile(csv) ((csv)->file) +#define wbExportCSV_getSeperator(csv) ((csv)->seperator) + +#define wbExportCSV_setRowCount(csv, val) \ + (wbExportCSV_getRowCount(csv) = val) +#define wbExportCSV_setColumnCount(csv, val) \ + (wbExportCSV_getColumnCount(csv) = val) +#define wbExportCSV_setSeperator(csv, val) \ + (wbExportCSV_getSeperator(csv) = val) + +typedef struct st_wbExport_t { + wbExportKind_t kind; + union { + wbExportRaw_t raw; + wbExportCSV_t csv; + wbImage_t img; + wbExportText_t text; + } container; + char *file; +} wbExport_t; + +#define wbExport_getKind(exprt) ((exprt).kind) +#define wbExport_getContainer(exprt) ((exprt).container) +#define wbExport_getRaw(exprt) (wbExport_getContainer(exprt).raw) +#define wbExport_getCSV(exprt) (wbExport_getContainer(exprt).csv) +#define wbExport_getImage(exprt) (wbExport_getContainer(exprt).img) +#define wbExport_getText(exprt) (wbExport_getContainer(exprt).text) +#define wbExport_getFile(exprt) ((exprt).file) + +#define wbExport_setKind(exprt, val) (wbExport_getKind(exprt) = val) +#define wbExport_setRaw(exprt, val) (wbExport_getRaw(exprt) = val) +#define wbExport_setCSV(exprt, val) (wbExport_getCSV(exprt) = val) +#define wbExport_setImage(exprt, val) (wbExport_getImage(exprt) = val) +#define wbExport_setText(exprt, val) (wbExport_getText(exprt) = val) +#define wbExport_setFile(exprt, val) (wbExport_getFile(exprt) = val) + +void wbExport(const char *file, int *data, int rows, int columns); +void wbExport(const char *file, int *data, int rows); +void wbExport(const char *file, unsigned char *data, int rows, + int columns); +void wbExport(const char *file, unsigned char *data, int rows); +void wbExport(const char *file, int *data, int rows, int columns); +void wbExport(const char *file, int *data, int rows); +void wbExport(const char *file, wbReal_t *data, int rows, int columns); +void wbExport(const char *file, wbReal_t *data, int rows); +void wbExport(const char *file, wbImage_t img); + +void wbExport(const char *file, wbExportKind_t kind, void *data, int rows, + int columns, wbType_t type); + +void wbExport_text(const char *file, void *data, int length); + +#endif /* __WB_EXPORT_H__ */ diff --git a/CUDA_Histogram/libwb/wbFile.cpp b/CUDA_Histogram/libwb/wbFile.cpp new file mode 100644 index 0000000..b3fdbe7 --- /dev/null +++ b/CUDA_Histogram/libwb/wbFile.cpp @@ -0,0 +1,353 @@ + + +#include "wb.h" + +#define wbFile_maxCount 256 + +static wbFile_t wbFile_handles[wbFile_maxCount]; + +static int wbFile_nextIndex(void) { + int ii; + for (ii = 0; ii < wbFile_maxCount; ii++) { + if (wbFile_handles[ii] == NULL) { + return ii; + } + } + wbLog(ERROR, "Ran out of file handles."); + wbExit(); + return -1; +} + +wbFile_t wbFile_new(void) { + int idx = wbFile_nextIndex(); + wbFile_t file = wbNew(struct st_wbFile_t); + + wbAssert(idx >= 0); + + wbFile_setIndex(file, idx); + wbFile_setFileName(file, NULL); + wbFile_setMode(file, NULL); + wbFile_setFileHandle(file, NULL); + wbFile_setData(file, NULL); + + wbFile_handles[idx] = file; + + return file; +} + +void wbFile_delete(wbFile_t file) { + if (file != NULL) { + int idx = wbFile_getIndex(file); + if (wbFile_getFileName(file) != NULL) { + wbDelete(wbFile_getFileName(file)); + } + if (wbFile_getMode(file) != NULL) { + wbDelete(wbFile_getMode(file)); + } + if (wbFile_getFileHandle(file) != NULL) { + fflush(wbFile_getFileHandle(file)); + fclose(wbFile_getFileHandle(file)); + } + if (idx >= 0) { + wbAssert(wbFile_handles[idx] == file); + wbFile_handles[idx] = NULL; + } + if (wbFile_getData(file) != NULL) { + wbDelete(wbFile_getData(file)); + } + wbDelete(file); + } +} + +void wbFile_init(void) { + int ii; + + for (ii = 0; ii < wbFile_maxCount; ii++) { + wbFile_handles[ii] = NULL; + } +} + +void wbFile_atExit(void) { + int ii; + + for (ii = 0; ii < wbFile_maxCount; ii++) { + if (wbFile_handles[ii] != NULL) { + wbFile_delete(wbFile_handles[ii]); + } + } +} + +int wbFile_count(void) { + int ii, count = 0; + + for (ii = 0; ii < wbFile_maxCount; ii++) { + if (wbFile_handles[ii] != NULL) { + count++; + } + } + return count; +} + +wbFile_t wbFile_open(const char *fileName, const char *mode) { + FILE *handle; + wbFile_t file; + + if (fileName == NULL) { + return NULL; + } + + handle = fopen(fileName, mode); + if (handle == NULL) { + wbLog(ERROR, "Failed to open ", file, " in mode ", mode); + return NULL; + } + + file = wbFile_new(); + wbFile_setFileName(file, wbString_duplicate(fileName)); + wbFile_setMode(file, wbString_duplicate(mode)); + wbFile_setFileHandle(file, handle); + + return file; +} + +wbFile_t wbFile_open(const char *fileName) { + return wbFile_open(fileName, "r"); +} + +void wbFile_close(wbFile_t file) { + wbFile_delete(file); +} + +char *wbFile_read(wbFile_t file, size_t size, size_t count) { + size_t res; + char *buffer; + size_t bufferLen; + FILE *handle; + + if (file == NULL) { + return NULL; + } +#ifndef LAZY_FILE_LOAD + if (wbFile_getData(file) != NULL) { + char *data = wbFile_getData(file) + wbFile_getDataOffset(file); + wbFile_setDataOffset(file, wbFile_getDataOffset(file) + size * count); + return data; + } +#endif /* LAZY_FILE_LOAD */ + + handle = wbFile_getFileHandle(file); + bufferLen = size * count + 1; + buffer = wbNewArray(char, bufferLen); + + res = fread(buffer, size, count, handle); + // make valid C string + buffer[size * res] = '\0'; + + return buffer; +} + +char *wbFile_read(wbFile_t file, size_t len) { + char *buffer = wbFile_read(file, sizeof(char), len); + return buffer; +} + +void wbFile_rewind(wbFile_t file) { + if (file == NULL) { + return; + } + + if (wbFile_getData(file) == NULL) { + FILE *handle; + handle = wbFile_getFileHandle(file); + wbAssert(handle != NULL); + rewind(handle); + } +#ifndef LAZY_FILE_LOAD + else { + wbFile_setDataOffset(file, 0); + } +#endif + + return; +} + +size_t wbFile_size(wbFile_t file) { + size_t len; + FILE *handle; + + if (file == NULL) { + return 0; + } +#ifndef LAZY_FILE_LOAD + if (wbFile_getData(file) != NULL) { + if (wbFile_getLength(file) == 0) { + wbFile_setLength(file, strlen(wbFile_getData(file))); + } + return wbFile_getLength(file); + } +#endif /* LAZY_FILE_LOAD */ + + handle = wbFile_getFileHandle(file); + + fseek(handle, 0, SEEK_END); + len = ftell(handle); + rewind(handle); + + return len; +} + +char *wbFile_read(wbFile_t file) { + size_t len; + + if (file == NULL) { + return NULL; + } + + len = wbFile_size(file); + + if (len == 0) { + return NULL; + } + + wbFile_setLength(file, len); + + return wbFile_read(file, len); +} + +#define MAX_CHARS_PER_LINE (1 << 17) + +static char buffer[MAX_CHARS_PER_LINE]; + +char *wbFile_readLine(wbFile_t file) { + if (file == NULL) { + return NULL; + } +#ifdef LAZY_FILE_LOAD + FILE *handle; + memset(buffer, 0, MAX_CHARS_PER_LINE); + + handle = wbFile_getFileHandle(file); + + if (fgets(buffer, MAX_CHARS_PER_LINE - 1, handle)) { + return buffer; + } else { + // wbLog(ERROR, "Was not able to read line from ", + // wbFile_getFileName(file)); + return NULL; + } +#else + size_t newOffset; + size_t lenToNewLine = 0; + const char *tmp; + + if (wbFile_getData(file) == NULL) { + wbFile_setData(file, wbFile_read(file)); + fclose(wbFile_getFileHandle(file)); + wbFile_setFileHandle(file, NULL); + wbFile_setDataOffset(file, 0); + wbFile_setLength(file, strlen(wbFile_getData(file))); + } + + memset(buffer, 0, MAX_CHARS_PER_LINE); + + if (wbFile_getDataOffset(file) >= wbFile_getLength(file)) { + return NULL; + } + + newOffset = wbFile_getDataOffset(file); + tmp = wbFile_getData(file) + wbFile_getDataOffset(file); + while (newOffset < wbFile_getLength(file) && *tmp != '\n') { + tmp++; + lenToNewLine++; + newOffset++; + } + + memcpy(buffer, wbFile_getData(file) + wbFile_getDataOffset(file), + lenToNewLine); + wbFile_setDataOffset(file, newOffset + 1); + + return buffer; +#endif +} + +void wbFile_write(wbFile_t file, const void *buffer, size_t size, + size_t count) { + size_t res; + FILE *handle; + + if (file == NULL) { + return; + } + + handle = wbFile_getFileHandle(file); + + res = fwrite(buffer, size, count, handle); + if (res != count) { + wbLog(ERROR, "Failed to write data to ", wbFile_getFileName(file)); + } + + return; +} + +void wbFile_write(wbFile_t file, const void *buffer, size_t len) { + wbFile_write(file, buffer, sizeof(char), len); + return; +} + +void wbFile_write(wbFile_t file, const char *buffer) { + size_t len; + + len = strlen(buffer); + wbFile_write(file, buffer, len); + + return; +} + +void wbFile_writeLine(wbFile_t file, const char *buffer0) { + string buffer = wbString(buffer0, "\n"); + wbFile_write(file, buffer.c_str()); +} + +void wbFile_write(wbFile_t file, string buffer) { + wbFile_write(file, buffer.c_str()); +} + +void wbFile_writeLine(wbFile_t file, string buffer0) { + string buffer = buffer0 + "\n"; + wbFile_write(file, buffer.c_str()); +} + +wbBool wbFile_existsQ(const char *path) { + if (path == NULL) { + return wbFalse; + } else { + FILE *file = fopen(path, "r"); + if (file != NULL) { + fclose(file); + return wbTrue; + } + return wbFalse; + } +} + +char *wbFile_extension(const char *file) { + char *extension; + char *extensionLower; + char *end; + size_t len; + + len = strlen(file); + end = (char *)&file[len - 1]; + while (*end != '.') { + end--; + } + if (*end == '.') { + end++; + } + + extension = wbString_duplicate(end); + extensionLower = wbString_toLower(extension); + wbDelete(extension); + + return extensionLower; +} diff --git a/CUDA_Histogram/libwb/wbFile.h b/CUDA_Histogram/libwb/wbFile.h new file mode 100644 index 0000000..ea6b0cb --- /dev/null +++ b/CUDA_Histogram/libwb/wbFile.h @@ -0,0 +1,56 @@ + + +#ifndef __WB_FILE_H__ +#define __WB_FILE_H__ + +struct st_wbFile_t { + int index; + char *file; + char *mode; + char *data; + FILE *handle; + size_t len; + size_t offset; +}; + +#define wbFile_getIndex(file) ((file)->index) +#define wbFile_getFileName(file) ((file)->file) +#define wbFile_getMode(file) ((file)->mode) +#define wbFile_getData(file) ((file)->data) +#define wbFile_getLength(file) ((file)->len) +#define wbFile_getDataOffset(file) ((file)->offset) +#define wbFile_getFileHandle(file) ((file)->handle) + +#define wbFile_setIndex(file, val) (wbFile_getIndex(file) = val) +#define wbFile_setFileName(file, val) (wbFile_getFileName(file) = val) +#define wbFile_setMode(file, val) (wbFile_getMode(file) = val) +#define wbFile_setData(file, val) (wbFile_getData(file) = val) +#define wbFile_setLength(file, val) (wbFile_getLength(file) = val) +#define wbFile_setDataOffset(file, val) (wbFile_getDataOffset(file) = val) +#define wbFile_setFileHandle(file, val) (wbFile_getFileHandle(file) = val) + +wbFile_t wbFile_new(void); +void wbFile_delete(wbFile_t file); +void wbFile_close(wbFile_t file); +void wbFile_init(void); +void wbFile_atExit(void); +int wbFile_count(void); +wbFile_t wbFile_open(const char *fileName, const char *mode); +wbFile_t wbFile_open(const char *fileName); +char *wbFile_read(wbFile_t file, size_t size, size_t count); +char *wbFile_read(wbFile_t file, size_t len); +void wbFile_rewind(wbFile_t file); +size_t wbFile_size(wbFile_t file); +char *wbFile_read(wbFile_t file); +char *wbFile_readLine(wbFile_t file); +void wbFile_write(wbFile_t file, const void *buffer, size_t size, + size_t count); +void wbFile_write(wbFile_t file, const void *buffer, size_t len); +void wbFile_write(wbFile_t file, const char *buffer); +void wbFile_writeLine(wbFile_t file, const char *buffer0); +void wbFile_write(wbFile_t file, string buffer); +void wbFile_writeLine(wbFile_t file, string buffer0); +wbBool wbFile_existsQ(const char *path); +char *wbFile_extension(const char *file); + +#endif /* __WB_FILE_H__ */ diff --git a/CUDA_Histogram/libwb/wbImage.cpp b/CUDA_Histogram/libwb/wbImage.cpp new file mode 100644 index 0000000..1d95928 --- /dev/null +++ b/CUDA_Histogram/libwb/wbImage.cpp @@ -0,0 +1,134 @@ + + +#include "wb.h" + +static inline float _min(float x, float y) { + return x < y ? x : y; +} + +static inline float _max(float x, float y) { + return x > y ? x : y; +} + +static inline float _clamp(float x, float start, float end) { + return _min(_max(x, start), end); +} + +wbImage_t wbImage_new(int width, int height, int channels, float *data) { + wbImage_t img; + + img = wbNew(struct st_wbImage_t); + + wbImage_setWidth(img, width); + wbImage_setHeight(img, height); + wbImage_setChannels(img, channels); + wbImage_setPitch(img, width * channels); + + wbImage_setData(img, data); + return img; +} + +wbImage_t wbImage_new(int width, int height, int channels) { + float *data = wbNewArray(float, width *height *channels); + return wbImage_new(width, height, channels, data); +} + +wbImage_t wbImage_new(int width, int height) { + return wbImage_new(width, height, wbImage_channels); +} + +void wbImage_delete(wbImage_t img) { + if (img != NULL) { + if (wbImage_getData(img) != NULL) { + wbDelete(wbImage_getData(img)); + } + wbDelete(img); + } +} + +static inline void wbImage_setPixel(wbImage_t img, int x, int y, int c, + float val) { + float *data = wbImage_getData(img); + int channels = wbImage_getChannels(img); + int pitch = wbImage_getPitch(img); + + data[y * pitch + x * channels + c] = val; + + return; +} + +static inline float wbImage_getPixel(wbImage_t img, int x, int y, int c) { + float *data = wbImage_getData(img); + int channels = wbImage_getChannels(img); + int pitch = wbImage_getPitch(img); + + return data[y * pitch + x * channels + c]; +} + +wbBool wbImage_sameQ(wbImage_t a, wbImage_t b, + wbImage_onSameFunction_t onUnSame) { + if (a == NULL || b == NULL) { + wbLog(ERROR, "Comparing null images."); + return wbFalse; + } else if (a == b) { + return wbTrue; + } else if (wbImage_getWidth(a) != wbImage_getWidth(b)) { + wbLog(ERROR, "Image widths do not match."); + return wbFalse; + } else if (wbImage_getHeight(a) != wbImage_getHeight(b)) { + wbLog(ERROR, "Image heights do not match."); + return wbFalse; + } else if (wbImage_getChannels(a) != wbImage_getChannels(b)) { + wbLog(ERROR, "Image channels do not match."); + return wbFalse; + } else { + float *aData, *bData; + int width, height, channels; + int ii, jj, kk; + + aData = wbImage_getData(a); + bData = wbImage_getData(b); + + wbAssert(aData != NULL); + wbAssert(bData != NULL); + + width = wbImage_getWidth(a); + height = wbImage_getHeight(a); + channels = wbImage_getChannels(a); + + for (ii = 0; ii < height; ii++) { + for (jj = 0; jj < width; jj++) { + for (kk = 0; kk < channels; kk++) { + float x, y; + if (channels <= 3) { + x = _clamp(*aData++, 0, 1); + y = _clamp(*bData++, 0, 1); + } else { + x = *aData++; + y = *bData++; + } + if (wbUnequalQ(x, y)) { + if (onUnSame != NULL) { + string str = wbString( + "Image pixels do not match at position ( row = ", + wbString(ii, ", col = ", jj, ", channel = ", kk, + ") expecting a value of "), + wbString(y, " but got a computed value of ", x)); + onUnSame(str); + } + return wbFalse; + } + } + } + } + return wbTrue; + } +} + +static void wbImage_onUnsameFunction(string str) { + wbLog(ERROR, str); +} + +wbBool wbImage_sameQ(wbImage_t a, wbImage_t b) { + return wbImage_sameQ(a, b, wbImage_onUnsameFunction); +} diff --git a/CUDA_Histogram/libwb/wbImage.h b/CUDA_Histogram/libwb/wbImage.h new file mode 100644 index 0000000..020eec5 --- /dev/null +++ b/CUDA_Histogram/libwb/wbImage.h @@ -0,0 +1,40 @@ + + +#ifndef __IMAGE_H__ +#define __IMAGE_H__ + +#include "wbTypes.h" + +struct st_wbImage_t { + int width; + int height; + int channels; + int pitch; + float *data; +}; + +#define wbImage_channels 3 + +#define wbImage_getWidth(img) ((img)->width) +#define wbImage_getHeight(img) ((img)->height) +#define wbImage_getChannels(img) ((img)->channels) +#define wbImage_getPitch(img) ((img)->pitch) +#define wbImage_getData(img) ((img)->data) + +#define wbImage_setWidth(img, val) (wbImage_getWidth(img) = val) +#define wbImage_setHeight(img, val) (wbImage_getHeight(img) = val) +#define wbImage_setChannels(img, val) (wbImage_getChannels(img) = val) +#define wbImage_setPitch(img, val) (wbImage_getPitch(img) = val) +#define wbImage_setData(img, val) (wbImage_getData(img) = val) + +typedef void (*wbImage_onSameFunction_t)(string str); + +wbImage_t wbImage_new(int width, int height, int channels, float *data); +wbImage_t wbImage_new(int width, int height, int channels); +wbImage_t wbImage_new(int width, int height); +void wbImage_delete(wbImage_t img); +wbBool wbImage_sameQ(wbImage_t a, wbImage_t b, + wbImage_onSameFunction_t onUnSame); +wbBool wbImage_sameQ(wbImage_t a, wbImage_t b); + +#endif /* __IMAGE_H__ */ diff --git a/CUDA_Histogram/libwb/wbImport.cpp b/CUDA_Histogram/libwb/wbImport.cpp new file mode 100644 index 0000000..fccc071 --- /dev/null +++ b/CUDA_Histogram/libwb/wbImport.cpp @@ -0,0 +1,711 @@ + + +#include "wb.h" + +static inline void wbImportCSV_setFile(wbImportCSV_t csv, + const char *path) { + if (csv != NULL) { + if (wbImportCSV_getFile(csv) != NULL) { + wbFile_delete(wbImportCSV_getFile(csv)); + } + if (path != NULL) { + wbImportCSV_getFile(csv) = wbFile_open(path, "r"); + } else { + wbImportCSV_getFile(csv) = NULL; + } + } + + return; +} + +static inline wbImportCSV_t wbImportCSV_new(void) { + wbImportCSV_t csv; + + csv = wbNew(struct st_wbImportCSV_t); + + wbImportCSV_setRowCount(csv, -1); + wbImportCSV_setColumnCount(csv, -1); + wbImportCSV_setData(csv, NULL); + wbImportCSV_getFile(csv) = NULL; + wbImportCSV_setSeperator(csv, '\0'); + + return csv; +} + +static inline void wbImportCSV_delete(wbImportCSV_t csv) { + if (csv != NULL) { + wbImportCSV_setFile(csv, NULL); + if (wbImportCSV_getData(csv)) { + wbDelete(wbImportCSV_getData(csv)); + } + wbDelete(csv); + } +} + +static inline wbImportCSV_t wbImportCSV_findDimensions(wbImportCSV_t csv, + int *resRows, + int *resColumns) { + int rows = 0, columns = -1; + char *line; + wbFile_t file; + char seperator[2]; + + if (csv == NULL) { + return NULL; + } + + if (wbImportCSV_getSeperator(csv) == '\0') { + seperator[0] = ','; + } else { + seperator[0] = wbImportCSV_getSeperator(csv); + } + seperator[1] = '\0'; + + file = wbImportCSV_getFile(csv); + + while ((line = wbFile_readLine(file)) != NULL) { + int currColumn = 0; + char *token = strtok(line, seperator); + while (token != NULL) { + token = strtok(NULL, seperator); + currColumn++; + } + rows++; + if (columns == -1) { + columns = currColumn; + } + if (columns != currColumn) { + wbLog(ERROR, "The csv file is not rectangular."); + } + wbAssert(columns == currColumn); + } + + wbFile_rewind(file); + + *resRows = rows; + *resColumns = columns; + + return csv; +} + +static inline int *csv_readAsInteger(wbFile_t file, char sep, int rows, + int columns) { + int ii = 0; + int *data; + char *line; + int var; + char seperator[2]; + + if (file == NULL) { + return NULL; + } + + data = wbNewArray(int, rows *columns); + + if (sep == '\0') { + seperator[0] = ','; + } else { + seperator[0] = sep; + } + seperator[1] = '\0'; + + // printf("cols = %d rows = %d\n", columns, rows); + if (columns == 1) { + while ((line = wbFile_readLine(file)) != NULL) { + sscanf(line, "%d", &var); + // printf("reading %d\n", var); + data[ii++] = var; + } + } else { + while ((line = wbFile_readLine(file)) != NULL) { + char *token = strtok(line, seperator); + while (token != NULL) { + sscanf(token, "%d", &var); + token = strtok(NULL, seperator); + data[ii++] = var; + } + } + } + + return data; +} + +static inline wbReal_t *csv_readAsReal(wbFile_t file, char sep, int rows, + int columns) { + int ii = 0; + wbReal_t *data; + char *line; + wbReal_t var; + char seperator[2]; + + if (file == NULL) { + return NULL; + } + + data = wbNewArray(wbReal_t, rows * columns); + + if (sep == '\0') { + seperator[0] = ','; + } else { + seperator[0] = sep; + } + seperator[1] = '\0'; + + if (columns == 1) { + while ((line = wbFile_readLine(file)) != NULL) { + sscanf(line, "%f", &var); + data[ii++] = var; + } + } else { + while ((line = wbFile_readLine(file)) != NULL) { + char *token = strtok(line, seperator); + while (token != NULL) { + sscanf(token, "%f", &var); + token = strtok(NULL, seperator); + data[ii++] = var; + } + } + } + + return data; +} + +static inline wbImportCSV_t wbImportCSV_read(wbImportCSV_t csv, + wbType_t type) { + void *data; + wbFile_t file; + char seperator; + int rows, columns; + + if (csv == NULL) { + return NULL; + } + + if (wbImportCSV_getRowCount(csv) == -1 || + wbImportCSV_getColumnCount(csv) == -1) { + if (wbImportCSV_findDimensions(csv, &rows, &columns) == NULL) { + wbLog(ERROR, "Failed to figure out csv dimensions."); + return NULL; + } + wbImportCSV_setRowCount(csv, rows); + wbImportCSV_setColumnCount(csv, columns); + } + + file = wbImportCSV_getFile(csv); + seperator = wbImportCSV_getSeperator(csv); + rows = wbImportCSV_getRowCount(csv); + columns = wbImportCSV_getColumnCount(csv); + + if (wbImportCSV_getData(csv) != NULL) { + wbDelete(wbImportCSV_getData(csv)); + wbImportCSV_setData(csv, NULL); + } + + if (type == wbType_integer) { + // printf("ReadXXXing as integer...\n"); + data = csv_readAsInteger(file, seperator, rows, columns); + } else { + data = csv_readAsReal(file, seperator, rows, columns); + } + + wbImportCSV_setData(csv, data); + + return csv; +} + +static inline wbImportCSV_t wbImportCSV_readAsInteger(wbImportCSV_t csv) { + return wbImportCSV_read(csv, wbType_integer); +} + +static inline wbImportCSV_t wbImportCSV_readAsReal(wbImportCSV_t csv) { + return wbImportCSV_read(csv, wbType_real); +} + +static inline void wbImportRaw_setFile(wbImportRaw_t raw, + const char *path) { + if (raw != NULL) { + if (wbImportRaw_getFile(raw) != NULL) { + wbFile_delete(wbImportRaw_getFile(raw)); + } + if (path != NULL) { + wbImportRaw_getFile(raw) = wbFile_open(path, "r"); + } else { + wbImportRaw_getFile(raw) = NULL; + } + } + + return; +} + +static inline wbImportRaw_t wbImportRaw_new(void) { + wbImportRaw_t raw; + + raw = wbNew(struct st_wbImportRaw_t); + + wbImportRaw_setRowCount(raw, -1); + wbImportRaw_setColumnCount(raw, -1); + wbImportRaw_setData(raw, NULL); + wbImportRaw_getFile(raw) = NULL; + + return raw; +} + +static inline void wbImportRaw_delete(wbImportRaw_t raw) { + if (raw != NULL) { + wbImportRaw_setFile(raw, NULL); + if (wbImportRaw_getData(raw)) { + wbDelete(wbImportRaw_getData(raw)); + } + wbDelete(raw); + } +} + +static inline wbBool lineHasSpace(const char *line) { + while (*line != '\0') { + if (*line == ' ') { + return wbTrue; + } + line++; + } + return wbFalse; +} + +static inline char *lineStrip(const char *line) { + char *sl = wbString_duplicate(line); + char *iter = sl; + size_t slen = strlen(line); + + iter += slen - 1; + while (*iter == '\0' || *iter == '\r' || *iter == '\t' || + *iter == '\n' || *iter == ' ') { + *iter-- = '\0'; + } + return sl; +} + +static inline wbBool wbImportRaw_findDimensions(wbImportRaw_t raw) { + if (raw != NULL) { + int rows; + int columns; + char *line; + wbFile_t file; + char *strippedLine; + + file = wbImportRaw_getFile(raw); + + wbFile_rewind(file); + + line = wbFile_readLine(file); + + if (line == NULL) { + return wbTrue; + } + + strippedLine = lineStrip(line); + + if (lineHasSpace(strippedLine)) { + sscanf(strippedLine, "%d %d", &rows, &columns); + } else { + columns = 1; + sscanf(strippedLine, "%d", &rows); + } + + wbImportRaw_setRowCount(raw, rows); + wbImportRaw_setColumnCount(raw, columns); + + wbDelete(strippedLine); + + return wbFalse; + } + + return wbTrue; +} + +static inline wbImportRaw_t wbImportRaw_read(wbImportRaw_t raw, + wbType_t type) { + void *data; + wbFile_t file; + char seperator; + int rows, columns; + + if (raw == NULL) { + return NULL; + } + + if (wbImportRaw_getRowCount(raw) == -1 || + wbImportRaw_getColumnCount(raw) == -1) { + if (wbImportRaw_findDimensions(raw)) { + wbLog(ERROR, "Failed to figure out raw dimensions."); + return NULL; + } + } + + file = wbImportRaw_getFile(raw); + seperator = ' '; + rows = wbImportRaw_getRowCount(raw); + columns = wbImportRaw_getColumnCount(raw); + + if (wbImportRaw_getData(raw) != NULL) { + wbDelete(wbImportRaw_getData(raw)); + wbImportRaw_setData(raw, NULL); + } + + if (type == wbType_integer) { + // printf("Rdin gas integer...\n"); + data = csv_readAsInteger(file, seperator, rows, columns); + } else { + data = csv_readAsReal(file, seperator, rows, columns); + } + + wbImportRaw_setData(raw, data); + + return raw; +} + +static inline wbImportRaw_t wbImportRaw_readAsInteger(wbImportRaw_t raw) { + return wbImportRaw_read(raw, wbType_integer); +} + +static inline wbImportRaw_t wbImportRaw_readAsReal(wbImportRaw_t raw) { + return wbImportRaw_read(raw, wbType_real); +} + +static inline wbImportText_t wbImportText_new(void) { + wbImportText_t text; + + text = wbNew(struct st_wbImportText_t); + + wbImportText_setLength(text, 0); + wbImportText_setData(text, NULL); + wbImportText_getFile(text) = NULL; + + return text; +} + +static inline void wbImportText_setFile(wbImportText_t text, + const char *path) { + if (text != NULL) { + if (wbImportText_getFile(text) != NULL) { + wbFile_delete(wbImportText_getFile(text)); + } + if (path != NULL) { + wbImportText_getFile(text) = wbFile_open(path, "r"); + } else { + wbImportText_getFile(text) = NULL; + } + } + + return; +} + +static inline void wbImportText_delete(wbImportText_t text) { + if (text != NULL) { + wbImportText_setFile(text, NULL); + if (wbImportText_getData(text)) { + wbDelete(wbImportText_getData(text)); + } + wbDelete(text); + } +} + +static inline wbImportText_t wbImportText_read(wbImportText_t text) { + char *data; + wbFile_t file; + int length; + + if (text == NULL) { + return NULL; + } + + file = wbImportText_getFile(text); + + if (wbImportText_getData(text) != NULL) { + wbDelete(wbImportText_getData(text)); + wbImportText_setData(text, NULL); + } + + length = wbFile_size(file); + data = wbFile_read(file, length); + + wbImportText_setData(text, data); + wbImportText_setLength(text, length); + + return text; +} + +static inline wbImport_t wbImport_open(const char *file, + wbImportKind_t kind) { + wbImport_t imp; + + if (file == NULL) { + wbLog(ERROR, "Go NULL for file value."); + wbExit(); + } + + if (!wbFile_existsQ(file)) { + wbLog(ERROR, "File ", file, " does not exist."); + wbExit(); + } + + wbImport_setKind(imp, kind); + + if (kind == wbImportKind_raw) { + wbImportRaw_t raw = wbImportRaw_new(); + wbImportRaw_setFile(raw, file); + wbImport_setRaw(imp, raw); + } else if (kind == wbImportKind_tsv || kind == wbImportKind_csv) { + wbImportCSV_t csv = wbImportCSV_new(); + if (kind == wbImportKind_csv) { + wbImportCSV_setSeperator(csv, ','); + } else { + wbImportCSV_setSeperator(csv, '\t'); + } + wbImportCSV_setFile(csv, file); + wbImport_setCSV(imp, csv); + } else if (kind == wbImportKind_text) { + wbImportText_t text = wbImportText_new(); + wbImportText_setFile(text, file); + wbImport_setText(imp, text); + } else if (kind == wbImportKind_ppm) { + wbImage_t img = wbPPM_import(file); + wbImport_setImage(imp, img); + } else { + wbLog(ERROR, "Invalid import type."); + wbExit(); + } + + return imp; +} + +static inline wbImport_t wbImport_open(const char *file, + const char *type0) { + wbImport_t imp; + wbImportKind_t kind; + char *type; + + type = wbString_toLower(type0); + + if (wbString_sameQ(type, "csv")) { + kind = wbImportKind_csv; + } else if (wbString_sameQ(type, "tsv")) { + kind = wbImportKind_tsv; + } else if (wbString_sameQ(type, "raw") || wbString_sameQ(type, "dat")) { + kind = wbImportKind_raw; + } else if (wbString_sameQ(type, "ppm")) { + kind = wbImportKind_ppm; + } else if (wbString_sameQ(type, "text") || wbString_sameQ(type, "txt")) { + kind = wbImportKind_text; + } else { + wbLog(ERROR, "Invalid import type ", type0); + wbExit(); + } + + imp = wbImport_open(file, kind); + + wbDelete(type); + + return imp; +} + +static inline void wbImport_close(wbImport_t imp) { + wbImportKind_t kind; + + kind = wbImport_getKind(imp); + if (kind == wbImportKind_tsv || kind == wbImportKind_csv) { + wbImportCSV_t csv = wbImport_getCSV(imp); + wbImportCSV_delete(csv); + wbImport_setCSV(imp, NULL); + } else if (kind == wbImportKind_raw) { + wbImportRaw_t raw = wbImport_getRaw(imp); + wbImportRaw_delete(raw); + wbImport_setRaw(imp, NULL); + } else if (kind == wbImportKind_text) { + wbImportText_t text = wbImport_getText(imp); + wbImportText_delete(text); + wbImport_setText(imp, NULL); + } else if (kind == wbImportKind_ppm) { + } else { + wbLog(ERROR, "Invalid import type."); + wbExit(); + } + return; +} + +static inline void *wbImport_read(wbImport_t imp, wbType_t type) { + void *data = NULL; + wbImportKind_t kind; + + kind = wbImport_getKind(imp); + if (kind == wbImportKind_tsv || kind == wbImportKind_csv) { + wbImportCSV_t csv = wbImport_getCSV(imp); + wbImportCSV_read(csv, type); + data = wbImportCSV_getData(csv); + } else if (kind == wbImportKind_raw) { + wbImportRaw_t raw = wbImport_getRaw(imp); + wbImportRaw_read(raw, type); + data = wbImportRaw_getData(raw); + } else if (wbImportKind_text == kind) { + wbImportText_t text = wbImport_getText(imp); + text = wbImportText_read(text); + data = wbImportText_getData(text); + + } else { + wbLog(ERROR, "Invalid import type."); + wbExit(); + } + return data; +} + +static inline int *wbImport_readAsInteger(wbImport_t imp) { + void *data = wbImport_read(imp, wbType_integer); + return (int *)data; +} + +static inline wbReal_t *wbImport_readAsReal(wbImport_t imp) { + void *data = wbImport_read(imp, wbType_real); + return (wbReal_t *)data; +} + +static inline wbChar_t *wbImport_readAsText(wbImport_t imp) { + void *data = wbImport_read(imp, wbType_ubit8); + return (wbChar_t *)data; +} + +static wbImportKind_t _parseImportExtension(const char *file) { + char *extension; + wbImportKind_t kind; + + extension = wbFile_extension(file); + + if (wbString_sameQ(extension, "csv")) { + kind = wbImportKind_csv; + } else if (wbString_sameQ(extension, "tsv")) { + kind = wbImportKind_tsv; + } else if (wbString_sameQ(extension, "raw") || + wbString_sameQ(extension, "dat")) { + kind = wbImportKind_raw; + } else if (wbString_sameQ(extension, "ppm") || + wbString_sameQ(extension, "pbm")) { + kind = wbImportKind_ppm; + } else if (wbString_sameQ(extension, "text") || + wbString_sameQ(extension, "txt")) { + kind = wbImportKind_text; + } else { + kind = wbImportKind_unknown; + wbLog(ERROR, "File ", file, " does not have a compatible extension."); + } + + wbDelete(extension); + + return kind; +} + +void *wbImport(const char *file, int *resRows, int *resColumns, + const char *type) { + void *data, *res; + wbImport_t imp; + size_t sz; + int columns = 0, rows = 0; + wbImportKind_t kind; + + if (file == NULL) { + fprintf(stderr, "Failed to import file.\n"); + wbExit(); + } + + kind = _parseImportExtension(file); + + wbAssert(kind != wbImportKind_unknown); + + imp = wbImport_open(file, kind); + if (wbString_sameQ(type, "Real")) { + data = wbImport_readAsReal(imp); + sz = sizeof(wbReal_t); + } else if (wbString_sameQ(type, "Text")) { + data = wbImport_readAsText(imp); + sz = sizeof(char); + } else { + // printf("Reading as integer..d\n"); + data = wbImport_readAsInteger(imp); + sz = sizeof(int); + } + + if (kind == wbImportKind_csv || kind == wbImportKind_tsv) { + rows = wbImportCSV_getRowCount(wbImport_getCSV(imp)); + columns = wbImportCSV_getColumnCount(wbImport_getCSV(imp)); + } else if (kind == wbImportKind_raw) { + rows = wbImportRaw_getRowCount(wbImport_getRaw(imp)); + columns = wbImportRaw_getColumnCount(wbImport_getRaw(imp)); + } else if (kind == wbImportKind_text) { + rows = 1; + columns = wbImportText_getLength(wbImport_getText(imp)); + } + + if (rows == 1 && columns > 0) { + rows = columns; + columns = 1; + } + + if (resRows != NULL) { + *resRows = rows; + } + + if (resColumns != NULL) { + *resColumns = columns; + } + + res = wbMalloc(sz * rows * columns); + memcpy(res, data, sz * rows * columns); + + wbImport_close(imp); + + return res; +} + +void *wbImport(const char *file, int *rows, int *columns) { + return wbImport(file, rows, columns, "Real"); +} + +EXTERN_C void *wbImport(const char *file, int *rows) { + return wbImport(file, rows, NULL, "Real"); +} + +void *wbImport(const char *file, int *res_rows, const char *type) { + int cols, rows; + void *res = wbImport(file, &rows, &cols, type); + if (rows == 1 && cols > 1) { + rows = cols; + } + *res_rows = rows; + return res; +} + +wbImage_t wbImport(const char *file) { + wbImage_t img; + wbImport_t imp; + wbImportKind_t kind; + + if (file == NULL) { + fprintf(stderr, "Failed to import file.\n"); + wbExit(); + } + + kind = _parseImportExtension(file); + + wbAssert(kind == wbImportKind_ppm); + + imp = wbImport_open(file, kind); + img = wbImport_getImage(imp); + wbImport_close(imp); + + return img; +} + +int wbImport_flag(const char *file) { + int res; + wbFile_t fh = wbFile_open(file, "r"); + const char *line = wbFile_readLine(fh); + sscanf(line, "%d", &res); + wbFile_close(fh); + return res; +} diff --git a/CUDA_Histogram/libwb/wbImport.h b/CUDA_Histogram/libwb/wbImport.h new file mode 100644 index 0000000..ce13e1b --- /dev/null +++ b/CUDA_Histogram/libwb/wbImport.h @@ -0,0 +1,103 @@ + +#ifndef __WB_IMPORT_H__ +#define __WB_IMPORT_H__ + +#include "wbImage.h" + +typedef enum en_wbImportKind_t { + wbImportKind_unknown = -1, + wbImportKind_raw = 0x1000, + wbImportKind_csv, + wbImportKind_tsv, + wbImportKind_ppm, + wbImportKind_text +} wbImportKind_t; + +#define wbType_real wbType_float + +typedef struct st_wbImportCSV_t { + int rows; + int columns; + void *data; + wbFile_t file; + char seperator; +} * wbImportCSV_t; + +#define wbImportCSV_getRowCount(csv) ((csv)->rows) +#define wbImportCSV_getColumnCount(csv) ((csv)->columns) +#define wbImportCSV_getData(csv) ((csv)->data) +#define wbImportCSV_getFile(csv) ((csv)->file) +#define wbImportCSV_getSeperator(csv) ((csv)->seperator) + +#define wbImportCSV_setRowCount(csv, val) \ + (wbImportCSV_getRowCount(csv) = val) +#define wbImportCSV_setColumnCount(csv, val) \ + (wbImportCSV_getColumnCount(csv) = val) +#define wbImportCSV_setData(csv, val) (wbImportCSV_getData(csv) = val) +#define wbImportCSV_setSeperator(csv, val) \ + (wbImportCSV_getSeperator(csv) = val) + +typedef struct st_wbImportRaw_t { + int rows; + int columns; + void *data; + wbFile_t file; +} * wbImportRaw_t; + +#define wbImportRaw_getRowCount(raw) ((raw)->rows) +#define wbImportRaw_getColumnCount(raw) ((raw)->columns) +#define wbImportRaw_getData(raw) ((raw)->data) +#define wbImportRaw_getFile(raw) ((raw)->file) + +#define wbImportRaw_setRowCount(raw, val) \ + (wbImportRaw_getRowCount(raw) = val) +#define wbImportRaw_setColumnCount(raw, val) \ + (wbImportRaw_getColumnCount(raw) = val) +#define wbImportRaw_setData(raw, val) (wbImportRaw_getData(raw) = val) + +typedef struct st_wbImportText_t { + int length; + char *data; + wbFile_t file; +} * wbImportText_t; + +#define wbImportText_getLength(txt) ((txt)->length) +#define wbImportText_getData(txt) ((txt)->data) +#define wbImportText_getFile(txt) ((txt)->file) + +#define wbImportText_setLength(txt, val) \ + (wbImportText_getLength(txt) = val) +#define wbImportText_setData(txt, val) (wbImportText_getData(txt) = val) + +typedef struct st_wbImport_t { + wbImportKind_t kind; + union { + wbImportRaw_t raw; + wbImportCSV_t csv; + wbImportText_t text; + wbImage_t img; + } container; +} wbImport_t; + +#define wbImport_getKind(imp) ((imp).kind) +#define wbImport_getContainer(imp) ((imp).container) +#define wbImport_getRaw(imp) (wbImport_getContainer(imp).raw) +#define wbImport_getCSV(imp) (wbImport_getContainer(imp).csv) +#define wbImport_getText(imp) (wbImport_getContainer(imp).text) +#define wbImport_getImage(imp) (wbImport_getContainer(imp).img) + +#define wbImport_setKind(imp, val) (wbImport_getKind(imp) = val) +#define wbImport_setRaw(imp, val) (wbImport_getRaw(imp) = val) +#define wbImport_setCSV(imp, val) (wbImport_getCSV(imp) = val) +#define wbImport_setText(imp, val) (wbImport_getText(imp) = val) +#define wbImport_setImage(imp, val) (wbImport_getImage(imp) = val) + +EXTERN_C void *wbImport(const char *file, int *rows); +void *wbImport(const char *file, int *rows, int *columns); +void *wbImport(const char *file, int *rows, const char *type); +void *wbImport(const char *file, int *resRows, int *resColumns, + const char *type); +wbImage_t wbImport(const char *file); +int wbImport_flag(const char *file); + +#endif /* __WB_IMPORT_H__ */ diff --git a/CUDA_Histogram/libwb/wbInit.cpp b/CUDA_Histogram/libwb/wbInit.cpp new file mode 100644 index 0000000..96ebcf3 --- /dev/null +++ b/CUDA_Histogram/libwb/wbInit.cpp @@ -0,0 +1,85 @@ + +#include "wb.h" + +#define MB (1 << 20) +#ifndef WB_DEFAULT_HEAP_SIZE +#define WB_DEFAULT_HEAP_SIZE (1024 * MB) +#endif /* WB_DEFAULT_HEAP_SIZE */ + +static bool _initializedQ = wbFalse; + +#ifndef WB_USE_WINDOWS +__attribute__((__constructor__)) +#endif /* WB_USE_WINDOWS */ +void wb_init(int * +#ifdef WB_USE_MPI + argc +#endif /* WB_USE_MPI */ + , + char *** +#ifdef WB_USE_MPI + argv +#endif /* WB_USE_MPI */ + ) { + if (_initializedQ == wbTrue) { + return; + } +#ifdef WB_USE_MPI + wbMPI_Init(argc, argv); +#endif /* WB_USE_MPI */ + +#ifdef WB_USE_CUDA + CUresult err = cuInit(0); + +/* Select a random GPU */ + +#ifdef WB_USE_MPI + if (rankCount() > 1) { + int deviceCount; + cudaGetDeviceCount(&deviceCount); + srand(time(NULL)); + cudaSetDevice(wbMPI_getRank() % deviceCount); + } else { + int deviceCount; + cudaGetDeviceCount(&deviceCount); + + srand(time(NULL)); + cudaSetDevice(rand() % deviceCount); + } +#else + { + int deviceCount; + cudaGetDeviceCount(&deviceCount); + + srand(time(NULL)); + cudaSetDevice(rand() % deviceCount); + } +#endif /* WB_USE_MPI */ + + cudaDeviceSetLimit(cudaLimitPrintfFifoSize, 1 * MB); + cudaDeviceSetLimit(cudaLimitMallocHeapSize, WB_DEFAULT_HEAP_SIZE); + + cudaDeviceSynchronize(); + +#endif /* WB_USE_CUDA */ + +#ifdef WB_USE_WINDOWS + QueryPerformanceFrequency((LARGE_INTEGER *)&_hrtime_frequency); +#endif /* _MSC_VER */ + + _hrtime(); + + _timer = wbTimer_new(); + _logger = wbLogger_new(); + _initializedQ = wbTrue; + + wbFile_init(); + + solutionJSON = NULL; + +#ifdef WB_USE_MPI + atexit(wbMPI_Exit); +#else /* WB_USE_MPI */ + atexit(wb_atExit); +#endif /* WB_USE_MPI */ +} diff --git a/CUDA_Histogram/libwb/wbInit.h b/CUDA_Histogram/libwb/wbInit.h new file mode 100644 index 0000000..40e8e1c --- /dev/null +++ b/CUDA_Histogram/libwb/wbInit.h @@ -0,0 +1,11 @@ + + +#ifndef __WB_INIT_H__ +#define __WB_INIT_H__ + +#ifndef _MSC_VER +__attribute__((__constructor__)) +#endif /* _MSC_VER */ +void wb_init(int *argc, char ***argv); + +#endif /* __WB_INIT_H__ */ diff --git a/CUDA_Histogram/libwb/wbLogger.cpp b/CUDA_Histogram/libwb/wbLogger.cpp new file mode 100644 index 0000000..c2e2e17 --- /dev/null +++ b/CUDA_Histogram/libwb/wbLogger.cpp @@ -0,0 +1,310 @@ + +#include "wb.h" + +wbLogger_t _logger = NULL; + +static inline wbBool wbLogEntry_hasNext(wbLogEntry_t elem) { + return wbLogEntry_getNext(elem) != NULL; +} + +static inline wbLogEntry_t wbLogEntry_new() { + wbLogEntry_t elem; + + elem = wbNew(struct st_wbLogEntry_t); + + wbLogEntry_setMessage(elem, NULL); + wbLogEntry_setMPIRank(elem, wbMPI_getRank()); + wbLogEntry_setTime(elem, _hrtime()); + + wbLogEntry_setLevel(elem, wbLogLevel_TRACE); + + wbLogEntry_setNext(elem, NULL); + + wbLogEntry_setLine(elem, -1); + wbLogEntry_setFile(elem, NULL); + wbLogEntry_setFunction(elem, NULL); + + return elem; +} + +static inline wbLogEntry_t +wbLogEntry_initialize(wbLogLevel_t level, string msg, const char *file, + const char *fun, int line) { + wbLogEntry_t elem; + + elem = wbLogEntry_new(); + + wbLogEntry_setLevel(elem, level); + + wbLogEntry_setMessage(elem, wbString_duplicate(msg)); + + wbLogEntry_setLine(elem, line); + wbLogEntry_setFile(elem, file); + wbLogEntry_setFunction(elem, fun); + + return elem; +} + +static inline void wbLogEntry_delete(wbLogEntry_t elem) { + if (elem != NULL) { + if (wbLogEntry_getMessage(elem) != NULL) { + wbFree(wbLogEntry_getMessage(elem)); + } + wbDelete(elem); + } + return; +} + +static inline const char *getLevelName(wbLogLevel_t level) { + switch (level) { + case wbLogLevel_unknown: + return "Unknown"; + case wbLogLevel_OFF: + return "Off"; + case wbLogLevel_FATAL: + return "Fatal"; + case wbLogLevel_ERROR: + return "Error"; + case wbLogLevel_WARN: + return "Warn"; + case wbLogLevel_INFO: + return "Info"; + case wbLogLevel_DEBUG: + return "Debug"; + case wbLogLevel_TRACE: + return "Trace"; + } + return NULL; +} + +static inline json11::Json wbLogEntry_toJSONObject(wbLogEntry_t elem) { + json11::Json json = json11::Json::object{ + {"mpi_rank", wbLogEntry_getMPIRank(elem)}, + {"level", getLevelName(wbLogEntry_getLevel(elem))}, + {"file", wbLogEntry_getFile(elem)}, + {"function", wbLogEntry_getFunction(elem)}, + {"line", wbLogEntry_getLine(elem)}, + {"time", wbLogEntry_getTime(elem)}, + {"message", wbLogEntry_getMessage(elem)}, + }; + return json; +} + +static inline string wbLogEntry_toJSON(wbLogEntry_t elem) { + if (elem == NULL) { + return ""; + } else if (WB_USE_JSON11) { + json11::Json json = wbLogEntry_toJSONObject(elem); + return json.string_value(); + } else { + stringstream ss; + + ss << "{\n"; + ss << wbString_quote("mpi_rank") << ":" + << wbString(wbLogEntry_getMPIRank(elem)) << ",\n"; + ss << wbString_quote("level") << ":" + << wbString_quote(getLevelName(wbLogEntry_getLevel(elem))) << ",\n"; + ss << wbString_quote("message") << ":" + << wbString_quote(wbLogEntry_getMessage(elem)) << ",\n"; + ss << wbString_quote("file") << ":" + << wbString_quote(wbLogEntry_getFile(elem)) << ",\n"; + ss << wbString_quote("function") << ":" + << wbString_quote(wbLogEntry_getFunction(elem)) << ",\n"; + ss << wbString_quote("line") << ":" << wbLogEntry_getLine(elem) + << ",\n"; + ss << wbString_quote("time") << ":" << wbLogEntry_getTime(elem) + << "\n"; + ss << "}"; + + return ss.str(); + } + return ""; +} + +static inline string wbLogEntry_toXML(wbLogEntry_t elem) { + if (elem != NULL) { + stringstream ss; + + ss << "\n"; + ss << "" + << "LoggerElement" + << "\n"; + ss << "" << wbLogEntry_getLevel(elem) << "\n"; + ss << "" << wbLogEntry_getMessage(elem) << "\n"; + ss << "" << wbLogEntry_getFile(elem) << "\n"; + ss << "" << wbLogEntry_getFunction(elem) << "\n"; + ss << "" << wbLogEntry_getLine(elem) << "\n"; + ss << "\n"; + ss << "\n"; + + return ss.str(); + } + return ""; +} + +wbLogger_t wbLogger_new() { + wbLogger_t logger; + + logger = wbNew(struct st_wbLogger_t); + + wbLogger_setLength(logger, 0); + wbLogger_setHead(logger, NULL); + + wbLogger_getLevel(logger) = wbLogLevel_TRACE; + + return logger; +} + +static inline void _wbLogger_setLevel(wbLogger_t logger, + wbLogLevel_t level) { + wbLogger_getLevel(logger) = level; +} + +static inline void _wbLogger_setLevel(wbLogLevel_t level) { + _wbLogger_setLevel(_logger, level); +} + +#define wbLogger_setLevel(level) _wbLogger_setLevel(wbLogLevel_##level) + +void wbLogger_clear(wbLogger_t logger) { + if (logger != NULL) { + wbLogEntry_t tmp; + wbLogEntry_t iter; + + iter = wbLogger_getHead(logger); + while (iter != NULL) { + tmp = wbLogEntry_getNext(iter); + wbLogEntry_delete(iter); + iter = tmp; + } + + wbLogger_setLength(logger, 0); + wbLogger_setHead(logger, NULL); + } +} + +void wbLogger_delete(wbLogger_t logger) { + if (logger != NULL) { + wbLogger_clear(logger); + wbDelete(logger); + } + return; +} + +void wbLogger_append(wbLogLevel_t level, string msg, const char *file, + const char *fun, int line) { + wbLogEntry_t elem; + wbLogger_t logger; + + wb_init(NULL, NULL); + + logger = _logger; + + if (wbLogger_getLevel(logger) < level) { + return; + } + + elem = wbLogEntry_initialize(level, msg, file, fun, line); + +#ifdef wbLogger_printOnLog + if (wbLogger_printOnLog) { + if (level <= wbLogger_getLevel(logger) && elem) { + json11::Json json = json11::Json::object{ +#ifndef _MSC_VER //PMO + { "type", "logger" }, { "data", wbLogEntry_toJSONObject(elem) }}; +#else + { "data", wbLogEntry_toJSONObject(elem) }, { "type", "logger" }}; +#endif + std::cout << json.dump() << std::endl; + } + } +#endif /* wbLogger_printOnLog */ + + if (wbLogger_getHead(logger) == NULL) { + wbLogger_setHead(logger, elem); + } else { + wbLogEntry_t prev = wbLogger_getHead(logger); + + while (wbLogEntry_hasNext(prev)) { + prev = wbLogEntry_getNext(prev); + } + wbLogEntry_setNext(prev, elem); + } + +#if 0 + if (level <= wbLogger_getLevel(logger) && elem) { + const char *levelName = getLevelName(level); + + fprintf(stderr, "= LOG: %s: %s (In %s:%s on line %d). =\n", levelName, + wbLogEntry_getMessage(elem), wbLogEntry_getFile(elem), + wbLogEntry_getFunction(elem), wbLogEntry_getLine(elem)); + } +#endif + + wbLogger_incrementLength(logger); + + return; +} + +string wbLogger_toJSON() { + return wbLogger_toJSON(_logger); +} + +static json11::Json wbLogger_toJSONObject(wbLogger_t logger) { + std::vector elems{}; + + if (logger != NULL) { + wbLogEntry_t iter; + stringstream ss; + + for (iter = wbLogger_getHead(logger); iter != NULL; + iter = wbLogEntry_getNext(iter)) { + elems.push_back(wbLogEntry_toJSONObject(iter)); + } + } + return json11::Json(elems); +} + +string wbLogger_toJSON(wbLogger_t logger) { + if (logger != NULL) { + wbLogEntry_t iter; + stringstream ss; + + for (iter = wbLogger_getHead(logger); iter != NULL; + iter = wbLogEntry_getNext(iter)) { + ss << wbLogEntry_toJSON(iter); + if (wbLogEntry_getNext(iter) != NULL) { + ss << ",\n"; + } + } + + return ss.str(); + } + return ""; +} + +string wbLogger_toXML() { + return wbLogger_toXML(_logger); +} + +string wbLogger_toXML(wbLogger_t logger) { + if (logger != NULL) { + wbLogEntry_t iter; + stringstream ss; + + ss << "\n"; + ss << "" + << "Logger" + << "\n"; + ss << "\n"; + for (iter = wbLogger_getHead(logger); iter != NULL; + iter = wbLogEntry_getNext(iter)) { + ss << wbLogEntry_toXML(iter); + } + ss << "\n"; + ss << "\n"; + + return ss.str(); + } + return ""; +} diff --git a/CUDA_Histogram/libwb/wbLogger.h b/CUDA_Histogram/libwb/wbLogger.h new file mode 100644 index 0000000..b852592 --- /dev/null +++ b/CUDA_Histogram/libwb/wbLogger.h @@ -0,0 +1,87 @@ + +#ifndef __WB_LOGGER_H__ +#define __WB_LOGGER_H__ + +#include + +typedef enum en_wbLogLevel_t { + wbLogLevel_unknown = -1, + wbLogLevel_OFF = 0, + wbLogLevel_FATAL, + wbLogLevel_ERROR, + wbLogLevel_WARN, + wbLogLevel_INFO, + wbLogLevel_DEBUG, + wbLogLevel_TRACE +} wbLogLevel_t; + +struct st_wbLogEntry_t { + int line; + int mpiRank; + char *msg; + uint64_t time; + const char *fun; + const char *file; + wbLogLevel_t level; + wbLogEntry_t next; +}; + +struct st_wbLogger_t { + int length; + wbLogEntry_t head; + wbLogLevel_t level; +}; + +#define wbLogEntry_getMessage(elem) ((elem)->msg) +#define wbLogEntry_getMPIRank(elem) ((elem)->mpiRank) +#define wbLogEntry_getTime(elem) ((elem)->time) +#define wbLogEntry_getLevel(elem) ((elem)->level) +#define wbLogEntry_getNext(elem) ((elem)->next) +#define wbLogEntry_getLine(elem) ((elem)->line) +#define wbLogEntry_getFunction(elem) ((elem)->fun) +#define wbLogEntry_getFile(elem) ((elem)->file) + +#define wbLogEntry_setMessage(elem, val) \ + (wbLogEntry_getMessage(elem) = val) +#define wbLogEntry_setMPIRank(elem, val) \ + (wbLogEntry_getMPIRank(elem) = val) +#define wbLogEntry_setTime(elem, val) (wbLogEntry_getTime(elem) = val) +#define wbLogEntry_setLevel(elem, val) (wbLogEntry_getLevel(elem) = val) +#define wbLogEntry_setNext(elem, val) (wbLogEntry_getNext(elem) = val) +#define wbLogEntry_setLine(elem, val) (wbLogEntry_getLine(elem) = val) +#define wbLogEntry_setFunction(elem, val) \ + (wbLogEntry_getFunction(elem) = val) +#define wbLogEntry_setFile(elem, val) (wbLogEntry_getFile(elem) = val) + +#define wbLogger_getLength(log) ((log)->length) +#define wbLogger_getHead(log) ((log)->head) +#define wbLogger_getLevel(log) ((log)->level) + +#define wbLogger_setLength(log, val) (wbLogger_getLength(log) = val) +#define wbLogger_setHead(log, val) (wbLogger_getHead(log) = val) + +#define wbLogger_incrementLength(log) (wbLogger_getLength(log)++) +#define wbLogger_decrementLength(log) (wbLogger_getLength(log)--) + +#define wbLog(level, ...) \ + wbLogger_append(wbLogLevel_##level, wbString(__VA_ARGS__), wbFile, \ + wbFunction, wbLine) + +extern wbLogger_t _logger; + +wbLogger_t wbLogger_new(); + +void wbLogger_clear(wbLogger_t logger); + +void wbLogger_delete(wbLogger_t logger); + +void wbLogger_append(wbLogLevel_t level, string msg, const char *file, + const char *fun, int line); + +string wbLogger_toXML(wbLogger_t logger); +string wbLogger_toXML(); + +string wbLogger_toJSON(wbLogger_t logger); +string wbLogger_toJSON(); + +#endif /* __WB_LOGGER_H__ */ diff --git a/CUDA_Histogram/libwb/wbMD5.h b/CUDA_Histogram/libwb/wbMD5.h new file mode 100644 index 0000000..e83a8ef --- /dev/null +++ b/CUDA_Histogram/libwb/wbMD5.h @@ -0,0 +1,311 @@ + +/* + * This code implements the MD5 message-digest algorithm. + * The algorithm is due to Ron Rivest. This code was + * written by Colin Plumb in 1993, no copyright is claimed. + * This code is in the public domain; do with it what you wish. + * + * Equivalent code is available from RSA Data Security, Inc. + * This code has been tested against that, and is equivalent, + * except that you don't need to include two pages of legalese + * with every copy. + * + * To compute the message digest of a chunk of bytes, declare an + * MD5Context structure, pass it to MD5Init, call MD5Update as + * needed on buffers full of bytes, and then call MD5Final, which + * will fill a supplied 16-byte array with the digest. + * + * Changed so as no longer to depend on Colin Plumb's `usual.h' header + * definitions; now uses stuff from dpkg's config.h. + * - Ian Jackson . + * Still in the public domain. + */ + +#ifndef __WB_MD5_H__ +#define __WB_MD5_H__ + +#include /* for memcpy() */ +#include /* for stupid systems */ + +#define UWORD32 unsigned int + +#define md5byte unsigned char + +struct MD5Context { + UWORD32 buf[4]; + UWORD32 bytes[2]; + UWORD32 in[16]; +}; + +static void MD5Transform(UWORD32 buf[4], UWORD32 const in[16]); + +static int g_bigEndian = 0; +static int g_endianessDetected = 0; + +static void detectEndianess() { + int nl = 0x12345678; + short ns = 0x1234; + + unsigned char *p = (unsigned char *)(&nl); + unsigned char *sp = (unsigned char *)(&ns); + + if (g_endianessDetected) + return; + if (p[0] == 0x12 && p[1] == 0x34 && p[2] == 0x56 && p[3] == 0x78) { + g_bigEndian = 1; + } else if (p[0] == 0x78 && p[1] == 0x56 && p[2] == 0x34 && + p[3] == 0x12) { + g_bigEndian = 0; + } else { + g_bigEndian = *sp != 0x12; + } + + g_endianessDetected = 1; +} + +static void byteSwap(UWORD32 *buf, unsigned words) { + md5byte *p; + + if (!g_bigEndian) + return; + + p = (md5byte *)buf; + + do { + *buf++ = (UWORD32)((unsigned)p[3] << 8 | p[2]) << 16 | + ((unsigned)p[1] << 8 | p[0]); + p += 4; + } while (--words); +} + +/* + * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious + * initialization constants. + */ +static void MD5Init(struct MD5Context *ctx) { + detectEndianess(); + + ctx->buf[0] = 0x67452301; + ctx->buf[1] = 0xefcdab89; + ctx->buf[2] = 0x98badcfe; + ctx->buf[3] = 0x10325476; + + ctx->bytes[0] = 0; + ctx->bytes[1] = 0; +} + +/* + * Update context to reflect the concatenation of another buffer full + * of bytes. + */ +static void MD5Update(struct MD5Context *ctx, md5byte const *buf, + unsigned len) { + UWORD32 t; + + /* Update byte count */ + + t = ctx->bytes[0]; + if ((ctx->bytes[0] = t + len) < t) + ctx->bytes[1]++; /* Carry from low to high */ + + t = 64 - (t & 0x3f); /* Space available in ctx->in (at least 1) */ + if (t > len) { + memcpy((md5byte *)ctx->in + 64 - t, buf, len); + return; + } + /* First chunk is an odd size */ + memcpy((md5byte *)ctx->in + 64 - t, buf, t); + byteSwap(ctx->in, 16); + MD5Transform(ctx->buf, ctx->in); + buf += t; + len -= t; + + /* Process data in 64-byte chunks */ + while (len >= 64) { + memcpy(ctx->in, buf, 64); + byteSwap(ctx->in, 16); + MD5Transform(ctx->buf, ctx->in); + buf += 64; + len -= 64; + } + + /* Handle any remaining bytes of data. */ + memcpy(ctx->in, buf, len); +} + +/* + * Final wrapup - pad to 64-byte boundary with the bit pattern + * 1 0* (64-bit count of bits processed, MSB-first) + */ +static void MD5Final(md5byte digest[16], struct MD5Context *ctx) { + int count = ctx->bytes[0] & 0x3f; /* Number of bytes in ctx->in */ + md5byte *p = (md5byte *)ctx->in + count; + + /* Set the first char of padding to 0x80. There is always room. */ + *p++ = 0x80; + + /* Bytes of padding needed to make 56 bytes (-8..55) */ + count = 56 - 1 - count; + + if (count < 0) { /* Padding forces an extra block */ + memset(p, 0, count + 8); + byteSwap(ctx->in, 16); + MD5Transform(ctx->buf, ctx->in); + p = (md5byte *)ctx->in; + count = 56; + } + memset(p, 0, count); + byteSwap(ctx->in, 14); + + /* Append length in bits and transform */ + ctx->in[14] = ctx->bytes[0] << 3; + ctx->in[15] = ctx->bytes[1] << 3 | ctx->bytes[0] >> 29; + MD5Transform(ctx->buf, ctx->in); + + byteSwap(ctx->buf, 4); + memcpy(digest, ctx->buf, 16); + memset(&ctx, 0, sizeof(ctx)); /* In case it's sensitive */ +} + +#ifndef ASM_MD5 + +/* The four core functions - F1 is optimized somewhat */ + +/* #define F1(x, y, z) (x & y | ~x & z) */ +#define F1(x, y, z) (z ^ (x & (y ^ z))) +#define F2(x, y, z) F1(z, x, y) +#define F3(x, y, z) (x ^ y ^ z) +#define F4(x, y, z) (y ^ (x | ~z)) + +/* This is the central step in the MD5 algorithm. */ +#define MD5STEP(f, w, x, y, z, in, s) \ + (w += f(x, y, z) + in, w = (w << s | w >> (32 - s)) + x) + +/* + * The core of the MD5 algorithm, this alters an existing MD5 hash to + * reflect the addition of 16 longwords of new data. MD5Update blocks + * the data and converts bytes into longwords for this routine. + */ +static void MD5Transform(UWORD32 buf[4], UWORD32 const in[16]) { + UWORD32 a, b, c, d; + + a = buf[0]; + b = buf[1]; + c = buf[2]; + d = buf[3]; + + MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); + MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); + MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); + MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); + MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); + MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); + MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); + MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); + MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); + MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); + MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); + MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); + MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); + MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); + MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); + MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); + + MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); + MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); + MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); + MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); + MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); + MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); + MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); + MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); + MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); + MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); + MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); + MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); + MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); + MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); + MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); + MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); + + MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); + MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); + MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); + MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); + MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); + MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); + MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); + MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); + MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); + MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); + MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); + MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); + MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); + MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); + MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); + MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); + + MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); + MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); + MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); + MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); + MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); + MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); + MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); + MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); + MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); + MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); + MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); + MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); + MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); + MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); + MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); + MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} + +#endif + +static void MD5_buffer(const unsigned char *buf, unsigned int len, + unsigned char sig[16]) { + struct MD5Context md5; + MD5Init(&md5); + MD5Update(&md5, buf, len); + MD5Final(sig, &md5); +} + +#define wbMD5 MD5_buffer + +#define HEX_STRING "0123456789abcdef" /* to convert to hex */ + +static void wbMD5_sigToString(unsigned char signature[16], char *str, + int len) { + unsigned char *sig_p; + char *str_p, *max_p; + unsigned int high, low; + + str_p = str; + max_p = str + len; + + for (sig_p = (unsigned char *)signature; + sig_p < (unsigned char *)signature + 16; sig_p++) { + high = *sig_p / 16; + low = *sig_p % 16; + /* account for 2 chars */ + if (str_p + 1 >= max_p) { + break; + } + *str_p++ = HEX_STRING[high]; + *str_p++ = HEX_STRING[low]; + } + /* account for 2 chars */ + if (str_p < max_p) { + *str_p++ = '\0'; + } +} + +#endif /* __WB_MD5_H__ */ diff --git a/CUDA_Histogram/libwb/wbMPI.cpp b/CUDA_Histogram/libwb/wbMPI.cpp new file mode 100644 index 0000000..546c1ed --- /dev/null +++ b/CUDA_Histogram/libwb/wbMPI.cpp @@ -0,0 +1,75 @@ + +#ifdef WB_USE_MPI + +#include +#include +#include +#include "wb.h" + +static int rank = -1; + +int wbMPI_getRank() { + if (rank != -1) { + return rank; + } + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + return rank; +} + +int rankCount() { + int nRanks; + MPI_Comm_size(MPI_COMM_WORLD, &nRanks); + return nRanks; +} + +const char *wbMPI_getStringFromRank(int rank, int tag) { + if (isMasterQ) { + char *buf; + int bufSize; + MPI_Recv(&bufSize, 1, MPI_INT, rank, tag, MPI_COMM_WORLD, + MPI_STATUS_IGNORE); + buf = (char *)calloc(bufSize, sizeof(char)); + MPI_Recv(buf, bufSize, MPI_CHAR, rank, tag, MPI_COMM_WORLD, + MPI_STATUS_IGNORE); + return buf; + } + + return NULL; +} +void wbMPI_sendStringToMaster(const char *str, int tag) { + if (!isMasterQ) { + // we are going to send the string to the master + int len = (int)strlen(str) + 1; + MPI_Send(&len, 1, MPI_INT, 0, tag, MPI_COMM_WORLD); + MPI_Send((void *)str, len, MPI_CHAR, 0, tag, MPI_COMM_WORLD); + } + + return; +} + +int wbMPI_Init(int *argc, char ***argv) { + int err = MPI_SUCCESS; + err = MPI_Init(argc, argv); + // printf("argc = %d\n", *argc); + // err = MPI_Init(NULL, NULL); + // printf("rank = %d is master = %d\n", wbMPI_getRank(), isMasterQ); + // MPI_Barrier(MPI_COMM_WORLD); + return err; +} + +bool finalizedQ = false; + +extern "C" int wbMPI_Finalize(void) { + if (finalizedQ) { + return MPI_SUCCESS; + } + finalizedQ = true; + wb_atExit(); + return MPI_Finalize(); +} +extern "C" void wbMPI_Exit(void) { + wbMPI_Finalize(); + return; +} + +#endif /* WB_USE_MPI */ diff --git a/CUDA_Histogram/libwb/wbMPI.h b/CUDA_Histogram/libwb/wbMPI.h new file mode 100644 index 0000000..6275eaf --- /dev/null +++ b/CUDA_Histogram/libwb/wbMPI.h @@ -0,0 +1,37 @@ + +#ifndef __WB_MPI_H__ +#define __WB_MPI_H__ + +#ifdef WB_USE_MPI + +#include +#include +#include + +#define isMasterQ ((wbMPI_getRank()) == 0) + +extern int wbMPI_getRank(); + +extern int rankCount(); + +extern const char *wbMPI_getStringFromRank(int rank, int tag); +extern void wbMPI_sendStringToMaster(const char *str, int tag); + +extern int wbMPI_Init(int *argc, char ***argv); + +extern bool finalizedQ; + +extern "C" int wbMPI_Finalize(void); +extern "C" void wbMPI_Exit(void); + +#define MPI_Finalize wbMPI_Finalize + +#else /* WB_USE_MPI */ +static inline int rankCount() { + return 1; +} +static inline int wbMPI_getRank() { + return 0; +} +#endif /* WB_USE_MPI */ +#endif /* __WB_MPI_H__ */ diff --git a/CUDA_Histogram/libwb/wbMalloc.h b/CUDA_Histogram/libwb/wbMalloc.h new file mode 100644 index 0000000..5d74be4 --- /dev/null +++ b/CUDA_Histogram/libwb/wbMalloc.h @@ -0,0 +1,140 @@ + + +#ifndef __WB_MALLOC_H__ +#define __WB_MALLOC_H__ + +#ifdef WB_USE_CUSTOM_MALLOC +#ifdef __linux__ +#define THROW __THROW +#else +#define THROW +#endif + +static inline void *_malloc(size_t size) THROW { + if (size == 0) { + return NULL; + } else { + int err; + void *res = memmgr_alloc((ulong)size, &err); + if (err) { + fprintf(stderr, "<>:: Memory allocation failed\n"); + exit(1); + } else { + size_t ii = 0; + unsigned char *p = (unsigned char *)res; + while (ii++ < size) { + *p++ = 0; + } + return res; + } + } +} + +static inline void _free(void *ptr) THROW { + if (ptr != NULL) { + memmgr_free(ptr); + } +} + +static inline void *_calloc(size_t nmemb, size_t size) THROW { + return _malloc(nmemb * size); +} + +static inline void *_realloc(void *ptr, size_t size) THROW { + if (size == 0) { + free(ptr); + return NULL; + } else if (ptr == NULL) { + return malloc(size); + } else { + void *buf; + unsigned char *dst; + unsigned char *src; + size_t alloc_size, to_copy, i = 0; + + // Allocate new buffer + buf = malloc(size); + + if (buf != 0) { + // Find original allocation size + alloc_size = (size_t)memmgr_get_block_size(ptr); + to_copy = alloc_size; + if (to_copy > size) { + to_copy = size; + } + + // Copy data to new buffer + dst = (unsigned char *)buf; + src = (unsigned char *)ptr; + while (i++ < to_copy) { + *dst++ = *src++; + } + + // Free the old buffer + free(ptr); + } + + return buf; + } +} + +#define wbNew(type) ((type *)_malloc(sizeof(type))) +#define wbNewArray(type, len) ((type *)_malloc((len) * sizeof(type))) +#define wbMalloc(sz) _malloc(sz) +#define wbDelete(var) \ + _free(var); \ + var = NULL +#define wbFree(var) \ + _free(var); \ + var = NULL +#define wbRealloc(var, newSize) _realloc(var, newSize) +#define wbReallocArray(t, m, n) ((t *)_realloc(m, n * sizeof(t))) + +#define free _free +#define malloc _malloc +#define calloc _calloc +#define realloc _realloc + +#else /* WB_USE_CUSTOM_MALLOC */ + +static inline void *xMalloc(size_t sz) { + void *mem = NULL; + if (sz != 0) { + mem = malloc(sz); + } + return mem; +} + +static inline void xFree(void *mem) { + if (mem != NULL) { + free(mem); + } + return; +} + +static inline void *xRealloc(void *mem, size_t sz) { + if (mem == NULL) { + return NULL; + } else if (sz == 0) { + xFree(mem); + return NULL; + } else { + void *res = realloc(mem, sz); + wbAssert(res != NULL); + return res; + } +} + +#define wbNew(type) ((type *)wbMalloc(sizeof(type))) +#define wbNewArray(type, len) ((type *)wbMalloc((len) * sizeof(type))) +#define wbMalloc(sz) xMalloc(sz) +#define wbDelete(var) wbFree(var) +#define wbFree(var) \ + xFree(var); \ + var = NULL +#define wbRealloc(var, newSize) xRealloc(var, newSize) +#define wbReallocArray(t, m, n) ((t *)xRealloc(m, n * sizeof(t))) + +#endif /* WB_USE_CUSTOM_MALLOC */ + +#endif /* __WB_MALLOC_H__ */ diff --git a/CUDA_Histogram/libwb/wbPPM.cpp b/CUDA_Histogram/libwb/wbPPM.cpp new file mode 100644 index 0000000..86ab208 --- /dev/null +++ b/CUDA_Histogram/libwb/wbPPM.cpp @@ -0,0 +1,199 @@ + +#include +#include "wb.h" + +static inline float _min(float x, float y) { + return x < y ? x : y; +} + +static inline float _max(float x, float y) { + return x > y ? x : y; +} + +static inline float _clamp(float x, float start, float end) { + return _min(_max(x, start), end); +} + +static const char *skipSpaces(const char *line) { + while (*line == ' ' || *line == '\t') { + line++; + if (*line == '\0') { + break; + } + } + return line; +} + +static char nextNonSpaceChar(const char *line0) { + const char *line = skipSpaces(line0); + return *line; +} + +static wbBool isComment(const char *line) { + char nextChar = nextNonSpaceChar(line); + if (nextChar == '\0') { + return wbTrue; + } else { + return nextChar == '#'; + } +} + +static void parseDimensions(const char *line0, int *width, int *height) { + const char *line = skipSpaces(line0); + sscanf(line, "%d %d", width, height); +} + +static void parseDimensions(const char *line0, int *width, int *height, + int *channels) { + const char *line = skipSpaces(line0); + sscanf(line, "%d %d %d", width, height, channels); +} + +static void parseDepth(const char *line0, int *depth) { + const char *line = skipSpaces(line0); + sscanf(line, "%d", depth); +} + +static char *nextLine(wbFile_t file) { + char *line = NULL; + while ((line = wbFile_readLine(file)) != NULL) { + if (!isComment(line)) { + break; + } + } + return line; +} + +wbImage_t wbPPM_import(const char *filename) { + wbImage_t img; + wbFile_t file; + char *header; + char *line; + int ii, jj, kk, channels; + int width, height, depth; + unsigned char *charData, *charIter; + float *imgData, *floatIter; + float scale; + + img = NULL; + + file = wbFile_open(filename, "rb"); + if (file == NULL) { + printf("Could not open %s\n", filename); + goto cleanup; + } + + header = wbFile_readLine(file); + if (header == NULL) { + printf("Could not read from %s\n", filename); + goto cleanup; + } else if (strcmp(header, "P6") != 0 && strcmp(header, "P6\n") != 0 && + strcmp(header, "P5") != 0 && strcmp(header, "P5\n") != 0 && + strcmp(header, "S6") != 0 && strcmp(header, "S6\n") != 0) { + printf("Could find magic number for %s\n", filename); + goto cleanup; + } + + // P5 are monochrome while P6/S6 are rgb + // S6 needs to parse number of channels out of file + if (strcmp(header, "P5") == 0 || strcmp(header, "P5\n") == 0) { + channels = 1; + line = nextLine(file); + parseDimensions(line, &width, &height); + } else if (strcmp(header, "P6") == 0 || strcmp(header, "P6\n") == 0) { + channels = 3; + line = nextLine(file); + parseDimensions(line, &width, &height); + } else { + line = nextLine(file); + parseDimensions(line, &width, &height, &channels); + } + + // the line now contains the depth information + line = nextLine(file); + parseDepth(line, &depth); + + // the rest of the lines contain the data in binary format + charData = (unsigned char *)wbFile_read( + file, width * channels * sizeof(unsigned char), height); + + img = wbImage_new(width, height, channels); + + imgData = wbImage_getData(img); + + charIter = charData; + floatIter = imgData; + + scale = 1.0f / ((float)depth); + + for (ii = 0; ii < height; ii++) { + for (jj = 0; jj < width; jj++) { + for (kk = 0; kk < channels; kk++) { + *floatIter = ((float)*charIter) * scale; + floatIter++; + charIter++; + } + } + } + +#ifdef LAZY_FILE_LOAD + wbDelete(charData); +#endif + +cleanup: + wbFile_close(file); + return img; +} + +void wbPPM_export(const char *filename, wbImage_t img) { + int ii; + int jj; + int kk; + int depth; + int width; + int height; + int channels; + wbFile_t file; + float *floatIter; + unsigned char *charData; + unsigned char *charIter; + + file = wbFile_open(filename, "wb+"); + + width = wbImage_getWidth(img); + height = wbImage_getHeight(img); + channels = wbImage_getChannels(img); + depth = 255; + + if (channels == 1) { + wbFile_writeLine(file, "P5"); + } else { + wbFile_writeLine(file, "P6"); + } + wbFile_writeLine(file, "#Created via wbPPM Export"); + wbFile_writeLine(file, wbString(width, " ", height)); + wbFile_writeLine(file, wbString(depth)); + + charData = wbNewArray(unsigned char, width *height *channels); + + charIter = charData; + floatIter = wbImage_getData(img); + + for (ii = 0; ii < height; ii++) { + for (jj = 0; jj < width; jj++) { + for (kk = 0; kk < channels; kk++) { + *charIter = (unsigned char)ceil(_clamp(*floatIter, 0, 1) * depth); + floatIter++; + charIter++; + } + } + } + + wbFile_write(file, charData, width * channels * sizeof(unsigned char), + height); + + wbDelete(charData); + wbFile_delete(file); + + return; +} diff --git a/CUDA_Histogram/libwb/wbPPM.h b/CUDA_Histogram/libwb/wbPPM.h new file mode 100644 index 0000000..d589b36 --- /dev/null +++ b/CUDA_Histogram/libwb/wbPPM.h @@ -0,0 +1,11 @@ + + +#ifndef __wbPPM_H__ +#define __wbPPM_H__ + +START_EXTERN_C +wbImage_t wbPPM_import(const char *filename); +void wbPPM_export(const char *filename, wbImage_t img); +END_EXTERN_C + +#endif /* __wbPPM_H__ */ diff --git a/CUDA_Histogram/libwb/wbPath.cpp b/CUDA_Histogram/libwb/wbPath.cpp new file mode 100644 index 0000000..0d93e2b --- /dev/null +++ b/CUDA_Histogram/libwb/wbPath.cpp @@ -0,0 +1,42 @@ +#include "wb.h" + +char *wbPath_join(const char *p1, const char *p2) { + size_t s1 = strlen(p1); + size_t s2 = strlen(p2); + char *res = + wbNewArray(char, s1 + 1 /* seperator */ + s2 + 1 /* terminator */); + memcpy(res, p1, s1); + char *iter = res + s1; + *iter++ = wbDirectorySeperator; + memcpy(iter, p2, s2); + iter += s2; + *iter = '\0'; + return res; +} + +char *wbPath_join(const char *p1, const char *p2, const char *p3) { + char *p12 = wbPath_join(p1, p2); + char *res = wbPath_join(p12, p3); + wbDelete(p12); + return res; +} + +char *wbPath_join(const char *p1, const char *p2, const char *p3, + const char *p4) { + char *p123 = wbPath_join(p1, p2, p3); + char *res = wbPath_join(p123, p4); + wbDelete(p123); + return res; +} + +char *wbPath_join(const std::string &p1, const std::string &p2) { + return wbPath_join(p1.c_str(), p2.c_str()); +} +char *wbPath_join(const std::string &p1, const std::string &p2, + const std::string &p3) { + return wbPath_join(p1.c_str(), p2.c_str(), p3.c_str()); +} +char *wbPath_join(const std::string &p1, const std::string &p2, + const std::string &p3, const std::string &p4) { + return wbPath_join(p1.c_str(), p2.c_str(), p3.c_str(), p4.c_str()); +} \ No newline at end of file diff --git a/CUDA_Histogram/libwb/wbPath.h b/CUDA_Histogram/libwb/wbPath.h new file mode 100644 index 0000000..0dd3187 --- /dev/null +++ b/CUDA_Histogram/libwb/wbPath.h @@ -0,0 +1,30 @@ +#ifndef __WB_PATH_H__ +#define __WB_PATH_H__ + +char *wbPath_join(const char *p1, const char *p2); +char *wbPath_join(const char *p1, const char *p2, const char *p3); +char *wbPath_join(const char *p1, const char *p2, const char *p3, + const char *p4); + +char *wbPath_join(const std::string &p1, const std::string &p2); +char *wbPath_join(const std::string &p1, const std::string &p2, + const std::string &p3); +char *wbPath_join(const std::string &p1, const std::string &p2, + const std::string &p3, const std::string &p4); + +template +static char *wbPath_join(const T1 &p1, const T2 &p2) { + return wbPath_join(wbString(p1), wbString(p2)); +} +template +static char *wbPath_join(const T1 &p1, const T2 &p2, const T3 &p3) { + return wbPath_join(wbString(p1), wbString(p2), wbString(p3)); +} +template +static char *wbPath_join(const T1 &p1, const T2 &p2, const T3 &p3, + const T4 &p4) { + return wbPath_join(wbString(p1), wbString(p2), wbString(p3), + wbString(p4)); +} + +#endif /* __WB_PATH_H__ */ diff --git a/CUDA_Histogram/libwb/wbSolution.cpp b/CUDA_Histogram/libwb/wbSolution.cpp new file mode 100644 index 0000000..703f410 --- /dev/null +++ b/CUDA_Histogram/libwb/wbSolution.cpp @@ -0,0 +1,271 @@ + +#include "wb.h" + +char *solutionJSON = NULL; +static string _solution_correctQ(""); + +static void _onUnsameImageFunction(string str) { + _solution_correctQ = str; +} + +template +static wbBool wbSolution_listCorrectQ(const char *expectedOutputFile, + wbSolution_t sol, const char *type) { + wbBool res; + T *expectedData; + int expectedRows, expectedColumns; + + expectedData = (T *)wbImport(expectedOutputFile, &expectedRows, + &expectedColumns, type); + + if (expectedData == NULL) { + _solution_correctQ = "Failed to open expected output file."; + res = wbFalse; + } else if (expectedRows != wbSolution_getRows(sol)) { + wbLog(TRACE, "Number of rows in the solution is ", + wbSolution_getRows(sol), ". Expected number of rows is ", + expectedRows, "."); + _solution_correctQ = + "The number of rows in the solution did not match " + "that of the expected results."; + res = wbFalse; + } else if (expectedColumns != wbSolution_getColumns(sol)) { + wbLog(TRACE, "Number of columns in the solution is ", + wbSolution_getColumns(sol), ". Expected number of columns is ", + expectedColumns, "."); + _solution_correctQ = "The number of columns in the solution did not " + "match that of the expected results."; + res = wbFalse; + } else { + int ii, jj, idx; + T *solutionData; + + solutionData = (T *)wbSolution_getData(sol); + + for (ii = 0; ii < expectedRows; ii++) { + for (jj = 0; jj < expectedColumns; jj++) { + idx = ii * expectedColumns + jj; + if (wbUnequalQ(expectedData[idx], solutionData[idx])) { + string str; + if (expectedColumns == 1) { + str = wbString( + "The solution did not match the expected results at row ", + ii, ". Expecting ", expectedData[idx], " but got ", + solutionData[idx], "."); + } else { + str = wbString("The solution did not match the expected " + "results at column ", + jj, " and row ", ii, ". Expecting ", + expectedData[idx], " but got ", + solutionData[idx], "."); + } + _solution_correctQ = str; + res = wbFalse; + goto matrixCleanup; + } + } + } + + res = wbTrue; + matrixCleanup: + if (expectedData != NULL) { + wbFree(expectedData); + } + } + return res; +} + +static wbBool wbSolution_correctQ(char *expectedOutputFile, + wbSolution_t sol) { + if (expectedOutputFile == NULL) { + _solution_correctQ = "Failed to determined the expected output file."; + return wbFalse; + } else if (!wbFile_existsQ(expectedOutputFile)) { + _solution_correctQ = + wbString("The file ", expectedOutputFile, " does not exist."); + return wbFalse; + } else if (wbString_sameQ(wbSolution_getType(sol), "image")) { + wbBool res; + wbImage_t solutionImage = NULL; + wbImage_t expectedImage = wbImport(expectedOutputFile); + if (expectedImage == NULL) { + _solution_correctQ = "Failed to open expected output file."; + res = wbFalse; + } else if (wbImage_getWidth(expectedImage) != + wbSolution_getWidth(sol)) { + _solution_correctQ = + "The image width of the expected image does not " + "match that of the solution."; + res = wbFalse; + } else if (wbImage_getHeight(expectedImage) != + wbSolution_getHeight(sol)) { + _solution_correctQ = + "The image height of the expected image does not " + "match that of the solution."; + res = wbFalse; + } else if (wbImage_getChannels(expectedImage) != + wbSolution_getChannels(sol)) { + _solution_correctQ = + "The image channels of the expected image does not " + "match that of the solution."; + res = wbFalse; + } else { + solutionImage = (wbImage_t)wbSolution_getData(sol); + wbAssert(solutionImage != NULL); + res = wbImage_sameQ(solutionImage, expectedImage, + _onUnsameImageFunction); + } + if (expectedImage != NULL) { + wbImage_delete(expectedImage); + } + return res; + } else if (wbString_sameQ(wbSolution_getType(sol), "histogram")) { + return wbSolution_listCorrectQ(expectedOutputFile, sol, + "Integer"); + } else if (wbString_sameQ(wbSolution_getType(sol), "integral_vector")) { + return wbSolution_listCorrectQ(expectedOutputFile, sol, + "Integer"); + } else if (wbString_sameQ(wbSolution_getType(sol), "vector") || + wbString_sameQ(wbSolution_getType(sol), "matrix")) { + return wbSolution_listCorrectQ(expectedOutputFile, sol, + "Real"); + } else { + wbAssert(wbFalse); + return wbFalse; + } +} + +wbBool wbSolution(char *expectedOutputFile, char *outputFile, char *type0, + void *data, int rows, int columns, int depth) { + char *type; + wbBool res; + wbSolution_t sol; + + if (expectedOutputFile == NULL || data == NULL || type0 == NULL) { + wbLog(ERROR, "Failed to grade solution"); + return wbFalse; + } + + type = wbString_toLower(type0); + + if (_solution_correctQ != "") { + _solution_correctQ = ""; + } + + wbSolution_setOutputFile(sol, outputFile); + wbSolution_setType(sol, type); + wbSolution_setData(sol, data); + wbSolution_setRows(sol, rows); + wbSolution_setColumns(sol, columns); + wbSolution_setDepth(sol, depth); + + res = wbSolution_correctQ(expectedOutputFile, sol); + + if (outputFile != NULL) { + if (wbString_sameQ(type, "image")) { + wbImage_t inputImage = (wbImage_t)data; + wbImage_t img = wbImage_new(wbImage_getWidth(inputImage), + wbImage_getHeight(inputImage), + wbImage_getChannels(inputImage)); + memcpy(wbImage_getData(img), wbImage_getData(inputImage), + rows * columns * wbImage_channels * sizeof(wbReal_t)); + wbExport(outputFile, img); + wbImage_delete(img); + } else if (wbString_sameQ(type, "integral_vector")) { + wbExport(outputFile, (int *)data, rows, columns); + } else if (wbString_sameQ(type, "vector") || + wbString_sameQ(type, "matrix")) { + wbExport(outputFile, (wbReal_t *)data, rows, columns); + } else if (wbString_sameQ(type, "histogram")) { + wbExport(outputFile, (unsigned char *)data, rows, columns); + } else if (wbString_sameQ(type, "text")) { + wbExport_text(outputFile, (unsigned char *)data, rows * columns); + } + } + + wbFree(type); + + return res; +} + +wbBool wbSolution(char *expectedOutputFile, char *outputFile, char *type0, + void *data, int rows, int columns) { + return wbSolution(expectedOutputFile, outputFile, type0, data, rows, + columns, 1); +} + +wbBool wbSolution(wbArg_t arg, void *data, int rows, int columns, + int depth) { + char *type; + wbBool res; + char *expectedOutputFile; + char *outputFile; + stringstream ss; + + expectedOutputFile = wbArg_getExpectedOutputFile(arg); + outputFile = wbArg_getOutputFile(arg); + type = wbArg_getType(arg); + + wbAssert(type != NULL); + wbAssert(expectedOutputFile != NULL); + wbAssert(outputFile != NULL); + + res = wbSolution(expectedOutputFile, outputFile, type, data, rows, + columns, depth); + + if (WB_USE_JSON11) { + json11::Json json; + if (res) { + json = json11::Json::object{{"correctq", true}, + {"message", "The solution is correct"}}; + } else { + json = json11::Json::object{{"correctq", false}, + {"message", _solution_correctQ}}; + } + +#ifdef wbLogger_printOnLog + if (wbLogger_printOnLog) { + json11::Json e = +//PMO +#ifndef _MSC_VER + json11::Json::object{{"type", "solution"}, {"data", json}}; +#else + json11::Json::object{{"data", json }, {"type", "solution" }}; +#endif + std::cout << e.dump() << std::endl; + } +#endif /* wbLogger_printOnLog */ + + solutionJSON = wbString_duplicate(json.string_value()); + } else { + if (res) { + ss << "{\n"; + ss << wbString_quote("correctq") << ": true,\n"; + ss << wbString_quote("message") << ": " + << wbString_quote("Solution is correct.") << "\n"; + ss << "}"; + } else { + ss << "{\n"; + ss << wbString_quote("correctq") << ": false,\n"; + ss << wbString_quote("message") << ": " + << wbString_quote(_solution_correctQ) << "\n"; + ss << "}"; + } + solutionJSON = wbString_duplicate(ss.str()); + } + + return res; +} + +wbBool wbSolution(wbArg_t arg, void *data, int rows, int columns) { + return wbSolution(arg, data, rows, columns, 1); +} + +EXTERN_C wbBool wbSolution(wbArg_t arg, void *data, int rows) { + return wbSolution(arg, data, rows, 1); +} + +wbBool wbSolution(wbArg_t arg, wbImage_t img) { + return wbSolution(arg, img, wbImage_getHeight(img), + wbImage_getWidth(img), wbImage_getChannels(img)); +} diff --git a/CUDA_Histogram/libwb/wbSolution.h b/CUDA_Histogram/libwb/wbSolution.h new file mode 100644 index 0000000..f18d07d --- /dev/null +++ b/CUDA_Histogram/libwb/wbSolution.h @@ -0,0 +1,40 @@ + + +#ifndef __WB_SOLUTION_H__ +#define __WB_SOLUTION_H__ + +typedef struct st_wbSolution_t { + char *type; + char *outputFile; + void *data; + int rows; + int columns; + int depth; +} wbSolution_t; + +#define wbSolution_getType(sol) ((sol).type) +#define wbSolution_getOutputFile(sol) ((sol).outputFile) +#define wbSolution_getData(sol) ((sol).data) +#define wbSolution_getRows(sol) ((sol).rows) +#define wbSolution_getColumns(sol) ((sol).columns) +#define wbSolution_getDepth(sol) ((sol).depth) + +#define wbSolution_getHeight wbSolution_getRows +#define wbSolution_getWidth wbSolution_getColumns +#define wbSolution_getChannels wbSolution_getDepth + +#define wbSolution_setType(sol, val) (wbSolution_getType(sol) = val) +#define wbSolution_setOutputFile(sol, val) \ + (wbSolution_getOutputFile(sol) = val) +#define wbSolution_setData(sol, val) (wbSolution_getData(sol) = val) +#define wbSolution_setRows(sol, val) (wbSolution_getRows(sol) = val) +#define wbSolution_setColumns(sol, val) (wbSolution_getColumns(sol) = val) +#define wbSolution_setDepth(sol, val) (wbSolution_getDepth(sol) = val) + +wbBool wbSolution(char *expectedOutputFile, char *outputFile, char *type0, + void *data, int rows, int columns); +wbBool wbSolution(wbArg_t arg, void *data, int rows, int columns); +EXTERN_C wbBool wbSolution(wbArg_t arg, void *data, int rows); +wbBool wbSolution(wbArg_t arg, wbImage_t img); + +#endif /* __WB_SOLUTION_H__ */ diff --git a/CUDA_Histogram/libwb/wbSparse.cpp b/CUDA_Histogram/libwb/wbSparse.cpp new file mode 100644 index 0000000..9cdcba3 --- /dev/null +++ b/CUDA_Histogram/libwb/wbSparse.cpp @@ -0,0 +1,82 @@ + +#include "wb.h" + +static void sort(int *data, int *key, int start, int end) { + if ((end - start + 1) > 1) { + int left = start, right = end; + int pivot = key[right]; + while (left <= right) { + while (key[left] > pivot) { + left = left + 1; + } + while (key[right] < pivot) { + right = right - 1; + } + if (left <= right) { + int tmp = key[left]; + key[left] = key[right]; + key[right] = tmp; + tmp = data[left]; + data[left] = data[right]; + data[right] = tmp; + left = left + 1; + right = right - 1; + } + } + sort(data, key, start, right); + sort(data, key, left, end); + } +} + +EXTERN_C void CSRToJDS(int dim, int *csrRowPtr, int *csrColIdx, + float *csrData, int **jdsRowPerm, int **jdsRowNNZ, + int **jdsColStartIdx, int **jdsColIdx, + float **jdsData) { + // Row Permutation Vector + *jdsRowPerm = (int *)malloc(sizeof(int) * dim); + for (int rowIdx = 0; rowIdx < dim; ++rowIdx) { + (*jdsRowPerm)[rowIdx] = rowIdx; + } + + // Number of non-zeros per row + *jdsRowNNZ = (int *)malloc(sizeof(int) * dim); + for (int rowIdx = 0; rowIdx < dim; ++rowIdx) { + (*jdsRowNNZ)[rowIdx] = csrRowPtr[rowIdx + 1] - csrRowPtr[rowIdx]; + } + + // Sort rows by number of non-zeros + sort(*jdsRowPerm, *jdsRowNNZ, 0, dim - 1); + + // Starting point of each compressed column + int maxRowNNZ = (*jdsRowNNZ)[0]; // Largest number of non-zeros per row + DEBUG(printf("jdsRowNNZ = %d\n", maxRowNNZ)); + *jdsColStartIdx = (int *)malloc(sizeof(int) * maxRowNNZ); + (*jdsColStartIdx)[0] = 0; // First column starts at 0 + for (int col = 0; col < maxRowNNZ - 1; ++col) { + // Count the number of rows with entries in this column + int count = 0; + for (int idx = 0; idx < dim; ++idx) { + if ((*jdsRowNNZ)[idx] > col) { + ++count; + } + } + (*jdsColStartIdx)[col + 1] = (*jdsColStartIdx)[col] + count; + } + + // Sort the column indexes and data + const int NNZ = csrRowPtr[dim]; + DEBUG(printf("NNZ = %d\n", NNZ)); + *jdsColIdx = (int *)malloc(sizeof(int) * NNZ); + DEBUG(printf("dim = %d\n", dim)); + *jdsData = (float *)malloc(sizeof(float) * NNZ); + for (int idx = 0; idx < dim; ++idx) { // For every row + int row = (*jdsRowPerm)[idx]; + int rowNNZ = (*jdsRowNNZ)[idx]; + for (int nnzIdx = 0; nnzIdx < rowNNZ; ++nnzIdx) { + int jdsPos = (*jdsColStartIdx)[nnzIdx] + idx; + int csrPos = csrRowPtr[row] + nnzIdx; + (*jdsColIdx)[jdsPos] = csrColIdx[csrPos]; + (*jdsData)[jdsPos] = csrData[csrPos]; + } + } +} diff --git a/CUDA_Histogram/libwb/wbSparse.h b/CUDA_Histogram/libwb/wbSparse.h new file mode 100644 index 0000000..c04a857 --- /dev/null +++ b/CUDA_Histogram/libwb/wbSparse.h @@ -0,0 +1,10 @@ + +#ifndef __WB_SPARSE_H__ +#define __WB_SPARSE_H__ + +EXTERN_C void CSRToJDS(int dim, int *csrRowPtr, int *csrColIdx, + float *csrData, int **jdsRowPerm, int **jdsRowNNZ, + int **jdsColStartIdx, int **jdsColIdx, + float **jdsData); + +#endif /* __WB_SPARSE_H__ */ diff --git a/CUDA_Histogram/libwb/wbString.h b/CUDA_Histogram/libwb/wbString.h new file mode 100644 index 0000000..65e52f8 --- /dev/null +++ b/CUDA_Histogram/libwb/wbString.h @@ -0,0 +1,324 @@ + + +#ifndef __WB_STRING_H__ +#define __WB_STRING_H__ + +#include +#include +#include +#include +#include +#include +#include "wb.h" + +using std::string; +using std::vector; +using std::stringstream; +using std::exception; + +template +static inline string wbString(const T &x); + +static inline void wbString_replace(string &value, string const &search, + string const &replace) { + for (string::size_type next = value.find(search); next != string::npos; + next = value.find(search, next)) { + value.replace(next, search.length(), replace); + next += replace.length(); + } +} + +static inline string wbString_quote(string str) { + string s = str; + wbString_replace(s, "\\", "\\\\"); + s = "\"" + s + "\""; + return s; +} + +static inline string wbString_quote(const char *str) { + if (str == NULL) { + return wbString_quote(""); + } else { + return wbString_quote(string(str)); + } +} + +static inline char *wbString_duplicate(const char *str) { + if (str == NULL) { + return NULL; + } else { + char *newstr; + size_t len = strlen(str); + newstr = wbNewArray(char, len + 1); + memcpy(newstr, str, len * sizeof(char)); + newstr[len] = '\0'; + return newstr; + } +} + +static inline char *wbString_duplicate(std::string str) { + return wbString_duplicate(str.c_str()); +} + +static inline string wbString(void) { + string s = ""; + return s; +} + +template +static inline string wbString(const T &x) { + try { + stringstream ss; + ss << x; + return ss.str(); + } catch (exception &e) { + return string(); + } +} + +template <> +inline string wbString(const bool &x) { + return x ? "True" : "False"; +} + +template <> +inline string wbString(const vector &x) { + stringstream ss; + ss << "{"; + for (size_t ii = 0; ii < x.size(); ii++) { + ss << wbString_quote(x[ii]); + if (ii != x.size() - 1) { + ss << ", "; + } + } + ss << "}"; + + return ss.str(); +} + +template <> +inline string wbString(const vector &x) { + stringstream ss; + ss << "{"; + for (size_t ii = 0; ii < x.size(); ii++) { + ss << x[ii]; + if (ii != x.size() - 1) { + ss << ", "; + } + } + ss << "}"; + + return ss.str(); +} + +template <> +inline string wbString(const vector &x) { + stringstream ss; + ss << "{"; + for (size_t ii = 0; ii < x.size(); ii++) { + ss << x[ii]; + if (ii != x.size() - 1) { + ss << ", "; + } + } + ss << "}"; + + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1) { + stringstream ss; + ss << wbString(x0) << wbString(x1); + + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1, const T2 &x2) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2); + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1, const T2 &x2, + const T3 &x3) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2) << wbString(x3); + + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1, const T2 &x2, + const T3 &x3, const T4 &x4) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2) << wbString(x3) + << wbString(x4); + + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1, const T2 &x2, + const T3 &x3, const T4 &x4, const T5 &x5) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2) << wbString(x3) + << wbString(x4) << wbString(x5); + + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1, const T2 &x2, + const T3 &x3, const T4 &x4, const T5 &x5, + const T6 &x6) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2) << wbString(x3) + << wbString(x4) << wbString(x5) << wbString(x6); + + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1, const T2 &x2, + const T3 &x3, const T4 &x4, const T5 &x5, + const T6 &x6, const T7 &x7) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2) << wbString(x3) + << wbString(x4) << wbString(x5) << wbString(x6) << wbString(x7); + + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1, const T2 &x2, + const T3 &x3, const T4 &x4, const T5 &x5, + const T6 &x6, const T7 &x7, const T8 &x8) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2) << wbString(x3) + << wbString(x4) << wbString(x5) << wbString(x6) << wbString(x7) + << wbString(x8); + + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1, const T2 &x2, + const T3 &x3, const T4 &x4, const T5 &x5, + const T6 &x6, const T7 &x7, const T8 &x8, + const T9 &x9) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2) << wbString(x3) + << wbString(x4) << wbString(x5) << wbString(x6) << wbString(x7) + << wbString(x8) << wbString(x9); + + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1, const T2 &x2, + const T3 &x3, const T4 &x4, const T5 &x5, + const T6 &x6, const T7 &x7, const T8 &x8, + const T9 &x9, const T10 &x10) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2) << wbString(x3) + << wbString(x4) << wbString(x5) << wbString(x6) << wbString(x7) + << wbString(x8) << wbString(x9) << wbString(x10); + + return ss.str(); +} + +template +static inline string +wbString(const T0 &x0, const T1 &x1, const T2 &x2, const T3 &x3, + const T4 &x4, const T5 &x5, const T6 &x6, const T7 &x7, + const T8 &x8, const T9 &x9, const T10 &x10, const T11 &x11) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2) << wbString(x3) + << wbString(x4) << wbString(x5) << wbString(x6) << wbString(x7) + << wbString(x8) << wbString(x9) << wbString(x10) << wbString(x11); + + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1, const T2 &x2, + const T3 &x3, const T4 &x4, const T5 &x5, + const T6 &x6, const T7 &x7, const T8 &x8, + const T9 &x9, const T10 &x10, const T11 &x11, + const T12 &x12) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2) << wbString(x3) + << wbString(x4) << wbString(x5) << wbString(x6) << wbString(x7) + << wbString(x8) << wbString(x9) << wbString(x10) << wbString(x11) + << wbString(x12); + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1, const T2 &x2, + const T3 &x3, const T4 &x4, const T5 &x5, + const T6 &x6, const T7 &x7, const T8 &x8, + const T9 &x9, const T10 &x10, const T11 &x11, + const T12 &x12, const T13 &x13) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2) << wbString(x3) + << wbString(x4) << wbString(x5) << wbString(x6) << wbString(x7) + << wbString(x8) << wbString(x9) << wbString(x10) << wbString(x11) + << wbString(x12) << wbString(x13); + return ss.str(); +} + +template +static inline wbBool wbString_sameQ(const X &x, const Y &y) { + string xs = wbString(x); + string ys = wbString(y); + return strcmp(xs.c_str(), ys.c_str()) == 0; +} + +static inline wbBool wbString_sameQ(const string &x, const string &y) { + return x.compare(y) == 0; +} + +static inline char *wbString_toLower(const char *str) { + if (str == NULL) { + return NULL; + } else { + char *res, *iter; + + res = iter = wbString_duplicate(str); + while (*iter != '\0') { + *iter++ = tolower(*str++); + } + return res; + } +} + +static inline wbBool wbString_startsWith(const char *str, + const char *prefix) { + while (*prefix != '\0') { + if (*str == '\0' || *str != *prefix) { + return wbFalse; + } + str++; + prefix++; + } + return wbTrue; +} + +#endif /* __WB_STRING_H__ */ diff --git a/CUDA_Histogram/libwb/wbThrust.h b/CUDA_Histogram/libwb/wbThrust.h new file mode 100644 index 0000000..e2d3160 --- /dev/null +++ b/CUDA_Histogram/libwb/wbThrust.h @@ -0,0 +1,15 @@ + +#ifndef __WB_THRUST_H__ +#define __WB_THRUST_H__ + +#ifdef WB_USE_CUDA +#include +#include +#include +#include +#include +#include + +#endif /* WB_USE_CUDA */ + +#endif /* __WB_THRUST_H__ */ diff --git a/CUDA_Histogram/libwb/wbTimer.cpp b/CUDA_Histogram/libwb/wbTimer.cpp new file mode 100644 index 0000000..c9fbdb8 --- /dev/null +++ b/CUDA_Histogram/libwb/wbTimer.cpp @@ -0,0 +1,493 @@ +#include "wb.h" + +#ifdef WB_USE_WINDOWS +uint64_t _hrtime_frequency = 0; +#endif /* WB_USE_WINDOWS */ +wbTimer_t _timer = NULL; + +#ifdef WB_USE_DARWIN +static double o_timebase = 0; +static uint64_t o_timestart = 0; +#endif /* WB_USE_DARWIN */ + +uint64_t _hrtime(void) { +#define NANOSEC ((uint64_t)1e9) +#ifdef WB_USE_WINDOWS + LARGE_INTEGER counter; + if (!QueryPerformanceCounter(&counter)) { + return 0; + } + return ((uint64_t)counter.LowPart * NANOSEC / _hrtime_frequency) + + (((uint64_t)counter.HighPart * NANOSEC / _hrtime_frequency) + << 32); +#else + struct timespec ts; +#ifdef WB_USE_DARWIN +#define O_NANOSEC (+1.0E-9) +#define O_GIGA UINT64_C(1000000000) + if (!o_timestart) { + mach_timebase_info_data_t tb{}; + mach_timebase_info(&tb); + o_timebase = tb.numer; + o_timebase /= tb.denom; + o_timestart = mach_absolute_time(); + } + double diff = (mach_absolute_time() - o_timestart) * o_timebase; + ts.tv_sec = diff * O_NANOSEC; + ts.tv_nsec = diff - (ts.tv_sec * O_GIGA); +#undef O_NANOSEC +#undef O_GIGA +#else /* WB_USE_DARWIN */ + clock_gettime(CLOCK_MONOTONIC, &ts); +#endif /* WB_USE_DARWIN */ + return (((uint64_t)ts.tv_sec) * NANOSEC + ts.tv_nsec); +#endif /* WB_USE_WINDOWS */ +#undef NANOSEC +} + +static inline uint64_t getTime(void) { +#ifdef WB_USE_CUDA + cudaDeviceSynchronize(); +#endif /* WB_USE_CUDA */ + return _hrtime(); +} + +static inline wbTimerNode_t wbTimerNode_new(int id, wbTimerKind_t kind, + const char *file, + const char *fun, + int startLine) { + wbTimerNode_t node = wbNew(struct st_wbTimerNode_t); + wbTimerNode_setId(node, id); + wbTimerNode_setMPIRank(node, wbMPI_getRank()); + wbTimerNode_setLevel(node, 0); + wbTimerNode_setStoppedQ(node, wbFalse); + wbTimerNode_setKind(node, kind); + wbTimerNode_setStartTime(node, 0); + wbTimerNode_setEndTime(node, 0); + wbTimerNode_setElapsedTime(node, 0); + wbTimerNode_setStartLine(node, startLine); + wbTimerNode_setEndLine(node, 0); + wbTimerNode_setStartFunction(node, fun); + wbTimerNode_setEndFunction(node, NULL); + wbTimerNode_setStartFile(node, file); + wbTimerNode_setEndFile(node, NULL); + wbTimerNode_setNext(node, NULL); + wbTimerNode_setPrevious(node, NULL); + wbTimerNode_setParent(node, NULL); + wbTimerNode_setMessage(node, NULL); + return node; +} + +static inline void wbTimerNode_delete(wbTimerNode_t node) { + if (node != NULL) { + if (wbTimerNode_getMessage(node)) { + wbDelete(wbTimerNode_getMessage(node)); + } + wbDelete(node); + } +} + +static inline const char *_nodeKind(wbTimerKind_t kind) { + switch (kind) { + case wbTimerKind_Generic: + return "Generic"; + case wbTimerKind_IO: + return "IO"; + case wbTimerKind_GPU: + return "GPU"; + case wbTimerKind_Copy: + return "Copy"; + case wbTimerKind_Driver: + return "Driver"; + case wbTimerKind_CopyAsync: + return "CopyAsync"; + case wbTimerKind_Compute: + return "Compute"; + case wbTimerKind_CPUGPUOverlap: + return "CPUGPUOverlap"; + } + return "Undefined"; +} + +static inline json11::Json wbTimerNode_toJSONObject(wbTimerNode_t node) { + json11::Json json = json11::Json::object{ + {"id", wbTimerNode_getId(node)}, + {"mpi_rank", wbTimerNode_getMPIRank(node)}, + {"stopped", wbTimerNode_stoppedQ(node)}, + {"kind", _nodeKind(wbTimerNode_getKind(node))}, + {"start_time", wbTimerNode_getStartTime(node)}, + {"end_time", wbTimerNode_getEndTime(node)}, + {"elapsed_time", wbTimerNode_getElapsedTime(node)}, + {"start_line", wbTimerNode_getStartLine(node)}, + {"end_line", wbTimerNode_getEndLine(node)}, + {"start_function", wbTimerNode_getStartFunction(node)}, + {"end_function", wbTimerNode_getEndFunction(node)}, + {"start_file", wbTimerNode_getStartFile(node)}, + {"end_file", wbTimerNode_getEndFile(node)}, + {"parent_id", wbTimerNode_hasParent(node) + ? wbTimerNode_getId(wbTimerNode_getParent(node)) + : -1}, + {"message", wbTimerNode_getMessage(node)}, + }; + return json; +} + +static inline string wbTimerNode_toJSON(wbTimerNode_t node) { + if (node == NULL) { + return ""; + } else if (WB_USE_JSON11) { + json11::Json json = wbTimerNode_toJSONObject(node); + return json.string_value(); + } else { + stringstream ss; + + ss << "{\n"; + ss << wbString_quote("id") << ":" << wbTimerNode_getId(node) << ",\n"; + ss << wbString_quote("mpi_rank") << ":" << wbTimerNode_getMPIRank(node) + << ",\n"; + ss << wbString_quote("stopped") << ":" + << wbString(wbTimerNode_stoppedQ(node) ? "true" : "false") << ",\n"; + ss << wbString_quote("kind") << ":" + << wbString_quote(_nodeKind(wbTimerNode_getKind(node))) << ",\n"; + ss << wbString_quote("start_time") << ":" + << wbTimerNode_getStartTime(node) << ",\n"; + ss << wbString_quote("end_time") << ":" << wbTimerNode_getEndTime(node) + << ",\n"; + ss << wbString_quote("elapsed_time") << ":" + << wbTimerNode_getElapsedTime(node) << ",\n"; + ss << wbString_quote("start_line") << ":" + << wbTimerNode_getStartLine(node) << ",\n"; + ss << wbString_quote("end_line") << ":" << wbTimerNode_getEndLine(node) + << ",\n"; + ss << wbString_quote("start_function") << ":" + << wbString_quote(wbTimerNode_getStartFunction(node)) << ",\n"; + ss << wbString_quote("end_function") << ":" + << wbString_quote(wbTimerNode_getEndFunction(node)) << ",\n"; + ss << wbString_quote("start_file") << ":" + << wbString_quote(wbTimerNode_getStartFile(node)) << ",\n"; + ss << wbString_quote("end_file") << ":" + << wbString_quote(wbTimerNode_getEndFile(node)) << ",\n"; + ss << wbString_quote("parent_id") << ":" + << wbString(wbTimerNode_hasParent(node) + ? wbTimerNode_getId(wbTimerNode_getParent(node)) + : -1) + << ",\n"; + ss << wbString_quote("message") << ":" + << wbString_quote(wbTimerNode_getMessage(node)) << "\n"; + ss << "}"; + + return ss.str(); + } +} + +static inline string wbTimerNode_toXML(wbTimerNode_t node) { + if (node == NULL) { + return ""; + } else { + stringstream ss; + + ss << "\n"; + ss << "" << wbTimerNode_getId(node) << "\n"; + ss << "" + << wbString(wbTimerNode_stoppedQ(node) ? "true" : "false") + << "\n"; + ss << "" << _nodeKind(wbTimerNode_getKind(node)) << "\n"; + ss << "" << wbTimerNode_getStartTime(node) + << "\n"; + ss << "" << wbTimerNode_getEndTime(node) << "\n"; + ss << "" << wbTimerNode_getElapsedTime(node) + << "\n"; + ss << "" << wbTimerNode_getStartLine(node) + << "\n"; + ss << "" << wbTimerNode_getEndLine(node) << "\n"; + ss << "" << wbTimerNode_getStartFunction(node) + << "\n"; + ss << "" << wbTimerNode_getEndFunction(node) + << "\n"; + ss << "" << wbTimerNode_getStartFile(node) + << "\n"; + ss << "" << wbTimerNode_getEndFile(node) << "\n"; + ss << "" + << wbString(wbTimerNode_hasParent(node) + ? wbTimerNode_getId(wbTimerNode_getParent(node)) + : -1) + << "\n"; + ss << "" << wbTimerNode_getMessage(node) << "\n"; + ss << "\n"; + + return ss.str(); + } +} + +#define wbTimer_getLength(timer) ((timer)->length) +#define wbTimer_getHead(timer) ((timer)->head) +#define wbTimer_getTail(timer) ((timer)->tail) +#define wbTimer_getStartTime(timer) ((timer)->startTime) +#define wbTimer_getEndTime(timer) ((timer)->endTime) +#define wbTimer_getElapsedTime(timer) ((timer)->elapsedTime) + +#define wbTimer_setLength(timer, val) (wbTimer_getLength(timer) = val) +#define wbTimer_setHead(timer, val) (wbTimer_getHead(timer) = val) +#define wbTimer_setTail(timer, val) (wbTimer_getTail(timer) = val) +#define wbTimer_setStartTime(node, val) (wbTimer_getStartTime(node) = val) +#define wbTimer_setEndTime(node, val) (wbTimer_getEndTime(node) = val) +#define wbTimer_setElapsedTime(node, val) \ + (wbTimer_getElapsedTime(node) = val) + +#define wbTimer_incrementLength(timer) (wbTimer_getLength(timer)++) +#define wbTimer_decrementLength(timer) (wbTimer_getLength(timer)--) + +#define wbTimer_emptyQ(timer) (wbTimer_getLength(timer) == 0) + +void wbTimer_delete(wbTimer_t timer) { + if (timer != NULL) { + wbTimerNode_t tmp, iter; + + iter = wbTimer_getHead(timer); + while (iter) { + tmp = wbTimerNode_getNext(iter); + wbTimerNode_delete(iter); + iter = tmp; + } + + wbDelete(timer); + } +} + +static json11::Json wbTimer_toJSONObject(wbTimer_t timer) { + + stringstream ss; + wbTimerNode_t iter; + uint64_t currentTime; + std::vector elems; + + currentTime = getTime(); + + wbTimer_setEndTime(timer, currentTime); + wbTimer_setElapsedTime(timer, currentTime - wbTimer_getStartTime(timer)); + + for (iter = wbTimer_getHead(timer); iter != NULL; + iter = wbTimerNode_getNext(iter)) { + if (!wbTimerNode_stoppedQ(iter)) { + wbTimerNode_setEndTime(iter, currentTime); + wbTimerNode_setElapsedTime(iter, currentTime - + wbTimerNode_getStartTime(iter)); + } + elems.push_back(wbTimerNode_toJSONObject(iter)); + } + return json11::Json(elems); +} + +string wbTimer_toJSON(wbTimer_t timer) { + if (timer == NULL) { + return ""; + } else if (WB_USE_JSON11) { + json11::Json json = wbTimer_toJSONObject(timer); + return json.string_value(); + } else { + stringstream ss; + wbTimerNode_t iter; + uint64_t currentTime; + + currentTime = getTime(); + + wbTimer_setEndTime(timer, currentTime); + wbTimer_setElapsedTime(timer, + currentTime - wbTimer_getStartTime(timer)); + + for (iter = wbTimer_getHead(timer); iter != NULL; + iter = wbTimerNode_getNext(iter)) { + if (!wbTimerNode_stoppedQ(iter)) { + wbTimerNode_setEndTime(iter, currentTime); + wbTimerNode_setElapsedTime( + iter, currentTime - wbTimerNode_getStartTime(iter)); + } + ss << wbTimerNode_toJSON(iter); + if (wbTimerNode_getNext(iter) != NULL) { + ss << ",\n"; + } + } + + return ss.str(); + } +} + +string wbTimer_toJSON() { + return wbTimer_toJSON(_timer); +} + +string wbTimer_toXML(wbTimer_t timer) { + if (timer == NULL) { + return ""; + } else { + stringstream ss; + wbTimerNode_t iter; + uint64_t currentTime; + + currentTime = getTime(); + + wbTimer_setEndTime(timer, currentTime); + wbTimer_setElapsedTime(timer, + currentTime - wbTimer_getStartTime(timer)); + + ss << "\n"; + ss << "" << wbTimer_getStartTime(timer) + << "\n"; + ss << "" << wbTimer_getEndTime(timer) << "\n"; + ss << "" << wbTimer_getElapsedTime(timer) + << "\n"; + ss << "\n"; + for (iter = wbTimer_getHead(timer); iter != NULL; + iter = wbTimerNode_getNext(iter)) { + if (!wbTimerNode_stoppedQ(iter)) { + wbTimerNode_setEndTime(iter, currentTime); + wbTimerNode_setElapsedTime( + iter, currentTime - wbTimerNode_getStartTime(iter)); + } + ss << wbTimerNode_toXML(iter); + } + ss << "\n"; + ss << "\n"; + + return ss.str(); + } +} + +string wbTimer_toXML() { + return wbTimer_toXML(_timer); +} + +wbTimer_t wbTimer_new(void) { + wbTimer_t timer = wbNew(struct st_wbTimer_t); + wbTimer_setLength(timer, 0); + wbTimer_setHead(timer, NULL); + wbTimer_setTail(timer, NULL); + wbTimer_setStartTime(timer, getTime()); + wbTimer_setEndTime(timer, 0); + wbTimer_setElapsedTime(timer, 0); + + return timer; +} + +static inline wbTimerNode_t _findParent(wbTimer_t timer) { + wbTimerNode_t iter; + + for (iter = wbTimer_getTail(timer); iter != NULL; + iter = wbTimerNode_getPrevious(iter)) { + if (!wbTimerNode_stoppedQ(iter)) { + return iter; + } + } + return NULL; +} + +static inline void _insertIntoList(wbTimer_t timer, wbTimerNode_t node) { + if (wbTimer_emptyQ(timer)) { + wbTimer_setHead(timer, node); + wbTimer_setTail(timer, node); + } else { + wbTimerNode_t end = wbTimer_getTail(timer); + wbTimer_setTail(timer, node); + wbTimerNode_setNext(end, node); + wbTimerNode_setPrevious(node, end); + } + wbTimer_incrementLength(timer); +} + +wbTimerNode_t wbTimer_start(wbTimerKind_t kind, const char *file, + const char *fun, int line) { + int id; + uint64_t currentTime; + wbTimerNode_t node; + wbTimerNode_t parent; + + wb_init(NULL, NULL); + + currentTime = getTime(); + + id = wbTimer_getLength(_timer); + + node = wbTimerNode_new(id, kind, file, fun, line); + + parent = _findParent(_timer); + _insertIntoList(_timer, node); + + wbTimerNode_setStartTime(node, currentTime); + wbTimerNode_setParent(node, parent); + if (parent != NULL) { + wbTimerNode_setLevel(node, wbTimerNode_getLevel(parent) + 1); + } + + return node; +} + +wbTimerNode_t wbTimer_start(wbTimerKind_t kind, string msg, + const char *file, const char *fun, int line) { + wbTimerNode_t node = wbTimer_start(kind, file, fun, line); + wbTimerNode_setMessage(node, wbString_duplicate(msg)); + return node; +} + +static inline wbTimerNode_t _findNode(wbTimer_t timer, wbTimerKind_t kind, + string msg) { + wbTimerNode_t iter; + + for (iter = wbTimer_getTail(timer); iter != NULL; + iter = wbTimerNode_getPrevious(iter)) { + if (msg == "") { + if (!wbTimerNode_stoppedQ(iter) && + wbTimerNode_getKind(iter) == kind) { + return iter; + } + } else { + if (!wbTimerNode_stoppedQ(iter) && + wbTimerNode_getKind(iter) == kind && + msg == wbTimerNode_getMessage(iter)) { + return iter; + } + } + } + return NULL; +} + +void wbTimer_stop(wbTimerKind_t kind, string msg, const char *file, + const char *fun, int line) { + uint64_t currentTime; + wbTimerNode_t node; + + currentTime = getTime(); + + node = _findNode(_timer, kind, msg); + + wbAssert(node != NULL); + if (node == NULL) { + return; + } + + wbTimerNode_setEndTime(node, currentTime); + wbTimerNode_setElapsedTime(node, + currentTime - wbTimerNode_getStartTime(node)); + wbTimerNode_setEndLine(node, line); + wbTimerNode_setEndFunction(node, fun); + wbTimerNode_setEndFile(node, file); + wbTimerNode_setStoppedQ(node, wbTrue); + +#ifdef wbLogger_printOnLog + if (wbLogger_printOnLog) { + json11::Json json = json11::Json::object{ +//PMO +#ifndef _MSC_VER + { "type", "timer" }, { "data", wbTimerNode_toJSONObject(node) }}; +#else + { "data", wbTimerNode_toJSONObject(node) }, { "type", "timer" }}; +#endif + std::cout << json.dump() << std::endl; + } +#endif /* wbLogger_printOnLog */ + return; +} + +void wbTimer_stop(wbTimerKind_t kind, const char *file, const char *fun, + int line) { + wbTimer_stop(kind, "", file, fun, line); +} diff --git a/CUDA_Histogram/libwb/wbTimer.h b/CUDA_Histogram/libwb/wbTimer.h new file mode 100644 index 0000000..133b58f --- /dev/null +++ b/CUDA_Histogram/libwb/wbTimer.h @@ -0,0 +1,139 @@ + + +#ifndef __WB_TIMER_H__ +#define __WB_TIMER_H__ + +#ifdef WB_USE_WINDOWS +extern uint64_t _hrtime_frequency; +#endif /* _WIN32 */ + +extern wbTimer_t _timer; + +typedef enum en_wbTimerKind_t { + wbTimerKind_Generic, + wbTimerKind_IO, + wbTimerKind_GPU, + wbTimerKind_Copy, + wbTimerKind_Driver, + wbTimerKind_CopyAsync, + wbTimerKind_Compute, + wbTimerKind_CPUGPUOverlap, +} wbTimerKind_t; + +struct st_wbTimerNode_t { + int id; + int mpiRank; + int level; + wbBool stoppedQ; + wbTimerKind_t kind; + uint64_t startTime; + uint64_t endTime; + uint64_t elapsedTime; + int startLine; + int endLine; + const char *startFunction; + const char *endFunction; + const char *startFile; + const char *endFile; + wbTimerNode_t next; + wbTimerNode_t prev; + wbTimerNode_t parent; + char *msg; +}; + +struct st_wbTimer_t { + size_t length; + wbTimerNode_t head; + wbTimerNode_t tail; + uint64_t startTime; + uint64_t endTime; + uint64_t elapsedTime; +}; + +#define wbTimerNode_getId(node) ((node)->id) +#define wbTimerNode_getMPIRank(node) ((node)->mpiRank) +#define wbTimerNode_getLevel(node) ((node)->level) +#define wbTimerNode_getStoppedQ(node) ((node)->stoppedQ) +#define wbTimerNode_getKind(node) ((node)->kind) +#define wbTimerNode_getStartTime(node) ((node)->startTime) +#define wbTimerNode_getEndTime(node) ((node)->endTime) +#define wbTimerNode_getElapsedTime(node) ((node)->elapsedTime) +#define wbTimerNode_getStartLine(node) ((node)->startLine) +#define wbTimerNode_getEndLine(node) ((node)->endLine) +#define wbTimerNode_getStartFunction(node) ((node)->startFunction) +#define wbTimerNode_getEndFunction(node) ((node)->endFunction) +#define wbTimerNode_getStartFile(node) ((node)->startFile) +#define wbTimerNode_getEndFile(node) ((node)->endFile) +#define wbTimerNode_getNext(node) ((node)->next) +#define wbTimerNode_getPrevious(node) ((node)->prev) +#define wbTimerNode_getParent(node) ((node)->parent) +#define wbTimerNode_getMessage(node) ((node)->msg) + +#define wbTimerNode_setId(node, val) (wbTimerNode_getId(node) = val) +#define wbTimerNode_setMPIRank(node, val) \ + (wbTimerNode_getMPIRank(node) = val) +#define wbTimerNode_setLevel(node, val) (wbTimerNode_getLevel(node) = val) +#define wbTimerNode_setStoppedQ(node, val) \ + (wbTimerNode_getStoppedQ(node) = val) +#define wbTimerNode_setKind(node, val) (wbTimerNode_getKind(node) = val) +#define wbTimerNode_setStartTime(node, val) \ + (wbTimerNode_getStartTime(node) = val) +#define wbTimerNode_setEndTime(node, val) \ + (wbTimerNode_getEndTime(node) = val) +#define wbTimerNode_setElapsedTime(node, val) \ + (wbTimerNode_getElapsedTime(node) = val) +#define wbTimerNode_setStartLine(node, val) \ + (wbTimerNode_getStartLine(node) = val) +#define wbTimerNode_setEndLine(node, val) \ + (wbTimerNode_getEndLine(node) = val) +#define wbTimerNode_setStartFunction(node, val) \ + (wbTimerNode_getStartFunction(node) = val) +#define wbTimerNode_setEndFunction(node, val) \ + (wbTimerNode_getEndFunction(node) = val) +#define wbTimerNode_setStartFile(node, val) \ + (wbTimerNode_getStartFile(node) = val) +#define wbTimerNode_setEndFile(node, val) \ + (wbTimerNode_getEndFile(node) = val) +#define wbTimerNode_setNext(node, val) (wbTimerNode_getNext(node) = val) +#define wbTimerNode_setPrevious(node, val) \ + (wbTimerNode_getPrevious(node) = val) +#define wbTimerNode_setParent(node, val) \ + (wbTimerNode_getParent(node) = val) +#define wbTimerNode_setMessage(node, val) \ + (wbTimerNode_getMessage(node) = val) + +#define wbTimerNode_stoppedQ(node) \ + (wbTimerNode_getStoppedQ(node) == wbTrue) +#define wbTimerNode_hasNext(node) (wbTimerNode_getNext(node) != NULL) +#define wbTimerNode_hasPrevious(node) \ + (wbTimerNode_getPrevious(node) != NULL) +#define wbTimerNode_hasParent(node) (wbTimerNode_getParent(node) != NULL) + +uint64_t _hrtime(void); + +wbTimer_t wbTimer_new(void); +void wbTimer_delete(wbTimer_t timer); + +string wbTimer_toJSON(wbTimer_t timer); +string wbTimer_toJSON(); + +string wbTimer_toXML(wbTimer_t timer); +string wbTimer_toXML(); + +wbTimerNode_t wbTimer_start(wbTimerKind_t kind, const char *file, + const char *fun, int line); +wbTimerNode_t wbTimer_start(wbTimerKind_t kind, string msg, + const char *file, const char *fun, int line); +void wbTimer_stop(wbTimerKind_t kind, string msg, const char *file, + const char *fun, int line); +void wbTimer_stop(wbTimerKind_t kind, const char *file, const char *fun, + int line); + +#define wbTime_start(kind, ...) \ + wbTimer_start(wbTimerKind_##kind, wbString(__VA_ARGS__), wbFile, \ + wbFunction, wbLine) +#define wbTime_stop(kind, ...) \ + wbTimer_stop(wbTimerKind_##kind, wbString(__VA_ARGS__), wbFile, \ + wbFunction, wbLine) + +#endif /* __WB_TIMER_H__ */ diff --git a/CUDA_Histogram/libwb/wbTypes.h b/CUDA_Histogram/libwb/wbTypes.h new file mode 100644 index 0000000..6837792 --- /dev/null +++ b/CUDA_Histogram/libwb/wbTypes.h @@ -0,0 +1,55 @@ + + +#ifndef __WB_TYPES_H__ +#define __WB_TYPES_H__ + +#include "wbAssert.h" + +typedef bool wbBool; +typedef float wbReal_t; +typedef char wbChar_t; + +typedef struct st_wbTimerNode_t *wbTimerNode_t; +typedef struct st_wbTimer_t *wbTimer_t; +typedef struct st_wbLogEntry_t *wbLogEntry_t; +typedef struct st_wbLogger_t *wbLogger_t; +typedef struct st_wbArg_t wbArg_t; +typedef struct st_wbImage_t *wbImage_t; +typedef struct st_wbFile_t *wbFile_t; + +#define wbTrue true +#define wbFalse false + +typedef enum en_wbType_t { + wbType_unknown = -1, + wbType_ascii = 1, + wbType_bit8, + wbType_ubit8, + wbType_integer, + wbType_float, + wbType_double +} wbType_t; + +static inline size_t wbType_size(wbType_t ty) { + switch (ty) { + case wbType_unknown: + wbAssert(false && "Invalid wbType_unknown"); + return 0; + case wbType_ascii: + return sizeof(char); + case wbType_bit8: + return sizeof(char); + case wbType_ubit8: + return sizeof(unsigned char); + case wbType_integer: + return sizeof(int); + case wbType_float: + return sizeof(float); + case wbType_double: + return sizeof(double); + } + wbAssert(false && "Invalid type"); + return 0; +} + +#endif /* __WB_TYPES_H__ */ diff --git a/CUDA_Histogram/libwb/wbUtils.h b/CUDA_Histogram/libwb/wbUtils.h new file mode 100644 index 0000000..cbd1b91 --- /dev/null +++ b/CUDA_Histogram/libwb/wbUtils.h @@ -0,0 +1,10 @@ +#ifndef __WB_UTILS_H__ +#define __WB_UTILS_H__ + +#ifdef WB_DEBUG +#define DEBUG(...) __VA_ARGS__ +#else /* WB_DEBUG */ +#define DEBUG(...) +#endif /* WB_DEBUG */ + +#endif /* __WB_UTILS_H__ */ diff --git a/CUDA_Histogram/libwb/wb_test.cpp b/CUDA_Histogram/libwb/wb_test.cpp new file mode 100644 index 0000000..87883c8 --- /dev/null +++ b/CUDA_Histogram/libwb/wb_test.cpp @@ -0,0 +1,4 @@ +#define CATCH_CONFIG_MAIN + +#include "wb.h" +#include "vendor/catch.hpp" diff --git a/CUDA_ListScan/ListScan/template.cu b/CUDA_ListScan/ListScan/template.cu new file mode 100644 index 0000000..9930fb2 --- /dev/null +++ b/CUDA_ListScan/ListScan/template.cu @@ -0,0 +1,176 @@ +#include + +#define BLOCK_SIZE 512 + +#define wbCheck(stmt) \ + do { \ + cudaError_t err = stmt; \ + if (err != cudaSuccess) { \ + wbLog(ERROR, "Failed to run stmt ", #stmt); \ + wbLog(ERROR, "Got CUDA error ... ", cudaGetErrorString(err)); \ + return -1; \ + } \ + } while (0) + +__global__ void addScannedBlockSums(float *input, float *aux, int len) { + //@@ add scanned block sums to all values of the scanned blocks + + unsigned int tx = threadIdx.x; + unsigned int b = (2 * blockIdx.x * BLOCK_SIZE); + + if (blockIdx.x > 0) { + if (b + tx < len) { + input[b + tx] += aux[blockIdx.x - 1]; + } + if (b + BLOCK_SIZE + tx < len) { + input[b + BLOCK_SIZE + tx] += aux[blockIdx.x - 1]; + } + } +} +__global__ void scan(float *input, float *output, float *aux, int len) { + //@@ generate the scanned blocks + //@@ workefficient version of the parallel scan + //@@ store the block sum to the aux array + + //------------------------------------------------------------------- + // Load a segment of the input vector into shared memory + __shared__ float XY[BLOCK_SIZE * 2]; + + unsigned int tx = threadIdx.x; + unsigned int b = (2 * blockIdx.x * BLOCK_SIZE); + + if (b + tx < len) { // first half + XY[threadIdx.x] = input[b + tx]; + } else { + XY[threadIdx.x] = 0; + } + if (b + BLOCK_SIZE + tx < len) { // second half + XY[BLOCK_SIZE + threadIdx.x] = input[b + BLOCK_SIZE + tx]; + } else { + XY[BLOCK_SIZE + threadIdx.x] = 0; + } + + __syncthreads(); + + // Reduction Phase Kernel Code + for (unsigned int stride = 1; stride <= BLOCK_SIZE; stride *= 2) { + //__syncthreads(); + int index = (threadIdx.x + 1) * stride * 2 - 1; + if (index < 2 * BLOCK_SIZE) { + XY[index] += XY[index - stride]; + } + __syncthreads(); + } + + // Post Reduction Reverse Phase Kernel Code + for (unsigned int stride = BLOCK_SIZE / 2; stride > 0; stride /= 2) { + //__syncthreads(); + int index = (threadIdx.x + 1) * stride * 2 - 1; + if (index + stride < 2 * BLOCK_SIZE) { + XY[index + stride] += XY[index]; + } + __syncthreads(); + } + __syncthreads(); + if (b + tx < len) { + output[b + tx] = XY[threadIdx.x]; + } + + if (b + BLOCK_SIZE + tx < len) { + output[b + BLOCK_SIZE + tx] = XY[BLOCK_SIZE + threadIdx.x]; + } + + if (aux && threadIdx.x == 0) { + aux[blockIdx.x] = XY[2 * BLOCK_SIZE - 1]; + } + +} + +int main(int argc, char **argv) { + wbArg_t args; + float *hostInput; // The input 1D list + float *hostOutput; // The output 1D list + float *deviceInput; + float *deviceOutput; + float *deviceAuxArray, *deviceAuxScannedArray; + int numElements; // number of elements in the input/output list + + args = wbArg_read(argc, argv); + + wbTime_start(Generic, "Importing data and creating memory on host"); + hostInput = (float *)wbImport(wbArg_getInputFile(args, 0), &numElements); + hostOutput = (float *)malloc(numElements * sizeof(float)); + wbTime_stop(Generic, "Importing data and creating memory on host"); + + wbLog(TRACE, "The number of input elements in the input is ", + numElements); + + wbTime_start(GPU, "Allocating GPU memory."); + //@@ Allocate device memory + + cudaMalloc((void**) &deviceInput, numElements * sizeof(float)); + cudaMalloc((void**) &deviceOutput, numElements * sizeof(float)); + + cudaMalloc(&deviceAuxArray, (BLOCK_SIZE * 2) * sizeof(float)); + cudaMalloc(&deviceAuxScannedArray, (BLOCK_SIZE * 2) * sizeof(float)); + + wbTime_stop(GPU, "Allocating GPU memory."); + + wbTime_start(GPU, "Clearing output device memory."); + //@@ Clear output memory + wbCheck(cudaMemset(deviceOutput, 0, numElements * sizeof(float))); + wbTime_stop(GPU, "Clearing output device memory."); + + wbTime_start(GPU, "Copying input memory to the GPU."); + //@@ Copy host memory to device + + wbCheck(cudaMemcpy(deviceInput, hostInput, numElements * sizeof(float), cudaMemcpyHostToDevice)); + + wbTime_stop(GPU, "Copying input memory to the GPU."); + + //@@ Initialize the grid and block dimensions + + int g = ceil((float) numElements / (BLOCK_SIZE * 2)); + dim3 dimGrid(g, 1, 1); + dim3 dimBlock(BLOCK_SIZE, 1, 1); + + wbTime_start(Compute, "Performing CUDA computation"); + //@@ launch scan kernel twice: for generating scanned blocks + //@@ (by passing deviceAuxArray to the aux parameter) + //@@ and for generating scanned aux array that has the scanned block sums. + //@@ (by pass NULL to the aux parameter) + //@@ Then call addScannedBlockSums kernel. + + scan<<>>(deviceInput, deviceOutput, deviceAuxArray, numElements); + cudaDeviceSynchronize(); + scan<<>>(deviceAuxArray, deviceAuxScannedArray, NULL, (BLOCK_SIZE * 2)); + cudaDeviceSynchronize(); + addScannedBlockSums<<>>(deviceOutput, deviceAuxScannedArray, numElements); + cudaDeviceSynchronize(); + + wbTime_stop(Compute, "Performing CUDA computation"); + + wbTime_start(Copy, "Copying output memory to the CPU"); + //@@ Copy results from device to host + + cudaMemcpy(hostOutput, deviceOutput, numElements * sizeof(float), cudaMemcpyDeviceToHost); + + wbTime_stop(Copy, "Copying output memory to the CPU"); + + wbTime_start(GPU, "Freeing GPU Memory"); + //@@ Deallocate device memory + + cudaFree(deviceInput); + cudaFree(deviceOutput); + cudaFree(deviceAuxArray); + cudaFree(deviceAuxScannedArray); + + wbTime_stop(GPU, "Freeing GPU Memory"); + + wbSolution(args, hostOutput, numElements); + + free(hostInput); + free(hostOutput); + + return 0; +} diff --git a/CUDA_ListScan/libwb/.clang-format b/CUDA_ListScan/libwb/.clang-format new file mode 100644 index 0000000..4757ed4 --- /dev/null +++ b/CUDA_ListScan/libwb/.clang-format @@ -0,0 +1,21 @@ +--- +Language: Cpp +BasedOnStyle: LLVM +ColumnLimit: 75 +AccessModifierOffset: -2 +BreakBeforeBraces: Attach +AlignTrailingComments: true +AlignEscapedNewlinesLeft: false +AlignConsecutiveAssignments: true +AlignOperands: true +AllowShortFunctionsOnASingleLine: false +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AlwaysBreakTemplateDeclarations: true +IndentCaseLabels: true +SpacesBeforeTrailingComments: 1 +Standard: Cpp11 +TabWidth: 4 +UseTab: Never +SortIncludes: false +... diff --git a/CUDA_ListScan/libwb/.travis.yml b/CUDA_ListScan/libwb/.travis.yml new file mode 100644 index 0000000..e32c621 --- /dev/null +++ b/CUDA_ListScan/libwb/.travis.yml @@ -0,0 +1,65 @@ +# Use new trusty images, should yield newer compilers and packages +sudo: required +dist: precise +language: cpp + +matrix: + include: + - compiler: gcc + addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - g++-4.9 + env: COMPILER=g++-4.9 + - compiler: gcc + addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - g++-5 + env: COMPILER=g++-5 + - compiler: clang + addons: + apt: + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-precise-3.6 + packages: + - clang-3.6 + env: COMPILER=clang++-3.6 + - compiler: clang + addons: + apt: + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-precise-3.7 + packages: + - clang-3.7 + env: COMPILER=clang++-3.7 +# - compiler: gcc +# addons: +# apt: +# sources: +# - ubuntu-toolchain-r-test +# packages: +# - g++-6 +# env: COMPILER=g++-6 + # - compiler: clang + # addons: + # apt: + # sources: + # - ubuntu-toolchain-r-test + # - llvm-toolchain-precise-3.8 + # packages: + # - clang-3.8 + # env: COMPILER=clang++-3.8 + +before_install: + - sudo apt-get update -qq +script: + - $COMPILER --version + - make CXX=$COMPILER test + - ./test diff --git a/CUDA_ListScan/libwb/CMakeLists.txt b/CUDA_ListScan/libwb/CMakeLists.txt new file mode 100644 index 0000000..f732c32 --- /dev/null +++ b/CUDA_ListScan/libwb/CMakeLists.txt @@ -0,0 +1,34 @@ +cmake_minimum_required(VERSION 2.8 FATAL_ERROR) + +set(CMAKE_BUILD_TYPE Release) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) +set(CMAKE_COLOR_MAKEFILE ON) +set(VERBOSE_BUILD ON) +set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) +set(CMAKE_MACOSX_RPATH TRUE) +set_property(GLOBAL PROPERTY USE_FOLDERS ON) + + +project(wb) + +set(current_dir "${CMAKE_CURRENT_SOURCE_DIR}") + +if(NOT EXISTS "${CMAKE_CURRENT_BINARY_DIR}/cotire.cmake") + file(DOWNLOAD "https://raw.githubusercontent.com/sakra/cotire/master/CMake/cotire.cmake" "${CMAKE_CURRENT_BINARY_DIR}/cotire.cmake") +endif() + + + +include(${current_dir}/sources.cmake) + +set(WBLIB_STATIC ${WBLIB}) +set(WBLIB_SHARED lib${WBLIB}) + +add_library(${WBLIB_STATIC} STATIC ${LIBWB_SOURCE_FILES} ) +add_library(${WBLIB_SHARED} SHARED ${LIBWB_SOURCE_FILES} ) +set_property(TARGET ${WBLIB_STATIC} PROPERTY CXX_STANDARD 11) +set_property(TARGET ${WBLIB_SHARED} PROPERTY CXX_STANDARD 11) +if (UNIX) + set_target_properties(${WBLIB_SHARED} PROPERTIES OUTPUT_NAME ${WBLIB_STATIC}) +endif (UNIX) +set_property(TARGET ${WBLIB} PROPERTY CXX_STANDARD 11) diff --git a/CUDA_ListScan/libwb/LICENSE.TXT b/CUDA_ListScan/libwb/LICENSE.TXT new file mode 100644 index 0000000..8df244d --- /dev/null +++ b/CUDA_ListScan/libwb/LICENSE.TXT @@ -0,0 +1,36 @@ +Copyright (c) 2016, Abdul Dakkak All rights reserved. + +Developed by: Abdul Dakkak + IMPACT Group + University of Illinois, Urbana-Champaign + impact.crhc.illinois.edu + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal with the +Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, +sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +Redistributions of source code must retain the above +copyright notice, this list of conditions and the following +disclaimers. +Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following +disclaimers in the documentation and/or other materials +provided with the distribution. +Neither the names of Abdul Dakkak, Impact Group, nor the +names of its contributors may be used to endorse or promote +products derived from this Software without specific prior +written permission. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +WITH THE SOFTWARE. diff --git a/CUDA_ListScan/libwb/Makefile b/CUDA_ListScan/libwb/Makefile new file mode 100644 index 0000000..b8a72d7 --- /dev/null +++ b/CUDA_ListScan/libwb/Makefile @@ -0,0 +1,56 @@ +########################################## +# Options +########################################## +WB_LIB_PATH=$(CURDIR)/lib +WB_SRC_PATH=$(CURDIR) + +########################################## +########################################## + +DEFINES= +CXX_FLAGS=-fPIC -Wno-unused-function -x c++ -O3 -g -std=c++11 -Wall -Wno-unused-function -pedantic -I . -I $(WB_SRC_PATH) $(DEFINES) +LIBS=-lm -lstdc++ + +########################################## +########################################## + +UNAME_S := $(shell uname -s) +ifeq ($(UNAME_S),Linux) + LIBS += -lrt +endif + +########################################## +########################################## + +SOURCES := $(shell find $(WB_SRC_PATH) ! -name "*_test.cpp" -name "*.cpp") +TESTS := $(shell find $(WB_SRC_PATH) -name "*_test.cpp") + +OBJECTS = $(SOURCES:.cpp=.o) +TESTOBJECTS = $(TESTS:.cpp=.o) + +############################################## +# OUTPUT +############################################## + +.PHONY: all +.SUFFIXES: .o .cpp +all: libwb.so + +.cpp.o: + $(CXX) $(DEFINES) $(CXX_FLAGS) -c -o $@ $< + +libwb.so: $(OBJECTS) + mkdir -p $(WB_LIB_PATH) + $(CXX) -fPIC -shared -o $(WB_LIB_PATH)/$@ $(OBJECTS) $(LIBS) + +libwb.a: $(OBJECTS) + mkdir -p $(WB_LIB_PATH) + ar rcs -o $(WB_LIB_PATH)/$@ $(OBJECTS) + +test: $(TESTOBJECTS) $(OBJECTS) + $(CXX) -fPIC -o $@ $(TESTOBJECTS) $(OBJECTS) $(LIBS) + + +clean: + rm -fr $(ARCH) + -rm -f $(EXES) *.o *~ \ No newline at end of file diff --git a/CUDA_ListScan/libwb/README.md b/CUDA_ListScan/libwb/README.md new file mode 100644 index 0000000..0486f93 --- /dev/null +++ b/CUDA_ListScan/libwb/README.md @@ -0,0 +1,7 @@ + +# libWB + +[![Travis Build Status](https://travis-ci.org/abduld/libwb.svg?branch=master)](https://travis-ci.org/abduld/libwb) +[![AppVeyor status](https://ci.appveyor.com/api/projects/status/0nx5ie7gn5c0e6ai/branch/master?svg=true)](https://ci.appveyor.com/project/abduld/libwb/branch/master) + \ No newline at end of file diff --git a/CUDA_ListScan/libwb/appveyor.yml b/CUDA_ListScan/libwb/appveyor.yml new file mode 100644 index 0000000..e7a6c95 --- /dev/null +++ b/CUDA_ListScan/libwb/appveyor.yml @@ -0,0 +1,54 @@ + + +# Operating system (build VM template) +os: + - Visual Studio 2015 + + +# scripts that are called at very beginning, before repo cloning +init: + - echo init step + - git config --global core.autocrlf input + - cmake --version + - C:\"Program Files (x86)"\"Microsoft Visual Studio 14.0"\VC\vcvarsall.bat %PLATFORM% + +# clone directory +clone_folder: c:\projects\libwb +# fetch repository as zip archive +shallow_clone: true # default is "false" + +# branches to build +branches: + # whitelist + only: + - master + +platform: + - x64 +configuration: + - Release + +environment: + P: "c:/projects/libs" + + +install: + # by default, all script lines are interpreted as batch + +build: + project: ALL_BUILD.vcxproj # path to Visual Studio solution or project + +# scripts to run before build +before_build: + - echo Running cmake... + - cd c:\projects\libwb + - cmake -G "Visual Studio 14 2015 Win64" -DCMAKE_INSTALL_PREFIX=%P% + +# after_build: +# - echo after_build step + + +# on_finish always executes regardless of passed or failed builds +# on_finish: +# - echo on_finish step +# - ps: ls \ No newline at end of file diff --git a/CUDA_ListScan/libwb/sources.cmake b/CUDA_ListScan/libwb/sources.cmake new file mode 100644 index 0000000..4ac1b10 --- /dev/null +++ b/CUDA_ListScan/libwb/sources.cmake @@ -0,0 +1,31 @@ + +set(WBLIB "wb") + +include_directories(${CMAKE_CURRENT_LIST_DIR}) + +file(GLOB THESE_CPP_FILES + ${CMAKE_CURRENT_LIST_DIR}/*.cpp +) + +file(GLOB THESE_TEST_FILES + ${CMAKE_CURRENT_LIST_DIR}/*_test.cpp +) + +list(REMOVE_ITEM THESE_CPP_FILES ${THESE_TEST_FILES}) + +file(GLOB THESE_HEADER_FILES + ${CMAKE_CURRENT_LIST_DIR}/*.h +) + +list(APPEND LIBWB_HEADER_FILES + ${THESE_HEADER_FILES} +) + +list(APPEND LIBWB_SOURCE_FILES + ${THESE_CPP_FILES} + ${CMAKE_CURRENT_LIST_DIR}/vendor/json11.cpp +) + +list(APPEND LIBWB_TEST_FILES + ${THESE_TEST_FILES} +) diff --git a/CUDA_ListScan/libwb/vendor/catch.hpp b/CUDA_ListScan/libwb/vendor/catch.hpp new file mode 100644 index 0000000..f52eebd --- /dev/null +++ b/CUDA_ListScan/libwb/vendor/catch.hpp @@ -0,0 +1,10414 @@ +/* + * Catch v1.3.6 + * Generated: 2016-03-11 18:30:42.852700 + * ---------------------------------------------------------- + * This file has been merged from multiple headers. Please don't edit it directly + * Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved. + * + * Distributed under the Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + */ +#ifndef TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED +#define TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED + +#define TWOBLUECUBES_CATCH_HPP_INCLUDED + +#ifdef __clang__ +# pragma clang system_header +#elif defined __GNUC__ +# pragma GCC system_header +#endif + +// #included from: internal/catch_suppress_warnings.h + +#ifdef __clang__ +# ifdef __ICC // icpc defines the __clang__ macro +# pragma warning(push) +# pragma warning(disable: 161 1682) +# else // __ICC +# pragma clang diagnostic ignored "-Wglobal-constructors" +# pragma clang diagnostic ignored "-Wvariadic-macros" +# pragma clang diagnostic ignored "-Wc99-extensions" +# pragma clang diagnostic ignored "-Wunused-variable" +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wpadded" +# pragma clang diagnostic ignored "-Wc++98-compat" +# pragma clang diagnostic ignored "-Wc++98-compat-pedantic" +# pragma clang diagnostic ignored "-Wswitch-enum" +# pragma clang diagnostic ignored "-Wcovered-switch-default" +# endif +#elif defined __GNUC__ +# pragma GCC diagnostic ignored "-Wvariadic-macros" +# pragma GCC diagnostic ignored "-Wunused-variable" +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wpadded" +#endif +#if defined(CATCH_CONFIG_MAIN) || defined(CATCH_CONFIG_RUNNER) +# define CATCH_IMPL +#endif + +#ifdef CATCH_IMPL +# ifndef CLARA_CONFIG_MAIN +# define CLARA_CONFIG_MAIN_NOT_DEFINED +# define CLARA_CONFIG_MAIN +# endif +#endif + +// #included from: internal/catch_notimplemented_exception.h +#define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_H_INCLUDED + +// #included from: catch_common.h +#define TWOBLUECUBES_CATCH_COMMON_H_INCLUDED + +#define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line +#define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) +#define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ ) + +#define INTERNAL_CATCH_STRINGIFY2( expr ) #expr +#define INTERNAL_CATCH_STRINGIFY( expr ) INTERNAL_CATCH_STRINGIFY2( expr ) + +#include +#include +#include + +// #included from: catch_compiler_capabilities.h +#define TWOBLUECUBES_CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED + +// Detect a number of compiler features - mostly C++11/14 conformance - by compiler +// The following features are defined: +// +// CATCH_CONFIG_CPP11_NULLPTR : is nullptr supported? +// CATCH_CONFIG_CPP11_NOEXCEPT : is noexcept supported? +// CATCH_CONFIG_CPP11_GENERATED_METHODS : The delete and default keywords for compiler generated methods +// CATCH_CONFIG_CPP11_IS_ENUM : std::is_enum is supported? +// CATCH_CONFIG_CPP11_TUPLE : std::tuple is supported +// CATCH_CONFIG_CPP11_LONG_LONG : is long long supported? +// CATCH_CONFIG_CPP11_OVERRIDE : is override supported? +// CATCH_CONFIG_CPP11_UNIQUE_PTR : is unique_ptr supported (otherwise use auto_ptr) + +// CATCH_CONFIG_CPP11_OR_GREATER : Is C++11 supported? + +// CATCH_CONFIG_VARIADIC_MACROS : are variadic macros supported? + +// **************** +// Note to maintainers: if new toggles are added please document them +// in configuration.md, too +// **************** + +// In general each macro has a _NO_ form +// (e.g. CATCH_CONFIG_CPP11_NO_NULLPTR) which disables the feature. +// Many features, at point of detection, define an _INTERNAL_ macro, so they +// can be combined, en-mass, with the _NO_ forms later. + +// All the C++11 features can be disabled with CATCH_CONFIG_NO_CPP11 + +#if defined(__cplusplus) && __cplusplus >= 201103L +# define CATCH_CPP11_OR_GREATER +#endif + +#ifdef __clang__ + +# if __has_feature(cxx_nullptr) +# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR +# endif + +# if __has_feature(cxx_noexcept) +# define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT +# endif + +# if defined(CATCH_CPP11_OR_GREATER) +# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS _Pragma( "clang diagnostic ignored \"-Wparentheses\"" ) +# endif + +#endif // __clang__ + +//////////////////////////////////////////////////////////////////////////////// +// Borland +#ifdef __BORLANDC__ + +#endif // __BORLANDC__ + +//////////////////////////////////////////////////////////////////////////////// +// EDG +#ifdef __EDG_VERSION__ + +#endif // __EDG_VERSION__ + +//////////////////////////////////////////////////////////////////////////////// +// Digital Mars +#ifdef __DMC__ + +#endif // __DMC__ + +//////////////////////////////////////////////////////////////////////////////// +// GCC +#ifdef __GNUC__ + +# if __GNUC__ == 4 && __GNUC_MINOR__ >= 6 && defined(__GXX_EXPERIMENTAL_CXX0X__) +# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR +# endif + +# if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS) && defined(CATCH_CPP11_OR_GREATER) +# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS _Pragma( "GCC diagnostic ignored \"-Wparentheses\"" ) +# endif + +// - otherwise more recent versions define __cplusplus >= 201103L +// and will get picked up below + +#endif // __GNUC__ + +//////////////////////////////////////////////////////////////////////////////// +// Visual C++ +#ifdef _MSC_VER + +#if (_MSC_VER >= 1600) +# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR +# define CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR +#endif + +#if (_MSC_VER >= 1900 ) // (VC++ 13 (VS2015)) +#define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT +#define CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS +#endif + +#endif // _MSC_VER + +//////////////////////////////////////////////////////////////////////////////// + +// Use variadic macros if the compiler supports them +#if ( defined _MSC_VER && _MSC_VER > 1400 && !defined __EDGE__) || \ + ( defined __WAVE__ && __WAVE_HAS_VARIADICS ) || \ + ( defined __GNUC__ && __GNUC__ >= 3 ) || \ + ( !defined __cplusplus && __STDC_VERSION__ >= 199901L || __cplusplus >= 201103L ) + +#define CATCH_INTERNAL_CONFIG_VARIADIC_MACROS + +#endif + +//////////////////////////////////////////////////////////////////////////////// +// C++ language feature support + +// catch all support for C++11 +#if defined(CATCH_CPP11_OR_GREATER) + +# if !defined(CATCH_INTERNAL_CONFIG_CPP11_NULLPTR) +# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR +# endif + +# ifndef CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT +# define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT +# endif + +# ifndef CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS +# define CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS +# endif + +# ifndef CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM +# define CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM +# endif + +# ifndef CATCH_INTERNAL_CONFIG_CPP11_TUPLE +# define CATCH_INTERNAL_CONFIG_CPP11_TUPLE +# endif + +# ifndef CATCH_INTERNAL_CONFIG_VARIADIC_MACROS +# define CATCH_INTERNAL_CONFIG_VARIADIC_MACROS +# endif + +# if !defined(CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG) +# define CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG +# endif + +# if !defined(CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE) +# define CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE +# endif +# if !defined(CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) +# define CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR +# endif + +#endif // __cplusplus >= 201103L + +// Now set the actual defines based on the above + anything the user has configured +#if defined(CATCH_INTERNAL_CONFIG_CPP11_NULLPTR) && !defined(CATCH_CONFIG_CPP11_NO_NULLPTR) && !defined(CATCH_CONFIG_CPP11_NULLPTR) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_NULLPTR +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_CONFIG_CPP11_NO_NOEXCEPT) && !defined(CATCH_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_NOEXCEPT +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS) && !defined(CATCH_CONFIG_CPP11_NO_GENERATED_METHODS) && !defined(CATCH_CONFIG_CPP11_GENERATED_METHODS) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_GENERATED_METHODS +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM) && !defined(CATCH_CONFIG_CPP11_NO_IS_ENUM) && !defined(CATCH_CONFIG_CPP11_IS_ENUM) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_IS_ENUM +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_TUPLE) && !defined(CATCH_CONFIG_CPP11_NO_TUPLE) && !defined(CATCH_CONFIG_CPP11_TUPLE) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_TUPLE +#endif +#if defined(CATCH_INTERNAL_CONFIG_VARIADIC_MACROS) && !defined(CATCH_CONFIG_NO_VARIADIC_MACROS) && !defined(CATCH_CONFIG_VARIADIC_MACROS) +# define CATCH_CONFIG_VARIADIC_MACROS +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG) && !defined(CATCH_CONFIG_NO_LONG_LONG) && !defined(CATCH_CONFIG_CPP11_LONG_LONG) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_LONG_LONG +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE) && !defined(CATCH_CONFIG_NO_OVERRIDE) && !defined(CATCH_CONFIG_CPP11_OVERRIDE) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_OVERRIDE +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) && !defined(CATCH_CONFIG_NO_UNIQUE_PTR) && !defined(CATCH_CONFIG_CPP11_UNIQUE_PTR) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_UNIQUE_PTR +#endif + +#if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS) +# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS +#endif + +// noexcept support: +#if defined(CATCH_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_NOEXCEPT) +# define CATCH_NOEXCEPT noexcept +# define CATCH_NOEXCEPT_IS(x) noexcept(x) +#else +# define CATCH_NOEXCEPT throw() +# define CATCH_NOEXCEPT_IS(x) +#endif + +// nullptr support +#ifdef CATCH_CONFIG_CPP11_NULLPTR +# define CATCH_NULL nullptr +#else +# define CATCH_NULL NULL +#endif + +// override support +#ifdef CATCH_CONFIG_CPP11_OVERRIDE +# define CATCH_OVERRIDE override +#else +# define CATCH_OVERRIDE +#endif + +// unique_ptr support +#ifdef CATCH_CONFIG_CPP11_UNIQUE_PTR +# define CATCH_AUTO_PTR( T ) std::unique_ptr +#else +# define CATCH_AUTO_PTR( T ) std::auto_ptr +#endif + +namespace Catch { + + struct IConfig; + + struct CaseSensitive { enum Choice { + Yes, + No + }; }; + + class NonCopyable { +#ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + NonCopyable( NonCopyable const& ) = delete; + NonCopyable( NonCopyable && ) = delete; + NonCopyable& operator = ( NonCopyable const& ) = delete; + NonCopyable& operator = ( NonCopyable && ) = delete; +#else + NonCopyable( NonCopyable const& info ); + NonCopyable& operator = ( NonCopyable const& ); +#endif + + protected: + NonCopyable() {} + virtual ~NonCopyable(); + }; + + class SafeBool { + public: + typedef void (SafeBool::*type)() const; + + static type makeSafe( bool value ) { + return value ? &SafeBool::trueValue : 0; + } + private: + void trueValue() const {} + }; + + template + inline void deleteAll( ContainerT& container ) { + typename ContainerT::const_iterator it = container.begin(); + typename ContainerT::const_iterator itEnd = container.end(); + for(; it != itEnd; ++it ) + delete *it; + } + template + inline void deleteAllValues( AssociativeContainerT& container ) { + typename AssociativeContainerT::const_iterator it = container.begin(); + typename AssociativeContainerT::const_iterator itEnd = container.end(); + for(; it != itEnd; ++it ) + delete it->second; + } + + bool startsWith( std::string const& s, std::string const& prefix ); + bool endsWith( std::string const& s, std::string const& suffix ); + bool contains( std::string const& s, std::string const& infix ); + void toLowerInPlace( std::string& s ); + std::string toLower( std::string const& s ); + std::string trim( std::string const& str ); + bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ); + + struct pluralise { + pluralise( std::size_t count, std::string const& label ); + + friend std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ); + + std::size_t m_count; + std::string m_label; + }; + + struct SourceLineInfo { + + SourceLineInfo(); + SourceLineInfo( char const* _file, std::size_t _line ); + SourceLineInfo( SourceLineInfo const& other ); +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + SourceLineInfo( SourceLineInfo && ) = default; + SourceLineInfo& operator = ( SourceLineInfo const& ) = default; + SourceLineInfo& operator = ( SourceLineInfo && ) = default; +# endif + bool empty() const; + bool operator == ( SourceLineInfo const& other ) const; + bool operator < ( SourceLineInfo const& other ) const; + + std::string file; + std::size_t line; + }; + + std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ); + + // This is just here to avoid compiler warnings with macro constants and boolean literals + inline bool isTrue( bool value ){ return value; } + inline bool alwaysTrue() { return true; } + inline bool alwaysFalse() { return false; } + + void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo ); + + void seedRng( IConfig const& config ); + unsigned int rngSeed(); + + // Use this in variadic streaming macros to allow + // >> +StreamEndStop + // as well as + // >> stuff +StreamEndStop + struct StreamEndStop { + std::string operator+() { + return std::string(); + } + }; + template + T const& operator + ( T const& value, StreamEndStop ) { + return value; + } +} + +#define CATCH_INTERNAL_LINEINFO ::Catch::SourceLineInfo( __FILE__, static_cast( __LINE__ ) ) +#define CATCH_INTERNAL_ERROR( msg ) ::Catch::throwLogicError( msg, CATCH_INTERNAL_LINEINFO ); + +#include + +namespace Catch { + + class NotImplementedException : public std::exception + { + public: + NotImplementedException( SourceLineInfo const& lineInfo ); + NotImplementedException( NotImplementedException const& ) {} + + virtual ~NotImplementedException() CATCH_NOEXCEPT {} + + virtual const char* what() const CATCH_NOEXCEPT; + + private: + std::string m_what; + SourceLineInfo m_lineInfo; + }; + +} // end namespace Catch + +/////////////////////////////////////////////////////////////////////////////// +#define CATCH_NOT_IMPLEMENTED throw Catch::NotImplementedException( CATCH_INTERNAL_LINEINFO ) + +// #included from: internal/catch_context.h +#define TWOBLUECUBES_CATCH_CONTEXT_H_INCLUDED + +// #included from: catch_interfaces_generators.h +#define TWOBLUECUBES_CATCH_INTERFACES_GENERATORS_H_INCLUDED + +#include + +namespace Catch { + + struct IGeneratorInfo { + virtual ~IGeneratorInfo(); + virtual bool moveNext() = 0; + virtual std::size_t getCurrentIndex() const = 0; + }; + + struct IGeneratorsForTest { + virtual ~IGeneratorsForTest(); + + virtual IGeneratorInfo& getGeneratorInfo( std::string const& fileInfo, std::size_t size ) = 0; + virtual bool moveNext() = 0; + }; + + IGeneratorsForTest* createGeneratorsForTest(); + +} // end namespace Catch + +// #included from: catch_ptr.hpp +#define TWOBLUECUBES_CATCH_PTR_HPP_INCLUDED + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpadded" +#endif + +namespace Catch { + + // An intrusive reference counting smart pointer. + // T must implement addRef() and release() methods + // typically implementing the IShared interface + template + class Ptr { + public: + Ptr() : m_p( CATCH_NULL ){} + Ptr( T* p ) : m_p( p ){ + if( m_p ) + m_p->addRef(); + } + Ptr( Ptr const& other ) : m_p( other.m_p ){ + if( m_p ) + m_p->addRef(); + } + ~Ptr(){ + if( m_p ) + m_p->release(); + } + void reset() { + if( m_p ) + m_p->release(); + m_p = CATCH_NULL; + } + Ptr& operator = ( T* p ){ + Ptr temp( p ); + swap( temp ); + return *this; + } + Ptr& operator = ( Ptr const& other ){ + Ptr temp( other ); + swap( temp ); + return *this; + } + void swap( Ptr& other ) { std::swap( m_p, other.m_p ); } + T* get() const{ return m_p; } + T& operator*() const { return *m_p; } + T* operator->() const { return m_p; } + bool operator !() const { return m_p == CATCH_NULL; } + operator SafeBool::type() const { return SafeBool::makeSafe( m_p != CATCH_NULL ); } + + private: + T* m_p; + }; + + struct IShared : NonCopyable { + virtual ~IShared(); + virtual void addRef() const = 0; + virtual void release() const = 0; + }; + + template + struct SharedImpl : T { + + SharedImpl() : m_rc( 0 ){} + + virtual void addRef() const { + ++m_rc; + } + virtual void release() const { + if( --m_rc == 0 ) + delete this; + } + + mutable unsigned int m_rc; + }; + +} // end namespace Catch + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +#include +#include +#include + +namespace Catch { + + class TestCase; + class Stream; + struct IResultCapture; + struct IRunner; + struct IGeneratorsForTest; + struct IConfig; + + struct IContext + { + virtual ~IContext(); + + virtual IResultCapture* getResultCapture() = 0; + virtual IRunner* getRunner() = 0; + virtual size_t getGeneratorIndex( std::string const& fileInfo, size_t totalSize ) = 0; + virtual bool advanceGeneratorsForCurrentTest() = 0; + virtual Ptr getConfig() const = 0; + }; + + struct IMutableContext : IContext + { + virtual ~IMutableContext(); + virtual void setResultCapture( IResultCapture* resultCapture ) = 0; + virtual void setRunner( IRunner* runner ) = 0; + virtual void setConfig( Ptr const& config ) = 0; + }; + + IContext& getCurrentContext(); + IMutableContext& getCurrentMutableContext(); + void cleanUpContext(); + Stream createStream( std::string const& streamName ); + +} + +// #included from: internal/catch_test_registry.hpp +#define TWOBLUECUBES_CATCH_TEST_REGISTRY_HPP_INCLUDED + +// #included from: catch_interfaces_testcase.h +#define TWOBLUECUBES_CATCH_INTERFACES_TESTCASE_H_INCLUDED + +#include + +namespace Catch { + + class TestSpec; + + struct ITestCase : IShared { + virtual void invoke () const = 0; + protected: + virtual ~ITestCase(); + }; + + class TestCase; + struct IConfig; + + struct ITestCaseRegistry { + virtual ~ITestCaseRegistry(); + virtual std::vector const& getAllTests() const = 0; + virtual std::vector const& getAllTestsSorted( IConfig const& config ) const = 0; + }; + + bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ); + std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ); + std::vector const& getAllTestCasesSorted( IConfig const& config ); + +} + +namespace Catch { + +template +class MethodTestCase : public SharedImpl { + +public: + MethodTestCase( void (C::*method)() ) : m_method( method ) {} + + virtual void invoke() const { + C obj; + (obj.*m_method)(); + } + +private: + virtual ~MethodTestCase() {} + + void (C::*m_method)(); +}; + +typedef void(*TestFunction)(); + +struct NameAndDesc { + NameAndDesc( const char* _name = "", const char* _description= "" ) + : name( _name ), description( _description ) + {} + + const char* name; + const char* description; +}; + +void registerTestCase + ( ITestCase* testCase, + char const* className, + NameAndDesc const& nameAndDesc, + SourceLineInfo const& lineInfo ); + +struct AutoReg { + + AutoReg + ( TestFunction function, + SourceLineInfo const& lineInfo, + NameAndDesc const& nameAndDesc ); + + template + AutoReg + ( void (C::*method)(), + char const* className, + NameAndDesc const& nameAndDesc, + SourceLineInfo const& lineInfo ) { + + registerTestCase + ( new MethodTestCase( method ), + className, + nameAndDesc, + lineInfo ); + } + + ~AutoReg(); + +private: + AutoReg( AutoReg const& ); + void operator= ( AutoReg const& ); +}; + +void registerTestCaseFunction + ( TestFunction function, + SourceLineInfo const& lineInfo, + NameAndDesc const& nameAndDesc ); + +} // end namespace Catch + +#ifdef CATCH_CONFIG_VARIADIC_MACROS + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_TESTCASE( ... ) \ + static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )(); \ + namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( __VA_ARGS__ ) ); }\ + static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )() + + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \ + namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); } + + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, ... )\ + namespace{ \ + struct INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ) : ClassName{ \ + void test(); \ + }; \ + Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test, #ClassName, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); \ + } \ + void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test() + + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, ... ) \ + Catch::AutoReg( Function, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( __VA_ARGS__ ) ); + +#else + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_TESTCASE( Name, Desc ) \ + static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )(); \ + namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( Name, Desc ) ); }\ + static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )() + + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, Name, Desc ) \ + namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( Name, Desc ), CATCH_INTERNAL_LINEINFO ); } + + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, TestName, Desc )\ + namespace{ \ + struct INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ) : ClassName{ \ + void test(); \ + }; \ + Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test, #ClassName, Catch::NameAndDesc( TestName, Desc ), CATCH_INTERNAL_LINEINFO ); \ + } \ + void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test() + + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, Name, Desc ) \ + Catch::AutoReg( Function, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( Name, Desc ) ); +#endif + +// #included from: internal/catch_capture.hpp +#define TWOBLUECUBES_CATCH_CAPTURE_HPP_INCLUDED + +// #included from: catch_result_builder.h +#define TWOBLUECUBES_CATCH_RESULT_BUILDER_H_INCLUDED + +// #included from: catch_result_type.h +#define TWOBLUECUBES_CATCH_RESULT_TYPE_H_INCLUDED + +namespace Catch { + + // ResultWas::OfType enum + struct ResultWas { enum OfType { + Unknown = -1, + Ok = 0, + Info = 1, + Warning = 2, + + FailureBit = 0x10, + + ExpressionFailed = FailureBit | 1, + ExplicitFailure = FailureBit | 2, + + Exception = 0x100 | FailureBit, + + ThrewException = Exception | 1, + DidntThrowException = Exception | 2, + + FatalErrorCondition = 0x200 | FailureBit + + }; }; + + inline bool isOk( ResultWas::OfType resultType ) { + return ( resultType & ResultWas::FailureBit ) == 0; + } + inline bool isJustInfo( int flags ) { + return flags == ResultWas::Info; + } + + // ResultDisposition::Flags enum + struct ResultDisposition { enum Flags { + Normal = 0x01, + + ContinueOnFailure = 0x02, // Failures fail test, but execution continues + FalseTest = 0x04, // Prefix expression with ! + SuppressFail = 0x08 // Failures are reported but do not fail the test + }; }; + + inline ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs ) { + return static_cast( static_cast( lhs ) | static_cast( rhs ) ); + } + + inline bool shouldContinueOnFailure( int flags ) { return ( flags & ResultDisposition::ContinueOnFailure ) != 0; } + inline bool isFalseTest( int flags ) { return ( flags & ResultDisposition::FalseTest ) != 0; } + inline bool shouldSuppressFailure( int flags ) { return ( flags & ResultDisposition::SuppressFail ) != 0; } + +} // end namespace Catch + +// #included from: catch_assertionresult.h +#define TWOBLUECUBES_CATCH_ASSERTIONRESULT_H_INCLUDED + +#include + +namespace Catch { + + struct AssertionInfo + { + AssertionInfo() {} + AssertionInfo( std::string const& _macroName, + SourceLineInfo const& _lineInfo, + std::string const& _capturedExpression, + ResultDisposition::Flags _resultDisposition ); + + std::string macroName; + SourceLineInfo lineInfo; + std::string capturedExpression; + ResultDisposition::Flags resultDisposition; + }; + + struct AssertionResultData + { + AssertionResultData() : resultType( ResultWas::Unknown ) {} + + std::string reconstructedExpression; + std::string message; + ResultWas::OfType resultType; + }; + + class AssertionResult { + public: + AssertionResult(); + AssertionResult( AssertionInfo const& info, AssertionResultData const& data ); + ~AssertionResult(); +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + AssertionResult( AssertionResult const& ) = default; + AssertionResult( AssertionResult && ) = default; + AssertionResult& operator = ( AssertionResult const& ) = default; + AssertionResult& operator = ( AssertionResult && ) = default; +# endif + + bool isOk() const; + bool succeeded() const; + ResultWas::OfType getResultType() const; + bool hasExpression() const; + bool hasMessage() const; + std::string getExpression() const; + std::string getExpressionInMacro() const; + bool hasExpandedExpression() const; + std::string getExpandedExpression() const; + std::string getMessage() const; + SourceLineInfo getSourceInfo() const; + std::string getTestMacroName() const; + + protected: + AssertionInfo m_info; + AssertionResultData m_resultData; + }; + +} // end namespace Catch + +// #included from: catch_matchers.hpp +#define TWOBLUECUBES_CATCH_MATCHERS_HPP_INCLUDED + +namespace Catch { +namespace Matchers { + namespace Impl { + + namespace Generic { + template class AllOf; + template class AnyOf; + template class Not; + } + + template + struct Matcher : SharedImpl + { + typedef ExpressionT ExpressionType; + + virtual ~Matcher() {} + virtual Ptr clone() const = 0; + virtual bool match( ExpressionT const& expr ) const = 0; + virtual std::string toString() const = 0; + + Generic::AllOf operator && ( Matcher const& other ) const; + Generic::AnyOf operator || ( Matcher const& other ) const; + Generic::Not operator ! () const; + }; + + template + struct MatcherImpl : Matcher { + + virtual Ptr > clone() const { + return Ptr >( new DerivedT( static_cast( *this ) ) ); + } + }; + + namespace Generic { + template + class Not : public MatcherImpl, ExpressionT> { + public: + explicit Not( Matcher const& matcher ) : m_matcher(matcher.clone()) {} + Not( Not const& other ) : m_matcher( other.m_matcher ) {} + + virtual bool match( ExpressionT const& expr ) const CATCH_OVERRIDE { + return !m_matcher->match( expr ); + } + + virtual std::string toString() const CATCH_OVERRIDE { + return "not " + m_matcher->toString(); + } + private: + Ptr< Matcher > m_matcher; + }; + + template + class AllOf : public MatcherImpl, ExpressionT> { + public: + + AllOf() {} + AllOf( AllOf const& other ) : m_matchers( other.m_matchers ) {} + + AllOf& add( Matcher const& matcher ) { + m_matchers.push_back( matcher.clone() ); + return *this; + } + virtual bool match( ExpressionT const& expr ) const + { + for( std::size_t i = 0; i < m_matchers.size(); ++i ) + if( !m_matchers[i]->match( expr ) ) + return false; + return true; + } + virtual std::string toString() const { + std::ostringstream oss; + oss << "( "; + for( std::size_t i = 0; i < m_matchers.size(); ++i ) { + if( i != 0 ) + oss << " and "; + oss << m_matchers[i]->toString(); + } + oss << " )"; + return oss.str(); + } + + AllOf operator && ( Matcher const& other ) const { + AllOf allOfExpr( *this ); + allOfExpr.add( other ); + return allOfExpr; + } + + private: + std::vector > > m_matchers; + }; + + template + class AnyOf : public MatcherImpl, ExpressionT> { + public: + + AnyOf() {} + AnyOf( AnyOf const& other ) : m_matchers( other.m_matchers ) {} + + AnyOf& add( Matcher const& matcher ) { + m_matchers.push_back( matcher.clone() ); + return *this; + } + virtual bool match( ExpressionT const& expr ) const + { + for( std::size_t i = 0; i < m_matchers.size(); ++i ) + if( m_matchers[i]->match( expr ) ) + return true; + return false; + } + virtual std::string toString() const { + std::ostringstream oss; + oss << "( "; + for( std::size_t i = 0; i < m_matchers.size(); ++i ) { + if( i != 0 ) + oss << " or "; + oss << m_matchers[i]->toString(); + } + oss << " )"; + return oss.str(); + } + + AnyOf operator || ( Matcher const& other ) const { + AnyOf anyOfExpr( *this ); + anyOfExpr.add( other ); + return anyOfExpr; + } + + private: + std::vector > > m_matchers; + }; + + } // namespace Generic + + template + Generic::AllOf Matcher::operator && ( Matcher const& other ) const { + Generic::AllOf allOfExpr; + allOfExpr.add( *this ); + allOfExpr.add( other ); + return allOfExpr; + } + + template + Generic::AnyOf Matcher::operator || ( Matcher const& other ) const { + Generic::AnyOf anyOfExpr; + anyOfExpr.add( *this ); + anyOfExpr.add( other ); + return anyOfExpr; + } + + template + Generic::Not Matcher::operator ! () const { + return Generic::Not( *this ); + } + + namespace StdString { + + inline std::string makeString( std::string const& str ) { return str; } + inline std::string makeString( const char* str ) { return str ? std::string( str ) : std::string(); } + + struct CasedString + { + CasedString( std::string const& str, CaseSensitive::Choice caseSensitivity ) + : m_caseSensitivity( caseSensitivity ), + m_str( adjustString( str ) ) + {} + std::string adjustString( std::string const& str ) const { + return m_caseSensitivity == CaseSensitive::No + ? toLower( str ) + : str; + + } + std::string toStringSuffix() const + { + return m_caseSensitivity == CaseSensitive::No + ? " (case insensitive)" + : ""; + } + CaseSensitive::Choice m_caseSensitivity; + std::string m_str; + }; + + struct Equals : MatcherImpl { + Equals( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) + : m_data( str, caseSensitivity ) + {} + Equals( Equals const& other ) : m_data( other.m_data ){} + + virtual ~Equals(); + + virtual bool match( std::string const& expr ) const { + return m_data.m_str == m_data.adjustString( expr );; + } + virtual std::string toString() const { + return "equals: \"" + m_data.m_str + "\"" + m_data.toStringSuffix(); + } + + CasedString m_data; + }; + + struct Contains : MatcherImpl { + Contains( std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) + : m_data( substr, caseSensitivity ){} + Contains( Contains const& other ) : m_data( other.m_data ){} + + virtual ~Contains(); + + virtual bool match( std::string const& expr ) const { + return m_data.adjustString( expr ).find( m_data.m_str ) != std::string::npos; + } + virtual std::string toString() const { + return "contains: \"" + m_data.m_str + "\"" + m_data.toStringSuffix(); + } + + CasedString m_data; + }; + + struct StartsWith : MatcherImpl { + StartsWith( std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) + : m_data( substr, caseSensitivity ){} + + StartsWith( StartsWith const& other ) : m_data( other.m_data ){} + + virtual ~StartsWith(); + + virtual bool match( std::string const& expr ) const { + return startsWith( m_data.adjustString( expr ), m_data.m_str ); + } + virtual std::string toString() const { + return "starts with: \"" + m_data.m_str + "\"" + m_data.toStringSuffix(); + } + + CasedString m_data; + }; + + struct EndsWith : MatcherImpl { + EndsWith( std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) + : m_data( substr, caseSensitivity ){} + EndsWith( EndsWith const& other ) : m_data( other.m_data ){} + + virtual ~EndsWith(); + + virtual bool match( std::string const& expr ) const { + return endsWith( m_data.adjustString( expr ), m_data.m_str ); + } + virtual std::string toString() const { + return "ends with: \"" + m_data.m_str + "\"" + m_data.toStringSuffix(); + } + + CasedString m_data; + }; + } // namespace StdString + } // namespace Impl + + // The following functions create the actual matcher objects. + // This allows the types to be inferred + template + inline Impl::Generic::Not Not( Impl::Matcher const& m ) { + return Impl::Generic::Not( m ); + } + + template + inline Impl::Generic::AllOf AllOf( Impl::Matcher const& m1, + Impl::Matcher const& m2 ) { + return Impl::Generic::AllOf().add( m1 ).add( m2 ); + } + template + inline Impl::Generic::AllOf AllOf( Impl::Matcher const& m1, + Impl::Matcher const& m2, + Impl::Matcher const& m3 ) { + return Impl::Generic::AllOf().add( m1 ).add( m2 ).add( m3 ); + } + template + inline Impl::Generic::AnyOf AnyOf( Impl::Matcher const& m1, + Impl::Matcher const& m2 ) { + return Impl::Generic::AnyOf().add( m1 ).add( m2 ); + } + template + inline Impl::Generic::AnyOf AnyOf( Impl::Matcher const& m1, + Impl::Matcher const& m2, + Impl::Matcher const& m3 ) { + return Impl::Generic::AnyOf().add( m1 ).add( m2 ).add( m3 ); + } + + inline Impl::StdString::Equals Equals( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) { + return Impl::StdString::Equals( str, caseSensitivity ); + } + inline Impl::StdString::Equals Equals( const char* str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) { + return Impl::StdString::Equals( Impl::StdString::makeString( str ), caseSensitivity ); + } + inline Impl::StdString::Contains Contains( std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) { + return Impl::StdString::Contains( substr, caseSensitivity ); + } + inline Impl::StdString::Contains Contains( const char* substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) { + return Impl::StdString::Contains( Impl::StdString::makeString( substr ), caseSensitivity ); + } + inline Impl::StdString::StartsWith StartsWith( std::string const& substr ) { + return Impl::StdString::StartsWith( substr ); + } + inline Impl::StdString::StartsWith StartsWith( const char* substr ) { + return Impl::StdString::StartsWith( Impl::StdString::makeString( substr ) ); + } + inline Impl::StdString::EndsWith EndsWith( std::string const& substr ) { + return Impl::StdString::EndsWith( substr ); + } + inline Impl::StdString::EndsWith EndsWith( const char* substr ) { + return Impl::StdString::EndsWith( Impl::StdString::makeString( substr ) ); + } + +} // namespace Matchers + +using namespace Matchers; + +} // namespace Catch + +namespace Catch { + + struct TestFailureException{}; + + template class ExpressionLhs; + + struct STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison; + + struct CopyableStream { + CopyableStream() {} + CopyableStream( CopyableStream const& other ) { + oss << other.oss.str(); + } + CopyableStream& operator=( CopyableStream const& other ) { + oss.str(""); + oss << other.oss.str(); + return *this; + } + std::ostringstream oss; + }; + + class ResultBuilder { + public: + ResultBuilder( char const* macroName, + SourceLineInfo const& lineInfo, + char const* capturedExpression, + ResultDisposition::Flags resultDisposition, + char const* secondArg = "" ); + + template + ExpressionLhs operator <= ( T const& operand ); + ExpressionLhs operator <= ( bool value ); + + template + ResultBuilder& operator << ( T const& value ) { + m_stream.oss << value; + return *this; + } + + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( RhsT const& ); + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || ( RhsT const& ); + + ResultBuilder& setResultType( ResultWas::OfType result ); + ResultBuilder& setResultType( bool result ); + ResultBuilder& setLhs( std::string const& lhs ); + ResultBuilder& setRhs( std::string const& rhs ); + ResultBuilder& setOp( std::string const& op ); + + void endExpression(); + + std::string reconstructExpression() const; + AssertionResult build() const; + + void useActiveException( ResultDisposition::Flags resultDisposition = ResultDisposition::Normal ); + void captureResult( ResultWas::OfType resultType ); + void captureExpression(); + void captureExpectedException( std::string const& expectedMessage ); + void captureExpectedException( Matchers::Impl::Matcher const& matcher ); + void handleResult( AssertionResult const& result ); + void react(); + bool shouldDebugBreak() const; + bool allowThrows() const; + + private: + AssertionInfo m_assertionInfo; + AssertionResultData m_data; + struct ExprComponents { + ExprComponents() : testFalse( false ) {} + bool testFalse; + std::string lhs, rhs, op; + } m_exprComponents; + CopyableStream m_stream; + + bool m_shouldDebugBreak; + bool m_shouldThrow; + }; + +} // namespace Catch + +// Include after due to circular dependency: +// #included from: catch_expression_lhs.hpp +#define TWOBLUECUBES_CATCH_EXPRESSION_LHS_HPP_INCLUDED + +// #included from: catch_evaluate.hpp +#define TWOBLUECUBES_CATCH_EVALUATE_HPP_INCLUDED + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable:4389) // '==' : signed/unsigned mismatch +#endif + +#include + +namespace Catch { +namespace Internal { + + enum Operator { + IsEqualTo, + IsNotEqualTo, + IsLessThan, + IsGreaterThan, + IsLessThanOrEqualTo, + IsGreaterThanOrEqualTo + }; + + template struct OperatorTraits { static const char* getName(){ return "*error*"; } }; + template<> struct OperatorTraits { static const char* getName(){ return "=="; } }; + template<> struct OperatorTraits { static const char* getName(){ return "!="; } }; + template<> struct OperatorTraits { static const char* getName(){ return "<"; } }; + template<> struct OperatorTraits { static const char* getName(){ return ">"; } }; + template<> struct OperatorTraits { static const char* getName(){ return "<="; } }; + template<> struct OperatorTraits{ static const char* getName(){ return ">="; } }; + + template + inline T& opCast(T const& t) { return const_cast(t); } + +// nullptr_t support based on pull request #154 from Konstantin Baumann +#ifdef CATCH_CONFIG_CPP11_NULLPTR + inline std::nullptr_t opCast(std::nullptr_t) { return nullptr; } +#endif // CATCH_CONFIG_CPP11_NULLPTR + + // So the compare overloads can be operator agnostic we convey the operator as a template + // enum, which is used to specialise an Evaluator for doing the comparison. + template + class Evaluator{}; + + template + struct Evaluator { + static bool evaluate( T1 const& lhs, T2 const& rhs) { + return bool( opCast( lhs ) == opCast( rhs ) ); + } + }; + template + struct Evaluator { + static bool evaluate( T1 const& lhs, T2 const& rhs ) { + return bool( opCast( lhs ) != opCast( rhs ) ); + } + }; + template + struct Evaluator { + static bool evaluate( T1 const& lhs, T2 const& rhs ) { + return bool( opCast( lhs ) < opCast( rhs ) ); + } + }; + template + struct Evaluator { + static bool evaluate( T1 const& lhs, T2 const& rhs ) { + return bool( opCast( lhs ) > opCast( rhs ) ); + } + }; + template + struct Evaluator { + static bool evaluate( T1 const& lhs, T2 const& rhs ) { + return bool( opCast( lhs ) >= opCast( rhs ) ); + } + }; + template + struct Evaluator { + static bool evaluate( T1 const& lhs, T2 const& rhs ) { + return bool( opCast( lhs ) <= opCast( rhs ) ); + } + }; + + template + bool applyEvaluator( T1 const& lhs, T2 const& rhs ) { + return Evaluator::evaluate( lhs, rhs ); + } + + // This level of indirection allows us to specialise for integer types + // to avoid signed/ unsigned warnings + + // "base" overload + template + bool compare( T1 const& lhs, T2 const& rhs ) { + return Evaluator::evaluate( lhs, rhs ); + } + + // unsigned X to int + template bool compare( unsigned int lhs, int rhs ) { + return applyEvaluator( lhs, static_cast( rhs ) ); + } + template bool compare( unsigned long lhs, int rhs ) { + return applyEvaluator( lhs, static_cast( rhs ) ); + } + template bool compare( unsigned char lhs, int rhs ) { + return applyEvaluator( lhs, static_cast( rhs ) ); + } + + // unsigned X to long + template bool compare( unsigned int lhs, long rhs ) { + return applyEvaluator( lhs, static_cast( rhs ) ); + } + template bool compare( unsigned long lhs, long rhs ) { + return applyEvaluator( lhs, static_cast( rhs ) ); + } + template bool compare( unsigned char lhs, long rhs ) { + return applyEvaluator( lhs, static_cast( rhs ) ); + } + + // int to unsigned X + template bool compare( int lhs, unsigned int rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( int lhs, unsigned long rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( int lhs, unsigned char rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + + // long to unsigned X + template bool compare( long lhs, unsigned int rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( long lhs, unsigned long rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( long lhs, unsigned char rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + + // pointer to long (when comparing against NULL) + template bool compare( long lhs, T* rhs ) { + return Evaluator::evaluate( reinterpret_cast( lhs ), rhs ); + } + template bool compare( T* lhs, long rhs ) { + return Evaluator::evaluate( lhs, reinterpret_cast( rhs ) ); + } + + // pointer to int (when comparing against NULL) + template bool compare( int lhs, T* rhs ) { + return Evaluator::evaluate( reinterpret_cast( lhs ), rhs ); + } + template bool compare( T* lhs, int rhs ) { + return Evaluator::evaluate( lhs, reinterpret_cast( rhs ) ); + } + +#ifdef CATCH_CONFIG_CPP11_LONG_LONG + // long long to unsigned X + template bool compare( long long lhs, unsigned int rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( long long lhs, unsigned long rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( long long lhs, unsigned long long rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( long long lhs, unsigned char rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + + // unsigned long long to X + template bool compare( unsigned long long lhs, int rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( unsigned long long lhs, long rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( unsigned long long lhs, long long rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( unsigned long long lhs, char rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + + // pointer to long long (when comparing against NULL) + template bool compare( long long lhs, T* rhs ) { + return Evaluator::evaluate( reinterpret_cast( lhs ), rhs ); + } + template bool compare( T* lhs, long long rhs ) { + return Evaluator::evaluate( lhs, reinterpret_cast( rhs ) ); + } +#endif // CATCH_CONFIG_CPP11_LONG_LONG + +#ifdef CATCH_CONFIG_CPP11_NULLPTR + // pointer to nullptr_t (when comparing against nullptr) + template bool compare( std::nullptr_t, T* rhs ) { + return Evaluator::evaluate( nullptr, rhs ); + } + template bool compare( T* lhs, std::nullptr_t ) { + return Evaluator::evaluate( lhs, nullptr ); + } +#endif // CATCH_CONFIG_CPP11_NULLPTR + +} // end of namespace Internal +} // end of namespace Catch + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +// #included from: catch_tostring.h +#define TWOBLUECUBES_CATCH_TOSTRING_H_INCLUDED + +#include +#include +#include +#include +#include + +#ifdef __OBJC__ +// #included from: catch_objc_arc.hpp +#define TWOBLUECUBES_CATCH_OBJC_ARC_HPP_INCLUDED + +#import + +#ifdef __has_feature +#define CATCH_ARC_ENABLED __has_feature(objc_arc) +#else +#define CATCH_ARC_ENABLED 0 +#endif + +void arcSafeRelease( NSObject* obj ); +id performOptionalSelector( id obj, SEL sel ); + +#if !CATCH_ARC_ENABLED +inline void arcSafeRelease( NSObject* obj ) { + [obj release]; +} +inline id performOptionalSelector( id obj, SEL sel ) { + if( [obj respondsToSelector: sel] ) + return [obj performSelector: sel]; + return nil; +} +#define CATCH_UNSAFE_UNRETAINED +#define CATCH_ARC_STRONG +#else +inline void arcSafeRelease( NSObject* ){} +inline id performOptionalSelector( id obj, SEL sel ) { +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Warc-performSelector-leaks" +#endif + if( [obj respondsToSelector: sel] ) + return [obj performSelector: sel]; +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + return nil; +} +#define CATCH_UNSAFE_UNRETAINED __unsafe_unretained +#define CATCH_ARC_STRONG __strong +#endif + +#endif + +#ifdef CATCH_CONFIG_CPP11_TUPLE +#include +#endif + +#ifdef CATCH_CONFIG_CPP11_IS_ENUM +#include +#endif + +namespace Catch { + +// Why we're here. +template +std::string toString( T const& value ); + +// Built in overloads + +std::string toString( std::string const& value ); +std::string toString( std::wstring const& value ); +std::string toString( const char* const value ); +std::string toString( char* const value ); +std::string toString( const wchar_t* const value ); +std::string toString( wchar_t* const value ); +std::string toString( int value ); +std::string toString( unsigned long value ); +std::string toString( unsigned int value ); +std::string toString( const double value ); +std::string toString( const float value ); +std::string toString( bool value ); +std::string toString( char value ); +std::string toString( signed char value ); +std::string toString( unsigned char value ); + +#ifdef CATCH_CONFIG_CPP11_LONG_LONG +std::string toString( long long value ); +std::string toString( unsigned long long value ); +#endif + +#ifdef CATCH_CONFIG_CPP11_NULLPTR +std::string toString( std::nullptr_t ); +#endif + +#ifdef __OBJC__ + std::string toString( NSString const * const& nsstring ); + std::string toString( NSString * CATCH_ARC_STRONG const& nsstring ); + std::string toString( NSObject* const& nsObject ); +#endif + +namespace Detail { + + extern const std::string unprintableString; + + struct BorgType { + template BorgType( T const& ); + }; + + struct TrueType { char sizer[1]; }; + struct FalseType { char sizer[2]; }; + + TrueType& testStreamable( std::ostream& ); + FalseType testStreamable( FalseType ); + + FalseType operator<<( std::ostream const&, BorgType const& ); + + template + struct IsStreamInsertable { + static std::ostream &s; + static T const&t; + enum { value = sizeof( testStreamable(s << t) ) == sizeof( TrueType ) }; + }; + +#if defined(CATCH_CONFIG_CPP11_IS_ENUM) + template::value + > + struct EnumStringMaker + { + static std::string convert( T const& ) { return unprintableString; } + }; + + template + struct EnumStringMaker + { + static std::string convert( T const& v ) + { + return ::Catch::toString( + static_cast::type>(v) + ); + } + }; +#endif + template + struct StringMakerBase { +#if defined(CATCH_CONFIG_CPP11_IS_ENUM) + template + static std::string convert( T const& v ) + { + return EnumStringMaker::convert( v ); + } +#else + template + static std::string convert( T const& ) { return unprintableString; } +#endif + }; + + template<> + struct StringMakerBase { + template + static std::string convert( T const& _value ) { + std::ostringstream oss; + oss << _value; + return oss.str(); + } + }; + + std::string rawMemoryToString( const void *object, std::size_t size ); + + template + inline std::string rawMemoryToString( const T& object ) { + return rawMemoryToString( &object, sizeof(object) ); + } + +} // end namespace Detail + +template +struct StringMaker : + Detail::StringMakerBase::value> {}; + +template +struct StringMaker { + template + static std::string convert( U* p ) { + if( !p ) + return "NULL"; + else + return Detail::rawMemoryToString( p ); + } +}; + +template +struct StringMaker { + static std::string convert( R C::* p ) { + if( !p ) + return "NULL"; + else + return Detail::rawMemoryToString( p ); + } +}; + +namespace Detail { + template + std::string rangeToString( InputIterator first, InputIterator last ); +} + +//template +//struct StringMaker > { +// static std::string convert( std::vector const& v ) { +// return Detail::rangeToString( v.begin(), v.end() ); +// } +//}; + +template +std::string toString( std::vector const& v ) { + return Detail::rangeToString( v.begin(), v.end() ); +} + +#ifdef CATCH_CONFIG_CPP11_TUPLE + +// toString for tuples +namespace TupleDetail { + template< + typename Tuple, + std::size_t N = 0, + bool = (N < std::tuple_size::value) + > + struct ElementPrinter { + static void print( const Tuple& tuple, std::ostream& os ) + { + os << ( N ? ", " : " " ) + << Catch::toString(std::get(tuple)); + ElementPrinter::print(tuple,os); + } + }; + + template< + typename Tuple, + std::size_t N + > + struct ElementPrinter { + static void print( const Tuple&, std::ostream& ) {} + }; + +} + +template +struct StringMaker> { + + static std::string convert( const std::tuple& tuple ) + { + std::ostringstream os; + os << '{'; + TupleDetail::ElementPrinter>::print( tuple, os ); + os << " }"; + return os.str(); + } +}; +#endif // CATCH_CONFIG_CPP11_TUPLE + +namespace Detail { + template + std::string makeString( T const& value ) { + return StringMaker::convert( value ); + } +} // end namespace Detail + +/// \brief converts any type to a string +/// +/// The default template forwards on to ostringstream - except when an +/// ostringstream overload does not exist - in which case it attempts to detect +/// that and writes {?}. +/// Overload (not specialise) this template for custom typs that you don't want +/// to provide an ostream overload for. +template +std::string toString( T const& value ) { + return StringMaker::convert( value ); +} + + namespace Detail { + template + std::string rangeToString( InputIterator first, InputIterator last ) { + std::ostringstream oss; + oss << "{ "; + if( first != last ) { + oss << Catch::toString( *first ); + for( ++first ; first != last ; ++first ) + oss << ", " << Catch::toString( *first ); + } + oss << " }"; + return oss.str(); + } +} + +} // end namespace Catch + +namespace Catch { + +// Wraps the LHS of an expression and captures the operator and RHS (if any) - +// wrapping them all in a ResultBuilder object +template +class ExpressionLhs { + ExpressionLhs& operator = ( ExpressionLhs const& ); +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + ExpressionLhs& operator = ( ExpressionLhs && ) = delete; +# endif + +public: + ExpressionLhs( ResultBuilder& rb, T lhs ) : m_rb( rb ), m_lhs( lhs ) {} +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + ExpressionLhs( ExpressionLhs const& ) = default; + ExpressionLhs( ExpressionLhs && ) = default; +# endif + + template + ResultBuilder& operator == ( RhsT const& rhs ) { + return captureExpression( rhs ); + } + + template + ResultBuilder& operator != ( RhsT const& rhs ) { + return captureExpression( rhs ); + } + + template + ResultBuilder& operator < ( RhsT const& rhs ) { + return captureExpression( rhs ); + } + + template + ResultBuilder& operator > ( RhsT const& rhs ) { + return captureExpression( rhs ); + } + + template + ResultBuilder& operator <= ( RhsT const& rhs ) { + return captureExpression( rhs ); + } + + template + ResultBuilder& operator >= ( RhsT const& rhs ) { + return captureExpression( rhs ); + } + + ResultBuilder& operator == ( bool rhs ) { + return captureExpression( rhs ); + } + + ResultBuilder& operator != ( bool rhs ) { + return captureExpression( rhs ); + } + + void endExpression() { + bool value = m_lhs ? true : false; + m_rb + .setLhs( Catch::toString( value ) ) + .setResultType( value ) + .endExpression(); + } + + // Only simple binary expressions are allowed on the LHS. + // If more complex compositions are required then place the sub expression in parentheses + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator + ( RhsT const& ); + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator - ( RhsT const& ); + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator / ( RhsT const& ); + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator * ( RhsT const& ); + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( RhsT const& ); + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || ( RhsT const& ); + +private: + template + ResultBuilder& captureExpression( RhsT const& rhs ) { + return m_rb + .setResultType( Internal::compare( m_lhs, rhs ) ) + .setLhs( Catch::toString( m_lhs ) ) + .setRhs( Catch::toString( rhs ) ) + .setOp( Internal::OperatorTraits::getName() ); + } + +private: + ResultBuilder& m_rb; + T m_lhs; +}; + +} // end namespace Catch + + +namespace Catch { + + template + inline ExpressionLhs ResultBuilder::operator <= ( T const& operand ) { + return ExpressionLhs( *this, operand ); + } + + inline ExpressionLhs ResultBuilder::operator <= ( bool value ) { + return ExpressionLhs( *this, value ); + } + +} // namespace Catch + +// #included from: catch_message.h +#define TWOBLUECUBES_CATCH_MESSAGE_H_INCLUDED + +#include + +namespace Catch { + + struct MessageInfo { + MessageInfo( std::string const& _macroName, + SourceLineInfo const& _lineInfo, + ResultWas::OfType _type ); + + std::string macroName; + SourceLineInfo lineInfo; + ResultWas::OfType type; + std::string message; + unsigned int sequence; + + bool operator == ( MessageInfo const& other ) const { + return sequence == other.sequence; + } + bool operator < ( MessageInfo const& other ) const { + return sequence < other.sequence; + } + private: + static unsigned int globalCount; + }; + + struct MessageBuilder { + MessageBuilder( std::string const& macroName, + SourceLineInfo const& lineInfo, + ResultWas::OfType type ) + : m_info( macroName, lineInfo, type ) + {} + + template + MessageBuilder& operator << ( T const& value ) { + m_stream << value; + return *this; + } + + MessageInfo m_info; + std::ostringstream m_stream; + }; + + class ScopedMessage { + public: + ScopedMessage( MessageBuilder const& builder ); + ScopedMessage( ScopedMessage const& other ); + ~ScopedMessage(); + + MessageInfo m_info; + }; + +} // end namespace Catch + +// #included from: catch_interfaces_capture.h +#define TWOBLUECUBES_CATCH_INTERFACES_CAPTURE_H_INCLUDED + +#include + +namespace Catch { + + class TestCase; + class AssertionResult; + struct AssertionInfo; + struct SectionInfo; + struct SectionEndInfo; + struct MessageInfo; + class ScopedMessageBuilder; + struct Counts; + + struct IResultCapture { + + virtual ~IResultCapture(); + + virtual void assertionEnded( AssertionResult const& result ) = 0; + virtual bool sectionStarted( SectionInfo const& sectionInfo, + Counts& assertions ) = 0; + virtual void sectionEnded( SectionEndInfo const& endInfo ) = 0; + virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) = 0; + virtual void pushScopedMessage( MessageInfo const& message ) = 0; + virtual void popScopedMessage( MessageInfo const& message ) = 0; + + virtual std::string getCurrentTestName() const = 0; + virtual const AssertionResult* getLastResult() const = 0; + + virtual void handleFatalErrorCondition( std::string const& message ) = 0; + }; + + IResultCapture& getResultCapture(); +} + +// #included from: catch_debugger.h +#define TWOBLUECUBES_CATCH_DEBUGGER_H_INCLUDED + +// #included from: catch_platform.h +#define TWOBLUECUBES_CATCH_PLATFORM_H_INCLUDED + +#if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) +#define CATCH_PLATFORM_MAC +#elif defined(__IPHONE_OS_VERSION_MIN_REQUIRED) +#define CATCH_PLATFORM_IPHONE +#elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) +#define CATCH_PLATFORM_WINDOWS +#endif + +#include + +namespace Catch{ + + bool isDebuggerActive(); + void writeToDebugConsole( std::string const& text ); +} + +#ifdef CATCH_PLATFORM_MAC + + // The following code snippet based on: + // http://cocoawithlove.com/2008/03/break-into-debugger.html + #ifdef DEBUG + #if defined(__ppc64__) || defined(__ppc__) + #define CATCH_BREAK_INTO_DEBUGGER() \ + if( Catch::isDebuggerActive() ) { \ + __asm__("li r0, 20\nsc\nnop\nli r0, 37\nli r4, 2\nsc\nnop\n" \ + : : : "memory","r0","r3","r4" ); \ + } + #else + #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) {__asm__("int $3\n" : : );} + #endif + #endif + +#elif defined(_MSC_VER) + #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { __debugbreak(); } +#elif defined(__MINGW32__) + extern "C" __declspec(dllimport) void __stdcall DebugBreak(); + #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { DebugBreak(); } +#endif + +#ifndef CATCH_BREAK_INTO_DEBUGGER +#define CATCH_BREAK_INTO_DEBUGGER() Catch::alwaysTrue(); +#endif + +// #included from: catch_interfaces_runner.h +#define TWOBLUECUBES_CATCH_INTERFACES_RUNNER_H_INCLUDED + +namespace Catch { + class TestCase; + + struct IRunner { + virtual ~IRunner(); + virtual bool aborting() const = 0; + }; +} + +/////////////////////////////////////////////////////////////////////////////// +// In the event of a failure works out if the debugger needs to be invoked +// and/or an exception thrown and takes appropriate action. +// This needs to be done as a macro so the debugger will stop in the user +// source code rather than in Catch library code +#define INTERNAL_CATCH_REACT( resultBuilder ) \ + if( resultBuilder.shouldDebugBreak() ) CATCH_BREAK_INTO_DEBUGGER(); \ + resultBuilder.react(); + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \ + try { \ + CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ + ( __catchResult <= expr ).endExpression(); \ + } \ + catch( ... ) { \ + __catchResult.useActiveException( Catch::ResultDisposition::Normal ); \ + } \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::isTrue( false && static_cast(expr) ) ) // expr here is never evaluated at runtime but it forces the compiler to give it a look + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_IF( expr, resultDisposition, macroName ) \ + INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ); \ + if( Catch::getResultCapture().getLastResult()->succeeded() ) + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_ELSE( expr, resultDisposition, macroName ) \ + INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ); \ + if( !Catch::getResultCapture().getLastResult()->succeeded() ) + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_NO_THROW( expr, resultDisposition, macroName ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \ + try { \ + expr; \ + __catchResult.captureResult( Catch::ResultWas::Ok ); \ + } \ + catch( ... ) { \ + __catchResult.useActiveException( resultDisposition ); \ + } \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::alwaysFalse() ) + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_THROWS( expr, resultDisposition, matcher, macroName ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition, #matcher ); \ + if( __catchResult.allowThrows() ) \ + try { \ + expr; \ + __catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \ + } \ + catch( ... ) { \ + __catchResult.captureExpectedException( matcher ); \ + } \ + else \ + __catchResult.captureResult( Catch::ResultWas::Ok ); \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::alwaysFalse() ) + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_THROWS_AS( expr, exceptionType, resultDisposition, macroName ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \ + if( __catchResult.allowThrows() ) \ + try { \ + expr; \ + __catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \ + } \ + catch( exceptionType ) { \ + __catchResult.captureResult( Catch::ResultWas::Ok ); \ + } \ + catch( ... ) { \ + __catchResult.useActiveException( resultDisposition ); \ + } \ + else \ + __catchResult.captureResult( Catch::ResultWas::Ok ); \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::alwaysFalse() ) + +/////////////////////////////////////////////////////////////////////////////// +#ifdef CATCH_CONFIG_VARIADIC_MACROS + #define INTERNAL_CATCH_MSG( messageType, resultDisposition, macroName, ... ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \ + __catchResult << __VA_ARGS__ + ::Catch::StreamEndStop(); \ + __catchResult.captureResult( messageType ); \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::alwaysFalse() ) +#else + #define INTERNAL_CATCH_MSG( messageType, resultDisposition, macroName, log ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \ + __catchResult << log + ::Catch::StreamEndStop(); \ + __catchResult.captureResult( messageType ); \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::alwaysFalse() ) +#endif + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_INFO( log, macroName ) \ + Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME( scopedMessage ) = Catch::MessageBuilder( macroName, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log; + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CHECK_THAT( arg, matcher, resultDisposition, macroName ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #arg ", " #matcher, resultDisposition ); \ + try { \ + std::string matcherAsString = (matcher).toString(); \ + __catchResult \ + .setLhs( Catch::toString( arg ) ) \ + .setRhs( matcherAsString == Catch::Detail::unprintableString ? #matcher : matcherAsString ) \ + .setOp( "matches" ) \ + .setResultType( (matcher).match( arg ) ); \ + __catchResult.captureExpression(); \ + } catch( ... ) { \ + __catchResult.useActiveException( resultDisposition | Catch::ResultDisposition::ContinueOnFailure ); \ + } \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::alwaysFalse() ) + +// #included from: internal/catch_section.h +#define TWOBLUECUBES_CATCH_SECTION_H_INCLUDED + +// #included from: catch_section_info.h +#define TWOBLUECUBES_CATCH_SECTION_INFO_H_INCLUDED + +// #included from: catch_totals.hpp +#define TWOBLUECUBES_CATCH_TOTALS_HPP_INCLUDED + +#include + +namespace Catch { + + struct Counts { + Counts() : passed( 0 ), failed( 0 ), failedButOk( 0 ) {} + + Counts operator - ( Counts const& other ) const { + Counts diff; + diff.passed = passed - other.passed; + diff.failed = failed - other.failed; + diff.failedButOk = failedButOk - other.failedButOk; + return diff; + } + Counts& operator += ( Counts const& other ) { + passed += other.passed; + failed += other.failed; + failedButOk += other.failedButOk; + return *this; + } + + std::size_t total() const { + return passed + failed + failedButOk; + } + bool allPassed() const { + return failed == 0 && failedButOk == 0; + } + bool allOk() const { + return failed == 0; + } + + std::size_t passed; + std::size_t failed; + std::size_t failedButOk; + }; + + struct Totals { + + Totals operator - ( Totals const& other ) const { + Totals diff; + diff.assertions = assertions - other.assertions; + diff.testCases = testCases - other.testCases; + return diff; + } + + Totals delta( Totals const& prevTotals ) const { + Totals diff = *this - prevTotals; + if( diff.assertions.failed > 0 ) + ++diff.testCases.failed; + else if( diff.assertions.failedButOk > 0 ) + ++diff.testCases.failedButOk; + else + ++diff.testCases.passed; + return diff; + } + + Totals& operator += ( Totals const& other ) { + assertions += other.assertions; + testCases += other.testCases; + return *this; + } + + Counts assertions; + Counts testCases; + }; +} + +namespace Catch { + + struct SectionInfo { + SectionInfo + ( SourceLineInfo const& _lineInfo, + std::string const& _name, + std::string const& _description = std::string() ); + + std::string name; + std::string description; + SourceLineInfo lineInfo; + }; + + struct SectionEndInfo { + SectionEndInfo( SectionInfo const& _sectionInfo, Counts const& _prevAssertions, double _durationInSeconds ) + : sectionInfo( _sectionInfo ), prevAssertions( _prevAssertions ), durationInSeconds( _durationInSeconds ) + {} + + SectionInfo sectionInfo; + Counts prevAssertions; + double durationInSeconds; + }; + +} // end namespace Catch + +// #included from: catch_timer.h +#define TWOBLUECUBES_CATCH_TIMER_H_INCLUDED + +#ifdef CATCH_PLATFORM_WINDOWS +typedef unsigned long long uint64_t; +#else +#include +#endif + +namespace Catch { + + class Timer { + public: + Timer() : m_ticks( 0 ) {} + void start(); + unsigned int getElapsedMicroseconds() const; + unsigned int getElapsedMilliseconds() const; + double getElapsedSeconds() const; + + private: + uint64_t m_ticks; + }; + +} // namespace Catch + +#include + +namespace Catch { + + class Section : NonCopyable { + public: + Section( SectionInfo const& info ); + ~Section(); + + // This indicates whether the section should be executed or not + operator bool() const; + + private: + SectionInfo m_info; + + std::string m_name; + Counts m_assertions; + bool m_sectionIncluded; + Timer m_timer; + }; + +} // end namespace Catch + +#ifdef CATCH_CONFIG_VARIADIC_MACROS + #define INTERNAL_CATCH_SECTION( ... ) \ + if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) ) +#else + #define INTERNAL_CATCH_SECTION( name, desc ) \ + if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, name, desc ) ) +#endif + +// #included from: internal/catch_generators.hpp +#define TWOBLUECUBES_CATCH_GENERATORS_HPP_INCLUDED + +#include +#include +#include +#include + +namespace Catch { + +template +struct IGenerator { + virtual ~IGenerator() {} + virtual T getValue( std::size_t index ) const = 0; + virtual std::size_t size () const = 0; +}; + +template +class BetweenGenerator : public IGenerator { +public: + BetweenGenerator( T from, T to ) : m_from( from ), m_to( to ){} + + virtual T getValue( std::size_t index ) const { + return m_from+static_cast( index ); + } + + virtual std::size_t size() const { + return static_cast( 1+m_to-m_from ); + } + +private: + + T m_from; + T m_to; +}; + +template +class ValuesGenerator : public IGenerator { +public: + ValuesGenerator(){} + + void add( T value ) { + m_values.push_back( value ); + } + + virtual T getValue( std::size_t index ) const { + return m_values[index]; + } + + virtual std::size_t size() const { + return m_values.size(); + } + +private: + std::vector m_values; +}; + +template +class CompositeGenerator { +public: + CompositeGenerator() : m_totalSize( 0 ) {} + + // *** Move semantics, similar to auto_ptr *** + CompositeGenerator( CompositeGenerator& other ) + : m_fileInfo( other.m_fileInfo ), + m_totalSize( 0 ) + { + move( other ); + } + + CompositeGenerator& setFileInfo( const char* fileInfo ) { + m_fileInfo = fileInfo; + return *this; + } + + ~CompositeGenerator() { + deleteAll( m_composed ); + } + + operator T () const { + size_t overallIndex = getCurrentContext().getGeneratorIndex( m_fileInfo, m_totalSize ); + + typename std::vector*>::const_iterator it = m_composed.begin(); + typename std::vector*>::const_iterator itEnd = m_composed.end(); + for( size_t index = 0; it != itEnd; ++it ) + { + const IGenerator* generator = *it; + if( overallIndex >= index && overallIndex < index + generator->size() ) + { + return generator->getValue( overallIndex-index ); + } + index += generator->size(); + } + CATCH_INTERNAL_ERROR( "Indexed past end of generated range" ); + return T(); // Suppress spurious "not all control paths return a value" warning in Visual Studio - if you know how to fix this please do so + } + + void add( const IGenerator* generator ) { + m_totalSize += generator->size(); + m_composed.push_back( generator ); + } + + CompositeGenerator& then( CompositeGenerator& other ) { + move( other ); + return *this; + } + + CompositeGenerator& then( T value ) { + ValuesGenerator* valuesGen = new ValuesGenerator(); + valuesGen->add( value ); + add( valuesGen ); + return *this; + } + +private: + + void move( CompositeGenerator& other ) { + std::copy( other.m_composed.begin(), other.m_composed.end(), std::back_inserter( m_composed ) ); + m_totalSize += other.m_totalSize; + other.m_composed.clear(); + } + + std::vector*> m_composed; + std::string m_fileInfo; + size_t m_totalSize; +}; + +namespace Generators +{ + template + CompositeGenerator between( T from, T to ) { + CompositeGenerator generators; + generators.add( new BetweenGenerator( from, to ) ); + return generators; + } + + template + CompositeGenerator values( T val1, T val2 ) { + CompositeGenerator generators; + ValuesGenerator* valuesGen = new ValuesGenerator(); + valuesGen->add( val1 ); + valuesGen->add( val2 ); + generators.add( valuesGen ); + return generators; + } + + template + CompositeGenerator values( T val1, T val2, T val3 ){ + CompositeGenerator generators; + ValuesGenerator* valuesGen = new ValuesGenerator(); + valuesGen->add( val1 ); + valuesGen->add( val2 ); + valuesGen->add( val3 ); + generators.add( valuesGen ); + return generators; + } + + template + CompositeGenerator values( T val1, T val2, T val3, T val4 ) { + CompositeGenerator generators; + ValuesGenerator* valuesGen = new ValuesGenerator(); + valuesGen->add( val1 ); + valuesGen->add( val2 ); + valuesGen->add( val3 ); + valuesGen->add( val4 ); + generators.add( valuesGen ); + return generators; + } + +} // end namespace Generators + +using namespace Generators; + +} // end namespace Catch + +#define INTERNAL_CATCH_LINESTR2( line ) #line +#define INTERNAL_CATCH_LINESTR( line ) INTERNAL_CATCH_LINESTR2( line ) + +#define INTERNAL_CATCH_GENERATE( expr ) expr.setFileInfo( __FILE__ "(" INTERNAL_CATCH_LINESTR( __LINE__ ) ")" ) + +// #included from: internal/catch_interfaces_exception.h +#define TWOBLUECUBES_CATCH_INTERFACES_EXCEPTION_H_INCLUDED + +#include +#include + +// #included from: catch_interfaces_registry_hub.h +#define TWOBLUECUBES_CATCH_INTERFACES_REGISTRY_HUB_H_INCLUDED + +#include + +namespace Catch { + + class TestCase; + struct ITestCaseRegistry; + struct IExceptionTranslatorRegistry; + struct IExceptionTranslator; + struct IReporterRegistry; + struct IReporterFactory; + + struct IRegistryHub { + virtual ~IRegistryHub(); + + virtual IReporterRegistry const& getReporterRegistry() const = 0; + virtual ITestCaseRegistry const& getTestCaseRegistry() const = 0; + virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() = 0; + }; + + struct IMutableRegistryHub { + virtual ~IMutableRegistryHub(); + virtual void registerReporter( std::string const& name, Ptr const& factory ) = 0; + virtual void registerListener( Ptr const& factory ) = 0; + virtual void registerTest( TestCase const& testInfo ) = 0; + virtual void registerTranslator( const IExceptionTranslator* translator ) = 0; + }; + + IRegistryHub& getRegistryHub(); + IMutableRegistryHub& getMutableRegistryHub(); + void cleanUp(); + std::string translateActiveException(); + +} + +namespace Catch { + + typedef std::string(*exceptionTranslateFunction)(); + + struct IExceptionTranslator; + typedef std::vector ExceptionTranslators; + + struct IExceptionTranslator { + virtual ~IExceptionTranslator(); + virtual std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const = 0; + }; + + struct IExceptionTranslatorRegistry { + virtual ~IExceptionTranslatorRegistry(); + + virtual std::string translateActiveException() const = 0; + }; + + class ExceptionTranslatorRegistrar { + template + class ExceptionTranslator : public IExceptionTranslator { + public: + + ExceptionTranslator( std::string(*translateFunction)( T& ) ) + : m_translateFunction( translateFunction ) + {} + + virtual std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const CATCH_OVERRIDE { + try { + if( it == itEnd ) + throw; + else + return (*it)->translate( it+1, itEnd ); + } + catch( T& ex ) { + return m_translateFunction( ex ); + } + } + + protected: + std::string(*m_translateFunction)( T& ); + }; + + public: + template + ExceptionTranslatorRegistrar( std::string(*translateFunction)( T& ) ) { + getMutableRegistryHub().registerTranslator + ( new ExceptionTranslator( translateFunction ) ); + } + }; +} + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) \ + static std::string INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator )( signature ); \ + namespace{ Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ) ); }\ + static std::string INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator )( signature ) + +// #included from: internal/catch_approx.hpp +#define TWOBLUECUBES_CATCH_APPROX_HPP_INCLUDED + +#include +#include + +namespace Catch { +namespace Detail { + + class Approx { + public: + explicit Approx ( double value ) + : m_epsilon( std::numeric_limits::epsilon()*100 ), + m_scale( 1.0 ), + m_value( value ) + {} + + Approx( Approx const& other ) + : m_epsilon( other.m_epsilon ), + m_scale( other.m_scale ), + m_value( other.m_value ) + {} + + static Approx custom() { + return Approx( 0 ); + } + + Approx operator()( double value ) { + Approx approx( value ); + approx.epsilon( m_epsilon ); + approx.scale( m_scale ); + return approx; + } + + friend bool operator == ( double lhs, Approx const& rhs ) { + // Thanks to Richard Harris for his help refining this formula + return fabs( lhs - rhs.m_value ) < rhs.m_epsilon * (rhs.m_scale + (std::max)( fabs(lhs), fabs(rhs.m_value) ) ); + } + + friend bool operator == ( Approx const& lhs, double rhs ) { + return operator==( rhs, lhs ); + } + + friend bool operator != ( double lhs, Approx const& rhs ) { + return !operator==( lhs, rhs ); + } + + friend bool operator != ( Approx const& lhs, double rhs ) { + return !operator==( rhs, lhs ); + } + + Approx& epsilon( double newEpsilon ) { + m_epsilon = newEpsilon; + return *this; + } + + Approx& scale( double newScale ) { + m_scale = newScale; + return *this; + } + + std::string toString() const { + std::ostringstream oss; + oss << "Approx( " << Catch::toString( m_value ) << " )"; + return oss.str(); + } + + private: + double m_epsilon; + double m_scale; + double m_value; + }; +} + +template<> +inline std::string toString( Detail::Approx const& value ) { + return value.toString(); +} + +} // end namespace Catch + +// #included from: internal/catch_interfaces_tag_alias_registry.h +#define TWOBLUECUBES_CATCH_INTERFACES_TAG_ALIAS_REGISTRY_H_INCLUDED + +// #included from: catch_tag_alias.h +#define TWOBLUECUBES_CATCH_TAG_ALIAS_H_INCLUDED + +#include + +namespace Catch { + + struct TagAlias { + TagAlias( std::string _tag, SourceLineInfo _lineInfo ) : tag( _tag ), lineInfo( _lineInfo ) {} + + std::string tag; + SourceLineInfo lineInfo; + }; + + struct RegistrarForTagAliases { + RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ); + }; + +} // end namespace Catch + +#define CATCH_REGISTER_TAG_ALIAS( alias, spec ) namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); } +// #included from: catch_option.hpp +#define TWOBLUECUBES_CATCH_OPTION_HPP_INCLUDED + +namespace Catch { + + // An optional type + template + class Option { + public: + Option() : nullableValue( CATCH_NULL ) {} + Option( T const& _value ) + : nullableValue( new( storage ) T( _value ) ) + {} + Option( Option const& _other ) + : nullableValue( _other ? new( storage ) T( *_other ) : CATCH_NULL ) + {} + + ~Option() { + reset(); + } + + Option& operator= ( Option const& _other ) { + if( &_other != this ) { + reset(); + if( _other ) + nullableValue = new( storage ) T( *_other ); + } + return *this; + } + Option& operator = ( T const& _value ) { + reset(); + nullableValue = new( storage ) T( _value ); + return *this; + } + + void reset() { + if( nullableValue ) + nullableValue->~T(); + nullableValue = CATCH_NULL; + } + + T& operator*() { return *nullableValue; } + T const& operator*() const { return *nullableValue; } + T* operator->() { return nullableValue; } + const T* operator->() const { return nullableValue; } + + T valueOr( T const& defaultValue ) const { + return nullableValue ? *nullableValue : defaultValue; + } + + bool some() const { return nullableValue != CATCH_NULL; } + bool none() const { return nullableValue == CATCH_NULL; } + + bool operator !() const { return nullableValue == CATCH_NULL; } + operator SafeBool::type() const { + return SafeBool::makeSafe( some() ); + } + + private: + T* nullableValue; + char storage[sizeof(T)]; + }; + +} // end namespace Catch + +namespace Catch { + + struct ITagAliasRegistry { + virtual ~ITagAliasRegistry(); + virtual Option find( std::string const& alias ) const = 0; + virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const = 0; + + static ITagAliasRegistry const& get(); + }; + +} // end namespace Catch + +// These files are included here so the single_include script doesn't put them +// in the conditionally compiled sections +// #included from: internal/catch_test_case_info.h +#define TWOBLUECUBES_CATCH_TEST_CASE_INFO_H_INCLUDED + +#include +#include + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpadded" +#endif + +namespace Catch { + + struct ITestCase; + + struct TestCaseInfo { + enum SpecialProperties{ + None = 0, + IsHidden = 1 << 1, + ShouldFail = 1 << 2, + MayFail = 1 << 3, + Throws = 1 << 4 + }; + + TestCaseInfo( std::string const& _name, + std::string const& _className, + std::string const& _description, + std::set const& _tags, + SourceLineInfo const& _lineInfo ); + + TestCaseInfo( TestCaseInfo const& other ); + + friend void setTags( TestCaseInfo& testCaseInfo, std::set const& tags ); + + bool isHidden() const; + bool throws() const; + bool okToFail() const; + bool expectedToFail() const; + + std::string name; + std::string className; + std::string description; + std::set tags; + std::set lcaseTags; + std::string tagsAsString; + SourceLineInfo lineInfo; + SpecialProperties properties; + }; + + class TestCase : public TestCaseInfo { + public: + + TestCase( ITestCase* testCase, TestCaseInfo const& info ); + TestCase( TestCase const& other ); + + TestCase withName( std::string const& _newName ) const; + + void invoke() const; + + TestCaseInfo const& getTestCaseInfo() const; + + void swap( TestCase& other ); + bool operator == ( TestCase const& other ) const; + bool operator < ( TestCase const& other ) const; + TestCase& operator = ( TestCase const& other ); + + private: + Ptr test; + }; + + TestCase makeTestCase( ITestCase* testCase, + std::string const& className, + std::string const& name, + std::string const& description, + SourceLineInfo const& lineInfo ); +} + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + + +#ifdef __OBJC__ +// #included from: internal/catch_objc.hpp +#define TWOBLUECUBES_CATCH_OBJC_HPP_INCLUDED + +#import + +#include + +// NB. Any general catch headers included here must be included +// in catch.hpp first to make sure they are included by the single +// header for non obj-usage + +/////////////////////////////////////////////////////////////////////////////// +// This protocol is really only here for (self) documenting purposes, since +// all its methods are optional. +@protocol OcFixture + +@optional + +-(void) setUp; +-(void) tearDown; + +@end + +namespace Catch { + + class OcMethod : public SharedImpl { + + public: + OcMethod( Class cls, SEL sel ) : m_cls( cls ), m_sel( sel ) {} + + virtual void invoke() const { + id obj = [[m_cls alloc] init]; + + performOptionalSelector( obj, @selector(setUp) ); + performOptionalSelector( obj, m_sel ); + performOptionalSelector( obj, @selector(tearDown) ); + + arcSafeRelease( obj ); + } + private: + virtual ~OcMethod() {} + + Class m_cls; + SEL m_sel; + }; + + namespace Detail{ + + inline std::string getAnnotation( Class cls, + std::string const& annotationName, + std::string const& testCaseName ) { + NSString* selStr = [[NSString alloc] initWithFormat:@"Catch_%s_%s", annotationName.c_str(), testCaseName.c_str()]; + SEL sel = NSSelectorFromString( selStr ); + arcSafeRelease( selStr ); + id value = performOptionalSelector( cls, sel ); + if( value ) + return [(NSString*)value UTF8String]; + return ""; + } + } + + inline size_t registerTestMethods() { + size_t noTestMethods = 0; + int noClasses = objc_getClassList( CATCH_NULL, 0 ); + + Class* classes = (CATCH_UNSAFE_UNRETAINED Class *)malloc( sizeof(Class) * noClasses); + objc_getClassList( classes, noClasses ); + + for( int c = 0; c < noClasses; c++ ) { + Class cls = classes[c]; + { + u_int count; + Method* methods = class_copyMethodList( cls, &count ); + for( u_int m = 0; m < count ; m++ ) { + SEL selector = method_getName(methods[m]); + std::string methodName = sel_getName(selector); + if( startsWith( methodName, "Catch_TestCase_" ) ) { + std::string testCaseName = methodName.substr( 15 ); + std::string name = Detail::getAnnotation( cls, "Name", testCaseName ); + std::string desc = Detail::getAnnotation( cls, "Description", testCaseName ); + const char* className = class_getName( cls ); + + getMutableRegistryHub().registerTest( makeTestCase( new OcMethod( cls, selector ), className, name.c_str(), desc.c_str(), SourceLineInfo() ) ); + noTestMethods++; + } + } + free(methods); + } + } + return noTestMethods; + } + + namespace Matchers { + namespace Impl { + namespace NSStringMatchers { + + template + struct StringHolder : MatcherImpl{ + StringHolder( NSString* substr ) : m_substr( [substr copy] ){} + StringHolder( StringHolder const& other ) : m_substr( [other.m_substr copy] ){} + StringHolder() { + arcSafeRelease( m_substr ); + } + + NSString* m_substr; + }; + + struct Equals : StringHolder { + Equals( NSString* substr ) : StringHolder( substr ){} + + virtual bool match( ExpressionType const& str ) const { + return (str != nil || m_substr == nil ) && + [str isEqualToString:m_substr]; + } + + virtual std::string toString() const { + return "equals string: " + Catch::toString( m_substr ); + } + }; + + struct Contains : StringHolder { + Contains( NSString* substr ) : StringHolder( substr ){} + + virtual bool match( ExpressionType const& str ) const { + return (str != nil || m_substr == nil ) && + [str rangeOfString:m_substr].location != NSNotFound; + } + + virtual std::string toString() const { + return "contains string: " + Catch::toString( m_substr ); + } + }; + + struct StartsWith : StringHolder { + StartsWith( NSString* substr ) : StringHolder( substr ){} + + virtual bool match( ExpressionType const& str ) const { + return (str != nil || m_substr == nil ) && + [str rangeOfString:m_substr].location == 0; + } + + virtual std::string toString() const { + return "starts with: " + Catch::toString( m_substr ); + } + }; + struct EndsWith : StringHolder { + EndsWith( NSString* substr ) : StringHolder( substr ){} + + virtual bool match( ExpressionType const& str ) const { + return (str != nil || m_substr == nil ) && + [str rangeOfString:m_substr].location == [str length] - [m_substr length]; + } + + virtual std::string toString() const { + return "ends with: " + Catch::toString( m_substr ); + } + }; + + } // namespace NSStringMatchers + } // namespace Impl + + inline Impl::NSStringMatchers::Equals + Equals( NSString* substr ){ return Impl::NSStringMatchers::Equals( substr ); } + + inline Impl::NSStringMatchers::Contains + Contains( NSString* substr ){ return Impl::NSStringMatchers::Contains( substr ); } + + inline Impl::NSStringMatchers::StartsWith + StartsWith( NSString* substr ){ return Impl::NSStringMatchers::StartsWith( substr ); } + + inline Impl::NSStringMatchers::EndsWith + EndsWith( NSString* substr ){ return Impl::NSStringMatchers::EndsWith( substr ); } + + } // namespace Matchers + + using namespace Matchers; + +} // namespace Catch + +/////////////////////////////////////////////////////////////////////////////// +#define OC_TEST_CASE( name, desc )\ ++(NSString*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Name_test ) \ +{\ +return @ name; \ +}\ ++(NSString*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Description_test ) \ +{ \ +return @ desc; \ +} \ +-(void) INTERNAL_CATCH_UNIQUE_NAME( Catch_TestCase_test ) + +#endif + +#ifdef CATCH_IMPL +// #included from: internal/catch_impl.hpp +#define TWOBLUECUBES_CATCH_IMPL_HPP_INCLUDED + +// Collect all the implementation files together here +// These are the equivalent of what would usually be cpp files + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wweak-vtables" +#endif + +// #included from: ../catch_session.hpp +#define TWOBLUECUBES_CATCH_RUNNER_HPP_INCLUDED + +// #included from: internal/catch_commandline.hpp +#define TWOBLUECUBES_CATCH_COMMANDLINE_HPP_INCLUDED + +// #included from: catch_config.hpp +#define TWOBLUECUBES_CATCH_CONFIG_HPP_INCLUDED + +// #included from: catch_test_spec_parser.hpp +#define TWOBLUECUBES_CATCH_TEST_SPEC_PARSER_HPP_INCLUDED + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpadded" +#endif + +// #included from: catch_test_spec.hpp +#define TWOBLUECUBES_CATCH_TEST_SPEC_HPP_INCLUDED + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpadded" +#endif + +// #included from: catch_wildcard_pattern.hpp +#define TWOBLUECUBES_CATCH_WILDCARD_PATTERN_HPP_INCLUDED + +namespace Catch +{ + class WildcardPattern { + enum WildcardPosition { + NoWildcard = 0, + WildcardAtStart = 1, + WildcardAtEnd = 2, + WildcardAtBothEnds = WildcardAtStart | WildcardAtEnd + }; + + public: + + WildcardPattern( std::string const& pattern, CaseSensitive::Choice caseSensitivity ) + : m_caseSensitivity( caseSensitivity ), + m_wildcard( NoWildcard ), + m_pattern( adjustCase( pattern ) ) + { + if( startsWith( m_pattern, "*" ) ) { + m_pattern = m_pattern.substr( 1 ); + m_wildcard = WildcardAtStart; + } + if( endsWith( m_pattern, "*" ) ) { + m_pattern = m_pattern.substr( 0, m_pattern.size()-1 ); + m_wildcard = static_cast( m_wildcard | WildcardAtEnd ); + } + } + virtual ~WildcardPattern(); + virtual bool matches( std::string const& str ) const { + switch( m_wildcard ) { + case NoWildcard: + return m_pattern == adjustCase( str ); + case WildcardAtStart: + return endsWith( adjustCase( str ), m_pattern ); + case WildcardAtEnd: + return startsWith( adjustCase( str ), m_pattern ); + case WildcardAtBothEnds: + return contains( adjustCase( str ), m_pattern ); + } + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunreachable-code" +#endif + throw std::logic_error( "Unknown enum" ); +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + } + private: + std::string adjustCase( std::string const& str ) const { + return m_caseSensitivity == CaseSensitive::No ? toLower( str ) : str; + } + CaseSensitive::Choice m_caseSensitivity; + WildcardPosition m_wildcard; + std::string m_pattern; + }; +} + +#include +#include + +namespace Catch { + + class TestSpec { + struct Pattern : SharedImpl<> { + virtual ~Pattern(); + virtual bool matches( TestCaseInfo const& testCase ) const = 0; + }; + class NamePattern : public Pattern { + public: + NamePattern( std::string const& name ) + : m_wildcardPattern( toLower( name ), CaseSensitive::No ) + {} + virtual ~NamePattern(); + virtual bool matches( TestCaseInfo const& testCase ) const { + return m_wildcardPattern.matches( toLower( testCase.name ) ); + } + private: + WildcardPattern m_wildcardPattern; + }; + + class TagPattern : public Pattern { + public: + TagPattern( std::string const& tag ) : m_tag( toLower( tag ) ) {} + virtual ~TagPattern(); + virtual bool matches( TestCaseInfo const& testCase ) const { + return testCase.lcaseTags.find( m_tag ) != testCase.lcaseTags.end(); + } + private: + std::string m_tag; + }; + + class ExcludedPattern : public Pattern { + public: + ExcludedPattern( Ptr const& underlyingPattern ) : m_underlyingPattern( underlyingPattern ) {} + virtual ~ExcludedPattern(); + virtual bool matches( TestCaseInfo const& testCase ) const { return !m_underlyingPattern->matches( testCase ); } + private: + Ptr m_underlyingPattern; + }; + + struct Filter { + std::vector > m_patterns; + + bool matches( TestCaseInfo const& testCase ) const { + // All patterns in a filter must match for the filter to be a match + for( std::vector >::const_iterator it = m_patterns.begin(), itEnd = m_patterns.end(); it != itEnd; ++it ) + if( !(*it)->matches( testCase ) ) + return false; + return true; + } + }; + + public: + bool hasFilters() const { + return !m_filters.empty(); + } + bool matches( TestCaseInfo const& testCase ) const { + // A TestSpec matches if any filter matches + for( std::vector::const_iterator it = m_filters.begin(), itEnd = m_filters.end(); it != itEnd; ++it ) + if( it->matches( testCase ) ) + return true; + return false; + } + + private: + std::vector m_filters; + + friend class TestSpecParser; + }; +} + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +namespace Catch { + + class TestSpecParser { + enum Mode{ None, Name, QuotedName, Tag }; + Mode m_mode; + bool m_exclusion; + std::size_t m_start, m_pos; + std::string m_arg; + TestSpec::Filter m_currentFilter; + TestSpec m_testSpec; + ITagAliasRegistry const* m_tagAliases; + + public: + TestSpecParser( ITagAliasRegistry const& tagAliases ) : m_tagAliases( &tagAliases ) {} + + TestSpecParser& parse( std::string const& arg ) { + m_mode = None; + m_exclusion = false; + m_start = std::string::npos; + m_arg = m_tagAliases->expandAliases( arg ); + for( m_pos = 0; m_pos < m_arg.size(); ++m_pos ) + visitChar( m_arg[m_pos] ); + if( m_mode == Name ) + addPattern(); + return *this; + } + TestSpec testSpec() { + addFilter(); + return m_testSpec; + } + private: + void visitChar( char c ) { + if( m_mode == None ) { + switch( c ) { + case ' ': return; + case '~': m_exclusion = true; return; + case '[': return startNewMode( Tag, ++m_pos ); + case '"': return startNewMode( QuotedName, ++m_pos ); + default: startNewMode( Name, m_pos ); break; + } + } + if( m_mode == Name ) { + if( c == ',' ) { + addPattern(); + addFilter(); + } + else if( c == '[' ) { + if( subString() == "exclude:" ) + m_exclusion = true; + else + addPattern(); + startNewMode( Tag, ++m_pos ); + } + } + else if( m_mode == QuotedName && c == '"' ) + addPattern(); + else if( m_mode == Tag && c == ']' ) + addPattern(); + } + void startNewMode( Mode mode, std::size_t start ) { + m_mode = mode; + m_start = start; + } + std::string subString() const { return m_arg.substr( m_start, m_pos - m_start ); } + template + void addPattern() { + std::string token = subString(); + if( startsWith( token, "exclude:" ) ) { + m_exclusion = true; + token = token.substr( 8 ); + } + if( !token.empty() ) { + Ptr pattern = new T( token ); + if( m_exclusion ) + pattern = new TestSpec::ExcludedPattern( pattern ); + m_currentFilter.m_patterns.push_back( pattern ); + } + m_exclusion = false; + m_mode = None; + } + void addFilter() { + if( !m_currentFilter.m_patterns.empty() ) { + m_testSpec.m_filters.push_back( m_currentFilter ); + m_currentFilter = TestSpec::Filter(); + } + } + }; + inline TestSpec parseTestSpec( std::string const& arg ) { + return TestSpecParser( ITagAliasRegistry::get() ).parse( arg ).testSpec(); + } + +} // namespace Catch + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +// #included from: catch_interfaces_config.h +#define TWOBLUECUBES_CATCH_INTERFACES_CONFIG_H_INCLUDED + +#include +#include +#include + +namespace Catch { + + struct Verbosity { enum Level { + NoOutput = 0, + Quiet, + Normal + }; }; + + struct WarnAbout { enum What { + Nothing = 0x00, + NoAssertions = 0x01 + }; }; + + struct ShowDurations { enum OrNot { + DefaultForReporter, + Always, + Never + }; }; + struct RunTests { enum InWhatOrder { + InDeclarationOrder, + InLexicographicalOrder, + InRandomOrder + }; }; + struct UseColour { enum YesOrNo { + Auto, + Yes, + No + }; }; + + class TestSpec; + + struct IConfig : IShared { + + virtual ~IConfig(); + + virtual bool allowThrows() const = 0; + virtual std::ostream& stream() const = 0; + virtual std::string name() const = 0; + virtual bool includeSuccessfulResults() const = 0; + virtual bool shouldDebugBreak() const = 0; + virtual bool warnAboutMissingAssertions() const = 0; + virtual int abortAfter() const = 0; + virtual bool showInvisibles() const = 0; + virtual ShowDurations::OrNot showDurations() const = 0; + virtual TestSpec const& testSpec() const = 0; + virtual RunTests::InWhatOrder runOrder() const = 0; + virtual unsigned int rngSeed() const = 0; + virtual UseColour::YesOrNo useColour() const = 0; + }; +} + +// #included from: catch_stream.h +#define TWOBLUECUBES_CATCH_STREAM_H_INCLUDED + +// #included from: catch_streambuf.h +#define TWOBLUECUBES_CATCH_STREAMBUF_H_INCLUDED + +#include + +namespace Catch { + + class StreamBufBase : public std::streambuf { + public: + virtual ~StreamBufBase() CATCH_NOEXCEPT; + }; +} + +#include +#include +#include + +namespace Catch { + + std::ostream& cout(); + std::ostream& cerr(); + + struct IStream { + virtual ~IStream() CATCH_NOEXCEPT; + virtual std::ostream& stream() const = 0; + }; + + class FileStream : public IStream { + mutable std::ofstream m_ofs; + public: + FileStream( std::string const& filename ); + virtual ~FileStream() CATCH_NOEXCEPT; + public: // IStream + virtual std::ostream& stream() const CATCH_OVERRIDE; + }; + + class CoutStream : public IStream { + mutable std::ostream m_os; + public: + CoutStream(); + virtual ~CoutStream() CATCH_NOEXCEPT; + + public: // IStream + virtual std::ostream& stream() const CATCH_OVERRIDE; + }; + + class DebugOutStream : public IStream { + std::auto_ptr m_streamBuf; + mutable std::ostream m_os; + public: + DebugOutStream(); + virtual ~DebugOutStream() CATCH_NOEXCEPT; + + public: // IStream + virtual std::ostream& stream() const CATCH_OVERRIDE; + }; +} + +#include +#include +#include +#include +#include + +#ifndef CATCH_CONFIG_CONSOLE_WIDTH +#define CATCH_CONFIG_CONSOLE_WIDTH 80 +#endif + +namespace Catch { + + struct ConfigData { + + ConfigData() + : listTests( false ), + listTags( false ), + listReporters( false ), + listTestNamesOnly( false ), + showSuccessfulTests( false ), + shouldDebugBreak( false ), + noThrow( false ), + showHelp( false ), + showInvisibles( false ), + filenamesAsTags( false ), + abortAfter( -1 ), + rngSeed( 0 ), + verbosity( Verbosity::Normal ), + warnings( WarnAbout::Nothing ), + showDurations( ShowDurations::DefaultForReporter ), + runOrder( RunTests::InDeclarationOrder ), + useColour( UseColour::Auto ) + {} + + bool listTests; + bool listTags; + bool listReporters; + bool listTestNamesOnly; + + bool showSuccessfulTests; + bool shouldDebugBreak; + bool noThrow; + bool showHelp; + bool showInvisibles; + bool filenamesAsTags; + + int abortAfter; + unsigned int rngSeed; + + Verbosity::Level verbosity; + WarnAbout::What warnings; + ShowDurations::OrNot showDurations; + RunTests::InWhatOrder runOrder; + UseColour::YesOrNo useColour; + + std::string outputFilename; + std::string name; + std::string processName; + + std::vector reporterNames; + std::vector testsOrTags; + }; + + class Config : public SharedImpl { + private: + Config( Config const& other ); + Config& operator = ( Config const& other ); + virtual void dummy(); + public: + + Config() + {} + + Config( ConfigData const& data ) + : m_data( data ), + m_stream( openStream() ) + { + if( !data.testsOrTags.empty() ) { + TestSpecParser parser( ITagAliasRegistry::get() ); + for( std::size_t i = 0; i < data.testsOrTags.size(); ++i ) + parser.parse( data.testsOrTags[i] ); + m_testSpec = parser.testSpec(); + } + } + + virtual ~Config() { + } + + std::string const& getFilename() const { + return m_data.outputFilename ; + } + + bool listTests() const { return m_data.listTests; } + bool listTestNamesOnly() const { return m_data.listTestNamesOnly; } + bool listTags() const { return m_data.listTags; } + bool listReporters() const { return m_data.listReporters; } + + std::string getProcessName() const { return m_data.processName; } + + bool shouldDebugBreak() const { return m_data.shouldDebugBreak; } + + std::vector getReporterNames() const { return m_data.reporterNames; } + + int abortAfter() const { return m_data.abortAfter; } + + TestSpec const& testSpec() const { return m_testSpec; } + + bool showHelp() const { return m_data.showHelp; } + bool showInvisibles() const { return m_data.showInvisibles; } + + // IConfig interface + virtual bool allowThrows() const { return !m_data.noThrow; } + virtual std::ostream& stream() const { return m_stream->stream(); } + virtual std::string name() const { return m_data.name.empty() ? m_data.processName : m_data.name; } + virtual bool includeSuccessfulResults() const { return m_data.showSuccessfulTests; } + virtual bool warnAboutMissingAssertions() const { return m_data.warnings & WarnAbout::NoAssertions; } + virtual ShowDurations::OrNot showDurations() const { return m_data.showDurations; } + virtual RunTests::InWhatOrder runOrder() const { return m_data.runOrder; } + virtual unsigned int rngSeed() const { return m_data.rngSeed; } + virtual UseColour::YesOrNo useColour() const { return m_data.useColour; } + + private: + + IStream const* openStream() { + if( m_data.outputFilename.empty() ) + return new CoutStream(); + else if( m_data.outputFilename[0] == '%' ) { + if( m_data.outputFilename == "%debug" ) + return new DebugOutStream(); + else + throw std::domain_error( "Unrecognised stream: " + m_data.outputFilename ); + } + else + return new FileStream( m_data.outputFilename ); + } + ConfigData m_data; + + std::auto_ptr m_stream; + TestSpec m_testSpec; + }; + +} // end namespace Catch + +// #included from: catch_clara.h +#define TWOBLUECUBES_CATCH_CLARA_H_INCLUDED + +// Use Catch's value for console width (store Clara's off to the side, if present) +#ifdef CLARA_CONFIG_CONSOLE_WIDTH +#define CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH CLARA_CONFIG_CONSOLE_WIDTH +#undef CLARA_CONFIG_CONSOLE_WIDTH +#endif +#define CLARA_CONFIG_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH + +// Declare Clara inside the Catch namespace +#define STITCH_CLARA_OPEN_NAMESPACE namespace Catch { +// #included from: ../external/clara.h + +// Version 0.0.1.1 + +// Only use header guard if we are not using an outer namespace +#if !defined(TWOBLUECUBES_CLARA_H_INCLUDED) || defined(STITCH_CLARA_OPEN_NAMESPACE) + +#ifndef STITCH_CLARA_OPEN_NAMESPACE +#define TWOBLUECUBES_CLARA_H_INCLUDED +#define STITCH_CLARA_OPEN_NAMESPACE +#define STITCH_CLARA_CLOSE_NAMESPACE +#else +#define STITCH_CLARA_CLOSE_NAMESPACE } +#endif + +#define STITCH_TBC_TEXT_FORMAT_OPEN_NAMESPACE STITCH_CLARA_OPEN_NAMESPACE + +// ----------- #included from tbc_text_format.h ----------- + +// Only use header guard if we are not using an outer namespace +#if !defined(TBC_TEXT_FORMAT_H_INCLUDED) || defined(STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE) +#ifndef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE +#define TBC_TEXT_FORMAT_H_INCLUDED +#endif + +#include +#include +#include +#include + +// Use optional outer namespace +#ifdef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE +namespace STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE { +#endif + +namespace Tbc { + +#ifdef TBC_TEXT_FORMAT_CONSOLE_WIDTH + const unsigned int consoleWidth = TBC_TEXT_FORMAT_CONSOLE_WIDTH; +#else + const unsigned int consoleWidth = 80; +#endif + + struct TextAttributes { + TextAttributes() + : initialIndent( std::string::npos ), + indent( 0 ), + width( consoleWidth-1 ), + tabChar( '\t' ) + {} + + TextAttributes& setInitialIndent( std::size_t _value ) { initialIndent = _value; return *this; } + TextAttributes& setIndent( std::size_t _value ) { indent = _value; return *this; } + TextAttributes& setWidth( std::size_t _value ) { width = _value; return *this; } + TextAttributes& setTabChar( char _value ) { tabChar = _value; return *this; } + + std::size_t initialIndent; // indent of first line, or npos + std::size_t indent; // indent of subsequent lines, or all if initialIndent is npos + std::size_t width; // maximum width of text, including indent. Longer text will wrap + char tabChar; // If this char is seen the indent is changed to current pos + }; + + class Text { + public: + Text( std::string const& _str, TextAttributes const& _attr = TextAttributes() ) + : attr( _attr ) + { + std::string wrappableChars = " [({.,/|\\-"; + std::size_t indent = _attr.initialIndent != std::string::npos + ? _attr.initialIndent + : _attr.indent; + std::string remainder = _str; + + while( !remainder.empty() ) { + if( lines.size() >= 1000 ) { + lines.push_back( "... message truncated due to excessive size" ); + return; + } + std::size_t tabPos = std::string::npos; + std::size_t width = (std::min)( remainder.size(), _attr.width - indent ); + std::size_t pos = remainder.find_first_of( '\n' ); + if( pos <= width ) { + width = pos; + } + pos = remainder.find_last_of( _attr.tabChar, width ); + if( pos != std::string::npos ) { + tabPos = pos; + if( remainder[width] == '\n' ) + width--; + remainder = remainder.substr( 0, tabPos ) + remainder.substr( tabPos+1 ); + } + + if( width == remainder.size() ) { + spliceLine( indent, remainder, width ); + } + else if( remainder[width] == '\n' ) { + spliceLine( indent, remainder, width ); + if( width <= 1 || remainder.size() != 1 ) + remainder = remainder.substr( 1 ); + indent = _attr.indent; + } + else { + pos = remainder.find_last_of( wrappableChars, width ); + if( pos != std::string::npos && pos > 0 ) { + spliceLine( indent, remainder, pos ); + if( remainder[0] == ' ' ) + remainder = remainder.substr( 1 ); + } + else { + spliceLine( indent, remainder, width-1 ); + lines.back() += "-"; + } + if( lines.size() == 1 ) + indent = _attr.indent; + if( tabPos != std::string::npos ) + indent += tabPos; + } + } + } + + void spliceLine( std::size_t _indent, std::string& _remainder, std::size_t _pos ) { + lines.push_back( std::string( _indent, ' ' ) + _remainder.substr( 0, _pos ) ); + _remainder = _remainder.substr( _pos ); + } + + typedef std::vector::const_iterator const_iterator; + + const_iterator begin() const { return lines.begin(); } + const_iterator end() const { return lines.end(); } + std::string const& last() const { return lines.back(); } + std::size_t size() const { return lines.size(); } + std::string const& operator[]( std::size_t _index ) const { return lines[_index]; } + std::string toString() const { + std::ostringstream oss; + oss << *this; + return oss.str(); + } + + inline friend std::ostream& operator << ( std::ostream& _stream, Text const& _text ) { + for( Text::const_iterator it = _text.begin(), itEnd = _text.end(); + it != itEnd; ++it ) { + if( it != _text.begin() ) + _stream << "\n"; + _stream << *it; + } + return _stream; + } + + private: + std::string str; + TextAttributes attr; + std::vector lines; + }; + +} // end namespace Tbc + +#ifdef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE +} // end outer namespace +#endif + +#endif // TBC_TEXT_FORMAT_H_INCLUDED + +// ----------- end of #include from tbc_text_format.h ----------- +// ........... back in clara.h + +#undef STITCH_TBC_TEXT_FORMAT_OPEN_NAMESPACE + +// ----------- #included from clara_compilers.h ----------- + +#ifndef TWOBLUECUBES_CLARA_COMPILERS_H_INCLUDED +#define TWOBLUECUBES_CLARA_COMPILERS_H_INCLUDED + +// Detect a number of compiler features - mostly C++11/14 conformance - by compiler +// The following features are defined: +// +// CLARA_CONFIG_CPP11_NULLPTR : is nullptr supported? +// CLARA_CONFIG_CPP11_NOEXCEPT : is noexcept supported? +// CLARA_CONFIG_CPP11_GENERATED_METHODS : The delete and default keywords for compiler generated methods +// CLARA_CONFIG_CPP11_OVERRIDE : is override supported? +// CLARA_CONFIG_CPP11_UNIQUE_PTR : is unique_ptr supported (otherwise use auto_ptr) + +// CLARA_CONFIG_CPP11_OR_GREATER : Is C++11 supported? + +// CLARA_CONFIG_VARIADIC_MACROS : are variadic macros supported? + +// In general each macro has a _NO_ form +// (e.g. CLARA_CONFIG_CPP11_NO_NULLPTR) which disables the feature. +// Many features, at point of detection, define an _INTERNAL_ macro, so they +// can be combined, en-mass, with the _NO_ forms later. + +// All the C++11 features can be disabled with CLARA_CONFIG_NO_CPP11 + +#ifdef __clang__ + +#if __has_feature(cxx_nullptr) +#define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR +#endif + +#if __has_feature(cxx_noexcept) +#define CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT +#endif + +#endif // __clang__ + +//////////////////////////////////////////////////////////////////////////////// +// GCC +#ifdef __GNUC__ + +#if __GNUC__ == 4 && __GNUC_MINOR__ >= 6 && defined(__GXX_EXPERIMENTAL_CXX0X__) +#define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR +#endif + +// - otherwise more recent versions define __cplusplus >= 201103L +// and will get picked up below + +#endif // __GNUC__ + +//////////////////////////////////////////////////////////////////////////////// +// Visual C++ +#ifdef _MSC_VER + +#if (_MSC_VER >= 1600) +#define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR +#define CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR +#endif + +#if (_MSC_VER >= 1900 ) // (VC++ 13 (VS2015)) +#define CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT +#define CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS +#endif + +#endif // _MSC_VER + +//////////////////////////////////////////////////////////////////////////////// +// C++ language feature support + +// catch all support for C++11 +#if defined(__cplusplus) && __cplusplus >= 201103L + +#define CLARA_CPP11_OR_GREATER + +#if !defined(CLARA_INTERNAL_CONFIG_CPP11_NULLPTR) +#define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR +#endif + +#ifndef CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT +#define CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT +#endif + +#ifndef CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS +#define CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS +#endif + +#if !defined(CLARA_INTERNAL_CONFIG_CPP11_OVERRIDE) +#define CLARA_INTERNAL_CONFIG_CPP11_OVERRIDE +#endif +#if !defined(CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) +#define CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR +#endif + +#endif // __cplusplus >= 201103L + +// Now set the actual defines based on the above + anything the user has configured +#if defined(CLARA_INTERNAL_CONFIG_CPP11_NULLPTR) && !defined(CLARA_CONFIG_CPP11_NO_NULLPTR) && !defined(CLARA_CONFIG_CPP11_NULLPTR) && !defined(CLARA_CONFIG_NO_CPP11) +#define CLARA_CONFIG_CPP11_NULLPTR +#endif +#if defined(CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT) && !defined(CLARA_CONFIG_CPP11_NO_NOEXCEPT) && !defined(CLARA_CONFIG_CPP11_NOEXCEPT) && !defined(CLARA_CONFIG_NO_CPP11) +#define CLARA_CONFIG_CPP11_NOEXCEPT +#endif +#if defined(CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS) && !defined(CLARA_CONFIG_CPP11_NO_GENERATED_METHODS) && !defined(CLARA_CONFIG_CPP11_GENERATED_METHODS) && !defined(CLARA_CONFIG_NO_CPP11) +#define CLARA_CONFIG_CPP11_GENERATED_METHODS +#endif +#if defined(CLARA_INTERNAL_CONFIG_CPP11_OVERRIDE) && !defined(CLARA_CONFIG_NO_OVERRIDE) && !defined(CLARA_CONFIG_CPP11_OVERRIDE) && !defined(CLARA_CONFIG_NO_CPP11) +#define CLARA_CONFIG_CPP11_OVERRIDE +#endif +#if defined(CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) && !defined(CLARA_CONFIG_NO_UNIQUE_PTR) && !defined(CLARA_CONFIG_CPP11_UNIQUE_PTR) && !defined(CLARA_CONFIG_NO_CPP11) +#define CLARA_CONFIG_CPP11_UNIQUE_PTR +#endif + +// noexcept support: +#if defined(CLARA_CONFIG_CPP11_NOEXCEPT) && !defined(CLARA_NOEXCEPT) +#define CLARA_NOEXCEPT noexcept +# define CLARA_NOEXCEPT_IS(x) noexcept(x) +#else +#define CLARA_NOEXCEPT throw() +# define CLARA_NOEXCEPT_IS(x) +#endif + +// nullptr support +#ifdef CLARA_CONFIG_CPP11_NULLPTR +#define CLARA_NULL nullptr +#else +#define CLARA_NULL NULL +#endif + +// override support +#ifdef CLARA_CONFIG_CPP11_OVERRIDE +#define CLARA_OVERRIDE override +#else +#define CLARA_OVERRIDE +#endif + +// unique_ptr support +#ifdef CLARA_CONFIG_CPP11_UNIQUE_PTR +# define CLARA_AUTO_PTR( T ) std::unique_ptr +#else +# define CLARA_AUTO_PTR( T ) std::auto_ptr +#endif + +#endif // TWOBLUECUBES_CLARA_COMPILERS_H_INCLUDED + +// ----------- end of #include from clara_compilers.h ----------- +// ........... back in clara.h + +#include +#include +#include + +// Use optional outer namespace +#ifdef STITCH_CLARA_OPEN_NAMESPACE +STITCH_CLARA_OPEN_NAMESPACE +#endif + +namespace Clara { + + struct UnpositionalTag {}; + + extern UnpositionalTag _; + +#ifdef CLARA_CONFIG_MAIN + UnpositionalTag _; +#endif + + namespace Detail { + +#ifdef CLARA_CONSOLE_WIDTH + const unsigned int consoleWidth = CLARA_CONFIG_CONSOLE_WIDTH; +#else + const unsigned int consoleWidth = 80; +#endif + + // Use this to try and stop compiler from warning about unreachable code + inline bool isTrue( bool value ) { return value; } + + using namespace Tbc; + + inline bool startsWith( std::string const& str, std::string const& prefix ) { + return str.size() >= prefix.size() && str.substr( 0, prefix.size() ) == prefix; + } + + template struct RemoveConstRef{ typedef T type; }; + template struct RemoveConstRef{ typedef T type; }; + template struct RemoveConstRef{ typedef T type; }; + template struct RemoveConstRef{ typedef T type; }; + + template struct IsBool { static const bool value = false; }; + template<> struct IsBool { static const bool value = true; }; + + template + void convertInto( std::string const& _source, T& _dest ) { + std::stringstream ss; + ss << _source; + ss >> _dest; + if( ss.fail() ) + throw std::runtime_error( "Unable to convert " + _source + " to destination type" ); + } + inline void convertInto( std::string const& _source, std::string& _dest ) { + _dest = _source; + } + inline void convertInto( std::string const& _source, bool& _dest ) { + std::string sourceLC = _source; + std::transform( sourceLC.begin(), sourceLC.end(), sourceLC.begin(), ::tolower ); + if( sourceLC == "y" || sourceLC == "1" || sourceLC == "true" || sourceLC == "yes" || sourceLC == "on" ) + _dest = true; + else if( sourceLC == "n" || sourceLC == "0" || sourceLC == "false" || sourceLC == "no" || sourceLC == "off" ) + _dest = false; + else + throw std::runtime_error( "Expected a boolean value but did not recognise:\n '" + _source + "'" ); + } + inline void convertInto( bool _source, bool& _dest ) { + _dest = _source; + } + template + inline void convertInto( bool, T& ) { + if( isTrue( true ) ) + throw std::runtime_error( "Invalid conversion" ); + } + + template + struct IArgFunction { + virtual ~IArgFunction() {} +#ifdef CLARA_CONFIG_CPP11_GENERATED_METHODS + IArgFunction() = default; + IArgFunction( IArgFunction const& ) = default; +#endif + virtual void set( ConfigT& config, std::string const& value ) const = 0; + virtual void setFlag( ConfigT& config ) const = 0; + virtual bool takesArg() const = 0; + virtual IArgFunction* clone() const = 0; + }; + + template + class BoundArgFunction { + public: + BoundArgFunction() : functionObj( CLARA_NULL ) {} + BoundArgFunction( IArgFunction* _functionObj ) : functionObj( _functionObj ) {} + BoundArgFunction( BoundArgFunction const& other ) : functionObj( other.functionObj ? other.functionObj->clone() : CLARA_NULL ) {} + BoundArgFunction& operator = ( BoundArgFunction const& other ) { + IArgFunction* newFunctionObj = other.functionObj ? other.functionObj->clone() : CLARA_NULL; + delete functionObj; + functionObj = newFunctionObj; + return *this; + } + ~BoundArgFunction() { delete functionObj; } + + void set( ConfigT& config, std::string const& value ) const { + functionObj->set( config, value ); + } + void setFlag( ConfigT& config ) const { + functionObj->setFlag( config ); + } + bool takesArg() const { return functionObj->takesArg(); } + + bool isSet() const { + return functionObj != CLARA_NULL; + } + private: + IArgFunction* functionObj; + }; + + template + struct NullBinder : IArgFunction{ + virtual void set( C&, std::string const& ) const {} + virtual void setFlag( C& ) const {} + virtual bool takesArg() const { return true; } + virtual IArgFunction* clone() const { return new NullBinder( *this ); } + }; + + template + struct BoundDataMember : IArgFunction{ + BoundDataMember( M C::* _member ) : member( _member ) {} + virtual void set( C& p, std::string const& stringValue ) const { + convertInto( stringValue, p.*member ); + } + virtual void setFlag( C& p ) const { + convertInto( true, p.*member ); + } + virtual bool takesArg() const { return !IsBool::value; } + virtual IArgFunction* clone() const { return new BoundDataMember( *this ); } + M C::* member; + }; + template + struct BoundUnaryMethod : IArgFunction{ + BoundUnaryMethod( void (C::*_member)( M ) ) : member( _member ) {} + virtual void set( C& p, std::string const& stringValue ) const { + typename RemoveConstRef::type value; + convertInto( stringValue, value ); + (p.*member)( value ); + } + virtual void setFlag( C& p ) const { + typename RemoveConstRef::type value; + convertInto( true, value ); + (p.*member)( value ); + } + virtual bool takesArg() const { return !IsBool::value; } + virtual IArgFunction* clone() const { return new BoundUnaryMethod( *this ); } + void (C::*member)( M ); + }; + template + struct BoundNullaryMethod : IArgFunction{ + BoundNullaryMethod( void (C::*_member)() ) : member( _member ) {} + virtual void set( C& p, std::string const& stringValue ) const { + bool value; + convertInto( stringValue, value ); + if( value ) + (p.*member)(); + } + virtual void setFlag( C& p ) const { + (p.*member)(); + } + virtual bool takesArg() const { return false; } + virtual IArgFunction* clone() const { return new BoundNullaryMethod( *this ); } + void (C::*member)(); + }; + + template + struct BoundUnaryFunction : IArgFunction{ + BoundUnaryFunction( void (*_function)( C& ) ) : function( _function ) {} + virtual void set( C& obj, std::string const& stringValue ) const { + bool value; + convertInto( stringValue, value ); + if( value ) + function( obj ); + } + virtual void setFlag( C& p ) const { + function( p ); + } + virtual bool takesArg() const { return false; } + virtual IArgFunction* clone() const { return new BoundUnaryFunction( *this ); } + void (*function)( C& ); + }; + + template + struct BoundBinaryFunction : IArgFunction{ + BoundBinaryFunction( void (*_function)( C&, T ) ) : function( _function ) {} + virtual void set( C& obj, std::string const& stringValue ) const { + typename RemoveConstRef::type value; + convertInto( stringValue, value ); + function( obj, value ); + } + virtual void setFlag( C& obj ) const { + typename RemoveConstRef::type value; + convertInto( true, value ); + function( obj, value ); + } + virtual bool takesArg() const { return !IsBool::value; } + virtual IArgFunction* clone() const { return new BoundBinaryFunction( *this ); } + void (*function)( C&, T ); + }; + + } // namespace Detail + + struct Parser { + Parser() : separators( " \t=:" ) {} + + struct Token { + enum Type { Positional, ShortOpt, LongOpt }; + Token( Type _type, std::string const& _data ) : type( _type ), data( _data ) {} + Type type; + std::string data; + }; + + void parseIntoTokens( int argc, char const* const argv[], std::vector& tokens ) const { + const std::string doubleDash = "--"; + for( int i = 1; i < argc && argv[i] != doubleDash; ++i ) + parseIntoTokens( argv[i] , tokens); + } + void parseIntoTokens( std::string arg, std::vector& tokens ) const { + while( !arg.empty() ) { + Parser::Token token( Parser::Token::Positional, arg ); + arg = ""; + if( token.data[0] == '-' ) { + if( token.data.size() > 1 && token.data[1] == '-' ) { + token = Parser::Token( Parser::Token::LongOpt, token.data.substr( 2 ) ); + } + else { + token = Parser::Token( Parser::Token::ShortOpt, token.data.substr( 1 ) ); + if( token.data.size() > 1 && separators.find( token.data[1] ) == std::string::npos ) { + arg = "-" + token.data.substr( 1 ); + token.data = token.data.substr( 0, 1 ); + } + } + } + if( token.type != Parser::Token::Positional ) { + std::size_t pos = token.data.find_first_of( separators ); + if( pos != std::string::npos ) { + arg = token.data.substr( pos+1 ); + token.data = token.data.substr( 0, pos ); + } + } + tokens.push_back( token ); + } + } + std::string separators; + }; + + template + struct CommonArgProperties { + CommonArgProperties() {} + CommonArgProperties( Detail::BoundArgFunction const& _boundField ) : boundField( _boundField ) {} + + Detail::BoundArgFunction boundField; + std::string description; + std::string detail; + std::string placeholder; // Only value if boundField takes an arg + + bool takesArg() const { + return !placeholder.empty(); + } + void validate() const { + if( !boundField.isSet() ) + throw std::logic_error( "option not bound" ); + } + }; + struct OptionArgProperties { + std::vector shortNames; + std::string longName; + + bool hasShortName( std::string const& shortName ) const { + return std::find( shortNames.begin(), shortNames.end(), shortName ) != shortNames.end(); + } + bool hasLongName( std::string const& _longName ) const { + return _longName == longName; + } + }; + struct PositionalArgProperties { + PositionalArgProperties() : position( -1 ) {} + int position; // -1 means non-positional (floating) + + bool isFixedPositional() const { + return position != -1; + } + }; + + template + class CommandLine { + + struct Arg : CommonArgProperties, OptionArgProperties, PositionalArgProperties { + Arg() {} + Arg( Detail::BoundArgFunction const& _boundField ) : CommonArgProperties( _boundField ) {} + + using CommonArgProperties::placeholder; // !TBD + + std::string dbgName() const { + if( !longName.empty() ) + return "--" + longName; + if( !shortNames.empty() ) + return "-" + shortNames[0]; + return "positional args"; + } + std::string commands() const { + std::ostringstream oss; + bool first = true; + std::vector::const_iterator it = shortNames.begin(), itEnd = shortNames.end(); + for(; it != itEnd; ++it ) { + if( first ) + first = false; + else + oss << ", "; + oss << "-" << *it; + } + if( !longName.empty() ) { + if( !first ) + oss << ", "; + oss << "--" << longName; + } + if( !placeholder.empty() ) + oss << " <" << placeholder << ">"; + return oss.str(); + } + }; + + typedef CLARA_AUTO_PTR( Arg ) ArgAutoPtr; + + friend void addOptName( Arg& arg, std::string const& optName ) + { + if( optName.empty() ) + return; + if( Detail::startsWith( optName, "--" ) ) { + if( !arg.longName.empty() ) + throw std::logic_error( "Only one long opt may be specified. '" + + arg.longName + + "' already specified, now attempting to add '" + + optName + "'" ); + arg.longName = optName.substr( 2 ); + } + else if( Detail::startsWith( optName, "-" ) ) + arg.shortNames.push_back( optName.substr( 1 ) ); + else + throw std::logic_error( "option must begin with - or --. Option was: '" + optName + "'" ); + } + friend void setPositionalArg( Arg& arg, int position ) + { + arg.position = position; + } + + class ArgBuilder { + public: + ArgBuilder( Arg* arg ) : m_arg( arg ) {} + + // Bind a non-boolean data member (requires placeholder string) + template + void bind( M C::* field, std::string const& placeholder ) { + m_arg->boundField = new Detail::BoundDataMember( field ); + m_arg->placeholder = placeholder; + } + // Bind a boolean data member (no placeholder required) + template + void bind( bool C::* field ) { + m_arg->boundField = new Detail::BoundDataMember( field ); + } + + // Bind a method taking a single, non-boolean argument (requires a placeholder string) + template + void bind( void (C::* unaryMethod)( M ), std::string const& placeholder ) { + m_arg->boundField = new Detail::BoundUnaryMethod( unaryMethod ); + m_arg->placeholder = placeholder; + } + + // Bind a method taking a single, boolean argument (no placeholder string required) + template + void bind( void (C::* unaryMethod)( bool ) ) { + m_arg->boundField = new Detail::BoundUnaryMethod( unaryMethod ); + } + + // Bind a method that takes no arguments (will be called if opt is present) + template + void bind( void (C::* nullaryMethod)() ) { + m_arg->boundField = new Detail::BoundNullaryMethod( nullaryMethod ); + } + + // Bind a free function taking a single argument - the object to operate on (no placeholder string required) + template + void bind( void (* unaryFunction)( C& ) ) { + m_arg->boundField = new Detail::BoundUnaryFunction( unaryFunction ); + } + + // Bind a free function taking a single argument - the object to operate on (requires a placeholder string) + template + void bind( void (* binaryFunction)( C&, T ), std::string const& placeholder ) { + m_arg->boundField = new Detail::BoundBinaryFunction( binaryFunction ); + m_arg->placeholder = placeholder; + } + + ArgBuilder& describe( std::string const& description ) { + m_arg->description = description; + return *this; + } + ArgBuilder& detail( std::string const& detail ) { + m_arg->detail = detail; + return *this; + } + + protected: + Arg* m_arg; + }; + + class OptBuilder : public ArgBuilder { + public: + OptBuilder( Arg* arg ) : ArgBuilder( arg ) {} + OptBuilder( OptBuilder& other ) : ArgBuilder( other ) {} + + OptBuilder& operator[]( std::string const& optName ) { + addOptName( *ArgBuilder::m_arg, optName ); + return *this; + } + }; + + public: + + CommandLine() + : m_boundProcessName( new Detail::NullBinder() ), + m_highestSpecifiedArgPosition( 0 ), + m_throwOnUnrecognisedTokens( false ) + {} + CommandLine( CommandLine const& other ) + : m_boundProcessName( other.m_boundProcessName ), + m_options ( other.m_options ), + m_positionalArgs( other.m_positionalArgs ), + m_highestSpecifiedArgPosition( other.m_highestSpecifiedArgPosition ), + m_throwOnUnrecognisedTokens( other.m_throwOnUnrecognisedTokens ) + { + if( other.m_floatingArg.get() ) + m_floatingArg.reset( new Arg( *other.m_floatingArg ) ); + } + + CommandLine& setThrowOnUnrecognisedTokens( bool shouldThrow = true ) { + m_throwOnUnrecognisedTokens = shouldThrow; + return *this; + } + + OptBuilder operator[]( std::string const& optName ) { + m_options.push_back( Arg() ); + addOptName( m_options.back(), optName ); + OptBuilder builder( &m_options.back() ); + return builder; + } + + ArgBuilder operator[]( int position ) { + m_positionalArgs.insert( std::make_pair( position, Arg() ) ); + if( position > m_highestSpecifiedArgPosition ) + m_highestSpecifiedArgPosition = position; + setPositionalArg( m_positionalArgs[position], position ); + ArgBuilder builder( &m_positionalArgs[position] ); + return builder; + } + + // Invoke this with the _ instance + ArgBuilder operator[]( UnpositionalTag ) { + if( m_floatingArg.get() ) + throw std::logic_error( "Only one unpositional argument can be added" ); + m_floatingArg.reset( new Arg() ); + ArgBuilder builder( m_floatingArg.get() ); + return builder; + } + + template + void bindProcessName( M C::* field ) { + m_boundProcessName = new Detail::BoundDataMember( field ); + } + template + void bindProcessName( void (C::*_unaryMethod)( M ) ) { + m_boundProcessName = new Detail::BoundUnaryMethod( _unaryMethod ); + } + + void optUsage( std::ostream& os, std::size_t indent = 0, std::size_t width = Detail::consoleWidth ) const { + typename std::vector::const_iterator itBegin = m_options.begin(), itEnd = m_options.end(), it; + std::size_t maxWidth = 0; + for( it = itBegin; it != itEnd; ++it ) + maxWidth = (std::max)( maxWidth, it->commands().size() ); + + for( it = itBegin; it != itEnd; ++it ) { + Detail::Text usage( it->commands(), Detail::TextAttributes() + .setWidth( maxWidth+indent ) + .setIndent( indent ) ); + Detail::Text desc( it->description, Detail::TextAttributes() + .setWidth( width - maxWidth - 3 ) ); + + for( std::size_t i = 0; i < (std::max)( usage.size(), desc.size() ); ++i ) { + std::string usageCol = i < usage.size() ? usage[i] : ""; + os << usageCol; + + if( i < desc.size() && !desc[i].empty() ) + os << std::string( indent + 2 + maxWidth - usageCol.size(), ' ' ) + << desc[i]; + os << "\n"; + } + } + } + std::string optUsage() const { + std::ostringstream oss; + optUsage( oss ); + return oss.str(); + } + + void argSynopsis( std::ostream& os ) const { + for( int i = 1; i <= m_highestSpecifiedArgPosition; ++i ) { + if( i > 1 ) + os << " "; + typename std::map::const_iterator it = m_positionalArgs.find( i ); + if( it != m_positionalArgs.end() ) + os << "<" << it->second.placeholder << ">"; + else if( m_floatingArg.get() ) + os << "<" << m_floatingArg->placeholder << ">"; + else + throw std::logic_error( "non consecutive positional arguments with no floating args" ); + } + // !TBD No indication of mandatory args + if( m_floatingArg.get() ) { + if( m_highestSpecifiedArgPosition > 1 ) + os << " "; + os << "[<" << m_floatingArg->placeholder << "> ...]"; + } + } + std::string argSynopsis() const { + std::ostringstream oss; + argSynopsis( oss ); + return oss.str(); + } + + void usage( std::ostream& os, std::string const& procName ) const { + validate(); + os << "usage:\n " << procName << " "; + argSynopsis( os ); + if( !m_options.empty() ) { + os << " [options]\n\nwhere options are: \n"; + optUsage( os, 2 ); + } + os << "\n"; + } + std::string usage( std::string const& procName ) const { + std::ostringstream oss; + usage( oss, procName ); + return oss.str(); + } + + ConfigT parse( int argc, char const* const argv[] ) const { + ConfigT config; + parseInto( argc, argv, config ); + return config; + } + + std::vector parseInto( int argc, char const* argv[], ConfigT& config ) const { + std::string processName = argv[0]; + std::size_t lastSlash = processName.find_last_of( "/\\" ); + if( lastSlash != std::string::npos ) + processName = processName.substr( lastSlash+1 ); + m_boundProcessName.set( config, processName ); + std::vector tokens; + Parser parser; + parser.parseIntoTokens( argc, argv, tokens ); + return populate( tokens, config ); + } + + std::vector populate( std::vector const& tokens, ConfigT& config ) const { + validate(); + std::vector unusedTokens = populateOptions( tokens, config ); + unusedTokens = populateFixedArgs( unusedTokens, config ); + unusedTokens = populateFloatingArgs( unusedTokens, config ); + return unusedTokens; + } + + std::vector populateOptions( std::vector const& tokens, ConfigT& config ) const { + std::vector unusedTokens; + std::vector errors; + for( std::size_t i = 0; i < tokens.size(); ++i ) { + Parser::Token const& token = tokens[i]; + typename std::vector::const_iterator it = m_options.begin(), itEnd = m_options.end(); + for(; it != itEnd; ++it ) { + Arg const& arg = *it; + + try { + if( ( token.type == Parser::Token::ShortOpt && arg.hasShortName( token.data ) ) || + ( token.type == Parser::Token::LongOpt && arg.hasLongName( token.data ) ) ) { + if( arg.takesArg() ) { + if( i == tokens.size()-1 || tokens[i+1].type != Parser::Token::Positional ) + errors.push_back( "Expected argument to option: " + token.data ); + else + arg.boundField.set( config, tokens[++i].data ); + } + else { + arg.boundField.setFlag( config ); + } + break; + } + } + catch( std::exception& ex ) { + errors.push_back( std::string( ex.what() ) + "\n- while parsing: (" + arg.commands() + ")" ); + } + } + if( it == itEnd ) { + if( token.type == Parser::Token::Positional || !m_throwOnUnrecognisedTokens ) + unusedTokens.push_back( token ); + else if( errors.empty() && m_throwOnUnrecognisedTokens ) + errors.push_back( "unrecognised option: " + token.data ); + } + } + if( !errors.empty() ) { + std::ostringstream oss; + for( std::vector::const_iterator it = errors.begin(), itEnd = errors.end(); + it != itEnd; + ++it ) { + if( it != errors.begin() ) + oss << "\n"; + oss << *it; + } + throw std::runtime_error( oss.str() ); + } + return unusedTokens; + } + std::vector populateFixedArgs( std::vector const& tokens, ConfigT& config ) const { + std::vector unusedTokens; + int position = 1; + for( std::size_t i = 0; i < tokens.size(); ++i ) { + Parser::Token const& token = tokens[i]; + typename std::map::const_iterator it = m_positionalArgs.find( position ); + if( it != m_positionalArgs.end() ) + it->second.boundField.set( config, token.data ); + else + unusedTokens.push_back( token ); + if( token.type == Parser::Token::Positional ) + position++; + } + return unusedTokens; + } + std::vector populateFloatingArgs( std::vector const& tokens, ConfigT& config ) const { + if( !m_floatingArg.get() ) + return tokens; + std::vector unusedTokens; + for( std::size_t i = 0; i < tokens.size(); ++i ) { + Parser::Token const& token = tokens[i]; + if( token.type == Parser::Token::Positional ) + m_floatingArg->boundField.set( config, token.data ); + else + unusedTokens.push_back( token ); + } + return unusedTokens; + } + + void validate() const + { + if( m_options.empty() && m_positionalArgs.empty() && !m_floatingArg.get() ) + throw std::logic_error( "No options or arguments specified" ); + + for( typename std::vector::const_iterator it = m_options.begin(), + itEnd = m_options.end(); + it != itEnd; ++it ) + it->validate(); + } + + private: + Detail::BoundArgFunction m_boundProcessName; + std::vector m_options; + std::map m_positionalArgs; + ArgAutoPtr m_floatingArg; + int m_highestSpecifiedArgPosition; + bool m_throwOnUnrecognisedTokens; + }; + +} // end namespace Clara + +STITCH_CLARA_CLOSE_NAMESPACE +#undef STITCH_CLARA_OPEN_NAMESPACE +#undef STITCH_CLARA_CLOSE_NAMESPACE + +#endif // TWOBLUECUBES_CLARA_H_INCLUDED +#undef STITCH_CLARA_OPEN_NAMESPACE + +// Restore Clara's value for console width, if present +#ifdef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH +#define CLARA_CONFIG_CONSOLE_WIDTH CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH +#undef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH +#endif + +#include + +namespace Catch { + + inline void abortAfterFirst( ConfigData& config ) { config.abortAfter = 1; } + inline void abortAfterX( ConfigData& config, int x ) { + if( x < 1 ) + throw std::runtime_error( "Value after -x or --abortAfter must be greater than zero" ); + config.abortAfter = x; + } + inline void addTestOrTags( ConfigData& config, std::string const& _testSpec ) { config.testsOrTags.push_back( _testSpec ); } + inline void addReporterName( ConfigData& config, std::string const& _reporterName ) { config.reporterNames.push_back( _reporterName ); } + + inline void addWarning( ConfigData& config, std::string const& _warning ) { + if( _warning == "NoAssertions" ) + config.warnings = static_cast( config.warnings | WarnAbout::NoAssertions ); + else + throw std::runtime_error( "Unrecognised warning: '" + _warning + "'" ); + } + inline void setOrder( ConfigData& config, std::string const& order ) { + if( startsWith( "declared", order ) ) + config.runOrder = RunTests::InDeclarationOrder; + else if( startsWith( "lexical", order ) ) + config.runOrder = RunTests::InLexicographicalOrder; + else if( startsWith( "random", order ) ) + config.runOrder = RunTests::InRandomOrder; + else + throw std::runtime_error( "Unrecognised ordering: '" + order + "'" ); + } + inline void setRngSeed( ConfigData& config, std::string const& seed ) { + if( seed == "time" ) { + config.rngSeed = static_cast( std::time(0) ); + } + else { + std::stringstream ss; + ss << seed; + ss >> config.rngSeed; + if( ss.fail() ) + throw std::runtime_error( "Argment to --rng-seed should be the word 'time' or a number" ); + } + } + inline void setVerbosity( ConfigData& config, int level ) { + // !TBD: accept strings? + config.verbosity = static_cast( level ); + } + inline void setShowDurations( ConfigData& config, bool _showDurations ) { + config.showDurations = _showDurations + ? ShowDurations::Always + : ShowDurations::Never; + } + inline void setUseColour( ConfigData& config, std::string const& value ) { + std::string mode = toLower( value ); + + if( mode == "yes" ) + config.useColour = UseColour::Yes; + else if( mode == "no" ) + config.useColour = UseColour::No; + else if( mode == "auto" ) + config.useColour = UseColour::Auto; + else + throw std::runtime_error( "colour mode must be one of: auto, yes or no" ); + } + inline void forceColour( ConfigData& config ) { + config.useColour = UseColour::Yes; + } + inline void loadTestNamesFromFile( ConfigData& config, std::string const& _filename ) { + std::ifstream f( _filename.c_str() ); + if( !f.is_open() ) + throw std::domain_error( "Unable to load input file: " + _filename ); + + std::string line; + while( std::getline( f, line ) ) { + line = trim(line); + if( !line.empty() && !startsWith( line, "#" ) ) + addTestOrTags( config, "\"" + line + "\"," ); + } + } + + inline Clara::CommandLine makeCommandLineParser() { + + using namespace Clara; + CommandLine cli; + + cli.bindProcessName( &ConfigData::processName ); + + cli["-?"]["-h"]["--help"] + .describe( "display usage information" ) + .bind( &ConfigData::showHelp ); + + cli["-l"]["--list-tests"] + .describe( "list all/matching test cases" ) + .bind( &ConfigData::listTests ); + + cli["-t"]["--list-tags"] + .describe( "list all/matching tags" ) + .bind( &ConfigData::listTags ); + + cli["-s"]["--success"] + .describe( "include successful tests in output" ) + .bind( &ConfigData::showSuccessfulTests ); + + cli["-b"]["--break"] + .describe( "break into debugger on failure" ) + .bind( &ConfigData::shouldDebugBreak ); + + cli["-e"]["--nothrow"] + .describe( "skip exception tests" ) + .bind( &ConfigData::noThrow ); + + cli["-i"]["--invisibles"] + .describe( "show invisibles (tabs, newlines)" ) + .bind( &ConfigData::showInvisibles ); + + cli["-o"]["--out"] + .describe( "output filename" ) + .bind( &ConfigData::outputFilename, "filename" ); + + cli["-r"]["--reporter"] +// .placeholder( "name[:filename]" ) + .describe( "reporter to use (defaults to console)" ) + .bind( &addReporterName, "name" ); + + cli["-n"]["--name"] + .describe( "suite name" ) + .bind( &ConfigData::name, "name" ); + + cli["-a"]["--abort"] + .describe( "abort at first failure" ) + .bind( &abortAfterFirst ); + + cli["-x"]["--abortx"] + .describe( "abort after x failures" ) + .bind( &abortAfterX, "no. failures" ); + + cli["-w"]["--warn"] + .describe( "enable warnings" ) + .bind( &addWarning, "warning name" ); + +// - needs updating if reinstated +// cli.into( &setVerbosity ) +// .describe( "level of verbosity (0=no output)" ) +// .shortOpt( "v") +// .longOpt( "verbosity" ) +// .placeholder( "level" ); + + cli[_] + .describe( "which test or tests to use" ) + .bind( &addTestOrTags, "test name, pattern or tags" ); + + cli["-d"]["--durations"] + .describe( "show test durations" ) + .bind( &setShowDurations, "yes|no" ); + + cli["-f"]["--input-file"] + .describe( "load test names to run from a file" ) + .bind( &loadTestNamesFromFile, "filename" ); + + cli["-#"]["--filenames-as-tags"] + .describe( "adds a tag for the filename" ) + .bind( &ConfigData::filenamesAsTags ); + + // Less common commands which don't have a short form + cli["--list-test-names-only"] + .describe( "list all/matching test cases names only" ) + .bind( &ConfigData::listTestNamesOnly ); + + cli["--list-reporters"] + .describe( "list all reporters" ) + .bind( &ConfigData::listReporters ); + + cli["--order"] + .describe( "test case order (defaults to decl)" ) + .bind( &setOrder, "decl|lex|rand" ); + + cli["--rng-seed"] + .describe( "set a specific seed for random numbers" ) + .bind( &setRngSeed, "'time'|number" ); + + cli["--force-colour"] + .describe( "force colourised output (deprecated)" ) + .bind( &forceColour ); + + cli["--use-colour"] + .describe( "should output be colourised" ) + .bind( &setUseColour, "yes|no" ); + + return cli; + } + +} // end namespace Catch + +// #included from: internal/catch_list.hpp +#define TWOBLUECUBES_CATCH_LIST_HPP_INCLUDED + +// #included from: catch_text.h +#define TWOBLUECUBES_CATCH_TEXT_H_INCLUDED + +#define TBC_TEXT_FORMAT_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH + +#define CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE Catch +// #included from: ../external/tbc_text_format.h +// Only use header guard if we are not using an outer namespace +#ifndef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE +# ifdef TWOBLUECUBES_TEXT_FORMAT_H_INCLUDED +# ifndef TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED +# define TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED +# endif +# else +# define TWOBLUECUBES_TEXT_FORMAT_H_INCLUDED +# endif +#endif +#ifndef TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED +#include +#include +#include + +// Use optional outer namespace +#ifdef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE +namespace CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE { +#endif + +namespace Tbc { + +#ifdef TBC_TEXT_FORMAT_CONSOLE_WIDTH + const unsigned int consoleWidth = TBC_TEXT_FORMAT_CONSOLE_WIDTH; +#else + const unsigned int consoleWidth = 80; +#endif + + struct TextAttributes { + TextAttributes() + : initialIndent( std::string::npos ), + indent( 0 ), + width( consoleWidth-1 ), + tabChar( '\t' ) + {} + + TextAttributes& setInitialIndent( std::size_t _value ) { initialIndent = _value; return *this; } + TextAttributes& setIndent( std::size_t _value ) { indent = _value; return *this; } + TextAttributes& setWidth( std::size_t _value ) { width = _value; return *this; } + TextAttributes& setTabChar( char _value ) { tabChar = _value; return *this; } + + std::size_t initialIndent; // indent of first line, or npos + std::size_t indent; // indent of subsequent lines, or all if initialIndent is npos + std::size_t width; // maximum width of text, including indent. Longer text will wrap + char tabChar; // If this char is seen the indent is changed to current pos + }; + + class Text { + public: + Text( std::string const& _str, TextAttributes const& _attr = TextAttributes() ) + : attr( _attr ) + { + std::string wrappableChars = " [({.,/|\\-"; + std::size_t indent = _attr.initialIndent != std::string::npos + ? _attr.initialIndent + : _attr.indent; + std::string remainder = _str; + + while( !remainder.empty() ) { + if( lines.size() >= 1000 ) { + lines.push_back( "... message truncated due to excessive size" ); + return; + } + std::size_t tabPos = std::string::npos; + std::size_t width = (std::min)( remainder.size(), _attr.width - indent ); + std::size_t pos = remainder.find_first_of( '\n' ); + if( pos <= width ) { + width = pos; + } + pos = remainder.find_last_of( _attr.tabChar, width ); + if( pos != std::string::npos ) { + tabPos = pos; + if( remainder[width] == '\n' ) + width--; + remainder = remainder.substr( 0, tabPos ) + remainder.substr( tabPos+1 ); + } + + if( width == remainder.size() ) { + spliceLine( indent, remainder, width ); + } + else if( remainder[width] == '\n' ) { + spliceLine( indent, remainder, width ); + if( width <= 1 || remainder.size() != 1 ) + remainder = remainder.substr( 1 ); + indent = _attr.indent; + } + else { + pos = remainder.find_last_of( wrappableChars, width ); + if( pos != std::string::npos && pos > 0 ) { + spliceLine( indent, remainder, pos ); + if( remainder[0] == ' ' ) + remainder = remainder.substr( 1 ); + } + else { + spliceLine( indent, remainder, width-1 ); + lines.back() += "-"; + } + if( lines.size() == 1 ) + indent = _attr.indent; + if( tabPos != std::string::npos ) + indent += tabPos; + } + } + } + + void spliceLine( std::size_t _indent, std::string& _remainder, std::size_t _pos ) { + lines.push_back( std::string( _indent, ' ' ) + _remainder.substr( 0, _pos ) ); + _remainder = _remainder.substr( _pos ); + } + + typedef std::vector::const_iterator const_iterator; + + const_iterator begin() const { return lines.begin(); } + const_iterator end() const { return lines.end(); } + std::string const& last() const { return lines.back(); } + std::size_t size() const { return lines.size(); } + std::string const& operator[]( std::size_t _index ) const { return lines[_index]; } + std::string toString() const { + std::ostringstream oss; + oss << *this; + return oss.str(); + } + + inline friend std::ostream& operator << ( std::ostream& _stream, Text const& _text ) { + for( Text::const_iterator it = _text.begin(), itEnd = _text.end(); + it != itEnd; ++it ) { + if( it != _text.begin() ) + _stream << "\n"; + _stream << *it; + } + return _stream; + } + + private: + std::string str; + TextAttributes attr; + std::vector lines; + }; + +} // end namespace Tbc + +#ifdef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE +} // end outer namespace +#endif + +#endif // TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED +#undef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE + +namespace Catch { + using Tbc::Text; + using Tbc::TextAttributes; +} + +// #included from: catch_console_colour.hpp +#define TWOBLUECUBES_CATCH_CONSOLE_COLOUR_HPP_INCLUDED + +namespace Catch { + + struct Colour { + enum Code { + None = 0, + + White, + Red, + Green, + Blue, + Cyan, + Yellow, + Grey, + + Bright = 0x10, + + BrightRed = Bright | Red, + BrightGreen = Bright | Green, + LightGrey = Bright | Grey, + BrightWhite = Bright | White, + + // By intention + FileName = LightGrey, + Warning = Yellow, + ResultError = BrightRed, + ResultSuccess = BrightGreen, + ResultExpectedFailure = Warning, + + Error = BrightRed, + Success = Green, + + OriginalExpression = Cyan, + ReconstructedExpression = Yellow, + + SecondaryText = LightGrey, + Headers = White + }; + + // Use constructed object for RAII guard + Colour( Code _colourCode ); + Colour( Colour const& other ); + ~Colour(); + + // Use static method for one-shot changes + static void use( Code _colourCode ); + + private: + bool m_moved; + }; + + inline std::ostream& operator << ( std::ostream& os, Colour const& ) { return os; } + +} // end namespace Catch + +// #included from: catch_interfaces_reporter.h +#define TWOBLUECUBES_CATCH_INTERFACES_REPORTER_H_INCLUDED + +#include +#include +#include +#include + +namespace Catch +{ + struct ReporterConfig { + explicit ReporterConfig( Ptr const& _fullConfig ) + : m_stream( &_fullConfig->stream() ), m_fullConfig( _fullConfig ) {} + + ReporterConfig( Ptr const& _fullConfig, std::ostream& _stream ) + : m_stream( &_stream ), m_fullConfig( _fullConfig ) {} + + std::ostream& stream() const { return *m_stream; } + Ptr fullConfig() const { return m_fullConfig; } + + private: + std::ostream* m_stream; + Ptr m_fullConfig; + }; + + struct ReporterPreferences { + ReporterPreferences() + : shouldRedirectStdOut( false ) + {} + + bool shouldRedirectStdOut; + }; + + template + struct LazyStat : Option { + LazyStat() : used( false ) {} + LazyStat& operator=( T const& _value ) { + Option::operator=( _value ); + used = false; + return *this; + } + void reset() { + Option::reset(); + used = false; + } + bool used; + }; + + struct TestRunInfo { + TestRunInfo( std::string const& _name ) : name( _name ) {} + std::string name; + }; + struct GroupInfo { + GroupInfo( std::string const& _name, + std::size_t _groupIndex, + std::size_t _groupsCount ) + : name( _name ), + groupIndex( _groupIndex ), + groupsCounts( _groupsCount ) + {} + + std::string name; + std::size_t groupIndex; + std::size_t groupsCounts; + }; + + struct AssertionStats { + AssertionStats( AssertionResult const& _assertionResult, + std::vector const& _infoMessages, + Totals const& _totals ) + : assertionResult( _assertionResult ), + infoMessages( _infoMessages ), + totals( _totals ) + { + if( assertionResult.hasMessage() ) { + // Copy message into messages list. + // !TBD This should have been done earlier, somewhere + MessageBuilder builder( assertionResult.getTestMacroName(), assertionResult.getSourceInfo(), assertionResult.getResultType() ); + builder << assertionResult.getMessage(); + builder.m_info.message = builder.m_stream.str(); + + infoMessages.push_back( builder.m_info ); + } + } + virtual ~AssertionStats(); + +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + AssertionStats( AssertionStats const& ) = default; + AssertionStats( AssertionStats && ) = default; + AssertionStats& operator = ( AssertionStats const& ) = default; + AssertionStats& operator = ( AssertionStats && ) = default; +# endif + + AssertionResult assertionResult; + std::vector infoMessages; + Totals totals; + }; + + struct SectionStats { + SectionStats( SectionInfo const& _sectionInfo, + Counts const& _assertions, + double _durationInSeconds, + bool _missingAssertions ) + : sectionInfo( _sectionInfo ), + assertions( _assertions ), + durationInSeconds( _durationInSeconds ), + missingAssertions( _missingAssertions ) + {} + virtual ~SectionStats(); +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + SectionStats( SectionStats const& ) = default; + SectionStats( SectionStats && ) = default; + SectionStats& operator = ( SectionStats const& ) = default; + SectionStats& operator = ( SectionStats && ) = default; +# endif + + SectionInfo sectionInfo; + Counts assertions; + double durationInSeconds; + bool missingAssertions; + }; + + struct TestCaseStats { + TestCaseStats( TestCaseInfo const& _testInfo, + Totals const& _totals, + std::string const& _stdOut, + std::string const& _stdErr, + bool _aborting ) + : testInfo( _testInfo ), + totals( _totals ), + stdOut( _stdOut ), + stdErr( _stdErr ), + aborting( _aborting ) + {} + virtual ~TestCaseStats(); + +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + TestCaseStats( TestCaseStats const& ) = default; + TestCaseStats( TestCaseStats && ) = default; + TestCaseStats& operator = ( TestCaseStats const& ) = default; + TestCaseStats& operator = ( TestCaseStats && ) = default; +# endif + + TestCaseInfo testInfo; + Totals totals; + std::string stdOut; + std::string stdErr; + bool aborting; + }; + + struct TestGroupStats { + TestGroupStats( GroupInfo const& _groupInfo, + Totals const& _totals, + bool _aborting ) + : groupInfo( _groupInfo ), + totals( _totals ), + aborting( _aborting ) + {} + TestGroupStats( GroupInfo const& _groupInfo ) + : groupInfo( _groupInfo ), + aborting( false ) + {} + virtual ~TestGroupStats(); + +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + TestGroupStats( TestGroupStats const& ) = default; + TestGroupStats( TestGroupStats && ) = default; + TestGroupStats& operator = ( TestGroupStats const& ) = default; + TestGroupStats& operator = ( TestGroupStats && ) = default; +# endif + + GroupInfo groupInfo; + Totals totals; + bool aborting; + }; + + struct TestRunStats { + TestRunStats( TestRunInfo const& _runInfo, + Totals const& _totals, + bool _aborting ) + : runInfo( _runInfo ), + totals( _totals ), + aborting( _aborting ) + {} + virtual ~TestRunStats(); + +# ifndef CATCH_CONFIG_CPP11_GENERATED_METHODS + TestRunStats( TestRunStats const& _other ) + : runInfo( _other.runInfo ), + totals( _other.totals ), + aborting( _other.aborting ) + {} +# else + TestRunStats( TestRunStats const& ) = default; + TestRunStats( TestRunStats && ) = default; + TestRunStats& operator = ( TestRunStats const& ) = default; + TestRunStats& operator = ( TestRunStats && ) = default; +# endif + + TestRunInfo runInfo; + Totals totals; + bool aborting; + }; + + struct IStreamingReporter : IShared { + virtual ~IStreamingReporter(); + + // Implementing class must also provide the following static method: + // static std::string getDescription(); + + virtual ReporterPreferences getPreferences() const = 0; + + virtual void noMatchingTestCases( std::string const& spec ) = 0; + + virtual void testRunStarting( TestRunInfo const& testRunInfo ) = 0; + virtual void testGroupStarting( GroupInfo const& groupInfo ) = 0; + + virtual void testCaseStarting( TestCaseInfo const& testInfo ) = 0; + virtual void sectionStarting( SectionInfo const& sectionInfo ) = 0; + + virtual void assertionStarting( AssertionInfo const& assertionInfo ) = 0; + + // The return value indicates if the messages buffer should be cleared: + virtual bool assertionEnded( AssertionStats const& assertionStats ) = 0; + + virtual void sectionEnded( SectionStats const& sectionStats ) = 0; + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) = 0; + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) = 0; + virtual void testRunEnded( TestRunStats const& testRunStats ) = 0; + + virtual void skipTest( TestCaseInfo const& testInfo ) = 0; + }; + + struct IReporterFactory : IShared { + virtual ~IReporterFactory(); + virtual IStreamingReporter* create( ReporterConfig const& config ) const = 0; + virtual std::string getDescription() const = 0; + }; + + struct IReporterRegistry { + typedef std::map > FactoryMap; + typedef std::vector > Listeners; + + virtual ~IReporterRegistry(); + virtual IStreamingReporter* create( std::string const& name, Ptr const& config ) const = 0; + virtual FactoryMap const& getFactories() const = 0; + virtual Listeners const& getListeners() const = 0; + }; + + Ptr addReporter( Ptr const& existingReporter, Ptr const& additionalReporter ); + +} + +#include +#include + +namespace Catch { + + inline std::size_t listTests( Config const& config ) { + + TestSpec testSpec = config.testSpec(); + if( config.testSpec().hasFilters() ) + Catch::cout() << "Matching test cases:\n"; + else { + Catch::cout() << "All available test cases:\n"; + testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); + } + + std::size_t matchedTests = 0; + TextAttributes nameAttr, tagsAttr; + nameAttr.setInitialIndent( 2 ).setIndent( 4 ); + tagsAttr.setIndent( 6 ); + + std::vector matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); + for( std::vector::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); + it != itEnd; + ++it ) { + matchedTests++; + TestCaseInfo const& testCaseInfo = it->getTestCaseInfo(); + Colour::Code colour = testCaseInfo.isHidden() + ? Colour::SecondaryText + : Colour::None; + Colour colourGuard( colour ); + + Catch::cout() << Text( testCaseInfo.name, nameAttr ) << std::endl; + if( !testCaseInfo.tags.empty() ) + Catch::cout() << Text( testCaseInfo.tagsAsString, tagsAttr ) << std::endl; + } + + if( !config.testSpec().hasFilters() ) + Catch::cout() << pluralise( matchedTests, "test case" ) << "\n" << std::endl; + else + Catch::cout() << pluralise( matchedTests, "matching test case" ) << "\n" << std::endl; + return matchedTests; + } + + inline std::size_t listTestsNamesOnly( Config const& config ) { + TestSpec testSpec = config.testSpec(); + if( !config.testSpec().hasFilters() ) + testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); + std::size_t matchedTests = 0; + std::vector matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); + for( std::vector::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); + it != itEnd; + ++it ) { + matchedTests++; + TestCaseInfo const& testCaseInfo = it->getTestCaseInfo(); + Catch::cout() << testCaseInfo.name << std::endl; + } + return matchedTests; + } + + struct TagInfo { + TagInfo() : count ( 0 ) {} + void add( std::string const& spelling ) { + ++count; + spellings.insert( spelling ); + } + std::string all() const { + std::string out; + for( std::set::const_iterator it = spellings.begin(), itEnd = spellings.end(); + it != itEnd; + ++it ) + out += "[" + *it + "]"; + return out; + } + std::set spellings; + std::size_t count; + }; + + inline std::size_t listTags( Config const& config ) { + TestSpec testSpec = config.testSpec(); + if( config.testSpec().hasFilters() ) + Catch::cout() << "Tags for matching test cases:\n"; + else { + Catch::cout() << "All available tags:\n"; + testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); + } + + std::map tagCounts; + + std::vector matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); + for( std::vector::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); + it != itEnd; + ++it ) { + for( std::set::const_iterator tagIt = it->getTestCaseInfo().tags.begin(), + tagItEnd = it->getTestCaseInfo().tags.end(); + tagIt != tagItEnd; + ++tagIt ) { + std::string tagName = *tagIt; + std::string lcaseTagName = toLower( tagName ); + std::map::iterator countIt = tagCounts.find( lcaseTagName ); + if( countIt == tagCounts.end() ) + countIt = tagCounts.insert( std::make_pair( lcaseTagName, TagInfo() ) ).first; + countIt->second.add( tagName ); + } + } + + for( std::map::const_iterator countIt = tagCounts.begin(), + countItEnd = tagCounts.end(); + countIt != countItEnd; + ++countIt ) { + std::ostringstream oss; + oss << " " << std::setw(2) << countIt->second.count << " "; + Text wrapper( countIt->second.all(), TextAttributes() + .setInitialIndent( 0 ) + .setIndent( oss.str().size() ) + .setWidth( CATCH_CONFIG_CONSOLE_WIDTH-10 ) ); + Catch::cout() << oss.str() << wrapper << "\n"; + } + Catch::cout() << pluralise( tagCounts.size(), "tag" ) << "\n" << std::endl; + return tagCounts.size(); + } + + inline std::size_t listReporters( Config const& /*config*/ ) { + Catch::cout() << "Available reporters:\n"; + IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories(); + IReporterRegistry::FactoryMap::const_iterator itBegin = factories.begin(), itEnd = factories.end(), it; + std::size_t maxNameLen = 0; + for(it = itBegin; it != itEnd; ++it ) + maxNameLen = (std::max)( maxNameLen, it->first.size() ); + + for(it = itBegin; it != itEnd; ++it ) { + Text wrapper( it->second->getDescription(), TextAttributes() + .setInitialIndent( 0 ) + .setIndent( 7+maxNameLen ) + .setWidth( CATCH_CONFIG_CONSOLE_WIDTH - maxNameLen-8 ) ); + Catch::cout() << " " + << it->first + << ":" + << std::string( maxNameLen - it->first.size() + 2, ' ' ) + << wrapper << "\n"; + } + Catch::cout() << std::endl; + return factories.size(); + } + + inline Option list( Config const& config ) { + Option listedCount; + if( config.listTests() ) + listedCount = listedCount.valueOr(0) + listTests( config ); + if( config.listTestNamesOnly() ) + listedCount = listedCount.valueOr(0) + listTestsNamesOnly( config ); + if( config.listTags() ) + listedCount = listedCount.valueOr(0) + listTags( config ); + if( config.listReporters() ) + listedCount = listedCount.valueOr(0) + listReporters( config ); + return listedCount; + } + +} // end namespace Catch + +// #included from: internal/catch_run_context.hpp +#define TWOBLUECUBES_CATCH_RUNNER_IMPL_HPP_INCLUDED + +// #included from: catch_test_case_tracker.hpp +#define TWOBLUECUBES_CATCH_TEST_CASE_TRACKER_HPP_INCLUDED + +#include +#include +#include +#include + +namespace Catch { +namespace TestCaseTracking { + + struct ITracker : SharedImpl<> { + virtual ~ITracker(); + + // static queries + virtual std::string name() const = 0; + + // dynamic queries + virtual bool isComplete() const = 0; // Successfully completed or failed + virtual bool isSuccessfullyCompleted() const = 0; + virtual bool isOpen() const = 0; // Started but not complete + virtual bool hasChildren() const = 0; + + virtual ITracker& parent() = 0; + + // actions + virtual void close() = 0; // Successfully complete + virtual void fail() = 0; + virtual void markAsNeedingAnotherRun() = 0; + + virtual void addChild( Ptr const& child ) = 0; + virtual ITracker* findChild( std::string const& name ) = 0; + virtual void openChild() = 0; + }; + + class TrackerContext { + + enum RunState { + NotStarted, + Executing, + CompletedCycle + }; + + Ptr m_rootTracker; + ITracker* m_currentTracker; + RunState m_runState; + + public: + + static TrackerContext& instance() { + static TrackerContext s_instance; + return s_instance; + } + + TrackerContext() + : m_currentTracker( CATCH_NULL ), + m_runState( NotStarted ) + {} + + ITracker& startRun(); + + void endRun() { + m_rootTracker.reset(); + m_currentTracker = CATCH_NULL; + m_runState = NotStarted; + } + + void startCycle() { + m_currentTracker = m_rootTracker.get(); + m_runState = Executing; + } + void completeCycle() { + m_runState = CompletedCycle; + } + + bool completedCycle() const { + return m_runState == CompletedCycle; + } + ITracker& currentTracker() { + return *m_currentTracker; + } + void setCurrentTracker( ITracker* tracker ) { + m_currentTracker = tracker; + } + }; + + class TrackerBase : public ITracker { + protected: + enum CycleState { + NotStarted, + Executing, + ExecutingChildren, + NeedsAnotherRun, + CompletedSuccessfully, + Failed + }; + class TrackerHasName { + std::string m_name; + public: + TrackerHasName( std::string const& name ) : m_name( name ) {} + bool operator ()( Ptr const& tracker ) { + return tracker->name() == m_name; + } + }; + typedef std::vector > Children; + std::string m_name; + TrackerContext& m_ctx; + ITracker* m_parent; + Children m_children; + CycleState m_runState; + public: + TrackerBase( std::string const& name, TrackerContext& ctx, ITracker* parent ) + : m_name( name ), + m_ctx( ctx ), + m_parent( parent ), + m_runState( NotStarted ) + {} + virtual ~TrackerBase(); + + virtual std::string name() const CATCH_OVERRIDE { + return m_name; + } + virtual bool isComplete() const CATCH_OVERRIDE { + return m_runState == CompletedSuccessfully || m_runState == Failed; + } + virtual bool isSuccessfullyCompleted() const CATCH_OVERRIDE { + return m_runState == CompletedSuccessfully; + } + virtual bool isOpen() const CATCH_OVERRIDE { + return m_runState != NotStarted && !isComplete(); + } + virtual bool hasChildren() const CATCH_OVERRIDE { + return !m_children.empty(); + } + + virtual void addChild( Ptr const& child ) CATCH_OVERRIDE { + m_children.push_back( child ); + } + + virtual ITracker* findChild( std::string const& name ) CATCH_OVERRIDE { + Children::const_iterator it = std::find_if( m_children.begin(), m_children.end(), TrackerHasName( name ) ); + return( it != m_children.end() ) + ? it->get() + : CATCH_NULL; + } + virtual ITracker& parent() CATCH_OVERRIDE { + assert( m_parent ); // Should always be non-null except for root + return *m_parent; + } + + virtual void openChild() CATCH_OVERRIDE { + if( m_runState != ExecutingChildren ) { + m_runState = ExecutingChildren; + if( m_parent ) + m_parent->openChild(); + } + } + void open() { + m_runState = Executing; + moveToThis(); + if( m_parent ) + m_parent->openChild(); + } + + virtual void close() CATCH_OVERRIDE { + + // Close any still open children (e.g. generators) + while( &m_ctx.currentTracker() != this ) + m_ctx.currentTracker().close(); + + switch( m_runState ) { + case NotStarted: + case CompletedSuccessfully: + case Failed: + throw std::logic_error( "Illogical state" ); + + case NeedsAnotherRun: + break;; + + case Executing: + m_runState = CompletedSuccessfully; + break; + case ExecutingChildren: + if( m_children.empty() || m_children.back()->isComplete() ) + m_runState = CompletedSuccessfully; + break; + + default: + throw std::logic_error( "Unexpected state" ); + } + moveToParent(); + m_ctx.completeCycle(); + } + virtual void fail() CATCH_OVERRIDE { + m_runState = Failed; + if( m_parent ) + m_parent->markAsNeedingAnotherRun(); + moveToParent(); + m_ctx.completeCycle(); + } + virtual void markAsNeedingAnotherRun() CATCH_OVERRIDE { + m_runState = NeedsAnotherRun; + } + private: + void moveToParent() { + assert( m_parent ); + m_ctx.setCurrentTracker( m_parent ); + } + void moveToThis() { + m_ctx.setCurrentTracker( this ); + } + }; + + class SectionTracker : public TrackerBase { + public: + SectionTracker( std::string const& name, TrackerContext& ctx, ITracker* parent ) + : TrackerBase( name, ctx, parent ) + {} + virtual ~SectionTracker(); + + static SectionTracker& acquire( TrackerContext& ctx, std::string const& name ) { + SectionTracker* section = CATCH_NULL; + + ITracker& currentTracker = ctx.currentTracker(); + if( ITracker* childTracker = currentTracker.findChild( name ) ) { + section = dynamic_cast( childTracker ); + assert( section ); + } + else { + section = new SectionTracker( name, ctx, ¤tTracker ); + currentTracker.addChild( section ); + } + if( !ctx.completedCycle() && !section->isComplete() ) { + + section->open(); + } + return *section; + } + }; + + class IndexTracker : public TrackerBase { + int m_size; + int m_index; + public: + IndexTracker( std::string const& name, TrackerContext& ctx, ITracker* parent, int size ) + : TrackerBase( name, ctx, parent ), + m_size( size ), + m_index( -1 ) + {} + virtual ~IndexTracker(); + + static IndexTracker& acquire( TrackerContext& ctx, std::string const& name, int size ) { + IndexTracker* tracker = CATCH_NULL; + + ITracker& currentTracker = ctx.currentTracker(); + if( ITracker* childTracker = currentTracker.findChild( name ) ) { + tracker = dynamic_cast( childTracker ); + assert( tracker ); + } + else { + tracker = new IndexTracker( name, ctx, ¤tTracker, size ); + currentTracker.addChild( tracker ); + } + + if( !ctx.completedCycle() && !tracker->isComplete() ) { + if( tracker->m_runState != ExecutingChildren && tracker->m_runState != NeedsAnotherRun ) + tracker->moveNext(); + tracker->open(); + } + + return *tracker; + } + + int index() const { return m_index; } + + void moveNext() { + m_index++; + m_children.clear(); + } + + virtual void close() CATCH_OVERRIDE { + TrackerBase::close(); + if( m_runState == CompletedSuccessfully && m_index < m_size-1 ) + m_runState = Executing; + } + }; + + inline ITracker& TrackerContext::startRun() { + m_rootTracker = new SectionTracker( "{root}", *this, CATCH_NULL ); + m_currentTracker = CATCH_NULL; + m_runState = Executing; + return *m_rootTracker; + } + +} // namespace TestCaseTracking + +using TestCaseTracking::ITracker; +using TestCaseTracking::TrackerContext; +using TestCaseTracking::SectionTracker; +using TestCaseTracking::IndexTracker; + +} // namespace Catch + +// #included from: catch_fatal_condition.hpp +#define TWOBLUECUBES_CATCH_FATAL_CONDITION_H_INCLUDED + +namespace Catch { + + // Report the error condition then exit the process + inline void fatal( std::string const& message, int exitCode ) { + IContext& context = Catch::getCurrentContext(); + IResultCapture* resultCapture = context.getResultCapture(); + resultCapture->handleFatalErrorCondition( message ); + + if( Catch::alwaysTrue() ) // avoids "no return" warnings + exit( exitCode ); + } + +} // namespace Catch + +#if defined ( CATCH_PLATFORM_WINDOWS ) ///////////////////////////////////////// + +namespace Catch { + + struct FatalConditionHandler { + void reset() {} + }; + +} // namespace Catch + +#else // Not Windows - assumed to be POSIX compatible ////////////////////////// + +#include + +namespace Catch { + + struct SignalDefs { int id; const char* name; }; + extern SignalDefs signalDefs[]; + SignalDefs signalDefs[] = { + { SIGINT, "SIGINT - Terminal interrupt signal" }, + { SIGILL, "SIGILL - Illegal instruction signal" }, + { SIGFPE, "SIGFPE - Floating point error signal" }, + { SIGSEGV, "SIGSEGV - Segmentation violation signal" }, + { SIGTERM, "SIGTERM - Termination request signal" }, + { SIGABRT, "SIGABRT - Abort (abnormal termination) signal" } + }; + + struct FatalConditionHandler { + + static void handleSignal( int sig ) { + for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) + if( sig == signalDefs[i].id ) + fatal( signalDefs[i].name, -sig ); + fatal( "", -sig ); + } + + FatalConditionHandler() : m_isSet( true ) { + for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) + signal( signalDefs[i].id, handleSignal ); + } + ~FatalConditionHandler() { + reset(); + } + void reset() { + if( m_isSet ) { + for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) + signal( signalDefs[i].id, SIG_DFL ); + m_isSet = false; + } + } + + bool m_isSet; + }; + +} // namespace Catch + +#endif // not Windows + +#include +#include + +namespace Catch { + + class StreamRedirect { + + public: + StreamRedirect( std::ostream& stream, std::string& targetString ) + : m_stream( stream ), + m_prevBuf( stream.rdbuf() ), + m_targetString( targetString ) + { + stream.rdbuf( m_oss.rdbuf() ); + } + + ~StreamRedirect() { + m_targetString += m_oss.str(); + m_stream.rdbuf( m_prevBuf ); + } + + private: + std::ostream& m_stream; + std::streambuf* m_prevBuf; + std::ostringstream m_oss; + std::string& m_targetString; + }; + + /////////////////////////////////////////////////////////////////////////// + + class RunContext : public IResultCapture, public IRunner { + + RunContext( RunContext const& ); + void operator =( RunContext const& ); + + public: + + explicit RunContext( Ptr const& _config, Ptr const& reporter ) + : m_runInfo( _config->name() ), + m_context( getCurrentMutableContext() ), + m_activeTestCase( CATCH_NULL ), + m_config( _config ), + m_reporter( reporter ) + { + m_context.setRunner( this ); + m_context.setConfig( m_config ); + m_context.setResultCapture( this ); + m_reporter->testRunStarting( m_runInfo ); + } + + virtual ~RunContext() { + m_reporter->testRunEnded( TestRunStats( m_runInfo, m_totals, aborting() ) ); + } + + void testGroupStarting( std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount ) { + m_reporter->testGroupStarting( GroupInfo( testSpec, groupIndex, groupsCount ) ); + } + void testGroupEnded( std::string const& testSpec, Totals const& totals, std::size_t groupIndex, std::size_t groupsCount ) { + m_reporter->testGroupEnded( TestGroupStats( GroupInfo( testSpec, groupIndex, groupsCount ), totals, aborting() ) ); + } + + Totals runTest( TestCase const& testCase ) { + Totals prevTotals = m_totals; + + std::string redirectedCout; + std::string redirectedCerr; + + TestCaseInfo testInfo = testCase.getTestCaseInfo(); + + m_reporter->testCaseStarting( testInfo ); + + m_activeTestCase = &testCase; + + do { + m_trackerContext.startRun(); + do { + m_trackerContext.startCycle(); + m_testCaseTracker = &SectionTracker::acquire( m_trackerContext, testInfo.name ); + runCurrentTest( redirectedCout, redirectedCerr ); + } + while( !m_testCaseTracker->isSuccessfullyCompleted() && !aborting() ); + } + // !TBD: deprecated - this will be replaced by indexed trackers + while( getCurrentContext().advanceGeneratorsForCurrentTest() && !aborting() ); + + Totals deltaTotals = m_totals.delta( prevTotals ); + m_totals.testCases += deltaTotals.testCases; + m_reporter->testCaseEnded( TestCaseStats( testInfo, + deltaTotals, + redirectedCout, + redirectedCerr, + aborting() ) ); + + m_activeTestCase = CATCH_NULL; + m_testCaseTracker = CATCH_NULL; + + return deltaTotals; + } + + Ptr config() const { + return m_config; + } + + private: // IResultCapture + + virtual void assertionEnded( AssertionResult const& result ) { + if( result.getResultType() == ResultWas::Ok ) { + m_totals.assertions.passed++; + } + else if( !result.isOk() ) { + m_totals.assertions.failed++; + } + + if( m_reporter->assertionEnded( AssertionStats( result, m_messages, m_totals ) ) ) + m_messages.clear(); + + // Reset working state + m_lastAssertionInfo = AssertionInfo( "", m_lastAssertionInfo.lineInfo, "{Unknown expression after the reported line}" , m_lastAssertionInfo.resultDisposition ); + m_lastResult = result; + } + + virtual bool sectionStarted ( + SectionInfo const& sectionInfo, + Counts& assertions + ) + { + std::ostringstream oss; + oss << sectionInfo.name << "@" << sectionInfo.lineInfo; + + ITracker& sectionTracker = SectionTracker::acquire( m_trackerContext, oss.str() ); + if( !sectionTracker.isOpen() ) + return false; + m_activeSections.push_back( §ionTracker ); + + m_lastAssertionInfo.lineInfo = sectionInfo.lineInfo; + + m_reporter->sectionStarting( sectionInfo ); + + assertions = m_totals.assertions; + + return true; + } + bool testForMissingAssertions( Counts& assertions ) { + if( assertions.total() != 0 ) + return false; + if( !m_config->warnAboutMissingAssertions() ) + return false; + if( m_trackerContext.currentTracker().hasChildren() ) + return false; + m_totals.assertions.failed++; + assertions.failed++; + return true; + } + + virtual void sectionEnded( SectionEndInfo const& endInfo ) { + Counts assertions = m_totals.assertions - endInfo.prevAssertions; + bool missingAssertions = testForMissingAssertions( assertions ); + + if( !m_activeSections.empty() ) { + m_activeSections.back()->close(); + m_activeSections.pop_back(); + } + + m_reporter->sectionEnded( SectionStats( endInfo.sectionInfo, assertions, endInfo.durationInSeconds, missingAssertions ) ); + m_messages.clear(); + } + + virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) { + if( m_unfinishedSections.empty() ) + m_activeSections.back()->fail(); + else + m_activeSections.back()->close(); + m_activeSections.pop_back(); + + m_unfinishedSections.push_back( endInfo ); + } + + virtual void pushScopedMessage( MessageInfo const& message ) { + m_messages.push_back( message ); + } + + virtual void popScopedMessage( MessageInfo const& message ) { + m_messages.erase( std::remove( m_messages.begin(), m_messages.end(), message ), m_messages.end() ); + } + + virtual std::string getCurrentTestName() const { + return m_activeTestCase + ? m_activeTestCase->getTestCaseInfo().name + : ""; + } + + virtual const AssertionResult* getLastResult() const { + return &m_lastResult; + } + + virtual void handleFatalErrorCondition( std::string const& message ) { + ResultBuilder resultBuilder = makeUnexpectedResultBuilder(); + resultBuilder.setResultType( ResultWas::FatalErrorCondition ); + resultBuilder << message; + resultBuilder.captureExpression(); + + handleUnfinishedSections(); + + // Recreate section for test case (as we will lose the one that was in scope) + TestCaseInfo const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); + SectionInfo testCaseSection( testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description ); + + Counts assertions; + assertions.failed = 1; + SectionStats testCaseSectionStats( testCaseSection, assertions, 0, false ); + m_reporter->sectionEnded( testCaseSectionStats ); + + TestCaseInfo testInfo = m_activeTestCase->getTestCaseInfo(); + + Totals deltaTotals; + deltaTotals.testCases.failed = 1; + m_reporter->testCaseEnded( TestCaseStats( testInfo, + deltaTotals, + "", + "", + false ) ); + m_totals.testCases.failed++; + testGroupEnded( "", m_totals, 1, 1 ); + m_reporter->testRunEnded( TestRunStats( m_runInfo, m_totals, false ) ); + } + + public: + // !TBD We need to do this another way! + bool aborting() const { + return m_totals.assertions.failed == static_cast( m_config->abortAfter() ); + } + + private: + + void runCurrentTest( std::string& redirectedCout, std::string& redirectedCerr ) { + TestCaseInfo const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); + SectionInfo testCaseSection( testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description ); + m_reporter->sectionStarting( testCaseSection ); + Counts prevAssertions = m_totals.assertions; + double duration = 0; + try { + m_lastAssertionInfo = AssertionInfo( "TEST_CASE", testCaseInfo.lineInfo, "", ResultDisposition::Normal ); + + seedRng( *m_config ); + + Timer timer; + timer.start(); + if( m_reporter->getPreferences().shouldRedirectStdOut ) { + StreamRedirect coutRedir( Catch::cout(), redirectedCout ); + StreamRedirect cerrRedir( Catch::cerr(), redirectedCerr ); + invokeActiveTestCase(); + } + else { + invokeActiveTestCase(); + } + duration = timer.getElapsedSeconds(); + } + catch( TestFailureException& ) { + // This just means the test was aborted due to failure + } + catch(...) { + makeUnexpectedResultBuilder().useActiveException(); + } + m_testCaseTracker->close(); + handleUnfinishedSections(); + m_messages.clear(); + + Counts assertions = m_totals.assertions - prevAssertions; + bool missingAssertions = testForMissingAssertions( assertions ); + + if( testCaseInfo.okToFail() ) { + std::swap( assertions.failedButOk, assertions.failed ); + m_totals.assertions.failed -= assertions.failedButOk; + m_totals.assertions.failedButOk += assertions.failedButOk; + } + + SectionStats testCaseSectionStats( testCaseSection, assertions, duration, missingAssertions ); + m_reporter->sectionEnded( testCaseSectionStats ); + } + + void invokeActiveTestCase() { + FatalConditionHandler fatalConditionHandler; // Handle signals + m_activeTestCase->invoke(); + fatalConditionHandler.reset(); + } + + private: + + ResultBuilder makeUnexpectedResultBuilder() const { + return ResultBuilder( m_lastAssertionInfo.macroName.c_str(), + m_lastAssertionInfo.lineInfo, + m_lastAssertionInfo.capturedExpression.c_str(), + m_lastAssertionInfo.resultDisposition ); + } + + void handleUnfinishedSections() { + // If sections ended prematurely due to an exception we stored their + // infos here so we can tear them down outside the unwind process. + for( std::vector::const_reverse_iterator it = m_unfinishedSections.rbegin(), + itEnd = m_unfinishedSections.rend(); + it != itEnd; + ++it ) + sectionEnded( *it ); + m_unfinishedSections.clear(); + } + + TestRunInfo m_runInfo; + IMutableContext& m_context; + TestCase const* m_activeTestCase; + ITracker* m_testCaseTracker; + ITracker* m_currentSectionTracker; + AssertionResult m_lastResult; + + Ptr m_config; + Totals m_totals; + Ptr m_reporter; + std::vector m_messages; + AssertionInfo m_lastAssertionInfo; + std::vector m_unfinishedSections; + std::vector m_activeSections; + TrackerContext m_trackerContext; + }; + + IResultCapture& getResultCapture() { + if( IResultCapture* capture = getCurrentContext().getResultCapture() ) + return *capture; + else + throw std::logic_error( "No result capture instance" ); + } + +} // end namespace Catch + +// #included from: internal/catch_version.h +#define TWOBLUECUBES_CATCH_VERSION_H_INCLUDED + +namespace Catch { + + // Versioning information + struct Version { + Version( unsigned int _majorVersion, + unsigned int _minorVersion, + unsigned int _patchNumber, + std::string const& _branchName, + unsigned int _buildNumber ); + + unsigned int const majorVersion; + unsigned int const minorVersion; + unsigned int const patchNumber; + + // buildNumber is only used if branchName is not null + std::string const branchName; + unsigned int const buildNumber; + + friend std::ostream& operator << ( std::ostream& os, Version const& version ); + + private: + void operator=( Version const& ); + }; + + extern Version libraryVersion; +} + +#include +#include +#include + +namespace Catch { + + Ptr createReporter( std::string const& reporterName, Ptr const& config ) { + Ptr reporter = getRegistryHub().getReporterRegistry().create( reporterName, config.get() ); + if( !reporter ) { + std::ostringstream oss; + oss << "No reporter registered with name: '" << reporterName << "'"; + throw std::domain_error( oss.str() ); + } + return reporter; + } + + Ptr makeReporter( Ptr const& config ) { + std::vector reporters = config->getReporterNames(); + if( reporters.empty() ) + reporters.push_back( "console" ); + + Ptr reporter; + for( std::vector::const_iterator it = reporters.begin(), itEnd = reporters.end(); + it != itEnd; + ++it ) + reporter = addReporter( reporter, createReporter( *it, config ) ); + return reporter; + } + Ptr addListeners( Ptr const& config, Ptr reporters ) { + IReporterRegistry::Listeners listeners = getRegistryHub().getReporterRegistry().getListeners(); + for( IReporterRegistry::Listeners::const_iterator it = listeners.begin(), itEnd = listeners.end(); + it != itEnd; + ++it ) + reporters = addReporter(reporters, (*it)->create( ReporterConfig( config ) ) ); + return reporters; + } + + Totals runTests( Ptr const& config ) { + + Ptr iconfig = config.get(); + + Ptr reporter = makeReporter( config ); + reporter = addListeners( iconfig, reporter ); + + RunContext context( iconfig, reporter ); + + Totals totals; + + context.testGroupStarting( config->name(), 1, 1 ); + + TestSpec testSpec = config->testSpec(); + if( !testSpec.hasFilters() ) + testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "~[.]" ).testSpec(); // All not hidden tests + + std::vector const& allTestCases = getAllTestCasesSorted( *iconfig ); + for( std::vector::const_iterator it = allTestCases.begin(), itEnd = allTestCases.end(); + it != itEnd; + ++it ) { + if( !context.aborting() && matchTest( *it, testSpec, *iconfig ) ) + totals += context.runTest( *it ); + else + reporter->skipTest( *it ); + } + + context.testGroupEnded( iconfig->name(), totals, 1, 1 ); + return totals; + } + + void applyFilenamesAsTags( IConfig const& config ) { + std::vector const& tests = getAllTestCasesSorted( config ); + for(std::size_t i = 0; i < tests.size(); ++i ) { + TestCase& test = const_cast( tests[i] ); + std::set tags = test.tags; + + std::string filename = test.lineInfo.file; + std::string::size_type lastSlash = filename.find_last_of( "\\/" ); + if( lastSlash != std::string::npos ) + filename = filename.substr( lastSlash+1 ); + + std::string::size_type lastDot = filename.find_last_of( "." ); + if( lastDot != std::string::npos ) + filename = filename.substr( 0, lastDot ); + + tags.insert( "#" + filename ); + setTags( test, tags ); + } + } + + class Session : NonCopyable { + static bool alreadyInstantiated; + + public: + + struct OnUnusedOptions { enum DoWhat { Ignore, Fail }; }; + + Session() + : m_cli( makeCommandLineParser() ) { + if( alreadyInstantiated ) { + std::string msg = "Only one instance of Catch::Session can ever be used"; + Catch::cerr() << msg << std::endl; + throw std::logic_error( msg ); + } + alreadyInstantiated = true; + } + ~Session() { + Catch::cleanUp(); + } + + void showHelp( std::string const& processName ) { + Catch::cout() << "\nCatch v" << libraryVersion << "\n"; + + m_cli.usage( Catch::cout(), processName ); + Catch::cout() << "For more detail usage please see the project docs\n" << std::endl; + } + + int applyCommandLine( int argc, char const* argv[], OnUnusedOptions::DoWhat unusedOptionBehaviour = OnUnusedOptions::Fail ) { + try { + m_cli.setThrowOnUnrecognisedTokens( unusedOptionBehaviour == OnUnusedOptions::Fail ); + m_unusedTokens = m_cli.parseInto( argc, argv, m_configData ); + if( m_configData.showHelp ) + showHelp( m_configData.processName ); + m_config.reset(); + } + catch( std::exception& ex ) { + { + Colour colourGuard( Colour::Red ); + Catch::cerr() + << "\nError(s) in input:\n" + << Text( ex.what(), TextAttributes().setIndent(2) ) + << "\n\n"; + } + m_cli.usage( Catch::cout(), m_configData.processName ); + return (std::numeric_limits::max)(); + } + return 0; + } + + void useConfigData( ConfigData const& _configData ) { + m_configData = _configData; + m_config.reset(); + } + + int run( int argc, char const* argv[] ) { + + int returnCode = applyCommandLine( argc, argv ); + if( returnCode == 0 ) + returnCode = run(); + return returnCode; + } + int run( int argc, char* argv[] ) { + return run( argc, const_cast( argv ) ); + } + + int run() { + if( m_configData.showHelp ) + return 0; + + try + { + config(); // Force config to be constructed + + seedRng( *m_config ); + + if( m_configData.filenamesAsTags ) + applyFilenamesAsTags( *m_config ); + + // Handle list request + if( Option listed = list( config() ) ) + return static_cast( *listed ); + + return static_cast( runTests( m_config ).assertions.failed ); + } + catch( std::exception& ex ) { + Catch::cerr() << ex.what() << std::endl; + return (std::numeric_limits::max)(); + } + } + + Clara::CommandLine const& cli() const { + return m_cli; + } + std::vector const& unusedTokens() const { + return m_unusedTokens; + } + ConfigData& configData() { + return m_configData; + } + Config& config() { + if( !m_config ) + m_config = new Config( m_configData ); + return *m_config; + } + private: + Clara::CommandLine m_cli; + std::vector m_unusedTokens; + ConfigData m_configData; + Ptr m_config; + }; + + bool Session::alreadyInstantiated = false; + +} // end namespace Catch + +// #included from: catch_registry_hub.hpp +#define TWOBLUECUBES_CATCH_REGISTRY_HUB_HPP_INCLUDED + +// #included from: catch_test_case_registry_impl.hpp +#define TWOBLUECUBES_CATCH_TEST_CASE_REGISTRY_IMPL_HPP_INCLUDED + +#include +#include +#include +#include +#include + +namespace Catch { + + struct LexSort { + bool operator() (TestCase i,TestCase j) const { return (i sortTests( IConfig const& config, std::vector const& unsortedTestCases ) { + + std::vector sorted = unsortedTestCases; + + switch( config.runOrder() ) { + case RunTests::InLexicographicalOrder: + std::sort( sorted.begin(), sorted.end(), LexSort() ); + break; + case RunTests::InRandomOrder: + { + seedRng( config ); + + RandomNumberGenerator rng; + std::random_shuffle( sorted.begin(), sorted.end(), rng ); + } + break; + case RunTests::InDeclarationOrder: + // already in declaration order + break; + } + return sorted; + } + bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ) { + return testSpec.matches( testCase ) && ( config.allowThrows() || !testCase.throws() ); + } + + void enforceNoDuplicateTestCases( std::vector const& functions ) { + std::set seenFunctions; + for( std::vector::const_iterator it = functions.begin(), itEnd = functions.end(); + it != itEnd; + ++it ) { + std::pair::const_iterator, bool> prev = seenFunctions.insert( *it ); + if( !prev.second ){ + Catch::cerr() + << Colour( Colour::Red ) + << "error: TEST_CASE( \"" << it->name << "\" ) already defined.\n" + << "\tFirst seen at " << prev.first->getTestCaseInfo().lineInfo << "\n" + << "\tRedefined at " << it->getTestCaseInfo().lineInfo << std::endl; + exit(1); + } + } + } + + std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ) { + std::vector filtered; + filtered.reserve( testCases.size() ); + for( std::vector::const_iterator it = testCases.begin(), itEnd = testCases.end(); + it != itEnd; + ++it ) + if( matchTest( *it, testSpec, config ) ) + filtered.push_back( *it ); + return filtered; + } + std::vector const& getAllTestCasesSorted( IConfig const& config ) { + return getRegistryHub().getTestCaseRegistry().getAllTestsSorted( config ); + } + + class TestRegistry : public ITestCaseRegistry { + public: + TestRegistry() + : m_currentSortOrder( RunTests::InDeclarationOrder ), + m_unnamedCount( 0 ) + {} + virtual ~TestRegistry(); + + virtual void registerTest( TestCase const& testCase ) { + std::string name = testCase.getTestCaseInfo().name; + if( name == "" ) { + std::ostringstream oss; + oss << "Anonymous test case " << ++m_unnamedCount; + return registerTest( testCase.withName( oss.str() ) ); + } + m_functions.push_back( testCase ); + } + + virtual std::vector const& getAllTests() const { + return m_functions; + } + virtual std::vector const& getAllTestsSorted( IConfig const& config ) const { + if( m_sortedFunctions.empty() ) + enforceNoDuplicateTestCases( m_functions ); + + if( m_currentSortOrder != config.runOrder() || m_sortedFunctions.empty() ) { + m_sortedFunctions = sortTests( config, m_functions ); + m_currentSortOrder = config.runOrder(); + } + return m_sortedFunctions; + } + + private: + std::vector m_functions; + mutable RunTests::InWhatOrder m_currentSortOrder; + mutable std::vector m_sortedFunctions; + size_t m_unnamedCount; + std::ios_base::Init m_ostreamInit; // Forces cout/ cerr to be initialised + }; + + /////////////////////////////////////////////////////////////////////////// + + class FreeFunctionTestCase : public SharedImpl { + public: + + FreeFunctionTestCase( TestFunction fun ) : m_fun( fun ) {} + + virtual void invoke() const { + m_fun(); + } + + private: + virtual ~FreeFunctionTestCase(); + + TestFunction m_fun; + }; + + inline std::string extractClassName( std::string const& classOrQualifiedMethodName ) { + std::string className = classOrQualifiedMethodName; + if( startsWith( className, "&" ) ) + { + std::size_t lastColons = className.rfind( "::" ); + std::size_t penultimateColons = className.rfind( "::", lastColons-1 ); + if( penultimateColons == std::string::npos ) + penultimateColons = 1; + className = className.substr( penultimateColons, lastColons-penultimateColons ); + } + return className; + } + + void registerTestCase + ( ITestCase* testCase, + char const* classOrQualifiedMethodName, + NameAndDesc const& nameAndDesc, + SourceLineInfo const& lineInfo ) { + + getMutableRegistryHub().registerTest + ( makeTestCase + ( testCase, + extractClassName( classOrQualifiedMethodName ), + nameAndDesc.name, + nameAndDesc.description, + lineInfo ) ); + } + void registerTestCaseFunction + ( TestFunction function, + SourceLineInfo const& lineInfo, + NameAndDesc const& nameAndDesc ) { + registerTestCase( new FreeFunctionTestCase( function ), "", nameAndDesc, lineInfo ); + } + + /////////////////////////////////////////////////////////////////////////// + + AutoReg::AutoReg + ( TestFunction function, + SourceLineInfo const& lineInfo, + NameAndDesc const& nameAndDesc ) { + registerTestCaseFunction( function, lineInfo, nameAndDesc ); + } + + AutoReg::~AutoReg() {} + +} // end namespace Catch + +// #included from: catch_reporter_registry.hpp +#define TWOBLUECUBES_CATCH_REPORTER_REGISTRY_HPP_INCLUDED + +#include + +namespace Catch { + + class ReporterRegistry : public IReporterRegistry { + + public: + + virtual ~ReporterRegistry() CATCH_OVERRIDE {} + + virtual IStreamingReporter* create( std::string const& name, Ptr const& config ) const CATCH_OVERRIDE { + FactoryMap::const_iterator it = m_factories.find( name ); + if( it == m_factories.end() ) + return CATCH_NULL; + return it->second->create( ReporterConfig( config ) ); + } + + void registerReporter( std::string const& name, Ptr const& factory ) { + m_factories.insert( std::make_pair( name, factory ) ); + } + void registerListener( Ptr const& factory ) { + m_listeners.push_back( factory ); + } + + virtual FactoryMap const& getFactories() const CATCH_OVERRIDE { + return m_factories; + } + virtual Listeners const& getListeners() const CATCH_OVERRIDE { + return m_listeners; + } + + private: + FactoryMap m_factories; + Listeners m_listeners; + }; +} + +// #included from: catch_exception_translator_registry.hpp +#define TWOBLUECUBES_CATCH_EXCEPTION_TRANSLATOR_REGISTRY_HPP_INCLUDED + +#ifdef __OBJC__ +#import "Foundation/Foundation.h" +#endif + +namespace Catch { + + class ExceptionTranslatorRegistry : public IExceptionTranslatorRegistry { + public: + ~ExceptionTranslatorRegistry() { + deleteAll( m_translators ); + } + + virtual void registerTranslator( const IExceptionTranslator* translator ) { + m_translators.push_back( translator ); + } + + virtual std::string translateActiveException() const { + try { +#ifdef __OBJC__ + // In Objective-C try objective-c exceptions first + @try { + return tryTranslators(); + } + @catch (NSException *exception) { + return Catch::toString( [exception description] ); + } +#else + return tryTranslators(); +#endif + } + catch( TestFailureException& ) { + throw; + } + catch( std::exception& ex ) { + return ex.what(); + } + catch( std::string& msg ) { + return msg; + } + catch( const char* msg ) { + return msg; + } + catch(...) { + return "Unknown exception"; + } + } + + std::string tryTranslators() const { + if( m_translators.empty() ) + throw; + else + return m_translators[0]->translate( m_translators.begin()+1, m_translators.end() ); + } + + private: + std::vector m_translators; + }; +} + +namespace Catch { + + namespace { + + class RegistryHub : public IRegistryHub, public IMutableRegistryHub { + + RegistryHub( RegistryHub const& ); + void operator=( RegistryHub const& ); + + public: // IRegistryHub + RegistryHub() { + } + virtual IReporterRegistry const& getReporterRegistry() const CATCH_OVERRIDE { + return m_reporterRegistry; + } + virtual ITestCaseRegistry const& getTestCaseRegistry() const CATCH_OVERRIDE { + return m_testCaseRegistry; + } + virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() CATCH_OVERRIDE { + return m_exceptionTranslatorRegistry; + } + + public: // IMutableRegistryHub + virtual void registerReporter( std::string const& name, Ptr const& factory ) CATCH_OVERRIDE { + m_reporterRegistry.registerReporter( name, factory ); + } + virtual void registerListener( Ptr const& factory ) CATCH_OVERRIDE { + m_reporterRegistry.registerListener( factory ); + } + virtual void registerTest( TestCase const& testInfo ) CATCH_OVERRIDE { + m_testCaseRegistry.registerTest( testInfo ); + } + virtual void registerTranslator( const IExceptionTranslator* translator ) CATCH_OVERRIDE { + m_exceptionTranslatorRegistry.registerTranslator( translator ); + } + + private: + TestRegistry m_testCaseRegistry; + ReporterRegistry m_reporterRegistry; + ExceptionTranslatorRegistry m_exceptionTranslatorRegistry; + }; + + // Single, global, instance + inline RegistryHub*& getTheRegistryHub() { + static RegistryHub* theRegistryHub = CATCH_NULL; + if( !theRegistryHub ) + theRegistryHub = new RegistryHub(); + return theRegistryHub; + } + } + + IRegistryHub& getRegistryHub() { + return *getTheRegistryHub(); + } + IMutableRegistryHub& getMutableRegistryHub() { + return *getTheRegistryHub(); + } + void cleanUp() { + delete getTheRegistryHub(); + getTheRegistryHub() = CATCH_NULL; + cleanUpContext(); + } + std::string translateActiveException() { + return getRegistryHub().getExceptionTranslatorRegistry().translateActiveException(); + } + +} // end namespace Catch + +// #included from: catch_notimplemented_exception.hpp +#define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_HPP_INCLUDED + +#include + +namespace Catch { + + NotImplementedException::NotImplementedException( SourceLineInfo const& lineInfo ) + : m_lineInfo( lineInfo ) { + std::ostringstream oss; + oss << lineInfo << ": function "; + oss << "not implemented"; + m_what = oss.str(); + } + + const char* NotImplementedException::what() const CATCH_NOEXCEPT { + return m_what.c_str(); + } + +} // end namespace Catch + +// #included from: catch_context_impl.hpp +#define TWOBLUECUBES_CATCH_CONTEXT_IMPL_HPP_INCLUDED + +// #included from: catch_stream.hpp +#define TWOBLUECUBES_CATCH_STREAM_HPP_INCLUDED + +#include +#include +#include + +namespace Catch { + + template + class StreamBufImpl : public StreamBufBase { + char data[bufferSize]; + WriterF m_writer; + + public: + StreamBufImpl() { + setp( data, data + sizeof(data) ); + } + + ~StreamBufImpl() CATCH_NOEXCEPT { + sync(); + } + + private: + int overflow( int c ) { + sync(); + + if( c != EOF ) { + if( pbase() == epptr() ) + m_writer( std::string( 1, static_cast( c ) ) ); + else + sputc( static_cast( c ) ); + } + return 0; + } + + int sync() { + if( pbase() != pptr() ) { + m_writer( std::string( pbase(), static_cast( pptr() - pbase() ) ) ); + setp( pbase(), epptr() ); + } + return 0; + } + }; + + /////////////////////////////////////////////////////////////////////////// + + FileStream::FileStream( std::string const& filename ) { + m_ofs.open( filename.c_str() ); + if( m_ofs.fail() ) { + std::ostringstream oss; + oss << "Unable to open file: '" << filename << "'"; + throw std::domain_error( oss.str() ); + } + } + + std::ostream& FileStream::stream() const { + return m_ofs; + } + + struct OutputDebugWriter { + + void operator()( std::string const&str ) { + writeToDebugConsole( str ); + } + }; + + DebugOutStream::DebugOutStream() + : m_streamBuf( new StreamBufImpl() ), + m_os( m_streamBuf.get() ) + {} + + std::ostream& DebugOutStream::stream() const { + return m_os; + } + + // Store the streambuf from cout up-front because + // cout may get redirected when running tests + CoutStream::CoutStream() + : m_os( Catch::cout().rdbuf() ) + {} + + std::ostream& CoutStream::stream() const { + return m_os; + } + +#ifndef CATCH_CONFIG_NOSTDOUT // If you #define this you must implement these functions + std::ostream& cout() { + return std::cout; + } + std::ostream& cerr() { + return std::cerr; + } +#endif +} + +namespace Catch { + + class Context : public IMutableContext { + + Context() : m_config( CATCH_NULL ), m_runner( CATCH_NULL ), m_resultCapture( CATCH_NULL ) {} + Context( Context const& ); + void operator=( Context const& ); + + public: // IContext + virtual IResultCapture* getResultCapture() { + return m_resultCapture; + } + virtual IRunner* getRunner() { + return m_runner; + } + virtual size_t getGeneratorIndex( std::string const& fileInfo, size_t totalSize ) { + return getGeneratorsForCurrentTest() + .getGeneratorInfo( fileInfo, totalSize ) + .getCurrentIndex(); + } + virtual bool advanceGeneratorsForCurrentTest() { + IGeneratorsForTest* generators = findGeneratorsForCurrentTest(); + return generators && generators->moveNext(); + } + + virtual Ptr getConfig() const { + return m_config; + } + + public: // IMutableContext + virtual void setResultCapture( IResultCapture* resultCapture ) { + m_resultCapture = resultCapture; + } + virtual void setRunner( IRunner* runner ) { + m_runner = runner; + } + virtual void setConfig( Ptr const& config ) { + m_config = config; + } + + friend IMutableContext& getCurrentMutableContext(); + + private: + IGeneratorsForTest* findGeneratorsForCurrentTest() { + std::string testName = getResultCapture()->getCurrentTestName(); + + std::map::const_iterator it = + m_generatorsByTestName.find( testName ); + return it != m_generatorsByTestName.end() + ? it->second + : CATCH_NULL; + } + + IGeneratorsForTest& getGeneratorsForCurrentTest() { + IGeneratorsForTest* generators = findGeneratorsForCurrentTest(); + if( !generators ) { + std::string testName = getResultCapture()->getCurrentTestName(); + generators = createGeneratorsForTest(); + m_generatorsByTestName.insert( std::make_pair( testName, generators ) ); + } + return *generators; + } + + private: + Ptr m_config; + IRunner* m_runner; + IResultCapture* m_resultCapture; + std::map m_generatorsByTestName; + }; + + namespace { + Context* currentContext = CATCH_NULL; + } + IMutableContext& getCurrentMutableContext() { + if( !currentContext ) + currentContext = new Context(); + return *currentContext; + } + IContext& getCurrentContext() { + return getCurrentMutableContext(); + } + + void cleanUpContext() { + delete currentContext; + currentContext = CATCH_NULL; + } +} + +// #included from: catch_console_colour_impl.hpp +#define TWOBLUECUBES_CATCH_CONSOLE_COLOUR_IMPL_HPP_INCLUDED + +namespace Catch { + namespace { + + struct IColourImpl { + virtual ~IColourImpl() {} + virtual void use( Colour::Code _colourCode ) = 0; + }; + + struct NoColourImpl : IColourImpl { + void use( Colour::Code ) {} + + static IColourImpl* instance() { + static NoColourImpl s_instance; + return &s_instance; + } + }; + + } // anon namespace +} // namespace Catch + +#if !defined( CATCH_CONFIG_COLOUR_NONE ) && !defined( CATCH_CONFIG_COLOUR_WINDOWS ) && !defined( CATCH_CONFIG_COLOUR_ANSI ) +# ifdef CATCH_PLATFORM_WINDOWS +# define CATCH_CONFIG_COLOUR_WINDOWS +# else +# define CATCH_CONFIG_COLOUR_ANSI +# endif +#endif + +#if defined ( CATCH_CONFIG_COLOUR_WINDOWS ) ///////////////////////////////////////// + +#ifndef NOMINMAX +#define NOMINMAX +#endif + +#ifdef __AFXDLL +#include +#else +#include +#endif + +namespace Catch { +namespace { + + class Win32ColourImpl : public IColourImpl { + public: + Win32ColourImpl() : stdoutHandle( GetStdHandle(STD_OUTPUT_HANDLE) ) + { + CONSOLE_SCREEN_BUFFER_INFO csbiInfo; + GetConsoleScreenBufferInfo( stdoutHandle, &csbiInfo ); + originalForegroundAttributes = csbiInfo.wAttributes & ~( BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_BLUE | BACKGROUND_INTENSITY ); + originalBackgroundAttributes = csbiInfo.wAttributes & ~( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY ); + } + + virtual void use( Colour::Code _colourCode ) { + switch( _colourCode ) { + case Colour::None: return setTextAttribute( originalForegroundAttributes ); + case Colour::White: return setTextAttribute( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE ); + case Colour::Red: return setTextAttribute( FOREGROUND_RED ); + case Colour::Green: return setTextAttribute( FOREGROUND_GREEN ); + case Colour::Blue: return setTextAttribute( FOREGROUND_BLUE ); + case Colour::Cyan: return setTextAttribute( FOREGROUND_BLUE | FOREGROUND_GREEN ); + case Colour::Yellow: return setTextAttribute( FOREGROUND_RED | FOREGROUND_GREEN ); + case Colour::Grey: return setTextAttribute( 0 ); + + case Colour::LightGrey: return setTextAttribute( FOREGROUND_INTENSITY ); + case Colour::BrightRed: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED ); + case Colour::BrightGreen: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN ); + case Colour::BrightWhite: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE ); + + case Colour::Bright: throw std::logic_error( "not a colour" ); + } + } + + private: + void setTextAttribute( WORD _textAttribute ) { + SetConsoleTextAttribute( stdoutHandle, _textAttribute | originalBackgroundAttributes ); + } + HANDLE stdoutHandle; + WORD originalForegroundAttributes; + WORD originalBackgroundAttributes; + }; + + IColourImpl* platformColourInstance() { + static Win32ColourImpl s_instance; + + Ptr config = getCurrentContext().getConfig(); + UseColour::YesOrNo colourMode = config + ? config->useColour() + : UseColour::Auto; + if( colourMode == UseColour::Auto ) + colourMode = !isDebuggerActive() + ? UseColour::Yes + : UseColour::No; + return colourMode == UseColour::Yes + ? &s_instance + : NoColourImpl::instance(); + } + +} // end anon namespace +} // end namespace Catch + +#elif defined( CATCH_CONFIG_COLOUR_ANSI ) ////////////////////////////////////// + +#include + +namespace Catch { +namespace { + + // use POSIX/ ANSI console terminal codes + // Thanks to Adam Strzelecki for original contribution + // (http://github.com/nanoant) + // https://github.com/philsquared/Catch/pull/131 + class PosixColourImpl : public IColourImpl { + public: + virtual void use( Colour::Code _colourCode ) { + switch( _colourCode ) { + case Colour::None: + case Colour::White: return setColour( "[0m" ); + case Colour::Red: return setColour( "[0;31m" ); + case Colour::Green: return setColour( "[0;32m" ); + case Colour::Blue: return setColour( "[0:34m" ); + case Colour::Cyan: return setColour( "[0;36m" ); + case Colour::Yellow: return setColour( "[0;33m" ); + case Colour::Grey: return setColour( "[1;30m" ); + + case Colour::LightGrey: return setColour( "[0;37m" ); + case Colour::BrightRed: return setColour( "[1;31m" ); + case Colour::BrightGreen: return setColour( "[1;32m" ); + case Colour::BrightWhite: return setColour( "[1;37m" ); + + case Colour::Bright: throw std::logic_error( "not a colour" ); + } + } + static IColourImpl* instance() { + static PosixColourImpl s_instance; + return &s_instance; + } + + private: + void setColour( const char* _escapeCode ) { + Catch::cout() << '\033' << _escapeCode; + } + }; + + IColourImpl* platformColourInstance() { + Ptr config = getCurrentContext().getConfig(); + UseColour::YesOrNo colourMode = config + ? config->useColour() + : UseColour::Auto; + if( colourMode == UseColour::Auto ) + colourMode = (!isDebuggerActive() && isatty(STDOUT_FILENO) ) + ? UseColour::Yes + : UseColour::No; + return colourMode == UseColour::Yes + ? PosixColourImpl::instance() + : NoColourImpl::instance(); + } + +} // end anon namespace +} // end namespace Catch + +#else // not Windows or ANSI /////////////////////////////////////////////// + +namespace Catch { + + static IColourImpl* platformColourInstance() { return NoColourImpl::instance(); } + +} // end namespace Catch + +#endif // Windows/ ANSI/ None + +namespace Catch { + + Colour::Colour( Code _colourCode ) : m_moved( false ) { use( _colourCode ); } + Colour::Colour( Colour const& _other ) : m_moved( false ) { const_cast( _other ).m_moved = true; } + Colour::~Colour(){ if( !m_moved ) use( None ); } + + void Colour::use( Code _colourCode ) { + static IColourImpl* impl = platformColourInstance(); + impl->use( _colourCode ); + } + +} // end namespace Catch + +// #included from: catch_generators_impl.hpp +#define TWOBLUECUBES_CATCH_GENERATORS_IMPL_HPP_INCLUDED + +#include +#include +#include + +namespace Catch { + + struct GeneratorInfo : IGeneratorInfo { + + GeneratorInfo( std::size_t size ) + : m_size( size ), + m_currentIndex( 0 ) + {} + + bool moveNext() { + if( ++m_currentIndex == m_size ) { + m_currentIndex = 0; + return false; + } + return true; + } + + std::size_t getCurrentIndex() const { + return m_currentIndex; + } + + std::size_t m_size; + std::size_t m_currentIndex; + }; + + /////////////////////////////////////////////////////////////////////////// + + class GeneratorsForTest : public IGeneratorsForTest { + + public: + ~GeneratorsForTest() { + deleteAll( m_generatorsInOrder ); + } + + IGeneratorInfo& getGeneratorInfo( std::string const& fileInfo, std::size_t size ) { + std::map::const_iterator it = m_generatorsByName.find( fileInfo ); + if( it == m_generatorsByName.end() ) { + IGeneratorInfo* info = new GeneratorInfo( size ); + m_generatorsByName.insert( std::make_pair( fileInfo, info ) ); + m_generatorsInOrder.push_back( info ); + return *info; + } + return *it->second; + } + + bool moveNext() { + std::vector::const_iterator it = m_generatorsInOrder.begin(); + std::vector::const_iterator itEnd = m_generatorsInOrder.end(); + for(; it != itEnd; ++it ) { + if( (*it)->moveNext() ) + return true; + } + return false; + } + + private: + std::map m_generatorsByName; + std::vector m_generatorsInOrder; + }; + + IGeneratorsForTest* createGeneratorsForTest() + { + return new GeneratorsForTest(); + } + +} // end namespace Catch + +// #included from: catch_assertionresult.hpp +#define TWOBLUECUBES_CATCH_ASSERTIONRESULT_HPP_INCLUDED + +namespace Catch { + + AssertionInfo::AssertionInfo( std::string const& _macroName, + SourceLineInfo const& _lineInfo, + std::string const& _capturedExpression, + ResultDisposition::Flags _resultDisposition ) + : macroName( _macroName ), + lineInfo( _lineInfo ), + capturedExpression( _capturedExpression ), + resultDisposition( _resultDisposition ) + {} + + AssertionResult::AssertionResult() {} + + AssertionResult::AssertionResult( AssertionInfo const& info, AssertionResultData const& data ) + : m_info( info ), + m_resultData( data ) + {} + + AssertionResult::~AssertionResult() {} + + // Result was a success + bool AssertionResult::succeeded() const { + return Catch::isOk( m_resultData.resultType ); + } + + // Result was a success, or failure is suppressed + bool AssertionResult::isOk() const { + return Catch::isOk( m_resultData.resultType ) || shouldSuppressFailure( m_info.resultDisposition ); + } + + ResultWas::OfType AssertionResult::getResultType() const { + return m_resultData.resultType; + } + + bool AssertionResult::hasExpression() const { + return !m_info.capturedExpression.empty(); + } + + bool AssertionResult::hasMessage() const { + return !m_resultData.message.empty(); + } + + std::string AssertionResult::getExpression() const { + if( isFalseTest( m_info.resultDisposition ) ) + return "!" + m_info.capturedExpression; + else + return m_info.capturedExpression; + } + std::string AssertionResult::getExpressionInMacro() const { + if( m_info.macroName.empty() ) + return m_info.capturedExpression; + else + return m_info.macroName + "( " + m_info.capturedExpression + " )"; + } + + bool AssertionResult::hasExpandedExpression() const { + return hasExpression() && getExpandedExpression() != getExpression(); + } + + std::string AssertionResult::getExpandedExpression() const { + return m_resultData.reconstructedExpression; + } + + std::string AssertionResult::getMessage() const { + return m_resultData.message; + } + SourceLineInfo AssertionResult::getSourceInfo() const { + return m_info.lineInfo; + } + + std::string AssertionResult::getTestMacroName() const { + return m_info.macroName; + } + +} // end namespace Catch + +// #included from: catch_test_case_info.hpp +#define TWOBLUECUBES_CATCH_TEST_CASE_INFO_HPP_INCLUDED + +namespace Catch { + + inline TestCaseInfo::SpecialProperties parseSpecialTag( std::string const& tag ) { + if( startsWith( tag, "." ) || + tag == "hide" || + tag == "!hide" ) + return TestCaseInfo::IsHidden; + else if( tag == "!throws" ) + return TestCaseInfo::Throws; + else if( tag == "!shouldfail" ) + return TestCaseInfo::ShouldFail; + else if( tag == "!mayfail" ) + return TestCaseInfo::MayFail; + else + return TestCaseInfo::None; + } + inline bool isReservedTag( std::string const& tag ) { + return parseSpecialTag( tag ) == TestCaseInfo::None && tag.size() > 0 && !isalnum( tag[0] ); + } + inline void enforceNotReservedTag( std::string const& tag, SourceLineInfo const& _lineInfo ) { + if( isReservedTag( tag ) ) { + { + Colour colourGuard( Colour::Red ); + Catch::cerr() + << "Tag name [" << tag << "] not allowed.\n" + << "Tag names starting with non alpha-numeric characters are reserved\n"; + } + { + Colour colourGuard( Colour::FileName ); + Catch::cerr() << _lineInfo << std::endl; + } + exit(1); + } + } + + TestCase makeTestCase( ITestCase* _testCase, + std::string const& _className, + std::string const& _name, + std::string const& _descOrTags, + SourceLineInfo const& _lineInfo ) + { + bool isHidden( startsWith( _name, "./" ) ); // Legacy support + + // Parse out tags + std::set tags; + std::string desc, tag; + bool inTag = false; + for( std::size_t i = 0; i < _descOrTags.size(); ++i ) { + char c = _descOrTags[i]; + if( !inTag ) { + if( c == '[' ) + inTag = true; + else + desc += c; + } + else { + if( c == ']' ) { + TestCaseInfo::SpecialProperties prop = parseSpecialTag( tag ); + if( prop == TestCaseInfo::IsHidden ) + isHidden = true; + else if( prop == TestCaseInfo::None ) + enforceNotReservedTag( tag, _lineInfo ); + + tags.insert( tag ); + tag.clear(); + inTag = false; + } + else + tag += c; + } + } + if( isHidden ) { + tags.insert( "hide" ); + tags.insert( "." ); + } + + TestCaseInfo info( _name, _className, desc, tags, _lineInfo ); + return TestCase( _testCase, info ); + } + + void setTags( TestCaseInfo& testCaseInfo, std::set const& tags ) + { + testCaseInfo.tags = tags; + testCaseInfo.lcaseTags.clear(); + + std::ostringstream oss; + for( std::set::const_iterator it = tags.begin(), itEnd = tags.end(); it != itEnd; ++it ) { + oss << "[" << *it << "]"; + std::string lcaseTag = toLower( *it ); + testCaseInfo.properties = static_cast( testCaseInfo.properties | parseSpecialTag( lcaseTag ) ); + testCaseInfo.lcaseTags.insert( lcaseTag ); + } + testCaseInfo.tagsAsString = oss.str(); + } + + TestCaseInfo::TestCaseInfo( std::string const& _name, + std::string const& _className, + std::string const& _description, + std::set const& _tags, + SourceLineInfo const& _lineInfo ) + : name( _name ), + className( _className ), + description( _description ), + lineInfo( _lineInfo ), + properties( None ) + { + setTags( *this, _tags ); + } + + TestCaseInfo::TestCaseInfo( TestCaseInfo const& other ) + : name( other.name ), + className( other.className ), + description( other.description ), + tags( other.tags ), + lcaseTags( other.lcaseTags ), + tagsAsString( other.tagsAsString ), + lineInfo( other.lineInfo ), + properties( other.properties ) + {} + + bool TestCaseInfo::isHidden() const { + return ( properties & IsHidden ) != 0; + } + bool TestCaseInfo::throws() const { + return ( properties & Throws ) != 0; + } + bool TestCaseInfo::okToFail() const { + return ( properties & (ShouldFail | MayFail ) ) != 0; + } + bool TestCaseInfo::expectedToFail() const { + return ( properties & (ShouldFail ) ) != 0; + } + + TestCase::TestCase( ITestCase* testCase, TestCaseInfo const& info ) : TestCaseInfo( info ), test( testCase ) {} + + TestCase::TestCase( TestCase const& other ) + : TestCaseInfo( other ), + test( other.test ) + {} + + TestCase TestCase::withName( std::string const& _newName ) const { + TestCase other( *this ); + other.name = _newName; + return other; + } + + void TestCase::swap( TestCase& other ) { + test.swap( other.test ); + name.swap( other.name ); + className.swap( other.className ); + description.swap( other.description ); + tags.swap( other.tags ); + lcaseTags.swap( other.lcaseTags ); + tagsAsString.swap( other.tagsAsString ); + std::swap( TestCaseInfo::properties, static_cast( other ).properties ); + std::swap( lineInfo, other.lineInfo ); + } + + void TestCase::invoke() const { + test->invoke(); + } + + bool TestCase::operator == ( TestCase const& other ) const { + return test.get() == other.test.get() && + name == other.name && + className == other.className; + } + + bool TestCase::operator < ( TestCase const& other ) const { + return name < other.name; + } + TestCase& TestCase::operator = ( TestCase const& other ) { + TestCase temp( other ); + swap( temp ); + return *this; + } + + TestCaseInfo const& TestCase::getTestCaseInfo() const + { + return *this; + } + +} // end namespace Catch + +// #included from: catch_version.hpp +#define TWOBLUECUBES_CATCH_VERSION_HPP_INCLUDED + +namespace Catch { + + Version::Version + ( unsigned int _majorVersion, + unsigned int _minorVersion, + unsigned int _patchNumber, + std::string const& _branchName, + unsigned int _buildNumber ) + : majorVersion( _majorVersion ), + minorVersion( _minorVersion ), + patchNumber( _patchNumber ), + branchName( _branchName ), + buildNumber( _buildNumber ) + {} + + std::ostream& operator << ( std::ostream& os, Version const& version ) { + os << version.majorVersion << "." + << version.minorVersion << "." + << version.patchNumber; + + if( !version.branchName.empty() ) { + os << "-" << version.branchName + << "." << version.buildNumber; + } + return os; + } + + Version libraryVersion( 1, 3, 6, "", 0 ); + +} + +// #included from: catch_message.hpp +#define TWOBLUECUBES_CATCH_MESSAGE_HPP_INCLUDED + +namespace Catch { + + MessageInfo::MessageInfo( std::string const& _macroName, + SourceLineInfo const& _lineInfo, + ResultWas::OfType _type ) + : macroName( _macroName ), + lineInfo( _lineInfo ), + type( _type ), + sequence( ++globalCount ) + {} + + // This may need protecting if threading support is added + unsigned int MessageInfo::globalCount = 0; + + //////////////////////////////////////////////////////////////////////////// + + ScopedMessage::ScopedMessage( MessageBuilder const& builder ) + : m_info( builder.m_info ) + { + m_info.message = builder.m_stream.str(); + getResultCapture().pushScopedMessage( m_info ); + } + ScopedMessage::ScopedMessage( ScopedMessage const& other ) + : m_info( other.m_info ) + {} + + ScopedMessage::~ScopedMessage() { + getResultCapture().popScopedMessage( m_info ); + } + +} // end namespace Catch + +// #included from: catch_legacy_reporter_adapter.hpp +#define TWOBLUECUBES_CATCH_LEGACY_REPORTER_ADAPTER_HPP_INCLUDED + +// #included from: catch_legacy_reporter_adapter.h +#define TWOBLUECUBES_CATCH_LEGACY_REPORTER_ADAPTER_H_INCLUDED + +namespace Catch +{ + // Deprecated + struct IReporter : IShared { + virtual ~IReporter(); + + virtual bool shouldRedirectStdout() const = 0; + + virtual void StartTesting() = 0; + virtual void EndTesting( Totals const& totals ) = 0; + virtual void StartGroup( std::string const& groupName ) = 0; + virtual void EndGroup( std::string const& groupName, Totals const& totals ) = 0; + virtual void StartTestCase( TestCaseInfo const& testInfo ) = 0; + virtual void EndTestCase( TestCaseInfo const& testInfo, Totals const& totals, std::string const& stdOut, std::string const& stdErr ) = 0; + virtual void StartSection( std::string const& sectionName, std::string const& description ) = 0; + virtual void EndSection( std::string const& sectionName, Counts const& assertions ) = 0; + virtual void NoAssertionsInSection( std::string const& sectionName ) = 0; + virtual void NoAssertionsInTestCase( std::string const& testName ) = 0; + virtual void Aborted() = 0; + virtual void Result( AssertionResult const& result ) = 0; + }; + + class LegacyReporterAdapter : public SharedImpl + { + public: + LegacyReporterAdapter( Ptr const& legacyReporter ); + virtual ~LegacyReporterAdapter(); + + virtual ReporterPreferences getPreferences() const; + virtual void noMatchingTestCases( std::string const& ); + virtual void testRunStarting( TestRunInfo const& ); + virtual void testGroupStarting( GroupInfo const& groupInfo ); + virtual void testCaseStarting( TestCaseInfo const& testInfo ); + virtual void sectionStarting( SectionInfo const& sectionInfo ); + virtual void assertionStarting( AssertionInfo const& ); + virtual bool assertionEnded( AssertionStats const& assertionStats ); + virtual void sectionEnded( SectionStats const& sectionStats ); + virtual void testCaseEnded( TestCaseStats const& testCaseStats ); + virtual void testGroupEnded( TestGroupStats const& testGroupStats ); + virtual void testRunEnded( TestRunStats const& testRunStats ); + virtual void skipTest( TestCaseInfo const& ); + + private: + Ptr m_legacyReporter; + }; +} + +namespace Catch +{ + LegacyReporterAdapter::LegacyReporterAdapter( Ptr const& legacyReporter ) + : m_legacyReporter( legacyReporter ) + {} + LegacyReporterAdapter::~LegacyReporterAdapter() {} + + ReporterPreferences LegacyReporterAdapter::getPreferences() const { + ReporterPreferences prefs; + prefs.shouldRedirectStdOut = m_legacyReporter->shouldRedirectStdout(); + return prefs; + } + + void LegacyReporterAdapter::noMatchingTestCases( std::string const& ) {} + void LegacyReporterAdapter::testRunStarting( TestRunInfo const& ) { + m_legacyReporter->StartTesting(); + } + void LegacyReporterAdapter::testGroupStarting( GroupInfo const& groupInfo ) { + m_legacyReporter->StartGroup( groupInfo.name ); + } + void LegacyReporterAdapter::testCaseStarting( TestCaseInfo const& testInfo ) { + m_legacyReporter->StartTestCase( testInfo ); + } + void LegacyReporterAdapter::sectionStarting( SectionInfo const& sectionInfo ) { + m_legacyReporter->StartSection( sectionInfo.name, sectionInfo.description ); + } + void LegacyReporterAdapter::assertionStarting( AssertionInfo const& ) { + // Not on legacy interface + } + + bool LegacyReporterAdapter::assertionEnded( AssertionStats const& assertionStats ) { + if( assertionStats.assertionResult.getResultType() != ResultWas::Ok ) { + for( std::vector::const_iterator it = assertionStats.infoMessages.begin(), itEnd = assertionStats.infoMessages.end(); + it != itEnd; + ++it ) { + if( it->type == ResultWas::Info ) { + ResultBuilder rb( it->macroName.c_str(), it->lineInfo, "", ResultDisposition::Normal ); + rb << it->message; + rb.setResultType( ResultWas::Info ); + AssertionResult result = rb.build(); + m_legacyReporter->Result( result ); + } + } + } + m_legacyReporter->Result( assertionStats.assertionResult ); + return true; + } + void LegacyReporterAdapter::sectionEnded( SectionStats const& sectionStats ) { + if( sectionStats.missingAssertions ) + m_legacyReporter->NoAssertionsInSection( sectionStats.sectionInfo.name ); + m_legacyReporter->EndSection( sectionStats.sectionInfo.name, sectionStats.assertions ); + } + void LegacyReporterAdapter::testCaseEnded( TestCaseStats const& testCaseStats ) { + m_legacyReporter->EndTestCase + ( testCaseStats.testInfo, + testCaseStats.totals, + testCaseStats.stdOut, + testCaseStats.stdErr ); + } + void LegacyReporterAdapter::testGroupEnded( TestGroupStats const& testGroupStats ) { + if( testGroupStats.aborting ) + m_legacyReporter->Aborted(); + m_legacyReporter->EndGroup( testGroupStats.groupInfo.name, testGroupStats.totals ); + } + void LegacyReporterAdapter::testRunEnded( TestRunStats const& testRunStats ) { + m_legacyReporter->EndTesting( testRunStats.totals ); + } + void LegacyReporterAdapter::skipTest( TestCaseInfo const& ) { + } +} + +// #included from: catch_timer.hpp + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wc++11-long-long" +#endif + +#ifdef CATCH_PLATFORM_WINDOWS +#include +#else +#include +#endif + +namespace Catch { + + namespace { +#ifdef CATCH_PLATFORM_WINDOWS + uint64_t getCurrentTicks() { + static uint64_t hz=0, hzo=0; + if (!hz) { + QueryPerformanceFrequency( reinterpret_cast( &hz ) ); + QueryPerformanceCounter( reinterpret_cast( &hzo ) ); + } + uint64_t t; + QueryPerformanceCounter( reinterpret_cast( &t ) ); + return ((t-hzo)*1000000)/hz; + } +#else + uint64_t getCurrentTicks() { + timeval t; + gettimeofday(&t,CATCH_NULL); + return static_cast( t.tv_sec ) * 1000000ull + static_cast( t.tv_usec ); + } +#endif + } + + void Timer::start() { + m_ticks = getCurrentTicks(); + } + unsigned int Timer::getElapsedMicroseconds() const { + return static_cast(getCurrentTicks() - m_ticks); + } + unsigned int Timer::getElapsedMilliseconds() const { + return static_cast(getElapsedMicroseconds()/1000); + } + double Timer::getElapsedSeconds() const { + return getElapsedMicroseconds()/1000000.0; + } + +} // namespace Catch + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif +// #included from: catch_common.hpp +#define TWOBLUECUBES_CATCH_COMMON_HPP_INCLUDED + +namespace Catch { + + bool startsWith( std::string const& s, std::string const& prefix ) { + return s.size() >= prefix.size() && s.substr( 0, prefix.size() ) == prefix; + } + bool endsWith( std::string const& s, std::string const& suffix ) { + return s.size() >= suffix.size() && s.substr( s.size()-suffix.size(), suffix.size() ) == suffix; + } + bool contains( std::string const& s, std::string const& infix ) { + return s.find( infix ) != std::string::npos; + } + void toLowerInPlace( std::string& s ) { + std::transform( s.begin(), s.end(), s.begin(), ::tolower ); + } + std::string toLower( std::string const& s ) { + std::string lc = s; + toLowerInPlace( lc ); + return lc; + } + std::string trim( std::string const& str ) { + static char const* whitespaceChars = "\n\r\t "; + std::string::size_type start = str.find_first_not_of( whitespaceChars ); + std::string::size_type end = str.find_last_not_of( whitespaceChars ); + + return start != std::string::npos ? str.substr( start, 1+end-start ) : ""; + } + + bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ) { + bool replaced = false; + std::size_t i = str.find( replaceThis ); + while( i != std::string::npos ) { + replaced = true; + str = str.substr( 0, i ) + withThis + str.substr( i+replaceThis.size() ); + if( i < str.size()-withThis.size() ) + i = str.find( replaceThis, i+withThis.size() ); + else + i = std::string::npos; + } + return replaced; + } + + pluralise::pluralise( std::size_t count, std::string const& label ) + : m_count( count ), + m_label( label ) + {} + + std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ) { + os << pluraliser.m_count << " " << pluraliser.m_label; + if( pluraliser.m_count != 1 ) + os << "s"; + return os; + } + + SourceLineInfo::SourceLineInfo() : line( 0 ){} + SourceLineInfo::SourceLineInfo( char const* _file, std::size_t _line ) + : file( _file ), + line( _line ) + {} + SourceLineInfo::SourceLineInfo( SourceLineInfo const& other ) + : file( other.file ), + line( other.line ) + {} + bool SourceLineInfo::empty() const { + return file.empty(); + } + bool SourceLineInfo::operator == ( SourceLineInfo const& other ) const { + return line == other.line && file == other.file; + } + bool SourceLineInfo::operator < ( SourceLineInfo const& other ) const { + return line < other.line || ( line == other.line && file < other.file ); + } + + void seedRng( IConfig const& config ) { + if( config.rngSeed() != 0 ) + std::srand( config.rngSeed() ); + } + unsigned int rngSeed() { + return getCurrentContext().getConfig()->rngSeed(); + } + + std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ) { +#ifndef __GNUG__ + os << info.file << "(" << info.line << ")"; +#else + os << info.file << ":" << info.line; +#endif + return os; + } + + void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo ) { + std::ostringstream oss; + oss << locationInfo << ": Internal Catch error: '" << message << "'"; + if( alwaysTrue() ) + throw std::logic_error( oss.str() ); + } +} + +// #included from: catch_section.hpp +#define TWOBLUECUBES_CATCH_SECTION_HPP_INCLUDED + +namespace Catch { + + SectionInfo::SectionInfo + ( SourceLineInfo const& _lineInfo, + std::string const& _name, + std::string const& _description ) + : name( _name ), + description( _description ), + lineInfo( _lineInfo ) + {} + + Section::Section( SectionInfo const& info ) + : m_info( info ), + m_sectionIncluded( getResultCapture().sectionStarted( m_info, m_assertions ) ) + { + m_timer.start(); + } + + Section::~Section() { + if( m_sectionIncluded ) { + SectionEndInfo endInfo( m_info, m_assertions, m_timer.getElapsedSeconds() ); + if( std::uncaught_exception() ) + getResultCapture().sectionEndedEarly( endInfo ); + else + getResultCapture().sectionEnded( endInfo ); + } + } + + // This indicates whether the section should be executed or not + Section::operator bool() const { + return m_sectionIncluded; + } + +} // end namespace Catch + +// #included from: catch_debugger.hpp +#define TWOBLUECUBES_CATCH_DEBUGGER_HPP_INCLUDED + +#include + +#ifdef CATCH_PLATFORM_MAC + + #include + #include + #include + #include + #include + + namespace Catch{ + + // The following function is taken directly from the following technical note: + // http://developer.apple.com/library/mac/#qa/qa2004/qa1361.html + + // Returns true if the current process is being debugged (either + // running under the debugger or has a debugger attached post facto). + bool isDebuggerActive(){ + + int mib[4]; + struct kinfo_proc info; + size_t size; + + // Initialize the flags so that, if sysctl fails for some bizarre + // reason, we get a predictable result. + + info.kp_proc.p_flag = 0; + + // Initialize mib, which tells sysctl the info we want, in this case + // we're looking for information about a specific process ID. + + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PID; + mib[3] = getpid(); + + // Call sysctl. + + size = sizeof(info); + if( sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, CATCH_NULL, 0) != 0 ) { + Catch::cerr() << "\n** Call to sysctl failed - unable to determine if debugger is active **\n" << std::endl; + return false; + } + + // We're being debugged if the P_TRACED flag is set. + + return ( (info.kp_proc.p_flag & P_TRACED) != 0 ); + } + } // namespace Catch + +#elif defined(_MSC_VER) + extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); + namespace Catch { + bool isDebuggerActive() { + return IsDebuggerPresent() != 0; + } + } +#elif defined(__MINGW32__) + extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); + namespace Catch { + bool isDebuggerActive() { + return IsDebuggerPresent() != 0; + } + } +#else + namespace Catch { + inline bool isDebuggerActive() { return false; } + } +#endif // Platform + +#ifdef CATCH_PLATFORM_WINDOWS + extern "C" __declspec(dllimport) void __stdcall OutputDebugStringA( const char* ); + namespace Catch { + void writeToDebugConsole( std::string const& text ) { + ::OutputDebugStringA( text.c_str() ); + } + } +#else + namespace Catch { + void writeToDebugConsole( std::string const& text ) { + // !TBD: Need a version for Mac/ XCode and other IDEs + Catch::cout() << text; + } + } +#endif // Platform + +// #included from: catch_tostring.hpp +#define TWOBLUECUBES_CATCH_TOSTRING_HPP_INCLUDED + +namespace Catch { + +namespace Detail { + + const std::string unprintableString = "{?}"; + + namespace { + const int hexThreshold = 255; + + struct Endianness { + enum Arch { Big, Little }; + + static Arch which() { + union _{ + int asInt; + char asChar[sizeof (int)]; + } u; + + u.asInt = 1; + return ( u.asChar[sizeof(int)-1] == 1 ) ? Big : Little; + } + }; + } + + std::string rawMemoryToString( const void *object, std::size_t size ) + { + // Reverse order for little endian architectures + int i = 0, end = static_cast( size ), inc = 1; + if( Endianness::which() == Endianness::Little ) { + i = end-1; + end = inc = -1; + } + + unsigned char const *bytes = static_cast(object); + std::ostringstream os; + os << "0x" << std::setfill('0') << std::hex; + for( ; i != end; i += inc ) + os << std::setw(2) << static_cast(bytes[i]); + return os.str(); + } +} + +std::string toString( std::string const& value ) { + std::string s = value; + if( getCurrentContext().getConfig()->showInvisibles() ) { + for(size_t i = 0; i < s.size(); ++i ) { + std::string subs; + switch( s[i] ) { + case '\n': subs = "\\n"; break; + case '\t': subs = "\\t"; break; + default: break; + } + if( !subs.empty() ) { + s = s.substr( 0, i ) + subs + s.substr( i+1 ); + ++i; + } + } + } + return "\"" + s + "\""; +} +std::string toString( std::wstring const& value ) { + + std::string s; + s.reserve( value.size() ); + for(size_t i = 0; i < value.size(); ++i ) + s += value[i] <= 0xff ? static_cast( value[i] ) : '?'; + return Catch::toString( s ); +} + +std::string toString( const char* const value ) { + return value ? Catch::toString( std::string( value ) ) : std::string( "{null string}" ); +} + +std::string toString( char* const value ) { + return Catch::toString( static_cast( value ) ); +} + +std::string toString( const wchar_t* const value ) +{ + return value ? Catch::toString( std::wstring(value) ) : std::string( "{null string}" ); +} + +std::string toString( wchar_t* const value ) +{ + return Catch::toString( static_cast( value ) ); +} + +std::string toString( int value ) { + std::ostringstream oss; + oss << value; + if( value > Detail::hexThreshold ) + oss << " (0x" << std::hex << value << ")"; + return oss.str(); +} + +std::string toString( unsigned long value ) { + std::ostringstream oss; + oss << value; + if( value > Detail::hexThreshold ) + oss << " (0x" << std::hex << value << ")"; + return oss.str(); +} + +std::string toString( unsigned int value ) { + return Catch::toString( static_cast( value ) ); +} + +template +std::string fpToString( T value, int precision ) { + std::ostringstream oss; + oss << std::setprecision( precision ) + << std::fixed + << value; + std::string d = oss.str(); + std::size_t i = d.find_last_not_of( '0' ); + if( i != std::string::npos && i != d.size()-1 ) { + if( d[i] == '.' ) + i++; + d = d.substr( 0, i+1 ); + } + return d; +} + +std::string toString( const double value ) { + return fpToString( value, 10 ); +} +std::string toString( const float value ) { + return fpToString( value, 5 ) + "f"; +} + +std::string toString( bool value ) { + return value ? "true" : "false"; +} + +std::string toString( char value ) { + return value < ' ' + ? toString( static_cast( value ) ) + : Detail::makeString( value ); +} + +std::string toString( signed char value ) { + return toString( static_cast( value ) ); +} + +std::string toString( unsigned char value ) { + return toString( static_cast( value ) ); +} + +#ifdef CATCH_CONFIG_CPP11_LONG_LONG +std::string toString( long long value ) { + std::ostringstream oss; + oss << value; + if( value > Detail::hexThreshold ) + oss << " (0x" << std::hex << value << ")"; + return oss.str(); +} +std::string toString( unsigned long long value ) { + std::ostringstream oss; + oss << value; + if( value > Detail::hexThreshold ) + oss << " (0x" << std::hex << value << ")"; + return oss.str(); +} +#endif + +#ifdef CATCH_CONFIG_CPP11_NULLPTR +std::string toString( std::nullptr_t ) { + return "nullptr"; +} +#endif + +#ifdef __OBJC__ + std::string toString( NSString const * const& nsstring ) { + if( !nsstring ) + return "nil"; + return "@" + toString([nsstring UTF8String]); + } + std::string toString( NSString * CATCH_ARC_STRONG const& nsstring ) { + if( !nsstring ) + return "nil"; + return "@" + toString([nsstring UTF8String]); + } + std::string toString( NSObject* const& nsObject ) { + return toString( [nsObject description] ); + } +#endif + +} // end namespace Catch + +// #included from: catch_result_builder.hpp +#define TWOBLUECUBES_CATCH_RESULT_BUILDER_HPP_INCLUDED + +namespace Catch { + + std::string capturedExpressionWithSecondArgument( std::string const& capturedExpression, std::string const& secondArg ) { + return secondArg.empty() || secondArg == "\"\"" + ? capturedExpression + : capturedExpression + ", " + secondArg; + } + ResultBuilder::ResultBuilder( char const* macroName, + SourceLineInfo const& lineInfo, + char const* capturedExpression, + ResultDisposition::Flags resultDisposition, + char const* secondArg ) + : m_assertionInfo( macroName, lineInfo, capturedExpressionWithSecondArgument( capturedExpression, secondArg ), resultDisposition ), + m_shouldDebugBreak( false ), + m_shouldThrow( false ) + {} + + ResultBuilder& ResultBuilder::setResultType( ResultWas::OfType result ) { + m_data.resultType = result; + return *this; + } + ResultBuilder& ResultBuilder::setResultType( bool result ) { + m_data.resultType = result ? ResultWas::Ok : ResultWas::ExpressionFailed; + return *this; + } + ResultBuilder& ResultBuilder::setLhs( std::string const& lhs ) { + m_exprComponents.lhs = lhs; + return *this; + } + ResultBuilder& ResultBuilder::setRhs( std::string const& rhs ) { + m_exprComponents.rhs = rhs; + return *this; + } + ResultBuilder& ResultBuilder::setOp( std::string const& op ) { + m_exprComponents.op = op; + return *this; + } + + void ResultBuilder::endExpression() { + m_exprComponents.testFalse = isFalseTest( m_assertionInfo.resultDisposition ); + captureExpression(); + } + + void ResultBuilder::useActiveException( ResultDisposition::Flags resultDisposition ) { + m_assertionInfo.resultDisposition = resultDisposition; + m_stream.oss << Catch::translateActiveException(); + captureResult( ResultWas::ThrewException ); + } + + void ResultBuilder::captureResult( ResultWas::OfType resultType ) { + setResultType( resultType ); + captureExpression(); + } + void ResultBuilder::captureExpectedException( std::string const& expectedMessage ) { + if( expectedMessage.empty() ) + captureExpectedException( Matchers::Impl::Generic::AllOf() ); + else + captureExpectedException( Matchers::Equals( expectedMessage ) ); + } + + void ResultBuilder::captureExpectedException( Matchers::Impl::Matcher const& matcher ) { + + assert( m_exprComponents.testFalse == false ); + AssertionResultData data = m_data; + data.resultType = ResultWas::Ok; + data.reconstructedExpression = m_assertionInfo.capturedExpression; + + std::string actualMessage = Catch::translateActiveException(); + if( !matcher.match( actualMessage ) ) { + data.resultType = ResultWas::ExpressionFailed; + data.reconstructedExpression = actualMessage; + } + AssertionResult result( m_assertionInfo, data ); + handleResult( result ); + } + + void ResultBuilder::captureExpression() { + AssertionResult result = build(); + handleResult( result ); + } + void ResultBuilder::handleResult( AssertionResult const& result ) + { + getResultCapture().assertionEnded( result ); + + if( !result.isOk() ) { + if( getCurrentContext().getConfig()->shouldDebugBreak() ) + m_shouldDebugBreak = true; + if( getCurrentContext().getRunner()->aborting() || (m_assertionInfo.resultDisposition & ResultDisposition::Normal) ) + m_shouldThrow = true; + } + } + void ResultBuilder::react() { + if( m_shouldThrow ) + throw Catch::TestFailureException(); + } + + bool ResultBuilder::shouldDebugBreak() const { return m_shouldDebugBreak; } + bool ResultBuilder::allowThrows() const { return getCurrentContext().getConfig()->allowThrows(); } + + AssertionResult ResultBuilder::build() const + { + assert( m_data.resultType != ResultWas::Unknown ); + + AssertionResultData data = m_data; + + // Flip bool results if testFalse is set + if( m_exprComponents.testFalse ) { + if( data.resultType == ResultWas::Ok ) + data.resultType = ResultWas::ExpressionFailed; + else if( data.resultType == ResultWas::ExpressionFailed ) + data.resultType = ResultWas::Ok; + } + + data.message = m_stream.oss.str(); + data.reconstructedExpression = reconstructExpression(); + if( m_exprComponents.testFalse ) { + if( m_exprComponents.op == "" ) + data.reconstructedExpression = "!" + data.reconstructedExpression; + else + data.reconstructedExpression = "!(" + data.reconstructedExpression + ")"; + } + return AssertionResult( m_assertionInfo, data ); + } + std::string ResultBuilder::reconstructExpression() const { + if( m_exprComponents.op == "" ) + return m_exprComponents.lhs.empty() ? m_assertionInfo.capturedExpression : m_exprComponents.op + m_exprComponents.lhs; + else if( m_exprComponents.op == "matches" ) + return m_exprComponents.lhs + " " + m_exprComponents.rhs; + else if( m_exprComponents.op != "!" ) { + if( m_exprComponents.lhs.size() + m_exprComponents.rhs.size() < 40 && + m_exprComponents.lhs.find("\n") == std::string::npos && + m_exprComponents.rhs.find("\n") == std::string::npos ) + return m_exprComponents.lhs + " " + m_exprComponents.op + " " + m_exprComponents.rhs; + else + return m_exprComponents.lhs + "\n" + m_exprComponents.op + "\n" + m_exprComponents.rhs; + } + else + return "{can't expand - use " + m_assertionInfo.macroName + "_FALSE( " + m_assertionInfo.capturedExpression.substr(1) + " ) instead of " + m_assertionInfo.macroName + "( " + m_assertionInfo.capturedExpression + " ) for better diagnostics}"; + } + +} // end namespace Catch + +// #included from: catch_tag_alias_registry.hpp +#define TWOBLUECUBES_CATCH_TAG_ALIAS_REGISTRY_HPP_INCLUDED + +// #included from: catch_tag_alias_registry.h +#define TWOBLUECUBES_CATCH_TAG_ALIAS_REGISTRY_H_INCLUDED + +#include + +namespace Catch { + + class TagAliasRegistry : public ITagAliasRegistry { + public: + virtual ~TagAliasRegistry(); + virtual Option find( std::string const& alias ) const; + virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const; + void add( char const* alias, char const* tag, SourceLineInfo const& lineInfo ); + static TagAliasRegistry& get(); + + private: + std::map m_registry; + }; + +} // end namespace Catch + +#include +#include + +namespace Catch { + + TagAliasRegistry::~TagAliasRegistry() {} + + Option TagAliasRegistry::find( std::string const& alias ) const { + std::map::const_iterator it = m_registry.find( alias ); + if( it != m_registry.end() ) + return it->second; + else + return Option(); + } + + std::string TagAliasRegistry::expandAliases( std::string const& unexpandedTestSpec ) const { + std::string expandedTestSpec = unexpandedTestSpec; + for( std::map::const_iterator it = m_registry.begin(), itEnd = m_registry.end(); + it != itEnd; + ++it ) { + std::size_t pos = expandedTestSpec.find( it->first ); + if( pos != std::string::npos ) { + expandedTestSpec = expandedTestSpec.substr( 0, pos ) + + it->second.tag + + expandedTestSpec.substr( pos + it->first.size() ); + } + } + return expandedTestSpec; + } + + void TagAliasRegistry::add( char const* alias, char const* tag, SourceLineInfo const& lineInfo ) { + + if( !startsWith( alias, "[@" ) || !endsWith( alias, "]" ) ) { + std::ostringstream oss; + oss << "error: tag alias, \"" << alias << "\" is not of the form [@alias name].\n" << lineInfo; + throw std::domain_error( oss.str().c_str() ); + } + if( !m_registry.insert( std::make_pair( alias, TagAlias( tag, lineInfo ) ) ).second ) { + std::ostringstream oss; + oss << "error: tag alias, \"" << alias << "\" already registered.\n" + << "\tFirst seen at " << find(alias)->lineInfo << "\n" + << "\tRedefined at " << lineInfo; + throw std::domain_error( oss.str().c_str() ); + } + } + + TagAliasRegistry& TagAliasRegistry::get() { + static TagAliasRegistry instance; + return instance; + + } + + ITagAliasRegistry::~ITagAliasRegistry() {} + ITagAliasRegistry const& ITagAliasRegistry::get() { return TagAliasRegistry::get(); } + + RegistrarForTagAliases::RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ) { + try { + TagAliasRegistry::get().add( alias, tag, lineInfo ); + } + catch( std::exception& ex ) { + Colour colourGuard( Colour::Red ); + Catch::cerr() << ex.what() << std::endl; + exit(1); + } + } + +} // end namespace Catch + +// #included from: ../reporters/catch_reporter_multi.hpp +#define TWOBLUECUBES_CATCH_REPORTER_MULTI_HPP_INCLUDED + +namespace Catch { + +class MultipleReporters : public SharedImpl { + typedef std::vector > Reporters; + Reporters m_reporters; + +public: + void add( Ptr const& reporter ) { + m_reporters.push_back( reporter ); + } + +public: // IStreamingReporter + + virtual ReporterPreferences getPreferences() const CATCH_OVERRIDE { + return m_reporters[0]->getPreferences(); + } + + virtual void noMatchingTestCases( std::string const& spec ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->noMatchingTestCases( spec ); + } + + virtual void testRunStarting( TestRunInfo const& testRunInfo ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->testRunStarting( testRunInfo ); + } + + virtual void testGroupStarting( GroupInfo const& groupInfo ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->testGroupStarting( groupInfo ); + } + + virtual void testCaseStarting( TestCaseInfo const& testInfo ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->testCaseStarting( testInfo ); + } + + virtual void sectionStarting( SectionInfo const& sectionInfo ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->sectionStarting( sectionInfo ); + } + + virtual void assertionStarting( AssertionInfo const& assertionInfo ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->assertionStarting( assertionInfo ); + } + + // The return value indicates if the messages buffer should be cleared: + virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE { + bool clearBuffer = false; + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + clearBuffer |= (*it)->assertionEnded( assertionStats ); + return clearBuffer; + } + + virtual void sectionEnded( SectionStats const& sectionStats ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->sectionEnded( sectionStats ); + } + + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->testCaseEnded( testCaseStats ); + } + + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->testGroupEnded( testGroupStats ); + } + + virtual void testRunEnded( TestRunStats const& testRunStats ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->testRunEnded( testRunStats ); + } + + virtual void skipTest( TestCaseInfo const& testInfo ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->skipTest( testInfo ); + } +}; + +Ptr addReporter( Ptr const& existingReporter, Ptr const& additionalReporter ) { + Ptr resultingReporter; + + if( existingReporter ) { + MultipleReporters* multi = dynamic_cast( existingReporter.get() ); + if( !multi ) { + multi = new MultipleReporters; + resultingReporter = Ptr( multi ); + if( existingReporter ) + multi->add( existingReporter ); + } + else + resultingReporter = existingReporter; + multi->add( additionalReporter ); + } + else + resultingReporter = additionalReporter; + + return resultingReporter; +} + +} // end namespace Catch + +// #included from: ../reporters/catch_reporter_xml.hpp +#define TWOBLUECUBES_CATCH_REPORTER_XML_HPP_INCLUDED + +// #included from: catch_reporter_bases.hpp +#define TWOBLUECUBES_CATCH_REPORTER_BASES_HPP_INCLUDED + +#include + +namespace Catch { + + struct StreamingReporterBase : SharedImpl { + + StreamingReporterBase( ReporterConfig const& _config ) + : m_config( _config.fullConfig() ), + stream( _config.stream() ) + { + m_reporterPrefs.shouldRedirectStdOut = false; + } + + virtual ReporterPreferences getPreferences() const CATCH_OVERRIDE { + return m_reporterPrefs; + } + + virtual ~StreamingReporterBase() CATCH_OVERRIDE; + + virtual void noMatchingTestCases( std::string const& ) CATCH_OVERRIDE {} + + virtual void testRunStarting( TestRunInfo const& _testRunInfo ) CATCH_OVERRIDE { + currentTestRunInfo = _testRunInfo; + } + virtual void testGroupStarting( GroupInfo const& _groupInfo ) CATCH_OVERRIDE { + currentGroupInfo = _groupInfo; + } + + virtual void testCaseStarting( TestCaseInfo const& _testInfo ) CATCH_OVERRIDE { + currentTestCaseInfo = _testInfo; + } + virtual void sectionStarting( SectionInfo const& _sectionInfo ) CATCH_OVERRIDE { + m_sectionStack.push_back( _sectionInfo ); + } + + virtual void sectionEnded( SectionStats const& /* _sectionStats */ ) CATCH_OVERRIDE { + m_sectionStack.pop_back(); + } + virtual void testCaseEnded( TestCaseStats const& /* _testCaseStats */ ) CATCH_OVERRIDE { + currentTestCaseInfo.reset(); + } + virtual void testGroupEnded( TestGroupStats const& /* _testGroupStats */ ) CATCH_OVERRIDE { + currentGroupInfo.reset(); + } + virtual void testRunEnded( TestRunStats const& /* _testRunStats */ ) CATCH_OVERRIDE { + currentTestCaseInfo.reset(); + currentGroupInfo.reset(); + currentTestRunInfo.reset(); + } + + virtual void skipTest( TestCaseInfo const& ) CATCH_OVERRIDE { + // Don't do anything with this by default. + // It can optionally be overridden in the derived class. + } + + Ptr m_config; + std::ostream& stream; + + LazyStat currentTestRunInfo; + LazyStat currentGroupInfo; + LazyStat currentTestCaseInfo; + + std::vector m_sectionStack; + ReporterPreferences m_reporterPrefs; + }; + + struct CumulativeReporterBase : SharedImpl { + template + struct Node : SharedImpl<> { + explicit Node( T const& _value ) : value( _value ) {} + virtual ~Node() {} + + typedef std::vector > ChildNodes; + T value; + ChildNodes children; + }; + struct SectionNode : SharedImpl<> { + explicit SectionNode( SectionStats const& _stats ) : stats( _stats ) {} + virtual ~SectionNode(); + + bool operator == ( SectionNode const& other ) const { + return stats.sectionInfo.lineInfo == other.stats.sectionInfo.lineInfo; + } + bool operator == ( Ptr const& other ) const { + return operator==( *other ); + } + + SectionStats stats; + typedef std::vector > ChildSections; + typedef std::vector Assertions; + ChildSections childSections; + Assertions assertions; + std::string stdOut; + std::string stdErr; + }; + + struct BySectionInfo { + BySectionInfo( SectionInfo const& other ) : m_other( other ) {} + BySectionInfo( BySectionInfo const& other ) : m_other( other.m_other ) {} + bool operator() ( Ptr const& node ) const { + return node->stats.sectionInfo.lineInfo == m_other.lineInfo; + } + private: + void operator=( BySectionInfo const& ); + SectionInfo const& m_other; + }; + + typedef Node TestCaseNode; + typedef Node TestGroupNode; + typedef Node TestRunNode; + + CumulativeReporterBase( ReporterConfig const& _config ) + : m_config( _config.fullConfig() ), + stream( _config.stream() ) + { + m_reporterPrefs.shouldRedirectStdOut = false; + } + ~CumulativeReporterBase(); + + virtual ReporterPreferences getPreferences() const CATCH_OVERRIDE { + return m_reporterPrefs; + } + + virtual void testRunStarting( TestRunInfo const& ) CATCH_OVERRIDE {} + virtual void testGroupStarting( GroupInfo const& ) CATCH_OVERRIDE {} + + virtual void testCaseStarting( TestCaseInfo const& ) CATCH_OVERRIDE {} + + virtual void sectionStarting( SectionInfo const& sectionInfo ) CATCH_OVERRIDE { + SectionStats incompleteStats( sectionInfo, Counts(), 0, false ); + Ptr node; + if( m_sectionStack.empty() ) { + if( !m_rootSection ) + m_rootSection = new SectionNode( incompleteStats ); + node = m_rootSection; + } + else { + SectionNode& parentNode = *m_sectionStack.back(); + SectionNode::ChildSections::const_iterator it = + std::find_if( parentNode.childSections.begin(), + parentNode.childSections.end(), + BySectionInfo( sectionInfo ) ); + if( it == parentNode.childSections.end() ) { + node = new SectionNode( incompleteStats ); + parentNode.childSections.push_back( node ); + } + else + node = *it; + } + m_sectionStack.push_back( node ); + m_deepestSection = node; + } + + virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE {} + + virtual bool assertionEnded( AssertionStats const& assertionStats ) { + assert( !m_sectionStack.empty() ); + SectionNode& sectionNode = *m_sectionStack.back(); + sectionNode.assertions.push_back( assertionStats ); + return true; + } + virtual void sectionEnded( SectionStats const& sectionStats ) CATCH_OVERRIDE { + assert( !m_sectionStack.empty() ); + SectionNode& node = *m_sectionStack.back(); + node.stats = sectionStats; + m_sectionStack.pop_back(); + } + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE { + Ptr node = new TestCaseNode( testCaseStats ); + assert( m_sectionStack.size() == 0 ); + node->children.push_back( m_rootSection ); + m_testCases.push_back( node ); + m_rootSection.reset(); + + assert( m_deepestSection ); + m_deepestSection->stdOut = testCaseStats.stdOut; + m_deepestSection->stdErr = testCaseStats.stdErr; + } + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE { + Ptr node = new TestGroupNode( testGroupStats ); + node->children.swap( m_testCases ); + m_testGroups.push_back( node ); + } + virtual void testRunEnded( TestRunStats const& testRunStats ) CATCH_OVERRIDE { + Ptr node = new TestRunNode( testRunStats ); + node->children.swap( m_testGroups ); + m_testRuns.push_back( node ); + testRunEndedCumulative(); + } + virtual void testRunEndedCumulative() = 0; + + virtual void skipTest( TestCaseInfo const& ) CATCH_OVERRIDE {} + + Ptr m_config; + std::ostream& stream; + std::vector m_assertions; + std::vector > > m_sections; + std::vector > m_testCases; + std::vector > m_testGroups; + + std::vector > m_testRuns; + + Ptr m_rootSection; + Ptr m_deepestSection; + std::vector > m_sectionStack; + ReporterPreferences m_reporterPrefs; + + }; + + template + char const* getLineOfChars() { + static char line[CATCH_CONFIG_CONSOLE_WIDTH] = {0}; + if( !*line ) { + memset( line, C, CATCH_CONFIG_CONSOLE_WIDTH-1 ); + line[CATCH_CONFIG_CONSOLE_WIDTH-1] = 0; + } + return line; + } + + struct TestEventListenerBase : StreamingReporterBase { + TestEventListenerBase( ReporterConfig const& _config ) + : StreamingReporterBase( _config ) + {} + + virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE {} + virtual bool assertionEnded( AssertionStats const& ) CATCH_OVERRIDE { + return false; + } + }; + +} // end namespace Catch + +// #included from: ../internal/catch_reporter_registrars.hpp +#define TWOBLUECUBES_CATCH_REPORTER_REGISTRARS_HPP_INCLUDED + +namespace Catch { + + template + class LegacyReporterRegistrar { + + class ReporterFactory : public IReporterFactory { + virtual IStreamingReporter* create( ReporterConfig const& config ) const { + return new LegacyReporterAdapter( new T( config ) ); + } + + virtual std::string getDescription() const { + return T::getDescription(); + } + }; + + public: + + LegacyReporterRegistrar( std::string const& name ) { + getMutableRegistryHub().registerReporter( name, new ReporterFactory() ); + } + }; + + template + class ReporterRegistrar { + + class ReporterFactory : public SharedImpl { + + // *** Please Note ***: + // - If you end up here looking at a compiler error because it's trying to register + // your custom reporter class be aware that the native reporter interface has changed + // to IStreamingReporter. The "legacy" interface, IReporter, is still supported via + // an adapter. Just use REGISTER_LEGACY_REPORTER to take advantage of the adapter. + // However please consider updating to the new interface as the old one is now + // deprecated and will probably be removed quite soon! + // Please contact me via github if you have any questions at all about this. + // In fact, ideally, please contact me anyway to let me know you've hit this - as I have + // no idea who is actually using custom reporters at all (possibly no-one!). + // The new interface is designed to minimise exposure to interface changes in the future. + virtual IStreamingReporter* create( ReporterConfig const& config ) const { + return new T( config ); + } + + virtual std::string getDescription() const { + return T::getDescription(); + } + }; + + public: + + ReporterRegistrar( std::string const& name ) { + getMutableRegistryHub().registerReporter( name, new ReporterFactory() ); + } + }; + + template + class ListenerRegistrar { + + class ListenerFactory : public SharedImpl { + + virtual IStreamingReporter* create( ReporterConfig const& config ) const { + return new T( config ); + } + virtual std::string getDescription() const { + return ""; + } + }; + + public: + + ListenerRegistrar() { + getMutableRegistryHub().registerListener( new ListenerFactory() ); + } + }; +} + +#define INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) \ + namespace{ Catch::LegacyReporterRegistrar catch_internal_RegistrarFor##reporterType( name ); } + +#define INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) \ + namespace{ Catch::ReporterRegistrar catch_internal_RegistrarFor##reporterType( name ); } + +#define INTERNAL_CATCH_REGISTER_LISTENER( listenerType ) \ + namespace{ Catch::ListenerRegistrar catch_internal_RegistrarFor##listenerType; } + +// #included from: ../internal/catch_xmlwriter.hpp +#define TWOBLUECUBES_CATCH_XMLWRITER_HPP_INCLUDED + +#include +#include +#include +#include + +namespace Catch { + + class XmlEncode { + public: + enum ForWhat { ForTextNodes, ForAttributes }; + + XmlEncode( std::string const& str, ForWhat forWhat = ForTextNodes ) + : m_str( str ), + m_forWhat( forWhat ) + {} + + void encodeTo( std::ostream& os ) const { + + // Apostrophe escaping not necessary if we always use " to write attributes + // (see: http://www.w3.org/TR/xml/#syntax) + + for( std::size_t i = 0; i < m_str.size(); ++ i ) { + char c = m_str[i]; + switch( c ) { + case '<': os << "<"; break; + case '&': os << "&"; break; + + case '>': + // See: http://www.w3.org/TR/xml/#syntax + if( i > 2 && m_str[i-1] == ']' && m_str[i-2] == ']' ) + os << ">"; + else + os << c; + break; + + case '\"': + if( m_forWhat == ForAttributes ) + os << """; + else + os << c; + break; + + default: + // Escape control chars - based on contribution by @espenalb in PR #465 + if ( ( c < '\x09' ) || ( c > '\x0D' && c < '\x20') || c=='\x7F' ) + os << "&#x" << std::uppercase << std::hex << static_cast( c ); + else + os << c; + } + } + } + + friend std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ) { + xmlEncode.encodeTo( os ); + return os; + } + + private: + std::string m_str; + ForWhat m_forWhat; + }; + + class XmlWriter { + public: + + class ScopedElement { + public: + ScopedElement( XmlWriter* writer ) + : m_writer( writer ) + {} + + ScopedElement( ScopedElement const& other ) + : m_writer( other.m_writer ){ + other.m_writer = CATCH_NULL; + } + + ~ScopedElement() { + if( m_writer ) + m_writer->endElement(); + } + + ScopedElement& writeText( std::string const& text, bool indent = true ) { + m_writer->writeText( text, indent ); + return *this; + } + + template + ScopedElement& writeAttribute( std::string const& name, T const& attribute ) { + m_writer->writeAttribute( name, attribute ); + return *this; + } + + private: + mutable XmlWriter* m_writer; + }; + + XmlWriter() + : m_tagIsOpen( false ), + m_needsNewline( false ), + m_os( &Catch::cout() ) + {} + + XmlWriter( std::ostream& os ) + : m_tagIsOpen( false ), + m_needsNewline( false ), + m_os( &os ) + {} + + ~XmlWriter() { + while( !m_tags.empty() ) + endElement(); + } + + XmlWriter& startElement( std::string const& name ) { + ensureTagClosed(); + newlineIfNecessary(); + stream() << m_indent << "<" << name; + m_tags.push_back( name ); + m_indent += " "; + m_tagIsOpen = true; + return *this; + } + + ScopedElement scopedElement( std::string const& name ) { + ScopedElement scoped( this ); + startElement( name ); + return scoped; + } + + XmlWriter& endElement() { + newlineIfNecessary(); + m_indent = m_indent.substr( 0, m_indent.size()-2 ); + if( m_tagIsOpen ) { + stream() << "/>\n"; + m_tagIsOpen = false; + } + else { + stream() << m_indent << "\n"; + } + m_tags.pop_back(); + return *this; + } + + XmlWriter& writeAttribute( std::string const& name, std::string const& attribute ) { + if( !name.empty() && !attribute.empty() ) + stream() << " " << name << "=\"" << XmlEncode( attribute, XmlEncode::ForAttributes ) << "\""; + return *this; + } + + XmlWriter& writeAttribute( std::string const& name, bool attribute ) { + stream() << " " << name << "=\"" << ( attribute ? "true" : "false" ) << "\""; + return *this; + } + + template + XmlWriter& writeAttribute( std::string const& name, T const& attribute ) { + std::ostringstream oss; + oss << attribute; + return writeAttribute( name, oss.str() ); + } + + XmlWriter& writeText( std::string const& text, bool indent = true ) { + if( !text.empty() ){ + bool tagWasOpen = m_tagIsOpen; + ensureTagClosed(); + if( tagWasOpen && indent ) + stream() << m_indent; + stream() << XmlEncode( text ); + m_needsNewline = true; + } + return *this; + } + + XmlWriter& writeComment( std::string const& text ) { + ensureTagClosed(); + stream() << m_indent << ""; + m_needsNewline = true; + return *this; + } + + XmlWriter& writeBlankLine() { + ensureTagClosed(); + stream() << "\n"; + return *this; + } + + void setStream( std::ostream& os ) { + m_os = &os; + } + + private: + XmlWriter( XmlWriter const& ); + void operator=( XmlWriter const& ); + + std::ostream& stream() { + return *m_os; + } + + void ensureTagClosed() { + if( m_tagIsOpen ) { + stream() << ">\n"; + m_tagIsOpen = false; + } + } + + void newlineIfNecessary() { + if( m_needsNewline ) { + stream() << "\n"; + m_needsNewline = false; + } + } + + bool m_tagIsOpen; + bool m_needsNewline; + std::vector m_tags; + std::string m_indent; + std::ostream* m_os; + }; + +} +// #included from: catch_reenable_warnings.h + +#define TWOBLUECUBES_CATCH_REENABLE_WARNINGS_H_INCLUDED + +#ifdef __clang__ +# ifdef __ICC // icpc defines the __clang__ macro +# pragma warning(pop) +# else +# pragma clang diagnostic pop +# endif +#elif defined __GNUC__ +# pragma GCC diagnostic pop +#endif + + +namespace Catch { + class XmlReporter : public StreamingReporterBase { + public: + XmlReporter( ReporterConfig const& _config ) + : StreamingReporterBase( _config ), + m_sectionDepth( 0 ) + { + m_reporterPrefs.shouldRedirectStdOut = true; + } + + virtual ~XmlReporter() CATCH_OVERRIDE; + + static std::string getDescription() { + return "Reports test results as an XML document"; + } + + public: // StreamingReporterBase + + virtual void noMatchingTestCases( std::string const& s ) CATCH_OVERRIDE { + StreamingReporterBase::noMatchingTestCases( s ); + } + + virtual void testRunStarting( TestRunInfo const& testInfo ) CATCH_OVERRIDE { + StreamingReporterBase::testRunStarting( testInfo ); + m_xml.setStream( stream ); + m_xml.startElement( "Catch" ); + if( !m_config->name().empty() ) + m_xml.writeAttribute( "name", m_config->name() ); + } + + virtual void testGroupStarting( GroupInfo const& groupInfo ) CATCH_OVERRIDE { + StreamingReporterBase::testGroupStarting( groupInfo ); + m_xml.startElement( "Group" ) + .writeAttribute( "name", groupInfo.name ); + } + + virtual void testCaseStarting( TestCaseInfo const& testInfo ) CATCH_OVERRIDE { + StreamingReporterBase::testCaseStarting(testInfo); + m_xml.startElement( "TestCase" ).writeAttribute( "name", trim( testInfo.name ) ); + + if ( m_config->showDurations() == ShowDurations::Always ) + m_testCaseTimer.start(); + } + + virtual void sectionStarting( SectionInfo const& sectionInfo ) CATCH_OVERRIDE { + StreamingReporterBase::sectionStarting( sectionInfo ); + if( m_sectionDepth++ > 0 ) { + m_xml.startElement( "Section" ) + .writeAttribute( "name", trim( sectionInfo.name ) ) + .writeAttribute( "description", sectionInfo.description ); + } + } + + virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE { } + + virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE { + const AssertionResult& assertionResult = assertionStats.assertionResult; + + // Print any info messages in tags. + if( assertionStats.assertionResult.getResultType() != ResultWas::Ok ) { + for( std::vector::const_iterator it = assertionStats.infoMessages.begin(), itEnd = assertionStats.infoMessages.end(); + it != itEnd; + ++it ) { + if( it->type == ResultWas::Info ) { + m_xml.scopedElement( "Info" ) + .writeText( it->message ); + } else if ( it->type == ResultWas::Warning ) { + m_xml.scopedElement( "Warning" ) + .writeText( it->message ); + } + } + } + + // Drop out if result was successful but we're not printing them. + if( !m_config->includeSuccessfulResults() && isOk(assertionResult.getResultType()) ) + return true; + + // Print the expression if there is one. + if( assertionResult.hasExpression() ) { + m_xml.startElement( "Expression" ) + .writeAttribute( "success", assertionResult.succeeded() ) + .writeAttribute( "type", assertionResult.getTestMacroName() ) + .writeAttribute( "filename", assertionResult.getSourceInfo().file ) + .writeAttribute( "line", assertionResult.getSourceInfo().line ); + + m_xml.scopedElement( "Original" ) + .writeText( assertionResult.getExpression() ); + m_xml.scopedElement( "Expanded" ) + .writeText( assertionResult.getExpandedExpression() ); + } + + // And... Print a result applicable to each result type. + switch( assertionResult.getResultType() ) { + case ResultWas::ThrewException: + m_xml.scopedElement( "Exception" ) + .writeAttribute( "filename", assertionResult.getSourceInfo().file ) + .writeAttribute( "line", assertionResult.getSourceInfo().line ) + .writeText( assertionResult.getMessage() ); + break; + case ResultWas::FatalErrorCondition: + m_xml.scopedElement( "Fatal Error Condition" ) + .writeAttribute( "filename", assertionResult.getSourceInfo().file ) + .writeAttribute( "line", assertionResult.getSourceInfo().line ) + .writeText( assertionResult.getMessage() ); + break; + case ResultWas::Info: + m_xml.scopedElement( "Info" ) + .writeText( assertionResult.getMessage() ); + break; + case ResultWas::Warning: + // Warning will already have been written + break; + case ResultWas::ExplicitFailure: + m_xml.scopedElement( "Failure" ) + .writeText( assertionResult.getMessage() ); + break; + default: + break; + } + + if( assertionResult.hasExpression() ) + m_xml.endElement(); + + return true; + } + + virtual void sectionEnded( SectionStats const& sectionStats ) CATCH_OVERRIDE { + StreamingReporterBase::sectionEnded( sectionStats ); + if( --m_sectionDepth > 0 ) { + XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResults" ); + e.writeAttribute( "successes", sectionStats.assertions.passed ); + e.writeAttribute( "failures", sectionStats.assertions.failed ); + e.writeAttribute( "expectedFailures", sectionStats.assertions.failedButOk ); + + if ( m_config->showDurations() == ShowDurations::Always ) + e.writeAttribute( "durationInSeconds", sectionStats.durationInSeconds ); + + m_xml.endElement(); + } + } + + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE { + StreamingReporterBase::testCaseEnded( testCaseStats ); + XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResult" ); + e.writeAttribute( "success", testCaseStats.totals.assertions.allOk() ); + + if ( m_config->showDurations() == ShowDurations::Always ) + e.writeAttribute( "durationInSeconds", m_testCaseTimer.getElapsedSeconds() ); + + m_xml.endElement(); + } + + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE { + StreamingReporterBase::testGroupEnded( testGroupStats ); + // TODO: Check testGroupStats.aborting and act accordingly. + m_xml.scopedElement( "OverallResults" ) + .writeAttribute( "successes", testGroupStats.totals.assertions.passed ) + .writeAttribute( "failures", testGroupStats.totals.assertions.failed ) + .writeAttribute( "expectedFailures", testGroupStats.totals.assertions.failedButOk ); + m_xml.endElement(); + } + + virtual void testRunEnded( TestRunStats const& testRunStats ) CATCH_OVERRIDE { + StreamingReporterBase::testRunEnded( testRunStats ); + m_xml.scopedElement( "OverallResults" ) + .writeAttribute( "successes", testRunStats.totals.assertions.passed ) + .writeAttribute( "failures", testRunStats.totals.assertions.failed ) + .writeAttribute( "expectedFailures", testRunStats.totals.assertions.failedButOk ); + m_xml.endElement(); + } + + private: + Timer m_testCaseTimer; + XmlWriter m_xml; + int m_sectionDepth; + }; + + INTERNAL_CATCH_REGISTER_REPORTER( "xml", XmlReporter ) + +} // end namespace Catch + +// #included from: ../reporters/catch_reporter_junit.hpp +#define TWOBLUECUBES_CATCH_REPORTER_JUNIT_HPP_INCLUDED + +#include + +namespace Catch { + + class JunitReporter : public CumulativeReporterBase { + public: + JunitReporter( ReporterConfig const& _config ) + : CumulativeReporterBase( _config ), + xml( _config.stream() ) + { + m_reporterPrefs.shouldRedirectStdOut = true; + } + + virtual ~JunitReporter() CATCH_OVERRIDE; + + static std::string getDescription() { + return "Reports test results in an XML format that looks like Ant's junitreport target"; + } + + virtual void noMatchingTestCases( std::string const& /*spec*/ ) CATCH_OVERRIDE {} + + virtual void testRunStarting( TestRunInfo const& runInfo ) CATCH_OVERRIDE { + CumulativeReporterBase::testRunStarting( runInfo ); + xml.startElement( "testsuites" ); + } + + virtual void testGroupStarting( GroupInfo const& groupInfo ) CATCH_OVERRIDE { + suiteTimer.start(); + stdOutForSuite.str(""); + stdErrForSuite.str(""); + unexpectedExceptions = 0; + CumulativeReporterBase::testGroupStarting( groupInfo ); + } + + virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE { + if( assertionStats.assertionResult.getResultType() == ResultWas::ThrewException ) + unexpectedExceptions++; + return CumulativeReporterBase::assertionEnded( assertionStats ); + } + + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE { + stdOutForSuite << testCaseStats.stdOut; + stdErrForSuite << testCaseStats.stdErr; + CumulativeReporterBase::testCaseEnded( testCaseStats ); + } + + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE { + double suiteTime = suiteTimer.getElapsedSeconds(); + CumulativeReporterBase::testGroupEnded( testGroupStats ); + writeGroup( *m_testGroups.back(), suiteTime ); + } + + virtual void testRunEndedCumulative() CATCH_OVERRIDE { + xml.endElement(); + } + + void writeGroup( TestGroupNode const& groupNode, double suiteTime ) { + XmlWriter::ScopedElement e = xml.scopedElement( "testsuite" ); + TestGroupStats const& stats = groupNode.value; + xml.writeAttribute( "name", stats.groupInfo.name ); + xml.writeAttribute( "errors", unexpectedExceptions ); + xml.writeAttribute( "failures", stats.totals.assertions.failed-unexpectedExceptions ); + xml.writeAttribute( "tests", stats.totals.assertions.total() ); + xml.writeAttribute( "hostname", "tbd" ); // !TBD + if( m_config->showDurations() == ShowDurations::Never ) + xml.writeAttribute( "time", "" ); + else + xml.writeAttribute( "time", suiteTime ); + xml.writeAttribute( "timestamp", "tbd" ); // !TBD + + // Write test cases + for( TestGroupNode::ChildNodes::const_iterator + it = groupNode.children.begin(), itEnd = groupNode.children.end(); + it != itEnd; + ++it ) + writeTestCase( **it ); + + xml.scopedElement( "system-out" ).writeText( trim( stdOutForSuite.str() ), false ); + xml.scopedElement( "system-err" ).writeText( trim( stdErrForSuite.str() ), false ); + } + + void writeTestCase( TestCaseNode const& testCaseNode ) { + TestCaseStats const& stats = testCaseNode.value; + + // All test cases have exactly one section - which represents the + // test case itself. That section may have 0-n nested sections + assert( testCaseNode.children.size() == 1 ); + SectionNode const& rootSection = *testCaseNode.children.front(); + + std::string className = stats.testInfo.className; + + if( className.empty() ) { + if( rootSection.childSections.empty() ) + className = "global"; + } + writeSection( className, "", rootSection ); + } + + void writeSection( std::string const& className, + std::string const& rootName, + SectionNode const& sectionNode ) { + std::string name = trim( sectionNode.stats.sectionInfo.name ); + if( !rootName.empty() ) + name = rootName + "/" + name; + + if( !sectionNode.assertions.empty() || + !sectionNode.stdOut.empty() || + !sectionNode.stdErr.empty() ) { + XmlWriter::ScopedElement e = xml.scopedElement( "testcase" ); + if( className.empty() ) { + xml.writeAttribute( "classname", name ); + xml.writeAttribute( "name", "root" ); + } + else { + xml.writeAttribute( "classname", className ); + xml.writeAttribute( "name", name ); + } + xml.writeAttribute( "time", Catch::toString( sectionNode.stats.durationInSeconds ) ); + + writeAssertions( sectionNode ); + + if( !sectionNode.stdOut.empty() ) + xml.scopedElement( "system-out" ).writeText( trim( sectionNode.stdOut ), false ); + if( !sectionNode.stdErr.empty() ) + xml.scopedElement( "system-err" ).writeText( trim( sectionNode.stdErr ), false ); + } + for( SectionNode::ChildSections::const_iterator + it = sectionNode.childSections.begin(), + itEnd = sectionNode.childSections.end(); + it != itEnd; + ++it ) + if( className.empty() ) + writeSection( name, "", **it ); + else + writeSection( className, name, **it ); + } + + void writeAssertions( SectionNode const& sectionNode ) { + for( SectionNode::Assertions::const_iterator + it = sectionNode.assertions.begin(), itEnd = sectionNode.assertions.end(); + it != itEnd; + ++it ) + writeAssertion( *it ); + } + void writeAssertion( AssertionStats const& stats ) { + AssertionResult const& result = stats.assertionResult; + if( !result.isOk() ) { + std::string elementName; + switch( result.getResultType() ) { + case ResultWas::ThrewException: + case ResultWas::FatalErrorCondition: + elementName = "error"; + break; + case ResultWas::ExplicitFailure: + elementName = "failure"; + break; + case ResultWas::ExpressionFailed: + elementName = "failure"; + break; + case ResultWas::DidntThrowException: + elementName = "failure"; + break; + + // We should never see these here: + case ResultWas::Info: + case ResultWas::Warning: + case ResultWas::Ok: + case ResultWas::Unknown: + case ResultWas::FailureBit: + case ResultWas::Exception: + elementName = "internalError"; + break; + } + + XmlWriter::ScopedElement e = xml.scopedElement( elementName ); + + xml.writeAttribute( "message", result.getExpandedExpression() ); + xml.writeAttribute( "type", result.getTestMacroName() ); + + std::ostringstream oss; + if( !result.getMessage().empty() ) + oss << result.getMessage() << "\n"; + for( std::vector::const_iterator + it = stats.infoMessages.begin(), + itEnd = stats.infoMessages.end(); + it != itEnd; + ++it ) + if( it->type == ResultWas::Info ) + oss << it->message << "\n"; + + oss << "at " << result.getSourceInfo(); + xml.writeText( oss.str(), false ); + } + } + + XmlWriter xml; + Timer suiteTimer; + std::ostringstream stdOutForSuite; + std::ostringstream stdErrForSuite; + unsigned int unexpectedExceptions; + }; + + INTERNAL_CATCH_REGISTER_REPORTER( "junit", JunitReporter ) + +} // end namespace Catch + +// #included from: ../reporters/catch_reporter_console.hpp +#define TWOBLUECUBES_CATCH_REPORTER_CONSOLE_HPP_INCLUDED + +namespace Catch { + + struct ConsoleReporter : StreamingReporterBase { + ConsoleReporter( ReporterConfig const& _config ) + : StreamingReporterBase( _config ), + m_headerPrinted( false ) + {} + + virtual ~ConsoleReporter() CATCH_OVERRIDE; + static std::string getDescription() { + return "Reports test results as plain lines of text"; + } + + virtual void noMatchingTestCases( std::string const& spec ) CATCH_OVERRIDE { + stream << "No test cases matched '" << spec << "'" << std::endl; + } + + virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE { + } + + virtual bool assertionEnded( AssertionStats const& _assertionStats ) CATCH_OVERRIDE { + AssertionResult const& result = _assertionStats.assertionResult; + + bool printInfoMessages = true; + + // Drop out if result was successful and we're not printing those + if( !m_config->includeSuccessfulResults() && result.isOk() ) { + if( result.getResultType() != ResultWas::Warning ) + return false; + printInfoMessages = false; + } + + lazyPrint(); + + AssertionPrinter printer( stream, _assertionStats, printInfoMessages ); + printer.print(); + stream << std::endl; + return true; + } + + virtual void sectionStarting( SectionInfo const& _sectionInfo ) CATCH_OVERRIDE { + m_headerPrinted = false; + StreamingReporterBase::sectionStarting( _sectionInfo ); + } + virtual void sectionEnded( SectionStats const& _sectionStats ) CATCH_OVERRIDE { + if( _sectionStats.missingAssertions ) { + lazyPrint(); + Colour colour( Colour::ResultError ); + if( m_sectionStack.size() > 1 ) + stream << "\nNo assertions in section"; + else + stream << "\nNo assertions in test case"; + stream << " '" << _sectionStats.sectionInfo.name << "'\n" << std::endl; + } + if( m_headerPrinted ) { + if( m_config->showDurations() == ShowDurations::Always ) + stream << "Completed in " << _sectionStats.durationInSeconds << "s" << std::endl; + m_headerPrinted = false; + } + else { + if( m_config->showDurations() == ShowDurations::Always ) + stream << _sectionStats.sectionInfo.name << " completed in " << _sectionStats.durationInSeconds << "s" << std::endl; + } + StreamingReporterBase::sectionEnded( _sectionStats ); + } + + virtual void testCaseEnded( TestCaseStats const& _testCaseStats ) CATCH_OVERRIDE { + StreamingReporterBase::testCaseEnded( _testCaseStats ); + m_headerPrinted = false; + } + virtual void testGroupEnded( TestGroupStats const& _testGroupStats ) CATCH_OVERRIDE { + if( currentGroupInfo.used ) { + printSummaryDivider(); + stream << "Summary for group '" << _testGroupStats.groupInfo.name << "':\n"; + printTotals( _testGroupStats.totals ); + stream << "\n" << std::endl; + } + StreamingReporterBase::testGroupEnded( _testGroupStats ); + } + virtual void testRunEnded( TestRunStats const& _testRunStats ) CATCH_OVERRIDE { + printTotalsDivider( _testRunStats.totals ); + printTotals( _testRunStats.totals ); + stream << std::endl; + StreamingReporterBase::testRunEnded( _testRunStats ); + } + + private: + + class AssertionPrinter { + void operator= ( AssertionPrinter const& ); + public: + AssertionPrinter( std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages ) + : stream( _stream ), + stats( _stats ), + result( _stats.assertionResult ), + colour( Colour::None ), + message( result.getMessage() ), + messages( _stats.infoMessages ), + printInfoMessages( _printInfoMessages ) + { + switch( result.getResultType() ) { + case ResultWas::Ok: + colour = Colour::Success; + passOrFail = "PASSED"; + //if( result.hasMessage() ) + if( _stats.infoMessages.size() == 1 ) + messageLabel = "with message"; + if( _stats.infoMessages.size() > 1 ) + messageLabel = "with messages"; + break; + case ResultWas::ExpressionFailed: + if( result.isOk() ) { + colour = Colour::Success; + passOrFail = "FAILED - but was ok"; + } + else { + colour = Colour::Error; + passOrFail = "FAILED"; + } + if( _stats.infoMessages.size() == 1 ) + messageLabel = "with message"; + if( _stats.infoMessages.size() > 1 ) + messageLabel = "with messages"; + break; + case ResultWas::ThrewException: + colour = Colour::Error; + passOrFail = "FAILED"; + messageLabel = "due to unexpected exception with message"; + break; + case ResultWas::FatalErrorCondition: + colour = Colour::Error; + passOrFail = "FAILED"; + messageLabel = "due to a fatal error condition"; + break; + case ResultWas::DidntThrowException: + colour = Colour::Error; + passOrFail = "FAILED"; + messageLabel = "because no exception was thrown where one was expected"; + break; + case ResultWas::Info: + messageLabel = "info"; + break; + case ResultWas::Warning: + messageLabel = "warning"; + break; + case ResultWas::ExplicitFailure: + passOrFail = "FAILED"; + colour = Colour::Error; + if( _stats.infoMessages.size() == 1 ) + messageLabel = "explicitly with message"; + if( _stats.infoMessages.size() > 1 ) + messageLabel = "explicitly with messages"; + break; + // These cases are here to prevent compiler warnings + case ResultWas::Unknown: + case ResultWas::FailureBit: + case ResultWas::Exception: + passOrFail = "** internal error **"; + colour = Colour::Error; + break; + } + } + + void print() const { + printSourceInfo(); + if( stats.totals.assertions.total() > 0 ) { + if( result.isOk() ) + stream << "\n"; + printResultType(); + printOriginalExpression(); + printReconstructedExpression(); + } + else { + stream << "\n"; + } + printMessage(); + } + + private: + void printResultType() const { + if( !passOrFail.empty() ) { + Colour colourGuard( colour ); + stream << passOrFail << ":\n"; + } + } + void printOriginalExpression() const { + if( result.hasExpression() ) { + Colour colourGuard( Colour::OriginalExpression ); + stream << " "; + stream << result.getExpressionInMacro(); + stream << "\n"; + } + } + void printReconstructedExpression() const { + if( result.hasExpandedExpression() ) { + stream << "with expansion:\n"; + Colour colourGuard( Colour::ReconstructedExpression ); + stream << Text( result.getExpandedExpression(), TextAttributes().setIndent(2) ) << "\n"; + } + } + void printMessage() const { + if( !messageLabel.empty() ) + stream << messageLabel << ":" << "\n"; + for( std::vector::const_iterator it = messages.begin(), itEnd = messages.end(); + it != itEnd; + ++it ) { + // If this assertion is a warning ignore any INFO messages + if( printInfoMessages || it->type != ResultWas::Info ) + stream << Text( it->message, TextAttributes().setIndent(2) ) << "\n"; + } + } + void printSourceInfo() const { + Colour colourGuard( Colour::FileName ); + stream << result.getSourceInfo() << ": "; + } + + std::ostream& stream; + AssertionStats const& stats; + AssertionResult const& result; + Colour::Code colour; + std::string passOrFail; + std::string messageLabel; + std::string message; + std::vector messages; + bool printInfoMessages; + }; + + void lazyPrint() { + + if( !currentTestRunInfo.used ) + lazyPrintRunInfo(); + if( !currentGroupInfo.used ) + lazyPrintGroupInfo(); + + if( !m_headerPrinted ) { + printTestCaseAndSectionHeader(); + m_headerPrinted = true; + } + } + void lazyPrintRunInfo() { + stream << "\n" << getLineOfChars<'~'>() << "\n"; + Colour colour( Colour::SecondaryText ); + stream << currentTestRunInfo->name + << " is a Catch v" << libraryVersion << " host application.\n" + << "Run with -? for options\n\n"; + + if( m_config->rngSeed() != 0 ) + stream << "Randomness seeded to: " << m_config->rngSeed() << "\n\n"; + + currentTestRunInfo.used = true; + } + void lazyPrintGroupInfo() { + if( !currentGroupInfo->name.empty() && currentGroupInfo->groupsCounts > 1 ) { + printClosedHeader( "Group: " + currentGroupInfo->name ); + currentGroupInfo.used = true; + } + } + void printTestCaseAndSectionHeader() { + assert( !m_sectionStack.empty() ); + printOpenHeader( currentTestCaseInfo->name ); + + if( m_sectionStack.size() > 1 ) { + Colour colourGuard( Colour::Headers ); + + std::vector::const_iterator + it = m_sectionStack.begin()+1, // Skip first section (test case) + itEnd = m_sectionStack.end(); + for( ; it != itEnd; ++it ) + printHeaderString( it->name, 2 ); + } + + SourceLineInfo lineInfo = m_sectionStack.front().lineInfo; + + if( !lineInfo.empty() ){ + stream << getLineOfChars<'-'>() << "\n"; + Colour colourGuard( Colour::FileName ); + stream << lineInfo << "\n"; + } + stream << getLineOfChars<'.'>() << "\n" << std::endl; + } + + void printClosedHeader( std::string const& _name ) { + printOpenHeader( _name ); + stream << getLineOfChars<'.'>() << "\n"; + } + void printOpenHeader( std::string const& _name ) { + stream << getLineOfChars<'-'>() << "\n"; + { + Colour colourGuard( Colour::Headers ); + printHeaderString( _name ); + } + } + + // if string has a : in first line will set indent to follow it on + // subsequent lines + void printHeaderString( std::string const& _string, std::size_t indent = 0 ) { + std::size_t i = _string.find( ": " ); + if( i != std::string::npos ) + i+=2; + else + i = 0; + stream << Text( _string, TextAttributes() + .setIndent( indent+i) + .setInitialIndent( indent ) ) << "\n"; + } + + struct SummaryColumn { + + SummaryColumn( std::string const& _label, Colour::Code _colour ) + : label( _label ), + colour( _colour ) + {} + SummaryColumn addRow( std::size_t count ) { + std::ostringstream oss; + oss << count; + std::string row = oss.str(); + for( std::vector::iterator it = rows.begin(); it != rows.end(); ++it ) { + while( it->size() < row.size() ) + *it = " " + *it; + while( it->size() > row.size() ) + row = " " + row; + } + rows.push_back( row ); + return *this; + } + + std::string label; + Colour::Code colour; + std::vector rows; + + }; + + void printTotals( Totals const& totals ) { + if( totals.testCases.total() == 0 ) { + stream << Colour( Colour::Warning ) << "No tests ran\n"; + } + else if( totals.assertions.total() > 0 && totals.assertions.allPassed() ) { + stream << Colour( Colour::ResultSuccess ) << "All tests passed"; + stream << " (" + << pluralise( totals.assertions.passed, "assertion" ) << " in " + << pluralise( totals.testCases.passed, "test case" ) << ")" + << "\n"; + } + else { + + std::vector columns; + columns.push_back( SummaryColumn( "", Colour::None ) + .addRow( totals.testCases.total() ) + .addRow( totals.assertions.total() ) ); + columns.push_back( SummaryColumn( "passed", Colour::Success ) + .addRow( totals.testCases.passed ) + .addRow( totals.assertions.passed ) ); + columns.push_back( SummaryColumn( "failed", Colour::ResultError ) + .addRow( totals.testCases.failed ) + .addRow( totals.assertions.failed ) ); + columns.push_back( SummaryColumn( "failed as expected", Colour::ResultExpectedFailure ) + .addRow( totals.testCases.failedButOk ) + .addRow( totals.assertions.failedButOk ) ); + + printSummaryRow( "test cases", columns, 0 ); + printSummaryRow( "assertions", columns, 1 ); + } + } + void printSummaryRow( std::string const& label, std::vector const& cols, std::size_t row ) { + for( std::vector::const_iterator it = cols.begin(); it != cols.end(); ++it ) { + std::string value = it->rows[row]; + if( it->label.empty() ) { + stream << label << ": "; + if( value != "0" ) + stream << value; + else + stream << Colour( Colour::Warning ) << "- none -"; + } + else if( value != "0" ) { + stream << Colour( Colour::LightGrey ) << " | "; + stream << Colour( it->colour ) + << value << " " << it->label; + } + } + stream << "\n"; + } + + static std::size_t makeRatio( std::size_t number, std::size_t total ) { + std::size_t ratio = total > 0 ? CATCH_CONFIG_CONSOLE_WIDTH * number/ total : 0; + return ( ratio == 0 && number > 0 ) ? 1 : ratio; + } + static std::size_t& findMax( std::size_t& i, std::size_t& j, std::size_t& k ) { + if( i > j && i > k ) + return i; + else if( j > k ) + return j; + else + return k; + } + + void printTotalsDivider( Totals const& totals ) { + if( totals.testCases.total() > 0 ) { + std::size_t failedRatio = makeRatio( totals.testCases.failed, totals.testCases.total() ); + std::size_t failedButOkRatio = makeRatio( totals.testCases.failedButOk, totals.testCases.total() ); + std::size_t passedRatio = makeRatio( totals.testCases.passed, totals.testCases.total() ); + while( failedRatio + failedButOkRatio + passedRatio < CATCH_CONFIG_CONSOLE_WIDTH-1 ) + findMax( failedRatio, failedButOkRatio, passedRatio )++; + while( failedRatio + failedButOkRatio + passedRatio > CATCH_CONFIG_CONSOLE_WIDTH-1 ) + findMax( failedRatio, failedButOkRatio, passedRatio )--; + + stream << Colour( Colour::Error ) << std::string( failedRatio, '=' ); + stream << Colour( Colour::ResultExpectedFailure ) << std::string( failedButOkRatio, '=' ); + if( totals.testCases.allPassed() ) + stream << Colour( Colour::ResultSuccess ) << std::string( passedRatio, '=' ); + else + stream << Colour( Colour::Success ) << std::string( passedRatio, '=' ); + } + else { + stream << Colour( Colour::Warning ) << std::string( CATCH_CONFIG_CONSOLE_WIDTH-1, '=' ); + } + stream << "\n"; + } + void printSummaryDivider() { + stream << getLineOfChars<'-'>() << "\n"; + } + + private: + bool m_headerPrinted; + }; + + INTERNAL_CATCH_REGISTER_REPORTER( "console", ConsoleReporter ) + +} // end namespace Catch + +// #included from: ../reporters/catch_reporter_compact.hpp +#define TWOBLUECUBES_CATCH_REPORTER_COMPACT_HPP_INCLUDED + +namespace Catch { + + struct CompactReporter : StreamingReporterBase { + + CompactReporter( ReporterConfig const& _config ) + : StreamingReporterBase( _config ) + {} + + virtual ~CompactReporter(); + + static std::string getDescription() { + return "Reports test results on a single line, suitable for IDEs"; + } + + virtual ReporterPreferences getPreferences() const { + ReporterPreferences prefs; + prefs.shouldRedirectStdOut = false; + return prefs; + } + + virtual void noMatchingTestCases( std::string const& spec ) { + stream << "No test cases matched '" << spec << "'" << std::endl; + } + + virtual void assertionStarting( AssertionInfo const& ) { + } + + virtual bool assertionEnded( AssertionStats const& _assertionStats ) { + AssertionResult const& result = _assertionStats.assertionResult; + + bool printInfoMessages = true; + + // Drop out if result was successful and we're not printing those + if( !m_config->includeSuccessfulResults() && result.isOk() ) { + if( result.getResultType() != ResultWas::Warning ) + return false; + printInfoMessages = false; + } + + AssertionPrinter printer( stream, _assertionStats, printInfoMessages ); + printer.print(); + + stream << std::endl; + return true; + } + + virtual void testRunEnded( TestRunStats const& _testRunStats ) { + printTotals( _testRunStats.totals ); + stream << "\n" << std::endl; + StreamingReporterBase::testRunEnded( _testRunStats ); + } + + private: + class AssertionPrinter { + void operator= ( AssertionPrinter const& ); + public: + AssertionPrinter( std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages ) + : stream( _stream ) + , stats( _stats ) + , result( _stats.assertionResult ) + , messages( _stats.infoMessages ) + , itMessage( _stats.infoMessages.begin() ) + , printInfoMessages( _printInfoMessages ) + {} + + void print() { + printSourceInfo(); + + itMessage = messages.begin(); + + switch( result.getResultType() ) { + case ResultWas::Ok: + printResultType( Colour::ResultSuccess, passedString() ); + printOriginalExpression(); + printReconstructedExpression(); + if ( ! result.hasExpression() ) + printRemainingMessages( Colour::None ); + else + printRemainingMessages(); + break; + case ResultWas::ExpressionFailed: + if( result.isOk() ) + printResultType( Colour::ResultSuccess, failedString() + std::string( " - but was ok" ) ); + else + printResultType( Colour::Error, failedString() ); + printOriginalExpression(); + printReconstructedExpression(); + printRemainingMessages(); + break; + case ResultWas::ThrewException: + printResultType( Colour::Error, failedString() ); + printIssue( "unexpected exception with message:" ); + printMessage(); + printExpressionWas(); + printRemainingMessages(); + break; + case ResultWas::FatalErrorCondition: + printResultType( Colour::Error, failedString() ); + printIssue( "fatal error condition with message:" ); + printMessage(); + printExpressionWas(); + printRemainingMessages(); + break; + case ResultWas::DidntThrowException: + printResultType( Colour::Error, failedString() ); + printIssue( "expected exception, got none" ); + printExpressionWas(); + printRemainingMessages(); + break; + case ResultWas::Info: + printResultType( Colour::None, "info" ); + printMessage(); + printRemainingMessages(); + break; + case ResultWas::Warning: + printResultType( Colour::None, "warning" ); + printMessage(); + printRemainingMessages(); + break; + case ResultWas::ExplicitFailure: + printResultType( Colour::Error, failedString() ); + printIssue( "explicitly" ); + printRemainingMessages( Colour::None ); + break; + // These cases are here to prevent compiler warnings + case ResultWas::Unknown: + case ResultWas::FailureBit: + case ResultWas::Exception: + printResultType( Colour::Error, "** internal error **" ); + break; + } + } + + private: + // Colour::LightGrey + + static Colour::Code dimColour() { return Colour::FileName; } + +#ifdef CATCH_PLATFORM_MAC + static const char* failedString() { return "FAILED"; } + static const char* passedString() { return "PASSED"; } +#else + static const char* failedString() { return "failed"; } + static const char* passedString() { return "passed"; } +#endif + + void printSourceInfo() const { + Colour colourGuard( Colour::FileName ); + stream << result.getSourceInfo() << ":"; + } + + void printResultType( Colour::Code colour, std::string passOrFail ) const { + if( !passOrFail.empty() ) { + { + Colour colourGuard( colour ); + stream << " " << passOrFail; + } + stream << ":"; + } + } + + void printIssue( std::string issue ) const { + stream << " " << issue; + } + + void printExpressionWas() { + if( result.hasExpression() ) { + stream << ";"; + { + Colour colour( dimColour() ); + stream << " expression was:"; + } + printOriginalExpression(); + } + } + + void printOriginalExpression() const { + if( result.hasExpression() ) { + stream << " " << result.getExpression(); + } + } + + void printReconstructedExpression() const { + if( result.hasExpandedExpression() ) { + { + Colour colour( dimColour() ); + stream << " for: "; + } + stream << result.getExpandedExpression(); + } + } + + void printMessage() { + if ( itMessage != messages.end() ) { + stream << " '" << itMessage->message << "'"; + ++itMessage; + } + } + + void printRemainingMessages( Colour::Code colour = dimColour() ) { + if ( itMessage == messages.end() ) + return; + + // using messages.end() directly yields compilation error: + std::vector::const_iterator itEnd = messages.end(); + const std::size_t N = static_cast( std::distance( itMessage, itEnd ) ); + + { + Colour colourGuard( colour ); + stream << " with " << pluralise( N, "message" ) << ":"; + } + + for(; itMessage != itEnd; ) { + // If this assertion is a warning ignore any INFO messages + if( printInfoMessages || itMessage->type != ResultWas::Info ) { + stream << " '" << itMessage->message << "'"; + if ( ++itMessage != itEnd ) { + Colour colourGuard( dimColour() ); + stream << " and"; + } + } + } + } + + private: + std::ostream& stream; + AssertionStats const& stats; + AssertionResult const& result; + std::vector messages; + std::vector::const_iterator itMessage; + bool printInfoMessages; + }; + + // Colour, message variants: + // - white: No tests ran. + // - red: Failed [both/all] N test cases, failed [both/all] M assertions. + // - white: Passed [both/all] N test cases (no assertions). + // - red: Failed N tests cases, failed M assertions. + // - green: Passed [both/all] N tests cases with M assertions. + + std::string bothOrAll( std::size_t count ) const { + return count == 1 ? "" : count == 2 ? "both " : "all " ; + } + + void printTotals( const Totals& totals ) const { + if( totals.testCases.total() == 0 ) { + stream << "No tests ran."; + } + else if( totals.testCases.failed == totals.testCases.total() ) { + Colour colour( Colour::ResultError ); + const std::string qualify_assertions_failed = + totals.assertions.failed == totals.assertions.total() ? + bothOrAll( totals.assertions.failed ) : ""; + stream << + "Failed " << bothOrAll( totals.testCases.failed ) + << pluralise( totals.testCases.failed, "test case" ) << ", " + "failed " << qualify_assertions_failed << + pluralise( totals.assertions.failed, "assertion" ) << "."; + } + else if( totals.assertions.total() == 0 ) { + stream << + "Passed " << bothOrAll( totals.testCases.total() ) + << pluralise( totals.testCases.total(), "test case" ) + << " (no assertions)."; + } + else if( totals.assertions.failed ) { + Colour colour( Colour::ResultError ); + stream << + "Failed " << pluralise( totals.testCases.failed, "test case" ) << ", " + "failed " << pluralise( totals.assertions.failed, "assertion" ) << "."; + } + else { + Colour colour( Colour::ResultSuccess ); + stream << + "Passed " << bothOrAll( totals.testCases.passed ) + << pluralise( totals.testCases.passed, "test case" ) << + " with " << pluralise( totals.assertions.passed, "assertion" ) << "."; + } + } + }; + + INTERNAL_CATCH_REGISTER_REPORTER( "compact", CompactReporter ) + +} // end namespace Catch + +namespace Catch { + // These are all here to avoid warnings about not having any out of line + // virtual methods + NonCopyable::~NonCopyable() {} + IShared::~IShared() {} + IStream::~IStream() CATCH_NOEXCEPT {} + FileStream::~FileStream() CATCH_NOEXCEPT {} + CoutStream::~CoutStream() CATCH_NOEXCEPT {} + DebugOutStream::~DebugOutStream() CATCH_NOEXCEPT {} + StreamBufBase::~StreamBufBase() CATCH_NOEXCEPT {} + IContext::~IContext() {} + IResultCapture::~IResultCapture() {} + ITestCase::~ITestCase() {} + ITestCaseRegistry::~ITestCaseRegistry() {} + IRegistryHub::~IRegistryHub() {} + IMutableRegistryHub::~IMutableRegistryHub() {} + IExceptionTranslator::~IExceptionTranslator() {} + IExceptionTranslatorRegistry::~IExceptionTranslatorRegistry() {} + IReporter::~IReporter() {} + IReporterFactory::~IReporterFactory() {} + IReporterRegistry::~IReporterRegistry() {} + IStreamingReporter::~IStreamingReporter() {} + AssertionStats::~AssertionStats() {} + SectionStats::~SectionStats() {} + TestCaseStats::~TestCaseStats() {} + TestGroupStats::~TestGroupStats() {} + TestRunStats::~TestRunStats() {} + CumulativeReporterBase::SectionNode::~SectionNode() {} + CumulativeReporterBase::~CumulativeReporterBase() {} + + StreamingReporterBase::~StreamingReporterBase() {} + ConsoleReporter::~ConsoleReporter() {} + CompactReporter::~CompactReporter() {} + IRunner::~IRunner() {} + IMutableContext::~IMutableContext() {} + IConfig::~IConfig() {} + XmlReporter::~XmlReporter() {} + JunitReporter::~JunitReporter() {} + TestRegistry::~TestRegistry() {} + FreeFunctionTestCase::~FreeFunctionTestCase() {} + IGeneratorInfo::~IGeneratorInfo() {} + IGeneratorsForTest::~IGeneratorsForTest() {} + WildcardPattern::~WildcardPattern() {} + TestSpec::Pattern::~Pattern() {} + TestSpec::NamePattern::~NamePattern() {} + TestSpec::TagPattern::~TagPattern() {} + TestSpec::ExcludedPattern::~ExcludedPattern() {} + + Matchers::Impl::StdString::Equals::~Equals() {} + Matchers::Impl::StdString::Contains::~Contains() {} + Matchers::Impl::StdString::StartsWith::~StartsWith() {} + Matchers::Impl::StdString::EndsWith::~EndsWith() {} + + void Config::dummy() {} + + namespace TestCaseTracking { + ITracker::~ITracker() {} + TrackerBase::~TrackerBase() {} + SectionTracker::~SectionTracker() {} + IndexTracker::~IndexTracker() {} + } +} + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +#endif + +#ifdef CATCH_CONFIG_MAIN +// #included from: internal/catch_default_main.hpp +#define TWOBLUECUBES_CATCH_DEFAULT_MAIN_HPP_INCLUDED + +#ifndef __OBJC__ + +// Standard C/C++ main entry point +int main (int argc, char * argv[]) { + return Catch::Session().run( argc, argv ); +} + +#else // __OBJC__ + +// Objective-C entry point +int main (int argc, char * const argv[]) { +#if !CATCH_ARC_ENABLED + NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; +#endif + + Catch::registerTestMethods(); + int result = Catch::Session().run( argc, (char* const*)argv ); + +#if !CATCH_ARC_ENABLED + [pool drain]; +#endif + + return result; +} + +#endif // __OBJC__ + +#endif + +#ifdef CLARA_CONFIG_MAIN_NOT_DEFINED +# undef CLARA_CONFIG_MAIN +#endif + +////// + +// If this config identifier is defined then all CATCH macros are prefixed with CATCH_ +#ifdef CATCH_CONFIG_PREFIX_ALL + +#define CATCH_REQUIRE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE" ) +#define CATCH_REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, "CATCH_REQUIRE_FALSE" ) + +#define CATCH_REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, "", "CATCH_REQUIRE_THROWS" ) +#define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THROWS_AS" ) +#define CATCH_REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, matcher, "CATCH_REQUIRE_THROWS_WITH" ) +#define CATCH_REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_NOTHROW" ) + +#define CATCH_CHECK( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK" ) +#define CATCH_CHECK_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, "CATCH_CHECK_FALSE" ) +#define CATCH_CHECKED_IF( expr ) INTERNAL_CATCH_IF( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECKED_IF" ) +#define CATCH_CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECKED_ELSE" ) +#define CATCH_CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, "CATCH_CHECK_NOFAIL" ) + +#define CATCH_CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THROWS" ) +#define CATCH_CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THROWS_AS" ) +#define CATCH_CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, matcher, "CATCH_CHECK_THROWS_WITH" ) +#define CATCH_CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_NOTHROW" ) + +#define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THAT" ) +#define CATCH_REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THAT" ) + +#define CATCH_INFO( msg ) INTERNAL_CATCH_INFO( msg, "CATCH_INFO" ) +#define CATCH_WARN( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, "CATCH_WARN", msg ) +#define CATCH_SCOPED_INFO( msg ) INTERNAL_CATCH_INFO( msg, "CATCH_INFO" ) +#define CATCH_CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CATCH_CAPTURE" ) +#define CATCH_SCOPED_CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CATCH_CAPTURE" ) + +#ifdef CATCH_CONFIG_VARIADIC_MACROS + #define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ ) + #define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ ) + #define CATCH_METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ ) + #define CATCH_REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ ) + #define CATCH_SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) + #define CATCH_FAIL( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "CATCH_FAIL", __VA_ARGS__ ) + #define CATCH_SUCCEED( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "CATCH_SUCCEED", __VA_ARGS__ ) +#else + #define CATCH_TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description ) + #define CATCH_TEST_CASE_METHOD( className, name, description ) INTERNAL_CATCH_TEST_CASE_METHOD( className, name, description ) + #define CATCH_METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description ) + #define CATCH_REGISTER_TEST_CASE( function, name, description ) INTERNAL_CATCH_REGISTER_TESTCASE( function, name, description ) + #define CATCH_SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description ) + #define CATCH_FAIL( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "CATCH_FAIL", msg ) + #define CATCH_SUCCEED( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "CATCH_SUCCEED", msg ) +#endif +#define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE( "", "" ) + +#define CATCH_REGISTER_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) +#define CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) + +#define CATCH_GENERATE( expr) INTERNAL_CATCH_GENERATE( expr ) + +// "BDD-style" convenience wrappers +#ifdef CATCH_CONFIG_VARIADIC_MACROS +#define CATCH_SCENARIO( ... ) CATCH_TEST_CASE( "Scenario: " __VA_ARGS__ ) +#define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ ) +#else +#define CATCH_SCENARIO( name, tags ) CATCH_TEST_CASE( "Scenario: " name, tags ) +#define CATCH_SCENARIO_METHOD( className, name, tags ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " name, tags ) +#endif +#define CATCH_GIVEN( desc ) CATCH_SECTION( std::string( "Given: ") + desc, "" ) +#define CATCH_WHEN( desc ) CATCH_SECTION( std::string( " When: ") + desc, "" ) +#define CATCH_AND_WHEN( desc ) CATCH_SECTION( std::string( " And: ") + desc, "" ) +#define CATCH_THEN( desc ) CATCH_SECTION( std::string( " Then: ") + desc, "" ) +#define CATCH_AND_THEN( desc ) CATCH_SECTION( std::string( " And: ") + desc, "" ) + +// If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required +#else + +#define REQUIRE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal, "REQUIRE" ) +#define REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, "REQUIRE_FALSE" ) + +#define REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, "", "REQUIRE_THROWS" ) +#define REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::Normal, "REQUIRE_THROWS_AS" ) +#define REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, matcher, "REQUIRE_THROWS_WITH" ) +#define REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::Normal, "REQUIRE_NOTHROW" ) + +#define CHECK( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK" ) +#define CHECK_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, "CHECK_FALSE" ) +#define CHECKED_IF( expr ) INTERNAL_CATCH_IF( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECKED_IF" ) +#define CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECKED_ELSE" ) +#define CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, "CHECK_NOFAIL" ) + +#define CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, "", "CHECK_THROWS" ) +#define CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THROWS_AS" ) +#define CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, matcher, "CHECK_THROWS_WITH" ) +#define CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK_NOTHROW" ) + +#define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THAT" ) +#define REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::Normal, "REQUIRE_THAT" ) + +#define INFO( msg ) INTERNAL_CATCH_INFO( msg, "INFO" ) +#define WARN( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, "WARN", msg ) +#define SCOPED_INFO( msg ) INTERNAL_CATCH_INFO( msg, "INFO" ) +#define CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CAPTURE" ) +#define SCOPED_CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CAPTURE" ) + +#ifdef CATCH_CONFIG_VARIADIC_MACROS + #define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ ) + #define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ ) + #define METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ ) + #define REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ ) + #define SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) + #define FAIL( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "FAIL", __VA_ARGS__ ) + #define SUCCEED( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "SUCCEED", __VA_ARGS__ ) +#else + #define TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description ) + #define TEST_CASE_METHOD( className, name, description ) INTERNAL_CATCH_TEST_CASE_METHOD( className, name, description ) + #define METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description ) + #define REGISTER_TEST_CASE( method, name, description ) INTERNAL_CATCH_REGISTER_TESTCASE( method, name, description ) + #define SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description ) + #define FAIL( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "FAIL", msg ) + #define SUCCEED( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "SUCCEED", msg ) +#endif +#define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE( "", "" ) + +#define REGISTER_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) +#define REGISTER_LEGACY_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) + +#define GENERATE( expr) INTERNAL_CATCH_GENERATE( expr ) + +#endif + +#define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) + +// "BDD-style" convenience wrappers +#ifdef CATCH_CONFIG_VARIADIC_MACROS +#define SCENARIO( ... ) TEST_CASE( "Scenario: " __VA_ARGS__ ) +#define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ ) +#else +#define SCENARIO( name, tags ) TEST_CASE( "Scenario: " name, tags ) +#define SCENARIO_METHOD( className, name, tags ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " name, tags ) +#endif +#define GIVEN( desc ) SECTION( std::string(" Given: ") + desc, "" ) +#define WHEN( desc ) SECTION( std::string(" When: ") + desc, "" ) +#define AND_WHEN( desc ) SECTION( std::string("And when: ") + desc, "" ) +#define THEN( desc ) SECTION( std::string(" Then: ") + desc, "" ) +#define AND_THEN( desc ) SECTION( std::string(" And: ") + desc, "" ) + +using Catch::Detail::Approx; + +#endif // TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED + diff --git a/CUDA_ListScan/libwb/vendor/json11.cpp b/CUDA_ListScan/libwb/vendor/json11.cpp new file mode 100644 index 0000000..f401c26 --- /dev/null +++ b/CUDA_ListScan/libwb/vendor/json11.cpp @@ -0,0 +1,1013 @@ +/* Copyright (c) 2013 Dropbox, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy + * of this software and associated documentation files (the "Software"), to + * deal + * in the Software without restriction, including without limitation the + * rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN + * THE SOFTWARE. + */ + +#include "json11.hpp" +#include +#include +#include +#include +#include +#include + +namespace json11 { + +static const int max_depth = 200; + +using std::string; +using std::vector; +using std::map; +using std::make_shared; +using std::initializer_list; +using std::move; + +/* * * * * * * * * * * * * * * * * * * * + * Serialization + */ + +static void dump(std::nullptr_t, string &out) { + out += "null"; +} + +static void dump(double value, string &out) { + if (std::isfinite(value)) { + char buf[32]; +//PMO +#ifndef _MSC_VER + snprintf(buf, sizeof buf, "%.17g", value); +#else + _snprintf_s(buf, sizeof buf, "%.17g", value); +#endif + out += buf; + } else { + out += "null"; + } +} + +static void dump(int value, string &out) { + char buf[32]; +//PMO +#ifndef _MSC_VER + snprintf(buf, sizeof buf, "%d", value); +#else + _snprintf_s(buf, sizeof buf, "%d", value); +#endif + out += buf; +} + +static void dump(int64_t value, string &out) { + char buf[64]; +//PMO +#ifndef _MSC_VER + snprintf(buf, sizeof buf, "%" PRId64, value); +#else + _snprintf_s(buf, sizeof buf, "%" PRId64, value); +#endif + out += buf; +} + +static void dump(uint64_t value, string &out) { + char buf[128]; +//PMO +#ifndef _MSC_VER + snprintf(buf, sizeof buf, "%" PRIu64, value); +#else + _snprintf_s(buf, sizeof buf, "%" PRIu64, value); +#endif + out += buf; +} + +static void dump(bool value, string &out) { + out += value ? "true" : "false"; +} + +static void dump(const string &value, string &out) { + out += '"'; + for (size_t i = 0; i < value.length(); i++) { + const char ch = value[i]; + if (ch == '\\') { + out += "\\\\"; + } else if (ch == '"') { + out += "\\\""; + } else if (ch == '\b') { + out += "\\b"; + } else if (ch == '\f') { + out += "\\f"; + } else if (ch == '\n') { + out += "\\n"; + } else if (ch == '\r') { + out += "\\r"; + } else if (ch == '\t') { + out += "\\t"; + } else if (static_cast(ch) <= 0x1f) { + char buf[8]; +//PMO +#ifndef _MSC_VER + snprintf(buf, sizeof buf, "\\u%04x", ch); +#else + _snprintf_s(buf, sizeof buf, "\\u%04x", ch); +#endif + out += buf; + } else if (static_cast(ch) == 0xe2 && + static_cast(value[i + 1]) == 0x80 && + static_cast(value[i + 2]) == 0xa8) { + out += "\\u2028"; + i += 2; + } else if (static_cast(ch) == 0xe2 && + static_cast(value[i + 1]) == 0x80 && + static_cast(value[i + 2]) == 0xa9) { + out += "\\u2029"; + i += 2; + } else { + out += ch; + } + } + out += '"'; +} + +static void dump(const Json::array &values, string &out) { + bool first = true; + out += "["; + for (const auto &value : values) { + if (!first) + out += ", "; + value.dump(out); + first = false; + } + out += "]"; +} + +static void dump(const Json::object &values, string &out) { + bool first = true; + out += "{"; + for (const auto &kv : values) { + if (!first) + out += ", "; + dump(kv.first, out); + out += ": "; + kv.second.dump(out); + first = false; + } + out += "}"; +} + +void Json::dump(string &out) const { + m_ptr->dump(out); +} + +/* * * * * * * * * * * * * * * * * * * * + * Value wrappers + */ + +template +class Value : public JsonValue { +protected: + // Constructors + explicit Value(const T &value) : m_value(value) { + } + explicit Value(T &&value) : m_value(move(value)) { + } + + // Get type tag + Json::Type type() const override { + return tag; + } + + // Comparisons + bool equals(const JsonValue *other) const override { + return m_value == static_cast *>(other)->m_value; + } + bool less(const JsonValue *other) const override { + return m_value < static_cast *>(other)->m_value; + } + + const T m_value; + void dump(string &out) const override { + json11::dump(m_value, out); + } +}; + +class JsonDouble final : public Value { + double number_value() const override { + return m_value; + } + int int_value() const override { + return static_cast(m_value); + } + int64_t int64_value() const override { + return (int64_t)m_value; + } + uint64_t uint64_value() const override { + return (uint64_t)m_value; + } + bool equals(const JsonValue *other) const override { + return m_value == other->number_value(); + } + bool less(const JsonValue *other) const override { + return m_value < other->number_value(); + } + +public: + explicit JsonDouble(double value) : Value(value) { + } +}; + +class JsonInt final : public Value { + double number_value() const override { + return m_value; + } + int int_value() const override { + return m_value; + } + int64_t int64_value() const override { + return m_value; + } + uint64_t uint64_value() const override { + return m_value; + } + bool equals(const JsonValue *other) const override { + return m_value == other->number_value(); + } + bool less(const JsonValue *other) const override { + return m_value < other->number_value(); + } + +public: + explicit JsonInt(int value) : Value(value) { + } +}; + +class JsonInt64 final : public Value { + double number_value() const override { + return m_value; + } + int int_value() const override { + return (int)m_value; + } + int64_t int64_value() const override { + return m_value; + } + uint64_t uint64_value() const override { + return (uint64_t)m_value; + } + bool equals(const JsonValue *other) const override { + return m_value == other->number_value(); + } + bool less(const JsonValue *other) const override { + return m_value < other->number_value(); + } + +public: + explicit JsonInt64(int64_t value) : Value(value) { + } +}; + +class JsonUInt64 final : public Value { + double number_value() const override { + return m_value; + } + int int_value() const override { + return (int)m_value; + } + int64_t int64_value() const override { + return (int64_t)m_value; + } + uint64_t uint64_value() const override { + return m_value; + } + bool equals(const JsonValue *other) const override { + return m_value == other->number_value(); + } + bool less(const JsonValue *other) const override { + return m_value < other->number_value(); + } + +public: + explicit JsonUInt64(uint64_t value) : Value(value) { + } +}; + +class JsonBoolean final : public Value { + bool bool_value() const override { + return m_value; + } + +public: + explicit JsonBoolean(bool value) : Value(value) { + } +}; + +class JsonString final : public Value { + const string &string_value() const override { + return m_value; + } + +public: + explicit JsonString(const string &value) : Value(value) { + } + explicit JsonString(string &&value) : Value(move(value)) { + } +}; + +class JsonArray final : public Value { + const Json::array &array_items() const override { + return m_value; + } + const Json &operator[](size_t i) const override; + +public: + explicit JsonArray(const Json::array &value) : Value(value) { + } + explicit JsonArray(Json::array &&value) : Value(move(value)) { + } +}; + +class JsonObject final : public Value { + const Json::object &object_items() const override { + return m_value; + } + const Json &operator[](const string &key) const override; + +public: + explicit JsonObject(const Json::object &value) : Value(value) { + } + explicit JsonObject(Json::object &&value) : Value(move(value)) { + } +}; + +class JsonNull final : public Value { +public: + JsonNull() : Value(nullptr) { + } +}; + +/* * * * * * * * * * * * * * * * * * * * + * Static globals - static-init-safe + */ +struct Statics { + const std::shared_ptr null = make_shared(); + const std::shared_ptr t = make_shared(true); + const std::shared_ptr f = make_shared(false); + const string empty_string; + const vector empty_vector; + const map empty_map; + Statics() { + } +}; + +static const Statics &statics() { + static const Statics s{}; + return s; +} + +static const Json &static_null() { + // This has to be separate, not in Statics, because Json() accesses + // statics().null. + static const Json json_null; + return json_null; +} + +/* * * * * * * * * * * * * * * * * * * * + * Constructors + */ + +Json::Json() NOEXCEPT : m_ptr(statics().null) { +} +Json::Json(std::nullptr_t) NOEXCEPT : m_ptr(statics().null) { +} +Json::Json(double value) : m_ptr(make_shared(value)) { +} +Json::Json(int value) : m_ptr(make_shared(value)) { +} +Json::Json(int64_t value) : m_ptr(make_shared(value)) { +} +Json::Json(uint64_t value) : m_ptr(make_shared(value)) { +} +Json::Json(bool value) : m_ptr(value ? statics().t : statics().f) { +} +Json::Json(const string &value) : m_ptr(make_shared(value)) { +} +Json::Json(string &&value) : m_ptr(make_shared(move(value))) { +} +Json::Json(const char *value) : m_ptr(make_shared(value)) { +} +Json::Json(const Json::array &values) + : m_ptr(make_shared(values)) { +} +Json::Json(Json::array &&values) + : m_ptr(make_shared(move(values))) { +} +Json::Json(const Json::object &values) + : m_ptr(make_shared(values)) { +} +Json::Json(Json::object &&values) + : m_ptr(make_shared(move(values))) { +} + +/* * * * * * * * * * * * * * * * * * * * + * Accessors + */ + +Json::Type Json::type() const { + return m_ptr->type(); +} +double Json::number_value() const { + return m_ptr->number_value(); +} +int Json::int_value() const { + return m_ptr->int_value(); +} +int64_t Json::int64_value() const { + return m_ptr->int64_value(); +} +uint64_t Json::uint64_value() const { + return m_ptr->uint64_value(); +} +bool Json::bool_value() const { + return m_ptr->bool_value(); +} +const string &Json::string_value() const { + return m_ptr->string_value(); +} +const vector &Json::array_items() const { + return m_ptr->array_items(); +} +const map &Json::object_items() const { + return m_ptr->object_items(); +} +const Json &Json::operator[](size_t i) const { + return (*m_ptr)[i]; +} +const Json &Json::operator[](const string &key) const { + return (*m_ptr)[key]; +} + +double JsonValue::number_value() const { + return 0; +} +int JsonValue::int_value() const { + return 0; +} +int64_t JsonValue::int64_value() const { + return 0; +} +uint64_t JsonValue::uint64_value() const { + return 0; +} +bool JsonValue::bool_value() const { + return false; +} +const string &JsonValue::string_value() const { + return statics().empty_string; +} +const vector &JsonValue::array_items() const { + return statics().empty_vector; +} +const map &JsonValue::object_items() const { + return statics().empty_map; +} +const Json &JsonValue::operator[](size_t) const { + return static_null(); +} +const Json &JsonValue::operator[](const string &) const { + return static_null(); +} + +const Json &JsonObject::operator[](const string &key) const { + auto iter = m_value.find(key); + return (iter == m_value.end()) ? static_null() : iter->second; +} +const Json &JsonArray::operator[](size_t i) const { + if (i >= m_value.size()) + return static_null(); + else + return m_value[i]; +} + +/* * * * * * * * * * * * * * * * * * * * + * Comparison + */ + +bool Json::operator==(const Json &other) const { + if (m_ptr->type() != other.m_ptr->type()) + return false; + + return m_ptr->equals(other.m_ptr.get()); +} + +bool Json::operator<(const Json &other) const { + if (m_ptr->type() != other.m_ptr->type()) + return m_ptr->type() < other.m_ptr->type(); + + return m_ptr->less(other.m_ptr.get()); +} + +/* * * * * * * * * * * * * * * * * * * * + * Parsing + */ + +/* esc(c) + * + * Format char c suitable for printing in an error message. + */ +static inline string esc(char c) { + char buf[12]; + if (static_cast(c) >= 0x20 && static_cast(c) <= 0x7f) { +//PMO +#ifndef _MSC_VER + snprintf(buf, sizeof buf, "'%c' (%d)", c, c); +#else + _snprintf_s(buf, sizeof buf, "'%c' (%d)", c, c); +#endif + } else { +//PMO +#ifndef _MSC_VER + snprintf(buf, sizeof buf, "(%d)", c); +#else + _snprintf_s(buf, sizeof buf, "(%d)", c); +#endif + } + return string(buf); +} + +static inline bool in_range(long x, long lower, long upper) { + return (x >= lower && x <= upper); +} + +/* JsonParser + * + * Object that tracks all state of an in-progress parse. + */ +struct JsonParser { + + /* State + */ + const string &str; + size_t i; + string &err; + bool failed; + const JsonParse strategy; + + /* fail(msg, err_ret = Json()) + * + * Mark this parse as failed. + */ + Json fail(string &&msg) { + return fail(move(msg), Json()); + } + + template + T fail(string &&msg, const T err_ret) { + if (!failed) + err = std::move(msg); + failed = true; + return err_ret; + } + + /* consume_whitespace() + * + * Advance until the current character is non-whitespace. + */ + void consume_whitespace() { + while (str[i] == ' ' || str[i] == '\r' || str[i] == '\n' || + str[i] == '\t') + i++; + } + + /* consume_comment() + * + * Advance comments (c-style inline and multiline). + */ + bool consume_comment() { + bool comment_found = false; + if (str[i] == '/') { + i++; + if (i == str.size()) + return fail("unexpected end of input inside comment", 0); + if (str[i] == '/') { // inline comment + i++; + if (i == str.size()) + return fail("unexpected end of input inside inline comment", 0); + // advance until next line + while (str[i] != '\n') { + i++; + if (i == str.size()) + return fail("unexpected end of input inside inline comment", + 0); + } + comment_found = true; + } else if (str[i] == '*') { // multiline comment + i++; + if (i > str.size() - 2) + return fail("unexpected end of input inside multi-line comment", + 0); + // advance until closing tokens + while (!(str[i] == '*' && str[i + 1] == '/')) { + i++; + if (i > str.size() - 2) + return fail( + "unexpected end of input inside multi-line comment", 0); + } + i += 2; + if (i == str.size()) + return fail("unexpected end of input inside multi-line comment", + 0); + comment_found = true; + } else + return fail("malformed comment", 0); + } + return comment_found; + } + + /* consume_garbage() + * + * Advance until the current character is non-whitespace and non-comment. + */ + void consume_garbage() { + consume_whitespace(); + if (strategy == JsonParse::COMMENTS) { + bool comment_found = false; + do { + comment_found = consume_comment(); + consume_whitespace(); + } while (comment_found); + } + } + + /* get_next_token() + * + * Return the next non-whitespace character. If the end of the input is + * reached, + * flag an error and return 0. + */ + char get_next_token() { + consume_garbage(); + if (i == str.size()) + return fail("unexpected end of input", 0); + + return str[i++]; + } + + /* encode_utf8(pt, out) + * + * Encode pt as UTF-8 and add it to out. + */ + void encode_utf8(long pt, string &out) { + if (pt < 0) + return; + + if (pt < 0x80) { + out += static_cast(pt); + } else if (pt < 0x800) { + out += static_cast((pt >> 6) | 0xC0); + out += static_cast((pt & 0x3F) | 0x80); + } else if (pt < 0x10000) { + out += static_cast((pt >> 12) | 0xE0); + out += static_cast(((pt >> 6) & 0x3F) | 0x80); + out += static_cast((pt & 0x3F) | 0x80); + } else { + out += static_cast((pt >> 18) | 0xF0); + out += static_cast(((pt >> 12) & 0x3F) | 0x80); + out += static_cast(((pt >> 6) & 0x3F) | 0x80); + out += static_cast((pt & 0x3F) | 0x80); + } + } + + /* parse_string() + * + * Parse a string, starting at the current position. + */ + string parse_string() { + string out; + long last_escaped_codepoint = -1; + while (true) { + if (i == str.size()) + return fail("unexpected end of input in string", ""); + + char ch = str[i++]; + + if (ch == '"') { + encode_utf8(last_escaped_codepoint, out); + return out; + } + + if (in_range(ch, 0, 0x1f)) + return fail("unescaped " + esc(ch) + " in string", ""); + + // The usual case: non-escaped characters + if (ch != '\\') { + encode_utf8(last_escaped_codepoint, out); + last_escaped_codepoint = -1; + out += ch; + continue; + } + + // Handle escapes + if (i == str.size()) + return fail("unexpected end of input in string", ""); + + ch = str[i++]; + + if (ch == 'u') { + // Extract 4-byte escape sequence + string esc = str.substr(i, 4); + // Explicitly check length of the substring. The following loop + // relies on std::string returning the terminating NUL when + // accessing str[length]. Checking here reduces brittleness. + if (esc.length() < 4) { + return fail("bad \\u escape: " + esc, ""); + } + for (int j = 0; j < 4; j++) { + if (!in_range(esc[j], 'a', 'f') && !in_range(esc[j], 'A', 'F') && + !in_range(esc[j], '0', '9')) + return fail("bad \\u escape: " + esc, ""); + } + + long codepoint = strtol(esc.data(), nullptr, 16); + + // JSON specifies that characters outside the BMP shall be encoded + // as a pair + // of 4-hex-digit \u escapes encoding their surrogate pair + // components. Check + // whether we're in the middle of such a beast: the previous + // codepoint was an + // escaped lead (high) surrogate, and this is a trail (low) + // surrogate. + if (in_range(last_escaped_codepoint, 0xD800, 0xDBFF) && + in_range(codepoint, 0xDC00, 0xDFFF)) { + // Reassemble the two surrogate pairs into one astral-plane + // character, per + // the UTF-16 algorithm. + encode_utf8((((last_escaped_codepoint - 0xD800) << 10) | + (codepoint - 0xDC00)) + + 0x10000, + out); + last_escaped_codepoint = -1; + } else { + encode_utf8(last_escaped_codepoint, out); + last_escaped_codepoint = codepoint; + } + + i += 4; + continue; + } + + encode_utf8(last_escaped_codepoint, out); + last_escaped_codepoint = -1; + + if (ch == 'b') { + out += '\b'; + } else if (ch == 'f') { + out += '\f'; + } else if (ch == 'n') { + out += '\n'; + } else if (ch == 'r') { + out += '\r'; + } else if (ch == 't') { + out += '\t'; + } else if (ch == '"' || ch == '\\' || ch == '/') { + out += ch; + } else { + return fail("invalid escape character " + esc(ch), ""); + } + } + } + + /* parse_number() + * + * Parse a double. + */ + Json parse_number() { + size_t start_pos = i; + + if (str[i] == '-') + i++; + + // Integer part + if (str[i] == '0') { + i++; + if (in_range(str[i], '0', '9')) + return fail("leading 0s not permitted in numbers"); + } else if (in_range(str[i], '1', '9')) { + i++; + while (in_range(str[i], '0', '9')) + i++; + } else { + return fail("invalid " + esc(str[i]) + " in number"); + } + + if (str[i] != '.' && str[i] != 'e' && str[i] != 'E' && + (i - start_pos) <= + static_cast(std::numeric_limits::digits10)) { + return std::atoi(str.c_str() + start_pos); + } + + // Decimal part + if (str[i] == '.') { + i++; + if (!in_range(str[i], '0', '9')) + return fail("at least one digit required in fractional part"); + + while (in_range(str[i], '0', '9')) + i++; + } + + // Exponent part + if (str[i] == 'e' || str[i] == 'E') { + i++; + + if (str[i] == '+' || str[i] == '-') + i++; + + if (!in_range(str[i], '0', '9')) + return fail("at least one digit required in exponent"); + + while (in_range(str[i], '0', '9')) + i++; + } + + return std::strtod(str.c_str() + start_pos, nullptr); + } + + /* expect(str, res) + * + * Expect that 'str' starts at the character that was just read. If it + * does, advance + * the input and return res. If not, flag an error. + */ + Json expect(const string &expected, Json res) { + assert(i != 0); + i--; + if (str.compare(i, expected.length(), expected) == 0) { + i += expected.length(); + return res; + } else { + return fail("parse error: expected " + expected + ", got " + + str.substr(i, expected.length())); + } + } + + /* parse_json() + * + * Parse a JSON object. + */ + Json parse_json(int depth) { + if (depth > max_depth) { + return fail("exceeded maximum nesting depth"); + } + + char ch = get_next_token(); + if (failed) + return Json(); + + if (ch == '-' || (ch >= '0' && ch <= '9')) { + i--; + return parse_number(); + } + + if (ch == 't') + return expect("true", true); + + if (ch == 'f') + return expect("false", false); + + if (ch == 'n') + return expect("null", Json()); + + if (ch == '"') + return parse_string(); + + if (ch == '{') { + map data; + ch = get_next_token(); + if (ch == '}') + return data; + + while (1) { + if (ch != '"') + return fail("expected '\"' in object, got " + esc(ch)); + + string key = parse_string(); + if (failed) + return Json(); + + ch = get_next_token(); + if (ch != ':') + return fail("expected ':' in object, got " + esc(ch)); + + data[std::move(key)] = parse_json(depth + 1); + if (failed) + return Json(); + + ch = get_next_token(); + if (ch == '}') + break; + if (ch != ',') + return fail("expected ',' in object, got " + esc(ch)); + + ch = get_next_token(); + } + return data; + } + + if (ch == '[') { + vector data; + ch = get_next_token(); + if (ch == ']') + return data; + + while (1) { + i--; + data.push_back(parse_json(depth + 1)); + if (failed) + return Json(); + + ch = get_next_token(); + if (ch == ']') + break; + if (ch != ',') + return fail("expected ',' in list, got " + esc(ch)); + + ch = get_next_token(); + (void)ch; + } + return data; + } + + return fail("expected value, got " + esc(ch)); + } +}; + +Json Json::parse(const string &in, string &err, JsonParse strategy) { + JsonParser parser{in, 0, err, false, strategy}; + Json result = parser.parse_json(0); + + // Check for any trailing garbage + parser.consume_garbage(); + if (parser.i != in.size()) + return parser.fail("unexpected trailing " + esc(in[parser.i])); + + return result; +} + +// Documented in json11.hpp +vector Json::parse_multi(const string &in, string &err, + JsonParse strategy) { + JsonParser parser{in, 0, err, false, strategy}; + + vector json_vec; + while (parser.i != in.size() && !parser.failed) { + json_vec.push_back(parser.parse_json(0)); + // Check for another object + parser.consume_garbage(); + } + return json_vec; +} + +/* * * * * * * * * * * * * * * * * * * * + * Shape-checking + */ + +bool Json::has_shape(const shape &types, string &err) const { + if (!is_object()) { + err = "expected JSON object, got " + dump(); + return false; + } + + for (auto &item : types) { + if ((*this)[item.first].type() != item.second) { + err = "bad type for " + item.first + " in " + dump(); + return false; + } + } + + return true; +} + +} // namespace json11 diff --git a/CUDA_ListScan/libwb/vendor/json11.hpp b/CUDA_ListScan/libwb/vendor/json11.hpp new file mode 100644 index 0000000..9e0f0d9 --- /dev/null +++ b/CUDA_ListScan/libwb/vendor/json11.hpp @@ -0,0 +1,300 @@ +/* json11 + * + * json11 is a tiny JSON library for C++11, providing JSON parsing and + * serialization. + * + * The core object provided by the library is json11::Json. A Json object + * represents any JSON + * value: null, bool, number (int or double), string (std::string), array + * (std::vector), or + * object (std::map). + * + * Json objects act like values: they can be assigned, copied, moved, + * compared for equality or + * order, etc. There are also helper methods Json::dump, to serialize a + * Json to a string, and + * Json::parse (static) to parse a std::string as a Json object. + * + * Internally, the various types of Json object are represented by the + * JsonValue class + * hierarchy. + * + * A note on numbers - JSON specifies the syntax of number formatting but + * not its semantics, + * so some JSON implementations distinguish between integers and + * floating-point numbers, while + * some don't. In json11, we choose the latter. Because some JSON + * implementations (namely + * Javascript itself) treat all numbers as the same type, distinguishing + * the two leads + * to JSON that will be *silently* changed by a round-trip through those + * implementations. + * Dangerous! To avoid that risk, json11 stores all numbers as double + * internally, but also + * provides integer helpers. + * + * Fortunately, double-precision IEEE754 ('double') can precisely store any + * integer in the + * range +/-2^53, which includes every 'int' on most systems. (Timestamps + * often use int64 + * or long long to avoid the Y2038K problem; a double storing microseconds + * since some epoch + * will be exact for +/- 275 years.) + */ + +/* Copyright (c) 2013 Dropbox, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy + * of this software and associated documentation files (the "Software"), to + * deal + * in the Software without restriction, including without limitation the + * rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN + * THE SOFTWARE. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +//PMO +#ifndef _MSC_VER +#define NOEXCEPT noexcept +#else +#define NOEXCEPT _NOEXCEPT +#endif + +namespace json11 { + +enum JsonParse { STANDARD, COMMENTS }; + +class JsonValue; + +class Json final { +public: + // Types + enum Type { + NUL, + NUMBER, + NUMBER64, + UNUMBER64, + BOOL, + STRING, + ARRAY, + OBJECT + }; + + // Array and object typedefs + typedef std::vector array; + typedef std::map object; + + // Constructors for the various types of JSON value. + //PMO + //Json() noexcept; // NUL + Json() NOEXCEPT; // NUL + //Json(std::nullptr_t) noexcept; // NUL + Json(std::nullptr_t) NOEXCEPT; // NUL + Json(double value); // NUMBER + Json(int value); // NUMBER + Json(int64_t value); // NUMBER64 + Json(uint64_t value); // UNUMBER64 + Json(bool value); // BOOL + Json(const std::string &value); // STRING + Json(std::string &&value); // STRING + Json(const char *value); // STRING + Json(const array &values); // ARRAY + Json(array &&values); // ARRAY + Json(const object &values); // OBJECT + Json(object &&values); // OBJECT + + // Implicit constructor: anything with a to_json() function. + template + Json(const T &t) : Json(t.to_json()) { + } + + // Implicit constructor: map-like objects (std::map, std::unordered_map, + // etc) + template < + class M, + typename std::enable_if< + std::is_constructible::value && + std::is_constructible::value, + int>::type = 0> + Json(const M &m) : Json(object(m.begin(), m.end())) { + } + + // Implicit constructor: vector-like objects (std::list, std::vector, + // std::set, etc) + template ::value, + int>::type = 0> + Json(const V &v) : Json(array(v.begin(), v.end())) { + } + + // This prevents Json(some_pointer) from accidentally producing a bool. + // Use + // Json(bool(some_pointer)) if that behavior is desired. + Json(void *) = delete; + + // Accessors + Type type() const; + + bool is_null() const { + return type() == NUL; + } + bool is_number() const { + return type() == NUMBER; + } + bool is_number64() const { + return type() == NUMBER64; + } + bool is_unumber64() const { + return type() == UNUMBER64; + } + bool is_bool() const { + return type() == BOOL; + } + bool is_string() const { + return type() == STRING; + } + bool is_array() const { + return type() == ARRAY; + } + bool is_object() const { + return type() == OBJECT; + } + + // Return the enclosed value if this is a number, 0 otherwise. Note that + // json11 does not + // distinguish between integer and non-integer numbers - number_value() + // and int_value() + // can both be applied to a NUMBER-typed object. + double number_value() const; + int int_value() const; + int64_t int64_value() const; + uint64_t uint64_value() const; + + // Return the enclosed value if this is a boolean, false otherwise. + bool bool_value() const; + // Return the enclosed string if this is a string, "" otherwise. + const std::string &string_value() const; + // Return the enclosed std::vector if this is an array, or an empty + // vector otherwise. + const array &array_items() const; + // Return the enclosed std::map if this is an object, or an empty map + // otherwise. + const object &object_items() const; + + // Return a reference to arr[i] if this is an array, Json() otherwise. + const Json &operator[](size_t i) const; + // Return a reference to obj[key] if this is an object, Json() otherwise. + const Json &operator[](const std::string &key) const; + + // Serialize. + void dump(std::string &out) const; + std::string dump() const { + std::string out; + dump(out); + return out; + } + + // Parse. If parse fails, return Json() and assign an error message to + // err. + static Json parse(const std::string &in, std::string &err, + JsonParse strategy = JsonParse::STANDARD); + static Json parse(const char *in, std::string &err, + JsonParse strategy = JsonParse::STANDARD) { + if (in) { + return parse(std::string(in), err, strategy); + } else { + err = "null input"; + return nullptr; + } + } + // Parse multiple objects, concatenated or separated by whitespace + static std::vector + parse_multi(const std::string &in, std::string &err, + JsonParse strategy = JsonParse::STANDARD); + + bool operator==(const Json &rhs) const; + bool operator<(const Json &rhs) const; + bool operator!=(const Json &rhs) const { + return !(*this == rhs); + } + bool operator<=(const Json &rhs) const { + return !(rhs < *this); + } + bool operator>(const Json &rhs) const { + return (rhs < *this); + } + bool operator>=(const Json &rhs) const { + return !(*this < rhs); + } + + /* has_shape(types, err) + * + * Return true if this is a JSON object and, for each item in types, has + * a field of + * the given type. If not, return false and set err to a descriptive + * message. + */ + typedef std::initializer_list> shape; + bool has_shape(const shape &types, std::string &err) const; + +private: + std::shared_ptr m_ptr; +}; + +// Internal class hierarchy - JsonValue objects are not exposed to users of +// this API. +class JsonValue { +protected: + friend class Json; + friend class JsonInt; + friend class JsonInt64; + friend class JsonUInt64; + friend class JsonDouble; + virtual Json::Type type() const = 0; + virtual bool equals(const JsonValue *other) const = 0; + virtual bool less(const JsonValue *other) const = 0; + virtual void dump(std::string &out) const = 0; + virtual double number_value() const; + virtual int int_value() const; + virtual int64_t int64_value() const; + virtual uint64_t uint64_value() const; + virtual bool bool_value() const; + virtual const std::string &string_value() const; + virtual const Json::array &array_items() const; + virtual const Json &operator[](size_t i) const; + virtual const Json::object &object_items() const; + virtual const Json &operator[](const std::string &key) const; + virtual ~JsonValue() { + } +}; + +} // namespace json11 diff --git a/CUDA_ListScan/libwb/wb.h b/CUDA_ListScan/libwb/wb.h new file mode 100644 index 0000000..8f41e23 --- /dev/null +++ b/CUDA_ListScan/libwb/wb.h @@ -0,0 +1,155 @@ + + +#ifndef __WB_H__ +#define __WB_H__ + +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ + +#include +#include +#include +#include + +#ifdef _MSC_VER + +// set minimal warning level +#pragma warning(push,0) +// some warnings still occur at this level +// if necessary, disable specific warnings not covered by previous pragma +#pragma warning(disable : 4244 4056 4305 4800 4267 4996 4756 4661 4385 4101) + +#define __func__ __FUNCTION__ +#ifndef _CRT_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_WARNINGS 1 +#endif /* _CRT_SECURE_NO_WARNINGS */ +#define _CRT_SECURE_NO_DEPRECATE 1 +#define _CRT_NONSTDC_NO_DEPRECATE 1 +#include +#include +#include +#define WB_USE_WINDOWS +#else /* _MSC_VER */ +#include +#include +#include +#include +#define WB_USE_UNIX +#ifdef __APPLE__ +#include +#define WB_USE_DARWIN +#else /* __APPLE__ */ +#define WB_USE_LINUX +#endif /* __APPLE__ */ +#endif /* _MSC_VER */ + +#define wbStmt(stmt) stmt + +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ + +#define wbLine __LINE__ +#define wbFile __FILE__ +#define wbFunction __func__ + +#define wbExit() \ + wbAssert(0); \ + exit(1) + +#ifdef WB_USE_COURSERA +#define wbLogger_printOnExit 1 +#else /* WB_USE_COURSERA */ +#define wbLogger_printOnLog 1 +#endif /* WB_USE_COURSERA */ + +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ + +#ifdef __cplusplus +#define EXTERN_C extern "C" +#define START_EXTERN_C EXTERN_C { +#define END_EXTERN_C } +#else +#define EXTERN_C +#define START_EXTERN_C +#define END_EXTERN_C +#endif /* __cplusplus */ + +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ + +#include +#define WB_USE_JSON11 1 + +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ + +#define LAZY_FILE_LOAD +extern char *solutionJSON; + +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ + +#ifdef WB_USE_OPENCL +#ifdef WB_USE_DARWIN +#include +#else /* WB_USE_DARWIN */ +#include +#endif /* WB_USE_DARWIN */ +#endif /* WB_USE_OPENCL */ + +#include "wbTypes.h" + +#include "wbAssert.h" +#include "wbMalloc.h" +#include "wbString.h" +#include "wbUtils.h" + +#include "wbArg.h" +#include "wbCUDA.h" +#include "wbCast.h" +#include "wbComparator.h" +#include "wbDirectory.h" +#include "wbExit.h" +#include "wbExport.h" +#include "wbFile.h" +#include "wbImage.h" +#include "wbImport.h" +#include "wbInit.h" +#include "wbLogger.h" +#include "wbMD5.h" +#include "wbMPI.h" +#include "wbSolution.h" +#include "wbSparse.h" +#include "wbThrust.h" +#include "wbTimer.h" +#include "wbPath.h" + +#include "wbDataset.h" + +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ + +#endif /* __WB_H__ */ diff --git a/CUDA_ListScan/libwb/wbArg.cpp b/CUDA_ListScan/libwb/wbArg.cpp new file mode 100644 index 0000000..2a5c736 --- /dev/null +++ b/CUDA_ListScan/libwb/wbArg.cpp @@ -0,0 +1,105 @@ + +#include "wb.h" + +EXTERN_C wbArg_t wbArg_new(int *argc, char ***argv) { + wbArg_t arg; + + wb_init(argc, argv); + + wbArg_setInputCount(arg, 0); + wbArg_setInputFiles(arg, NULL); + wbArg_setOutputFile(arg, NULL); + wbArg_setType(arg, NULL); + wbArg_setExpectedOutputFile(arg, NULL); + return arg; +} + +EXTERN_C void wbArg_delete(wbArg_t arg) { + if (wbArg_getInputCount(arg) > 0 && wbArg_getInputFiles(arg) != NULL) { + int ii; + for (ii = 0; ii < wbArg_getInputCount(arg); ii++) { + wbDelete(wbArg_getInputFile(arg, ii)); + } + wbDelete(wbArg_getInputFiles(arg)); + wbArg_setInputCount(arg, 0); + wbArg_setInputFiles(arg, NULL); + } + if (wbArg_getOutputFile(arg)) { + wbDelete(wbArg_getOutputFile(arg)); + wbArg_setOutputFile(arg, NULL); + } + if (wbArg_getExpectedOutputFile(arg)) { + wbDelete(wbArg_getExpectedOutputFile(arg)); + wbArg_setExpectedOutputFile(arg, NULL); + } + if (wbArg_getType(arg)) { + wbDelete(wbArg_getType(arg)); + wbArg_setType(arg, NULL); + } + return; +} + +static int getInputFileCount(char *arg) { + int count = 1; + while (*arg != '\0' && *arg != '-') { + if (*arg == ',') { + count++; + } + arg++; + } + return count; +} + +static char **parseInputFiles(char *arg, int *resCount) { + int count; + int ii = 0; + char **files; + char *token; + + count = getInputFileCount(arg); + + files = wbNewArray(char *, count); + + token = strtok(arg, ","); + while (token != NULL) { + files[ii++] = wbString_duplicate(token); + token = strtok(NULL, ","); + } + *resCount = ii; + return files; +} + +static char *parseString(char *arg) { + return wbString_duplicate(arg); +} + +EXTERN_C wbArg_t wbArg_read(int argc, char **argv) { + int ii; + wbArg_t arg; + + arg = wbArg_new(&argc, &argv); + for (ii = 0; ii < argc; ii++) { + if (wbString_startsWith(argv[ii], "-i")) { + int fileCount; + char **files; + + files = parseInputFiles(argv[ii + 1], &fileCount); + + wbArg_setInputCount(arg, fileCount); + wbArg_setInputFiles(arg, files); + } else if (wbString_startsWith(argv[ii], "-o")) { + char *file = parseString(argv[ii + 1]); + wbArg_setOutputFile(arg, file); + } else if (wbString_startsWith(argv[ii], "-e")) { + char *file = parseString(argv[ii + 1]); + wbArg_setExpectedOutputFile(arg, file); + } else if (wbString_startsWith(argv[ii], "-t")) { + char *type = parseString(argv[ii + 1]); + wbArg_setType(arg, type); + } else if (argv[ii][0] == '-') { + wbLog(ERROR, "Unexpected program option ", argv[ii]); + } + } + + return arg; +} diff --git a/CUDA_ListScan/libwb/wbArg.h b/CUDA_ListScan/libwb/wbArg.h new file mode 100644 index 0000000..c98bcf7 --- /dev/null +++ b/CUDA_ListScan/libwb/wbArg.h @@ -0,0 +1,33 @@ + + +#ifndef __WB_ARG_H__ +#define __WB_ARG_H__ + +struct st_wbArg_t { + int inputCount; + char **inputFiles; + char *outputFile; + char *expectedOutput; + char *type; +}; + +#define wbArg_getInputCount(wa) ((wa).inputCount) +#define wbArg_getInputFiles(wa) ((wa).inputFiles) +#define wbArg_getInputFile(wa, ii) (wbArg_getInputFiles(wa)[ii]) +#define wbArg_getOutputFile(wa) ((wa).outputFile) +#define wbArg_getExpectedOutputFile(wa) ((wa).expectedOutput) +#define wbArg_getType(wa) ((wa).type) + +#define wbArg_setInputCount(wa, val) (wbArg_getInputCount(wa) = val) +#define wbArg_setInputFiles(wa, val) (wbArg_getInputFiles(wa) = val) +#define wbArg_setInputFile(wa, ii, val) (wbArg_getInputFile(wa, ii) = val) +#define wbArg_setOutputFile(wa, val) (wbArg_getOutputFile(wa) = val) +#define wbArg_setExpectedOutputFile(wa, val) \ + (wbArg_getExpectedOutputFile(wa) = val) +#define wbArg_setType(wa, val) (wbArg_getType(wa) = val) + +EXTERN_C wbArg_t wbArg_new(int *argc, char ***argv); +EXTERN_C void wbArg_delete(wbArg_t arg); +EXTERN_C wbArg_t wbArg_read(int argc, char **argv); + +#endif /* __WB_ARG_H__ */ diff --git a/CUDA_ListScan/libwb/wbAssert.h b/CUDA_ListScan/libwb/wbAssert.h new file mode 100644 index 0000000..b8ed669 --- /dev/null +++ b/CUDA_ListScan/libwb/wbAssert.h @@ -0,0 +1,24 @@ + + +#ifndef __WB_ASSERT_H__ +#define __WB_ASSERT_H__ + +#include + +#ifdef WB_DEBUG +#define wbAssert(cond) assert(cond) +#define wbAssertMessage(msg, cond) \ + do { \ + if (!(cond)) { \ + wbPrint(msg); \ + wbAssert(cond); \ + } \ + } while (0) +#else /* WB_DEBUG */ +#define wbAssert(...) +#define wbAssertMessage(...) +#endif /* WB_DEBUG */ + +#define wbTodo(msg) wbAssertMessage(msg, false) + +#endif /* __WB_ASSERT_H__ */ diff --git a/CUDA_ListScan/libwb/wbCUDA.cpp b/CUDA_ListScan/libwb/wbCUDA.cpp new file mode 100644 index 0000000..cb26895 --- /dev/null +++ b/CUDA_ListScan/libwb/wbCUDA.cpp @@ -0,0 +1,25 @@ + +#include "wb.h" +#ifdef WB_USE_CUDA + +int _cudaMemoryListIdx = 0; + +size_t _cudaMallocSize = 0; + +wbCUDAMemory_t _cudaMemoryList[_cudaMemoryListSize]; + +char *wbRandom_list(size_t sz) { + size_t ii; + char *rands = wbNewArray(char, sz); + int *irands = (int *)rands; + for (ii = 0; ii < sz / sizeof(int); ii++) { + irands[ii] = rand(); + } + while (ii < sz) { + rands[ii] = (char)(rand() % 255); + ii++; + } + return rands; +} + +#endif /* WB_USE_CUDA */ diff --git a/CUDA_ListScan/libwb/wbCUDA.h b/CUDA_ListScan/libwb/wbCUDA.h new file mode 100644 index 0000000..658ff39 --- /dev/null +++ b/CUDA_ListScan/libwb/wbCUDA.h @@ -0,0 +1,77 @@ + +#ifndef __WB_CUDA_H__ +#define __WB_CUDA_H__ + +#ifdef WB_USE_CUDA +#ifdef __PGI +#define __GNUC__ 4 +#endif /* __PGI */ +#include +#include + +typedef struct st_wbCUDAMemory_t { + void *mem; + size_t sz; +} wbCUDAMemory_t; + +#define _cudaMemoryListSize 1024 + +extern size_t _cudaMallocSize; +extern wbCUDAMemory_t _cudaMemoryList[]; +extern int _cudaMemoryListIdx; + +char *wbRandom_list(size_t sz); + +static inline cudaError_t wbCUDAMalloc(void **devPtr, size_t sz) { + int idx = _cudaMemoryListIdx; + + cudaError_t err = cudaMalloc(devPtr, sz); + + if (idx == 0) { + srand(time(NULL)); + memset(_cudaMemoryList, 0, + sizeof(wbCUDAMemory_t) * _cudaMemoryListSize); + } + + if (err == cudaSuccess) { +#if 0 + char * rands = wbRandom_list(sz); + // can use curand here, but do not want to invoke a kernel + err = cudaMemcpy(*devPtr, rands, sz, cudaMemcpyHostToDevice); + wbFree(rands); +#else + err = cudaMemset(*devPtr, 0, sz); +#endif + } + + _cudaMallocSize += sz; + _cudaMemoryList[idx].mem = *devPtr; + _cudaMemoryList[idx].sz = sz; + _cudaMemoryListIdx++; + return err; +} + +static inline cudaError_t wbCUDAFree(void *mem) { + int idx = _cudaMemoryListIdx; + if (idx == 0) { + memset(_cudaMemoryList, 0, + sizeof(wbCUDAMemory_t) * _cudaMemoryListSize); + } + for (int ii = 0; ii < idx; ii++) { + if (_cudaMemoryList[ii].mem != NULL && + _cudaMemoryList[ii].mem == mem) { + cudaError_t err = cudaFree(mem); + _cudaMallocSize -= _cudaMemoryList[ii].sz; + _cudaMemoryList[ii].mem = NULL; + return err; + } + } + return cudaErrorMemoryAllocation; +} + +#define cudaMalloc(elem, err) wbCUDAMalloc((void **)elem, err) +#define cudaFree wbCUDAFree + +#endif /* WB_USE_CUDA */ + +#endif /* __WB_CUDA_H__ */ diff --git a/CUDA_ListScan/libwb/wbCast.h b/CUDA_ListScan/libwb/wbCast.h new file mode 100644 index 0000000..01e8387 --- /dev/null +++ b/CUDA_ListScan/libwb/wbCast.h @@ -0,0 +1,29 @@ + + +#ifndef __WB_CAST_H__ +#define __WB_CAST_H__ + +template +static inline void wbCast(X &x, const Y &y, size_t len) { + size_t ii; + + for (ii = 0; ii < len; ii++) { + x[ii] = (X)y[ii]; + } + + return; +} + +template +static inline X *wbCast(const Y &y, size_t len) { + size_t ii; + X *x = wbNewArray(X, len); + + for (ii = 0; ii < len; ii++) { + x[ii] = (X)y[ii]; + } + + return x; +} + +#endif /* __WB_CAST_H__ */ diff --git a/CUDA_ListScan/libwb/wbComparator.h b/CUDA_ListScan/libwb/wbComparator.h new file mode 100644 index 0000000..26fd0cb --- /dev/null +++ b/CUDA_ListScan/libwb/wbComparator.h @@ -0,0 +1,187 @@ + + +#ifndef __WB_COMPARATOR_H__ +#define __WB_COMPARATOR_H__ + +#include "wb.h" + +template +static inline T _abs(const T &a) { + return a < 0 ? -a : a; +} + +static inline wbBool _almostEqual(double A, double B, double eps) { + if (A == 0) { + return _abs(B) < eps; + } else if (B == 0) { + return _abs(A) < eps; + } else { +#if 0 + double d = max(_abs(A), _abs(B)); + double g = (_abs(A - B) / d); +#else + double g = _abs(A - B); +#endif + if (g <= eps) { + return wbTrue; + } else { + return wbFalse; + } + } +} + +static inline wbBool _almostEqual(float A, float B, float eps) { + if (A == 0) { + return _abs(B) < eps; + } else if (B == 0) { + return _abs(A) < eps; + } else { +#if 0 + float d = max(_abs(A), _abs(B)); + float g = (_abs(A - B) / d); +#else + float g = _abs(A - B); +#endif + if (g <= eps) { + return wbTrue; + } else { + return wbFalse; + } + } +} + +static inline wbBool _almostEqual(double A, double B) { + return _almostEqual(A, B, 0.2); +} + +static inline wbBool _almostEqual(float A, float B) { + return _almostEqual(A, B, 0.2f); +} + +static inline wbBool _almostEqual2sComplement(float A, float B, + int maxUlps) { + // Make sure maxUlps is non-negative and small enough that the + // default NAN won't compare as equal to anything. + + int aInt, bInt, intDiff; + + wbAssert(maxUlps > 0 && maxUlps < 4 * 1024 * 1024); + + int *tmp = reinterpret_cast(&A); + aInt = *tmp; + + // Make aInt lexicographically ordered as a twos-complement int + if (aInt < 0) { + aInt = 0x80000000 - aInt; + } + // Make bInt lexicographically ordered as a twos-complement int + tmp = reinterpret_cast(&B); + bInt = *tmp; + if (bInt < 0) { + bInt = 0x80000000 - bInt; + } + intDiff = _abs(aInt - bInt); + if (intDiff <= maxUlps) { + return wbTrue; + } + return wbFalse; +} + +static inline wbBool _almostEqual2sComplement(float A, float B) { + return _almostEqual2sComplement(A, B, 4); +} + +static inline wbBool _almostEqual2sComplement(double A, double B, + int maxUlps) { + // Make sure maxUlps is non-negative and small enough that the + // default NAN won't compare as equal to anything. + + int64_t aInt, bInt, intDiff; + + wbAssert(maxUlps > 0 && maxUlps < 4 * 1024 * 1024); + + int64_t *tmp = reinterpret_cast(&A); + aInt = *tmp; + + // Make aInt lexicographically ordered as a twos-complement int + if (aInt < 0) { + aInt = 0x80000000 - aInt; + } + // Make bInt lexicographically ordered as a twos-complement int + tmp = reinterpret_cast(&B); + bInt = *tmp; + if (bInt < 0) { + bInt = 0x80000000 - bInt; + } + intDiff = _abs(aInt - bInt); + if (intDiff <= maxUlps) { + return wbTrue; + } + return wbFalse; +} + +static inline wbBool _almostEqual2sComplement(double A, double B) { + return _almostEqual2sComplement(A, B, 4); +} + +template +static inline int wbCompare(const T &a, const T &b) { + if (a == b) { + return 0; + } else if (a < b) { + return -1; + } else { + return 1; + } +} + +template <> +inline int wbCompare(const double &a, const double &b) { + if (_almostEqual(a, b)) { + return 0; + } else if (a < b) { + return -1; + } else { + return 1; + } +} + +template <> +inline int wbCompare(const float &a, const float &b) { + if (_almostEqual(a, b)) { + return 0; + } else if (a < b) { + return -1; + } else { + return 1; + } +} + +template +static inline wbBool wbEqualQ(const T &a, const T &b) { + return wbCompare(a, b) == 0; +} + +template +static inline wbBool wbUnequalQ(const T &a, const T &b) { + return wbCompare(a, b) != 0; +} + +template +static inline wbBool wbEqualQ(const T *a, const T *b, size_t n) { + size_t ii; + + for (ii = 0; ii < n; ii++) { + if (wbUnequalQ(a[ii], b[ii])) { + return wbFalse; + } + } + return wbTrue; +} + +template +static inline wbBool wbUnequalQ(const T *a, const T *b, size_t n) { + return !wbEqualQ(a, b, n); +} + +#endif /* __WB_COMPARATOR_H__ */ diff --git a/CUDA_ListScan/libwb/wbDataset.cpp b/CUDA_ListScan/libwb/wbDataset.cpp new file mode 100644 index 0000000..a11f064 --- /dev/null +++ b/CUDA_ListScan/libwb/wbDataset.cpp @@ -0,0 +1,177 @@ +#include "wb.h" + +template +static inline T _min(const T &x, const T &y) { + return x < y ? x : y; +} + +template +static inline T _max(const T &x, const T &y) { + return x > y ? x : y; +} + +template +inline T lerp(const double &x, const T &start, const T &end) { + return (1 - x) * start + x * end; +} + +static inline void genRandom(void *trgt, wbType_t type, double minVal, + double maxVal) { + const int span = maxVal - minVal; + const int r = rand(); + const double rf = ((double)r) / ((double)RAND_MAX); + switch (type) { + case wbType_ascii: + *((char *)trgt) = (r % span) + minVal; // random printable character; + break; + case wbType_bit8: + *((char *)trgt) = lerp(rf, minVal, maxVal); + break; + case wbType_ubit8: + *((unsigned char *)trgt) = lerp(rf, minVal, maxVal); + break; + case wbType_integer: + *((int *)trgt) = lerp(rf, minVal, maxVal); + break; + case wbType_float: { + *((float *)trgt) = lerp(rf, minVal, maxVal); + break; + } + case wbType_double: { + *((double *)trgt) = lerp(rf, minVal, maxVal); + break; + } + case wbType_unknown: + wbAssert(false && "Invalid wbType_unknown"); + break; + } + return; +} + +static inline void *genRandomList(wbType_t type, size_t len, double minVal, + double maxVal) { + size_t ii; + void *data = wbNewArray(char, wbType_size(type) * len); + switch (type) { + case wbType_ascii: + case wbType_bit8: { + char *iter = (char *)data; + for (ii = 0; ii < len; ii++) { + genRandom(iter++, type, minVal, maxVal); + } + break; + } + case wbType_ubit8: { + unsigned char *iter = (unsigned char *)data; + for (ii = 0; ii < len; ii++) { + genRandom(iter++, type, minVal, maxVal); + } + break; + } + case wbType_integer: { + int *iter = (int *)data; + for (ii = 0; ii < len; ii++) { + genRandom(iter++, type, minVal, maxVal); + } + break; + } + case wbType_float: { + float *iter = (float *)data; + for (ii = 0; ii < len; ii++) { + genRandom(iter++, type, minVal, maxVal); + } + break; + } + case wbType_double: { + double *iter = (double *)data; + for (ii = 0; ii < len; ii++) { + genRandom(iter++, type, minVal, maxVal); + } + break; + } + case wbType_unknown: + wbAssert(false && "Invalid wbType_unknown"); + break; + } + return data; +} + +static void genRaw(const char *path, wbRaw_GenerateParams_t params) { + int rows = _max(1, params.rows); + int cols = _max(1, params.cols); + double minVal = params.minVal; + double maxVal = params.maxVal; + wbType_t type = params.type; + void *data = genRandomList(type, rows * cols, minVal, maxVal); + wbExport(path, wbExportKind_raw, data, rows, cols, type); + wbDelete(data); +} + +static void genCSV(const char *path, wbCSV_GenerateParams_t params) { + int rows = _max(1, params.rows); + int cols = _max(1, params.cols); + double minVal = params.minVal; + double maxVal = params.maxVal; + wbType_t type = params.type; + void *data = genRandomList(type, rows * cols, minVal, maxVal); + wbExport(path, wbExportKind_csv, data, rows, cols, type); + wbDelete(data); +} + +static void genTSV(const char *path, wbTSV_GenerateParams_t params) { + int rows = _max(1, params.rows); + int cols = _max(1, params.cols); + double minVal = params.minVal; + double maxVal = params.maxVal; + wbType_t type = params.type; + void *data = genRandomList(type, rows * cols, minVal, maxVal); + wbExport(path, wbExportKind_tsv, data, rows, cols, type); + wbDelete(data); +} + +static void genText(const char *path, wbText_GenerateParams_t params) { + int length = _max(1, params.length); + wbType_t type = wbType_ascii; + void *data = genRandomList(type, length, 32, 128); + wbExport(path, wbExportKind_text, data, length, 1, type); + wbDelete(data); +} + +static void genPPM(const char *path, wbPPM_GenerateParams_t params) { + int width = _max(1, params.width); + int height = _max(1, params.height); + int channels = _max(1, params.channels); + double minVal = params.minVal; + double maxVal = params.maxVal; + wbType_t type = wbType_float; + float *data = (float *)genRandomList(type, width * height * channels, + minVal, maxVal); + wbImage_t img = wbImage_new(width, height, channels, data); + wbExport(path, img); + wbImage_delete(img); +} + +EXTERN_C void wbDataset_generate(const char *path, wbExportKind_t kind, + wbGenerateParams_t params) { + wbDirectory_create(wbDirectory_name(path)); + + switch (kind) { + case wbExportKind_raw: + genRaw(path, params.raw); + break; + case wbExportKind_csv: + genCSV(path, params.csv); + break; + case wbExportKind_tsv: + genTSV(path, params.tsv); + break; + case wbExportKind_ppm: + genPPM(path, params.ppm); + break; + case wbExportKind_text: + genText(path, params.text); + break; + default: + wbAssert(false && "Invalid Export kind"); + } +} diff --git a/CUDA_ListScan/libwb/wbDataset.h b/CUDA_ListScan/libwb/wbDataset.h new file mode 100644 index 0000000..ce81c28 --- /dev/null +++ b/CUDA_ListScan/libwb/wbDataset.h @@ -0,0 +1,52 @@ +#ifndef __WB_DATASET_H__ +#define __WB_DATASET_H__ + +#include "wbImport.h" +#include "wbTypes.h" + +typedef struct { + int rows; + int cols; + wbType_t type; + double minVal; + double maxVal; +} wbCSV_GenerateParams_t; + +typedef struct { + int rows; + int cols; + wbType_t type; + double minVal; + double maxVal; +} wbTSV_GenerateParams_t; + +typedef struct { + int rows; + int cols; + double minVal; + double maxVal; + wbType_t type; +} wbRaw_GenerateParams_t; + +typedef struct { + int width; + int height; + int channels; + double minVal; + double maxVal; +} wbPPM_GenerateParams_t; + +typedef struct { int length; } wbText_GenerateParams_t; + +typedef union { + wbCSV_GenerateParams_t csv; + wbRaw_GenerateParams_t raw; + wbTSV_GenerateParams_t tsv; + wbPPM_GenerateParams_t ppm; + wbText_GenerateParams_t text; +} wbGenerateParams_t; + +EXTERN_C void wbDataset_generate(const char *path, wbExportKind_t kind, + wbGenerateParams_t params); + +#endif /* __WB_DATASET_H__ */ diff --git a/CUDA_ListScan/libwb/wbDataset_test.cpp b/CUDA_ListScan/libwb/wbDataset_test.cpp new file mode 100644 index 0000000..4f08042 --- /dev/null +++ b/CUDA_ListScan/libwb/wbDataset_test.cpp @@ -0,0 +1,23 @@ + +#include "wb.h" +#include "vendor/catch.hpp" + +TEST_CASE("Can create Raw dataset", "[DataGenerator]") { + wbGenerateParams_t params; + params.raw.rows = 2; + params.raw.cols = 300; + params.raw.minVal = 0; + params.raw.maxVal = 30; + params.raw.type = wbType_integer; + wbDataset_generate( + wbPath_join(wbDirectory_current(), "test-dataset", "test.raw"), + wbExportKind_raw, params); +} + +TEST_CASE("Can create Text dataset", "[DataGenerator]") { + wbGenerateParams_t params; + params.text.length = 2000; + wbDataset_generate( + wbPath_join(wbDirectory_current(), "test-dataset", "test.txt"), + wbExportKind_text, params); +} diff --git a/CUDA_ListScan/libwb/wbDirectory.cpp b/CUDA_ListScan/libwb/wbDirectory.cpp new file mode 100644 index 0000000..10dc8c5 --- /dev/null +++ b/CUDA_ListScan/libwb/wbDirectory.cpp @@ -0,0 +1,88 @@ +#include "wb.h" + +#ifndef PATH_MAX +#ifdef FILENAME_MAX +#define PATH_MAX FILENAME_MAX +#else /* FILENAME_MAX */ +#define PATH_MAX 4096 +#endif /* FILENAME_MAX */ +#endif /* PATH_MAX */ + +#ifdef WB_USE_UNIX +const char wbDirectorySeperator = '/'; +static char *getcwd_(char *buf, int maxLen) { + return getcwd(buf, maxLen); +} +static void mkdir_(const char *dir) { + mkdir(dir, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); +} +#else /* WB_USE_LINUX */ +const char wbDirectorySeperator = '\\'; +static char *getcwd_(char *buf, int maxLen) { + return _getcwd(buf, maxLen); +} +static void mkdir_(const char *dir) { + _mkdir(dir); +} +#endif /* WB_USE_LINUX */ + +EXTERN_C const char * wbDirectory_create(const char *dir) { + char tmp[PATH_MAX]; + char *p = NULL; + size_t len; +//PMO +#ifndef _MSC_VER + snprintf(tmp, sizeof(tmp), "%s", dir); +#else + _snprintf_s(tmp, sizeof(tmp), "%s", dir); +#endif + len = strlen(tmp); + if (tmp[len - 1] == wbDirectorySeperator) { + tmp[len - 1] = 0; + } + for (p = tmp + 1; *p; p++) { + if (*p == wbDirectorySeperator) { + *p = 0; + mkdir_(tmp); + *p = wbDirectorySeperator; + } + } + mkdir_(tmp); + return dir; +} + +EXTERN_C char *wbDirectory_name(const char *pth0) { + char *pth = wbString_duplicate(pth0); + char *p = strrchr(pth, wbDirectorySeperator); + if (p) { + p[0] = 0; + } + return pth; +} + +EXTERN_C char *wbDirectory_current() { + char *tmp = wbNewArray(char, PATH_MAX + 1); + if (getcwd_(tmp, PATH_MAX)) { + return tmp; + } + + wbDelete(tmp); + + int error = errno; + switch (error) { + case EACCES: + std::cerr + << "Cannot get current directory :: access denied. exiting..." + << std::endl; + exit(-1); + case ENOMEM: + std::cerr << "Cannot get current directory :: insufficient storage. " + "exiting..." + << std::endl; + exit(-1); + default: + std::cerr << "Cannot get current directory :: unrecognised error " + << error << std::endl; + exit(-1); + } +} \ No newline at end of file diff --git a/CUDA_ListScan/libwb/wbDirectory.h b/CUDA_ListScan/libwb/wbDirectory.h new file mode 100644 index 0000000..cb14f81 --- /dev/null +++ b/CUDA_ListScan/libwb/wbDirectory.h @@ -0,0 +1,9 @@ +#ifndef __WB_DIRECTORY__ +#define __WB_DIRECTORY__ + +extern const char wbDirectorySeperator; +EXTERN_C char *wbDirectory_name(const char *pth); +EXTERN_C const char * wbDirectory_create(const char *dir); +EXTERN_C char *wbDirectory_current(); + +#endif /* __WB_DIRECTORY__ */ diff --git a/CUDA_ListScan/libwb/wbExit.cpp b/CUDA_ListScan/libwb/wbExit.cpp new file mode 100644 index 0000000..a7edc3a --- /dev/null +++ b/CUDA_ListScan/libwb/wbExit.cpp @@ -0,0 +1,119 @@ + +#include "wb.h" + +enum { + wbMPI_timerTag = 2, + wbMPI_loggerTag = 4, + wbMPI_solutionExistsTag = 8, + wbMPI_solutionTag = 16 +}; + +void wb_atExit(void) { + using std::cout; + using std::endl; + +#ifdef WB_USE_CUDA + cudaDeviceSynchronize(); +#endif /* WB_USE_CUDA */ + + int nranks = rankCount(); + if (nranks > 1) { +#ifdef WB_USE_MPI + if (isMasterQ) { +#ifdef wbLogger_printOnExit + cout << "==$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$" << endl; + + cout << "{\n"; + cout << wbString_quote("timer") << ":"; + cout << "[\n"; + for (int ii = 0; ii < nranks; ii++) { + if (ii == 0) { + cout << wbTimer_toJSON(); + } else { + const char *msg = wbMPI_getStringFromRank(ii, wbMPI_timerTag); + if (msg != NULL && strlen(msg) != 0) { + cout << ",\n"; + cout << msg; + // free(msg); + } + } + } + cout << "]" << endl; // close timer + + cout << "," << endl; // start logger + cout << wbString_quote("logger") << ":"; + cout << "[\n"; + for (int ii = 0; ii < nranks; ii++) { + if (ii == 0) { + cout << wbLogger_toJSON(); + } else { + const char *msg = wbMPI_getStringFromRank(ii, wbMPI_loggerTag); + if (msg != NULL && strlen(msg) != 0) { + cout << ",\n"; + cout << msg; + // free(msg); + } + } + } + cout << "]" << endl; // close logger + + cout << "," << endl; // start solutionExists + cout << wbString_quote("cuda_memory") << ":" << _cudaMallocSize + << ",\n"; + + if (solutionJSON) { + cout << wbString_quote("solution_exists") << ": true,\n"; + cout << wbString_quote("solution") << ":" << solutionJSON << "\n"; + } else { + cout << wbString_quote("solution_exists") << ": false\n"; + } + cout << "}" << endl; // close json + + } else { + wbMPI_sendStringToMaster(wbTimer_toJSON().c_str(), wbMPI_timerTag); + wbMPI_sendStringToMaster(wbLogger_toJSON().c_str(), wbMPI_loggerTag); + } +#endif /* wbLogger_printOnExit */ + +#endif /* WB_USE_MPI */ + } else { +#ifdef wbLogger_printOnExit + cout << "==$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$" << endl; + + cout << "{\n" << wbString_quote("timer") << ":[" << wbTimer_toJSON() + << "],\n" << wbString_quote("logger") << ":[" << wbLogger_toJSON() + << "],\n"; + +#ifdef WB_USE_CUDA + cout << wbString_quote("cuda_memory") << ":" << _cudaMallocSize + << ",\n"; +#endif /* WB_USE_CUDA */ + + if (solutionJSON) { + cout << wbString_quote("solution_exists") << ": true,\n"; + cout << wbString_quote("solution") << ":" << solutionJSON << "\n"; + } else { + cout << wbString_quote("solution_exists") << ": false\n"; + } + cout << "}" << endl; +#endif /* wbLogger_printOnExit */ + } + + // wbTimer_delete(_timer); + // wbLogger_delete(_logger); + + _timer = NULL; + _logger = NULL; + +// wbFile_atExit(); + +#ifdef WB_USE_CUDA + cudaDeviceReset(); +#endif + + exit(0); + + // assert(0); + + return; +} diff --git a/CUDA_ListScan/libwb/wbExit.h b/CUDA_ListScan/libwb/wbExit.h new file mode 100644 index 0000000..4400108 --- /dev/null +++ b/CUDA_ListScan/libwb/wbExit.h @@ -0,0 +1,7 @@ + +#ifndef __WB_EXIT_H__ +#define __WB_EXIT_H__ + +void wb_atExit(void); + +#endif /* __WB_EXIT_H__ */ diff --git a/CUDA_ListScan/libwb/wbExport.cpp b/CUDA_ListScan/libwb/wbExport.cpp new file mode 100644 index 0000000..59b7a33 --- /dev/null +++ b/CUDA_ListScan/libwb/wbExport.cpp @@ -0,0 +1,510 @@ + +#include "wb.h" + +static inline void wbExportText_setFile(wbExportText_t text, + const char *path) { + if (text != NULL) { + if (wbExportText_getFile(text) != NULL) { + wbFile_delete(wbExportText_getFile(text)); + } + if (path != NULL) { + wbExportText_getFile(text) = wbFile_open(path, "w+"); + } else { + wbExportText_getFile(text) = NULL; + } + } + + return; +} + +static inline wbExportText_t wbExportText_new(void) { + wbExportText_t text; + + text = wbNew(struct st_wbExportText_t); + + wbExportText_getFile(text) = NULL; + wbExportText_setLength(text, -1); + + return text; +} + +static inline void wbExportText_delete(wbExportText_t text) { + if (text != NULL) { + wbExportText_setFile(text, NULL); + wbDelete(text); + } + return; +} + +static inline void wbExportText_write(wbExportText_t text, + const char *data, int length) { + int ii; + FILE *handle; + wbFile_t file; + + if (text == NULL || wbExportText_getFile(text) == NULL) { + return; + } + + file = wbExportText_getFile(text); + + handle = wbFile_getFileHandle(file); + + if (handle == NULL) { + return; + } + + for (ii = 0; ii < length; ii++) { + fprintf(handle, "%c", data[ii]); + } + + return; +} + +static inline void wbExportRaw_setFile(wbExportRaw_t raw, + const char *path) { + if (raw != NULL) { + if (wbExportRaw_getFile(raw) != NULL) { + wbFile_delete(wbExportRaw_getFile(raw)); + } + if (path != NULL) { + wbExportRaw_getFile(raw) = wbFile_open(path, "w+"); + } else { + wbExportRaw_getFile(raw) = NULL; + } + } + + return; +} + +static inline wbExportRaw_t wbExportRaw_new(void) { + wbExportRaw_t raw; + + raw = wbNew(struct st_wbExportRaw_t); + + wbExportRaw_getFile(raw) = NULL; + wbExportRaw_setRowCount(raw, -1); + wbExportRaw_setColumnCount(raw, -1); + + return raw; +} + +static inline void wbExportRaw_delete(wbExportRaw_t raw) { + if (raw != NULL) { + wbExportRaw_setFile(raw, NULL); + wbDelete(raw); + } + return; +} + +static inline void wbExportRaw_write(wbExportRaw_t raw, void *data, + int rows, int columns, + wbType_t type) { + int ii, jj; + FILE *handle; + wbFile_t file; + + if (raw == NULL || wbExportRaw_getFile(raw) == NULL) { + return; + } + + file = wbExportRaw_getFile(raw); + + handle = wbFile_getFileHandle(file); + + if (handle == NULL) { + return; + } + + if (columns == 1) { + fprintf(handle, "%d\n", rows); + } else { + fprintf(handle, "%d %d\n", rows, columns); + } + + for (ii = 0; ii < rows; ii++) { + for (jj = 0; jj < columns; jj++) { + if (type == wbType_integer) { + int elem = ((int *)data)[ii * columns + jj]; + fprintf(handle, "%d", elem); + } else if (type == wbType_ubit8) { + int elem = ((unsigned char *)data)[ii * columns + jj]; + fprintf(handle, "%d", elem); + } else { + wbReal_t elem = ((wbReal_t *)data)[ii * columns + jj]; + fprintf(handle, "%f", elem); + } + if (jj == columns - 1) { + fprintf(handle, "\n"); + } else { + fprintf(handle, " "); + } + } + } + + return; +} + +static inline void wbExportCSV_setFile(wbExportCSV_t csv, + const char *path) { + if (csv != NULL) { + if (wbExportCSV_getFile(csv) != NULL) { + wbFile_delete(wbExportCSV_getFile(csv)); + } + if (path != NULL) { + wbExportCSV_getFile(csv) = wbFile_open(path, "w+"); + } else { + wbExportCSV_getFile(csv) = NULL; + } + } + + return; +} + +static inline wbExportCSV_t wbExportCSV_new(void) { + wbExportCSV_t csv; + + csv = wbNew(struct st_wbExportCSV_t); + + wbExportCSV_getFile(csv) = NULL; + wbExportCSV_setColumnCount(csv, -1); + wbExportCSV_setRowCount(csv, -1); + wbExportCSV_setSeperator(csv, '\0'); + + return csv; +} + +static inline void wbExportCSV_delete(wbExportCSV_t csv) { + if (csv != NULL) { + wbExportCSV_setFile(csv, NULL); + wbDelete(csv); + } +} + +static inline void wbExportCSV_write(wbExportCSV_t csv, void *data, + int rows, int columns, char sep, + wbType_t type) { + int ii, jj; + wbFile_t file; + FILE *handle; + char seperator[2]; + + if (csv == NULL || wbExportCSV_getFile(csv) == NULL) { + return; + } + + file = wbExportCSV_getFile(csv); + + handle = wbFile_getFileHandle(file); + + if (handle == NULL) { + return; + } + + if (sep == '\0') { + seperator[0] = ','; + } else { + seperator[0] = sep; + } + seperator[1] = '\0'; + + for (ii = 0; ii < rows; ii++) { + for (jj = 0; jj < columns; jj++) { + if (type == wbType_integer) { + int elem = ((int *)data)[ii * columns + jj]; + fprintf(handle, "%d", elem); + } else if (type == wbType_ubit8) { + int elem = ((unsigned char *)data)[ii * columns + jj]; + fprintf(handle, "%d", elem); + } else { + wbReal_t elem = ((wbReal_t *)data)[ii * columns + jj]; + fprintf(handle, "%f", elem); + } + if (jj == columns - 1) { + fprintf(handle, "\n"); + } else { + fprintf(handle, "%s", seperator); + } + } + } + + return; +} + +static inline wbExport_t wbExport_open(const char *file, + wbExportKind_t kind) { + wbExport_t exprt; + + if (file == NULL) { + wbLog(ERROR, "Go NULL for file value."); + wbExit(); + } + + wbExport_setFile(exprt, NULL); + wbExport_setKind(exprt, kind); + + if (kind == wbExportKind_raw) { + wbExportRaw_t raw = wbExportRaw_new(); + wbExportRaw_setFile(raw, file); + wbExport_setRaw(exprt, raw); + } else if (kind == wbExportKind_text) { + wbExportText_t txt = wbExportText_new(); + wbExportText_setFile(txt, file); + wbExport_setText(exprt, txt); + } else if (kind == wbExportKind_tsv || kind == wbExportKind_csv) { + wbExportCSV_t csv = wbExportCSV_new(); + if (kind == wbExportKind_csv) { + wbExportCSV_setSeperator(csv, ','); + } else { + wbExportCSV_setSeperator(csv, '\t'); + } + wbExportCSV_setFile(csv, file); + wbExport_setCSV(exprt, csv); + } else if (kind == wbExportKind_ppm) { + wbExport_setFile(exprt, wbString_duplicate(file)); + } else { + wbLog(ERROR, "Invalid export type."); + wbExit(); + } + + return exprt; +} + +static inline wbExport_t wbExport_open(const char *file, + const char *type0) { + wbExport_t exprt; + wbExportKind_t kind; + char *type; + + type = wbString_toLower(type0); + + if (wbString_sameQ(type, "csv")) { + kind = wbExportKind_csv; + } else if (wbString_sameQ(type, "tsv")) { + kind = wbExportKind_tsv; + } else if (wbString_sameQ(type, "raw") || wbString_sameQ(type, "dat")) { + kind = wbExportKind_raw; + } else if (wbString_sameQ(type, "ppm") || wbString_sameQ(type, "pbm")) { + kind = wbExportKind_ppm; + } else if (wbString_sameQ(type, "txt") || wbString_sameQ(type, "text")) { + kind = wbExportKind_text; + } else { + wbLog(ERROR, "Invalid export type ", type0); + wbExit(); + } + + exprt = wbExport_open(file, kind); + + wbDelete(type); + + return exprt; +} + +static inline void wbExport_close(wbExport_t exprt) { + wbExportKind_t kind; + + kind = wbExport_getKind(exprt); + + if (wbExport_getFile(exprt)) { + wbDelete(wbExport_getFile(exprt)); + } + + if (kind == wbExportKind_tsv || kind == wbExportKind_csv) { + wbExportCSV_t csv = wbExport_getCSV(exprt); + wbExportCSV_delete(csv); + wbExport_setCSV(exprt, NULL); + } else if (kind == wbExportKind_raw) { + wbExportRaw_t raw = wbExport_getRaw(exprt); + wbExportRaw_delete(raw); + wbExport_setRaw(exprt, NULL); + } else if (kind == wbExportKind_text) { + wbExportText_t text = wbExport_getText(exprt); + wbExportText_delete(text); + wbExport_setText(exprt, NULL); + } else if (kind == wbExportKind_ppm) { + } else { + wbLog(ERROR, "Invalid export type."); + wbExit(); + } + return; +} + +static inline void wbExport_writeAsImage(wbExport_t exprt, wbImage_t img) { + wbAssert(wbExport_getKind(exprt) == wbExportKind_ppm); + + wbPPM_export(wbExport_getFile(exprt), img); + + return; +} + +static inline void wbExport_write(wbExport_t exprt, void *data, int rows, + int columns, char sep, wbType_t type) { + wbExportKind_t kind; + + kind = wbExport_getKind(exprt); + if (kind == wbExportKind_tsv || kind == wbExportKind_csv) { + wbExportCSV_t csv = wbExport_getCSV(exprt); + wbExportCSV_write(csv, data, rows, columns, sep, type); + } else if (kind == wbExportKind_raw) { + wbExportRaw_t raw = wbExport_getRaw(exprt); + wbExportRaw_write(raw, data, rows, columns, type); + } else if (kind == wbExportKind_text) { + wbExportText_t text = wbExport_getText(exprt); + if (columns == 0) { + columns = 1; + } + if (rows == 0) { + rows = 1; + } + wbExportText_write(text, (const char *)data, rows * columns); + } else { + wbLog(ERROR, "Invalid export type."); + wbExit(); + } + return; +} + +static inline void wbExport_write(wbExport_t exprt, void *data, int rows, + int columns, wbType_t type) { + wbExport_write(exprt, data, rows, columns, ',', type); +} + +static wbExportKind_t _parseExportExtension(const char *file) { + char *extension; + wbExportKind_t kind; + + extension = wbFile_extension(file); + + if (wbString_sameQ(extension, "csv")) { + kind = wbExportKind_csv; + } else if (wbString_sameQ(extension, "tsv")) { + kind = wbExportKind_tsv; + } else if (wbString_sameQ(extension, "raw") || + wbString_sameQ(extension, "dat")) { + kind = wbExportKind_raw; + } else if (wbString_sameQ(extension, "text") || + wbString_sameQ(extension, "txt")) { + kind = wbExportKind_text; + } else if (wbString_sameQ(extension, "ppm")) { + kind = wbExportKind_ppm; + } else { + kind = wbExportKind_unknown; + wbLog(ERROR, "File ", file, " does not have a compatible extension."); + } + + wbDelete(extension); + + return kind; +} + +static void wbExport(const char *file, void *data, int rows, int columns, + wbType_t type) { + wbExportKind_t kind; + wbExport_t exprt; + + if (file == NULL) { + return; + } + + kind = _parseExportExtension(file); + exprt = wbExport_open(file, kind); + + wbExport_write(exprt, data, rows, columns, type); + wbExport_close(exprt); +} + +void wbExport(const char *file, unsigned char *data, int rows) { + wbExport(file, data, rows, 1); + return; +} + +void wbExport(const char *file, int *data, int rows) { + wbExport(file, data, rows, 1); + return; +} + +void wbExport(const char *file, wbReal_t *data, int rows) { + wbExport(file, data, rows, 1); + return; +} + +void wbExport(const char *file, unsigned char *data, int rows, + int columns) { + wbExportKind_t kind; + wbExport_t exprt; + + if (file == NULL) { + return; + } + + kind = _parseExportExtension(file); + exprt = wbExport_open(file, kind); + + wbExport_write(exprt, data, rows, columns, wbType_ubit8); + wbExport_close(exprt); +} + +void wbExport(const char *file, int *data, int rows, int columns) { + wbExportKind_t kind; + wbExport_t exprt; + + if (file == NULL) { + return; + } + + kind = _parseExportExtension(file); + exprt = wbExport_open(file, kind); + + wbExport_write(exprt, data, rows, columns, wbType_integer); + wbExport_close(exprt); +} + +void wbExport(const char *file, wbReal_t *data, int rows, int columns) { + wbExportKind_t kind; + wbExport_t exprt; + + if (file == NULL) { + return; + } + + kind = _parseExportExtension(file); + exprt = wbExport_open(file, kind); + + wbExport_write(exprt, data, rows, columns, wbType_real); + wbExport_close(exprt); +} + +void wbExport(const char *file, wbExportKind_t kind, void *data, int rows, + int columns, wbType_t type) { + wbExport_t exprt; + + if (file == NULL) { + return; + } + + exprt = wbExport_open(file, kind); + + wbExport_write(exprt, data, rows, columns, type); + wbExport_close(exprt); +} + +void wbExport(const char *file, wbImage_t img) { + wbExportKind_t kind; + wbExport_t exprt; + + if (file == NULL) { + return; + } + + kind = _parseExportExtension(file); + exprt = wbExport_open(file, kind); + + wbAssert(kind == wbExportKind_ppm); + + wbExport_writeAsImage(exprt, img); + wbExport_close(exprt); +} + +void wbExport_text(const char *file, void *data, int length) { + wbExport(file, wbExportKind_text, data, 1, length, wbType_ascii); +} diff --git a/CUDA_ListScan/libwb/wbExport.h b/CUDA_ListScan/libwb/wbExport.h new file mode 100644 index 0000000..dd16b3f --- /dev/null +++ b/CUDA_ListScan/libwb/wbExport.h @@ -0,0 +1,106 @@ + + +#ifndef __WB_EXPORT_H__ +#define __WB_EXPORT_H__ + +#include "wb.h" +#include "wbFile.h" +#include "wbPPM.h" + +typedef enum en_wbExportKind_t { + wbExportKind_unknown = -1, + wbExportKind_raw = 0x1000, + wbExportKind_csv, + wbExportKind_tsv, + wbExportKind_ppm, + wbExportKind_text, +} wbExportKind_t; + +typedef struct st_wbExportText_t { + int length; + wbFile_t file; +} * wbExportText_t; + +#define wbExportText_getLength(txt) ((txt)->length) +#define wbExportText_getFile(txt) ((txt)->file) + +#define wbExportText_setLength(txt, val) \ + (wbExportText_getLength(txt) = val) + +typedef struct st_wbExportRaw_t { + int rows; + int columns; + wbFile_t file; +} * wbExportRaw_t; + +#define wbExportRaw_getColumnCount(raw) ((raw)->columns) +#define wbExportRaw_getRowCount(raw) ((raw)->rows) +#define wbExportRaw_getFile(raw) ((raw)->file) + +#define wbExportRaw_setRowCount(raw, val) \ + (wbExportRaw_getRowCount(raw) = val) +#define wbExportRaw_setColumnCount(raw, val) \ + (wbExportRaw_getColumnCount(raw) = val) + +typedef struct st_wbExportCSV_t { + int rows; + int columns; + wbFile_t file; + char seperator; +} * wbExportCSV_t; + +#define wbExportCSV_getRowCount(csv) ((csv)->rows) +#define wbExportCSV_getColumnCount(csv) ((csv)->columns) +#define wbExportCSV_getFile(csv) ((csv)->file) +#define wbExportCSV_getSeperator(csv) ((csv)->seperator) + +#define wbExportCSV_setRowCount(csv, val) \ + (wbExportCSV_getRowCount(csv) = val) +#define wbExportCSV_setColumnCount(csv, val) \ + (wbExportCSV_getColumnCount(csv) = val) +#define wbExportCSV_setSeperator(csv, val) \ + (wbExportCSV_getSeperator(csv) = val) + +typedef struct st_wbExport_t { + wbExportKind_t kind; + union { + wbExportRaw_t raw; + wbExportCSV_t csv; + wbImage_t img; + wbExportText_t text; + } container; + char *file; +} wbExport_t; + +#define wbExport_getKind(exprt) ((exprt).kind) +#define wbExport_getContainer(exprt) ((exprt).container) +#define wbExport_getRaw(exprt) (wbExport_getContainer(exprt).raw) +#define wbExport_getCSV(exprt) (wbExport_getContainer(exprt).csv) +#define wbExport_getImage(exprt) (wbExport_getContainer(exprt).img) +#define wbExport_getText(exprt) (wbExport_getContainer(exprt).text) +#define wbExport_getFile(exprt) ((exprt).file) + +#define wbExport_setKind(exprt, val) (wbExport_getKind(exprt) = val) +#define wbExport_setRaw(exprt, val) (wbExport_getRaw(exprt) = val) +#define wbExport_setCSV(exprt, val) (wbExport_getCSV(exprt) = val) +#define wbExport_setImage(exprt, val) (wbExport_getImage(exprt) = val) +#define wbExport_setText(exprt, val) (wbExport_getText(exprt) = val) +#define wbExport_setFile(exprt, val) (wbExport_getFile(exprt) = val) + +void wbExport(const char *file, int *data, int rows, int columns); +void wbExport(const char *file, int *data, int rows); +void wbExport(const char *file, unsigned char *data, int rows, + int columns); +void wbExport(const char *file, unsigned char *data, int rows); +void wbExport(const char *file, int *data, int rows, int columns); +void wbExport(const char *file, int *data, int rows); +void wbExport(const char *file, wbReal_t *data, int rows, int columns); +void wbExport(const char *file, wbReal_t *data, int rows); +void wbExport(const char *file, wbImage_t img); + +void wbExport(const char *file, wbExportKind_t kind, void *data, int rows, + int columns, wbType_t type); + +void wbExport_text(const char *file, void *data, int length); + +#endif /* __WB_EXPORT_H__ */ diff --git a/CUDA_ListScan/libwb/wbFile.cpp b/CUDA_ListScan/libwb/wbFile.cpp new file mode 100644 index 0000000..b3fdbe7 --- /dev/null +++ b/CUDA_ListScan/libwb/wbFile.cpp @@ -0,0 +1,353 @@ + + +#include "wb.h" + +#define wbFile_maxCount 256 + +static wbFile_t wbFile_handles[wbFile_maxCount]; + +static int wbFile_nextIndex(void) { + int ii; + for (ii = 0; ii < wbFile_maxCount; ii++) { + if (wbFile_handles[ii] == NULL) { + return ii; + } + } + wbLog(ERROR, "Ran out of file handles."); + wbExit(); + return -1; +} + +wbFile_t wbFile_new(void) { + int idx = wbFile_nextIndex(); + wbFile_t file = wbNew(struct st_wbFile_t); + + wbAssert(idx >= 0); + + wbFile_setIndex(file, idx); + wbFile_setFileName(file, NULL); + wbFile_setMode(file, NULL); + wbFile_setFileHandle(file, NULL); + wbFile_setData(file, NULL); + + wbFile_handles[idx] = file; + + return file; +} + +void wbFile_delete(wbFile_t file) { + if (file != NULL) { + int idx = wbFile_getIndex(file); + if (wbFile_getFileName(file) != NULL) { + wbDelete(wbFile_getFileName(file)); + } + if (wbFile_getMode(file) != NULL) { + wbDelete(wbFile_getMode(file)); + } + if (wbFile_getFileHandle(file) != NULL) { + fflush(wbFile_getFileHandle(file)); + fclose(wbFile_getFileHandle(file)); + } + if (idx >= 0) { + wbAssert(wbFile_handles[idx] == file); + wbFile_handles[idx] = NULL; + } + if (wbFile_getData(file) != NULL) { + wbDelete(wbFile_getData(file)); + } + wbDelete(file); + } +} + +void wbFile_init(void) { + int ii; + + for (ii = 0; ii < wbFile_maxCount; ii++) { + wbFile_handles[ii] = NULL; + } +} + +void wbFile_atExit(void) { + int ii; + + for (ii = 0; ii < wbFile_maxCount; ii++) { + if (wbFile_handles[ii] != NULL) { + wbFile_delete(wbFile_handles[ii]); + } + } +} + +int wbFile_count(void) { + int ii, count = 0; + + for (ii = 0; ii < wbFile_maxCount; ii++) { + if (wbFile_handles[ii] != NULL) { + count++; + } + } + return count; +} + +wbFile_t wbFile_open(const char *fileName, const char *mode) { + FILE *handle; + wbFile_t file; + + if (fileName == NULL) { + return NULL; + } + + handle = fopen(fileName, mode); + if (handle == NULL) { + wbLog(ERROR, "Failed to open ", file, " in mode ", mode); + return NULL; + } + + file = wbFile_new(); + wbFile_setFileName(file, wbString_duplicate(fileName)); + wbFile_setMode(file, wbString_duplicate(mode)); + wbFile_setFileHandle(file, handle); + + return file; +} + +wbFile_t wbFile_open(const char *fileName) { + return wbFile_open(fileName, "r"); +} + +void wbFile_close(wbFile_t file) { + wbFile_delete(file); +} + +char *wbFile_read(wbFile_t file, size_t size, size_t count) { + size_t res; + char *buffer; + size_t bufferLen; + FILE *handle; + + if (file == NULL) { + return NULL; + } +#ifndef LAZY_FILE_LOAD + if (wbFile_getData(file) != NULL) { + char *data = wbFile_getData(file) + wbFile_getDataOffset(file); + wbFile_setDataOffset(file, wbFile_getDataOffset(file) + size * count); + return data; + } +#endif /* LAZY_FILE_LOAD */ + + handle = wbFile_getFileHandle(file); + bufferLen = size * count + 1; + buffer = wbNewArray(char, bufferLen); + + res = fread(buffer, size, count, handle); + // make valid C string + buffer[size * res] = '\0'; + + return buffer; +} + +char *wbFile_read(wbFile_t file, size_t len) { + char *buffer = wbFile_read(file, sizeof(char), len); + return buffer; +} + +void wbFile_rewind(wbFile_t file) { + if (file == NULL) { + return; + } + + if (wbFile_getData(file) == NULL) { + FILE *handle; + handle = wbFile_getFileHandle(file); + wbAssert(handle != NULL); + rewind(handle); + } +#ifndef LAZY_FILE_LOAD + else { + wbFile_setDataOffset(file, 0); + } +#endif + + return; +} + +size_t wbFile_size(wbFile_t file) { + size_t len; + FILE *handle; + + if (file == NULL) { + return 0; + } +#ifndef LAZY_FILE_LOAD + if (wbFile_getData(file) != NULL) { + if (wbFile_getLength(file) == 0) { + wbFile_setLength(file, strlen(wbFile_getData(file))); + } + return wbFile_getLength(file); + } +#endif /* LAZY_FILE_LOAD */ + + handle = wbFile_getFileHandle(file); + + fseek(handle, 0, SEEK_END); + len = ftell(handle); + rewind(handle); + + return len; +} + +char *wbFile_read(wbFile_t file) { + size_t len; + + if (file == NULL) { + return NULL; + } + + len = wbFile_size(file); + + if (len == 0) { + return NULL; + } + + wbFile_setLength(file, len); + + return wbFile_read(file, len); +} + +#define MAX_CHARS_PER_LINE (1 << 17) + +static char buffer[MAX_CHARS_PER_LINE]; + +char *wbFile_readLine(wbFile_t file) { + if (file == NULL) { + return NULL; + } +#ifdef LAZY_FILE_LOAD + FILE *handle; + memset(buffer, 0, MAX_CHARS_PER_LINE); + + handle = wbFile_getFileHandle(file); + + if (fgets(buffer, MAX_CHARS_PER_LINE - 1, handle)) { + return buffer; + } else { + // wbLog(ERROR, "Was not able to read line from ", + // wbFile_getFileName(file)); + return NULL; + } +#else + size_t newOffset; + size_t lenToNewLine = 0; + const char *tmp; + + if (wbFile_getData(file) == NULL) { + wbFile_setData(file, wbFile_read(file)); + fclose(wbFile_getFileHandle(file)); + wbFile_setFileHandle(file, NULL); + wbFile_setDataOffset(file, 0); + wbFile_setLength(file, strlen(wbFile_getData(file))); + } + + memset(buffer, 0, MAX_CHARS_PER_LINE); + + if (wbFile_getDataOffset(file) >= wbFile_getLength(file)) { + return NULL; + } + + newOffset = wbFile_getDataOffset(file); + tmp = wbFile_getData(file) + wbFile_getDataOffset(file); + while (newOffset < wbFile_getLength(file) && *tmp != '\n') { + tmp++; + lenToNewLine++; + newOffset++; + } + + memcpy(buffer, wbFile_getData(file) + wbFile_getDataOffset(file), + lenToNewLine); + wbFile_setDataOffset(file, newOffset + 1); + + return buffer; +#endif +} + +void wbFile_write(wbFile_t file, const void *buffer, size_t size, + size_t count) { + size_t res; + FILE *handle; + + if (file == NULL) { + return; + } + + handle = wbFile_getFileHandle(file); + + res = fwrite(buffer, size, count, handle); + if (res != count) { + wbLog(ERROR, "Failed to write data to ", wbFile_getFileName(file)); + } + + return; +} + +void wbFile_write(wbFile_t file, const void *buffer, size_t len) { + wbFile_write(file, buffer, sizeof(char), len); + return; +} + +void wbFile_write(wbFile_t file, const char *buffer) { + size_t len; + + len = strlen(buffer); + wbFile_write(file, buffer, len); + + return; +} + +void wbFile_writeLine(wbFile_t file, const char *buffer0) { + string buffer = wbString(buffer0, "\n"); + wbFile_write(file, buffer.c_str()); +} + +void wbFile_write(wbFile_t file, string buffer) { + wbFile_write(file, buffer.c_str()); +} + +void wbFile_writeLine(wbFile_t file, string buffer0) { + string buffer = buffer0 + "\n"; + wbFile_write(file, buffer.c_str()); +} + +wbBool wbFile_existsQ(const char *path) { + if (path == NULL) { + return wbFalse; + } else { + FILE *file = fopen(path, "r"); + if (file != NULL) { + fclose(file); + return wbTrue; + } + return wbFalse; + } +} + +char *wbFile_extension(const char *file) { + char *extension; + char *extensionLower; + char *end; + size_t len; + + len = strlen(file); + end = (char *)&file[len - 1]; + while (*end != '.') { + end--; + } + if (*end == '.') { + end++; + } + + extension = wbString_duplicate(end); + extensionLower = wbString_toLower(extension); + wbDelete(extension); + + return extensionLower; +} diff --git a/CUDA_ListScan/libwb/wbFile.h b/CUDA_ListScan/libwb/wbFile.h new file mode 100644 index 0000000..ea6b0cb --- /dev/null +++ b/CUDA_ListScan/libwb/wbFile.h @@ -0,0 +1,56 @@ + + +#ifndef __WB_FILE_H__ +#define __WB_FILE_H__ + +struct st_wbFile_t { + int index; + char *file; + char *mode; + char *data; + FILE *handle; + size_t len; + size_t offset; +}; + +#define wbFile_getIndex(file) ((file)->index) +#define wbFile_getFileName(file) ((file)->file) +#define wbFile_getMode(file) ((file)->mode) +#define wbFile_getData(file) ((file)->data) +#define wbFile_getLength(file) ((file)->len) +#define wbFile_getDataOffset(file) ((file)->offset) +#define wbFile_getFileHandle(file) ((file)->handle) + +#define wbFile_setIndex(file, val) (wbFile_getIndex(file) = val) +#define wbFile_setFileName(file, val) (wbFile_getFileName(file) = val) +#define wbFile_setMode(file, val) (wbFile_getMode(file) = val) +#define wbFile_setData(file, val) (wbFile_getData(file) = val) +#define wbFile_setLength(file, val) (wbFile_getLength(file) = val) +#define wbFile_setDataOffset(file, val) (wbFile_getDataOffset(file) = val) +#define wbFile_setFileHandle(file, val) (wbFile_getFileHandle(file) = val) + +wbFile_t wbFile_new(void); +void wbFile_delete(wbFile_t file); +void wbFile_close(wbFile_t file); +void wbFile_init(void); +void wbFile_atExit(void); +int wbFile_count(void); +wbFile_t wbFile_open(const char *fileName, const char *mode); +wbFile_t wbFile_open(const char *fileName); +char *wbFile_read(wbFile_t file, size_t size, size_t count); +char *wbFile_read(wbFile_t file, size_t len); +void wbFile_rewind(wbFile_t file); +size_t wbFile_size(wbFile_t file); +char *wbFile_read(wbFile_t file); +char *wbFile_readLine(wbFile_t file); +void wbFile_write(wbFile_t file, const void *buffer, size_t size, + size_t count); +void wbFile_write(wbFile_t file, const void *buffer, size_t len); +void wbFile_write(wbFile_t file, const char *buffer); +void wbFile_writeLine(wbFile_t file, const char *buffer0); +void wbFile_write(wbFile_t file, string buffer); +void wbFile_writeLine(wbFile_t file, string buffer0); +wbBool wbFile_existsQ(const char *path); +char *wbFile_extension(const char *file); + +#endif /* __WB_FILE_H__ */ diff --git a/CUDA_ListScan/libwb/wbImage.cpp b/CUDA_ListScan/libwb/wbImage.cpp new file mode 100644 index 0000000..1d95928 --- /dev/null +++ b/CUDA_ListScan/libwb/wbImage.cpp @@ -0,0 +1,134 @@ + + +#include "wb.h" + +static inline float _min(float x, float y) { + return x < y ? x : y; +} + +static inline float _max(float x, float y) { + return x > y ? x : y; +} + +static inline float _clamp(float x, float start, float end) { + return _min(_max(x, start), end); +} + +wbImage_t wbImage_new(int width, int height, int channels, float *data) { + wbImage_t img; + + img = wbNew(struct st_wbImage_t); + + wbImage_setWidth(img, width); + wbImage_setHeight(img, height); + wbImage_setChannels(img, channels); + wbImage_setPitch(img, width * channels); + + wbImage_setData(img, data); + return img; +} + +wbImage_t wbImage_new(int width, int height, int channels) { + float *data = wbNewArray(float, width *height *channels); + return wbImage_new(width, height, channels, data); +} + +wbImage_t wbImage_new(int width, int height) { + return wbImage_new(width, height, wbImage_channels); +} + +void wbImage_delete(wbImage_t img) { + if (img != NULL) { + if (wbImage_getData(img) != NULL) { + wbDelete(wbImage_getData(img)); + } + wbDelete(img); + } +} + +static inline void wbImage_setPixel(wbImage_t img, int x, int y, int c, + float val) { + float *data = wbImage_getData(img); + int channels = wbImage_getChannels(img); + int pitch = wbImage_getPitch(img); + + data[y * pitch + x * channels + c] = val; + + return; +} + +static inline float wbImage_getPixel(wbImage_t img, int x, int y, int c) { + float *data = wbImage_getData(img); + int channels = wbImage_getChannels(img); + int pitch = wbImage_getPitch(img); + + return data[y * pitch + x * channels + c]; +} + +wbBool wbImage_sameQ(wbImage_t a, wbImage_t b, + wbImage_onSameFunction_t onUnSame) { + if (a == NULL || b == NULL) { + wbLog(ERROR, "Comparing null images."); + return wbFalse; + } else if (a == b) { + return wbTrue; + } else if (wbImage_getWidth(a) != wbImage_getWidth(b)) { + wbLog(ERROR, "Image widths do not match."); + return wbFalse; + } else if (wbImage_getHeight(a) != wbImage_getHeight(b)) { + wbLog(ERROR, "Image heights do not match."); + return wbFalse; + } else if (wbImage_getChannels(a) != wbImage_getChannels(b)) { + wbLog(ERROR, "Image channels do not match."); + return wbFalse; + } else { + float *aData, *bData; + int width, height, channels; + int ii, jj, kk; + + aData = wbImage_getData(a); + bData = wbImage_getData(b); + + wbAssert(aData != NULL); + wbAssert(bData != NULL); + + width = wbImage_getWidth(a); + height = wbImage_getHeight(a); + channels = wbImage_getChannels(a); + + for (ii = 0; ii < height; ii++) { + for (jj = 0; jj < width; jj++) { + for (kk = 0; kk < channels; kk++) { + float x, y; + if (channels <= 3) { + x = _clamp(*aData++, 0, 1); + y = _clamp(*bData++, 0, 1); + } else { + x = *aData++; + y = *bData++; + } + if (wbUnequalQ(x, y)) { + if (onUnSame != NULL) { + string str = wbString( + "Image pixels do not match at position ( row = ", + wbString(ii, ", col = ", jj, ", channel = ", kk, + ") expecting a value of "), + wbString(y, " but got a computed value of ", x)); + onUnSame(str); + } + return wbFalse; + } + } + } + } + return wbTrue; + } +} + +static void wbImage_onUnsameFunction(string str) { + wbLog(ERROR, str); +} + +wbBool wbImage_sameQ(wbImage_t a, wbImage_t b) { + return wbImage_sameQ(a, b, wbImage_onUnsameFunction); +} diff --git a/CUDA_ListScan/libwb/wbImage.h b/CUDA_ListScan/libwb/wbImage.h new file mode 100644 index 0000000..020eec5 --- /dev/null +++ b/CUDA_ListScan/libwb/wbImage.h @@ -0,0 +1,40 @@ + + +#ifndef __IMAGE_H__ +#define __IMAGE_H__ + +#include "wbTypes.h" + +struct st_wbImage_t { + int width; + int height; + int channels; + int pitch; + float *data; +}; + +#define wbImage_channels 3 + +#define wbImage_getWidth(img) ((img)->width) +#define wbImage_getHeight(img) ((img)->height) +#define wbImage_getChannels(img) ((img)->channels) +#define wbImage_getPitch(img) ((img)->pitch) +#define wbImage_getData(img) ((img)->data) + +#define wbImage_setWidth(img, val) (wbImage_getWidth(img) = val) +#define wbImage_setHeight(img, val) (wbImage_getHeight(img) = val) +#define wbImage_setChannels(img, val) (wbImage_getChannels(img) = val) +#define wbImage_setPitch(img, val) (wbImage_getPitch(img) = val) +#define wbImage_setData(img, val) (wbImage_getData(img) = val) + +typedef void (*wbImage_onSameFunction_t)(string str); + +wbImage_t wbImage_new(int width, int height, int channels, float *data); +wbImage_t wbImage_new(int width, int height, int channels); +wbImage_t wbImage_new(int width, int height); +void wbImage_delete(wbImage_t img); +wbBool wbImage_sameQ(wbImage_t a, wbImage_t b, + wbImage_onSameFunction_t onUnSame); +wbBool wbImage_sameQ(wbImage_t a, wbImage_t b); + +#endif /* __IMAGE_H__ */ diff --git a/CUDA_ListScan/libwb/wbImport.cpp b/CUDA_ListScan/libwb/wbImport.cpp new file mode 100644 index 0000000..fccc071 --- /dev/null +++ b/CUDA_ListScan/libwb/wbImport.cpp @@ -0,0 +1,711 @@ + + +#include "wb.h" + +static inline void wbImportCSV_setFile(wbImportCSV_t csv, + const char *path) { + if (csv != NULL) { + if (wbImportCSV_getFile(csv) != NULL) { + wbFile_delete(wbImportCSV_getFile(csv)); + } + if (path != NULL) { + wbImportCSV_getFile(csv) = wbFile_open(path, "r"); + } else { + wbImportCSV_getFile(csv) = NULL; + } + } + + return; +} + +static inline wbImportCSV_t wbImportCSV_new(void) { + wbImportCSV_t csv; + + csv = wbNew(struct st_wbImportCSV_t); + + wbImportCSV_setRowCount(csv, -1); + wbImportCSV_setColumnCount(csv, -1); + wbImportCSV_setData(csv, NULL); + wbImportCSV_getFile(csv) = NULL; + wbImportCSV_setSeperator(csv, '\0'); + + return csv; +} + +static inline void wbImportCSV_delete(wbImportCSV_t csv) { + if (csv != NULL) { + wbImportCSV_setFile(csv, NULL); + if (wbImportCSV_getData(csv)) { + wbDelete(wbImportCSV_getData(csv)); + } + wbDelete(csv); + } +} + +static inline wbImportCSV_t wbImportCSV_findDimensions(wbImportCSV_t csv, + int *resRows, + int *resColumns) { + int rows = 0, columns = -1; + char *line; + wbFile_t file; + char seperator[2]; + + if (csv == NULL) { + return NULL; + } + + if (wbImportCSV_getSeperator(csv) == '\0') { + seperator[0] = ','; + } else { + seperator[0] = wbImportCSV_getSeperator(csv); + } + seperator[1] = '\0'; + + file = wbImportCSV_getFile(csv); + + while ((line = wbFile_readLine(file)) != NULL) { + int currColumn = 0; + char *token = strtok(line, seperator); + while (token != NULL) { + token = strtok(NULL, seperator); + currColumn++; + } + rows++; + if (columns == -1) { + columns = currColumn; + } + if (columns != currColumn) { + wbLog(ERROR, "The csv file is not rectangular."); + } + wbAssert(columns == currColumn); + } + + wbFile_rewind(file); + + *resRows = rows; + *resColumns = columns; + + return csv; +} + +static inline int *csv_readAsInteger(wbFile_t file, char sep, int rows, + int columns) { + int ii = 0; + int *data; + char *line; + int var; + char seperator[2]; + + if (file == NULL) { + return NULL; + } + + data = wbNewArray(int, rows *columns); + + if (sep == '\0') { + seperator[0] = ','; + } else { + seperator[0] = sep; + } + seperator[1] = '\0'; + + // printf("cols = %d rows = %d\n", columns, rows); + if (columns == 1) { + while ((line = wbFile_readLine(file)) != NULL) { + sscanf(line, "%d", &var); + // printf("reading %d\n", var); + data[ii++] = var; + } + } else { + while ((line = wbFile_readLine(file)) != NULL) { + char *token = strtok(line, seperator); + while (token != NULL) { + sscanf(token, "%d", &var); + token = strtok(NULL, seperator); + data[ii++] = var; + } + } + } + + return data; +} + +static inline wbReal_t *csv_readAsReal(wbFile_t file, char sep, int rows, + int columns) { + int ii = 0; + wbReal_t *data; + char *line; + wbReal_t var; + char seperator[2]; + + if (file == NULL) { + return NULL; + } + + data = wbNewArray(wbReal_t, rows * columns); + + if (sep == '\0') { + seperator[0] = ','; + } else { + seperator[0] = sep; + } + seperator[1] = '\0'; + + if (columns == 1) { + while ((line = wbFile_readLine(file)) != NULL) { + sscanf(line, "%f", &var); + data[ii++] = var; + } + } else { + while ((line = wbFile_readLine(file)) != NULL) { + char *token = strtok(line, seperator); + while (token != NULL) { + sscanf(token, "%f", &var); + token = strtok(NULL, seperator); + data[ii++] = var; + } + } + } + + return data; +} + +static inline wbImportCSV_t wbImportCSV_read(wbImportCSV_t csv, + wbType_t type) { + void *data; + wbFile_t file; + char seperator; + int rows, columns; + + if (csv == NULL) { + return NULL; + } + + if (wbImportCSV_getRowCount(csv) == -1 || + wbImportCSV_getColumnCount(csv) == -1) { + if (wbImportCSV_findDimensions(csv, &rows, &columns) == NULL) { + wbLog(ERROR, "Failed to figure out csv dimensions."); + return NULL; + } + wbImportCSV_setRowCount(csv, rows); + wbImportCSV_setColumnCount(csv, columns); + } + + file = wbImportCSV_getFile(csv); + seperator = wbImportCSV_getSeperator(csv); + rows = wbImportCSV_getRowCount(csv); + columns = wbImportCSV_getColumnCount(csv); + + if (wbImportCSV_getData(csv) != NULL) { + wbDelete(wbImportCSV_getData(csv)); + wbImportCSV_setData(csv, NULL); + } + + if (type == wbType_integer) { + // printf("ReadXXXing as integer...\n"); + data = csv_readAsInteger(file, seperator, rows, columns); + } else { + data = csv_readAsReal(file, seperator, rows, columns); + } + + wbImportCSV_setData(csv, data); + + return csv; +} + +static inline wbImportCSV_t wbImportCSV_readAsInteger(wbImportCSV_t csv) { + return wbImportCSV_read(csv, wbType_integer); +} + +static inline wbImportCSV_t wbImportCSV_readAsReal(wbImportCSV_t csv) { + return wbImportCSV_read(csv, wbType_real); +} + +static inline void wbImportRaw_setFile(wbImportRaw_t raw, + const char *path) { + if (raw != NULL) { + if (wbImportRaw_getFile(raw) != NULL) { + wbFile_delete(wbImportRaw_getFile(raw)); + } + if (path != NULL) { + wbImportRaw_getFile(raw) = wbFile_open(path, "r"); + } else { + wbImportRaw_getFile(raw) = NULL; + } + } + + return; +} + +static inline wbImportRaw_t wbImportRaw_new(void) { + wbImportRaw_t raw; + + raw = wbNew(struct st_wbImportRaw_t); + + wbImportRaw_setRowCount(raw, -1); + wbImportRaw_setColumnCount(raw, -1); + wbImportRaw_setData(raw, NULL); + wbImportRaw_getFile(raw) = NULL; + + return raw; +} + +static inline void wbImportRaw_delete(wbImportRaw_t raw) { + if (raw != NULL) { + wbImportRaw_setFile(raw, NULL); + if (wbImportRaw_getData(raw)) { + wbDelete(wbImportRaw_getData(raw)); + } + wbDelete(raw); + } +} + +static inline wbBool lineHasSpace(const char *line) { + while (*line != '\0') { + if (*line == ' ') { + return wbTrue; + } + line++; + } + return wbFalse; +} + +static inline char *lineStrip(const char *line) { + char *sl = wbString_duplicate(line); + char *iter = sl; + size_t slen = strlen(line); + + iter += slen - 1; + while (*iter == '\0' || *iter == '\r' || *iter == '\t' || + *iter == '\n' || *iter == ' ') { + *iter-- = '\0'; + } + return sl; +} + +static inline wbBool wbImportRaw_findDimensions(wbImportRaw_t raw) { + if (raw != NULL) { + int rows; + int columns; + char *line; + wbFile_t file; + char *strippedLine; + + file = wbImportRaw_getFile(raw); + + wbFile_rewind(file); + + line = wbFile_readLine(file); + + if (line == NULL) { + return wbTrue; + } + + strippedLine = lineStrip(line); + + if (lineHasSpace(strippedLine)) { + sscanf(strippedLine, "%d %d", &rows, &columns); + } else { + columns = 1; + sscanf(strippedLine, "%d", &rows); + } + + wbImportRaw_setRowCount(raw, rows); + wbImportRaw_setColumnCount(raw, columns); + + wbDelete(strippedLine); + + return wbFalse; + } + + return wbTrue; +} + +static inline wbImportRaw_t wbImportRaw_read(wbImportRaw_t raw, + wbType_t type) { + void *data; + wbFile_t file; + char seperator; + int rows, columns; + + if (raw == NULL) { + return NULL; + } + + if (wbImportRaw_getRowCount(raw) == -1 || + wbImportRaw_getColumnCount(raw) == -1) { + if (wbImportRaw_findDimensions(raw)) { + wbLog(ERROR, "Failed to figure out raw dimensions."); + return NULL; + } + } + + file = wbImportRaw_getFile(raw); + seperator = ' '; + rows = wbImportRaw_getRowCount(raw); + columns = wbImportRaw_getColumnCount(raw); + + if (wbImportRaw_getData(raw) != NULL) { + wbDelete(wbImportRaw_getData(raw)); + wbImportRaw_setData(raw, NULL); + } + + if (type == wbType_integer) { + // printf("Rdin gas integer...\n"); + data = csv_readAsInteger(file, seperator, rows, columns); + } else { + data = csv_readAsReal(file, seperator, rows, columns); + } + + wbImportRaw_setData(raw, data); + + return raw; +} + +static inline wbImportRaw_t wbImportRaw_readAsInteger(wbImportRaw_t raw) { + return wbImportRaw_read(raw, wbType_integer); +} + +static inline wbImportRaw_t wbImportRaw_readAsReal(wbImportRaw_t raw) { + return wbImportRaw_read(raw, wbType_real); +} + +static inline wbImportText_t wbImportText_new(void) { + wbImportText_t text; + + text = wbNew(struct st_wbImportText_t); + + wbImportText_setLength(text, 0); + wbImportText_setData(text, NULL); + wbImportText_getFile(text) = NULL; + + return text; +} + +static inline void wbImportText_setFile(wbImportText_t text, + const char *path) { + if (text != NULL) { + if (wbImportText_getFile(text) != NULL) { + wbFile_delete(wbImportText_getFile(text)); + } + if (path != NULL) { + wbImportText_getFile(text) = wbFile_open(path, "r"); + } else { + wbImportText_getFile(text) = NULL; + } + } + + return; +} + +static inline void wbImportText_delete(wbImportText_t text) { + if (text != NULL) { + wbImportText_setFile(text, NULL); + if (wbImportText_getData(text)) { + wbDelete(wbImportText_getData(text)); + } + wbDelete(text); + } +} + +static inline wbImportText_t wbImportText_read(wbImportText_t text) { + char *data; + wbFile_t file; + int length; + + if (text == NULL) { + return NULL; + } + + file = wbImportText_getFile(text); + + if (wbImportText_getData(text) != NULL) { + wbDelete(wbImportText_getData(text)); + wbImportText_setData(text, NULL); + } + + length = wbFile_size(file); + data = wbFile_read(file, length); + + wbImportText_setData(text, data); + wbImportText_setLength(text, length); + + return text; +} + +static inline wbImport_t wbImport_open(const char *file, + wbImportKind_t kind) { + wbImport_t imp; + + if (file == NULL) { + wbLog(ERROR, "Go NULL for file value."); + wbExit(); + } + + if (!wbFile_existsQ(file)) { + wbLog(ERROR, "File ", file, " does not exist."); + wbExit(); + } + + wbImport_setKind(imp, kind); + + if (kind == wbImportKind_raw) { + wbImportRaw_t raw = wbImportRaw_new(); + wbImportRaw_setFile(raw, file); + wbImport_setRaw(imp, raw); + } else if (kind == wbImportKind_tsv || kind == wbImportKind_csv) { + wbImportCSV_t csv = wbImportCSV_new(); + if (kind == wbImportKind_csv) { + wbImportCSV_setSeperator(csv, ','); + } else { + wbImportCSV_setSeperator(csv, '\t'); + } + wbImportCSV_setFile(csv, file); + wbImport_setCSV(imp, csv); + } else if (kind == wbImportKind_text) { + wbImportText_t text = wbImportText_new(); + wbImportText_setFile(text, file); + wbImport_setText(imp, text); + } else if (kind == wbImportKind_ppm) { + wbImage_t img = wbPPM_import(file); + wbImport_setImage(imp, img); + } else { + wbLog(ERROR, "Invalid import type."); + wbExit(); + } + + return imp; +} + +static inline wbImport_t wbImport_open(const char *file, + const char *type0) { + wbImport_t imp; + wbImportKind_t kind; + char *type; + + type = wbString_toLower(type0); + + if (wbString_sameQ(type, "csv")) { + kind = wbImportKind_csv; + } else if (wbString_sameQ(type, "tsv")) { + kind = wbImportKind_tsv; + } else if (wbString_sameQ(type, "raw") || wbString_sameQ(type, "dat")) { + kind = wbImportKind_raw; + } else if (wbString_sameQ(type, "ppm")) { + kind = wbImportKind_ppm; + } else if (wbString_sameQ(type, "text") || wbString_sameQ(type, "txt")) { + kind = wbImportKind_text; + } else { + wbLog(ERROR, "Invalid import type ", type0); + wbExit(); + } + + imp = wbImport_open(file, kind); + + wbDelete(type); + + return imp; +} + +static inline void wbImport_close(wbImport_t imp) { + wbImportKind_t kind; + + kind = wbImport_getKind(imp); + if (kind == wbImportKind_tsv || kind == wbImportKind_csv) { + wbImportCSV_t csv = wbImport_getCSV(imp); + wbImportCSV_delete(csv); + wbImport_setCSV(imp, NULL); + } else if (kind == wbImportKind_raw) { + wbImportRaw_t raw = wbImport_getRaw(imp); + wbImportRaw_delete(raw); + wbImport_setRaw(imp, NULL); + } else if (kind == wbImportKind_text) { + wbImportText_t text = wbImport_getText(imp); + wbImportText_delete(text); + wbImport_setText(imp, NULL); + } else if (kind == wbImportKind_ppm) { + } else { + wbLog(ERROR, "Invalid import type."); + wbExit(); + } + return; +} + +static inline void *wbImport_read(wbImport_t imp, wbType_t type) { + void *data = NULL; + wbImportKind_t kind; + + kind = wbImport_getKind(imp); + if (kind == wbImportKind_tsv || kind == wbImportKind_csv) { + wbImportCSV_t csv = wbImport_getCSV(imp); + wbImportCSV_read(csv, type); + data = wbImportCSV_getData(csv); + } else if (kind == wbImportKind_raw) { + wbImportRaw_t raw = wbImport_getRaw(imp); + wbImportRaw_read(raw, type); + data = wbImportRaw_getData(raw); + } else if (wbImportKind_text == kind) { + wbImportText_t text = wbImport_getText(imp); + text = wbImportText_read(text); + data = wbImportText_getData(text); + + } else { + wbLog(ERROR, "Invalid import type."); + wbExit(); + } + return data; +} + +static inline int *wbImport_readAsInteger(wbImport_t imp) { + void *data = wbImport_read(imp, wbType_integer); + return (int *)data; +} + +static inline wbReal_t *wbImport_readAsReal(wbImport_t imp) { + void *data = wbImport_read(imp, wbType_real); + return (wbReal_t *)data; +} + +static inline wbChar_t *wbImport_readAsText(wbImport_t imp) { + void *data = wbImport_read(imp, wbType_ubit8); + return (wbChar_t *)data; +} + +static wbImportKind_t _parseImportExtension(const char *file) { + char *extension; + wbImportKind_t kind; + + extension = wbFile_extension(file); + + if (wbString_sameQ(extension, "csv")) { + kind = wbImportKind_csv; + } else if (wbString_sameQ(extension, "tsv")) { + kind = wbImportKind_tsv; + } else if (wbString_sameQ(extension, "raw") || + wbString_sameQ(extension, "dat")) { + kind = wbImportKind_raw; + } else if (wbString_sameQ(extension, "ppm") || + wbString_sameQ(extension, "pbm")) { + kind = wbImportKind_ppm; + } else if (wbString_sameQ(extension, "text") || + wbString_sameQ(extension, "txt")) { + kind = wbImportKind_text; + } else { + kind = wbImportKind_unknown; + wbLog(ERROR, "File ", file, " does not have a compatible extension."); + } + + wbDelete(extension); + + return kind; +} + +void *wbImport(const char *file, int *resRows, int *resColumns, + const char *type) { + void *data, *res; + wbImport_t imp; + size_t sz; + int columns = 0, rows = 0; + wbImportKind_t kind; + + if (file == NULL) { + fprintf(stderr, "Failed to import file.\n"); + wbExit(); + } + + kind = _parseImportExtension(file); + + wbAssert(kind != wbImportKind_unknown); + + imp = wbImport_open(file, kind); + if (wbString_sameQ(type, "Real")) { + data = wbImport_readAsReal(imp); + sz = sizeof(wbReal_t); + } else if (wbString_sameQ(type, "Text")) { + data = wbImport_readAsText(imp); + sz = sizeof(char); + } else { + // printf("Reading as integer..d\n"); + data = wbImport_readAsInteger(imp); + sz = sizeof(int); + } + + if (kind == wbImportKind_csv || kind == wbImportKind_tsv) { + rows = wbImportCSV_getRowCount(wbImport_getCSV(imp)); + columns = wbImportCSV_getColumnCount(wbImport_getCSV(imp)); + } else if (kind == wbImportKind_raw) { + rows = wbImportRaw_getRowCount(wbImport_getRaw(imp)); + columns = wbImportRaw_getColumnCount(wbImport_getRaw(imp)); + } else if (kind == wbImportKind_text) { + rows = 1; + columns = wbImportText_getLength(wbImport_getText(imp)); + } + + if (rows == 1 && columns > 0) { + rows = columns; + columns = 1; + } + + if (resRows != NULL) { + *resRows = rows; + } + + if (resColumns != NULL) { + *resColumns = columns; + } + + res = wbMalloc(sz * rows * columns); + memcpy(res, data, sz * rows * columns); + + wbImport_close(imp); + + return res; +} + +void *wbImport(const char *file, int *rows, int *columns) { + return wbImport(file, rows, columns, "Real"); +} + +EXTERN_C void *wbImport(const char *file, int *rows) { + return wbImport(file, rows, NULL, "Real"); +} + +void *wbImport(const char *file, int *res_rows, const char *type) { + int cols, rows; + void *res = wbImport(file, &rows, &cols, type); + if (rows == 1 && cols > 1) { + rows = cols; + } + *res_rows = rows; + return res; +} + +wbImage_t wbImport(const char *file) { + wbImage_t img; + wbImport_t imp; + wbImportKind_t kind; + + if (file == NULL) { + fprintf(stderr, "Failed to import file.\n"); + wbExit(); + } + + kind = _parseImportExtension(file); + + wbAssert(kind == wbImportKind_ppm); + + imp = wbImport_open(file, kind); + img = wbImport_getImage(imp); + wbImport_close(imp); + + return img; +} + +int wbImport_flag(const char *file) { + int res; + wbFile_t fh = wbFile_open(file, "r"); + const char *line = wbFile_readLine(fh); + sscanf(line, "%d", &res); + wbFile_close(fh); + return res; +} diff --git a/CUDA_ListScan/libwb/wbImport.h b/CUDA_ListScan/libwb/wbImport.h new file mode 100644 index 0000000..ce13e1b --- /dev/null +++ b/CUDA_ListScan/libwb/wbImport.h @@ -0,0 +1,103 @@ + +#ifndef __WB_IMPORT_H__ +#define __WB_IMPORT_H__ + +#include "wbImage.h" + +typedef enum en_wbImportKind_t { + wbImportKind_unknown = -1, + wbImportKind_raw = 0x1000, + wbImportKind_csv, + wbImportKind_tsv, + wbImportKind_ppm, + wbImportKind_text +} wbImportKind_t; + +#define wbType_real wbType_float + +typedef struct st_wbImportCSV_t { + int rows; + int columns; + void *data; + wbFile_t file; + char seperator; +} * wbImportCSV_t; + +#define wbImportCSV_getRowCount(csv) ((csv)->rows) +#define wbImportCSV_getColumnCount(csv) ((csv)->columns) +#define wbImportCSV_getData(csv) ((csv)->data) +#define wbImportCSV_getFile(csv) ((csv)->file) +#define wbImportCSV_getSeperator(csv) ((csv)->seperator) + +#define wbImportCSV_setRowCount(csv, val) \ + (wbImportCSV_getRowCount(csv) = val) +#define wbImportCSV_setColumnCount(csv, val) \ + (wbImportCSV_getColumnCount(csv) = val) +#define wbImportCSV_setData(csv, val) (wbImportCSV_getData(csv) = val) +#define wbImportCSV_setSeperator(csv, val) \ + (wbImportCSV_getSeperator(csv) = val) + +typedef struct st_wbImportRaw_t { + int rows; + int columns; + void *data; + wbFile_t file; +} * wbImportRaw_t; + +#define wbImportRaw_getRowCount(raw) ((raw)->rows) +#define wbImportRaw_getColumnCount(raw) ((raw)->columns) +#define wbImportRaw_getData(raw) ((raw)->data) +#define wbImportRaw_getFile(raw) ((raw)->file) + +#define wbImportRaw_setRowCount(raw, val) \ + (wbImportRaw_getRowCount(raw) = val) +#define wbImportRaw_setColumnCount(raw, val) \ + (wbImportRaw_getColumnCount(raw) = val) +#define wbImportRaw_setData(raw, val) (wbImportRaw_getData(raw) = val) + +typedef struct st_wbImportText_t { + int length; + char *data; + wbFile_t file; +} * wbImportText_t; + +#define wbImportText_getLength(txt) ((txt)->length) +#define wbImportText_getData(txt) ((txt)->data) +#define wbImportText_getFile(txt) ((txt)->file) + +#define wbImportText_setLength(txt, val) \ + (wbImportText_getLength(txt) = val) +#define wbImportText_setData(txt, val) (wbImportText_getData(txt) = val) + +typedef struct st_wbImport_t { + wbImportKind_t kind; + union { + wbImportRaw_t raw; + wbImportCSV_t csv; + wbImportText_t text; + wbImage_t img; + } container; +} wbImport_t; + +#define wbImport_getKind(imp) ((imp).kind) +#define wbImport_getContainer(imp) ((imp).container) +#define wbImport_getRaw(imp) (wbImport_getContainer(imp).raw) +#define wbImport_getCSV(imp) (wbImport_getContainer(imp).csv) +#define wbImport_getText(imp) (wbImport_getContainer(imp).text) +#define wbImport_getImage(imp) (wbImport_getContainer(imp).img) + +#define wbImport_setKind(imp, val) (wbImport_getKind(imp) = val) +#define wbImport_setRaw(imp, val) (wbImport_getRaw(imp) = val) +#define wbImport_setCSV(imp, val) (wbImport_getCSV(imp) = val) +#define wbImport_setText(imp, val) (wbImport_getText(imp) = val) +#define wbImport_setImage(imp, val) (wbImport_getImage(imp) = val) + +EXTERN_C void *wbImport(const char *file, int *rows); +void *wbImport(const char *file, int *rows, int *columns); +void *wbImport(const char *file, int *rows, const char *type); +void *wbImport(const char *file, int *resRows, int *resColumns, + const char *type); +wbImage_t wbImport(const char *file); +int wbImport_flag(const char *file); + +#endif /* __WB_IMPORT_H__ */ diff --git a/CUDA_ListScan/libwb/wbInit.cpp b/CUDA_ListScan/libwb/wbInit.cpp new file mode 100644 index 0000000..96ebcf3 --- /dev/null +++ b/CUDA_ListScan/libwb/wbInit.cpp @@ -0,0 +1,85 @@ + +#include "wb.h" + +#define MB (1 << 20) +#ifndef WB_DEFAULT_HEAP_SIZE +#define WB_DEFAULT_HEAP_SIZE (1024 * MB) +#endif /* WB_DEFAULT_HEAP_SIZE */ + +static bool _initializedQ = wbFalse; + +#ifndef WB_USE_WINDOWS +__attribute__((__constructor__)) +#endif /* WB_USE_WINDOWS */ +void wb_init(int * +#ifdef WB_USE_MPI + argc +#endif /* WB_USE_MPI */ + , + char *** +#ifdef WB_USE_MPI + argv +#endif /* WB_USE_MPI */ + ) { + if (_initializedQ == wbTrue) { + return; + } +#ifdef WB_USE_MPI + wbMPI_Init(argc, argv); +#endif /* WB_USE_MPI */ + +#ifdef WB_USE_CUDA + CUresult err = cuInit(0); + +/* Select a random GPU */ + +#ifdef WB_USE_MPI + if (rankCount() > 1) { + int deviceCount; + cudaGetDeviceCount(&deviceCount); + srand(time(NULL)); + cudaSetDevice(wbMPI_getRank() % deviceCount); + } else { + int deviceCount; + cudaGetDeviceCount(&deviceCount); + + srand(time(NULL)); + cudaSetDevice(rand() % deviceCount); + } +#else + { + int deviceCount; + cudaGetDeviceCount(&deviceCount); + + srand(time(NULL)); + cudaSetDevice(rand() % deviceCount); + } +#endif /* WB_USE_MPI */ + + cudaDeviceSetLimit(cudaLimitPrintfFifoSize, 1 * MB); + cudaDeviceSetLimit(cudaLimitMallocHeapSize, WB_DEFAULT_HEAP_SIZE); + + cudaDeviceSynchronize(); + +#endif /* WB_USE_CUDA */ + +#ifdef WB_USE_WINDOWS + QueryPerformanceFrequency((LARGE_INTEGER *)&_hrtime_frequency); +#endif /* _MSC_VER */ + + _hrtime(); + + _timer = wbTimer_new(); + _logger = wbLogger_new(); + _initializedQ = wbTrue; + + wbFile_init(); + + solutionJSON = NULL; + +#ifdef WB_USE_MPI + atexit(wbMPI_Exit); +#else /* WB_USE_MPI */ + atexit(wb_atExit); +#endif /* WB_USE_MPI */ +} diff --git a/CUDA_ListScan/libwb/wbInit.h b/CUDA_ListScan/libwb/wbInit.h new file mode 100644 index 0000000..40e8e1c --- /dev/null +++ b/CUDA_ListScan/libwb/wbInit.h @@ -0,0 +1,11 @@ + + +#ifndef __WB_INIT_H__ +#define __WB_INIT_H__ + +#ifndef _MSC_VER +__attribute__((__constructor__)) +#endif /* _MSC_VER */ +void wb_init(int *argc, char ***argv); + +#endif /* __WB_INIT_H__ */ diff --git a/CUDA_ListScan/libwb/wbLogger.cpp b/CUDA_ListScan/libwb/wbLogger.cpp new file mode 100644 index 0000000..c2e2e17 --- /dev/null +++ b/CUDA_ListScan/libwb/wbLogger.cpp @@ -0,0 +1,310 @@ + +#include "wb.h" + +wbLogger_t _logger = NULL; + +static inline wbBool wbLogEntry_hasNext(wbLogEntry_t elem) { + return wbLogEntry_getNext(elem) != NULL; +} + +static inline wbLogEntry_t wbLogEntry_new() { + wbLogEntry_t elem; + + elem = wbNew(struct st_wbLogEntry_t); + + wbLogEntry_setMessage(elem, NULL); + wbLogEntry_setMPIRank(elem, wbMPI_getRank()); + wbLogEntry_setTime(elem, _hrtime()); + + wbLogEntry_setLevel(elem, wbLogLevel_TRACE); + + wbLogEntry_setNext(elem, NULL); + + wbLogEntry_setLine(elem, -1); + wbLogEntry_setFile(elem, NULL); + wbLogEntry_setFunction(elem, NULL); + + return elem; +} + +static inline wbLogEntry_t +wbLogEntry_initialize(wbLogLevel_t level, string msg, const char *file, + const char *fun, int line) { + wbLogEntry_t elem; + + elem = wbLogEntry_new(); + + wbLogEntry_setLevel(elem, level); + + wbLogEntry_setMessage(elem, wbString_duplicate(msg)); + + wbLogEntry_setLine(elem, line); + wbLogEntry_setFile(elem, file); + wbLogEntry_setFunction(elem, fun); + + return elem; +} + +static inline void wbLogEntry_delete(wbLogEntry_t elem) { + if (elem != NULL) { + if (wbLogEntry_getMessage(elem) != NULL) { + wbFree(wbLogEntry_getMessage(elem)); + } + wbDelete(elem); + } + return; +} + +static inline const char *getLevelName(wbLogLevel_t level) { + switch (level) { + case wbLogLevel_unknown: + return "Unknown"; + case wbLogLevel_OFF: + return "Off"; + case wbLogLevel_FATAL: + return "Fatal"; + case wbLogLevel_ERROR: + return "Error"; + case wbLogLevel_WARN: + return "Warn"; + case wbLogLevel_INFO: + return "Info"; + case wbLogLevel_DEBUG: + return "Debug"; + case wbLogLevel_TRACE: + return "Trace"; + } + return NULL; +} + +static inline json11::Json wbLogEntry_toJSONObject(wbLogEntry_t elem) { + json11::Json json = json11::Json::object{ + {"mpi_rank", wbLogEntry_getMPIRank(elem)}, + {"level", getLevelName(wbLogEntry_getLevel(elem))}, + {"file", wbLogEntry_getFile(elem)}, + {"function", wbLogEntry_getFunction(elem)}, + {"line", wbLogEntry_getLine(elem)}, + {"time", wbLogEntry_getTime(elem)}, + {"message", wbLogEntry_getMessage(elem)}, + }; + return json; +} + +static inline string wbLogEntry_toJSON(wbLogEntry_t elem) { + if (elem == NULL) { + return ""; + } else if (WB_USE_JSON11) { + json11::Json json = wbLogEntry_toJSONObject(elem); + return json.string_value(); + } else { + stringstream ss; + + ss << "{\n"; + ss << wbString_quote("mpi_rank") << ":" + << wbString(wbLogEntry_getMPIRank(elem)) << ",\n"; + ss << wbString_quote("level") << ":" + << wbString_quote(getLevelName(wbLogEntry_getLevel(elem))) << ",\n"; + ss << wbString_quote("message") << ":" + << wbString_quote(wbLogEntry_getMessage(elem)) << ",\n"; + ss << wbString_quote("file") << ":" + << wbString_quote(wbLogEntry_getFile(elem)) << ",\n"; + ss << wbString_quote("function") << ":" + << wbString_quote(wbLogEntry_getFunction(elem)) << ",\n"; + ss << wbString_quote("line") << ":" << wbLogEntry_getLine(elem) + << ",\n"; + ss << wbString_quote("time") << ":" << wbLogEntry_getTime(elem) + << "\n"; + ss << "}"; + + return ss.str(); + } + return ""; +} + +static inline string wbLogEntry_toXML(wbLogEntry_t elem) { + if (elem != NULL) { + stringstream ss; + + ss << "\n"; + ss << "" + << "LoggerElement" + << "\n"; + ss << "" << wbLogEntry_getLevel(elem) << "\n"; + ss << "" << wbLogEntry_getMessage(elem) << "\n"; + ss << "" << wbLogEntry_getFile(elem) << "\n"; + ss << "" << wbLogEntry_getFunction(elem) << "\n"; + ss << "" << wbLogEntry_getLine(elem) << "\n"; + ss << "\n"; + ss << "\n"; + + return ss.str(); + } + return ""; +} + +wbLogger_t wbLogger_new() { + wbLogger_t logger; + + logger = wbNew(struct st_wbLogger_t); + + wbLogger_setLength(logger, 0); + wbLogger_setHead(logger, NULL); + + wbLogger_getLevel(logger) = wbLogLevel_TRACE; + + return logger; +} + +static inline void _wbLogger_setLevel(wbLogger_t logger, + wbLogLevel_t level) { + wbLogger_getLevel(logger) = level; +} + +static inline void _wbLogger_setLevel(wbLogLevel_t level) { + _wbLogger_setLevel(_logger, level); +} + +#define wbLogger_setLevel(level) _wbLogger_setLevel(wbLogLevel_##level) + +void wbLogger_clear(wbLogger_t logger) { + if (logger != NULL) { + wbLogEntry_t tmp; + wbLogEntry_t iter; + + iter = wbLogger_getHead(logger); + while (iter != NULL) { + tmp = wbLogEntry_getNext(iter); + wbLogEntry_delete(iter); + iter = tmp; + } + + wbLogger_setLength(logger, 0); + wbLogger_setHead(logger, NULL); + } +} + +void wbLogger_delete(wbLogger_t logger) { + if (logger != NULL) { + wbLogger_clear(logger); + wbDelete(logger); + } + return; +} + +void wbLogger_append(wbLogLevel_t level, string msg, const char *file, + const char *fun, int line) { + wbLogEntry_t elem; + wbLogger_t logger; + + wb_init(NULL, NULL); + + logger = _logger; + + if (wbLogger_getLevel(logger) < level) { + return; + } + + elem = wbLogEntry_initialize(level, msg, file, fun, line); + +#ifdef wbLogger_printOnLog + if (wbLogger_printOnLog) { + if (level <= wbLogger_getLevel(logger) && elem) { + json11::Json json = json11::Json::object{ +#ifndef _MSC_VER //PMO + { "type", "logger" }, { "data", wbLogEntry_toJSONObject(elem) }}; +#else + { "data", wbLogEntry_toJSONObject(elem) }, { "type", "logger" }}; +#endif + std::cout << json.dump() << std::endl; + } + } +#endif /* wbLogger_printOnLog */ + + if (wbLogger_getHead(logger) == NULL) { + wbLogger_setHead(logger, elem); + } else { + wbLogEntry_t prev = wbLogger_getHead(logger); + + while (wbLogEntry_hasNext(prev)) { + prev = wbLogEntry_getNext(prev); + } + wbLogEntry_setNext(prev, elem); + } + +#if 0 + if (level <= wbLogger_getLevel(logger) && elem) { + const char *levelName = getLevelName(level); + + fprintf(stderr, "= LOG: %s: %s (In %s:%s on line %d). =\n", levelName, + wbLogEntry_getMessage(elem), wbLogEntry_getFile(elem), + wbLogEntry_getFunction(elem), wbLogEntry_getLine(elem)); + } +#endif + + wbLogger_incrementLength(logger); + + return; +} + +string wbLogger_toJSON() { + return wbLogger_toJSON(_logger); +} + +static json11::Json wbLogger_toJSONObject(wbLogger_t logger) { + std::vector elems{}; + + if (logger != NULL) { + wbLogEntry_t iter; + stringstream ss; + + for (iter = wbLogger_getHead(logger); iter != NULL; + iter = wbLogEntry_getNext(iter)) { + elems.push_back(wbLogEntry_toJSONObject(iter)); + } + } + return json11::Json(elems); +} + +string wbLogger_toJSON(wbLogger_t logger) { + if (logger != NULL) { + wbLogEntry_t iter; + stringstream ss; + + for (iter = wbLogger_getHead(logger); iter != NULL; + iter = wbLogEntry_getNext(iter)) { + ss << wbLogEntry_toJSON(iter); + if (wbLogEntry_getNext(iter) != NULL) { + ss << ",\n"; + } + } + + return ss.str(); + } + return ""; +} + +string wbLogger_toXML() { + return wbLogger_toXML(_logger); +} + +string wbLogger_toXML(wbLogger_t logger) { + if (logger != NULL) { + wbLogEntry_t iter; + stringstream ss; + + ss << "\n"; + ss << "" + << "Logger" + << "\n"; + ss << "\n"; + for (iter = wbLogger_getHead(logger); iter != NULL; + iter = wbLogEntry_getNext(iter)) { + ss << wbLogEntry_toXML(iter); + } + ss << "\n"; + ss << "\n"; + + return ss.str(); + } + return ""; +} diff --git a/CUDA_ListScan/libwb/wbLogger.h b/CUDA_ListScan/libwb/wbLogger.h new file mode 100644 index 0000000..b852592 --- /dev/null +++ b/CUDA_ListScan/libwb/wbLogger.h @@ -0,0 +1,87 @@ + +#ifndef __WB_LOGGER_H__ +#define __WB_LOGGER_H__ + +#include + +typedef enum en_wbLogLevel_t { + wbLogLevel_unknown = -1, + wbLogLevel_OFF = 0, + wbLogLevel_FATAL, + wbLogLevel_ERROR, + wbLogLevel_WARN, + wbLogLevel_INFO, + wbLogLevel_DEBUG, + wbLogLevel_TRACE +} wbLogLevel_t; + +struct st_wbLogEntry_t { + int line; + int mpiRank; + char *msg; + uint64_t time; + const char *fun; + const char *file; + wbLogLevel_t level; + wbLogEntry_t next; +}; + +struct st_wbLogger_t { + int length; + wbLogEntry_t head; + wbLogLevel_t level; +}; + +#define wbLogEntry_getMessage(elem) ((elem)->msg) +#define wbLogEntry_getMPIRank(elem) ((elem)->mpiRank) +#define wbLogEntry_getTime(elem) ((elem)->time) +#define wbLogEntry_getLevel(elem) ((elem)->level) +#define wbLogEntry_getNext(elem) ((elem)->next) +#define wbLogEntry_getLine(elem) ((elem)->line) +#define wbLogEntry_getFunction(elem) ((elem)->fun) +#define wbLogEntry_getFile(elem) ((elem)->file) + +#define wbLogEntry_setMessage(elem, val) \ + (wbLogEntry_getMessage(elem) = val) +#define wbLogEntry_setMPIRank(elem, val) \ + (wbLogEntry_getMPIRank(elem) = val) +#define wbLogEntry_setTime(elem, val) (wbLogEntry_getTime(elem) = val) +#define wbLogEntry_setLevel(elem, val) (wbLogEntry_getLevel(elem) = val) +#define wbLogEntry_setNext(elem, val) (wbLogEntry_getNext(elem) = val) +#define wbLogEntry_setLine(elem, val) (wbLogEntry_getLine(elem) = val) +#define wbLogEntry_setFunction(elem, val) \ + (wbLogEntry_getFunction(elem) = val) +#define wbLogEntry_setFile(elem, val) (wbLogEntry_getFile(elem) = val) + +#define wbLogger_getLength(log) ((log)->length) +#define wbLogger_getHead(log) ((log)->head) +#define wbLogger_getLevel(log) ((log)->level) + +#define wbLogger_setLength(log, val) (wbLogger_getLength(log) = val) +#define wbLogger_setHead(log, val) (wbLogger_getHead(log) = val) + +#define wbLogger_incrementLength(log) (wbLogger_getLength(log)++) +#define wbLogger_decrementLength(log) (wbLogger_getLength(log)--) + +#define wbLog(level, ...) \ + wbLogger_append(wbLogLevel_##level, wbString(__VA_ARGS__), wbFile, \ + wbFunction, wbLine) + +extern wbLogger_t _logger; + +wbLogger_t wbLogger_new(); + +void wbLogger_clear(wbLogger_t logger); + +void wbLogger_delete(wbLogger_t logger); + +void wbLogger_append(wbLogLevel_t level, string msg, const char *file, + const char *fun, int line); + +string wbLogger_toXML(wbLogger_t logger); +string wbLogger_toXML(); + +string wbLogger_toJSON(wbLogger_t logger); +string wbLogger_toJSON(); + +#endif /* __WB_LOGGER_H__ */ diff --git a/CUDA_ListScan/libwb/wbMD5.h b/CUDA_ListScan/libwb/wbMD5.h new file mode 100644 index 0000000..e83a8ef --- /dev/null +++ b/CUDA_ListScan/libwb/wbMD5.h @@ -0,0 +1,311 @@ + +/* + * This code implements the MD5 message-digest algorithm. + * The algorithm is due to Ron Rivest. This code was + * written by Colin Plumb in 1993, no copyright is claimed. + * This code is in the public domain; do with it what you wish. + * + * Equivalent code is available from RSA Data Security, Inc. + * This code has been tested against that, and is equivalent, + * except that you don't need to include two pages of legalese + * with every copy. + * + * To compute the message digest of a chunk of bytes, declare an + * MD5Context structure, pass it to MD5Init, call MD5Update as + * needed on buffers full of bytes, and then call MD5Final, which + * will fill a supplied 16-byte array with the digest. + * + * Changed so as no longer to depend on Colin Plumb's `usual.h' header + * definitions; now uses stuff from dpkg's config.h. + * - Ian Jackson . + * Still in the public domain. + */ + +#ifndef __WB_MD5_H__ +#define __WB_MD5_H__ + +#include /* for memcpy() */ +#include /* for stupid systems */ + +#define UWORD32 unsigned int + +#define md5byte unsigned char + +struct MD5Context { + UWORD32 buf[4]; + UWORD32 bytes[2]; + UWORD32 in[16]; +}; + +static void MD5Transform(UWORD32 buf[4], UWORD32 const in[16]); + +static int g_bigEndian = 0; +static int g_endianessDetected = 0; + +static void detectEndianess() { + int nl = 0x12345678; + short ns = 0x1234; + + unsigned char *p = (unsigned char *)(&nl); + unsigned char *sp = (unsigned char *)(&ns); + + if (g_endianessDetected) + return; + if (p[0] == 0x12 && p[1] == 0x34 && p[2] == 0x56 && p[3] == 0x78) { + g_bigEndian = 1; + } else if (p[0] == 0x78 && p[1] == 0x56 && p[2] == 0x34 && + p[3] == 0x12) { + g_bigEndian = 0; + } else { + g_bigEndian = *sp != 0x12; + } + + g_endianessDetected = 1; +} + +static void byteSwap(UWORD32 *buf, unsigned words) { + md5byte *p; + + if (!g_bigEndian) + return; + + p = (md5byte *)buf; + + do { + *buf++ = (UWORD32)((unsigned)p[3] << 8 | p[2]) << 16 | + ((unsigned)p[1] << 8 | p[0]); + p += 4; + } while (--words); +} + +/* + * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious + * initialization constants. + */ +static void MD5Init(struct MD5Context *ctx) { + detectEndianess(); + + ctx->buf[0] = 0x67452301; + ctx->buf[1] = 0xefcdab89; + ctx->buf[2] = 0x98badcfe; + ctx->buf[3] = 0x10325476; + + ctx->bytes[0] = 0; + ctx->bytes[1] = 0; +} + +/* + * Update context to reflect the concatenation of another buffer full + * of bytes. + */ +static void MD5Update(struct MD5Context *ctx, md5byte const *buf, + unsigned len) { + UWORD32 t; + + /* Update byte count */ + + t = ctx->bytes[0]; + if ((ctx->bytes[0] = t + len) < t) + ctx->bytes[1]++; /* Carry from low to high */ + + t = 64 - (t & 0x3f); /* Space available in ctx->in (at least 1) */ + if (t > len) { + memcpy((md5byte *)ctx->in + 64 - t, buf, len); + return; + } + /* First chunk is an odd size */ + memcpy((md5byte *)ctx->in + 64 - t, buf, t); + byteSwap(ctx->in, 16); + MD5Transform(ctx->buf, ctx->in); + buf += t; + len -= t; + + /* Process data in 64-byte chunks */ + while (len >= 64) { + memcpy(ctx->in, buf, 64); + byteSwap(ctx->in, 16); + MD5Transform(ctx->buf, ctx->in); + buf += 64; + len -= 64; + } + + /* Handle any remaining bytes of data. */ + memcpy(ctx->in, buf, len); +} + +/* + * Final wrapup - pad to 64-byte boundary with the bit pattern + * 1 0* (64-bit count of bits processed, MSB-first) + */ +static void MD5Final(md5byte digest[16], struct MD5Context *ctx) { + int count = ctx->bytes[0] & 0x3f; /* Number of bytes in ctx->in */ + md5byte *p = (md5byte *)ctx->in + count; + + /* Set the first char of padding to 0x80. There is always room. */ + *p++ = 0x80; + + /* Bytes of padding needed to make 56 bytes (-8..55) */ + count = 56 - 1 - count; + + if (count < 0) { /* Padding forces an extra block */ + memset(p, 0, count + 8); + byteSwap(ctx->in, 16); + MD5Transform(ctx->buf, ctx->in); + p = (md5byte *)ctx->in; + count = 56; + } + memset(p, 0, count); + byteSwap(ctx->in, 14); + + /* Append length in bits and transform */ + ctx->in[14] = ctx->bytes[0] << 3; + ctx->in[15] = ctx->bytes[1] << 3 | ctx->bytes[0] >> 29; + MD5Transform(ctx->buf, ctx->in); + + byteSwap(ctx->buf, 4); + memcpy(digest, ctx->buf, 16); + memset(&ctx, 0, sizeof(ctx)); /* In case it's sensitive */ +} + +#ifndef ASM_MD5 + +/* The four core functions - F1 is optimized somewhat */ + +/* #define F1(x, y, z) (x & y | ~x & z) */ +#define F1(x, y, z) (z ^ (x & (y ^ z))) +#define F2(x, y, z) F1(z, x, y) +#define F3(x, y, z) (x ^ y ^ z) +#define F4(x, y, z) (y ^ (x | ~z)) + +/* This is the central step in the MD5 algorithm. */ +#define MD5STEP(f, w, x, y, z, in, s) \ + (w += f(x, y, z) + in, w = (w << s | w >> (32 - s)) + x) + +/* + * The core of the MD5 algorithm, this alters an existing MD5 hash to + * reflect the addition of 16 longwords of new data. MD5Update blocks + * the data and converts bytes into longwords for this routine. + */ +static void MD5Transform(UWORD32 buf[4], UWORD32 const in[16]) { + UWORD32 a, b, c, d; + + a = buf[0]; + b = buf[1]; + c = buf[2]; + d = buf[3]; + + MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); + MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); + MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); + MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); + MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); + MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); + MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); + MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); + MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); + MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); + MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); + MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); + MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); + MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); + MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); + MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); + + MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); + MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); + MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); + MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); + MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); + MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); + MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); + MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); + MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); + MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); + MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); + MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); + MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); + MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); + MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); + MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); + + MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); + MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); + MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); + MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); + MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); + MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); + MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); + MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); + MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); + MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); + MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); + MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); + MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); + MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); + MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); + MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); + + MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); + MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); + MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); + MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); + MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); + MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); + MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); + MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); + MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); + MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); + MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); + MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); + MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); + MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); + MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); + MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} + +#endif + +static void MD5_buffer(const unsigned char *buf, unsigned int len, + unsigned char sig[16]) { + struct MD5Context md5; + MD5Init(&md5); + MD5Update(&md5, buf, len); + MD5Final(sig, &md5); +} + +#define wbMD5 MD5_buffer + +#define HEX_STRING "0123456789abcdef" /* to convert to hex */ + +static void wbMD5_sigToString(unsigned char signature[16], char *str, + int len) { + unsigned char *sig_p; + char *str_p, *max_p; + unsigned int high, low; + + str_p = str; + max_p = str + len; + + for (sig_p = (unsigned char *)signature; + sig_p < (unsigned char *)signature + 16; sig_p++) { + high = *sig_p / 16; + low = *sig_p % 16; + /* account for 2 chars */ + if (str_p + 1 >= max_p) { + break; + } + *str_p++ = HEX_STRING[high]; + *str_p++ = HEX_STRING[low]; + } + /* account for 2 chars */ + if (str_p < max_p) { + *str_p++ = '\0'; + } +} + +#endif /* __WB_MD5_H__ */ diff --git a/CUDA_ListScan/libwb/wbMPI.cpp b/CUDA_ListScan/libwb/wbMPI.cpp new file mode 100644 index 0000000..546c1ed --- /dev/null +++ b/CUDA_ListScan/libwb/wbMPI.cpp @@ -0,0 +1,75 @@ + +#ifdef WB_USE_MPI + +#include +#include +#include +#include "wb.h" + +static int rank = -1; + +int wbMPI_getRank() { + if (rank != -1) { + return rank; + } + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + return rank; +} + +int rankCount() { + int nRanks; + MPI_Comm_size(MPI_COMM_WORLD, &nRanks); + return nRanks; +} + +const char *wbMPI_getStringFromRank(int rank, int tag) { + if (isMasterQ) { + char *buf; + int bufSize; + MPI_Recv(&bufSize, 1, MPI_INT, rank, tag, MPI_COMM_WORLD, + MPI_STATUS_IGNORE); + buf = (char *)calloc(bufSize, sizeof(char)); + MPI_Recv(buf, bufSize, MPI_CHAR, rank, tag, MPI_COMM_WORLD, + MPI_STATUS_IGNORE); + return buf; + } + + return NULL; +} +void wbMPI_sendStringToMaster(const char *str, int tag) { + if (!isMasterQ) { + // we are going to send the string to the master + int len = (int)strlen(str) + 1; + MPI_Send(&len, 1, MPI_INT, 0, tag, MPI_COMM_WORLD); + MPI_Send((void *)str, len, MPI_CHAR, 0, tag, MPI_COMM_WORLD); + } + + return; +} + +int wbMPI_Init(int *argc, char ***argv) { + int err = MPI_SUCCESS; + err = MPI_Init(argc, argv); + // printf("argc = %d\n", *argc); + // err = MPI_Init(NULL, NULL); + // printf("rank = %d is master = %d\n", wbMPI_getRank(), isMasterQ); + // MPI_Barrier(MPI_COMM_WORLD); + return err; +} + +bool finalizedQ = false; + +extern "C" int wbMPI_Finalize(void) { + if (finalizedQ) { + return MPI_SUCCESS; + } + finalizedQ = true; + wb_atExit(); + return MPI_Finalize(); +} +extern "C" void wbMPI_Exit(void) { + wbMPI_Finalize(); + return; +} + +#endif /* WB_USE_MPI */ diff --git a/CUDA_ListScan/libwb/wbMPI.h b/CUDA_ListScan/libwb/wbMPI.h new file mode 100644 index 0000000..6275eaf --- /dev/null +++ b/CUDA_ListScan/libwb/wbMPI.h @@ -0,0 +1,37 @@ + +#ifndef __WB_MPI_H__ +#define __WB_MPI_H__ + +#ifdef WB_USE_MPI + +#include +#include +#include + +#define isMasterQ ((wbMPI_getRank()) == 0) + +extern int wbMPI_getRank(); + +extern int rankCount(); + +extern const char *wbMPI_getStringFromRank(int rank, int tag); +extern void wbMPI_sendStringToMaster(const char *str, int tag); + +extern int wbMPI_Init(int *argc, char ***argv); + +extern bool finalizedQ; + +extern "C" int wbMPI_Finalize(void); +extern "C" void wbMPI_Exit(void); + +#define MPI_Finalize wbMPI_Finalize + +#else /* WB_USE_MPI */ +static inline int rankCount() { + return 1; +} +static inline int wbMPI_getRank() { + return 0; +} +#endif /* WB_USE_MPI */ +#endif /* __WB_MPI_H__ */ diff --git a/CUDA_ListScan/libwb/wbMalloc.h b/CUDA_ListScan/libwb/wbMalloc.h new file mode 100644 index 0000000..5d74be4 --- /dev/null +++ b/CUDA_ListScan/libwb/wbMalloc.h @@ -0,0 +1,140 @@ + + +#ifndef __WB_MALLOC_H__ +#define __WB_MALLOC_H__ + +#ifdef WB_USE_CUSTOM_MALLOC +#ifdef __linux__ +#define THROW __THROW +#else +#define THROW +#endif + +static inline void *_malloc(size_t size) THROW { + if (size == 0) { + return NULL; + } else { + int err; + void *res = memmgr_alloc((ulong)size, &err); + if (err) { + fprintf(stderr, "<>:: Memory allocation failed\n"); + exit(1); + } else { + size_t ii = 0; + unsigned char *p = (unsigned char *)res; + while (ii++ < size) { + *p++ = 0; + } + return res; + } + } +} + +static inline void _free(void *ptr) THROW { + if (ptr != NULL) { + memmgr_free(ptr); + } +} + +static inline void *_calloc(size_t nmemb, size_t size) THROW { + return _malloc(nmemb * size); +} + +static inline void *_realloc(void *ptr, size_t size) THROW { + if (size == 0) { + free(ptr); + return NULL; + } else if (ptr == NULL) { + return malloc(size); + } else { + void *buf; + unsigned char *dst; + unsigned char *src; + size_t alloc_size, to_copy, i = 0; + + // Allocate new buffer + buf = malloc(size); + + if (buf != 0) { + // Find original allocation size + alloc_size = (size_t)memmgr_get_block_size(ptr); + to_copy = alloc_size; + if (to_copy > size) { + to_copy = size; + } + + // Copy data to new buffer + dst = (unsigned char *)buf; + src = (unsigned char *)ptr; + while (i++ < to_copy) { + *dst++ = *src++; + } + + // Free the old buffer + free(ptr); + } + + return buf; + } +} + +#define wbNew(type) ((type *)_malloc(sizeof(type))) +#define wbNewArray(type, len) ((type *)_malloc((len) * sizeof(type))) +#define wbMalloc(sz) _malloc(sz) +#define wbDelete(var) \ + _free(var); \ + var = NULL +#define wbFree(var) \ + _free(var); \ + var = NULL +#define wbRealloc(var, newSize) _realloc(var, newSize) +#define wbReallocArray(t, m, n) ((t *)_realloc(m, n * sizeof(t))) + +#define free _free +#define malloc _malloc +#define calloc _calloc +#define realloc _realloc + +#else /* WB_USE_CUSTOM_MALLOC */ + +static inline void *xMalloc(size_t sz) { + void *mem = NULL; + if (sz != 0) { + mem = malloc(sz); + } + return mem; +} + +static inline void xFree(void *mem) { + if (mem != NULL) { + free(mem); + } + return; +} + +static inline void *xRealloc(void *mem, size_t sz) { + if (mem == NULL) { + return NULL; + } else if (sz == 0) { + xFree(mem); + return NULL; + } else { + void *res = realloc(mem, sz); + wbAssert(res != NULL); + return res; + } +} + +#define wbNew(type) ((type *)wbMalloc(sizeof(type))) +#define wbNewArray(type, len) ((type *)wbMalloc((len) * sizeof(type))) +#define wbMalloc(sz) xMalloc(sz) +#define wbDelete(var) wbFree(var) +#define wbFree(var) \ + xFree(var); \ + var = NULL +#define wbRealloc(var, newSize) xRealloc(var, newSize) +#define wbReallocArray(t, m, n) ((t *)xRealloc(m, n * sizeof(t))) + +#endif /* WB_USE_CUSTOM_MALLOC */ + +#endif /* __WB_MALLOC_H__ */ diff --git a/CUDA_ListScan/libwb/wbPPM.cpp b/CUDA_ListScan/libwb/wbPPM.cpp new file mode 100644 index 0000000..86ab208 --- /dev/null +++ b/CUDA_ListScan/libwb/wbPPM.cpp @@ -0,0 +1,199 @@ + +#include +#include "wb.h" + +static inline float _min(float x, float y) { + return x < y ? x : y; +} + +static inline float _max(float x, float y) { + return x > y ? x : y; +} + +static inline float _clamp(float x, float start, float end) { + return _min(_max(x, start), end); +} + +static const char *skipSpaces(const char *line) { + while (*line == ' ' || *line == '\t') { + line++; + if (*line == '\0') { + break; + } + } + return line; +} + +static char nextNonSpaceChar(const char *line0) { + const char *line = skipSpaces(line0); + return *line; +} + +static wbBool isComment(const char *line) { + char nextChar = nextNonSpaceChar(line); + if (nextChar == '\0') { + return wbTrue; + } else { + return nextChar == '#'; + } +} + +static void parseDimensions(const char *line0, int *width, int *height) { + const char *line = skipSpaces(line0); + sscanf(line, "%d %d", width, height); +} + +static void parseDimensions(const char *line0, int *width, int *height, + int *channels) { + const char *line = skipSpaces(line0); + sscanf(line, "%d %d %d", width, height, channels); +} + +static void parseDepth(const char *line0, int *depth) { + const char *line = skipSpaces(line0); + sscanf(line, "%d", depth); +} + +static char *nextLine(wbFile_t file) { + char *line = NULL; + while ((line = wbFile_readLine(file)) != NULL) { + if (!isComment(line)) { + break; + } + } + return line; +} + +wbImage_t wbPPM_import(const char *filename) { + wbImage_t img; + wbFile_t file; + char *header; + char *line; + int ii, jj, kk, channels; + int width, height, depth; + unsigned char *charData, *charIter; + float *imgData, *floatIter; + float scale; + + img = NULL; + + file = wbFile_open(filename, "rb"); + if (file == NULL) { + printf("Could not open %s\n", filename); + goto cleanup; + } + + header = wbFile_readLine(file); + if (header == NULL) { + printf("Could not read from %s\n", filename); + goto cleanup; + } else if (strcmp(header, "P6") != 0 && strcmp(header, "P6\n") != 0 && + strcmp(header, "P5") != 0 && strcmp(header, "P5\n") != 0 && + strcmp(header, "S6") != 0 && strcmp(header, "S6\n") != 0) { + printf("Could find magic number for %s\n", filename); + goto cleanup; + } + + // P5 are monochrome while P6/S6 are rgb + // S6 needs to parse number of channels out of file + if (strcmp(header, "P5") == 0 || strcmp(header, "P5\n") == 0) { + channels = 1; + line = nextLine(file); + parseDimensions(line, &width, &height); + } else if (strcmp(header, "P6") == 0 || strcmp(header, "P6\n") == 0) { + channels = 3; + line = nextLine(file); + parseDimensions(line, &width, &height); + } else { + line = nextLine(file); + parseDimensions(line, &width, &height, &channels); + } + + // the line now contains the depth information + line = nextLine(file); + parseDepth(line, &depth); + + // the rest of the lines contain the data in binary format + charData = (unsigned char *)wbFile_read( + file, width * channels * sizeof(unsigned char), height); + + img = wbImage_new(width, height, channels); + + imgData = wbImage_getData(img); + + charIter = charData; + floatIter = imgData; + + scale = 1.0f / ((float)depth); + + for (ii = 0; ii < height; ii++) { + for (jj = 0; jj < width; jj++) { + for (kk = 0; kk < channels; kk++) { + *floatIter = ((float)*charIter) * scale; + floatIter++; + charIter++; + } + } + } + +#ifdef LAZY_FILE_LOAD + wbDelete(charData); +#endif + +cleanup: + wbFile_close(file); + return img; +} + +void wbPPM_export(const char *filename, wbImage_t img) { + int ii; + int jj; + int kk; + int depth; + int width; + int height; + int channels; + wbFile_t file; + float *floatIter; + unsigned char *charData; + unsigned char *charIter; + + file = wbFile_open(filename, "wb+"); + + width = wbImage_getWidth(img); + height = wbImage_getHeight(img); + channels = wbImage_getChannels(img); + depth = 255; + + if (channels == 1) { + wbFile_writeLine(file, "P5"); + } else { + wbFile_writeLine(file, "P6"); + } + wbFile_writeLine(file, "#Created via wbPPM Export"); + wbFile_writeLine(file, wbString(width, " ", height)); + wbFile_writeLine(file, wbString(depth)); + + charData = wbNewArray(unsigned char, width *height *channels); + + charIter = charData; + floatIter = wbImage_getData(img); + + for (ii = 0; ii < height; ii++) { + for (jj = 0; jj < width; jj++) { + for (kk = 0; kk < channels; kk++) { + *charIter = (unsigned char)ceil(_clamp(*floatIter, 0, 1) * depth); + floatIter++; + charIter++; + } + } + } + + wbFile_write(file, charData, width * channels * sizeof(unsigned char), + height); + + wbDelete(charData); + wbFile_delete(file); + + return; +} diff --git a/CUDA_ListScan/libwb/wbPPM.h b/CUDA_ListScan/libwb/wbPPM.h new file mode 100644 index 0000000..d589b36 --- /dev/null +++ b/CUDA_ListScan/libwb/wbPPM.h @@ -0,0 +1,11 @@ + + +#ifndef __wbPPM_H__ +#define __wbPPM_H__ + +START_EXTERN_C +wbImage_t wbPPM_import(const char *filename); +void wbPPM_export(const char *filename, wbImage_t img); +END_EXTERN_C + +#endif /* __wbPPM_H__ */ diff --git a/CUDA_ListScan/libwb/wbPath.cpp b/CUDA_ListScan/libwb/wbPath.cpp new file mode 100644 index 0000000..0d93e2b --- /dev/null +++ b/CUDA_ListScan/libwb/wbPath.cpp @@ -0,0 +1,42 @@ +#include "wb.h" + +char *wbPath_join(const char *p1, const char *p2) { + size_t s1 = strlen(p1); + size_t s2 = strlen(p2); + char *res = + wbNewArray(char, s1 + 1 /* seperator */ + s2 + 1 /* terminator */); + memcpy(res, p1, s1); + char *iter = res + s1; + *iter++ = wbDirectorySeperator; + memcpy(iter, p2, s2); + iter += s2; + *iter = '\0'; + return res; +} + +char *wbPath_join(const char *p1, const char *p2, const char *p3) { + char *p12 = wbPath_join(p1, p2); + char *res = wbPath_join(p12, p3); + wbDelete(p12); + return res; +} + +char *wbPath_join(const char *p1, const char *p2, const char *p3, + const char *p4) { + char *p123 = wbPath_join(p1, p2, p3); + char *res = wbPath_join(p123, p4); + wbDelete(p123); + return res; +} + +char *wbPath_join(const std::string &p1, const std::string &p2) { + return wbPath_join(p1.c_str(), p2.c_str()); +} +char *wbPath_join(const std::string &p1, const std::string &p2, + const std::string &p3) { + return wbPath_join(p1.c_str(), p2.c_str(), p3.c_str()); +} +char *wbPath_join(const std::string &p1, const std::string &p2, + const std::string &p3, const std::string &p4) { + return wbPath_join(p1.c_str(), p2.c_str(), p3.c_str(), p4.c_str()); +} \ No newline at end of file diff --git a/CUDA_ListScan/libwb/wbPath.h b/CUDA_ListScan/libwb/wbPath.h new file mode 100644 index 0000000..0dd3187 --- /dev/null +++ b/CUDA_ListScan/libwb/wbPath.h @@ -0,0 +1,30 @@ +#ifndef __WB_PATH_H__ +#define __WB_PATH_H__ + +char *wbPath_join(const char *p1, const char *p2); +char *wbPath_join(const char *p1, const char *p2, const char *p3); +char *wbPath_join(const char *p1, const char *p2, const char *p3, + const char *p4); + +char *wbPath_join(const std::string &p1, const std::string &p2); +char *wbPath_join(const std::string &p1, const std::string &p2, + const std::string &p3); +char *wbPath_join(const std::string &p1, const std::string &p2, + const std::string &p3, const std::string &p4); + +template +static char *wbPath_join(const T1 &p1, const T2 &p2) { + return wbPath_join(wbString(p1), wbString(p2)); +} +template +static char *wbPath_join(const T1 &p1, const T2 &p2, const T3 &p3) { + return wbPath_join(wbString(p1), wbString(p2), wbString(p3)); +} +template +static char *wbPath_join(const T1 &p1, const T2 &p2, const T3 &p3, + const T4 &p4) { + return wbPath_join(wbString(p1), wbString(p2), wbString(p3), + wbString(p4)); +} + +#endif /* __WB_PATH_H__ */ diff --git a/CUDA_ListScan/libwb/wbSolution.cpp b/CUDA_ListScan/libwb/wbSolution.cpp new file mode 100644 index 0000000..703f410 --- /dev/null +++ b/CUDA_ListScan/libwb/wbSolution.cpp @@ -0,0 +1,271 @@ + +#include "wb.h" + +char *solutionJSON = NULL; +static string _solution_correctQ(""); + +static void _onUnsameImageFunction(string str) { + _solution_correctQ = str; +} + +template +static wbBool wbSolution_listCorrectQ(const char *expectedOutputFile, + wbSolution_t sol, const char *type) { + wbBool res; + T *expectedData; + int expectedRows, expectedColumns; + + expectedData = (T *)wbImport(expectedOutputFile, &expectedRows, + &expectedColumns, type); + + if (expectedData == NULL) { + _solution_correctQ = "Failed to open expected output file."; + res = wbFalse; + } else if (expectedRows != wbSolution_getRows(sol)) { + wbLog(TRACE, "Number of rows in the solution is ", + wbSolution_getRows(sol), ". Expected number of rows is ", + expectedRows, "."); + _solution_correctQ = + "The number of rows in the solution did not match " + "that of the expected results."; + res = wbFalse; + } else if (expectedColumns != wbSolution_getColumns(sol)) { + wbLog(TRACE, "Number of columns in the solution is ", + wbSolution_getColumns(sol), ". Expected number of columns is ", + expectedColumns, "."); + _solution_correctQ = "The number of columns in the solution did not " + "match that of the expected results."; + res = wbFalse; + } else { + int ii, jj, idx; + T *solutionData; + + solutionData = (T *)wbSolution_getData(sol); + + for (ii = 0; ii < expectedRows; ii++) { + for (jj = 0; jj < expectedColumns; jj++) { + idx = ii * expectedColumns + jj; + if (wbUnequalQ(expectedData[idx], solutionData[idx])) { + string str; + if (expectedColumns == 1) { + str = wbString( + "The solution did not match the expected results at row ", + ii, ". Expecting ", expectedData[idx], " but got ", + solutionData[idx], "."); + } else { + str = wbString("The solution did not match the expected " + "results at column ", + jj, " and row ", ii, ". Expecting ", + expectedData[idx], " but got ", + solutionData[idx], "."); + } + _solution_correctQ = str; + res = wbFalse; + goto matrixCleanup; + } + } + } + + res = wbTrue; + matrixCleanup: + if (expectedData != NULL) { + wbFree(expectedData); + } + } + return res; +} + +static wbBool wbSolution_correctQ(char *expectedOutputFile, + wbSolution_t sol) { + if (expectedOutputFile == NULL) { + _solution_correctQ = "Failed to determined the expected output file."; + return wbFalse; + } else if (!wbFile_existsQ(expectedOutputFile)) { + _solution_correctQ = + wbString("The file ", expectedOutputFile, " does not exist."); + return wbFalse; + } else if (wbString_sameQ(wbSolution_getType(sol), "image")) { + wbBool res; + wbImage_t solutionImage = NULL; + wbImage_t expectedImage = wbImport(expectedOutputFile); + if (expectedImage == NULL) { + _solution_correctQ = "Failed to open expected output file."; + res = wbFalse; + } else if (wbImage_getWidth(expectedImage) != + wbSolution_getWidth(sol)) { + _solution_correctQ = + "The image width of the expected image does not " + "match that of the solution."; + res = wbFalse; + } else if (wbImage_getHeight(expectedImage) != + wbSolution_getHeight(sol)) { + _solution_correctQ = + "The image height of the expected image does not " + "match that of the solution."; + res = wbFalse; + } else if (wbImage_getChannels(expectedImage) != + wbSolution_getChannels(sol)) { + _solution_correctQ = + "The image channels of the expected image does not " + "match that of the solution."; + res = wbFalse; + } else { + solutionImage = (wbImage_t)wbSolution_getData(sol); + wbAssert(solutionImage != NULL); + res = wbImage_sameQ(solutionImage, expectedImage, + _onUnsameImageFunction); + } + if (expectedImage != NULL) { + wbImage_delete(expectedImage); + } + return res; + } else if (wbString_sameQ(wbSolution_getType(sol), "histogram")) { + return wbSolution_listCorrectQ(expectedOutputFile, sol, + "Integer"); + } else if (wbString_sameQ(wbSolution_getType(sol), "integral_vector")) { + return wbSolution_listCorrectQ(expectedOutputFile, sol, + "Integer"); + } else if (wbString_sameQ(wbSolution_getType(sol), "vector") || + wbString_sameQ(wbSolution_getType(sol), "matrix")) { + return wbSolution_listCorrectQ(expectedOutputFile, sol, + "Real"); + } else { + wbAssert(wbFalse); + return wbFalse; + } +} + +wbBool wbSolution(char *expectedOutputFile, char *outputFile, char *type0, + void *data, int rows, int columns, int depth) { + char *type; + wbBool res; + wbSolution_t sol; + + if (expectedOutputFile == NULL || data == NULL || type0 == NULL) { + wbLog(ERROR, "Failed to grade solution"); + return wbFalse; + } + + type = wbString_toLower(type0); + + if (_solution_correctQ != "") { + _solution_correctQ = ""; + } + + wbSolution_setOutputFile(sol, outputFile); + wbSolution_setType(sol, type); + wbSolution_setData(sol, data); + wbSolution_setRows(sol, rows); + wbSolution_setColumns(sol, columns); + wbSolution_setDepth(sol, depth); + + res = wbSolution_correctQ(expectedOutputFile, sol); + + if (outputFile != NULL) { + if (wbString_sameQ(type, "image")) { + wbImage_t inputImage = (wbImage_t)data; + wbImage_t img = wbImage_new(wbImage_getWidth(inputImage), + wbImage_getHeight(inputImage), + wbImage_getChannels(inputImage)); + memcpy(wbImage_getData(img), wbImage_getData(inputImage), + rows * columns * wbImage_channels * sizeof(wbReal_t)); + wbExport(outputFile, img); + wbImage_delete(img); + } else if (wbString_sameQ(type, "integral_vector")) { + wbExport(outputFile, (int *)data, rows, columns); + } else if (wbString_sameQ(type, "vector") || + wbString_sameQ(type, "matrix")) { + wbExport(outputFile, (wbReal_t *)data, rows, columns); + } else if (wbString_sameQ(type, "histogram")) { + wbExport(outputFile, (unsigned char *)data, rows, columns); + } else if (wbString_sameQ(type, "text")) { + wbExport_text(outputFile, (unsigned char *)data, rows * columns); + } + } + + wbFree(type); + + return res; +} + +wbBool wbSolution(char *expectedOutputFile, char *outputFile, char *type0, + void *data, int rows, int columns) { + return wbSolution(expectedOutputFile, outputFile, type0, data, rows, + columns, 1); +} + +wbBool wbSolution(wbArg_t arg, void *data, int rows, int columns, + int depth) { + char *type; + wbBool res; + char *expectedOutputFile; + char *outputFile; + stringstream ss; + + expectedOutputFile = wbArg_getExpectedOutputFile(arg); + outputFile = wbArg_getOutputFile(arg); + type = wbArg_getType(arg); + + wbAssert(type != NULL); + wbAssert(expectedOutputFile != NULL); + wbAssert(outputFile != NULL); + + res = wbSolution(expectedOutputFile, outputFile, type, data, rows, + columns, depth); + + if (WB_USE_JSON11) { + json11::Json json; + if (res) { + json = json11::Json::object{{"correctq", true}, + {"message", "The solution is correct"}}; + } else { + json = json11::Json::object{{"correctq", false}, + {"message", _solution_correctQ}}; + } + +#ifdef wbLogger_printOnLog + if (wbLogger_printOnLog) { + json11::Json e = +//PMO +#ifndef _MSC_VER + json11::Json::object{{"type", "solution"}, {"data", json}}; +#else + json11::Json::object{{"data", json }, {"type", "solution" }}; +#endif + std::cout << e.dump() << std::endl; + } +#endif /* wbLogger_printOnLog */ + + solutionJSON = wbString_duplicate(json.string_value()); + } else { + if (res) { + ss << "{\n"; + ss << wbString_quote("correctq") << ": true,\n"; + ss << wbString_quote("message") << ": " + << wbString_quote("Solution is correct.") << "\n"; + ss << "}"; + } else { + ss << "{\n"; + ss << wbString_quote("correctq") << ": false,\n"; + ss << wbString_quote("message") << ": " + << wbString_quote(_solution_correctQ) << "\n"; + ss << "}"; + } + solutionJSON = wbString_duplicate(ss.str()); + } + + return res; +} + +wbBool wbSolution(wbArg_t arg, void *data, int rows, int columns) { + return wbSolution(arg, data, rows, columns, 1); +} + +EXTERN_C wbBool wbSolution(wbArg_t arg, void *data, int rows) { + return wbSolution(arg, data, rows, 1); +} + +wbBool wbSolution(wbArg_t arg, wbImage_t img) { + return wbSolution(arg, img, wbImage_getHeight(img), + wbImage_getWidth(img), wbImage_getChannels(img)); +} diff --git a/CUDA_ListScan/libwb/wbSolution.h b/CUDA_ListScan/libwb/wbSolution.h new file mode 100644 index 0000000..f18d07d --- /dev/null +++ b/CUDA_ListScan/libwb/wbSolution.h @@ -0,0 +1,40 @@ + + +#ifndef __WB_SOLUTION_H__ +#define __WB_SOLUTION_H__ + +typedef struct st_wbSolution_t { + char *type; + char *outputFile; + void *data; + int rows; + int columns; + int depth; +} wbSolution_t; + +#define wbSolution_getType(sol) ((sol).type) +#define wbSolution_getOutputFile(sol) ((sol).outputFile) +#define wbSolution_getData(sol) ((sol).data) +#define wbSolution_getRows(sol) ((sol).rows) +#define wbSolution_getColumns(sol) ((sol).columns) +#define wbSolution_getDepth(sol) ((sol).depth) + +#define wbSolution_getHeight wbSolution_getRows +#define wbSolution_getWidth wbSolution_getColumns +#define wbSolution_getChannels wbSolution_getDepth + +#define wbSolution_setType(sol, val) (wbSolution_getType(sol) = val) +#define wbSolution_setOutputFile(sol, val) \ + (wbSolution_getOutputFile(sol) = val) +#define wbSolution_setData(sol, val) (wbSolution_getData(sol) = val) +#define wbSolution_setRows(sol, val) (wbSolution_getRows(sol) = val) +#define wbSolution_setColumns(sol, val) (wbSolution_getColumns(sol) = val) +#define wbSolution_setDepth(sol, val) (wbSolution_getDepth(sol) = val) + +wbBool wbSolution(char *expectedOutputFile, char *outputFile, char *type0, + void *data, int rows, int columns); +wbBool wbSolution(wbArg_t arg, void *data, int rows, int columns); +EXTERN_C wbBool wbSolution(wbArg_t arg, void *data, int rows); +wbBool wbSolution(wbArg_t arg, wbImage_t img); + +#endif /* __WB_SOLUTION_H__ */ diff --git a/CUDA_ListScan/libwb/wbSparse.cpp b/CUDA_ListScan/libwb/wbSparse.cpp new file mode 100644 index 0000000..9cdcba3 --- /dev/null +++ b/CUDA_ListScan/libwb/wbSparse.cpp @@ -0,0 +1,82 @@ + +#include "wb.h" + +static void sort(int *data, int *key, int start, int end) { + if ((end - start + 1) > 1) { + int left = start, right = end; + int pivot = key[right]; + while (left <= right) { + while (key[left] > pivot) { + left = left + 1; + } + while (key[right] < pivot) { + right = right - 1; + } + if (left <= right) { + int tmp = key[left]; + key[left] = key[right]; + key[right] = tmp; + tmp = data[left]; + data[left] = data[right]; + data[right] = tmp; + left = left + 1; + right = right - 1; + } + } + sort(data, key, start, right); + sort(data, key, left, end); + } +} + +EXTERN_C void CSRToJDS(int dim, int *csrRowPtr, int *csrColIdx, + float *csrData, int **jdsRowPerm, int **jdsRowNNZ, + int **jdsColStartIdx, int **jdsColIdx, + float **jdsData) { + // Row Permutation Vector + *jdsRowPerm = (int *)malloc(sizeof(int) * dim); + for (int rowIdx = 0; rowIdx < dim; ++rowIdx) { + (*jdsRowPerm)[rowIdx] = rowIdx; + } + + // Number of non-zeros per row + *jdsRowNNZ = (int *)malloc(sizeof(int) * dim); + for (int rowIdx = 0; rowIdx < dim; ++rowIdx) { + (*jdsRowNNZ)[rowIdx] = csrRowPtr[rowIdx + 1] - csrRowPtr[rowIdx]; + } + + // Sort rows by number of non-zeros + sort(*jdsRowPerm, *jdsRowNNZ, 0, dim - 1); + + // Starting point of each compressed column + int maxRowNNZ = (*jdsRowNNZ)[0]; // Largest number of non-zeros per row + DEBUG(printf("jdsRowNNZ = %d\n", maxRowNNZ)); + *jdsColStartIdx = (int *)malloc(sizeof(int) * maxRowNNZ); + (*jdsColStartIdx)[0] = 0; // First column starts at 0 + for (int col = 0; col < maxRowNNZ - 1; ++col) { + // Count the number of rows with entries in this column + int count = 0; + for (int idx = 0; idx < dim; ++idx) { + if ((*jdsRowNNZ)[idx] > col) { + ++count; + } + } + (*jdsColStartIdx)[col + 1] = (*jdsColStartIdx)[col] + count; + } + + // Sort the column indexes and data + const int NNZ = csrRowPtr[dim]; + DEBUG(printf("NNZ = %d\n", NNZ)); + *jdsColIdx = (int *)malloc(sizeof(int) * NNZ); + DEBUG(printf("dim = %d\n", dim)); + *jdsData = (float *)malloc(sizeof(float) * NNZ); + for (int idx = 0; idx < dim; ++idx) { // For every row + int row = (*jdsRowPerm)[idx]; + int rowNNZ = (*jdsRowNNZ)[idx]; + for (int nnzIdx = 0; nnzIdx < rowNNZ; ++nnzIdx) { + int jdsPos = (*jdsColStartIdx)[nnzIdx] + idx; + int csrPos = csrRowPtr[row] + nnzIdx; + (*jdsColIdx)[jdsPos] = csrColIdx[csrPos]; + (*jdsData)[jdsPos] = csrData[csrPos]; + } + } +} diff --git a/CUDA_ListScan/libwb/wbSparse.h b/CUDA_ListScan/libwb/wbSparse.h new file mode 100644 index 0000000..c04a857 --- /dev/null +++ b/CUDA_ListScan/libwb/wbSparse.h @@ -0,0 +1,10 @@ + +#ifndef __WB_SPARSE_H__ +#define __WB_SPARSE_H__ + +EXTERN_C void CSRToJDS(int dim, int *csrRowPtr, int *csrColIdx, + float *csrData, int **jdsRowPerm, int **jdsRowNNZ, + int **jdsColStartIdx, int **jdsColIdx, + float **jdsData); + +#endif /* __WB_SPARSE_H__ */ diff --git a/CUDA_ListScan/libwb/wbString.h b/CUDA_ListScan/libwb/wbString.h new file mode 100644 index 0000000..65e52f8 --- /dev/null +++ b/CUDA_ListScan/libwb/wbString.h @@ -0,0 +1,324 @@ + + +#ifndef __WB_STRING_H__ +#define __WB_STRING_H__ + +#include +#include +#include +#include +#include +#include +#include "wb.h" + +using std::string; +using std::vector; +using std::stringstream; +using std::exception; + +template +static inline string wbString(const T &x); + +static inline void wbString_replace(string &value, string const &search, + string const &replace) { + for (string::size_type next = value.find(search); next != string::npos; + next = value.find(search, next)) { + value.replace(next, search.length(), replace); + next += replace.length(); + } +} + +static inline string wbString_quote(string str) { + string s = str; + wbString_replace(s, "\\", "\\\\"); + s = "\"" + s + "\""; + return s; +} + +static inline string wbString_quote(const char *str) { + if (str == NULL) { + return wbString_quote(""); + } else { + return wbString_quote(string(str)); + } +} + +static inline char *wbString_duplicate(const char *str) { + if (str == NULL) { + return NULL; + } else { + char *newstr; + size_t len = strlen(str); + newstr = wbNewArray(char, len + 1); + memcpy(newstr, str, len * sizeof(char)); + newstr[len] = '\0'; + return newstr; + } +} + +static inline char *wbString_duplicate(std::string str) { + return wbString_duplicate(str.c_str()); +} + +static inline string wbString(void) { + string s = ""; + return s; +} + +template +static inline string wbString(const T &x) { + try { + stringstream ss; + ss << x; + return ss.str(); + } catch (exception &e) { + return string(); + } +} + +template <> +inline string wbString(const bool &x) { + return x ? "True" : "False"; +} + +template <> +inline string wbString(const vector &x) { + stringstream ss; + ss << "{"; + for (size_t ii = 0; ii < x.size(); ii++) { + ss << wbString_quote(x[ii]); + if (ii != x.size() - 1) { + ss << ", "; + } + } + ss << "}"; + + return ss.str(); +} + +template <> +inline string wbString(const vector &x) { + stringstream ss; + ss << "{"; + for (size_t ii = 0; ii < x.size(); ii++) { + ss << x[ii]; + if (ii != x.size() - 1) { + ss << ", "; + } + } + ss << "}"; + + return ss.str(); +} + +template <> +inline string wbString(const vector &x) { + stringstream ss; + ss << "{"; + for (size_t ii = 0; ii < x.size(); ii++) { + ss << x[ii]; + if (ii != x.size() - 1) { + ss << ", "; + } + } + ss << "}"; + + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1) { + stringstream ss; + ss << wbString(x0) << wbString(x1); + + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1, const T2 &x2) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2); + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1, const T2 &x2, + const T3 &x3) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2) << wbString(x3); + + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1, const T2 &x2, + const T3 &x3, const T4 &x4) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2) << wbString(x3) + << wbString(x4); + + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1, const T2 &x2, + const T3 &x3, const T4 &x4, const T5 &x5) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2) << wbString(x3) + << wbString(x4) << wbString(x5); + + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1, const T2 &x2, + const T3 &x3, const T4 &x4, const T5 &x5, + const T6 &x6) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2) << wbString(x3) + << wbString(x4) << wbString(x5) << wbString(x6); + + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1, const T2 &x2, + const T3 &x3, const T4 &x4, const T5 &x5, + const T6 &x6, const T7 &x7) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2) << wbString(x3) + << wbString(x4) << wbString(x5) << wbString(x6) << wbString(x7); + + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1, const T2 &x2, + const T3 &x3, const T4 &x4, const T5 &x5, + const T6 &x6, const T7 &x7, const T8 &x8) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2) << wbString(x3) + << wbString(x4) << wbString(x5) << wbString(x6) << wbString(x7) + << wbString(x8); + + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1, const T2 &x2, + const T3 &x3, const T4 &x4, const T5 &x5, + const T6 &x6, const T7 &x7, const T8 &x8, + const T9 &x9) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2) << wbString(x3) + << wbString(x4) << wbString(x5) << wbString(x6) << wbString(x7) + << wbString(x8) << wbString(x9); + + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1, const T2 &x2, + const T3 &x3, const T4 &x4, const T5 &x5, + const T6 &x6, const T7 &x7, const T8 &x8, + const T9 &x9, const T10 &x10) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2) << wbString(x3) + << wbString(x4) << wbString(x5) << wbString(x6) << wbString(x7) + << wbString(x8) << wbString(x9) << wbString(x10); + + return ss.str(); +} + +template +static inline string +wbString(const T0 &x0, const T1 &x1, const T2 &x2, const T3 &x3, + const T4 &x4, const T5 &x5, const T6 &x6, const T7 &x7, + const T8 &x8, const T9 &x9, const T10 &x10, const T11 &x11) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2) << wbString(x3) + << wbString(x4) << wbString(x5) << wbString(x6) << wbString(x7) + << wbString(x8) << wbString(x9) << wbString(x10) << wbString(x11); + + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1, const T2 &x2, + const T3 &x3, const T4 &x4, const T5 &x5, + const T6 &x6, const T7 &x7, const T8 &x8, + const T9 &x9, const T10 &x10, const T11 &x11, + const T12 &x12) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2) << wbString(x3) + << wbString(x4) << wbString(x5) << wbString(x6) << wbString(x7) + << wbString(x8) << wbString(x9) << wbString(x10) << wbString(x11) + << wbString(x12); + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1, const T2 &x2, + const T3 &x3, const T4 &x4, const T5 &x5, + const T6 &x6, const T7 &x7, const T8 &x8, + const T9 &x9, const T10 &x10, const T11 &x11, + const T12 &x12, const T13 &x13) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2) << wbString(x3) + << wbString(x4) << wbString(x5) << wbString(x6) << wbString(x7) + << wbString(x8) << wbString(x9) << wbString(x10) << wbString(x11) + << wbString(x12) << wbString(x13); + return ss.str(); +} + +template +static inline wbBool wbString_sameQ(const X &x, const Y &y) { + string xs = wbString(x); + string ys = wbString(y); + return strcmp(xs.c_str(), ys.c_str()) == 0; +} + +static inline wbBool wbString_sameQ(const string &x, const string &y) { + return x.compare(y) == 0; +} + +static inline char *wbString_toLower(const char *str) { + if (str == NULL) { + return NULL; + } else { + char *res, *iter; + + res = iter = wbString_duplicate(str); + while (*iter != '\0') { + *iter++ = tolower(*str++); + } + return res; + } +} + +static inline wbBool wbString_startsWith(const char *str, + const char *prefix) { + while (*prefix != '\0') { + if (*str == '\0' || *str != *prefix) { + return wbFalse; + } + str++; + prefix++; + } + return wbTrue; +} + +#endif /* __WB_STRING_H__ */ diff --git a/CUDA_ListScan/libwb/wbThrust.h b/CUDA_ListScan/libwb/wbThrust.h new file mode 100644 index 0000000..e2d3160 --- /dev/null +++ b/CUDA_ListScan/libwb/wbThrust.h @@ -0,0 +1,15 @@ + +#ifndef __WB_THRUST_H__ +#define __WB_THRUST_H__ + +#ifdef WB_USE_CUDA +#include +#include +#include +#include +#include +#include + +#endif /* WB_USE_CUDA */ + +#endif /* __WB_THRUST_H__ */ diff --git a/CUDA_ListScan/libwb/wbTimer.cpp b/CUDA_ListScan/libwb/wbTimer.cpp new file mode 100644 index 0000000..c9fbdb8 --- /dev/null +++ b/CUDA_ListScan/libwb/wbTimer.cpp @@ -0,0 +1,493 @@ +#include "wb.h" + +#ifdef WB_USE_WINDOWS +uint64_t _hrtime_frequency = 0; +#endif /* WB_USE_WINDOWS */ +wbTimer_t _timer = NULL; + +#ifdef WB_USE_DARWIN +static double o_timebase = 0; +static uint64_t o_timestart = 0; +#endif /* WB_USE_DARWIN */ + +uint64_t _hrtime(void) { +#define NANOSEC ((uint64_t)1e9) +#ifdef WB_USE_WINDOWS + LARGE_INTEGER counter; + if (!QueryPerformanceCounter(&counter)) { + return 0; + } + return ((uint64_t)counter.LowPart * NANOSEC / _hrtime_frequency) + + (((uint64_t)counter.HighPart * NANOSEC / _hrtime_frequency) + << 32); +#else + struct timespec ts; +#ifdef WB_USE_DARWIN +#define O_NANOSEC (+1.0E-9) +#define O_GIGA UINT64_C(1000000000) + if (!o_timestart) { + mach_timebase_info_data_t tb{}; + mach_timebase_info(&tb); + o_timebase = tb.numer; + o_timebase /= tb.denom; + o_timestart = mach_absolute_time(); + } + double diff = (mach_absolute_time() - o_timestart) * o_timebase; + ts.tv_sec = diff * O_NANOSEC; + ts.tv_nsec = diff - (ts.tv_sec * O_GIGA); +#undef O_NANOSEC +#undef O_GIGA +#else /* WB_USE_DARWIN */ + clock_gettime(CLOCK_MONOTONIC, &ts); +#endif /* WB_USE_DARWIN */ + return (((uint64_t)ts.tv_sec) * NANOSEC + ts.tv_nsec); +#endif /* WB_USE_WINDOWS */ +#undef NANOSEC +} + +static inline uint64_t getTime(void) { +#ifdef WB_USE_CUDA + cudaDeviceSynchronize(); +#endif /* WB_USE_CUDA */ + return _hrtime(); +} + +static inline wbTimerNode_t wbTimerNode_new(int id, wbTimerKind_t kind, + const char *file, + const char *fun, + int startLine) { + wbTimerNode_t node = wbNew(struct st_wbTimerNode_t); + wbTimerNode_setId(node, id); + wbTimerNode_setMPIRank(node, wbMPI_getRank()); + wbTimerNode_setLevel(node, 0); + wbTimerNode_setStoppedQ(node, wbFalse); + wbTimerNode_setKind(node, kind); + wbTimerNode_setStartTime(node, 0); + wbTimerNode_setEndTime(node, 0); + wbTimerNode_setElapsedTime(node, 0); + wbTimerNode_setStartLine(node, startLine); + wbTimerNode_setEndLine(node, 0); + wbTimerNode_setStartFunction(node, fun); + wbTimerNode_setEndFunction(node, NULL); + wbTimerNode_setStartFile(node, file); + wbTimerNode_setEndFile(node, NULL); + wbTimerNode_setNext(node, NULL); + wbTimerNode_setPrevious(node, NULL); + wbTimerNode_setParent(node, NULL); + wbTimerNode_setMessage(node, NULL); + return node; +} + +static inline void wbTimerNode_delete(wbTimerNode_t node) { + if (node != NULL) { + if (wbTimerNode_getMessage(node)) { + wbDelete(wbTimerNode_getMessage(node)); + } + wbDelete(node); + } +} + +static inline const char *_nodeKind(wbTimerKind_t kind) { + switch (kind) { + case wbTimerKind_Generic: + return "Generic"; + case wbTimerKind_IO: + return "IO"; + case wbTimerKind_GPU: + return "GPU"; + case wbTimerKind_Copy: + return "Copy"; + case wbTimerKind_Driver: + return "Driver"; + case wbTimerKind_CopyAsync: + return "CopyAsync"; + case wbTimerKind_Compute: + return "Compute"; + case wbTimerKind_CPUGPUOverlap: + return "CPUGPUOverlap"; + } + return "Undefined"; +} + +static inline json11::Json wbTimerNode_toJSONObject(wbTimerNode_t node) { + json11::Json json = json11::Json::object{ + {"id", wbTimerNode_getId(node)}, + {"mpi_rank", wbTimerNode_getMPIRank(node)}, + {"stopped", wbTimerNode_stoppedQ(node)}, + {"kind", _nodeKind(wbTimerNode_getKind(node))}, + {"start_time", wbTimerNode_getStartTime(node)}, + {"end_time", wbTimerNode_getEndTime(node)}, + {"elapsed_time", wbTimerNode_getElapsedTime(node)}, + {"start_line", wbTimerNode_getStartLine(node)}, + {"end_line", wbTimerNode_getEndLine(node)}, + {"start_function", wbTimerNode_getStartFunction(node)}, + {"end_function", wbTimerNode_getEndFunction(node)}, + {"start_file", wbTimerNode_getStartFile(node)}, + {"end_file", wbTimerNode_getEndFile(node)}, + {"parent_id", wbTimerNode_hasParent(node) + ? wbTimerNode_getId(wbTimerNode_getParent(node)) + : -1}, + {"message", wbTimerNode_getMessage(node)}, + }; + return json; +} + +static inline string wbTimerNode_toJSON(wbTimerNode_t node) { + if (node == NULL) { + return ""; + } else if (WB_USE_JSON11) { + json11::Json json = wbTimerNode_toJSONObject(node); + return json.string_value(); + } else { + stringstream ss; + + ss << "{\n"; + ss << wbString_quote("id") << ":" << wbTimerNode_getId(node) << ",\n"; + ss << wbString_quote("mpi_rank") << ":" << wbTimerNode_getMPIRank(node) + << ",\n"; + ss << wbString_quote("stopped") << ":" + << wbString(wbTimerNode_stoppedQ(node) ? "true" : "false") << ",\n"; + ss << wbString_quote("kind") << ":" + << wbString_quote(_nodeKind(wbTimerNode_getKind(node))) << ",\n"; + ss << wbString_quote("start_time") << ":" + << wbTimerNode_getStartTime(node) << ",\n"; + ss << wbString_quote("end_time") << ":" << wbTimerNode_getEndTime(node) + << ",\n"; + ss << wbString_quote("elapsed_time") << ":" + << wbTimerNode_getElapsedTime(node) << ",\n"; + ss << wbString_quote("start_line") << ":" + << wbTimerNode_getStartLine(node) << ",\n"; + ss << wbString_quote("end_line") << ":" << wbTimerNode_getEndLine(node) + << ",\n"; + ss << wbString_quote("start_function") << ":" + << wbString_quote(wbTimerNode_getStartFunction(node)) << ",\n"; + ss << wbString_quote("end_function") << ":" + << wbString_quote(wbTimerNode_getEndFunction(node)) << ",\n"; + ss << wbString_quote("start_file") << ":" + << wbString_quote(wbTimerNode_getStartFile(node)) << ",\n"; + ss << wbString_quote("end_file") << ":" + << wbString_quote(wbTimerNode_getEndFile(node)) << ",\n"; + ss << wbString_quote("parent_id") << ":" + << wbString(wbTimerNode_hasParent(node) + ? wbTimerNode_getId(wbTimerNode_getParent(node)) + : -1) + << ",\n"; + ss << wbString_quote("message") << ":" + << wbString_quote(wbTimerNode_getMessage(node)) << "\n"; + ss << "}"; + + return ss.str(); + } +} + +static inline string wbTimerNode_toXML(wbTimerNode_t node) { + if (node == NULL) { + return ""; + } else { + stringstream ss; + + ss << "\n"; + ss << "" << wbTimerNode_getId(node) << "\n"; + ss << "" + << wbString(wbTimerNode_stoppedQ(node) ? "true" : "false") + << "\n"; + ss << "" << _nodeKind(wbTimerNode_getKind(node)) << "\n"; + ss << "" << wbTimerNode_getStartTime(node) + << "\n"; + ss << "" << wbTimerNode_getEndTime(node) << "\n"; + ss << "" << wbTimerNode_getElapsedTime(node) + << "\n"; + ss << "" << wbTimerNode_getStartLine(node) + << "\n"; + ss << "" << wbTimerNode_getEndLine(node) << "\n"; + ss << "" << wbTimerNode_getStartFunction(node) + << "\n"; + ss << "" << wbTimerNode_getEndFunction(node) + << "\n"; + ss << "" << wbTimerNode_getStartFile(node) + << "\n"; + ss << "" << wbTimerNode_getEndFile(node) << "\n"; + ss << "" + << wbString(wbTimerNode_hasParent(node) + ? wbTimerNode_getId(wbTimerNode_getParent(node)) + : -1) + << "\n"; + ss << "" << wbTimerNode_getMessage(node) << "\n"; + ss << "\n"; + + return ss.str(); + } +} + +#define wbTimer_getLength(timer) ((timer)->length) +#define wbTimer_getHead(timer) ((timer)->head) +#define wbTimer_getTail(timer) ((timer)->tail) +#define wbTimer_getStartTime(timer) ((timer)->startTime) +#define wbTimer_getEndTime(timer) ((timer)->endTime) +#define wbTimer_getElapsedTime(timer) ((timer)->elapsedTime) + +#define wbTimer_setLength(timer, val) (wbTimer_getLength(timer) = val) +#define wbTimer_setHead(timer, val) (wbTimer_getHead(timer) = val) +#define wbTimer_setTail(timer, val) (wbTimer_getTail(timer) = val) +#define wbTimer_setStartTime(node, val) (wbTimer_getStartTime(node) = val) +#define wbTimer_setEndTime(node, val) (wbTimer_getEndTime(node) = val) +#define wbTimer_setElapsedTime(node, val) \ + (wbTimer_getElapsedTime(node) = val) + +#define wbTimer_incrementLength(timer) (wbTimer_getLength(timer)++) +#define wbTimer_decrementLength(timer) (wbTimer_getLength(timer)--) + +#define wbTimer_emptyQ(timer) (wbTimer_getLength(timer) == 0) + +void wbTimer_delete(wbTimer_t timer) { + if (timer != NULL) { + wbTimerNode_t tmp, iter; + + iter = wbTimer_getHead(timer); + while (iter) { + tmp = wbTimerNode_getNext(iter); + wbTimerNode_delete(iter); + iter = tmp; + } + + wbDelete(timer); + } +} + +static json11::Json wbTimer_toJSONObject(wbTimer_t timer) { + + stringstream ss; + wbTimerNode_t iter; + uint64_t currentTime; + std::vector elems; + + currentTime = getTime(); + + wbTimer_setEndTime(timer, currentTime); + wbTimer_setElapsedTime(timer, currentTime - wbTimer_getStartTime(timer)); + + for (iter = wbTimer_getHead(timer); iter != NULL; + iter = wbTimerNode_getNext(iter)) { + if (!wbTimerNode_stoppedQ(iter)) { + wbTimerNode_setEndTime(iter, currentTime); + wbTimerNode_setElapsedTime(iter, currentTime - + wbTimerNode_getStartTime(iter)); + } + elems.push_back(wbTimerNode_toJSONObject(iter)); + } + return json11::Json(elems); +} + +string wbTimer_toJSON(wbTimer_t timer) { + if (timer == NULL) { + return ""; + } else if (WB_USE_JSON11) { + json11::Json json = wbTimer_toJSONObject(timer); + return json.string_value(); + } else { + stringstream ss; + wbTimerNode_t iter; + uint64_t currentTime; + + currentTime = getTime(); + + wbTimer_setEndTime(timer, currentTime); + wbTimer_setElapsedTime(timer, + currentTime - wbTimer_getStartTime(timer)); + + for (iter = wbTimer_getHead(timer); iter != NULL; + iter = wbTimerNode_getNext(iter)) { + if (!wbTimerNode_stoppedQ(iter)) { + wbTimerNode_setEndTime(iter, currentTime); + wbTimerNode_setElapsedTime( + iter, currentTime - wbTimerNode_getStartTime(iter)); + } + ss << wbTimerNode_toJSON(iter); + if (wbTimerNode_getNext(iter) != NULL) { + ss << ",\n"; + } + } + + return ss.str(); + } +} + +string wbTimer_toJSON() { + return wbTimer_toJSON(_timer); +} + +string wbTimer_toXML(wbTimer_t timer) { + if (timer == NULL) { + return ""; + } else { + stringstream ss; + wbTimerNode_t iter; + uint64_t currentTime; + + currentTime = getTime(); + + wbTimer_setEndTime(timer, currentTime); + wbTimer_setElapsedTime(timer, + currentTime - wbTimer_getStartTime(timer)); + + ss << "\n"; + ss << "" << wbTimer_getStartTime(timer) + << "\n"; + ss << "" << wbTimer_getEndTime(timer) << "\n"; + ss << "" << wbTimer_getElapsedTime(timer) + << "\n"; + ss << "\n"; + for (iter = wbTimer_getHead(timer); iter != NULL; + iter = wbTimerNode_getNext(iter)) { + if (!wbTimerNode_stoppedQ(iter)) { + wbTimerNode_setEndTime(iter, currentTime); + wbTimerNode_setElapsedTime( + iter, currentTime - wbTimerNode_getStartTime(iter)); + } + ss << wbTimerNode_toXML(iter); + } + ss << "\n"; + ss << "\n"; + + return ss.str(); + } +} + +string wbTimer_toXML() { + return wbTimer_toXML(_timer); +} + +wbTimer_t wbTimer_new(void) { + wbTimer_t timer = wbNew(struct st_wbTimer_t); + wbTimer_setLength(timer, 0); + wbTimer_setHead(timer, NULL); + wbTimer_setTail(timer, NULL); + wbTimer_setStartTime(timer, getTime()); + wbTimer_setEndTime(timer, 0); + wbTimer_setElapsedTime(timer, 0); + + return timer; +} + +static inline wbTimerNode_t _findParent(wbTimer_t timer) { + wbTimerNode_t iter; + + for (iter = wbTimer_getTail(timer); iter != NULL; + iter = wbTimerNode_getPrevious(iter)) { + if (!wbTimerNode_stoppedQ(iter)) { + return iter; + } + } + return NULL; +} + +static inline void _insertIntoList(wbTimer_t timer, wbTimerNode_t node) { + if (wbTimer_emptyQ(timer)) { + wbTimer_setHead(timer, node); + wbTimer_setTail(timer, node); + } else { + wbTimerNode_t end = wbTimer_getTail(timer); + wbTimer_setTail(timer, node); + wbTimerNode_setNext(end, node); + wbTimerNode_setPrevious(node, end); + } + wbTimer_incrementLength(timer); +} + +wbTimerNode_t wbTimer_start(wbTimerKind_t kind, const char *file, + const char *fun, int line) { + int id; + uint64_t currentTime; + wbTimerNode_t node; + wbTimerNode_t parent; + + wb_init(NULL, NULL); + + currentTime = getTime(); + + id = wbTimer_getLength(_timer); + + node = wbTimerNode_new(id, kind, file, fun, line); + + parent = _findParent(_timer); + _insertIntoList(_timer, node); + + wbTimerNode_setStartTime(node, currentTime); + wbTimerNode_setParent(node, parent); + if (parent != NULL) { + wbTimerNode_setLevel(node, wbTimerNode_getLevel(parent) + 1); + } + + return node; +} + +wbTimerNode_t wbTimer_start(wbTimerKind_t kind, string msg, + const char *file, const char *fun, int line) { + wbTimerNode_t node = wbTimer_start(kind, file, fun, line); + wbTimerNode_setMessage(node, wbString_duplicate(msg)); + return node; +} + +static inline wbTimerNode_t _findNode(wbTimer_t timer, wbTimerKind_t kind, + string msg) { + wbTimerNode_t iter; + + for (iter = wbTimer_getTail(timer); iter != NULL; + iter = wbTimerNode_getPrevious(iter)) { + if (msg == "") { + if (!wbTimerNode_stoppedQ(iter) && + wbTimerNode_getKind(iter) == kind) { + return iter; + } + } else { + if (!wbTimerNode_stoppedQ(iter) && + wbTimerNode_getKind(iter) == kind && + msg == wbTimerNode_getMessage(iter)) { + return iter; + } + } + } + return NULL; +} + +void wbTimer_stop(wbTimerKind_t kind, string msg, const char *file, + const char *fun, int line) { + uint64_t currentTime; + wbTimerNode_t node; + + currentTime = getTime(); + + node = _findNode(_timer, kind, msg); + + wbAssert(node != NULL); + if (node == NULL) { + return; + } + + wbTimerNode_setEndTime(node, currentTime); + wbTimerNode_setElapsedTime(node, + currentTime - wbTimerNode_getStartTime(node)); + wbTimerNode_setEndLine(node, line); + wbTimerNode_setEndFunction(node, fun); + wbTimerNode_setEndFile(node, file); + wbTimerNode_setStoppedQ(node, wbTrue); + +#ifdef wbLogger_printOnLog + if (wbLogger_printOnLog) { + json11::Json json = json11::Json::object{ +//PMO +#ifndef _MSC_VER + { "type", "timer" }, { "data", wbTimerNode_toJSONObject(node) }}; +#else + { "data", wbTimerNode_toJSONObject(node) }, { "type", "timer" }}; +#endif + std::cout << json.dump() << std::endl; + } +#endif /* wbLogger_printOnLog */ + return; +} + +void wbTimer_stop(wbTimerKind_t kind, const char *file, const char *fun, + int line) { + wbTimer_stop(kind, "", file, fun, line); +} diff --git a/CUDA_ListScan/libwb/wbTimer.h b/CUDA_ListScan/libwb/wbTimer.h new file mode 100644 index 0000000..133b58f --- /dev/null +++ b/CUDA_ListScan/libwb/wbTimer.h @@ -0,0 +1,139 @@ + + +#ifndef __WB_TIMER_H__ +#define __WB_TIMER_H__ + +#ifdef WB_USE_WINDOWS +extern uint64_t _hrtime_frequency; +#endif /* _WIN32 */ + +extern wbTimer_t _timer; + +typedef enum en_wbTimerKind_t { + wbTimerKind_Generic, + wbTimerKind_IO, + wbTimerKind_GPU, + wbTimerKind_Copy, + wbTimerKind_Driver, + wbTimerKind_CopyAsync, + wbTimerKind_Compute, + wbTimerKind_CPUGPUOverlap, +} wbTimerKind_t; + +struct st_wbTimerNode_t { + int id; + int mpiRank; + int level; + wbBool stoppedQ; + wbTimerKind_t kind; + uint64_t startTime; + uint64_t endTime; + uint64_t elapsedTime; + int startLine; + int endLine; + const char *startFunction; + const char *endFunction; + const char *startFile; + const char *endFile; + wbTimerNode_t next; + wbTimerNode_t prev; + wbTimerNode_t parent; + char *msg; +}; + +struct st_wbTimer_t { + size_t length; + wbTimerNode_t head; + wbTimerNode_t tail; + uint64_t startTime; + uint64_t endTime; + uint64_t elapsedTime; +}; + +#define wbTimerNode_getId(node) ((node)->id) +#define wbTimerNode_getMPIRank(node) ((node)->mpiRank) +#define wbTimerNode_getLevel(node) ((node)->level) +#define wbTimerNode_getStoppedQ(node) ((node)->stoppedQ) +#define wbTimerNode_getKind(node) ((node)->kind) +#define wbTimerNode_getStartTime(node) ((node)->startTime) +#define wbTimerNode_getEndTime(node) ((node)->endTime) +#define wbTimerNode_getElapsedTime(node) ((node)->elapsedTime) +#define wbTimerNode_getStartLine(node) ((node)->startLine) +#define wbTimerNode_getEndLine(node) ((node)->endLine) +#define wbTimerNode_getStartFunction(node) ((node)->startFunction) +#define wbTimerNode_getEndFunction(node) ((node)->endFunction) +#define wbTimerNode_getStartFile(node) ((node)->startFile) +#define wbTimerNode_getEndFile(node) ((node)->endFile) +#define wbTimerNode_getNext(node) ((node)->next) +#define wbTimerNode_getPrevious(node) ((node)->prev) +#define wbTimerNode_getParent(node) ((node)->parent) +#define wbTimerNode_getMessage(node) ((node)->msg) + +#define wbTimerNode_setId(node, val) (wbTimerNode_getId(node) = val) +#define wbTimerNode_setMPIRank(node, val) \ + (wbTimerNode_getMPIRank(node) = val) +#define wbTimerNode_setLevel(node, val) (wbTimerNode_getLevel(node) = val) +#define wbTimerNode_setStoppedQ(node, val) \ + (wbTimerNode_getStoppedQ(node) = val) +#define wbTimerNode_setKind(node, val) (wbTimerNode_getKind(node) = val) +#define wbTimerNode_setStartTime(node, val) \ + (wbTimerNode_getStartTime(node) = val) +#define wbTimerNode_setEndTime(node, val) \ + (wbTimerNode_getEndTime(node) = val) +#define wbTimerNode_setElapsedTime(node, val) \ + (wbTimerNode_getElapsedTime(node) = val) +#define wbTimerNode_setStartLine(node, val) \ + (wbTimerNode_getStartLine(node) = val) +#define wbTimerNode_setEndLine(node, val) \ + (wbTimerNode_getEndLine(node) = val) +#define wbTimerNode_setStartFunction(node, val) \ + (wbTimerNode_getStartFunction(node) = val) +#define wbTimerNode_setEndFunction(node, val) \ + (wbTimerNode_getEndFunction(node) = val) +#define wbTimerNode_setStartFile(node, val) \ + (wbTimerNode_getStartFile(node) = val) +#define wbTimerNode_setEndFile(node, val) \ + (wbTimerNode_getEndFile(node) = val) +#define wbTimerNode_setNext(node, val) (wbTimerNode_getNext(node) = val) +#define wbTimerNode_setPrevious(node, val) \ + (wbTimerNode_getPrevious(node) = val) +#define wbTimerNode_setParent(node, val) \ + (wbTimerNode_getParent(node) = val) +#define wbTimerNode_setMessage(node, val) \ + (wbTimerNode_getMessage(node) = val) + +#define wbTimerNode_stoppedQ(node) \ + (wbTimerNode_getStoppedQ(node) == wbTrue) +#define wbTimerNode_hasNext(node) (wbTimerNode_getNext(node) != NULL) +#define wbTimerNode_hasPrevious(node) \ + (wbTimerNode_getPrevious(node) != NULL) +#define wbTimerNode_hasParent(node) (wbTimerNode_getParent(node) != NULL) + +uint64_t _hrtime(void); + +wbTimer_t wbTimer_new(void); +void wbTimer_delete(wbTimer_t timer); + +string wbTimer_toJSON(wbTimer_t timer); +string wbTimer_toJSON(); + +string wbTimer_toXML(wbTimer_t timer); +string wbTimer_toXML(); + +wbTimerNode_t wbTimer_start(wbTimerKind_t kind, const char *file, + const char *fun, int line); +wbTimerNode_t wbTimer_start(wbTimerKind_t kind, string msg, + const char *file, const char *fun, int line); +void wbTimer_stop(wbTimerKind_t kind, string msg, const char *file, + const char *fun, int line); +void wbTimer_stop(wbTimerKind_t kind, const char *file, const char *fun, + int line); + +#define wbTime_start(kind, ...) \ + wbTimer_start(wbTimerKind_##kind, wbString(__VA_ARGS__), wbFile, \ + wbFunction, wbLine) +#define wbTime_stop(kind, ...) \ + wbTimer_stop(wbTimerKind_##kind, wbString(__VA_ARGS__), wbFile, \ + wbFunction, wbLine) + +#endif /* __WB_TIMER_H__ */ diff --git a/CUDA_ListScan/libwb/wbTypes.h b/CUDA_ListScan/libwb/wbTypes.h new file mode 100644 index 0000000..6837792 --- /dev/null +++ b/CUDA_ListScan/libwb/wbTypes.h @@ -0,0 +1,55 @@ + + +#ifndef __WB_TYPES_H__ +#define __WB_TYPES_H__ + +#include "wbAssert.h" + +typedef bool wbBool; +typedef float wbReal_t; +typedef char wbChar_t; + +typedef struct st_wbTimerNode_t *wbTimerNode_t; +typedef struct st_wbTimer_t *wbTimer_t; +typedef struct st_wbLogEntry_t *wbLogEntry_t; +typedef struct st_wbLogger_t *wbLogger_t; +typedef struct st_wbArg_t wbArg_t; +typedef struct st_wbImage_t *wbImage_t; +typedef struct st_wbFile_t *wbFile_t; + +#define wbTrue true +#define wbFalse false + +typedef enum en_wbType_t { + wbType_unknown = -1, + wbType_ascii = 1, + wbType_bit8, + wbType_ubit8, + wbType_integer, + wbType_float, + wbType_double +} wbType_t; + +static inline size_t wbType_size(wbType_t ty) { + switch (ty) { + case wbType_unknown: + wbAssert(false && "Invalid wbType_unknown"); + return 0; + case wbType_ascii: + return sizeof(char); + case wbType_bit8: + return sizeof(char); + case wbType_ubit8: + return sizeof(unsigned char); + case wbType_integer: + return sizeof(int); + case wbType_float: + return sizeof(float); + case wbType_double: + return sizeof(double); + } + wbAssert(false && "Invalid type"); + return 0; +} + +#endif /* __WB_TYPES_H__ */ diff --git a/CUDA_ListScan/libwb/wbUtils.h b/CUDA_ListScan/libwb/wbUtils.h new file mode 100644 index 0000000..cbd1b91 --- /dev/null +++ b/CUDA_ListScan/libwb/wbUtils.h @@ -0,0 +1,10 @@ +#ifndef __WB_UTILS_H__ +#define __WB_UTILS_H__ + +#ifdef WB_DEBUG +#define DEBUG(...) __VA_ARGS__ +#else /* WB_DEBUG */ +#define DEBUG(...) +#endif /* WB_DEBUG */ + +#endif /* __WB_UTILS_H__ */ diff --git a/CUDA_ListScan/libwb/wb_test.cpp b/CUDA_ListScan/libwb/wb_test.cpp new file mode 100644 index 0000000..87883c8 --- /dev/null +++ b/CUDA_ListScan/libwb/wb_test.cpp @@ -0,0 +1,4 @@ +#define CATCH_CONFIG_MAIN + +#include "wb.h" +#include "vendor/catch.hpp" diff --git a/CUDA_TiledMatrixMultiplication/TiledMatrixMultiplication/template.cu b/CUDA_TiledMatrixMultiplication/TiledMatrixMultiplication/template.cu new file mode 100644 index 0000000..da55b01 --- /dev/null +++ b/CUDA_TiledMatrixMultiplication/TiledMatrixMultiplication/template.cu @@ -0,0 +1,154 @@ +#include + +#define wbCheck(stmt) \ + do { \ + cudaError_t err = stmt; \ + if (err != cudaSuccess) { \ + wbLog(ERROR, "Failed to run stmt ", #stmt); \ + wbLog(ERROR, "Got CUDA error ... ", cudaGetErrorString(err)); \ + return -1; \ + } \ + } while (0) + +#define TILE_WIDTH 16 + +// Compute C = A * B +__global__ void matrixMultiplyShared(float *A, float *B, float *C, int numARows, int numAColumns, int numBRows, int numBColumns, int numCRows, int numCColumns) { + + //@@finding matrix dimension and matching with thread and matrix element + int bx = blockIdx.x; int by = blockIdx.y; + int tx = threadIdx.x; int ty = threadIdx.y; + + int Row = blockIdx.y * TILE_WIDTH + threadIdx.y; + int Col = blockIdx.x * TILE_WIDTH + threadIdx.x; + float Pvalue = 0; + + //@@declaring shared memory + __shared__ float ds_M[TILE_WIDTH][TILE_WIDTH]; + __shared__ float ds_N[TILE_WIDTH][TILE_WIDTH]; + + for (int p = 0; p < ((numAColumns - 1) / TILE_WIDTH + 1); ++p) { + + if (Row < numARows && p * TILE_WIDTH + tx < numAColumns) { + ds_M[ty][tx] = A[Row * numAColumns + p * TILE_WIDTH + tx]; + } else { + ds_M[ty][tx] = 0.0; + } + + if (p * TILE_WIDTH + ty < numBRows && Col < numBColumns){ + ds_N[ty][tx] = B[(p * TILE_WIDTH + ty) * numBColumns + Col]; + } else { + ds_N[ty][tx] = 0.0; + } + + __syncthreads(); //@@to keep track the shared memory as if all threads can be done at same time + if (Row < numCRows && Col < numCColumns){ + for (int i = 0; i < TILE_WIDTH; ++i) { + Pvalue += ds_M[ty][i] * ds_N[i][tx]; + } + __syncthreads(); + } + } + + if (Row < numCRows && Col < numCColumns) { + C[Row * numCColumns + Col] = Pvalue; + } +} + +int main(int argc, char **argv) { + wbArg_t args; + float *hostA; // The A matrix + float *hostB; // The B matrix + float *hostC; // The output C matrix + float *deviceA; + float *deviceB; + float *deviceC; + int numARows; // number of rows in the matrix A + int numAColumns; // number of columns in the matrix A + int numBRows; // number of rows in the matrix B + int numBColumns; // number of columns in the matrix B + int numCRows; // number of rows in the matrix C + int numCColumns; // number of columns in the matrix C + + int sizeA, sizeB, sizeC; + + hostC = NULL; + + args = wbArg_read(argc, argv); + + wbTime_start(Generic, "Importing data and creating memory on host"); + hostA = (float *)wbImport(wbArg_getInputFile(args, 0), &numARows, + &numAColumns); + hostB = (float *)wbImport(wbArg_getInputFile(args, 1), &numBRows, + &numBColumns); + //@@ Set numCRows and numCColumns + numCRows = numARows; + numCColumns = numBColumns; + + sizeA = numARows * numAColumns * sizeof(float); + sizeB = numBRows * numBColumns * sizeof(float); + sizeC = numCRows * numCColumns * sizeof(float); + + //@@ Allocate the hostC matrix + + hostC = (float*) malloc(sizeC); + + wbTime_stop(Generic, "Importing data and creating memory on host"); + + wbLog(TRACE, "The dimensions of A are ", numARows, " x ", numAColumns); + wbLog(TRACE, "The dimensions of B are ", numBRows, " x ", numBColumns); + + wbTime_start(GPU, "Allocating GPU memory."); + //@@ Allocate GPU memory + + wbCheck(cudaMalloc((void**) &deviceA, sizeA)); + wbCheck(cudaMalloc((void**) &deviceB, sizeB)); + wbCheck(cudaMalloc((void**) &deviceC, sizeC)); + + wbTime_stop(GPU, "Allocating GPU memory."); + + wbTime_start(GPU, "Copying input memory to the GPU."); + //@@ Copy memory to the GPU + + wbCheck(cudaMemcpy(deviceA, hostA, sizeA, cudaMemcpyHostToDevice)); + wbCheck(cudaMemcpy(deviceB, hostB, sizeB, cudaMemcpyHostToDevice)); + + wbTime_stop(GPU, "Copying input memory to the GPU."); + + //@@ Initialize the grid and block dimensions + + dim3 dimBlock(TILE_WIDTH, TILE_WIDTH, 1); + dim3 dimGrid(numBColumns / TILE_WIDTH, numARows / TILE_WIDTH, 1); + + wbTime_start(Compute, "Performing CUDA computation"); + //@@ Launch the GPU Kernel + + matrixMultiplyShared<<>>(deviceA, deviceB, deviceC, numARows, numAColumns, numBRows, numBColumns, numCRows, numCColumns); + + wbCheck(cudaDeviceSynchronize()); + wbTime_stop(Compute, "Performing CUDA computation"); + + wbTime_start(Copy, "Copying output memory to the CPU"); + //@@ Copy the GPU memory back to the CPU + + wbCheck(cudaMemcpy(hostC, deviceC, sizeC, cudaMemcpyDeviceToHost)); + + wbTime_stop(Copy, "Copying output memory to the CPU"); + + wbTime_start(GPU, "Freeing GPU Memory"); + //@@ Free the GPU memory + + wbCheck(cudaFree(deviceA)); + wbCheck(cudaFree(deviceB)); + wbCheck(cudaFree(deviceC)); + + wbTime_stop(GPU, "Freeing GPU Memory"); + + wbSolution(args, hostC, numCRows, numCColumns); + + free(hostA); + free(hostB); + free(hostC); + + return 0; +} diff --git a/CUDA_TiledMatrixMultiplication/libwb/.clang-format b/CUDA_TiledMatrixMultiplication/libwb/.clang-format new file mode 100644 index 0000000..4757ed4 --- /dev/null +++ b/CUDA_TiledMatrixMultiplication/libwb/.clang-format @@ -0,0 +1,21 @@ +--- +Language: Cpp +BasedOnStyle: LLVM +ColumnLimit: 75 +AccessModifierOffset: -2 +BreakBeforeBraces: Attach +AlignTrailingComments: true +AlignEscapedNewlinesLeft: false +AlignConsecutiveAssignments: true +AlignOperands: true +AllowShortFunctionsOnASingleLine: false +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AlwaysBreakTemplateDeclarations: true +IndentCaseLabels: true +SpacesBeforeTrailingComments: 1 +Standard: Cpp11 +TabWidth: 4 +UseTab: Never +SortIncludes: false +... diff --git a/CUDA_TiledMatrixMultiplication/libwb/.travis.yml b/CUDA_TiledMatrixMultiplication/libwb/.travis.yml new file mode 100644 index 0000000..e32c621 --- /dev/null +++ b/CUDA_TiledMatrixMultiplication/libwb/.travis.yml @@ -0,0 +1,65 @@ +# Use new trusty images, should yield newer compilers and packages +sudo: required +dist: precise +language: cpp + +matrix: + include: + - compiler: gcc + addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - g++-4.9 + env: COMPILER=g++-4.9 + - compiler: gcc + addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - g++-5 + env: COMPILER=g++-5 + - compiler: clang + addons: + apt: + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-precise-3.6 + packages: + - clang-3.6 + env: COMPILER=clang++-3.6 + - compiler: clang + addons: + apt: + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-precise-3.7 + packages: + - clang-3.7 + env: COMPILER=clang++-3.7 +# - compiler: gcc +# addons: +# apt: +# sources: +# - ubuntu-toolchain-r-test +# packages: +# - g++-6 +# env: COMPILER=g++-6 + # - compiler: clang + # addons: + # apt: + # sources: + # - ubuntu-toolchain-r-test + # - llvm-toolchain-precise-3.8 + # packages: + # - clang-3.8 + # env: COMPILER=clang++-3.8 + +before_install: + - sudo apt-get update -qq +script: + - $COMPILER --version + - make CXX=$COMPILER test + - ./test diff --git a/CUDA_TiledMatrixMultiplication/libwb/CMakeLists.txt b/CUDA_TiledMatrixMultiplication/libwb/CMakeLists.txt new file mode 100644 index 0000000..f732c32 --- /dev/null +++ b/CUDA_TiledMatrixMultiplication/libwb/CMakeLists.txt @@ -0,0 +1,34 @@ +cmake_minimum_required(VERSION 2.8 FATAL_ERROR) + +set(CMAKE_BUILD_TYPE Release) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) +set(CMAKE_COLOR_MAKEFILE ON) +set(VERBOSE_BUILD ON) +set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) +set(CMAKE_MACOSX_RPATH TRUE) +set_property(GLOBAL PROPERTY USE_FOLDERS ON) + + +project(wb) + +set(current_dir "${CMAKE_CURRENT_SOURCE_DIR}") + +if(NOT EXISTS "${CMAKE_CURRENT_BINARY_DIR}/cotire.cmake") + file(DOWNLOAD "https://raw.githubusercontent.com/sakra/cotire/master/CMake/cotire.cmake" "${CMAKE_CURRENT_BINARY_DIR}/cotire.cmake") +endif() + + + +include(${current_dir}/sources.cmake) + +set(WBLIB_STATIC ${WBLIB}) +set(WBLIB_SHARED lib${WBLIB}) + +add_library(${WBLIB_STATIC} STATIC ${LIBWB_SOURCE_FILES} ) +add_library(${WBLIB_SHARED} SHARED ${LIBWB_SOURCE_FILES} ) +set_property(TARGET ${WBLIB_STATIC} PROPERTY CXX_STANDARD 11) +set_property(TARGET ${WBLIB_SHARED} PROPERTY CXX_STANDARD 11) +if (UNIX) + set_target_properties(${WBLIB_SHARED} PROPERTIES OUTPUT_NAME ${WBLIB_STATIC}) +endif (UNIX) +set_property(TARGET ${WBLIB} PROPERTY CXX_STANDARD 11) diff --git a/CUDA_TiledMatrixMultiplication/libwb/LICENSE.TXT b/CUDA_TiledMatrixMultiplication/libwb/LICENSE.TXT new file mode 100644 index 0000000..8df244d --- /dev/null +++ b/CUDA_TiledMatrixMultiplication/libwb/LICENSE.TXT @@ -0,0 +1,36 @@ +Copyright (c) 2016, Abdul Dakkak All rights reserved. + +Developed by: Abdul Dakkak + IMPACT Group + University of Illinois, Urbana-Champaign + impact.crhc.illinois.edu + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal with the +Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, +sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +Redistributions of source code must retain the above +copyright notice, this list of conditions and the following +disclaimers. +Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following +disclaimers in the documentation and/or other materials +provided with the distribution. +Neither the names of Abdul Dakkak, Impact Group, nor the +names of its contributors may be used to endorse or promote +products derived from this Software without specific prior +written permission. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +WITH THE SOFTWARE. diff --git a/CUDA_TiledMatrixMultiplication/libwb/Makefile b/CUDA_TiledMatrixMultiplication/libwb/Makefile new file mode 100644 index 0000000..b8a72d7 --- /dev/null +++ b/CUDA_TiledMatrixMultiplication/libwb/Makefile @@ -0,0 +1,56 @@ +########################################## +# Options +########################################## +WB_LIB_PATH=$(CURDIR)/lib +WB_SRC_PATH=$(CURDIR) + +########################################## +########################################## + +DEFINES= +CXX_FLAGS=-fPIC -Wno-unused-function -x c++ -O3 -g -std=c++11 -Wall -Wno-unused-function -pedantic -I . -I $(WB_SRC_PATH) $(DEFINES) +LIBS=-lm -lstdc++ + +########################################## +########################################## + +UNAME_S := $(shell uname -s) +ifeq ($(UNAME_S),Linux) + LIBS += -lrt +endif + +########################################## +########################################## + +SOURCES := $(shell find $(WB_SRC_PATH) ! -name "*_test.cpp" -name "*.cpp") +TESTS := $(shell find $(WB_SRC_PATH) -name "*_test.cpp") + +OBJECTS = $(SOURCES:.cpp=.o) +TESTOBJECTS = $(TESTS:.cpp=.o) + +############################################## +# OUTPUT +############################################## + +.PHONY: all +.SUFFIXES: .o .cpp +all: libwb.so + +.cpp.o: + $(CXX) $(DEFINES) $(CXX_FLAGS) -c -o $@ $< + +libwb.so: $(OBJECTS) + mkdir -p $(WB_LIB_PATH) + $(CXX) -fPIC -shared -o $(WB_LIB_PATH)/$@ $(OBJECTS) $(LIBS) + +libwb.a: $(OBJECTS) + mkdir -p $(WB_LIB_PATH) + ar rcs -o $(WB_LIB_PATH)/$@ $(OBJECTS) + +test: $(TESTOBJECTS) $(OBJECTS) + $(CXX) -fPIC -o $@ $(TESTOBJECTS) $(OBJECTS) $(LIBS) + + +clean: + rm -fr $(ARCH) + -rm -f $(EXES) *.o *~ \ No newline at end of file diff --git a/CUDA_TiledMatrixMultiplication/libwb/README.md b/CUDA_TiledMatrixMultiplication/libwb/README.md new file mode 100644 index 0000000..0486f93 --- /dev/null +++ b/CUDA_TiledMatrixMultiplication/libwb/README.md @@ -0,0 +1,7 @@ + +# libWB + +[![Travis Build Status](https://travis-ci.org/abduld/libwb.svg?branch=master)](https://travis-ci.org/abduld/libwb) +[![AppVeyor status](https://ci.appveyor.com/api/projects/status/0nx5ie7gn5c0e6ai/branch/master?svg=true)](https://ci.appveyor.com/project/abduld/libwb/branch/master) + \ No newline at end of file diff --git a/CUDA_TiledMatrixMultiplication/libwb/appveyor.yml b/CUDA_TiledMatrixMultiplication/libwb/appveyor.yml new file mode 100644 index 0000000..e7a6c95 --- /dev/null +++ b/CUDA_TiledMatrixMultiplication/libwb/appveyor.yml @@ -0,0 +1,54 @@ + + +# Operating system (build VM template) +os: + - Visual Studio 2015 + + +# scripts that are called at very beginning, before repo cloning +init: + - echo init step + - git config --global core.autocrlf input + - cmake --version + - C:\"Program Files (x86)"\"Microsoft Visual Studio 14.0"\VC\vcvarsall.bat %PLATFORM% + +# clone directory +clone_folder: c:\projects\libwb +# fetch repository as zip archive +shallow_clone: true # default is "false" + +# branches to build +branches: + # whitelist + only: + - master + +platform: + - x64 +configuration: + - Release + +environment: + P: "c:/projects/libs" + + +install: + # by default, all script lines are interpreted as batch + +build: + project: ALL_BUILD.vcxproj # path to Visual Studio solution or project + +# scripts to run before build +before_build: + - echo Running cmake... + - cd c:\projects\libwb + - cmake -G "Visual Studio 14 2015 Win64" -DCMAKE_INSTALL_PREFIX=%P% + +# after_build: +# - echo after_build step + + +# on_finish always executes regardless of passed or failed builds +# on_finish: +# - echo on_finish step +# - ps: ls \ No newline at end of file diff --git a/CUDA_TiledMatrixMultiplication/libwb/sources.cmake b/CUDA_TiledMatrixMultiplication/libwb/sources.cmake new file mode 100644 index 0000000..4ac1b10 --- /dev/null +++ b/CUDA_TiledMatrixMultiplication/libwb/sources.cmake @@ -0,0 +1,31 @@ + +set(WBLIB "wb") + +include_directories(${CMAKE_CURRENT_LIST_DIR}) + +file(GLOB THESE_CPP_FILES + ${CMAKE_CURRENT_LIST_DIR}/*.cpp +) + +file(GLOB THESE_TEST_FILES + ${CMAKE_CURRENT_LIST_DIR}/*_test.cpp +) + +list(REMOVE_ITEM THESE_CPP_FILES ${THESE_TEST_FILES}) + +file(GLOB THESE_HEADER_FILES + ${CMAKE_CURRENT_LIST_DIR}/*.h +) + +list(APPEND LIBWB_HEADER_FILES + ${THESE_HEADER_FILES} +) + +list(APPEND LIBWB_SOURCE_FILES + ${THESE_CPP_FILES} + ${CMAKE_CURRENT_LIST_DIR}/vendor/json11.cpp +) + +list(APPEND LIBWB_TEST_FILES + ${THESE_TEST_FILES} +) diff --git a/CUDA_TiledMatrixMultiplication/libwb/vendor/catch.hpp b/CUDA_TiledMatrixMultiplication/libwb/vendor/catch.hpp new file mode 100644 index 0000000..f52eebd --- /dev/null +++ b/CUDA_TiledMatrixMultiplication/libwb/vendor/catch.hpp @@ -0,0 +1,10414 @@ +/* + * Catch v1.3.6 + * Generated: 2016-03-11 18:30:42.852700 + * ---------------------------------------------------------- + * This file has been merged from multiple headers. Please don't edit it directly + * Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved. + * + * Distributed under the Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + */ +#ifndef TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED +#define TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED + +#define TWOBLUECUBES_CATCH_HPP_INCLUDED + +#ifdef __clang__ +# pragma clang system_header +#elif defined __GNUC__ +# pragma GCC system_header +#endif + +// #included from: internal/catch_suppress_warnings.h + +#ifdef __clang__ +# ifdef __ICC // icpc defines the __clang__ macro +# pragma warning(push) +# pragma warning(disable: 161 1682) +# else // __ICC +# pragma clang diagnostic ignored "-Wglobal-constructors" +# pragma clang diagnostic ignored "-Wvariadic-macros" +# pragma clang diagnostic ignored "-Wc99-extensions" +# pragma clang diagnostic ignored "-Wunused-variable" +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wpadded" +# pragma clang diagnostic ignored "-Wc++98-compat" +# pragma clang diagnostic ignored "-Wc++98-compat-pedantic" +# pragma clang diagnostic ignored "-Wswitch-enum" +# pragma clang diagnostic ignored "-Wcovered-switch-default" +# endif +#elif defined __GNUC__ +# pragma GCC diagnostic ignored "-Wvariadic-macros" +# pragma GCC diagnostic ignored "-Wunused-variable" +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wpadded" +#endif +#if defined(CATCH_CONFIG_MAIN) || defined(CATCH_CONFIG_RUNNER) +# define CATCH_IMPL +#endif + +#ifdef CATCH_IMPL +# ifndef CLARA_CONFIG_MAIN +# define CLARA_CONFIG_MAIN_NOT_DEFINED +# define CLARA_CONFIG_MAIN +# endif +#endif + +// #included from: internal/catch_notimplemented_exception.h +#define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_H_INCLUDED + +// #included from: catch_common.h +#define TWOBLUECUBES_CATCH_COMMON_H_INCLUDED + +#define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line +#define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) +#define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ ) + +#define INTERNAL_CATCH_STRINGIFY2( expr ) #expr +#define INTERNAL_CATCH_STRINGIFY( expr ) INTERNAL_CATCH_STRINGIFY2( expr ) + +#include +#include +#include + +// #included from: catch_compiler_capabilities.h +#define TWOBLUECUBES_CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED + +// Detect a number of compiler features - mostly C++11/14 conformance - by compiler +// The following features are defined: +// +// CATCH_CONFIG_CPP11_NULLPTR : is nullptr supported? +// CATCH_CONFIG_CPP11_NOEXCEPT : is noexcept supported? +// CATCH_CONFIG_CPP11_GENERATED_METHODS : The delete and default keywords for compiler generated methods +// CATCH_CONFIG_CPP11_IS_ENUM : std::is_enum is supported? +// CATCH_CONFIG_CPP11_TUPLE : std::tuple is supported +// CATCH_CONFIG_CPP11_LONG_LONG : is long long supported? +// CATCH_CONFIG_CPP11_OVERRIDE : is override supported? +// CATCH_CONFIG_CPP11_UNIQUE_PTR : is unique_ptr supported (otherwise use auto_ptr) + +// CATCH_CONFIG_CPP11_OR_GREATER : Is C++11 supported? + +// CATCH_CONFIG_VARIADIC_MACROS : are variadic macros supported? + +// **************** +// Note to maintainers: if new toggles are added please document them +// in configuration.md, too +// **************** + +// In general each macro has a _NO_ form +// (e.g. CATCH_CONFIG_CPP11_NO_NULLPTR) which disables the feature. +// Many features, at point of detection, define an _INTERNAL_ macro, so they +// can be combined, en-mass, with the _NO_ forms later. + +// All the C++11 features can be disabled with CATCH_CONFIG_NO_CPP11 + +#if defined(__cplusplus) && __cplusplus >= 201103L +# define CATCH_CPP11_OR_GREATER +#endif + +#ifdef __clang__ + +# if __has_feature(cxx_nullptr) +# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR +# endif + +# if __has_feature(cxx_noexcept) +# define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT +# endif + +# if defined(CATCH_CPP11_OR_GREATER) +# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS _Pragma( "clang diagnostic ignored \"-Wparentheses\"" ) +# endif + +#endif // __clang__ + +//////////////////////////////////////////////////////////////////////////////// +// Borland +#ifdef __BORLANDC__ + +#endif // __BORLANDC__ + +//////////////////////////////////////////////////////////////////////////////// +// EDG +#ifdef __EDG_VERSION__ + +#endif // __EDG_VERSION__ + +//////////////////////////////////////////////////////////////////////////////// +// Digital Mars +#ifdef __DMC__ + +#endif // __DMC__ + +//////////////////////////////////////////////////////////////////////////////// +// GCC +#ifdef __GNUC__ + +# if __GNUC__ == 4 && __GNUC_MINOR__ >= 6 && defined(__GXX_EXPERIMENTAL_CXX0X__) +# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR +# endif + +# if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS) && defined(CATCH_CPP11_OR_GREATER) +# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS _Pragma( "GCC diagnostic ignored \"-Wparentheses\"" ) +# endif + +// - otherwise more recent versions define __cplusplus >= 201103L +// and will get picked up below + +#endif // __GNUC__ + +//////////////////////////////////////////////////////////////////////////////// +// Visual C++ +#ifdef _MSC_VER + +#if (_MSC_VER >= 1600) +# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR +# define CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR +#endif + +#if (_MSC_VER >= 1900 ) // (VC++ 13 (VS2015)) +#define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT +#define CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS +#endif + +#endif // _MSC_VER + +//////////////////////////////////////////////////////////////////////////////// + +// Use variadic macros if the compiler supports them +#if ( defined _MSC_VER && _MSC_VER > 1400 && !defined __EDGE__) || \ + ( defined __WAVE__ && __WAVE_HAS_VARIADICS ) || \ + ( defined __GNUC__ && __GNUC__ >= 3 ) || \ + ( !defined __cplusplus && __STDC_VERSION__ >= 199901L || __cplusplus >= 201103L ) + +#define CATCH_INTERNAL_CONFIG_VARIADIC_MACROS + +#endif + +//////////////////////////////////////////////////////////////////////////////// +// C++ language feature support + +// catch all support for C++11 +#if defined(CATCH_CPP11_OR_GREATER) + +# if !defined(CATCH_INTERNAL_CONFIG_CPP11_NULLPTR) +# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR +# endif + +# ifndef CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT +# define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT +# endif + +# ifndef CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS +# define CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS +# endif + +# ifndef CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM +# define CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM +# endif + +# ifndef CATCH_INTERNAL_CONFIG_CPP11_TUPLE +# define CATCH_INTERNAL_CONFIG_CPP11_TUPLE +# endif + +# ifndef CATCH_INTERNAL_CONFIG_VARIADIC_MACROS +# define CATCH_INTERNAL_CONFIG_VARIADIC_MACROS +# endif + +# if !defined(CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG) +# define CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG +# endif + +# if !defined(CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE) +# define CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE +# endif +# if !defined(CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) +# define CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR +# endif + +#endif // __cplusplus >= 201103L + +// Now set the actual defines based on the above + anything the user has configured +#if defined(CATCH_INTERNAL_CONFIG_CPP11_NULLPTR) && !defined(CATCH_CONFIG_CPP11_NO_NULLPTR) && !defined(CATCH_CONFIG_CPP11_NULLPTR) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_NULLPTR +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_CONFIG_CPP11_NO_NOEXCEPT) && !defined(CATCH_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_NOEXCEPT +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS) && !defined(CATCH_CONFIG_CPP11_NO_GENERATED_METHODS) && !defined(CATCH_CONFIG_CPP11_GENERATED_METHODS) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_GENERATED_METHODS +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM) && !defined(CATCH_CONFIG_CPP11_NO_IS_ENUM) && !defined(CATCH_CONFIG_CPP11_IS_ENUM) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_IS_ENUM +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_TUPLE) && !defined(CATCH_CONFIG_CPP11_NO_TUPLE) && !defined(CATCH_CONFIG_CPP11_TUPLE) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_TUPLE +#endif +#if defined(CATCH_INTERNAL_CONFIG_VARIADIC_MACROS) && !defined(CATCH_CONFIG_NO_VARIADIC_MACROS) && !defined(CATCH_CONFIG_VARIADIC_MACROS) +# define CATCH_CONFIG_VARIADIC_MACROS +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG) && !defined(CATCH_CONFIG_NO_LONG_LONG) && !defined(CATCH_CONFIG_CPP11_LONG_LONG) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_LONG_LONG +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE) && !defined(CATCH_CONFIG_NO_OVERRIDE) && !defined(CATCH_CONFIG_CPP11_OVERRIDE) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_OVERRIDE +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) && !defined(CATCH_CONFIG_NO_UNIQUE_PTR) && !defined(CATCH_CONFIG_CPP11_UNIQUE_PTR) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_UNIQUE_PTR +#endif + +#if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS) +# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS +#endif + +// noexcept support: +#if defined(CATCH_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_NOEXCEPT) +# define CATCH_NOEXCEPT noexcept +# define CATCH_NOEXCEPT_IS(x) noexcept(x) +#else +# define CATCH_NOEXCEPT throw() +# define CATCH_NOEXCEPT_IS(x) +#endif + +// nullptr support +#ifdef CATCH_CONFIG_CPP11_NULLPTR +# define CATCH_NULL nullptr +#else +# define CATCH_NULL NULL +#endif + +// override support +#ifdef CATCH_CONFIG_CPP11_OVERRIDE +# define CATCH_OVERRIDE override +#else +# define CATCH_OVERRIDE +#endif + +// unique_ptr support +#ifdef CATCH_CONFIG_CPP11_UNIQUE_PTR +# define CATCH_AUTO_PTR( T ) std::unique_ptr +#else +# define CATCH_AUTO_PTR( T ) std::auto_ptr +#endif + +namespace Catch { + + struct IConfig; + + struct CaseSensitive { enum Choice { + Yes, + No + }; }; + + class NonCopyable { +#ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + NonCopyable( NonCopyable const& ) = delete; + NonCopyable( NonCopyable && ) = delete; + NonCopyable& operator = ( NonCopyable const& ) = delete; + NonCopyable& operator = ( NonCopyable && ) = delete; +#else + NonCopyable( NonCopyable const& info ); + NonCopyable& operator = ( NonCopyable const& ); +#endif + + protected: + NonCopyable() {} + virtual ~NonCopyable(); + }; + + class SafeBool { + public: + typedef void (SafeBool::*type)() const; + + static type makeSafe( bool value ) { + return value ? &SafeBool::trueValue : 0; + } + private: + void trueValue() const {} + }; + + template + inline void deleteAll( ContainerT& container ) { + typename ContainerT::const_iterator it = container.begin(); + typename ContainerT::const_iterator itEnd = container.end(); + for(; it != itEnd; ++it ) + delete *it; + } + template + inline void deleteAllValues( AssociativeContainerT& container ) { + typename AssociativeContainerT::const_iterator it = container.begin(); + typename AssociativeContainerT::const_iterator itEnd = container.end(); + for(; it != itEnd; ++it ) + delete it->second; + } + + bool startsWith( std::string const& s, std::string const& prefix ); + bool endsWith( std::string const& s, std::string const& suffix ); + bool contains( std::string const& s, std::string const& infix ); + void toLowerInPlace( std::string& s ); + std::string toLower( std::string const& s ); + std::string trim( std::string const& str ); + bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ); + + struct pluralise { + pluralise( std::size_t count, std::string const& label ); + + friend std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ); + + std::size_t m_count; + std::string m_label; + }; + + struct SourceLineInfo { + + SourceLineInfo(); + SourceLineInfo( char const* _file, std::size_t _line ); + SourceLineInfo( SourceLineInfo const& other ); +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + SourceLineInfo( SourceLineInfo && ) = default; + SourceLineInfo& operator = ( SourceLineInfo const& ) = default; + SourceLineInfo& operator = ( SourceLineInfo && ) = default; +# endif + bool empty() const; + bool operator == ( SourceLineInfo const& other ) const; + bool operator < ( SourceLineInfo const& other ) const; + + std::string file; + std::size_t line; + }; + + std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ); + + // This is just here to avoid compiler warnings with macro constants and boolean literals + inline bool isTrue( bool value ){ return value; } + inline bool alwaysTrue() { return true; } + inline bool alwaysFalse() { return false; } + + void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo ); + + void seedRng( IConfig const& config ); + unsigned int rngSeed(); + + // Use this in variadic streaming macros to allow + // >> +StreamEndStop + // as well as + // >> stuff +StreamEndStop + struct StreamEndStop { + std::string operator+() { + return std::string(); + } + }; + template + T const& operator + ( T const& value, StreamEndStop ) { + return value; + } +} + +#define CATCH_INTERNAL_LINEINFO ::Catch::SourceLineInfo( __FILE__, static_cast( __LINE__ ) ) +#define CATCH_INTERNAL_ERROR( msg ) ::Catch::throwLogicError( msg, CATCH_INTERNAL_LINEINFO ); + +#include + +namespace Catch { + + class NotImplementedException : public std::exception + { + public: + NotImplementedException( SourceLineInfo const& lineInfo ); + NotImplementedException( NotImplementedException const& ) {} + + virtual ~NotImplementedException() CATCH_NOEXCEPT {} + + virtual const char* what() const CATCH_NOEXCEPT; + + private: + std::string m_what; + SourceLineInfo m_lineInfo; + }; + +} // end namespace Catch + +/////////////////////////////////////////////////////////////////////////////// +#define CATCH_NOT_IMPLEMENTED throw Catch::NotImplementedException( CATCH_INTERNAL_LINEINFO ) + +// #included from: internal/catch_context.h +#define TWOBLUECUBES_CATCH_CONTEXT_H_INCLUDED + +// #included from: catch_interfaces_generators.h +#define TWOBLUECUBES_CATCH_INTERFACES_GENERATORS_H_INCLUDED + +#include + +namespace Catch { + + struct IGeneratorInfo { + virtual ~IGeneratorInfo(); + virtual bool moveNext() = 0; + virtual std::size_t getCurrentIndex() const = 0; + }; + + struct IGeneratorsForTest { + virtual ~IGeneratorsForTest(); + + virtual IGeneratorInfo& getGeneratorInfo( std::string const& fileInfo, std::size_t size ) = 0; + virtual bool moveNext() = 0; + }; + + IGeneratorsForTest* createGeneratorsForTest(); + +} // end namespace Catch + +// #included from: catch_ptr.hpp +#define TWOBLUECUBES_CATCH_PTR_HPP_INCLUDED + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpadded" +#endif + +namespace Catch { + + // An intrusive reference counting smart pointer. + // T must implement addRef() and release() methods + // typically implementing the IShared interface + template + class Ptr { + public: + Ptr() : m_p( CATCH_NULL ){} + Ptr( T* p ) : m_p( p ){ + if( m_p ) + m_p->addRef(); + } + Ptr( Ptr const& other ) : m_p( other.m_p ){ + if( m_p ) + m_p->addRef(); + } + ~Ptr(){ + if( m_p ) + m_p->release(); + } + void reset() { + if( m_p ) + m_p->release(); + m_p = CATCH_NULL; + } + Ptr& operator = ( T* p ){ + Ptr temp( p ); + swap( temp ); + return *this; + } + Ptr& operator = ( Ptr const& other ){ + Ptr temp( other ); + swap( temp ); + return *this; + } + void swap( Ptr& other ) { std::swap( m_p, other.m_p ); } + T* get() const{ return m_p; } + T& operator*() const { return *m_p; } + T* operator->() const { return m_p; } + bool operator !() const { return m_p == CATCH_NULL; } + operator SafeBool::type() const { return SafeBool::makeSafe( m_p != CATCH_NULL ); } + + private: + T* m_p; + }; + + struct IShared : NonCopyable { + virtual ~IShared(); + virtual void addRef() const = 0; + virtual void release() const = 0; + }; + + template + struct SharedImpl : T { + + SharedImpl() : m_rc( 0 ){} + + virtual void addRef() const { + ++m_rc; + } + virtual void release() const { + if( --m_rc == 0 ) + delete this; + } + + mutable unsigned int m_rc; + }; + +} // end namespace Catch + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +#include +#include +#include + +namespace Catch { + + class TestCase; + class Stream; + struct IResultCapture; + struct IRunner; + struct IGeneratorsForTest; + struct IConfig; + + struct IContext + { + virtual ~IContext(); + + virtual IResultCapture* getResultCapture() = 0; + virtual IRunner* getRunner() = 0; + virtual size_t getGeneratorIndex( std::string const& fileInfo, size_t totalSize ) = 0; + virtual bool advanceGeneratorsForCurrentTest() = 0; + virtual Ptr getConfig() const = 0; + }; + + struct IMutableContext : IContext + { + virtual ~IMutableContext(); + virtual void setResultCapture( IResultCapture* resultCapture ) = 0; + virtual void setRunner( IRunner* runner ) = 0; + virtual void setConfig( Ptr const& config ) = 0; + }; + + IContext& getCurrentContext(); + IMutableContext& getCurrentMutableContext(); + void cleanUpContext(); + Stream createStream( std::string const& streamName ); + +} + +// #included from: internal/catch_test_registry.hpp +#define TWOBLUECUBES_CATCH_TEST_REGISTRY_HPP_INCLUDED + +// #included from: catch_interfaces_testcase.h +#define TWOBLUECUBES_CATCH_INTERFACES_TESTCASE_H_INCLUDED + +#include + +namespace Catch { + + class TestSpec; + + struct ITestCase : IShared { + virtual void invoke () const = 0; + protected: + virtual ~ITestCase(); + }; + + class TestCase; + struct IConfig; + + struct ITestCaseRegistry { + virtual ~ITestCaseRegistry(); + virtual std::vector const& getAllTests() const = 0; + virtual std::vector const& getAllTestsSorted( IConfig const& config ) const = 0; + }; + + bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ); + std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ); + std::vector const& getAllTestCasesSorted( IConfig const& config ); + +} + +namespace Catch { + +template +class MethodTestCase : public SharedImpl { + +public: + MethodTestCase( void (C::*method)() ) : m_method( method ) {} + + virtual void invoke() const { + C obj; + (obj.*m_method)(); + } + +private: + virtual ~MethodTestCase() {} + + void (C::*m_method)(); +}; + +typedef void(*TestFunction)(); + +struct NameAndDesc { + NameAndDesc( const char* _name = "", const char* _description= "" ) + : name( _name ), description( _description ) + {} + + const char* name; + const char* description; +}; + +void registerTestCase + ( ITestCase* testCase, + char const* className, + NameAndDesc const& nameAndDesc, + SourceLineInfo const& lineInfo ); + +struct AutoReg { + + AutoReg + ( TestFunction function, + SourceLineInfo const& lineInfo, + NameAndDesc const& nameAndDesc ); + + template + AutoReg + ( void (C::*method)(), + char const* className, + NameAndDesc const& nameAndDesc, + SourceLineInfo const& lineInfo ) { + + registerTestCase + ( new MethodTestCase( method ), + className, + nameAndDesc, + lineInfo ); + } + + ~AutoReg(); + +private: + AutoReg( AutoReg const& ); + void operator= ( AutoReg const& ); +}; + +void registerTestCaseFunction + ( TestFunction function, + SourceLineInfo const& lineInfo, + NameAndDesc const& nameAndDesc ); + +} // end namespace Catch + +#ifdef CATCH_CONFIG_VARIADIC_MACROS + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_TESTCASE( ... ) \ + static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )(); \ + namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( __VA_ARGS__ ) ); }\ + static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )() + + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \ + namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); } + + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, ... )\ + namespace{ \ + struct INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ) : ClassName{ \ + void test(); \ + }; \ + Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test, #ClassName, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); \ + } \ + void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test() + + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, ... ) \ + Catch::AutoReg( Function, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( __VA_ARGS__ ) ); + +#else + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_TESTCASE( Name, Desc ) \ + static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )(); \ + namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( Name, Desc ) ); }\ + static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )() + + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, Name, Desc ) \ + namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( Name, Desc ), CATCH_INTERNAL_LINEINFO ); } + + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, TestName, Desc )\ + namespace{ \ + struct INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ) : ClassName{ \ + void test(); \ + }; \ + Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test, #ClassName, Catch::NameAndDesc( TestName, Desc ), CATCH_INTERNAL_LINEINFO ); \ + } \ + void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test() + + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, Name, Desc ) \ + Catch::AutoReg( Function, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( Name, Desc ) ); +#endif + +// #included from: internal/catch_capture.hpp +#define TWOBLUECUBES_CATCH_CAPTURE_HPP_INCLUDED + +// #included from: catch_result_builder.h +#define TWOBLUECUBES_CATCH_RESULT_BUILDER_H_INCLUDED + +// #included from: catch_result_type.h +#define TWOBLUECUBES_CATCH_RESULT_TYPE_H_INCLUDED + +namespace Catch { + + // ResultWas::OfType enum + struct ResultWas { enum OfType { + Unknown = -1, + Ok = 0, + Info = 1, + Warning = 2, + + FailureBit = 0x10, + + ExpressionFailed = FailureBit | 1, + ExplicitFailure = FailureBit | 2, + + Exception = 0x100 | FailureBit, + + ThrewException = Exception | 1, + DidntThrowException = Exception | 2, + + FatalErrorCondition = 0x200 | FailureBit + + }; }; + + inline bool isOk( ResultWas::OfType resultType ) { + return ( resultType & ResultWas::FailureBit ) == 0; + } + inline bool isJustInfo( int flags ) { + return flags == ResultWas::Info; + } + + // ResultDisposition::Flags enum + struct ResultDisposition { enum Flags { + Normal = 0x01, + + ContinueOnFailure = 0x02, // Failures fail test, but execution continues + FalseTest = 0x04, // Prefix expression with ! + SuppressFail = 0x08 // Failures are reported but do not fail the test + }; }; + + inline ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs ) { + return static_cast( static_cast( lhs ) | static_cast( rhs ) ); + } + + inline bool shouldContinueOnFailure( int flags ) { return ( flags & ResultDisposition::ContinueOnFailure ) != 0; } + inline bool isFalseTest( int flags ) { return ( flags & ResultDisposition::FalseTest ) != 0; } + inline bool shouldSuppressFailure( int flags ) { return ( flags & ResultDisposition::SuppressFail ) != 0; } + +} // end namespace Catch + +// #included from: catch_assertionresult.h +#define TWOBLUECUBES_CATCH_ASSERTIONRESULT_H_INCLUDED + +#include + +namespace Catch { + + struct AssertionInfo + { + AssertionInfo() {} + AssertionInfo( std::string const& _macroName, + SourceLineInfo const& _lineInfo, + std::string const& _capturedExpression, + ResultDisposition::Flags _resultDisposition ); + + std::string macroName; + SourceLineInfo lineInfo; + std::string capturedExpression; + ResultDisposition::Flags resultDisposition; + }; + + struct AssertionResultData + { + AssertionResultData() : resultType( ResultWas::Unknown ) {} + + std::string reconstructedExpression; + std::string message; + ResultWas::OfType resultType; + }; + + class AssertionResult { + public: + AssertionResult(); + AssertionResult( AssertionInfo const& info, AssertionResultData const& data ); + ~AssertionResult(); +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + AssertionResult( AssertionResult const& ) = default; + AssertionResult( AssertionResult && ) = default; + AssertionResult& operator = ( AssertionResult const& ) = default; + AssertionResult& operator = ( AssertionResult && ) = default; +# endif + + bool isOk() const; + bool succeeded() const; + ResultWas::OfType getResultType() const; + bool hasExpression() const; + bool hasMessage() const; + std::string getExpression() const; + std::string getExpressionInMacro() const; + bool hasExpandedExpression() const; + std::string getExpandedExpression() const; + std::string getMessage() const; + SourceLineInfo getSourceInfo() const; + std::string getTestMacroName() const; + + protected: + AssertionInfo m_info; + AssertionResultData m_resultData; + }; + +} // end namespace Catch + +// #included from: catch_matchers.hpp +#define TWOBLUECUBES_CATCH_MATCHERS_HPP_INCLUDED + +namespace Catch { +namespace Matchers { + namespace Impl { + + namespace Generic { + template class AllOf; + template class AnyOf; + template class Not; + } + + template + struct Matcher : SharedImpl + { + typedef ExpressionT ExpressionType; + + virtual ~Matcher() {} + virtual Ptr clone() const = 0; + virtual bool match( ExpressionT const& expr ) const = 0; + virtual std::string toString() const = 0; + + Generic::AllOf operator && ( Matcher const& other ) const; + Generic::AnyOf operator || ( Matcher const& other ) const; + Generic::Not operator ! () const; + }; + + template + struct MatcherImpl : Matcher { + + virtual Ptr > clone() const { + return Ptr >( new DerivedT( static_cast( *this ) ) ); + } + }; + + namespace Generic { + template + class Not : public MatcherImpl, ExpressionT> { + public: + explicit Not( Matcher const& matcher ) : m_matcher(matcher.clone()) {} + Not( Not const& other ) : m_matcher( other.m_matcher ) {} + + virtual bool match( ExpressionT const& expr ) const CATCH_OVERRIDE { + return !m_matcher->match( expr ); + } + + virtual std::string toString() const CATCH_OVERRIDE { + return "not " + m_matcher->toString(); + } + private: + Ptr< Matcher > m_matcher; + }; + + template + class AllOf : public MatcherImpl, ExpressionT> { + public: + + AllOf() {} + AllOf( AllOf const& other ) : m_matchers( other.m_matchers ) {} + + AllOf& add( Matcher const& matcher ) { + m_matchers.push_back( matcher.clone() ); + return *this; + } + virtual bool match( ExpressionT const& expr ) const + { + for( std::size_t i = 0; i < m_matchers.size(); ++i ) + if( !m_matchers[i]->match( expr ) ) + return false; + return true; + } + virtual std::string toString() const { + std::ostringstream oss; + oss << "( "; + for( std::size_t i = 0; i < m_matchers.size(); ++i ) { + if( i != 0 ) + oss << " and "; + oss << m_matchers[i]->toString(); + } + oss << " )"; + return oss.str(); + } + + AllOf operator && ( Matcher const& other ) const { + AllOf allOfExpr( *this ); + allOfExpr.add( other ); + return allOfExpr; + } + + private: + std::vector > > m_matchers; + }; + + template + class AnyOf : public MatcherImpl, ExpressionT> { + public: + + AnyOf() {} + AnyOf( AnyOf const& other ) : m_matchers( other.m_matchers ) {} + + AnyOf& add( Matcher const& matcher ) { + m_matchers.push_back( matcher.clone() ); + return *this; + } + virtual bool match( ExpressionT const& expr ) const + { + for( std::size_t i = 0; i < m_matchers.size(); ++i ) + if( m_matchers[i]->match( expr ) ) + return true; + return false; + } + virtual std::string toString() const { + std::ostringstream oss; + oss << "( "; + for( std::size_t i = 0; i < m_matchers.size(); ++i ) { + if( i != 0 ) + oss << " or "; + oss << m_matchers[i]->toString(); + } + oss << " )"; + return oss.str(); + } + + AnyOf operator || ( Matcher const& other ) const { + AnyOf anyOfExpr( *this ); + anyOfExpr.add( other ); + return anyOfExpr; + } + + private: + std::vector > > m_matchers; + }; + + } // namespace Generic + + template + Generic::AllOf Matcher::operator && ( Matcher const& other ) const { + Generic::AllOf allOfExpr; + allOfExpr.add( *this ); + allOfExpr.add( other ); + return allOfExpr; + } + + template + Generic::AnyOf Matcher::operator || ( Matcher const& other ) const { + Generic::AnyOf anyOfExpr; + anyOfExpr.add( *this ); + anyOfExpr.add( other ); + return anyOfExpr; + } + + template + Generic::Not Matcher::operator ! () const { + return Generic::Not( *this ); + } + + namespace StdString { + + inline std::string makeString( std::string const& str ) { return str; } + inline std::string makeString( const char* str ) { return str ? std::string( str ) : std::string(); } + + struct CasedString + { + CasedString( std::string const& str, CaseSensitive::Choice caseSensitivity ) + : m_caseSensitivity( caseSensitivity ), + m_str( adjustString( str ) ) + {} + std::string adjustString( std::string const& str ) const { + return m_caseSensitivity == CaseSensitive::No + ? toLower( str ) + : str; + + } + std::string toStringSuffix() const + { + return m_caseSensitivity == CaseSensitive::No + ? " (case insensitive)" + : ""; + } + CaseSensitive::Choice m_caseSensitivity; + std::string m_str; + }; + + struct Equals : MatcherImpl { + Equals( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) + : m_data( str, caseSensitivity ) + {} + Equals( Equals const& other ) : m_data( other.m_data ){} + + virtual ~Equals(); + + virtual bool match( std::string const& expr ) const { + return m_data.m_str == m_data.adjustString( expr );; + } + virtual std::string toString() const { + return "equals: \"" + m_data.m_str + "\"" + m_data.toStringSuffix(); + } + + CasedString m_data; + }; + + struct Contains : MatcherImpl { + Contains( std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) + : m_data( substr, caseSensitivity ){} + Contains( Contains const& other ) : m_data( other.m_data ){} + + virtual ~Contains(); + + virtual bool match( std::string const& expr ) const { + return m_data.adjustString( expr ).find( m_data.m_str ) != std::string::npos; + } + virtual std::string toString() const { + return "contains: \"" + m_data.m_str + "\"" + m_data.toStringSuffix(); + } + + CasedString m_data; + }; + + struct StartsWith : MatcherImpl { + StartsWith( std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) + : m_data( substr, caseSensitivity ){} + + StartsWith( StartsWith const& other ) : m_data( other.m_data ){} + + virtual ~StartsWith(); + + virtual bool match( std::string const& expr ) const { + return startsWith( m_data.adjustString( expr ), m_data.m_str ); + } + virtual std::string toString() const { + return "starts with: \"" + m_data.m_str + "\"" + m_data.toStringSuffix(); + } + + CasedString m_data; + }; + + struct EndsWith : MatcherImpl { + EndsWith( std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) + : m_data( substr, caseSensitivity ){} + EndsWith( EndsWith const& other ) : m_data( other.m_data ){} + + virtual ~EndsWith(); + + virtual bool match( std::string const& expr ) const { + return endsWith( m_data.adjustString( expr ), m_data.m_str ); + } + virtual std::string toString() const { + return "ends with: \"" + m_data.m_str + "\"" + m_data.toStringSuffix(); + } + + CasedString m_data; + }; + } // namespace StdString + } // namespace Impl + + // The following functions create the actual matcher objects. + // This allows the types to be inferred + template + inline Impl::Generic::Not Not( Impl::Matcher const& m ) { + return Impl::Generic::Not( m ); + } + + template + inline Impl::Generic::AllOf AllOf( Impl::Matcher const& m1, + Impl::Matcher const& m2 ) { + return Impl::Generic::AllOf().add( m1 ).add( m2 ); + } + template + inline Impl::Generic::AllOf AllOf( Impl::Matcher const& m1, + Impl::Matcher const& m2, + Impl::Matcher const& m3 ) { + return Impl::Generic::AllOf().add( m1 ).add( m2 ).add( m3 ); + } + template + inline Impl::Generic::AnyOf AnyOf( Impl::Matcher const& m1, + Impl::Matcher const& m2 ) { + return Impl::Generic::AnyOf().add( m1 ).add( m2 ); + } + template + inline Impl::Generic::AnyOf AnyOf( Impl::Matcher const& m1, + Impl::Matcher const& m2, + Impl::Matcher const& m3 ) { + return Impl::Generic::AnyOf().add( m1 ).add( m2 ).add( m3 ); + } + + inline Impl::StdString::Equals Equals( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) { + return Impl::StdString::Equals( str, caseSensitivity ); + } + inline Impl::StdString::Equals Equals( const char* str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) { + return Impl::StdString::Equals( Impl::StdString::makeString( str ), caseSensitivity ); + } + inline Impl::StdString::Contains Contains( std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) { + return Impl::StdString::Contains( substr, caseSensitivity ); + } + inline Impl::StdString::Contains Contains( const char* substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) { + return Impl::StdString::Contains( Impl::StdString::makeString( substr ), caseSensitivity ); + } + inline Impl::StdString::StartsWith StartsWith( std::string const& substr ) { + return Impl::StdString::StartsWith( substr ); + } + inline Impl::StdString::StartsWith StartsWith( const char* substr ) { + return Impl::StdString::StartsWith( Impl::StdString::makeString( substr ) ); + } + inline Impl::StdString::EndsWith EndsWith( std::string const& substr ) { + return Impl::StdString::EndsWith( substr ); + } + inline Impl::StdString::EndsWith EndsWith( const char* substr ) { + return Impl::StdString::EndsWith( Impl::StdString::makeString( substr ) ); + } + +} // namespace Matchers + +using namespace Matchers; + +} // namespace Catch + +namespace Catch { + + struct TestFailureException{}; + + template class ExpressionLhs; + + struct STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison; + + struct CopyableStream { + CopyableStream() {} + CopyableStream( CopyableStream const& other ) { + oss << other.oss.str(); + } + CopyableStream& operator=( CopyableStream const& other ) { + oss.str(""); + oss << other.oss.str(); + return *this; + } + std::ostringstream oss; + }; + + class ResultBuilder { + public: + ResultBuilder( char const* macroName, + SourceLineInfo const& lineInfo, + char const* capturedExpression, + ResultDisposition::Flags resultDisposition, + char const* secondArg = "" ); + + template + ExpressionLhs operator <= ( T const& operand ); + ExpressionLhs operator <= ( bool value ); + + template + ResultBuilder& operator << ( T const& value ) { + m_stream.oss << value; + return *this; + } + + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( RhsT const& ); + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || ( RhsT const& ); + + ResultBuilder& setResultType( ResultWas::OfType result ); + ResultBuilder& setResultType( bool result ); + ResultBuilder& setLhs( std::string const& lhs ); + ResultBuilder& setRhs( std::string const& rhs ); + ResultBuilder& setOp( std::string const& op ); + + void endExpression(); + + std::string reconstructExpression() const; + AssertionResult build() const; + + void useActiveException( ResultDisposition::Flags resultDisposition = ResultDisposition::Normal ); + void captureResult( ResultWas::OfType resultType ); + void captureExpression(); + void captureExpectedException( std::string const& expectedMessage ); + void captureExpectedException( Matchers::Impl::Matcher const& matcher ); + void handleResult( AssertionResult const& result ); + void react(); + bool shouldDebugBreak() const; + bool allowThrows() const; + + private: + AssertionInfo m_assertionInfo; + AssertionResultData m_data; + struct ExprComponents { + ExprComponents() : testFalse( false ) {} + bool testFalse; + std::string lhs, rhs, op; + } m_exprComponents; + CopyableStream m_stream; + + bool m_shouldDebugBreak; + bool m_shouldThrow; + }; + +} // namespace Catch + +// Include after due to circular dependency: +// #included from: catch_expression_lhs.hpp +#define TWOBLUECUBES_CATCH_EXPRESSION_LHS_HPP_INCLUDED + +// #included from: catch_evaluate.hpp +#define TWOBLUECUBES_CATCH_EVALUATE_HPP_INCLUDED + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable:4389) // '==' : signed/unsigned mismatch +#endif + +#include + +namespace Catch { +namespace Internal { + + enum Operator { + IsEqualTo, + IsNotEqualTo, + IsLessThan, + IsGreaterThan, + IsLessThanOrEqualTo, + IsGreaterThanOrEqualTo + }; + + template struct OperatorTraits { static const char* getName(){ return "*error*"; } }; + template<> struct OperatorTraits { static const char* getName(){ return "=="; } }; + template<> struct OperatorTraits { static const char* getName(){ return "!="; } }; + template<> struct OperatorTraits { static const char* getName(){ return "<"; } }; + template<> struct OperatorTraits { static const char* getName(){ return ">"; } }; + template<> struct OperatorTraits { static const char* getName(){ return "<="; } }; + template<> struct OperatorTraits{ static const char* getName(){ return ">="; } }; + + template + inline T& opCast(T const& t) { return const_cast(t); } + +// nullptr_t support based on pull request #154 from Konstantin Baumann +#ifdef CATCH_CONFIG_CPP11_NULLPTR + inline std::nullptr_t opCast(std::nullptr_t) { return nullptr; } +#endif // CATCH_CONFIG_CPP11_NULLPTR + + // So the compare overloads can be operator agnostic we convey the operator as a template + // enum, which is used to specialise an Evaluator for doing the comparison. + template + class Evaluator{}; + + template + struct Evaluator { + static bool evaluate( T1 const& lhs, T2 const& rhs) { + return bool( opCast( lhs ) == opCast( rhs ) ); + } + }; + template + struct Evaluator { + static bool evaluate( T1 const& lhs, T2 const& rhs ) { + return bool( opCast( lhs ) != opCast( rhs ) ); + } + }; + template + struct Evaluator { + static bool evaluate( T1 const& lhs, T2 const& rhs ) { + return bool( opCast( lhs ) < opCast( rhs ) ); + } + }; + template + struct Evaluator { + static bool evaluate( T1 const& lhs, T2 const& rhs ) { + return bool( opCast( lhs ) > opCast( rhs ) ); + } + }; + template + struct Evaluator { + static bool evaluate( T1 const& lhs, T2 const& rhs ) { + return bool( opCast( lhs ) >= opCast( rhs ) ); + } + }; + template + struct Evaluator { + static bool evaluate( T1 const& lhs, T2 const& rhs ) { + return bool( opCast( lhs ) <= opCast( rhs ) ); + } + }; + + template + bool applyEvaluator( T1 const& lhs, T2 const& rhs ) { + return Evaluator::evaluate( lhs, rhs ); + } + + // This level of indirection allows us to specialise for integer types + // to avoid signed/ unsigned warnings + + // "base" overload + template + bool compare( T1 const& lhs, T2 const& rhs ) { + return Evaluator::evaluate( lhs, rhs ); + } + + // unsigned X to int + template bool compare( unsigned int lhs, int rhs ) { + return applyEvaluator( lhs, static_cast( rhs ) ); + } + template bool compare( unsigned long lhs, int rhs ) { + return applyEvaluator( lhs, static_cast( rhs ) ); + } + template bool compare( unsigned char lhs, int rhs ) { + return applyEvaluator( lhs, static_cast( rhs ) ); + } + + // unsigned X to long + template bool compare( unsigned int lhs, long rhs ) { + return applyEvaluator( lhs, static_cast( rhs ) ); + } + template bool compare( unsigned long lhs, long rhs ) { + return applyEvaluator( lhs, static_cast( rhs ) ); + } + template bool compare( unsigned char lhs, long rhs ) { + return applyEvaluator( lhs, static_cast( rhs ) ); + } + + // int to unsigned X + template bool compare( int lhs, unsigned int rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( int lhs, unsigned long rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( int lhs, unsigned char rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + + // long to unsigned X + template bool compare( long lhs, unsigned int rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( long lhs, unsigned long rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( long lhs, unsigned char rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + + // pointer to long (when comparing against NULL) + template bool compare( long lhs, T* rhs ) { + return Evaluator::evaluate( reinterpret_cast( lhs ), rhs ); + } + template bool compare( T* lhs, long rhs ) { + return Evaluator::evaluate( lhs, reinterpret_cast( rhs ) ); + } + + // pointer to int (when comparing against NULL) + template bool compare( int lhs, T* rhs ) { + return Evaluator::evaluate( reinterpret_cast( lhs ), rhs ); + } + template bool compare( T* lhs, int rhs ) { + return Evaluator::evaluate( lhs, reinterpret_cast( rhs ) ); + } + +#ifdef CATCH_CONFIG_CPP11_LONG_LONG + // long long to unsigned X + template bool compare( long long lhs, unsigned int rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( long long lhs, unsigned long rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( long long lhs, unsigned long long rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( long long lhs, unsigned char rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + + // unsigned long long to X + template bool compare( unsigned long long lhs, int rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( unsigned long long lhs, long rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( unsigned long long lhs, long long rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( unsigned long long lhs, char rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + + // pointer to long long (when comparing against NULL) + template bool compare( long long lhs, T* rhs ) { + return Evaluator::evaluate( reinterpret_cast( lhs ), rhs ); + } + template bool compare( T* lhs, long long rhs ) { + return Evaluator::evaluate( lhs, reinterpret_cast( rhs ) ); + } +#endif // CATCH_CONFIG_CPP11_LONG_LONG + +#ifdef CATCH_CONFIG_CPP11_NULLPTR + // pointer to nullptr_t (when comparing against nullptr) + template bool compare( std::nullptr_t, T* rhs ) { + return Evaluator::evaluate( nullptr, rhs ); + } + template bool compare( T* lhs, std::nullptr_t ) { + return Evaluator::evaluate( lhs, nullptr ); + } +#endif // CATCH_CONFIG_CPP11_NULLPTR + +} // end of namespace Internal +} // end of namespace Catch + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +// #included from: catch_tostring.h +#define TWOBLUECUBES_CATCH_TOSTRING_H_INCLUDED + +#include +#include +#include +#include +#include + +#ifdef __OBJC__ +// #included from: catch_objc_arc.hpp +#define TWOBLUECUBES_CATCH_OBJC_ARC_HPP_INCLUDED + +#import + +#ifdef __has_feature +#define CATCH_ARC_ENABLED __has_feature(objc_arc) +#else +#define CATCH_ARC_ENABLED 0 +#endif + +void arcSafeRelease( NSObject* obj ); +id performOptionalSelector( id obj, SEL sel ); + +#if !CATCH_ARC_ENABLED +inline void arcSafeRelease( NSObject* obj ) { + [obj release]; +} +inline id performOptionalSelector( id obj, SEL sel ) { + if( [obj respondsToSelector: sel] ) + return [obj performSelector: sel]; + return nil; +} +#define CATCH_UNSAFE_UNRETAINED +#define CATCH_ARC_STRONG +#else +inline void arcSafeRelease( NSObject* ){} +inline id performOptionalSelector( id obj, SEL sel ) { +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Warc-performSelector-leaks" +#endif + if( [obj respondsToSelector: sel] ) + return [obj performSelector: sel]; +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + return nil; +} +#define CATCH_UNSAFE_UNRETAINED __unsafe_unretained +#define CATCH_ARC_STRONG __strong +#endif + +#endif + +#ifdef CATCH_CONFIG_CPP11_TUPLE +#include +#endif + +#ifdef CATCH_CONFIG_CPP11_IS_ENUM +#include +#endif + +namespace Catch { + +// Why we're here. +template +std::string toString( T const& value ); + +// Built in overloads + +std::string toString( std::string const& value ); +std::string toString( std::wstring const& value ); +std::string toString( const char* const value ); +std::string toString( char* const value ); +std::string toString( const wchar_t* const value ); +std::string toString( wchar_t* const value ); +std::string toString( int value ); +std::string toString( unsigned long value ); +std::string toString( unsigned int value ); +std::string toString( const double value ); +std::string toString( const float value ); +std::string toString( bool value ); +std::string toString( char value ); +std::string toString( signed char value ); +std::string toString( unsigned char value ); + +#ifdef CATCH_CONFIG_CPP11_LONG_LONG +std::string toString( long long value ); +std::string toString( unsigned long long value ); +#endif + +#ifdef CATCH_CONFIG_CPP11_NULLPTR +std::string toString( std::nullptr_t ); +#endif + +#ifdef __OBJC__ + std::string toString( NSString const * const& nsstring ); + std::string toString( NSString * CATCH_ARC_STRONG const& nsstring ); + std::string toString( NSObject* const& nsObject ); +#endif + +namespace Detail { + + extern const std::string unprintableString; + + struct BorgType { + template BorgType( T const& ); + }; + + struct TrueType { char sizer[1]; }; + struct FalseType { char sizer[2]; }; + + TrueType& testStreamable( std::ostream& ); + FalseType testStreamable( FalseType ); + + FalseType operator<<( std::ostream const&, BorgType const& ); + + template + struct IsStreamInsertable { + static std::ostream &s; + static T const&t; + enum { value = sizeof( testStreamable(s << t) ) == sizeof( TrueType ) }; + }; + +#if defined(CATCH_CONFIG_CPP11_IS_ENUM) + template::value + > + struct EnumStringMaker + { + static std::string convert( T const& ) { return unprintableString; } + }; + + template + struct EnumStringMaker + { + static std::string convert( T const& v ) + { + return ::Catch::toString( + static_cast::type>(v) + ); + } + }; +#endif + template + struct StringMakerBase { +#if defined(CATCH_CONFIG_CPP11_IS_ENUM) + template + static std::string convert( T const& v ) + { + return EnumStringMaker::convert( v ); + } +#else + template + static std::string convert( T const& ) { return unprintableString; } +#endif + }; + + template<> + struct StringMakerBase { + template + static std::string convert( T const& _value ) { + std::ostringstream oss; + oss << _value; + return oss.str(); + } + }; + + std::string rawMemoryToString( const void *object, std::size_t size ); + + template + inline std::string rawMemoryToString( const T& object ) { + return rawMemoryToString( &object, sizeof(object) ); + } + +} // end namespace Detail + +template +struct StringMaker : + Detail::StringMakerBase::value> {}; + +template +struct StringMaker { + template + static std::string convert( U* p ) { + if( !p ) + return "NULL"; + else + return Detail::rawMemoryToString( p ); + } +}; + +template +struct StringMaker { + static std::string convert( R C::* p ) { + if( !p ) + return "NULL"; + else + return Detail::rawMemoryToString( p ); + } +}; + +namespace Detail { + template + std::string rangeToString( InputIterator first, InputIterator last ); +} + +//template +//struct StringMaker > { +// static std::string convert( std::vector const& v ) { +// return Detail::rangeToString( v.begin(), v.end() ); +// } +//}; + +template +std::string toString( std::vector const& v ) { + return Detail::rangeToString( v.begin(), v.end() ); +} + +#ifdef CATCH_CONFIG_CPP11_TUPLE + +// toString for tuples +namespace TupleDetail { + template< + typename Tuple, + std::size_t N = 0, + bool = (N < std::tuple_size::value) + > + struct ElementPrinter { + static void print( const Tuple& tuple, std::ostream& os ) + { + os << ( N ? ", " : " " ) + << Catch::toString(std::get(tuple)); + ElementPrinter::print(tuple,os); + } + }; + + template< + typename Tuple, + std::size_t N + > + struct ElementPrinter { + static void print( const Tuple&, std::ostream& ) {} + }; + +} + +template +struct StringMaker> { + + static std::string convert( const std::tuple& tuple ) + { + std::ostringstream os; + os << '{'; + TupleDetail::ElementPrinter>::print( tuple, os ); + os << " }"; + return os.str(); + } +}; +#endif // CATCH_CONFIG_CPP11_TUPLE + +namespace Detail { + template + std::string makeString( T const& value ) { + return StringMaker::convert( value ); + } +} // end namespace Detail + +/// \brief converts any type to a string +/// +/// The default template forwards on to ostringstream - except when an +/// ostringstream overload does not exist - in which case it attempts to detect +/// that and writes {?}. +/// Overload (not specialise) this template for custom typs that you don't want +/// to provide an ostream overload for. +template +std::string toString( T const& value ) { + return StringMaker::convert( value ); +} + + namespace Detail { + template + std::string rangeToString( InputIterator first, InputIterator last ) { + std::ostringstream oss; + oss << "{ "; + if( first != last ) { + oss << Catch::toString( *first ); + for( ++first ; first != last ; ++first ) + oss << ", " << Catch::toString( *first ); + } + oss << " }"; + return oss.str(); + } +} + +} // end namespace Catch + +namespace Catch { + +// Wraps the LHS of an expression and captures the operator and RHS (if any) - +// wrapping them all in a ResultBuilder object +template +class ExpressionLhs { + ExpressionLhs& operator = ( ExpressionLhs const& ); +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + ExpressionLhs& operator = ( ExpressionLhs && ) = delete; +# endif + +public: + ExpressionLhs( ResultBuilder& rb, T lhs ) : m_rb( rb ), m_lhs( lhs ) {} +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + ExpressionLhs( ExpressionLhs const& ) = default; + ExpressionLhs( ExpressionLhs && ) = default; +# endif + + template + ResultBuilder& operator == ( RhsT const& rhs ) { + return captureExpression( rhs ); + } + + template + ResultBuilder& operator != ( RhsT const& rhs ) { + return captureExpression( rhs ); + } + + template + ResultBuilder& operator < ( RhsT const& rhs ) { + return captureExpression( rhs ); + } + + template + ResultBuilder& operator > ( RhsT const& rhs ) { + return captureExpression( rhs ); + } + + template + ResultBuilder& operator <= ( RhsT const& rhs ) { + return captureExpression( rhs ); + } + + template + ResultBuilder& operator >= ( RhsT const& rhs ) { + return captureExpression( rhs ); + } + + ResultBuilder& operator == ( bool rhs ) { + return captureExpression( rhs ); + } + + ResultBuilder& operator != ( bool rhs ) { + return captureExpression( rhs ); + } + + void endExpression() { + bool value = m_lhs ? true : false; + m_rb + .setLhs( Catch::toString( value ) ) + .setResultType( value ) + .endExpression(); + } + + // Only simple binary expressions are allowed on the LHS. + // If more complex compositions are required then place the sub expression in parentheses + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator + ( RhsT const& ); + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator - ( RhsT const& ); + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator / ( RhsT const& ); + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator * ( RhsT const& ); + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( RhsT const& ); + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || ( RhsT const& ); + +private: + template + ResultBuilder& captureExpression( RhsT const& rhs ) { + return m_rb + .setResultType( Internal::compare( m_lhs, rhs ) ) + .setLhs( Catch::toString( m_lhs ) ) + .setRhs( Catch::toString( rhs ) ) + .setOp( Internal::OperatorTraits::getName() ); + } + +private: + ResultBuilder& m_rb; + T m_lhs; +}; + +} // end namespace Catch + + +namespace Catch { + + template + inline ExpressionLhs ResultBuilder::operator <= ( T const& operand ) { + return ExpressionLhs( *this, operand ); + } + + inline ExpressionLhs ResultBuilder::operator <= ( bool value ) { + return ExpressionLhs( *this, value ); + } + +} // namespace Catch + +// #included from: catch_message.h +#define TWOBLUECUBES_CATCH_MESSAGE_H_INCLUDED + +#include + +namespace Catch { + + struct MessageInfo { + MessageInfo( std::string const& _macroName, + SourceLineInfo const& _lineInfo, + ResultWas::OfType _type ); + + std::string macroName; + SourceLineInfo lineInfo; + ResultWas::OfType type; + std::string message; + unsigned int sequence; + + bool operator == ( MessageInfo const& other ) const { + return sequence == other.sequence; + } + bool operator < ( MessageInfo const& other ) const { + return sequence < other.sequence; + } + private: + static unsigned int globalCount; + }; + + struct MessageBuilder { + MessageBuilder( std::string const& macroName, + SourceLineInfo const& lineInfo, + ResultWas::OfType type ) + : m_info( macroName, lineInfo, type ) + {} + + template + MessageBuilder& operator << ( T const& value ) { + m_stream << value; + return *this; + } + + MessageInfo m_info; + std::ostringstream m_stream; + }; + + class ScopedMessage { + public: + ScopedMessage( MessageBuilder const& builder ); + ScopedMessage( ScopedMessage const& other ); + ~ScopedMessage(); + + MessageInfo m_info; + }; + +} // end namespace Catch + +// #included from: catch_interfaces_capture.h +#define TWOBLUECUBES_CATCH_INTERFACES_CAPTURE_H_INCLUDED + +#include + +namespace Catch { + + class TestCase; + class AssertionResult; + struct AssertionInfo; + struct SectionInfo; + struct SectionEndInfo; + struct MessageInfo; + class ScopedMessageBuilder; + struct Counts; + + struct IResultCapture { + + virtual ~IResultCapture(); + + virtual void assertionEnded( AssertionResult const& result ) = 0; + virtual bool sectionStarted( SectionInfo const& sectionInfo, + Counts& assertions ) = 0; + virtual void sectionEnded( SectionEndInfo const& endInfo ) = 0; + virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) = 0; + virtual void pushScopedMessage( MessageInfo const& message ) = 0; + virtual void popScopedMessage( MessageInfo const& message ) = 0; + + virtual std::string getCurrentTestName() const = 0; + virtual const AssertionResult* getLastResult() const = 0; + + virtual void handleFatalErrorCondition( std::string const& message ) = 0; + }; + + IResultCapture& getResultCapture(); +} + +// #included from: catch_debugger.h +#define TWOBLUECUBES_CATCH_DEBUGGER_H_INCLUDED + +// #included from: catch_platform.h +#define TWOBLUECUBES_CATCH_PLATFORM_H_INCLUDED + +#if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) +#define CATCH_PLATFORM_MAC +#elif defined(__IPHONE_OS_VERSION_MIN_REQUIRED) +#define CATCH_PLATFORM_IPHONE +#elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) +#define CATCH_PLATFORM_WINDOWS +#endif + +#include + +namespace Catch{ + + bool isDebuggerActive(); + void writeToDebugConsole( std::string const& text ); +} + +#ifdef CATCH_PLATFORM_MAC + + // The following code snippet based on: + // http://cocoawithlove.com/2008/03/break-into-debugger.html + #ifdef DEBUG + #if defined(__ppc64__) || defined(__ppc__) + #define CATCH_BREAK_INTO_DEBUGGER() \ + if( Catch::isDebuggerActive() ) { \ + __asm__("li r0, 20\nsc\nnop\nli r0, 37\nli r4, 2\nsc\nnop\n" \ + : : : "memory","r0","r3","r4" ); \ + } + #else + #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) {__asm__("int $3\n" : : );} + #endif + #endif + +#elif defined(_MSC_VER) + #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { __debugbreak(); } +#elif defined(__MINGW32__) + extern "C" __declspec(dllimport) void __stdcall DebugBreak(); + #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { DebugBreak(); } +#endif + +#ifndef CATCH_BREAK_INTO_DEBUGGER +#define CATCH_BREAK_INTO_DEBUGGER() Catch::alwaysTrue(); +#endif + +// #included from: catch_interfaces_runner.h +#define TWOBLUECUBES_CATCH_INTERFACES_RUNNER_H_INCLUDED + +namespace Catch { + class TestCase; + + struct IRunner { + virtual ~IRunner(); + virtual bool aborting() const = 0; + }; +} + +/////////////////////////////////////////////////////////////////////////////// +// In the event of a failure works out if the debugger needs to be invoked +// and/or an exception thrown and takes appropriate action. +// This needs to be done as a macro so the debugger will stop in the user +// source code rather than in Catch library code +#define INTERNAL_CATCH_REACT( resultBuilder ) \ + if( resultBuilder.shouldDebugBreak() ) CATCH_BREAK_INTO_DEBUGGER(); \ + resultBuilder.react(); + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \ + try { \ + CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ + ( __catchResult <= expr ).endExpression(); \ + } \ + catch( ... ) { \ + __catchResult.useActiveException( Catch::ResultDisposition::Normal ); \ + } \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::isTrue( false && static_cast(expr) ) ) // expr here is never evaluated at runtime but it forces the compiler to give it a look + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_IF( expr, resultDisposition, macroName ) \ + INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ); \ + if( Catch::getResultCapture().getLastResult()->succeeded() ) + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_ELSE( expr, resultDisposition, macroName ) \ + INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ); \ + if( !Catch::getResultCapture().getLastResult()->succeeded() ) + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_NO_THROW( expr, resultDisposition, macroName ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \ + try { \ + expr; \ + __catchResult.captureResult( Catch::ResultWas::Ok ); \ + } \ + catch( ... ) { \ + __catchResult.useActiveException( resultDisposition ); \ + } \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::alwaysFalse() ) + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_THROWS( expr, resultDisposition, matcher, macroName ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition, #matcher ); \ + if( __catchResult.allowThrows() ) \ + try { \ + expr; \ + __catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \ + } \ + catch( ... ) { \ + __catchResult.captureExpectedException( matcher ); \ + } \ + else \ + __catchResult.captureResult( Catch::ResultWas::Ok ); \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::alwaysFalse() ) + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_THROWS_AS( expr, exceptionType, resultDisposition, macroName ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \ + if( __catchResult.allowThrows() ) \ + try { \ + expr; \ + __catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \ + } \ + catch( exceptionType ) { \ + __catchResult.captureResult( Catch::ResultWas::Ok ); \ + } \ + catch( ... ) { \ + __catchResult.useActiveException( resultDisposition ); \ + } \ + else \ + __catchResult.captureResult( Catch::ResultWas::Ok ); \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::alwaysFalse() ) + +/////////////////////////////////////////////////////////////////////////////// +#ifdef CATCH_CONFIG_VARIADIC_MACROS + #define INTERNAL_CATCH_MSG( messageType, resultDisposition, macroName, ... ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \ + __catchResult << __VA_ARGS__ + ::Catch::StreamEndStop(); \ + __catchResult.captureResult( messageType ); \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::alwaysFalse() ) +#else + #define INTERNAL_CATCH_MSG( messageType, resultDisposition, macroName, log ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \ + __catchResult << log + ::Catch::StreamEndStop(); \ + __catchResult.captureResult( messageType ); \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::alwaysFalse() ) +#endif + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_INFO( log, macroName ) \ + Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME( scopedMessage ) = Catch::MessageBuilder( macroName, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log; + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CHECK_THAT( arg, matcher, resultDisposition, macroName ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #arg ", " #matcher, resultDisposition ); \ + try { \ + std::string matcherAsString = (matcher).toString(); \ + __catchResult \ + .setLhs( Catch::toString( arg ) ) \ + .setRhs( matcherAsString == Catch::Detail::unprintableString ? #matcher : matcherAsString ) \ + .setOp( "matches" ) \ + .setResultType( (matcher).match( arg ) ); \ + __catchResult.captureExpression(); \ + } catch( ... ) { \ + __catchResult.useActiveException( resultDisposition | Catch::ResultDisposition::ContinueOnFailure ); \ + } \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::alwaysFalse() ) + +// #included from: internal/catch_section.h +#define TWOBLUECUBES_CATCH_SECTION_H_INCLUDED + +// #included from: catch_section_info.h +#define TWOBLUECUBES_CATCH_SECTION_INFO_H_INCLUDED + +// #included from: catch_totals.hpp +#define TWOBLUECUBES_CATCH_TOTALS_HPP_INCLUDED + +#include + +namespace Catch { + + struct Counts { + Counts() : passed( 0 ), failed( 0 ), failedButOk( 0 ) {} + + Counts operator - ( Counts const& other ) const { + Counts diff; + diff.passed = passed - other.passed; + diff.failed = failed - other.failed; + diff.failedButOk = failedButOk - other.failedButOk; + return diff; + } + Counts& operator += ( Counts const& other ) { + passed += other.passed; + failed += other.failed; + failedButOk += other.failedButOk; + return *this; + } + + std::size_t total() const { + return passed + failed + failedButOk; + } + bool allPassed() const { + return failed == 0 && failedButOk == 0; + } + bool allOk() const { + return failed == 0; + } + + std::size_t passed; + std::size_t failed; + std::size_t failedButOk; + }; + + struct Totals { + + Totals operator - ( Totals const& other ) const { + Totals diff; + diff.assertions = assertions - other.assertions; + diff.testCases = testCases - other.testCases; + return diff; + } + + Totals delta( Totals const& prevTotals ) const { + Totals diff = *this - prevTotals; + if( diff.assertions.failed > 0 ) + ++diff.testCases.failed; + else if( diff.assertions.failedButOk > 0 ) + ++diff.testCases.failedButOk; + else + ++diff.testCases.passed; + return diff; + } + + Totals& operator += ( Totals const& other ) { + assertions += other.assertions; + testCases += other.testCases; + return *this; + } + + Counts assertions; + Counts testCases; + }; +} + +namespace Catch { + + struct SectionInfo { + SectionInfo + ( SourceLineInfo const& _lineInfo, + std::string const& _name, + std::string const& _description = std::string() ); + + std::string name; + std::string description; + SourceLineInfo lineInfo; + }; + + struct SectionEndInfo { + SectionEndInfo( SectionInfo const& _sectionInfo, Counts const& _prevAssertions, double _durationInSeconds ) + : sectionInfo( _sectionInfo ), prevAssertions( _prevAssertions ), durationInSeconds( _durationInSeconds ) + {} + + SectionInfo sectionInfo; + Counts prevAssertions; + double durationInSeconds; + }; + +} // end namespace Catch + +// #included from: catch_timer.h +#define TWOBLUECUBES_CATCH_TIMER_H_INCLUDED + +#ifdef CATCH_PLATFORM_WINDOWS +typedef unsigned long long uint64_t; +#else +#include +#endif + +namespace Catch { + + class Timer { + public: + Timer() : m_ticks( 0 ) {} + void start(); + unsigned int getElapsedMicroseconds() const; + unsigned int getElapsedMilliseconds() const; + double getElapsedSeconds() const; + + private: + uint64_t m_ticks; + }; + +} // namespace Catch + +#include + +namespace Catch { + + class Section : NonCopyable { + public: + Section( SectionInfo const& info ); + ~Section(); + + // This indicates whether the section should be executed or not + operator bool() const; + + private: + SectionInfo m_info; + + std::string m_name; + Counts m_assertions; + bool m_sectionIncluded; + Timer m_timer; + }; + +} // end namespace Catch + +#ifdef CATCH_CONFIG_VARIADIC_MACROS + #define INTERNAL_CATCH_SECTION( ... ) \ + if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) ) +#else + #define INTERNAL_CATCH_SECTION( name, desc ) \ + if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, name, desc ) ) +#endif + +// #included from: internal/catch_generators.hpp +#define TWOBLUECUBES_CATCH_GENERATORS_HPP_INCLUDED + +#include +#include +#include +#include + +namespace Catch { + +template +struct IGenerator { + virtual ~IGenerator() {} + virtual T getValue( std::size_t index ) const = 0; + virtual std::size_t size () const = 0; +}; + +template +class BetweenGenerator : public IGenerator { +public: + BetweenGenerator( T from, T to ) : m_from( from ), m_to( to ){} + + virtual T getValue( std::size_t index ) const { + return m_from+static_cast( index ); + } + + virtual std::size_t size() const { + return static_cast( 1+m_to-m_from ); + } + +private: + + T m_from; + T m_to; +}; + +template +class ValuesGenerator : public IGenerator { +public: + ValuesGenerator(){} + + void add( T value ) { + m_values.push_back( value ); + } + + virtual T getValue( std::size_t index ) const { + return m_values[index]; + } + + virtual std::size_t size() const { + return m_values.size(); + } + +private: + std::vector m_values; +}; + +template +class CompositeGenerator { +public: + CompositeGenerator() : m_totalSize( 0 ) {} + + // *** Move semantics, similar to auto_ptr *** + CompositeGenerator( CompositeGenerator& other ) + : m_fileInfo( other.m_fileInfo ), + m_totalSize( 0 ) + { + move( other ); + } + + CompositeGenerator& setFileInfo( const char* fileInfo ) { + m_fileInfo = fileInfo; + return *this; + } + + ~CompositeGenerator() { + deleteAll( m_composed ); + } + + operator T () const { + size_t overallIndex = getCurrentContext().getGeneratorIndex( m_fileInfo, m_totalSize ); + + typename std::vector*>::const_iterator it = m_composed.begin(); + typename std::vector*>::const_iterator itEnd = m_composed.end(); + for( size_t index = 0; it != itEnd; ++it ) + { + const IGenerator* generator = *it; + if( overallIndex >= index && overallIndex < index + generator->size() ) + { + return generator->getValue( overallIndex-index ); + } + index += generator->size(); + } + CATCH_INTERNAL_ERROR( "Indexed past end of generated range" ); + return T(); // Suppress spurious "not all control paths return a value" warning in Visual Studio - if you know how to fix this please do so + } + + void add( const IGenerator* generator ) { + m_totalSize += generator->size(); + m_composed.push_back( generator ); + } + + CompositeGenerator& then( CompositeGenerator& other ) { + move( other ); + return *this; + } + + CompositeGenerator& then( T value ) { + ValuesGenerator* valuesGen = new ValuesGenerator(); + valuesGen->add( value ); + add( valuesGen ); + return *this; + } + +private: + + void move( CompositeGenerator& other ) { + std::copy( other.m_composed.begin(), other.m_composed.end(), std::back_inserter( m_composed ) ); + m_totalSize += other.m_totalSize; + other.m_composed.clear(); + } + + std::vector*> m_composed; + std::string m_fileInfo; + size_t m_totalSize; +}; + +namespace Generators +{ + template + CompositeGenerator between( T from, T to ) { + CompositeGenerator generators; + generators.add( new BetweenGenerator( from, to ) ); + return generators; + } + + template + CompositeGenerator values( T val1, T val2 ) { + CompositeGenerator generators; + ValuesGenerator* valuesGen = new ValuesGenerator(); + valuesGen->add( val1 ); + valuesGen->add( val2 ); + generators.add( valuesGen ); + return generators; + } + + template + CompositeGenerator values( T val1, T val2, T val3 ){ + CompositeGenerator generators; + ValuesGenerator* valuesGen = new ValuesGenerator(); + valuesGen->add( val1 ); + valuesGen->add( val2 ); + valuesGen->add( val3 ); + generators.add( valuesGen ); + return generators; + } + + template + CompositeGenerator values( T val1, T val2, T val3, T val4 ) { + CompositeGenerator generators; + ValuesGenerator* valuesGen = new ValuesGenerator(); + valuesGen->add( val1 ); + valuesGen->add( val2 ); + valuesGen->add( val3 ); + valuesGen->add( val4 ); + generators.add( valuesGen ); + return generators; + } + +} // end namespace Generators + +using namespace Generators; + +} // end namespace Catch + +#define INTERNAL_CATCH_LINESTR2( line ) #line +#define INTERNAL_CATCH_LINESTR( line ) INTERNAL_CATCH_LINESTR2( line ) + +#define INTERNAL_CATCH_GENERATE( expr ) expr.setFileInfo( __FILE__ "(" INTERNAL_CATCH_LINESTR( __LINE__ ) ")" ) + +// #included from: internal/catch_interfaces_exception.h +#define TWOBLUECUBES_CATCH_INTERFACES_EXCEPTION_H_INCLUDED + +#include +#include + +// #included from: catch_interfaces_registry_hub.h +#define TWOBLUECUBES_CATCH_INTERFACES_REGISTRY_HUB_H_INCLUDED + +#include + +namespace Catch { + + class TestCase; + struct ITestCaseRegistry; + struct IExceptionTranslatorRegistry; + struct IExceptionTranslator; + struct IReporterRegistry; + struct IReporterFactory; + + struct IRegistryHub { + virtual ~IRegistryHub(); + + virtual IReporterRegistry const& getReporterRegistry() const = 0; + virtual ITestCaseRegistry const& getTestCaseRegistry() const = 0; + virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() = 0; + }; + + struct IMutableRegistryHub { + virtual ~IMutableRegistryHub(); + virtual void registerReporter( std::string const& name, Ptr const& factory ) = 0; + virtual void registerListener( Ptr const& factory ) = 0; + virtual void registerTest( TestCase const& testInfo ) = 0; + virtual void registerTranslator( const IExceptionTranslator* translator ) = 0; + }; + + IRegistryHub& getRegistryHub(); + IMutableRegistryHub& getMutableRegistryHub(); + void cleanUp(); + std::string translateActiveException(); + +} + +namespace Catch { + + typedef std::string(*exceptionTranslateFunction)(); + + struct IExceptionTranslator; + typedef std::vector ExceptionTranslators; + + struct IExceptionTranslator { + virtual ~IExceptionTranslator(); + virtual std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const = 0; + }; + + struct IExceptionTranslatorRegistry { + virtual ~IExceptionTranslatorRegistry(); + + virtual std::string translateActiveException() const = 0; + }; + + class ExceptionTranslatorRegistrar { + template + class ExceptionTranslator : public IExceptionTranslator { + public: + + ExceptionTranslator( std::string(*translateFunction)( T& ) ) + : m_translateFunction( translateFunction ) + {} + + virtual std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const CATCH_OVERRIDE { + try { + if( it == itEnd ) + throw; + else + return (*it)->translate( it+1, itEnd ); + } + catch( T& ex ) { + return m_translateFunction( ex ); + } + } + + protected: + std::string(*m_translateFunction)( T& ); + }; + + public: + template + ExceptionTranslatorRegistrar( std::string(*translateFunction)( T& ) ) { + getMutableRegistryHub().registerTranslator + ( new ExceptionTranslator( translateFunction ) ); + } + }; +} + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) \ + static std::string INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator )( signature ); \ + namespace{ Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ) ); }\ + static std::string INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator )( signature ) + +// #included from: internal/catch_approx.hpp +#define TWOBLUECUBES_CATCH_APPROX_HPP_INCLUDED + +#include +#include + +namespace Catch { +namespace Detail { + + class Approx { + public: + explicit Approx ( double value ) + : m_epsilon( std::numeric_limits::epsilon()*100 ), + m_scale( 1.0 ), + m_value( value ) + {} + + Approx( Approx const& other ) + : m_epsilon( other.m_epsilon ), + m_scale( other.m_scale ), + m_value( other.m_value ) + {} + + static Approx custom() { + return Approx( 0 ); + } + + Approx operator()( double value ) { + Approx approx( value ); + approx.epsilon( m_epsilon ); + approx.scale( m_scale ); + return approx; + } + + friend bool operator == ( double lhs, Approx const& rhs ) { + // Thanks to Richard Harris for his help refining this formula + return fabs( lhs - rhs.m_value ) < rhs.m_epsilon * (rhs.m_scale + (std::max)( fabs(lhs), fabs(rhs.m_value) ) ); + } + + friend bool operator == ( Approx const& lhs, double rhs ) { + return operator==( rhs, lhs ); + } + + friend bool operator != ( double lhs, Approx const& rhs ) { + return !operator==( lhs, rhs ); + } + + friend bool operator != ( Approx const& lhs, double rhs ) { + return !operator==( rhs, lhs ); + } + + Approx& epsilon( double newEpsilon ) { + m_epsilon = newEpsilon; + return *this; + } + + Approx& scale( double newScale ) { + m_scale = newScale; + return *this; + } + + std::string toString() const { + std::ostringstream oss; + oss << "Approx( " << Catch::toString( m_value ) << " )"; + return oss.str(); + } + + private: + double m_epsilon; + double m_scale; + double m_value; + }; +} + +template<> +inline std::string toString( Detail::Approx const& value ) { + return value.toString(); +} + +} // end namespace Catch + +// #included from: internal/catch_interfaces_tag_alias_registry.h +#define TWOBLUECUBES_CATCH_INTERFACES_TAG_ALIAS_REGISTRY_H_INCLUDED + +// #included from: catch_tag_alias.h +#define TWOBLUECUBES_CATCH_TAG_ALIAS_H_INCLUDED + +#include + +namespace Catch { + + struct TagAlias { + TagAlias( std::string _tag, SourceLineInfo _lineInfo ) : tag( _tag ), lineInfo( _lineInfo ) {} + + std::string tag; + SourceLineInfo lineInfo; + }; + + struct RegistrarForTagAliases { + RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ); + }; + +} // end namespace Catch + +#define CATCH_REGISTER_TAG_ALIAS( alias, spec ) namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); } +// #included from: catch_option.hpp +#define TWOBLUECUBES_CATCH_OPTION_HPP_INCLUDED + +namespace Catch { + + // An optional type + template + class Option { + public: + Option() : nullableValue( CATCH_NULL ) {} + Option( T const& _value ) + : nullableValue( new( storage ) T( _value ) ) + {} + Option( Option const& _other ) + : nullableValue( _other ? new( storage ) T( *_other ) : CATCH_NULL ) + {} + + ~Option() { + reset(); + } + + Option& operator= ( Option const& _other ) { + if( &_other != this ) { + reset(); + if( _other ) + nullableValue = new( storage ) T( *_other ); + } + return *this; + } + Option& operator = ( T const& _value ) { + reset(); + nullableValue = new( storage ) T( _value ); + return *this; + } + + void reset() { + if( nullableValue ) + nullableValue->~T(); + nullableValue = CATCH_NULL; + } + + T& operator*() { return *nullableValue; } + T const& operator*() const { return *nullableValue; } + T* operator->() { return nullableValue; } + const T* operator->() const { return nullableValue; } + + T valueOr( T const& defaultValue ) const { + return nullableValue ? *nullableValue : defaultValue; + } + + bool some() const { return nullableValue != CATCH_NULL; } + bool none() const { return nullableValue == CATCH_NULL; } + + bool operator !() const { return nullableValue == CATCH_NULL; } + operator SafeBool::type() const { + return SafeBool::makeSafe( some() ); + } + + private: + T* nullableValue; + char storage[sizeof(T)]; + }; + +} // end namespace Catch + +namespace Catch { + + struct ITagAliasRegistry { + virtual ~ITagAliasRegistry(); + virtual Option find( std::string const& alias ) const = 0; + virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const = 0; + + static ITagAliasRegistry const& get(); + }; + +} // end namespace Catch + +// These files are included here so the single_include script doesn't put them +// in the conditionally compiled sections +// #included from: internal/catch_test_case_info.h +#define TWOBLUECUBES_CATCH_TEST_CASE_INFO_H_INCLUDED + +#include +#include + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpadded" +#endif + +namespace Catch { + + struct ITestCase; + + struct TestCaseInfo { + enum SpecialProperties{ + None = 0, + IsHidden = 1 << 1, + ShouldFail = 1 << 2, + MayFail = 1 << 3, + Throws = 1 << 4 + }; + + TestCaseInfo( std::string const& _name, + std::string const& _className, + std::string const& _description, + std::set const& _tags, + SourceLineInfo const& _lineInfo ); + + TestCaseInfo( TestCaseInfo const& other ); + + friend void setTags( TestCaseInfo& testCaseInfo, std::set const& tags ); + + bool isHidden() const; + bool throws() const; + bool okToFail() const; + bool expectedToFail() const; + + std::string name; + std::string className; + std::string description; + std::set tags; + std::set lcaseTags; + std::string tagsAsString; + SourceLineInfo lineInfo; + SpecialProperties properties; + }; + + class TestCase : public TestCaseInfo { + public: + + TestCase( ITestCase* testCase, TestCaseInfo const& info ); + TestCase( TestCase const& other ); + + TestCase withName( std::string const& _newName ) const; + + void invoke() const; + + TestCaseInfo const& getTestCaseInfo() const; + + void swap( TestCase& other ); + bool operator == ( TestCase const& other ) const; + bool operator < ( TestCase const& other ) const; + TestCase& operator = ( TestCase const& other ); + + private: + Ptr test; + }; + + TestCase makeTestCase( ITestCase* testCase, + std::string const& className, + std::string const& name, + std::string const& description, + SourceLineInfo const& lineInfo ); +} + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + + +#ifdef __OBJC__ +// #included from: internal/catch_objc.hpp +#define TWOBLUECUBES_CATCH_OBJC_HPP_INCLUDED + +#import + +#include + +// NB. Any general catch headers included here must be included +// in catch.hpp first to make sure they are included by the single +// header for non obj-usage + +/////////////////////////////////////////////////////////////////////////////// +// This protocol is really only here for (self) documenting purposes, since +// all its methods are optional. +@protocol OcFixture + +@optional + +-(void) setUp; +-(void) tearDown; + +@end + +namespace Catch { + + class OcMethod : public SharedImpl { + + public: + OcMethod( Class cls, SEL sel ) : m_cls( cls ), m_sel( sel ) {} + + virtual void invoke() const { + id obj = [[m_cls alloc] init]; + + performOptionalSelector( obj, @selector(setUp) ); + performOptionalSelector( obj, m_sel ); + performOptionalSelector( obj, @selector(tearDown) ); + + arcSafeRelease( obj ); + } + private: + virtual ~OcMethod() {} + + Class m_cls; + SEL m_sel; + }; + + namespace Detail{ + + inline std::string getAnnotation( Class cls, + std::string const& annotationName, + std::string const& testCaseName ) { + NSString* selStr = [[NSString alloc] initWithFormat:@"Catch_%s_%s", annotationName.c_str(), testCaseName.c_str()]; + SEL sel = NSSelectorFromString( selStr ); + arcSafeRelease( selStr ); + id value = performOptionalSelector( cls, sel ); + if( value ) + return [(NSString*)value UTF8String]; + return ""; + } + } + + inline size_t registerTestMethods() { + size_t noTestMethods = 0; + int noClasses = objc_getClassList( CATCH_NULL, 0 ); + + Class* classes = (CATCH_UNSAFE_UNRETAINED Class *)malloc( sizeof(Class) * noClasses); + objc_getClassList( classes, noClasses ); + + for( int c = 0; c < noClasses; c++ ) { + Class cls = classes[c]; + { + u_int count; + Method* methods = class_copyMethodList( cls, &count ); + for( u_int m = 0; m < count ; m++ ) { + SEL selector = method_getName(methods[m]); + std::string methodName = sel_getName(selector); + if( startsWith( methodName, "Catch_TestCase_" ) ) { + std::string testCaseName = methodName.substr( 15 ); + std::string name = Detail::getAnnotation( cls, "Name", testCaseName ); + std::string desc = Detail::getAnnotation( cls, "Description", testCaseName ); + const char* className = class_getName( cls ); + + getMutableRegistryHub().registerTest( makeTestCase( new OcMethod( cls, selector ), className, name.c_str(), desc.c_str(), SourceLineInfo() ) ); + noTestMethods++; + } + } + free(methods); + } + } + return noTestMethods; + } + + namespace Matchers { + namespace Impl { + namespace NSStringMatchers { + + template + struct StringHolder : MatcherImpl{ + StringHolder( NSString* substr ) : m_substr( [substr copy] ){} + StringHolder( StringHolder const& other ) : m_substr( [other.m_substr copy] ){} + StringHolder() { + arcSafeRelease( m_substr ); + } + + NSString* m_substr; + }; + + struct Equals : StringHolder { + Equals( NSString* substr ) : StringHolder( substr ){} + + virtual bool match( ExpressionType const& str ) const { + return (str != nil || m_substr == nil ) && + [str isEqualToString:m_substr]; + } + + virtual std::string toString() const { + return "equals string: " + Catch::toString( m_substr ); + } + }; + + struct Contains : StringHolder { + Contains( NSString* substr ) : StringHolder( substr ){} + + virtual bool match( ExpressionType const& str ) const { + return (str != nil || m_substr == nil ) && + [str rangeOfString:m_substr].location != NSNotFound; + } + + virtual std::string toString() const { + return "contains string: " + Catch::toString( m_substr ); + } + }; + + struct StartsWith : StringHolder { + StartsWith( NSString* substr ) : StringHolder( substr ){} + + virtual bool match( ExpressionType const& str ) const { + return (str != nil || m_substr == nil ) && + [str rangeOfString:m_substr].location == 0; + } + + virtual std::string toString() const { + return "starts with: " + Catch::toString( m_substr ); + } + }; + struct EndsWith : StringHolder { + EndsWith( NSString* substr ) : StringHolder( substr ){} + + virtual bool match( ExpressionType const& str ) const { + return (str != nil || m_substr == nil ) && + [str rangeOfString:m_substr].location == [str length] - [m_substr length]; + } + + virtual std::string toString() const { + return "ends with: " + Catch::toString( m_substr ); + } + }; + + } // namespace NSStringMatchers + } // namespace Impl + + inline Impl::NSStringMatchers::Equals + Equals( NSString* substr ){ return Impl::NSStringMatchers::Equals( substr ); } + + inline Impl::NSStringMatchers::Contains + Contains( NSString* substr ){ return Impl::NSStringMatchers::Contains( substr ); } + + inline Impl::NSStringMatchers::StartsWith + StartsWith( NSString* substr ){ return Impl::NSStringMatchers::StartsWith( substr ); } + + inline Impl::NSStringMatchers::EndsWith + EndsWith( NSString* substr ){ return Impl::NSStringMatchers::EndsWith( substr ); } + + } // namespace Matchers + + using namespace Matchers; + +} // namespace Catch + +/////////////////////////////////////////////////////////////////////////////// +#define OC_TEST_CASE( name, desc )\ ++(NSString*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Name_test ) \ +{\ +return @ name; \ +}\ ++(NSString*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Description_test ) \ +{ \ +return @ desc; \ +} \ +-(void) INTERNAL_CATCH_UNIQUE_NAME( Catch_TestCase_test ) + +#endif + +#ifdef CATCH_IMPL +// #included from: internal/catch_impl.hpp +#define TWOBLUECUBES_CATCH_IMPL_HPP_INCLUDED + +// Collect all the implementation files together here +// These are the equivalent of what would usually be cpp files + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wweak-vtables" +#endif + +// #included from: ../catch_session.hpp +#define TWOBLUECUBES_CATCH_RUNNER_HPP_INCLUDED + +// #included from: internal/catch_commandline.hpp +#define TWOBLUECUBES_CATCH_COMMANDLINE_HPP_INCLUDED + +// #included from: catch_config.hpp +#define TWOBLUECUBES_CATCH_CONFIG_HPP_INCLUDED + +// #included from: catch_test_spec_parser.hpp +#define TWOBLUECUBES_CATCH_TEST_SPEC_PARSER_HPP_INCLUDED + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpadded" +#endif + +// #included from: catch_test_spec.hpp +#define TWOBLUECUBES_CATCH_TEST_SPEC_HPP_INCLUDED + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpadded" +#endif + +// #included from: catch_wildcard_pattern.hpp +#define TWOBLUECUBES_CATCH_WILDCARD_PATTERN_HPP_INCLUDED + +namespace Catch +{ + class WildcardPattern { + enum WildcardPosition { + NoWildcard = 0, + WildcardAtStart = 1, + WildcardAtEnd = 2, + WildcardAtBothEnds = WildcardAtStart | WildcardAtEnd + }; + + public: + + WildcardPattern( std::string const& pattern, CaseSensitive::Choice caseSensitivity ) + : m_caseSensitivity( caseSensitivity ), + m_wildcard( NoWildcard ), + m_pattern( adjustCase( pattern ) ) + { + if( startsWith( m_pattern, "*" ) ) { + m_pattern = m_pattern.substr( 1 ); + m_wildcard = WildcardAtStart; + } + if( endsWith( m_pattern, "*" ) ) { + m_pattern = m_pattern.substr( 0, m_pattern.size()-1 ); + m_wildcard = static_cast( m_wildcard | WildcardAtEnd ); + } + } + virtual ~WildcardPattern(); + virtual bool matches( std::string const& str ) const { + switch( m_wildcard ) { + case NoWildcard: + return m_pattern == adjustCase( str ); + case WildcardAtStart: + return endsWith( adjustCase( str ), m_pattern ); + case WildcardAtEnd: + return startsWith( adjustCase( str ), m_pattern ); + case WildcardAtBothEnds: + return contains( adjustCase( str ), m_pattern ); + } + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunreachable-code" +#endif + throw std::logic_error( "Unknown enum" ); +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + } + private: + std::string adjustCase( std::string const& str ) const { + return m_caseSensitivity == CaseSensitive::No ? toLower( str ) : str; + } + CaseSensitive::Choice m_caseSensitivity; + WildcardPosition m_wildcard; + std::string m_pattern; + }; +} + +#include +#include + +namespace Catch { + + class TestSpec { + struct Pattern : SharedImpl<> { + virtual ~Pattern(); + virtual bool matches( TestCaseInfo const& testCase ) const = 0; + }; + class NamePattern : public Pattern { + public: + NamePattern( std::string const& name ) + : m_wildcardPattern( toLower( name ), CaseSensitive::No ) + {} + virtual ~NamePattern(); + virtual bool matches( TestCaseInfo const& testCase ) const { + return m_wildcardPattern.matches( toLower( testCase.name ) ); + } + private: + WildcardPattern m_wildcardPattern; + }; + + class TagPattern : public Pattern { + public: + TagPattern( std::string const& tag ) : m_tag( toLower( tag ) ) {} + virtual ~TagPattern(); + virtual bool matches( TestCaseInfo const& testCase ) const { + return testCase.lcaseTags.find( m_tag ) != testCase.lcaseTags.end(); + } + private: + std::string m_tag; + }; + + class ExcludedPattern : public Pattern { + public: + ExcludedPattern( Ptr const& underlyingPattern ) : m_underlyingPattern( underlyingPattern ) {} + virtual ~ExcludedPattern(); + virtual bool matches( TestCaseInfo const& testCase ) const { return !m_underlyingPattern->matches( testCase ); } + private: + Ptr m_underlyingPattern; + }; + + struct Filter { + std::vector > m_patterns; + + bool matches( TestCaseInfo const& testCase ) const { + // All patterns in a filter must match for the filter to be a match + for( std::vector >::const_iterator it = m_patterns.begin(), itEnd = m_patterns.end(); it != itEnd; ++it ) + if( !(*it)->matches( testCase ) ) + return false; + return true; + } + }; + + public: + bool hasFilters() const { + return !m_filters.empty(); + } + bool matches( TestCaseInfo const& testCase ) const { + // A TestSpec matches if any filter matches + for( std::vector::const_iterator it = m_filters.begin(), itEnd = m_filters.end(); it != itEnd; ++it ) + if( it->matches( testCase ) ) + return true; + return false; + } + + private: + std::vector m_filters; + + friend class TestSpecParser; + }; +} + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +namespace Catch { + + class TestSpecParser { + enum Mode{ None, Name, QuotedName, Tag }; + Mode m_mode; + bool m_exclusion; + std::size_t m_start, m_pos; + std::string m_arg; + TestSpec::Filter m_currentFilter; + TestSpec m_testSpec; + ITagAliasRegistry const* m_tagAliases; + + public: + TestSpecParser( ITagAliasRegistry const& tagAliases ) : m_tagAliases( &tagAliases ) {} + + TestSpecParser& parse( std::string const& arg ) { + m_mode = None; + m_exclusion = false; + m_start = std::string::npos; + m_arg = m_tagAliases->expandAliases( arg ); + for( m_pos = 0; m_pos < m_arg.size(); ++m_pos ) + visitChar( m_arg[m_pos] ); + if( m_mode == Name ) + addPattern(); + return *this; + } + TestSpec testSpec() { + addFilter(); + return m_testSpec; + } + private: + void visitChar( char c ) { + if( m_mode == None ) { + switch( c ) { + case ' ': return; + case '~': m_exclusion = true; return; + case '[': return startNewMode( Tag, ++m_pos ); + case '"': return startNewMode( QuotedName, ++m_pos ); + default: startNewMode( Name, m_pos ); break; + } + } + if( m_mode == Name ) { + if( c == ',' ) { + addPattern(); + addFilter(); + } + else if( c == '[' ) { + if( subString() == "exclude:" ) + m_exclusion = true; + else + addPattern(); + startNewMode( Tag, ++m_pos ); + } + } + else if( m_mode == QuotedName && c == '"' ) + addPattern(); + else if( m_mode == Tag && c == ']' ) + addPattern(); + } + void startNewMode( Mode mode, std::size_t start ) { + m_mode = mode; + m_start = start; + } + std::string subString() const { return m_arg.substr( m_start, m_pos - m_start ); } + template + void addPattern() { + std::string token = subString(); + if( startsWith( token, "exclude:" ) ) { + m_exclusion = true; + token = token.substr( 8 ); + } + if( !token.empty() ) { + Ptr pattern = new T( token ); + if( m_exclusion ) + pattern = new TestSpec::ExcludedPattern( pattern ); + m_currentFilter.m_patterns.push_back( pattern ); + } + m_exclusion = false; + m_mode = None; + } + void addFilter() { + if( !m_currentFilter.m_patterns.empty() ) { + m_testSpec.m_filters.push_back( m_currentFilter ); + m_currentFilter = TestSpec::Filter(); + } + } + }; + inline TestSpec parseTestSpec( std::string const& arg ) { + return TestSpecParser( ITagAliasRegistry::get() ).parse( arg ).testSpec(); + } + +} // namespace Catch + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +// #included from: catch_interfaces_config.h +#define TWOBLUECUBES_CATCH_INTERFACES_CONFIG_H_INCLUDED + +#include +#include +#include + +namespace Catch { + + struct Verbosity { enum Level { + NoOutput = 0, + Quiet, + Normal + }; }; + + struct WarnAbout { enum What { + Nothing = 0x00, + NoAssertions = 0x01 + }; }; + + struct ShowDurations { enum OrNot { + DefaultForReporter, + Always, + Never + }; }; + struct RunTests { enum InWhatOrder { + InDeclarationOrder, + InLexicographicalOrder, + InRandomOrder + }; }; + struct UseColour { enum YesOrNo { + Auto, + Yes, + No + }; }; + + class TestSpec; + + struct IConfig : IShared { + + virtual ~IConfig(); + + virtual bool allowThrows() const = 0; + virtual std::ostream& stream() const = 0; + virtual std::string name() const = 0; + virtual bool includeSuccessfulResults() const = 0; + virtual bool shouldDebugBreak() const = 0; + virtual bool warnAboutMissingAssertions() const = 0; + virtual int abortAfter() const = 0; + virtual bool showInvisibles() const = 0; + virtual ShowDurations::OrNot showDurations() const = 0; + virtual TestSpec const& testSpec() const = 0; + virtual RunTests::InWhatOrder runOrder() const = 0; + virtual unsigned int rngSeed() const = 0; + virtual UseColour::YesOrNo useColour() const = 0; + }; +} + +// #included from: catch_stream.h +#define TWOBLUECUBES_CATCH_STREAM_H_INCLUDED + +// #included from: catch_streambuf.h +#define TWOBLUECUBES_CATCH_STREAMBUF_H_INCLUDED + +#include + +namespace Catch { + + class StreamBufBase : public std::streambuf { + public: + virtual ~StreamBufBase() CATCH_NOEXCEPT; + }; +} + +#include +#include +#include + +namespace Catch { + + std::ostream& cout(); + std::ostream& cerr(); + + struct IStream { + virtual ~IStream() CATCH_NOEXCEPT; + virtual std::ostream& stream() const = 0; + }; + + class FileStream : public IStream { + mutable std::ofstream m_ofs; + public: + FileStream( std::string const& filename ); + virtual ~FileStream() CATCH_NOEXCEPT; + public: // IStream + virtual std::ostream& stream() const CATCH_OVERRIDE; + }; + + class CoutStream : public IStream { + mutable std::ostream m_os; + public: + CoutStream(); + virtual ~CoutStream() CATCH_NOEXCEPT; + + public: // IStream + virtual std::ostream& stream() const CATCH_OVERRIDE; + }; + + class DebugOutStream : public IStream { + std::auto_ptr m_streamBuf; + mutable std::ostream m_os; + public: + DebugOutStream(); + virtual ~DebugOutStream() CATCH_NOEXCEPT; + + public: // IStream + virtual std::ostream& stream() const CATCH_OVERRIDE; + }; +} + +#include +#include +#include +#include +#include + +#ifndef CATCH_CONFIG_CONSOLE_WIDTH +#define CATCH_CONFIG_CONSOLE_WIDTH 80 +#endif + +namespace Catch { + + struct ConfigData { + + ConfigData() + : listTests( false ), + listTags( false ), + listReporters( false ), + listTestNamesOnly( false ), + showSuccessfulTests( false ), + shouldDebugBreak( false ), + noThrow( false ), + showHelp( false ), + showInvisibles( false ), + filenamesAsTags( false ), + abortAfter( -1 ), + rngSeed( 0 ), + verbosity( Verbosity::Normal ), + warnings( WarnAbout::Nothing ), + showDurations( ShowDurations::DefaultForReporter ), + runOrder( RunTests::InDeclarationOrder ), + useColour( UseColour::Auto ) + {} + + bool listTests; + bool listTags; + bool listReporters; + bool listTestNamesOnly; + + bool showSuccessfulTests; + bool shouldDebugBreak; + bool noThrow; + bool showHelp; + bool showInvisibles; + bool filenamesAsTags; + + int abortAfter; + unsigned int rngSeed; + + Verbosity::Level verbosity; + WarnAbout::What warnings; + ShowDurations::OrNot showDurations; + RunTests::InWhatOrder runOrder; + UseColour::YesOrNo useColour; + + std::string outputFilename; + std::string name; + std::string processName; + + std::vector reporterNames; + std::vector testsOrTags; + }; + + class Config : public SharedImpl { + private: + Config( Config const& other ); + Config& operator = ( Config const& other ); + virtual void dummy(); + public: + + Config() + {} + + Config( ConfigData const& data ) + : m_data( data ), + m_stream( openStream() ) + { + if( !data.testsOrTags.empty() ) { + TestSpecParser parser( ITagAliasRegistry::get() ); + for( std::size_t i = 0; i < data.testsOrTags.size(); ++i ) + parser.parse( data.testsOrTags[i] ); + m_testSpec = parser.testSpec(); + } + } + + virtual ~Config() { + } + + std::string const& getFilename() const { + return m_data.outputFilename ; + } + + bool listTests() const { return m_data.listTests; } + bool listTestNamesOnly() const { return m_data.listTestNamesOnly; } + bool listTags() const { return m_data.listTags; } + bool listReporters() const { return m_data.listReporters; } + + std::string getProcessName() const { return m_data.processName; } + + bool shouldDebugBreak() const { return m_data.shouldDebugBreak; } + + std::vector getReporterNames() const { return m_data.reporterNames; } + + int abortAfter() const { return m_data.abortAfter; } + + TestSpec const& testSpec() const { return m_testSpec; } + + bool showHelp() const { return m_data.showHelp; } + bool showInvisibles() const { return m_data.showInvisibles; } + + // IConfig interface + virtual bool allowThrows() const { return !m_data.noThrow; } + virtual std::ostream& stream() const { return m_stream->stream(); } + virtual std::string name() const { return m_data.name.empty() ? m_data.processName : m_data.name; } + virtual bool includeSuccessfulResults() const { return m_data.showSuccessfulTests; } + virtual bool warnAboutMissingAssertions() const { return m_data.warnings & WarnAbout::NoAssertions; } + virtual ShowDurations::OrNot showDurations() const { return m_data.showDurations; } + virtual RunTests::InWhatOrder runOrder() const { return m_data.runOrder; } + virtual unsigned int rngSeed() const { return m_data.rngSeed; } + virtual UseColour::YesOrNo useColour() const { return m_data.useColour; } + + private: + + IStream const* openStream() { + if( m_data.outputFilename.empty() ) + return new CoutStream(); + else if( m_data.outputFilename[0] == '%' ) { + if( m_data.outputFilename == "%debug" ) + return new DebugOutStream(); + else + throw std::domain_error( "Unrecognised stream: " + m_data.outputFilename ); + } + else + return new FileStream( m_data.outputFilename ); + } + ConfigData m_data; + + std::auto_ptr m_stream; + TestSpec m_testSpec; + }; + +} // end namespace Catch + +// #included from: catch_clara.h +#define TWOBLUECUBES_CATCH_CLARA_H_INCLUDED + +// Use Catch's value for console width (store Clara's off to the side, if present) +#ifdef CLARA_CONFIG_CONSOLE_WIDTH +#define CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH CLARA_CONFIG_CONSOLE_WIDTH +#undef CLARA_CONFIG_CONSOLE_WIDTH +#endif +#define CLARA_CONFIG_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH + +// Declare Clara inside the Catch namespace +#define STITCH_CLARA_OPEN_NAMESPACE namespace Catch { +// #included from: ../external/clara.h + +// Version 0.0.1.1 + +// Only use header guard if we are not using an outer namespace +#if !defined(TWOBLUECUBES_CLARA_H_INCLUDED) || defined(STITCH_CLARA_OPEN_NAMESPACE) + +#ifndef STITCH_CLARA_OPEN_NAMESPACE +#define TWOBLUECUBES_CLARA_H_INCLUDED +#define STITCH_CLARA_OPEN_NAMESPACE +#define STITCH_CLARA_CLOSE_NAMESPACE +#else +#define STITCH_CLARA_CLOSE_NAMESPACE } +#endif + +#define STITCH_TBC_TEXT_FORMAT_OPEN_NAMESPACE STITCH_CLARA_OPEN_NAMESPACE + +// ----------- #included from tbc_text_format.h ----------- + +// Only use header guard if we are not using an outer namespace +#if !defined(TBC_TEXT_FORMAT_H_INCLUDED) || defined(STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE) +#ifndef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE +#define TBC_TEXT_FORMAT_H_INCLUDED +#endif + +#include +#include +#include +#include + +// Use optional outer namespace +#ifdef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE +namespace STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE { +#endif + +namespace Tbc { + +#ifdef TBC_TEXT_FORMAT_CONSOLE_WIDTH + const unsigned int consoleWidth = TBC_TEXT_FORMAT_CONSOLE_WIDTH; +#else + const unsigned int consoleWidth = 80; +#endif + + struct TextAttributes { + TextAttributes() + : initialIndent( std::string::npos ), + indent( 0 ), + width( consoleWidth-1 ), + tabChar( '\t' ) + {} + + TextAttributes& setInitialIndent( std::size_t _value ) { initialIndent = _value; return *this; } + TextAttributes& setIndent( std::size_t _value ) { indent = _value; return *this; } + TextAttributes& setWidth( std::size_t _value ) { width = _value; return *this; } + TextAttributes& setTabChar( char _value ) { tabChar = _value; return *this; } + + std::size_t initialIndent; // indent of first line, or npos + std::size_t indent; // indent of subsequent lines, or all if initialIndent is npos + std::size_t width; // maximum width of text, including indent. Longer text will wrap + char tabChar; // If this char is seen the indent is changed to current pos + }; + + class Text { + public: + Text( std::string const& _str, TextAttributes const& _attr = TextAttributes() ) + : attr( _attr ) + { + std::string wrappableChars = " [({.,/|\\-"; + std::size_t indent = _attr.initialIndent != std::string::npos + ? _attr.initialIndent + : _attr.indent; + std::string remainder = _str; + + while( !remainder.empty() ) { + if( lines.size() >= 1000 ) { + lines.push_back( "... message truncated due to excessive size" ); + return; + } + std::size_t tabPos = std::string::npos; + std::size_t width = (std::min)( remainder.size(), _attr.width - indent ); + std::size_t pos = remainder.find_first_of( '\n' ); + if( pos <= width ) { + width = pos; + } + pos = remainder.find_last_of( _attr.tabChar, width ); + if( pos != std::string::npos ) { + tabPos = pos; + if( remainder[width] == '\n' ) + width--; + remainder = remainder.substr( 0, tabPos ) + remainder.substr( tabPos+1 ); + } + + if( width == remainder.size() ) { + spliceLine( indent, remainder, width ); + } + else if( remainder[width] == '\n' ) { + spliceLine( indent, remainder, width ); + if( width <= 1 || remainder.size() != 1 ) + remainder = remainder.substr( 1 ); + indent = _attr.indent; + } + else { + pos = remainder.find_last_of( wrappableChars, width ); + if( pos != std::string::npos && pos > 0 ) { + spliceLine( indent, remainder, pos ); + if( remainder[0] == ' ' ) + remainder = remainder.substr( 1 ); + } + else { + spliceLine( indent, remainder, width-1 ); + lines.back() += "-"; + } + if( lines.size() == 1 ) + indent = _attr.indent; + if( tabPos != std::string::npos ) + indent += tabPos; + } + } + } + + void spliceLine( std::size_t _indent, std::string& _remainder, std::size_t _pos ) { + lines.push_back( std::string( _indent, ' ' ) + _remainder.substr( 0, _pos ) ); + _remainder = _remainder.substr( _pos ); + } + + typedef std::vector::const_iterator const_iterator; + + const_iterator begin() const { return lines.begin(); } + const_iterator end() const { return lines.end(); } + std::string const& last() const { return lines.back(); } + std::size_t size() const { return lines.size(); } + std::string const& operator[]( std::size_t _index ) const { return lines[_index]; } + std::string toString() const { + std::ostringstream oss; + oss << *this; + return oss.str(); + } + + inline friend std::ostream& operator << ( std::ostream& _stream, Text const& _text ) { + for( Text::const_iterator it = _text.begin(), itEnd = _text.end(); + it != itEnd; ++it ) { + if( it != _text.begin() ) + _stream << "\n"; + _stream << *it; + } + return _stream; + } + + private: + std::string str; + TextAttributes attr; + std::vector lines; + }; + +} // end namespace Tbc + +#ifdef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE +} // end outer namespace +#endif + +#endif // TBC_TEXT_FORMAT_H_INCLUDED + +// ----------- end of #include from tbc_text_format.h ----------- +// ........... back in clara.h + +#undef STITCH_TBC_TEXT_FORMAT_OPEN_NAMESPACE + +// ----------- #included from clara_compilers.h ----------- + +#ifndef TWOBLUECUBES_CLARA_COMPILERS_H_INCLUDED +#define TWOBLUECUBES_CLARA_COMPILERS_H_INCLUDED + +// Detect a number of compiler features - mostly C++11/14 conformance - by compiler +// The following features are defined: +// +// CLARA_CONFIG_CPP11_NULLPTR : is nullptr supported? +// CLARA_CONFIG_CPP11_NOEXCEPT : is noexcept supported? +// CLARA_CONFIG_CPP11_GENERATED_METHODS : The delete and default keywords for compiler generated methods +// CLARA_CONFIG_CPP11_OVERRIDE : is override supported? +// CLARA_CONFIG_CPP11_UNIQUE_PTR : is unique_ptr supported (otherwise use auto_ptr) + +// CLARA_CONFIG_CPP11_OR_GREATER : Is C++11 supported? + +// CLARA_CONFIG_VARIADIC_MACROS : are variadic macros supported? + +// In general each macro has a _NO_ form +// (e.g. CLARA_CONFIG_CPP11_NO_NULLPTR) which disables the feature. +// Many features, at point of detection, define an _INTERNAL_ macro, so they +// can be combined, en-mass, with the _NO_ forms later. + +// All the C++11 features can be disabled with CLARA_CONFIG_NO_CPP11 + +#ifdef __clang__ + +#if __has_feature(cxx_nullptr) +#define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR +#endif + +#if __has_feature(cxx_noexcept) +#define CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT +#endif + +#endif // __clang__ + +//////////////////////////////////////////////////////////////////////////////// +// GCC +#ifdef __GNUC__ + +#if __GNUC__ == 4 && __GNUC_MINOR__ >= 6 && defined(__GXX_EXPERIMENTAL_CXX0X__) +#define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR +#endif + +// - otherwise more recent versions define __cplusplus >= 201103L +// and will get picked up below + +#endif // __GNUC__ + +//////////////////////////////////////////////////////////////////////////////// +// Visual C++ +#ifdef _MSC_VER + +#if (_MSC_VER >= 1600) +#define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR +#define CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR +#endif + +#if (_MSC_VER >= 1900 ) // (VC++ 13 (VS2015)) +#define CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT +#define CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS +#endif + +#endif // _MSC_VER + +//////////////////////////////////////////////////////////////////////////////// +// C++ language feature support + +// catch all support for C++11 +#if defined(__cplusplus) && __cplusplus >= 201103L + +#define CLARA_CPP11_OR_GREATER + +#if !defined(CLARA_INTERNAL_CONFIG_CPP11_NULLPTR) +#define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR +#endif + +#ifndef CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT +#define CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT +#endif + +#ifndef CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS +#define CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS +#endif + +#if !defined(CLARA_INTERNAL_CONFIG_CPP11_OVERRIDE) +#define CLARA_INTERNAL_CONFIG_CPP11_OVERRIDE +#endif +#if !defined(CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) +#define CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR +#endif + +#endif // __cplusplus >= 201103L + +// Now set the actual defines based on the above + anything the user has configured +#if defined(CLARA_INTERNAL_CONFIG_CPP11_NULLPTR) && !defined(CLARA_CONFIG_CPP11_NO_NULLPTR) && !defined(CLARA_CONFIG_CPP11_NULLPTR) && !defined(CLARA_CONFIG_NO_CPP11) +#define CLARA_CONFIG_CPP11_NULLPTR +#endif +#if defined(CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT) && !defined(CLARA_CONFIG_CPP11_NO_NOEXCEPT) && !defined(CLARA_CONFIG_CPP11_NOEXCEPT) && !defined(CLARA_CONFIG_NO_CPP11) +#define CLARA_CONFIG_CPP11_NOEXCEPT +#endif +#if defined(CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS) && !defined(CLARA_CONFIG_CPP11_NO_GENERATED_METHODS) && !defined(CLARA_CONFIG_CPP11_GENERATED_METHODS) && !defined(CLARA_CONFIG_NO_CPP11) +#define CLARA_CONFIG_CPP11_GENERATED_METHODS +#endif +#if defined(CLARA_INTERNAL_CONFIG_CPP11_OVERRIDE) && !defined(CLARA_CONFIG_NO_OVERRIDE) && !defined(CLARA_CONFIG_CPP11_OVERRIDE) && !defined(CLARA_CONFIG_NO_CPP11) +#define CLARA_CONFIG_CPP11_OVERRIDE +#endif +#if defined(CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) && !defined(CLARA_CONFIG_NO_UNIQUE_PTR) && !defined(CLARA_CONFIG_CPP11_UNIQUE_PTR) && !defined(CLARA_CONFIG_NO_CPP11) +#define CLARA_CONFIG_CPP11_UNIQUE_PTR +#endif + +// noexcept support: +#if defined(CLARA_CONFIG_CPP11_NOEXCEPT) && !defined(CLARA_NOEXCEPT) +#define CLARA_NOEXCEPT noexcept +# define CLARA_NOEXCEPT_IS(x) noexcept(x) +#else +#define CLARA_NOEXCEPT throw() +# define CLARA_NOEXCEPT_IS(x) +#endif + +// nullptr support +#ifdef CLARA_CONFIG_CPP11_NULLPTR +#define CLARA_NULL nullptr +#else +#define CLARA_NULL NULL +#endif + +// override support +#ifdef CLARA_CONFIG_CPP11_OVERRIDE +#define CLARA_OVERRIDE override +#else +#define CLARA_OVERRIDE +#endif + +// unique_ptr support +#ifdef CLARA_CONFIG_CPP11_UNIQUE_PTR +# define CLARA_AUTO_PTR( T ) std::unique_ptr +#else +# define CLARA_AUTO_PTR( T ) std::auto_ptr +#endif + +#endif // TWOBLUECUBES_CLARA_COMPILERS_H_INCLUDED + +// ----------- end of #include from clara_compilers.h ----------- +// ........... back in clara.h + +#include +#include +#include + +// Use optional outer namespace +#ifdef STITCH_CLARA_OPEN_NAMESPACE +STITCH_CLARA_OPEN_NAMESPACE +#endif + +namespace Clara { + + struct UnpositionalTag {}; + + extern UnpositionalTag _; + +#ifdef CLARA_CONFIG_MAIN + UnpositionalTag _; +#endif + + namespace Detail { + +#ifdef CLARA_CONSOLE_WIDTH + const unsigned int consoleWidth = CLARA_CONFIG_CONSOLE_WIDTH; +#else + const unsigned int consoleWidth = 80; +#endif + + // Use this to try and stop compiler from warning about unreachable code + inline bool isTrue( bool value ) { return value; } + + using namespace Tbc; + + inline bool startsWith( std::string const& str, std::string const& prefix ) { + return str.size() >= prefix.size() && str.substr( 0, prefix.size() ) == prefix; + } + + template struct RemoveConstRef{ typedef T type; }; + template struct RemoveConstRef{ typedef T type; }; + template struct RemoveConstRef{ typedef T type; }; + template struct RemoveConstRef{ typedef T type; }; + + template struct IsBool { static const bool value = false; }; + template<> struct IsBool { static const bool value = true; }; + + template + void convertInto( std::string const& _source, T& _dest ) { + std::stringstream ss; + ss << _source; + ss >> _dest; + if( ss.fail() ) + throw std::runtime_error( "Unable to convert " + _source + " to destination type" ); + } + inline void convertInto( std::string const& _source, std::string& _dest ) { + _dest = _source; + } + inline void convertInto( std::string const& _source, bool& _dest ) { + std::string sourceLC = _source; + std::transform( sourceLC.begin(), sourceLC.end(), sourceLC.begin(), ::tolower ); + if( sourceLC == "y" || sourceLC == "1" || sourceLC == "true" || sourceLC == "yes" || sourceLC == "on" ) + _dest = true; + else if( sourceLC == "n" || sourceLC == "0" || sourceLC == "false" || sourceLC == "no" || sourceLC == "off" ) + _dest = false; + else + throw std::runtime_error( "Expected a boolean value but did not recognise:\n '" + _source + "'" ); + } + inline void convertInto( bool _source, bool& _dest ) { + _dest = _source; + } + template + inline void convertInto( bool, T& ) { + if( isTrue( true ) ) + throw std::runtime_error( "Invalid conversion" ); + } + + template + struct IArgFunction { + virtual ~IArgFunction() {} +#ifdef CLARA_CONFIG_CPP11_GENERATED_METHODS + IArgFunction() = default; + IArgFunction( IArgFunction const& ) = default; +#endif + virtual void set( ConfigT& config, std::string const& value ) const = 0; + virtual void setFlag( ConfigT& config ) const = 0; + virtual bool takesArg() const = 0; + virtual IArgFunction* clone() const = 0; + }; + + template + class BoundArgFunction { + public: + BoundArgFunction() : functionObj( CLARA_NULL ) {} + BoundArgFunction( IArgFunction* _functionObj ) : functionObj( _functionObj ) {} + BoundArgFunction( BoundArgFunction const& other ) : functionObj( other.functionObj ? other.functionObj->clone() : CLARA_NULL ) {} + BoundArgFunction& operator = ( BoundArgFunction const& other ) { + IArgFunction* newFunctionObj = other.functionObj ? other.functionObj->clone() : CLARA_NULL; + delete functionObj; + functionObj = newFunctionObj; + return *this; + } + ~BoundArgFunction() { delete functionObj; } + + void set( ConfigT& config, std::string const& value ) const { + functionObj->set( config, value ); + } + void setFlag( ConfigT& config ) const { + functionObj->setFlag( config ); + } + bool takesArg() const { return functionObj->takesArg(); } + + bool isSet() const { + return functionObj != CLARA_NULL; + } + private: + IArgFunction* functionObj; + }; + + template + struct NullBinder : IArgFunction{ + virtual void set( C&, std::string const& ) const {} + virtual void setFlag( C& ) const {} + virtual bool takesArg() const { return true; } + virtual IArgFunction* clone() const { return new NullBinder( *this ); } + }; + + template + struct BoundDataMember : IArgFunction{ + BoundDataMember( M C::* _member ) : member( _member ) {} + virtual void set( C& p, std::string const& stringValue ) const { + convertInto( stringValue, p.*member ); + } + virtual void setFlag( C& p ) const { + convertInto( true, p.*member ); + } + virtual bool takesArg() const { return !IsBool::value; } + virtual IArgFunction* clone() const { return new BoundDataMember( *this ); } + M C::* member; + }; + template + struct BoundUnaryMethod : IArgFunction{ + BoundUnaryMethod( void (C::*_member)( M ) ) : member( _member ) {} + virtual void set( C& p, std::string const& stringValue ) const { + typename RemoveConstRef::type value; + convertInto( stringValue, value ); + (p.*member)( value ); + } + virtual void setFlag( C& p ) const { + typename RemoveConstRef::type value; + convertInto( true, value ); + (p.*member)( value ); + } + virtual bool takesArg() const { return !IsBool::value; } + virtual IArgFunction* clone() const { return new BoundUnaryMethod( *this ); } + void (C::*member)( M ); + }; + template + struct BoundNullaryMethod : IArgFunction{ + BoundNullaryMethod( void (C::*_member)() ) : member( _member ) {} + virtual void set( C& p, std::string const& stringValue ) const { + bool value; + convertInto( stringValue, value ); + if( value ) + (p.*member)(); + } + virtual void setFlag( C& p ) const { + (p.*member)(); + } + virtual bool takesArg() const { return false; } + virtual IArgFunction* clone() const { return new BoundNullaryMethod( *this ); } + void (C::*member)(); + }; + + template + struct BoundUnaryFunction : IArgFunction{ + BoundUnaryFunction( void (*_function)( C& ) ) : function( _function ) {} + virtual void set( C& obj, std::string const& stringValue ) const { + bool value; + convertInto( stringValue, value ); + if( value ) + function( obj ); + } + virtual void setFlag( C& p ) const { + function( p ); + } + virtual bool takesArg() const { return false; } + virtual IArgFunction* clone() const { return new BoundUnaryFunction( *this ); } + void (*function)( C& ); + }; + + template + struct BoundBinaryFunction : IArgFunction{ + BoundBinaryFunction( void (*_function)( C&, T ) ) : function( _function ) {} + virtual void set( C& obj, std::string const& stringValue ) const { + typename RemoveConstRef::type value; + convertInto( stringValue, value ); + function( obj, value ); + } + virtual void setFlag( C& obj ) const { + typename RemoveConstRef::type value; + convertInto( true, value ); + function( obj, value ); + } + virtual bool takesArg() const { return !IsBool::value; } + virtual IArgFunction* clone() const { return new BoundBinaryFunction( *this ); } + void (*function)( C&, T ); + }; + + } // namespace Detail + + struct Parser { + Parser() : separators( " \t=:" ) {} + + struct Token { + enum Type { Positional, ShortOpt, LongOpt }; + Token( Type _type, std::string const& _data ) : type( _type ), data( _data ) {} + Type type; + std::string data; + }; + + void parseIntoTokens( int argc, char const* const argv[], std::vector& tokens ) const { + const std::string doubleDash = "--"; + for( int i = 1; i < argc && argv[i] != doubleDash; ++i ) + parseIntoTokens( argv[i] , tokens); + } + void parseIntoTokens( std::string arg, std::vector& tokens ) const { + while( !arg.empty() ) { + Parser::Token token( Parser::Token::Positional, arg ); + arg = ""; + if( token.data[0] == '-' ) { + if( token.data.size() > 1 && token.data[1] == '-' ) { + token = Parser::Token( Parser::Token::LongOpt, token.data.substr( 2 ) ); + } + else { + token = Parser::Token( Parser::Token::ShortOpt, token.data.substr( 1 ) ); + if( token.data.size() > 1 && separators.find( token.data[1] ) == std::string::npos ) { + arg = "-" + token.data.substr( 1 ); + token.data = token.data.substr( 0, 1 ); + } + } + } + if( token.type != Parser::Token::Positional ) { + std::size_t pos = token.data.find_first_of( separators ); + if( pos != std::string::npos ) { + arg = token.data.substr( pos+1 ); + token.data = token.data.substr( 0, pos ); + } + } + tokens.push_back( token ); + } + } + std::string separators; + }; + + template + struct CommonArgProperties { + CommonArgProperties() {} + CommonArgProperties( Detail::BoundArgFunction const& _boundField ) : boundField( _boundField ) {} + + Detail::BoundArgFunction boundField; + std::string description; + std::string detail; + std::string placeholder; // Only value if boundField takes an arg + + bool takesArg() const { + return !placeholder.empty(); + } + void validate() const { + if( !boundField.isSet() ) + throw std::logic_error( "option not bound" ); + } + }; + struct OptionArgProperties { + std::vector shortNames; + std::string longName; + + bool hasShortName( std::string const& shortName ) const { + return std::find( shortNames.begin(), shortNames.end(), shortName ) != shortNames.end(); + } + bool hasLongName( std::string const& _longName ) const { + return _longName == longName; + } + }; + struct PositionalArgProperties { + PositionalArgProperties() : position( -1 ) {} + int position; // -1 means non-positional (floating) + + bool isFixedPositional() const { + return position != -1; + } + }; + + template + class CommandLine { + + struct Arg : CommonArgProperties, OptionArgProperties, PositionalArgProperties { + Arg() {} + Arg( Detail::BoundArgFunction const& _boundField ) : CommonArgProperties( _boundField ) {} + + using CommonArgProperties::placeholder; // !TBD + + std::string dbgName() const { + if( !longName.empty() ) + return "--" + longName; + if( !shortNames.empty() ) + return "-" + shortNames[0]; + return "positional args"; + } + std::string commands() const { + std::ostringstream oss; + bool first = true; + std::vector::const_iterator it = shortNames.begin(), itEnd = shortNames.end(); + for(; it != itEnd; ++it ) { + if( first ) + first = false; + else + oss << ", "; + oss << "-" << *it; + } + if( !longName.empty() ) { + if( !first ) + oss << ", "; + oss << "--" << longName; + } + if( !placeholder.empty() ) + oss << " <" << placeholder << ">"; + return oss.str(); + } + }; + + typedef CLARA_AUTO_PTR( Arg ) ArgAutoPtr; + + friend void addOptName( Arg& arg, std::string const& optName ) + { + if( optName.empty() ) + return; + if( Detail::startsWith( optName, "--" ) ) { + if( !arg.longName.empty() ) + throw std::logic_error( "Only one long opt may be specified. '" + + arg.longName + + "' already specified, now attempting to add '" + + optName + "'" ); + arg.longName = optName.substr( 2 ); + } + else if( Detail::startsWith( optName, "-" ) ) + arg.shortNames.push_back( optName.substr( 1 ) ); + else + throw std::logic_error( "option must begin with - or --. Option was: '" + optName + "'" ); + } + friend void setPositionalArg( Arg& arg, int position ) + { + arg.position = position; + } + + class ArgBuilder { + public: + ArgBuilder( Arg* arg ) : m_arg( arg ) {} + + // Bind a non-boolean data member (requires placeholder string) + template + void bind( M C::* field, std::string const& placeholder ) { + m_arg->boundField = new Detail::BoundDataMember( field ); + m_arg->placeholder = placeholder; + } + // Bind a boolean data member (no placeholder required) + template + void bind( bool C::* field ) { + m_arg->boundField = new Detail::BoundDataMember( field ); + } + + // Bind a method taking a single, non-boolean argument (requires a placeholder string) + template + void bind( void (C::* unaryMethod)( M ), std::string const& placeholder ) { + m_arg->boundField = new Detail::BoundUnaryMethod( unaryMethod ); + m_arg->placeholder = placeholder; + } + + // Bind a method taking a single, boolean argument (no placeholder string required) + template + void bind( void (C::* unaryMethod)( bool ) ) { + m_arg->boundField = new Detail::BoundUnaryMethod( unaryMethod ); + } + + // Bind a method that takes no arguments (will be called if opt is present) + template + void bind( void (C::* nullaryMethod)() ) { + m_arg->boundField = new Detail::BoundNullaryMethod( nullaryMethod ); + } + + // Bind a free function taking a single argument - the object to operate on (no placeholder string required) + template + void bind( void (* unaryFunction)( C& ) ) { + m_arg->boundField = new Detail::BoundUnaryFunction( unaryFunction ); + } + + // Bind a free function taking a single argument - the object to operate on (requires a placeholder string) + template + void bind( void (* binaryFunction)( C&, T ), std::string const& placeholder ) { + m_arg->boundField = new Detail::BoundBinaryFunction( binaryFunction ); + m_arg->placeholder = placeholder; + } + + ArgBuilder& describe( std::string const& description ) { + m_arg->description = description; + return *this; + } + ArgBuilder& detail( std::string const& detail ) { + m_arg->detail = detail; + return *this; + } + + protected: + Arg* m_arg; + }; + + class OptBuilder : public ArgBuilder { + public: + OptBuilder( Arg* arg ) : ArgBuilder( arg ) {} + OptBuilder( OptBuilder& other ) : ArgBuilder( other ) {} + + OptBuilder& operator[]( std::string const& optName ) { + addOptName( *ArgBuilder::m_arg, optName ); + return *this; + } + }; + + public: + + CommandLine() + : m_boundProcessName( new Detail::NullBinder() ), + m_highestSpecifiedArgPosition( 0 ), + m_throwOnUnrecognisedTokens( false ) + {} + CommandLine( CommandLine const& other ) + : m_boundProcessName( other.m_boundProcessName ), + m_options ( other.m_options ), + m_positionalArgs( other.m_positionalArgs ), + m_highestSpecifiedArgPosition( other.m_highestSpecifiedArgPosition ), + m_throwOnUnrecognisedTokens( other.m_throwOnUnrecognisedTokens ) + { + if( other.m_floatingArg.get() ) + m_floatingArg.reset( new Arg( *other.m_floatingArg ) ); + } + + CommandLine& setThrowOnUnrecognisedTokens( bool shouldThrow = true ) { + m_throwOnUnrecognisedTokens = shouldThrow; + return *this; + } + + OptBuilder operator[]( std::string const& optName ) { + m_options.push_back( Arg() ); + addOptName( m_options.back(), optName ); + OptBuilder builder( &m_options.back() ); + return builder; + } + + ArgBuilder operator[]( int position ) { + m_positionalArgs.insert( std::make_pair( position, Arg() ) ); + if( position > m_highestSpecifiedArgPosition ) + m_highestSpecifiedArgPosition = position; + setPositionalArg( m_positionalArgs[position], position ); + ArgBuilder builder( &m_positionalArgs[position] ); + return builder; + } + + // Invoke this with the _ instance + ArgBuilder operator[]( UnpositionalTag ) { + if( m_floatingArg.get() ) + throw std::logic_error( "Only one unpositional argument can be added" ); + m_floatingArg.reset( new Arg() ); + ArgBuilder builder( m_floatingArg.get() ); + return builder; + } + + template + void bindProcessName( M C::* field ) { + m_boundProcessName = new Detail::BoundDataMember( field ); + } + template + void bindProcessName( void (C::*_unaryMethod)( M ) ) { + m_boundProcessName = new Detail::BoundUnaryMethod( _unaryMethod ); + } + + void optUsage( std::ostream& os, std::size_t indent = 0, std::size_t width = Detail::consoleWidth ) const { + typename std::vector::const_iterator itBegin = m_options.begin(), itEnd = m_options.end(), it; + std::size_t maxWidth = 0; + for( it = itBegin; it != itEnd; ++it ) + maxWidth = (std::max)( maxWidth, it->commands().size() ); + + for( it = itBegin; it != itEnd; ++it ) { + Detail::Text usage( it->commands(), Detail::TextAttributes() + .setWidth( maxWidth+indent ) + .setIndent( indent ) ); + Detail::Text desc( it->description, Detail::TextAttributes() + .setWidth( width - maxWidth - 3 ) ); + + for( std::size_t i = 0; i < (std::max)( usage.size(), desc.size() ); ++i ) { + std::string usageCol = i < usage.size() ? usage[i] : ""; + os << usageCol; + + if( i < desc.size() && !desc[i].empty() ) + os << std::string( indent + 2 + maxWidth - usageCol.size(), ' ' ) + << desc[i]; + os << "\n"; + } + } + } + std::string optUsage() const { + std::ostringstream oss; + optUsage( oss ); + return oss.str(); + } + + void argSynopsis( std::ostream& os ) const { + for( int i = 1; i <= m_highestSpecifiedArgPosition; ++i ) { + if( i > 1 ) + os << " "; + typename std::map::const_iterator it = m_positionalArgs.find( i ); + if( it != m_positionalArgs.end() ) + os << "<" << it->second.placeholder << ">"; + else if( m_floatingArg.get() ) + os << "<" << m_floatingArg->placeholder << ">"; + else + throw std::logic_error( "non consecutive positional arguments with no floating args" ); + } + // !TBD No indication of mandatory args + if( m_floatingArg.get() ) { + if( m_highestSpecifiedArgPosition > 1 ) + os << " "; + os << "[<" << m_floatingArg->placeholder << "> ...]"; + } + } + std::string argSynopsis() const { + std::ostringstream oss; + argSynopsis( oss ); + return oss.str(); + } + + void usage( std::ostream& os, std::string const& procName ) const { + validate(); + os << "usage:\n " << procName << " "; + argSynopsis( os ); + if( !m_options.empty() ) { + os << " [options]\n\nwhere options are: \n"; + optUsage( os, 2 ); + } + os << "\n"; + } + std::string usage( std::string const& procName ) const { + std::ostringstream oss; + usage( oss, procName ); + return oss.str(); + } + + ConfigT parse( int argc, char const* const argv[] ) const { + ConfigT config; + parseInto( argc, argv, config ); + return config; + } + + std::vector parseInto( int argc, char const* argv[], ConfigT& config ) const { + std::string processName = argv[0]; + std::size_t lastSlash = processName.find_last_of( "/\\" ); + if( lastSlash != std::string::npos ) + processName = processName.substr( lastSlash+1 ); + m_boundProcessName.set( config, processName ); + std::vector tokens; + Parser parser; + parser.parseIntoTokens( argc, argv, tokens ); + return populate( tokens, config ); + } + + std::vector populate( std::vector const& tokens, ConfigT& config ) const { + validate(); + std::vector unusedTokens = populateOptions( tokens, config ); + unusedTokens = populateFixedArgs( unusedTokens, config ); + unusedTokens = populateFloatingArgs( unusedTokens, config ); + return unusedTokens; + } + + std::vector populateOptions( std::vector const& tokens, ConfigT& config ) const { + std::vector unusedTokens; + std::vector errors; + for( std::size_t i = 0; i < tokens.size(); ++i ) { + Parser::Token const& token = tokens[i]; + typename std::vector::const_iterator it = m_options.begin(), itEnd = m_options.end(); + for(; it != itEnd; ++it ) { + Arg const& arg = *it; + + try { + if( ( token.type == Parser::Token::ShortOpt && arg.hasShortName( token.data ) ) || + ( token.type == Parser::Token::LongOpt && arg.hasLongName( token.data ) ) ) { + if( arg.takesArg() ) { + if( i == tokens.size()-1 || tokens[i+1].type != Parser::Token::Positional ) + errors.push_back( "Expected argument to option: " + token.data ); + else + arg.boundField.set( config, tokens[++i].data ); + } + else { + arg.boundField.setFlag( config ); + } + break; + } + } + catch( std::exception& ex ) { + errors.push_back( std::string( ex.what() ) + "\n- while parsing: (" + arg.commands() + ")" ); + } + } + if( it == itEnd ) { + if( token.type == Parser::Token::Positional || !m_throwOnUnrecognisedTokens ) + unusedTokens.push_back( token ); + else if( errors.empty() && m_throwOnUnrecognisedTokens ) + errors.push_back( "unrecognised option: " + token.data ); + } + } + if( !errors.empty() ) { + std::ostringstream oss; + for( std::vector::const_iterator it = errors.begin(), itEnd = errors.end(); + it != itEnd; + ++it ) { + if( it != errors.begin() ) + oss << "\n"; + oss << *it; + } + throw std::runtime_error( oss.str() ); + } + return unusedTokens; + } + std::vector populateFixedArgs( std::vector const& tokens, ConfigT& config ) const { + std::vector unusedTokens; + int position = 1; + for( std::size_t i = 0; i < tokens.size(); ++i ) { + Parser::Token const& token = tokens[i]; + typename std::map::const_iterator it = m_positionalArgs.find( position ); + if( it != m_positionalArgs.end() ) + it->second.boundField.set( config, token.data ); + else + unusedTokens.push_back( token ); + if( token.type == Parser::Token::Positional ) + position++; + } + return unusedTokens; + } + std::vector populateFloatingArgs( std::vector const& tokens, ConfigT& config ) const { + if( !m_floatingArg.get() ) + return tokens; + std::vector unusedTokens; + for( std::size_t i = 0; i < tokens.size(); ++i ) { + Parser::Token const& token = tokens[i]; + if( token.type == Parser::Token::Positional ) + m_floatingArg->boundField.set( config, token.data ); + else + unusedTokens.push_back( token ); + } + return unusedTokens; + } + + void validate() const + { + if( m_options.empty() && m_positionalArgs.empty() && !m_floatingArg.get() ) + throw std::logic_error( "No options or arguments specified" ); + + for( typename std::vector::const_iterator it = m_options.begin(), + itEnd = m_options.end(); + it != itEnd; ++it ) + it->validate(); + } + + private: + Detail::BoundArgFunction m_boundProcessName; + std::vector m_options; + std::map m_positionalArgs; + ArgAutoPtr m_floatingArg; + int m_highestSpecifiedArgPosition; + bool m_throwOnUnrecognisedTokens; + }; + +} // end namespace Clara + +STITCH_CLARA_CLOSE_NAMESPACE +#undef STITCH_CLARA_OPEN_NAMESPACE +#undef STITCH_CLARA_CLOSE_NAMESPACE + +#endif // TWOBLUECUBES_CLARA_H_INCLUDED +#undef STITCH_CLARA_OPEN_NAMESPACE + +// Restore Clara's value for console width, if present +#ifdef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH +#define CLARA_CONFIG_CONSOLE_WIDTH CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH +#undef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH +#endif + +#include + +namespace Catch { + + inline void abortAfterFirst( ConfigData& config ) { config.abortAfter = 1; } + inline void abortAfterX( ConfigData& config, int x ) { + if( x < 1 ) + throw std::runtime_error( "Value after -x or --abortAfter must be greater than zero" ); + config.abortAfter = x; + } + inline void addTestOrTags( ConfigData& config, std::string const& _testSpec ) { config.testsOrTags.push_back( _testSpec ); } + inline void addReporterName( ConfigData& config, std::string const& _reporterName ) { config.reporterNames.push_back( _reporterName ); } + + inline void addWarning( ConfigData& config, std::string const& _warning ) { + if( _warning == "NoAssertions" ) + config.warnings = static_cast( config.warnings | WarnAbout::NoAssertions ); + else + throw std::runtime_error( "Unrecognised warning: '" + _warning + "'" ); + } + inline void setOrder( ConfigData& config, std::string const& order ) { + if( startsWith( "declared", order ) ) + config.runOrder = RunTests::InDeclarationOrder; + else if( startsWith( "lexical", order ) ) + config.runOrder = RunTests::InLexicographicalOrder; + else if( startsWith( "random", order ) ) + config.runOrder = RunTests::InRandomOrder; + else + throw std::runtime_error( "Unrecognised ordering: '" + order + "'" ); + } + inline void setRngSeed( ConfigData& config, std::string const& seed ) { + if( seed == "time" ) { + config.rngSeed = static_cast( std::time(0) ); + } + else { + std::stringstream ss; + ss << seed; + ss >> config.rngSeed; + if( ss.fail() ) + throw std::runtime_error( "Argment to --rng-seed should be the word 'time' or a number" ); + } + } + inline void setVerbosity( ConfigData& config, int level ) { + // !TBD: accept strings? + config.verbosity = static_cast( level ); + } + inline void setShowDurations( ConfigData& config, bool _showDurations ) { + config.showDurations = _showDurations + ? ShowDurations::Always + : ShowDurations::Never; + } + inline void setUseColour( ConfigData& config, std::string const& value ) { + std::string mode = toLower( value ); + + if( mode == "yes" ) + config.useColour = UseColour::Yes; + else if( mode == "no" ) + config.useColour = UseColour::No; + else if( mode == "auto" ) + config.useColour = UseColour::Auto; + else + throw std::runtime_error( "colour mode must be one of: auto, yes or no" ); + } + inline void forceColour( ConfigData& config ) { + config.useColour = UseColour::Yes; + } + inline void loadTestNamesFromFile( ConfigData& config, std::string const& _filename ) { + std::ifstream f( _filename.c_str() ); + if( !f.is_open() ) + throw std::domain_error( "Unable to load input file: " + _filename ); + + std::string line; + while( std::getline( f, line ) ) { + line = trim(line); + if( !line.empty() && !startsWith( line, "#" ) ) + addTestOrTags( config, "\"" + line + "\"," ); + } + } + + inline Clara::CommandLine makeCommandLineParser() { + + using namespace Clara; + CommandLine cli; + + cli.bindProcessName( &ConfigData::processName ); + + cli["-?"]["-h"]["--help"] + .describe( "display usage information" ) + .bind( &ConfigData::showHelp ); + + cli["-l"]["--list-tests"] + .describe( "list all/matching test cases" ) + .bind( &ConfigData::listTests ); + + cli["-t"]["--list-tags"] + .describe( "list all/matching tags" ) + .bind( &ConfigData::listTags ); + + cli["-s"]["--success"] + .describe( "include successful tests in output" ) + .bind( &ConfigData::showSuccessfulTests ); + + cli["-b"]["--break"] + .describe( "break into debugger on failure" ) + .bind( &ConfigData::shouldDebugBreak ); + + cli["-e"]["--nothrow"] + .describe( "skip exception tests" ) + .bind( &ConfigData::noThrow ); + + cli["-i"]["--invisibles"] + .describe( "show invisibles (tabs, newlines)" ) + .bind( &ConfigData::showInvisibles ); + + cli["-o"]["--out"] + .describe( "output filename" ) + .bind( &ConfigData::outputFilename, "filename" ); + + cli["-r"]["--reporter"] +// .placeholder( "name[:filename]" ) + .describe( "reporter to use (defaults to console)" ) + .bind( &addReporterName, "name" ); + + cli["-n"]["--name"] + .describe( "suite name" ) + .bind( &ConfigData::name, "name" ); + + cli["-a"]["--abort"] + .describe( "abort at first failure" ) + .bind( &abortAfterFirst ); + + cli["-x"]["--abortx"] + .describe( "abort after x failures" ) + .bind( &abortAfterX, "no. failures" ); + + cli["-w"]["--warn"] + .describe( "enable warnings" ) + .bind( &addWarning, "warning name" ); + +// - needs updating if reinstated +// cli.into( &setVerbosity ) +// .describe( "level of verbosity (0=no output)" ) +// .shortOpt( "v") +// .longOpt( "verbosity" ) +// .placeholder( "level" ); + + cli[_] + .describe( "which test or tests to use" ) + .bind( &addTestOrTags, "test name, pattern or tags" ); + + cli["-d"]["--durations"] + .describe( "show test durations" ) + .bind( &setShowDurations, "yes|no" ); + + cli["-f"]["--input-file"] + .describe( "load test names to run from a file" ) + .bind( &loadTestNamesFromFile, "filename" ); + + cli["-#"]["--filenames-as-tags"] + .describe( "adds a tag for the filename" ) + .bind( &ConfigData::filenamesAsTags ); + + // Less common commands which don't have a short form + cli["--list-test-names-only"] + .describe( "list all/matching test cases names only" ) + .bind( &ConfigData::listTestNamesOnly ); + + cli["--list-reporters"] + .describe( "list all reporters" ) + .bind( &ConfigData::listReporters ); + + cli["--order"] + .describe( "test case order (defaults to decl)" ) + .bind( &setOrder, "decl|lex|rand" ); + + cli["--rng-seed"] + .describe( "set a specific seed for random numbers" ) + .bind( &setRngSeed, "'time'|number" ); + + cli["--force-colour"] + .describe( "force colourised output (deprecated)" ) + .bind( &forceColour ); + + cli["--use-colour"] + .describe( "should output be colourised" ) + .bind( &setUseColour, "yes|no" ); + + return cli; + } + +} // end namespace Catch + +// #included from: internal/catch_list.hpp +#define TWOBLUECUBES_CATCH_LIST_HPP_INCLUDED + +// #included from: catch_text.h +#define TWOBLUECUBES_CATCH_TEXT_H_INCLUDED + +#define TBC_TEXT_FORMAT_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH + +#define CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE Catch +// #included from: ../external/tbc_text_format.h +// Only use header guard if we are not using an outer namespace +#ifndef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE +# ifdef TWOBLUECUBES_TEXT_FORMAT_H_INCLUDED +# ifndef TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED +# define TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED +# endif +# else +# define TWOBLUECUBES_TEXT_FORMAT_H_INCLUDED +# endif +#endif +#ifndef TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED +#include +#include +#include + +// Use optional outer namespace +#ifdef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE +namespace CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE { +#endif + +namespace Tbc { + +#ifdef TBC_TEXT_FORMAT_CONSOLE_WIDTH + const unsigned int consoleWidth = TBC_TEXT_FORMAT_CONSOLE_WIDTH; +#else + const unsigned int consoleWidth = 80; +#endif + + struct TextAttributes { + TextAttributes() + : initialIndent( std::string::npos ), + indent( 0 ), + width( consoleWidth-1 ), + tabChar( '\t' ) + {} + + TextAttributes& setInitialIndent( std::size_t _value ) { initialIndent = _value; return *this; } + TextAttributes& setIndent( std::size_t _value ) { indent = _value; return *this; } + TextAttributes& setWidth( std::size_t _value ) { width = _value; return *this; } + TextAttributes& setTabChar( char _value ) { tabChar = _value; return *this; } + + std::size_t initialIndent; // indent of first line, or npos + std::size_t indent; // indent of subsequent lines, or all if initialIndent is npos + std::size_t width; // maximum width of text, including indent. Longer text will wrap + char tabChar; // If this char is seen the indent is changed to current pos + }; + + class Text { + public: + Text( std::string const& _str, TextAttributes const& _attr = TextAttributes() ) + : attr( _attr ) + { + std::string wrappableChars = " [({.,/|\\-"; + std::size_t indent = _attr.initialIndent != std::string::npos + ? _attr.initialIndent + : _attr.indent; + std::string remainder = _str; + + while( !remainder.empty() ) { + if( lines.size() >= 1000 ) { + lines.push_back( "... message truncated due to excessive size" ); + return; + } + std::size_t tabPos = std::string::npos; + std::size_t width = (std::min)( remainder.size(), _attr.width - indent ); + std::size_t pos = remainder.find_first_of( '\n' ); + if( pos <= width ) { + width = pos; + } + pos = remainder.find_last_of( _attr.tabChar, width ); + if( pos != std::string::npos ) { + tabPos = pos; + if( remainder[width] == '\n' ) + width--; + remainder = remainder.substr( 0, tabPos ) + remainder.substr( tabPos+1 ); + } + + if( width == remainder.size() ) { + spliceLine( indent, remainder, width ); + } + else if( remainder[width] == '\n' ) { + spliceLine( indent, remainder, width ); + if( width <= 1 || remainder.size() != 1 ) + remainder = remainder.substr( 1 ); + indent = _attr.indent; + } + else { + pos = remainder.find_last_of( wrappableChars, width ); + if( pos != std::string::npos && pos > 0 ) { + spliceLine( indent, remainder, pos ); + if( remainder[0] == ' ' ) + remainder = remainder.substr( 1 ); + } + else { + spliceLine( indent, remainder, width-1 ); + lines.back() += "-"; + } + if( lines.size() == 1 ) + indent = _attr.indent; + if( tabPos != std::string::npos ) + indent += tabPos; + } + } + } + + void spliceLine( std::size_t _indent, std::string& _remainder, std::size_t _pos ) { + lines.push_back( std::string( _indent, ' ' ) + _remainder.substr( 0, _pos ) ); + _remainder = _remainder.substr( _pos ); + } + + typedef std::vector::const_iterator const_iterator; + + const_iterator begin() const { return lines.begin(); } + const_iterator end() const { return lines.end(); } + std::string const& last() const { return lines.back(); } + std::size_t size() const { return lines.size(); } + std::string const& operator[]( std::size_t _index ) const { return lines[_index]; } + std::string toString() const { + std::ostringstream oss; + oss << *this; + return oss.str(); + } + + inline friend std::ostream& operator << ( std::ostream& _stream, Text const& _text ) { + for( Text::const_iterator it = _text.begin(), itEnd = _text.end(); + it != itEnd; ++it ) { + if( it != _text.begin() ) + _stream << "\n"; + _stream << *it; + } + return _stream; + } + + private: + std::string str; + TextAttributes attr; + std::vector lines; + }; + +} // end namespace Tbc + +#ifdef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE +} // end outer namespace +#endif + +#endif // TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED +#undef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE + +namespace Catch { + using Tbc::Text; + using Tbc::TextAttributes; +} + +// #included from: catch_console_colour.hpp +#define TWOBLUECUBES_CATCH_CONSOLE_COLOUR_HPP_INCLUDED + +namespace Catch { + + struct Colour { + enum Code { + None = 0, + + White, + Red, + Green, + Blue, + Cyan, + Yellow, + Grey, + + Bright = 0x10, + + BrightRed = Bright | Red, + BrightGreen = Bright | Green, + LightGrey = Bright | Grey, + BrightWhite = Bright | White, + + // By intention + FileName = LightGrey, + Warning = Yellow, + ResultError = BrightRed, + ResultSuccess = BrightGreen, + ResultExpectedFailure = Warning, + + Error = BrightRed, + Success = Green, + + OriginalExpression = Cyan, + ReconstructedExpression = Yellow, + + SecondaryText = LightGrey, + Headers = White + }; + + // Use constructed object for RAII guard + Colour( Code _colourCode ); + Colour( Colour const& other ); + ~Colour(); + + // Use static method for one-shot changes + static void use( Code _colourCode ); + + private: + bool m_moved; + }; + + inline std::ostream& operator << ( std::ostream& os, Colour const& ) { return os; } + +} // end namespace Catch + +// #included from: catch_interfaces_reporter.h +#define TWOBLUECUBES_CATCH_INTERFACES_REPORTER_H_INCLUDED + +#include +#include +#include +#include + +namespace Catch +{ + struct ReporterConfig { + explicit ReporterConfig( Ptr const& _fullConfig ) + : m_stream( &_fullConfig->stream() ), m_fullConfig( _fullConfig ) {} + + ReporterConfig( Ptr const& _fullConfig, std::ostream& _stream ) + : m_stream( &_stream ), m_fullConfig( _fullConfig ) {} + + std::ostream& stream() const { return *m_stream; } + Ptr fullConfig() const { return m_fullConfig; } + + private: + std::ostream* m_stream; + Ptr m_fullConfig; + }; + + struct ReporterPreferences { + ReporterPreferences() + : shouldRedirectStdOut( false ) + {} + + bool shouldRedirectStdOut; + }; + + template + struct LazyStat : Option { + LazyStat() : used( false ) {} + LazyStat& operator=( T const& _value ) { + Option::operator=( _value ); + used = false; + return *this; + } + void reset() { + Option::reset(); + used = false; + } + bool used; + }; + + struct TestRunInfo { + TestRunInfo( std::string const& _name ) : name( _name ) {} + std::string name; + }; + struct GroupInfo { + GroupInfo( std::string const& _name, + std::size_t _groupIndex, + std::size_t _groupsCount ) + : name( _name ), + groupIndex( _groupIndex ), + groupsCounts( _groupsCount ) + {} + + std::string name; + std::size_t groupIndex; + std::size_t groupsCounts; + }; + + struct AssertionStats { + AssertionStats( AssertionResult const& _assertionResult, + std::vector const& _infoMessages, + Totals const& _totals ) + : assertionResult( _assertionResult ), + infoMessages( _infoMessages ), + totals( _totals ) + { + if( assertionResult.hasMessage() ) { + // Copy message into messages list. + // !TBD This should have been done earlier, somewhere + MessageBuilder builder( assertionResult.getTestMacroName(), assertionResult.getSourceInfo(), assertionResult.getResultType() ); + builder << assertionResult.getMessage(); + builder.m_info.message = builder.m_stream.str(); + + infoMessages.push_back( builder.m_info ); + } + } + virtual ~AssertionStats(); + +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + AssertionStats( AssertionStats const& ) = default; + AssertionStats( AssertionStats && ) = default; + AssertionStats& operator = ( AssertionStats const& ) = default; + AssertionStats& operator = ( AssertionStats && ) = default; +# endif + + AssertionResult assertionResult; + std::vector infoMessages; + Totals totals; + }; + + struct SectionStats { + SectionStats( SectionInfo const& _sectionInfo, + Counts const& _assertions, + double _durationInSeconds, + bool _missingAssertions ) + : sectionInfo( _sectionInfo ), + assertions( _assertions ), + durationInSeconds( _durationInSeconds ), + missingAssertions( _missingAssertions ) + {} + virtual ~SectionStats(); +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + SectionStats( SectionStats const& ) = default; + SectionStats( SectionStats && ) = default; + SectionStats& operator = ( SectionStats const& ) = default; + SectionStats& operator = ( SectionStats && ) = default; +# endif + + SectionInfo sectionInfo; + Counts assertions; + double durationInSeconds; + bool missingAssertions; + }; + + struct TestCaseStats { + TestCaseStats( TestCaseInfo const& _testInfo, + Totals const& _totals, + std::string const& _stdOut, + std::string const& _stdErr, + bool _aborting ) + : testInfo( _testInfo ), + totals( _totals ), + stdOut( _stdOut ), + stdErr( _stdErr ), + aborting( _aborting ) + {} + virtual ~TestCaseStats(); + +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + TestCaseStats( TestCaseStats const& ) = default; + TestCaseStats( TestCaseStats && ) = default; + TestCaseStats& operator = ( TestCaseStats const& ) = default; + TestCaseStats& operator = ( TestCaseStats && ) = default; +# endif + + TestCaseInfo testInfo; + Totals totals; + std::string stdOut; + std::string stdErr; + bool aborting; + }; + + struct TestGroupStats { + TestGroupStats( GroupInfo const& _groupInfo, + Totals const& _totals, + bool _aborting ) + : groupInfo( _groupInfo ), + totals( _totals ), + aborting( _aborting ) + {} + TestGroupStats( GroupInfo const& _groupInfo ) + : groupInfo( _groupInfo ), + aborting( false ) + {} + virtual ~TestGroupStats(); + +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + TestGroupStats( TestGroupStats const& ) = default; + TestGroupStats( TestGroupStats && ) = default; + TestGroupStats& operator = ( TestGroupStats const& ) = default; + TestGroupStats& operator = ( TestGroupStats && ) = default; +# endif + + GroupInfo groupInfo; + Totals totals; + bool aborting; + }; + + struct TestRunStats { + TestRunStats( TestRunInfo const& _runInfo, + Totals const& _totals, + bool _aborting ) + : runInfo( _runInfo ), + totals( _totals ), + aborting( _aborting ) + {} + virtual ~TestRunStats(); + +# ifndef CATCH_CONFIG_CPP11_GENERATED_METHODS + TestRunStats( TestRunStats const& _other ) + : runInfo( _other.runInfo ), + totals( _other.totals ), + aborting( _other.aborting ) + {} +# else + TestRunStats( TestRunStats const& ) = default; + TestRunStats( TestRunStats && ) = default; + TestRunStats& operator = ( TestRunStats const& ) = default; + TestRunStats& operator = ( TestRunStats && ) = default; +# endif + + TestRunInfo runInfo; + Totals totals; + bool aborting; + }; + + struct IStreamingReporter : IShared { + virtual ~IStreamingReporter(); + + // Implementing class must also provide the following static method: + // static std::string getDescription(); + + virtual ReporterPreferences getPreferences() const = 0; + + virtual void noMatchingTestCases( std::string const& spec ) = 0; + + virtual void testRunStarting( TestRunInfo const& testRunInfo ) = 0; + virtual void testGroupStarting( GroupInfo const& groupInfo ) = 0; + + virtual void testCaseStarting( TestCaseInfo const& testInfo ) = 0; + virtual void sectionStarting( SectionInfo const& sectionInfo ) = 0; + + virtual void assertionStarting( AssertionInfo const& assertionInfo ) = 0; + + // The return value indicates if the messages buffer should be cleared: + virtual bool assertionEnded( AssertionStats const& assertionStats ) = 0; + + virtual void sectionEnded( SectionStats const& sectionStats ) = 0; + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) = 0; + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) = 0; + virtual void testRunEnded( TestRunStats const& testRunStats ) = 0; + + virtual void skipTest( TestCaseInfo const& testInfo ) = 0; + }; + + struct IReporterFactory : IShared { + virtual ~IReporterFactory(); + virtual IStreamingReporter* create( ReporterConfig const& config ) const = 0; + virtual std::string getDescription() const = 0; + }; + + struct IReporterRegistry { + typedef std::map > FactoryMap; + typedef std::vector > Listeners; + + virtual ~IReporterRegistry(); + virtual IStreamingReporter* create( std::string const& name, Ptr const& config ) const = 0; + virtual FactoryMap const& getFactories() const = 0; + virtual Listeners const& getListeners() const = 0; + }; + + Ptr addReporter( Ptr const& existingReporter, Ptr const& additionalReporter ); + +} + +#include +#include + +namespace Catch { + + inline std::size_t listTests( Config const& config ) { + + TestSpec testSpec = config.testSpec(); + if( config.testSpec().hasFilters() ) + Catch::cout() << "Matching test cases:\n"; + else { + Catch::cout() << "All available test cases:\n"; + testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); + } + + std::size_t matchedTests = 0; + TextAttributes nameAttr, tagsAttr; + nameAttr.setInitialIndent( 2 ).setIndent( 4 ); + tagsAttr.setIndent( 6 ); + + std::vector matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); + for( std::vector::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); + it != itEnd; + ++it ) { + matchedTests++; + TestCaseInfo const& testCaseInfo = it->getTestCaseInfo(); + Colour::Code colour = testCaseInfo.isHidden() + ? Colour::SecondaryText + : Colour::None; + Colour colourGuard( colour ); + + Catch::cout() << Text( testCaseInfo.name, nameAttr ) << std::endl; + if( !testCaseInfo.tags.empty() ) + Catch::cout() << Text( testCaseInfo.tagsAsString, tagsAttr ) << std::endl; + } + + if( !config.testSpec().hasFilters() ) + Catch::cout() << pluralise( matchedTests, "test case" ) << "\n" << std::endl; + else + Catch::cout() << pluralise( matchedTests, "matching test case" ) << "\n" << std::endl; + return matchedTests; + } + + inline std::size_t listTestsNamesOnly( Config const& config ) { + TestSpec testSpec = config.testSpec(); + if( !config.testSpec().hasFilters() ) + testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); + std::size_t matchedTests = 0; + std::vector matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); + for( std::vector::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); + it != itEnd; + ++it ) { + matchedTests++; + TestCaseInfo const& testCaseInfo = it->getTestCaseInfo(); + Catch::cout() << testCaseInfo.name << std::endl; + } + return matchedTests; + } + + struct TagInfo { + TagInfo() : count ( 0 ) {} + void add( std::string const& spelling ) { + ++count; + spellings.insert( spelling ); + } + std::string all() const { + std::string out; + for( std::set::const_iterator it = spellings.begin(), itEnd = spellings.end(); + it != itEnd; + ++it ) + out += "[" + *it + "]"; + return out; + } + std::set spellings; + std::size_t count; + }; + + inline std::size_t listTags( Config const& config ) { + TestSpec testSpec = config.testSpec(); + if( config.testSpec().hasFilters() ) + Catch::cout() << "Tags for matching test cases:\n"; + else { + Catch::cout() << "All available tags:\n"; + testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); + } + + std::map tagCounts; + + std::vector matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); + for( std::vector::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); + it != itEnd; + ++it ) { + for( std::set::const_iterator tagIt = it->getTestCaseInfo().tags.begin(), + tagItEnd = it->getTestCaseInfo().tags.end(); + tagIt != tagItEnd; + ++tagIt ) { + std::string tagName = *tagIt; + std::string lcaseTagName = toLower( tagName ); + std::map::iterator countIt = tagCounts.find( lcaseTagName ); + if( countIt == tagCounts.end() ) + countIt = tagCounts.insert( std::make_pair( lcaseTagName, TagInfo() ) ).first; + countIt->second.add( tagName ); + } + } + + for( std::map::const_iterator countIt = tagCounts.begin(), + countItEnd = tagCounts.end(); + countIt != countItEnd; + ++countIt ) { + std::ostringstream oss; + oss << " " << std::setw(2) << countIt->second.count << " "; + Text wrapper( countIt->second.all(), TextAttributes() + .setInitialIndent( 0 ) + .setIndent( oss.str().size() ) + .setWidth( CATCH_CONFIG_CONSOLE_WIDTH-10 ) ); + Catch::cout() << oss.str() << wrapper << "\n"; + } + Catch::cout() << pluralise( tagCounts.size(), "tag" ) << "\n" << std::endl; + return tagCounts.size(); + } + + inline std::size_t listReporters( Config const& /*config*/ ) { + Catch::cout() << "Available reporters:\n"; + IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories(); + IReporterRegistry::FactoryMap::const_iterator itBegin = factories.begin(), itEnd = factories.end(), it; + std::size_t maxNameLen = 0; + for(it = itBegin; it != itEnd; ++it ) + maxNameLen = (std::max)( maxNameLen, it->first.size() ); + + for(it = itBegin; it != itEnd; ++it ) { + Text wrapper( it->second->getDescription(), TextAttributes() + .setInitialIndent( 0 ) + .setIndent( 7+maxNameLen ) + .setWidth( CATCH_CONFIG_CONSOLE_WIDTH - maxNameLen-8 ) ); + Catch::cout() << " " + << it->first + << ":" + << std::string( maxNameLen - it->first.size() + 2, ' ' ) + << wrapper << "\n"; + } + Catch::cout() << std::endl; + return factories.size(); + } + + inline Option list( Config const& config ) { + Option listedCount; + if( config.listTests() ) + listedCount = listedCount.valueOr(0) + listTests( config ); + if( config.listTestNamesOnly() ) + listedCount = listedCount.valueOr(0) + listTestsNamesOnly( config ); + if( config.listTags() ) + listedCount = listedCount.valueOr(0) + listTags( config ); + if( config.listReporters() ) + listedCount = listedCount.valueOr(0) + listReporters( config ); + return listedCount; + } + +} // end namespace Catch + +// #included from: internal/catch_run_context.hpp +#define TWOBLUECUBES_CATCH_RUNNER_IMPL_HPP_INCLUDED + +// #included from: catch_test_case_tracker.hpp +#define TWOBLUECUBES_CATCH_TEST_CASE_TRACKER_HPP_INCLUDED + +#include +#include +#include +#include + +namespace Catch { +namespace TestCaseTracking { + + struct ITracker : SharedImpl<> { + virtual ~ITracker(); + + // static queries + virtual std::string name() const = 0; + + // dynamic queries + virtual bool isComplete() const = 0; // Successfully completed or failed + virtual bool isSuccessfullyCompleted() const = 0; + virtual bool isOpen() const = 0; // Started but not complete + virtual bool hasChildren() const = 0; + + virtual ITracker& parent() = 0; + + // actions + virtual void close() = 0; // Successfully complete + virtual void fail() = 0; + virtual void markAsNeedingAnotherRun() = 0; + + virtual void addChild( Ptr const& child ) = 0; + virtual ITracker* findChild( std::string const& name ) = 0; + virtual void openChild() = 0; + }; + + class TrackerContext { + + enum RunState { + NotStarted, + Executing, + CompletedCycle + }; + + Ptr m_rootTracker; + ITracker* m_currentTracker; + RunState m_runState; + + public: + + static TrackerContext& instance() { + static TrackerContext s_instance; + return s_instance; + } + + TrackerContext() + : m_currentTracker( CATCH_NULL ), + m_runState( NotStarted ) + {} + + ITracker& startRun(); + + void endRun() { + m_rootTracker.reset(); + m_currentTracker = CATCH_NULL; + m_runState = NotStarted; + } + + void startCycle() { + m_currentTracker = m_rootTracker.get(); + m_runState = Executing; + } + void completeCycle() { + m_runState = CompletedCycle; + } + + bool completedCycle() const { + return m_runState == CompletedCycle; + } + ITracker& currentTracker() { + return *m_currentTracker; + } + void setCurrentTracker( ITracker* tracker ) { + m_currentTracker = tracker; + } + }; + + class TrackerBase : public ITracker { + protected: + enum CycleState { + NotStarted, + Executing, + ExecutingChildren, + NeedsAnotherRun, + CompletedSuccessfully, + Failed + }; + class TrackerHasName { + std::string m_name; + public: + TrackerHasName( std::string const& name ) : m_name( name ) {} + bool operator ()( Ptr const& tracker ) { + return tracker->name() == m_name; + } + }; + typedef std::vector > Children; + std::string m_name; + TrackerContext& m_ctx; + ITracker* m_parent; + Children m_children; + CycleState m_runState; + public: + TrackerBase( std::string const& name, TrackerContext& ctx, ITracker* parent ) + : m_name( name ), + m_ctx( ctx ), + m_parent( parent ), + m_runState( NotStarted ) + {} + virtual ~TrackerBase(); + + virtual std::string name() const CATCH_OVERRIDE { + return m_name; + } + virtual bool isComplete() const CATCH_OVERRIDE { + return m_runState == CompletedSuccessfully || m_runState == Failed; + } + virtual bool isSuccessfullyCompleted() const CATCH_OVERRIDE { + return m_runState == CompletedSuccessfully; + } + virtual bool isOpen() const CATCH_OVERRIDE { + return m_runState != NotStarted && !isComplete(); + } + virtual bool hasChildren() const CATCH_OVERRIDE { + return !m_children.empty(); + } + + virtual void addChild( Ptr const& child ) CATCH_OVERRIDE { + m_children.push_back( child ); + } + + virtual ITracker* findChild( std::string const& name ) CATCH_OVERRIDE { + Children::const_iterator it = std::find_if( m_children.begin(), m_children.end(), TrackerHasName( name ) ); + return( it != m_children.end() ) + ? it->get() + : CATCH_NULL; + } + virtual ITracker& parent() CATCH_OVERRIDE { + assert( m_parent ); // Should always be non-null except for root + return *m_parent; + } + + virtual void openChild() CATCH_OVERRIDE { + if( m_runState != ExecutingChildren ) { + m_runState = ExecutingChildren; + if( m_parent ) + m_parent->openChild(); + } + } + void open() { + m_runState = Executing; + moveToThis(); + if( m_parent ) + m_parent->openChild(); + } + + virtual void close() CATCH_OVERRIDE { + + // Close any still open children (e.g. generators) + while( &m_ctx.currentTracker() != this ) + m_ctx.currentTracker().close(); + + switch( m_runState ) { + case NotStarted: + case CompletedSuccessfully: + case Failed: + throw std::logic_error( "Illogical state" ); + + case NeedsAnotherRun: + break;; + + case Executing: + m_runState = CompletedSuccessfully; + break; + case ExecutingChildren: + if( m_children.empty() || m_children.back()->isComplete() ) + m_runState = CompletedSuccessfully; + break; + + default: + throw std::logic_error( "Unexpected state" ); + } + moveToParent(); + m_ctx.completeCycle(); + } + virtual void fail() CATCH_OVERRIDE { + m_runState = Failed; + if( m_parent ) + m_parent->markAsNeedingAnotherRun(); + moveToParent(); + m_ctx.completeCycle(); + } + virtual void markAsNeedingAnotherRun() CATCH_OVERRIDE { + m_runState = NeedsAnotherRun; + } + private: + void moveToParent() { + assert( m_parent ); + m_ctx.setCurrentTracker( m_parent ); + } + void moveToThis() { + m_ctx.setCurrentTracker( this ); + } + }; + + class SectionTracker : public TrackerBase { + public: + SectionTracker( std::string const& name, TrackerContext& ctx, ITracker* parent ) + : TrackerBase( name, ctx, parent ) + {} + virtual ~SectionTracker(); + + static SectionTracker& acquire( TrackerContext& ctx, std::string const& name ) { + SectionTracker* section = CATCH_NULL; + + ITracker& currentTracker = ctx.currentTracker(); + if( ITracker* childTracker = currentTracker.findChild( name ) ) { + section = dynamic_cast( childTracker ); + assert( section ); + } + else { + section = new SectionTracker( name, ctx, ¤tTracker ); + currentTracker.addChild( section ); + } + if( !ctx.completedCycle() && !section->isComplete() ) { + + section->open(); + } + return *section; + } + }; + + class IndexTracker : public TrackerBase { + int m_size; + int m_index; + public: + IndexTracker( std::string const& name, TrackerContext& ctx, ITracker* parent, int size ) + : TrackerBase( name, ctx, parent ), + m_size( size ), + m_index( -1 ) + {} + virtual ~IndexTracker(); + + static IndexTracker& acquire( TrackerContext& ctx, std::string const& name, int size ) { + IndexTracker* tracker = CATCH_NULL; + + ITracker& currentTracker = ctx.currentTracker(); + if( ITracker* childTracker = currentTracker.findChild( name ) ) { + tracker = dynamic_cast( childTracker ); + assert( tracker ); + } + else { + tracker = new IndexTracker( name, ctx, ¤tTracker, size ); + currentTracker.addChild( tracker ); + } + + if( !ctx.completedCycle() && !tracker->isComplete() ) { + if( tracker->m_runState != ExecutingChildren && tracker->m_runState != NeedsAnotherRun ) + tracker->moveNext(); + tracker->open(); + } + + return *tracker; + } + + int index() const { return m_index; } + + void moveNext() { + m_index++; + m_children.clear(); + } + + virtual void close() CATCH_OVERRIDE { + TrackerBase::close(); + if( m_runState == CompletedSuccessfully && m_index < m_size-1 ) + m_runState = Executing; + } + }; + + inline ITracker& TrackerContext::startRun() { + m_rootTracker = new SectionTracker( "{root}", *this, CATCH_NULL ); + m_currentTracker = CATCH_NULL; + m_runState = Executing; + return *m_rootTracker; + } + +} // namespace TestCaseTracking + +using TestCaseTracking::ITracker; +using TestCaseTracking::TrackerContext; +using TestCaseTracking::SectionTracker; +using TestCaseTracking::IndexTracker; + +} // namespace Catch + +// #included from: catch_fatal_condition.hpp +#define TWOBLUECUBES_CATCH_FATAL_CONDITION_H_INCLUDED + +namespace Catch { + + // Report the error condition then exit the process + inline void fatal( std::string const& message, int exitCode ) { + IContext& context = Catch::getCurrentContext(); + IResultCapture* resultCapture = context.getResultCapture(); + resultCapture->handleFatalErrorCondition( message ); + + if( Catch::alwaysTrue() ) // avoids "no return" warnings + exit( exitCode ); + } + +} // namespace Catch + +#if defined ( CATCH_PLATFORM_WINDOWS ) ///////////////////////////////////////// + +namespace Catch { + + struct FatalConditionHandler { + void reset() {} + }; + +} // namespace Catch + +#else // Not Windows - assumed to be POSIX compatible ////////////////////////// + +#include + +namespace Catch { + + struct SignalDefs { int id; const char* name; }; + extern SignalDefs signalDefs[]; + SignalDefs signalDefs[] = { + { SIGINT, "SIGINT - Terminal interrupt signal" }, + { SIGILL, "SIGILL - Illegal instruction signal" }, + { SIGFPE, "SIGFPE - Floating point error signal" }, + { SIGSEGV, "SIGSEGV - Segmentation violation signal" }, + { SIGTERM, "SIGTERM - Termination request signal" }, + { SIGABRT, "SIGABRT - Abort (abnormal termination) signal" } + }; + + struct FatalConditionHandler { + + static void handleSignal( int sig ) { + for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) + if( sig == signalDefs[i].id ) + fatal( signalDefs[i].name, -sig ); + fatal( "", -sig ); + } + + FatalConditionHandler() : m_isSet( true ) { + for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) + signal( signalDefs[i].id, handleSignal ); + } + ~FatalConditionHandler() { + reset(); + } + void reset() { + if( m_isSet ) { + for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) + signal( signalDefs[i].id, SIG_DFL ); + m_isSet = false; + } + } + + bool m_isSet; + }; + +} // namespace Catch + +#endif // not Windows + +#include +#include + +namespace Catch { + + class StreamRedirect { + + public: + StreamRedirect( std::ostream& stream, std::string& targetString ) + : m_stream( stream ), + m_prevBuf( stream.rdbuf() ), + m_targetString( targetString ) + { + stream.rdbuf( m_oss.rdbuf() ); + } + + ~StreamRedirect() { + m_targetString += m_oss.str(); + m_stream.rdbuf( m_prevBuf ); + } + + private: + std::ostream& m_stream; + std::streambuf* m_prevBuf; + std::ostringstream m_oss; + std::string& m_targetString; + }; + + /////////////////////////////////////////////////////////////////////////// + + class RunContext : public IResultCapture, public IRunner { + + RunContext( RunContext const& ); + void operator =( RunContext const& ); + + public: + + explicit RunContext( Ptr const& _config, Ptr const& reporter ) + : m_runInfo( _config->name() ), + m_context( getCurrentMutableContext() ), + m_activeTestCase( CATCH_NULL ), + m_config( _config ), + m_reporter( reporter ) + { + m_context.setRunner( this ); + m_context.setConfig( m_config ); + m_context.setResultCapture( this ); + m_reporter->testRunStarting( m_runInfo ); + } + + virtual ~RunContext() { + m_reporter->testRunEnded( TestRunStats( m_runInfo, m_totals, aborting() ) ); + } + + void testGroupStarting( std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount ) { + m_reporter->testGroupStarting( GroupInfo( testSpec, groupIndex, groupsCount ) ); + } + void testGroupEnded( std::string const& testSpec, Totals const& totals, std::size_t groupIndex, std::size_t groupsCount ) { + m_reporter->testGroupEnded( TestGroupStats( GroupInfo( testSpec, groupIndex, groupsCount ), totals, aborting() ) ); + } + + Totals runTest( TestCase const& testCase ) { + Totals prevTotals = m_totals; + + std::string redirectedCout; + std::string redirectedCerr; + + TestCaseInfo testInfo = testCase.getTestCaseInfo(); + + m_reporter->testCaseStarting( testInfo ); + + m_activeTestCase = &testCase; + + do { + m_trackerContext.startRun(); + do { + m_trackerContext.startCycle(); + m_testCaseTracker = &SectionTracker::acquire( m_trackerContext, testInfo.name ); + runCurrentTest( redirectedCout, redirectedCerr ); + } + while( !m_testCaseTracker->isSuccessfullyCompleted() && !aborting() ); + } + // !TBD: deprecated - this will be replaced by indexed trackers + while( getCurrentContext().advanceGeneratorsForCurrentTest() && !aborting() ); + + Totals deltaTotals = m_totals.delta( prevTotals ); + m_totals.testCases += deltaTotals.testCases; + m_reporter->testCaseEnded( TestCaseStats( testInfo, + deltaTotals, + redirectedCout, + redirectedCerr, + aborting() ) ); + + m_activeTestCase = CATCH_NULL; + m_testCaseTracker = CATCH_NULL; + + return deltaTotals; + } + + Ptr config() const { + return m_config; + } + + private: // IResultCapture + + virtual void assertionEnded( AssertionResult const& result ) { + if( result.getResultType() == ResultWas::Ok ) { + m_totals.assertions.passed++; + } + else if( !result.isOk() ) { + m_totals.assertions.failed++; + } + + if( m_reporter->assertionEnded( AssertionStats( result, m_messages, m_totals ) ) ) + m_messages.clear(); + + // Reset working state + m_lastAssertionInfo = AssertionInfo( "", m_lastAssertionInfo.lineInfo, "{Unknown expression after the reported line}" , m_lastAssertionInfo.resultDisposition ); + m_lastResult = result; + } + + virtual bool sectionStarted ( + SectionInfo const& sectionInfo, + Counts& assertions + ) + { + std::ostringstream oss; + oss << sectionInfo.name << "@" << sectionInfo.lineInfo; + + ITracker& sectionTracker = SectionTracker::acquire( m_trackerContext, oss.str() ); + if( !sectionTracker.isOpen() ) + return false; + m_activeSections.push_back( §ionTracker ); + + m_lastAssertionInfo.lineInfo = sectionInfo.lineInfo; + + m_reporter->sectionStarting( sectionInfo ); + + assertions = m_totals.assertions; + + return true; + } + bool testForMissingAssertions( Counts& assertions ) { + if( assertions.total() != 0 ) + return false; + if( !m_config->warnAboutMissingAssertions() ) + return false; + if( m_trackerContext.currentTracker().hasChildren() ) + return false; + m_totals.assertions.failed++; + assertions.failed++; + return true; + } + + virtual void sectionEnded( SectionEndInfo const& endInfo ) { + Counts assertions = m_totals.assertions - endInfo.prevAssertions; + bool missingAssertions = testForMissingAssertions( assertions ); + + if( !m_activeSections.empty() ) { + m_activeSections.back()->close(); + m_activeSections.pop_back(); + } + + m_reporter->sectionEnded( SectionStats( endInfo.sectionInfo, assertions, endInfo.durationInSeconds, missingAssertions ) ); + m_messages.clear(); + } + + virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) { + if( m_unfinishedSections.empty() ) + m_activeSections.back()->fail(); + else + m_activeSections.back()->close(); + m_activeSections.pop_back(); + + m_unfinishedSections.push_back( endInfo ); + } + + virtual void pushScopedMessage( MessageInfo const& message ) { + m_messages.push_back( message ); + } + + virtual void popScopedMessage( MessageInfo const& message ) { + m_messages.erase( std::remove( m_messages.begin(), m_messages.end(), message ), m_messages.end() ); + } + + virtual std::string getCurrentTestName() const { + return m_activeTestCase + ? m_activeTestCase->getTestCaseInfo().name + : ""; + } + + virtual const AssertionResult* getLastResult() const { + return &m_lastResult; + } + + virtual void handleFatalErrorCondition( std::string const& message ) { + ResultBuilder resultBuilder = makeUnexpectedResultBuilder(); + resultBuilder.setResultType( ResultWas::FatalErrorCondition ); + resultBuilder << message; + resultBuilder.captureExpression(); + + handleUnfinishedSections(); + + // Recreate section for test case (as we will lose the one that was in scope) + TestCaseInfo const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); + SectionInfo testCaseSection( testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description ); + + Counts assertions; + assertions.failed = 1; + SectionStats testCaseSectionStats( testCaseSection, assertions, 0, false ); + m_reporter->sectionEnded( testCaseSectionStats ); + + TestCaseInfo testInfo = m_activeTestCase->getTestCaseInfo(); + + Totals deltaTotals; + deltaTotals.testCases.failed = 1; + m_reporter->testCaseEnded( TestCaseStats( testInfo, + deltaTotals, + "", + "", + false ) ); + m_totals.testCases.failed++; + testGroupEnded( "", m_totals, 1, 1 ); + m_reporter->testRunEnded( TestRunStats( m_runInfo, m_totals, false ) ); + } + + public: + // !TBD We need to do this another way! + bool aborting() const { + return m_totals.assertions.failed == static_cast( m_config->abortAfter() ); + } + + private: + + void runCurrentTest( std::string& redirectedCout, std::string& redirectedCerr ) { + TestCaseInfo const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); + SectionInfo testCaseSection( testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description ); + m_reporter->sectionStarting( testCaseSection ); + Counts prevAssertions = m_totals.assertions; + double duration = 0; + try { + m_lastAssertionInfo = AssertionInfo( "TEST_CASE", testCaseInfo.lineInfo, "", ResultDisposition::Normal ); + + seedRng( *m_config ); + + Timer timer; + timer.start(); + if( m_reporter->getPreferences().shouldRedirectStdOut ) { + StreamRedirect coutRedir( Catch::cout(), redirectedCout ); + StreamRedirect cerrRedir( Catch::cerr(), redirectedCerr ); + invokeActiveTestCase(); + } + else { + invokeActiveTestCase(); + } + duration = timer.getElapsedSeconds(); + } + catch( TestFailureException& ) { + // This just means the test was aborted due to failure + } + catch(...) { + makeUnexpectedResultBuilder().useActiveException(); + } + m_testCaseTracker->close(); + handleUnfinishedSections(); + m_messages.clear(); + + Counts assertions = m_totals.assertions - prevAssertions; + bool missingAssertions = testForMissingAssertions( assertions ); + + if( testCaseInfo.okToFail() ) { + std::swap( assertions.failedButOk, assertions.failed ); + m_totals.assertions.failed -= assertions.failedButOk; + m_totals.assertions.failedButOk += assertions.failedButOk; + } + + SectionStats testCaseSectionStats( testCaseSection, assertions, duration, missingAssertions ); + m_reporter->sectionEnded( testCaseSectionStats ); + } + + void invokeActiveTestCase() { + FatalConditionHandler fatalConditionHandler; // Handle signals + m_activeTestCase->invoke(); + fatalConditionHandler.reset(); + } + + private: + + ResultBuilder makeUnexpectedResultBuilder() const { + return ResultBuilder( m_lastAssertionInfo.macroName.c_str(), + m_lastAssertionInfo.lineInfo, + m_lastAssertionInfo.capturedExpression.c_str(), + m_lastAssertionInfo.resultDisposition ); + } + + void handleUnfinishedSections() { + // If sections ended prematurely due to an exception we stored their + // infos here so we can tear them down outside the unwind process. + for( std::vector::const_reverse_iterator it = m_unfinishedSections.rbegin(), + itEnd = m_unfinishedSections.rend(); + it != itEnd; + ++it ) + sectionEnded( *it ); + m_unfinishedSections.clear(); + } + + TestRunInfo m_runInfo; + IMutableContext& m_context; + TestCase const* m_activeTestCase; + ITracker* m_testCaseTracker; + ITracker* m_currentSectionTracker; + AssertionResult m_lastResult; + + Ptr m_config; + Totals m_totals; + Ptr m_reporter; + std::vector m_messages; + AssertionInfo m_lastAssertionInfo; + std::vector m_unfinishedSections; + std::vector m_activeSections; + TrackerContext m_trackerContext; + }; + + IResultCapture& getResultCapture() { + if( IResultCapture* capture = getCurrentContext().getResultCapture() ) + return *capture; + else + throw std::logic_error( "No result capture instance" ); + } + +} // end namespace Catch + +// #included from: internal/catch_version.h +#define TWOBLUECUBES_CATCH_VERSION_H_INCLUDED + +namespace Catch { + + // Versioning information + struct Version { + Version( unsigned int _majorVersion, + unsigned int _minorVersion, + unsigned int _patchNumber, + std::string const& _branchName, + unsigned int _buildNumber ); + + unsigned int const majorVersion; + unsigned int const minorVersion; + unsigned int const patchNumber; + + // buildNumber is only used if branchName is not null + std::string const branchName; + unsigned int const buildNumber; + + friend std::ostream& operator << ( std::ostream& os, Version const& version ); + + private: + void operator=( Version const& ); + }; + + extern Version libraryVersion; +} + +#include +#include +#include + +namespace Catch { + + Ptr createReporter( std::string const& reporterName, Ptr const& config ) { + Ptr reporter = getRegistryHub().getReporterRegistry().create( reporterName, config.get() ); + if( !reporter ) { + std::ostringstream oss; + oss << "No reporter registered with name: '" << reporterName << "'"; + throw std::domain_error( oss.str() ); + } + return reporter; + } + + Ptr makeReporter( Ptr const& config ) { + std::vector reporters = config->getReporterNames(); + if( reporters.empty() ) + reporters.push_back( "console" ); + + Ptr reporter; + for( std::vector::const_iterator it = reporters.begin(), itEnd = reporters.end(); + it != itEnd; + ++it ) + reporter = addReporter( reporter, createReporter( *it, config ) ); + return reporter; + } + Ptr addListeners( Ptr const& config, Ptr reporters ) { + IReporterRegistry::Listeners listeners = getRegistryHub().getReporterRegistry().getListeners(); + for( IReporterRegistry::Listeners::const_iterator it = listeners.begin(), itEnd = listeners.end(); + it != itEnd; + ++it ) + reporters = addReporter(reporters, (*it)->create( ReporterConfig( config ) ) ); + return reporters; + } + + Totals runTests( Ptr const& config ) { + + Ptr iconfig = config.get(); + + Ptr reporter = makeReporter( config ); + reporter = addListeners( iconfig, reporter ); + + RunContext context( iconfig, reporter ); + + Totals totals; + + context.testGroupStarting( config->name(), 1, 1 ); + + TestSpec testSpec = config->testSpec(); + if( !testSpec.hasFilters() ) + testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "~[.]" ).testSpec(); // All not hidden tests + + std::vector const& allTestCases = getAllTestCasesSorted( *iconfig ); + for( std::vector::const_iterator it = allTestCases.begin(), itEnd = allTestCases.end(); + it != itEnd; + ++it ) { + if( !context.aborting() && matchTest( *it, testSpec, *iconfig ) ) + totals += context.runTest( *it ); + else + reporter->skipTest( *it ); + } + + context.testGroupEnded( iconfig->name(), totals, 1, 1 ); + return totals; + } + + void applyFilenamesAsTags( IConfig const& config ) { + std::vector const& tests = getAllTestCasesSorted( config ); + for(std::size_t i = 0; i < tests.size(); ++i ) { + TestCase& test = const_cast( tests[i] ); + std::set tags = test.tags; + + std::string filename = test.lineInfo.file; + std::string::size_type lastSlash = filename.find_last_of( "\\/" ); + if( lastSlash != std::string::npos ) + filename = filename.substr( lastSlash+1 ); + + std::string::size_type lastDot = filename.find_last_of( "." ); + if( lastDot != std::string::npos ) + filename = filename.substr( 0, lastDot ); + + tags.insert( "#" + filename ); + setTags( test, tags ); + } + } + + class Session : NonCopyable { + static bool alreadyInstantiated; + + public: + + struct OnUnusedOptions { enum DoWhat { Ignore, Fail }; }; + + Session() + : m_cli( makeCommandLineParser() ) { + if( alreadyInstantiated ) { + std::string msg = "Only one instance of Catch::Session can ever be used"; + Catch::cerr() << msg << std::endl; + throw std::logic_error( msg ); + } + alreadyInstantiated = true; + } + ~Session() { + Catch::cleanUp(); + } + + void showHelp( std::string const& processName ) { + Catch::cout() << "\nCatch v" << libraryVersion << "\n"; + + m_cli.usage( Catch::cout(), processName ); + Catch::cout() << "For more detail usage please see the project docs\n" << std::endl; + } + + int applyCommandLine( int argc, char const* argv[], OnUnusedOptions::DoWhat unusedOptionBehaviour = OnUnusedOptions::Fail ) { + try { + m_cli.setThrowOnUnrecognisedTokens( unusedOptionBehaviour == OnUnusedOptions::Fail ); + m_unusedTokens = m_cli.parseInto( argc, argv, m_configData ); + if( m_configData.showHelp ) + showHelp( m_configData.processName ); + m_config.reset(); + } + catch( std::exception& ex ) { + { + Colour colourGuard( Colour::Red ); + Catch::cerr() + << "\nError(s) in input:\n" + << Text( ex.what(), TextAttributes().setIndent(2) ) + << "\n\n"; + } + m_cli.usage( Catch::cout(), m_configData.processName ); + return (std::numeric_limits::max)(); + } + return 0; + } + + void useConfigData( ConfigData const& _configData ) { + m_configData = _configData; + m_config.reset(); + } + + int run( int argc, char const* argv[] ) { + + int returnCode = applyCommandLine( argc, argv ); + if( returnCode == 0 ) + returnCode = run(); + return returnCode; + } + int run( int argc, char* argv[] ) { + return run( argc, const_cast( argv ) ); + } + + int run() { + if( m_configData.showHelp ) + return 0; + + try + { + config(); // Force config to be constructed + + seedRng( *m_config ); + + if( m_configData.filenamesAsTags ) + applyFilenamesAsTags( *m_config ); + + // Handle list request + if( Option listed = list( config() ) ) + return static_cast( *listed ); + + return static_cast( runTests( m_config ).assertions.failed ); + } + catch( std::exception& ex ) { + Catch::cerr() << ex.what() << std::endl; + return (std::numeric_limits::max)(); + } + } + + Clara::CommandLine const& cli() const { + return m_cli; + } + std::vector const& unusedTokens() const { + return m_unusedTokens; + } + ConfigData& configData() { + return m_configData; + } + Config& config() { + if( !m_config ) + m_config = new Config( m_configData ); + return *m_config; + } + private: + Clara::CommandLine m_cli; + std::vector m_unusedTokens; + ConfigData m_configData; + Ptr m_config; + }; + + bool Session::alreadyInstantiated = false; + +} // end namespace Catch + +// #included from: catch_registry_hub.hpp +#define TWOBLUECUBES_CATCH_REGISTRY_HUB_HPP_INCLUDED + +// #included from: catch_test_case_registry_impl.hpp +#define TWOBLUECUBES_CATCH_TEST_CASE_REGISTRY_IMPL_HPP_INCLUDED + +#include +#include +#include +#include +#include + +namespace Catch { + + struct LexSort { + bool operator() (TestCase i,TestCase j) const { return (i sortTests( IConfig const& config, std::vector const& unsortedTestCases ) { + + std::vector sorted = unsortedTestCases; + + switch( config.runOrder() ) { + case RunTests::InLexicographicalOrder: + std::sort( sorted.begin(), sorted.end(), LexSort() ); + break; + case RunTests::InRandomOrder: + { + seedRng( config ); + + RandomNumberGenerator rng; + std::random_shuffle( sorted.begin(), sorted.end(), rng ); + } + break; + case RunTests::InDeclarationOrder: + // already in declaration order + break; + } + return sorted; + } + bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ) { + return testSpec.matches( testCase ) && ( config.allowThrows() || !testCase.throws() ); + } + + void enforceNoDuplicateTestCases( std::vector const& functions ) { + std::set seenFunctions; + for( std::vector::const_iterator it = functions.begin(), itEnd = functions.end(); + it != itEnd; + ++it ) { + std::pair::const_iterator, bool> prev = seenFunctions.insert( *it ); + if( !prev.second ){ + Catch::cerr() + << Colour( Colour::Red ) + << "error: TEST_CASE( \"" << it->name << "\" ) already defined.\n" + << "\tFirst seen at " << prev.first->getTestCaseInfo().lineInfo << "\n" + << "\tRedefined at " << it->getTestCaseInfo().lineInfo << std::endl; + exit(1); + } + } + } + + std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ) { + std::vector filtered; + filtered.reserve( testCases.size() ); + for( std::vector::const_iterator it = testCases.begin(), itEnd = testCases.end(); + it != itEnd; + ++it ) + if( matchTest( *it, testSpec, config ) ) + filtered.push_back( *it ); + return filtered; + } + std::vector const& getAllTestCasesSorted( IConfig const& config ) { + return getRegistryHub().getTestCaseRegistry().getAllTestsSorted( config ); + } + + class TestRegistry : public ITestCaseRegistry { + public: + TestRegistry() + : m_currentSortOrder( RunTests::InDeclarationOrder ), + m_unnamedCount( 0 ) + {} + virtual ~TestRegistry(); + + virtual void registerTest( TestCase const& testCase ) { + std::string name = testCase.getTestCaseInfo().name; + if( name == "" ) { + std::ostringstream oss; + oss << "Anonymous test case " << ++m_unnamedCount; + return registerTest( testCase.withName( oss.str() ) ); + } + m_functions.push_back( testCase ); + } + + virtual std::vector const& getAllTests() const { + return m_functions; + } + virtual std::vector const& getAllTestsSorted( IConfig const& config ) const { + if( m_sortedFunctions.empty() ) + enforceNoDuplicateTestCases( m_functions ); + + if( m_currentSortOrder != config.runOrder() || m_sortedFunctions.empty() ) { + m_sortedFunctions = sortTests( config, m_functions ); + m_currentSortOrder = config.runOrder(); + } + return m_sortedFunctions; + } + + private: + std::vector m_functions; + mutable RunTests::InWhatOrder m_currentSortOrder; + mutable std::vector m_sortedFunctions; + size_t m_unnamedCount; + std::ios_base::Init m_ostreamInit; // Forces cout/ cerr to be initialised + }; + + /////////////////////////////////////////////////////////////////////////// + + class FreeFunctionTestCase : public SharedImpl { + public: + + FreeFunctionTestCase( TestFunction fun ) : m_fun( fun ) {} + + virtual void invoke() const { + m_fun(); + } + + private: + virtual ~FreeFunctionTestCase(); + + TestFunction m_fun; + }; + + inline std::string extractClassName( std::string const& classOrQualifiedMethodName ) { + std::string className = classOrQualifiedMethodName; + if( startsWith( className, "&" ) ) + { + std::size_t lastColons = className.rfind( "::" ); + std::size_t penultimateColons = className.rfind( "::", lastColons-1 ); + if( penultimateColons == std::string::npos ) + penultimateColons = 1; + className = className.substr( penultimateColons, lastColons-penultimateColons ); + } + return className; + } + + void registerTestCase + ( ITestCase* testCase, + char const* classOrQualifiedMethodName, + NameAndDesc const& nameAndDesc, + SourceLineInfo const& lineInfo ) { + + getMutableRegistryHub().registerTest + ( makeTestCase + ( testCase, + extractClassName( classOrQualifiedMethodName ), + nameAndDesc.name, + nameAndDesc.description, + lineInfo ) ); + } + void registerTestCaseFunction + ( TestFunction function, + SourceLineInfo const& lineInfo, + NameAndDesc const& nameAndDesc ) { + registerTestCase( new FreeFunctionTestCase( function ), "", nameAndDesc, lineInfo ); + } + + /////////////////////////////////////////////////////////////////////////// + + AutoReg::AutoReg + ( TestFunction function, + SourceLineInfo const& lineInfo, + NameAndDesc const& nameAndDesc ) { + registerTestCaseFunction( function, lineInfo, nameAndDesc ); + } + + AutoReg::~AutoReg() {} + +} // end namespace Catch + +// #included from: catch_reporter_registry.hpp +#define TWOBLUECUBES_CATCH_REPORTER_REGISTRY_HPP_INCLUDED + +#include + +namespace Catch { + + class ReporterRegistry : public IReporterRegistry { + + public: + + virtual ~ReporterRegistry() CATCH_OVERRIDE {} + + virtual IStreamingReporter* create( std::string const& name, Ptr const& config ) const CATCH_OVERRIDE { + FactoryMap::const_iterator it = m_factories.find( name ); + if( it == m_factories.end() ) + return CATCH_NULL; + return it->second->create( ReporterConfig( config ) ); + } + + void registerReporter( std::string const& name, Ptr const& factory ) { + m_factories.insert( std::make_pair( name, factory ) ); + } + void registerListener( Ptr const& factory ) { + m_listeners.push_back( factory ); + } + + virtual FactoryMap const& getFactories() const CATCH_OVERRIDE { + return m_factories; + } + virtual Listeners const& getListeners() const CATCH_OVERRIDE { + return m_listeners; + } + + private: + FactoryMap m_factories; + Listeners m_listeners; + }; +} + +// #included from: catch_exception_translator_registry.hpp +#define TWOBLUECUBES_CATCH_EXCEPTION_TRANSLATOR_REGISTRY_HPP_INCLUDED + +#ifdef __OBJC__ +#import "Foundation/Foundation.h" +#endif + +namespace Catch { + + class ExceptionTranslatorRegistry : public IExceptionTranslatorRegistry { + public: + ~ExceptionTranslatorRegistry() { + deleteAll( m_translators ); + } + + virtual void registerTranslator( const IExceptionTranslator* translator ) { + m_translators.push_back( translator ); + } + + virtual std::string translateActiveException() const { + try { +#ifdef __OBJC__ + // In Objective-C try objective-c exceptions first + @try { + return tryTranslators(); + } + @catch (NSException *exception) { + return Catch::toString( [exception description] ); + } +#else + return tryTranslators(); +#endif + } + catch( TestFailureException& ) { + throw; + } + catch( std::exception& ex ) { + return ex.what(); + } + catch( std::string& msg ) { + return msg; + } + catch( const char* msg ) { + return msg; + } + catch(...) { + return "Unknown exception"; + } + } + + std::string tryTranslators() const { + if( m_translators.empty() ) + throw; + else + return m_translators[0]->translate( m_translators.begin()+1, m_translators.end() ); + } + + private: + std::vector m_translators; + }; +} + +namespace Catch { + + namespace { + + class RegistryHub : public IRegistryHub, public IMutableRegistryHub { + + RegistryHub( RegistryHub const& ); + void operator=( RegistryHub const& ); + + public: // IRegistryHub + RegistryHub() { + } + virtual IReporterRegistry const& getReporterRegistry() const CATCH_OVERRIDE { + return m_reporterRegistry; + } + virtual ITestCaseRegistry const& getTestCaseRegistry() const CATCH_OVERRIDE { + return m_testCaseRegistry; + } + virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() CATCH_OVERRIDE { + return m_exceptionTranslatorRegistry; + } + + public: // IMutableRegistryHub + virtual void registerReporter( std::string const& name, Ptr const& factory ) CATCH_OVERRIDE { + m_reporterRegistry.registerReporter( name, factory ); + } + virtual void registerListener( Ptr const& factory ) CATCH_OVERRIDE { + m_reporterRegistry.registerListener( factory ); + } + virtual void registerTest( TestCase const& testInfo ) CATCH_OVERRIDE { + m_testCaseRegistry.registerTest( testInfo ); + } + virtual void registerTranslator( const IExceptionTranslator* translator ) CATCH_OVERRIDE { + m_exceptionTranslatorRegistry.registerTranslator( translator ); + } + + private: + TestRegistry m_testCaseRegistry; + ReporterRegistry m_reporterRegistry; + ExceptionTranslatorRegistry m_exceptionTranslatorRegistry; + }; + + // Single, global, instance + inline RegistryHub*& getTheRegistryHub() { + static RegistryHub* theRegistryHub = CATCH_NULL; + if( !theRegistryHub ) + theRegistryHub = new RegistryHub(); + return theRegistryHub; + } + } + + IRegistryHub& getRegistryHub() { + return *getTheRegistryHub(); + } + IMutableRegistryHub& getMutableRegistryHub() { + return *getTheRegistryHub(); + } + void cleanUp() { + delete getTheRegistryHub(); + getTheRegistryHub() = CATCH_NULL; + cleanUpContext(); + } + std::string translateActiveException() { + return getRegistryHub().getExceptionTranslatorRegistry().translateActiveException(); + } + +} // end namespace Catch + +// #included from: catch_notimplemented_exception.hpp +#define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_HPP_INCLUDED + +#include + +namespace Catch { + + NotImplementedException::NotImplementedException( SourceLineInfo const& lineInfo ) + : m_lineInfo( lineInfo ) { + std::ostringstream oss; + oss << lineInfo << ": function "; + oss << "not implemented"; + m_what = oss.str(); + } + + const char* NotImplementedException::what() const CATCH_NOEXCEPT { + return m_what.c_str(); + } + +} // end namespace Catch + +// #included from: catch_context_impl.hpp +#define TWOBLUECUBES_CATCH_CONTEXT_IMPL_HPP_INCLUDED + +// #included from: catch_stream.hpp +#define TWOBLUECUBES_CATCH_STREAM_HPP_INCLUDED + +#include +#include +#include + +namespace Catch { + + template + class StreamBufImpl : public StreamBufBase { + char data[bufferSize]; + WriterF m_writer; + + public: + StreamBufImpl() { + setp( data, data + sizeof(data) ); + } + + ~StreamBufImpl() CATCH_NOEXCEPT { + sync(); + } + + private: + int overflow( int c ) { + sync(); + + if( c != EOF ) { + if( pbase() == epptr() ) + m_writer( std::string( 1, static_cast( c ) ) ); + else + sputc( static_cast( c ) ); + } + return 0; + } + + int sync() { + if( pbase() != pptr() ) { + m_writer( std::string( pbase(), static_cast( pptr() - pbase() ) ) ); + setp( pbase(), epptr() ); + } + return 0; + } + }; + + /////////////////////////////////////////////////////////////////////////// + + FileStream::FileStream( std::string const& filename ) { + m_ofs.open( filename.c_str() ); + if( m_ofs.fail() ) { + std::ostringstream oss; + oss << "Unable to open file: '" << filename << "'"; + throw std::domain_error( oss.str() ); + } + } + + std::ostream& FileStream::stream() const { + return m_ofs; + } + + struct OutputDebugWriter { + + void operator()( std::string const&str ) { + writeToDebugConsole( str ); + } + }; + + DebugOutStream::DebugOutStream() + : m_streamBuf( new StreamBufImpl() ), + m_os( m_streamBuf.get() ) + {} + + std::ostream& DebugOutStream::stream() const { + return m_os; + } + + // Store the streambuf from cout up-front because + // cout may get redirected when running tests + CoutStream::CoutStream() + : m_os( Catch::cout().rdbuf() ) + {} + + std::ostream& CoutStream::stream() const { + return m_os; + } + +#ifndef CATCH_CONFIG_NOSTDOUT // If you #define this you must implement these functions + std::ostream& cout() { + return std::cout; + } + std::ostream& cerr() { + return std::cerr; + } +#endif +} + +namespace Catch { + + class Context : public IMutableContext { + + Context() : m_config( CATCH_NULL ), m_runner( CATCH_NULL ), m_resultCapture( CATCH_NULL ) {} + Context( Context const& ); + void operator=( Context const& ); + + public: // IContext + virtual IResultCapture* getResultCapture() { + return m_resultCapture; + } + virtual IRunner* getRunner() { + return m_runner; + } + virtual size_t getGeneratorIndex( std::string const& fileInfo, size_t totalSize ) { + return getGeneratorsForCurrentTest() + .getGeneratorInfo( fileInfo, totalSize ) + .getCurrentIndex(); + } + virtual bool advanceGeneratorsForCurrentTest() { + IGeneratorsForTest* generators = findGeneratorsForCurrentTest(); + return generators && generators->moveNext(); + } + + virtual Ptr getConfig() const { + return m_config; + } + + public: // IMutableContext + virtual void setResultCapture( IResultCapture* resultCapture ) { + m_resultCapture = resultCapture; + } + virtual void setRunner( IRunner* runner ) { + m_runner = runner; + } + virtual void setConfig( Ptr const& config ) { + m_config = config; + } + + friend IMutableContext& getCurrentMutableContext(); + + private: + IGeneratorsForTest* findGeneratorsForCurrentTest() { + std::string testName = getResultCapture()->getCurrentTestName(); + + std::map::const_iterator it = + m_generatorsByTestName.find( testName ); + return it != m_generatorsByTestName.end() + ? it->second + : CATCH_NULL; + } + + IGeneratorsForTest& getGeneratorsForCurrentTest() { + IGeneratorsForTest* generators = findGeneratorsForCurrentTest(); + if( !generators ) { + std::string testName = getResultCapture()->getCurrentTestName(); + generators = createGeneratorsForTest(); + m_generatorsByTestName.insert( std::make_pair( testName, generators ) ); + } + return *generators; + } + + private: + Ptr m_config; + IRunner* m_runner; + IResultCapture* m_resultCapture; + std::map m_generatorsByTestName; + }; + + namespace { + Context* currentContext = CATCH_NULL; + } + IMutableContext& getCurrentMutableContext() { + if( !currentContext ) + currentContext = new Context(); + return *currentContext; + } + IContext& getCurrentContext() { + return getCurrentMutableContext(); + } + + void cleanUpContext() { + delete currentContext; + currentContext = CATCH_NULL; + } +} + +// #included from: catch_console_colour_impl.hpp +#define TWOBLUECUBES_CATCH_CONSOLE_COLOUR_IMPL_HPP_INCLUDED + +namespace Catch { + namespace { + + struct IColourImpl { + virtual ~IColourImpl() {} + virtual void use( Colour::Code _colourCode ) = 0; + }; + + struct NoColourImpl : IColourImpl { + void use( Colour::Code ) {} + + static IColourImpl* instance() { + static NoColourImpl s_instance; + return &s_instance; + } + }; + + } // anon namespace +} // namespace Catch + +#if !defined( CATCH_CONFIG_COLOUR_NONE ) && !defined( CATCH_CONFIG_COLOUR_WINDOWS ) && !defined( CATCH_CONFIG_COLOUR_ANSI ) +# ifdef CATCH_PLATFORM_WINDOWS +# define CATCH_CONFIG_COLOUR_WINDOWS +# else +# define CATCH_CONFIG_COLOUR_ANSI +# endif +#endif + +#if defined ( CATCH_CONFIG_COLOUR_WINDOWS ) ///////////////////////////////////////// + +#ifndef NOMINMAX +#define NOMINMAX +#endif + +#ifdef __AFXDLL +#include +#else +#include +#endif + +namespace Catch { +namespace { + + class Win32ColourImpl : public IColourImpl { + public: + Win32ColourImpl() : stdoutHandle( GetStdHandle(STD_OUTPUT_HANDLE) ) + { + CONSOLE_SCREEN_BUFFER_INFO csbiInfo; + GetConsoleScreenBufferInfo( stdoutHandle, &csbiInfo ); + originalForegroundAttributes = csbiInfo.wAttributes & ~( BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_BLUE | BACKGROUND_INTENSITY ); + originalBackgroundAttributes = csbiInfo.wAttributes & ~( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY ); + } + + virtual void use( Colour::Code _colourCode ) { + switch( _colourCode ) { + case Colour::None: return setTextAttribute( originalForegroundAttributes ); + case Colour::White: return setTextAttribute( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE ); + case Colour::Red: return setTextAttribute( FOREGROUND_RED ); + case Colour::Green: return setTextAttribute( FOREGROUND_GREEN ); + case Colour::Blue: return setTextAttribute( FOREGROUND_BLUE ); + case Colour::Cyan: return setTextAttribute( FOREGROUND_BLUE | FOREGROUND_GREEN ); + case Colour::Yellow: return setTextAttribute( FOREGROUND_RED | FOREGROUND_GREEN ); + case Colour::Grey: return setTextAttribute( 0 ); + + case Colour::LightGrey: return setTextAttribute( FOREGROUND_INTENSITY ); + case Colour::BrightRed: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED ); + case Colour::BrightGreen: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN ); + case Colour::BrightWhite: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE ); + + case Colour::Bright: throw std::logic_error( "not a colour" ); + } + } + + private: + void setTextAttribute( WORD _textAttribute ) { + SetConsoleTextAttribute( stdoutHandle, _textAttribute | originalBackgroundAttributes ); + } + HANDLE stdoutHandle; + WORD originalForegroundAttributes; + WORD originalBackgroundAttributes; + }; + + IColourImpl* platformColourInstance() { + static Win32ColourImpl s_instance; + + Ptr config = getCurrentContext().getConfig(); + UseColour::YesOrNo colourMode = config + ? config->useColour() + : UseColour::Auto; + if( colourMode == UseColour::Auto ) + colourMode = !isDebuggerActive() + ? UseColour::Yes + : UseColour::No; + return colourMode == UseColour::Yes + ? &s_instance + : NoColourImpl::instance(); + } + +} // end anon namespace +} // end namespace Catch + +#elif defined( CATCH_CONFIG_COLOUR_ANSI ) ////////////////////////////////////// + +#include + +namespace Catch { +namespace { + + // use POSIX/ ANSI console terminal codes + // Thanks to Adam Strzelecki for original contribution + // (http://github.com/nanoant) + // https://github.com/philsquared/Catch/pull/131 + class PosixColourImpl : public IColourImpl { + public: + virtual void use( Colour::Code _colourCode ) { + switch( _colourCode ) { + case Colour::None: + case Colour::White: return setColour( "[0m" ); + case Colour::Red: return setColour( "[0;31m" ); + case Colour::Green: return setColour( "[0;32m" ); + case Colour::Blue: return setColour( "[0:34m" ); + case Colour::Cyan: return setColour( "[0;36m" ); + case Colour::Yellow: return setColour( "[0;33m" ); + case Colour::Grey: return setColour( "[1;30m" ); + + case Colour::LightGrey: return setColour( "[0;37m" ); + case Colour::BrightRed: return setColour( "[1;31m" ); + case Colour::BrightGreen: return setColour( "[1;32m" ); + case Colour::BrightWhite: return setColour( "[1;37m" ); + + case Colour::Bright: throw std::logic_error( "not a colour" ); + } + } + static IColourImpl* instance() { + static PosixColourImpl s_instance; + return &s_instance; + } + + private: + void setColour( const char* _escapeCode ) { + Catch::cout() << '\033' << _escapeCode; + } + }; + + IColourImpl* platformColourInstance() { + Ptr config = getCurrentContext().getConfig(); + UseColour::YesOrNo colourMode = config + ? config->useColour() + : UseColour::Auto; + if( colourMode == UseColour::Auto ) + colourMode = (!isDebuggerActive() && isatty(STDOUT_FILENO) ) + ? UseColour::Yes + : UseColour::No; + return colourMode == UseColour::Yes + ? PosixColourImpl::instance() + : NoColourImpl::instance(); + } + +} // end anon namespace +} // end namespace Catch + +#else // not Windows or ANSI /////////////////////////////////////////////// + +namespace Catch { + + static IColourImpl* platformColourInstance() { return NoColourImpl::instance(); } + +} // end namespace Catch + +#endif // Windows/ ANSI/ None + +namespace Catch { + + Colour::Colour( Code _colourCode ) : m_moved( false ) { use( _colourCode ); } + Colour::Colour( Colour const& _other ) : m_moved( false ) { const_cast( _other ).m_moved = true; } + Colour::~Colour(){ if( !m_moved ) use( None ); } + + void Colour::use( Code _colourCode ) { + static IColourImpl* impl = platformColourInstance(); + impl->use( _colourCode ); + } + +} // end namespace Catch + +// #included from: catch_generators_impl.hpp +#define TWOBLUECUBES_CATCH_GENERATORS_IMPL_HPP_INCLUDED + +#include +#include +#include + +namespace Catch { + + struct GeneratorInfo : IGeneratorInfo { + + GeneratorInfo( std::size_t size ) + : m_size( size ), + m_currentIndex( 0 ) + {} + + bool moveNext() { + if( ++m_currentIndex == m_size ) { + m_currentIndex = 0; + return false; + } + return true; + } + + std::size_t getCurrentIndex() const { + return m_currentIndex; + } + + std::size_t m_size; + std::size_t m_currentIndex; + }; + + /////////////////////////////////////////////////////////////////////////// + + class GeneratorsForTest : public IGeneratorsForTest { + + public: + ~GeneratorsForTest() { + deleteAll( m_generatorsInOrder ); + } + + IGeneratorInfo& getGeneratorInfo( std::string const& fileInfo, std::size_t size ) { + std::map::const_iterator it = m_generatorsByName.find( fileInfo ); + if( it == m_generatorsByName.end() ) { + IGeneratorInfo* info = new GeneratorInfo( size ); + m_generatorsByName.insert( std::make_pair( fileInfo, info ) ); + m_generatorsInOrder.push_back( info ); + return *info; + } + return *it->second; + } + + bool moveNext() { + std::vector::const_iterator it = m_generatorsInOrder.begin(); + std::vector::const_iterator itEnd = m_generatorsInOrder.end(); + for(; it != itEnd; ++it ) { + if( (*it)->moveNext() ) + return true; + } + return false; + } + + private: + std::map m_generatorsByName; + std::vector m_generatorsInOrder; + }; + + IGeneratorsForTest* createGeneratorsForTest() + { + return new GeneratorsForTest(); + } + +} // end namespace Catch + +// #included from: catch_assertionresult.hpp +#define TWOBLUECUBES_CATCH_ASSERTIONRESULT_HPP_INCLUDED + +namespace Catch { + + AssertionInfo::AssertionInfo( std::string const& _macroName, + SourceLineInfo const& _lineInfo, + std::string const& _capturedExpression, + ResultDisposition::Flags _resultDisposition ) + : macroName( _macroName ), + lineInfo( _lineInfo ), + capturedExpression( _capturedExpression ), + resultDisposition( _resultDisposition ) + {} + + AssertionResult::AssertionResult() {} + + AssertionResult::AssertionResult( AssertionInfo const& info, AssertionResultData const& data ) + : m_info( info ), + m_resultData( data ) + {} + + AssertionResult::~AssertionResult() {} + + // Result was a success + bool AssertionResult::succeeded() const { + return Catch::isOk( m_resultData.resultType ); + } + + // Result was a success, or failure is suppressed + bool AssertionResult::isOk() const { + return Catch::isOk( m_resultData.resultType ) || shouldSuppressFailure( m_info.resultDisposition ); + } + + ResultWas::OfType AssertionResult::getResultType() const { + return m_resultData.resultType; + } + + bool AssertionResult::hasExpression() const { + return !m_info.capturedExpression.empty(); + } + + bool AssertionResult::hasMessage() const { + return !m_resultData.message.empty(); + } + + std::string AssertionResult::getExpression() const { + if( isFalseTest( m_info.resultDisposition ) ) + return "!" + m_info.capturedExpression; + else + return m_info.capturedExpression; + } + std::string AssertionResult::getExpressionInMacro() const { + if( m_info.macroName.empty() ) + return m_info.capturedExpression; + else + return m_info.macroName + "( " + m_info.capturedExpression + " )"; + } + + bool AssertionResult::hasExpandedExpression() const { + return hasExpression() && getExpandedExpression() != getExpression(); + } + + std::string AssertionResult::getExpandedExpression() const { + return m_resultData.reconstructedExpression; + } + + std::string AssertionResult::getMessage() const { + return m_resultData.message; + } + SourceLineInfo AssertionResult::getSourceInfo() const { + return m_info.lineInfo; + } + + std::string AssertionResult::getTestMacroName() const { + return m_info.macroName; + } + +} // end namespace Catch + +// #included from: catch_test_case_info.hpp +#define TWOBLUECUBES_CATCH_TEST_CASE_INFO_HPP_INCLUDED + +namespace Catch { + + inline TestCaseInfo::SpecialProperties parseSpecialTag( std::string const& tag ) { + if( startsWith( tag, "." ) || + tag == "hide" || + tag == "!hide" ) + return TestCaseInfo::IsHidden; + else if( tag == "!throws" ) + return TestCaseInfo::Throws; + else if( tag == "!shouldfail" ) + return TestCaseInfo::ShouldFail; + else if( tag == "!mayfail" ) + return TestCaseInfo::MayFail; + else + return TestCaseInfo::None; + } + inline bool isReservedTag( std::string const& tag ) { + return parseSpecialTag( tag ) == TestCaseInfo::None && tag.size() > 0 && !isalnum( tag[0] ); + } + inline void enforceNotReservedTag( std::string const& tag, SourceLineInfo const& _lineInfo ) { + if( isReservedTag( tag ) ) { + { + Colour colourGuard( Colour::Red ); + Catch::cerr() + << "Tag name [" << tag << "] not allowed.\n" + << "Tag names starting with non alpha-numeric characters are reserved\n"; + } + { + Colour colourGuard( Colour::FileName ); + Catch::cerr() << _lineInfo << std::endl; + } + exit(1); + } + } + + TestCase makeTestCase( ITestCase* _testCase, + std::string const& _className, + std::string const& _name, + std::string const& _descOrTags, + SourceLineInfo const& _lineInfo ) + { + bool isHidden( startsWith( _name, "./" ) ); // Legacy support + + // Parse out tags + std::set tags; + std::string desc, tag; + bool inTag = false; + for( std::size_t i = 0; i < _descOrTags.size(); ++i ) { + char c = _descOrTags[i]; + if( !inTag ) { + if( c == '[' ) + inTag = true; + else + desc += c; + } + else { + if( c == ']' ) { + TestCaseInfo::SpecialProperties prop = parseSpecialTag( tag ); + if( prop == TestCaseInfo::IsHidden ) + isHidden = true; + else if( prop == TestCaseInfo::None ) + enforceNotReservedTag( tag, _lineInfo ); + + tags.insert( tag ); + tag.clear(); + inTag = false; + } + else + tag += c; + } + } + if( isHidden ) { + tags.insert( "hide" ); + tags.insert( "." ); + } + + TestCaseInfo info( _name, _className, desc, tags, _lineInfo ); + return TestCase( _testCase, info ); + } + + void setTags( TestCaseInfo& testCaseInfo, std::set const& tags ) + { + testCaseInfo.tags = tags; + testCaseInfo.lcaseTags.clear(); + + std::ostringstream oss; + for( std::set::const_iterator it = tags.begin(), itEnd = tags.end(); it != itEnd; ++it ) { + oss << "[" << *it << "]"; + std::string lcaseTag = toLower( *it ); + testCaseInfo.properties = static_cast( testCaseInfo.properties | parseSpecialTag( lcaseTag ) ); + testCaseInfo.lcaseTags.insert( lcaseTag ); + } + testCaseInfo.tagsAsString = oss.str(); + } + + TestCaseInfo::TestCaseInfo( std::string const& _name, + std::string const& _className, + std::string const& _description, + std::set const& _tags, + SourceLineInfo const& _lineInfo ) + : name( _name ), + className( _className ), + description( _description ), + lineInfo( _lineInfo ), + properties( None ) + { + setTags( *this, _tags ); + } + + TestCaseInfo::TestCaseInfo( TestCaseInfo const& other ) + : name( other.name ), + className( other.className ), + description( other.description ), + tags( other.tags ), + lcaseTags( other.lcaseTags ), + tagsAsString( other.tagsAsString ), + lineInfo( other.lineInfo ), + properties( other.properties ) + {} + + bool TestCaseInfo::isHidden() const { + return ( properties & IsHidden ) != 0; + } + bool TestCaseInfo::throws() const { + return ( properties & Throws ) != 0; + } + bool TestCaseInfo::okToFail() const { + return ( properties & (ShouldFail | MayFail ) ) != 0; + } + bool TestCaseInfo::expectedToFail() const { + return ( properties & (ShouldFail ) ) != 0; + } + + TestCase::TestCase( ITestCase* testCase, TestCaseInfo const& info ) : TestCaseInfo( info ), test( testCase ) {} + + TestCase::TestCase( TestCase const& other ) + : TestCaseInfo( other ), + test( other.test ) + {} + + TestCase TestCase::withName( std::string const& _newName ) const { + TestCase other( *this ); + other.name = _newName; + return other; + } + + void TestCase::swap( TestCase& other ) { + test.swap( other.test ); + name.swap( other.name ); + className.swap( other.className ); + description.swap( other.description ); + tags.swap( other.tags ); + lcaseTags.swap( other.lcaseTags ); + tagsAsString.swap( other.tagsAsString ); + std::swap( TestCaseInfo::properties, static_cast( other ).properties ); + std::swap( lineInfo, other.lineInfo ); + } + + void TestCase::invoke() const { + test->invoke(); + } + + bool TestCase::operator == ( TestCase const& other ) const { + return test.get() == other.test.get() && + name == other.name && + className == other.className; + } + + bool TestCase::operator < ( TestCase const& other ) const { + return name < other.name; + } + TestCase& TestCase::operator = ( TestCase const& other ) { + TestCase temp( other ); + swap( temp ); + return *this; + } + + TestCaseInfo const& TestCase::getTestCaseInfo() const + { + return *this; + } + +} // end namespace Catch + +// #included from: catch_version.hpp +#define TWOBLUECUBES_CATCH_VERSION_HPP_INCLUDED + +namespace Catch { + + Version::Version + ( unsigned int _majorVersion, + unsigned int _minorVersion, + unsigned int _patchNumber, + std::string const& _branchName, + unsigned int _buildNumber ) + : majorVersion( _majorVersion ), + minorVersion( _minorVersion ), + patchNumber( _patchNumber ), + branchName( _branchName ), + buildNumber( _buildNumber ) + {} + + std::ostream& operator << ( std::ostream& os, Version const& version ) { + os << version.majorVersion << "." + << version.minorVersion << "." + << version.patchNumber; + + if( !version.branchName.empty() ) { + os << "-" << version.branchName + << "." << version.buildNumber; + } + return os; + } + + Version libraryVersion( 1, 3, 6, "", 0 ); + +} + +// #included from: catch_message.hpp +#define TWOBLUECUBES_CATCH_MESSAGE_HPP_INCLUDED + +namespace Catch { + + MessageInfo::MessageInfo( std::string const& _macroName, + SourceLineInfo const& _lineInfo, + ResultWas::OfType _type ) + : macroName( _macroName ), + lineInfo( _lineInfo ), + type( _type ), + sequence( ++globalCount ) + {} + + // This may need protecting if threading support is added + unsigned int MessageInfo::globalCount = 0; + + //////////////////////////////////////////////////////////////////////////// + + ScopedMessage::ScopedMessage( MessageBuilder const& builder ) + : m_info( builder.m_info ) + { + m_info.message = builder.m_stream.str(); + getResultCapture().pushScopedMessage( m_info ); + } + ScopedMessage::ScopedMessage( ScopedMessage const& other ) + : m_info( other.m_info ) + {} + + ScopedMessage::~ScopedMessage() { + getResultCapture().popScopedMessage( m_info ); + } + +} // end namespace Catch + +// #included from: catch_legacy_reporter_adapter.hpp +#define TWOBLUECUBES_CATCH_LEGACY_REPORTER_ADAPTER_HPP_INCLUDED + +// #included from: catch_legacy_reporter_adapter.h +#define TWOBLUECUBES_CATCH_LEGACY_REPORTER_ADAPTER_H_INCLUDED + +namespace Catch +{ + // Deprecated + struct IReporter : IShared { + virtual ~IReporter(); + + virtual bool shouldRedirectStdout() const = 0; + + virtual void StartTesting() = 0; + virtual void EndTesting( Totals const& totals ) = 0; + virtual void StartGroup( std::string const& groupName ) = 0; + virtual void EndGroup( std::string const& groupName, Totals const& totals ) = 0; + virtual void StartTestCase( TestCaseInfo const& testInfo ) = 0; + virtual void EndTestCase( TestCaseInfo const& testInfo, Totals const& totals, std::string const& stdOut, std::string const& stdErr ) = 0; + virtual void StartSection( std::string const& sectionName, std::string const& description ) = 0; + virtual void EndSection( std::string const& sectionName, Counts const& assertions ) = 0; + virtual void NoAssertionsInSection( std::string const& sectionName ) = 0; + virtual void NoAssertionsInTestCase( std::string const& testName ) = 0; + virtual void Aborted() = 0; + virtual void Result( AssertionResult const& result ) = 0; + }; + + class LegacyReporterAdapter : public SharedImpl + { + public: + LegacyReporterAdapter( Ptr const& legacyReporter ); + virtual ~LegacyReporterAdapter(); + + virtual ReporterPreferences getPreferences() const; + virtual void noMatchingTestCases( std::string const& ); + virtual void testRunStarting( TestRunInfo const& ); + virtual void testGroupStarting( GroupInfo const& groupInfo ); + virtual void testCaseStarting( TestCaseInfo const& testInfo ); + virtual void sectionStarting( SectionInfo const& sectionInfo ); + virtual void assertionStarting( AssertionInfo const& ); + virtual bool assertionEnded( AssertionStats const& assertionStats ); + virtual void sectionEnded( SectionStats const& sectionStats ); + virtual void testCaseEnded( TestCaseStats const& testCaseStats ); + virtual void testGroupEnded( TestGroupStats const& testGroupStats ); + virtual void testRunEnded( TestRunStats const& testRunStats ); + virtual void skipTest( TestCaseInfo const& ); + + private: + Ptr m_legacyReporter; + }; +} + +namespace Catch +{ + LegacyReporterAdapter::LegacyReporterAdapter( Ptr const& legacyReporter ) + : m_legacyReporter( legacyReporter ) + {} + LegacyReporterAdapter::~LegacyReporterAdapter() {} + + ReporterPreferences LegacyReporterAdapter::getPreferences() const { + ReporterPreferences prefs; + prefs.shouldRedirectStdOut = m_legacyReporter->shouldRedirectStdout(); + return prefs; + } + + void LegacyReporterAdapter::noMatchingTestCases( std::string const& ) {} + void LegacyReporterAdapter::testRunStarting( TestRunInfo const& ) { + m_legacyReporter->StartTesting(); + } + void LegacyReporterAdapter::testGroupStarting( GroupInfo const& groupInfo ) { + m_legacyReporter->StartGroup( groupInfo.name ); + } + void LegacyReporterAdapter::testCaseStarting( TestCaseInfo const& testInfo ) { + m_legacyReporter->StartTestCase( testInfo ); + } + void LegacyReporterAdapter::sectionStarting( SectionInfo const& sectionInfo ) { + m_legacyReporter->StartSection( sectionInfo.name, sectionInfo.description ); + } + void LegacyReporterAdapter::assertionStarting( AssertionInfo const& ) { + // Not on legacy interface + } + + bool LegacyReporterAdapter::assertionEnded( AssertionStats const& assertionStats ) { + if( assertionStats.assertionResult.getResultType() != ResultWas::Ok ) { + for( std::vector::const_iterator it = assertionStats.infoMessages.begin(), itEnd = assertionStats.infoMessages.end(); + it != itEnd; + ++it ) { + if( it->type == ResultWas::Info ) { + ResultBuilder rb( it->macroName.c_str(), it->lineInfo, "", ResultDisposition::Normal ); + rb << it->message; + rb.setResultType( ResultWas::Info ); + AssertionResult result = rb.build(); + m_legacyReporter->Result( result ); + } + } + } + m_legacyReporter->Result( assertionStats.assertionResult ); + return true; + } + void LegacyReporterAdapter::sectionEnded( SectionStats const& sectionStats ) { + if( sectionStats.missingAssertions ) + m_legacyReporter->NoAssertionsInSection( sectionStats.sectionInfo.name ); + m_legacyReporter->EndSection( sectionStats.sectionInfo.name, sectionStats.assertions ); + } + void LegacyReporterAdapter::testCaseEnded( TestCaseStats const& testCaseStats ) { + m_legacyReporter->EndTestCase + ( testCaseStats.testInfo, + testCaseStats.totals, + testCaseStats.stdOut, + testCaseStats.stdErr ); + } + void LegacyReporterAdapter::testGroupEnded( TestGroupStats const& testGroupStats ) { + if( testGroupStats.aborting ) + m_legacyReporter->Aborted(); + m_legacyReporter->EndGroup( testGroupStats.groupInfo.name, testGroupStats.totals ); + } + void LegacyReporterAdapter::testRunEnded( TestRunStats const& testRunStats ) { + m_legacyReporter->EndTesting( testRunStats.totals ); + } + void LegacyReporterAdapter::skipTest( TestCaseInfo const& ) { + } +} + +// #included from: catch_timer.hpp + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wc++11-long-long" +#endif + +#ifdef CATCH_PLATFORM_WINDOWS +#include +#else +#include +#endif + +namespace Catch { + + namespace { +#ifdef CATCH_PLATFORM_WINDOWS + uint64_t getCurrentTicks() { + static uint64_t hz=0, hzo=0; + if (!hz) { + QueryPerformanceFrequency( reinterpret_cast( &hz ) ); + QueryPerformanceCounter( reinterpret_cast( &hzo ) ); + } + uint64_t t; + QueryPerformanceCounter( reinterpret_cast( &t ) ); + return ((t-hzo)*1000000)/hz; + } +#else + uint64_t getCurrentTicks() { + timeval t; + gettimeofday(&t,CATCH_NULL); + return static_cast( t.tv_sec ) * 1000000ull + static_cast( t.tv_usec ); + } +#endif + } + + void Timer::start() { + m_ticks = getCurrentTicks(); + } + unsigned int Timer::getElapsedMicroseconds() const { + return static_cast(getCurrentTicks() - m_ticks); + } + unsigned int Timer::getElapsedMilliseconds() const { + return static_cast(getElapsedMicroseconds()/1000); + } + double Timer::getElapsedSeconds() const { + return getElapsedMicroseconds()/1000000.0; + } + +} // namespace Catch + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif +// #included from: catch_common.hpp +#define TWOBLUECUBES_CATCH_COMMON_HPP_INCLUDED + +namespace Catch { + + bool startsWith( std::string const& s, std::string const& prefix ) { + return s.size() >= prefix.size() && s.substr( 0, prefix.size() ) == prefix; + } + bool endsWith( std::string const& s, std::string const& suffix ) { + return s.size() >= suffix.size() && s.substr( s.size()-suffix.size(), suffix.size() ) == suffix; + } + bool contains( std::string const& s, std::string const& infix ) { + return s.find( infix ) != std::string::npos; + } + void toLowerInPlace( std::string& s ) { + std::transform( s.begin(), s.end(), s.begin(), ::tolower ); + } + std::string toLower( std::string const& s ) { + std::string lc = s; + toLowerInPlace( lc ); + return lc; + } + std::string trim( std::string const& str ) { + static char const* whitespaceChars = "\n\r\t "; + std::string::size_type start = str.find_first_not_of( whitespaceChars ); + std::string::size_type end = str.find_last_not_of( whitespaceChars ); + + return start != std::string::npos ? str.substr( start, 1+end-start ) : ""; + } + + bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ) { + bool replaced = false; + std::size_t i = str.find( replaceThis ); + while( i != std::string::npos ) { + replaced = true; + str = str.substr( 0, i ) + withThis + str.substr( i+replaceThis.size() ); + if( i < str.size()-withThis.size() ) + i = str.find( replaceThis, i+withThis.size() ); + else + i = std::string::npos; + } + return replaced; + } + + pluralise::pluralise( std::size_t count, std::string const& label ) + : m_count( count ), + m_label( label ) + {} + + std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ) { + os << pluraliser.m_count << " " << pluraliser.m_label; + if( pluraliser.m_count != 1 ) + os << "s"; + return os; + } + + SourceLineInfo::SourceLineInfo() : line( 0 ){} + SourceLineInfo::SourceLineInfo( char const* _file, std::size_t _line ) + : file( _file ), + line( _line ) + {} + SourceLineInfo::SourceLineInfo( SourceLineInfo const& other ) + : file( other.file ), + line( other.line ) + {} + bool SourceLineInfo::empty() const { + return file.empty(); + } + bool SourceLineInfo::operator == ( SourceLineInfo const& other ) const { + return line == other.line && file == other.file; + } + bool SourceLineInfo::operator < ( SourceLineInfo const& other ) const { + return line < other.line || ( line == other.line && file < other.file ); + } + + void seedRng( IConfig const& config ) { + if( config.rngSeed() != 0 ) + std::srand( config.rngSeed() ); + } + unsigned int rngSeed() { + return getCurrentContext().getConfig()->rngSeed(); + } + + std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ) { +#ifndef __GNUG__ + os << info.file << "(" << info.line << ")"; +#else + os << info.file << ":" << info.line; +#endif + return os; + } + + void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo ) { + std::ostringstream oss; + oss << locationInfo << ": Internal Catch error: '" << message << "'"; + if( alwaysTrue() ) + throw std::logic_error( oss.str() ); + } +} + +// #included from: catch_section.hpp +#define TWOBLUECUBES_CATCH_SECTION_HPP_INCLUDED + +namespace Catch { + + SectionInfo::SectionInfo + ( SourceLineInfo const& _lineInfo, + std::string const& _name, + std::string const& _description ) + : name( _name ), + description( _description ), + lineInfo( _lineInfo ) + {} + + Section::Section( SectionInfo const& info ) + : m_info( info ), + m_sectionIncluded( getResultCapture().sectionStarted( m_info, m_assertions ) ) + { + m_timer.start(); + } + + Section::~Section() { + if( m_sectionIncluded ) { + SectionEndInfo endInfo( m_info, m_assertions, m_timer.getElapsedSeconds() ); + if( std::uncaught_exception() ) + getResultCapture().sectionEndedEarly( endInfo ); + else + getResultCapture().sectionEnded( endInfo ); + } + } + + // This indicates whether the section should be executed or not + Section::operator bool() const { + return m_sectionIncluded; + } + +} // end namespace Catch + +// #included from: catch_debugger.hpp +#define TWOBLUECUBES_CATCH_DEBUGGER_HPP_INCLUDED + +#include + +#ifdef CATCH_PLATFORM_MAC + + #include + #include + #include + #include + #include + + namespace Catch{ + + // The following function is taken directly from the following technical note: + // http://developer.apple.com/library/mac/#qa/qa2004/qa1361.html + + // Returns true if the current process is being debugged (either + // running under the debugger or has a debugger attached post facto). + bool isDebuggerActive(){ + + int mib[4]; + struct kinfo_proc info; + size_t size; + + // Initialize the flags so that, if sysctl fails for some bizarre + // reason, we get a predictable result. + + info.kp_proc.p_flag = 0; + + // Initialize mib, which tells sysctl the info we want, in this case + // we're looking for information about a specific process ID. + + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PID; + mib[3] = getpid(); + + // Call sysctl. + + size = sizeof(info); + if( sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, CATCH_NULL, 0) != 0 ) { + Catch::cerr() << "\n** Call to sysctl failed - unable to determine if debugger is active **\n" << std::endl; + return false; + } + + // We're being debugged if the P_TRACED flag is set. + + return ( (info.kp_proc.p_flag & P_TRACED) != 0 ); + } + } // namespace Catch + +#elif defined(_MSC_VER) + extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); + namespace Catch { + bool isDebuggerActive() { + return IsDebuggerPresent() != 0; + } + } +#elif defined(__MINGW32__) + extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); + namespace Catch { + bool isDebuggerActive() { + return IsDebuggerPresent() != 0; + } + } +#else + namespace Catch { + inline bool isDebuggerActive() { return false; } + } +#endif // Platform + +#ifdef CATCH_PLATFORM_WINDOWS + extern "C" __declspec(dllimport) void __stdcall OutputDebugStringA( const char* ); + namespace Catch { + void writeToDebugConsole( std::string const& text ) { + ::OutputDebugStringA( text.c_str() ); + } + } +#else + namespace Catch { + void writeToDebugConsole( std::string const& text ) { + // !TBD: Need a version for Mac/ XCode and other IDEs + Catch::cout() << text; + } + } +#endif // Platform + +// #included from: catch_tostring.hpp +#define TWOBLUECUBES_CATCH_TOSTRING_HPP_INCLUDED + +namespace Catch { + +namespace Detail { + + const std::string unprintableString = "{?}"; + + namespace { + const int hexThreshold = 255; + + struct Endianness { + enum Arch { Big, Little }; + + static Arch which() { + union _{ + int asInt; + char asChar[sizeof (int)]; + } u; + + u.asInt = 1; + return ( u.asChar[sizeof(int)-1] == 1 ) ? Big : Little; + } + }; + } + + std::string rawMemoryToString( const void *object, std::size_t size ) + { + // Reverse order for little endian architectures + int i = 0, end = static_cast( size ), inc = 1; + if( Endianness::which() == Endianness::Little ) { + i = end-1; + end = inc = -1; + } + + unsigned char const *bytes = static_cast(object); + std::ostringstream os; + os << "0x" << std::setfill('0') << std::hex; + for( ; i != end; i += inc ) + os << std::setw(2) << static_cast(bytes[i]); + return os.str(); + } +} + +std::string toString( std::string const& value ) { + std::string s = value; + if( getCurrentContext().getConfig()->showInvisibles() ) { + for(size_t i = 0; i < s.size(); ++i ) { + std::string subs; + switch( s[i] ) { + case '\n': subs = "\\n"; break; + case '\t': subs = "\\t"; break; + default: break; + } + if( !subs.empty() ) { + s = s.substr( 0, i ) + subs + s.substr( i+1 ); + ++i; + } + } + } + return "\"" + s + "\""; +} +std::string toString( std::wstring const& value ) { + + std::string s; + s.reserve( value.size() ); + for(size_t i = 0; i < value.size(); ++i ) + s += value[i] <= 0xff ? static_cast( value[i] ) : '?'; + return Catch::toString( s ); +} + +std::string toString( const char* const value ) { + return value ? Catch::toString( std::string( value ) ) : std::string( "{null string}" ); +} + +std::string toString( char* const value ) { + return Catch::toString( static_cast( value ) ); +} + +std::string toString( const wchar_t* const value ) +{ + return value ? Catch::toString( std::wstring(value) ) : std::string( "{null string}" ); +} + +std::string toString( wchar_t* const value ) +{ + return Catch::toString( static_cast( value ) ); +} + +std::string toString( int value ) { + std::ostringstream oss; + oss << value; + if( value > Detail::hexThreshold ) + oss << " (0x" << std::hex << value << ")"; + return oss.str(); +} + +std::string toString( unsigned long value ) { + std::ostringstream oss; + oss << value; + if( value > Detail::hexThreshold ) + oss << " (0x" << std::hex << value << ")"; + return oss.str(); +} + +std::string toString( unsigned int value ) { + return Catch::toString( static_cast( value ) ); +} + +template +std::string fpToString( T value, int precision ) { + std::ostringstream oss; + oss << std::setprecision( precision ) + << std::fixed + << value; + std::string d = oss.str(); + std::size_t i = d.find_last_not_of( '0' ); + if( i != std::string::npos && i != d.size()-1 ) { + if( d[i] == '.' ) + i++; + d = d.substr( 0, i+1 ); + } + return d; +} + +std::string toString( const double value ) { + return fpToString( value, 10 ); +} +std::string toString( const float value ) { + return fpToString( value, 5 ) + "f"; +} + +std::string toString( bool value ) { + return value ? "true" : "false"; +} + +std::string toString( char value ) { + return value < ' ' + ? toString( static_cast( value ) ) + : Detail::makeString( value ); +} + +std::string toString( signed char value ) { + return toString( static_cast( value ) ); +} + +std::string toString( unsigned char value ) { + return toString( static_cast( value ) ); +} + +#ifdef CATCH_CONFIG_CPP11_LONG_LONG +std::string toString( long long value ) { + std::ostringstream oss; + oss << value; + if( value > Detail::hexThreshold ) + oss << " (0x" << std::hex << value << ")"; + return oss.str(); +} +std::string toString( unsigned long long value ) { + std::ostringstream oss; + oss << value; + if( value > Detail::hexThreshold ) + oss << " (0x" << std::hex << value << ")"; + return oss.str(); +} +#endif + +#ifdef CATCH_CONFIG_CPP11_NULLPTR +std::string toString( std::nullptr_t ) { + return "nullptr"; +} +#endif + +#ifdef __OBJC__ + std::string toString( NSString const * const& nsstring ) { + if( !nsstring ) + return "nil"; + return "@" + toString([nsstring UTF8String]); + } + std::string toString( NSString * CATCH_ARC_STRONG const& nsstring ) { + if( !nsstring ) + return "nil"; + return "@" + toString([nsstring UTF8String]); + } + std::string toString( NSObject* const& nsObject ) { + return toString( [nsObject description] ); + } +#endif + +} // end namespace Catch + +// #included from: catch_result_builder.hpp +#define TWOBLUECUBES_CATCH_RESULT_BUILDER_HPP_INCLUDED + +namespace Catch { + + std::string capturedExpressionWithSecondArgument( std::string const& capturedExpression, std::string const& secondArg ) { + return secondArg.empty() || secondArg == "\"\"" + ? capturedExpression + : capturedExpression + ", " + secondArg; + } + ResultBuilder::ResultBuilder( char const* macroName, + SourceLineInfo const& lineInfo, + char const* capturedExpression, + ResultDisposition::Flags resultDisposition, + char const* secondArg ) + : m_assertionInfo( macroName, lineInfo, capturedExpressionWithSecondArgument( capturedExpression, secondArg ), resultDisposition ), + m_shouldDebugBreak( false ), + m_shouldThrow( false ) + {} + + ResultBuilder& ResultBuilder::setResultType( ResultWas::OfType result ) { + m_data.resultType = result; + return *this; + } + ResultBuilder& ResultBuilder::setResultType( bool result ) { + m_data.resultType = result ? ResultWas::Ok : ResultWas::ExpressionFailed; + return *this; + } + ResultBuilder& ResultBuilder::setLhs( std::string const& lhs ) { + m_exprComponents.lhs = lhs; + return *this; + } + ResultBuilder& ResultBuilder::setRhs( std::string const& rhs ) { + m_exprComponents.rhs = rhs; + return *this; + } + ResultBuilder& ResultBuilder::setOp( std::string const& op ) { + m_exprComponents.op = op; + return *this; + } + + void ResultBuilder::endExpression() { + m_exprComponents.testFalse = isFalseTest( m_assertionInfo.resultDisposition ); + captureExpression(); + } + + void ResultBuilder::useActiveException( ResultDisposition::Flags resultDisposition ) { + m_assertionInfo.resultDisposition = resultDisposition; + m_stream.oss << Catch::translateActiveException(); + captureResult( ResultWas::ThrewException ); + } + + void ResultBuilder::captureResult( ResultWas::OfType resultType ) { + setResultType( resultType ); + captureExpression(); + } + void ResultBuilder::captureExpectedException( std::string const& expectedMessage ) { + if( expectedMessage.empty() ) + captureExpectedException( Matchers::Impl::Generic::AllOf() ); + else + captureExpectedException( Matchers::Equals( expectedMessage ) ); + } + + void ResultBuilder::captureExpectedException( Matchers::Impl::Matcher const& matcher ) { + + assert( m_exprComponents.testFalse == false ); + AssertionResultData data = m_data; + data.resultType = ResultWas::Ok; + data.reconstructedExpression = m_assertionInfo.capturedExpression; + + std::string actualMessage = Catch::translateActiveException(); + if( !matcher.match( actualMessage ) ) { + data.resultType = ResultWas::ExpressionFailed; + data.reconstructedExpression = actualMessage; + } + AssertionResult result( m_assertionInfo, data ); + handleResult( result ); + } + + void ResultBuilder::captureExpression() { + AssertionResult result = build(); + handleResult( result ); + } + void ResultBuilder::handleResult( AssertionResult const& result ) + { + getResultCapture().assertionEnded( result ); + + if( !result.isOk() ) { + if( getCurrentContext().getConfig()->shouldDebugBreak() ) + m_shouldDebugBreak = true; + if( getCurrentContext().getRunner()->aborting() || (m_assertionInfo.resultDisposition & ResultDisposition::Normal) ) + m_shouldThrow = true; + } + } + void ResultBuilder::react() { + if( m_shouldThrow ) + throw Catch::TestFailureException(); + } + + bool ResultBuilder::shouldDebugBreak() const { return m_shouldDebugBreak; } + bool ResultBuilder::allowThrows() const { return getCurrentContext().getConfig()->allowThrows(); } + + AssertionResult ResultBuilder::build() const + { + assert( m_data.resultType != ResultWas::Unknown ); + + AssertionResultData data = m_data; + + // Flip bool results if testFalse is set + if( m_exprComponents.testFalse ) { + if( data.resultType == ResultWas::Ok ) + data.resultType = ResultWas::ExpressionFailed; + else if( data.resultType == ResultWas::ExpressionFailed ) + data.resultType = ResultWas::Ok; + } + + data.message = m_stream.oss.str(); + data.reconstructedExpression = reconstructExpression(); + if( m_exprComponents.testFalse ) { + if( m_exprComponents.op == "" ) + data.reconstructedExpression = "!" + data.reconstructedExpression; + else + data.reconstructedExpression = "!(" + data.reconstructedExpression + ")"; + } + return AssertionResult( m_assertionInfo, data ); + } + std::string ResultBuilder::reconstructExpression() const { + if( m_exprComponents.op == "" ) + return m_exprComponents.lhs.empty() ? m_assertionInfo.capturedExpression : m_exprComponents.op + m_exprComponents.lhs; + else if( m_exprComponents.op == "matches" ) + return m_exprComponents.lhs + " " + m_exprComponents.rhs; + else if( m_exprComponents.op != "!" ) { + if( m_exprComponents.lhs.size() + m_exprComponents.rhs.size() < 40 && + m_exprComponents.lhs.find("\n") == std::string::npos && + m_exprComponents.rhs.find("\n") == std::string::npos ) + return m_exprComponents.lhs + " " + m_exprComponents.op + " " + m_exprComponents.rhs; + else + return m_exprComponents.lhs + "\n" + m_exprComponents.op + "\n" + m_exprComponents.rhs; + } + else + return "{can't expand - use " + m_assertionInfo.macroName + "_FALSE( " + m_assertionInfo.capturedExpression.substr(1) + " ) instead of " + m_assertionInfo.macroName + "( " + m_assertionInfo.capturedExpression + " ) for better diagnostics}"; + } + +} // end namespace Catch + +// #included from: catch_tag_alias_registry.hpp +#define TWOBLUECUBES_CATCH_TAG_ALIAS_REGISTRY_HPP_INCLUDED + +// #included from: catch_tag_alias_registry.h +#define TWOBLUECUBES_CATCH_TAG_ALIAS_REGISTRY_H_INCLUDED + +#include + +namespace Catch { + + class TagAliasRegistry : public ITagAliasRegistry { + public: + virtual ~TagAliasRegistry(); + virtual Option find( std::string const& alias ) const; + virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const; + void add( char const* alias, char const* tag, SourceLineInfo const& lineInfo ); + static TagAliasRegistry& get(); + + private: + std::map m_registry; + }; + +} // end namespace Catch + +#include +#include + +namespace Catch { + + TagAliasRegistry::~TagAliasRegistry() {} + + Option TagAliasRegistry::find( std::string const& alias ) const { + std::map::const_iterator it = m_registry.find( alias ); + if( it != m_registry.end() ) + return it->second; + else + return Option(); + } + + std::string TagAliasRegistry::expandAliases( std::string const& unexpandedTestSpec ) const { + std::string expandedTestSpec = unexpandedTestSpec; + for( std::map::const_iterator it = m_registry.begin(), itEnd = m_registry.end(); + it != itEnd; + ++it ) { + std::size_t pos = expandedTestSpec.find( it->first ); + if( pos != std::string::npos ) { + expandedTestSpec = expandedTestSpec.substr( 0, pos ) + + it->second.tag + + expandedTestSpec.substr( pos + it->first.size() ); + } + } + return expandedTestSpec; + } + + void TagAliasRegistry::add( char const* alias, char const* tag, SourceLineInfo const& lineInfo ) { + + if( !startsWith( alias, "[@" ) || !endsWith( alias, "]" ) ) { + std::ostringstream oss; + oss << "error: tag alias, \"" << alias << "\" is not of the form [@alias name].\n" << lineInfo; + throw std::domain_error( oss.str().c_str() ); + } + if( !m_registry.insert( std::make_pair( alias, TagAlias( tag, lineInfo ) ) ).second ) { + std::ostringstream oss; + oss << "error: tag alias, \"" << alias << "\" already registered.\n" + << "\tFirst seen at " << find(alias)->lineInfo << "\n" + << "\tRedefined at " << lineInfo; + throw std::domain_error( oss.str().c_str() ); + } + } + + TagAliasRegistry& TagAliasRegistry::get() { + static TagAliasRegistry instance; + return instance; + + } + + ITagAliasRegistry::~ITagAliasRegistry() {} + ITagAliasRegistry const& ITagAliasRegistry::get() { return TagAliasRegistry::get(); } + + RegistrarForTagAliases::RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ) { + try { + TagAliasRegistry::get().add( alias, tag, lineInfo ); + } + catch( std::exception& ex ) { + Colour colourGuard( Colour::Red ); + Catch::cerr() << ex.what() << std::endl; + exit(1); + } + } + +} // end namespace Catch + +// #included from: ../reporters/catch_reporter_multi.hpp +#define TWOBLUECUBES_CATCH_REPORTER_MULTI_HPP_INCLUDED + +namespace Catch { + +class MultipleReporters : public SharedImpl { + typedef std::vector > Reporters; + Reporters m_reporters; + +public: + void add( Ptr const& reporter ) { + m_reporters.push_back( reporter ); + } + +public: // IStreamingReporter + + virtual ReporterPreferences getPreferences() const CATCH_OVERRIDE { + return m_reporters[0]->getPreferences(); + } + + virtual void noMatchingTestCases( std::string const& spec ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->noMatchingTestCases( spec ); + } + + virtual void testRunStarting( TestRunInfo const& testRunInfo ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->testRunStarting( testRunInfo ); + } + + virtual void testGroupStarting( GroupInfo const& groupInfo ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->testGroupStarting( groupInfo ); + } + + virtual void testCaseStarting( TestCaseInfo const& testInfo ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->testCaseStarting( testInfo ); + } + + virtual void sectionStarting( SectionInfo const& sectionInfo ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->sectionStarting( sectionInfo ); + } + + virtual void assertionStarting( AssertionInfo const& assertionInfo ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->assertionStarting( assertionInfo ); + } + + // The return value indicates if the messages buffer should be cleared: + virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE { + bool clearBuffer = false; + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + clearBuffer |= (*it)->assertionEnded( assertionStats ); + return clearBuffer; + } + + virtual void sectionEnded( SectionStats const& sectionStats ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->sectionEnded( sectionStats ); + } + + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->testCaseEnded( testCaseStats ); + } + + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->testGroupEnded( testGroupStats ); + } + + virtual void testRunEnded( TestRunStats const& testRunStats ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->testRunEnded( testRunStats ); + } + + virtual void skipTest( TestCaseInfo const& testInfo ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->skipTest( testInfo ); + } +}; + +Ptr addReporter( Ptr const& existingReporter, Ptr const& additionalReporter ) { + Ptr resultingReporter; + + if( existingReporter ) { + MultipleReporters* multi = dynamic_cast( existingReporter.get() ); + if( !multi ) { + multi = new MultipleReporters; + resultingReporter = Ptr( multi ); + if( existingReporter ) + multi->add( existingReporter ); + } + else + resultingReporter = existingReporter; + multi->add( additionalReporter ); + } + else + resultingReporter = additionalReporter; + + return resultingReporter; +} + +} // end namespace Catch + +// #included from: ../reporters/catch_reporter_xml.hpp +#define TWOBLUECUBES_CATCH_REPORTER_XML_HPP_INCLUDED + +// #included from: catch_reporter_bases.hpp +#define TWOBLUECUBES_CATCH_REPORTER_BASES_HPP_INCLUDED + +#include + +namespace Catch { + + struct StreamingReporterBase : SharedImpl { + + StreamingReporterBase( ReporterConfig const& _config ) + : m_config( _config.fullConfig() ), + stream( _config.stream() ) + { + m_reporterPrefs.shouldRedirectStdOut = false; + } + + virtual ReporterPreferences getPreferences() const CATCH_OVERRIDE { + return m_reporterPrefs; + } + + virtual ~StreamingReporterBase() CATCH_OVERRIDE; + + virtual void noMatchingTestCases( std::string const& ) CATCH_OVERRIDE {} + + virtual void testRunStarting( TestRunInfo const& _testRunInfo ) CATCH_OVERRIDE { + currentTestRunInfo = _testRunInfo; + } + virtual void testGroupStarting( GroupInfo const& _groupInfo ) CATCH_OVERRIDE { + currentGroupInfo = _groupInfo; + } + + virtual void testCaseStarting( TestCaseInfo const& _testInfo ) CATCH_OVERRIDE { + currentTestCaseInfo = _testInfo; + } + virtual void sectionStarting( SectionInfo const& _sectionInfo ) CATCH_OVERRIDE { + m_sectionStack.push_back( _sectionInfo ); + } + + virtual void sectionEnded( SectionStats const& /* _sectionStats */ ) CATCH_OVERRIDE { + m_sectionStack.pop_back(); + } + virtual void testCaseEnded( TestCaseStats const& /* _testCaseStats */ ) CATCH_OVERRIDE { + currentTestCaseInfo.reset(); + } + virtual void testGroupEnded( TestGroupStats const& /* _testGroupStats */ ) CATCH_OVERRIDE { + currentGroupInfo.reset(); + } + virtual void testRunEnded( TestRunStats const& /* _testRunStats */ ) CATCH_OVERRIDE { + currentTestCaseInfo.reset(); + currentGroupInfo.reset(); + currentTestRunInfo.reset(); + } + + virtual void skipTest( TestCaseInfo const& ) CATCH_OVERRIDE { + // Don't do anything with this by default. + // It can optionally be overridden in the derived class. + } + + Ptr m_config; + std::ostream& stream; + + LazyStat currentTestRunInfo; + LazyStat currentGroupInfo; + LazyStat currentTestCaseInfo; + + std::vector m_sectionStack; + ReporterPreferences m_reporterPrefs; + }; + + struct CumulativeReporterBase : SharedImpl { + template + struct Node : SharedImpl<> { + explicit Node( T const& _value ) : value( _value ) {} + virtual ~Node() {} + + typedef std::vector > ChildNodes; + T value; + ChildNodes children; + }; + struct SectionNode : SharedImpl<> { + explicit SectionNode( SectionStats const& _stats ) : stats( _stats ) {} + virtual ~SectionNode(); + + bool operator == ( SectionNode const& other ) const { + return stats.sectionInfo.lineInfo == other.stats.sectionInfo.lineInfo; + } + bool operator == ( Ptr const& other ) const { + return operator==( *other ); + } + + SectionStats stats; + typedef std::vector > ChildSections; + typedef std::vector Assertions; + ChildSections childSections; + Assertions assertions; + std::string stdOut; + std::string stdErr; + }; + + struct BySectionInfo { + BySectionInfo( SectionInfo const& other ) : m_other( other ) {} + BySectionInfo( BySectionInfo const& other ) : m_other( other.m_other ) {} + bool operator() ( Ptr const& node ) const { + return node->stats.sectionInfo.lineInfo == m_other.lineInfo; + } + private: + void operator=( BySectionInfo const& ); + SectionInfo const& m_other; + }; + + typedef Node TestCaseNode; + typedef Node TestGroupNode; + typedef Node TestRunNode; + + CumulativeReporterBase( ReporterConfig const& _config ) + : m_config( _config.fullConfig() ), + stream( _config.stream() ) + { + m_reporterPrefs.shouldRedirectStdOut = false; + } + ~CumulativeReporterBase(); + + virtual ReporterPreferences getPreferences() const CATCH_OVERRIDE { + return m_reporterPrefs; + } + + virtual void testRunStarting( TestRunInfo const& ) CATCH_OVERRIDE {} + virtual void testGroupStarting( GroupInfo const& ) CATCH_OVERRIDE {} + + virtual void testCaseStarting( TestCaseInfo const& ) CATCH_OVERRIDE {} + + virtual void sectionStarting( SectionInfo const& sectionInfo ) CATCH_OVERRIDE { + SectionStats incompleteStats( sectionInfo, Counts(), 0, false ); + Ptr node; + if( m_sectionStack.empty() ) { + if( !m_rootSection ) + m_rootSection = new SectionNode( incompleteStats ); + node = m_rootSection; + } + else { + SectionNode& parentNode = *m_sectionStack.back(); + SectionNode::ChildSections::const_iterator it = + std::find_if( parentNode.childSections.begin(), + parentNode.childSections.end(), + BySectionInfo( sectionInfo ) ); + if( it == parentNode.childSections.end() ) { + node = new SectionNode( incompleteStats ); + parentNode.childSections.push_back( node ); + } + else + node = *it; + } + m_sectionStack.push_back( node ); + m_deepestSection = node; + } + + virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE {} + + virtual bool assertionEnded( AssertionStats const& assertionStats ) { + assert( !m_sectionStack.empty() ); + SectionNode& sectionNode = *m_sectionStack.back(); + sectionNode.assertions.push_back( assertionStats ); + return true; + } + virtual void sectionEnded( SectionStats const& sectionStats ) CATCH_OVERRIDE { + assert( !m_sectionStack.empty() ); + SectionNode& node = *m_sectionStack.back(); + node.stats = sectionStats; + m_sectionStack.pop_back(); + } + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE { + Ptr node = new TestCaseNode( testCaseStats ); + assert( m_sectionStack.size() == 0 ); + node->children.push_back( m_rootSection ); + m_testCases.push_back( node ); + m_rootSection.reset(); + + assert( m_deepestSection ); + m_deepestSection->stdOut = testCaseStats.stdOut; + m_deepestSection->stdErr = testCaseStats.stdErr; + } + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE { + Ptr node = new TestGroupNode( testGroupStats ); + node->children.swap( m_testCases ); + m_testGroups.push_back( node ); + } + virtual void testRunEnded( TestRunStats const& testRunStats ) CATCH_OVERRIDE { + Ptr node = new TestRunNode( testRunStats ); + node->children.swap( m_testGroups ); + m_testRuns.push_back( node ); + testRunEndedCumulative(); + } + virtual void testRunEndedCumulative() = 0; + + virtual void skipTest( TestCaseInfo const& ) CATCH_OVERRIDE {} + + Ptr m_config; + std::ostream& stream; + std::vector m_assertions; + std::vector > > m_sections; + std::vector > m_testCases; + std::vector > m_testGroups; + + std::vector > m_testRuns; + + Ptr m_rootSection; + Ptr m_deepestSection; + std::vector > m_sectionStack; + ReporterPreferences m_reporterPrefs; + + }; + + template + char const* getLineOfChars() { + static char line[CATCH_CONFIG_CONSOLE_WIDTH] = {0}; + if( !*line ) { + memset( line, C, CATCH_CONFIG_CONSOLE_WIDTH-1 ); + line[CATCH_CONFIG_CONSOLE_WIDTH-1] = 0; + } + return line; + } + + struct TestEventListenerBase : StreamingReporterBase { + TestEventListenerBase( ReporterConfig const& _config ) + : StreamingReporterBase( _config ) + {} + + virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE {} + virtual bool assertionEnded( AssertionStats const& ) CATCH_OVERRIDE { + return false; + } + }; + +} // end namespace Catch + +// #included from: ../internal/catch_reporter_registrars.hpp +#define TWOBLUECUBES_CATCH_REPORTER_REGISTRARS_HPP_INCLUDED + +namespace Catch { + + template + class LegacyReporterRegistrar { + + class ReporterFactory : public IReporterFactory { + virtual IStreamingReporter* create( ReporterConfig const& config ) const { + return new LegacyReporterAdapter( new T( config ) ); + } + + virtual std::string getDescription() const { + return T::getDescription(); + } + }; + + public: + + LegacyReporterRegistrar( std::string const& name ) { + getMutableRegistryHub().registerReporter( name, new ReporterFactory() ); + } + }; + + template + class ReporterRegistrar { + + class ReporterFactory : public SharedImpl { + + // *** Please Note ***: + // - If you end up here looking at a compiler error because it's trying to register + // your custom reporter class be aware that the native reporter interface has changed + // to IStreamingReporter. The "legacy" interface, IReporter, is still supported via + // an adapter. Just use REGISTER_LEGACY_REPORTER to take advantage of the adapter. + // However please consider updating to the new interface as the old one is now + // deprecated and will probably be removed quite soon! + // Please contact me via github if you have any questions at all about this. + // In fact, ideally, please contact me anyway to let me know you've hit this - as I have + // no idea who is actually using custom reporters at all (possibly no-one!). + // The new interface is designed to minimise exposure to interface changes in the future. + virtual IStreamingReporter* create( ReporterConfig const& config ) const { + return new T( config ); + } + + virtual std::string getDescription() const { + return T::getDescription(); + } + }; + + public: + + ReporterRegistrar( std::string const& name ) { + getMutableRegistryHub().registerReporter( name, new ReporterFactory() ); + } + }; + + template + class ListenerRegistrar { + + class ListenerFactory : public SharedImpl { + + virtual IStreamingReporter* create( ReporterConfig const& config ) const { + return new T( config ); + } + virtual std::string getDescription() const { + return ""; + } + }; + + public: + + ListenerRegistrar() { + getMutableRegistryHub().registerListener( new ListenerFactory() ); + } + }; +} + +#define INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) \ + namespace{ Catch::LegacyReporterRegistrar catch_internal_RegistrarFor##reporterType( name ); } + +#define INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) \ + namespace{ Catch::ReporterRegistrar catch_internal_RegistrarFor##reporterType( name ); } + +#define INTERNAL_CATCH_REGISTER_LISTENER( listenerType ) \ + namespace{ Catch::ListenerRegistrar catch_internal_RegistrarFor##listenerType; } + +// #included from: ../internal/catch_xmlwriter.hpp +#define TWOBLUECUBES_CATCH_XMLWRITER_HPP_INCLUDED + +#include +#include +#include +#include + +namespace Catch { + + class XmlEncode { + public: + enum ForWhat { ForTextNodes, ForAttributes }; + + XmlEncode( std::string const& str, ForWhat forWhat = ForTextNodes ) + : m_str( str ), + m_forWhat( forWhat ) + {} + + void encodeTo( std::ostream& os ) const { + + // Apostrophe escaping not necessary if we always use " to write attributes + // (see: http://www.w3.org/TR/xml/#syntax) + + for( std::size_t i = 0; i < m_str.size(); ++ i ) { + char c = m_str[i]; + switch( c ) { + case '<': os << "<"; break; + case '&': os << "&"; break; + + case '>': + // See: http://www.w3.org/TR/xml/#syntax + if( i > 2 && m_str[i-1] == ']' && m_str[i-2] == ']' ) + os << ">"; + else + os << c; + break; + + case '\"': + if( m_forWhat == ForAttributes ) + os << """; + else + os << c; + break; + + default: + // Escape control chars - based on contribution by @espenalb in PR #465 + if ( ( c < '\x09' ) || ( c > '\x0D' && c < '\x20') || c=='\x7F' ) + os << "&#x" << std::uppercase << std::hex << static_cast( c ); + else + os << c; + } + } + } + + friend std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ) { + xmlEncode.encodeTo( os ); + return os; + } + + private: + std::string m_str; + ForWhat m_forWhat; + }; + + class XmlWriter { + public: + + class ScopedElement { + public: + ScopedElement( XmlWriter* writer ) + : m_writer( writer ) + {} + + ScopedElement( ScopedElement const& other ) + : m_writer( other.m_writer ){ + other.m_writer = CATCH_NULL; + } + + ~ScopedElement() { + if( m_writer ) + m_writer->endElement(); + } + + ScopedElement& writeText( std::string const& text, bool indent = true ) { + m_writer->writeText( text, indent ); + return *this; + } + + template + ScopedElement& writeAttribute( std::string const& name, T const& attribute ) { + m_writer->writeAttribute( name, attribute ); + return *this; + } + + private: + mutable XmlWriter* m_writer; + }; + + XmlWriter() + : m_tagIsOpen( false ), + m_needsNewline( false ), + m_os( &Catch::cout() ) + {} + + XmlWriter( std::ostream& os ) + : m_tagIsOpen( false ), + m_needsNewline( false ), + m_os( &os ) + {} + + ~XmlWriter() { + while( !m_tags.empty() ) + endElement(); + } + + XmlWriter& startElement( std::string const& name ) { + ensureTagClosed(); + newlineIfNecessary(); + stream() << m_indent << "<" << name; + m_tags.push_back( name ); + m_indent += " "; + m_tagIsOpen = true; + return *this; + } + + ScopedElement scopedElement( std::string const& name ) { + ScopedElement scoped( this ); + startElement( name ); + return scoped; + } + + XmlWriter& endElement() { + newlineIfNecessary(); + m_indent = m_indent.substr( 0, m_indent.size()-2 ); + if( m_tagIsOpen ) { + stream() << "/>\n"; + m_tagIsOpen = false; + } + else { + stream() << m_indent << "\n"; + } + m_tags.pop_back(); + return *this; + } + + XmlWriter& writeAttribute( std::string const& name, std::string const& attribute ) { + if( !name.empty() && !attribute.empty() ) + stream() << " " << name << "=\"" << XmlEncode( attribute, XmlEncode::ForAttributes ) << "\""; + return *this; + } + + XmlWriter& writeAttribute( std::string const& name, bool attribute ) { + stream() << " " << name << "=\"" << ( attribute ? "true" : "false" ) << "\""; + return *this; + } + + template + XmlWriter& writeAttribute( std::string const& name, T const& attribute ) { + std::ostringstream oss; + oss << attribute; + return writeAttribute( name, oss.str() ); + } + + XmlWriter& writeText( std::string const& text, bool indent = true ) { + if( !text.empty() ){ + bool tagWasOpen = m_tagIsOpen; + ensureTagClosed(); + if( tagWasOpen && indent ) + stream() << m_indent; + stream() << XmlEncode( text ); + m_needsNewline = true; + } + return *this; + } + + XmlWriter& writeComment( std::string const& text ) { + ensureTagClosed(); + stream() << m_indent << ""; + m_needsNewline = true; + return *this; + } + + XmlWriter& writeBlankLine() { + ensureTagClosed(); + stream() << "\n"; + return *this; + } + + void setStream( std::ostream& os ) { + m_os = &os; + } + + private: + XmlWriter( XmlWriter const& ); + void operator=( XmlWriter const& ); + + std::ostream& stream() { + return *m_os; + } + + void ensureTagClosed() { + if( m_tagIsOpen ) { + stream() << ">\n"; + m_tagIsOpen = false; + } + } + + void newlineIfNecessary() { + if( m_needsNewline ) { + stream() << "\n"; + m_needsNewline = false; + } + } + + bool m_tagIsOpen; + bool m_needsNewline; + std::vector m_tags; + std::string m_indent; + std::ostream* m_os; + }; + +} +// #included from: catch_reenable_warnings.h + +#define TWOBLUECUBES_CATCH_REENABLE_WARNINGS_H_INCLUDED + +#ifdef __clang__ +# ifdef __ICC // icpc defines the __clang__ macro +# pragma warning(pop) +# else +# pragma clang diagnostic pop +# endif +#elif defined __GNUC__ +# pragma GCC diagnostic pop +#endif + + +namespace Catch { + class XmlReporter : public StreamingReporterBase { + public: + XmlReporter( ReporterConfig const& _config ) + : StreamingReporterBase( _config ), + m_sectionDepth( 0 ) + { + m_reporterPrefs.shouldRedirectStdOut = true; + } + + virtual ~XmlReporter() CATCH_OVERRIDE; + + static std::string getDescription() { + return "Reports test results as an XML document"; + } + + public: // StreamingReporterBase + + virtual void noMatchingTestCases( std::string const& s ) CATCH_OVERRIDE { + StreamingReporterBase::noMatchingTestCases( s ); + } + + virtual void testRunStarting( TestRunInfo const& testInfo ) CATCH_OVERRIDE { + StreamingReporterBase::testRunStarting( testInfo ); + m_xml.setStream( stream ); + m_xml.startElement( "Catch" ); + if( !m_config->name().empty() ) + m_xml.writeAttribute( "name", m_config->name() ); + } + + virtual void testGroupStarting( GroupInfo const& groupInfo ) CATCH_OVERRIDE { + StreamingReporterBase::testGroupStarting( groupInfo ); + m_xml.startElement( "Group" ) + .writeAttribute( "name", groupInfo.name ); + } + + virtual void testCaseStarting( TestCaseInfo const& testInfo ) CATCH_OVERRIDE { + StreamingReporterBase::testCaseStarting(testInfo); + m_xml.startElement( "TestCase" ).writeAttribute( "name", trim( testInfo.name ) ); + + if ( m_config->showDurations() == ShowDurations::Always ) + m_testCaseTimer.start(); + } + + virtual void sectionStarting( SectionInfo const& sectionInfo ) CATCH_OVERRIDE { + StreamingReporterBase::sectionStarting( sectionInfo ); + if( m_sectionDepth++ > 0 ) { + m_xml.startElement( "Section" ) + .writeAttribute( "name", trim( sectionInfo.name ) ) + .writeAttribute( "description", sectionInfo.description ); + } + } + + virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE { } + + virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE { + const AssertionResult& assertionResult = assertionStats.assertionResult; + + // Print any info messages in tags. + if( assertionStats.assertionResult.getResultType() != ResultWas::Ok ) { + for( std::vector::const_iterator it = assertionStats.infoMessages.begin(), itEnd = assertionStats.infoMessages.end(); + it != itEnd; + ++it ) { + if( it->type == ResultWas::Info ) { + m_xml.scopedElement( "Info" ) + .writeText( it->message ); + } else if ( it->type == ResultWas::Warning ) { + m_xml.scopedElement( "Warning" ) + .writeText( it->message ); + } + } + } + + // Drop out if result was successful but we're not printing them. + if( !m_config->includeSuccessfulResults() && isOk(assertionResult.getResultType()) ) + return true; + + // Print the expression if there is one. + if( assertionResult.hasExpression() ) { + m_xml.startElement( "Expression" ) + .writeAttribute( "success", assertionResult.succeeded() ) + .writeAttribute( "type", assertionResult.getTestMacroName() ) + .writeAttribute( "filename", assertionResult.getSourceInfo().file ) + .writeAttribute( "line", assertionResult.getSourceInfo().line ); + + m_xml.scopedElement( "Original" ) + .writeText( assertionResult.getExpression() ); + m_xml.scopedElement( "Expanded" ) + .writeText( assertionResult.getExpandedExpression() ); + } + + // And... Print a result applicable to each result type. + switch( assertionResult.getResultType() ) { + case ResultWas::ThrewException: + m_xml.scopedElement( "Exception" ) + .writeAttribute( "filename", assertionResult.getSourceInfo().file ) + .writeAttribute( "line", assertionResult.getSourceInfo().line ) + .writeText( assertionResult.getMessage() ); + break; + case ResultWas::FatalErrorCondition: + m_xml.scopedElement( "Fatal Error Condition" ) + .writeAttribute( "filename", assertionResult.getSourceInfo().file ) + .writeAttribute( "line", assertionResult.getSourceInfo().line ) + .writeText( assertionResult.getMessage() ); + break; + case ResultWas::Info: + m_xml.scopedElement( "Info" ) + .writeText( assertionResult.getMessage() ); + break; + case ResultWas::Warning: + // Warning will already have been written + break; + case ResultWas::ExplicitFailure: + m_xml.scopedElement( "Failure" ) + .writeText( assertionResult.getMessage() ); + break; + default: + break; + } + + if( assertionResult.hasExpression() ) + m_xml.endElement(); + + return true; + } + + virtual void sectionEnded( SectionStats const& sectionStats ) CATCH_OVERRIDE { + StreamingReporterBase::sectionEnded( sectionStats ); + if( --m_sectionDepth > 0 ) { + XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResults" ); + e.writeAttribute( "successes", sectionStats.assertions.passed ); + e.writeAttribute( "failures", sectionStats.assertions.failed ); + e.writeAttribute( "expectedFailures", sectionStats.assertions.failedButOk ); + + if ( m_config->showDurations() == ShowDurations::Always ) + e.writeAttribute( "durationInSeconds", sectionStats.durationInSeconds ); + + m_xml.endElement(); + } + } + + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE { + StreamingReporterBase::testCaseEnded( testCaseStats ); + XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResult" ); + e.writeAttribute( "success", testCaseStats.totals.assertions.allOk() ); + + if ( m_config->showDurations() == ShowDurations::Always ) + e.writeAttribute( "durationInSeconds", m_testCaseTimer.getElapsedSeconds() ); + + m_xml.endElement(); + } + + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE { + StreamingReporterBase::testGroupEnded( testGroupStats ); + // TODO: Check testGroupStats.aborting and act accordingly. + m_xml.scopedElement( "OverallResults" ) + .writeAttribute( "successes", testGroupStats.totals.assertions.passed ) + .writeAttribute( "failures", testGroupStats.totals.assertions.failed ) + .writeAttribute( "expectedFailures", testGroupStats.totals.assertions.failedButOk ); + m_xml.endElement(); + } + + virtual void testRunEnded( TestRunStats const& testRunStats ) CATCH_OVERRIDE { + StreamingReporterBase::testRunEnded( testRunStats ); + m_xml.scopedElement( "OverallResults" ) + .writeAttribute( "successes", testRunStats.totals.assertions.passed ) + .writeAttribute( "failures", testRunStats.totals.assertions.failed ) + .writeAttribute( "expectedFailures", testRunStats.totals.assertions.failedButOk ); + m_xml.endElement(); + } + + private: + Timer m_testCaseTimer; + XmlWriter m_xml; + int m_sectionDepth; + }; + + INTERNAL_CATCH_REGISTER_REPORTER( "xml", XmlReporter ) + +} // end namespace Catch + +// #included from: ../reporters/catch_reporter_junit.hpp +#define TWOBLUECUBES_CATCH_REPORTER_JUNIT_HPP_INCLUDED + +#include + +namespace Catch { + + class JunitReporter : public CumulativeReporterBase { + public: + JunitReporter( ReporterConfig const& _config ) + : CumulativeReporterBase( _config ), + xml( _config.stream() ) + { + m_reporterPrefs.shouldRedirectStdOut = true; + } + + virtual ~JunitReporter() CATCH_OVERRIDE; + + static std::string getDescription() { + return "Reports test results in an XML format that looks like Ant's junitreport target"; + } + + virtual void noMatchingTestCases( std::string const& /*spec*/ ) CATCH_OVERRIDE {} + + virtual void testRunStarting( TestRunInfo const& runInfo ) CATCH_OVERRIDE { + CumulativeReporterBase::testRunStarting( runInfo ); + xml.startElement( "testsuites" ); + } + + virtual void testGroupStarting( GroupInfo const& groupInfo ) CATCH_OVERRIDE { + suiteTimer.start(); + stdOutForSuite.str(""); + stdErrForSuite.str(""); + unexpectedExceptions = 0; + CumulativeReporterBase::testGroupStarting( groupInfo ); + } + + virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE { + if( assertionStats.assertionResult.getResultType() == ResultWas::ThrewException ) + unexpectedExceptions++; + return CumulativeReporterBase::assertionEnded( assertionStats ); + } + + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE { + stdOutForSuite << testCaseStats.stdOut; + stdErrForSuite << testCaseStats.stdErr; + CumulativeReporterBase::testCaseEnded( testCaseStats ); + } + + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE { + double suiteTime = suiteTimer.getElapsedSeconds(); + CumulativeReporterBase::testGroupEnded( testGroupStats ); + writeGroup( *m_testGroups.back(), suiteTime ); + } + + virtual void testRunEndedCumulative() CATCH_OVERRIDE { + xml.endElement(); + } + + void writeGroup( TestGroupNode const& groupNode, double suiteTime ) { + XmlWriter::ScopedElement e = xml.scopedElement( "testsuite" ); + TestGroupStats const& stats = groupNode.value; + xml.writeAttribute( "name", stats.groupInfo.name ); + xml.writeAttribute( "errors", unexpectedExceptions ); + xml.writeAttribute( "failures", stats.totals.assertions.failed-unexpectedExceptions ); + xml.writeAttribute( "tests", stats.totals.assertions.total() ); + xml.writeAttribute( "hostname", "tbd" ); // !TBD + if( m_config->showDurations() == ShowDurations::Never ) + xml.writeAttribute( "time", "" ); + else + xml.writeAttribute( "time", suiteTime ); + xml.writeAttribute( "timestamp", "tbd" ); // !TBD + + // Write test cases + for( TestGroupNode::ChildNodes::const_iterator + it = groupNode.children.begin(), itEnd = groupNode.children.end(); + it != itEnd; + ++it ) + writeTestCase( **it ); + + xml.scopedElement( "system-out" ).writeText( trim( stdOutForSuite.str() ), false ); + xml.scopedElement( "system-err" ).writeText( trim( stdErrForSuite.str() ), false ); + } + + void writeTestCase( TestCaseNode const& testCaseNode ) { + TestCaseStats const& stats = testCaseNode.value; + + // All test cases have exactly one section - which represents the + // test case itself. That section may have 0-n nested sections + assert( testCaseNode.children.size() == 1 ); + SectionNode const& rootSection = *testCaseNode.children.front(); + + std::string className = stats.testInfo.className; + + if( className.empty() ) { + if( rootSection.childSections.empty() ) + className = "global"; + } + writeSection( className, "", rootSection ); + } + + void writeSection( std::string const& className, + std::string const& rootName, + SectionNode const& sectionNode ) { + std::string name = trim( sectionNode.stats.sectionInfo.name ); + if( !rootName.empty() ) + name = rootName + "/" + name; + + if( !sectionNode.assertions.empty() || + !sectionNode.stdOut.empty() || + !sectionNode.stdErr.empty() ) { + XmlWriter::ScopedElement e = xml.scopedElement( "testcase" ); + if( className.empty() ) { + xml.writeAttribute( "classname", name ); + xml.writeAttribute( "name", "root" ); + } + else { + xml.writeAttribute( "classname", className ); + xml.writeAttribute( "name", name ); + } + xml.writeAttribute( "time", Catch::toString( sectionNode.stats.durationInSeconds ) ); + + writeAssertions( sectionNode ); + + if( !sectionNode.stdOut.empty() ) + xml.scopedElement( "system-out" ).writeText( trim( sectionNode.stdOut ), false ); + if( !sectionNode.stdErr.empty() ) + xml.scopedElement( "system-err" ).writeText( trim( sectionNode.stdErr ), false ); + } + for( SectionNode::ChildSections::const_iterator + it = sectionNode.childSections.begin(), + itEnd = sectionNode.childSections.end(); + it != itEnd; + ++it ) + if( className.empty() ) + writeSection( name, "", **it ); + else + writeSection( className, name, **it ); + } + + void writeAssertions( SectionNode const& sectionNode ) { + for( SectionNode::Assertions::const_iterator + it = sectionNode.assertions.begin(), itEnd = sectionNode.assertions.end(); + it != itEnd; + ++it ) + writeAssertion( *it ); + } + void writeAssertion( AssertionStats const& stats ) { + AssertionResult const& result = stats.assertionResult; + if( !result.isOk() ) { + std::string elementName; + switch( result.getResultType() ) { + case ResultWas::ThrewException: + case ResultWas::FatalErrorCondition: + elementName = "error"; + break; + case ResultWas::ExplicitFailure: + elementName = "failure"; + break; + case ResultWas::ExpressionFailed: + elementName = "failure"; + break; + case ResultWas::DidntThrowException: + elementName = "failure"; + break; + + // We should never see these here: + case ResultWas::Info: + case ResultWas::Warning: + case ResultWas::Ok: + case ResultWas::Unknown: + case ResultWas::FailureBit: + case ResultWas::Exception: + elementName = "internalError"; + break; + } + + XmlWriter::ScopedElement e = xml.scopedElement( elementName ); + + xml.writeAttribute( "message", result.getExpandedExpression() ); + xml.writeAttribute( "type", result.getTestMacroName() ); + + std::ostringstream oss; + if( !result.getMessage().empty() ) + oss << result.getMessage() << "\n"; + for( std::vector::const_iterator + it = stats.infoMessages.begin(), + itEnd = stats.infoMessages.end(); + it != itEnd; + ++it ) + if( it->type == ResultWas::Info ) + oss << it->message << "\n"; + + oss << "at " << result.getSourceInfo(); + xml.writeText( oss.str(), false ); + } + } + + XmlWriter xml; + Timer suiteTimer; + std::ostringstream stdOutForSuite; + std::ostringstream stdErrForSuite; + unsigned int unexpectedExceptions; + }; + + INTERNAL_CATCH_REGISTER_REPORTER( "junit", JunitReporter ) + +} // end namespace Catch + +// #included from: ../reporters/catch_reporter_console.hpp +#define TWOBLUECUBES_CATCH_REPORTER_CONSOLE_HPP_INCLUDED + +namespace Catch { + + struct ConsoleReporter : StreamingReporterBase { + ConsoleReporter( ReporterConfig const& _config ) + : StreamingReporterBase( _config ), + m_headerPrinted( false ) + {} + + virtual ~ConsoleReporter() CATCH_OVERRIDE; + static std::string getDescription() { + return "Reports test results as plain lines of text"; + } + + virtual void noMatchingTestCases( std::string const& spec ) CATCH_OVERRIDE { + stream << "No test cases matched '" << spec << "'" << std::endl; + } + + virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE { + } + + virtual bool assertionEnded( AssertionStats const& _assertionStats ) CATCH_OVERRIDE { + AssertionResult const& result = _assertionStats.assertionResult; + + bool printInfoMessages = true; + + // Drop out if result was successful and we're not printing those + if( !m_config->includeSuccessfulResults() && result.isOk() ) { + if( result.getResultType() != ResultWas::Warning ) + return false; + printInfoMessages = false; + } + + lazyPrint(); + + AssertionPrinter printer( stream, _assertionStats, printInfoMessages ); + printer.print(); + stream << std::endl; + return true; + } + + virtual void sectionStarting( SectionInfo const& _sectionInfo ) CATCH_OVERRIDE { + m_headerPrinted = false; + StreamingReporterBase::sectionStarting( _sectionInfo ); + } + virtual void sectionEnded( SectionStats const& _sectionStats ) CATCH_OVERRIDE { + if( _sectionStats.missingAssertions ) { + lazyPrint(); + Colour colour( Colour::ResultError ); + if( m_sectionStack.size() > 1 ) + stream << "\nNo assertions in section"; + else + stream << "\nNo assertions in test case"; + stream << " '" << _sectionStats.sectionInfo.name << "'\n" << std::endl; + } + if( m_headerPrinted ) { + if( m_config->showDurations() == ShowDurations::Always ) + stream << "Completed in " << _sectionStats.durationInSeconds << "s" << std::endl; + m_headerPrinted = false; + } + else { + if( m_config->showDurations() == ShowDurations::Always ) + stream << _sectionStats.sectionInfo.name << " completed in " << _sectionStats.durationInSeconds << "s" << std::endl; + } + StreamingReporterBase::sectionEnded( _sectionStats ); + } + + virtual void testCaseEnded( TestCaseStats const& _testCaseStats ) CATCH_OVERRIDE { + StreamingReporterBase::testCaseEnded( _testCaseStats ); + m_headerPrinted = false; + } + virtual void testGroupEnded( TestGroupStats const& _testGroupStats ) CATCH_OVERRIDE { + if( currentGroupInfo.used ) { + printSummaryDivider(); + stream << "Summary for group '" << _testGroupStats.groupInfo.name << "':\n"; + printTotals( _testGroupStats.totals ); + stream << "\n" << std::endl; + } + StreamingReporterBase::testGroupEnded( _testGroupStats ); + } + virtual void testRunEnded( TestRunStats const& _testRunStats ) CATCH_OVERRIDE { + printTotalsDivider( _testRunStats.totals ); + printTotals( _testRunStats.totals ); + stream << std::endl; + StreamingReporterBase::testRunEnded( _testRunStats ); + } + + private: + + class AssertionPrinter { + void operator= ( AssertionPrinter const& ); + public: + AssertionPrinter( std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages ) + : stream( _stream ), + stats( _stats ), + result( _stats.assertionResult ), + colour( Colour::None ), + message( result.getMessage() ), + messages( _stats.infoMessages ), + printInfoMessages( _printInfoMessages ) + { + switch( result.getResultType() ) { + case ResultWas::Ok: + colour = Colour::Success; + passOrFail = "PASSED"; + //if( result.hasMessage() ) + if( _stats.infoMessages.size() == 1 ) + messageLabel = "with message"; + if( _stats.infoMessages.size() > 1 ) + messageLabel = "with messages"; + break; + case ResultWas::ExpressionFailed: + if( result.isOk() ) { + colour = Colour::Success; + passOrFail = "FAILED - but was ok"; + } + else { + colour = Colour::Error; + passOrFail = "FAILED"; + } + if( _stats.infoMessages.size() == 1 ) + messageLabel = "with message"; + if( _stats.infoMessages.size() > 1 ) + messageLabel = "with messages"; + break; + case ResultWas::ThrewException: + colour = Colour::Error; + passOrFail = "FAILED"; + messageLabel = "due to unexpected exception with message"; + break; + case ResultWas::FatalErrorCondition: + colour = Colour::Error; + passOrFail = "FAILED"; + messageLabel = "due to a fatal error condition"; + break; + case ResultWas::DidntThrowException: + colour = Colour::Error; + passOrFail = "FAILED"; + messageLabel = "because no exception was thrown where one was expected"; + break; + case ResultWas::Info: + messageLabel = "info"; + break; + case ResultWas::Warning: + messageLabel = "warning"; + break; + case ResultWas::ExplicitFailure: + passOrFail = "FAILED"; + colour = Colour::Error; + if( _stats.infoMessages.size() == 1 ) + messageLabel = "explicitly with message"; + if( _stats.infoMessages.size() > 1 ) + messageLabel = "explicitly with messages"; + break; + // These cases are here to prevent compiler warnings + case ResultWas::Unknown: + case ResultWas::FailureBit: + case ResultWas::Exception: + passOrFail = "** internal error **"; + colour = Colour::Error; + break; + } + } + + void print() const { + printSourceInfo(); + if( stats.totals.assertions.total() > 0 ) { + if( result.isOk() ) + stream << "\n"; + printResultType(); + printOriginalExpression(); + printReconstructedExpression(); + } + else { + stream << "\n"; + } + printMessage(); + } + + private: + void printResultType() const { + if( !passOrFail.empty() ) { + Colour colourGuard( colour ); + stream << passOrFail << ":\n"; + } + } + void printOriginalExpression() const { + if( result.hasExpression() ) { + Colour colourGuard( Colour::OriginalExpression ); + stream << " "; + stream << result.getExpressionInMacro(); + stream << "\n"; + } + } + void printReconstructedExpression() const { + if( result.hasExpandedExpression() ) { + stream << "with expansion:\n"; + Colour colourGuard( Colour::ReconstructedExpression ); + stream << Text( result.getExpandedExpression(), TextAttributes().setIndent(2) ) << "\n"; + } + } + void printMessage() const { + if( !messageLabel.empty() ) + stream << messageLabel << ":" << "\n"; + for( std::vector::const_iterator it = messages.begin(), itEnd = messages.end(); + it != itEnd; + ++it ) { + // If this assertion is a warning ignore any INFO messages + if( printInfoMessages || it->type != ResultWas::Info ) + stream << Text( it->message, TextAttributes().setIndent(2) ) << "\n"; + } + } + void printSourceInfo() const { + Colour colourGuard( Colour::FileName ); + stream << result.getSourceInfo() << ": "; + } + + std::ostream& stream; + AssertionStats const& stats; + AssertionResult const& result; + Colour::Code colour; + std::string passOrFail; + std::string messageLabel; + std::string message; + std::vector messages; + bool printInfoMessages; + }; + + void lazyPrint() { + + if( !currentTestRunInfo.used ) + lazyPrintRunInfo(); + if( !currentGroupInfo.used ) + lazyPrintGroupInfo(); + + if( !m_headerPrinted ) { + printTestCaseAndSectionHeader(); + m_headerPrinted = true; + } + } + void lazyPrintRunInfo() { + stream << "\n" << getLineOfChars<'~'>() << "\n"; + Colour colour( Colour::SecondaryText ); + stream << currentTestRunInfo->name + << " is a Catch v" << libraryVersion << " host application.\n" + << "Run with -? for options\n\n"; + + if( m_config->rngSeed() != 0 ) + stream << "Randomness seeded to: " << m_config->rngSeed() << "\n\n"; + + currentTestRunInfo.used = true; + } + void lazyPrintGroupInfo() { + if( !currentGroupInfo->name.empty() && currentGroupInfo->groupsCounts > 1 ) { + printClosedHeader( "Group: " + currentGroupInfo->name ); + currentGroupInfo.used = true; + } + } + void printTestCaseAndSectionHeader() { + assert( !m_sectionStack.empty() ); + printOpenHeader( currentTestCaseInfo->name ); + + if( m_sectionStack.size() > 1 ) { + Colour colourGuard( Colour::Headers ); + + std::vector::const_iterator + it = m_sectionStack.begin()+1, // Skip first section (test case) + itEnd = m_sectionStack.end(); + for( ; it != itEnd; ++it ) + printHeaderString( it->name, 2 ); + } + + SourceLineInfo lineInfo = m_sectionStack.front().lineInfo; + + if( !lineInfo.empty() ){ + stream << getLineOfChars<'-'>() << "\n"; + Colour colourGuard( Colour::FileName ); + stream << lineInfo << "\n"; + } + stream << getLineOfChars<'.'>() << "\n" << std::endl; + } + + void printClosedHeader( std::string const& _name ) { + printOpenHeader( _name ); + stream << getLineOfChars<'.'>() << "\n"; + } + void printOpenHeader( std::string const& _name ) { + stream << getLineOfChars<'-'>() << "\n"; + { + Colour colourGuard( Colour::Headers ); + printHeaderString( _name ); + } + } + + // if string has a : in first line will set indent to follow it on + // subsequent lines + void printHeaderString( std::string const& _string, std::size_t indent = 0 ) { + std::size_t i = _string.find( ": " ); + if( i != std::string::npos ) + i+=2; + else + i = 0; + stream << Text( _string, TextAttributes() + .setIndent( indent+i) + .setInitialIndent( indent ) ) << "\n"; + } + + struct SummaryColumn { + + SummaryColumn( std::string const& _label, Colour::Code _colour ) + : label( _label ), + colour( _colour ) + {} + SummaryColumn addRow( std::size_t count ) { + std::ostringstream oss; + oss << count; + std::string row = oss.str(); + for( std::vector::iterator it = rows.begin(); it != rows.end(); ++it ) { + while( it->size() < row.size() ) + *it = " " + *it; + while( it->size() > row.size() ) + row = " " + row; + } + rows.push_back( row ); + return *this; + } + + std::string label; + Colour::Code colour; + std::vector rows; + + }; + + void printTotals( Totals const& totals ) { + if( totals.testCases.total() == 0 ) { + stream << Colour( Colour::Warning ) << "No tests ran\n"; + } + else if( totals.assertions.total() > 0 && totals.assertions.allPassed() ) { + stream << Colour( Colour::ResultSuccess ) << "All tests passed"; + stream << " (" + << pluralise( totals.assertions.passed, "assertion" ) << " in " + << pluralise( totals.testCases.passed, "test case" ) << ")" + << "\n"; + } + else { + + std::vector columns; + columns.push_back( SummaryColumn( "", Colour::None ) + .addRow( totals.testCases.total() ) + .addRow( totals.assertions.total() ) ); + columns.push_back( SummaryColumn( "passed", Colour::Success ) + .addRow( totals.testCases.passed ) + .addRow( totals.assertions.passed ) ); + columns.push_back( SummaryColumn( "failed", Colour::ResultError ) + .addRow( totals.testCases.failed ) + .addRow( totals.assertions.failed ) ); + columns.push_back( SummaryColumn( "failed as expected", Colour::ResultExpectedFailure ) + .addRow( totals.testCases.failedButOk ) + .addRow( totals.assertions.failedButOk ) ); + + printSummaryRow( "test cases", columns, 0 ); + printSummaryRow( "assertions", columns, 1 ); + } + } + void printSummaryRow( std::string const& label, std::vector const& cols, std::size_t row ) { + for( std::vector::const_iterator it = cols.begin(); it != cols.end(); ++it ) { + std::string value = it->rows[row]; + if( it->label.empty() ) { + stream << label << ": "; + if( value != "0" ) + stream << value; + else + stream << Colour( Colour::Warning ) << "- none -"; + } + else if( value != "0" ) { + stream << Colour( Colour::LightGrey ) << " | "; + stream << Colour( it->colour ) + << value << " " << it->label; + } + } + stream << "\n"; + } + + static std::size_t makeRatio( std::size_t number, std::size_t total ) { + std::size_t ratio = total > 0 ? CATCH_CONFIG_CONSOLE_WIDTH * number/ total : 0; + return ( ratio == 0 && number > 0 ) ? 1 : ratio; + } + static std::size_t& findMax( std::size_t& i, std::size_t& j, std::size_t& k ) { + if( i > j && i > k ) + return i; + else if( j > k ) + return j; + else + return k; + } + + void printTotalsDivider( Totals const& totals ) { + if( totals.testCases.total() > 0 ) { + std::size_t failedRatio = makeRatio( totals.testCases.failed, totals.testCases.total() ); + std::size_t failedButOkRatio = makeRatio( totals.testCases.failedButOk, totals.testCases.total() ); + std::size_t passedRatio = makeRatio( totals.testCases.passed, totals.testCases.total() ); + while( failedRatio + failedButOkRatio + passedRatio < CATCH_CONFIG_CONSOLE_WIDTH-1 ) + findMax( failedRatio, failedButOkRatio, passedRatio )++; + while( failedRatio + failedButOkRatio + passedRatio > CATCH_CONFIG_CONSOLE_WIDTH-1 ) + findMax( failedRatio, failedButOkRatio, passedRatio )--; + + stream << Colour( Colour::Error ) << std::string( failedRatio, '=' ); + stream << Colour( Colour::ResultExpectedFailure ) << std::string( failedButOkRatio, '=' ); + if( totals.testCases.allPassed() ) + stream << Colour( Colour::ResultSuccess ) << std::string( passedRatio, '=' ); + else + stream << Colour( Colour::Success ) << std::string( passedRatio, '=' ); + } + else { + stream << Colour( Colour::Warning ) << std::string( CATCH_CONFIG_CONSOLE_WIDTH-1, '=' ); + } + stream << "\n"; + } + void printSummaryDivider() { + stream << getLineOfChars<'-'>() << "\n"; + } + + private: + bool m_headerPrinted; + }; + + INTERNAL_CATCH_REGISTER_REPORTER( "console", ConsoleReporter ) + +} // end namespace Catch + +// #included from: ../reporters/catch_reporter_compact.hpp +#define TWOBLUECUBES_CATCH_REPORTER_COMPACT_HPP_INCLUDED + +namespace Catch { + + struct CompactReporter : StreamingReporterBase { + + CompactReporter( ReporterConfig const& _config ) + : StreamingReporterBase( _config ) + {} + + virtual ~CompactReporter(); + + static std::string getDescription() { + return "Reports test results on a single line, suitable for IDEs"; + } + + virtual ReporterPreferences getPreferences() const { + ReporterPreferences prefs; + prefs.shouldRedirectStdOut = false; + return prefs; + } + + virtual void noMatchingTestCases( std::string const& spec ) { + stream << "No test cases matched '" << spec << "'" << std::endl; + } + + virtual void assertionStarting( AssertionInfo const& ) { + } + + virtual bool assertionEnded( AssertionStats const& _assertionStats ) { + AssertionResult const& result = _assertionStats.assertionResult; + + bool printInfoMessages = true; + + // Drop out if result was successful and we're not printing those + if( !m_config->includeSuccessfulResults() && result.isOk() ) { + if( result.getResultType() != ResultWas::Warning ) + return false; + printInfoMessages = false; + } + + AssertionPrinter printer( stream, _assertionStats, printInfoMessages ); + printer.print(); + + stream << std::endl; + return true; + } + + virtual void testRunEnded( TestRunStats const& _testRunStats ) { + printTotals( _testRunStats.totals ); + stream << "\n" << std::endl; + StreamingReporterBase::testRunEnded( _testRunStats ); + } + + private: + class AssertionPrinter { + void operator= ( AssertionPrinter const& ); + public: + AssertionPrinter( std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages ) + : stream( _stream ) + , stats( _stats ) + , result( _stats.assertionResult ) + , messages( _stats.infoMessages ) + , itMessage( _stats.infoMessages.begin() ) + , printInfoMessages( _printInfoMessages ) + {} + + void print() { + printSourceInfo(); + + itMessage = messages.begin(); + + switch( result.getResultType() ) { + case ResultWas::Ok: + printResultType( Colour::ResultSuccess, passedString() ); + printOriginalExpression(); + printReconstructedExpression(); + if ( ! result.hasExpression() ) + printRemainingMessages( Colour::None ); + else + printRemainingMessages(); + break; + case ResultWas::ExpressionFailed: + if( result.isOk() ) + printResultType( Colour::ResultSuccess, failedString() + std::string( " - but was ok" ) ); + else + printResultType( Colour::Error, failedString() ); + printOriginalExpression(); + printReconstructedExpression(); + printRemainingMessages(); + break; + case ResultWas::ThrewException: + printResultType( Colour::Error, failedString() ); + printIssue( "unexpected exception with message:" ); + printMessage(); + printExpressionWas(); + printRemainingMessages(); + break; + case ResultWas::FatalErrorCondition: + printResultType( Colour::Error, failedString() ); + printIssue( "fatal error condition with message:" ); + printMessage(); + printExpressionWas(); + printRemainingMessages(); + break; + case ResultWas::DidntThrowException: + printResultType( Colour::Error, failedString() ); + printIssue( "expected exception, got none" ); + printExpressionWas(); + printRemainingMessages(); + break; + case ResultWas::Info: + printResultType( Colour::None, "info" ); + printMessage(); + printRemainingMessages(); + break; + case ResultWas::Warning: + printResultType( Colour::None, "warning" ); + printMessage(); + printRemainingMessages(); + break; + case ResultWas::ExplicitFailure: + printResultType( Colour::Error, failedString() ); + printIssue( "explicitly" ); + printRemainingMessages( Colour::None ); + break; + // These cases are here to prevent compiler warnings + case ResultWas::Unknown: + case ResultWas::FailureBit: + case ResultWas::Exception: + printResultType( Colour::Error, "** internal error **" ); + break; + } + } + + private: + // Colour::LightGrey + + static Colour::Code dimColour() { return Colour::FileName; } + +#ifdef CATCH_PLATFORM_MAC + static const char* failedString() { return "FAILED"; } + static const char* passedString() { return "PASSED"; } +#else + static const char* failedString() { return "failed"; } + static const char* passedString() { return "passed"; } +#endif + + void printSourceInfo() const { + Colour colourGuard( Colour::FileName ); + stream << result.getSourceInfo() << ":"; + } + + void printResultType( Colour::Code colour, std::string passOrFail ) const { + if( !passOrFail.empty() ) { + { + Colour colourGuard( colour ); + stream << " " << passOrFail; + } + stream << ":"; + } + } + + void printIssue( std::string issue ) const { + stream << " " << issue; + } + + void printExpressionWas() { + if( result.hasExpression() ) { + stream << ";"; + { + Colour colour( dimColour() ); + stream << " expression was:"; + } + printOriginalExpression(); + } + } + + void printOriginalExpression() const { + if( result.hasExpression() ) { + stream << " " << result.getExpression(); + } + } + + void printReconstructedExpression() const { + if( result.hasExpandedExpression() ) { + { + Colour colour( dimColour() ); + stream << " for: "; + } + stream << result.getExpandedExpression(); + } + } + + void printMessage() { + if ( itMessage != messages.end() ) { + stream << " '" << itMessage->message << "'"; + ++itMessage; + } + } + + void printRemainingMessages( Colour::Code colour = dimColour() ) { + if ( itMessage == messages.end() ) + return; + + // using messages.end() directly yields compilation error: + std::vector::const_iterator itEnd = messages.end(); + const std::size_t N = static_cast( std::distance( itMessage, itEnd ) ); + + { + Colour colourGuard( colour ); + stream << " with " << pluralise( N, "message" ) << ":"; + } + + for(; itMessage != itEnd; ) { + // If this assertion is a warning ignore any INFO messages + if( printInfoMessages || itMessage->type != ResultWas::Info ) { + stream << " '" << itMessage->message << "'"; + if ( ++itMessage != itEnd ) { + Colour colourGuard( dimColour() ); + stream << " and"; + } + } + } + } + + private: + std::ostream& stream; + AssertionStats const& stats; + AssertionResult const& result; + std::vector messages; + std::vector::const_iterator itMessage; + bool printInfoMessages; + }; + + // Colour, message variants: + // - white: No tests ran. + // - red: Failed [both/all] N test cases, failed [both/all] M assertions. + // - white: Passed [both/all] N test cases (no assertions). + // - red: Failed N tests cases, failed M assertions. + // - green: Passed [both/all] N tests cases with M assertions. + + std::string bothOrAll( std::size_t count ) const { + return count == 1 ? "" : count == 2 ? "both " : "all " ; + } + + void printTotals( const Totals& totals ) const { + if( totals.testCases.total() == 0 ) { + stream << "No tests ran."; + } + else if( totals.testCases.failed == totals.testCases.total() ) { + Colour colour( Colour::ResultError ); + const std::string qualify_assertions_failed = + totals.assertions.failed == totals.assertions.total() ? + bothOrAll( totals.assertions.failed ) : ""; + stream << + "Failed " << bothOrAll( totals.testCases.failed ) + << pluralise( totals.testCases.failed, "test case" ) << ", " + "failed " << qualify_assertions_failed << + pluralise( totals.assertions.failed, "assertion" ) << "."; + } + else if( totals.assertions.total() == 0 ) { + stream << + "Passed " << bothOrAll( totals.testCases.total() ) + << pluralise( totals.testCases.total(), "test case" ) + << " (no assertions)."; + } + else if( totals.assertions.failed ) { + Colour colour( Colour::ResultError ); + stream << + "Failed " << pluralise( totals.testCases.failed, "test case" ) << ", " + "failed " << pluralise( totals.assertions.failed, "assertion" ) << "."; + } + else { + Colour colour( Colour::ResultSuccess ); + stream << + "Passed " << bothOrAll( totals.testCases.passed ) + << pluralise( totals.testCases.passed, "test case" ) << + " with " << pluralise( totals.assertions.passed, "assertion" ) << "."; + } + } + }; + + INTERNAL_CATCH_REGISTER_REPORTER( "compact", CompactReporter ) + +} // end namespace Catch + +namespace Catch { + // These are all here to avoid warnings about not having any out of line + // virtual methods + NonCopyable::~NonCopyable() {} + IShared::~IShared() {} + IStream::~IStream() CATCH_NOEXCEPT {} + FileStream::~FileStream() CATCH_NOEXCEPT {} + CoutStream::~CoutStream() CATCH_NOEXCEPT {} + DebugOutStream::~DebugOutStream() CATCH_NOEXCEPT {} + StreamBufBase::~StreamBufBase() CATCH_NOEXCEPT {} + IContext::~IContext() {} + IResultCapture::~IResultCapture() {} + ITestCase::~ITestCase() {} + ITestCaseRegistry::~ITestCaseRegistry() {} + IRegistryHub::~IRegistryHub() {} + IMutableRegistryHub::~IMutableRegistryHub() {} + IExceptionTranslator::~IExceptionTranslator() {} + IExceptionTranslatorRegistry::~IExceptionTranslatorRegistry() {} + IReporter::~IReporter() {} + IReporterFactory::~IReporterFactory() {} + IReporterRegistry::~IReporterRegistry() {} + IStreamingReporter::~IStreamingReporter() {} + AssertionStats::~AssertionStats() {} + SectionStats::~SectionStats() {} + TestCaseStats::~TestCaseStats() {} + TestGroupStats::~TestGroupStats() {} + TestRunStats::~TestRunStats() {} + CumulativeReporterBase::SectionNode::~SectionNode() {} + CumulativeReporterBase::~CumulativeReporterBase() {} + + StreamingReporterBase::~StreamingReporterBase() {} + ConsoleReporter::~ConsoleReporter() {} + CompactReporter::~CompactReporter() {} + IRunner::~IRunner() {} + IMutableContext::~IMutableContext() {} + IConfig::~IConfig() {} + XmlReporter::~XmlReporter() {} + JunitReporter::~JunitReporter() {} + TestRegistry::~TestRegistry() {} + FreeFunctionTestCase::~FreeFunctionTestCase() {} + IGeneratorInfo::~IGeneratorInfo() {} + IGeneratorsForTest::~IGeneratorsForTest() {} + WildcardPattern::~WildcardPattern() {} + TestSpec::Pattern::~Pattern() {} + TestSpec::NamePattern::~NamePattern() {} + TestSpec::TagPattern::~TagPattern() {} + TestSpec::ExcludedPattern::~ExcludedPattern() {} + + Matchers::Impl::StdString::Equals::~Equals() {} + Matchers::Impl::StdString::Contains::~Contains() {} + Matchers::Impl::StdString::StartsWith::~StartsWith() {} + Matchers::Impl::StdString::EndsWith::~EndsWith() {} + + void Config::dummy() {} + + namespace TestCaseTracking { + ITracker::~ITracker() {} + TrackerBase::~TrackerBase() {} + SectionTracker::~SectionTracker() {} + IndexTracker::~IndexTracker() {} + } +} + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +#endif + +#ifdef CATCH_CONFIG_MAIN +// #included from: internal/catch_default_main.hpp +#define TWOBLUECUBES_CATCH_DEFAULT_MAIN_HPP_INCLUDED + +#ifndef __OBJC__ + +// Standard C/C++ main entry point +int main (int argc, char * argv[]) { + return Catch::Session().run( argc, argv ); +} + +#else // __OBJC__ + +// Objective-C entry point +int main (int argc, char * const argv[]) { +#if !CATCH_ARC_ENABLED + NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; +#endif + + Catch::registerTestMethods(); + int result = Catch::Session().run( argc, (char* const*)argv ); + +#if !CATCH_ARC_ENABLED + [pool drain]; +#endif + + return result; +} + +#endif // __OBJC__ + +#endif + +#ifdef CLARA_CONFIG_MAIN_NOT_DEFINED +# undef CLARA_CONFIG_MAIN +#endif + +////// + +// If this config identifier is defined then all CATCH macros are prefixed with CATCH_ +#ifdef CATCH_CONFIG_PREFIX_ALL + +#define CATCH_REQUIRE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE" ) +#define CATCH_REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, "CATCH_REQUIRE_FALSE" ) + +#define CATCH_REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, "", "CATCH_REQUIRE_THROWS" ) +#define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THROWS_AS" ) +#define CATCH_REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, matcher, "CATCH_REQUIRE_THROWS_WITH" ) +#define CATCH_REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_NOTHROW" ) + +#define CATCH_CHECK( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK" ) +#define CATCH_CHECK_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, "CATCH_CHECK_FALSE" ) +#define CATCH_CHECKED_IF( expr ) INTERNAL_CATCH_IF( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECKED_IF" ) +#define CATCH_CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECKED_ELSE" ) +#define CATCH_CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, "CATCH_CHECK_NOFAIL" ) + +#define CATCH_CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THROWS" ) +#define CATCH_CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THROWS_AS" ) +#define CATCH_CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, matcher, "CATCH_CHECK_THROWS_WITH" ) +#define CATCH_CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_NOTHROW" ) + +#define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THAT" ) +#define CATCH_REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THAT" ) + +#define CATCH_INFO( msg ) INTERNAL_CATCH_INFO( msg, "CATCH_INFO" ) +#define CATCH_WARN( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, "CATCH_WARN", msg ) +#define CATCH_SCOPED_INFO( msg ) INTERNAL_CATCH_INFO( msg, "CATCH_INFO" ) +#define CATCH_CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CATCH_CAPTURE" ) +#define CATCH_SCOPED_CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CATCH_CAPTURE" ) + +#ifdef CATCH_CONFIG_VARIADIC_MACROS + #define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ ) + #define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ ) + #define CATCH_METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ ) + #define CATCH_REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ ) + #define CATCH_SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) + #define CATCH_FAIL( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "CATCH_FAIL", __VA_ARGS__ ) + #define CATCH_SUCCEED( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "CATCH_SUCCEED", __VA_ARGS__ ) +#else + #define CATCH_TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description ) + #define CATCH_TEST_CASE_METHOD( className, name, description ) INTERNAL_CATCH_TEST_CASE_METHOD( className, name, description ) + #define CATCH_METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description ) + #define CATCH_REGISTER_TEST_CASE( function, name, description ) INTERNAL_CATCH_REGISTER_TESTCASE( function, name, description ) + #define CATCH_SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description ) + #define CATCH_FAIL( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "CATCH_FAIL", msg ) + #define CATCH_SUCCEED( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "CATCH_SUCCEED", msg ) +#endif +#define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE( "", "" ) + +#define CATCH_REGISTER_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) +#define CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) + +#define CATCH_GENERATE( expr) INTERNAL_CATCH_GENERATE( expr ) + +// "BDD-style" convenience wrappers +#ifdef CATCH_CONFIG_VARIADIC_MACROS +#define CATCH_SCENARIO( ... ) CATCH_TEST_CASE( "Scenario: " __VA_ARGS__ ) +#define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ ) +#else +#define CATCH_SCENARIO( name, tags ) CATCH_TEST_CASE( "Scenario: " name, tags ) +#define CATCH_SCENARIO_METHOD( className, name, tags ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " name, tags ) +#endif +#define CATCH_GIVEN( desc ) CATCH_SECTION( std::string( "Given: ") + desc, "" ) +#define CATCH_WHEN( desc ) CATCH_SECTION( std::string( " When: ") + desc, "" ) +#define CATCH_AND_WHEN( desc ) CATCH_SECTION( std::string( " And: ") + desc, "" ) +#define CATCH_THEN( desc ) CATCH_SECTION( std::string( " Then: ") + desc, "" ) +#define CATCH_AND_THEN( desc ) CATCH_SECTION( std::string( " And: ") + desc, "" ) + +// If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required +#else + +#define REQUIRE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal, "REQUIRE" ) +#define REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, "REQUIRE_FALSE" ) + +#define REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, "", "REQUIRE_THROWS" ) +#define REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::Normal, "REQUIRE_THROWS_AS" ) +#define REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, matcher, "REQUIRE_THROWS_WITH" ) +#define REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::Normal, "REQUIRE_NOTHROW" ) + +#define CHECK( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK" ) +#define CHECK_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, "CHECK_FALSE" ) +#define CHECKED_IF( expr ) INTERNAL_CATCH_IF( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECKED_IF" ) +#define CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECKED_ELSE" ) +#define CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, "CHECK_NOFAIL" ) + +#define CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, "", "CHECK_THROWS" ) +#define CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THROWS_AS" ) +#define CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, matcher, "CHECK_THROWS_WITH" ) +#define CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK_NOTHROW" ) + +#define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THAT" ) +#define REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::Normal, "REQUIRE_THAT" ) + +#define INFO( msg ) INTERNAL_CATCH_INFO( msg, "INFO" ) +#define WARN( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, "WARN", msg ) +#define SCOPED_INFO( msg ) INTERNAL_CATCH_INFO( msg, "INFO" ) +#define CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CAPTURE" ) +#define SCOPED_CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CAPTURE" ) + +#ifdef CATCH_CONFIG_VARIADIC_MACROS + #define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ ) + #define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ ) + #define METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ ) + #define REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ ) + #define SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) + #define FAIL( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "FAIL", __VA_ARGS__ ) + #define SUCCEED( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "SUCCEED", __VA_ARGS__ ) +#else + #define TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description ) + #define TEST_CASE_METHOD( className, name, description ) INTERNAL_CATCH_TEST_CASE_METHOD( className, name, description ) + #define METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description ) + #define REGISTER_TEST_CASE( method, name, description ) INTERNAL_CATCH_REGISTER_TESTCASE( method, name, description ) + #define SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description ) + #define FAIL( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "FAIL", msg ) + #define SUCCEED( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "SUCCEED", msg ) +#endif +#define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE( "", "" ) + +#define REGISTER_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) +#define REGISTER_LEGACY_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) + +#define GENERATE( expr) INTERNAL_CATCH_GENERATE( expr ) + +#endif + +#define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) + +// "BDD-style" convenience wrappers +#ifdef CATCH_CONFIG_VARIADIC_MACROS +#define SCENARIO( ... ) TEST_CASE( "Scenario: " __VA_ARGS__ ) +#define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ ) +#else +#define SCENARIO( name, tags ) TEST_CASE( "Scenario: " name, tags ) +#define SCENARIO_METHOD( className, name, tags ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " name, tags ) +#endif +#define GIVEN( desc ) SECTION( std::string(" Given: ") + desc, "" ) +#define WHEN( desc ) SECTION( std::string(" When: ") + desc, "" ) +#define AND_WHEN( desc ) SECTION( std::string("And when: ") + desc, "" ) +#define THEN( desc ) SECTION( std::string(" Then: ") + desc, "" ) +#define AND_THEN( desc ) SECTION( std::string(" And: ") + desc, "" ) + +using Catch::Detail::Approx; + +#endif // TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED + diff --git a/CUDA_TiledMatrixMultiplication/libwb/vendor/json11.cpp b/CUDA_TiledMatrixMultiplication/libwb/vendor/json11.cpp new file mode 100644 index 0000000..f401c26 --- /dev/null +++ b/CUDA_TiledMatrixMultiplication/libwb/vendor/json11.cpp @@ -0,0 +1,1013 @@ +/* Copyright (c) 2013 Dropbox, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy + * of this software and associated documentation files (the "Software"), to + * deal + * in the Software without restriction, including without limitation the + * rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN + * THE SOFTWARE. + */ + +#include "json11.hpp" +#include +#include +#include +#include +#include +#include + +namespace json11 { + +static const int max_depth = 200; + +using std::string; +using std::vector; +using std::map; +using std::make_shared; +using std::initializer_list; +using std::move; + +/* * * * * * * * * * * * * * * * * * * * + * Serialization + */ + +static void dump(std::nullptr_t, string &out) { + out += "null"; +} + +static void dump(double value, string &out) { + if (std::isfinite(value)) { + char buf[32]; +//PMO +#ifndef _MSC_VER + snprintf(buf, sizeof buf, "%.17g", value); +#else + _snprintf_s(buf, sizeof buf, "%.17g", value); +#endif + out += buf; + } else { + out += "null"; + } +} + +static void dump(int value, string &out) { + char buf[32]; +//PMO +#ifndef _MSC_VER + snprintf(buf, sizeof buf, "%d", value); +#else + _snprintf_s(buf, sizeof buf, "%d", value); +#endif + out += buf; +} + +static void dump(int64_t value, string &out) { + char buf[64]; +//PMO +#ifndef _MSC_VER + snprintf(buf, sizeof buf, "%" PRId64, value); +#else + _snprintf_s(buf, sizeof buf, "%" PRId64, value); +#endif + out += buf; +} + +static void dump(uint64_t value, string &out) { + char buf[128]; +//PMO +#ifndef _MSC_VER + snprintf(buf, sizeof buf, "%" PRIu64, value); +#else + _snprintf_s(buf, sizeof buf, "%" PRIu64, value); +#endif + out += buf; +} + +static void dump(bool value, string &out) { + out += value ? "true" : "false"; +} + +static void dump(const string &value, string &out) { + out += '"'; + for (size_t i = 0; i < value.length(); i++) { + const char ch = value[i]; + if (ch == '\\') { + out += "\\\\"; + } else if (ch == '"') { + out += "\\\""; + } else if (ch == '\b') { + out += "\\b"; + } else if (ch == '\f') { + out += "\\f"; + } else if (ch == '\n') { + out += "\\n"; + } else if (ch == '\r') { + out += "\\r"; + } else if (ch == '\t') { + out += "\\t"; + } else if (static_cast(ch) <= 0x1f) { + char buf[8]; +//PMO +#ifndef _MSC_VER + snprintf(buf, sizeof buf, "\\u%04x", ch); +#else + _snprintf_s(buf, sizeof buf, "\\u%04x", ch); +#endif + out += buf; + } else if (static_cast(ch) == 0xe2 && + static_cast(value[i + 1]) == 0x80 && + static_cast(value[i + 2]) == 0xa8) { + out += "\\u2028"; + i += 2; + } else if (static_cast(ch) == 0xe2 && + static_cast(value[i + 1]) == 0x80 && + static_cast(value[i + 2]) == 0xa9) { + out += "\\u2029"; + i += 2; + } else { + out += ch; + } + } + out += '"'; +} + +static void dump(const Json::array &values, string &out) { + bool first = true; + out += "["; + for (const auto &value : values) { + if (!first) + out += ", "; + value.dump(out); + first = false; + } + out += "]"; +} + +static void dump(const Json::object &values, string &out) { + bool first = true; + out += "{"; + for (const auto &kv : values) { + if (!first) + out += ", "; + dump(kv.first, out); + out += ": "; + kv.second.dump(out); + first = false; + } + out += "}"; +} + +void Json::dump(string &out) const { + m_ptr->dump(out); +} + +/* * * * * * * * * * * * * * * * * * * * + * Value wrappers + */ + +template +class Value : public JsonValue { +protected: + // Constructors + explicit Value(const T &value) : m_value(value) { + } + explicit Value(T &&value) : m_value(move(value)) { + } + + // Get type tag + Json::Type type() const override { + return tag; + } + + // Comparisons + bool equals(const JsonValue *other) const override { + return m_value == static_cast *>(other)->m_value; + } + bool less(const JsonValue *other) const override { + return m_value < static_cast *>(other)->m_value; + } + + const T m_value; + void dump(string &out) const override { + json11::dump(m_value, out); + } +}; + +class JsonDouble final : public Value { + double number_value() const override { + return m_value; + } + int int_value() const override { + return static_cast(m_value); + } + int64_t int64_value() const override { + return (int64_t)m_value; + } + uint64_t uint64_value() const override { + return (uint64_t)m_value; + } + bool equals(const JsonValue *other) const override { + return m_value == other->number_value(); + } + bool less(const JsonValue *other) const override { + return m_value < other->number_value(); + } + +public: + explicit JsonDouble(double value) : Value(value) { + } +}; + +class JsonInt final : public Value { + double number_value() const override { + return m_value; + } + int int_value() const override { + return m_value; + } + int64_t int64_value() const override { + return m_value; + } + uint64_t uint64_value() const override { + return m_value; + } + bool equals(const JsonValue *other) const override { + return m_value == other->number_value(); + } + bool less(const JsonValue *other) const override { + return m_value < other->number_value(); + } + +public: + explicit JsonInt(int value) : Value(value) { + } +}; + +class JsonInt64 final : public Value { + double number_value() const override { + return m_value; + } + int int_value() const override { + return (int)m_value; + } + int64_t int64_value() const override { + return m_value; + } + uint64_t uint64_value() const override { + return (uint64_t)m_value; + } + bool equals(const JsonValue *other) const override { + return m_value == other->number_value(); + } + bool less(const JsonValue *other) const override { + return m_value < other->number_value(); + } + +public: + explicit JsonInt64(int64_t value) : Value(value) { + } +}; + +class JsonUInt64 final : public Value { + double number_value() const override { + return m_value; + } + int int_value() const override { + return (int)m_value; + } + int64_t int64_value() const override { + return (int64_t)m_value; + } + uint64_t uint64_value() const override { + return m_value; + } + bool equals(const JsonValue *other) const override { + return m_value == other->number_value(); + } + bool less(const JsonValue *other) const override { + return m_value < other->number_value(); + } + +public: + explicit JsonUInt64(uint64_t value) : Value(value) { + } +}; + +class JsonBoolean final : public Value { + bool bool_value() const override { + return m_value; + } + +public: + explicit JsonBoolean(bool value) : Value(value) { + } +}; + +class JsonString final : public Value { + const string &string_value() const override { + return m_value; + } + +public: + explicit JsonString(const string &value) : Value(value) { + } + explicit JsonString(string &&value) : Value(move(value)) { + } +}; + +class JsonArray final : public Value { + const Json::array &array_items() const override { + return m_value; + } + const Json &operator[](size_t i) const override; + +public: + explicit JsonArray(const Json::array &value) : Value(value) { + } + explicit JsonArray(Json::array &&value) : Value(move(value)) { + } +}; + +class JsonObject final : public Value { + const Json::object &object_items() const override { + return m_value; + } + const Json &operator[](const string &key) const override; + +public: + explicit JsonObject(const Json::object &value) : Value(value) { + } + explicit JsonObject(Json::object &&value) : Value(move(value)) { + } +}; + +class JsonNull final : public Value { +public: + JsonNull() : Value(nullptr) { + } +}; + +/* * * * * * * * * * * * * * * * * * * * + * Static globals - static-init-safe + */ +struct Statics { + const std::shared_ptr null = make_shared(); + const std::shared_ptr t = make_shared(true); + const std::shared_ptr f = make_shared(false); + const string empty_string; + const vector empty_vector; + const map empty_map; + Statics() { + } +}; + +static const Statics &statics() { + static const Statics s{}; + return s; +} + +static const Json &static_null() { + // This has to be separate, not in Statics, because Json() accesses + // statics().null. + static const Json json_null; + return json_null; +} + +/* * * * * * * * * * * * * * * * * * * * + * Constructors + */ + +Json::Json() NOEXCEPT : m_ptr(statics().null) { +} +Json::Json(std::nullptr_t) NOEXCEPT : m_ptr(statics().null) { +} +Json::Json(double value) : m_ptr(make_shared(value)) { +} +Json::Json(int value) : m_ptr(make_shared(value)) { +} +Json::Json(int64_t value) : m_ptr(make_shared(value)) { +} +Json::Json(uint64_t value) : m_ptr(make_shared(value)) { +} +Json::Json(bool value) : m_ptr(value ? statics().t : statics().f) { +} +Json::Json(const string &value) : m_ptr(make_shared(value)) { +} +Json::Json(string &&value) : m_ptr(make_shared(move(value))) { +} +Json::Json(const char *value) : m_ptr(make_shared(value)) { +} +Json::Json(const Json::array &values) + : m_ptr(make_shared(values)) { +} +Json::Json(Json::array &&values) + : m_ptr(make_shared(move(values))) { +} +Json::Json(const Json::object &values) + : m_ptr(make_shared(values)) { +} +Json::Json(Json::object &&values) + : m_ptr(make_shared(move(values))) { +} + +/* * * * * * * * * * * * * * * * * * * * + * Accessors + */ + +Json::Type Json::type() const { + return m_ptr->type(); +} +double Json::number_value() const { + return m_ptr->number_value(); +} +int Json::int_value() const { + return m_ptr->int_value(); +} +int64_t Json::int64_value() const { + return m_ptr->int64_value(); +} +uint64_t Json::uint64_value() const { + return m_ptr->uint64_value(); +} +bool Json::bool_value() const { + return m_ptr->bool_value(); +} +const string &Json::string_value() const { + return m_ptr->string_value(); +} +const vector &Json::array_items() const { + return m_ptr->array_items(); +} +const map &Json::object_items() const { + return m_ptr->object_items(); +} +const Json &Json::operator[](size_t i) const { + return (*m_ptr)[i]; +} +const Json &Json::operator[](const string &key) const { + return (*m_ptr)[key]; +} + +double JsonValue::number_value() const { + return 0; +} +int JsonValue::int_value() const { + return 0; +} +int64_t JsonValue::int64_value() const { + return 0; +} +uint64_t JsonValue::uint64_value() const { + return 0; +} +bool JsonValue::bool_value() const { + return false; +} +const string &JsonValue::string_value() const { + return statics().empty_string; +} +const vector &JsonValue::array_items() const { + return statics().empty_vector; +} +const map &JsonValue::object_items() const { + return statics().empty_map; +} +const Json &JsonValue::operator[](size_t) const { + return static_null(); +} +const Json &JsonValue::operator[](const string &) const { + return static_null(); +} + +const Json &JsonObject::operator[](const string &key) const { + auto iter = m_value.find(key); + return (iter == m_value.end()) ? static_null() : iter->second; +} +const Json &JsonArray::operator[](size_t i) const { + if (i >= m_value.size()) + return static_null(); + else + return m_value[i]; +} + +/* * * * * * * * * * * * * * * * * * * * + * Comparison + */ + +bool Json::operator==(const Json &other) const { + if (m_ptr->type() != other.m_ptr->type()) + return false; + + return m_ptr->equals(other.m_ptr.get()); +} + +bool Json::operator<(const Json &other) const { + if (m_ptr->type() != other.m_ptr->type()) + return m_ptr->type() < other.m_ptr->type(); + + return m_ptr->less(other.m_ptr.get()); +} + +/* * * * * * * * * * * * * * * * * * * * + * Parsing + */ + +/* esc(c) + * + * Format char c suitable for printing in an error message. + */ +static inline string esc(char c) { + char buf[12]; + if (static_cast(c) >= 0x20 && static_cast(c) <= 0x7f) { +//PMO +#ifndef _MSC_VER + snprintf(buf, sizeof buf, "'%c' (%d)", c, c); +#else + _snprintf_s(buf, sizeof buf, "'%c' (%d)", c, c); +#endif + } else { +//PMO +#ifndef _MSC_VER + snprintf(buf, sizeof buf, "(%d)", c); +#else + _snprintf_s(buf, sizeof buf, "(%d)", c); +#endif + } + return string(buf); +} + +static inline bool in_range(long x, long lower, long upper) { + return (x >= lower && x <= upper); +} + +/* JsonParser + * + * Object that tracks all state of an in-progress parse. + */ +struct JsonParser { + + /* State + */ + const string &str; + size_t i; + string &err; + bool failed; + const JsonParse strategy; + + /* fail(msg, err_ret = Json()) + * + * Mark this parse as failed. + */ + Json fail(string &&msg) { + return fail(move(msg), Json()); + } + + template + T fail(string &&msg, const T err_ret) { + if (!failed) + err = std::move(msg); + failed = true; + return err_ret; + } + + /* consume_whitespace() + * + * Advance until the current character is non-whitespace. + */ + void consume_whitespace() { + while (str[i] == ' ' || str[i] == '\r' || str[i] == '\n' || + str[i] == '\t') + i++; + } + + /* consume_comment() + * + * Advance comments (c-style inline and multiline). + */ + bool consume_comment() { + bool comment_found = false; + if (str[i] == '/') { + i++; + if (i == str.size()) + return fail("unexpected end of input inside comment", 0); + if (str[i] == '/') { // inline comment + i++; + if (i == str.size()) + return fail("unexpected end of input inside inline comment", 0); + // advance until next line + while (str[i] != '\n') { + i++; + if (i == str.size()) + return fail("unexpected end of input inside inline comment", + 0); + } + comment_found = true; + } else if (str[i] == '*') { // multiline comment + i++; + if (i > str.size() - 2) + return fail("unexpected end of input inside multi-line comment", + 0); + // advance until closing tokens + while (!(str[i] == '*' && str[i + 1] == '/')) { + i++; + if (i > str.size() - 2) + return fail( + "unexpected end of input inside multi-line comment", 0); + } + i += 2; + if (i == str.size()) + return fail("unexpected end of input inside multi-line comment", + 0); + comment_found = true; + } else + return fail("malformed comment", 0); + } + return comment_found; + } + + /* consume_garbage() + * + * Advance until the current character is non-whitespace and non-comment. + */ + void consume_garbage() { + consume_whitespace(); + if (strategy == JsonParse::COMMENTS) { + bool comment_found = false; + do { + comment_found = consume_comment(); + consume_whitespace(); + } while (comment_found); + } + } + + /* get_next_token() + * + * Return the next non-whitespace character. If the end of the input is + * reached, + * flag an error and return 0. + */ + char get_next_token() { + consume_garbage(); + if (i == str.size()) + return fail("unexpected end of input", 0); + + return str[i++]; + } + + /* encode_utf8(pt, out) + * + * Encode pt as UTF-8 and add it to out. + */ + void encode_utf8(long pt, string &out) { + if (pt < 0) + return; + + if (pt < 0x80) { + out += static_cast(pt); + } else if (pt < 0x800) { + out += static_cast((pt >> 6) | 0xC0); + out += static_cast((pt & 0x3F) | 0x80); + } else if (pt < 0x10000) { + out += static_cast((pt >> 12) | 0xE0); + out += static_cast(((pt >> 6) & 0x3F) | 0x80); + out += static_cast((pt & 0x3F) | 0x80); + } else { + out += static_cast((pt >> 18) | 0xF0); + out += static_cast(((pt >> 12) & 0x3F) | 0x80); + out += static_cast(((pt >> 6) & 0x3F) | 0x80); + out += static_cast((pt & 0x3F) | 0x80); + } + } + + /* parse_string() + * + * Parse a string, starting at the current position. + */ + string parse_string() { + string out; + long last_escaped_codepoint = -1; + while (true) { + if (i == str.size()) + return fail("unexpected end of input in string", ""); + + char ch = str[i++]; + + if (ch == '"') { + encode_utf8(last_escaped_codepoint, out); + return out; + } + + if (in_range(ch, 0, 0x1f)) + return fail("unescaped " + esc(ch) + " in string", ""); + + // The usual case: non-escaped characters + if (ch != '\\') { + encode_utf8(last_escaped_codepoint, out); + last_escaped_codepoint = -1; + out += ch; + continue; + } + + // Handle escapes + if (i == str.size()) + return fail("unexpected end of input in string", ""); + + ch = str[i++]; + + if (ch == 'u') { + // Extract 4-byte escape sequence + string esc = str.substr(i, 4); + // Explicitly check length of the substring. The following loop + // relies on std::string returning the terminating NUL when + // accessing str[length]. Checking here reduces brittleness. + if (esc.length() < 4) { + return fail("bad \\u escape: " + esc, ""); + } + for (int j = 0; j < 4; j++) { + if (!in_range(esc[j], 'a', 'f') && !in_range(esc[j], 'A', 'F') && + !in_range(esc[j], '0', '9')) + return fail("bad \\u escape: " + esc, ""); + } + + long codepoint = strtol(esc.data(), nullptr, 16); + + // JSON specifies that characters outside the BMP shall be encoded + // as a pair + // of 4-hex-digit \u escapes encoding their surrogate pair + // components. Check + // whether we're in the middle of such a beast: the previous + // codepoint was an + // escaped lead (high) surrogate, and this is a trail (low) + // surrogate. + if (in_range(last_escaped_codepoint, 0xD800, 0xDBFF) && + in_range(codepoint, 0xDC00, 0xDFFF)) { + // Reassemble the two surrogate pairs into one astral-plane + // character, per + // the UTF-16 algorithm. + encode_utf8((((last_escaped_codepoint - 0xD800) << 10) | + (codepoint - 0xDC00)) + + 0x10000, + out); + last_escaped_codepoint = -1; + } else { + encode_utf8(last_escaped_codepoint, out); + last_escaped_codepoint = codepoint; + } + + i += 4; + continue; + } + + encode_utf8(last_escaped_codepoint, out); + last_escaped_codepoint = -1; + + if (ch == 'b') { + out += '\b'; + } else if (ch == 'f') { + out += '\f'; + } else if (ch == 'n') { + out += '\n'; + } else if (ch == 'r') { + out += '\r'; + } else if (ch == 't') { + out += '\t'; + } else if (ch == '"' || ch == '\\' || ch == '/') { + out += ch; + } else { + return fail("invalid escape character " + esc(ch), ""); + } + } + } + + /* parse_number() + * + * Parse a double. + */ + Json parse_number() { + size_t start_pos = i; + + if (str[i] == '-') + i++; + + // Integer part + if (str[i] == '0') { + i++; + if (in_range(str[i], '0', '9')) + return fail("leading 0s not permitted in numbers"); + } else if (in_range(str[i], '1', '9')) { + i++; + while (in_range(str[i], '0', '9')) + i++; + } else { + return fail("invalid " + esc(str[i]) + " in number"); + } + + if (str[i] != '.' && str[i] != 'e' && str[i] != 'E' && + (i - start_pos) <= + static_cast(std::numeric_limits::digits10)) { + return std::atoi(str.c_str() + start_pos); + } + + // Decimal part + if (str[i] == '.') { + i++; + if (!in_range(str[i], '0', '9')) + return fail("at least one digit required in fractional part"); + + while (in_range(str[i], '0', '9')) + i++; + } + + // Exponent part + if (str[i] == 'e' || str[i] == 'E') { + i++; + + if (str[i] == '+' || str[i] == '-') + i++; + + if (!in_range(str[i], '0', '9')) + return fail("at least one digit required in exponent"); + + while (in_range(str[i], '0', '9')) + i++; + } + + return std::strtod(str.c_str() + start_pos, nullptr); + } + + /* expect(str, res) + * + * Expect that 'str' starts at the character that was just read. If it + * does, advance + * the input and return res. If not, flag an error. + */ + Json expect(const string &expected, Json res) { + assert(i != 0); + i--; + if (str.compare(i, expected.length(), expected) == 0) { + i += expected.length(); + return res; + } else { + return fail("parse error: expected " + expected + ", got " + + str.substr(i, expected.length())); + } + } + + /* parse_json() + * + * Parse a JSON object. + */ + Json parse_json(int depth) { + if (depth > max_depth) { + return fail("exceeded maximum nesting depth"); + } + + char ch = get_next_token(); + if (failed) + return Json(); + + if (ch == '-' || (ch >= '0' && ch <= '9')) { + i--; + return parse_number(); + } + + if (ch == 't') + return expect("true", true); + + if (ch == 'f') + return expect("false", false); + + if (ch == 'n') + return expect("null", Json()); + + if (ch == '"') + return parse_string(); + + if (ch == '{') { + map data; + ch = get_next_token(); + if (ch == '}') + return data; + + while (1) { + if (ch != '"') + return fail("expected '\"' in object, got " + esc(ch)); + + string key = parse_string(); + if (failed) + return Json(); + + ch = get_next_token(); + if (ch != ':') + return fail("expected ':' in object, got " + esc(ch)); + + data[std::move(key)] = parse_json(depth + 1); + if (failed) + return Json(); + + ch = get_next_token(); + if (ch == '}') + break; + if (ch != ',') + return fail("expected ',' in object, got " + esc(ch)); + + ch = get_next_token(); + } + return data; + } + + if (ch == '[') { + vector data; + ch = get_next_token(); + if (ch == ']') + return data; + + while (1) { + i--; + data.push_back(parse_json(depth + 1)); + if (failed) + return Json(); + + ch = get_next_token(); + if (ch == ']') + break; + if (ch != ',') + return fail("expected ',' in list, got " + esc(ch)); + + ch = get_next_token(); + (void)ch; + } + return data; + } + + return fail("expected value, got " + esc(ch)); + } +}; + +Json Json::parse(const string &in, string &err, JsonParse strategy) { + JsonParser parser{in, 0, err, false, strategy}; + Json result = parser.parse_json(0); + + // Check for any trailing garbage + parser.consume_garbage(); + if (parser.i != in.size()) + return parser.fail("unexpected trailing " + esc(in[parser.i])); + + return result; +} + +// Documented in json11.hpp +vector Json::parse_multi(const string &in, string &err, + JsonParse strategy) { + JsonParser parser{in, 0, err, false, strategy}; + + vector json_vec; + while (parser.i != in.size() && !parser.failed) { + json_vec.push_back(parser.parse_json(0)); + // Check for another object + parser.consume_garbage(); + } + return json_vec; +} + +/* * * * * * * * * * * * * * * * * * * * + * Shape-checking + */ + +bool Json::has_shape(const shape &types, string &err) const { + if (!is_object()) { + err = "expected JSON object, got " + dump(); + return false; + } + + for (auto &item : types) { + if ((*this)[item.first].type() != item.second) { + err = "bad type for " + item.first + " in " + dump(); + return false; + } + } + + return true; +} + +} // namespace json11 diff --git a/CUDA_TiledMatrixMultiplication/libwb/vendor/json11.hpp b/CUDA_TiledMatrixMultiplication/libwb/vendor/json11.hpp new file mode 100644 index 0000000..9e0f0d9 --- /dev/null +++ b/CUDA_TiledMatrixMultiplication/libwb/vendor/json11.hpp @@ -0,0 +1,300 @@ +/* json11 + * + * json11 is a tiny JSON library for C++11, providing JSON parsing and + * serialization. + * + * The core object provided by the library is json11::Json. A Json object + * represents any JSON + * value: null, bool, number (int or double), string (std::string), array + * (std::vector), or + * object (std::map). + * + * Json objects act like values: they can be assigned, copied, moved, + * compared for equality or + * order, etc. There are also helper methods Json::dump, to serialize a + * Json to a string, and + * Json::parse (static) to parse a std::string as a Json object. + * + * Internally, the various types of Json object are represented by the + * JsonValue class + * hierarchy. + * + * A note on numbers - JSON specifies the syntax of number formatting but + * not its semantics, + * so some JSON implementations distinguish between integers and + * floating-point numbers, while + * some don't. In json11, we choose the latter. Because some JSON + * implementations (namely + * Javascript itself) treat all numbers as the same type, distinguishing + * the two leads + * to JSON that will be *silently* changed by a round-trip through those + * implementations. + * Dangerous! To avoid that risk, json11 stores all numbers as double + * internally, but also + * provides integer helpers. + * + * Fortunately, double-precision IEEE754 ('double') can precisely store any + * integer in the + * range +/-2^53, which includes every 'int' on most systems. (Timestamps + * often use int64 + * or long long to avoid the Y2038K problem; a double storing microseconds + * since some epoch + * will be exact for +/- 275 years.) + */ + +/* Copyright (c) 2013 Dropbox, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy + * of this software and associated documentation files (the "Software"), to + * deal + * in the Software without restriction, including without limitation the + * rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN + * THE SOFTWARE. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +//PMO +#ifndef _MSC_VER +#define NOEXCEPT noexcept +#else +#define NOEXCEPT _NOEXCEPT +#endif + +namespace json11 { + +enum JsonParse { STANDARD, COMMENTS }; + +class JsonValue; + +class Json final { +public: + // Types + enum Type { + NUL, + NUMBER, + NUMBER64, + UNUMBER64, + BOOL, + STRING, + ARRAY, + OBJECT + }; + + // Array and object typedefs + typedef std::vector array; + typedef std::map object; + + // Constructors for the various types of JSON value. + //PMO + //Json() noexcept; // NUL + Json() NOEXCEPT; // NUL + //Json(std::nullptr_t) noexcept; // NUL + Json(std::nullptr_t) NOEXCEPT; // NUL + Json(double value); // NUMBER + Json(int value); // NUMBER + Json(int64_t value); // NUMBER64 + Json(uint64_t value); // UNUMBER64 + Json(bool value); // BOOL + Json(const std::string &value); // STRING + Json(std::string &&value); // STRING + Json(const char *value); // STRING + Json(const array &values); // ARRAY + Json(array &&values); // ARRAY + Json(const object &values); // OBJECT + Json(object &&values); // OBJECT + + // Implicit constructor: anything with a to_json() function. + template + Json(const T &t) : Json(t.to_json()) { + } + + // Implicit constructor: map-like objects (std::map, std::unordered_map, + // etc) + template < + class M, + typename std::enable_if< + std::is_constructible::value && + std::is_constructible::value, + int>::type = 0> + Json(const M &m) : Json(object(m.begin(), m.end())) { + } + + // Implicit constructor: vector-like objects (std::list, std::vector, + // std::set, etc) + template ::value, + int>::type = 0> + Json(const V &v) : Json(array(v.begin(), v.end())) { + } + + // This prevents Json(some_pointer) from accidentally producing a bool. + // Use + // Json(bool(some_pointer)) if that behavior is desired. + Json(void *) = delete; + + // Accessors + Type type() const; + + bool is_null() const { + return type() == NUL; + } + bool is_number() const { + return type() == NUMBER; + } + bool is_number64() const { + return type() == NUMBER64; + } + bool is_unumber64() const { + return type() == UNUMBER64; + } + bool is_bool() const { + return type() == BOOL; + } + bool is_string() const { + return type() == STRING; + } + bool is_array() const { + return type() == ARRAY; + } + bool is_object() const { + return type() == OBJECT; + } + + // Return the enclosed value if this is a number, 0 otherwise. Note that + // json11 does not + // distinguish between integer and non-integer numbers - number_value() + // and int_value() + // can both be applied to a NUMBER-typed object. + double number_value() const; + int int_value() const; + int64_t int64_value() const; + uint64_t uint64_value() const; + + // Return the enclosed value if this is a boolean, false otherwise. + bool bool_value() const; + // Return the enclosed string if this is a string, "" otherwise. + const std::string &string_value() const; + // Return the enclosed std::vector if this is an array, or an empty + // vector otherwise. + const array &array_items() const; + // Return the enclosed std::map if this is an object, or an empty map + // otherwise. + const object &object_items() const; + + // Return a reference to arr[i] if this is an array, Json() otherwise. + const Json &operator[](size_t i) const; + // Return a reference to obj[key] if this is an object, Json() otherwise. + const Json &operator[](const std::string &key) const; + + // Serialize. + void dump(std::string &out) const; + std::string dump() const { + std::string out; + dump(out); + return out; + } + + // Parse. If parse fails, return Json() and assign an error message to + // err. + static Json parse(const std::string &in, std::string &err, + JsonParse strategy = JsonParse::STANDARD); + static Json parse(const char *in, std::string &err, + JsonParse strategy = JsonParse::STANDARD) { + if (in) { + return parse(std::string(in), err, strategy); + } else { + err = "null input"; + return nullptr; + } + } + // Parse multiple objects, concatenated or separated by whitespace + static std::vector + parse_multi(const std::string &in, std::string &err, + JsonParse strategy = JsonParse::STANDARD); + + bool operator==(const Json &rhs) const; + bool operator<(const Json &rhs) const; + bool operator!=(const Json &rhs) const { + return !(*this == rhs); + } + bool operator<=(const Json &rhs) const { + return !(rhs < *this); + } + bool operator>(const Json &rhs) const { + return (rhs < *this); + } + bool operator>=(const Json &rhs) const { + return !(*this < rhs); + } + + /* has_shape(types, err) + * + * Return true if this is a JSON object and, for each item in types, has + * a field of + * the given type. If not, return false and set err to a descriptive + * message. + */ + typedef std::initializer_list> shape; + bool has_shape(const shape &types, std::string &err) const; + +private: + std::shared_ptr m_ptr; +}; + +// Internal class hierarchy - JsonValue objects are not exposed to users of +// this API. +class JsonValue { +protected: + friend class Json; + friend class JsonInt; + friend class JsonInt64; + friend class JsonUInt64; + friend class JsonDouble; + virtual Json::Type type() const = 0; + virtual bool equals(const JsonValue *other) const = 0; + virtual bool less(const JsonValue *other) const = 0; + virtual void dump(std::string &out) const = 0; + virtual double number_value() const; + virtual int int_value() const; + virtual int64_t int64_value() const; + virtual uint64_t uint64_value() const; + virtual bool bool_value() const; + virtual const std::string &string_value() const; + virtual const Json::array &array_items() const; + virtual const Json &operator[](size_t i) const; + virtual const Json::object &object_items() const; + virtual const Json &operator[](const std::string &key) const; + virtual ~JsonValue() { + } +}; + +} // namespace json11 diff --git a/CUDA_TiledMatrixMultiplication/libwb/wb.h b/CUDA_TiledMatrixMultiplication/libwb/wb.h new file mode 100644 index 0000000..8f41e23 --- /dev/null +++ b/CUDA_TiledMatrixMultiplication/libwb/wb.h @@ -0,0 +1,155 @@ + + +#ifndef __WB_H__ +#define __WB_H__ + +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ + +#include +#include +#include +#include + +#ifdef _MSC_VER + +// set minimal warning level +#pragma warning(push,0) +// some warnings still occur at this level +// if necessary, disable specific warnings not covered by previous pragma +#pragma warning(disable : 4244 4056 4305 4800 4267 4996 4756 4661 4385 4101) + +#define __func__ __FUNCTION__ +#ifndef _CRT_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_WARNINGS 1 +#endif /* _CRT_SECURE_NO_WARNINGS */ +#define _CRT_SECURE_NO_DEPRECATE 1 +#define _CRT_NONSTDC_NO_DEPRECATE 1 +#include +#include +#include +#define WB_USE_WINDOWS +#else /* _MSC_VER */ +#include +#include +#include +#include +#define WB_USE_UNIX +#ifdef __APPLE__ +#include +#define WB_USE_DARWIN +#else /* __APPLE__ */ +#define WB_USE_LINUX +#endif /* __APPLE__ */ +#endif /* _MSC_VER */ + +#define wbStmt(stmt) stmt + +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ + +#define wbLine __LINE__ +#define wbFile __FILE__ +#define wbFunction __func__ + +#define wbExit() \ + wbAssert(0); \ + exit(1) + +#ifdef WB_USE_COURSERA +#define wbLogger_printOnExit 1 +#else /* WB_USE_COURSERA */ +#define wbLogger_printOnLog 1 +#endif /* WB_USE_COURSERA */ + +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ + +#ifdef __cplusplus +#define EXTERN_C extern "C" +#define START_EXTERN_C EXTERN_C { +#define END_EXTERN_C } +#else +#define EXTERN_C +#define START_EXTERN_C +#define END_EXTERN_C +#endif /* __cplusplus */ + +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ + +#include +#define WB_USE_JSON11 1 + +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ + +#define LAZY_FILE_LOAD +extern char *solutionJSON; + +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ + +#ifdef WB_USE_OPENCL +#ifdef WB_USE_DARWIN +#include +#else /* WB_USE_DARWIN */ +#include +#endif /* WB_USE_DARWIN */ +#endif /* WB_USE_OPENCL */ + +#include "wbTypes.h" + +#include "wbAssert.h" +#include "wbMalloc.h" +#include "wbString.h" +#include "wbUtils.h" + +#include "wbArg.h" +#include "wbCUDA.h" +#include "wbCast.h" +#include "wbComparator.h" +#include "wbDirectory.h" +#include "wbExit.h" +#include "wbExport.h" +#include "wbFile.h" +#include "wbImage.h" +#include "wbImport.h" +#include "wbInit.h" +#include "wbLogger.h" +#include "wbMD5.h" +#include "wbMPI.h" +#include "wbSolution.h" +#include "wbSparse.h" +#include "wbThrust.h" +#include "wbTimer.h" +#include "wbPath.h" + +#include "wbDataset.h" + +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ + +#endif /* __WB_H__ */ diff --git a/CUDA_TiledMatrixMultiplication/libwb/wbArg.cpp b/CUDA_TiledMatrixMultiplication/libwb/wbArg.cpp new file mode 100644 index 0000000..2a5c736 --- /dev/null +++ b/CUDA_TiledMatrixMultiplication/libwb/wbArg.cpp @@ -0,0 +1,105 @@ + +#include "wb.h" + +EXTERN_C wbArg_t wbArg_new(int *argc, char ***argv) { + wbArg_t arg; + + wb_init(argc, argv); + + wbArg_setInputCount(arg, 0); + wbArg_setInputFiles(arg, NULL); + wbArg_setOutputFile(arg, NULL); + wbArg_setType(arg, NULL); + wbArg_setExpectedOutputFile(arg, NULL); + return arg; +} + +EXTERN_C void wbArg_delete(wbArg_t arg) { + if (wbArg_getInputCount(arg) > 0 && wbArg_getInputFiles(arg) != NULL) { + int ii; + for (ii = 0; ii < wbArg_getInputCount(arg); ii++) { + wbDelete(wbArg_getInputFile(arg, ii)); + } + wbDelete(wbArg_getInputFiles(arg)); + wbArg_setInputCount(arg, 0); + wbArg_setInputFiles(arg, NULL); + } + if (wbArg_getOutputFile(arg)) { + wbDelete(wbArg_getOutputFile(arg)); + wbArg_setOutputFile(arg, NULL); + } + if (wbArg_getExpectedOutputFile(arg)) { + wbDelete(wbArg_getExpectedOutputFile(arg)); + wbArg_setExpectedOutputFile(arg, NULL); + } + if (wbArg_getType(arg)) { + wbDelete(wbArg_getType(arg)); + wbArg_setType(arg, NULL); + } + return; +} + +static int getInputFileCount(char *arg) { + int count = 1; + while (*arg != '\0' && *arg != '-') { + if (*arg == ',') { + count++; + } + arg++; + } + return count; +} + +static char **parseInputFiles(char *arg, int *resCount) { + int count; + int ii = 0; + char **files; + char *token; + + count = getInputFileCount(arg); + + files = wbNewArray(char *, count); + + token = strtok(arg, ","); + while (token != NULL) { + files[ii++] = wbString_duplicate(token); + token = strtok(NULL, ","); + } + *resCount = ii; + return files; +} + +static char *parseString(char *arg) { + return wbString_duplicate(arg); +} + +EXTERN_C wbArg_t wbArg_read(int argc, char **argv) { + int ii; + wbArg_t arg; + + arg = wbArg_new(&argc, &argv); + for (ii = 0; ii < argc; ii++) { + if (wbString_startsWith(argv[ii], "-i")) { + int fileCount; + char **files; + + files = parseInputFiles(argv[ii + 1], &fileCount); + + wbArg_setInputCount(arg, fileCount); + wbArg_setInputFiles(arg, files); + } else if (wbString_startsWith(argv[ii], "-o")) { + char *file = parseString(argv[ii + 1]); + wbArg_setOutputFile(arg, file); + } else if (wbString_startsWith(argv[ii], "-e")) { + char *file = parseString(argv[ii + 1]); + wbArg_setExpectedOutputFile(arg, file); + } else if (wbString_startsWith(argv[ii], "-t")) { + char *type = parseString(argv[ii + 1]); + wbArg_setType(arg, type); + } else if (argv[ii][0] == '-') { + wbLog(ERROR, "Unexpected program option ", argv[ii]); + } + } + + return arg; +} diff --git a/CUDA_TiledMatrixMultiplication/libwb/wbArg.h b/CUDA_TiledMatrixMultiplication/libwb/wbArg.h new file mode 100644 index 0000000..c98bcf7 --- /dev/null +++ b/CUDA_TiledMatrixMultiplication/libwb/wbArg.h @@ -0,0 +1,33 @@ + + +#ifndef __WB_ARG_H__ +#define __WB_ARG_H__ + +struct st_wbArg_t { + int inputCount; + char **inputFiles; + char *outputFile; + char *expectedOutput; + char *type; +}; + +#define wbArg_getInputCount(wa) ((wa).inputCount) +#define wbArg_getInputFiles(wa) ((wa).inputFiles) +#define wbArg_getInputFile(wa, ii) (wbArg_getInputFiles(wa)[ii]) +#define wbArg_getOutputFile(wa) ((wa).outputFile) +#define wbArg_getExpectedOutputFile(wa) ((wa).expectedOutput) +#define wbArg_getType(wa) ((wa).type) + +#define wbArg_setInputCount(wa, val) (wbArg_getInputCount(wa) = val) +#define wbArg_setInputFiles(wa, val) (wbArg_getInputFiles(wa) = val) +#define wbArg_setInputFile(wa, ii, val) (wbArg_getInputFile(wa, ii) = val) +#define wbArg_setOutputFile(wa, val) (wbArg_getOutputFile(wa) = val) +#define wbArg_setExpectedOutputFile(wa, val) \ + (wbArg_getExpectedOutputFile(wa) = val) +#define wbArg_setType(wa, val) (wbArg_getType(wa) = val) + +EXTERN_C wbArg_t wbArg_new(int *argc, char ***argv); +EXTERN_C void wbArg_delete(wbArg_t arg); +EXTERN_C wbArg_t wbArg_read(int argc, char **argv); + +#endif /* __WB_ARG_H__ */ diff --git a/CUDA_TiledMatrixMultiplication/libwb/wbAssert.h b/CUDA_TiledMatrixMultiplication/libwb/wbAssert.h new file mode 100644 index 0000000..b8ed669 --- /dev/null +++ b/CUDA_TiledMatrixMultiplication/libwb/wbAssert.h @@ -0,0 +1,24 @@ + + +#ifndef __WB_ASSERT_H__ +#define __WB_ASSERT_H__ + +#include + +#ifdef WB_DEBUG +#define wbAssert(cond) assert(cond) +#define wbAssertMessage(msg, cond) \ + do { \ + if (!(cond)) { \ + wbPrint(msg); \ + wbAssert(cond); \ + } \ + } while (0) +#else /* WB_DEBUG */ +#define wbAssert(...) +#define wbAssertMessage(...) +#endif /* WB_DEBUG */ + +#define wbTodo(msg) wbAssertMessage(msg, false) + +#endif /* __WB_ASSERT_H__ */ diff --git a/CUDA_TiledMatrixMultiplication/libwb/wbCUDA.cpp b/CUDA_TiledMatrixMultiplication/libwb/wbCUDA.cpp new file mode 100644 index 0000000..cb26895 --- /dev/null +++ b/CUDA_TiledMatrixMultiplication/libwb/wbCUDA.cpp @@ -0,0 +1,25 @@ + +#include "wb.h" +#ifdef WB_USE_CUDA + +int _cudaMemoryListIdx = 0; + +size_t _cudaMallocSize = 0; + +wbCUDAMemory_t _cudaMemoryList[_cudaMemoryListSize]; + +char *wbRandom_list(size_t sz) { + size_t ii; + char *rands = wbNewArray(char, sz); + int *irands = (int *)rands; + for (ii = 0; ii < sz / sizeof(int); ii++) { + irands[ii] = rand(); + } + while (ii < sz) { + rands[ii] = (char)(rand() % 255); + ii++; + } + return rands; +} + +#endif /* WB_USE_CUDA */ diff --git a/CUDA_TiledMatrixMultiplication/libwb/wbCUDA.h b/CUDA_TiledMatrixMultiplication/libwb/wbCUDA.h new file mode 100644 index 0000000..658ff39 --- /dev/null +++ b/CUDA_TiledMatrixMultiplication/libwb/wbCUDA.h @@ -0,0 +1,77 @@ + +#ifndef __WB_CUDA_H__ +#define __WB_CUDA_H__ + +#ifdef WB_USE_CUDA +#ifdef __PGI +#define __GNUC__ 4 +#endif /* __PGI */ +#include +#include + +typedef struct st_wbCUDAMemory_t { + void *mem; + size_t sz; +} wbCUDAMemory_t; + +#define _cudaMemoryListSize 1024 + +extern size_t _cudaMallocSize; +extern wbCUDAMemory_t _cudaMemoryList[]; +extern int _cudaMemoryListIdx; + +char *wbRandom_list(size_t sz); + +static inline cudaError_t wbCUDAMalloc(void **devPtr, size_t sz) { + int idx = _cudaMemoryListIdx; + + cudaError_t err = cudaMalloc(devPtr, sz); + + if (idx == 0) { + srand(time(NULL)); + memset(_cudaMemoryList, 0, + sizeof(wbCUDAMemory_t) * _cudaMemoryListSize); + } + + if (err == cudaSuccess) { +#if 0 + char * rands = wbRandom_list(sz); + // can use curand here, but do not want to invoke a kernel + err = cudaMemcpy(*devPtr, rands, sz, cudaMemcpyHostToDevice); + wbFree(rands); +#else + err = cudaMemset(*devPtr, 0, sz); +#endif + } + + _cudaMallocSize += sz; + _cudaMemoryList[idx].mem = *devPtr; + _cudaMemoryList[idx].sz = sz; + _cudaMemoryListIdx++; + return err; +} + +static inline cudaError_t wbCUDAFree(void *mem) { + int idx = _cudaMemoryListIdx; + if (idx == 0) { + memset(_cudaMemoryList, 0, + sizeof(wbCUDAMemory_t) * _cudaMemoryListSize); + } + for (int ii = 0; ii < idx; ii++) { + if (_cudaMemoryList[ii].mem != NULL && + _cudaMemoryList[ii].mem == mem) { + cudaError_t err = cudaFree(mem); + _cudaMallocSize -= _cudaMemoryList[ii].sz; + _cudaMemoryList[ii].mem = NULL; + return err; + } + } + return cudaErrorMemoryAllocation; +} + +#define cudaMalloc(elem, err) wbCUDAMalloc((void **)elem, err) +#define cudaFree wbCUDAFree + +#endif /* WB_USE_CUDA */ + +#endif /* __WB_CUDA_H__ */ diff --git a/CUDA_TiledMatrixMultiplication/libwb/wbCast.h b/CUDA_TiledMatrixMultiplication/libwb/wbCast.h new file mode 100644 index 0000000..01e8387 --- /dev/null +++ b/CUDA_TiledMatrixMultiplication/libwb/wbCast.h @@ -0,0 +1,29 @@ + + +#ifndef __WB_CAST_H__ +#define __WB_CAST_H__ + +template +static inline void wbCast(X &x, const Y &y, size_t len) { + size_t ii; + + for (ii = 0; ii < len; ii++) { + x[ii] = (X)y[ii]; + } + + return; +} + +template +static inline X *wbCast(const Y &y, size_t len) { + size_t ii; + X *x = wbNewArray(X, len); + + for (ii = 0; ii < len; ii++) { + x[ii] = (X)y[ii]; + } + + return x; +} + +#endif /* __WB_CAST_H__ */ diff --git a/CUDA_TiledMatrixMultiplication/libwb/wbComparator.h b/CUDA_TiledMatrixMultiplication/libwb/wbComparator.h new file mode 100644 index 0000000..26fd0cb --- /dev/null +++ b/CUDA_TiledMatrixMultiplication/libwb/wbComparator.h @@ -0,0 +1,187 @@ + + +#ifndef __WB_COMPARATOR_H__ +#define __WB_COMPARATOR_H__ + +#include "wb.h" + +template +static inline T _abs(const T &a) { + return a < 0 ? -a : a; +} + +static inline wbBool _almostEqual(double A, double B, double eps) { + if (A == 0) { + return _abs(B) < eps; + } else if (B == 0) { + return _abs(A) < eps; + } else { +#if 0 + double d = max(_abs(A), _abs(B)); + double g = (_abs(A - B) / d); +#else + double g = _abs(A - B); +#endif + if (g <= eps) { + return wbTrue; + } else { + return wbFalse; + } + } +} + +static inline wbBool _almostEqual(float A, float B, float eps) { + if (A == 0) { + return _abs(B) < eps; + } else if (B == 0) { + return _abs(A) < eps; + } else { +#if 0 + float d = max(_abs(A), _abs(B)); + float g = (_abs(A - B) / d); +#else + float g = _abs(A - B); +#endif + if (g <= eps) { + return wbTrue; + } else { + return wbFalse; + } + } +} + +static inline wbBool _almostEqual(double A, double B) { + return _almostEqual(A, B, 0.2); +} + +static inline wbBool _almostEqual(float A, float B) { + return _almostEqual(A, B, 0.2f); +} + +static inline wbBool _almostEqual2sComplement(float A, float B, + int maxUlps) { + // Make sure maxUlps is non-negative and small enough that the + // default NAN won't compare as equal to anything. + + int aInt, bInt, intDiff; + + wbAssert(maxUlps > 0 && maxUlps < 4 * 1024 * 1024); + + int *tmp = reinterpret_cast(&A); + aInt = *tmp; + + // Make aInt lexicographically ordered as a twos-complement int + if (aInt < 0) { + aInt = 0x80000000 - aInt; + } + // Make bInt lexicographically ordered as a twos-complement int + tmp = reinterpret_cast(&B); + bInt = *tmp; + if (bInt < 0) { + bInt = 0x80000000 - bInt; + } + intDiff = _abs(aInt - bInt); + if (intDiff <= maxUlps) { + return wbTrue; + } + return wbFalse; +} + +static inline wbBool _almostEqual2sComplement(float A, float B) { + return _almostEqual2sComplement(A, B, 4); +} + +static inline wbBool _almostEqual2sComplement(double A, double B, + int maxUlps) { + // Make sure maxUlps is non-negative and small enough that the + // default NAN won't compare as equal to anything. + + int64_t aInt, bInt, intDiff; + + wbAssert(maxUlps > 0 && maxUlps < 4 * 1024 * 1024); + + int64_t *tmp = reinterpret_cast(&A); + aInt = *tmp; + + // Make aInt lexicographically ordered as a twos-complement int + if (aInt < 0) { + aInt = 0x80000000 - aInt; + } + // Make bInt lexicographically ordered as a twos-complement int + tmp = reinterpret_cast(&B); + bInt = *tmp; + if (bInt < 0) { + bInt = 0x80000000 - bInt; + } + intDiff = _abs(aInt - bInt); + if (intDiff <= maxUlps) { + return wbTrue; + } + return wbFalse; +} + +static inline wbBool _almostEqual2sComplement(double A, double B) { + return _almostEqual2sComplement(A, B, 4); +} + +template +static inline int wbCompare(const T &a, const T &b) { + if (a == b) { + return 0; + } else if (a < b) { + return -1; + } else { + return 1; + } +} + +template <> +inline int wbCompare(const double &a, const double &b) { + if (_almostEqual(a, b)) { + return 0; + } else if (a < b) { + return -1; + } else { + return 1; + } +} + +template <> +inline int wbCompare(const float &a, const float &b) { + if (_almostEqual(a, b)) { + return 0; + } else if (a < b) { + return -1; + } else { + return 1; + } +} + +template +static inline wbBool wbEqualQ(const T &a, const T &b) { + return wbCompare(a, b) == 0; +} + +template +static inline wbBool wbUnequalQ(const T &a, const T &b) { + return wbCompare(a, b) != 0; +} + +template +static inline wbBool wbEqualQ(const T *a, const T *b, size_t n) { + size_t ii; + + for (ii = 0; ii < n; ii++) { + if (wbUnequalQ(a[ii], b[ii])) { + return wbFalse; + } + } + return wbTrue; +} + +template +static inline wbBool wbUnequalQ(const T *a, const T *b, size_t n) { + return !wbEqualQ(a, b, n); +} + +#endif /* __WB_COMPARATOR_H__ */ diff --git a/CUDA_TiledMatrixMultiplication/libwb/wbDataset.cpp b/CUDA_TiledMatrixMultiplication/libwb/wbDataset.cpp new file mode 100644 index 0000000..a11f064 --- /dev/null +++ b/CUDA_TiledMatrixMultiplication/libwb/wbDataset.cpp @@ -0,0 +1,177 @@ +#include "wb.h" + +template +static inline T _min(const T &x, const T &y) { + return x < y ? x : y; +} + +template +static inline T _max(const T &x, const T &y) { + return x > y ? x : y; +} + +template +inline T lerp(const double &x, const T &start, const T &end) { + return (1 - x) * start + x * end; +} + +static inline void genRandom(void *trgt, wbType_t type, double minVal, + double maxVal) { + const int span = maxVal - minVal; + const int r = rand(); + const double rf = ((double)r) / ((double)RAND_MAX); + switch (type) { + case wbType_ascii: + *((char *)trgt) = (r % span) + minVal; // random printable character; + break; + case wbType_bit8: + *((char *)trgt) = lerp(rf, minVal, maxVal); + break; + case wbType_ubit8: + *((unsigned char *)trgt) = lerp(rf, minVal, maxVal); + break; + case wbType_integer: + *((int *)trgt) = lerp(rf, minVal, maxVal); + break; + case wbType_float: { + *((float *)trgt) = lerp(rf, minVal, maxVal); + break; + } + case wbType_double: { + *((double *)trgt) = lerp(rf, minVal, maxVal); + break; + } + case wbType_unknown: + wbAssert(false && "Invalid wbType_unknown"); + break; + } + return; +} + +static inline void *genRandomList(wbType_t type, size_t len, double minVal, + double maxVal) { + size_t ii; + void *data = wbNewArray(char, wbType_size(type) * len); + switch (type) { + case wbType_ascii: + case wbType_bit8: { + char *iter = (char *)data; + for (ii = 0; ii < len; ii++) { + genRandom(iter++, type, minVal, maxVal); + } + break; + } + case wbType_ubit8: { + unsigned char *iter = (unsigned char *)data; + for (ii = 0; ii < len; ii++) { + genRandom(iter++, type, minVal, maxVal); + } + break; + } + case wbType_integer: { + int *iter = (int *)data; + for (ii = 0; ii < len; ii++) { + genRandom(iter++, type, minVal, maxVal); + } + break; + } + case wbType_float: { + float *iter = (float *)data; + for (ii = 0; ii < len; ii++) { + genRandom(iter++, type, minVal, maxVal); + } + break; + } + case wbType_double: { + double *iter = (double *)data; + for (ii = 0; ii < len; ii++) { + genRandom(iter++, type, minVal, maxVal); + } + break; + } + case wbType_unknown: + wbAssert(false && "Invalid wbType_unknown"); + break; + } + return data; +} + +static void genRaw(const char *path, wbRaw_GenerateParams_t params) { + int rows = _max(1, params.rows); + int cols = _max(1, params.cols); + double minVal = params.minVal; + double maxVal = params.maxVal; + wbType_t type = params.type; + void *data = genRandomList(type, rows * cols, minVal, maxVal); + wbExport(path, wbExportKind_raw, data, rows, cols, type); + wbDelete(data); +} + +static void genCSV(const char *path, wbCSV_GenerateParams_t params) { + int rows = _max(1, params.rows); + int cols = _max(1, params.cols); + double minVal = params.minVal; + double maxVal = params.maxVal; + wbType_t type = params.type; + void *data = genRandomList(type, rows * cols, minVal, maxVal); + wbExport(path, wbExportKind_csv, data, rows, cols, type); + wbDelete(data); +} + +static void genTSV(const char *path, wbTSV_GenerateParams_t params) { + int rows = _max(1, params.rows); + int cols = _max(1, params.cols); + double minVal = params.minVal; + double maxVal = params.maxVal; + wbType_t type = params.type; + void *data = genRandomList(type, rows * cols, minVal, maxVal); + wbExport(path, wbExportKind_tsv, data, rows, cols, type); + wbDelete(data); +} + +static void genText(const char *path, wbText_GenerateParams_t params) { + int length = _max(1, params.length); + wbType_t type = wbType_ascii; + void *data = genRandomList(type, length, 32, 128); + wbExport(path, wbExportKind_text, data, length, 1, type); + wbDelete(data); +} + +static void genPPM(const char *path, wbPPM_GenerateParams_t params) { + int width = _max(1, params.width); + int height = _max(1, params.height); + int channels = _max(1, params.channels); + double minVal = params.minVal; + double maxVal = params.maxVal; + wbType_t type = wbType_float; + float *data = (float *)genRandomList(type, width * height * channels, + minVal, maxVal); + wbImage_t img = wbImage_new(width, height, channels, data); + wbExport(path, img); + wbImage_delete(img); +} + +EXTERN_C void wbDataset_generate(const char *path, wbExportKind_t kind, + wbGenerateParams_t params) { + wbDirectory_create(wbDirectory_name(path)); + + switch (kind) { + case wbExportKind_raw: + genRaw(path, params.raw); + break; + case wbExportKind_csv: + genCSV(path, params.csv); + break; + case wbExportKind_tsv: + genTSV(path, params.tsv); + break; + case wbExportKind_ppm: + genPPM(path, params.ppm); + break; + case wbExportKind_text: + genText(path, params.text); + break; + default: + wbAssert(false && "Invalid Export kind"); + } +} diff --git a/CUDA_TiledMatrixMultiplication/libwb/wbDataset.h b/CUDA_TiledMatrixMultiplication/libwb/wbDataset.h new file mode 100644 index 0000000..ce81c28 --- /dev/null +++ b/CUDA_TiledMatrixMultiplication/libwb/wbDataset.h @@ -0,0 +1,52 @@ +#ifndef __WB_DATASET_H__ +#define __WB_DATASET_H__ + +#include "wbImport.h" +#include "wbTypes.h" + +typedef struct { + int rows; + int cols; + wbType_t type; + double minVal; + double maxVal; +} wbCSV_GenerateParams_t; + +typedef struct { + int rows; + int cols; + wbType_t type; + double minVal; + double maxVal; +} wbTSV_GenerateParams_t; + +typedef struct { + int rows; + int cols; + double minVal; + double maxVal; + wbType_t type; +} wbRaw_GenerateParams_t; + +typedef struct { + int width; + int height; + int channels; + double minVal; + double maxVal; +} wbPPM_GenerateParams_t; + +typedef struct { int length; } wbText_GenerateParams_t; + +typedef union { + wbCSV_GenerateParams_t csv; + wbRaw_GenerateParams_t raw; + wbTSV_GenerateParams_t tsv; + wbPPM_GenerateParams_t ppm; + wbText_GenerateParams_t text; +} wbGenerateParams_t; + +EXTERN_C void wbDataset_generate(const char *path, wbExportKind_t kind, + wbGenerateParams_t params); + +#endif /* __WB_DATASET_H__ */ diff --git a/CUDA_TiledMatrixMultiplication/libwb/wbDataset_test.cpp b/CUDA_TiledMatrixMultiplication/libwb/wbDataset_test.cpp new file mode 100644 index 0000000..4f08042 --- /dev/null +++ b/CUDA_TiledMatrixMultiplication/libwb/wbDataset_test.cpp @@ -0,0 +1,23 @@ + +#include "wb.h" +#include "vendor/catch.hpp" + +TEST_CASE("Can create Raw dataset", "[DataGenerator]") { + wbGenerateParams_t params; + params.raw.rows = 2; + params.raw.cols = 300; + params.raw.minVal = 0; + params.raw.maxVal = 30; + params.raw.type = wbType_integer; + wbDataset_generate( + wbPath_join(wbDirectory_current(), "test-dataset", "test.raw"), + wbExportKind_raw, params); +} + +TEST_CASE("Can create Text dataset", "[DataGenerator]") { + wbGenerateParams_t params; + params.text.length = 2000; + wbDataset_generate( + wbPath_join(wbDirectory_current(), "test-dataset", "test.txt"), + wbExportKind_text, params); +} diff --git a/CUDA_TiledMatrixMultiplication/libwb/wbDirectory.cpp b/CUDA_TiledMatrixMultiplication/libwb/wbDirectory.cpp new file mode 100644 index 0000000..10dc8c5 --- /dev/null +++ b/CUDA_TiledMatrixMultiplication/libwb/wbDirectory.cpp @@ -0,0 +1,88 @@ +#include "wb.h" + +#ifndef PATH_MAX +#ifdef FILENAME_MAX +#define PATH_MAX FILENAME_MAX +#else /* FILENAME_MAX */ +#define PATH_MAX 4096 +#endif /* FILENAME_MAX */ +#endif /* PATH_MAX */ + +#ifdef WB_USE_UNIX +const char wbDirectorySeperator = '/'; +static char *getcwd_(char *buf, int maxLen) { + return getcwd(buf, maxLen); +} +static void mkdir_(const char *dir) { + mkdir(dir, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); +} +#else /* WB_USE_LINUX */ +const char wbDirectorySeperator = '\\'; +static char *getcwd_(char *buf, int maxLen) { + return _getcwd(buf, maxLen); +} +static void mkdir_(const char *dir) { + _mkdir(dir); +} +#endif /* WB_USE_LINUX */ + +EXTERN_C const char * wbDirectory_create(const char *dir) { + char tmp[PATH_MAX]; + char *p = NULL; + size_t len; +//PMO +#ifndef _MSC_VER + snprintf(tmp, sizeof(tmp), "%s", dir); +#else + _snprintf_s(tmp, sizeof(tmp), "%s", dir); +#endif + len = strlen(tmp); + if (tmp[len - 1] == wbDirectorySeperator) { + tmp[len - 1] = 0; + } + for (p = tmp + 1; *p; p++) { + if (*p == wbDirectorySeperator) { + *p = 0; + mkdir_(tmp); + *p = wbDirectorySeperator; + } + } + mkdir_(tmp); + return dir; +} + +EXTERN_C char *wbDirectory_name(const char *pth0) { + char *pth = wbString_duplicate(pth0); + char *p = strrchr(pth, wbDirectorySeperator); + if (p) { + p[0] = 0; + } + return pth; +} + +EXTERN_C char *wbDirectory_current() { + char *tmp = wbNewArray(char, PATH_MAX + 1); + if (getcwd_(tmp, PATH_MAX)) { + return tmp; + } + + wbDelete(tmp); + + int error = errno; + switch (error) { + case EACCES: + std::cerr + << "Cannot get current directory :: access denied. exiting..." + << std::endl; + exit(-1); + case ENOMEM: + std::cerr << "Cannot get current directory :: insufficient storage. " + "exiting..." + << std::endl; + exit(-1); + default: + std::cerr << "Cannot get current directory :: unrecognised error " + << error << std::endl; + exit(-1); + } +} \ No newline at end of file diff --git a/CUDA_TiledMatrixMultiplication/libwb/wbDirectory.h b/CUDA_TiledMatrixMultiplication/libwb/wbDirectory.h new file mode 100644 index 0000000..cb14f81 --- /dev/null +++ b/CUDA_TiledMatrixMultiplication/libwb/wbDirectory.h @@ -0,0 +1,9 @@ +#ifndef __WB_DIRECTORY__ +#define __WB_DIRECTORY__ + +extern const char wbDirectorySeperator; +EXTERN_C char *wbDirectory_name(const char *pth); +EXTERN_C const char * wbDirectory_create(const char *dir); +EXTERN_C char *wbDirectory_current(); + +#endif /* __WB_DIRECTORY__ */ diff --git a/CUDA_TiledMatrixMultiplication/libwb/wbExit.cpp b/CUDA_TiledMatrixMultiplication/libwb/wbExit.cpp new file mode 100644 index 0000000..a7edc3a --- /dev/null +++ b/CUDA_TiledMatrixMultiplication/libwb/wbExit.cpp @@ -0,0 +1,119 @@ + +#include "wb.h" + +enum { + wbMPI_timerTag = 2, + wbMPI_loggerTag = 4, + wbMPI_solutionExistsTag = 8, + wbMPI_solutionTag = 16 +}; + +void wb_atExit(void) { + using std::cout; + using std::endl; + +#ifdef WB_USE_CUDA + cudaDeviceSynchronize(); +#endif /* WB_USE_CUDA */ + + int nranks = rankCount(); + if (nranks > 1) { +#ifdef WB_USE_MPI + if (isMasterQ) { +#ifdef wbLogger_printOnExit + cout << "==$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$" << endl; + + cout << "{\n"; + cout << wbString_quote("timer") << ":"; + cout << "[\n"; + for (int ii = 0; ii < nranks; ii++) { + if (ii == 0) { + cout << wbTimer_toJSON(); + } else { + const char *msg = wbMPI_getStringFromRank(ii, wbMPI_timerTag); + if (msg != NULL && strlen(msg) != 0) { + cout << ",\n"; + cout << msg; + // free(msg); + } + } + } + cout << "]" << endl; // close timer + + cout << "," << endl; // start logger + cout << wbString_quote("logger") << ":"; + cout << "[\n"; + for (int ii = 0; ii < nranks; ii++) { + if (ii == 0) { + cout << wbLogger_toJSON(); + } else { + const char *msg = wbMPI_getStringFromRank(ii, wbMPI_loggerTag); + if (msg != NULL && strlen(msg) != 0) { + cout << ",\n"; + cout << msg; + // free(msg); + } + } + } + cout << "]" << endl; // close logger + + cout << "," << endl; // start solutionExists + cout << wbString_quote("cuda_memory") << ":" << _cudaMallocSize + << ",\n"; + + if (solutionJSON) { + cout << wbString_quote("solution_exists") << ": true,\n"; + cout << wbString_quote("solution") << ":" << solutionJSON << "\n"; + } else { + cout << wbString_quote("solution_exists") << ": false\n"; + } + cout << "}" << endl; // close json + + } else { + wbMPI_sendStringToMaster(wbTimer_toJSON().c_str(), wbMPI_timerTag); + wbMPI_sendStringToMaster(wbLogger_toJSON().c_str(), wbMPI_loggerTag); + } +#endif /* wbLogger_printOnExit */ + +#endif /* WB_USE_MPI */ + } else { +#ifdef wbLogger_printOnExit + cout << "==$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$" << endl; + + cout << "{\n" << wbString_quote("timer") << ":[" << wbTimer_toJSON() + << "],\n" << wbString_quote("logger") << ":[" << wbLogger_toJSON() + << "],\n"; + +#ifdef WB_USE_CUDA + cout << wbString_quote("cuda_memory") << ":" << _cudaMallocSize + << ",\n"; +#endif /* WB_USE_CUDA */ + + if (solutionJSON) { + cout << wbString_quote("solution_exists") << ": true,\n"; + cout << wbString_quote("solution") << ":" << solutionJSON << "\n"; + } else { + cout << wbString_quote("solution_exists") << ": false\n"; + } + cout << "}" << endl; +#endif /* wbLogger_printOnExit */ + } + + // wbTimer_delete(_timer); + // wbLogger_delete(_logger); + + _timer = NULL; + _logger = NULL; + +// wbFile_atExit(); + +#ifdef WB_USE_CUDA + cudaDeviceReset(); +#endif + + exit(0); + + // assert(0); + + return; +} diff --git a/CUDA_TiledMatrixMultiplication/libwb/wbExit.h b/CUDA_TiledMatrixMultiplication/libwb/wbExit.h new file mode 100644 index 0000000..4400108 --- /dev/null +++ b/CUDA_TiledMatrixMultiplication/libwb/wbExit.h @@ -0,0 +1,7 @@ + +#ifndef __WB_EXIT_H__ +#define __WB_EXIT_H__ + +void wb_atExit(void); + +#endif /* __WB_EXIT_H__ */ diff --git a/CUDA_TiledMatrixMultiplication/libwb/wbExport.cpp b/CUDA_TiledMatrixMultiplication/libwb/wbExport.cpp new file mode 100644 index 0000000..59b7a33 --- /dev/null +++ b/CUDA_TiledMatrixMultiplication/libwb/wbExport.cpp @@ -0,0 +1,510 @@ + +#include "wb.h" + +static inline void wbExportText_setFile(wbExportText_t text, + const char *path) { + if (text != NULL) { + if (wbExportText_getFile(text) != NULL) { + wbFile_delete(wbExportText_getFile(text)); + } + if (path != NULL) { + wbExportText_getFile(text) = wbFile_open(path, "w+"); + } else { + wbExportText_getFile(text) = NULL; + } + } + + return; +} + +static inline wbExportText_t wbExportText_new(void) { + wbExportText_t text; + + text = wbNew(struct st_wbExportText_t); + + wbExportText_getFile(text) = NULL; + wbExportText_setLength(text, -1); + + return text; +} + +static inline void wbExportText_delete(wbExportText_t text) { + if (text != NULL) { + wbExportText_setFile(text, NULL); + wbDelete(text); + } + return; +} + +static inline void wbExportText_write(wbExportText_t text, + const char *data, int length) { + int ii; + FILE *handle; + wbFile_t file; + + if (text == NULL || wbExportText_getFile(text) == NULL) { + return; + } + + file = wbExportText_getFile(text); + + handle = wbFile_getFileHandle(file); + + if (handle == NULL) { + return; + } + + for (ii = 0; ii < length; ii++) { + fprintf(handle, "%c", data[ii]); + } + + return; +} + +static inline void wbExportRaw_setFile(wbExportRaw_t raw, + const char *path) { + if (raw != NULL) { + if (wbExportRaw_getFile(raw) != NULL) { + wbFile_delete(wbExportRaw_getFile(raw)); + } + if (path != NULL) { + wbExportRaw_getFile(raw) = wbFile_open(path, "w+"); + } else { + wbExportRaw_getFile(raw) = NULL; + } + } + + return; +} + +static inline wbExportRaw_t wbExportRaw_new(void) { + wbExportRaw_t raw; + + raw = wbNew(struct st_wbExportRaw_t); + + wbExportRaw_getFile(raw) = NULL; + wbExportRaw_setRowCount(raw, -1); + wbExportRaw_setColumnCount(raw, -1); + + return raw; +} + +static inline void wbExportRaw_delete(wbExportRaw_t raw) { + if (raw != NULL) { + wbExportRaw_setFile(raw, NULL); + wbDelete(raw); + } + return; +} + +static inline void wbExportRaw_write(wbExportRaw_t raw, void *data, + int rows, int columns, + wbType_t type) { + int ii, jj; + FILE *handle; + wbFile_t file; + + if (raw == NULL || wbExportRaw_getFile(raw) == NULL) { + return; + } + + file = wbExportRaw_getFile(raw); + + handle = wbFile_getFileHandle(file); + + if (handle == NULL) { + return; + } + + if (columns == 1) { + fprintf(handle, "%d\n", rows); + } else { + fprintf(handle, "%d %d\n", rows, columns); + } + + for (ii = 0; ii < rows; ii++) { + for (jj = 0; jj < columns; jj++) { + if (type == wbType_integer) { + int elem = ((int *)data)[ii * columns + jj]; + fprintf(handle, "%d", elem); + } else if (type == wbType_ubit8) { + int elem = ((unsigned char *)data)[ii * columns + jj]; + fprintf(handle, "%d", elem); + } else { + wbReal_t elem = ((wbReal_t *)data)[ii * columns + jj]; + fprintf(handle, "%f", elem); + } + if (jj == columns - 1) { + fprintf(handle, "\n"); + } else { + fprintf(handle, " "); + } + } + } + + return; +} + +static inline void wbExportCSV_setFile(wbExportCSV_t csv, + const char *path) { + if (csv != NULL) { + if (wbExportCSV_getFile(csv) != NULL) { + wbFile_delete(wbExportCSV_getFile(csv)); + } + if (path != NULL) { + wbExportCSV_getFile(csv) = wbFile_open(path, "w+"); + } else { + wbExportCSV_getFile(csv) = NULL; + } + } + + return; +} + +static inline wbExportCSV_t wbExportCSV_new(void) { + wbExportCSV_t csv; + + csv = wbNew(struct st_wbExportCSV_t); + + wbExportCSV_getFile(csv) = NULL; + wbExportCSV_setColumnCount(csv, -1); + wbExportCSV_setRowCount(csv, -1); + wbExportCSV_setSeperator(csv, '\0'); + + return csv; +} + +static inline void wbExportCSV_delete(wbExportCSV_t csv) { + if (csv != NULL) { + wbExportCSV_setFile(csv, NULL); + wbDelete(csv); + } +} + +static inline void wbExportCSV_write(wbExportCSV_t csv, void *data, + int rows, int columns, char sep, + wbType_t type) { + int ii, jj; + wbFile_t file; + FILE *handle; + char seperator[2]; + + if (csv == NULL || wbExportCSV_getFile(csv) == NULL) { + return; + } + + file = wbExportCSV_getFile(csv); + + handle = wbFile_getFileHandle(file); + + if (handle == NULL) { + return; + } + + if (sep == '\0') { + seperator[0] = ','; + } else { + seperator[0] = sep; + } + seperator[1] = '\0'; + + for (ii = 0; ii < rows; ii++) { + for (jj = 0; jj < columns; jj++) { + if (type == wbType_integer) { + int elem = ((int *)data)[ii * columns + jj]; + fprintf(handle, "%d", elem); + } else if (type == wbType_ubit8) { + int elem = ((unsigned char *)data)[ii * columns + jj]; + fprintf(handle, "%d", elem); + } else { + wbReal_t elem = ((wbReal_t *)data)[ii * columns + jj]; + fprintf(handle, "%f", elem); + } + if (jj == columns - 1) { + fprintf(handle, "\n"); + } else { + fprintf(handle, "%s", seperator); + } + } + } + + return; +} + +static inline wbExport_t wbExport_open(const char *file, + wbExportKind_t kind) { + wbExport_t exprt; + + if (file == NULL) { + wbLog(ERROR, "Go NULL for file value."); + wbExit(); + } + + wbExport_setFile(exprt, NULL); + wbExport_setKind(exprt, kind); + + if (kind == wbExportKind_raw) { + wbExportRaw_t raw = wbExportRaw_new(); + wbExportRaw_setFile(raw, file); + wbExport_setRaw(exprt, raw); + } else if (kind == wbExportKind_text) { + wbExportText_t txt = wbExportText_new(); + wbExportText_setFile(txt, file); + wbExport_setText(exprt, txt); + } else if (kind == wbExportKind_tsv || kind == wbExportKind_csv) { + wbExportCSV_t csv = wbExportCSV_new(); + if (kind == wbExportKind_csv) { + wbExportCSV_setSeperator(csv, ','); + } else { + wbExportCSV_setSeperator(csv, '\t'); + } + wbExportCSV_setFile(csv, file); + wbExport_setCSV(exprt, csv); + } else if (kind == wbExportKind_ppm) { + wbExport_setFile(exprt, wbString_duplicate(file)); + } else { + wbLog(ERROR, "Invalid export type."); + wbExit(); + } + + return exprt; +} + +static inline wbExport_t wbExport_open(const char *file, + const char *type0) { + wbExport_t exprt; + wbExportKind_t kind; + char *type; + + type = wbString_toLower(type0); + + if (wbString_sameQ(type, "csv")) { + kind = wbExportKind_csv; + } else if (wbString_sameQ(type, "tsv")) { + kind = wbExportKind_tsv; + } else if (wbString_sameQ(type, "raw") || wbString_sameQ(type, "dat")) { + kind = wbExportKind_raw; + } else if (wbString_sameQ(type, "ppm") || wbString_sameQ(type, "pbm")) { + kind = wbExportKind_ppm; + } else if (wbString_sameQ(type, "txt") || wbString_sameQ(type, "text")) { + kind = wbExportKind_text; + } else { + wbLog(ERROR, "Invalid export type ", type0); + wbExit(); + } + + exprt = wbExport_open(file, kind); + + wbDelete(type); + + return exprt; +} + +static inline void wbExport_close(wbExport_t exprt) { + wbExportKind_t kind; + + kind = wbExport_getKind(exprt); + + if (wbExport_getFile(exprt)) { + wbDelete(wbExport_getFile(exprt)); + } + + if (kind == wbExportKind_tsv || kind == wbExportKind_csv) { + wbExportCSV_t csv = wbExport_getCSV(exprt); + wbExportCSV_delete(csv); + wbExport_setCSV(exprt, NULL); + } else if (kind == wbExportKind_raw) { + wbExportRaw_t raw = wbExport_getRaw(exprt); + wbExportRaw_delete(raw); + wbExport_setRaw(exprt, NULL); + } else if (kind == wbExportKind_text) { + wbExportText_t text = wbExport_getText(exprt); + wbExportText_delete(text); + wbExport_setText(exprt, NULL); + } else if (kind == wbExportKind_ppm) { + } else { + wbLog(ERROR, "Invalid export type."); + wbExit(); + } + return; +} + +static inline void wbExport_writeAsImage(wbExport_t exprt, wbImage_t img) { + wbAssert(wbExport_getKind(exprt) == wbExportKind_ppm); + + wbPPM_export(wbExport_getFile(exprt), img); + + return; +} + +static inline void wbExport_write(wbExport_t exprt, void *data, int rows, + int columns, char sep, wbType_t type) { + wbExportKind_t kind; + + kind = wbExport_getKind(exprt); + if (kind == wbExportKind_tsv || kind == wbExportKind_csv) { + wbExportCSV_t csv = wbExport_getCSV(exprt); + wbExportCSV_write(csv, data, rows, columns, sep, type); + } else if (kind == wbExportKind_raw) { + wbExportRaw_t raw = wbExport_getRaw(exprt); + wbExportRaw_write(raw, data, rows, columns, type); + } else if (kind == wbExportKind_text) { + wbExportText_t text = wbExport_getText(exprt); + if (columns == 0) { + columns = 1; + } + if (rows == 0) { + rows = 1; + } + wbExportText_write(text, (const char *)data, rows * columns); + } else { + wbLog(ERROR, "Invalid export type."); + wbExit(); + } + return; +} + +static inline void wbExport_write(wbExport_t exprt, void *data, int rows, + int columns, wbType_t type) { + wbExport_write(exprt, data, rows, columns, ',', type); +} + +static wbExportKind_t _parseExportExtension(const char *file) { + char *extension; + wbExportKind_t kind; + + extension = wbFile_extension(file); + + if (wbString_sameQ(extension, "csv")) { + kind = wbExportKind_csv; + } else if (wbString_sameQ(extension, "tsv")) { + kind = wbExportKind_tsv; + } else if (wbString_sameQ(extension, "raw") || + wbString_sameQ(extension, "dat")) { + kind = wbExportKind_raw; + } else if (wbString_sameQ(extension, "text") || + wbString_sameQ(extension, "txt")) { + kind = wbExportKind_text; + } else if (wbString_sameQ(extension, "ppm")) { + kind = wbExportKind_ppm; + } else { + kind = wbExportKind_unknown; + wbLog(ERROR, "File ", file, " does not have a compatible extension."); + } + + wbDelete(extension); + + return kind; +} + +static void wbExport(const char *file, void *data, int rows, int columns, + wbType_t type) { + wbExportKind_t kind; + wbExport_t exprt; + + if (file == NULL) { + return; + } + + kind = _parseExportExtension(file); + exprt = wbExport_open(file, kind); + + wbExport_write(exprt, data, rows, columns, type); + wbExport_close(exprt); +} + +void wbExport(const char *file, unsigned char *data, int rows) { + wbExport(file, data, rows, 1); + return; +} + +void wbExport(const char *file, int *data, int rows) { + wbExport(file, data, rows, 1); + return; +} + +void wbExport(const char *file, wbReal_t *data, int rows) { + wbExport(file, data, rows, 1); + return; +} + +void wbExport(const char *file, unsigned char *data, int rows, + int columns) { + wbExportKind_t kind; + wbExport_t exprt; + + if (file == NULL) { + return; + } + + kind = _parseExportExtension(file); + exprt = wbExport_open(file, kind); + + wbExport_write(exprt, data, rows, columns, wbType_ubit8); + wbExport_close(exprt); +} + +void wbExport(const char *file, int *data, int rows, int columns) { + wbExportKind_t kind; + wbExport_t exprt; + + if (file == NULL) { + return; + } + + kind = _parseExportExtension(file); + exprt = wbExport_open(file, kind); + + wbExport_write(exprt, data, rows, columns, wbType_integer); + wbExport_close(exprt); +} + +void wbExport(const char *file, wbReal_t *data, int rows, int columns) { + wbExportKind_t kind; + wbExport_t exprt; + + if (file == NULL) { + return; + } + + kind = _parseExportExtension(file); + exprt = wbExport_open(file, kind); + + wbExport_write(exprt, data, rows, columns, wbType_real); + wbExport_close(exprt); +} + +void wbExport(const char *file, wbExportKind_t kind, void *data, int rows, + int columns, wbType_t type) { + wbExport_t exprt; + + if (file == NULL) { + return; + } + + exprt = wbExport_open(file, kind); + + wbExport_write(exprt, data, rows, columns, type); + wbExport_close(exprt); +} + +void wbExport(const char *file, wbImage_t img) { + wbExportKind_t kind; + wbExport_t exprt; + + if (file == NULL) { + return; + } + + kind = _parseExportExtension(file); + exprt = wbExport_open(file, kind); + + wbAssert(kind == wbExportKind_ppm); + + wbExport_writeAsImage(exprt, img); + wbExport_close(exprt); +} + +void wbExport_text(const char *file, void *data, int length) { + wbExport(file, wbExportKind_text, data, 1, length, wbType_ascii); +} diff --git a/CUDA_TiledMatrixMultiplication/libwb/wbExport.h b/CUDA_TiledMatrixMultiplication/libwb/wbExport.h new file mode 100644 index 0000000..dd16b3f --- /dev/null +++ b/CUDA_TiledMatrixMultiplication/libwb/wbExport.h @@ -0,0 +1,106 @@ + + +#ifndef __WB_EXPORT_H__ +#define __WB_EXPORT_H__ + +#include "wb.h" +#include "wbFile.h" +#include "wbPPM.h" + +typedef enum en_wbExportKind_t { + wbExportKind_unknown = -1, + wbExportKind_raw = 0x1000, + wbExportKind_csv, + wbExportKind_tsv, + wbExportKind_ppm, + wbExportKind_text, +} wbExportKind_t; + +typedef struct st_wbExportText_t { + int length; + wbFile_t file; +} * wbExportText_t; + +#define wbExportText_getLength(txt) ((txt)->length) +#define wbExportText_getFile(txt) ((txt)->file) + +#define wbExportText_setLength(txt, val) \ + (wbExportText_getLength(txt) = val) + +typedef struct st_wbExportRaw_t { + int rows; + int columns; + wbFile_t file; +} * wbExportRaw_t; + +#define wbExportRaw_getColumnCount(raw) ((raw)->columns) +#define wbExportRaw_getRowCount(raw) ((raw)->rows) +#define wbExportRaw_getFile(raw) ((raw)->file) + +#define wbExportRaw_setRowCount(raw, val) \ + (wbExportRaw_getRowCount(raw) = val) +#define wbExportRaw_setColumnCount(raw, val) \ + (wbExportRaw_getColumnCount(raw) = val) + +typedef struct st_wbExportCSV_t { + int rows; + int columns; + wbFile_t file; + char seperator; +} * wbExportCSV_t; + +#define wbExportCSV_getRowCount(csv) ((csv)->rows) +#define wbExportCSV_getColumnCount(csv) ((csv)->columns) +#define wbExportCSV_getFile(csv) ((csv)->file) +#define wbExportCSV_getSeperator(csv) ((csv)->seperator) + +#define wbExportCSV_setRowCount(csv, val) \ + (wbExportCSV_getRowCount(csv) = val) +#define wbExportCSV_setColumnCount(csv, val) \ + (wbExportCSV_getColumnCount(csv) = val) +#define wbExportCSV_setSeperator(csv, val) \ + (wbExportCSV_getSeperator(csv) = val) + +typedef struct st_wbExport_t { + wbExportKind_t kind; + union { + wbExportRaw_t raw; + wbExportCSV_t csv; + wbImage_t img; + wbExportText_t text; + } container; + char *file; +} wbExport_t; + +#define wbExport_getKind(exprt) ((exprt).kind) +#define wbExport_getContainer(exprt) ((exprt).container) +#define wbExport_getRaw(exprt) (wbExport_getContainer(exprt).raw) +#define wbExport_getCSV(exprt) (wbExport_getContainer(exprt).csv) +#define wbExport_getImage(exprt) (wbExport_getContainer(exprt).img) +#define wbExport_getText(exprt) (wbExport_getContainer(exprt).text) +#define wbExport_getFile(exprt) ((exprt).file) + +#define wbExport_setKind(exprt, val) (wbExport_getKind(exprt) = val) +#define wbExport_setRaw(exprt, val) (wbExport_getRaw(exprt) = val) +#define wbExport_setCSV(exprt, val) (wbExport_getCSV(exprt) = val) +#define wbExport_setImage(exprt, val) (wbExport_getImage(exprt) = val) +#define wbExport_setText(exprt, val) (wbExport_getText(exprt) = val) +#define wbExport_setFile(exprt, val) (wbExport_getFile(exprt) = val) + +void wbExport(const char *file, int *data, int rows, int columns); +void wbExport(const char *file, int *data, int rows); +void wbExport(const char *file, unsigned char *data, int rows, + int columns); +void wbExport(const char *file, unsigned char *data, int rows); +void wbExport(const char *file, int *data, int rows, int columns); +void wbExport(const char *file, int *data, int rows); +void wbExport(const char *file, wbReal_t *data, int rows, int columns); +void wbExport(const char *file, wbReal_t *data, int rows); +void wbExport(const char *file, wbImage_t img); + +void wbExport(const char *file, wbExportKind_t kind, void *data, int rows, + int columns, wbType_t type); + +void wbExport_text(const char *file, void *data, int length); + +#endif /* __WB_EXPORT_H__ */ diff --git a/CUDA_TiledMatrixMultiplication/libwb/wbFile.cpp b/CUDA_TiledMatrixMultiplication/libwb/wbFile.cpp new file mode 100644 index 0000000..b3fdbe7 --- /dev/null +++ b/CUDA_TiledMatrixMultiplication/libwb/wbFile.cpp @@ -0,0 +1,353 @@ + + +#include "wb.h" + +#define wbFile_maxCount 256 + +static wbFile_t wbFile_handles[wbFile_maxCount]; + +static int wbFile_nextIndex(void) { + int ii; + for (ii = 0; ii < wbFile_maxCount; ii++) { + if (wbFile_handles[ii] == NULL) { + return ii; + } + } + wbLog(ERROR, "Ran out of file handles."); + wbExit(); + return -1; +} + +wbFile_t wbFile_new(void) { + int idx = wbFile_nextIndex(); + wbFile_t file = wbNew(struct st_wbFile_t); + + wbAssert(idx >= 0); + + wbFile_setIndex(file, idx); + wbFile_setFileName(file, NULL); + wbFile_setMode(file, NULL); + wbFile_setFileHandle(file, NULL); + wbFile_setData(file, NULL); + + wbFile_handles[idx] = file; + + return file; +} + +void wbFile_delete(wbFile_t file) { + if (file != NULL) { + int idx = wbFile_getIndex(file); + if (wbFile_getFileName(file) != NULL) { + wbDelete(wbFile_getFileName(file)); + } + if (wbFile_getMode(file) != NULL) { + wbDelete(wbFile_getMode(file)); + } + if (wbFile_getFileHandle(file) != NULL) { + fflush(wbFile_getFileHandle(file)); + fclose(wbFile_getFileHandle(file)); + } + if (idx >= 0) { + wbAssert(wbFile_handles[idx] == file); + wbFile_handles[idx] = NULL; + } + if (wbFile_getData(file) != NULL) { + wbDelete(wbFile_getData(file)); + } + wbDelete(file); + } +} + +void wbFile_init(void) { + int ii; + + for (ii = 0; ii < wbFile_maxCount; ii++) { + wbFile_handles[ii] = NULL; + } +} + +void wbFile_atExit(void) { + int ii; + + for (ii = 0; ii < wbFile_maxCount; ii++) { + if (wbFile_handles[ii] != NULL) { + wbFile_delete(wbFile_handles[ii]); + } + } +} + +int wbFile_count(void) { + int ii, count = 0; + + for (ii = 0; ii < wbFile_maxCount; ii++) { + if (wbFile_handles[ii] != NULL) { + count++; + } + } + return count; +} + +wbFile_t wbFile_open(const char *fileName, const char *mode) { + FILE *handle; + wbFile_t file; + + if (fileName == NULL) { + return NULL; + } + + handle = fopen(fileName, mode); + if (handle == NULL) { + wbLog(ERROR, "Failed to open ", file, " in mode ", mode); + return NULL; + } + + file = wbFile_new(); + wbFile_setFileName(file, wbString_duplicate(fileName)); + wbFile_setMode(file, wbString_duplicate(mode)); + wbFile_setFileHandle(file, handle); + + return file; +} + +wbFile_t wbFile_open(const char *fileName) { + return wbFile_open(fileName, "r"); +} + +void wbFile_close(wbFile_t file) { + wbFile_delete(file); +} + +char *wbFile_read(wbFile_t file, size_t size, size_t count) { + size_t res; + char *buffer; + size_t bufferLen; + FILE *handle; + + if (file == NULL) { + return NULL; + } +#ifndef LAZY_FILE_LOAD + if (wbFile_getData(file) != NULL) { + char *data = wbFile_getData(file) + wbFile_getDataOffset(file); + wbFile_setDataOffset(file, wbFile_getDataOffset(file) + size * count); + return data; + } +#endif /* LAZY_FILE_LOAD */ + + handle = wbFile_getFileHandle(file); + bufferLen = size * count + 1; + buffer = wbNewArray(char, bufferLen); + + res = fread(buffer, size, count, handle); + // make valid C string + buffer[size * res] = '\0'; + + return buffer; +} + +char *wbFile_read(wbFile_t file, size_t len) { + char *buffer = wbFile_read(file, sizeof(char), len); + return buffer; +} + +void wbFile_rewind(wbFile_t file) { + if (file == NULL) { + return; + } + + if (wbFile_getData(file) == NULL) { + FILE *handle; + handle = wbFile_getFileHandle(file); + wbAssert(handle != NULL); + rewind(handle); + } +#ifndef LAZY_FILE_LOAD + else { + wbFile_setDataOffset(file, 0); + } +#endif + + return; +} + +size_t wbFile_size(wbFile_t file) { + size_t len; + FILE *handle; + + if (file == NULL) { + return 0; + } +#ifndef LAZY_FILE_LOAD + if (wbFile_getData(file) != NULL) { + if (wbFile_getLength(file) == 0) { + wbFile_setLength(file, strlen(wbFile_getData(file))); + } + return wbFile_getLength(file); + } +#endif /* LAZY_FILE_LOAD */ + + handle = wbFile_getFileHandle(file); + + fseek(handle, 0, SEEK_END); + len = ftell(handle); + rewind(handle); + + return len; +} + +char *wbFile_read(wbFile_t file) { + size_t len; + + if (file == NULL) { + return NULL; + } + + len = wbFile_size(file); + + if (len == 0) { + return NULL; + } + + wbFile_setLength(file, len); + + return wbFile_read(file, len); +} + +#define MAX_CHARS_PER_LINE (1 << 17) + +static char buffer[MAX_CHARS_PER_LINE]; + +char *wbFile_readLine(wbFile_t file) { + if (file == NULL) { + return NULL; + } +#ifdef LAZY_FILE_LOAD + FILE *handle; + memset(buffer, 0, MAX_CHARS_PER_LINE); + + handle = wbFile_getFileHandle(file); + + if (fgets(buffer, MAX_CHARS_PER_LINE - 1, handle)) { + return buffer; + } else { + // wbLog(ERROR, "Was not able to read line from ", + // wbFile_getFileName(file)); + return NULL; + } +#else + size_t newOffset; + size_t lenToNewLine = 0; + const char *tmp; + + if (wbFile_getData(file) == NULL) { + wbFile_setData(file, wbFile_read(file)); + fclose(wbFile_getFileHandle(file)); + wbFile_setFileHandle(file, NULL); + wbFile_setDataOffset(file, 0); + wbFile_setLength(file, strlen(wbFile_getData(file))); + } + + memset(buffer, 0, MAX_CHARS_PER_LINE); + + if (wbFile_getDataOffset(file) >= wbFile_getLength(file)) { + return NULL; + } + + newOffset = wbFile_getDataOffset(file); + tmp = wbFile_getData(file) + wbFile_getDataOffset(file); + while (newOffset < wbFile_getLength(file) && *tmp != '\n') { + tmp++; + lenToNewLine++; + newOffset++; + } + + memcpy(buffer, wbFile_getData(file) + wbFile_getDataOffset(file), + lenToNewLine); + wbFile_setDataOffset(file, newOffset + 1); + + return buffer; +#endif +} + +void wbFile_write(wbFile_t file, const void *buffer, size_t size, + size_t count) { + size_t res; + FILE *handle; + + if (file == NULL) { + return; + } + + handle = wbFile_getFileHandle(file); + + res = fwrite(buffer, size, count, handle); + if (res != count) { + wbLog(ERROR, "Failed to write data to ", wbFile_getFileName(file)); + } + + return; +} + +void wbFile_write(wbFile_t file, const void *buffer, size_t len) { + wbFile_write(file, buffer, sizeof(char), len); + return; +} + +void wbFile_write(wbFile_t file, const char *buffer) { + size_t len; + + len = strlen(buffer); + wbFile_write(file, buffer, len); + + return; +} + +void wbFile_writeLine(wbFile_t file, const char *buffer0) { + string buffer = wbString(buffer0, "\n"); + wbFile_write(file, buffer.c_str()); +} + +void wbFile_write(wbFile_t file, string buffer) { + wbFile_write(file, buffer.c_str()); +} + +void wbFile_writeLine(wbFile_t file, string buffer0) { + string buffer = buffer0 + "\n"; + wbFile_write(file, buffer.c_str()); +} + +wbBool wbFile_existsQ(const char *path) { + if (path == NULL) { + return wbFalse; + } else { + FILE *file = fopen(path, "r"); + if (file != NULL) { + fclose(file); + return wbTrue; + } + return wbFalse; + } +} + +char *wbFile_extension(const char *file) { + char *extension; + char *extensionLower; + char *end; + size_t len; + + len = strlen(file); + end = (char *)&file[len - 1]; + while (*end != '.') { + end--; + } + if (*end == '.') { + end++; + } + + extension = wbString_duplicate(end); + extensionLower = wbString_toLower(extension); + wbDelete(extension); + + return extensionLower; +} diff --git a/CUDA_TiledMatrixMultiplication/libwb/wbFile.h b/CUDA_TiledMatrixMultiplication/libwb/wbFile.h new file mode 100644 index 0000000..ea6b0cb --- /dev/null +++ b/CUDA_TiledMatrixMultiplication/libwb/wbFile.h @@ -0,0 +1,56 @@ + + +#ifndef __WB_FILE_H__ +#define __WB_FILE_H__ + +struct st_wbFile_t { + int index; + char *file; + char *mode; + char *data; + FILE *handle; + size_t len; + size_t offset; +}; + +#define wbFile_getIndex(file) ((file)->index) +#define wbFile_getFileName(file) ((file)->file) +#define wbFile_getMode(file) ((file)->mode) +#define wbFile_getData(file) ((file)->data) +#define wbFile_getLength(file) ((file)->len) +#define wbFile_getDataOffset(file) ((file)->offset) +#define wbFile_getFileHandle(file) ((file)->handle) + +#define wbFile_setIndex(file, val) (wbFile_getIndex(file) = val) +#define wbFile_setFileName(file, val) (wbFile_getFileName(file) = val) +#define wbFile_setMode(file, val) (wbFile_getMode(file) = val) +#define wbFile_setData(file, val) (wbFile_getData(file) = val) +#define wbFile_setLength(file, val) (wbFile_getLength(file) = val) +#define wbFile_setDataOffset(file, val) (wbFile_getDataOffset(file) = val) +#define wbFile_setFileHandle(file, val) (wbFile_getFileHandle(file) = val) + +wbFile_t wbFile_new(void); +void wbFile_delete(wbFile_t file); +void wbFile_close(wbFile_t file); +void wbFile_init(void); +void wbFile_atExit(void); +int wbFile_count(void); +wbFile_t wbFile_open(const char *fileName, const char *mode); +wbFile_t wbFile_open(const char *fileName); +char *wbFile_read(wbFile_t file, size_t size, size_t count); +char *wbFile_read(wbFile_t file, size_t len); +void wbFile_rewind(wbFile_t file); +size_t wbFile_size(wbFile_t file); +char *wbFile_read(wbFile_t file); +char *wbFile_readLine(wbFile_t file); +void wbFile_write(wbFile_t file, const void *buffer, size_t size, + size_t count); +void wbFile_write(wbFile_t file, const void *buffer, size_t len); +void wbFile_write(wbFile_t file, const char *buffer); +void wbFile_writeLine(wbFile_t file, const char *buffer0); +void wbFile_write(wbFile_t file, string buffer); +void wbFile_writeLine(wbFile_t file, string buffer0); +wbBool wbFile_existsQ(const char *path); +char *wbFile_extension(const char *file); + +#endif /* __WB_FILE_H__ */ diff --git a/CUDA_TiledMatrixMultiplication/libwb/wbImage.cpp b/CUDA_TiledMatrixMultiplication/libwb/wbImage.cpp new file mode 100644 index 0000000..1d95928 --- /dev/null +++ b/CUDA_TiledMatrixMultiplication/libwb/wbImage.cpp @@ -0,0 +1,134 @@ + + +#include "wb.h" + +static inline float _min(float x, float y) { + return x < y ? x : y; +} + +static inline float _max(float x, float y) { + return x > y ? x : y; +} + +static inline float _clamp(float x, float start, float end) { + return _min(_max(x, start), end); +} + +wbImage_t wbImage_new(int width, int height, int channels, float *data) { + wbImage_t img; + + img = wbNew(struct st_wbImage_t); + + wbImage_setWidth(img, width); + wbImage_setHeight(img, height); + wbImage_setChannels(img, channels); + wbImage_setPitch(img, width * channels); + + wbImage_setData(img, data); + return img; +} + +wbImage_t wbImage_new(int width, int height, int channels) { + float *data = wbNewArray(float, width *height *channels); + return wbImage_new(width, height, channels, data); +} + +wbImage_t wbImage_new(int width, int height) { + return wbImage_new(width, height, wbImage_channels); +} + +void wbImage_delete(wbImage_t img) { + if (img != NULL) { + if (wbImage_getData(img) != NULL) { + wbDelete(wbImage_getData(img)); + } + wbDelete(img); + } +} + +static inline void wbImage_setPixel(wbImage_t img, int x, int y, int c, + float val) { + float *data = wbImage_getData(img); + int channels = wbImage_getChannels(img); + int pitch = wbImage_getPitch(img); + + data[y * pitch + x * channels + c] = val; + + return; +} + +static inline float wbImage_getPixel(wbImage_t img, int x, int y, int c) { + float *data = wbImage_getData(img); + int channels = wbImage_getChannels(img); + int pitch = wbImage_getPitch(img); + + return data[y * pitch + x * channels + c]; +} + +wbBool wbImage_sameQ(wbImage_t a, wbImage_t b, + wbImage_onSameFunction_t onUnSame) { + if (a == NULL || b == NULL) { + wbLog(ERROR, "Comparing null images."); + return wbFalse; + } else if (a == b) { + return wbTrue; + } else if (wbImage_getWidth(a) != wbImage_getWidth(b)) { + wbLog(ERROR, "Image widths do not match."); + return wbFalse; + } else if (wbImage_getHeight(a) != wbImage_getHeight(b)) { + wbLog(ERROR, "Image heights do not match."); + return wbFalse; + } else if (wbImage_getChannels(a) != wbImage_getChannels(b)) { + wbLog(ERROR, "Image channels do not match."); + return wbFalse; + } else { + float *aData, *bData; + int width, height, channels; + int ii, jj, kk; + + aData = wbImage_getData(a); + bData = wbImage_getData(b); + + wbAssert(aData != NULL); + wbAssert(bData != NULL); + + width = wbImage_getWidth(a); + height = wbImage_getHeight(a); + channels = wbImage_getChannels(a); + + for (ii = 0; ii < height; ii++) { + for (jj = 0; jj < width; jj++) { + for (kk = 0; kk < channels; kk++) { + float x, y; + if (channels <= 3) { + x = _clamp(*aData++, 0, 1); + y = _clamp(*bData++, 0, 1); + } else { + x = *aData++; + y = *bData++; + } + if (wbUnequalQ(x, y)) { + if (onUnSame != NULL) { + string str = wbString( + "Image pixels do not match at position ( row = ", + wbString(ii, ", col = ", jj, ", channel = ", kk, + ") expecting a value of "), + wbString(y, " but got a computed value of ", x)); + onUnSame(str); + } + return wbFalse; + } + } + } + } + return wbTrue; + } +} + +static void wbImage_onUnsameFunction(string str) { + wbLog(ERROR, str); +} + +wbBool wbImage_sameQ(wbImage_t a, wbImage_t b) { + return wbImage_sameQ(a, b, wbImage_onUnsameFunction); +} diff --git a/CUDA_TiledMatrixMultiplication/libwb/wbImage.h b/CUDA_TiledMatrixMultiplication/libwb/wbImage.h new file mode 100644 index 0000000..020eec5 --- /dev/null +++ b/CUDA_TiledMatrixMultiplication/libwb/wbImage.h @@ -0,0 +1,40 @@ + + +#ifndef __IMAGE_H__ +#define __IMAGE_H__ + +#include "wbTypes.h" + +struct st_wbImage_t { + int width; + int height; + int channels; + int pitch; + float *data; +}; + +#define wbImage_channels 3 + +#define wbImage_getWidth(img) ((img)->width) +#define wbImage_getHeight(img) ((img)->height) +#define wbImage_getChannels(img) ((img)->channels) +#define wbImage_getPitch(img) ((img)->pitch) +#define wbImage_getData(img) ((img)->data) + +#define wbImage_setWidth(img, val) (wbImage_getWidth(img) = val) +#define wbImage_setHeight(img, val) (wbImage_getHeight(img) = val) +#define wbImage_setChannels(img, val) (wbImage_getChannels(img) = val) +#define wbImage_setPitch(img, val) (wbImage_getPitch(img) = val) +#define wbImage_setData(img, val) (wbImage_getData(img) = val) + +typedef void (*wbImage_onSameFunction_t)(string str); + +wbImage_t wbImage_new(int width, int height, int channels, float *data); +wbImage_t wbImage_new(int width, int height, int channels); +wbImage_t wbImage_new(int width, int height); +void wbImage_delete(wbImage_t img); +wbBool wbImage_sameQ(wbImage_t a, wbImage_t b, + wbImage_onSameFunction_t onUnSame); +wbBool wbImage_sameQ(wbImage_t a, wbImage_t b); + +#endif /* __IMAGE_H__ */ diff --git a/CUDA_TiledMatrixMultiplication/libwb/wbImport.cpp b/CUDA_TiledMatrixMultiplication/libwb/wbImport.cpp new file mode 100644 index 0000000..fccc071 --- /dev/null +++ b/CUDA_TiledMatrixMultiplication/libwb/wbImport.cpp @@ -0,0 +1,711 @@ + + +#include "wb.h" + +static inline void wbImportCSV_setFile(wbImportCSV_t csv, + const char *path) { + if (csv != NULL) { + if (wbImportCSV_getFile(csv) != NULL) { + wbFile_delete(wbImportCSV_getFile(csv)); + } + if (path != NULL) { + wbImportCSV_getFile(csv) = wbFile_open(path, "r"); + } else { + wbImportCSV_getFile(csv) = NULL; + } + } + + return; +} + +static inline wbImportCSV_t wbImportCSV_new(void) { + wbImportCSV_t csv; + + csv = wbNew(struct st_wbImportCSV_t); + + wbImportCSV_setRowCount(csv, -1); + wbImportCSV_setColumnCount(csv, -1); + wbImportCSV_setData(csv, NULL); + wbImportCSV_getFile(csv) = NULL; + wbImportCSV_setSeperator(csv, '\0'); + + return csv; +} + +static inline void wbImportCSV_delete(wbImportCSV_t csv) { + if (csv != NULL) { + wbImportCSV_setFile(csv, NULL); + if (wbImportCSV_getData(csv)) { + wbDelete(wbImportCSV_getData(csv)); + } + wbDelete(csv); + } +} + +static inline wbImportCSV_t wbImportCSV_findDimensions(wbImportCSV_t csv, + int *resRows, + int *resColumns) { + int rows = 0, columns = -1; + char *line; + wbFile_t file; + char seperator[2]; + + if (csv == NULL) { + return NULL; + } + + if (wbImportCSV_getSeperator(csv) == '\0') { + seperator[0] = ','; + } else { + seperator[0] = wbImportCSV_getSeperator(csv); + } + seperator[1] = '\0'; + + file = wbImportCSV_getFile(csv); + + while ((line = wbFile_readLine(file)) != NULL) { + int currColumn = 0; + char *token = strtok(line, seperator); + while (token != NULL) { + token = strtok(NULL, seperator); + currColumn++; + } + rows++; + if (columns == -1) { + columns = currColumn; + } + if (columns != currColumn) { + wbLog(ERROR, "The csv file is not rectangular."); + } + wbAssert(columns == currColumn); + } + + wbFile_rewind(file); + + *resRows = rows; + *resColumns = columns; + + return csv; +} + +static inline int *csv_readAsInteger(wbFile_t file, char sep, int rows, + int columns) { + int ii = 0; + int *data; + char *line; + int var; + char seperator[2]; + + if (file == NULL) { + return NULL; + } + + data = wbNewArray(int, rows *columns); + + if (sep == '\0') { + seperator[0] = ','; + } else { + seperator[0] = sep; + } + seperator[1] = '\0'; + + // printf("cols = %d rows = %d\n", columns, rows); + if (columns == 1) { + while ((line = wbFile_readLine(file)) != NULL) { + sscanf(line, "%d", &var); + // printf("reading %d\n", var); + data[ii++] = var; + } + } else { + while ((line = wbFile_readLine(file)) != NULL) { + char *token = strtok(line, seperator); + while (token != NULL) { + sscanf(token, "%d", &var); + token = strtok(NULL, seperator); + data[ii++] = var; + } + } + } + + return data; +} + +static inline wbReal_t *csv_readAsReal(wbFile_t file, char sep, int rows, + int columns) { + int ii = 0; + wbReal_t *data; + char *line; + wbReal_t var; + char seperator[2]; + + if (file == NULL) { + return NULL; + } + + data = wbNewArray(wbReal_t, rows * columns); + + if (sep == '\0') { + seperator[0] = ','; + } else { + seperator[0] = sep; + } + seperator[1] = '\0'; + + if (columns == 1) { + while ((line = wbFile_readLine(file)) != NULL) { + sscanf(line, "%f", &var); + data[ii++] = var; + } + } else { + while ((line = wbFile_readLine(file)) != NULL) { + char *token = strtok(line, seperator); + while (token != NULL) { + sscanf(token, "%f", &var); + token = strtok(NULL, seperator); + data[ii++] = var; + } + } + } + + return data; +} + +static inline wbImportCSV_t wbImportCSV_read(wbImportCSV_t csv, + wbType_t type) { + void *data; + wbFile_t file; + char seperator; + int rows, columns; + + if (csv == NULL) { + return NULL; + } + + if (wbImportCSV_getRowCount(csv) == -1 || + wbImportCSV_getColumnCount(csv) == -1) { + if (wbImportCSV_findDimensions(csv, &rows, &columns) == NULL) { + wbLog(ERROR, "Failed to figure out csv dimensions."); + return NULL; + } + wbImportCSV_setRowCount(csv, rows); + wbImportCSV_setColumnCount(csv, columns); + } + + file = wbImportCSV_getFile(csv); + seperator = wbImportCSV_getSeperator(csv); + rows = wbImportCSV_getRowCount(csv); + columns = wbImportCSV_getColumnCount(csv); + + if (wbImportCSV_getData(csv) != NULL) { + wbDelete(wbImportCSV_getData(csv)); + wbImportCSV_setData(csv, NULL); + } + + if (type == wbType_integer) { + // printf("ReadXXXing as integer...\n"); + data = csv_readAsInteger(file, seperator, rows, columns); + } else { + data = csv_readAsReal(file, seperator, rows, columns); + } + + wbImportCSV_setData(csv, data); + + return csv; +} + +static inline wbImportCSV_t wbImportCSV_readAsInteger(wbImportCSV_t csv) { + return wbImportCSV_read(csv, wbType_integer); +} + +static inline wbImportCSV_t wbImportCSV_readAsReal(wbImportCSV_t csv) { + return wbImportCSV_read(csv, wbType_real); +} + +static inline void wbImportRaw_setFile(wbImportRaw_t raw, + const char *path) { + if (raw != NULL) { + if (wbImportRaw_getFile(raw) != NULL) { + wbFile_delete(wbImportRaw_getFile(raw)); + } + if (path != NULL) { + wbImportRaw_getFile(raw) = wbFile_open(path, "r"); + } else { + wbImportRaw_getFile(raw) = NULL; + } + } + + return; +} + +static inline wbImportRaw_t wbImportRaw_new(void) { + wbImportRaw_t raw; + + raw = wbNew(struct st_wbImportRaw_t); + + wbImportRaw_setRowCount(raw, -1); + wbImportRaw_setColumnCount(raw, -1); + wbImportRaw_setData(raw, NULL); + wbImportRaw_getFile(raw) = NULL; + + return raw; +} + +static inline void wbImportRaw_delete(wbImportRaw_t raw) { + if (raw != NULL) { + wbImportRaw_setFile(raw, NULL); + if (wbImportRaw_getData(raw)) { + wbDelete(wbImportRaw_getData(raw)); + } + wbDelete(raw); + } +} + +static inline wbBool lineHasSpace(const char *line) { + while (*line != '\0') { + if (*line == ' ') { + return wbTrue; + } + line++; + } + return wbFalse; +} + +static inline char *lineStrip(const char *line) { + char *sl = wbString_duplicate(line); + char *iter = sl; + size_t slen = strlen(line); + + iter += slen - 1; + while (*iter == '\0' || *iter == '\r' || *iter == '\t' || + *iter == '\n' || *iter == ' ') { + *iter-- = '\0'; + } + return sl; +} + +static inline wbBool wbImportRaw_findDimensions(wbImportRaw_t raw) { + if (raw != NULL) { + int rows; + int columns; + char *line; + wbFile_t file; + char *strippedLine; + + file = wbImportRaw_getFile(raw); + + wbFile_rewind(file); + + line = wbFile_readLine(file); + + if (line == NULL) { + return wbTrue; + } + + strippedLine = lineStrip(line); + + if (lineHasSpace(strippedLine)) { + sscanf(strippedLine, "%d %d", &rows, &columns); + } else { + columns = 1; + sscanf(strippedLine, "%d", &rows); + } + + wbImportRaw_setRowCount(raw, rows); + wbImportRaw_setColumnCount(raw, columns); + + wbDelete(strippedLine); + + return wbFalse; + } + + return wbTrue; +} + +static inline wbImportRaw_t wbImportRaw_read(wbImportRaw_t raw, + wbType_t type) { + void *data; + wbFile_t file; + char seperator; + int rows, columns; + + if (raw == NULL) { + return NULL; + } + + if (wbImportRaw_getRowCount(raw) == -1 || + wbImportRaw_getColumnCount(raw) == -1) { + if (wbImportRaw_findDimensions(raw)) { + wbLog(ERROR, "Failed to figure out raw dimensions."); + return NULL; + } + } + + file = wbImportRaw_getFile(raw); + seperator = ' '; + rows = wbImportRaw_getRowCount(raw); + columns = wbImportRaw_getColumnCount(raw); + + if (wbImportRaw_getData(raw) != NULL) { + wbDelete(wbImportRaw_getData(raw)); + wbImportRaw_setData(raw, NULL); + } + + if (type == wbType_integer) { + // printf("Rdin gas integer...\n"); + data = csv_readAsInteger(file, seperator, rows, columns); + } else { + data = csv_readAsReal(file, seperator, rows, columns); + } + + wbImportRaw_setData(raw, data); + + return raw; +} + +static inline wbImportRaw_t wbImportRaw_readAsInteger(wbImportRaw_t raw) { + return wbImportRaw_read(raw, wbType_integer); +} + +static inline wbImportRaw_t wbImportRaw_readAsReal(wbImportRaw_t raw) { + return wbImportRaw_read(raw, wbType_real); +} + +static inline wbImportText_t wbImportText_new(void) { + wbImportText_t text; + + text = wbNew(struct st_wbImportText_t); + + wbImportText_setLength(text, 0); + wbImportText_setData(text, NULL); + wbImportText_getFile(text) = NULL; + + return text; +} + +static inline void wbImportText_setFile(wbImportText_t text, + const char *path) { + if (text != NULL) { + if (wbImportText_getFile(text) != NULL) { + wbFile_delete(wbImportText_getFile(text)); + } + if (path != NULL) { + wbImportText_getFile(text) = wbFile_open(path, "r"); + } else { + wbImportText_getFile(text) = NULL; + } + } + + return; +} + +static inline void wbImportText_delete(wbImportText_t text) { + if (text != NULL) { + wbImportText_setFile(text, NULL); + if (wbImportText_getData(text)) { + wbDelete(wbImportText_getData(text)); + } + wbDelete(text); + } +} + +static inline wbImportText_t wbImportText_read(wbImportText_t text) { + char *data; + wbFile_t file; + int length; + + if (text == NULL) { + return NULL; + } + + file = wbImportText_getFile(text); + + if (wbImportText_getData(text) != NULL) { + wbDelete(wbImportText_getData(text)); + wbImportText_setData(text, NULL); + } + + length = wbFile_size(file); + data = wbFile_read(file, length); + + wbImportText_setData(text, data); + wbImportText_setLength(text, length); + + return text; +} + +static inline wbImport_t wbImport_open(const char *file, + wbImportKind_t kind) { + wbImport_t imp; + + if (file == NULL) { + wbLog(ERROR, "Go NULL for file value."); + wbExit(); + } + + if (!wbFile_existsQ(file)) { + wbLog(ERROR, "File ", file, " does not exist."); + wbExit(); + } + + wbImport_setKind(imp, kind); + + if (kind == wbImportKind_raw) { + wbImportRaw_t raw = wbImportRaw_new(); + wbImportRaw_setFile(raw, file); + wbImport_setRaw(imp, raw); + } else if (kind == wbImportKind_tsv || kind == wbImportKind_csv) { + wbImportCSV_t csv = wbImportCSV_new(); + if (kind == wbImportKind_csv) { + wbImportCSV_setSeperator(csv, ','); + } else { + wbImportCSV_setSeperator(csv, '\t'); + } + wbImportCSV_setFile(csv, file); + wbImport_setCSV(imp, csv); + } else if (kind == wbImportKind_text) { + wbImportText_t text = wbImportText_new(); + wbImportText_setFile(text, file); + wbImport_setText(imp, text); + } else if (kind == wbImportKind_ppm) { + wbImage_t img = wbPPM_import(file); + wbImport_setImage(imp, img); + } else { + wbLog(ERROR, "Invalid import type."); + wbExit(); + } + + return imp; +} + +static inline wbImport_t wbImport_open(const char *file, + const char *type0) { + wbImport_t imp; + wbImportKind_t kind; + char *type; + + type = wbString_toLower(type0); + + if (wbString_sameQ(type, "csv")) { + kind = wbImportKind_csv; + } else if (wbString_sameQ(type, "tsv")) { + kind = wbImportKind_tsv; + } else if (wbString_sameQ(type, "raw") || wbString_sameQ(type, "dat")) { + kind = wbImportKind_raw; + } else if (wbString_sameQ(type, "ppm")) { + kind = wbImportKind_ppm; + } else if (wbString_sameQ(type, "text") || wbString_sameQ(type, "txt")) { + kind = wbImportKind_text; + } else { + wbLog(ERROR, "Invalid import type ", type0); + wbExit(); + } + + imp = wbImport_open(file, kind); + + wbDelete(type); + + return imp; +} + +static inline void wbImport_close(wbImport_t imp) { + wbImportKind_t kind; + + kind = wbImport_getKind(imp); + if (kind == wbImportKind_tsv || kind == wbImportKind_csv) { + wbImportCSV_t csv = wbImport_getCSV(imp); + wbImportCSV_delete(csv); + wbImport_setCSV(imp, NULL); + } else if (kind == wbImportKind_raw) { + wbImportRaw_t raw = wbImport_getRaw(imp); + wbImportRaw_delete(raw); + wbImport_setRaw(imp, NULL); + } else if (kind == wbImportKind_text) { + wbImportText_t text = wbImport_getText(imp); + wbImportText_delete(text); + wbImport_setText(imp, NULL); + } else if (kind == wbImportKind_ppm) { + } else { + wbLog(ERROR, "Invalid import type."); + wbExit(); + } + return; +} + +static inline void *wbImport_read(wbImport_t imp, wbType_t type) { + void *data = NULL; + wbImportKind_t kind; + + kind = wbImport_getKind(imp); + if (kind == wbImportKind_tsv || kind == wbImportKind_csv) { + wbImportCSV_t csv = wbImport_getCSV(imp); + wbImportCSV_read(csv, type); + data = wbImportCSV_getData(csv); + } else if (kind == wbImportKind_raw) { + wbImportRaw_t raw = wbImport_getRaw(imp); + wbImportRaw_read(raw, type); + data = wbImportRaw_getData(raw); + } else if (wbImportKind_text == kind) { + wbImportText_t text = wbImport_getText(imp); + text = wbImportText_read(text); + data = wbImportText_getData(text); + + } else { + wbLog(ERROR, "Invalid import type."); + wbExit(); + } + return data; +} + +static inline int *wbImport_readAsInteger(wbImport_t imp) { + void *data = wbImport_read(imp, wbType_integer); + return (int *)data; +} + +static inline wbReal_t *wbImport_readAsReal(wbImport_t imp) { + void *data = wbImport_read(imp, wbType_real); + return (wbReal_t *)data; +} + +static inline wbChar_t *wbImport_readAsText(wbImport_t imp) { + void *data = wbImport_read(imp, wbType_ubit8); + return (wbChar_t *)data; +} + +static wbImportKind_t _parseImportExtension(const char *file) { + char *extension; + wbImportKind_t kind; + + extension = wbFile_extension(file); + + if (wbString_sameQ(extension, "csv")) { + kind = wbImportKind_csv; + } else if (wbString_sameQ(extension, "tsv")) { + kind = wbImportKind_tsv; + } else if (wbString_sameQ(extension, "raw") || + wbString_sameQ(extension, "dat")) { + kind = wbImportKind_raw; + } else if (wbString_sameQ(extension, "ppm") || + wbString_sameQ(extension, "pbm")) { + kind = wbImportKind_ppm; + } else if (wbString_sameQ(extension, "text") || + wbString_sameQ(extension, "txt")) { + kind = wbImportKind_text; + } else { + kind = wbImportKind_unknown; + wbLog(ERROR, "File ", file, " does not have a compatible extension."); + } + + wbDelete(extension); + + return kind; +} + +void *wbImport(const char *file, int *resRows, int *resColumns, + const char *type) { + void *data, *res; + wbImport_t imp; + size_t sz; + int columns = 0, rows = 0; + wbImportKind_t kind; + + if (file == NULL) { + fprintf(stderr, "Failed to import file.\n"); + wbExit(); + } + + kind = _parseImportExtension(file); + + wbAssert(kind != wbImportKind_unknown); + + imp = wbImport_open(file, kind); + if (wbString_sameQ(type, "Real")) { + data = wbImport_readAsReal(imp); + sz = sizeof(wbReal_t); + } else if (wbString_sameQ(type, "Text")) { + data = wbImport_readAsText(imp); + sz = sizeof(char); + } else { + // printf("Reading as integer..d\n"); + data = wbImport_readAsInteger(imp); + sz = sizeof(int); + } + + if (kind == wbImportKind_csv || kind == wbImportKind_tsv) { + rows = wbImportCSV_getRowCount(wbImport_getCSV(imp)); + columns = wbImportCSV_getColumnCount(wbImport_getCSV(imp)); + } else if (kind == wbImportKind_raw) { + rows = wbImportRaw_getRowCount(wbImport_getRaw(imp)); + columns = wbImportRaw_getColumnCount(wbImport_getRaw(imp)); + } else if (kind == wbImportKind_text) { + rows = 1; + columns = wbImportText_getLength(wbImport_getText(imp)); + } + + if (rows == 1 && columns > 0) { + rows = columns; + columns = 1; + } + + if (resRows != NULL) { + *resRows = rows; + } + + if (resColumns != NULL) { + *resColumns = columns; + } + + res = wbMalloc(sz * rows * columns); + memcpy(res, data, sz * rows * columns); + + wbImport_close(imp); + + return res; +} + +void *wbImport(const char *file, int *rows, int *columns) { + return wbImport(file, rows, columns, "Real"); +} + +EXTERN_C void *wbImport(const char *file, int *rows) { + return wbImport(file, rows, NULL, "Real"); +} + +void *wbImport(const char *file, int *res_rows, const char *type) { + int cols, rows; + void *res = wbImport(file, &rows, &cols, type); + if (rows == 1 && cols > 1) { + rows = cols; + } + *res_rows = rows; + return res; +} + +wbImage_t wbImport(const char *file) { + wbImage_t img; + wbImport_t imp; + wbImportKind_t kind; + + if (file == NULL) { + fprintf(stderr, "Failed to import file.\n"); + wbExit(); + } + + kind = _parseImportExtension(file); + + wbAssert(kind == wbImportKind_ppm); + + imp = wbImport_open(file, kind); + img = wbImport_getImage(imp); + wbImport_close(imp); + + return img; +} + +int wbImport_flag(const char *file) { + int res; + wbFile_t fh = wbFile_open(file, "r"); + const char *line = wbFile_readLine(fh); + sscanf(line, "%d", &res); + wbFile_close(fh); + return res; +} diff --git a/CUDA_TiledMatrixMultiplication/libwb/wbImport.h b/CUDA_TiledMatrixMultiplication/libwb/wbImport.h new file mode 100644 index 0000000..ce13e1b --- /dev/null +++ b/CUDA_TiledMatrixMultiplication/libwb/wbImport.h @@ -0,0 +1,103 @@ + +#ifndef __WB_IMPORT_H__ +#define __WB_IMPORT_H__ + +#include "wbImage.h" + +typedef enum en_wbImportKind_t { + wbImportKind_unknown = -1, + wbImportKind_raw = 0x1000, + wbImportKind_csv, + wbImportKind_tsv, + wbImportKind_ppm, + wbImportKind_text +} wbImportKind_t; + +#define wbType_real wbType_float + +typedef struct st_wbImportCSV_t { + int rows; + int columns; + void *data; + wbFile_t file; + char seperator; +} * wbImportCSV_t; + +#define wbImportCSV_getRowCount(csv) ((csv)->rows) +#define wbImportCSV_getColumnCount(csv) ((csv)->columns) +#define wbImportCSV_getData(csv) ((csv)->data) +#define wbImportCSV_getFile(csv) ((csv)->file) +#define wbImportCSV_getSeperator(csv) ((csv)->seperator) + +#define wbImportCSV_setRowCount(csv, val) \ + (wbImportCSV_getRowCount(csv) = val) +#define wbImportCSV_setColumnCount(csv, val) \ + (wbImportCSV_getColumnCount(csv) = val) +#define wbImportCSV_setData(csv, val) (wbImportCSV_getData(csv) = val) +#define wbImportCSV_setSeperator(csv, val) \ + (wbImportCSV_getSeperator(csv) = val) + +typedef struct st_wbImportRaw_t { + int rows; + int columns; + void *data; + wbFile_t file; +} * wbImportRaw_t; + +#define wbImportRaw_getRowCount(raw) ((raw)->rows) +#define wbImportRaw_getColumnCount(raw) ((raw)->columns) +#define wbImportRaw_getData(raw) ((raw)->data) +#define wbImportRaw_getFile(raw) ((raw)->file) + +#define wbImportRaw_setRowCount(raw, val) \ + (wbImportRaw_getRowCount(raw) = val) +#define wbImportRaw_setColumnCount(raw, val) \ + (wbImportRaw_getColumnCount(raw) = val) +#define wbImportRaw_setData(raw, val) (wbImportRaw_getData(raw) = val) + +typedef struct st_wbImportText_t { + int length; + char *data; + wbFile_t file; +} * wbImportText_t; + +#define wbImportText_getLength(txt) ((txt)->length) +#define wbImportText_getData(txt) ((txt)->data) +#define wbImportText_getFile(txt) ((txt)->file) + +#define wbImportText_setLength(txt, val) \ + (wbImportText_getLength(txt) = val) +#define wbImportText_setData(txt, val) (wbImportText_getData(txt) = val) + +typedef struct st_wbImport_t { + wbImportKind_t kind; + union { + wbImportRaw_t raw; + wbImportCSV_t csv; + wbImportText_t text; + wbImage_t img; + } container; +} wbImport_t; + +#define wbImport_getKind(imp) ((imp).kind) +#define wbImport_getContainer(imp) ((imp).container) +#define wbImport_getRaw(imp) (wbImport_getContainer(imp).raw) +#define wbImport_getCSV(imp) (wbImport_getContainer(imp).csv) +#define wbImport_getText(imp) (wbImport_getContainer(imp).text) +#define wbImport_getImage(imp) (wbImport_getContainer(imp).img) + +#define wbImport_setKind(imp, val) (wbImport_getKind(imp) = val) +#define wbImport_setRaw(imp, val) (wbImport_getRaw(imp) = val) +#define wbImport_setCSV(imp, val) (wbImport_getCSV(imp) = val) +#define wbImport_setText(imp, val) (wbImport_getText(imp) = val) +#define wbImport_setImage(imp, val) (wbImport_getImage(imp) = val) + +EXTERN_C void *wbImport(const char *file, int *rows); +void *wbImport(const char *file, int *rows, int *columns); +void *wbImport(const char *file, int *rows, const char *type); +void *wbImport(const char *file, int *resRows, int *resColumns, + const char *type); +wbImage_t wbImport(const char *file); +int wbImport_flag(const char *file); + +#endif /* __WB_IMPORT_H__ */ diff --git a/CUDA_TiledMatrixMultiplication/libwb/wbInit.cpp b/CUDA_TiledMatrixMultiplication/libwb/wbInit.cpp new file mode 100644 index 0000000..96ebcf3 --- /dev/null +++ b/CUDA_TiledMatrixMultiplication/libwb/wbInit.cpp @@ -0,0 +1,85 @@ + +#include "wb.h" + +#define MB (1 << 20) +#ifndef WB_DEFAULT_HEAP_SIZE +#define WB_DEFAULT_HEAP_SIZE (1024 * MB) +#endif /* WB_DEFAULT_HEAP_SIZE */ + +static bool _initializedQ = wbFalse; + +#ifndef WB_USE_WINDOWS +__attribute__((__constructor__)) +#endif /* WB_USE_WINDOWS */ +void wb_init(int * +#ifdef WB_USE_MPI + argc +#endif /* WB_USE_MPI */ + , + char *** +#ifdef WB_USE_MPI + argv +#endif /* WB_USE_MPI */ + ) { + if (_initializedQ == wbTrue) { + return; + } +#ifdef WB_USE_MPI + wbMPI_Init(argc, argv); +#endif /* WB_USE_MPI */ + +#ifdef WB_USE_CUDA + CUresult err = cuInit(0); + +/* Select a random GPU */ + +#ifdef WB_USE_MPI + if (rankCount() > 1) { + int deviceCount; + cudaGetDeviceCount(&deviceCount); + srand(time(NULL)); + cudaSetDevice(wbMPI_getRank() % deviceCount); + } else { + int deviceCount; + cudaGetDeviceCount(&deviceCount); + + srand(time(NULL)); + cudaSetDevice(rand() % deviceCount); + } +#else + { + int deviceCount; + cudaGetDeviceCount(&deviceCount); + + srand(time(NULL)); + cudaSetDevice(rand() % deviceCount); + } +#endif /* WB_USE_MPI */ + + cudaDeviceSetLimit(cudaLimitPrintfFifoSize, 1 * MB); + cudaDeviceSetLimit(cudaLimitMallocHeapSize, WB_DEFAULT_HEAP_SIZE); + + cudaDeviceSynchronize(); + +#endif /* WB_USE_CUDA */ + +#ifdef WB_USE_WINDOWS + QueryPerformanceFrequency((LARGE_INTEGER *)&_hrtime_frequency); +#endif /* _MSC_VER */ + + _hrtime(); + + _timer = wbTimer_new(); + _logger = wbLogger_new(); + _initializedQ = wbTrue; + + wbFile_init(); + + solutionJSON = NULL; + +#ifdef WB_USE_MPI + atexit(wbMPI_Exit); +#else /* WB_USE_MPI */ + atexit(wb_atExit); +#endif /* WB_USE_MPI */ +} diff --git a/CUDA_TiledMatrixMultiplication/libwb/wbInit.h b/CUDA_TiledMatrixMultiplication/libwb/wbInit.h new file mode 100644 index 0000000..40e8e1c --- /dev/null +++ b/CUDA_TiledMatrixMultiplication/libwb/wbInit.h @@ -0,0 +1,11 @@ + + +#ifndef __WB_INIT_H__ +#define __WB_INIT_H__ + +#ifndef _MSC_VER +__attribute__((__constructor__)) +#endif /* _MSC_VER */ +void wb_init(int *argc, char ***argv); + +#endif /* __WB_INIT_H__ */ diff --git a/CUDA_TiledMatrixMultiplication/libwb/wbLogger.cpp b/CUDA_TiledMatrixMultiplication/libwb/wbLogger.cpp new file mode 100644 index 0000000..c2e2e17 --- /dev/null +++ b/CUDA_TiledMatrixMultiplication/libwb/wbLogger.cpp @@ -0,0 +1,310 @@ + +#include "wb.h" + +wbLogger_t _logger = NULL; + +static inline wbBool wbLogEntry_hasNext(wbLogEntry_t elem) { + return wbLogEntry_getNext(elem) != NULL; +} + +static inline wbLogEntry_t wbLogEntry_new() { + wbLogEntry_t elem; + + elem = wbNew(struct st_wbLogEntry_t); + + wbLogEntry_setMessage(elem, NULL); + wbLogEntry_setMPIRank(elem, wbMPI_getRank()); + wbLogEntry_setTime(elem, _hrtime()); + + wbLogEntry_setLevel(elem, wbLogLevel_TRACE); + + wbLogEntry_setNext(elem, NULL); + + wbLogEntry_setLine(elem, -1); + wbLogEntry_setFile(elem, NULL); + wbLogEntry_setFunction(elem, NULL); + + return elem; +} + +static inline wbLogEntry_t +wbLogEntry_initialize(wbLogLevel_t level, string msg, const char *file, + const char *fun, int line) { + wbLogEntry_t elem; + + elem = wbLogEntry_new(); + + wbLogEntry_setLevel(elem, level); + + wbLogEntry_setMessage(elem, wbString_duplicate(msg)); + + wbLogEntry_setLine(elem, line); + wbLogEntry_setFile(elem, file); + wbLogEntry_setFunction(elem, fun); + + return elem; +} + +static inline void wbLogEntry_delete(wbLogEntry_t elem) { + if (elem != NULL) { + if (wbLogEntry_getMessage(elem) != NULL) { + wbFree(wbLogEntry_getMessage(elem)); + } + wbDelete(elem); + } + return; +} + +static inline const char *getLevelName(wbLogLevel_t level) { + switch (level) { + case wbLogLevel_unknown: + return "Unknown"; + case wbLogLevel_OFF: + return "Off"; + case wbLogLevel_FATAL: + return "Fatal"; + case wbLogLevel_ERROR: + return "Error"; + case wbLogLevel_WARN: + return "Warn"; + case wbLogLevel_INFO: + return "Info"; + case wbLogLevel_DEBUG: + return "Debug"; + case wbLogLevel_TRACE: + return "Trace"; + } + return NULL; +} + +static inline json11::Json wbLogEntry_toJSONObject(wbLogEntry_t elem) { + json11::Json json = json11::Json::object{ + {"mpi_rank", wbLogEntry_getMPIRank(elem)}, + {"level", getLevelName(wbLogEntry_getLevel(elem))}, + {"file", wbLogEntry_getFile(elem)}, + {"function", wbLogEntry_getFunction(elem)}, + {"line", wbLogEntry_getLine(elem)}, + {"time", wbLogEntry_getTime(elem)}, + {"message", wbLogEntry_getMessage(elem)}, + }; + return json; +} + +static inline string wbLogEntry_toJSON(wbLogEntry_t elem) { + if (elem == NULL) { + return ""; + } else if (WB_USE_JSON11) { + json11::Json json = wbLogEntry_toJSONObject(elem); + return json.string_value(); + } else { + stringstream ss; + + ss << "{\n"; + ss << wbString_quote("mpi_rank") << ":" + << wbString(wbLogEntry_getMPIRank(elem)) << ",\n"; + ss << wbString_quote("level") << ":" + << wbString_quote(getLevelName(wbLogEntry_getLevel(elem))) << ",\n"; + ss << wbString_quote("message") << ":" + << wbString_quote(wbLogEntry_getMessage(elem)) << ",\n"; + ss << wbString_quote("file") << ":" + << wbString_quote(wbLogEntry_getFile(elem)) << ",\n"; + ss << wbString_quote("function") << ":" + << wbString_quote(wbLogEntry_getFunction(elem)) << ",\n"; + ss << wbString_quote("line") << ":" << wbLogEntry_getLine(elem) + << ",\n"; + ss << wbString_quote("time") << ":" << wbLogEntry_getTime(elem) + << "\n"; + ss << "}"; + + return ss.str(); + } + return ""; +} + +static inline string wbLogEntry_toXML(wbLogEntry_t elem) { + if (elem != NULL) { + stringstream ss; + + ss << "\n"; + ss << "" + << "LoggerElement" + << "\n"; + ss << "" << wbLogEntry_getLevel(elem) << "\n"; + ss << "" << wbLogEntry_getMessage(elem) << "\n"; + ss << "" << wbLogEntry_getFile(elem) << "\n"; + ss << "" << wbLogEntry_getFunction(elem) << "\n"; + ss << "" << wbLogEntry_getLine(elem) << "\n"; + ss << "\n"; + ss << "\n"; + + return ss.str(); + } + return ""; +} + +wbLogger_t wbLogger_new() { + wbLogger_t logger; + + logger = wbNew(struct st_wbLogger_t); + + wbLogger_setLength(logger, 0); + wbLogger_setHead(logger, NULL); + + wbLogger_getLevel(logger) = wbLogLevel_TRACE; + + return logger; +} + +static inline void _wbLogger_setLevel(wbLogger_t logger, + wbLogLevel_t level) { + wbLogger_getLevel(logger) = level; +} + +static inline void _wbLogger_setLevel(wbLogLevel_t level) { + _wbLogger_setLevel(_logger, level); +} + +#define wbLogger_setLevel(level) _wbLogger_setLevel(wbLogLevel_##level) + +void wbLogger_clear(wbLogger_t logger) { + if (logger != NULL) { + wbLogEntry_t tmp; + wbLogEntry_t iter; + + iter = wbLogger_getHead(logger); + while (iter != NULL) { + tmp = wbLogEntry_getNext(iter); + wbLogEntry_delete(iter); + iter = tmp; + } + + wbLogger_setLength(logger, 0); + wbLogger_setHead(logger, NULL); + } +} + +void wbLogger_delete(wbLogger_t logger) { + if (logger != NULL) { + wbLogger_clear(logger); + wbDelete(logger); + } + return; +} + +void wbLogger_append(wbLogLevel_t level, string msg, const char *file, + const char *fun, int line) { + wbLogEntry_t elem; + wbLogger_t logger; + + wb_init(NULL, NULL); + + logger = _logger; + + if (wbLogger_getLevel(logger) < level) { + return; + } + + elem = wbLogEntry_initialize(level, msg, file, fun, line); + +#ifdef wbLogger_printOnLog + if (wbLogger_printOnLog) { + if (level <= wbLogger_getLevel(logger) && elem) { + json11::Json json = json11::Json::object{ +#ifndef _MSC_VER //PMO + { "type", "logger" }, { "data", wbLogEntry_toJSONObject(elem) }}; +#else + { "data", wbLogEntry_toJSONObject(elem) }, { "type", "logger" }}; +#endif + std::cout << json.dump() << std::endl; + } + } +#endif /* wbLogger_printOnLog */ + + if (wbLogger_getHead(logger) == NULL) { + wbLogger_setHead(logger, elem); + } else { + wbLogEntry_t prev = wbLogger_getHead(logger); + + while (wbLogEntry_hasNext(prev)) { + prev = wbLogEntry_getNext(prev); + } + wbLogEntry_setNext(prev, elem); + } + +#if 0 + if (level <= wbLogger_getLevel(logger) && elem) { + const char *levelName = getLevelName(level); + + fprintf(stderr, "= LOG: %s: %s (In %s:%s on line %d). =\n", levelName, + wbLogEntry_getMessage(elem), wbLogEntry_getFile(elem), + wbLogEntry_getFunction(elem), wbLogEntry_getLine(elem)); + } +#endif + + wbLogger_incrementLength(logger); + + return; +} + +string wbLogger_toJSON() { + return wbLogger_toJSON(_logger); +} + +static json11::Json wbLogger_toJSONObject(wbLogger_t logger) { + std::vector elems{}; + + if (logger != NULL) { + wbLogEntry_t iter; + stringstream ss; + + for (iter = wbLogger_getHead(logger); iter != NULL; + iter = wbLogEntry_getNext(iter)) { + elems.push_back(wbLogEntry_toJSONObject(iter)); + } + } + return json11::Json(elems); +} + +string wbLogger_toJSON(wbLogger_t logger) { + if (logger != NULL) { + wbLogEntry_t iter; + stringstream ss; + + for (iter = wbLogger_getHead(logger); iter != NULL; + iter = wbLogEntry_getNext(iter)) { + ss << wbLogEntry_toJSON(iter); + if (wbLogEntry_getNext(iter) != NULL) { + ss << ",\n"; + } + } + + return ss.str(); + } + return ""; +} + +string wbLogger_toXML() { + return wbLogger_toXML(_logger); +} + +string wbLogger_toXML(wbLogger_t logger) { + if (logger != NULL) { + wbLogEntry_t iter; + stringstream ss; + + ss << "\n"; + ss << "" + << "Logger" + << "\n"; + ss << "\n"; + for (iter = wbLogger_getHead(logger); iter != NULL; + iter = wbLogEntry_getNext(iter)) { + ss << wbLogEntry_toXML(iter); + } + ss << "\n"; + ss << "\n"; + + return ss.str(); + } + return ""; +} diff --git a/CUDA_TiledMatrixMultiplication/libwb/wbLogger.h b/CUDA_TiledMatrixMultiplication/libwb/wbLogger.h new file mode 100644 index 0000000..b852592 --- /dev/null +++ b/CUDA_TiledMatrixMultiplication/libwb/wbLogger.h @@ -0,0 +1,87 @@ + +#ifndef __WB_LOGGER_H__ +#define __WB_LOGGER_H__ + +#include + +typedef enum en_wbLogLevel_t { + wbLogLevel_unknown = -1, + wbLogLevel_OFF = 0, + wbLogLevel_FATAL, + wbLogLevel_ERROR, + wbLogLevel_WARN, + wbLogLevel_INFO, + wbLogLevel_DEBUG, + wbLogLevel_TRACE +} wbLogLevel_t; + +struct st_wbLogEntry_t { + int line; + int mpiRank; + char *msg; + uint64_t time; + const char *fun; + const char *file; + wbLogLevel_t level; + wbLogEntry_t next; +}; + +struct st_wbLogger_t { + int length; + wbLogEntry_t head; + wbLogLevel_t level; +}; + +#define wbLogEntry_getMessage(elem) ((elem)->msg) +#define wbLogEntry_getMPIRank(elem) ((elem)->mpiRank) +#define wbLogEntry_getTime(elem) ((elem)->time) +#define wbLogEntry_getLevel(elem) ((elem)->level) +#define wbLogEntry_getNext(elem) ((elem)->next) +#define wbLogEntry_getLine(elem) ((elem)->line) +#define wbLogEntry_getFunction(elem) ((elem)->fun) +#define wbLogEntry_getFile(elem) ((elem)->file) + +#define wbLogEntry_setMessage(elem, val) \ + (wbLogEntry_getMessage(elem) = val) +#define wbLogEntry_setMPIRank(elem, val) \ + (wbLogEntry_getMPIRank(elem) = val) +#define wbLogEntry_setTime(elem, val) (wbLogEntry_getTime(elem) = val) +#define wbLogEntry_setLevel(elem, val) (wbLogEntry_getLevel(elem) = val) +#define wbLogEntry_setNext(elem, val) (wbLogEntry_getNext(elem) = val) +#define wbLogEntry_setLine(elem, val) (wbLogEntry_getLine(elem) = val) +#define wbLogEntry_setFunction(elem, val) \ + (wbLogEntry_getFunction(elem) = val) +#define wbLogEntry_setFile(elem, val) (wbLogEntry_getFile(elem) = val) + +#define wbLogger_getLength(log) ((log)->length) +#define wbLogger_getHead(log) ((log)->head) +#define wbLogger_getLevel(log) ((log)->level) + +#define wbLogger_setLength(log, val) (wbLogger_getLength(log) = val) +#define wbLogger_setHead(log, val) (wbLogger_getHead(log) = val) + +#define wbLogger_incrementLength(log) (wbLogger_getLength(log)++) +#define wbLogger_decrementLength(log) (wbLogger_getLength(log)--) + +#define wbLog(level, ...) \ + wbLogger_append(wbLogLevel_##level, wbString(__VA_ARGS__), wbFile, \ + wbFunction, wbLine) + +extern wbLogger_t _logger; + +wbLogger_t wbLogger_new(); + +void wbLogger_clear(wbLogger_t logger); + +void wbLogger_delete(wbLogger_t logger); + +void wbLogger_append(wbLogLevel_t level, string msg, const char *file, + const char *fun, int line); + +string wbLogger_toXML(wbLogger_t logger); +string wbLogger_toXML(); + +string wbLogger_toJSON(wbLogger_t logger); +string wbLogger_toJSON(); + +#endif /* __WB_LOGGER_H__ */ diff --git a/CUDA_TiledMatrixMultiplication/libwb/wbMD5.h b/CUDA_TiledMatrixMultiplication/libwb/wbMD5.h new file mode 100644 index 0000000..e83a8ef --- /dev/null +++ b/CUDA_TiledMatrixMultiplication/libwb/wbMD5.h @@ -0,0 +1,311 @@ + +/* + * This code implements the MD5 message-digest algorithm. + * The algorithm is due to Ron Rivest. This code was + * written by Colin Plumb in 1993, no copyright is claimed. + * This code is in the public domain; do with it what you wish. + * + * Equivalent code is available from RSA Data Security, Inc. + * This code has been tested against that, and is equivalent, + * except that you don't need to include two pages of legalese + * with every copy. + * + * To compute the message digest of a chunk of bytes, declare an + * MD5Context structure, pass it to MD5Init, call MD5Update as + * needed on buffers full of bytes, and then call MD5Final, which + * will fill a supplied 16-byte array with the digest. + * + * Changed so as no longer to depend on Colin Plumb's `usual.h' header + * definitions; now uses stuff from dpkg's config.h. + * - Ian Jackson . + * Still in the public domain. + */ + +#ifndef __WB_MD5_H__ +#define __WB_MD5_H__ + +#include /* for memcpy() */ +#include /* for stupid systems */ + +#define UWORD32 unsigned int + +#define md5byte unsigned char + +struct MD5Context { + UWORD32 buf[4]; + UWORD32 bytes[2]; + UWORD32 in[16]; +}; + +static void MD5Transform(UWORD32 buf[4], UWORD32 const in[16]); + +static int g_bigEndian = 0; +static int g_endianessDetected = 0; + +static void detectEndianess() { + int nl = 0x12345678; + short ns = 0x1234; + + unsigned char *p = (unsigned char *)(&nl); + unsigned char *sp = (unsigned char *)(&ns); + + if (g_endianessDetected) + return; + if (p[0] == 0x12 && p[1] == 0x34 && p[2] == 0x56 && p[3] == 0x78) { + g_bigEndian = 1; + } else if (p[0] == 0x78 && p[1] == 0x56 && p[2] == 0x34 && + p[3] == 0x12) { + g_bigEndian = 0; + } else { + g_bigEndian = *sp != 0x12; + } + + g_endianessDetected = 1; +} + +static void byteSwap(UWORD32 *buf, unsigned words) { + md5byte *p; + + if (!g_bigEndian) + return; + + p = (md5byte *)buf; + + do { + *buf++ = (UWORD32)((unsigned)p[3] << 8 | p[2]) << 16 | + ((unsigned)p[1] << 8 | p[0]); + p += 4; + } while (--words); +} + +/* + * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious + * initialization constants. + */ +static void MD5Init(struct MD5Context *ctx) { + detectEndianess(); + + ctx->buf[0] = 0x67452301; + ctx->buf[1] = 0xefcdab89; + ctx->buf[2] = 0x98badcfe; + ctx->buf[3] = 0x10325476; + + ctx->bytes[0] = 0; + ctx->bytes[1] = 0; +} + +/* + * Update context to reflect the concatenation of another buffer full + * of bytes. + */ +static void MD5Update(struct MD5Context *ctx, md5byte const *buf, + unsigned len) { + UWORD32 t; + + /* Update byte count */ + + t = ctx->bytes[0]; + if ((ctx->bytes[0] = t + len) < t) + ctx->bytes[1]++; /* Carry from low to high */ + + t = 64 - (t & 0x3f); /* Space available in ctx->in (at least 1) */ + if (t > len) { + memcpy((md5byte *)ctx->in + 64 - t, buf, len); + return; + } + /* First chunk is an odd size */ + memcpy((md5byte *)ctx->in + 64 - t, buf, t); + byteSwap(ctx->in, 16); + MD5Transform(ctx->buf, ctx->in); + buf += t; + len -= t; + + /* Process data in 64-byte chunks */ + while (len >= 64) { + memcpy(ctx->in, buf, 64); + byteSwap(ctx->in, 16); + MD5Transform(ctx->buf, ctx->in); + buf += 64; + len -= 64; + } + + /* Handle any remaining bytes of data. */ + memcpy(ctx->in, buf, len); +} + +/* + * Final wrapup - pad to 64-byte boundary with the bit pattern + * 1 0* (64-bit count of bits processed, MSB-first) + */ +static void MD5Final(md5byte digest[16], struct MD5Context *ctx) { + int count = ctx->bytes[0] & 0x3f; /* Number of bytes in ctx->in */ + md5byte *p = (md5byte *)ctx->in + count; + + /* Set the first char of padding to 0x80. There is always room. */ + *p++ = 0x80; + + /* Bytes of padding needed to make 56 bytes (-8..55) */ + count = 56 - 1 - count; + + if (count < 0) { /* Padding forces an extra block */ + memset(p, 0, count + 8); + byteSwap(ctx->in, 16); + MD5Transform(ctx->buf, ctx->in); + p = (md5byte *)ctx->in; + count = 56; + } + memset(p, 0, count); + byteSwap(ctx->in, 14); + + /* Append length in bits and transform */ + ctx->in[14] = ctx->bytes[0] << 3; + ctx->in[15] = ctx->bytes[1] << 3 | ctx->bytes[0] >> 29; + MD5Transform(ctx->buf, ctx->in); + + byteSwap(ctx->buf, 4); + memcpy(digest, ctx->buf, 16); + memset(&ctx, 0, sizeof(ctx)); /* In case it's sensitive */ +} + +#ifndef ASM_MD5 + +/* The four core functions - F1 is optimized somewhat */ + +/* #define F1(x, y, z) (x & y | ~x & z) */ +#define F1(x, y, z) (z ^ (x & (y ^ z))) +#define F2(x, y, z) F1(z, x, y) +#define F3(x, y, z) (x ^ y ^ z) +#define F4(x, y, z) (y ^ (x | ~z)) + +/* This is the central step in the MD5 algorithm. */ +#define MD5STEP(f, w, x, y, z, in, s) \ + (w += f(x, y, z) + in, w = (w << s | w >> (32 - s)) + x) + +/* + * The core of the MD5 algorithm, this alters an existing MD5 hash to + * reflect the addition of 16 longwords of new data. MD5Update blocks + * the data and converts bytes into longwords for this routine. + */ +static void MD5Transform(UWORD32 buf[4], UWORD32 const in[16]) { + UWORD32 a, b, c, d; + + a = buf[0]; + b = buf[1]; + c = buf[2]; + d = buf[3]; + + MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); + MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); + MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); + MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); + MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); + MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); + MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); + MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); + MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); + MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); + MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); + MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); + MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); + MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); + MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); + MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); + + MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); + MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); + MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); + MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); + MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); + MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); + MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); + MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); + MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); + MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); + MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); + MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); + MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); + MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); + MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); + MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); + + MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); + MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); + MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); + MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); + MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); + MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); + MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); + MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); + MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); + MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); + MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); + MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); + MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); + MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); + MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); + MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); + + MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); + MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); + MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); + MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); + MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); + MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); + MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); + MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); + MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); + MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); + MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); + MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); + MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); + MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); + MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); + MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} + +#endif + +static void MD5_buffer(const unsigned char *buf, unsigned int len, + unsigned char sig[16]) { + struct MD5Context md5; + MD5Init(&md5); + MD5Update(&md5, buf, len); + MD5Final(sig, &md5); +} + +#define wbMD5 MD5_buffer + +#define HEX_STRING "0123456789abcdef" /* to convert to hex */ + +static void wbMD5_sigToString(unsigned char signature[16], char *str, + int len) { + unsigned char *sig_p; + char *str_p, *max_p; + unsigned int high, low; + + str_p = str; + max_p = str + len; + + for (sig_p = (unsigned char *)signature; + sig_p < (unsigned char *)signature + 16; sig_p++) { + high = *sig_p / 16; + low = *sig_p % 16; + /* account for 2 chars */ + if (str_p + 1 >= max_p) { + break; + } + *str_p++ = HEX_STRING[high]; + *str_p++ = HEX_STRING[low]; + } + /* account for 2 chars */ + if (str_p < max_p) { + *str_p++ = '\0'; + } +} + +#endif /* __WB_MD5_H__ */ diff --git a/CUDA_TiledMatrixMultiplication/libwb/wbMPI.cpp b/CUDA_TiledMatrixMultiplication/libwb/wbMPI.cpp new file mode 100644 index 0000000..546c1ed --- /dev/null +++ b/CUDA_TiledMatrixMultiplication/libwb/wbMPI.cpp @@ -0,0 +1,75 @@ + +#ifdef WB_USE_MPI + +#include +#include +#include +#include "wb.h" + +static int rank = -1; + +int wbMPI_getRank() { + if (rank != -1) { + return rank; + } + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + return rank; +} + +int rankCount() { + int nRanks; + MPI_Comm_size(MPI_COMM_WORLD, &nRanks); + return nRanks; +} + +const char *wbMPI_getStringFromRank(int rank, int tag) { + if (isMasterQ) { + char *buf; + int bufSize; + MPI_Recv(&bufSize, 1, MPI_INT, rank, tag, MPI_COMM_WORLD, + MPI_STATUS_IGNORE); + buf = (char *)calloc(bufSize, sizeof(char)); + MPI_Recv(buf, bufSize, MPI_CHAR, rank, tag, MPI_COMM_WORLD, + MPI_STATUS_IGNORE); + return buf; + } + + return NULL; +} +void wbMPI_sendStringToMaster(const char *str, int tag) { + if (!isMasterQ) { + // we are going to send the string to the master + int len = (int)strlen(str) + 1; + MPI_Send(&len, 1, MPI_INT, 0, tag, MPI_COMM_WORLD); + MPI_Send((void *)str, len, MPI_CHAR, 0, tag, MPI_COMM_WORLD); + } + + return; +} + +int wbMPI_Init(int *argc, char ***argv) { + int err = MPI_SUCCESS; + err = MPI_Init(argc, argv); + // printf("argc = %d\n", *argc); + // err = MPI_Init(NULL, NULL); + // printf("rank = %d is master = %d\n", wbMPI_getRank(), isMasterQ); + // MPI_Barrier(MPI_COMM_WORLD); + return err; +} + +bool finalizedQ = false; + +extern "C" int wbMPI_Finalize(void) { + if (finalizedQ) { + return MPI_SUCCESS; + } + finalizedQ = true; + wb_atExit(); + return MPI_Finalize(); +} +extern "C" void wbMPI_Exit(void) { + wbMPI_Finalize(); + return; +} + +#endif /* WB_USE_MPI */ diff --git a/CUDA_TiledMatrixMultiplication/libwb/wbMPI.h b/CUDA_TiledMatrixMultiplication/libwb/wbMPI.h new file mode 100644 index 0000000..6275eaf --- /dev/null +++ b/CUDA_TiledMatrixMultiplication/libwb/wbMPI.h @@ -0,0 +1,37 @@ + +#ifndef __WB_MPI_H__ +#define __WB_MPI_H__ + +#ifdef WB_USE_MPI + +#include +#include +#include + +#define isMasterQ ((wbMPI_getRank()) == 0) + +extern int wbMPI_getRank(); + +extern int rankCount(); + +extern const char *wbMPI_getStringFromRank(int rank, int tag); +extern void wbMPI_sendStringToMaster(const char *str, int tag); + +extern int wbMPI_Init(int *argc, char ***argv); + +extern bool finalizedQ; + +extern "C" int wbMPI_Finalize(void); +extern "C" void wbMPI_Exit(void); + +#define MPI_Finalize wbMPI_Finalize + +#else /* WB_USE_MPI */ +static inline int rankCount() { + return 1; +} +static inline int wbMPI_getRank() { + return 0; +} +#endif /* WB_USE_MPI */ +#endif /* __WB_MPI_H__ */ diff --git a/CUDA_TiledMatrixMultiplication/libwb/wbMalloc.h b/CUDA_TiledMatrixMultiplication/libwb/wbMalloc.h new file mode 100644 index 0000000..5d74be4 --- /dev/null +++ b/CUDA_TiledMatrixMultiplication/libwb/wbMalloc.h @@ -0,0 +1,140 @@ + + +#ifndef __WB_MALLOC_H__ +#define __WB_MALLOC_H__ + +#ifdef WB_USE_CUSTOM_MALLOC +#ifdef __linux__ +#define THROW __THROW +#else +#define THROW +#endif + +static inline void *_malloc(size_t size) THROW { + if (size == 0) { + return NULL; + } else { + int err; + void *res = memmgr_alloc((ulong)size, &err); + if (err) { + fprintf(stderr, "<>:: Memory allocation failed\n"); + exit(1); + } else { + size_t ii = 0; + unsigned char *p = (unsigned char *)res; + while (ii++ < size) { + *p++ = 0; + } + return res; + } + } +} + +static inline void _free(void *ptr) THROW { + if (ptr != NULL) { + memmgr_free(ptr); + } +} + +static inline void *_calloc(size_t nmemb, size_t size) THROW { + return _malloc(nmemb * size); +} + +static inline void *_realloc(void *ptr, size_t size) THROW { + if (size == 0) { + free(ptr); + return NULL; + } else if (ptr == NULL) { + return malloc(size); + } else { + void *buf; + unsigned char *dst; + unsigned char *src; + size_t alloc_size, to_copy, i = 0; + + // Allocate new buffer + buf = malloc(size); + + if (buf != 0) { + // Find original allocation size + alloc_size = (size_t)memmgr_get_block_size(ptr); + to_copy = alloc_size; + if (to_copy > size) { + to_copy = size; + } + + // Copy data to new buffer + dst = (unsigned char *)buf; + src = (unsigned char *)ptr; + while (i++ < to_copy) { + *dst++ = *src++; + } + + // Free the old buffer + free(ptr); + } + + return buf; + } +} + +#define wbNew(type) ((type *)_malloc(sizeof(type))) +#define wbNewArray(type, len) ((type *)_malloc((len) * sizeof(type))) +#define wbMalloc(sz) _malloc(sz) +#define wbDelete(var) \ + _free(var); \ + var = NULL +#define wbFree(var) \ + _free(var); \ + var = NULL +#define wbRealloc(var, newSize) _realloc(var, newSize) +#define wbReallocArray(t, m, n) ((t *)_realloc(m, n * sizeof(t))) + +#define free _free +#define malloc _malloc +#define calloc _calloc +#define realloc _realloc + +#else /* WB_USE_CUSTOM_MALLOC */ + +static inline void *xMalloc(size_t sz) { + void *mem = NULL; + if (sz != 0) { + mem = malloc(sz); + } + return mem; +} + +static inline void xFree(void *mem) { + if (mem != NULL) { + free(mem); + } + return; +} + +static inline void *xRealloc(void *mem, size_t sz) { + if (mem == NULL) { + return NULL; + } else if (sz == 0) { + xFree(mem); + return NULL; + } else { + void *res = realloc(mem, sz); + wbAssert(res != NULL); + return res; + } +} + +#define wbNew(type) ((type *)wbMalloc(sizeof(type))) +#define wbNewArray(type, len) ((type *)wbMalloc((len) * sizeof(type))) +#define wbMalloc(sz) xMalloc(sz) +#define wbDelete(var) wbFree(var) +#define wbFree(var) \ + xFree(var); \ + var = NULL +#define wbRealloc(var, newSize) xRealloc(var, newSize) +#define wbReallocArray(t, m, n) ((t *)xRealloc(m, n * sizeof(t))) + +#endif /* WB_USE_CUSTOM_MALLOC */ + +#endif /* __WB_MALLOC_H__ */ diff --git a/CUDA_TiledMatrixMultiplication/libwb/wbPPM.cpp b/CUDA_TiledMatrixMultiplication/libwb/wbPPM.cpp new file mode 100644 index 0000000..86ab208 --- /dev/null +++ b/CUDA_TiledMatrixMultiplication/libwb/wbPPM.cpp @@ -0,0 +1,199 @@ + +#include +#include "wb.h" + +static inline float _min(float x, float y) { + return x < y ? x : y; +} + +static inline float _max(float x, float y) { + return x > y ? x : y; +} + +static inline float _clamp(float x, float start, float end) { + return _min(_max(x, start), end); +} + +static const char *skipSpaces(const char *line) { + while (*line == ' ' || *line == '\t') { + line++; + if (*line == '\0') { + break; + } + } + return line; +} + +static char nextNonSpaceChar(const char *line0) { + const char *line = skipSpaces(line0); + return *line; +} + +static wbBool isComment(const char *line) { + char nextChar = nextNonSpaceChar(line); + if (nextChar == '\0') { + return wbTrue; + } else { + return nextChar == '#'; + } +} + +static void parseDimensions(const char *line0, int *width, int *height) { + const char *line = skipSpaces(line0); + sscanf(line, "%d %d", width, height); +} + +static void parseDimensions(const char *line0, int *width, int *height, + int *channels) { + const char *line = skipSpaces(line0); + sscanf(line, "%d %d %d", width, height, channels); +} + +static void parseDepth(const char *line0, int *depth) { + const char *line = skipSpaces(line0); + sscanf(line, "%d", depth); +} + +static char *nextLine(wbFile_t file) { + char *line = NULL; + while ((line = wbFile_readLine(file)) != NULL) { + if (!isComment(line)) { + break; + } + } + return line; +} + +wbImage_t wbPPM_import(const char *filename) { + wbImage_t img; + wbFile_t file; + char *header; + char *line; + int ii, jj, kk, channels; + int width, height, depth; + unsigned char *charData, *charIter; + float *imgData, *floatIter; + float scale; + + img = NULL; + + file = wbFile_open(filename, "rb"); + if (file == NULL) { + printf("Could not open %s\n", filename); + goto cleanup; + } + + header = wbFile_readLine(file); + if (header == NULL) { + printf("Could not read from %s\n", filename); + goto cleanup; + } else if (strcmp(header, "P6") != 0 && strcmp(header, "P6\n") != 0 && + strcmp(header, "P5") != 0 && strcmp(header, "P5\n") != 0 && + strcmp(header, "S6") != 0 && strcmp(header, "S6\n") != 0) { + printf("Could find magic number for %s\n", filename); + goto cleanup; + } + + // P5 are monochrome while P6/S6 are rgb + // S6 needs to parse number of channels out of file + if (strcmp(header, "P5") == 0 || strcmp(header, "P5\n") == 0) { + channels = 1; + line = nextLine(file); + parseDimensions(line, &width, &height); + } else if (strcmp(header, "P6") == 0 || strcmp(header, "P6\n") == 0) { + channels = 3; + line = nextLine(file); + parseDimensions(line, &width, &height); + } else { + line = nextLine(file); + parseDimensions(line, &width, &height, &channels); + } + + // the line now contains the depth information + line = nextLine(file); + parseDepth(line, &depth); + + // the rest of the lines contain the data in binary format + charData = (unsigned char *)wbFile_read( + file, width * channels * sizeof(unsigned char), height); + + img = wbImage_new(width, height, channels); + + imgData = wbImage_getData(img); + + charIter = charData; + floatIter = imgData; + + scale = 1.0f / ((float)depth); + + for (ii = 0; ii < height; ii++) { + for (jj = 0; jj < width; jj++) { + for (kk = 0; kk < channels; kk++) { + *floatIter = ((float)*charIter) * scale; + floatIter++; + charIter++; + } + } + } + +#ifdef LAZY_FILE_LOAD + wbDelete(charData); +#endif + +cleanup: + wbFile_close(file); + return img; +} + +void wbPPM_export(const char *filename, wbImage_t img) { + int ii; + int jj; + int kk; + int depth; + int width; + int height; + int channels; + wbFile_t file; + float *floatIter; + unsigned char *charData; + unsigned char *charIter; + + file = wbFile_open(filename, "wb+"); + + width = wbImage_getWidth(img); + height = wbImage_getHeight(img); + channels = wbImage_getChannels(img); + depth = 255; + + if (channels == 1) { + wbFile_writeLine(file, "P5"); + } else { + wbFile_writeLine(file, "P6"); + } + wbFile_writeLine(file, "#Created via wbPPM Export"); + wbFile_writeLine(file, wbString(width, " ", height)); + wbFile_writeLine(file, wbString(depth)); + + charData = wbNewArray(unsigned char, width *height *channels); + + charIter = charData; + floatIter = wbImage_getData(img); + + for (ii = 0; ii < height; ii++) { + for (jj = 0; jj < width; jj++) { + for (kk = 0; kk < channels; kk++) { + *charIter = (unsigned char)ceil(_clamp(*floatIter, 0, 1) * depth); + floatIter++; + charIter++; + } + } + } + + wbFile_write(file, charData, width * channels * sizeof(unsigned char), + height); + + wbDelete(charData); + wbFile_delete(file); + + return; +} diff --git a/CUDA_TiledMatrixMultiplication/libwb/wbPPM.h b/CUDA_TiledMatrixMultiplication/libwb/wbPPM.h new file mode 100644 index 0000000..d589b36 --- /dev/null +++ b/CUDA_TiledMatrixMultiplication/libwb/wbPPM.h @@ -0,0 +1,11 @@ + + +#ifndef __wbPPM_H__ +#define __wbPPM_H__ + +START_EXTERN_C +wbImage_t wbPPM_import(const char *filename); +void wbPPM_export(const char *filename, wbImage_t img); +END_EXTERN_C + +#endif /* __wbPPM_H__ */ diff --git a/CUDA_TiledMatrixMultiplication/libwb/wbPath.cpp b/CUDA_TiledMatrixMultiplication/libwb/wbPath.cpp new file mode 100644 index 0000000..0d93e2b --- /dev/null +++ b/CUDA_TiledMatrixMultiplication/libwb/wbPath.cpp @@ -0,0 +1,42 @@ +#include "wb.h" + +char *wbPath_join(const char *p1, const char *p2) { + size_t s1 = strlen(p1); + size_t s2 = strlen(p2); + char *res = + wbNewArray(char, s1 + 1 /* seperator */ + s2 + 1 /* terminator */); + memcpy(res, p1, s1); + char *iter = res + s1; + *iter++ = wbDirectorySeperator; + memcpy(iter, p2, s2); + iter += s2; + *iter = '\0'; + return res; +} + +char *wbPath_join(const char *p1, const char *p2, const char *p3) { + char *p12 = wbPath_join(p1, p2); + char *res = wbPath_join(p12, p3); + wbDelete(p12); + return res; +} + +char *wbPath_join(const char *p1, const char *p2, const char *p3, + const char *p4) { + char *p123 = wbPath_join(p1, p2, p3); + char *res = wbPath_join(p123, p4); + wbDelete(p123); + return res; +} + +char *wbPath_join(const std::string &p1, const std::string &p2) { + return wbPath_join(p1.c_str(), p2.c_str()); +} +char *wbPath_join(const std::string &p1, const std::string &p2, + const std::string &p3) { + return wbPath_join(p1.c_str(), p2.c_str(), p3.c_str()); +} +char *wbPath_join(const std::string &p1, const std::string &p2, + const std::string &p3, const std::string &p4) { + return wbPath_join(p1.c_str(), p2.c_str(), p3.c_str(), p4.c_str()); +} \ No newline at end of file diff --git a/CUDA_TiledMatrixMultiplication/libwb/wbPath.h b/CUDA_TiledMatrixMultiplication/libwb/wbPath.h new file mode 100644 index 0000000..0dd3187 --- /dev/null +++ b/CUDA_TiledMatrixMultiplication/libwb/wbPath.h @@ -0,0 +1,30 @@ +#ifndef __WB_PATH_H__ +#define __WB_PATH_H__ + +char *wbPath_join(const char *p1, const char *p2); +char *wbPath_join(const char *p1, const char *p2, const char *p3); +char *wbPath_join(const char *p1, const char *p2, const char *p3, + const char *p4); + +char *wbPath_join(const std::string &p1, const std::string &p2); +char *wbPath_join(const std::string &p1, const std::string &p2, + const std::string &p3); +char *wbPath_join(const std::string &p1, const std::string &p2, + const std::string &p3, const std::string &p4); + +template +static char *wbPath_join(const T1 &p1, const T2 &p2) { + return wbPath_join(wbString(p1), wbString(p2)); +} +template +static char *wbPath_join(const T1 &p1, const T2 &p2, const T3 &p3) { + return wbPath_join(wbString(p1), wbString(p2), wbString(p3)); +} +template +static char *wbPath_join(const T1 &p1, const T2 &p2, const T3 &p3, + const T4 &p4) { + return wbPath_join(wbString(p1), wbString(p2), wbString(p3), + wbString(p4)); +} + +#endif /* __WB_PATH_H__ */ diff --git a/CUDA_TiledMatrixMultiplication/libwb/wbSolution.cpp b/CUDA_TiledMatrixMultiplication/libwb/wbSolution.cpp new file mode 100644 index 0000000..703f410 --- /dev/null +++ b/CUDA_TiledMatrixMultiplication/libwb/wbSolution.cpp @@ -0,0 +1,271 @@ + +#include "wb.h" + +char *solutionJSON = NULL; +static string _solution_correctQ(""); + +static void _onUnsameImageFunction(string str) { + _solution_correctQ = str; +} + +template +static wbBool wbSolution_listCorrectQ(const char *expectedOutputFile, + wbSolution_t sol, const char *type) { + wbBool res; + T *expectedData; + int expectedRows, expectedColumns; + + expectedData = (T *)wbImport(expectedOutputFile, &expectedRows, + &expectedColumns, type); + + if (expectedData == NULL) { + _solution_correctQ = "Failed to open expected output file."; + res = wbFalse; + } else if (expectedRows != wbSolution_getRows(sol)) { + wbLog(TRACE, "Number of rows in the solution is ", + wbSolution_getRows(sol), ". Expected number of rows is ", + expectedRows, "."); + _solution_correctQ = + "The number of rows in the solution did not match " + "that of the expected results."; + res = wbFalse; + } else if (expectedColumns != wbSolution_getColumns(sol)) { + wbLog(TRACE, "Number of columns in the solution is ", + wbSolution_getColumns(sol), ". Expected number of columns is ", + expectedColumns, "."); + _solution_correctQ = "The number of columns in the solution did not " + "match that of the expected results."; + res = wbFalse; + } else { + int ii, jj, idx; + T *solutionData; + + solutionData = (T *)wbSolution_getData(sol); + + for (ii = 0; ii < expectedRows; ii++) { + for (jj = 0; jj < expectedColumns; jj++) { + idx = ii * expectedColumns + jj; + if (wbUnequalQ(expectedData[idx], solutionData[idx])) { + string str; + if (expectedColumns == 1) { + str = wbString( + "The solution did not match the expected results at row ", + ii, ". Expecting ", expectedData[idx], " but got ", + solutionData[idx], "."); + } else { + str = wbString("The solution did not match the expected " + "results at column ", + jj, " and row ", ii, ". Expecting ", + expectedData[idx], " but got ", + solutionData[idx], "."); + } + _solution_correctQ = str; + res = wbFalse; + goto matrixCleanup; + } + } + } + + res = wbTrue; + matrixCleanup: + if (expectedData != NULL) { + wbFree(expectedData); + } + } + return res; +} + +static wbBool wbSolution_correctQ(char *expectedOutputFile, + wbSolution_t sol) { + if (expectedOutputFile == NULL) { + _solution_correctQ = "Failed to determined the expected output file."; + return wbFalse; + } else if (!wbFile_existsQ(expectedOutputFile)) { + _solution_correctQ = + wbString("The file ", expectedOutputFile, " does not exist."); + return wbFalse; + } else if (wbString_sameQ(wbSolution_getType(sol), "image")) { + wbBool res; + wbImage_t solutionImage = NULL; + wbImage_t expectedImage = wbImport(expectedOutputFile); + if (expectedImage == NULL) { + _solution_correctQ = "Failed to open expected output file."; + res = wbFalse; + } else if (wbImage_getWidth(expectedImage) != + wbSolution_getWidth(sol)) { + _solution_correctQ = + "The image width of the expected image does not " + "match that of the solution."; + res = wbFalse; + } else if (wbImage_getHeight(expectedImage) != + wbSolution_getHeight(sol)) { + _solution_correctQ = + "The image height of the expected image does not " + "match that of the solution."; + res = wbFalse; + } else if (wbImage_getChannels(expectedImage) != + wbSolution_getChannels(sol)) { + _solution_correctQ = + "The image channels of the expected image does not " + "match that of the solution."; + res = wbFalse; + } else { + solutionImage = (wbImage_t)wbSolution_getData(sol); + wbAssert(solutionImage != NULL); + res = wbImage_sameQ(solutionImage, expectedImage, + _onUnsameImageFunction); + } + if (expectedImage != NULL) { + wbImage_delete(expectedImage); + } + return res; + } else if (wbString_sameQ(wbSolution_getType(sol), "histogram")) { + return wbSolution_listCorrectQ(expectedOutputFile, sol, + "Integer"); + } else if (wbString_sameQ(wbSolution_getType(sol), "integral_vector")) { + return wbSolution_listCorrectQ(expectedOutputFile, sol, + "Integer"); + } else if (wbString_sameQ(wbSolution_getType(sol), "vector") || + wbString_sameQ(wbSolution_getType(sol), "matrix")) { + return wbSolution_listCorrectQ(expectedOutputFile, sol, + "Real"); + } else { + wbAssert(wbFalse); + return wbFalse; + } +} + +wbBool wbSolution(char *expectedOutputFile, char *outputFile, char *type0, + void *data, int rows, int columns, int depth) { + char *type; + wbBool res; + wbSolution_t sol; + + if (expectedOutputFile == NULL || data == NULL || type0 == NULL) { + wbLog(ERROR, "Failed to grade solution"); + return wbFalse; + } + + type = wbString_toLower(type0); + + if (_solution_correctQ != "") { + _solution_correctQ = ""; + } + + wbSolution_setOutputFile(sol, outputFile); + wbSolution_setType(sol, type); + wbSolution_setData(sol, data); + wbSolution_setRows(sol, rows); + wbSolution_setColumns(sol, columns); + wbSolution_setDepth(sol, depth); + + res = wbSolution_correctQ(expectedOutputFile, sol); + + if (outputFile != NULL) { + if (wbString_sameQ(type, "image")) { + wbImage_t inputImage = (wbImage_t)data; + wbImage_t img = wbImage_new(wbImage_getWidth(inputImage), + wbImage_getHeight(inputImage), + wbImage_getChannels(inputImage)); + memcpy(wbImage_getData(img), wbImage_getData(inputImage), + rows * columns * wbImage_channels * sizeof(wbReal_t)); + wbExport(outputFile, img); + wbImage_delete(img); + } else if (wbString_sameQ(type, "integral_vector")) { + wbExport(outputFile, (int *)data, rows, columns); + } else if (wbString_sameQ(type, "vector") || + wbString_sameQ(type, "matrix")) { + wbExport(outputFile, (wbReal_t *)data, rows, columns); + } else if (wbString_sameQ(type, "histogram")) { + wbExport(outputFile, (unsigned char *)data, rows, columns); + } else if (wbString_sameQ(type, "text")) { + wbExport_text(outputFile, (unsigned char *)data, rows * columns); + } + } + + wbFree(type); + + return res; +} + +wbBool wbSolution(char *expectedOutputFile, char *outputFile, char *type0, + void *data, int rows, int columns) { + return wbSolution(expectedOutputFile, outputFile, type0, data, rows, + columns, 1); +} + +wbBool wbSolution(wbArg_t arg, void *data, int rows, int columns, + int depth) { + char *type; + wbBool res; + char *expectedOutputFile; + char *outputFile; + stringstream ss; + + expectedOutputFile = wbArg_getExpectedOutputFile(arg); + outputFile = wbArg_getOutputFile(arg); + type = wbArg_getType(arg); + + wbAssert(type != NULL); + wbAssert(expectedOutputFile != NULL); + wbAssert(outputFile != NULL); + + res = wbSolution(expectedOutputFile, outputFile, type, data, rows, + columns, depth); + + if (WB_USE_JSON11) { + json11::Json json; + if (res) { + json = json11::Json::object{{"correctq", true}, + {"message", "The solution is correct"}}; + } else { + json = json11::Json::object{{"correctq", false}, + {"message", _solution_correctQ}}; + } + +#ifdef wbLogger_printOnLog + if (wbLogger_printOnLog) { + json11::Json e = +//PMO +#ifndef _MSC_VER + json11::Json::object{{"type", "solution"}, {"data", json}}; +#else + json11::Json::object{{"data", json }, {"type", "solution" }}; +#endif + std::cout << e.dump() << std::endl; + } +#endif /* wbLogger_printOnLog */ + + solutionJSON = wbString_duplicate(json.string_value()); + } else { + if (res) { + ss << "{\n"; + ss << wbString_quote("correctq") << ": true,\n"; + ss << wbString_quote("message") << ": " + << wbString_quote("Solution is correct.") << "\n"; + ss << "}"; + } else { + ss << "{\n"; + ss << wbString_quote("correctq") << ": false,\n"; + ss << wbString_quote("message") << ": " + << wbString_quote(_solution_correctQ) << "\n"; + ss << "}"; + } + solutionJSON = wbString_duplicate(ss.str()); + } + + return res; +} + +wbBool wbSolution(wbArg_t arg, void *data, int rows, int columns) { + return wbSolution(arg, data, rows, columns, 1); +} + +EXTERN_C wbBool wbSolution(wbArg_t arg, void *data, int rows) { + return wbSolution(arg, data, rows, 1); +} + +wbBool wbSolution(wbArg_t arg, wbImage_t img) { + return wbSolution(arg, img, wbImage_getHeight(img), + wbImage_getWidth(img), wbImage_getChannels(img)); +} diff --git a/CUDA_TiledMatrixMultiplication/libwb/wbSolution.h b/CUDA_TiledMatrixMultiplication/libwb/wbSolution.h new file mode 100644 index 0000000..f18d07d --- /dev/null +++ b/CUDA_TiledMatrixMultiplication/libwb/wbSolution.h @@ -0,0 +1,40 @@ + + +#ifndef __WB_SOLUTION_H__ +#define __WB_SOLUTION_H__ + +typedef struct st_wbSolution_t { + char *type; + char *outputFile; + void *data; + int rows; + int columns; + int depth; +} wbSolution_t; + +#define wbSolution_getType(sol) ((sol).type) +#define wbSolution_getOutputFile(sol) ((sol).outputFile) +#define wbSolution_getData(sol) ((sol).data) +#define wbSolution_getRows(sol) ((sol).rows) +#define wbSolution_getColumns(sol) ((sol).columns) +#define wbSolution_getDepth(sol) ((sol).depth) + +#define wbSolution_getHeight wbSolution_getRows +#define wbSolution_getWidth wbSolution_getColumns +#define wbSolution_getChannels wbSolution_getDepth + +#define wbSolution_setType(sol, val) (wbSolution_getType(sol) = val) +#define wbSolution_setOutputFile(sol, val) \ + (wbSolution_getOutputFile(sol) = val) +#define wbSolution_setData(sol, val) (wbSolution_getData(sol) = val) +#define wbSolution_setRows(sol, val) (wbSolution_getRows(sol) = val) +#define wbSolution_setColumns(sol, val) (wbSolution_getColumns(sol) = val) +#define wbSolution_setDepth(sol, val) (wbSolution_getDepth(sol) = val) + +wbBool wbSolution(char *expectedOutputFile, char *outputFile, char *type0, + void *data, int rows, int columns); +wbBool wbSolution(wbArg_t arg, void *data, int rows, int columns); +EXTERN_C wbBool wbSolution(wbArg_t arg, void *data, int rows); +wbBool wbSolution(wbArg_t arg, wbImage_t img); + +#endif /* __WB_SOLUTION_H__ */ diff --git a/CUDA_TiledMatrixMultiplication/libwb/wbSparse.cpp b/CUDA_TiledMatrixMultiplication/libwb/wbSparse.cpp new file mode 100644 index 0000000..9cdcba3 --- /dev/null +++ b/CUDA_TiledMatrixMultiplication/libwb/wbSparse.cpp @@ -0,0 +1,82 @@ + +#include "wb.h" + +static void sort(int *data, int *key, int start, int end) { + if ((end - start + 1) > 1) { + int left = start, right = end; + int pivot = key[right]; + while (left <= right) { + while (key[left] > pivot) { + left = left + 1; + } + while (key[right] < pivot) { + right = right - 1; + } + if (left <= right) { + int tmp = key[left]; + key[left] = key[right]; + key[right] = tmp; + tmp = data[left]; + data[left] = data[right]; + data[right] = tmp; + left = left + 1; + right = right - 1; + } + } + sort(data, key, start, right); + sort(data, key, left, end); + } +} + +EXTERN_C void CSRToJDS(int dim, int *csrRowPtr, int *csrColIdx, + float *csrData, int **jdsRowPerm, int **jdsRowNNZ, + int **jdsColStartIdx, int **jdsColIdx, + float **jdsData) { + // Row Permutation Vector + *jdsRowPerm = (int *)malloc(sizeof(int) * dim); + for (int rowIdx = 0; rowIdx < dim; ++rowIdx) { + (*jdsRowPerm)[rowIdx] = rowIdx; + } + + // Number of non-zeros per row + *jdsRowNNZ = (int *)malloc(sizeof(int) * dim); + for (int rowIdx = 0; rowIdx < dim; ++rowIdx) { + (*jdsRowNNZ)[rowIdx] = csrRowPtr[rowIdx + 1] - csrRowPtr[rowIdx]; + } + + // Sort rows by number of non-zeros + sort(*jdsRowPerm, *jdsRowNNZ, 0, dim - 1); + + // Starting point of each compressed column + int maxRowNNZ = (*jdsRowNNZ)[0]; // Largest number of non-zeros per row + DEBUG(printf("jdsRowNNZ = %d\n", maxRowNNZ)); + *jdsColStartIdx = (int *)malloc(sizeof(int) * maxRowNNZ); + (*jdsColStartIdx)[0] = 0; // First column starts at 0 + for (int col = 0; col < maxRowNNZ - 1; ++col) { + // Count the number of rows with entries in this column + int count = 0; + for (int idx = 0; idx < dim; ++idx) { + if ((*jdsRowNNZ)[idx] > col) { + ++count; + } + } + (*jdsColStartIdx)[col + 1] = (*jdsColStartIdx)[col] + count; + } + + // Sort the column indexes and data + const int NNZ = csrRowPtr[dim]; + DEBUG(printf("NNZ = %d\n", NNZ)); + *jdsColIdx = (int *)malloc(sizeof(int) * NNZ); + DEBUG(printf("dim = %d\n", dim)); + *jdsData = (float *)malloc(sizeof(float) * NNZ); + for (int idx = 0; idx < dim; ++idx) { // For every row + int row = (*jdsRowPerm)[idx]; + int rowNNZ = (*jdsRowNNZ)[idx]; + for (int nnzIdx = 0; nnzIdx < rowNNZ; ++nnzIdx) { + int jdsPos = (*jdsColStartIdx)[nnzIdx] + idx; + int csrPos = csrRowPtr[row] + nnzIdx; + (*jdsColIdx)[jdsPos] = csrColIdx[csrPos]; + (*jdsData)[jdsPos] = csrData[csrPos]; + } + } +} diff --git a/CUDA_TiledMatrixMultiplication/libwb/wbSparse.h b/CUDA_TiledMatrixMultiplication/libwb/wbSparse.h new file mode 100644 index 0000000..c04a857 --- /dev/null +++ b/CUDA_TiledMatrixMultiplication/libwb/wbSparse.h @@ -0,0 +1,10 @@ + +#ifndef __WB_SPARSE_H__ +#define __WB_SPARSE_H__ + +EXTERN_C void CSRToJDS(int dim, int *csrRowPtr, int *csrColIdx, + float *csrData, int **jdsRowPerm, int **jdsRowNNZ, + int **jdsColStartIdx, int **jdsColIdx, + float **jdsData); + +#endif /* __WB_SPARSE_H__ */ diff --git a/CUDA_TiledMatrixMultiplication/libwb/wbString.h b/CUDA_TiledMatrixMultiplication/libwb/wbString.h new file mode 100644 index 0000000..65e52f8 --- /dev/null +++ b/CUDA_TiledMatrixMultiplication/libwb/wbString.h @@ -0,0 +1,324 @@ + + +#ifndef __WB_STRING_H__ +#define __WB_STRING_H__ + +#include +#include +#include +#include +#include +#include +#include "wb.h" + +using std::string; +using std::vector; +using std::stringstream; +using std::exception; + +template +static inline string wbString(const T &x); + +static inline void wbString_replace(string &value, string const &search, + string const &replace) { + for (string::size_type next = value.find(search); next != string::npos; + next = value.find(search, next)) { + value.replace(next, search.length(), replace); + next += replace.length(); + } +} + +static inline string wbString_quote(string str) { + string s = str; + wbString_replace(s, "\\", "\\\\"); + s = "\"" + s + "\""; + return s; +} + +static inline string wbString_quote(const char *str) { + if (str == NULL) { + return wbString_quote(""); + } else { + return wbString_quote(string(str)); + } +} + +static inline char *wbString_duplicate(const char *str) { + if (str == NULL) { + return NULL; + } else { + char *newstr; + size_t len = strlen(str); + newstr = wbNewArray(char, len + 1); + memcpy(newstr, str, len * sizeof(char)); + newstr[len] = '\0'; + return newstr; + } +} + +static inline char *wbString_duplicate(std::string str) { + return wbString_duplicate(str.c_str()); +} + +static inline string wbString(void) { + string s = ""; + return s; +} + +template +static inline string wbString(const T &x) { + try { + stringstream ss; + ss << x; + return ss.str(); + } catch (exception &e) { + return string(); + } +} + +template <> +inline string wbString(const bool &x) { + return x ? "True" : "False"; +} + +template <> +inline string wbString(const vector &x) { + stringstream ss; + ss << "{"; + for (size_t ii = 0; ii < x.size(); ii++) { + ss << wbString_quote(x[ii]); + if (ii != x.size() - 1) { + ss << ", "; + } + } + ss << "}"; + + return ss.str(); +} + +template <> +inline string wbString(const vector &x) { + stringstream ss; + ss << "{"; + for (size_t ii = 0; ii < x.size(); ii++) { + ss << x[ii]; + if (ii != x.size() - 1) { + ss << ", "; + } + } + ss << "}"; + + return ss.str(); +} + +template <> +inline string wbString(const vector &x) { + stringstream ss; + ss << "{"; + for (size_t ii = 0; ii < x.size(); ii++) { + ss << x[ii]; + if (ii != x.size() - 1) { + ss << ", "; + } + } + ss << "}"; + + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1) { + stringstream ss; + ss << wbString(x0) << wbString(x1); + + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1, const T2 &x2) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2); + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1, const T2 &x2, + const T3 &x3) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2) << wbString(x3); + + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1, const T2 &x2, + const T3 &x3, const T4 &x4) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2) << wbString(x3) + << wbString(x4); + + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1, const T2 &x2, + const T3 &x3, const T4 &x4, const T5 &x5) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2) << wbString(x3) + << wbString(x4) << wbString(x5); + + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1, const T2 &x2, + const T3 &x3, const T4 &x4, const T5 &x5, + const T6 &x6) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2) << wbString(x3) + << wbString(x4) << wbString(x5) << wbString(x6); + + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1, const T2 &x2, + const T3 &x3, const T4 &x4, const T5 &x5, + const T6 &x6, const T7 &x7) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2) << wbString(x3) + << wbString(x4) << wbString(x5) << wbString(x6) << wbString(x7); + + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1, const T2 &x2, + const T3 &x3, const T4 &x4, const T5 &x5, + const T6 &x6, const T7 &x7, const T8 &x8) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2) << wbString(x3) + << wbString(x4) << wbString(x5) << wbString(x6) << wbString(x7) + << wbString(x8); + + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1, const T2 &x2, + const T3 &x3, const T4 &x4, const T5 &x5, + const T6 &x6, const T7 &x7, const T8 &x8, + const T9 &x9) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2) << wbString(x3) + << wbString(x4) << wbString(x5) << wbString(x6) << wbString(x7) + << wbString(x8) << wbString(x9); + + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1, const T2 &x2, + const T3 &x3, const T4 &x4, const T5 &x5, + const T6 &x6, const T7 &x7, const T8 &x8, + const T9 &x9, const T10 &x10) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2) << wbString(x3) + << wbString(x4) << wbString(x5) << wbString(x6) << wbString(x7) + << wbString(x8) << wbString(x9) << wbString(x10); + + return ss.str(); +} + +template +static inline string +wbString(const T0 &x0, const T1 &x1, const T2 &x2, const T3 &x3, + const T4 &x4, const T5 &x5, const T6 &x6, const T7 &x7, + const T8 &x8, const T9 &x9, const T10 &x10, const T11 &x11) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2) << wbString(x3) + << wbString(x4) << wbString(x5) << wbString(x6) << wbString(x7) + << wbString(x8) << wbString(x9) << wbString(x10) << wbString(x11); + + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1, const T2 &x2, + const T3 &x3, const T4 &x4, const T5 &x5, + const T6 &x6, const T7 &x7, const T8 &x8, + const T9 &x9, const T10 &x10, const T11 &x11, + const T12 &x12) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2) << wbString(x3) + << wbString(x4) << wbString(x5) << wbString(x6) << wbString(x7) + << wbString(x8) << wbString(x9) << wbString(x10) << wbString(x11) + << wbString(x12); + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1, const T2 &x2, + const T3 &x3, const T4 &x4, const T5 &x5, + const T6 &x6, const T7 &x7, const T8 &x8, + const T9 &x9, const T10 &x10, const T11 &x11, + const T12 &x12, const T13 &x13) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2) << wbString(x3) + << wbString(x4) << wbString(x5) << wbString(x6) << wbString(x7) + << wbString(x8) << wbString(x9) << wbString(x10) << wbString(x11) + << wbString(x12) << wbString(x13); + return ss.str(); +} + +template +static inline wbBool wbString_sameQ(const X &x, const Y &y) { + string xs = wbString(x); + string ys = wbString(y); + return strcmp(xs.c_str(), ys.c_str()) == 0; +} + +static inline wbBool wbString_sameQ(const string &x, const string &y) { + return x.compare(y) == 0; +} + +static inline char *wbString_toLower(const char *str) { + if (str == NULL) { + return NULL; + } else { + char *res, *iter; + + res = iter = wbString_duplicate(str); + while (*iter != '\0') { + *iter++ = tolower(*str++); + } + return res; + } +} + +static inline wbBool wbString_startsWith(const char *str, + const char *prefix) { + while (*prefix != '\0') { + if (*str == '\0' || *str != *prefix) { + return wbFalse; + } + str++; + prefix++; + } + return wbTrue; +} + +#endif /* __WB_STRING_H__ */ diff --git a/CUDA_TiledMatrixMultiplication/libwb/wbThrust.h b/CUDA_TiledMatrixMultiplication/libwb/wbThrust.h new file mode 100644 index 0000000..e2d3160 --- /dev/null +++ b/CUDA_TiledMatrixMultiplication/libwb/wbThrust.h @@ -0,0 +1,15 @@ + +#ifndef __WB_THRUST_H__ +#define __WB_THRUST_H__ + +#ifdef WB_USE_CUDA +#include +#include +#include +#include +#include +#include + +#endif /* WB_USE_CUDA */ + +#endif /* __WB_THRUST_H__ */ diff --git a/CUDA_TiledMatrixMultiplication/libwb/wbTimer.cpp b/CUDA_TiledMatrixMultiplication/libwb/wbTimer.cpp new file mode 100644 index 0000000..c9fbdb8 --- /dev/null +++ b/CUDA_TiledMatrixMultiplication/libwb/wbTimer.cpp @@ -0,0 +1,493 @@ +#include "wb.h" + +#ifdef WB_USE_WINDOWS +uint64_t _hrtime_frequency = 0; +#endif /* WB_USE_WINDOWS */ +wbTimer_t _timer = NULL; + +#ifdef WB_USE_DARWIN +static double o_timebase = 0; +static uint64_t o_timestart = 0; +#endif /* WB_USE_DARWIN */ + +uint64_t _hrtime(void) { +#define NANOSEC ((uint64_t)1e9) +#ifdef WB_USE_WINDOWS + LARGE_INTEGER counter; + if (!QueryPerformanceCounter(&counter)) { + return 0; + } + return ((uint64_t)counter.LowPart * NANOSEC / _hrtime_frequency) + + (((uint64_t)counter.HighPart * NANOSEC / _hrtime_frequency) + << 32); +#else + struct timespec ts; +#ifdef WB_USE_DARWIN +#define O_NANOSEC (+1.0E-9) +#define O_GIGA UINT64_C(1000000000) + if (!o_timestart) { + mach_timebase_info_data_t tb{}; + mach_timebase_info(&tb); + o_timebase = tb.numer; + o_timebase /= tb.denom; + o_timestart = mach_absolute_time(); + } + double diff = (mach_absolute_time() - o_timestart) * o_timebase; + ts.tv_sec = diff * O_NANOSEC; + ts.tv_nsec = diff - (ts.tv_sec * O_GIGA); +#undef O_NANOSEC +#undef O_GIGA +#else /* WB_USE_DARWIN */ + clock_gettime(CLOCK_MONOTONIC, &ts); +#endif /* WB_USE_DARWIN */ + return (((uint64_t)ts.tv_sec) * NANOSEC + ts.tv_nsec); +#endif /* WB_USE_WINDOWS */ +#undef NANOSEC +} + +static inline uint64_t getTime(void) { +#ifdef WB_USE_CUDA + cudaDeviceSynchronize(); +#endif /* WB_USE_CUDA */ + return _hrtime(); +} + +static inline wbTimerNode_t wbTimerNode_new(int id, wbTimerKind_t kind, + const char *file, + const char *fun, + int startLine) { + wbTimerNode_t node = wbNew(struct st_wbTimerNode_t); + wbTimerNode_setId(node, id); + wbTimerNode_setMPIRank(node, wbMPI_getRank()); + wbTimerNode_setLevel(node, 0); + wbTimerNode_setStoppedQ(node, wbFalse); + wbTimerNode_setKind(node, kind); + wbTimerNode_setStartTime(node, 0); + wbTimerNode_setEndTime(node, 0); + wbTimerNode_setElapsedTime(node, 0); + wbTimerNode_setStartLine(node, startLine); + wbTimerNode_setEndLine(node, 0); + wbTimerNode_setStartFunction(node, fun); + wbTimerNode_setEndFunction(node, NULL); + wbTimerNode_setStartFile(node, file); + wbTimerNode_setEndFile(node, NULL); + wbTimerNode_setNext(node, NULL); + wbTimerNode_setPrevious(node, NULL); + wbTimerNode_setParent(node, NULL); + wbTimerNode_setMessage(node, NULL); + return node; +} + +static inline void wbTimerNode_delete(wbTimerNode_t node) { + if (node != NULL) { + if (wbTimerNode_getMessage(node)) { + wbDelete(wbTimerNode_getMessage(node)); + } + wbDelete(node); + } +} + +static inline const char *_nodeKind(wbTimerKind_t kind) { + switch (kind) { + case wbTimerKind_Generic: + return "Generic"; + case wbTimerKind_IO: + return "IO"; + case wbTimerKind_GPU: + return "GPU"; + case wbTimerKind_Copy: + return "Copy"; + case wbTimerKind_Driver: + return "Driver"; + case wbTimerKind_CopyAsync: + return "CopyAsync"; + case wbTimerKind_Compute: + return "Compute"; + case wbTimerKind_CPUGPUOverlap: + return "CPUGPUOverlap"; + } + return "Undefined"; +} + +static inline json11::Json wbTimerNode_toJSONObject(wbTimerNode_t node) { + json11::Json json = json11::Json::object{ + {"id", wbTimerNode_getId(node)}, + {"mpi_rank", wbTimerNode_getMPIRank(node)}, + {"stopped", wbTimerNode_stoppedQ(node)}, + {"kind", _nodeKind(wbTimerNode_getKind(node))}, + {"start_time", wbTimerNode_getStartTime(node)}, + {"end_time", wbTimerNode_getEndTime(node)}, + {"elapsed_time", wbTimerNode_getElapsedTime(node)}, + {"start_line", wbTimerNode_getStartLine(node)}, + {"end_line", wbTimerNode_getEndLine(node)}, + {"start_function", wbTimerNode_getStartFunction(node)}, + {"end_function", wbTimerNode_getEndFunction(node)}, + {"start_file", wbTimerNode_getStartFile(node)}, + {"end_file", wbTimerNode_getEndFile(node)}, + {"parent_id", wbTimerNode_hasParent(node) + ? wbTimerNode_getId(wbTimerNode_getParent(node)) + : -1}, + {"message", wbTimerNode_getMessage(node)}, + }; + return json; +} + +static inline string wbTimerNode_toJSON(wbTimerNode_t node) { + if (node == NULL) { + return ""; + } else if (WB_USE_JSON11) { + json11::Json json = wbTimerNode_toJSONObject(node); + return json.string_value(); + } else { + stringstream ss; + + ss << "{\n"; + ss << wbString_quote("id") << ":" << wbTimerNode_getId(node) << ",\n"; + ss << wbString_quote("mpi_rank") << ":" << wbTimerNode_getMPIRank(node) + << ",\n"; + ss << wbString_quote("stopped") << ":" + << wbString(wbTimerNode_stoppedQ(node) ? "true" : "false") << ",\n"; + ss << wbString_quote("kind") << ":" + << wbString_quote(_nodeKind(wbTimerNode_getKind(node))) << ",\n"; + ss << wbString_quote("start_time") << ":" + << wbTimerNode_getStartTime(node) << ",\n"; + ss << wbString_quote("end_time") << ":" << wbTimerNode_getEndTime(node) + << ",\n"; + ss << wbString_quote("elapsed_time") << ":" + << wbTimerNode_getElapsedTime(node) << ",\n"; + ss << wbString_quote("start_line") << ":" + << wbTimerNode_getStartLine(node) << ",\n"; + ss << wbString_quote("end_line") << ":" << wbTimerNode_getEndLine(node) + << ",\n"; + ss << wbString_quote("start_function") << ":" + << wbString_quote(wbTimerNode_getStartFunction(node)) << ",\n"; + ss << wbString_quote("end_function") << ":" + << wbString_quote(wbTimerNode_getEndFunction(node)) << ",\n"; + ss << wbString_quote("start_file") << ":" + << wbString_quote(wbTimerNode_getStartFile(node)) << ",\n"; + ss << wbString_quote("end_file") << ":" + << wbString_quote(wbTimerNode_getEndFile(node)) << ",\n"; + ss << wbString_quote("parent_id") << ":" + << wbString(wbTimerNode_hasParent(node) + ? wbTimerNode_getId(wbTimerNode_getParent(node)) + : -1) + << ",\n"; + ss << wbString_quote("message") << ":" + << wbString_quote(wbTimerNode_getMessage(node)) << "\n"; + ss << "}"; + + return ss.str(); + } +} + +static inline string wbTimerNode_toXML(wbTimerNode_t node) { + if (node == NULL) { + return ""; + } else { + stringstream ss; + + ss << "\n"; + ss << "" << wbTimerNode_getId(node) << "\n"; + ss << "" + << wbString(wbTimerNode_stoppedQ(node) ? "true" : "false") + << "\n"; + ss << "" << _nodeKind(wbTimerNode_getKind(node)) << "\n"; + ss << "" << wbTimerNode_getStartTime(node) + << "\n"; + ss << "" << wbTimerNode_getEndTime(node) << "\n"; + ss << "" << wbTimerNode_getElapsedTime(node) + << "\n"; + ss << "" << wbTimerNode_getStartLine(node) + << "\n"; + ss << "" << wbTimerNode_getEndLine(node) << "\n"; + ss << "" << wbTimerNode_getStartFunction(node) + << "\n"; + ss << "" << wbTimerNode_getEndFunction(node) + << "\n"; + ss << "" << wbTimerNode_getStartFile(node) + << "\n"; + ss << "" << wbTimerNode_getEndFile(node) << "\n"; + ss << "" + << wbString(wbTimerNode_hasParent(node) + ? wbTimerNode_getId(wbTimerNode_getParent(node)) + : -1) + << "\n"; + ss << "" << wbTimerNode_getMessage(node) << "\n"; + ss << "\n"; + + return ss.str(); + } +} + +#define wbTimer_getLength(timer) ((timer)->length) +#define wbTimer_getHead(timer) ((timer)->head) +#define wbTimer_getTail(timer) ((timer)->tail) +#define wbTimer_getStartTime(timer) ((timer)->startTime) +#define wbTimer_getEndTime(timer) ((timer)->endTime) +#define wbTimer_getElapsedTime(timer) ((timer)->elapsedTime) + +#define wbTimer_setLength(timer, val) (wbTimer_getLength(timer) = val) +#define wbTimer_setHead(timer, val) (wbTimer_getHead(timer) = val) +#define wbTimer_setTail(timer, val) (wbTimer_getTail(timer) = val) +#define wbTimer_setStartTime(node, val) (wbTimer_getStartTime(node) = val) +#define wbTimer_setEndTime(node, val) (wbTimer_getEndTime(node) = val) +#define wbTimer_setElapsedTime(node, val) \ + (wbTimer_getElapsedTime(node) = val) + +#define wbTimer_incrementLength(timer) (wbTimer_getLength(timer)++) +#define wbTimer_decrementLength(timer) (wbTimer_getLength(timer)--) + +#define wbTimer_emptyQ(timer) (wbTimer_getLength(timer) == 0) + +void wbTimer_delete(wbTimer_t timer) { + if (timer != NULL) { + wbTimerNode_t tmp, iter; + + iter = wbTimer_getHead(timer); + while (iter) { + tmp = wbTimerNode_getNext(iter); + wbTimerNode_delete(iter); + iter = tmp; + } + + wbDelete(timer); + } +} + +static json11::Json wbTimer_toJSONObject(wbTimer_t timer) { + + stringstream ss; + wbTimerNode_t iter; + uint64_t currentTime; + std::vector elems; + + currentTime = getTime(); + + wbTimer_setEndTime(timer, currentTime); + wbTimer_setElapsedTime(timer, currentTime - wbTimer_getStartTime(timer)); + + for (iter = wbTimer_getHead(timer); iter != NULL; + iter = wbTimerNode_getNext(iter)) { + if (!wbTimerNode_stoppedQ(iter)) { + wbTimerNode_setEndTime(iter, currentTime); + wbTimerNode_setElapsedTime(iter, currentTime - + wbTimerNode_getStartTime(iter)); + } + elems.push_back(wbTimerNode_toJSONObject(iter)); + } + return json11::Json(elems); +} + +string wbTimer_toJSON(wbTimer_t timer) { + if (timer == NULL) { + return ""; + } else if (WB_USE_JSON11) { + json11::Json json = wbTimer_toJSONObject(timer); + return json.string_value(); + } else { + stringstream ss; + wbTimerNode_t iter; + uint64_t currentTime; + + currentTime = getTime(); + + wbTimer_setEndTime(timer, currentTime); + wbTimer_setElapsedTime(timer, + currentTime - wbTimer_getStartTime(timer)); + + for (iter = wbTimer_getHead(timer); iter != NULL; + iter = wbTimerNode_getNext(iter)) { + if (!wbTimerNode_stoppedQ(iter)) { + wbTimerNode_setEndTime(iter, currentTime); + wbTimerNode_setElapsedTime( + iter, currentTime - wbTimerNode_getStartTime(iter)); + } + ss << wbTimerNode_toJSON(iter); + if (wbTimerNode_getNext(iter) != NULL) { + ss << ",\n"; + } + } + + return ss.str(); + } +} + +string wbTimer_toJSON() { + return wbTimer_toJSON(_timer); +} + +string wbTimer_toXML(wbTimer_t timer) { + if (timer == NULL) { + return ""; + } else { + stringstream ss; + wbTimerNode_t iter; + uint64_t currentTime; + + currentTime = getTime(); + + wbTimer_setEndTime(timer, currentTime); + wbTimer_setElapsedTime(timer, + currentTime - wbTimer_getStartTime(timer)); + + ss << "\n"; + ss << "" << wbTimer_getStartTime(timer) + << "\n"; + ss << "" << wbTimer_getEndTime(timer) << "\n"; + ss << "" << wbTimer_getElapsedTime(timer) + << "\n"; + ss << "\n"; + for (iter = wbTimer_getHead(timer); iter != NULL; + iter = wbTimerNode_getNext(iter)) { + if (!wbTimerNode_stoppedQ(iter)) { + wbTimerNode_setEndTime(iter, currentTime); + wbTimerNode_setElapsedTime( + iter, currentTime - wbTimerNode_getStartTime(iter)); + } + ss << wbTimerNode_toXML(iter); + } + ss << "\n"; + ss << "\n"; + + return ss.str(); + } +} + +string wbTimer_toXML() { + return wbTimer_toXML(_timer); +} + +wbTimer_t wbTimer_new(void) { + wbTimer_t timer = wbNew(struct st_wbTimer_t); + wbTimer_setLength(timer, 0); + wbTimer_setHead(timer, NULL); + wbTimer_setTail(timer, NULL); + wbTimer_setStartTime(timer, getTime()); + wbTimer_setEndTime(timer, 0); + wbTimer_setElapsedTime(timer, 0); + + return timer; +} + +static inline wbTimerNode_t _findParent(wbTimer_t timer) { + wbTimerNode_t iter; + + for (iter = wbTimer_getTail(timer); iter != NULL; + iter = wbTimerNode_getPrevious(iter)) { + if (!wbTimerNode_stoppedQ(iter)) { + return iter; + } + } + return NULL; +} + +static inline void _insertIntoList(wbTimer_t timer, wbTimerNode_t node) { + if (wbTimer_emptyQ(timer)) { + wbTimer_setHead(timer, node); + wbTimer_setTail(timer, node); + } else { + wbTimerNode_t end = wbTimer_getTail(timer); + wbTimer_setTail(timer, node); + wbTimerNode_setNext(end, node); + wbTimerNode_setPrevious(node, end); + } + wbTimer_incrementLength(timer); +} + +wbTimerNode_t wbTimer_start(wbTimerKind_t kind, const char *file, + const char *fun, int line) { + int id; + uint64_t currentTime; + wbTimerNode_t node; + wbTimerNode_t parent; + + wb_init(NULL, NULL); + + currentTime = getTime(); + + id = wbTimer_getLength(_timer); + + node = wbTimerNode_new(id, kind, file, fun, line); + + parent = _findParent(_timer); + _insertIntoList(_timer, node); + + wbTimerNode_setStartTime(node, currentTime); + wbTimerNode_setParent(node, parent); + if (parent != NULL) { + wbTimerNode_setLevel(node, wbTimerNode_getLevel(parent) + 1); + } + + return node; +} + +wbTimerNode_t wbTimer_start(wbTimerKind_t kind, string msg, + const char *file, const char *fun, int line) { + wbTimerNode_t node = wbTimer_start(kind, file, fun, line); + wbTimerNode_setMessage(node, wbString_duplicate(msg)); + return node; +} + +static inline wbTimerNode_t _findNode(wbTimer_t timer, wbTimerKind_t kind, + string msg) { + wbTimerNode_t iter; + + for (iter = wbTimer_getTail(timer); iter != NULL; + iter = wbTimerNode_getPrevious(iter)) { + if (msg == "") { + if (!wbTimerNode_stoppedQ(iter) && + wbTimerNode_getKind(iter) == kind) { + return iter; + } + } else { + if (!wbTimerNode_stoppedQ(iter) && + wbTimerNode_getKind(iter) == kind && + msg == wbTimerNode_getMessage(iter)) { + return iter; + } + } + } + return NULL; +} + +void wbTimer_stop(wbTimerKind_t kind, string msg, const char *file, + const char *fun, int line) { + uint64_t currentTime; + wbTimerNode_t node; + + currentTime = getTime(); + + node = _findNode(_timer, kind, msg); + + wbAssert(node != NULL); + if (node == NULL) { + return; + } + + wbTimerNode_setEndTime(node, currentTime); + wbTimerNode_setElapsedTime(node, + currentTime - wbTimerNode_getStartTime(node)); + wbTimerNode_setEndLine(node, line); + wbTimerNode_setEndFunction(node, fun); + wbTimerNode_setEndFile(node, file); + wbTimerNode_setStoppedQ(node, wbTrue); + +#ifdef wbLogger_printOnLog + if (wbLogger_printOnLog) { + json11::Json json = json11::Json::object{ +//PMO +#ifndef _MSC_VER + { "type", "timer" }, { "data", wbTimerNode_toJSONObject(node) }}; +#else + { "data", wbTimerNode_toJSONObject(node) }, { "type", "timer" }}; +#endif + std::cout << json.dump() << std::endl; + } +#endif /* wbLogger_printOnLog */ + return; +} + +void wbTimer_stop(wbTimerKind_t kind, const char *file, const char *fun, + int line) { + wbTimer_stop(kind, "", file, fun, line); +} diff --git a/CUDA_TiledMatrixMultiplication/libwb/wbTimer.h b/CUDA_TiledMatrixMultiplication/libwb/wbTimer.h new file mode 100644 index 0000000..133b58f --- /dev/null +++ b/CUDA_TiledMatrixMultiplication/libwb/wbTimer.h @@ -0,0 +1,139 @@ + + +#ifndef __WB_TIMER_H__ +#define __WB_TIMER_H__ + +#ifdef WB_USE_WINDOWS +extern uint64_t _hrtime_frequency; +#endif /* _WIN32 */ + +extern wbTimer_t _timer; + +typedef enum en_wbTimerKind_t { + wbTimerKind_Generic, + wbTimerKind_IO, + wbTimerKind_GPU, + wbTimerKind_Copy, + wbTimerKind_Driver, + wbTimerKind_CopyAsync, + wbTimerKind_Compute, + wbTimerKind_CPUGPUOverlap, +} wbTimerKind_t; + +struct st_wbTimerNode_t { + int id; + int mpiRank; + int level; + wbBool stoppedQ; + wbTimerKind_t kind; + uint64_t startTime; + uint64_t endTime; + uint64_t elapsedTime; + int startLine; + int endLine; + const char *startFunction; + const char *endFunction; + const char *startFile; + const char *endFile; + wbTimerNode_t next; + wbTimerNode_t prev; + wbTimerNode_t parent; + char *msg; +}; + +struct st_wbTimer_t { + size_t length; + wbTimerNode_t head; + wbTimerNode_t tail; + uint64_t startTime; + uint64_t endTime; + uint64_t elapsedTime; +}; + +#define wbTimerNode_getId(node) ((node)->id) +#define wbTimerNode_getMPIRank(node) ((node)->mpiRank) +#define wbTimerNode_getLevel(node) ((node)->level) +#define wbTimerNode_getStoppedQ(node) ((node)->stoppedQ) +#define wbTimerNode_getKind(node) ((node)->kind) +#define wbTimerNode_getStartTime(node) ((node)->startTime) +#define wbTimerNode_getEndTime(node) ((node)->endTime) +#define wbTimerNode_getElapsedTime(node) ((node)->elapsedTime) +#define wbTimerNode_getStartLine(node) ((node)->startLine) +#define wbTimerNode_getEndLine(node) ((node)->endLine) +#define wbTimerNode_getStartFunction(node) ((node)->startFunction) +#define wbTimerNode_getEndFunction(node) ((node)->endFunction) +#define wbTimerNode_getStartFile(node) ((node)->startFile) +#define wbTimerNode_getEndFile(node) ((node)->endFile) +#define wbTimerNode_getNext(node) ((node)->next) +#define wbTimerNode_getPrevious(node) ((node)->prev) +#define wbTimerNode_getParent(node) ((node)->parent) +#define wbTimerNode_getMessage(node) ((node)->msg) + +#define wbTimerNode_setId(node, val) (wbTimerNode_getId(node) = val) +#define wbTimerNode_setMPIRank(node, val) \ + (wbTimerNode_getMPIRank(node) = val) +#define wbTimerNode_setLevel(node, val) (wbTimerNode_getLevel(node) = val) +#define wbTimerNode_setStoppedQ(node, val) \ + (wbTimerNode_getStoppedQ(node) = val) +#define wbTimerNode_setKind(node, val) (wbTimerNode_getKind(node) = val) +#define wbTimerNode_setStartTime(node, val) \ + (wbTimerNode_getStartTime(node) = val) +#define wbTimerNode_setEndTime(node, val) \ + (wbTimerNode_getEndTime(node) = val) +#define wbTimerNode_setElapsedTime(node, val) \ + (wbTimerNode_getElapsedTime(node) = val) +#define wbTimerNode_setStartLine(node, val) \ + (wbTimerNode_getStartLine(node) = val) +#define wbTimerNode_setEndLine(node, val) \ + (wbTimerNode_getEndLine(node) = val) +#define wbTimerNode_setStartFunction(node, val) \ + (wbTimerNode_getStartFunction(node) = val) +#define wbTimerNode_setEndFunction(node, val) \ + (wbTimerNode_getEndFunction(node) = val) +#define wbTimerNode_setStartFile(node, val) \ + (wbTimerNode_getStartFile(node) = val) +#define wbTimerNode_setEndFile(node, val) \ + (wbTimerNode_getEndFile(node) = val) +#define wbTimerNode_setNext(node, val) (wbTimerNode_getNext(node) = val) +#define wbTimerNode_setPrevious(node, val) \ + (wbTimerNode_getPrevious(node) = val) +#define wbTimerNode_setParent(node, val) \ + (wbTimerNode_getParent(node) = val) +#define wbTimerNode_setMessage(node, val) \ + (wbTimerNode_getMessage(node) = val) + +#define wbTimerNode_stoppedQ(node) \ + (wbTimerNode_getStoppedQ(node) == wbTrue) +#define wbTimerNode_hasNext(node) (wbTimerNode_getNext(node) != NULL) +#define wbTimerNode_hasPrevious(node) \ + (wbTimerNode_getPrevious(node) != NULL) +#define wbTimerNode_hasParent(node) (wbTimerNode_getParent(node) != NULL) + +uint64_t _hrtime(void); + +wbTimer_t wbTimer_new(void); +void wbTimer_delete(wbTimer_t timer); + +string wbTimer_toJSON(wbTimer_t timer); +string wbTimer_toJSON(); + +string wbTimer_toXML(wbTimer_t timer); +string wbTimer_toXML(); + +wbTimerNode_t wbTimer_start(wbTimerKind_t kind, const char *file, + const char *fun, int line); +wbTimerNode_t wbTimer_start(wbTimerKind_t kind, string msg, + const char *file, const char *fun, int line); +void wbTimer_stop(wbTimerKind_t kind, string msg, const char *file, + const char *fun, int line); +void wbTimer_stop(wbTimerKind_t kind, const char *file, const char *fun, + int line); + +#define wbTime_start(kind, ...) \ + wbTimer_start(wbTimerKind_##kind, wbString(__VA_ARGS__), wbFile, \ + wbFunction, wbLine) +#define wbTime_stop(kind, ...) \ + wbTimer_stop(wbTimerKind_##kind, wbString(__VA_ARGS__), wbFile, \ + wbFunction, wbLine) + +#endif /* __WB_TIMER_H__ */ diff --git a/CUDA_TiledMatrixMultiplication/libwb/wbTypes.h b/CUDA_TiledMatrixMultiplication/libwb/wbTypes.h new file mode 100644 index 0000000..6837792 --- /dev/null +++ b/CUDA_TiledMatrixMultiplication/libwb/wbTypes.h @@ -0,0 +1,55 @@ + + +#ifndef __WB_TYPES_H__ +#define __WB_TYPES_H__ + +#include "wbAssert.h" + +typedef bool wbBool; +typedef float wbReal_t; +typedef char wbChar_t; + +typedef struct st_wbTimerNode_t *wbTimerNode_t; +typedef struct st_wbTimer_t *wbTimer_t; +typedef struct st_wbLogEntry_t *wbLogEntry_t; +typedef struct st_wbLogger_t *wbLogger_t; +typedef struct st_wbArg_t wbArg_t; +typedef struct st_wbImage_t *wbImage_t; +typedef struct st_wbFile_t *wbFile_t; + +#define wbTrue true +#define wbFalse false + +typedef enum en_wbType_t { + wbType_unknown = -1, + wbType_ascii = 1, + wbType_bit8, + wbType_ubit8, + wbType_integer, + wbType_float, + wbType_double +} wbType_t; + +static inline size_t wbType_size(wbType_t ty) { + switch (ty) { + case wbType_unknown: + wbAssert(false && "Invalid wbType_unknown"); + return 0; + case wbType_ascii: + return sizeof(char); + case wbType_bit8: + return sizeof(char); + case wbType_ubit8: + return sizeof(unsigned char); + case wbType_integer: + return sizeof(int); + case wbType_float: + return sizeof(float); + case wbType_double: + return sizeof(double); + } + wbAssert(false && "Invalid type"); + return 0; +} + +#endif /* __WB_TYPES_H__ */ diff --git a/CUDA_TiledMatrixMultiplication/libwb/wbUtils.h b/CUDA_TiledMatrixMultiplication/libwb/wbUtils.h new file mode 100644 index 0000000..cbd1b91 --- /dev/null +++ b/CUDA_TiledMatrixMultiplication/libwb/wbUtils.h @@ -0,0 +1,10 @@ +#ifndef __WB_UTILS_H__ +#define __WB_UTILS_H__ + +#ifdef WB_DEBUG +#define DEBUG(...) __VA_ARGS__ +#else /* WB_DEBUG */ +#define DEBUG(...) +#endif /* WB_DEBUG */ + +#endif /* __WB_UTILS_H__ */ diff --git a/CUDA_TiledMatrixMultiplication/libwb/wb_test.cpp b/CUDA_TiledMatrixMultiplication/libwb/wb_test.cpp new file mode 100644 index 0000000..87883c8 --- /dev/null +++ b/CUDA_TiledMatrixMultiplication/libwb/wb_test.cpp @@ -0,0 +1,4 @@ +#define CATCH_CONFIG_MAIN + +#include "wb.h" +#include "vendor/catch.hpp" diff --git a/CUDA_VectorAdd/VectorAdd/template.cu b/CUDA_VectorAdd/VectorAdd/template.cu new file mode 100644 index 0000000..bef4690 --- /dev/null +++ b/CUDA_VectorAdd/VectorAdd/template.cu @@ -0,0 +1,83 @@ +#include + +__global__ void vecAdd(float *in1, float *in2, float *out, int len) { + int i = threadIdx.x + blockDim.x * blockIdx.x; + if(i < len) { + out[i] = in1[i] + in2[i]; + } +} + +int main(int argc, char **argv) { + wbArg_t args; + int inputLength; + float *hostInput1; + float *hostInput2; + float *hostOutput; + float *deviceInput1; + float *deviceInput2; + float *deviceOutput; + + args = wbArg_read(argc, argv); + + wbTime_start(Generic, "Importing data and creating memory on host"); + hostInput1 = (float *) wbImport(wbArg_getInputFile(args, 0), &inputLength); + hostInput2 = (float *) wbImport(wbArg_getInputFile(args, 1), &inputLength); + hostOutput = (float *) malloc(inputLength * sizeof(float)); + wbTime_stop(Generic, "Importing data and creating memory on host"); + + wbLog(TRACE, "The input length is ", inputLength); + + wbTime_start(GPU, "Allocating GPU memory."); + //@@ Allocate GPU memory + + int size = inputLength * sizeof(float); + cudaMalloc((void **) &deviceInput1, size); + cudaMalloc((void **) &deviceInput2, size); + cudaMalloc((void **) &deviceOutput, size); + + wbTime_stop(GPU, "Allocating GPU memory."); + + wbTime_start(GPU, "Copying input memory to the GPU."); + //@@ Copy memory to the GPU + + cudaMemcpy(deviceInput1, hostInput1, size, cudaMemcpyHostToDevice); + cudaMemcpy(deviceInput2, hostInput2, size, cudaMemcpyHostToDevice); + + wbTime_stop(GPU, "Copying input memory to the GPU."); + + //@@ Initialize the grid and block dimensions + dim3 dimGrid((inputLength - 1) / 256 + 1, 1, 1); + dim3 dimBlock(256, 1, 1); + + wbTime_start(Compute, "Performing CUDA computation"); + //@@ Launch the GPU Kernel + + vecAdd<<>>(deviceInput1, deviceInput2, deviceOutput, inputLength); + + cudaDeviceSynchronize(); + wbTime_stop(Compute, "Performing CUDA computation"); + + wbTime_start(Copy, "Copying output memory to the CPU"); + //@@ Copy the GPU memory back to the CPU + + cudaMemcpy(hostOutput, deviceOutput, size, cudaMemcpyDeviceToHost); + + wbTime_stop(Copy, "Copying output memory to the CPU"); + + wbTime_start(GPU, "Freeing GPU Memory"); + //@@ Free the GPU memory + + cudaFree(deviceInput1); + cudaFree(deviceInput2); + cudaFree(deviceOutput); + + wbTime_stop(GPU, "Freeing GPU Memory"); + + wbSolution(args, hostOutput, inputLength); + + free(hostInput1); + free(hostInput2); + free(hostOutput); + + return 0; +} diff --git a/CUDA_VectorAdd/libwb/.clang-format b/CUDA_VectorAdd/libwb/.clang-format new file mode 100644 index 0000000..4757ed4 --- /dev/null +++ b/CUDA_VectorAdd/libwb/.clang-format @@ -0,0 +1,21 @@ +--- +Language: Cpp +BasedOnStyle: LLVM +ColumnLimit: 75 +AccessModifierOffset: -2 +BreakBeforeBraces: Attach +AlignTrailingComments: true +AlignEscapedNewlinesLeft: false +AlignConsecutiveAssignments: true +AlignOperands: true +AllowShortFunctionsOnASingleLine: false +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AlwaysBreakTemplateDeclarations: true +IndentCaseLabels: true +SpacesBeforeTrailingComments: 1 +Standard: Cpp11 +TabWidth: 4 +UseTab: Never +SortIncludes: false +... diff --git a/CUDA_VectorAdd/libwb/.travis.yml b/CUDA_VectorAdd/libwb/.travis.yml new file mode 100644 index 0000000..e32c621 --- /dev/null +++ b/CUDA_VectorAdd/libwb/.travis.yml @@ -0,0 +1,65 @@ +# Use new trusty images, should yield newer compilers and packages +sudo: required +dist: precise +language: cpp + +matrix: + include: + - compiler: gcc + addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - g++-4.9 + env: COMPILER=g++-4.9 + - compiler: gcc + addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - g++-5 + env: COMPILER=g++-5 + - compiler: clang + addons: + apt: + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-precise-3.6 + packages: + - clang-3.6 + env: COMPILER=clang++-3.6 + - compiler: clang + addons: + apt: + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-precise-3.7 + packages: + - clang-3.7 + env: COMPILER=clang++-3.7 +# - compiler: gcc +# addons: +# apt: +# sources: +# - ubuntu-toolchain-r-test +# packages: +# - g++-6 +# env: COMPILER=g++-6 + # - compiler: clang + # addons: + # apt: + # sources: + # - ubuntu-toolchain-r-test + # - llvm-toolchain-precise-3.8 + # packages: + # - clang-3.8 + # env: COMPILER=clang++-3.8 + +before_install: + - sudo apt-get update -qq +script: + - $COMPILER --version + - make CXX=$COMPILER test + - ./test diff --git a/CUDA_VectorAdd/libwb/CMakeLists.txt b/CUDA_VectorAdd/libwb/CMakeLists.txt new file mode 100644 index 0000000..f732c32 --- /dev/null +++ b/CUDA_VectorAdd/libwb/CMakeLists.txt @@ -0,0 +1,34 @@ +cmake_minimum_required(VERSION 2.8 FATAL_ERROR) + +set(CMAKE_BUILD_TYPE Release) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) +set(CMAKE_COLOR_MAKEFILE ON) +set(VERBOSE_BUILD ON) +set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) +set(CMAKE_MACOSX_RPATH TRUE) +set_property(GLOBAL PROPERTY USE_FOLDERS ON) + + +project(wb) + +set(current_dir "${CMAKE_CURRENT_SOURCE_DIR}") + +if(NOT EXISTS "${CMAKE_CURRENT_BINARY_DIR}/cotire.cmake") + file(DOWNLOAD "https://raw.githubusercontent.com/sakra/cotire/master/CMake/cotire.cmake" "${CMAKE_CURRENT_BINARY_DIR}/cotire.cmake") +endif() + + + +include(${current_dir}/sources.cmake) + +set(WBLIB_STATIC ${WBLIB}) +set(WBLIB_SHARED lib${WBLIB}) + +add_library(${WBLIB_STATIC} STATIC ${LIBWB_SOURCE_FILES} ) +add_library(${WBLIB_SHARED} SHARED ${LIBWB_SOURCE_FILES} ) +set_property(TARGET ${WBLIB_STATIC} PROPERTY CXX_STANDARD 11) +set_property(TARGET ${WBLIB_SHARED} PROPERTY CXX_STANDARD 11) +if (UNIX) + set_target_properties(${WBLIB_SHARED} PROPERTIES OUTPUT_NAME ${WBLIB_STATIC}) +endif (UNIX) +set_property(TARGET ${WBLIB} PROPERTY CXX_STANDARD 11) diff --git a/CUDA_VectorAdd/libwb/LICENSE.TXT b/CUDA_VectorAdd/libwb/LICENSE.TXT new file mode 100644 index 0000000..8df244d --- /dev/null +++ b/CUDA_VectorAdd/libwb/LICENSE.TXT @@ -0,0 +1,36 @@ +Copyright (c) 2016, Abdul Dakkak All rights reserved. + +Developed by: Abdul Dakkak + IMPACT Group + University of Illinois, Urbana-Champaign + impact.crhc.illinois.edu + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal with the +Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, +sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +Redistributions of source code must retain the above +copyright notice, this list of conditions and the following +disclaimers. +Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following +disclaimers in the documentation and/or other materials +provided with the distribution. +Neither the names of Abdul Dakkak, Impact Group, nor the +names of its contributors may be used to endorse or promote +products derived from this Software without specific prior +written permission. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +WITH THE SOFTWARE. diff --git a/CUDA_VectorAdd/libwb/Makefile b/CUDA_VectorAdd/libwb/Makefile new file mode 100644 index 0000000..b8a72d7 --- /dev/null +++ b/CUDA_VectorAdd/libwb/Makefile @@ -0,0 +1,56 @@ +########################################## +# Options +########################################## +WB_LIB_PATH=$(CURDIR)/lib +WB_SRC_PATH=$(CURDIR) + +########################################## +########################################## + +DEFINES= +CXX_FLAGS=-fPIC -Wno-unused-function -x c++ -O3 -g -std=c++11 -Wall -Wno-unused-function -pedantic -I . -I $(WB_SRC_PATH) $(DEFINES) +LIBS=-lm -lstdc++ + +########################################## +########################################## + +UNAME_S := $(shell uname -s) +ifeq ($(UNAME_S),Linux) + LIBS += -lrt +endif + +########################################## +########################################## + +SOURCES := $(shell find $(WB_SRC_PATH) ! -name "*_test.cpp" -name "*.cpp") +TESTS := $(shell find $(WB_SRC_PATH) -name "*_test.cpp") + +OBJECTS = $(SOURCES:.cpp=.o) +TESTOBJECTS = $(TESTS:.cpp=.o) + +############################################## +# OUTPUT +############################################## + +.PHONY: all +.SUFFIXES: .o .cpp +all: libwb.so + +.cpp.o: + $(CXX) $(DEFINES) $(CXX_FLAGS) -c -o $@ $< + +libwb.so: $(OBJECTS) + mkdir -p $(WB_LIB_PATH) + $(CXX) -fPIC -shared -o $(WB_LIB_PATH)/$@ $(OBJECTS) $(LIBS) + +libwb.a: $(OBJECTS) + mkdir -p $(WB_LIB_PATH) + ar rcs -o $(WB_LIB_PATH)/$@ $(OBJECTS) + +test: $(TESTOBJECTS) $(OBJECTS) + $(CXX) -fPIC -o $@ $(TESTOBJECTS) $(OBJECTS) $(LIBS) + + +clean: + rm -fr $(ARCH) + -rm -f $(EXES) *.o *~ \ No newline at end of file diff --git a/CUDA_VectorAdd/libwb/README.md b/CUDA_VectorAdd/libwb/README.md new file mode 100644 index 0000000..0486f93 --- /dev/null +++ b/CUDA_VectorAdd/libwb/README.md @@ -0,0 +1,7 @@ + +# libWB + +[![Travis Build Status](https://travis-ci.org/abduld/libwb.svg?branch=master)](https://travis-ci.org/abduld/libwb) +[![AppVeyor status](https://ci.appveyor.com/api/projects/status/0nx5ie7gn5c0e6ai/branch/master?svg=true)](https://ci.appveyor.com/project/abduld/libwb/branch/master) + \ No newline at end of file diff --git a/CUDA_VectorAdd/libwb/appveyor.yml b/CUDA_VectorAdd/libwb/appveyor.yml new file mode 100644 index 0000000..e7a6c95 --- /dev/null +++ b/CUDA_VectorAdd/libwb/appveyor.yml @@ -0,0 +1,54 @@ + + +# Operating system (build VM template) +os: + - Visual Studio 2015 + + +# scripts that are called at very beginning, before repo cloning +init: + - echo init step + - git config --global core.autocrlf input + - cmake --version + - C:\"Program Files (x86)"\"Microsoft Visual Studio 14.0"\VC\vcvarsall.bat %PLATFORM% + +# clone directory +clone_folder: c:\projects\libwb +# fetch repository as zip archive +shallow_clone: true # default is "false" + +# branches to build +branches: + # whitelist + only: + - master + +platform: + - x64 +configuration: + - Release + +environment: + P: "c:/projects/libs" + + +install: + # by default, all script lines are interpreted as batch + +build: + project: ALL_BUILD.vcxproj # path to Visual Studio solution or project + +# scripts to run before build +before_build: + - echo Running cmake... + - cd c:\projects\libwb + - cmake -G "Visual Studio 14 2015 Win64" -DCMAKE_INSTALL_PREFIX=%P% + +# after_build: +# - echo after_build step + + +# on_finish always executes regardless of passed or failed builds +# on_finish: +# - echo on_finish step +# - ps: ls \ No newline at end of file diff --git a/CUDA_VectorAdd/libwb/sources.cmake b/CUDA_VectorAdd/libwb/sources.cmake new file mode 100644 index 0000000..4ac1b10 --- /dev/null +++ b/CUDA_VectorAdd/libwb/sources.cmake @@ -0,0 +1,31 @@ + +set(WBLIB "wb") + +include_directories(${CMAKE_CURRENT_LIST_DIR}) + +file(GLOB THESE_CPP_FILES + ${CMAKE_CURRENT_LIST_DIR}/*.cpp +) + +file(GLOB THESE_TEST_FILES + ${CMAKE_CURRENT_LIST_DIR}/*_test.cpp +) + +list(REMOVE_ITEM THESE_CPP_FILES ${THESE_TEST_FILES}) + +file(GLOB THESE_HEADER_FILES + ${CMAKE_CURRENT_LIST_DIR}/*.h +) + +list(APPEND LIBWB_HEADER_FILES + ${THESE_HEADER_FILES} +) + +list(APPEND LIBWB_SOURCE_FILES + ${THESE_CPP_FILES} + ${CMAKE_CURRENT_LIST_DIR}/vendor/json11.cpp +) + +list(APPEND LIBWB_TEST_FILES + ${THESE_TEST_FILES} +) diff --git a/CUDA_VectorAdd/libwb/vendor/catch.hpp b/CUDA_VectorAdd/libwb/vendor/catch.hpp new file mode 100644 index 0000000..f52eebd --- /dev/null +++ b/CUDA_VectorAdd/libwb/vendor/catch.hpp @@ -0,0 +1,10414 @@ +/* + * Catch v1.3.6 + * Generated: 2016-03-11 18:30:42.852700 + * ---------------------------------------------------------- + * This file has been merged from multiple headers. Please don't edit it directly + * Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved. + * + * Distributed under the Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + */ +#ifndef TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED +#define TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED + +#define TWOBLUECUBES_CATCH_HPP_INCLUDED + +#ifdef __clang__ +# pragma clang system_header +#elif defined __GNUC__ +# pragma GCC system_header +#endif + +// #included from: internal/catch_suppress_warnings.h + +#ifdef __clang__ +# ifdef __ICC // icpc defines the __clang__ macro +# pragma warning(push) +# pragma warning(disable: 161 1682) +# else // __ICC +# pragma clang diagnostic ignored "-Wglobal-constructors" +# pragma clang diagnostic ignored "-Wvariadic-macros" +# pragma clang diagnostic ignored "-Wc99-extensions" +# pragma clang diagnostic ignored "-Wunused-variable" +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wpadded" +# pragma clang diagnostic ignored "-Wc++98-compat" +# pragma clang diagnostic ignored "-Wc++98-compat-pedantic" +# pragma clang diagnostic ignored "-Wswitch-enum" +# pragma clang diagnostic ignored "-Wcovered-switch-default" +# endif +#elif defined __GNUC__ +# pragma GCC diagnostic ignored "-Wvariadic-macros" +# pragma GCC diagnostic ignored "-Wunused-variable" +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wpadded" +#endif +#if defined(CATCH_CONFIG_MAIN) || defined(CATCH_CONFIG_RUNNER) +# define CATCH_IMPL +#endif + +#ifdef CATCH_IMPL +# ifndef CLARA_CONFIG_MAIN +# define CLARA_CONFIG_MAIN_NOT_DEFINED +# define CLARA_CONFIG_MAIN +# endif +#endif + +// #included from: internal/catch_notimplemented_exception.h +#define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_H_INCLUDED + +// #included from: catch_common.h +#define TWOBLUECUBES_CATCH_COMMON_H_INCLUDED + +#define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line +#define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) +#define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ ) + +#define INTERNAL_CATCH_STRINGIFY2( expr ) #expr +#define INTERNAL_CATCH_STRINGIFY( expr ) INTERNAL_CATCH_STRINGIFY2( expr ) + +#include +#include +#include + +// #included from: catch_compiler_capabilities.h +#define TWOBLUECUBES_CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED + +// Detect a number of compiler features - mostly C++11/14 conformance - by compiler +// The following features are defined: +// +// CATCH_CONFIG_CPP11_NULLPTR : is nullptr supported? +// CATCH_CONFIG_CPP11_NOEXCEPT : is noexcept supported? +// CATCH_CONFIG_CPP11_GENERATED_METHODS : The delete and default keywords for compiler generated methods +// CATCH_CONFIG_CPP11_IS_ENUM : std::is_enum is supported? +// CATCH_CONFIG_CPP11_TUPLE : std::tuple is supported +// CATCH_CONFIG_CPP11_LONG_LONG : is long long supported? +// CATCH_CONFIG_CPP11_OVERRIDE : is override supported? +// CATCH_CONFIG_CPP11_UNIQUE_PTR : is unique_ptr supported (otherwise use auto_ptr) + +// CATCH_CONFIG_CPP11_OR_GREATER : Is C++11 supported? + +// CATCH_CONFIG_VARIADIC_MACROS : are variadic macros supported? + +// **************** +// Note to maintainers: if new toggles are added please document them +// in configuration.md, too +// **************** + +// In general each macro has a _NO_ form +// (e.g. CATCH_CONFIG_CPP11_NO_NULLPTR) which disables the feature. +// Many features, at point of detection, define an _INTERNAL_ macro, so they +// can be combined, en-mass, with the _NO_ forms later. + +// All the C++11 features can be disabled with CATCH_CONFIG_NO_CPP11 + +#if defined(__cplusplus) && __cplusplus >= 201103L +# define CATCH_CPP11_OR_GREATER +#endif + +#ifdef __clang__ + +# if __has_feature(cxx_nullptr) +# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR +# endif + +# if __has_feature(cxx_noexcept) +# define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT +# endif + +# if defined(CATCH_CPP11_OR_GREATER) +# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS _Pragma( "clang diagnostic ignored \"-Wparentheses\"" ) +# endif + +#endif // __clang__ + +//////////////////////////////////////////////////////////////////////////////// +// Borland +#ifdef __BORLANDC__ + +#endif // __BORLANDC__ + +//////////////////////////////////////////////////////////////////////////////// +// EDG +#ifdef __EDG_VERSION__ + +#endif // __EDG_VERSION__ + +//////////////////////////////////////////////////////////////////////////////// +// Digital Mars +#ifdef __DMC__ + +#endif // __DMC__ + +//////////////////////////////////////////////////////////////////////////////// +// GCC +#ifdef __GNUC__ + +# if __GNUC__ == 4 && __GNUC_MINOR__ >= 6 && defined(__GXX_EXPERIMENTAL_CXX0X__) +# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR +# endif + +# if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS) && defined(CATCH_CPP11_OR_GREATER) +# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS _Pragma( "GCC diagnostic ignored \"-Wparentheses\"" ) +# endif + +// - otherwise more recent versions define __cplusplus >= 201103L +// and will get picked up below + +#endif // __GNUC__ + +//////////////////////////////////////////////////////////////////////////////// +// Visual C++ +#ifdef _MSC_VER + +#if (_MSC_VER >= 1600) +# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR +# define CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR +#endif + +#if (_MSC_VER >= 1900 ) // (VC++ 13 (VS2015)) +#define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT +#define CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS +#endif + +#endif // _MSC_VER + +//////////////////////////////////////////////////////////////////////////////// + +// Use variadic macros if the compiler supports them +#if ( defined _MSC_VER && _MSC_VER > 1400 && !defined __EDGE__) || \ + ( defined __WAVE__ && __WAVE_HAS_VARIADICS ) || \ + ( defined __GNUC__ && __GNUC__ >= 3 ) || \ + ( !defined __cplusplus && __STDC_VERSION__ >= 199901L || __cplusplus >= 201103L ) + +#define CATCH_INTERNAL_CONFIG_VARIADIC_MACROS + +#endif + +//////////////////////////////////////////////////////////////////////////////// +// C++ language feature support + +// catch all support for C++11 +#if defined(CATCH_CPP11_OR_GREATER) + +# if !defined(CATCH_INTERNAL_CONFIG_CPP11_NULLPTR) +# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR +# endif + +# ifndef CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT +# define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT +# endif + +# ifndef CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS +# define CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS +# endif + +# ifndef CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM +# define CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM +# endif + +# ifndef CATCH_INTERNAL_CONFIG_CPP11_TUPLE +# define CATCH_INTERNAL_CONFIG_CPP11_TUPLE +# endif + +# ifndef CATCH_INTERNAL_CONFIG_VARIADIC_MACROS +# define CATCH_INTERNAL_CONFIG_VARIADIC_MACROS +# endif + +# if !defined(CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG) +# define CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG +# endif + +# if !defined(CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE) +# define CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE +# endif +# if !defined(CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) +# define CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR +# endif + +#endif // __cplusplus >= 201103L + +// Now set the actual defines based on the above + anything the user has configured +#if defined(CATCH_INTERNAL_CONFIG_CPP11_NULLPTR) && !defined(CATCH_CONFIG_CPP11_NO_NULLPTR) && !defined(CATCH_CONFIG_CPP11_NULLPTR) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_NULLPTR +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_CONFIG_CPP11_NO_NOEXCEPT) && !defined(CATCH_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_NOEXCEPT +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS) && !defined(CATCH_CONFIG_CPP11_NO_GENERATED_METHODS) && !defined(CATCH_CONFIG_CPP11_GENERATED_METHODS) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_GENERATED_METHODS +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM) && !defined(CATCH_CONFIG_CPP11_NO_IS_ENUM) && !defined(CATCH_CONFIG_CPP11_IS_ENUM) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_IS_ENUM +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_TUPLE) && !defined(CATCH_CONFIG_CPP11_NO_TUPLE) && !defined(CATCH_CONFIG_CPP11_TUPLE) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_TUPLE +#endif +#if defined(CATCH_INTERNAL_CONFIG_VARIADIC_MACROS) && !defined(CATCH_CONFIG_NO_VARIADIC_MACROS) && !defined(CATCH_CONFIG_VARIADIC_MACROS) +# define CATCH_CONFIG_VARIADIC_MACROS +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG) && !defined(CATCH_CONFIG_NO_LONG_LONG) && !defined(CATCH_CONFIG_CPP11_LONG_LONG) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_LONG_LONG +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE) && !defined(CATCH_CONFIG_NO_OVERRIDE) && !defined(CATCH_CONFIG_CPP11_OVERRIDE) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_OVERRIDE +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) && !defined(CATCH_CONFIG_NO_UNIQUE_PTR) && !defined(CATCH_CONFIG_CPP11_UNIQUE_PTR) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_UNIQUE_PTR +#endif + +#if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS) +# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS +#endif + +// noexcept support: +#if defined(CATCH_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_NOEXCEPT) +# define CATCH_NOEXCEPT noexcept +# define CATCH_NOEXCEPT_IS(x) noexcept(x) +#else +# define CATCH_NOEXCEPT throw() +# define CATCH_NOEXCEPT_IS(x) +#endif + +// nullptr support +#ifdef CATCH_CONFIG_CPP11_NULLPTR +# define CATCH_NULL nullptr +#else +# define CATCH_NULL NULL +#endif + +// override support +#ifdef CATCH_CONFIG_CPP11_OVERRIDE +# define CATCH_OVERRIDE override +#else +# define CATCH_OVERRIDE +#endif + +// unique_ptr support +#ifdef CATCH_CONFIG_CPP11_UNIQUE_PTR +# define CATCH_AUTO_PTR( T ) std::unique_ptr +#else +# define CATCH_AUTO_PTR( T ) std::auto_ptr +#endif + +namespace Catch { + + struct IConfig; + + struct CaseSensitive { enum Choice { + Yes, + No + }; }; + + class NonCopyable { +#ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + NonCopyable( NonCopyable const& ) = delete; + NonCopyable( NonCopyable && ) = delete; + NonCopyable& operator = ( NonCopyable const& ) = delete; + NonCopyable& operator = ( NonCopyable && ) = delete; +#else + NonCopyable( NonCopyable const& info ); + NonCopyable& operator = ( NonCopyable const& ); +#endif + + protected: + NonCopyable() {} + virtual ~NonCopyable(); + }; + + class SafeBool { + public: + typedef void (SafeBool::*type)() const; + + static type makeSafe( bool value ) { + return value ? &SafeBool::trueValue : 0; + } + private: + void trueValue() const {} + }; + + template + inline void deleteAll( ContainerT& container ) { + typename ContainerT::const_iterator it = container.begin(); + typename ContainerT::const_iterator itEnd = container.end(); + for(; it != itEnd; ++it ) + delete *it; + } + template + inline void deleteAllValues( AssociativeContainerT& container ) { + typename AssociativeContainerT::const_iterator it = container.begin(); + typename AssociativeContainerT::const_iterator itEnd = container.end(); + for(; it != itEnd; ++it ) + delete it->second; + } + + bool startsWith( std::string const& s, std::string const& prefix ); + bool endsWith( std::string const& s, std::string const& suffix ); + bool contains( std::string const& s, std::string const& infix ); + void toLowerInPlace( std::string& s ); + std::string toLower( std::string const& s ); + std::string trim( std::string const& str ); + bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ); + + struct pluralise { + pluralise( std::size_t count, std::string const& label ); + + friend std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ); + + std::size_t m_count; + std::string m_label; + }; + + struct SourceLineInfo { + + SourceLineInfo(); + SourceLineInfo( char const* _file, std::size_t _line ); + SourceLineInfo( SourceLineInfo const& other ); +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + SourceLineInfo( SourceLineInfo && ) = default; + SourceLineInfo& operator = ( SourceLineInfo const& ) = default; + SourceLineInfo& operator = ( SourceLineInfo && ) = default; +# endif + bool empty() const; + bool operator == ( SourceLineInfo const& other ) const; + bool operator < ( SourceLineInfo const& other ) const; + + std::string file; + std::size_t line; + }; + + std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ); + + // This is just here to avoid compiler warnings with macro constants and boolean literals + inline bool isTrue( bool value ){ return value; } + inline bool alwaysTrue() { return true; } + inline bool alwaysFalse() { return false; } + + void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo ); + + void seedRng( IConfig const& config ); + unsigned int rngSeed(); + + // Use this in variadic streaming macros to allow + // >> +StreamEndStop + // as well as + // >> stuff +StreamEndStop + struct StreamEndStop { + std::string operator+() { + return std::string(); + } + }; + template + T const& operator + ( T const& value, StreamEndStop ) { + return value; + } +} + +#define CATCH_INTERNAL_LINEINFO ::Catch::SourceLineInfo( __FILE__, static_cast( __LINE__ ) ) +#define CATCH_INTERNAL_ERROR( msg ) ::Catch::throwLogicError( msg, CATCH_INTERNAL_LINEINFO ); + +#include + +namespace Catch { + + class NotImplementedException : public std::exception + { + public: + NotImplementedException( SourceLineInfo const& lineInfo ); + NotImplementedException( NotImplementedException const& ) {} + + virtual ~NotImplementedException() CATCH_NOEXCEPT {} + + virtual const char* what() const CATCH_NOEXCEPT; + + private: + std::string m_what; + SourceLineInfo m_lineInfo; + }; + +} // end namespace Catch + +/////////////////////////////////////////////////////////////////////////////// +#define CATCH_NOT_IMPLEMENTED throw Catch::NotImplementedException( CATCH_INTERNAL_LINEINFO ) + +// #included from: internal/catch_context.h +#define TWOBLUECUBES_CATCH_CONTEXT_H_INCLUDED + +// #included from: catch_interfaces_generators.h +#define TWOBLUECUBES_CATCH_INTERFACES_GENERATORS_H_INCLUDED + +#include + +namespace Catch { + + struct IGeneratorInfo { + virtual ~IGeneratorInfo(); + virtual bool moveNext() = 0; + virtual std::size_t getCurrentIndex() const = 0; + }; + + struct IGeneratorsForTest { + virtual ~IGeneratorsForTest(); + + virtual IGeneratorInfo& getGeneratorInfo( std::string const& fileInfo, std::size_t size ) = 0; + virtual bool moveNext() = 0; + }; + + IGeneratorsForTest* createGeneratorsForTest(); + +} // end namespace Catch + +// #included from: catch_ptr.hpp +#define TWOBLUECUBES_CATCH_PTR_HPP_INCLUDED + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpadded" +#endif + +namespace Catch { + + // An intrusive reference counting smart pointer. + // T must implement addRef() and release() methods + // typically implementing the IShared interface + template + class Ptr { + public: + Ptr() : m_p( CATCH_NULL ){} + Ptr( T* p ) : m_p( p ){ + if( m_p ) + m_p->addRef(); + } + Ptr( Ptr const& other ) : m_p( other.m_p ){ + if( m_p ) + m_p->addRef(); + } + ~Ptr(){ + if( m_p ) + m_p->release(); + } + void reset() { + if( m_p ) + m_p->release(); + m_p = CATCH_NULL; + } + Ptr& operator = ( T* p ){ + Ptr temp( p ); + swap( temp ); + return *this; + } + Ptr& operator = ( Ptr const& other ){ + Ptr temp( other ); + swap( temp ); + return *this; + } + void swap( Ptr& other ) { std::swap( m_p, other.m_p ); } + T* get() const{ return m_p; } + T& operator*() const { return *m_p; } + T* operator->() const { return m_p; } + bool operator !() const { return m_p == CATCH_NULL; } + operator SafeBool::type() const { return SafeBool::makeSafe( m_p != CATCH_NULL ); } + + private: + T* m_p; + }; + + struct IShared : NonCopyable { + virtual ~IShared(); + virtual void addRef() const = 0; + virtual void release() const = 0; + }; + + template + struct SharedImpl : T { + + SharedImpl() : m_rc( 0 ){} + + virtual void addRef() const { + ++m_rc; + } + virtual void release() const { + if( --m_rc == 0 ) + delete this; + } + + mutable unsigned int m_rc; + }; + +} // end namespace Catch + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +#include +#include +#include + +namespace Catch { + + class TestCase; + class Stream; + struct IResultCapture; + struct IRunner; + struct IGeneratorsForTest; + struct IConfig; + + struct IContext + { + virtual ~IContext(); + + virtual IResultCapture* getResultCapture() = 0; + virtual IRunner* getRunner() = 0; + virtual size_t getGeneratorIndex( std::string const& fileInfo, size_t totalSize ) = 0; + virtual bool advanceGeneratorsForCurrentTest() = 0; + virtual Ptr getConfig() const = 0; + }; + + struct IMutableContext : IContext + { + virtual ~IMutableContext(); + virtual void setResultCapture( IResultCapture* resultCapture ) = 0; + virtual void setRunner( IRunner* runner ) = 0; + virtual void setConfig( Ptr const& config ) = 0; + }; + + IContext& getCurrentContext(); + IMutableContext& getCurrentMutableContext(); + void cleanUpContext(); + Stream createStream( std::string const& streamName ); + +} + +// #included from: internal/catch_test_registry.hpp +#define TWOBLUECUBES_CATCH_TEST_REGISTRY_HPP_INCLUDED + +// #included from: catch_interfaces_testcase.h +#define TWOBLUECUBES_CATCH_INTERFACES_TESTCASE_H_INCLUDED + +#include + +namespace Catch { + + class TestSpec; + + struct ITestCase : IShared { + virtual void invoke () const = 0; + protected: + virtual ~ITestCase(); + }; + + class TestCase; + struct IConfig; + + struct ITestCaseRegistry { + virtual ~ITestCaseRegistry(); + virtual std::vector const& getAllTests() const = 0; + virtual std::vector const& getAllTestsSorted( IConfig const& config ) const = 0; + }; + + bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ); + std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ); + std::vector const& getAllTestCasesSorted( IConfig const& config ); + +} + +namespace Catch { + +template +class MethodTestCase : public SharedImpl { + +public: + MethodTestCase( void (C::*method)() ) : m_method( method ) {} + + virtual void invoke() const { + C obj; + (obj.*m_method)(); + } + +private: + virtual ~MethodTestCase() {} + + void (C::*m_method)(); +}; + +typedef void(*TestFunction)(); + +struct NameAndDesc { + NameAndDesc( const char* _name = "", const char* _description= "" ) + : name( _name ), description( _description ) + {} + + const char* name; + const char* description; +}; + +void registerTestCase + ( ITestCase* testCase, + char const* className, + NameAndDesc const& nameAndDesc, + SourceLineInfo const& lineInfo ); + +struct AutoReg { + + AutoReg + ( TestFunction function, + SourceLineInfo const& lineInfo, + NameAndDesc const& nameAndDesc ); + + template + AutoReg + ( void (C::*method)(), + char const* className, + NameAndDesc const& nameAndDesc, + SourceLineInfo const& lineInfo ) { + + registerTestCase + ( new MethodTestCase( method ), + className, + nameAndDesc, + lineInfo ); + } + + ~AutoReg(); + +private: + AutoReg( AutoReg const& ); + void operator= ( AutoReg const& ); +}; + +void registerTestCaseFunction + ( TestFunction function, + SourceLineInfo const& lineInfo, + NameAndDesc const& nameAndDesc ); + +} // end namespace Catch + +#ifdef CATCH_CONFIG_VARIADIC_MACROS + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_TESTCASE( ... ) \ + static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )(); \ + namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( __VA_ARGS__ ) ); }\ + static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )() + + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \ + namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); } + + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, ... )\ + namespace{ \ + struct INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ) : ClassName{ \ + void test(); \ + }; \ + Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test, #ClassName, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); \ + } \ + void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test() + + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, ... ) \ + Catch::AutoReg( Function, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( __VA_ARGS__ ) ); + +#else + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_TESTCASE( Name, Desc ) \ + static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )(); \ + namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( Name, Desc ) ); }\ + static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )() + + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, Name, Desc ) \ + namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( Name, Desc ), CATCH_INTERNAL_LINEINFO ); } + + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, TestName, Desc )\ + namespace{ \ + struct INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ) : ClassName{ \ + void test(); \ + }; \ + Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test, #ClassName, Catch::NameAndDesc( TestName, Desc ), CATCH_INTERNAL_LINEINFO ); \ + } \ + void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test() + + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, Name, Desc ) \ + Catch::AutoReg( Function, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( Name, Desc ) ); +#endif + +// #included from: internal/catch_capture.hpp +#define TWOBLUECUBES_CATCH_CAPTURE_HPP_INCLUDED + +// #included from: catch_result_builder.h +#define TWOBLUECUBES_CATCH_RESULT_BUILDER_H_INCLUDED + +// #included from: catch_result_type.h +#define TWOBLUECUBES_CATCH_RESULT_TYPE_H_INCLUDED + +namespace Catch { + + // ResultWas::OfType enum + struct ResultWas { enum OfType { + Unknown = -1, + Ok = 0, + Info = 1, + Warning = 2, + + FailureBit = 0x10, + + ExpressionFailed = FailureBit | 1, + ExplicitFailure = FailureBit | 2, + + Exception = 0x100 | FailureBit, + + ThrewException = Exception | 1, + DidntThrowException = Exception | 2, + + FatalErrorCondition = 0x200 | FailureBit + + }; }; + + inline bool isOk( ResultWas::OfType resultType ) { + return ( resultType & ResultWas::FailureBit ) == 0; + } + inline bool isJustInfo( int flags ) { + return flags == ResultWas::Info; + } + + // ResultDisposition::Flags enum + struct ResultDisposition { enum Flags { + Normal = 0x01, + + ContinueOnFailure = 0x02, // Failures fail test, but execution continues + FalseTest = 0x04, // Prefix expression with ! + SuppressFail = 0x08 // Failures are reported but do not fail the test + }; }; + + inline ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs ) { + return static_cast( static_cast( lhs ) | static_cast( rhs ) ); + } + + inline bool shouldContinueOnFailure( int flags ) { return ( flags & ResultDisposition::ContinueOnFailure ) != 0; } + inline bool isFalseTest( int flags ) { return ( flags & ResultDisposition::FalseTest ) != 0; } + inline bool shouldSuppressFailure( int flags ) { return ( flags & ResultDisposition::SuppressFail ) != 0; } + +} // end namespace Catch + +// #included from: catch_assertionresult.h +#define TWOBLUECUBES_CATCH_ASSERTIONRESULT_H_INCLUDED + +#include + +namespace Catch { + + struct AssertionInfo + { + AssertionInfo() {} + AssertionInfo( std::string const& _macroName, + SourceLineInfo const& _lineInfo, + std::string const& _capturedExpression, + ResultDisposition::Flags _resultDisposition ); + + std::string macroName; + SourceLineInfo lineInfo; + std::string capturedExpression; + ResultDisposition::Flags resultDisposition; + }; + + struct AssertionResultData + { + AssertionResultData() : resultType( ResultWas::Unknown ) {} + + std::string reconstructedExpression; + std::string message; + ResultWas::OfType resultType; + }; + + class AssertionResult { + public: + AssertionResult(); + AssertionResult( AssertionInfo const& info, AssertionResultData const& data ); + ~AssertionResult(); +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + AssertionResult( AssertionResult const& ) = default; + AssertionResult( AssertionResult && ) = default; + AssertionResult& operator = ( AssertionResult const& ) = default; + AssertionResult& operator = ( AssertionResult && ) = default; +# endif + + bool isOk() const; + bool succeeded() const; + ResultWas::OfType getResultType() const; + bool hasExpression() const; + bool hasMessage() const; + std::string getExpression() const; + std::string getExpressionInMacro() const; + bool hasExpandedExpression() const; + std::string getExpandedExpression() const; + std::string getMessage() const; + SourceLineInfo getSourceInfo() const; + std::string getTestMacroName() const; + + protected: + AssertionInfo m_info; + AssertionResultData m_resultData; + }; + +} // end namespace Catch + +// #included from: catch_matchers.hpp +#define TWOBLUECUBES_CATCH_MATCHERS_HPP_INCLUDED + +namespace Catch { +namespace Matchers { + namespace Impl { + + namespace Generic { + template class AllOf; + template class AnyOf; + template class Not; + } + + template + struct Matcher : SharedImpl + { + typedef ExpressionT ExpressionType; + + virtual ~Matcher() {} + virtual Ptr clone() const = 0; + virtual bool match( ExpressionT const& expr ) const = 0; + virtual std::string toString() const = 0; + + Generic::AllOf operator && ( Matcher const& other ) const; + Generic::AnyOf operator || ( Matcher const& other ) const; + Generic::Not operator ! () const; + }; + + template + struct MatcherImpl : Matcher { + + virtual Ptr > clone() const { + return Ptr >( new DerivedT( static_cast( *this ) ) ); + } + }; + + namespace Generic { + template + class Not : public MatcherImpl, ExpressionT> { + public: + explicit Not( Matcher const& matcher ) : m_matcher(matcher.clone()) {} + Not( Not const& other ) : m_matcher( other.m_matcher ) {} + + virtual bool match( ExpressionT const& expr ) const CATCH_OVERRIDE { + return !m_matcher->match( expr ); + } + + virtual std::string toString() const CATCH_OVERRIDE { + return "not " + m_matcher->toString(); + } + private: + Ptr< Matcher > m_matcher; + }; + + template + class AllOf : public MatcherImpl, ExpressionT> { + public: + + AllOf() {} + AllOf( AllOf const& other ) : m_matchers( other.m_matchers ) {} + + AllOf& add( Matcher const& matcher ) { + m_matchers.push_back( matcher.clone() ); + return *this; + } + virtual bool match( ExpressionT const& expr ) const + { + for( std::size_t i = 0; i < m_matchers.size(); ++i ) + if( !m_matchers[i]->match( expr ) ) + return false; + return true; + } + virtual std::string toString() const { + std::ostringstream oss; + oss << "( "; + for( std::size_t i = 0; i < m_matchers.size(); ++i ) { + if( i != 0 ) + oss << " and "; + oss << m_matchers[i]->toString(); + } + oss << " )"; + return oss.str(); + } + + AllOf operator && ( Matcher const& other ) const { + AllOf allOfExpr( *this ); + allOfExpr.add( other ); + return allOfExpr; + } + + private: + std::vector > > m_matchers; + }; + + template + class AnyOf : public MatcherImpl, ExpressionT> { + public: + + AnyOf() {} + AnyOf( AnyOf const& other ) : m_matchers( other.m_matchers ) {} + + AnyOf& add( Matcher const& matcher ) { + m_matchers.push_back( matcher.clone() ); + return *this; + } + virtual bool match( ExpressionT const& expr ) const + { + for( std::size_t i = 0; i < m_matchers.size(); ++i ) + if( m_matchers[i]->match( expr ) ) + return true; + return false; + } + virtual std::string toString() const { + std::ostringstream oss; + oss << "( "; + for( std::size_t i = 0; i < m_matchers.size(); ++i ) { + if( i != 0 ) + oss << " or "; + oss << m_matchers[i]->toString(); + } + oss << " )"; + return oss.str(); + } + + AnyOf operator || ( Matcher const& other ) const { + AnyOf anyOfExpr( *this ); + anyOfExpr.add( other ); + return anyOfExpr; + } + + private: + std::vector > > m_matchers; + }; + + } // namespace Generic + + template + Generic::AllOf Matcher::operator && ( Matcher const& other ) const { + Generic::AllOf allOfExpr; + allOfExpr.add( *this ); + allOfExpr.add( other ); + return allOfExpr; + } + + template + Generic::AnyOf Matcher::operator || ( Matcher const& other ) const { + Generic::AnyOf anyOfExpr; + anyOfExpr.add( *this ); + anyOfExpr.add( other ); + return anyOfExpr; + } + + template + Generic::Not Matcher::operator ! () const { + return Generic::Not( *this ); + } + + namespace StdString { + + inline std::string makeString( std::string const& str ) { return str; } + inline std::string makeString( const char* str ) { return str ? std::string( str ) : std::string(); } + + struct CasedString + { + CasedString( std::string const& str, CaseSensitive::Choice caseSensitivity ) + : m_caseSensitivity( caseSensitivity ), + m_str( adjustString( str ) ) + {} + std::string adjustString( std::string const& str ) const { + return m_caseSensitivity == CaseSensitive::No + ? toLower( str ) + : str; + + } + std::string toStringSuffix() const + { + return m_caseSensitivity == CaseSensitive::No + ? " (case insensitive)" + : ""; + } + CaseSensitive::Choice m_caseSensitivity; + std::string m_str; + }; + + struct Equals : MatcherImpl { + Equals( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) + : m_data( str, caseSensitivity ) + {} + Equals( Equals const& other ) : m_data( other.m_data ){} + + virtual ~Equals(); + + virtual bool match( std::string const& expr ) const { + return m_data.m_str == m_data.adjustString( expr );; + } + virtual std::string toString() const { + return "equals: \"" + m_data.m_str + "\"" + m_data.toStringSuffix(); + } + + CasedString m_data; + }; + + struct Contains : MatcherImpl { + Contains( std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) + : m_data( substr, caseSensitivity ){} + Contains( Contains const& other ) : m_data( other.m_data ){} + + virtual ~Contains(); + + virtual bool match( std::string const& expr ) const { + return m_data.adjustString( expr ).find( m_data.m_str ) != std::string::npos; + } + virtual std::string toString() const { + return "contains: \"" + m_data.m_str + "\"" + m_data.toStringSuffix(); + } + + CasedString m_data; + }; + + struct StartsWith : MatcherImpl { + StartsWith( std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) + : m_data( substr, caseSensitivity ){} + + StartsWith( StartsWith const& other ) : m_data( other.m_data ){} + + virtual ~StartsWith(); + + virtual bool match( std::string const& expr ) const { + return startsWith( m_data.adjustString( expr ), m_data.m_str ); + } + virtual std::string toString() const { + return "starts with: \"" + m_data.m_str + "\"" + m_data.toStringSuffix(); + } + + CasedString m_data; + }; + + struct EndsWith : MatcherImpl { + EndsWith( std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) + : m_data( substr, caseSensitivity ){} + EndsWith( EndsWith const& other ) : m_data( other.m_data ){} + + virtual ~EndsWith(); + + virtual bool match( std::string const& expr ) const { + return endsWith( m_data.adjustString( expr ), m_data.m_str ); + } + virtual std::string toString() const { + return "ends with: \"" + m_data.m_str + "\"" + m_data.toStringSuffix(); + } + + CasedString m_data; + }; + } // namespace StdString + } // namespace Impl + + // The following functions create the actual matcher objects. + // This allows the types to be inferred + template + inline Impl::Generic::Not Not( Impl::Matcher const& m ) { + return Impl::Generic::Not( m ); + } + + template + inline Impl::Generic::AllOf AllOf( Impl::Matcher const& m1, + Impl::Matcher const& m2 ) { + return Impl::Generic::AllOf().add( m1 ).add( m2 ); + } + template + inline Impl::Generic::AllOf AllOf( Impl::Matcher const& m1, + Impl::Matcher const& m2, + Impl::Matcher const& m3 ) { + return Impl::Generic::AllOf().add( m1 ).add( m2 ).add( m3 ); + } + template + inline Impl::Generic::AnyOf AnyOf( Impl::Matcher const& m1, + Impl::Matcher const& m2 ) { + return Impl::Generic::AnyOf().add( m1 ).add( m2 ); + } + template + inline Impl::Generic::AnyOf AnyOf( Impl::Matcher const& m1, + Impl::Matcher const& m2, + Impl::Matcher const& m3 ) { + return Impl::Generic::AnyOf().add( m1 ).add( m2 ).add( m3 ); + } + + inline Impl::StdString::Equals Equals( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) { + return Impl::StdString::Equals( str, caseSensitivity ); + } + inline Impl::StdString::Equals Equals( const char* str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) { + return Impl::StdString::Equals( Impl::StdString::makeString( str ), caseSensitivity ); + } + inline Impl::StdString::Contains Contains( std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) { + return Impl::StdString::Contains( substr, caseSensitivity ); + } + inline Impl::StdString::Contains Contains( const char* substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) { + return Impl::StdString::Contains( Impl::StdString::makeString( substr ), caseSensitivity ); + } + inline Impl::StdString::StartsWith StartsWith( std::string const& substr ) { + return Impl::StdString::StartsWith( substr ); + } + inline Impl::StdString::StartsWith StartsWith( const char* substr ) { + return Impl::StdString::StartsWith( Impl::StdString::makeString( substr ) ); + } + inline Impl::StdString::EndsWith EndsWith( std::string const& substr ) { + return Impl::StdString::EndsWith( substr ); + } + inline Impl::StdString::EndsWith EndsWith( const char* substr ) { + return Impl::StdString::EndsWith( Impl::StdString::makeString( substr ) ); + } + +} // namespace Matchers + +using namespace Matchers; + +} // namespace Catch + +namespace Catch { + + struct TestFailureException{}; + + template class ExpressionLhs; + + struct STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison; + + struct CopyableStream { + CopyableStream() {} + CopyableStream( CopyableStream const& other ) { + oss << other.oss.str(); + } + CopyableStream& operator=( CopyableStream const& other ) { + oss.str(""); + oss << other.oss.str(); + return *this; + } + std::ostringstream oss; + }; + + class ResultBuilder { + public: + ResultBuilder( char const* macroName, + SourceLineInfo const& lineInfo, + char const* capturedExpression, + ResultDisposition::Flags resultDisposition, + char const* secondArg = "" ); + + template + ExpressionLhs operator <= ( T const& operand ); + ExpressionLhs operator <= ( bool value ); + + template + ResultBuilder& operator << ( T const& value ) { + m_stream.oss << value; + return *this; + } + + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( RhsT const& ); + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || ( RhsT const& ); + + ResultBuilder& setResultType( ResultWas::OfType result ); + ResultBuilder& setResultType( bool result ); + ResultBuilder& setLhs( std::string const& lhs ); + ResultBuilder& setRhs( std::string const& rhs ); + ResultBuilder& setOp( std::string const& op ); + + void endExpression(); + + std::string reconstructExpression() const; + AssertionResult build() const; + + void useActiveException( ResultDisposition::Flags resultDisposition = ResultDisposition::Normal ); + void captureResult( ResultWas::OfType resultType ); + void captureExpression(); + void captureExpectedException( std::string const& expectedMessage ); + void captureExpectedException( Matchers::Impl::Matcher const& matcher ); + void handleResult( AssertionResult const& result ); + void react(); + bool shouldDebugBreak() const; + bool allowThrows() const; + + private: + AssertionInfo m_assertionInfo; + AssertionResultData m_data; + struct ExprComponents { + ExprComponents() : testFalse( false ) {} + bool testFalse; + std::string lhs, rhs, op; + } m_exprComponents; + CopyableStream m_stream; + + bool m_shouldDebugBreak; + bool m_shouldThrow; + }; + +} // namespace Catch + +// Include after due to circular dependency: +// #included from: catch_expression_lhs.hpp +#define TWOBLUECUBES_CATCH_EXPRESSION_LHS_HPP_INCLUDED + +// #included from: catch_evaluate.hpp +#define TWOBLUECUBES_CATCH_EVALUATE_HPP_INCLUDED + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable:4389) // '==' : signed/unsigned mismatch +#endif + +#include + +namespace Catch { +namespace Internal { + + enum Operator { + IsEqualTo, + IsNotEqualTo, + IsLessThan, + IsGreaterThan, + IsLessThanOrEqualTo, + IsGreaterThanOrEqualTo + }; + + template struct OperatorTraits { static const char* getName(){ return "*error*"; } }; + template<> struct OperatorTraits { static const char* getName(){ return "=="; } }; + template<> struct OperatorTraits { static const char* getName(){ return "!="; } }; + template<> struct OperatorTraits { static const char* getName(){ return "<"; } }; + template<> struct OperatorTraits { static const char* getName(){ return ">"; } }; + template<> struct OperatorTraits { static const char* getName(){ return "<="; } }; + template<> struct OperatorTraits{ static const char* getName(){ return ">="; } }; + + template + inline T& opCast(T const& t) { return const_cast(t); } + +// nullptr_t support based on pull request #154 from Konstantin Baumann +#ifdef CATCH_CONFIG_CPP11_NULLPTR + inline std::nullptr_t opCast(std::nullptr_t) { return nullptr; } +#endif // CATCH_CONFIG_CPP11_NULLPTR + + // So the compare overloads can be operator agnostic we convey the operator as a template + // enum, which is used to specialise an Evaluator for doing the comparison. + template + class Evaluator{}; + + template + struct Evaluator { + static bool evaluate( T1 const& lhs, T2 const& rhs) { + return bool( opCast( lhs ) == opCast( rhs ) ); + } + }; + template + struct Evaluator { + static bool evaluate( T1 const& lhs, T2 const& rhs ) { + return bool( opCast( lhs ) != opCast( rhs ) ); + } + }; + template + struct Evaluator { + static bool evaluate( T1 const& lhs, T2 const& rhs ) { + return bool( opCast( lhs ) < opCast( rhs ) ); + } + }; + template + struct Evaluator { + static bool evaluate( T1 const& lhs, T2 const& rhs ) { + return bool( opCast( lhs ) > opCast( rhs ) ); + } + }; + template + struct Evaluator { + static bool evaluate( T1 const& lhs, T2 const& rhs ) { + return bool( opCast( lhs ) >= opCast( rhs ) ); + } + }; + template + struct Evaluator { + static bool evaluate( T1 const& lhs, T2 const& rhs ) { + return bool( opCast( lhs ) <= opCast( rhs ) ); + } + }; + + template + bool applyEvaluator( T1 const& lhs, T2 const& rhs ) { + return Evaluator::evaluate( lhs, rhs ); + } + + // This level of indirection allows us to specialise for integer types + // to avoid signed/ unsigned warnings + + // "base" overload + template + bool compare( T1 const& lhs, T2 const& rhs ) { + return Evaluator::evaluate( lhs, rhs ); + } + + // unsigned X to int + template bool compare( unsigned int lhs, int rhs ) { + return applyEvaluator( lhs, static_cast( rhs ) ); + } + template bool compare( unsigned long lhs, int rhs ) { + return applyEvaluator( lhs, static_cast( rhs ) ); + } + template bool compare( unsigned char lhs, int rhs ) { + return applyEvaluator( lhs, static_cast( rhs ) ); + } + + // unsigned X to long + template bool compare( unsigned int lhs, long rhs ) { + return applyEvaluator( lhs, static_cast( rhs ) ); + } + template bool compare( unsigned long lhs, long rhs ) { + return applyEvaluator( lhs, static_cast( rhs ) ); + } + template bool compare( unsigned char lhs, long rhs ) { + return applyEvaluator( lhs, static_cast( rhs ) ); + } + + // int to unsigned X + template bool compare( int lhs, unsigned int rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( int lhs, unsigned long rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( int lhs, unsigned char rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + + // long to unsigned X + template bool compare( long lhs, unsigned int rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( long lhs, unsigned long rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( long lhs, unsigned char rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + + // pointer to long (when comparing against NULL) + template bool compare( long lhs, T* rhs ) { + return Evaluator::evaluate( reinterpret_cast( lhs ), rhs ); + } + template bool compare( T* lhs, long rhs ) { + return Evaluator::evaluate( lhs, reinterpret_cast( rhs ) ); + } + + // pointer to int (when comparing against NULL) + template bool compare( int lhs, T* rhs ) { + return Evaluator::evaluate( reinterpret_cast( lhs ), rhs ); + } + template bool compare( T* lhs, int rhs ) { + return Evaluator::evaluate( lhs, reinterpret_cast( rhs ) ); + } + +#ifdef CATCH_CONFIG_CPP11_LONG_LONG + // long long to unsigned X + template bool compare( long long lhs, unsigned int rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( long long lhs, unsigned long rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( long long lhs, unsigned long long rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( long long lhs, unsigned char rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + + // unsigned long long to X + template bool compare( unsigned long long lhs, int rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( unsigned long long lhs, long rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( unsigned long long lhs, long long rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( unsigned long long lhs, char rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + + // pointer to long long (when comparing against NULL) + template bool compare( long long lhs, T* rhs ) { + return Evaluator::evaluate( reinterpret_cast( lhs ), rhs ); + } + template bool compare( T* lhs, long long rhs ) { + return Evaluator::evaluate( lhs, reinterpret_cast( rhs ) ); + } +#endif // CATCH_CONFIG_CPP11_LONG_LONG + +#ifdef CATCH_CONFIG_CPP11_NULLPTR + // pointer to nullptr_t (when comparing against nullptr) + template bool compare( std::nullptr_t, T* rhs ) { + return Evaluator::evaluate( nullptr, rhs ); + } + template bool compare( T* lhs, std::nullptr_t ) { + return Evaluator::evaluate( lhs, nullptr ); + } +#endif // CATCH_CONFIG_CPP11_NULLPTR + +} // end of namespace Internal +} // end of namespace Catch + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +// #included from: catch_tostring.h +#define TWOBLUECUBES_CATCH_TOSTRING_H_INCLUDED + +#include +#include +#include +#include +#include + +#ifdef __OBJC__ +// #included from: catch_objc_arc.hpp +#define TWOBLUECUBES_CATCH_OBJC_ARC_HPP_INCLUDED + +#import + +#ifdef __has_feature +#define CATCH_ARC_ENABLED __has_feature(objc_arc) +#else +#define CATCH_ARC_ENABLED 0 +#endif + +void arcSafeRelease( NSObject* obj ); +id performOptionalSelector( id obj, SEL sel ); + +#if !CATCH_ARC_ENABLED +inline void arcSafeRelease( NSObject* obj ) { + [obj release]; +} +inline id performOptionalSelector( id obj, SEL sel ) { + if( [obj respondsToSelector: sel] ) + return [obj performSelector: sel]; + return nil; +} +#define CATCH_UNSAFE_UNRETAINED +#define CATCH_ARC_STRONG +#else +inline void arcSafeRelease( NSObject* ){} +inline id performOptionalSelector( id obj, SEL sel ) { +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Warc-performSelector-leaks" +#endif + if( [obj respondsToSelector: sel] ) + return [obj performSelector: sel]; +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + return nil; +} +#define CATCH_UNSAFE_UNRETAINED __unsafe_unretained +#define CATCH_ARC_STRONG __strong +#endif + +#endif + +#ifdef CATCH_CONFIG_CPP11_TUPLE +#include +#endif + +#ifdef CATCH_CONFIG_CPP11_IS_ENUM +#include +#endif + +namespace Catch { + +// Why we're here. +template +std::string toString( T const& value ); + +// Built in overloads + +std::string toString( std::string const& value ); +std::string toString( std::wstring const& value ); +std::string toString( const char* const value ); +std::string toString( char* const value ); +std::string toString( const wchar_t* const value ); +std::string toString( wchar_t* const value ); +std::string toString( int value ); +std::string toString( unsigned long value ); +std::string toString( unsigned int value ); +std::string toString( const double value ); +std::string toString( const float value ); +std::string toString( bool value ); +std::string toString( char value ); +std::string toString( signed char value ); +std::string toString( unsigned char value ); + +#ifdef CATCH_CONFIG_CPP11_LONG_LONG +std::string toString( long long value ); +std::string toString( unsigned long long value ); +#endif + +#ifdef CATCH_CONFIG_CPP11_NULLPTR +std::string toString( std::nullptr_t ); +#endif + +#ifdef __OBJC__ + std::string toString( NSString const * const& nsstring ); + std::string toString( NSString * CATCH_ARC_STRONG const& nsstring ); + std::string toString( NSObject* const& nsObject ); +#endif + +namespace Detail { + + extern const std::string unprintableString; + + struct BorgType { + template BorgType( T const& ); + }; + + struct TrueType { char sizer[1]; }; + struct FalseType { char sizer[2]; }; + + TrueType& testStreamable( std::ostream& ); + FalseType testStreamable( FalseType ); + + FalseType operator<<( std::ostream const&, BorgType const& ); + + template + struct IsStreamInsertable { + static std::ostream &s; + static T const&t; + enum { value = sizeof( testStreamable(s << t) ) == sizeof( TrueType ) }; + }; + +#if defined(CATCH_CONFIG_CPP11_IS_ENUM) + template::value + > + struct EnumStringMaker + { + static std::string convert( T const& ) { return unprintableString; } + }; + + template + struct EnumStringMaker + { + static std::string convert( T const& v ) + { + return ::Catch::toString( + static_cast::type>(v) + ); + } + }; +#endif + template + struct StringMakerBase { +#if defined(CATCH_CONFIG_CPP11_IS_ENUM) + template + static std::string convert( T const& v ) + { + return EnumStringMaker::convert( v ); + } +#else + template + static std::string convert( T const& ) { return unprintableString; } +#endif + }; + + template<> + struct StringMakerBase { + template + static std::string convert( T const& _value ) { + std::ostringstream oss; + oss << _value; + return oss.str(); + } + }; + + std::string rawMemoryToString( const void *object, std::size_t size ); + + template + inline std::string rawMemoryToString( const T& object ) { + return rawMemoryToString( &object, sizeof(object) ); + } + +} // end namespace Detail + +template +struct StringMaker : + Detail::StringMakerBase::value> {}; + +template +struct StringMaker { + template + static std::string convert( U* p ) { + if( !p ) + return "NULL"; + else + return Detail::rawMemoryToString( p ); + } +}; + +template +struct StringMaker { + static std::string convert( R C::* p ) { + if( !p ) + return "NULL"; + else + return Detail::rawMemoryToString( p ); + } +}; + +namespace Detail { + template + std::string rangeToString( InputIterator first, InputIterator last ); +} + +//template +//struct StringMaker > { +// static std::string convert( std::vector const& v ) { +// return Detail::rangeToString( v.begin(), v.end() ); +// } +//}; + +template +std::string toString( std::vector const& v ) { + return Detail::rangeToString( v.begin(), v.end() ); +} + +#ifdef CATCH_CONFIG_CPP11_TUPLE + +// toString for tuples +namespace TupleDetail { + template< + typename Tuple, + std::size_t N = 0, + bool = (N < std::tuple_size::value) + > + struct ElementPrinter { + static void print( const Tuple& tuple, std::ostream& os ) + { + os << ( N ? ", " : " " ) + << Catch::toString(std::get(tuple)); + ElementPrinter::print(tuple,os); + } + }; + + template< + typename Tuple, + std::size_t N + > + struct ElementPrinter { + static void print( const Tuple&, std::ostream& ) {} + }; + +} + +template +struct StringMaker> { + + static std::string convert( const std::tuple& tuple ) + { + std::ostringstream os; + os << '{'; + TupleDetail::ElementPrinter>::print( tuple, os ); + os << " }"; + return os.str(); + } +}; +#endif // CATCH_CONFIG_CPP11_TUPLE + +namespace Detail { + template + std::string makeString( T const& value ) { + return StringMaker::convert( value ); + } +} // end namespace Detail + +/// \brief converts any type to a string +/// +/// The default template forwards on to ostringstream - except when an +/// ostringstream overload does not exist - in which case it attempts to detect +/// that and writes {?}. +/// Overload (not specialise) this template for custom typs that you don't want +/// to provide an ostream overload for. +template +std::string toString( T const& value ) { + return StringMaker::convert( value ); +} + + namespace Detail { + template + std::string rangeToString( InputIterator first, InputIterator last ) { + std::ostringstream oss; + oss << "{ "; + if( first != last ) { + oss << Catch::toString( *first ); + for( ++first ; first != last ; ++first ) + oss << ", " << Catch::toString( *first ); + } + oss << " }"; + return oss.str(); + } +} + +} // end namespace Catch + +namespace Catch { + +// Wraps the LHS of an expression and captures the operator and RHS (if any) - +// wrapping them all in a ResultBuilder object +template +class ExpressionLhs { + ExpressionLhs& operator = ( ExpressionLhs const& ); +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + ExpressionLhs& operator = ( ExpressionLhs && ) = delete; +# endif + +public: + ExpressionLhs( ResultBuilder& rb, T lhs ) : m_rb( rb ), m_lhs( lhs ) {} +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + ExpressionLhs( ExpressionLhs const& ) = default; + ExpressionLhs( ExpressionLhs && ) = default; +# endif + + template + ResultBuilder& operator == ( RhsT const& rhs ) { + return captureExpression( rhs ); + } + + template + ResultBuilder& operator != ( RhsT const& rhs ) { + return captureExpression( rhs ); + } + + template + ResultBuilder& operator < ( RhsT const& rhs ) { + return captureExpression( rhs ); + } + + template + ResultBuilder& operator > ( RhsT const& rhs ) { + return captureExpression( rhs ); + } + + template + ResultBuilder& operator <= ( RhsT const& rhs ) { + return captureExpression( rhs ); + } + + template + ResultBuilder& operator >= ( RhsT const& rhs ) { + return captureExpression( rhs ); + } + + ResultBuilder& operator == ( bool rhs ) { + return captureExpression( rhs ); + } + + ResultBuilder& operator != ( bool rhs ) { + return captureExpression( rhs ); + } + + void endExpression() { + bool value = m_lhs ? true : false; + m_rb + .setLhs( Catch::toString( value ) ) + .setResultType( value ) + .endExpression(); + } + + // Only simple binary expressions are allowed on the LHS. + // If more complex compositions are required then place the sub expression in parentheses + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator + ( RhsT const& ); + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator - ( RhsT const& ); + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator / ( RhsT const& ); + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator * ( RhsT const& ); + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( RhsT const& ); + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || ( RhsT const& ); + +private: + template + ResultBuilder& captureExpression( RhsT const& rhs ) { + return m_rb + .setResultType( Internal::compare( m_lhs, rhs ) ) + .setLhs( Catch::toString( m_lhs ) ) + .setRhs( Catch::toString( rhs ) ) + .setOp( Internal::OperatorTraits::getName() ); + } + +private: + ResultBuilder& m_rb; + T m_lhs; +}; + +} // end namespace Catch + + +namespace Catch { + + template + inline ExpressionLhs ResultBuilder::operator <= ( T const& operand ) { + return ExpressionLhs( *this, operand ); + } + + inline ExpressionLhs ResultBuilder::operator <= ( bool value ) { + return ExpressionLhs( *this, value ); + } + +} // namespace Catch + +// #included from: catch_message.h +#define TWOBLUECUBES_CATCH_MESSAGE_H_INCLUDED + +#include + +namespace Catch { + + struct MessageInfo { + MessageInfo( std::string const& _macroName, + SourceLineInfo const& _lineInfo, + ResultWas::OfType _type ); + + std::string macroName; + SourceLineInfo lineInfo; + ResultWas::OfType type; + std::string message; + unsigned int sequence; + + bool operator == ( MessageInfo const& other ) const { + return sequence == other.sequence; + } + bool operator < ( MessageInfo const& other ) const { + return sequence < other.sequence; + } + private: + static unsigned int globalCount; + }; + + struct MessageBuilder { + MessageBuilder( std::string const& macroName, + SourceLineInfo const& lineInfo, + ResultWas::OfType type ) + : m_info( macroName, lineInfo, type ) + {} + + template + MessageBuilder& operator << ( T const& value ) { + m_stream << value; + return *this; + } + + MessageInfo m_info; + std::ostringstream m_stream; + }; + + class ScopedMessage { + public: + ScopedMessage( MessageBuilder const& builder ); + ScopedMessage( ScopedMessage const& other ); + ~ScopedMessage(); + + MessageInfo m_info; + }; + +} // end namespace Catch + +// #included from: catch_interfaces_capture.h +#define TWOBLUECUBES_CATCH_INTERFACES_CAPTURE_H_INCLUDED + +#include + +namespace Catch { + + class TestCase; + class AssertionResult; + struct AssertionInfo; + struct SectionInfo; + struct SectionEndInfo; + struct MessageInfo; + class ScopedMessageBuilder; + struct Counts; + + struct IResultCapture { + + virtual ~IResultCapture(); + + virtual void assertionEnded( AssertionResult const& result ) = 0; + virtual bool sectionStarted( SectionInfo const& sectionInfo, + Counts& assertions ) = 0; + virtual void sectionEnded( SectionEndInfo const& endInfo ) = 0; + virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) = 0; + virtual void pushScopedMessage( MessageInfo const& message ) = 0; + virtual void popScopedMessage( MessageInfo const& message ) = 0; + + virtual std::string getCurrentTestName() const = 0; + virtual const AssertionResult* getLastResult() const = 0; + + virtual void handleFatalErrorCondition( std::string const& message ) = 0; + }; + + IResultCapture& getResultCapture(); +} + +// #included from: catch_debugger.h +#define TWOBLUECUBES_CATCH_DEBUGGER_H_INCLUDED + +// #included from: catch_platform.h +#define TWOBLUECUBES_CATCH_PLATFORM_H_INCLUDED + +#if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) +#define CATCH_PLATFORM_MAC +#elif defined(__IPHONE_OS_VERSION_MIN_REQUIRED) +#define CATCH_PLATFORM_IPHONE +#elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) +#define CATCH_PLATFORM_WINDOWS +#endif + +#include + +namespace Catch{ + + bool isDebuggerActive(); + void writeToDebugConsole( std::string const& text ); +} + +#ifdef CATCH_PLATFORM_MAC + + // The following code snippet based on: + // http://cocoawithlove.com/2008/03/break-into-debugger.html + #ifdef DEBUG + #if defined(__ppc64__) || defined(__ppc__) + #define CATCH_BREAK_INTO_DEBUGGER() \ + if( Catch::isDebuggerActive() ) { \ + __asm__("li r0, 20\nsc\nnop\nli r0, 37\nli r4, 2\nsc\nnop\n" \ + : : : "memory","r0","r3","r4" ); \ + } + #else + #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) {__asm__("int $3\n" : : );} + #endif + #endif + +#elif defined(_MSC_VER) + #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { __debugbreak(); } +#elif defined(__MINGW32__) + extern "C" __declspec(dllimport) void __stdcall DebugBreak(); + #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { DebugBreak(); } +#endif + +#ifndef CATCH_BREAK_INTO_DEBUGGER +#define CATCH_BREAK_INTO_DEBUGGER() Catch::alwaysTrue(); +#endif + +// #included from: catch_interfaces_runner.h +#define TWOBLUECUBES_CATCH_INTERFACES_RUNNER_H_INCLUDED + +namespace Catch { + class TestCase; + + struct IRunner { + virtual ~IRunner(); + virtual bool aborting() const = 0; + }; +} + +/////////////////////////////////////////////////////////////////////////////// +// In the event of a failure works out if the debugger needs to be invoked +// and/or an exception thrown and takes appropriate action. +// This needs to be done as a macro so the debugger will stop in the user +// source code rather than in Catch library code +#define INTERNAL_CATCH_REACT( resultBuilder ) \ + if( resultBuilder.shouldDebugBreak() ) CATCH_BREAK_INTO_DEBUGGER(); \ + resultBuilder.react(); + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \ + try { \ + CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ + ( __catchResult <= expr ).endExpression(); \ + } \ + catch( ... ) { \ + __catchResult.useActiveException( Catch::ResultDisposition::Normal ); \ + } \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::isTrue( false && static_cast(expr) ) ) // expr here is never evaluated at runtime but it forces the compiler to give it a look + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_IF( expr, resultDisposition, macroName ) \ + INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ); \ + if( Catch::getResultCapture().getLastResult()->succeeded() ) + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_ELSE( expr, resultDisposition, macroName ) \ + INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ); \ + if( !Catch::getResultCapture().getLastResult()->succeeded() ) + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_NO_THROW( expr, resultDisposition, macroName ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \ + try { \ + expr; \ + __catchResult.captureResult( Catch::ResultWas::Ok ); \ + } \ + catch( ... ) { \ + __catchResult.useActiveException( resultDisposition ); \ + } \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::alwaysFalse() ) + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_THROWS( expr, resultDisposition, matcher, macroName ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition, #matcher ); \ + if( __catchResult.allowThrows() ) \ + try { \ + expr; \ + __catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \ + } \ + catch( ... ) { \ + __catchResult.captureExpectedException( matcher ); \ + } \ + else \ + __catchResult.captureResult( Catch::ResultWas::Ok ); \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::alwaysFalse() ) + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_THROWS_AS( expr, exceptionType, resultDisposition, macroName ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \ + if( __catchResult.allowThrows() ) \ + try { \ + expr; \ + __catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \ + } \ + catch( exceptionType ) { \ + __catchResult.captureResult( Catch::ResultWas::Ok ); \ + } \ + catch( ... ) { \ + __catchResult.useActiveException( resultDisposition ); \ + } \ + else \ + __catchResult.captureResult( Catch::ResultWas::Ok ); \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::alwaysFalse() ) + +/////////////////////////////////////////////////////////////////////////////// +#ifdef CATCH_CONFIG_VARIADIC_MACROS + #define INTERNAL_CATCH_MSG( messageType, resultDisposition, macroName, ... ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \ + __catchResult << __VA_ARGS__ + ::Catch::StreamEndStop(); \ + __catchResult.captureResult( messageType ); \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::alwaysFalse() ) +#else + #define INTERNAL_CATCH_MSG( messageType, resultDisposition, macroName, log ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \ + __catchResult << log + ::Catch::StreamEndStop(); \ + __catchResult.captureResult( messageType ); \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::alwaysFalse() ) +#endif + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_INFO( log, macroName ) \ + Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME( scopedMessage ) = Catch::MessageBuilder( macroName, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log; + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CHECK_THAT( arg, matcher, resultDisposition, macroName ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #arg ", " #matcher, resultDisposition ); \ + try { \ + std::string matcherAsString = (matcher).toString(); \ + __catchResult \ + .setLhs( Catch::toString( arg ) ) \ + .setRhs( matcherAsString == Catch::Detail::unprintableString ? #matcher : matcherAsString ) \ + .setOp( "matches" ) \ + .setResultType( (matcher).match( arg ) ); \ + __catchResult.captureExpression(); \ + } catch( ... ) { \ + __catchResult.useActiveException( resultDisposition | Catch::ResultDisposition::ContinueOnFailure ); \ + } \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::alwaysFalse() ) + +// #included from: internal/catch_section.h +#define TWOBLUECUBES_CATCH_SECTION_H_INCLUDED + +// #included from: catch_section_info.h +#define TWOBLUECUBES_CATCH_SECTION_INFO_H_INCLUDED + +// #included from: catch_totals.hpp +#define TWOBLUECUBES_CATCH_TOTALS_HPP_INCLUDED + +#include + +namespace Catch { + + struct Counts { + Counts() : passed( 0 ), failed( 0 ), failedButOk( 0 ) {} + + Counts operator - ( Counts const& other ) const { + Counts diff; + diff.passed = passed - other.passed; + diff.failed = failed - other.failed; + diff.failedButOk = failedButOk - other.failedButOk; + return diff; + } + Counts& operator += ( Counts const& other ) { + passed += other.passed; + failed += other.failed; + failedButOk += other.failedButOk; + return *this; + } + + std::size_t total() const { + return passed + failed + failedButOk; + } + bool allPassed() const { + return failed == 0 && failedButOk == 0; + } + bool allOk() const { + return failed == 0; + } + + std::size_t passed; + std::size_t failed; + std::size_t failedButOk; + }; + + struct Totals { + + Totals operator - ( Totals const& other ) const { + Totals diff; + diff.assertions = assertions - other.assertions; + diff.testCases = testCases - other.testCases; + return diff; + } + + Totals delta( Totals const& prevTotals ) const { + Totals diff = *this - prevTotals; + if( diff.assertions.failed > 0 ) + ++diff.testCases.failed; + else if( diff.assertions.failedButOk > 0 ) + ++diff.testCases.failedButOk; + else + ++diff.testCases.passed; + return diff; + } + + Totals& operator += ( Totals const& other ) { + assertions += other.assertions; + testCases += other.testCases; + return *this; + } + + Counts assertions; + Counts testCases; + }; +} + +namespace Catch { + + struct SectionInfo { + SectionInfo + ( SourceLineInfo const& _lineInfo, + std::string const& _name, + std::string const& _description = std::string() ); + + std::string name; + std::string description; + SourceLineInfo lineInfo; + }; + + struct SectionEndInfo { + SectionEndInfo( SectionInfo const& _sectionInfo, Counts const& _prevAssertions, double _durationInSeconds ) + : sectionInfo( _sectionInfo ), prevAssertions( _prevAssertions ), durationInSeconds( _durationInSeconds ) + {} + + SectionInfo sectionInfo; + Counts prevAssertions; + double durationInSeconds; + }; + +} // end namespace Catch + +// #included from: catch_timer.h +#define TWOBLUECUBES_CATCH_TIMER_H_INCLUDED + +#ifdef CATCH_PLATFORM_WINDOWS +typedef unsigned long long uint64_t; +#else +#include +#endif + +namespace Catch { + + class Timer { + public: + Timer() : m_ticks( 0 ) {} + void start(); + unsigned int getElapsedMicroseconds() const; + unsigned int getElapsedMilliseconds() const; + double getElapsedSeconds() const; + + private: + uint64_t m_ticks; + }; + +} // namespace Catch + +#include + +namespace Catch { + + class Section : NonCopyable { + public: + Section( SectionInfo const& info ); + ~Section(); + + // This indicates whether the section should be executed or not + operator bool() const; + + private: + SectionInfo m_info; + + std::string m_name; + Counts m_assertions; + bool m_sectionIncluded; + Timer m_timer; + }; + +} // end namespace Catch + +#ifdef CATCH_CONFIG_VARIADIC_MACROS + #define INTERNAL_CATCH_SECTION( ... ) \ + if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) ) +#else + #define INTERNAL_CATCH_SECTION( name, desc ) \ + if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, name, desc ) ) +#endif + +// #included from: internal/catch_generators.hpp +#define TWOBLUECUBES_CATCH_GENERATORS_HPP_INCLUDED + +#include +#include +#include +#include + +namespace Catch { + +template +struct IGenerator { + virtual ~IGenerator() {} + virtual T getValue( std::size_t index ) const = 0; + virtual std::size_t size () const = 0; +}; + +template +class BetweenGenerator : public IGenerator { +public: + BetweenGenerator( T from, T to ) : m_from( from ), m_to( to ){} + + virtual T getValue( std::size_t index ) const { + return m_from+static_cast( index ); + } + + virtual std::size_t size() const { + return static_cast( 1+m_to-m_from ); + } + +private: + + T m_from; + T m_to; +}; + +template +class ValuesGenerator : public IGenerator { +public: + ValuesGenerator(){} + + void add( T value ) { + m_values.push_back( value ); + } + + virtual T getValue( std::size_t index ) const { + return m_values[index]; + } + + virtual std::size_t size() const { + return m_values.size(); + } + +private: + std::vector m_values; +}; + +template +class CompositeGenerator { +public: + CompositeGenerator() : m_totalSize( 0 ) {} + + // *** Move semantics, similar to auto_ptr *** + CompositeGenerator( CompositeGenerator& other ) + : m_fileInfo( other.m_fileInfo ), + m_totalSize( 0 ) + { + move( other ); + } + + CompositeGenerator& setFileInfo( const char* fileInfo ) { + m_fileInfo = fileInfo; + return *this; + } + + ~CompositeGenerator() { + deleteAll( m_composed ); + } + + operator T () const { + size_t overallIndex = getCurrentContext().getGeneratorIndex( m_fileInfo, m_totalSize ); + + typename std::vector*>::const_iterator it = m_composed.begin(); + typename std::vector*>::const_iterator itEnd = m_composed.end(); + for( size_t index = 0; it != itEnd; ++it ) + { + const IGenerator* generator = *it; + if( overallIndex >= index && overallIndex < index + generator->size() ) + { + return generator->getValue( overallIndex-index ); + } + index += generator->size(); + } + CATCH_INTERNAL_ERROR( "Indexed past end of generated range" ); + return T(); // Suppress spurious "not all control paths return a value" warning in Visual Studio - if you know how to fix this please do so + } + + void add( const IGenerator* generator ) { + m_totalSize += generator->size(); + m_composed.push_back( generator ); + } + + CompositeGenerator& then( CompositeGenerator& other ) { + move( other ); + return *this; + } + + CompositeGenerator& then( T value ) { + ValuesGenerator* valuesGen = new ValuesGenerator(); + valuesGen->add( value ); + add( valuesGen ); + return *this; + } + +private: + + void move( CompositeGenerator& other ) { + std::copy( other.m_composed.begin(), other.m_composed.end(), std::back_inserter( m_composed ) ); + m_totalSize += other.m_totalSize; + other.m_composed.clear(); + } + + std::vector*> m_composed; + std::string m_fileInfo; + size_t m_totalSize; +}; + +namespace Generators +{ + template + CompositeGenerator between( T from, T to ) { + CompositeGenerator generators; + generators.add( new BetweenGenerator( from, to ) ); + return generators; + } + + template + CompositeGenerator values( T val1, T val2 ) { + CompositeGenerator generators; + ValuesGenerator* valuesGen = new ValuesGenerator(); + valuesGen->add( val1 ); + valuesGen->add( val2 ); + generators.add( valuesGen ); + return generators; + } + + template + CompositeGenerator values( T val1, T val2, T val3 ){ + CompositeGenerator generators; + ValuesGenerator* valuesGen = new ValuesGenerator(); + valuesGen->add( val1 ); + valuesGen->add( val2 ); + valuesGen->add( val3 ); + generators.add( valuesGen ); + return generators; + } + + template + CompositeGenerator values( T val1, T val2, T val3, T val4 ) { + CompositeGenerator generators; + ValuesGenerator* valuesGen = new ValuesGenerator(); + valuesGen->add( val1 ); + valuesGen->add( val2 ); + valuesGen->add( val3 ); + valuesGen->add( val4 ); + generators.add( valuesGen ); + return generators; + } + +} // end namespace Generators + +using namespace Generators; + +} // end namespace Catch + +#define INTERNAL_CATCH_LINESTR2( line ) #line +#define INTERNAL_CATCH_LINESTR( line ) INTERNAL_CATCH_LINESTR2( line ) + +#define INTERNAL_CATCH_GENERATE( expr ) expr.setFileInfo( __FILE__ "(" INTERNAL_CATCH_LINESTR( __LINE__ ) ")" ) + +// #included from: internal/catch_interfaces_exception.h +#define TWOBLUECUBES_CATCH_INTERFACES_EXCEPTION_H_INCLUDED + +#include +#include + +// #included from: catch_interfaces_registry_hub.h +#define TWOBLUECUBES_CATCH_INTERFACES_REGISTRY_HUB_H_INCLUDED + +#include + +namespace Catch { + + class TestCase; + struct ITestCaseRegistry; + struct IExceptionTranslatorRegistry; + struct IExceptionTranslator; + struct IReporterRegistry; + struct IReporterFactory; + + struct IRegistryHub { + virtual ~IRegistryHub(); + + virtual IReporterRegistry const& getReporterRegistry() const = 0; + virtual ITestCaseRegistry const& getTestCaseRegistry() const = 0; + virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() = 0; + }; + + struct IMutableRegistryHub { + virtual ~IMutableRegistryHub(); + virtual void registerReporter( std::string const& name, Ptr const& factory ) = 0; + virtual void registerListener( Ptr const& factory ) = 0; + virtual void registerTest( TestCase const& testInfo ) = 0; + virtual void registerTranslator( const IExceptionTranslator* translator ) = 0; + }; + + IRegistryHub& getRegistryHub(); + IMutableRegistryHub& getMutableRegistryHub(); + void cleanUp(); + std::string translateActiveException(); + +} + +namespace Catch { + + typedef std::string(*exceptionTranslateFunction)(); + + struct IExceptionTranslator; + typedef std::vector ExceptionTranslators; + + struct IExceptionTranslator { + virtual ~IExceptionTranslator(); + virtual std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const = 0; + }; + + struct IExceptionTranslatorRegistry { + virtual ~IExceptionTranslatorRegistry(); + + virtual std::string translateActiveException() const = 0; + }; + + class ExceptionTranslatorRegistrar { + template + class ExceptionTranslator : public IExceptionTranslator { + public: + + ExceptionTranslator( std::string(*translateFunction)( T& ) ) + : m_translateFunction( translateFunction ) + {} + + virtual std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const CATCH_OVERRIDE { + try { + if( it == itEnd ) + throw; + else + return (*it)->translate( it+1, itEnd ); + } + catch( T& ex ) { + return m_translateFunction( ex ); + } + } + + protected: + std::string(*m_translateFunction)( T& ); + }; + + public: + template + ExceptionTranslatorRegistrar( std::string(*translateFunction)( T& ) ) { + getMutableRegistryHub().registerTranslator + ( new ExceptionTranslator( translateFunction ) ); + } + }; +} + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) \ + static std::string INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator )( signature ); \ + namespace{ Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ) ); }\ + static std::string INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator )( signature ) + +// #included from: internal/catch_approx.hpp +#define TWOBLUECUBES_CATCH_APPROX_HPP_INCLUDED + +#include +#include + +namespace Catch { +namespace Detail { + + class Approx { + public: + explicit Approx ( double value ) + : m_epsilon( std::numeric_limits::epsilon()*100 ), + m_scale( 1.0 ), + m_value( value ) + {} + + Approx( Approx const& other ) + : m_epsilon( other.m_epsilon ), + m_scale( other.m_scale ), + m_value( other.m_value ) + {} + + static Approx custom() { + return Approx( 0 ); + } + + Approx operator()( double value ) { + Approx approx( value ); + approx.epsilon( m_epsilon ); + approx.scale( m_scale ); + return approx; + } + + friend bool operator == ( double lhs, Approx const& rhs ) { + // Thanks to Richard Harris for his help refining this formula + return fabs( lhs - rhs.m_value ) < rhs.m_epsilon * (rhs.m_scale + (std::max)( fabs(lhs), fabs(rhs.m_value) ) ); + } + + friend bool operator == ( Approx const& lhs, double rhs ) { + return operator==( rhs, lhs ); + } + + friend bool operator != ( double lhs, Approx const& rhs ) { + return !operator==( lhs, rhs ); + } + + friend bool operator != ( Approx const& lhs, double rhs ) { + return !operator==( rhs, lhs ); + } + + Approx& epsilon( double newEpsilon ) { + m_epsilon = newEpsilon; + return *this; + } + + Approx& scale( double newScale ) { + m_scale = newScale; + return *this; + } + + std::string toString() const { + std::ostringstream oss; + oss << "Approx( " << Catch::toString( m_value ) << " )"; + return oss.str(); + } + + private: + double m_epsilon; + double m_scale; + double m_value; + }; +} + +template<> +inline std::string toString( Detail::Approx const& value ) { + return value.toString(); +} + +} // end namespace Catch + +// #included from: internal/catch_interfaces_tag_alias_registry.h +#define TWOBLUECUBES_CATCH_INTERFACES_TAG_ALIAS_REGISTRY_H_INCLUDED + +// #included from: catch_tag_alias.h +#define TWOBLUECUBES_CATCH_TAG_ALIAS_H_INCLUDED + +#include + +namespace Catch { + + struct TagAlias { + TagAlias( std::string _tag, SourceLineInfo _lineInfo ) : tag( _tag ), lineInfo( _lineInfo ) {} + + std::string tag; + SourceLineInfo lineInfo; + }; + + struct RegistrarForTagAliases { + RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ); + }; + +} // end namespace Catch + +#define CATCH_REGISTER_TAG_ALIAS( alias, spec ) namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); } +// #included from: catch_option.hpp +#define TWOBLUECUBES_CATCH_OPTION_HPP_INCLUDED + +namespace Catch { + + // An optional type + template + class Option { + public: + Option() : nullableValue( CATCH_NULL ) {} + Option( T const& _value ) + : nullableValue( new( storage ) T( _value ) ) + {} + Option( Option const& _other ) + : nullableValue( _other ? new( storage ) T( *_other ) : CATCH_NULL ) + {} + + ~Option() { + reset(); + } + + Option& operator= ( Option const& _other ) { + if( &_other != this ) { + reset(); + if( _other ) + nullableValue = new( storage ) T( *_other ); + } + return *this; + } + Option& operator = ( T const& _value ) { + reset(); + nullableValue = new( storage ) T( _value ); + return *this; + } + + void reset() { + if( nullableValue ) + nullableValue->~T(); + nullableValue = CATCH_NULL; + } + + T& operator*() { return *nullableValue; } + T const& operator*() const { return *nullableValue; } + T* operator->() { return nullableValue; } + const T* operator->() const { return nullableValue; } + + T valueOr( T const& defaultValue ) const { + return nullableValue ? *nullableValue : defaultValue; + } + + bool some() const { return nullableValue != CATCH_NULL; } + bool none() const { return nullableValue == CATCH_NULL; } + + bool operator !() const { return nullableValue == CATCH_NULL; } + operator SafeBool::type() const { + return SafeBool::makeSafe( some() ); + } + + private: + T* nullableValue; + char storage[sizeof(T)]; + }; + +} // end namespace Catch + +namespace Catch { + + struct ITagAliasRegistry { + virtual ~ITagAliasRegistry(); + virtual Option find( std::string const& alias ) const = 0; + virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const = 0; + + static ITagAliasRegistry const& get(); + }; + +} // end namespace Catch + +// These files are included here so the single_include script doesn't put them +// in the conditionally compiled sections +// #included from: internal/catch_test_case_info.h +#define TWOBLUECUBES_CATCH_TEST_CASE_INFO_H_INCLUDED + +#include +#include + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpadded" +#endif + +namespace Catch { + + struct ITestCase; + + struct TestCaseInfo { + enum SpecialProperties{ + None = 0, + IsHidden = 1 << 1, + ShouldFail = 1 << 2, + MayFail = 1 << 3, + Throws = 1 << 4 + }; + + TestCaseInfo( std::string const& _name, + std::string const& _className, + std::string const& _description, + std::set const& _tags, + SourceLineInfo const& _lineInfo ); + + TestCaseInfo( TestCaseInfo const& other ); + + friend void setTags( TestCaseInfo& testCaseInfo, std::set const& tags ); + + bool isHidden() const; + bool throws() const; + bool okToFail() const; + bool expectedToFail() const; + + std::string name; + std::string className; + std::string description; + std::set tags; + std::set lcaseTags; + std::string tagsAsString; + SourceLineInfo lineInfo; + SpecialProperties properties; + }; + + class TestCase : public TestCaseInfo { + public: + + TestCase( ITestCase* testCase, TestCaseInfo const& info ); + TestCase( TestCase const& other ); + + TestCase withName( std::string const& _newName ) const; + + void invoke() const; + + TestCaseInfo const& getTestCaseInfo() const; + + void swap( TestCase& other ); + bool operator == ( TestCase const& other ) const; + bool operator < ( TestCase const& other ) const; + TestCase& operator = ( TestCase const& other ); + + private: + Ptr test; + }; + + TestCase makeTestCase( ITestCase* testCase, + std::string const& className, + std::string const& name, + std::string const& description, + SourceLineInfo const& lineInfo ); +} + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + + +#ifdef __OBJC__ +// #included from: internal/catch_objc.hpp +#define TWOBLUECUBES_CATCH_OBJC_HPP_INCLUDED + +#import + +#include + +// NB. Any general catch headers included here must be included +// in catch.hpp first to make sure they are included by the single +// header for non obj-usage + +/////////////////////////////////////////////////////////////////////////////// +// This protocol is really only here for (self) documenting purposes, since +// all its methods are optional. +@protocol OcFixture + +@optional + +-(void) setUp; +-(void) tearDown; + +@end + +namespace Catch { + + class OcMethod : public SharedImpl { + + public: + OcMethod( Class cls, SEL sel ) : m_cls( cls ), m_sel( sel ) {} + + virtual void invoke() const { + id obj = [[m_cls alloc] init]; + + performOptionalSelector( obj, @selector(setUp) ); + performOptionalSelector( obj, m_sel ); + performOptionalSelector( obj, @selector(tearDown) ); + + arcSafeRelease( obj ); + } + private: + virtual ~OcMethod() {} + + Class m_cls; + SEL m_sel; + }; + + namespace Detail{ + + inline std::string getAnnotation( Class cls, + std::string const& annotationName, + std::string const& testCaseName ) { + NSString* selStr = [[NSString alloc] initWithFormat:@"Catch_%s_%s", annotationName.c_str(), testCaseName.c_str()]; + SEL sel = NSSelectorFromString( selStr ); + arcSafeRelease( selStr ); + id value = performOptionalSelector( cls, sel ); + if( value ) + return [(NSString*)value UTF8String]; + return ""; + } + } + + inline size_t registerTestMethods() { + size_t noTestMethods = 0; + int noClasses = objc_getClassList( CATCH_NULL, 0 ); + + Class* classes = (CATCH_UNSAFE_UNRETAINED Class *)malloc( sizeof(Class) * noClasses); + objc_getClassList( classes, noClasses ); + + for( int c = 0; c < noClasses; c++ ) { + Class cls = classes[c]; + { + u_int count; + Method* methods = class_copyMethodList( cls, &count ); + for( u_int m = 0; m < count ; m++ ) { + SEL selector = method_getName(methods[m]); + std::string methodName = sel_getName(selector); + if( startsWith( methodName, "Catch_TestCase_" ) ) { + std::string testCaseName = methodName.substr( 15 ); + std::string name = Detail::getAnnotation( cls, "Name", testCaseName ); + std::string desc = Detail::getAnnotation( cls, "Description", testCaseName ); + const char* className = class_getName( cls ); + + getMutableRegistryHub().registerTest( makeTestCase( new OcMethod( cls, selector ), className, name.c_str(), desc.c_str(), SourceLineInfo() ) ); + noTestMethods++; + } + } + free(methods); + } + } + return noTestMethods; + } + + namespace Matchers { + namespace Impl { + namespace NSStringMatchers { + + template + struct StringHolder : MatcherImpl{ + StringHolder( NSString* substr ) : m_substr( [substr copy] ){} + StringHolder( StringHolder const& other ) : m_substr( [other.m_substr copy] ){} + StringHolder() { + arcSafeRelease( m_substr ); + } + + NSString* m_substr; + }; + + struct Equals : StringHolder { + Equals( NSString* substr ) : StringHolder( substr ){} + + virtual bool match( ExpressionType const& str ) const { + return (str != nil || m_substr == nil ) && + [str isEqualToString:m_substr]; + } + + virtual std::string toString() const { + return "equals string: " + Catch::toString( m_substr ); + } + }; + + struct Contains : StringHolder { + Contains( NSString* substr ) : StringHolder( substr ){} + + virtual bool match( ExpressionType const& str ) const { + return (str != nil || m_substr == nil ) && + [str rangeOfString:m_substr].location != NSNotFound; + } + + virtual std::string toString() const { + return "contains string: " + Catch::toString( m_substr ); + } + }; + + struct StartsWith : StringHolder { + StartsWith( NSString* substr ) : StringHolder( substr ){} + + virtual bool match( ExpressionType const& str ) const { + return (str != nil || m_substr == nil ) && + [str rangeOfString:m_substr].location == 0; + } + + virtual std::string toString() const { + return "starts with: " + Catch::toString( m_substr ); + } + }; + struct EndsWith : StringHolder { + EndsWith( NSString* substr ) : StringHolder( substr ){} + + virtual bool match( ExpressionType const& str ) const { + return (str != nil || m_substr == nil ) && + [str rangeOfString:m_substr].location == [str length] - [m_substr length]; + } + + virtual std::string toString() const { + return "ends with: " + Catch::toString( m_substr ); + } + }; + + } // namespace NSStringMatchers + } // namespace Impl + + inline Impl::NSStringMatchers::Equals + Equals( NSString* substr ){ return Impl::NSStringMatchers::Equals( substr ); } + + inline Impl::NSStringMatchers::Contains + Contains( NSString* substr ){ return Impl::NSStringMatchers::Contains( substr ); } + + inline Impl::NSStringMatchers::StartsWith + StartsWith( NSString* substr ){ return Impl::NSStringMatchers::StartsWith( substr ); } + + inline Impl::NSStringMatchers::EndsWith + EndsWith( NSString* substr ){ return Impl::NSStringMatchers::EndsWith( substr ); } + + } // namespace Matchers + + using namespace Matchers; + +} // namespace Catch + +/////////////////////////////////////////////////////////////////////////////// +#define OC_TEST_CASE( name, desc )\ ++(NSString*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Name_test ) \ +{\ +return @ name; \ +}\ ++(NSString*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Description_test ) \ +{ \ +return @ desc; \ +} \ +-(void) INTERNAL_CATCH_UNIQUE_NAME( Catch_TestCase_test ) + +#endif + +#ifdef CATCH_IMPL +// #included from: internal/catch_impl.hpp +#define TWOBLUECUBES_CATCH_IMPL_HPP_INCLUDED + +// Collect all the implementation files together here +// These are the equivalent of what would usually be cpp files + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wweak-vtables" +#endif + +// #included from: ../catch_session.hpp +#define TWOBLUECUBES_CATCH_RUNNER_HPP_INCLUDED + +// #included from: internal/catch_commandline.hpp +#define TWOBLUECUBES_CATCH_COMMANDLINE_HPP_INCLUDED + +// #included from: catch_config.hpp +#define TWOBLUECUBES_CATCH_CONFIG_HPP_INCLUDED + +// #included from: catch_test_spec_parser.hpp +#define TWOBLUECUBES_CATCH_TEST_SPEC_PARSER_HPP_INCLUDED + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpadded" +#endif + +// #included from: catch_test_spec.hpp +#define TWOBLUECUBES_CATCH_TEST_SPEC_HPP_INCLUDED + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpadded" +#endif + +// #included from: catch_wildcard_pattern.hpp +#define TWOBLUECUBES_CATCH_WILDCARD_PATTERN_HPP_INCLUDED + +namespace Catch +{ + class WildcardPattern { + enum WildcardPosition { + NoWildcard = 0, + WildcardAtStart = 1, + WildcardAtEnd = 2, + WildcardAtBothEnds = WildcardAtStart | WildcardAtEnd + }; + + public: + + WildcardPattern( std::string const& pattern, CaseSensitive::Choice caseSensitivity ) + : m_caseSensitivity( caseSensitivity ), + m_wildcard( NoWildcard ), + m_pattern( adjustCase( pattern ) ) + { + if( startsWith( m_pattern, "*" ) ) { + m_pattern = m_pattern.substr( 1 ); + m_wildcard = WildcardAtStart; + } + if( endsWith( m_pattern, "*" ) ) { + m_pattern = m_pattern.substr( 0, m_pattern.size()-1 ); + m_wildcard = static_cast( m_wildcard | WildcardAtEnd ); + } + } + virtual ~WildcardPattern(); + virtual bool matches( std::string const& str ) const { + switch( m_wildcard ) { + case NoWildcard: + return m_pattern == adjustCase( str ); + case WildcardAtStart: + return endsWith( adjustCase( str ), m_pattern ); + case WildcardAtEnd: + return startsWith( adjustCase( str ), m_pattern ); + case WildcardAtBothEnds: + return contains( adjustCase( str ), m_pattern ); + } + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunreachable-code" +#endif + throw std::logic_error( "Unknown enum" ); +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + } + private: + std::string adjustCase( std::string const& str ) const { + return m_caseSensitivity == CaseSensitive::No ? toLower( str ) : str; + } + CaseSensitive::Choice m_caseSensitivity; + WildcardPosition m_wildcard; + std::string m_pattern; + }; +} + +#include +#include + +namespace Catch { + + class TestSpec { + struct Pattern : SharedImpl<> { + virtual ~Pattern(); + virtual bool matches( TestCaseInfo const& testCase ) const = 0; + }; + class NamePattern : public Pattern { + public: + NamePattern( std::string const& name ) + : m_wildcardPattern( toLower( name ), CaseSensitive::No ) + {} + virtual ~NamePattern(); + virtual bool matches( TestCaseInfo const& testCase ) const { + return m_wildcardPattern.matches( toLower( testCase.name ) ); + } + private: + WildcardPattern m_wildcardPattern; + }; + + class TagPattern : public Pattern { + public: + TagPattern( std::string const& tag ) : m_tag( toLower( tag ) ) {} + virtual ~TagPattern(); + virtual bool matches( TestCaseInfo const& testCase ) const { + return testCase.lcaseTags.find( m_tag ) != testCase.lcaseTags.end(); + } + private: + std::string m_tag; + }; + + class ExcludedPattern : public Pattern { + public: + ExcludedPattern( Ptr const& underlyingPattern ) : m_underlyingPattern( underlyingPattern ) {} + virtual ~ExcludedPattern(); + virtual bool matches( TestCaseInfo const& testCase ) const { return !m_underlyingPattern->matches( testCase ); } + private: + Ptr m_underlyingPattern; + }; + + struct Filter { + std::vector > m_patterns; + + bool matches( TestCaseInfo const& testCase ) const { + // All patterns in a filter must match for the filter to be a match + for( std::vector >::const_iterator it = m_patterns.begin(), itEnd = m_patterns.end(); it != itEnd; ++it ) + if( !(*it)->matches( testCase ) ) + return false; + return true; + } + }; + + public: + bool hasFilters() const { + return !m_filters.empty(); + } + bool matches( TestCaseInfo const& testCase ) const { + // A TestSpec matches if any filter matches + for( std::vector::const_iterator it = m_filters.begin(), itEnd = m_filters.end(); it != itEnd; ++it ) + if( it->matches( testCase ) ) + return true; + return false; + } + + private: + std::vector m_filters; + + friend class TestSpecParser; + }; +} + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +namespace Catch { + + class TestSpecParser { + enum Mode{ None, Name, QuotedName, Tag }; + Mode m_mode; + bool m_exclusion; + std::size_t m_start, m_pos; + std::string m_arg; + TestSpec::Filter m_currentFilter; + TestSpec m_testSpec; + ITagAliasRegistry const* m_tagAliases; + + public: + TestSpecParser( ITagAliasRegistry const& tagAliases ) : m_tagAliases( &tagAliases ) {} + + TestSpecParser& parse( std::string const& arg ) { + m_mode = None; + m_exclusion = false; + m_start = std::string::npos; + m_arg = m_tagAliases->expandAliases( arg ); + for( m_pos = 0; m_pos < m_arg.size(); ++m_pos ) + visitChar( m_arg[m_pos] ); + if( m_mode == Name ) + addPattern(); + return *this; + } + TestSpec testSpec() { + addFilter(); + return m_testSpec; + } + private: + void visitChar( char c ) { + if( m_mode == None ) { + switch( c ) { + case ' ': return; + case '~': m_exclusion = true; return; + case '[': return startNewMode( Tag, ++m_pos ); + case '"': return startNewMode( QuotedName, ++m_pos ); + default: startNewMode( Name, m_pos ); break; + } + } + if( m_mode == Name ) { + if( c == ',' ) { + addPattern(); + addFilter(); + } + else if( c == '[' ) { + if( subString() == "exclude:" ) + m_exclusion = true; + else + addPattern(); + startNewMode( Tag, ++m_pos ); + } + } + else if( m_mode == QuotedName && c == '"' ) + addPattern(); + else if( m_mode == Tag && c == ']' ) + addPattern(); + } + void startNewMode( Mode mode, std::size_t start ) { + m_mode = mode; + m_start = start; + } + std::string subString() const { return m_arg.substr( m_start, m_pos - m_start ); } + template + void addPattern() { + std::string token = subString(); + if( startsWith( token, "exclude:" ) ) { + m_exclusion = true; + token = token.substr( 8 ); + } + if( !token.empty() ) { + Ptr pattern = new T( token ); + if( m_exclusion ) + pattern = new TestSpec::ExcludedPattern( pattern ); + m_currentFilter.m_patterns.push_back( pattern ); + } + m_exclusion = false; + m_mode = None; + } + void addFilter() { + if( !m_currentFilter.m_patterns.empty() ) { + m_testSpec.m_filters.push_back( m_currentFilter ); + m_currentFilter = TestSpec::Filter(); + } + } + }; + inline TestSpec parseTestSpec( std::string const& arg ) { + return TestSpecParser( ITagAliasRegistry::get() ).parse( arg ).testSpec(); + } + +} // namespace Catch + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +// #included from: catch_interfaces_config.h +#define TWOBLUECUBES_CATCH_INTERFACES_CONFIG_H_INCLUDED + +#include +#include +#include + +namespace Catch { + + struct Verbosity { enum Level { + NoOutput = 0, + Quiet, + Normal + }; }; + + struct WarnAbout { enum What { + Nothing = 0x00, + NoAssertions = 0x01 + }; }; + + struct ShowDurations { enum OrNot { + DefaultForReporter, + Always, + Never + }; }; + struct RunTests { enum InWhatOrder { + InDeclarationOrder, + InLexicographicalOrder, + InRandomOrder + }; }; + struct UseColour { enum YesOrNo { + Auto, + Yes, + No + }; }; + + class TestSpec; + + struct IConfig : IShared { + + virtual ~IConfig(); + + virtual bool allowThrows() const = 0; + virtual std::ostream& stream() const = 0; + virtual std::string name() const = 0; + virtual bool includeSuccessfulResults() const = 0; + virtual bool shouldDebugBreak() const = 0; + virtual bool warnAboutMissingAssertions() const = 0; + virtual int abortAfter() const = 0; + virtual bool showInvisibles() const = 0; + virtual ShowDurations::OrNot showDurations() const = 0; + virtual TestSpec const& testSpec() const = 0; + virtual RunTests::InWhatOrder runOrder() const = 0; + virtual unsigned int rngSeed() const = 0; + virtual UseColour::YesOrNo useColour() const = 0; + }; +} + +// #included from: catch_stream.h +#define TWOBLUECUBES_CATCH_STREAM_H_INCLUDED + +// #included from: catch_streambuf.h +#define TWOBLUECUBES_CATCH_STREAMBUF_H_INCLUDED + +#include + +namespace Catch { + + class StreamBufBase : public std::streambuf { + public: + virtual ~StreamBufBase() CATCH_NOEXCEPT; + }; +} + +#include +#include +#include + +namespace Catch { + + std::ostream& cout(); + std::ostream& cerr(); + + struct IStream { + virtual ~IStream() CATCH_NOEXCEPT; + virtual std::ostream& stream() const = 0; + }; + + class FileStream : public IStream { + mutable std::ofstream m_ofs; + public: + FileStream( std::string const& filename ); + virtual ~FileStream() CATCH_NOEXCEPT; + public: // IStream + virtual std::ostream& stream() const CATCH_OVERRIDE; + }; + + class CoutStream : public IStream { + mutable std::ostream m_os; + public: + CoutStream(); + virtual ~CoutStream() CATCH_NOEXCEPT; + + public: // IStream + virtual std::ostream& stream() const CATCH_OVERRIDE; + }; + + class DebugOutStream : public IStream { + std::auto_ptr m_streamBuf; + mutable std::ostream m_os; + public: + DebugOutStream(); + virtual ~DebugOutStream() CATCH_NOEXCEPT; + + public: // IStream + virtual std::ostream& stream() const CATCH_OVERRIDE; + }; +} + +#include +#include +#include +#include +#include + +#ifndef CATCH_CONFIG_CONSOLE_WIDTH +#define CATCH_CONFIG_CONSOLE_WIDTH 80 +#endif + +namespace Catch { + + struct ConfigData { + + ConfigData() + : listTests( false ), + listTags( false ), + listReporters( false ), + listTestNamesOnly( false ), + showSuccessfulTests( false ), + shouldDebugBreak( false ), + noThrow( false ), + showHelp( false ), + showInvisibles( false ), + filenamesAsTags( false ), + abortAfter( -1 ), + rngSeed( 0 ), + verbosity( Verbosity::Normal ), + warnings( WarnAbout::Nothing ), + showDurations( ShowDurations::DefaultForReporter ), + runOrder( RunTests::InDeclarationOrder ), + useColour( UseColour::Auto ) + {} + + bool listTests; + bool listTags; + bool listReporters; + bool listTestNamesOnly; + + bool showSuccessfulTests; + bool shouldDebugBreak; + bool noThrow; + bool showHelp; + bool showInvisibles; + bool filenamesAsTags; + + int abortAfter; + unsigned int rngSeed; + + Verbosity::Level verbosity; + WarnAbout::What warnings; + ShowDurations::OrNot showDurations; + RunTests::InWhatOrder runOrder; + UseColour::YesOrNo useColour; + + std::string outputFilename; + std::string name; + std::string processName; + + std::vector reporterNames; + std::vector testsOrTags; + }; + + class Config : public SharedImpl { + private: + Config( Config const& other ); + Config& operator = ( Config const& other ); + virtual void dummy(); + public: + + Config() + {} + + Config( ConfigData const& data ) + : m_data( data ), + m_stream( openStream() ) + { + if( !data.testsOrTags.empty() ) { + TestSpecParser parser( ITagAliasRegistry::get() ); + for( std::size_t i = 0; i < data.testsOrTags.size(); ++i ) + parser.parse( data.testsOrTags[i] ); + m_testSpec = parser.testSpec(); + } + } + + virtual ~Config() { + } + + std::string const& getFilename() const { + return m_data.outputFilename ; + } + + bool listTests() const { return m_data.listTests; } + bool listTestNamesOnly() const { return m_data.listTestNamesOnly; } + bool listTags() const { return m_data.listTags; } + bool listReporters() const { return m_data.listReporters; } + + std::string getProcessName() const { return m_data.processName; } + + bool shouldDebugBreak() const { return m_data.shouldDebugBreak; } + + std::vector getReporterNames() const { return m_data.reporterNames; } + + int abortAfter() const { return m_data.abortAfter; } + + TestSpec const& testSpec() const { return m_testSpec; } + + bool showHelp() const { return m_data.showHelp; } + bool showInvisibles() const { return m_data.showInvisibles; } + + // IConfig interface + virtual bool allowThrows() const { return !m_data.noThrow; } + virtual std::ostream& stream() const { return m_stream->stream(); } + virtual std::string name() const { return m_data.name.empty() ? m_data.processName : m_data.name; } + virtual bool includeSuccessfulResults() const { return m_data.showSuccessfulTests; } + virtual bool warnAboutMissingAssertions() const { return m_data.warnings & WarnAbout::NoAssertions; } + virtual ShowDurations::OrNot showDurations() const { return m_data.showDurations; } + virtual RunTests::InWhatOrder runOrder() const { return m_data.runOrder; } + virtual unsigned int rngSeed() const { return m_data.rngSeed; } + virtual UseColour::YesOrNo useColour() const { return m_data.useColour; } + + private: + + IStream const* openStream() { + if( m_data.outputFilename.empty() ) + return new CoutStream(); + else if( m_data.outputFilename[0] == '%' ) { + if( m_data.outputFilename == "%debug" ) + return new DebugOutStream(); + else + throw std::domain_error( "Unrecognised stream: " + m_data.outputFilename ); + } + else + return new FileStream( m_data.outputFilename ); + } + ConfigData m_data; + + std::auto_ptr m_stream; + TestSpec m_testSpec; + }; + +} // end namespace Catch + +// #included from: catch_clara.h +#define TWOBLUECUBES_CATCH_CLARA_H_INCLUDED + +// Use Catch's value for console width (store Clara's off to the side, if present) +#ifdef CLARA_CONFIG_CONSOLE_WIDTH +#define CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH CLARA_CONFIG_CONSOLE_WIDTH +#undef CLARA_CONFIG_CONSOLE_WIDTH +#endif +#define CLARA_CONFIG_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH + +// Declare Clara inside the Catch namespace +#define STITCH_CLARA_OPEN_NAMESPACE namespace Catch { +// #included from: ../external/clara.h + +// Version 0.0.1.1 + +// Only use header guard if we are not using an outer namespace +#if !defined(TWOBLUECUBES_CLARA_H_INCLUDED) || defined(STITCH_CLARA_OPEN_NAMESPACE) + +#ifndef STITCH_CLARA_OPEN_NAMESPACE +#define TWOBLUECUBES_CLARA_H_INCLUDED +#define STITCH_CLARA_OPEN_NAMESPACE +#define STITCH_CLARA_CLOSE_NAMESPACE +#else +#define STITCH_CLARA_CLOSE_NAMESPACE } +#endif + +#define STITCH_TBC_TEXT_FORMAT_OPEN_NAMESPACE STITCH_CLARA_OPEN_NAMESPACE + +// ----------- #included from tbc_text_format.h ----------- + +// Only use header guard if we are not using an outer namespace +#if !defined(TBC_TEXT_FORMAT_H_INCLUDED) || defined(STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE) +#ifndef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE +#define TBC_TEXT_FORMAT_H_INCLUDED +#endif + +#include +#include +#include +#include + +// Use optional outer namespace +#ifdef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE +namespace STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE { +#endif + +namespace Tbc { + +#ifdef TBC_TEXT_FORMAT_CONSOLE_WIDTH + const unsigned int consoleWidth = TBC_TEXT_FORMAT_CONSOLE_WIDTH; +#else + const unsigned int consoleWidth = 80; +#endif + + struct TextAttributes { + TextAttributes() + : initialIndent( std::string::npos ), + indent( 0 ), + width( consoleWidth-1 ), + tabChar( '\t' ) + {} + + TextAttributes& setInitialIndent( std::size_t _value ) { initialIndent = _value; return *this; } + TextAttributes& setIndent( std::size_t _value ) { indent = _value; return *this; } + TextAttributes& setWidth( std::size_t _value ) { width = _value; return *this; } + TextAttributes& setTabChar( char _value ) { tabChar = _value; return *this; } + + std::size_t initialIndent; // indent of first line, or npos + std::size_t indent; // indent of subsequent lines, or all if initialIndent is npos + std::size_t width; // maximum width of text, including indent. Longer text will wrap + char tabChar; // If this char is seen the indent is changed to current pos + }; + + class Text { + public: + Text( std::string const& _str, TextAttributes const& _attr = TextAttributes() ) + : attr( _attr ) + { + std::string wrappableChars = " [({.,/|\\-"; + std::size_t indent = _attr.initialIndent != std::string::npos + ? _attr.initialIndent + : _attr.indent; + std::string remainder = _str; + + while( !remainder.empty() ) { + if( lines.size() >= 1000 ) { + lines.push_back( "... message truncated due to excessive size" ); + return; + } + std::size_t tabPos = std::string::npos; + std::size_t width = (std::min)( remainder.size(), _attr.width - indent ); + std::size_t pos = remainder.find_first_of( '\n' ); + if( pos <= width ) { + width = pos; + } + pos = remainder.find_last_of( _attr.tabChar, width ); + if( pos != std::string::npos ) { + tabPos = pos; + if( remainder[width] == '\n' ) + width--; + remainder = remainder.substr( 0, tabPos ) + remainder.substr( tabPos+1 ); + } + + if( width == remainder.size() ) { + spliceLine( indent, remainder, width ); + } + else if( remainder[width] == '\n' ) { + spliceLine( indent, remainder, width ); + if( width <= 1 || remainder.size() != 1 ) + remainder = remainder.substr( 1 ); + indent = _attr.indent; + } + else { + pos = remainder.find_last_of( wrappableChars, width ); + if( pos != std::string::npos && pos > 0 ) { + spliceLine( indent, remainder, pos ); + if( remainder[0] == ' ' ) + remainder = remainder.substr( 1 ); + } + else { + spliceLine( indent, remainder, width-1 ); + lines.back() += "-"; + } + if( lines.size() == 1 ) + indent = _attr.indent; + if( tabPos != std::string::npos ) + indent += tabPos; + } + } + } + + void spliceLine( std::size_t _indent, std::string& _remainder, std::size_t _pos ) { + lines.push_back( std::string( _indent, ' ' ) + _remainder.substr( 0, _pos ) ); + _remainder = _remainder.substr( _pos ); + } + + typedef std::vector::const_iterator const_iterator; + + const_iterator begin() const { return lines.begin(); } + const_iterator end() const { return lines.end(); } + std::string const& last() const { return lines.back(); } + std::size_t size() const { return lines.size(); } + std::string const& operator[]( std::size_t _index ) const { return lines[_index]; } + std::string toString() const { + std::ostringstream oss; + oss << *this; + return oss.str(); + } + + inline friend std::ostream& operator << ( std::ostream& _stream, Text const& _text ) { + for( Text::const_iterator it = _text.begin(), itEnd = _text.end(); + it != itEnd; ++it ) { + if( it != _text.begin() ) + _stream << "\n"; + _stream << *it; + } + return _stream; + } + + private: + std::string str; + TextAttributes attr; + std::vector lines; + }; + +} // end namespace Tbc + +#ifdef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE +} // end outer namespace +#endif + +#endif // TBC_TEXT_FORMAT_H_INCLUDED + +// ----------- end of #include from tbc_text_format.h ----------- +// ........... back in clara.h + +#undef STITCH_TBC_TEXT_FORMAT_OPEN_NAMESPACE + +// ----------- #included from clara_compilers.h ----------- + +#ifndef TWOBLUECUBES_CLARA_COMPILERS_H_INCLUDED +#define TWOBLUECUBES_CLARA_COMPILERS_H_INCLUDED + +// Detect a number of compiler features - mostly C++11/14 conformance - by compiler +// The following features are defined: +// +// CLARA_CONFIG_CPP11_NULLPTR : is nullptr supported? +// CLARA_CONFIG_CPP11_NOEXCEPT : is noexcept supported? +// CLARA_CONFIG_CPP11_GENERATED_METHODS : The delete and default keywords for compiler generated methods +// CLARA_CONFIG_CPP11_OVERRIDE : is override supported? +// CLARA_CONFIG_CPP11_UNIQUE_PTR : is unique_ptr supported (otherwise use auto_ptr) + +// CLARA_CONFIG_CPP11_OR_GREATER : Is C++11 supported? + +// CLARA_CONFIG_VARIADIC_MACROS : are variadic macros supported? + +// In general each macro has a _NO_ form +// (e.g. CLARA_CONFIG_CPP11_NO_NULLPTR) which disables the feature. +// Many features, at point of detection, define an _INTERNAL_ macro, so they +// can be combined, en-mass, with the _NO_ forms later. + +// All the C++11 features can be disabled with CLARA_CONFIG_NO_CPP11 + +#ifdef __clang__ + +#if __has_feature(cxx_nullptr) +#define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR +#endif + +#if __has_feature(cxx_noexcept) +#define CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT +#endif + +#endif // __clang__ + +//////////////////////////////////////////////////////////////////////////////// +// GCC +#ifdef __GNUC__ + +#if __GNUC__ == 4 && __GNUC_MINOR__ >= 6 && defined(__GXX_EXPERIMENTAL_CXX0X__) +#define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR +#endif + +// - otherwise more recent versions define __cplusplus >= 201103L +// and will get picked up below + +#endif // __GNUC__ + +//////////////////////////////////////////////////////////////////////////////// +// Visual C++ +#ifdef _MSC_VER + +#if (_MSC_VER >= 1600) +#define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR +#define CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR +#endif + +#if (_MSC_VER >= 1900 ) // (VC++ 13 (VS2015)) +#define CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT +#define CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS +#endif + +#endif // _MSC_VER + +//////////////////////////////////////////////////////////////////////////////// +// C++ language feature support + +// catch all support for C++11 +#if defined(__cplusplus) && __cplusplus >= 201103L + +#define CLARA_CPP11_OR_GREATER + +#if !defined(CLARA_INTERNAL_CONFIG_CPP11_NULLPTR) +#define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR +#endif + +#ifndef CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT +#define CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT +#endif + +#ifndef CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS +#define CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS +#endif + +#if !defined(CLARA_INTERNAL_CONFIG_CPP11_OVERRIDE) +#define CLARA_INTERNAL_CONFIG_CPP11_OVERRIDE +#endif +#if !defined(CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) +#define CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR +#endif + +#endif // __cplusplus >= 201103L + +// Now set the actual defines based on the above + anything the user has configured +#if defined(CLARA_INTERNAL_CONFIG_CPP11_NULLPTR) && !defined(CLARA_CONFIG_CPP11_NO_NULLPTR) && !defined(CLARA_CONFIG_CPP11_NULLPTR) && !defined(CLARA_CONFIG_NO_CPP11) +#define CLARA_CONFIG_CPP11_NULLPTR +#endif +#if defined(CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT) && !defined(CLARA_CONFIG_CPP11_NO_NOEXCEPT) && !defined(CLARA_CONFIG_CPP11_NOEXCEPT) && !defined(CLARA_CONFIG_NO_CPP11) +#define CLARA_CONFIG_CPP11_NOEXCEPT +#endif +#if defined(CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS) && !defined(CLARA_CONFIG_CPP11_NO_GENERATED_METHODS) && !defined(CLARA_CONFIG_CPP11_GENERATED_METHODS) && !defined(CLARA_CONFIG_NO_CPP11) +#define CLARA_CONFIG_CPP11_GENERATED_METHODS +#endif +#if defined(CLARA_INTERNAL_CONFIG_CPP11_OVERRIDE) && !defined(CLARA_CONFIG_NO_OVERRIDE) && !defined(CLARA_CONFIG_CPP11_OVERRIDE) && !defined(CLARA_CONFIG_NO_CPP11) +#define CLARA_CONFIG_CPP11_OVERRIDE +#endif +#if defined(CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) && !defined(CLARA_CONFIG_NO_UNIQUE_PTR) && !defined(CLARA_CONFIG_CPP11_UNIQUE_PTR) && !defined(CLARA_CONFIG_NO_CPP11) +#define CLARA_CONFIG_CPP11_UNIQUE_PTR +#endif + +// noexcept support: +#if defined(CLARA_CONFIG_CPP11_NOEXCEPT) && !defined(CLARA_NOEXCEPT) +#define CLARA_NOEXCEPT noexcept +# define CLARA_NOEXCEPT_IS(x) noexcept(x) +#else +#define CLARA_NOEXCEPT throw() +# define CLARA_NOEXCEPT_IS(x) +#endif + +// nullptr support +#ifdef CLARA_CONFIG_CPP11_NULLPTR +#define CLARA_NULL nullptr +#else +#define CLARA_NULL NULL +#endif + +// override support +#ifdef CLARA_CONFIG_CPP11_OVERRIDE +#define CLARA_OVERRIDE override +#else +#define CLARA_OVERRIDE +#endif + +// unique_ptr support +#ifdef CLARA_CONFIG_CPP11_UNIQUE_PTR +# define CLARA_AUTO_PTR( T ) std::unique_ptr +#else +# define CLARA_AUTO_PTR( T ) std::auto_ptr +#endif + +#endif // TWOBLUECUBES_CLARA_COMPILERS_H_INCLUDED + +// ----------- end of #include from clara_compilers.h ----------- +// ........... back in clara.h + +#include +#include +#include + +// Use optional outer namespace +#ifdef STITCH_CLARA_OPEN_NAMESPACE +STITCH_CLARA_OPEN_NAMESPACE +#endif + +namespace Clara { + + struct UnpositionalTag {}; + + extern UnpositionalTag _; + +#ifdef CLARA_CONFIG_MAIN + UnpositionalTag _; +#endif + + namespace Detail { + +#ifdef CLARA_CONSOLE_WIDTH + const unsigned int consoleWidth = CLARA_CONFIG_CONSOLE_WIDTH; +#else + const unsigned int consoleWidth = 80; +#endif + + // Use this to try and stop compiler from warning about unreachable code + inline bool isTrue( bool value ) { return value; } + + using namespace Tbc; + + inline bool startsWith( std::string const& str, std::string const& prefix ) { + return str.size() >= prefix.size() && str.substr( 0, prefix.size() ) == prefix; + } + + template struct RemoveConstRef{ typedef T type; }; + template struct RemoveConstRef{ typedef T type; }; + template struct RemoveConstRef{ typedef T type; }; + template struct RemoveConstRef{ typedef T type; }; + + template struct IsBool { static const bool value = false; }; + template<> struct IsBool { static const bool value = true; }; + + template + void convertInto( std::string const& _source, T& _dest ) { + std::stringstream ss; + ss << _source; + ss >> _dest; + if( ss.fail() ) + throw std::runtime_error( "Unable to convert " + _source + " to destination type" ); + } + inline void convertInto( std::string const& _source, std::string& _dest ) { + _dest = _source; + } + inline void convertInto( std::string const& _source, bool& _dest ) { + std::string sourceLC = _source; + std::transform( sourceLC.begin(), sourceLC.end(), sourceLC.begin(), ::tolower ); + if( sourceLC == "y" || sourceLC == "1" || sourceLC == "true" || sourceLC == "yes" || sourceLC == "on" ) + _dest = true; + else if( sourceLC == "n" || sourceLC == "0" || sourceLC == "false" || sourceLC == "no" || sourceLC == "off" ) + _dest = false; + else + throw std::runtime_error( "Expected a boolean value but did not recognise:\n '" + _source + "'" ); + } + inline void convertInto( bool _source, bool& _dest ) { + _dest = _source; + } + template + inline void convertInto( bool, T& ) { + if( isTrue( true ) ) + throw std::runtime_error( "Invalid conversion" ); + } + + template + struct IArgFunction { + virtual ~IArgFunction() {} +#ifdef CLARA_CONFIG_CPP11_GENERATED_METHODS + IArgFunction() = default; + IArgFunction( IArgFunction const& ) = default; +#endif + virtual void set( ConfigT& config, std::string const& value ) const = 0; + virtual void setFlag( ConfigT& config ) const = 0; + virtual bool takesArg() const = 0; + virtual IArgFunction* clone() const = 0; + }; + + template + class BoundArgFunction { + public: + BoundArgFunction() : functionObj( CLARA_NULL ) {} + BoundArgFunction( IArgFunction* _functionObj ) : functionObj( _functionObj ) {} + BoundArgFunction( BoundArgFunction const& other ) : functionObj( other.functionObj ? other.functionObj->clone() : CLARA_NULL ) {} + BoundArgFunction& operator = ( BoundArgFunction const& other ) { + IArgFunction* newFunctionObj = other.functionObj ? other.functionObj->clone() : CLARA_NULL; + delete functionObj; + functionObj = newFunctionObj; + return *this; + } + ~BoundArgFunction() { delete functionObj; } + + void set( ConfigT& config, std::string const& value ) const { + functionObj->set( config, value ); + } + void setFlag( ConfigT& config ) const { + functionObj->setFlag( config ); + } + bool takesArg() const { return functionObj->takesArg(); } + + bool isSet() const { + return functionObj != CLARA_NULL; + } + private: + IArgFunction* functionObj; + }; + + template + struct NullBinder : IArgFunction{ + virtual void set( C&, std::string const& ) const {} + virtual void setFlag( C& ) const {} + virtual bool takesArg() const { return true; } + virtual IArgFunction* clone() const { return new NullBinder( *this ); } + }; + + template + struct BoundDataMember : IArgFunction{ + BoundDataMember( M C::* _member ) : member( _member ) {} + virtual void set( C& p, std::string const& stringValue ) const { + convertInto( stringValue, p.*member ); + } + virtual void setFlag( C& p ) const { + convertInto( true, p.*member ); + } + virtual bool takesArg() const { return !IsBool::value; } + virtual IArgFunction* clone() const { return new BoundDataMember( *this ); } + M C::* member; + }; + template + struct BoundUnaryMethod : IArgFunction{ + BoundUnaryMethod( void (C::*_member)( M ) ) : member( _member ) {} + virtual void set( C& p, std::string const& stringValue ) const { + typename RemoveConstRef::type value; + convertInto( stringValue, value ); + (p.*member)( value ); + } + virtual void setFlag( C& p ) const { + typename RemoveConstRef::type value; + convertInto( true, value ); + (p.*member)( value ); + } + virtual bool takesArg() const { return !IsBool::value; } + virtual IArgFunction* clone() const { return new BoundUnaryMethod( *this ); } + void (C::*member)( M ); + }; + template + struct BoundNullaryMethod : IArgFunction{ + BoundNullaryMethod( void (C::*_member)() ) : member( _member ) {} + virtual void set( C& p, std::string const& stringValue ) const { + bool value; + convertInto( stringValue, value ); + if( value ) + (p.*member)(); + } + virtual void setFlag( C& p ) const { + (p.*member)(); + } + virtual bool takesArg() const { return false; } + virtual IArgFunction* clone() const { return new BoundNullaryMethod( *this ); } + void (C::*member)(); + }; + + template + struct BoundUnaryFunction : IArgFunction{ + BoundUnaryFunction( void (*_function)( C& ) ) : function( _function ) {} + virtual void set( C& obj, std::string const& stringValue ) const { + bool value; + convertInto( stringValue, value ); + if( value ) + function( obj ); + } + virtual void setFlag( C& p ) const { + function( p ); + } + virtual bool takesArg() const { return false; } + virtual IArgFunction* clone() const { return new BoundUnaryFunction( *this ); } + void (*function)( C& ); + }; + + template + struct BoundBinaryFunction : IArgFunction{ + BoundBinaryFunction( void (*_function)( C&, T ) ) : function( _function ) {} + virtual void set( C& obj, std::string const& stringValue ) const { + typename RemoveConstRef::type value; + convertInto( stringValue, value ); + function( obj, value ); + } + virtual void setFlag( C& obj ) const { + typename RemoveConstRef::type value; + convertInto( true, value ); + function( obj, value ); + } + virtual bool takesArg() const { return !IsBool::value; } + virtual IArgFunction* clone() const { return new BoundBinaryFunction( *this ); } + void (*function)( C&, T ); + }; + + } // namespace Detail + + struct Parser { + Parser() : separators( " \t=:" ) {} + + struct Token { + enum Type { Positional, ShortOpt, LongOpt }; + Token( Type _type, std::string const& _data ) : type( _type ), data( _data ) {} + Type type; + std::string data; + }; + + void parseIntoTokens( int argc, char const* const argv[], std::vector& tokens ) const { + const std::string doubleDash = "--"; + for( int i = 1; i < argc && argv[i] != doubleDash; ++i ) + parseIntoTokens( argv[i] , tokens); + } + void parseIntoTokens( std::string arg, std::vector& tokens ) const { + while( !arg.empty() ) { + Parser::Token token( Parser::Token::Positional, arg ); + arg = ""; + if( token.data[0] == '-' ) { + if( token.data.size() > 1 && token.data[1] == '-' ) { + token = Parser::Token( Parser::Token::LongOpt, token.data.substr( 2 ) ); + } + else { + token = Parser::Token( Parser::Token::ShortOpt, token.data.substr( 1 ) ); + if( token.data.size() > 1 && separators.find( token.data[1] ) == std::string::npos ) { + arg = "-" + token.data.substr( 1 ); + token.data = token.data.substr( 0, 1 ); + } + } + } + if( token.type != Parser::Token::Positional ) { + std::size_t pos = token.data.find_first_of( separators ); + if( pos != std::string::npos ) { + arg = token.data.substr( pos+1 ); + token.data = token.data.substr( 0, pos ); + } + } + tokens.push_back( token ); + } + } + std::string separators; + }; + + template + struct CommonArgProperties { + CommonArgProperties() {} + CommonArgProperties( Detail::BoundArgFunction const& _boundField ) : boundField( _boundField ) {} + + Detail::BoundArgFunction boundField; + std::string description; + std::string detail; + std::string placeholder; // Only value if boundField takes an arg + + bool takesArg() const { + return !placeholder.empty(); + } + void validate() const { + if( !boundField.isSet() ) + throw std::logic_error( "option not bound" ); + } + }; + struct OptionArgProperties { + std::vector shortNames; + std::string longName; + + bool hasShortName( std::string const& shortName ) const { + return std::find( shortNames.begin(), shortNames.end(), shortName ) != shortNames.end(); + } + bool hasLongName( std::string const& _longName ) const { + return _longName == longName; + } + }; + struct PositionalArgProperties { + PositionalArgProperties() : position( -1 ) {} + int position; // -1 means non-positional (floating) + + bool isFixedPositional() const { + return position != -1; + } + }; + + template + class CommandLine { + + struct Arg : CommonArgProperties, OptionArgProperties, PositionalArgProperties { + Arg() {} + Arg( Detail::BoundArgFunction const& _boundField ) : CommonArgProperties( _boundField ) {} + + using CommonArgProperties::placeholder; // !TBD + + std::string dbgName() const { + if( !longName.empty() ) + return "--" + longName; + if( !shortNames.empty() ) + return "-" + shortNames[0]; + return "positional args"; + } + std::string commands() const { + std::ostringstream oss; + bool first = true; + std::vector::const_iterator it = shortNames.begin(), itEnd = shortNames.end(); + for(; it != itEnd; ++it ) { + if( first ) + first = false; + else + oss << ", "; + oss << "-" << *it; + } + if( !longName.empty() ) { + if( !first ) + oss << ", "; + oss << "--" << longName; + } + if( !placeholder.empty() ) + oss << " <" << placeholder << ">"; + return oss.str(); + } + }; + + typedef CLARA_AUTO_PTR( Arg ) ArgAutoPtr; + + friend void addOptName( Arg& arg, std::string const& optName ) + { + if( optName.empty() ) + return; + if( Detail::startsWith( optName, "--" ) ) { + if( !arg.longName.empty() ) + throw std::logic_error( "Only one long opt may be specified. '" + + arg.longName + + "' already specified, now attempting to add '" + + optName + "'" ); + arg.longName = optName.substr( 2 ); + } + else if( Detail::startsWith( optName, "-" ) ) + arg.shortNames.push_back( optName.substr( 1 ) ); + else + throw std::logic_error( "option must begin with - or --. Option was: '" + optName + "'" ); + } + friend void setPositionalArg( Arg& arg, int position ) + { + arg.position = position; + } + + class ArgBuilder { + public: + ArgBuilder( Arg* arg ) : m_arg( arg ) {} + + // Bind a non-boolean data member (requires placeholder string) + template + void bind( M C::* field, std::string const& placeholder ) { + m_arg->boundField = new Detail::BoundDataMember( field ); + m_arg->placeholder = placeholder; + } + // Bind a boolean data member (no placeholder required) + template + void bind( bool C::* field ) { + m_arg->boundField = new Detail::BoundDataMember( field ); + } + + // Bind a method taking a single, non-boolean argument (requires a placeholder string) + template + void bind( void (C::* unaryMethod)( M ), std::string const& placeholder ) { + m_arg->boundField = new Detail::BoundUnaryMethod( unaryMethod ); + m_arg->placeholder = placeholder; + } + + // Bind a method taking a single, boolean argument (no placeholder string required) + template + void bind( void (C::* unaryMethod)( bool ) ) { + m_arg->boundField = new Detail::BoundUnaryMethod( unaryMethod ); + } + + // Bind a method that takes no arguments (will be called if opt is present) + template + void bind( void (C::* nullaryMethod)() ) { + m_arg->boundField = new Detail::BoundNullaryMethod( nullaryMethod ); + } + + // Bind a free function taking a single argument - the object to operate on (no placeholder string required) + template + void bind( void (* unaryFunction)( C& ) ) { + m_arg->boundField = new Detail::BoundUnaryFunction( unaryFunction ); + } + + // Bind a free function taking a single argument - the object to operate on (requires a placeholder string) + template + void bind( void (* binaryFunction)( C&, T ), std::string const& placeholder ) { + m_arg->boundField = new Detail::BoundBinaryFunction( binaryFunction ); + m_arg->placeholder = placeholder; + } + + ArgBuilder& describe( std::string const& description ) { + m_arg->description = description; + return *this; + } + ArgBuilder& detail( std::string const& detail ) { + m_arg->detail = detail; + return *this; + } + + protected: + Arg* m_arg; + }; + + class OptBuilder : public ArgBuilder { + public: + OptBuilder( Arg* arg ) : ArgBuilder( arg ) {} + OptBuilder( OptBuilder& other ) : ArgBuilder( other ) {} + + OptBuilder& operator[]( std::string const& optName ) { + addOptName( *ArgBuilder::m_arg, optName ); + return *this; + } + }; + + public: + + CommandLine() + : m_boundProcessName( new Detail::NullBinder() ), + m_highestSpecifiedArgPosition( 0 ), + m_throwOnUnrecognisedTokens( false ) + {} + CommandLine( CommandLine const& other ) + : m_boundProcessName( other.m_boundProcessName ), + m_options ( other.m_options ), + m_positionalArgs( other.m_positionalArgs ), + m_highestSpecifiedArgPosition( other.m_highestSpecifiedArgPosition ), + m_throwOnUnrecognisedTokens( other.m_throwOnUnrecognisedTokens ) + { + if( other.m_floatingArg.get() ) + m_floatingArg.reset( new Arg( *other.m_floatingArg ) ); + } + + CommandLine& setThrowOnUnrecognisedTokens( bool shouldThrow = true ) { + m_throwOnUnrecognisedTokens = shouldThrow; + return *this; + } + + OptBuilder operator[]( std::string const& optName ) { + m_options.push_back( Arg() ); + addOptName( m_options.back(), optName ); + OptBuilder builder( &m_options.back() ); + return builder; + } + + ArgBuilder operator[]( int position ) { + m_positionalArgs.insert( std::make_pair( position, Arg() ) ); + if( position > m_highestSpecifiedArgPosition ) + m_highestSpecifiedArgPosition = position; + setPositionalArg( m_positionalArgs[position], position ); + ArgBuilder builder( &m_positionalArgs[position] ); + return builder; + } + + // Invoke this with the _ instance + ArgBuilder operator[]( UnpositionalTag ) { + if( m_floatingArg.get() ) + throw std::logic_error( "Only one unpositional argument can be added" ); + m_floatingArg.reset( new Arg() ); + ArgBuilder builder( m_floatingArg.get() ); + return builder; + } + + template + void bindProcessName( M C::* field ) { + m_boundProcessName = new Detail::BoundDataMember( field ); + } + template + void bindProcessName( void (C::*_unaryMethod)( M ) ) { + m_boundProcessName = new Detail::BoundUnaryMethod( _unaryMethod ); + } + + void optUsage( std::ostream& os, std::size_t indent = 0, std::size_t width = Detail::consoleWidth ) const { + typename std::vector::const_iterator itBegin = m_options.begin(), itEnd = m_options.end(), it; + std::size_t maxWidth = 0; + for( it = itBegin; it != itEnd; ++it ) + maxWidth = (std::max)( maxWidth, it->commands().size() ); + + for( it = itBegin; it != itEnd; ++it ) { + Detail::Text usage( it->commands(), Detail::TextAttributes() + .setWidth( maxWidth+indent ) + .setIndent( indent ) ); + Detail::Text desc( it->description, Detail::TextAttributes() + .setWidth( width - maxWidth - 3 ) ); + + for( std::size_t i = 0; i < (std::max)( usage.size(), desc.size() ); ++i ) { + std::string usageCol = i < usage.size() ? usage[i] : ""; + os << usageCol; + + if( i < desc.size() && !desc[i].empty() ) + os << std::string( indent + 2 + maxWidth - usageCol.size(), ' ' ) + << desc[i]; + os << "\n"; + } + } + } + std::string optUsage() const { + std::ostringstream oss; + optUsage( oss ); + return oss.str(); + } + + void argSynopsis( std::ostream& os ) const { + for( int i = 1; i <= m_highestSpecifiedArgPosition; ++i ) { + if( i > 1 ) + os << " "; + typename std::map::const_iterator it = m_positionalArgs.find( i ); + if( it != m_positionalArgs.end() ) + os << "<" << it->second.placeholder << ">"; + else if( m_floatingArg.get() ) + os << "<" << m_floatingArg->placeholder << ">"; + else + throw std::logic_error( "non consecutive positional arguments with no floating args" ); + } + // !TBD No indication of mandatory args + if( m_floatingArg.get() ) { + if( m_highestSpecifiedArgPosition > 1 ) + os << " "; + os << "[<" << m_floatingArg->placeholder << "> ...]"; + } + } + std::string argSynopsis() const { + std::ostringstream oss; + argSynopsis( oss ); + return oss.str(); + } + + void usage( std::ostream& os, std::string const& procName ) const { + validate(); + os << "usage:\n " << procName << " "; + argSynopsis( os ); + if( !m_options.empty() ) { + os << " [options]\n\nwhere options are: \n"; + optUsage( os, 2 ); + } + os << "\n"; + } + std::string usage( std::string const& procName ) const { + std::ostringstream oss; + usage( oss, procName ); + return oss.str(); + } + + ConfigT parse( int argc, char const* const argv[] ) const { + ConfigT config; + parseInto( argc, argv, config ); + return config; + } + + std::vector parseInto( int argc, char const* argv[], ConfigT& config ) const { + std::string processName = argv[0]; + std::size_t lastSlash = processName.find_last_of( "/\\" ); + if( lastSlash != std::string::npos ) + processName = processName.substr( lastSlash+1 ); + m_boundProcessName.set( config, processName ); + std::vector tokens; + Parser parser; + parser.parseIntoTokens( argc, argv, tokens ); + return populate( tokens, config ); + } + + std::vector populate( std::vector const& tokens, ConfigT& config ) const { + validate(); + std::vector unusedTokens = populateOptions( tokens, config ); + unusedTokens = populateFixedArgs( unusedTokens, config ); + unusedTokens = populateFloatingArgs( unusedTokens, config ); + return unusedTokens; + } + + std::vector populateOptions( std::vector const& tokens, ConfigT& config ) const { + std::vector unusedTokens; + std::vector errors; + for( std::size_t i = 0; i < tokens.size(); ++i ) { + Parser::Token const& token = tokens[i]; + typename std::vector::const_iterator it = m_options.begin(), itEnd = m_options.end(); + for(; it != itEnd; ++it ) { + Arg const& arg = *it; + + try { + if( ( token.type == Parser::Token::ShortOpt && arg.hasShortName( token.data ) ) || + ( token.type == Parser::Token::LongOpt && arg.hasLongName( token.data ) ) ) { + if( arg.takesArg() ) { + if( i == tokens.size()-1 || tokens[i+1].type != Parser::Token::Positional ) + errors.push_back( "Expected argument to option: " + token.data ); + else + arg.boundField.set( config, tokens[++i].data ); + } + else { + arg.boundField.setFlag( config ); + } + break; + } + } + catch( std::exception& ex ) { + errors.push_back( std::string( ex.what() ) + "\n- while parsing: (" + arg.commands() + ")" ); + } + } + if( it == itEnd ) { + if( token.type == Parser::Token::Positional || !m_throwOnUnrecognisedTokens ) + unusedTokens.push_back( token ); + else if( errors.empty() && m_throwOnUnrecognisedTokens ) + errors.push_back( "unrecognised option: " + token.data ); + } + } + if( !errors.empty() ) { + std::ostringstream oss; + for( std::vector::const_iterator it = errors.begin(), itEnd = errors.end(); + it != itEnd; + ++it ) { + if( it != errors.begin() ) + oss << "\n"; + oss << *it; + } + throw std::runtime_error( oss.str() ); + } + return unusedTokens; + } + std::vector populateFixedArgs( std::vector const& tokens, ConfigT& config ) const { + std::vector unusedTokens; + int position = 1; + for( std::size_t i = 0; i < tokens.size(); ++i ) { + Parser::Token const& token = tokens[i]; + typename std::map::const_iterator it = m_positionalArgs.find( position ); + if( it != m_positionalArgs.end() ) + it->second.boundField.set( config, token.data ); + else + unusedTokens.push_back( token ); + if( token.type == Parser::Token::Positional ) + position++; + } + return unusedTokens; + } + std::vector populateFloatingArgs( std::vector const& tokens, ConfigT& config ) const { + if( !m_floatingArg.get() ) + return tokens; + std::vector unusedTokens; + for( std::size_t i = 0; i < tokens.size(); ++i ) { + Parser::Token const& token = tokens[i]; + if( token.type == Parser::Token::Positional ) + m_floatingArg->boundField.set( config, token.data ); + else + unusedTokens.push_back( token ); + } + return unusedTokens; + } + + void validate() const + { + if( m_options.empty() && m_positionalArgs.empty() && !m_floatingArg.get() ) + throw std::logic_error( "No options or arguments specified" ); + + for( typename std::vector::const_iterator it = m_options.begin(), + itEnd = m_options.end(); + it != itEnd; ++it ) + it->validate(); + } + + private: + Detail::BoundArgFunction m_boundProcessName; + std::vector m_options; + std::map m_positionalArgs; + ArgAutoPtr m_floatingArg; + int m_highestSpecifiedArgPosition; + bool m_throwOnUnrecognisedTokens; + }; + +} // end namespace Clara + +STITCH_CLARA_CLOSE_NAMESPACE +#undef STITCH_CLARA_OPEN_NAMESPACE +#undef STITCH_CLARA_CLOSE_NAMESPACE + +#endif // TWOBLUECUBES_CLARA_H_INCLUDED +#undef STITCH_CLARA_OPEN_NAMESPACE + +// Restore Clara's value for console width, if present +#ifdef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH +#define CLARA_CONFIG_CONSOLE_WIDTH CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH +#undef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH +#endif + +#include + +namespace Catch { + + inline void abortAfterFirst( ConfigData& config ) { config.abortAfter = 1; } + inline void abortAfterX( ConfigData& config, int x ) { + if( x < 1 ) + throw std::runtime_error( "Value after -x or --abortAfter must be greater than zero" ); + config.abortAfter = x; + } + inline void addTestOrTags( ConfigData& config, std::string const& _testSpec ) { config.testsOrTags.push_back( _testSpec ); } + inline void addReporterName( ConfigData& config, std::string const& _reporterName ) { config.reporterNames.push_back( _reporterName ); } + + inline void addWarning( ConfigData& config, std::string const& _warning ) { + if( _warning == "NoAssertions" ) + config.warnings = static_cast( config.warnings | WarnAbout::NoAssertions ); + else + throw std::runtime_error( "Unrecognised warning: '" + _warning + "'" ); + } + inline void setOrder( ConfigData& config, std::string const& order ) { + if( startsWith( "declared", order ) ) + config.runOrder = RunTests::InDeclarationOrder; + else if( startsWith( "lexical", order ) ) + config.runOrder = RunTests::InLexicographicalOrder; + else if( startsWith( "random", order ) ) + config.runOrder = RunTests::InRandomOrder; + else + throw std::runtime_error( "Unrecognised ordering: '" + order + "'" ); + } + inline void setRngSeed( ConfigData& config, std::string const& seed ) { + if( seed == "time" ) { + config.rngSeed = static_cast( std::time(0) ); + } + else { + std::stringstream ss; + ss << seed; + ss >> config.rngSeed; + if( ss.fail() ) + throw std::runtime_error( "Argment to --rng-seed should be the word 'time' or a number" ); + } + } + inline void setVerbosity( ConfigData& config, int level ) { + // !TBD: accept strings? + config.verbosity = static_cast( level ); + } + inline void setShowDurations( ConfigData& config, bool _showDurations ) { + config.showDurations = _showDurations + ? ShowDurations::Always + : ShowDurations::Never; + } + inline void setUseColour( ConfigData& config, std::string const& value ) { + std::string mode = toLower( value ); + + if( mode == "yes" ) + config.useColour = UseColour::Yes; + else if( mode == "no" ) + config.useColour = UseColour::No; + else if( mode == "auto" ) + config.useColour = UseColour::Auto; + else + throw std::runtime_error( "colour mode must be one of: auto, yes or no" ); + } + inline void forceColour( ConfigData& config ) { + config.useColour = UseColour::Yes; + } + inline void loadTestNamesFromFile( ConfigData& config, std::string const& _filename ) { + std::ifstream f( _filename.c_str() ); + if( !f.is_open() ) + throw std::domain_error( "Unable to load input file: " + _filename ); + + std::string line; + while( std::getline( f, line ) ) { + line = trim(line); + if( !line.empty() && !startsWith( line, "#" ) ) + addTestOrTags( config, "\"" + line + "\"," ); + } + } + + inline Clara::CommandLine makeCommandLineParser() { + + using namespace Clara; + CommandLine cli; + + cli.bindProcessName( &ConfigData::processName ); + + cli["-?"]["-h"]["--help"] + .describe( "display usage information" ) + .bind( &ConfigData::showHelp ); + + cli["-l"]["--list-tests"] + .describe( "list all/matching test cases" ) + .bind( &ConfigData::listTests ); + + cli["-t"]["--list-tags"] + .describe( "list all/matching tags" ) + .bind( &ConfigData::listTags ); + + cli["-s"]["--success"] + .describe( "include successful tests in output" ) + .bind( &ConfigData::showSuccessfulTests ); + + cli["-b"]["--break"] + .describe( "break into debugger on failure" ) + .bind( &ConfigData::shouldDebugBreak ); + + cli["-e"]["--nothrow"] + .describe( "skip exception tests" ) + .bind( &ConfigData::noThrow ); + + cli["-i"]["--invisibles"] + .describe( "show invisibles (tabs, newlines)" ) + .bind( &ConfigData::showInvisibles ); + + cli["-o"]["--out"] + .describe( "output filename" ) + .bind( &ConfigData::outputFilename, "filename" ); + + cli["-r"]["--reporter"] +// .placeholder( "name[:filename]" ) + .describe( "reporter to use (defaults to console)" ) + .bind( &addReporterName, "name" ); + + cli["-n"]["--name"] + .describe( "suite name" ) + .bind( &ConfigData::name, "name" ); + + cli["-a"]["--abort"] + .describe( "abort at first failure" ) + .bind( &abortAfterFirst ); + + cli["-x"]["--abortx"] + .describe( "abort after x failures" ) + .bind( &abortAfterX, "no. failures" ); + + cli["-w"]["--warn"] + .describe( "enable warnings" ) + .bind( &addWarning, "warning name" ); + +// - needs updating if reinstated +// cli.into( &setVerbosity ) +// .describe( "level of verbosity (0=no output)" ) +// .shortOpt( "v") +// .longOpt( "verbosity" ) +// .placeholder( "level" ); + + cli[_] + .describe( "which test or tests to use" ) + .bind( &addTestOrTags, "test name, pattern or tags" ); + + cli["-d"]["--durations"] + .describe( "show test durations" ) + .bind( &setShowDurations, "yes|no" ); + + cli["-f"]["--input-file"] + .describe( "load test names to run from a file" ) + .bind( &loadTestNamesFromFile, "filename" ); + + cli["-#"]["--filenames-as-tags"] + .describe( "adds a tag for the filename" ) + .bind( &ConfigData::filenamesAsTags ); + + // Less common commands which don't have a short form + cli["--list-test-names-only"] + .describe( "list all/matching test cases names only" ) + .bind( &ConfigData::listTestNamesOnly ); + + cli["--list-reporters"] + .describe( "list all reporters" ) + .bind( &ConfigData::listReporters ); + + cli["--order"] + .describe( "test case order (defaults to decl)" ) + .bind( &setOrder, "decl|lex|rand" ); + + cli["--rng-seed"] + .describe( "set a specific seed for random numbers" ) + .bind( &setRngSeed, "'time'|number" ); + + cli["--force-colour"] + .describe( "force colourised output (deprecated)" ) + .bind( &forceColour ); + + cli["--use-colour"] + .describe( "should output be colourised" ) + .bind( &setUseColour, "yes|no" ); + + return cli; + } + +} // end namespace Catch + +// #included from: internal/catch_list.hpp +#define TWOBLUECUBES_CATCH_LIST_HPP_INCLUDED + +// #included from: catch_text.h +#define TWOBLUECUBES_CATCH_TEXT_H_INCLUDED + +#define TBC_TEXT_FORMAT_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH + +#define CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE Catch +// #included from: ../external/tbc_text_format.h +// Only use header guard if we are not using an outer namespace +#ifndef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE +# ifdef TWOBLUECUBES_TEXT_FORMAT_H_INCLUDED +# ifndef TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED +# define TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED +# endif +# else +# define TWOBLUECUBES_TEXT_FORMAT_H_INCLUDED +# endif +#endif +#ifndef TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED +#include +#include +#include + +// Use optional outer namespace +#ifdef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE +namespace CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE { +#endif + +namespace Tbc { + +#ifdef TBC_TEXT_FORMAT_CONSOLE_WIDTH + const unsigned int consoleWidth = TBC_TEXT_FORMAT_CONSOLE_WIDTH; +#else + const unsigned int consoleWidth = 80; +#endif + + struct TextAttributes { + TextAttributes() + : initialIndent( std::string::npos ), + indent( 0 ), + width( consoleWidth-1 ), + tabChar( '\t' ) + {} + + TextAttributes& setInitialIndent( std::size_t _value ) { initialIndent = _value; return *this; } + TextAttributes& setIndent( std::size_t _value ) { indent = _value; return *this; } + TextAttributes& setWidth( std::size_t _value ) { width = _value; return *this; } + TextAttributes& setTabChar( char _value ) { tabChar = _value; return *this; } + + std::size_t initialIndent; // indent of first line, or npos + std::size_t indent; // indent of subsequent lines, or all if initialIndent is npos + std::size_t width; // maximum width of text, including indent. Longer text will wrap + char tabChar; // If this char is seen the indent is changed to current pos + }; + + class Text { + public: + Text( std::string const& _str, TextAttributes const& _attr = TextAttributes() ) + : attr( _attr ) + { + std::string wrappableChars = " [({.,/|\\-"; + std::size_t indent = _attr.initialIndent != std::string::npos + ? _attr.initialIndent + : _attr.indent; + std::string remainder = _str; + + while( !remainder.empty() ) { + if( lines.size() >= 1000 ) { + lines.push_back( "... message truncated due to excessive size" ); + return; + } + std::size_t tabPos = std::string::npos; + std::size_t width = (std::min)( remainder.size(), _attr.width - indent ); + std::size_t pos = remainder.find_first_of( '\n' ); + if( pos <= width ) { + width = pos; + } + pos = remainder.find_last_of( _attr.tabChar, width ); + if( pos != std::string::npos ) { + tabPos = pos; + if( remainder[width] == '\n' ) + width--; + remainder = remainder.substr( 0, tabPos ) + remainder.substr( tabPos+1 ); + } + + if( width == remainder.size() ) { + spliceLine( indent, remainder, width ); + } + else if( remainder[width] == '\n' ) { + spliceLine( indent, remainder, width ); + if( width <= 1 || remainder.size() != 1 ) + remainder = remainder.substr( 1 ); + indent = _attr.indent; + } + else { + pos = remainder.find_last_of( wrappableChars, width ); + if( pos != std::string::npos && pos > 0 ) { + spliceLine( indent, remainder, pos ); + if( remainder[0] == ' ' ) + remainder = remainder.substr( 1 ); + } + else { + spliceLine( indent, remainder, width-1 ); + lines.back() += "-"; + } + if( lines.size() == 1 ) + indent = _attr.indent; + if( tabPos != std::string::npos ) + indent += tabPos; + } + } + } + + void spliceLine( std::size_t _indent, std::string& _remainder, std::size_t _pos ) { + lines.push_back( std::string( _indent, ' ' ) + _remainder.substr( 0, _pos ) ); + _remainder = _remainder.substr( _pos ); + } + + typedef std::vector::const_iterator const_iterator; + + const_iterator begin() const { return lines.begin(); } + const_iterator end() const { return lines.end(); } + std::string const& last() const { return lines.back(); } + std::size_t size() const { return lines.size(); } + std::string const& operator[]( std::size_t _index ) const { return lines[_index]; } + std::string toString() const { + std::ostringstream oss; + oss << *this; + return oss.str(); + } + + inline friend std::ostream& operator << ( std::ostream& _stream, Text const& _text ) { + for( Text::const_iterator it = _text.begin(), itEnd = _text.end(); + it != itEnd; ++it ) { + if( it != _text.begin() ) + _stream << "\n"; + _stream << *it; + } + return _stream; + } + + private: + std::string str; + TextAttributes attr; + std::vector lines; + }; + +} // end namespace Tbc + +#ifdef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE +} // end outer namespace +#endif + +#endif // TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED +#undef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE + +namespace Catch { + using Tbc::Text; + using Tbc::TextAttributes; +} + +// #included from: catch_console_colour.hpp +#define TWOBLUECUBES_CATCH_CONSOLE_COLOUR_HPP_INCLUDED + +namespace Catch { + + struct Colour { + enum Code { + None = 0, + + White, + Red, + Green, + Blue, + Cyan, + Yellow, + Grey, + + Bright = 0x10, + + BrightRed = Bright | Red, + BrightGreen = Bright | Green, + LightGrey = Bright | Grey, + BrightWhite = Bright | White, + + // By intention + FileName = LightGrey, + Warning = Yellow, + ResultError = BrightRed, + ResultSuccess = BrightGreen, + ResultExpectedFailure = Warning, + + Error = BrightRed, + Success = Green, + + OriginalExpression = Cyan, + ReconstructedExpression = Yellow, + + SecondaryText = LightGrey, + Headers = White + }; + + // Use constructed object for RAII guard + Colour( Code _colourCode ); + Colour( Colour const& other ); + ~Colour(); + + // Use static method for one-shot changes + static void use( Code _colourCode ); + + private: + bool m_moved; + }; + + inline std::ostream& operator << ( std::ostream& os, Colour const& ) { return os; } + +} // end namespace Catch + +// #included from: catch_interfaces_reporter.h +#define TWOBLUECUBES_CATCH_INTERFACES_REPORTER_H_INCLUDED + +#include +#include +#include +#include + +namespace Catch +{ + struct ReporterConfig { + explicit ReporterConfig( Ptr const& _fullConfig ) + : m_stream( &_fullConfig->stream() ), m_fullConfig( _fullConfig ) {} + + ReporterConfig( Ptr const& _fullConfig, std::ostream& _stream ) + : m_stream( &_stream ), m_fullConfig( _fullConfig ) {} + + std::ostream& stream() const { return *m_stream; } + Ptr fullConfig() const { return m_fullConfig; } + + private: + std::ostream* m_stream; + Ptr m_fullConfig; + }; + + struct ReporterPreferences { + ReporterPreferences() + : shouldRedirectStdOut( false ) + {} + + bool shouldRedirectStdOut; + }; + + template + struct LazyStat : Option { + LazyStat() : used( false ) {} + LazyStat& operator=( T const& _value ) { + Option::operator=( _value ); + used = false; + return *this; + } + void reset() { + Option::reset(); + used = false; + } + bool used; + }; + + struct TestRunInfo { + TestRunInfo( std::string const& _name ) : name( _name ) {} + std::string name; + }; + struct GroupInfo { + GroupInfo( std::string const& _name, + std::size_t _groupIndex, + std::size_t _groupsCount ) + : name( _name ), + groupIndex( _groupIndex ), + groupsCounts( _groupsCount ) + {} + + std::string name; + std::size_t groupIndex; + std::size_t groupsCounts; + }; + + struct AssertionStats { + AssertionStats( AssertionResult const& _assertionResult, + std::vector const& _infoMessages, + Totals const& _totals ) + : assertionResult( _assertionResult ), + infoMessages( _infoMessages ), + totals( _totals ) + { + if( assertionResult.hasMessage() ) { + // Copy message into messages list. + // !TBD This should have been done earlier, somewhere + MessageBuilder builder( assertionResult.getTestMacroName(), assertionResult.getSourceInfo(), assertionResult.getResultType() ); + builder << assertionResult.getMessage(); + builder.m_info.message = builder.m_stream.str(); + + infoMessages.push_back( builder.m_info ); + } + } + virtual ~AssertionStats(); + +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + AssertionStats( AssertionStats const& ) = default; + AssertionStats( AssertionStats && ) = default; + AssertionStats& operator = ( AssertionStats const& ) = default; + AssertionStats& operator = ( AssertionStats && ) = default; +# endif + + AssertionResult assertionResult; + std::vector infoMessages; + Totals totals; + }; + + struct SectionStats { + SectionStats( SectionInfo const& _sectionInfo, + Counts const& _assertions, + double _durationInSeconds, + bool _missingAssertions ) + : sectionInfo( _sectionInfo ), + assertions( _assertions ), + durationInSeconds( _durationInSeconds ), + missingAssertions( _missingAssertions ) + {} + virtual ~SectionStats(); +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + SectionStats( SectionStats const& ) = default; + SectionStats( SectionStats && ) = default; + SectionStats& operator = ( SectionStats const& ) = default; + SectionStats& operator = ( SectionStats && ) = default; +# endif + + SectionInfo sectionInfo; + Counts assertions; + double durationInSeconds; + bool missingAssertions; + }; + + struct TestCaseStats { + TestCaseStats( TestCaseInfo const& _testInfo, + Totals const& _totals, + std::string const& _stdOut, + std::string const& _stdErr, + bool _aborting ) + : testInfo( _testInfo ), + totals( _totals ), + stdOut( _stdOut ), + stdErr( _stdErr ), + aborting( _aborting ) + {} + virtual ~TestCaseStats(); + +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + TestCaseStats( TestCaseStats const& ) = default; + TestCaseStats( TestCaseStats && ) = default; + TestCaseStats& operator = ( TestCaseStats const& ) = default; + TestCaseStats& operator = ( TestCaseStats && ) = default; +# endif + + TestCaseInfo testInfo; + Totals totals; + std::string stdOut; + std::string stdErr; + bool aborting; + }; + + struct TestGroupStats { + TestGroupStats( GroupInfo const& _groupInfo, + Totals const& _totals, + bool _aborting ) + : groupInfo( _groupInfo ), + totals( _totals ), + aborting( _aborting ) + {} + TestGroupStats( GroupInfo const& _groupInfo ) + : groupInfo( _groupInfo ), + aborting( false ) + {} + virtual ~TestGroupStats(); + +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + TestGroupStats( TestGroupStats const& ) = default; + TestGroupStats( TestGroupStats && ) = default; + TestGroupStats& operator = ( TestGroupStats const& ) = default; + TestGroupStats& operator = ( TestGroupStats && ) = default; +# endif + + GroupInfo groupInfo; + Totals totals; + bool aborting; + }; + + struct TestRunStats { + TestRunStats( TestRunInfo const& _runInfo, + Totals const& _totals, + bool _aborting ) + : runInfo( _runInfo ), + totals( _totals ), + aborting( _aborting ) + {} + virtual ~TestRunStats(); + +# ifndef CATCH_CONFIG_CPP11_GENERATED_METHODS + TestRunStats( TestRunStats const& _other ) + : runInfo( _other.runInfo ), + totals( _other.totals ), + aborting( _other.aborting ) + {} +# else + TestRunStats( TestRunStats const& ) = default; + TestRunStats( TestRunStats && ) = default; + TestRunStats& operator = ( TestRunStats const& ) = default; + TestRunStats& operator = ( TestRunStats && ) = default; +# endif + + TestRunInfo runInfo; + Totals totals; + bool aborting; + }; + + struct IStreamingReporter : IShared { + virtual ~IStreamingReporter(); + + // Implementing class must also provide the following static method: + // static std::string getDescription(); + + virtual ReporterPreferences getPreferences() const = 0; + + virtual void noMatchingTestCases( std::string const& spec ) = 0; + + virtual void testRunStarting( TestRunInfo const& testRunInfo ) = 0; + virtual void testGroupStarting( GroupInfo const& groupInfo ) = 0; + + virtual void testCaseStarting( TestCaseInfo const& testInfo ) = 0; + virtual void sectionStarting( SectionInfo const& sectionInfo ) = 0; + + virtual void assertionStarting( AssertionInfo const& assertionInfo ) = 0; + + // The return value indicates if the messages buffer should be cleared: + virtual bool assertionEnded( AssertionStats const& assertionStats ) = 0; + + virtual void sectionEnded( SectionStats const& sectionStats ) = 0; + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) = 0; + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) = 0; + virtual void testRunEnded( TestRunStats const& testRunStats ) = 0; + + virtual void skipTest( TestCaseInfo const& testInfo ) = 0; + }; + + struct IReporterFactory : IShared { + virtual ~IReporterFactory(); + virtual IStreamingReporter* create( ReporterConfig const& config ) const = 0; + virtual std::string getDescription() const = 0; + }; + + struct IReporterRegistry { + typedef std::map > FactoryMap; + typedef std::vector > Listeners; + + virtual ~IReporterRegistry(); + virtual IStreamingReporter* create( std::string const& name, Ptr const& config ) const = 0; + virtual FactoryMap const& getFactories() const = 0; + virtual Listeners const& getListeners() const = 0; + }; + + Ptr addReporter( Ptr const& existingReporter, Ptr const& additionalReporter ); + +} + +#include +#include + +namespace Catch { + + inline std::size_t listTests( Config const& config ) { + + TestSpec testSpec = config.testSpec(); + if( config.testSpec().hasFilters() ) + Catch::cout() << "Matching test cases:\n"; + else { + Catch::cout() << "All available test cases:\n"; + testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); + } + + std::size_t matchedTests = 0; + TextAttributes nameAttr, tagsAttr; + nameAttr.setInitialIndent( 2 ).setIndent( 4 ); + tagsAttr.setIndent( 6 ); + + std::vector matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); + for( std::vector::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); + it != itEnd; + ++it ) { + matchedTests++; + TestCaseInfo const& testCaseInfo = it->getTestCaseInfo(); + Colour::Code colour = testCaseInfo.isHidden() + ? Colour::SecondaryText + : Colour::None; + Colour colourGuard( colour ); + + Catch::cout() << Text( testCaseInfo.name, nameAttr ) << std::endl; + if( !testCaseInfo.tags.empty() ) + Catch::cout() << Text( testCaseInfo.tagsAsString, tagsAttr ) << std::endl; + } + + if( !config.testSpec().hasFilters() ) + Catch::cout() << pluralise( matchedTests, "test case" ) << "\n" << std::endl; + else + Catch::cout() << pluralise( matchedTests, "matching test case" ) << "\n" << std::endl; + return matchedTests; + } + + inline std::size_t listTestsNamesOnly( Config const& config ) { + TestSpec testSpec = config.testSpec(); + if( !config.testSpec().hasFilters() ) + testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); + std::size_t matchedTests = 0; + std::vector matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); + for( std::vector::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); + it != itEnd; + ++it ) { + matchedTests++; + TestCaseInfo const& testCaseInfo = it->getTestCaseInfo(); + Catch::cout() << testCaseInfo.name << std::endl; + } + return matchedTests; + } + + struct TagInfo { + TagInfo() : count ( 0 ) {} + void add( std::string const& spelling ) { + ++count; + spellings.insert( spelling ); + } + std::string all() const { + std::string out; + for( std::set::const_iterator it = spellings.begin(), itEnd = spellings.end(); + it != itEnd; + ++it ) + out += "[" + *it + "]"; + return out; + } + std::set spellings; + std::size_t count; + }; + + inline std::size_t listTags( Config const& config ) { + TestSpec testSpec = config.testSpec(); + if( config.testSpec().hasFilters() ) + Catch::cout() << "Tags for matching test cases:\n"; + else { + Catch::cout() << "All available tags:\n"; + testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); + } + + std::map tagCounts; + + std::vector matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); + for( std::vector::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); + it != itEnd; + ++it ) { + for( std::set::const_iterator tagIt = it->getTestCaseInfo().tags.begin(), + tagItEnd = it->getTestCaseInfo().tags.end(); + tagIt != tagItEnd; + ++tagIt ) { + std::string tagName = *tagIt; + std::string lcaseTagName = toLower( tagName ); + std::map::iterator countIt = tagCounts.find( lcaseTagName ); + if( countIt == tagCounts.end() ) + countIt = tagCounts.insert( std::make_pair( lcaseTagName, TagInfo() ) ).first; + countIt->second.add( tagName ); + } + } + + for( std::map::const_iterator countIt = tagCounts.begin(), + countItEnd = tagCounts.end(); + countIt != countItEnd; + ++countIt ) { + std::ostringstream oss; + oss << " " << std::setw(2) << countIt->second.count << " "; + Text wrapper( countIt->second.all(), TextAttributes() + .setInitialIndent( 0 ) + .setIndent( oss.str().size() ) + .setWidth( CATCH_CONFIG_CONSOLE_WIDTH-10 ) ); + Catch::cout() << oss.str() << wrapper << "\n"; + } + Catch::cout() << pluralise( tagCounts.size(), "tag" ) << "\n" << std::endl; + return tagCounts.size(); + } + + inline std::size_t listReporters( Config const& /*config*/ ) { + Catch::cout() << "Available reporters:\n"; + IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories(); + IReporterRegistry::FactoryMap::const_iterator itBegin = factories.begin(), itEnd = factories.end(), it; + std::size_t maxNameLen = 0; + for(it = itBegin; it != itEnd; ++it ) + maxNameLen = (std::max)( maxNameLen, it->first.size() ); + + for(it = itBegin; it != itEnd; ++it ) { + Text wrapper( it->second->getDescription(), TextAttributes() + .setInitialIndent( 0 ) + .setIndent( 7+maxNameLen ) + .setWidth( CATCH_CONFIG_CONSOLE_WIDTH - maxNameLen-8 ) ); + Catch::cout() << " " + << it->first + << ":" + << std::string( maxNameLen - it->first.size() + 2, ' ' ) + << wrapper << "\n"; + } + Catch::cout() << std::endl; + return factories.size(); + } + + inline Option list( Config const& config ) { + Option listedCount; + if( config.listTests() ) + listedCount = listedCount.valueOr(0) + listTests( config ); + if( config.listTestNamesOnly() ) + listedCount = listedCount.valueOr(0) + listTestsNamesOnly( config ); + if( config.listTags() ) + listedCount = listedCount.valueOr(0) + listTags( config ); + if( config.listReporters() ) + listedCount = listedCount.valueOr(0) + listReporters( config ); + return listedCount; + } + +} // end namespace Catch + +// #included from: internal/catch_run_context.hpp +#define TWOBLUECUBES_CATCH_RUNNER_IMPL_HPP_INCLUDED + +// #included from: catch_test_case_tracker.hpp +#define TWOBLUECUBES_CATCH_TEST_CASE_TRACKER_HPP_INCLUDED + +#include +#include +#include +#include + +namespace Catch { +namespace TestCaseTracking { + + struct ITracker : SharedImpl<> { + virtual ~ITracker(); + + // static queries + virtual std::string name() const = 0; + + // dynamic queries + virtual bool isComplete() const = 0; // Successfully completed or failed + virtual bool isSuccessfullyCompleted() const = 0; + virtual bool isOpen() const = 0; // Started but not complete + virtual bool hasChildren() const = 0; + + virtual ITracker& parent() = 0; + + // actions + virtual void close() = 0; // Successfully complete + virtual void fail() = 0; + virtual void markAsNeedingAnotherRun() = 0; + + virtual void addChild( Ptr const& child ) = 0; + virtual ITracker* findChild( std::string const& name ) = 0; + virtual void openChild() = 0; + }; + + class TrackerContext { + + enum RunState { + NotStarted, + Executing, + CompletedCycle + }; + + Ptr m_rootTracker; + ITracker* m_currentTracker; + RunState m_runState; + + public: + + static TrackerContext& instance() { + static TrackerContext s_instance; + return s_instance; + } + + TrackerContext() + : m_currentTracker( CATCH_NULL ), + m_runState( NotStarted ) + {} + + ITracker& startRun(); + + void endRun() { + m_rootTracker.reset(); + m_currentTracker = CATCH_NULL; + m_runState = NotStarted; + } + + void startCycle() { + m_currentTracker = m_rootTracker.get(); + m_runState = Executing; + } + void completeCycle() { + m_runState = CompletedCycle; + } + + bool completedCycle() const { + return m_runState == CompletedCycle; + } + ITracker& currentTracker() { + return *m_currentTracker; + } + void setCurrentTracker( ITracker* tracker ) { + m_currentTracker = tracker; + } + }; + + class TrackerBase : public ITracker { + protected: + enum CycleState { + NotStarted, + Executing, + ExecutingChildren, + NeedsAnotherRun, + CompletedSuccessfully, + Failed + }; + class TrackerHasName { + std::string m_name; + public: + TrackerHasName( std::string const& name ) : m_name( name ) {} + bool operator ()( Ptr const& tracker ) { + return tracker->name() == m_name; + } + }; + typedef std::vector > Children; + std::string m_name; + TrackerContext& m_ctx; + ITracker* m_parent; + Children m_children; + CycleState m_runState; + public: + TrackerBase( std::string const& name, TrackerContext& ctx, ITracker* parent ) + : m_name( name ), + m_ctx( ctx ), + m_parent( parent ), + m_runState( NotStarted ) + {} + virtual ~TrackerBase(); + + virtual std::string name() const CATCH_OVERRIDE { + return m_name; + } + virtual bool isComplete() const CATCH_OVERRIDE { + return m_runState == CompletedSuccessfully || m_runState == Failed; + } + virtual bool isSuccessfullyCompleted() const CATCH_OVERRIDE { + return m_runState == CompletedSuccessfully; + } + virtual bool isOpen() const CATCH_OVERRIDE { + return m_runState != NotStarted && !isComplete(); + } + virtual bool hasChildren() const CATCH_OVERRIDE { + return !m_children.empty(); + } + + virtual void addChild( Ptr const& child ) CATCH_OVERRIDE { + m_children.push_back( child ); + } + + virtual ITracker* findChild( std::string const& name ) CATCH_OVERRIDE { + Children::const_iterator it = std::find_if( m_children.begin(), m_children.end(), TrackerHasName( name ) ); + return( it != m_children.end() ) + ? it->get() + : CATCH_NULL; + } + virtual ITracker& parent() CATCH_OVERRIDE { + assert( m_parent ); // Should always be non-null except for root + return *m_parent; + } + + virtual void openChild() CATCH_OVERRIDE { + if( m_runState != ExecutingChildren ) { + m_runState = ExecutingChildren; + if( m_parent ) + m_parent->openChild(); + } + } + void open() { + m_runState = Executing; + moveToThis(); + if( m_parent ) + m_parent->openChild(); + } + + virtual void close() CATCH_OVERRIDE { + + // Close any still open children (e.g. generators) + while( &m_ctx.currentTracker() != this ) + m_ctx.currentTracker().close(); + + switch( m_runState ) { + case NotStarted: + case CompletedSuccessfully: + case Failed: + throw std::logic_error( "Illogical state" ); + + case NeedsAnotherRun: + break;; + + case Executing: + m_runState = CompletedSuccessfully; + break; + case ExecutingChildren: + if( m_children.empty() || m_children.back()->isComplete() ) + m_runState = CompletedSuccessfully; + break; + + default: + throw std::logic_error( "Unexpected state" ); + } + moveToParent(); + m_ctx.completeCycle(); + } + virtual void fail() CATCH_OVERRIDE { + m_runState = Failed; + if( m_parent ) + m_parent->markAsNeedingAnotherRun(); + moveToParent(); + m_ctx.completeCycle(); + } + virtual void markAsNeedingAnotherRun() CATCH_OVERRIDE { + m_runState = NeedsAnotherRun; + } + private: + void moveToParent() { + assert( m_parent ); + m_ctx.setCurrentTracker( m_parent ); + } + void moveToThis() { + m_ctx.setCurrentTracker( this ); + } + }; + + class SectionTracker : public TrackerBase { + public: + SectionTracker( std::string const& name, TrackerContext& ctx, ITracker* parent ) + : TrackerBase( name, ctx, parent ) + {} + virtual ~SectionTracker(); + + static SectionTracker& acquire( TrackerContext& ctx, std::string const& name ) { + SectionTracker* section = CATCH_NULL; + + ITracker& currentTracker = ctx.currentTracker(); + if( ITracker* childTracker = currentTracker.findChild( name ) ) { + section = dynamic_cast( childTracker ); + assert( section ); + } + else { + section = new SectionTracker( name, ctx, ¤tTracker ); + currentTracker.addChild( section ); + } + if( !ctx.completedCycle() && !section->isComplete() ) { + + section->open(); + } + return *section; + } + }; + + class IndexTracker : public TrackerBase { + int m_size; + int m_index; + public: + IndexTracker( std::string const& name, TrackerContext& ctx, ITracker* parent, int size ) + : TrackerBase( name, ctx, parent ), + m_size( size ), + m_index( -1 ) + {} + virtual ~IndexTracker(); + + static IndexTracker& acquire( TrackerContext& ctx, std::string const& name, int size ) { + IndexTracker* tracker = CATCH_NULL; + + ITracker& currentTracker = ctx.currentTracker(); + if( ITracker* childTracker = currentTracker.findChild( name ) ) { + tracker = dynamic_cast( childTracker ); + assert( tracker ); + } + else { + tracker = new IndexTracker( name, ctx, ¤tTracker, size ); + currentTracker.addChild( tracker ); + } + + if( !ctx.completedCycle() && !tracker->isComplete() ) { + if( tracker->m_runState != ExecutingChildren && tracker->m_runState != NeedsAnotherRun ) + tracker->moveNext(); + tracker->open(); + } + + return *tracker; + } + + int index() const { return m_index; } + + void moveNext() { + m_index++; + m_children.clear(); + } + + virtual void close() CATCH_OVERRIDE { + TrackerBase::close(); + if( m_runState == CompletedSuccessfully && m_index < m_size-1 ) + m_runState = Executing; + } + }; + + inline ITracker& TrackerContext::startRun() { + m_rootTracker = new SectionTracker( "{root}", *this, CATCH_NULL ); + m_currentTracker = CATCH_NULL; + m_runState = Executing; + return *m_rootTracker; + } + +} // namespace TestCaseTracking + +using TestCaseTracking::ITracker; +using TestCaseTracking::TrackerContext; +using TestCaseTracking::SectionTracker; +using TestCaseTracking::IndexTracker; + +} // namespace Catch + +// #included from: catch_fatal_condition.hpp +#define TWOBLUECUBES_CATCH_FATAL_CONDITION_H_INCLUDED + +namespace Catch { + + // Report the error condition then exit the process + inline void fatal( std::string const& message, int exitCode ) { + IContext& context = Catch::getCurrentContext(); + IResultCapture* resultCapture = context.getResultCapture(); + resultCapture->handleFatalErrorCondition( message ); + + if( Catch::alwaysTrue() ) // avoids "no return" warnings + exit( exitCode ); + } + +} // namespace Catch + +#if defined ( CATCH_PLATFORM_WINDOWS ) ///////////////////////////////////////// + +namespace Catch { + + struct FatalConditionHandler { + void reset() {} + }; + +} // namespace Catch + +#else // Not Windows - assumed to be POSIX compatible ////////////////////////// + +#include + +namespace Catch { + + struct SignalDefs { int id; const char* name; }; + extern SignalDefs signalDefs[]; + SignalDefs signalDefs[] = { + { SIGINT, "SIGINT - Terminal interrupt signal" }, + { SIGILL, "SIGILL - Illegal instruction signal" }, + { SIGFPE, "SIGFPE - Floating point error signal" }, + { SIGSEGV, "SIGSEGV - Segmentation violation signal" }, + { SIGTERM, "SIGTERM - Termination request signal" }, + { SIGABRT, "SIGABRT - Abort (abnormal termination) signal" } + }; + + struct FatalConditionHandler { + + static void handleSignal( int sig ) { + for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) + if( sig == signalDefs[i].id ) + fatal( signalDefs[i].name, -sig ); + fatal( "", -sig ); + } + + FatalConditionHandler() : m_isSet( true ) { + for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) + signal( signalDefs[i].id, handleSignal ); + } + ~FatalConditionHandler() { + reset(); + } + void reset() { + if( m_isSet ) { + for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) + signal( signalDefs[i].id, SIG_DFL ); + m_isSet = false; + } + } + + bool m_isSet; + }; + +} // namespace Catch + +#endif // not Windows + +#include +#include + +namespace Catch { + + class StreamRedirect { + + public: + StreamRedirect( std::ostream& stream, std::string& targetString ) + : m_stream( stream ), + m_prevBuf( stream.rdbuf() ), + m_targetString( targetString ) + { + stream.rdbuf( m_oss.rdbuf() ); + } + + ~StreamRedirect() { + m_targetString += m_oss.str(); + m_stream.rdbuf( m_prevBuf ); + } + + private: + std::ostream& m_stream; + std::streambuf* m_prevBuf; + std::ostringstream m_oss; + std::string& m_targetString; + }; + + /////////////////////////////////////////////////////////////////////////// + + class RunContext : public IResultCapture, public IRunner { + + RunContext( RunContext const& ); + void operator =( RunContext const& ); + + public: + + explicit RunContext( Ptr const& _config, Ptr const& reporter ) + : m_runInfo( _config->name() ), + m_context( getCurrentMutableContext() ), + m_activeTestCase( CATCH_NULL ), + m_config( _config ), + m_reporter( reporter ) + { + m_context.setRunner( this ); + m_context.setConfig( m_config ); + m_context.setResultCapture( this ); + m_reporter->testRunStarting( m_runInfo ); + } + + virtual ~RunContext() { + m_reporter->testRunEnded( TestRunStats( m_runInfo, m_totals, aborting() ) ); + } + + void testGroupStarting( std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount ) { + m_reporter->testGroupStarting( GroupInfo( testSpec, groupIndex, groupsCount ) ); + } + void testGroupEnded( std::string const& testSpec, Totals const& totals, std::size_t groupIndex, std::size_t groupsCount ) { + m_reporter->testGroupEnded( TestGroupStats( GroupInfo( testSpec, groupIndex, groupsCount ), totals, aborting() ) ); + } + + Totals runTest( TestCase const& testCase ) { + Totals prevTotals = m_totals; + + std::string redirectedCout; + std::string redirectedCerr; + + TestCaseInfo testInfo = testCase.getTestCaseInfo(); + + m_reporter->testCaseStarting( testInfo ); + + m_activeTestCase = &testCase; + + do { + m_trackerContext.startRun(); + do { + m_trackerContext.startCycle(); + m_testCaseTracker = &SectionTracker::acquire( m_trackerContext, testInfo.name ); + runCurrentTest( redirectedCout, redirectedCerr ); + } + while( !m_testCaseTracker->isSuccessfullyCompleted() && !aborting() ); + } + // !TBD: deprecated - this will be replaced by indexed trackers + while( getCurrentContext().advanceGeneratorsForCurrentTest() && !aborting() ); + + Totals deltaTotals = m_totals.delta( prevTotals ); + m_totals.testCases += deltaTotals.testCases; + m_reporter->testCaseEnded( TestCaseStats( testInfo, + deltaTotals, + redirectedCout, + redirectedCerr, + aborting() ) ); + + m_activeTestCase = CATCH_NULL; + m_testCaseTracker = CATCH_NULL; + + return deltaTotals; + } + + Ptr config() const { + return m_config; + } + + private: // IResultCapture + + virtual void assertionEnded( AssertionResult const& result ) { + if( result.getResultType() == ResultWas::Ok ) { + m_totals.assertions.passed++; + } + else if( !result.isOk() ) { + m_totals.assertions.failed++; + } + + if( m_reporter->assertionEnded( AssertionStats( result, m_messages, m_totals ) ) ) + m_messages.clear(); + + // Reset working state + m_lastAssertionInfo = AssertionInfo( "", m_lastAssertionInfo.lineInfo, "{Unknown expression after the reported line}" , m_lastAssertionInfo.resultDisposition ); + m_lastResult = result; + } + + virtual bool sectionStarted ( + SectionInfo const& sectionInfo, + Counts& assertions + ) + { + std::ostringstream oss; + oss << sectionInfo.name << "@" << sectionInfo.lineInfo; + + ITracker& sectionTracker = SectionTracker::acquire( m_trackerContext, oss.str() ); + if( !sectionTracker.isOpen() ) + return false; + m_activeSections.push_back( §ionTracker ); + + m_lastAssertionInfo.lineInfo = sectionInfo.lineInfo; + + m_reporter->sectionStarting( sectionInfo ); + + assertions = m_totals.assertions; + + return true; + } + bool testForMissingAssertions( Counts& assertions ) { + if( assertions.total() != 0 ) + return false; + if( !m_config->warnAboutMissingAssertions() ) + return false; + if( m_trackerContext.currentTracker().hasChildren() ) + return false; + m_totals.assertions.failed++; + assertions.failed++; + return true; + } + + virtual void sectionEnded( SectionEndInfo const& endInfo ) { + Counts assertions = m_totals.assertions - endInfo.prevAssertions; + bool missingAssertions = testForMissingAssertions( assertions ); + + if( !m_activeSections.empty() ) { + m_activeSections.back()->close(); + m_activeSections.pop_back(); + } + + m_reporter->sectionEnded( SectionStats( endInfo.sectionInfo, assertions, endInfo.durationInSeconds, missingAssertions ) ); + m_messages.clear(); + } + + virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) { + if( m_unfinishedSections.empty() ) + m_activeSections.back()->fail(); + else + m_activeSections.back()->close(); + m_activeSections.pop_back(); + + m_unfinishedSections.push_back( endInfo ); + } + + virtual void pushScopedMessage( MessageInfo const& message ) { + m_messages.push_back( message ); + } + + virtual void popScopedMessage( MessageInfo const& message ) { + m_messages.erase( std::remove( m_messages.begin(), m_messages.end(), message ), m_messages.end() ); + } + + virtual std::string getCurrentTestName() const { + return m_activeTestCase + ? m_activeTestCase->getTestCaseInfo().name + : ""; + } + + virtual const AssertionResult* getLastResult() const { + return &m_lastResult; + } + + virtual void handleFatalErrorCondition( std::string const& message ) { + ResultBuilder resultBuilder = makeUnexpectedResultBuilder(); + resultBuilder.setResultType( ResultWas::FatalErrorCondition ); + resultBuilder << message; + resultBuilder.captureExpression(); + + handleUnfinishedSections(); + + // Recreate section for test case (as we will lose the one that was in scope) + TestCaseInfo const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); + SectionInfo testCaseSection( testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description ); + + Counts assertions; + assertions.failed = 1; + SectionStats testCaseSectionStats( testCaseSection, assertions, 0, false ); + m_reporter->sectionEnded( testCaseSectionStats ); + + TestCaseInfo testInfo = m_activeTestCase->getTestCaseInfo(); + + Totals deltaTotals; + deltaTotals.testCases.failed = 1; + m_reporter->testCaseEnded( TestCaseStats( testInfo, + deltaTotals, + "", + "", + false ) ); + m_totals.testCases.failed++; + testGroupEnded( "", m_totals, 1, 1 ); + m_reporter->testRunEnded( TestRunStats( m_runInfo, m_totals, false ) ); + } + + public: + // !TBD We need to do this another way! + bool aborting() const { + return m_totals.assertions.failed == static_cast( m_config->abortAfter() ); + } + + private: + + void runCurrentTest( std::string& redirectedCout, std::string& redirectedCerr ) { + TestCaseInfo const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); + SectionInfo testCaseSection( testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description ); + m_reporter->sectionStarting( testCaseSection ); + Counts prevAssertions = m_totals.assertions; + double duration = 0; + try { + m_lastAssertionInfo = AssertionInfo( "TEST_CASE", testCaseInfo.lineInfo, "", ResultDisposition::Normal ); + + seedRng( *m_config ); + + Timer timer; + timer.start(); + if( m_reporter->getPreferences().shouldRedirectStdOut ) { + StreamRedirect coutRedir( Catch::cout(), redirectedCout ); + StreamRedirect cerrRedir( Catch::cerr(), redirectedCerr ); + invokeActiveTestCase(); + } + else { + invokeActiveTestCase(); + } + duration = timer.getElapsedSeconds(); + } + catch( TestFailureException& ) { + // This just means the test was aborted due to failure + } + catch(...) { + makeUnexpectedResultBuilder().useActiveException(); + } + m_testCaseTracker->close(); + handleUnfinishedSections(); + m_messages.clear(); + + Counts assertions = m_totals.assertions - prevAssertions; + bool missingAssertions = testForMissingAssertions( assertions ); + + if( testCaseInfo.okToFail() ) { + std::swap( assertions.failedButOk, assertions.failed ); + m_totals.assertions.failed -= assertions.failedButOk; + m_totals.assertions.failedButOk += assertions.failedButOk; + } + + SectionStats testCaseSectionStats( testCaseSection, assertions, duration, missingAssertions ); + m_reporter->sectionEnded( testCaseSectionStats ); + } + + void invokeActiveTestCase() { + FatalConditionHandler fatalConditionHandler; // Handle signals + m_activeTestCase->invoke(); + fatalConditionHandler.reset(); + } + + private: + + ResultBuilder makeUnexpectedResultBuilder() const { + return ResultBuilder( m_lastAssertionInfo.macroName.c_str(), + m_lastAssertionInfo.lineInfo, + m_lastAssertionInfo.capturedExpression.c_str(), + m_lastAssertionInfo.resultDisposition ); + } + + void handleUnfinishedSections() { + // If sections ended prematurely due to an exception we stored their + // infos here so we can tear them down outside the unwind process. + for( std::vector::const_reverse_iterator it = m_unfinishedSections.rbegin(), + itEnd = m_unfinishedSections.rend(); + it != itEnd; + ++it ) + sectionEnded( *it ); + m_unfinishedSections.clear(); + } + + TestRunInfo m_runInfo; + IMutableContext& m_context; + TestCase const* m_activeTestCase; + ITracker* m_testCaseTracker; + ITracker* m_currentSectionTracker; + AssertionResult m_lastResult; + + Ptr m_config; + Totals m_totals; + Ptr m_reporter; + std::vector m_messages; + AssertionInfo m_lastAssertionInfo; + std::vector m_unfinishedSections; + std::vector m_activeSections; + TrackerContext m_trackerContext; + }; + + IResultCapture& getResultCapture() { + if( IResultCapture* capture = getCurrentContext().getResultCapture() ) + return *capture; + else + throw std::logic_error( "No result capture instance" ); + } + +} // end namespace Catch + +// #included from: internal/catch_version.h +#define TWOBLUECUBES_CATCH_VERSION_H_INCLUDED + +namespace Catch { + + // Versioning information + struct Version { + Version( unsigned int _majorVersion, + unsigned int _minorVersion, + unsigned int _patchNumber, + std::string const& _branchName, + unsigned int _buildNumber ); + + unsigned int const majorVersion; + unsigned int const minorVersion; + unsigned int const patchNumber; + + // buildNumber is only used if branchName is not null + std::string const branchName; + unsigned int const buildNumber; + + friend std::ostream& operator << ( std::ostream& os, Version const& version ); + + private: + void operator=( Version const& ); + }; + + extern Version libraryVersion; +} + +#include +#include +#include + +namespace Catch { + + Ptr createReporter( std::string const& reporterName, Ptr const& config ) { + Ptr reporter = getRegistryHub().getReporterRegistry().create( reporterName, config.get() ); + if( !reporter ) { + std::ostringstream oss; + oss << "No reporter registered with name: '" << reporterName << "'"; + throw std::domain_error( oss.str() ); + } + return reporter; + } + + Ptr makeReporter( Ptr const& config ) { + std::vector reporters = config->getReporterNames(); + if( reporters.empty() ) + reporters.push_back( "console" ); + + Ptr reporter; + for( std::vector::const_iterator it = reporters.begin(), itEnd = reporters.end(); + it != itEnd; + ++it ) + reporter = addReporter( reporter, createReporter( *it, config ) ); + return reporter; + } + Ptr addListeners( Ptr const& config, Ptr reporters ) { + IReporterRegistry::Listeners listeners = getRegistryHub().getReporterRegistry().getListeners(); + for( IReporterRegistry::Listeners::const_iterator it = listeners.begin(), itEnd = listeners.end(); + it != itEnd; + ++it ) + reporters = addReporter(reporters, (*it)->create( ReporterConfig( config ) ) ); + return reporters; + } + + Totals runTests( Ptr const& config ) { + + Ptr iconfig = config.get(); + + Ptr reporter = makeReporter( config ); + reporter = addListeners( iconfig, reporter ); + + RunContext context( iconfig, reporter ); + + Totals totals; + + context.testGroupStarting( config->name(), 1, 1 ); + + TestSpec testSpec = config->testSpec(); + if( !testSpec.hasFilters() ) + testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "~[.]" ).testSpec(); // All not hidden tests + + std::vector const& allTestCases = getAllTestCasesSorted( *iconfig ); + for( std::vector::const_iterator it = allTestCases.begin(), itEnd = allTestCases.end(); + it != itEnd; + ++it ) { + if( !context.aborting() && matchTest( *it, testSpec, *iconfig ) ) + totals += context.runTest( *it ); + else + reporter->skipTest( *it ); + } + + context.testGroupEnded( iconfig->name(), totals, 1, 1 ); + return totals; + } + + void applyFilenamesAsTags( IConfig const& config ) { + std::vector const& tests = getAllTestCasesSorted( config ); + for(std::size_t i = 0; i < tests.size(); ++i ) { + TestCase& test = const_cast( tests[i] ); + std::set tags = test.tags; + + std::string filename = test.lineInfo.file; + std::string::size_type lastSlash = filename.find_last_of( "\\/" ); + if( lastSlash != std::string::npos ) + filename = filename.substr( lastSlash+1 ); + + std::string::size_type lastDot = filename.find_last_of( "." ); + if( lastDot != std::string::npos ) + filename = filename.substr( 0, lastDot ); + + tags.insert( "#" + filename ); + setTags( test, tags ); + } + } + + class Session : NonCopyable { + static bool alreadyInstantiated; + + public: + + struct OnUnusedOptions { enum DoWhat { Ignore, Fail }; }; + + Session() + : m_cli( makeCommandLineParser() ) { + if( alreadyInstantiated ) { + std::string msg = "Only one instance of Catch::Session can ever be used"; + Catch::cerr() << msg << std::endl; + throw std::logic_error( msg ); + } + alreadyInstantiated = true; + } + ~Session() { + Catch::cleanUp(); + } + + void showHelp( std::string const& processName ) { + Catch::cout() << "\nCatch v" << libraryVersion << "\n"; + + m_cli.usage( Catch::cout(), processName ); + Catch::cout() << "For more detail usage please see the project docs\n" << std::endl; + } + + int applyCommandLine( int argc, char const* argv[], OnUnusedOptions::DoWhat unusedOptionBehaviour = OnUnusedOptions::Fail ) { + try { + m_cli.setThrowOnUnrecognisedTokens( unusedOptionBehaviour == OnUnusedOptions::Fail ); + m_unusedTokens = m_cli.parseInto( argc, argv, m_configData ); + if( m_configData.showHelp ) + showHelp( m_configData.processName ); + m_config.reset(); + } + catch( std::exception& ex ) { + { + Colour colourGuard( Colour::Red ); + Catch::cerr() + << "\nError(s) in input:\n" + << Text( ex.what(), TextAttributes().setIndent(2) ) + << "\n\n"; + } + m_cli.usage( Catch::cout(), m_configData.processName ); + return (std::numeric_limits::max)(); + } + return 0; + } + + void useConfigData( ConfigData const& _configData ) { + m_configData = _configData; + m_config.reset(); + } + + int run( int argc, char const* argv[] ) { + + int returnCode = applyCommandLine( argc, argv ); + if( returnCode == 0 ) + returnCode = run(); + return returnCode; + } + int run( int argc, char* argv[] ) { + return run( argc, const_cast( argv ) ); + } + + int run() { + if( m_configData.showHelp ) + return 0; + + try + { + config(); // Force config to be constructed + + seedRng( *m_config ); + + if( m_configData.filenamesAsTags ) + applyFilenamesAsTags( *m_config ); + + // Handle list request + if( Option listed = list( config() ) ) + return static_cast( *listed ); + + return static_cast( runTests( m_config ).assertions.failed ); + } + catch( std::exception& ex ) { + Catch::cerr() << ex.what() << std::endl; + return (std::numeric_limits::max)(); + } + } + + Clara::CommandLine const& cli() const { + return m_cli; + } + std::vector const& unusedTokens() const { + return m_unusedTokens; + } + ConfigData& configData() { + return m_configData; + } + Config& config() { + if( !m_config ) + m_config = new Config( m_configData ); + return *m_config; + } + private: + Clara::CommandLine m_cli; + std::vector m_unusedTokens; + ConfigData m_configData; + Ptr m_config; + }; + + bool Session::alreadyInstantiated = false; + +} // end namespace Catch + +// #included from: catch_registry_hub.hpp +#define TWOBLUECUBES_CATCH_REGISTRY_HUB_HPP_INCLUDED + +// #included from: catch_test_case_registry_impl.hpp +#define TWOBLUECUBES_CATCH_TEST_CASE_REGISTRY_IMPL_HPP_INCLUDED + +#include +#include +#include +#include +#include + +namespace Catch { + + struct LexSort { + bool operator() (TestCase i,TestCase j) const { return (i sortTests( IConfig const& config, std::vector const& unsortedTestCases ) { + + std::vector sorted = unsortedTestCases; + + switch( config.runOrder() ) { + case RunTests::InLexicographicalOrder: + std::sort( sorted.begin(), sorted.end(), LexSort() ); + break; + case RunTests::InRandomOrder: + { + seedRng( config ); + + RandomNumberGenerator rng; + std::random_shuffle( sorted.begin(), sorted.end(), rng ); + } + break; + case RunTests::InDeclarationOrder: + // already in declaration order + break; + } + return sorted; + } + bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ) { + return testSpec.matches( testCase ) && ( config.allowThrows() || !testCase.throws() ); + } + + void enforceNoDuplicateTestCases( std::vector const& functions ) { + std::set seenFunctions; + for( std::vector::const_iterator it = functions.begin(), itEnd = functions.end(); + it != itEnd; + ++it ) { + std::pair::const_iterator, bool> prev = seenFunctions.insert( *it ); + if( !prev.second ){ + Catch::cerr() + << Colour( Colour::Red ) + << "error: TEST_CASE( \"" << it->name << "\" ) already defined.\n" + << "\tFirst seen at " << prev.first->getTestCaseInfo().lineInfo << "\n" + << "\tRedefined at " << it->getTestCaseInfo().lineInfo << std::endl; + exit(1); + } + } + } + + std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ) { + std::vector filtered; + filtered.reserve( testCases.size() ); + for( std::vector::const_iterator it = testCases.begin(), itEnd = testCases.end(); + it != itEnd; + ++it ) + if( matchTest( *it, testSpec, config ) ) + filtered.push_back( *it ); + return filtered; + } + std::vector const& getAllTestCasesSorted( IConfig const& config ) { + return getRegistryHub().getTestCaseRegistry().getAllTestsSorted( config ); + } + + class TestRegistry : public ITestCaseRegistry { + public: + TestRegistry() + : m_currentSortOrder( RunTests::InDeclarationOrder ), + m_unnamedCount( 0 ) + {} + virtual ~TestRegistry(); + + virtual void registerTest( TestCase const& testCase ) { + std::string name = testCase.getTestCaseInfo().name; + if( name == "" ) { + std::ostringstream oss; + oss << "Anonymous test case " << ++m_unnamedCount; + return registerTest( testCase.withName( oss.str() ) ); + } + m_functions.push_back( testCase ); + } + + virtual std::vector const& getAllTests() const { + return m_functions; + } + virtual std::vector const& getAllTestsSorted( IConfig const& config ) const { + if( m_sortedFunctions.empty() ) + enforceNoDuplicateTestCases( m_functions ); + + if( m_currentSortOrder != config.runOrder() || m_sortedFunctions.empty() ) { + m_sortedFunctions = sortTests( config, m_functions ); + m_currentSortOrder = config.runOrder(); + } + return m_sortedFunctions; + } + + private: + std::vector m_functions; + mutable RunTests::InWhatOrder m_currentSortOrder; + mutable std::vector m_sortedFunctions; + size_t m_unnamedCount; + std::ios_base::Init m_ostreamInit; // Forces cout/ cerr to be initialised + }; + + /////////////////////////////////////////////////////////////////////////// + + class FreeFunctionTestCase : public SharedImpl { + public: + + FreeFunctionTestCase( TestFunction fun ) : m_fun( fun ) {} + + virtual void invoke() const { + m_fun(); + } + + private: + virtual ~FreeFunctionTestCase(); + + TestFunction m_fun; + }; + + inline std::string extractClassName( std::string const& classOrQualifiedMethodName ) { + std::string className = classOrQualifiedMethodName; + if( startsWith( className, "&" ) ) + { + std::size_t lastColons = className.rfind( "::" ); + std::size_t penultimateColons = className.rfind( "::", lastColons-1 ); + if( penultimateColons == std::string::npos ) + penultimateColons = 1; + className = className.substr( penultimateColons, lastColons-penultimateColons ); + } + return className; + } + + void registerTestCase + ( ITestCase* testCase, + char const* classOrQualifiedMethodName, + NameAndDesc const& nameAndDesc, + SourceLineInfo const& lineInfo ) { + + getMutableRegistryHub().registerTest + ( makeTestCase + ( testCase, + extractClassName( classOrQualifiedMethodName ), + nameAndDesc.name, + nameAndDesc.description, + lineInfo ) ); + } + void registerTestCaseFunction + ( TestFunction function, + SourceLineInfo const& lineInfo, + NameAndDesc const& nameAndDesc ) { + registerTestCase( new FreeFunctionTestCase( function ), "", nameAndDesc, lineInfo ); + } + + /////////////////////////////////////////////////////////////////////////// + + AutoReg::AutoReg + ( TestFunction function, + SourceLineInfo const& lineInfo, + NameAndDesc const& nameAndDesc ) { + registerTestCaseFunction( function, lineInfo, nameAndDesc ); + } + + AutoReg::~AutoReg() {} + +} // end namespace Catch + +// #included from: catch_reporter_registry.hpp +#define TWOBLUECUBES_CATCH_REPORTER_REGISTRY_HPP_INCLUDED + +#include + +namespace Catch { + + class ReporterRegistry : public IReporterRegistry { + + public: + + virtual ~ReporterRegistry() CATCH_OVERRIDE {} + + virtual IStreamingReporter* create( std::string const& name, Ptr const& config ) const CATCH_OVERRIDE { + FactoryMap::const_iterator it = m_factories.find( name ); + if( it == m_factories.end() ) + return CATCH_NULL; + return it->second->create( ReporterConfig( config ) ); + } + + void registerReporter( std::string const& name, Ptr const& factory ) { + m_factories.insert( std::make_pair( name, factory ) ); + } + void registerListener( Ptr const& factory ) { + m_listeners.push_back( factory ); + } + + virtual FactoryMap const& getFactories() const CATCH_OVERRIDE { + return m_factories; + } + virtual Listeners const& getListeners() const CATCH_OVERRIDE { + return m_listeners; + } + + private: + FactoryMap m_factories; + Listeners m_listeners; + }; +} + +// #included from: catch_exception_translator_registry.hpp +#define TWOBLUECUBES_CATCH_EXCEPTION_TRANSLATOR_REGISTRY_HPP_INCLUDED + +#ifdef __OBJC__ +#import "Foundation/Foundation.h" +#endif + +namespace Catch { + + class ExceptionTranslatorRegistry : public IExceptionTranslatorRegistry { + public: + ~ExceptionTranslatorRegistry() { + deleteAll( m_translators ); + } + + virtual void registerTranslator( const IExceptionTranslator* translator ) { + m_translators.push_back( translator ); + } + + virtual std::string translateActiveException() const { + try { +#ifdef __OBJC__ + // In Objective-C try objective-c exceptions first + @try { + return tryTranslators(); + } + @catch (NSException *exception) { + return Catch::toString( [exception description] ); + } +#else + return tryTranslators(); +#endif + } + catch( TestFailureException& ) { + throw; + } + catch( std::exception& ex ) { + return ex.what(); + } + catch( std::string& msg ) { + return msg; + } + catch( const char* msg ) { + return msg; + } + catch(...) { + return "Unknown exception"; + } + } + + std::string tryTranslators() const { + if( m_translators.empty() ) + throw; + else + return m_translators[0]->translate( m_translators.begin()+1, m_translators.end() ); + } + + private: + std::vector m_translators; + }; +} + +namespace Catch { + + namespace { + + class RegistryHub : public IRegistryHub, public IMutableRegistryHub { + + RegistryHub( RegistryHub const& ); + void operator=( RegistryHub const& ); + + public: // IRegistryHub + RegistryHub() { + } + virtual IReporterRegistry const& getReporterRegistry() const CATCH_OVERRIDE { + return m_reporterRegistry; + } + virtual ITestCaseRegistry const& getTestCaseRegistry() const CATCH_OVERRIDE { + return m_testCaseRegistry; + } + virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() CATCH_OVERRIDE { + return m_exceptionTranslatorRegistry; + } + + public: // IMutableRegistryHub + virtual void registerReporter( std::string const& name, Ptr const& factory ) CATCH_OVERRIDE { + m_reporterRegistry.registerReporter( name, factory ); + } + virtual void registerListener( Ptr const& factory ) CATCH_OVERRIDE { + m_reporterRegistry.registerListener( factory ); + } + virtual void registerTest( TestCase const& testInfo ) CATCH_OVERRIDE { + m_testCaseRegistry.registerTest( testInfo ); + } + virtual void registerTranslator( const IExceptionTranslator* translator ) CATCH_OVERRIDE { + m_exceptionTranslatorRegistry.registerTranslator( translator ); + } + + private: + TestRegistry m_testCaseRegistry; + ReporterRegistry m_reporterRegistry; + ExceptionTranslatorRegistry m_exceptionTranslatorRegistry; + }; + + // Single, global, instance + inline RegistryHub*& getTheRegistryHub() { + static RegistryHub* theRegistryHub = CATCH_NULL; + if( !theRegistryHub ) + theRegistryHub = new RegistryHub(); + return theRegistryHub; + } + } + + IRegistryHub& getRegistryHub() { + return *getTheRegistryHub(); + } + IMutableRegistryHub& getMutableRegistryHub() { + return *getTheRegistryHub(); + } + void cleanUp() { + delete getTheRegistryHub(); + getTheRegistryHub() = CATCH_NULL; + cleanUpContext(); + } + std::string translateActiveException() { + return getRegistryHub().getExceptionTranslatorRegistry().translateActiveException(); + } + +} // end namespace Catch + +// #included from: catch_notimplemented_exception.hpp +#define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_HPP_INCLUDED + +#include + +namespace Catch { + + NotImplementedException::NotImplementedException( SourceLineInfo const& lineInfo ) + : m_lineInfo( lineInfo ) { + std::ostringstream oss; + oss << lineInfo << ": function "; + oss << "not implemented"; + m_what = oss.str(); + } + + const char* NotImplementedException::what() const CATCH_NOEXCEPT { + return m_what.c_str(); + } + +} // end namespace Catch + +// #included from: catch_context_impl.hpp +#define TWOBLUECUBES_CATCH_CONTEXT_IMPL_HPP_INCLUDED + +// #included from: catch_stream.hpp +#define TWOBLUECUBES_CATCH_STREAM_HPP_INCLUDED + +#include +#include +#include + +namespace Catch { + + template + class StreamBufImpl : public StreamBufBase { + char data[bufferSize]; + WriterF m_writer; + + public: + StreamBufImpl() { + setp( data, data + sizeof(data) ); + } + + ~StreamBufImpl() CATCH_NOEXCEPT { + sync(); + } + + private: + int overflow( int c ) { + sync(); + + if( c != EOF ) { + if( pbase() == epptr() ) + m_writer( std::string( 1, static_cast( c ) ) ); + else + sputc( static_cast( c ) ); + } + return 0; + } + + int sync() { + if( pbase() != pptr() ) { + m_writer( std::string( pbase(), static_cast( pptr() - pbase() ) ) ); + setp( pbase(), epptr() ); + } + return 0; + } + }; + + /////////////////////////////////////////////////////////////////////////// + + FileStream::FileStream( std::string const& filename ) { + m_ofs.open( filename.c_str() ); + if( m_ofs.fail() ) { + std::ostringstream oss; + oss << "Unable to open file: '" << filename << "'"; + throw std::domain_error( oss.str() ); + } + } + + std::ostream& FileStream::stream() const { + return m_ofs; + } + + struct OutputDebugWriter { + + void operator()( std::string const&str ) { + writeToDebugConsole( str ); + } + }; + + DebugOutStream::DebugOutStream() + : m_streamBuf( new StreamBufImpl() ), + m_os( m_streamBuf.get() ) + {} + + std::ostream& DebugOutStream::stream() const { + return m_os; + } + + // Store the streambuf from cout up-front because + // cout may get redirected when running tests + CoutStream::CoutStream() + : m_os( Catch::cout().rdbuf() ) + {} + + std::ostream& CoutStream::stream() const { + return m_os; + } + +#ifndef CATCH_CONFIG_NOSTDOUT // If you #define this you must implement these functions + std::ostream& cout() { + return std::cout; + } + std::ostream& cerr() { + return std::cerr; + } +#endif +} + +namespace Catch { + + class Context : public IMutableContext { + + Context() : m_config( CATCH_NULL ), m_runner( CATCH_NULL ), m_resultCapture( CATCH_NULL ) {} + Context( Context const& ); + void operator=( Context const& ); + + public: // IContext + virtual IResultCapture* getResultCapture() { + return m_resultCapture; + } + virtual IRunner* getRunner() { + return m_runner; + } + virtual size_t getGeneratorIndex( std::string const& fileInfo, size_t totalSize ) { + return getGeneratorsForCurrentTest() + .getGeneratorInfo( fileInfo, totalSize ) + .getCurrentIndex(); + } + virtual bool advanceGeneratorsForCurrentTest() { + IGeneratorsForTest* generators = findGeneratorsForCurrentTest(); + return generators && generators->moveNext(); + } + + virtual Ptr getConfig() const { + return m_config; + } + + public: // IMutableContext + virtual void setResultCapture( IResultCapture* resultCapture ) { + m_resultCapture = resultCapture; + } + virtual void setRunner( IRunner* runner ) { + m_runner = runner; + } + virtual void setConfig( Ptr const& config ) { + m_config = config; + } + + friend IMutableContext& getCurrentMutableContext(); + + private: + IGeneratorsForTest* findGeneratorsForCurrentTest() { + std::string testName = getResultCapture()->getCurrentTestName(); + + std::map::const_iterator it = + m_generatorsByTestName.find( testName ); + return it != m_generatorsByTestName.end() + ? it->second + : CATCH_NULL; + } + + IGeneratorsForTest& getGeneratorsForCurrentTest() { + IGeneratorsForTest* generators = findGeneratorsForCurrentTest(); + if( !generators ) { + std::string testName = getResultCapture()->getCurrentTestName(); + generators = createGeneratorsForTest(); + m_generatorsByTestName.insert( std::make_pair( testName, generators ) ); + } + return *generators; + } + + private: + Ptr m_config; + IRunner* m_runner; + IResultCapture* m_resultCapture; + std::map m_generatorsByTestName; + }; + + namespace { + Context* currentContext = CATCH_NULL; + } + IMutableContext& getCurrentMutableContext() { + if( !currentContext ) + currentContext = new Context(); + return *currentContext; + } + IContext& getCurrentContext() { + return getCurrentMutableContext(); + } + + void cleanUpContext() { + delete currentContext; + currentContext = CATCH_NULL; + } +} + +// #included from: catch_console_colour_impl.hpp +#define TWOBLUECUBES_CATCH_CONSOLE_COLOUR_IMPL_HPP_INCLUDED + +namespace Catch { + namespace { + + struct IColourImpl { + virtual ~IColourImpl() {} + virtual void use( Colour::Code _colourCode ) = 0; + }; + + struct NoColourImpl : IColourImpl { + void use( Colour::Code ) {} + + static IColourImpl* instance() { + static NoColourImpl s_instance; + return &s_instance; + } + }; + + } // anon namespace +} // namespace Catch + +#if !defined( CATCH_CONFIG_COLOUR_NONE ) && !defined( CATCH_CONFIG_COLOUR_WINDOWS ) && !defined( CATCH_CONFIG_COLOUR_ANSI ) +# ifdef CATCH_PLATFORM_WINDOWS +# define CATCH_CONFIG_COLOUR_WINDOWS +# else +# define CATCH_CONFIG_COLOUR_ANSI +# endif +#endif + +#if defined ( CATCH_CONFIG_COLOUR_WINDOWS ) ///////////////////////////////////////// + +#ifndef NOMINMAX +#define NOMINMAX +#endif + +#ifdef __AFXDLL +#include +#else +#include +#endif + +namespace Catch { +namespace { + + class Win32ColourImpl : public IColourImpl { + public: + Win32ColourImpl() : stdoutHandle( GetStdHandle(STD_OUTPUT_HANDLE) ) + { + CONSOLE_SCREEN_BUFFER_INFO csbiInfo; + GetConsoleScreenBufferInfo( stdoutHandle, &csbiInfo ); + originalForegroundAttributes = csbiInfo.wAttributes & ~( BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_BLUE | BACKGROUND_INTENSITY ); + originalBackgroundAttributes = csbiInfo.wAttributes & ~( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY ); + } + + virtual void use( Colour::Code _colourCode ) { + switch( _colourCode ) { + case Colour::None: return setTextAttribute( originalForegroundAttributes ); + case Colour::White: return setTextAttribute( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE ); + case Colour::Red: return setTextAttribute( FOREGROUND_RED ); + case Colour::Green: return setTextAttribute( FOREGROUND_GREEN ); + case Colour::Blue: return setTextAttribute( FOREGROUND_BLUE ); + case Colour::Cyan: return setTextAttribute( FOREGROUND_BLUE | FOREGROUND_GREEN ); + case Colour::Yellow: return setTextAttribute( FOREGROUND_RED | FOREGROUND_GREEN ); + case Colour::Grey: return setTextAttribute( 0 ); + + case Colour::LightGrey: return setTextAttribute( FOREGROUND_INTENSITY ); + case Colour::BrightRed: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED ); + case Colour::BrightGreen: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN ); + case Colour::BrightWhite: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE ); + + case Colour::Bright: throw std::logic_error( "not a colour" ); + } + } + + private: + void setTextAttribute( WORD _textAttribute ) { + SetConsoleTextAttribute( stdoutHandle, _textAttribute | originalBackgroundAttributes ); + } + HANDLE stdoutHandle; + WORD originalForegroundAttributes; + WORD originalBackgroundAttributes; + }; + + IColourImpl* platformColourInstance() { + static Win32ColourImpl s_instance; + + Ptr config = getCurrentContext().getConfig(); + UseColour::YesOrNo colourMode = config + ? config->useColour() + : UseColour::Auto; + if( colourMode == UseColour::Auto ) + colourMode = !isDebuggerActive() + ? UseColour::Yes + : UseColour::No; + return colourMode == UseColour::Yes + ? &s_instance + : NoColourImpl::instance(); + } + +} // end anon namespace +} // end namespace Catch + +#elif defined( CATCH_CONFIG_COLOUR_ANSI ) ////////////////////////////////////// + +#include + +namespace Catch { +namespace { + + // use POSIX/ ANSI console terminal codes + // Thanks to Adam Strzelecki for original contribution + // (http://github.com/nanoant) + // https://github.com/philsquared/Catch/pull/131 + class PosixColourImpl : public IColourImpl { + public: + virtual void use( Colour::Code _colourCode ) { + switch( _colourCode ) { + case Colour::None: + case Colour::White: return setColour( "[0m" ); + case Colour::Red: return setColour( "[0;31m" ); + case Colour::Green: return setColour( "[0;32m" ); + case Colour::Blue: return setColour( "[0:34m" ); + case Colour::Cyan: return setColour( "[0;36m" ); + case Colour::Yellow: return setColour( "[0;33m" ); + case Colour::Grey: return setColour( "[1;30m" ); + + case Colour::LightGrey: return setColour( "[0;37m" ); + case Colour::BrightRed: return setColour( "[1;31m" ); + case Colour::BrightGreen: return setColour( "[1;32m" ); + case Colour::BrightWhite: return setColour( "[1;37m" ); + + case Colour::Bright: throw std::logic_error( "not a colour" ); + } + } + static IColourImpl* instance() { + static PosixColourImpl s_instance; + return &s_instance; + } + + private: + void setColour( const char* _escapeCode ) { + Catch::cout() << '\033' << _escapeCode; + } + }; + + IColourImpl* platformColourInstance() { + Ptr config = getCurrentContext().getConfig(); + UseColour::YesOrNo colourMode = config + ? config->useColour() + : UseColour::Auto; + if( colourMode == UseColour::Auto ) + colourMode = (!isDebuggerActive() && isatty(STDOUT_FILENO) ) + ? UseColour::Yes + : UseColour::No; + return colourMode == UseColour::Yes + ? PosixColourImpl::instance() + : NoColourImpl::instance(); + } + +} // end anon namespace +} // end namespace Catch + +#else // not Windows or ANSI /////////////////////////////////////////////// + +namespace Catch { + + static IColourImpl* platformColourInstance() { return NoColourImpl::instance(); } + +} // end namespace Catch + +#endif // Windows/ ANSI/ None + +namespace Catch { + + Colour::Colour( Code _colourCode ) : m_moved( false ) { use( _colourCode ); } + Colour::Colour( Colour const& _other ) : m_moved( false ) { const_cast( _other ).m_moved = true; } + Colour::~Colour(){ if( !m_moved ) use( None ); } + + void Colour::use( Code _colourCode ) { + static IColourImpl* impl = platformColourInstance(); + impl->use( _colourCode ); + } + +} // end namespace Catch + +// #included from: catch_generators_impl.hpp +#define TWOBLUECUBES_CATCH_GENERATORS_IMPL_HPP_INCLUDED + +#include +#include +#include + +namespace Catch { + + struct GeneratorInfo : IGeneratorInfo { + + GeneratorInfo( std::size_t size ) + : m_size( size ), + m_currentIndex( 0 ) + {} + + bool moveNext() { + if( ++m_currentIndex == m_size ) { + m_currentIndex = 0; + return false; + } + return true; + } + + std::size_t getCurrentIndex() const { + return m_currentIndex; + } + + std::size_t m_size; + std::size_t m_currentIndex; + }; + + /////////////////////////////////////////////////////////////////////////// + + class GeneratorsForTest : public IGeneratorsForTest { + + public: + ~GeneratorsForTest() { + deleteAll( m_generatorsInOrder ); + } + + IGeneratorInfo& getGeneratorInfo( std::string const& fileInfo, std::size_t size ) { + std::map::const_iterator it = m_generatorsByName.find( fileInfo ); + if( it == m_generatorsByName.end() ) { + IGeneratorInfo* info = new GeneratorInfo( size ); + m_generatorsByName.insert( std::make_pair( fileInfo, info ) ); + m_generatorsInOrder.push_back( info ); + return *info; + } + return *it->second; + } + + bool moveNext() { + std::vector::const_iterator it = m_generatorsInOrder.begin(); + std::vector::const_iterator itEnd = m_generatorsInOrder.end(); + for(; it != itEnd; ++it ) { + if( (*it)->moveNext() ) + return true; + } + return false; + } + + private: + std::map m_generatorsByName; + std::vector m_generatorsInOrder; + }; + + IGeneratorsForTest* createGeneratorsForTest() + { + return new GeneratorsForTest(); + } + +} // end namespace Catch + +// #included from: catch_assertionresult.hpp +#define TWOBLUECUBES_CATCH_ASSERTIONRESULT_HPP_INCLUDED + +namespace Catch { + + AssertionInfo::AssertionInfo( std::string const& _macroName, + SourceLineInfo const& _lineInfo, + std::string const& _capturedExpression, + ResultDisposition::Flags _resultDisposition ) + : macroName( _macroName ), + lineInfo( _lineInfo ), + capturedExpression( _capturedExpression ), + resultDisposition( _resultDisposition ) + {} + + AssertionResult::AssertionResult() {} + + AssertionResult::AssertionResult( AssertionInfo const& info, AssertionResultData const& data ) + : m_info( info ), + m_resultData( data ) + {} + + AssertionResult::~AssertionResult() {} + + // Result was a success + bool AssertionResult::succeeded() const { + return Catch::isOk( m_resultData.resultType ); + } + + // Result was a success, or failure is suppressed + bool AssertionResult::isOk() const { + return Catch::isOk( m_resultData.resultType ) || shouldSuppressFailure( m_info.resultDisposition ); + } + + ResultWas::OfType AssertionResult::getResultType() const { + return m_resultData.resultType; + } + + bool AssertionResult::hasExpression() const { + return !m_info.capturedExpression.empty(); + } + + bool AssertionResult::hasMessage() const { + return !m_resultData.message.empty(); + } + + std::string AssertionResult::getExpression() const { + if( isFalseTest( m_info.resultDisposition ) ) + return "!" + m_info.capturedExpression; + else + return m_info.capturedExpression; + } + std::string AssertionResult::getExpressionInMacro() const { + if( m_info.macroName.empty() ) + return m_info.capturedExpression; + else + return m_info.macroName + "( " + m_info.capturedExpression + " )"; + } + + bool AssertionResult::hasExpandedExpression() const { + return hasExpression() && getExpandedExpression() != getExpression(); + } + + std::string AssertionResult::getExpandedExpression() const { + return m_resultData.reconstructedExpression; + } + + std::string AssertionResult::getMessage() const { + return m_resultData.message; + } + SourceLineInfo AssertionResult::getSourceInfo() const { + return m_info.lineInfo; + } + + std::string AssertionResult::getTestMacroName() const { + return m_info.macroName; + } + +} // end namespace Catch + +// #included from: catch_test_case_info.hpp +#define TWOBLUECUBES_CATCH_TEST_CASE_INFO_HPP_INCLUDED + +namespace Catch { + + inline TestCaseInfo::SpecialProperties parseSpecialTag( std::string const& tag ) { + if( startsWith( tag, "." ) || + tag == "hide" || + tag == "!hide" ) + return TestCaseInfo::IsHidden; + else if( tag == "!throws" ) + return TestCaseInfo::Throws; + else if( tag == "!shouldfail" ) + return TestCaseInfo::ShouldFail; + else if( tag == "!mayfail" ) + return TestCaseInfo::MayFail; + else + return TestCaseInfo::None; + } + inline bool isReservedTag( std::string const& tag ) { + return parseSpecialTag( tag ) == TestCaseInfo::None && tag.size() > 0 && !isalnum( tag[0] ); + } + inline void enforceNotReservedTag( std::string const& tag, SourceLineInfo const& _lineInfo ) { + if( isReservedTag( tag ) ) { + { + Colour colourGuard( Colour::Red ); + Catch::cerr() + << "Tag name [" << tag << "] not allowed.\n" + << "Tag names starting with non alpha-numeric characters are reserved\n"; + } + { + Colour colourGuard( Colour::FileName ); + Catch::cerr() << _lineInfo << std::endl; + } + exit(1); + } + } + + TestCase makeTestCase( ITestCase* _testCase, + std::string const& _className, + std::string const& _name, + std::string const& _descOrTags, + SourceLineInfo const& _lineInfo ) + { + bool isHidden( startsWith( _name, "./" ) ); // Legacy support + + // Parse out tags + std::set tags; + std::string desc, tag; + bool inTag = false; + for( std::size_t i = 0; i < _descOrTags.size(); ++i ) { + char c = _descOrTags[i]; + if( !inTag ) { + if( c == '[' ) + inTag = true; + else + desc += c; + } + else { + if( c == ']' ) { + TestCaseInfo::SpecialProperties prop = parseSpecialTag( tag ); + if( prop == TestCaseInfo::IsHidden ) + isHidden = true; + else if( prop == TestCaseInfo::None ) + enforceNotReservedTag( tag, _lineInfo ); + + tags.insert( tag ); + tag.clear(); + inTag = false; + } + else + tag += c; + } + } + if( isHidden ) { + tags.insert( "hide" ); + tags.insert( "." ); + } + + TestCaseInfo info( _name, _className, desc, tags, _lineInfo ); + return TestCase( _testCase, info ); + } + + void setTags( TestCaseInfo& testCaseInfo, std::set const& tags ) + { + testCaseInfo.tags = tags; + testCaseInfo.lcaseTags.clear(); + + std::ostringstream oss; + for( std::set::const_iterator it = tags.begin(), itEnd = tags.end(); it != itEnd; ++it ) { + oss << "[" << *it << "]"; + std::string lcaseTag = toLower( *it ); + testCaseInfo.properties = static_cast( testCaseInfo.properties | parseSpecialTag( lcaseTag ) ); + testCaseInfo.lcaseTags.insert( lcaseTag ); + } + testCaseInfo.tagsAsString = oss.str(); + } + + TestCaseInfo::TestCaseInfo( std::string const& _name, + std::string const& _className, + std::string const& _description, + std::set const& _tags, + SourceLineInfo const& _lineInfo ) + : name( _name ), + className( _className ), + description( _description ), + lineInfo( _lineInfo ), + properties( None ) + { + setTags( *this, _tags ); + } + + TestCaseInfo::TestCaseInfo( TestCaseInfo const& other ) + : name( other.name ), + className( other.className ), + description( other.description ), + tags( other.tags ), + lcaseTags( other.lcaseTags ), + tagsAsString( other.tagsAsString ), + lineInfo( other.lineInfo ), + properties( other.properties ) + {} + + bool TestCaseInfo::isHidden() const { + return ( properties & IsHidden ) != 0; + } + bool TestCaseInfo::throws() const { + return ( properties & Throws ) != 0; + } + bool TestCaseInfo::okToFail() const { + return ( properties & (ShouldFail | MayFail ) ) != 0; + } + bool TestCaseInfo::expectedToFail() const { + return ( properties & (ShouldFail ) ) != 0; + } + + TestCase::TestCase( ITestCase* testCase, TestCaseInfo const& info ) : TestCaseInfo( info ), test( testCase ) {} + + TestCase::TestCase( TestCase const& other ) + : TestCaseInfo( other ), + test( other.test ) + {} + + TestCase TestCase::withName( std::string const& _newName ) const { + TestCase other( *this ); + other.name = _newName; + return other; + } + + void TestCase::swap( TestCase& other ) { + test.swap( other.test ); + name.swap( other.name ); + className.swap( other.className ); + description.swap( other.description ); + tags.swap( other.tags ); + lcaseTags.swap( other.lcaseTags ); + tagsAsString.swap( other.tagsAsString ); + std::swap( TestCaseInfo::properties, static_cast( other ).properties ); + std::swap( lineInfo, other.lineInfo ); + } + + void TestCase::invoke() const { + test->invoke(); + } + + bool TestCase::operator == ( TestCase const& other ) const { + return test.get() == other.test.get() && + name == other.name && + className == other.className; + } + + bool TestCase::operator < ( TestCase const& other ) const { + return name < other.name; + } + TestCase& TestCase::operator = ( TestCase const& other ) { + TestCase temp( other ); + swap( temp ); + return *this; + } + + TestCaseInfo const& TestCase::getTestCaseInfo() const + { + return *this; + } + +} // end namespace Catch + +// #included from: catch_version.hpp +#define TWOBLUECUBES_CATCH_VERSION_HPP_INCLUDED + +namespace Catch { + + Version::Version + ( unsigned int _majorVersion, + unsigned int _minorVersion, + unsigned int _patchNumber, + std::string const& _branchName, + unsigned int _buildNumber ) + : majorVersion( _majorVersion ), + minorVersion( _minorVersion ), + patchNumber( _patchNumber ), + branchName( _branchName ), + buildNumber( _buildNumber ) + {} + + std::ostream& operator << ( std::ostream& os, Version const& version ) { + os << version.majorVersion << "." + << version.minorVersion << "." + << version.patchNumber; + + if( !version.branchName.empty() ) { + os << "-" << version.branchName + << "." << version.buildNumber; + } + return os; + } + + Version libraryVersion( 1, 3, 6, "", 0 ); + +} + +// #included from: catch_message.hpp +#define TWOBLUECUBES_CATCH_MESSAGE_HPP_INCLUDED + +namespace Catch { + + MessageInfo::MessageInfo( std::string const& _macroName, + SourceLineInfo const& _lineInfo, + ResultWas::OfType _type ) + : macroName( _macroName ), + lineInfo( _lineInfo ), + type( _type ), + sequence( ++globalCount ) + {} + + // This may need protecting if threading support is added + unsigned int MessageInfo::globalCount = 0; + + //////////////////////////////////////////////////////////////////////////// + + ScopedMessage::ScopedMessage( MessageBuilder const& builder ) + : m_info( builder.m_info ) + { + m_info.message = builder.m_stream.str(); + getResultCapture().pushScopedMessage( m_info ); + } + ScopedMessage::ScopedMessage( ScopedMessage const& other ) + : m_info( other.m_info ) + {} + + ScopedMessage::~ScopedMessage() { + getResultCapture().popScopedMessage( m_info ); + } + +} // end namespace Catch + +// #included from: catch_legacy_reporter_adapter.hpp +#define TWOBLUECUBES_CATCH_LEGACY_REPORTER_ADAPTER_HPP_INCLUDED + +// #included from: catch_legacy_reporter_adapter.h +#define TWOBLUECUBES_CATCH_LEGACY_REPORTER_ADAPTER_H_INCLUDED + +namespace Catch +{ + // Deprecated + struct IReporter : IShared { + virtual ~IReporter(); + + virtual bool shouldRedirectStdout() const = 0; + + virtual void StartTesting() = 0; + virtual void EndTesting( Totals const& totals ) = 0; + virtual void StartGroup( std::string const& groupName ) = 0; + virtual void EndGroup( std::string const& groupName, Totals const& totals ) = 0; + virtual void StartTestCase( TestCaseInfo const& testInfo ) = 0; + virtual void EndTestCase( TestCaseInfo const& testInfo, Totals const& totals, std::string const& stdOut, std::string const& stdErr ) = 0; + virtual void StartSection( std::string const& sectionName, std::string const& description ) = 0; + virtual void EndSection( std::string const& sectionName, Counts const& assertions ) = 0; + virtual void NoAssertionsInSection( std::string const& sectionName ) = 0; + virtual void NoAssertionsInTestCase( std::string const& testName ) = 0; + virtual void Aborted() = 0; + virtual void Result( AssertionResult const& result ) = 0; + }; + + class LegacyReporterAdapter : public SharedImpl + { + public: + LegacyReporterAdapter( Ptr const& legacyReporter ); + virtual ~LegacyReporterAdapter(); + + virtual ReporterPreferences getPreferences() const; + virtual void noMatchingTestCases( std::string const& ); + virtual void testRunStarting( TestRunInfo const& ); + virtual void testGroupStarting( GroupInfo const& groupInfo ); + virtual void testCaseStarting( TestCaseInfo const& testInfo ); + virtual void sectionStarting( SectionInfo const& sectionInfo ); + virtual void assertionStarting( AssertionInfo const& ); + virtual bool assertionEnded( AssertionStats const& assertionStats ); + virtual void sectionEnded( SectionStats const& sectionStats ); + virtual void testCaseEnded( TestCaseStats const& testCaseStats ); + virtual void testGroupEnded( TestGroupStats const& testGroupStats ); + virtual void testRunEnded( TestRunStats const& testRunStats ); + virtual void skipTest( TestCaseInfo const& ); + + private: + Ptr m_legacyReporter; + }; +} + +namespace Catch +{ + LegacyReporterAdapter::LegacyReporterAdapter( Ptr const& legacyReporter ) + : m_legacyReporter( legacyReporter ) + {} + LegacyReporterAdapter::~LegacyReporterAdapter() {} + + ReporterPreferences LegacyReporterAdapter::getPreferences() const { + ReporterPreferences prefs; + prefs.shouldRedirectStdOut = m_legacyReporter->shouldRedirectStdout(); + return prefs; + } + + void LegacyReporterAdapter::noMatchingTestCases( std::string const& ) {} + void LegacyReporterAdapter::testRunStarting( TestRunInfo const& ) { + m_legacyReporter->StartTesting(); + } + void LegacyReporterAdapter::testGroupStarting( GroupInfo const& groupInfo ) { + m_legacyReporter->StartGroup( groupInfo.name ); + } + void LegacyReporterAdapter::testCaseStarting( TestCaseInfo const& testInfo ) { + m_legacyReporter->StartTestCase( testInfo ); + } + void LegacyReporterAdapter::sectionStarting( SectionInfo const& sectionInfo ) { + m_legacyReporter->StartSection( sectionInfo.name, sectionInfo.description ); + } + void LegacyReporterAdapter::assertionStarting( AssertionInfo const& ) { + // Not on legacy interface + } + + bool LegacyReporterAdapter::assertionEnded( AssertionStats const& assertionStats ) { + if( assertionStats.assertionResult.getResultType() != ResultWas::Ok ) { + for( std::vector::const_iterator it = assertionStats.infoMessages.begin(), itEnd = assertionStats.infoMessages.end(); + it != itEnd; + ++it ) { + if( it->type == ResultWas::Info ) { + ResultBuilder rb( it->macroName.c_str(), it->lineInfo, "", ResultDisposition::Normal ); + rb << it->message; + rb.setResultType( ResultWas::Info ); + AssertionResult result = rb.build(); + m_legacyReporter->Result( result ); + } + } + } + m_legacyReporter->Result( assertionStats.assertionResult ); + return true; + } + void LegacyReporterAdapter::sectionEnded( SectionStats const& sectionStats ) { + if( sectionStats.missingAssertions ) + m_legacyReporter->NoAssertionsInSection( sectionStats.sectionInfo.name ); + m_legacyReporter->EndSection( sectionStats.sectionInfo.name, sectionStats.assertions ); + } + void LegacyReporterAdapter::testCaseEnded( TestCaseStats const& testCaseStats ) { + m_legacyReporter->EndTestCase + ( testCaseStats.testInfo, + testCaseStats.totals, + testCaseStats.stdOut, + testCaseStats.stdErr ); + } + void LegacyReporterAdapter::testGroupEnded( TestGroupStats const& testGroupStats ) { + if( testGroupStats.aborting ) + m_legacyReporter->Aborted(); + m_legacyReporter->EndGroup( testGroupStats.groupInfo.name, testGroupStats.totals ); + } + void LegacyReporterAdapter::testRunEnded( TestRunStats const& testRunStats ) { + m_legacyReporter->EndTesting( testRunStats.totals ); + } + void LegacyReporterAdapter::skipTest( TestCaseInfo const& ) { + } +} + +// #included from: catch_timer.hpp + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wc++11-long-long" +#endif + +#ifdef CATCH_PLATFORM_WINDOWS +#include +#else +#include +#endif + +namespace Catch { + + namespace { +#ifdef CATCH_PLATFORM_WINDOWS + uint64_t getCurrentTicks() { + static uint64_t hz=0, hzo=0; + if (!hz) { + QueryPerformanceFrequency( reinterpret_cast( &hz ) ); + QueryPerformanceCounter( reinterpret_cast( &hzo ) ); + } + uint64_t t; + QueryPerformanceCounter( reinterpret_cast( &t ) ); + return ((t-hzo)*1000000)/hz; + } +#else + uint64_t getCurrentTicks() { + timeval t; + gettimeofday(&t,CATCH_NULL); + return static_cast( t.tv_sec ) * 1000000ull + static_cast( t.tv_usec ); + } +#endif + } + + void Timer::start() { + m_ticks = getCurrentTicks(); + } + unsigned int Timer::getElapsedMicroseconds() const { + return static_cast(getCurrentTicks() - m_ticks); + } + unsigned int Timer::getElapsedMilliseconds() const { + return static_cast(getElapsedMicroseconds()/1000); + } + double Timer::getElapsedSeconds() const { + return getElapsedMicroseconds()/1000000.0; + } + +} // namespace Catch + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif +// #included from: catch_common.hpp +#define TWOBLUECUBES_CATCH_COMMON_HPP_INCLUDED + +namespace Catch { + + bool startsWith( std::string const& s, std::string const& prefix ) { + return s.size() >= prefix.size() && s.substr( 0, prefix.size() ) == prefix; + } + bool endsWith( std::string const& s, std::string const& suffix ) { + return s.size() >= suffix.size() && s.substr( s.size()-suffix.size(), suffix.size() ) == suffix; + } + bool contains( std::string const& s, std::string const& infix ) { + return s.find( infix ) != std::string::npos; + } + void toLowerInPlace( std::string& s ) { + std::transform( s.begin(), s.end(), s.begin(), ::tolower ); + } + std::string toLower( std::string const& s ) { + std::string lc = s; + toLowerInPlace( lc ); + return lc; + } + std::string trim( std::string const& str ) { + static char const* whitespaceChars = "\n\r\t "; + std::string::size_type start = str.find_first_not_of( whitespaceChars ); + std::string::size_type end = str.find_last_not_of( whitespaceChars ); + + return start != std::string::npos ? str.substr( start, 1+end-start ) : ""; + } + + bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ) { + bool replaced = false; + std::size_t i = str.find( replaceThis ); + while( i != std::string::npos ) { + replaced = true; + str = str.substr( 0, i ) + withThis + str.substr( i+replaceThis.size() ); + if( i < str.size()-withThis.size() ) + i = str.find( replaceThis, i+withThis.size() ); + else + i = std::string::npos; + } + return replaced; + } + + pluralise::pluralise( std::size_t count, std::string const& label ) + : m_count( count ), + m_label( label ) + {} + + std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ) { + os << pluraliser.m_count << " " << pluraliser.m_label; + if( pluraliser.m_count != 1 ) + os << "s"; + return os; + } + + SourceLineInfo::SourceLineInfo() : line( 0 ){} + SourceLineInfo::SourceLineInfo( char const* _file, std::size_t _line ) + : file( _file ), + line( _line ) + {} + SourceLineInfo::SourceLineInfo( SourceLineInfo const& other ) + : file( other.file ), + line( other.line ) + {} + bool SourceLineInfo::empty() const { + return file.empty(); + } + bool SourceLineInfo::operator == ( SourceLineInfo const& other ) const { + return line == other.line && file == other.file; + } + bool SourceLineInfo::operator < ( SourceLineInfo const& other ) const { + return line < other.line || ( line == other.line && file < other.file ); + } + + void seedRng( IConfig const& config ) { + if( config.rngSeed() != 0 ) + std::srand( config.rngSeed() ); + } + unsigned int rngSeed() { + return getCurrentContext().getConfig()->rngSeed(); + } + + std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ) { +#ifndef __GNUG__ + os << info.file << "(" << info.line << ")"; +#else + os << info.file << ":" << info.line; +#endif + return os; + } + + void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo ) { + std::ostringstream oss; + oss << locationInfo << ": Internal Catch error: '" << message << "'"; + if( alwaysTrue() ) + throw std::logic_error( oss.str() ); + } +} + +// #included from: catch_section.hpp +#define TWOBLUECUBES_CATCH_SECTION_HPP_INCLUDED + +namespace Catch { + + SectionInfo::SectionInfo + ( SourceLineInfo const& _lineInfo, + std::string const& _name, + std::string const& _description ) + : name( _name ), + description( _description ), + lineInfo( _lineInfo ) + {} + + Section::Section( SectionInfo const& info ) + : m_info( info ), + m_sectionIncluded( getResultCapture().sectionStarted( m_info, m_assertions ) ) + { + m_timer.start(); + } + + Section::~Section() { + if( m_sectionIncluded ) { + SectionEndInfo endInfo( m_info, m_assertions, m_timer.getElapsedSeconds() ); + if( std::uncaught_exception() ) + getResultCapture().sectionEndedEarly( endInfo ); + else + getResultCapture().sectionEnded( endInfo ); + } + } + + // This indicates whether the section should be executed or not + Section::operator bool() const { + return m_sectionIncluded; + } + +} // end namespace Catch + +// #included from: catch_debugger.hpp +#define TWOBLUECUBES_CATCH_DEBUGGER_HPP_INCLUDED + +#include + +#ifdef CATCH_PLATFORM_MAC + + #include + #include + #include + #include + #include + + namespace Catch{ + + // The following function is taken directly from the following technical note: + // http://developer.apple.com/library/mac/#qa/qa2004/qa1361.html + + // Returns true if the current process is being debugged (either + // running under the debugger or has a debugger attached post facto). + bool isDebuggerActive(){ + + int mib[4]; + struct kinfo_proc info; + size_t size; + + // Initialize the flags so that, if sysctl fails for some bizarre + // reason, we get a predictable result. + + info.kp_proc.p_flag = 0; + + // Initialize mib, which tells sysctl the info we want, in this case + // we're looking for information about a specific process ID. + + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PID; + mib[3] = getpid(); + + // Call sysctl. + + size = sizeof(info); + if( sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, CATCH_NULL, 0) != 0 ) { + Catch::cerr() << "\n** Call to sysctl failed - unable to determine if debugger is active **\n" << std::endl; + return false; + } + + // We're being debugged if the P_TRACED flag is set. + + return ( (info.kp_proc.p_flag & P_TRACED) != 0 ); + } + } // namespace Catch + +#elif defined(_MSC_VER) + extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); + namespace Catch { + bool isDebuggerActive() { + return IsDebuggerPresent() != 0; + } + } +#elif defined(__MINGW32__) + extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); + namespace Catch { + bool isDebuggerActive() { + return IsDebuggerPresent() != 0; + } + } +#else + namespace Catch { + inline bool isDebuggerActive() { return false; } + } +#endif // Platform + +#ifdef CATCH_PLATFORM_WINDOWS + extern "C" __declspec(dllimport) void __stdcall OutputDebugStringA( const char* ); + namespace Catch { + void writeToDebugConsole( std::string const& text ) { + ::OutputDebugStringA( text.c_str() ); + } + } +#else + namespace Catch { + void writeToDebugConsole( std::string const& text ) { + // !TBD: Need a version for Mac/ XCode and other IDEs + Catch::cout() << text; + } + } +#endif // Platform + +// #included from: catch_tostring.hpp +#define TWOBLUECUBES_CATCH_TOSTRING_HPP_INCLUDED + +namespace Catch { + +namespace Detail { + + const std::string unprintableString = "{?}"; + + namespace { + const int hexThreshold = 255; + + struct Endianness { + enum Arch { Big, Little }; + + static Arch which() { + union _{ + int asInt; + char asChar[sizeof (int)]; + } u; + + u.asInt = 1; + return ( u.asChar[sizeof(int)-1] == 1 ) ? Big : Little; + } + }; + } + + std::string rawMemoryToString( const void *object, std::size_t size ) + { + // Reverse order for little endian architectures + int i = 0, end = static_cast( size ), inc = 1; + if( Endianness::which() == Endianness::Little ) { + i = end-1; + end = inc = -1; + } + + unsigned char const *bytes = static_cast(object); + std::ostringstream os; + os << "0x" << std::setfill('0') << std::hex; + for( ; i != end; i += inc ) + os << std::setw(2) << static_cast(bytes[i]); + return os.str(); + } +} + +std::string toString( std::string const& value ) { + std::string s = value; + if( getCurrentContext().getConfig()->showInvisibles() ) { + for(size_t i = 0; i < s.size(); ++i ) { + std::string subs; + switch( s[i] ) { + case '\n': subs = "\\n"; break; + case '\t': subs = "\\t"; break; + default: break; + } + if( !subs.empty() ) { + s = s.substr( 0, i ) + subs + s.substr( i+1 ); + ++i; + } + } + } + return "\"" + s + "\""; +} +std::string toString( std::wstring const& value ) { + + std::string s; + s.reserve( value.size() ); + for(size_t i = 0; i < value.size(); ++i ) + s += value[i] <= 0xff ? static_cast( value[i] ) : '?'; + return Catch::toString( s ); +} + +std::string toString( const char* const value ) { + return value ? Catch::toString( std::string( value ) ) : std::string( "{null string}" ); +} + +std::string toString( char* const value ) { + return Catch::toString( static_cast( value ) ); +} + +std::string toString( const wchar_t* const value ) +{ + return value ? Catch::toString( std::wstring(value) ) : std::string( "{null string}" ); +} + +std::string toString( wchar_t* const value ) +{ + return Catch::toString( static_cast( value ) ); +} + +std::string toString( int value ) { + std::ostringstream oss; + oss << value; + if( value > Detail::hexThreshold ) + oss << " (0x" << std::hex << value << ")"; + return oss.str(); +} + +std::string toString( unsigned long value ) { + std::ostringstream oss; + oss << value; + if( value > Detail::hexThreshold ) + oss << " (0x" << std::hex << value << ")"; + return oss.str(); +} + +std::string toString( unsigned int value ) { + return Catch::toString( static_cast( value ) ); +} + +template +std::string fpToString( T value, int precision ) { + std::ostringstream oss; + oss << std::setprecision( precision ) + << std::fixed + << value; + std::string d = oss.str(); + std::size_t i = d.find_last_not_of( '0' ); + if( i != std::string::npos && i != d.size()-1 ) { + if( d[i] == '.' ) + i++; + d = d.substr( 0, i+1 ); + } + return d; +} + +std::string toString( const double value ) { + return fpToString( value, 10 ); +} +std::string toString( const float value ) { + return fpToString( value, 5 ) + "f"; +} + +std::string toString( bool value ) { + return value ? "true" : "false"; +} + +std::string toString( char value ) { + return value < ' ' + ? toString( static_cast( value ) ) + : Detail::makeString( value ); +} + +std::string toString( signed char value ) { + return toString( static_cast( value ) ); +} + +std::string toString( unsigned char value ) { + return toString( static_cast( value ) ); +} + +#ifdef CATCH_CONFIG_CPP11_LONG_LONG +std::string toString( long long value ) { + std::ostringstream oss; + oss << value; + if( value > Detail::hexThreshold ) + oss << " (0x" << std::hex << value << ")"; + return oss.str(); +} +std::string toString( unsigned long long value ) { + std::ostringstream oss; + oss << value; + if( value > Detail::hexThreshold ) + oss << " (0x" << std::hex << value << ")"; + return oss.str(); +} +#endif + +#ifdef CATCH_CONFIG_CPP11_NULLPTR +std::string toString( std::nullptr_t ) { + return "nullptr"; +} +#endif + +#ifdef __OBJC__ + std::string toString( NSString const * const& nsstring ) { + if( !nsstring ) + return "nil"; + return "@" + toString([nsstring UTF8String]); + } + std::string toString( NSString * CATCH_ARC_STRONG const& nsstring ) { + if( !nsstring ) + return "nil"; + return "@" + toString([nsstring UTF8String]); + } + std::string toString( NSObject* const& nsObject ) { + return toString( [nsObject description] ); + } +#endif + +} // end namespace Catch + +// #included from: catch_result_builder.hpp +#define TWOBLUECUBES_CATCH_RESULT_BUILDER_HPP_INCLUDED + +namespace Catch { + + std::string capturedExpressionWithSecondArgument( std::string const& capturedExpression, std::string const& secondArg ) { + return secondArg.empty() || secondArg == "\"\"" + ? capturedExpression + : capturedExpression + ", " + secondArg; + } + ResultBuilder::ResultBuilder( char const* macroName, + SourceLineInfo const& lineInfo, + char const* capturedExpression, + ResultDisposition::Flags resultDisposition, + char const* secondArg ) + : m_assertionInfo( macroName, lineInfo, capturedExpressionWithSecondArgument( capturedExpression, secondArg ), resultDisposition ), + m_shouldDebugBreak( false ), + m_shouldThrow( false ) + {} + + ResultBuilder& ResultBuilder::setResultType( ResultWas::OfType result ) { + m_data.resultType = result; + return *this; + } + ResultBuilder& ResultBuilder::setResultType( bool result ) { + m_data.resultType = result ? ResultWas::Ok : ResultWas::ExpressionFailed; + return *this; + } + ResultBuilder& ResultBuilder::setLhs( std::string const& lhs ) { + m_exprComponents.lhs = lhs; + return *this; + } + ResultBuilder& ResultBuilder::setRhs( std::string const& rhs ) { + m_exprComponents.rhs = rhs; + return *this; + } + ResultBuilder& ResultBuilder::setOp( std::string const& op ) { + m_exprComponents.op = op; + return *this; + } + + void ResultBuilder::endExpression() { + m_exprComponents.testFalse = isFalseTest( m_assertionInfo.resultDisposition ); + captureExpression(); + } + + void ResultBuilder::useActiveException( ResultDisposition::Flags resultDisposition ) { + m_assertionInfo.resultDisposition = resultDisposition; + m_stream.oss << Catch::translateActiveException(); + captureResult( ResultWas::ThrewException ); + } + + void ResultBuilder::captureResult( ResultWas::OfType resultType ) { + setResultType( resultType ); + captureExpression(); + } + void ResultBuilder::captureExpectedException( std::string const& expectedMessage ) { + if( expectedMessage.empty() ) + captureExpectedException( Matchers::Impl::Generic::AllOf() ); + else + captureExpectedException( Matchers::Equals( expectedMessage ) ); + } + + void ResultBuilder::captureExpectedException( Matchers::Impl::Matcher const& matcher ) { + + assert( m_exprComponents.testFalse == false ); + AssertionResultData data = m_data; + data.resultType = ResultWas::Ok; + data.reconstructedExpression = m_assertionInfo.capturedExpression; + + std::string actualMessage = Catch::translateActiveException(); + if( !matcher.match( actualMessage ) ) { + data.resultType = ResultWas::ExpressionFailed; + data.reconstructedExpression = actualMessage; + } + AssertionResult result( m_assertionInfo, data ); + handleResult( result ); + } + + void ResultBuilder::captureExpression() { + AssertionResult result = build(); + handleResult( result ); + } + void ResultBuilder::handleResult( AssertionResult const& result ) + { + getResultCapture().assertionEnded( result ); + + if( !result.isOk() ) { + if( getCurrentContext().getConfig()->shouldDebugBreak() ) + m_shouldDebugBreak = true; + if( getCurrentContext().getRunner()->aborting() || (m_assertionInfo.resultDisposition & ResultDisposition::Normal) ) + m_shouldThrow = true; + } + } + void ResultBuilder::react() { + if( m_shouldThrow ) + throw Catch::TestFailureException(); + } + + bool ResultBuilder::shouldDebugBreak() const { return m_shouldDebugBreak; } + bool ResultBuilder::allowThrows() const { return getCurrentContext().getConfig()->allowThrows(); } + + AssertionResult ResultBuilder::build() const + { + assert( m_data.resultType != ResultWas::Unknown ); + + AssertionResultData data = m_data; + + // Flip bool results if testFalse is set + if( m_exprComponents.testFalse ) { + if( data.resultType == ResultWas::Ok ) + data.resultType = ResultWas::ExpressionFailed; + else if( data.resultType == ResultWas::ExpressionFailed ) + data.resultType = ResultWas::Ok; + } + + data.message = m_stream.oss.str(); + data.reconstructedExpression = reconstructExpression(); + if( m_exprComponents.testFalse ) { + if( m_exprComponents.op == "" ) + data.reconstructedExpression = "!" + data.reconstructedExpression; + else + data.reconstructedExpression = "!(" + data.reconstructedExpression + ")"; + } + return AssertionResult( m_assertionInfo, data ); + } + std::string ResultBuilder::reconstructExpression() const { + if( m_exprComponents.op == "" ) + return m_exprComponents.lhs.empty() ? m_assertionInfo.capturedExpression : m_exprComponents.op + m_exprComponents.lhs; + else if( m_exprComponents.op == "matches" ) + return m_exprComponents.lhs + " " + m_exprComponents.rhs; + else if( m_exprComponents.op != "!" ) { + if( m_exprComponents.lhs.size() + m_exprComponents.rhs.size() < 40 && + m_exprComponents.lhs.find("\n") == std::string::npos && + m_exprComponents.rhs.find("\n") == std::string::npos ) + return m_exprComponents.lhs + " " + m_exprComponents.op + " " + m_exprComponents.rhs; + else + return m_exprComponents.lhs + "\n" + m_exprComponents.op + "\n" + m_exprComponents.rhs; + } + else + return "{can't expand - use " + m_assertionInfo.macroName + "_FALSE( " + m_assertionInfo.capturedExpression.substr(1) + " ) instead of " + m_assertionInfo.macroName + "( " + m_assertionInfo.capturedExpression + " ) for better diagnostics}"; + } + +} // end namespace Catch + +// #included from: catch_tag_alias_registry.hpp +#define TWOBLUECUBES_CATCH_TAG_ALIAS_REGISTRY_HPP_INCLUDED + +// #included from: catch_tag_alias_registry.h +#define TWOBLUECUBES_CATCH_TAG_ALIAS_REGISTRY_H_INCLUDED + +#include + +namespace Catch { + + class TagAliasRegistry : public ITagAliasRegistry { + public: + virtual ~TagAliasRegistry(); + virtual Option find( std::string const& alias ) const; + virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const; + void add( char const* alias, char const* tag, SourceLineInfo const& lineInfo ); + static TagAliasRegistry& get(); + + private: + std::map m_registry; + }; + +} // end namespace Catch + +#include +#include + +namespace Catch { + + TagAliasRegistry::~TagAliasRegistry() {} + + Option TagAliasRegistry::find( std::string const& alias ) const { + std::map::const_iterator it = m_registry.find( alias ); + if( it != m_registry.end() ) + return it->second; + else + return Option(); + } + + std::string TagAliasRegistry::expandAliases( std::string const& unexpandedTestSpec ) const { + std::string expandedTestSpec = unexpandedTestSpec; + for( std::map::const_iterator it = m_registry.begin(), itEnd = m_registry.end(); + it != itEnd; + ++it ) { + std::size_t pos = expandedTestSpec.find( it->first ); + if( pos != std::string::npos ) { + expandedTestSpec = expandedTestSpec.substr( 0, pos ) + + it->second.tag + + expandedTestSpec.substr( pos + it->first.size() ); + } + } + return expandedTestSpec; + } + + void TagAliasRegistry::add( char const* alias, char const* tag, SourceLineInfo const& lineInfo ) { + + if( !startsWith( alias, "[@" ) || !endsWith( alias, "]" ) ) { + std::ostringstream oss; + oss << "error: tag alias, \"" << alias << "\" is not of the form [@alias name].\n" << lineInfo; + throw std::domain_error( oss.str().c_str() ); + } + if( !m_registry.insert( std::make_pair( alias, TagAlias( tag, lineInfo ) ) ).second ) { + std::ostringstream oss; + oss << "error: tag alias, \"" << alias << "\" already registered.\n" + << "\tFirst seen at " << find(alias)->lineInfo << "\n" + << "\tRedefined at " << lineInfo; + throw std::domain_error( oss.str().c_str() ); + } + } + + TagAliasRegistry& TagAliasRegistry::get() { + static TagAliasRegistry instance; + return instance; + + } + + ITagAliasRegistry::~ITagAliasRegistry() {} + ITagAliasRegistry const& ITagAliasRegistry::get() { return TagAliasRegistry::get(); } + + RegistrarForTagAliases::RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ) { + try { + TagAliasRegistry::get().add( alias, tag, lineInfo ); + } + catch( std::exception& ex ) { + Colour colourGuard( Colour::Red ); + Catch::cerr() << ex.what() << std::endl; + exit(1); + } + } + +} // end namespace Catch + +// #included from: ../reporters/catch_reporter_multi.hpp +#define TWOBLUECUBES_CATCH_REPORTER_MULTI_HPP_INCLUDED + +namespace Catch { + +class MultipleReporters : public SharedImpl { + typedef std::vector > Reporters; + Reporters m_reporters; + +public: + void add( Ptr const& reporter ) { + m_reporters.push_back( reporter ); + } + +public: // IStreamingReporter + + virtual ReporterPreferences getPreferences() const CATCH_OVERRIDE { + return m_reporters[0]->getPreferences(); + } + + virtual void noMatchingTestCases( std::string const& spec ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->noMatchingTestCases( spec ); + } + + virtual void testRunStarting( TestRunInfo const& testRunInfo ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->testRunStarting( testRunInfo ); + } + + virtual void testGroupStarting( GroupInfo const& groupInfo ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->testGroupStarting( groupInfo ); + } + + virtual void testCaseStarting( TestCaseInfo const& testInfo ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->testCaseStarting( testInfo ); + } + + virtual void sectionStarting( SectionInfo const& sectionInfo ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->sectionStarting( sectionInfo ); + } + + virtual void assertionStarting( AssertionInfo const& assertionInfo ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->assertionStarting( assertionInfo ); + } + + // The return value indicates if the messages buffer should be cleared: + virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE { + bool clearBuffer = false; + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + clearBuffer |= (*it)->assertionEnded( assertionStats ); + return clearBuffer; + } + + virtual void sectionEnded( SectionStats const& sectionStats ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->sectionEnded( sectionStats ); + } + + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->testCaseEnded( testCaseStats ); + } + + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->testGroupEnded( testGroupStats ); + } + + virtual void testRunEnded( TestRunStats const& testRunStats ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->testRunEnded( testRunStats ); + } + + virtual void skipTest( TestCaseInfo const& testInfo ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->skipTest( testInfo ); + } +}; + +Ptr addReporter( Ptr const& existingReporter, Ptr const& additionalReporter ) { + Ptr resultingReporter; + + if( existingReporter ) { + MultipleReporters* multi = dynamic_cast( existingReporter.get() ); + if( !multi ) { + multi = new MultipleReporters; + resultingReporter = Ptr( multi ); + if( existingReporter ) + multi->add( existingReporter ); + } + else + resultingReporter = existingReporter; + multi->add( additionalReporter ); + } + else + resultingReporter = additionalReporter; + + return resultingReporter; +} + +} // end namespace Catch + +// #included from: ../reporters/catch_reporter_xml.hpp +#define TWOBLUECUBES_CATCH_REPORTER_XML_HPP_INCLUDED + +// #included from: catch_reporter_bases.hpp +#define TWOBLUECUBES_CATCH_REPORTER_BASES_HPP_INCLUDED + +#include + +namespace Catch { + + struct StreamingReporterBase : SharedImpl { + + StreamingReporterBase( ReporterConfig const& _config ) + : m_config( _config.fullConfig() ), + stream( _config.stream() ) + { + m_reporterPrefs.shouldRedirectStdOut = false; + } + + virtual ReporterPreferences getPreferences() const CATCH_OVERRIDE { + return m_reporterPrefs; + } + + virtual ~StreamingReporterBase() CATCH_OVERRIDE; + + virtual void noMatchingTestCases( std::string const& ) CATCH_OVERRIDE {} + + virtual void testRunStarting( TestRunInfo const& _testRunInfo ) CATCH_OVERRIDE { + currentTestRunInfo = _testRunInfo; + } + virtual void testGroupStarting( GroupInfo const& _groupInfo ) CATCH_OVERRIDE { + currentGroupInfo = _groupInfo; + } + + virtual void testCaseStarting( TestCaseInfo const& _testInfo ) CATCH_OVERRIDE { + currentTestCaseInfo = _testInfo; + } + virtual void sectionStarting( SectionInfo const& _sectionInfo ) CATCH_OVERRIDE { + m_sectionStack.push_back( _sectionInfo ); + } + + virtual void sectionEnded( SectionStats const& /* _sectionStats */ ) CATCH_OVERRIDE { + m_sectionStack.pop_back(); + } + virtual void testCaseEnded( TestCaseStats const& /* _testCaseStats */ ) CATCH_OVERRIDE { + currentTestCaseInfo.reset(); + } + virtual void testGroupEnded( TestGroupStats const& /* _testGroupStats */ ) CATCH_OVERRIDE { + currentGroupInfo.reset(); + } + virtual void testRunEnded( TestRunStats const& /* _testRunStats */ ) CATCH_OVERRIDE { + currentTestCaseInfo.reset(); + currentGroupInfo.reset(); + currentTestRunInfo.reset(); + } + + virtual void skipTest( TestCaseInfo const& ) CATCH_OVERRIDE { + // Don't do anything with this by default. + // It can optionally be overridden in the derived class. + } + + Ptr m_config; + std::ostream& stream; + + LazyStat currentTestRunInfo; + LazyStat currentGroupInfo; + LazyStat currentTestCaseInfo; + + std::vector m_sectionStack; + ReporterPreferences m_reporterPrefs; + }; + + struct CumulativeReporterBase : SharedImpl { + template + struct Node : SharedImpl<> { + explicit Node( T const& _value ) : value( _value ) {} + virtual ~Node() {} + + typedef std::vector > ChildNodes; + T value; + ChildNodes children; + }; + struct SectionNode : SharedImpl<> { + explicit SectionNode( SectionStats const& _stats ) : stats( _stats ) {} + virtual ~SectionNode(); + + bool operator == ( SectionNode const& other ) const { + return stats.sectionInfo.lineInfo == other.stats.sectionInfo.lineInfo; + } + bool operator == ( Ptr const& other ) const { + return operator==( *other ); + } + + SectionStats stats; + typedef std::vector > ChildSections; + typedef std::vector Assertions; + ChildSections childSections; + Assertions assertions; + std::string stdOut; + std::string stdErr; + }; + + struct BySectionInfo { + BySectionInfo( SectionInfo const& other ) : m_other( other ) {} + BySectionInfo( BySectionInfo const& other ) : m_other( other.m_other ) {} + bool operator() ( Ptr const& node ) const { + return node->stats.sectionInfo.lineInfo == m_other.lineInfo; + } + private: + void operator=( BySectionInfo const& ); + SectionInfo const& m_other; + }; + + typedef Node TestCaseNode; + typedef Node TestGroupNode; + typedef Node TestRunNode; + + CumulativeReporterBase( ReporterConfig const& _config ) + : m_config( _config.fullConfig() ), + stream( _config.stream() ) + { + m_reporterPrefs.shouldRedirectStdOut = false; + } + ~CumulativeReporterBase(); + + virtual ReporterPreferences getPreferences() const CATCH_OVERRIDE { + return m_reporterPrefs; + } + + virtual void testRunStarting( TestRunInfo const& ) CATCH_OVERRIDE {} + virtual void testGroupStarting( GroupInfo const& ) CATCH_OVERRIDE {} + + virtual void testCaseStarting( TestCaseInfo const& ) CATCH_OVERRIDE {} + + virtual void sectionStarting( SectionInfo const& sectionInfo ) CATCH_OVERRIDE { + SectionStats incompleteStats( sectionInfo, Counts(), 0, false ); + Ptr node; + if( m_sectionStack.empty() ) { + if( !m_rootSection ) + m_rootSection = new SectionNode( incompleteStats ); + node = m_rootSection; + } + else { + SectionNode& parentNode = *m_sectionStack.back(); + SectionNode::ChildSections::const_iterator it = + std::find_if( parentNode.childSections.begin(), + parentNode.childSections.end(), + BySectionInfo( sectionInfo ) ); + if( it == parentNode.childSections.end() ) { + node = new SectionNode( incompleteStats ); + parentNode.childSections.push_back( node ); + } + else + node = *it; + } + m_sectionStack.push_back( node ); + m_deepestSection = node; + } + + virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE {} + + virtual bool assertionEnded( AssertionStats const& assertionStats ) { + assert( !m_sectionStack.empty() ); + SectionNode& sectionNode = *m_sectionStack.back(); + sectionNode.assertions.push_back( assertionStats ); + return true; + } + virtual void sectionEnded( SectionStats const& sectionStats ) CATCH_OVERRIDE { + assert( !m_sectionStack.empty() ); + SectionNode& node = *m_sectionStack.back(); + node.stats = sectionStats; + m_sectionStack.pop_back(); + } + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE { + Ptr node = new TestCaseNode( testCaseStats ); + assert( m_sectionStack.size() == 0 ); + node->children.push_back( m_rootSection ); + m_testCases.push_back( node ); + m_rootSection.reset(); + + assert( m_deepestSection ); + m_deepestSection->stdOut = testCaseStats.stdOut; + m_deepestSection->stdErr = testCaseStats.stdErr; + } + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE { + Ptr node = new TestGroupNode( testGroupStats ); + node->children.swap( m_testCases ); + m_testGroups.push_back( node ); + } + virtual void testRunEnded( TestRunStats const& testRunStats ) CATCH_OVERRIDE { + Ptr node = new TestRunNode( testRunStats ); + node->children.swap( m_testGroups ); + m_testRuns.push_back( node ); + testRunEndedCumulative(); + } + virtual void testRunEndedCumulative() = 0; + + virtual void skipTest( TestCaseInfo const& ) CATCH_OVERRIDE {} + + Ptr m_config; + std::ostream& stream; + std::vector m_assertions; + std::vector > > m_sections; + std::vector > m_testCases; + std::vector > m_testGroups; + + std::vector > m_testRuns; + + Ptr m_rootSection; + Ptr m_deepestSection; + std::vector > m_sectionStack; + ReporterPreferences m_reporterPrefs; + + }; + + template + char const* getLineOfChars() { + static char line[CATCH_CONFIG_CONSOLE_WIDTH] = {0}; + if( !*line ) { + memset( line, C, CATCH_CONFIG_CONSOLE_WIDTH-1 ); + line[CATCH_CONFIG_CONSOLE_WIDTH-1] = 0; + } + return line; + } + + struct TestEventListenerBase : StreamingReporterBase { + TestEventListenerBase( ReporterConfig const& _config ) + : StreamingReporterBase( _config ) + {} + + virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE {} + virtual bool assertionEnded( AssertionStats const& ) CATCH_OVERRIDE { + return false; + } + }; + +} // end namespace Catch + +// #included from: ../internal/catch_reporter_registrars.hpp +#define TWOBLUECUBES_CATCH_REPORTER_REGISTRARS_HPP_INCLUDED + +namespace Catch { + + template + class LegacyReporterRegistrar { + + class ReporterFactory : public IReporterFactory { + virtual IStreamingReporter* create( ReporterConfig const& config ) const { + return new LegacyReporterAdapter( new T( config ) ); + } + + virtual std::string getDescription() const { + return T::getDescription(); + } + }; + + public: + + LegacyReporterRegistrar( std::string const& name ) { + getMutableRegistryHub().registerReporter( name, new ReporterFactory() ); + } + }; + + template + class ReporterRegistrar { + + class ReporterFactory : public SharedImpl { + + // *** Please Note ***: + // - If you end up here looking at a compiler error because it's trying to register + // your custom reporter class be aware that the native reporter interface has changed + // to IStreamingReporter. The "legacy" interface, IReporter, is still supported via + // an adapter. Just use REGISTER_LEGACY_REPORTER to take advantage of the adapter. + // However please consider updating to the new interface as the old one is now + // deprecated and will probably be removed quite soon! + // Please contact me via github if you have any questions at all about this. + // In fact, ideally, please contact me anyway to let me know you've hit this - as I have + // no idea who is actually using custom reporters at all (possibly no-one!). + // The new interface is designed to minimise exposure to interface changes in the future. + virtual IStreamingReporter* create( ReporterConfig const& config ) const { + return new T( config ); + } + + virtual std::string getDescription() const { + return T::getDescription(); + } + }; + + public: + + ReporterRegistrar( std::string const& name ) { + getMutableRegistryHub().registerReporter( name, new ReporterFactory() ); + } + }; + + template + class ListenerRegistrar { + + class ListenerFactory : public SharedImpl { + + virtual IStreamingReporter* create( ReporterConfig const& config ) const { + return new T( config ); + } + virtual std::string getDescription() const { + return ""; + } + }; + + public: + + ListenerRegistrar() { + getMutableRegistryHub().registerListener( new ListenerFactory() ); + } + }; +} + +#define INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) \ + namespace{ Catch::LegacyReporterRegistrar catch_internal_RegistrarFor##reporterType( name ); } + +#define INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) \ + namespace{ Catch::ReporterRegistrar catch_internal_RegistrarFor##reporterType( name ); } + +#define INTERNAL_CATCH_REGISTER_LISTENER( listenerType ) \ + namespace{ Catch::ListenerRegistrar catch_internal_RegistrarFor##listenerType; } + +// #included from: ../internal/catch_xmlwriter.hpp +#define TWOBLUECUBES_CATCH_XMLWRITER_HPP_INCLUDED + +#include +#include +#include +#include + +namespace Catch { + + class XmlEncode { + public: + enum ForWhat { ForTextNodes, ForAttributes }; + + XmlEncode( std::string const& str, ForWhat forWhat = ForTextNodes ) + : m_str( str ), + m_forWhat( forWhat ) + {} + + void encodeTo( std::ostream& os ) const { + + // Apostrophe escaping not necessary if we always use " to write attributes + // (see: http://www.w3.org/TR/xml/#syntax) + + for( std::size_t i = 0; i < m_str.size(); ++ i ) { + char c = m_str[i]; + switch( c ) { + case '<': os << "<"; break; + case '&': os << "&"; break; + + case '>': + // See: http://www.w3.org/TR/xml/#syntax + if( i > 2 && m_str[i-1] == ']' && m_str[i-2] == ']' ) + os << ">"; + else + os << c; + break; + + case '\"': + if( m_forWhat == ForAttributes ) + os << """; + else + os << c; + break; + + default: + // Escape control chars - based on contribution by @espenalb in PR #465 + if ( ( c < '\x09' ) || ( c > '\x0D' && c < '\x20') || c=='\x7F' ) + os << "&#x" << std::uppercase << std::hex << static_cast( c ); + else + os << c; + } + } + } + + friend std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ) { + xmlEncode.encodeTo( os ); + return os; + } + + private: + std::string m_str; + ForWhat m_forWhat; + }; + + class XmlWriter { + public: + + class ScopedElement { + public: + ScopedElement( XmlWriter* writer ) + : m_writer( writer ) + {} + + ScopedElement( ScopedElement const& other ) + : m_writer( other.m_writer ){ + other.m_writer = CATCH_NULL; + } + + ~ScopedElement() { + if( m_writer ) + m_writer->endElement(); + } + + ScopedElement& writeText( std::string const& text, bool indent = true ) { + m_writer->writeText( text, indent ); + return *this; + } + + template + ScopedElement& writeAttribute( std::string const& name, T const& attribute ) { + m_writer->writeAttribute( name, attribute ); + return *this; + } + + private: + mutable XmlWriter* m_writer; + }; + + XmlWriter() + : m_tagIsOpen( false ), + m_needsNewline( false ), + m_os( &Catch::cout() ) + {} + + XmlWriter( std::ostream& os ) + : m_tagIsOpen( false ), + m_needsNewline( false ), + m_os( &os ) + {} + + ~XmlWriter() { + while( !m_tags.empty() ) + endElement(); + } + + XmlWriter& startElement( std::string const& name ) { + ensureTagClosed(); + newlineIfNecessary(); + stream() << m_indent << "<" << name; + m_tags.push_back( name ); + m_indent += " "; + m_tagIsOpen = true; + return *this; + } + + ScopedElement scopedElement( std::string const& name ) { + ScopedElement scoped( this ); + startElement( name ); + return scoped; + } + + XmlWriter& endElement() { + newlineIfNecessary(); + m_indent = m_indent.substr( 0, m_indent.size()-2 ); + if( m_tagIsOpen ) { + stream() << "/>\n"; + m_tagIsOpen = false; + } + else { + stream() << m_indent << "\n"; + } + m_tags.pop_back(); + return *this; + } + + XmlWriter& writeAttribute( std::string const& name, std::string const& attribute ) { + if( !name.empty() && !attribute.empty() ) + stream() << " " << name << "=\"" << XmlEncode( attribute, XmlEncode::ForAttributes ) << "\""; + return *this; + } + + XmlWriter& writeAttribute( std::string const& name, bool attribute ) { + stream() << " " << name << "=\"" << ( attribute ? "true" : "false" ) << "\""; + return *this; + } + + template + XmlWriter& writeAttribute( std::string const& name, T const& attribute ) { + std::ostringstream oss; + oss << attribute; + return writeAttribute( name, oss.str() ); + } + + XmlWriter& writeText( std::string const& text, bool indent = true ) { + if( !text.empty() ){ + bool tagWasOpen = m_tagIsOpen; + ensureTagClosed(); + if( tagWasOpen && indent ) + stream() << m_indent; + stream() << XmlEncode( text ); + m_needsNewline = true; + } + return *this; + } + + XmlWriter& writeComment( std::string const& text ) { + ensureTagClosed(); + stream() << m_indent << ""; + m_needsNewline = true; + return *this; + } + + XmlWriter& writeBlankLine() { + ensureTagClosed(); + stream() << "\n"; + return *this; + } + + void setStream( std::ostream& os ) { + m_os = &os; + } + + private: + XmlWriter( XmlWriter const& ); + void operator=( XmlWriter const& ); + + std::ostream& stream() { + return *m_os; + } + + void ensureTagClosed() { + if( m_tagIsOpen ) { + stream() << ">\n"; + m_tagIsOpen = false; + } + } + + void newlineIfNecessary() { + if( m_needsNewline ) { + stream() << "\n"; + m_needsNewline = false; + } + } + + bool m_tagIsOpen; + bool m_needsNewline; + std::vector m_tags; + std::string m_indent; + std::ostream* m_os; + }; + +} +// #included from: catch_reenable_warnings.h + +#define TWOBLUECUBES_CATCH_REENABLE_WARNINGS_H_INCLUDED + +#ifdef __clang__ +# ifdef __ICC // icpc defines the __clang__ macro +# pragma warning(pop) +# else +# pragma clang diagnostic pop +# endif +#elif defined __GNUC__ +# pragma GCC diagnostic pop +#endif + + +namespace Catch { + class XmlReporter : public StreamingReporterBase { + public: + XmlReporter( ReporterConfig const& _config ) + : StreamingReporterBase( _config ), + m_sectionDepth( 0 ) + { + m_reporterPrefs.shouldRedirectStdOut = true; + } + + virtual ~XmlReporter() CATCH_OVERRIDE; + + static std::string getDescription() { + return "Reports test results as an XML document"; + } + + public: // StreamingReporterBase + + virtual void noMatchingTestCases( std::string const& s ) CATCH_OVERRIDE { + StreamingReporterBase::noMatchingTestCases( s ); + } + + virtual void testRunStarting( TestRunInfo const& testInfo ) CATCH_OVERRIDE { + StreamingReporterBase::testRunStarting( testInfo ); + m_xml.setStream( stream ); + m_xml.startElement( "Catch" ); + if( !m_config->name().empty() ) + m_xml.writeAttribute( "name", m_config->name() ); + } + + virtual void testGroupStarting( GroupInfo const& groupInfo ) CATCH_OVERRIDE { + StreamingReporterBase::testGroupStarting( groupInfo ); + m_xml.startElement( "Group" ) + .writeAttribute( "name", groupInfo.name ); + } + + virtual void testCaseStarting( TestCaseInfo const& testInfo ) CATCH_OVERRIDE { + StreamingReporterBase::testCaseStarting(testInfo); + m_xml.startElement( "TestCase" ).writeAttribute( "name", trim( testInfo.name ) ); + + if ( m_config->showDurations() == ShowDurations::Always ) + m_testCaseTimer.start(); + } + + virtual void sectionStarting( SectionInfo const& sectionInfo ) CATCH_OVERRIDE { + StreamingReporterBase::sectionStarting( sectionInfo ); + if( m_sectionDepth++ > 0 ) { + m_xml.startElement( "Section" ) + .writeAttribute( "name", trim( sectionInfo.name ) ) + .writeAttribute( "description", sectionInfo.description ); + } + } + + virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE { } + + virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE { + const AssertionResult& assertionResult = assertionStats.assertionResult; + + // Print any info messages in tags. + if( assertionStats.assertionResult.getResultType() != ResultWas::Ok ) { + for( std::vector::const_iterator it = assertionStats.infoMessages.begin(), itEnd = assertionStats.infoMessages.end(); + it != itEnd; + ++it ) { + if( it->type == ResultWas::Info ) { + m_xml.scopedElement( "Info" ) + .writeText( it->message ); + } else if ( it->type == ResultWas::Warning ) { + m_xml.scopedElement( "Warning" ) + .writeText( it->message ); + } + } + } + + // Drop out if result was successful but we're not printing them. + if( !m_config->includeSuccessfulResults() && isOk(assertionResult.getResultType()) ) + return true; + + // Print the expression if there is one. + if( assertionResult.hasExpression() ) { + m_xml.startElement( "Expression" ) + .writeAttribute( "success", assertionResult.succeeded() ) + .writeAttribute( "type", assertionResult.getTestMacroName() ) + .writeAttribute( "filename", assertionResult.getSourceInfo().file ) + .writeAttribute( "line", assertionResult.getSourceInfo().line ); + + m_xml.scopedElement( "Original" ) + .writeText( assertionResult.getExpression() ); + m_xml.scopedElement( "Expanded" ) + .writeText( assertionResult.getExpandedExpression() ); + } + + // And... Print a result applicable to each result type. + switch( assertionResult.getResultType() ) { + case ResultWas::ThrewException: + m_xml.scopedElement( "Exception" ) + .writeAttribute( "filename", assertionResult.getSourceInfo().file ) + .writeAttribute( "line", assertionResult.getSourceInfo().line ) + .writeText( assertionResult.getMessage() ); + break; + case ResultWas::FatalErrorCondition: + m_xml.scopedElement( "Fatal Error Condition" ) + .writeAttribute( "filename", assertionResult.getSourceInfo().file ) + .writeAttribute( "line", assertionResult.getSourceInfo().line ) + .writeText( assertionResult.getMessage() ); + break; + case ResultWas::Info: + m_xml.scopedElement( "Info" ) + .writeText( assertionResult.getMessage() ); + break; + case ResultWas::Warning: + // Warning will already have been written + break; + case ResultWas::ExplicitFailure: + m_xml.scopedElement( "Failure" ) + .writeText( assertionResult.getMessage() ); + break; + default: + break; + } + + if( assertionResult.hasExpression() ) + m_xml.endElement(); + + return true; + } + + virtual void sectionEnded( SectionStats const& sectionStats ) CATCH_OVERRIDE { + StreamingReporterBase::sectionEnded( sectionStats ); + if( --m_sectionDepth > 0 ) { + XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResults" ); + e.writeAttribute( "successes", sectionStats.assertions.passed ); + e.writeAttribute( "failures", sectionStats.assertions.failed ); + e.writeAttribute( "expectedFailures", sectionStats.assertions.failedButOk ); + + if ( m_config->showDurations() == ShowDurations::Always ) + e.writeAttribute( "durationInSeconds", sectionStats.durationInSeconds ); + + m_xml.endElement(); + } + } + + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE { + StreamingReporterBase::testCaseEnded( testCaseStats ); + XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResult" ); + e.writeAttribute( "success", testCaseStats.totals.assertions.allOk() ); + + if ( m_config->showDurations() == ShowDurations::Always ) + e.writeAttribute( "durationInSeconds", m_testCaseTimer.getElapsedSeconds() ); + + m_xml.endElement(); + } + + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE { + StreamingReporterBase::testGroupEnded( testGroupStats ); + // TODO: Check testGroupStats.aborting and act accordingly. + m_xml.scopedElement( "OverallResults" ) + .writeAttribute( "successes", testGroupStats.totals.assertions.passed ) + .writeAttribute( "failures", testGroupStats.totals.assertions.failed ) + .writeAttribute( "expectedFailures", testGroupStats.totals.assertions.failedButOk ); + m_xml.endElement(); + } + + virtual void testRunEnded( TestRunStats const& testRunStats ) CATCH_OVERRIDE { + StreamingReporterBase::testRunEnded( testRunStats ); + m_xml.scopedElement( "OverallResults" ) + .writeAttribute( "successes", testRunStats.totals.assertions.passed ) + .writeAttribute( "failures", testRunStats.totals.assertions.failed ) + .writeAttribute( "expectedFailures", testRunStats.totals.assertions.failedButOk ); + m_xml.endElement(); + } + + private: + Timer m_testCaseTimer; + XmlWriter m_xml; + int m_sectionDepth; + }; + + INTERNAL_CATCH_REGISTER_REPORTER( "xml", XmlReporter ) + +} // end namespace Catch + +// #included from: ../reporters/catch_reporter_junit.hpp +#define TWOBLUECUBES_CATCH_REPORTER_JUNIT_HPP_INCLUDED + +#include + +namespace Catch { + + class JunitReporter : public CumulativeReporterBase { + public: + JunitReporter( ReporterConfig const& _config ) + : CumulativeReporterBase( _config ), + xml( _config.stream() ) + { + m_reporterPrefs.shouldRedirectStdOut = true; + } + + virtual ~JunitReporter() CATCH_OVERRIDE; + + static std::string getDescription() { + return "Reports test results in an XML format that looks like Ant's junitreport target"; + } + + virtual void noMatchingTestCases( std::string const& /*spec*/ ) CATCH_OVERRIDE {} + + virtual void testRunStarting( TestRunInfo const& runInfo ) CATCH_OVERRIDE { + CumulativeReporterBase::testRunStarting( runInfo ); + xml.startElement( "testsuites" ); + } + + virtual void testGroupStarting( GroupInfo const& groupInfo ) CATCH_OVERRIDE { + suiteTimer.start(); + stdOutForSuite.str(""); + stdErrForSuite.str(""); + unexpectedExceptions = 0; + CumulativeReporterBase::testGroupStarting( groupInfo ); + } + + virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE { + if( assertionStats.assertionResult.getResultType() == ResultWas::ThrewException ) + unexpectedExceptions++; + return CumulativeReporterBase::assertionEnded( assertionStats ); + } + + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE { + stdOutForSuite << testCaseStats.stdOut; + stdErrForSuite << testCaseStats.stdErr; + CumulativeReporterBase::testCaseEnded( testCaseStats ); + } + + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE { + double suiteTime = suiteTimer.getElapsedSeconds(); + CumulativeReporterBase::testGroupEnded( testGroupStats ); + writeGroup( *m_testGroups.back(), suiteTime ); + } + + virtual void testRunEndedCumulative() CATCH_OVERRIDE { + xml.endElement(); + } + + void writeGroup( TestGroupNode const& groupNode, double suiteTime ) { + XmlWriter::ScopedElement e = xml.scopedElement( "testsuite" ); + TestGroupStats const& stats = groupNode.value; + xml.writeAttribute( "name", stats.groupInfo.name ); + xml.writeAttribute( "errors", unexpectedExceptions ); + xml.writeAttribute( "failures", stats.totals.assertions.failed-unexpectedExceptions ); + xml.writeAttribute( "tests", stats.totals.assertions.total() ); + xml.writeAttribute( "hostname", "tbd" ); // !TBD + if( m_config->showDurations() == ShowDurations::Never ) + xml.writeAttribute( "time", "" ); + else + xml.writeAttribute( "time", suiteTime ); + xml.writeAttribute( "timestamp", "tbd" ); // !TBD + + // Write test cases + for( TestGroupNode::ChildNodes::const_iterator + it = groupNode.children.begin(), itEnd = groupNode.children.end(); + it != itEnd; + ++it ) + writeTestCase( **it ); + + xml.scopedElement( "system-out" ).writeText( trim( stdOutForSuite.str() ), false ); + xml.scopedElement( "system-err" ).writeText( trim( stdErrForSuite.str() ), false ); + } + + void writeTestCase( TestCaseNode const& testCaseNode ) { + TestCaseStats const& stats = testCaseNode.value; + + // All test cases have exactly one section - which represents the + // test case itself. That section may have 0-n nested sections + assert( testCaseNode.children.size() == 1 ); + SectionNode const& rootSection = *testCaseNode.children.front(); + + std::string className = stats.testInfo.className; + + if( className.empty() ) { + if( rootSection.childSections.empty() ) + className = "global"; + } + writeSection( className, "", rootSection ); + } + + void writeSection( std::string const& className, + std::string const& rootName, + SectionNode const& sectionNode ) { + std::string name = trim( sectionNode.stats.sectionInfo.name ); + if( !rootName.empty() ) + name = rootName + "/" + name; + + if( !sectionNode.assertions.empty() || + !sectionNode.stdOut.empty() || + !sectionNode.stdErr.empty() ) { + XmlWriter::ScopedElement e = xml.scopedElement( "testcase" ); + if( className.empty() ) { + xml.writeAttribute( "classname", name ); + xml.writeAttribute( "name", "root" ); + } + else { + xml.writeAttribute( "classname", className ); + xml.writeAttribute( "name", name ); + } + xml.writeAttribute( "time", Catch::toString( sectionNode.stats.durationInSeconds ) ); + + writeAssertions( sectionNode ); + + if( !sectionNode.stdOut.empty() ) + xml.scopedElement( "system-out" ).writeText( trim( sectionNode.stdOut ), false ); + if( !sectionNode.stdErr.empty() ) + xml.scopedElement( "system-err" ).writeText( trim( sectionNode.stdErr ), false ); + } + for( SectionNode::ChildSections::const_iterator + it = sectionNode.childSections.begin(), + itEnd = sectionNode.childSections.end(); + it != itEnd; + ++it ) + if( className.empty() ) + writeSection( name, "", **it ); + else + writeSection( className, name, **it ); + } + + void writeAssertions( SectionNode const& sectionNode ) { + for( SectionNode::Assertions::const_iterator + it = sectionNode.assertions.begin(), itEnd = sectionNode.assertions.end(); + it != itEnd; + ++it ) + writeAssertion( *it ); + } + void writeAssertion( AssertionStats const& stats ) { + AssertionResult const& result = stats.assertionResult; + if( !result.isOk() ) { + std::string elementName; + switch( result.getResultType() ) { + case ResultWas::ThrewException: + case ResultWas::FatalErrorCondition: + elementName = "error"; + break; + case ResultWas::ExplicitFailure: + elementName = "failure"; + break; + case ResultWas::ExpressionFailed: + elementName = "failure"; + break; + case ResultWas::DidntThrowException: + elementName = "failure"; + break; + + // We should never see these here: + case ResultWas::Info: + case ResultWas::Warning: + case ResultWas::Ok: + case ResultWas::Unknown: + case ResultWas::FailureBit: + case ResultWas::Exception: + elementName = "internalError"; + break; + } + + XmlWriter::ScopedElement e = xml.scopedElement( elementName ); + + xml.writeAttribute( "message", result.getExpandedExpression() ); + xml.writeAttribute( "type", result.getTestMacroName() ); + + std::ostringstream oss; + if( !result.getMessage().empty() ) + oss << result.getMessage() << "\n"; + for( std::vector::const_iterator + it = stats.infoMessages.begin(), + itEnd = stats.infoMessages.end(); + it != itEnd; + ++it ) + if( it->type == ResultWas::Info ) + oss << it->message << "\n"; + + oss << "at " << result.getSourceInfo(); + xml.writeText( oss.str(), false ); + } + } + + XmlWriter xml; + Timer suiteTimer; + std::ostringstream stdOutForSuite; + std::ostringstream stdErrForSuite; + unsigned int unexpectedExceptions; + }; + + INTERNAL_CATCH_REGISTER_REPORTER( "junit", JunitReporter ) + +} // end namespace Catch + +// #included from: ../reporters/catch_reporter_console.hpp +#define TWOBLUECUBES_CATCH_REPORTER_CONSOLE_HPP_INCLUDED + +namespace Catch { + + struct ConsoleReporter : StreamingReporterBase { + ConsoleReporter( ReporterConfig const& _config ) + : StreamingReporterBase( _config ), + m_headerPrinted( false ) + {} + + virtual ~ConsoleReporter() CATCH_OVERRIDE; + static std::string getDescription() { + return "Reports test results as plain lines of text"; + } + + virtual void noMatchingTestCases( std::string const& spec ) CATCH_OVERRIDE { + stream << "No test cases matched '" << spec << "'" << std::endl; + } + + virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE { + } + + virtual bool assertionEnded( AssertionStats const& _assertionStats ) CATCH_OVERRIDE { + AssertionResult const& result = _assertionStats.assertionResult; + + bool printInfoMessages = true; + + // Drop out if result was successful and we're not printing those + if( !m_config->includeSuccessfulResults() && result.isOk() ) { + if( result.getResultType() != ResultWas::Warning ) + return false; + printInfoMessages = false; + } + + lazyPrint(); + + AssertionPrinter printer( stream, _assertionStats, printInfoMessages ); + printer.print(); + stream << std::endl; + return true; + } + + virtual void sectionStarting( SectionInfo const& _sectionInfo ) CATCH_OVERRIDE { + m_headerPrinted = false; + StreamingReporterBase::sectionStarting( _sectionInfo ); + } + virtual void sectionEnded( SectionStats const& _sectionStats ) CATCH_OVERRIDE { + if( _sectionStats.missingAssertions ) { + lazyPrint(); + Colour colour( Colour::ResultError ); + if( m_sectionStack.size() > 1 ) + stream << "\nNo assertions in section"; + else + stream << "\nNo assertions in test case"; + stream << " '" << _sectionStats.sectionInfo.name << "'\n" << std::endl; + } + if( m_headerPrinted ) { + if( m_config->showDurations() == ShowDurations::Always ) + stream << "Completed in " << _sectionStats.durationInSeconds << "s" << std::endl; + m_headerPrinted = false; + } + else { + if( m_config->showDurations() == ShowDurations::Always ) + stream << _sectionStats.sectionInfo.name << " completed in " << _sectionStats.durationInSeconds << "s" << std::endl; + } + StreamingReporterBase::sectionEnded( _sectionStats ); + } + + virtual void testCaseEnded( TestCaseStats const& _testCaseStats ) CATCH_OVERRIDE { + StreamingReporterBase::testCaseEnded( _testCaseStats ); + m_headerPrinted = false; + } + virtual void testGroupEnded( TestGroupStats const& _testGroupStats ) CATCH_OVERRIDE { + if( currentGroupInfo.used ) { + printSummaryDivider(); + stream << "Summary for group '" << _testGroupStats.groupInfo.name << "':\n"; + printTotals( _testGroupStats.totals ); + stream << "\n" << std::endl; + } + StreamingReporterBase::testGroupEnded( _testGroupStats ); + } + virtual void testRunEnded( TestRunStats const& _testRunStats ) CATCH_OVERRIDE { + printTotalsDivider( _testRunStats.totals ); + printTotals( _testRunStats.totals ); + stream << std::endl; + StreamingReporterBase::testRunEnded( _testRunStats ); + } + + private: + + class AssertionPrinter { + void operator= ( AssertionPrinter const& ); + public: + AssertionPrinter( std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages ) + : stream( _stream ), + stats( _stats ), + result( _stats.assertionResult ), + colour( Colour::None ), + message( result.getMessage() ), + messages( _stats.infoMessages ), + printInfoMessages( _printInfoMessages ) + { + switch( result.getResultType() ) { + case ResultWas::Ok: + colour = Colour::Success; + passOrFail = "PASSED"; + //if( result.hasMessage() ) + if( _stats.infoMessages.size() == 1 ) + messageLabel = "with message"; + if( _stats.infoMessages.size() > 1 ) + messageLabel = "with messages"; + break; + case ResultWas::ExpressionFailed: + if( result.isOk() ) { + colour = Colour::Success; + passOrFail = "FAILED - but was ok"; + } + else { + colour = Colour::Error; + passOrFail = "FAILED"; + } + if( _stats.infoMessages.size() == 1 ) + messageLabel = "with message"; + if( _stats.infoMessages.size() > 1 ) + messageLabel = "with messages"; + break; + case ResultWas::ThrewException: + colour = Colour::Error; + passOrFail = "FAILED"; + messageLabel = "due to unexpected exception with message"; + break; + case ResultWas::FatalErrorCondition: + colour = Colour::Error; + passOrFail = "FAILED"; + messageLabel = "due to a fatal error condition"; + break; + case ResultWas::DidntThrowException: + colour = Colour::Error; + passOrFail = "FAILED"; + messageLabel = "because no exception was thrown where one was expected"; + break; + case ResultWas::Info: + messageLabel = "info"; + break; + case ResultWas::Warning: + messageLabel = "warning"; + break; + case ResultWas::ExplicitFailure: + passOrFail = "FAILED"; + colour = Colour::Error; + if( _stats.infoMessages.size() == 1 ) + messageLabel = "explicitly with message"; + if( _stats.infoMessages.size() > 1 ) + messageLabel = "explicitly with messages"; + break; + // These cases are here to prevent compiler warnings + case ResultWas::Unknown: + case ResultWas::FailureBit: + case ResultWas::Exception: + passOrFail = "** internal error **"; + colour = Colour::Error; + break; + } + } + + void print() const { + printSourceInfo(); + if( stats.totals.assertions.total() > 0 ) { + if( result.isOk() ) + stream << "\n"; + printResultType(); + printOriginalExpression(); + printReconstructedExpression(); + } + else { + stream << "\n"; + } + printMessage(); + } + + private: + void printResultType() const { + if( !passOrFail.empty() ) { + Colour colourGuard( colour ); + stream << passOrFail << ":\n"; + } + } + void printOriginalExpression() const { + if( result.hasExpression() ) { + Colour colourGuard( Colour::OriginalExpression ); + stream << " "; + stream << result.getExpressionInMacro(); + stream << "\n"; + } + } + void printReconstructedExpression() const { + if( result.hasExpandedExpression() ) { + stream << "with expansion:\n"; + Colour colourGuard( Colour::ReconstructedExpression ); + stream << Text( result.getExpandedExpression(), TextAttributes().setIndent(2) ) << "\n"; + } + } + void printMessage() const { + if( !messageLabel.empty() ) + stream << messageLabel << ":" << "\n"; + for( std::vector::const_iterator it = messages.begin(), itEnd = messages.end(); + it != itEnd; + ++it ) { + // If this assertion is a warning ignore any INFO messages + if( printInfoMessages || it->type != ResultWas::Info ) + stream << Text( it->message, TextAttributes().setIndent(2) ) << "\n"; + } + } + void printSourceInfo() const { + Colour colourGuard( Colour::FileName ); + stream << result.getSourceInfo() << ": "; + } + + std::ostream& stream; + AssertionStats const& stats; + AssertionResult const& result; + Colour::Code colour; + std::string passOrFail; + std::string messageLabel; + std::string message; + std::vector messages; + bool printInfoMessages; + }; + + void lazyPrint() { + + if( !currentTestRunInfo.used ) + lazyPrintRunInfo(); + if( !currentGroupInfo.used ) + lazyPrintGroupInfo(); + + if( !m_headerPrinted ) { + printTestCaseAndSectionHeader(); + m_headerPrinted = true; + } + } + void lazyPrintRunInfo() { + stream << "\n" << getLineOfChars<'~'>() << "\n"; + Colour colour( Colour::SecondaryText ); + stream << currentTestRunInfo->name + << " is a Catch v" << libraryVersion << " host application.\n" + << "Run with -? for options\n\n"; + + if( m_config->rngSeed() != 0 ) + stream << "Randomness seeded to: " << m_config->rngSeed() << "\n\n"; + + currentTestRunInfo.used = true; + } + void lazyPrintGroupInfo() { + if( !currentGroupInfo->name.empty() && currentGroupInfo->groupsCounts > 1 ) { + printClosedHeader( "Group: " + currentGroupInfo->name ); + currentGroupInfo.used = true; + } + } + void printTestCaseAndSectionHeader() { + assert( !m_sectionStack.empty() ); + printOpenHeader( currentTestCaseInfo->name ); + + if( m_sectionStack.size() > 1 ) { + Colour colourGuard( Colour::Headers ); + + std::vector::const_iterator + it = m_sectionStack.begin()+1, // Skip first section (test case) + itEnd = m_sectionStack.end(); + for( ; it != itEnd; ++it ) + printHeaderString( it->name, 2 ); + } + + SourceLineInfo lineInfo = m_sectionStack.front().lineInfo; + + if( !lineInfo.empty() ){ + stream << getLineOfChars<'-'>() << "\n"; + Colour colourGuard( Colour::FileName ); + stream << lineInfo << "\n"; + } + stream << getLineOfChars<'.'>() << "\n" << std::endl; + } + + void printClosedHeader( std::string const& _name ) { + printOpenHeader( _name ); + stream << getLineOfChars<'.'>() << "\n"; + } + void printOpenHeader( std::string const& _name ) { + stream << getLineOfChars<'-'>() << "\n"; + { + Colour colourGuard( Colour::Headers ); + printHeaderString( _name ); + } + } + + // if string has a : in first line will set indent to follow it on + // subsequent lines + void printHeaderString( std::string const& _string, std::size_t indent = 0 ) { + std::size_t i = _string.find( ": " ); + if( i != std::string::npos ) + i+=2; + else + i = 0; + stream << Text( _string, TextAttributes() + .setIndent( indent+i) + .setInitialIndent( indent ) ) << "\n"; + } + + struct SummaryColumn { + + SummaryColumn( std::string const& _label, Colour::Code _colour ) + : label( _label ), + colour( _colour ) + {} + SummaryColumn addRow( std::size_t count ) { + std::ostringstream oss; + oss << count; + std::string row = oss.str(); + for( std::vector::iterator it = rows.begin(); it != rows.end(); ++it ) { + while( it->size() < row.size() ) + *it = " " + *it; + while( it->size() > row.size() ) + row = " " + row; + } + rows.push_back( row ); + return *this; + } + + std::string label; + Colour::Code colour; + std::vector rows; + + }; + + void printTotals( Totals const& totals ) { + if( totals.testCases.total() == 0 ) { + stream << Colour( Colour::Warning ) << "No tests ran\n"; + } + else if( totals.assertions.total() > 0 && totals.assertions.allPassed() ) { + stream << Colour( Colour::ResultSuccess ) << "All tests passed"; + stream << " (" + << pluralise( totals.assertions.passed, "assertion" ) << " in " + << pluralise( totals.testCases.passed, "test case" ) << ")" + << "\n"; + } + else { + + std::vector columns; + columns.push_back( SummaryColumn( "", Colour::None ) + .addRow( totals.testCases.total() ) + .addRow( totals.assertions.total() ) ); + columns.push_back( SummaryColumn( "passed", Colour::Success ) + .addRow( totals.testCases.passed ) + .addRow( totals.assertions.passed ) ); + columns.push_back( SummaryColumn( "failed", Colour::ResultError ) + .addRow( totals.testCases.failed ) + .addRow( totals.assertions.failed ) ); + columns.push_back( SummaryColumn( "failed as expected", Colour::ResultExpectedFailure ) + .addRow( totals.testCases.failedButOk ) + .addRow( totals.assertions.failedButOk ) ); + + printSummaryRow( "test cases", columns, 0 ); + printSummaryRow( "assertions", columns, 1 ); + } + } + void printSummaryRow( std::string const& label, std::vector const& cols, std::size_t row ) { + for( std::vector::const_iterator it = cols.begin(); it != cols.end(); ++it ) { + std::string value = it->rows[row]; + if( it->label.empty() ) { + stream << label << ": "; + if( value != "0" ) + stream << value; + else + stream << Colour( Colour::Warning ) << "- none -"; + } + else if( value != "0" ) { + stream << Colour( Colour::LightGrey ) << " | "; + stream << Colour( it->colour ) + << value << " " << it->label; + } + } + stream << "\n"; + } + + static std::size_t makeRatio( std::size_t number, std::size_t total ) { + std::size_t ratio = total > 0 ? CATCH_CONFIG_CONSOLE_WIDTH * number/ total : 0; + return ( ratio == 0 && number > 0 ) ? 1 : ratio; + } + static std::size_t& findMax( std::size_t& i, std::size_t& j, std::size_t& k ) { + if( i > j && i > k ) + return i; + else if( j > k ) + return j; + else + return k; + } + + void printTotalsDivider( Totals const& totals ) { + if( totals.testCases.total() > 0 ) { + std::size_t failedRatio = makeRatio( totals.testCases.failed, totals.testCases.total() ); + std::size_t failedButOkRatio = makeRatio( totals.testCases.failedButOk, totals.testCases.total() ); + std::size_t passedRatio = makeRatio( totals.testCases.passed, totals.testCases.total() ); + while( failedRatio + failedButOkRatio + passedRatio < CATCH_CONFIG_CONSOLE_WIDTH-1 ) + findMax( failedRatio, failedButOkRatio, passedRatio )++; + while( failedRatio + failedButOkRatio + passedRatio > CATCH_CONFIG_CONSOLE_WIDTH-1 ) + findMax( failedRatio, failedButOkRatio, passedRatio )--; + + stream << Colour( Colour::Error ) << std::string( failedRatio, '=' ); + stream << Colour( Colour::ResultExpectedFailure ) << std::string( failedButOkRatio, '=' ); + if( totals.testCases.allPassed() ) + stream << Colour( Colour::ResultSuccess ) << std::string( passedRatio, '=' ); + else + stream << Colour( Colour::Success ) << std::string( passedRatio, '=' ); + } + else { + stream << Colour( Colour::Warning ) << std::string( CATCH_CONFIG_CONSOLE_WIDTH-1, '=' ); + } + stream << "\n"; + } + void printSummaryDivider() { + stream << getLineOfChars<'-'>() << "\n"; + } + + private: + bool m_headerPrinted; + }; + + INTERNAL_CATCH_REGISTER_REPORTER( "console", ConsoleReporter ) + +} // end namespace Catch + +// #included from: ../reporters/catch_reporter_compact.hpp +#define TWOBLUECUBES_CATCH_REPORTER_COMPACT_HPP_INCLUDED + +namespace Catch { + + struct CompactReporter : StreamingReporterBase { + + CompactReporter( ReporterConfig const& _config ) + : StreamingReporterBase( _config ) + {} + + virtual ~CompactReporter(); + + static std::string getDescription() { + return "Reports test results on a single line, suitable for IDEs"; + } + + virtual ReporterPreferences getPreferences() const { + ReporterPreferences prefs; + prefs.shouldRedirectStdOut = false; + return prefs; + } + + virtual void noMatchingTestCases( std::string const& spec ) { + stream << "No test cases matched '" << spec << "'" << std::endl; + } + + virtual void assertionStarting( AssertionInfo const& ) { + } + + virtual bool assertionEnded( AssertionStats const& _assertionStats ) { + AssertionResult const& result = _assertionStats.assertionResult; + + bool printInfoMessages = true; + + // Drop out if result was successful and we're not printing those + if( !m_config->includeSuccessfulResults() && result.isOk() ) { + if( result.getResultType() != ResultWas::Warning ) + return false; + printInfoMessages = false; + } + + AssertionPrinter printer( stream, _assertionStats, printInfoMessages ); + printer.print(); + + stream << std::endl; + return true; + } + + virtual void testRunEnded( TestRunStats const& _testRunStats ) { + printTotals( _testRunStats.totals ); + stream << "\n" << std::endl; + StreamingReporterBase::testRunEnded( _testRunStats ); + } + + private: + class AssertionPrinter { + void operator= ( AssertionPrinter const& ); + public: + AssertionPrinter( std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages ) + : stream( _stream ) + , stats( _stats ) + , result( _stats.assertionResult ) + , messages( _stats.infoMessages ) + , itMessage( _stats.infoMessages.begin() ) + , printInfoMessages( _printInfoMessages ) + {} + + void print() { + printSourceInfo(); + + itMessage = messages.begin(); + + switch( result.getResultType() ) { + case ResultWas::Ok: + printResultType( Colour::ResultSuccess, passedString() ); + printOriginalExpression(); + printReconstructedExpression(); + if ( ! result.hasExpression() ) + printRemainingMessages( Colour::None ); + else + printRemainingMessages(); + break; + case ResultWas::ExpressionFailed: + if( result.isOk() ) + printResultType( Colour::ResultSuccess, failedString() + std::string( " - but was ok" ) ); + else + printResultType( Colour::Error, failedString() ); + printOriginalExpression(); + printReconstructedExpression(); + printRemainingMessages(); + break; + case ResultWas::ThrewException: + printResultType( Colour::Error, failedString() ); + printIssue( "unexpected exception with message:" ); + printMessage(); + printExpressionWas(); + printRemainingMessages(); + break; + case ResultWas::FatalErrorCondition: + printResultType( Colour::Error, failedString() ); + printIssue( "fatal error condition with message:" ); + printMessage(); + printExpressionWas(); + printRemainingMessages(); + break; + case ResultWas::DidntThrowException: + printResultType( Colour::Error, failedString() ); + printIssue( "expected exception, got none" ); + printExpressionWas(); + printRemainingMessages(); + break; + case ResultWas::Info: + printResultType( Colour::None, "info" ); + printMessage(); + printRemainingMessages(); + break; + case ResultWas::Warning: + printResultType( Colour::None, "warning" ); + printMessage(); + printRemainingMessages(); + break; + case ResultWas::ExplicitFailure: + printResultType( Colour::Error, failedString() ); + printIssue( "explicitly" ); + printRemainingMessages( Colour::None ); + break; + // These cases are here to prevent compiler warnings + case ResultWas::Unknown: + case ResultWas::FailureBit: + case ResultWas::Exception: + printResultType( Colour::Error, "** internal error **" ); + break; + } + } + + private: + // Colour::LightGrey + + static Colour::Code dimColour() { return Colour::FileName; } + +#ifdef CATCH_PLATFORM_MAC + static const char* failedString() { return "FAILED"; } + static const char* passedString() { return "PASSED"; } +#else + static const char* failedString() { return "failed"; } + static const char* passedString() { return "passed"; } +#endif + + void printSourceInfo() const { + Colour colourGuard( Colour::FileName ); + stream << result.getSourceInfo() << ":"; + } + + void printResultType( Colour::Code colour, std::string passOrFail ) const { + if( !passOrFail.empty() ) { + { + Colour colourGuard( colour ); + stream << " " << passOrFail; + } + stream << ":"; + } + } + + void printIssue( std::string issue ) const { + stream << " " << issue; + } + + void printExpressionWas() { + if( result.hasExpression() ) { + stream << ";"; + { + Colour colour( dimColour() ); + stream << " expression was:"; + } + printOriginalExpression(); + } + } + + void printOriginalExpression() const { + if( result.hasExpression() ) { + stream << " " << result.getExpression(); + } + } + + void printReconstructedExpression() const { + if( result.hasExpandedExpression() ) { + { + Colour colour( dimColour() ); + stream << " for: "; + } + stream << result.getExpandedExpression(); + } + } + + void printMessage() { + if ( itMessage != messages.end() ) { + stream << " '" << itMessage->message << "'"; + ++itMessage; + } + } + + void printRemainingMessages( Colour::Code colour = dimColour() ) { + if ( itMessage == messages.end() ) + return; + + // using messages.end() directly yields compilation error: + std::vector::const_iterator itEnd = messages.end(); + const std::size_t N = static_cast( std::distance( itMessage, itEnd ) ); + + { + Colour colourGuard( colour ); + stream << " with " << pluralise( N, "message" ) << ":"; + } + + for(; itMessage != itEnd; ) { + // If this assertion is a warning ignore any INFO messages + if( printInfoMessages || itMessage->type != ResultWas::Info ) { + stream << " '" << itMessage->message << "'"; + if ( ++itMessage != itEnd ) { + Colour colourGuard( dimColour() ); + stream << " and"; + } + } + } + } + + private: + std::ostream& stream; + AssertionStats const& stats; + AssertionResult const& result; + std::vector messages; + std::vector::const_iterator itMessage; + bool printInfoMessages; + }; + + // Colour, message variants: + // - white: No tests ran. + // - red: Failed [both/all] N test cases, failed [both/all] M assertions. + // - white: Passed [both/all] N test cases (no assertions). + // - red: Failed N tests cases, failed M assertions. + // - green: Passed [both/all] N tests cases with M assertions. + + std::string bothOrAll( std::size_t count ) const { + return count == 1 ? "" : count == 2 ? "both " : "all " ; + } + + void printTotals( const Totals& totals ) const { + if( totals.testCases.total() == 0 ) { + stream << "No tests ran."; + } + else if( totals.testCases.failed == totals.testCases.total() ) { + Colour colour( Colour::ResultError ); + const std::string qualify_assertions_failed = + totals.assertions.failed == totals.assertions.total() ? + bothOrAll( totals.assertions.failed ) : ""; + stream << + "Failed " << bothOrAll( totals.testCases.failed ) + << pluralise( totals.testCases.failed, "test case" ) << ", " + "failed " << qualify_assertions_failed << + pluralise( totals.assertions.failed, "assertion" ) << "."; + } + else if( totals.assertions.total() == 0 ) { + stream << + "Passed " << bothOrAll( totals.testCases.total() ) + << pluralise( totals.testCases.total(), "test case" ) + << " (no assertions)."; + } + else if( totals.assertions.failed ) { + Colour colour( Colour::ResultError ); + stream << + "Failed " << pluralise( totals.testCases.failed, "test case" ) << ", " + "failed " << pluralise( totals.assertions.failed, "assertion" ) << "."; + } + else { + Colour colour( Colour::ResultSuccess ); + stream << + "Passed " << bothOrAll( totals.testCases.passed ) + << pluralise( totals.testCases.passed, "test case" ) << + " with " << pluralise( totals.assertions.passed, "assertion" ) << "."; + } + } + }; + + INTERNAL_CATCH_REGISTER_REPORTER( "compact", CompactReporter ) + +} // end namespace Catch + +namespace Catch { + // These are all here to avoid warnings about not having any out of line + // virtual methods + NonCopyable::~NonCopyable() {} + IShared::~IShared() {} + IStream::~IStream() CATCH_NOEXCEPT {} + FileStream::~FileStream() CATCH_NOEXCEPT {} + CoutStream::~CoutStream() CATCH_NOEXCEPT {} + DebugOutStream::~DebugOutStream() CATCH_NOEXCEPT {} + StreamBufBase::~StreamBufBase() CATCH_NOEXCEPT {} + IContext::~IContext() {} + IResultCapture::~IResultCapture() {} + ITestCase::~ITestCase() {} + ITestCaseRegistry::~ITestCaseRegistry() {} + IRegistryHub::~IRegistryHub() {} + IMutableRegistryHub::~IMutableRegistryHub() {} + IExceptionTranslator::~IExceptionTranslator() {} + IExceptionTranslatorRegistry::~IExceptionTranslatorRegistry() {} + IReporter::~IReporter() {} + IReporterFactory::~IReporterFactory() {} + IReporterRegistry::~IReporterRegistry() {} + IStreamingReporter::~IStreamingReporter() {} + AssertionStats::~AssertionStats() {} + SectionStats::~SectionStats() {} + TestCaseStats::~TestCaseStats() {} + TestGroupStats::~TestGroupStats() {} + TestRunStats::~TestRunStats() {} + CumulativeReporterBase::SectionNode::~SectionNode() {} + CumulativeReporterBase::~CumulativeReporterBase() {} + + StreamingReporterBase::~StreamingReporterBase() {} + ConsoleReporter::~ConsoleReporter() {} + CompactReporter::~CompactReporter() {} + IRunner::~IRunner() {} + IMutableContext::~IMutableContext() {} + IConfig::~IConfig() {} + XmlReporter::~XmlReporter() {} + JunitReporter::~JunitReporter() {} + TestRegistry::~TestRegistry() {} + FreeFunctionTestCase::~FreeFunctionTestCase() {} + IGeneratorInfo::~IGeneratorInfo() {} + IGeneratorsForTest::~IGeneratorsForTest() {} + WildcardPattern::~WildcardPattern() {} + TestSpec::Pattern::~Pattern() {} + TestSpec::NamePattern::~NamePattern() {} + TestSpec::TagPattern::~TagPattern() {} + TestSpec::ExcludedPattern::~ExcludedPattern() {} + + Matchers::Impl::StdString::Equals::~Equals() {} + Matchers::Impl::StdString::Contains::~Contains() {} + Matchers::Impl::StdString::StartsWith::~StartsWith() {} + Matchers::Impl::StdString::EndsWith::~EndsWith() {} + + void Config::dummy() {} + + namespace TestCaseTracking { + ITracker::~ITracker() {} + TrackerBase::~TrackerBase() {} + SectionTracker::~SectionTracker() {} + IndexTracker::~IndexTracker() {} + } +} + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +#endif + +#ifdef CATCH_CONFIG_MAIN +// #included from: internal/catch_default_main.hpp +#define TWOBLUECUBES_CATCH_DEFAULT_MAIN_HPP_INCLUDED + +#ifndef __OBJC__ + +// Standard C/C++ main entry point +int main (int argc, char * argv[]) { + return Catch::Session().run( argc, argv ); +} + +#else // __OBJC__ + +// Objective-C entry point +int main (int argc, char * const argv[]) { +#if !CATCH_ARC_ENABLED + NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; +#endif + + Catch::registerTestMethods(); + int result = Catch::Session().run( argc, (char* const*)argv ); + +#if !CATCH_ARC_ENABLED + [pool drain]; +#endif + + return result; +} + +#endif // __OBJC__ + +#endif + +#ifdef CLARA_CONFIG_MAIN_NOT_DEFINED +# undef CLARA_CONFIG_MAIN +#endif + +////// + +// If this config identifier is defined then all CATCH macros are prefixed with CATCH_ +#ifdef CATCH_CONFIG_PREFIX_ALL + +#define CATCH_REQUIRE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE" ) +#define CATCH_REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, "CATCH_REQUIRE_FALSE" ) + +#define CATCH_REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, "", "CATCH_REQUIRE_THROWS" ) +#define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THROWS_AS" ) +#define CATCH_REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, matcher, "CATCH_REQUIRE_THROWS_WITH" ) +#define CATCH_REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_NOTHROW" ) + +#define CATCH_CHECK( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK" ) +#define CATCH_CHECK_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, "CATCH_CHECK_FALSE" ) +#define CATCH_CHECKED_IF( expr ) INTERNAL_CATCH_IF( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECKED_IF" ) +#define CATCH_CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECKED_ELSE" ) +#define CATCH_CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, "CATCH_CHECK_NOFAIL" ) + +#define CATCH_CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THROWS" ) +#define CATCH_CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THROWS_AS" ) +#define CATCH_CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, matcher, "CATCH_CHECK_THROWS_WITH" ) +#define CATCH_CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_NOTHROW" ) + +#define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THAT" ) +#define CATCH_REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THAT" ) + +#define CATCH_INFO( msg ) INTERNAL_CATCH_INFO( msg, "CATCH_INFO" ) +#define CATCH_WARN( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, "CATCH_WARN", msg ) +#define CATCH_SCOPED_INFO( msg ) INTERNAL_CATCH_INFO( msg, "CATCH_INFO" ) +#define CATCH_CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CATCH_CAPTURE" ) +#define CATCH_SCOPED_CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CATCH_CAPTURE" ) + +#ifdef CATCH_CONFIG_VARIADIC_MACROS + #define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ ) + #define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ ) + #define CATCH_METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ ) + #define CATCH_REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ ) + #define CATCH_SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) + #define CATCH_FAIL( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "CATCH_FAIL", __VA_ARGS__ ) + #define CATCH_SUCCEED( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "CATCH_SUCCEED", __VA_ARGS__ ) +#else + #define CATCH_TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description ) + #define CATCH_TEST_CASE_METHOD( className, name, description ) INTERNAL_CATCH_TEST_CASE_METHOD( className, name, description ) + #define CATCH_METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description ) + #define CATCH_REGISTER_TEST_CASE( function, name, description ) INTERNAL_CATCH_REGISTER_TESTCASE( function, name, description ) + #define CATCH_SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description ) + #define CATCH_FAIL( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "CATCH_FAIL", msg ) + #define CATCH_SUCCEED( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "CATCH_SUCCEED", msg ) +#endif +#define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE( "", "" ) + +#define CATCH_REGISTER_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) +#define CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) + +#define CATCH_GENERATE( expr) INTERNAL_CATCH_GENERATE( expr ) + +// "BDD-style" convenience wrappers +#ifdef CATCH_CONFIG_VARIADIC_MACROS +#define CATCH_SCENARIO( ... ) CATCH_TEST_CASE( "Scenario: " __VA_ARGS__ ) +#define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ ) +#else +#define CATCH_SCENARIO( name, tags ) CATCH_TEST_CASE( "Scenario: " name, tags ) +#define CATCH_SCENARIO_METHOD( className, name, tags ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " name, tags ) +#endif +#define CATCH_GIVEN( desc ) CATCH_SECTION( std::string( "Given: ") + desc, "" ) +#define CATCH_WHEN( desc ) CATCH_SECTION( std::string( " When: ") + desc, "" ) +#define CATCH_AND_WHEN( desc ) CATCH_SECTION( std::string( " And: ") + desc, "" ) +#define CATCH_THEN( desc ) CATCH_SECTION( std::string( " Then: ") + desc, "" ) +#define CATCH_AND_THEN( desc ) CATCH_SECTION( std::string( " And: ") + desc, "" ) + +// If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required +#else + +#define REQUIRE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal, "REQUIRE" ) +#define REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, "REQUIRE_FALSE" ) + +#define REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, "", "REQUIRE_THROWS" ) +#define REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::Normal, "REQUIRE_THROWS_AS" ) +#define REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, matcher, "REQUIRE_THROWS_WITH" ) +#define REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::Normal, "REQUIRE_NOTHROW" ) + +#define CHECK( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK" ) +#define CHECK_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, "CHECK_FALSE" ) +#define CHECKED_IF( expr ) INTERNAL_CATCH_IF( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECKED_IF" ) +#define CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECKED_ELSE" ) +#define CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, "CHECK_NOFAIL" ) + +#define CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, "", "CHECK_THROWS" ) +#define CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THROWS_AS" ) +#define CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, matcher, "CHECK_THROWS_WITH" ) +#define CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK_NOTHROW" ) + +#define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THAT" ) +#define REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::Normal, "REQUIRE_THAT" ) + +#define INFO( msg ) INTERNAL_CATCH_INFO( msg, "INFO" ) +#define WARN( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, "WARN", msg ) +#define SCOPED_INFO( msg ) INTERNAL_CATCH_INFO( msg, "INFO" ) +#define CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CAPTURE" ) +#define SCOPED_CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CAPTURE" ) + +#ifdef CATCH_CONFIG_VARIADIC_MACROS + #define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ ) + #define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ ) + #define METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ ) + #define REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ ) + #define SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) + #define FAIL( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "FAIL", __VA_ARGS__ ) + #define SUCCEED( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "SUCCEED", __VA_ARGS__ ) +#else + #define TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description ) + #define TEST_CASE_METHOD( className, name, description ) INTERNAL_CATCH_TEST_CASE_METHOD( className, name, description ) + #define METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description ) + #define REGISTER_TEST_CASE( method, name, description ) INTERNAL_CATCH_REGISTER_TESTCASE( method, name, description ) + #define SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description ) + #define FAIL( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "FAIL", msg ) + #define SUCCEED( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "SUCCEED", msg ) +#endif +#define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE( "", "" ) + +#define REGISTER_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) +#define REGISTER_LEGACY_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) + +#define GENERATE( expr) INTERNAL_CATCH_GENERATE( expr ) + +#endif + +#define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) + +// "BDD-style" convenience wrappers +#ifdef CATCH_CONFIG_VARIADIC_MACROS +#define SCENARIO( ... ) TEST_CASE( "Scenario: " __VA_ARGS__ ) +#define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ ) +#else +#define SCENARIO( name, tags ) TEST_CASE( "Scenario: " name, tags ) +#define SCENARIO_METHOD( className, name, tags ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " name, tags ) +#endif +#define GIVEN( desc ) SECTION( std::string(" Given: ") + desc, "" ) +#define WHEN( desc ) SECTION( std::string(" When: ") + desc, "" ) +#define AND_WHEN( desc ) SECTION( std::string("And when: ") + desc, "" ) +#define THEN( desc ) SECTION( std::string(" Then: ") + desc, "" ) +#define AND_THEN( desc ) SECTION( std::string(" And: ") + desc, "" ) + +using Catch::Detail::Approx; + +#endif // TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED + diff --git a/CUDA_VectorAdd/libwb/vendor/json11.cpp b/CUDA_VectorAdd/libwb/vendor/json11.cpp new file mode 100644 index 0000000..f401c26 --- /dev/null +++ b/CUDA_VectorAdd/libwb/vendor/json11.cpp @@ -0,0 +1,1013 @@ +/* Copyright (c) 2013 Dropbox, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy + * of this software and associated documentation files (the "Software"), to + * deal + * in the Software without restriction, including without limitation the + * rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN + * THE SOFTWARE. + */ + +#include "json11.hpp" +#include +#include +#include +#include +#include +#include + +namespace json11 { + +static const int max_depth = 200; + +using std::string; +using std::vector; +using std::map; +using std::make_shared; +using std::initializer_list; +using std::move; + +/* * * * * * * * * * * * * * * * * * * * + * Serialization + */ + +static void dump(std::nullptr_t, string &out) { + out += "null"; +} + +static void dump(double value, string &out) { + if (std::isfinite(value)) { + char buf[32]; +//PMO +#ifndef _MSC_VER + snprintf(buf, sizeof buf, "%.17g", value); +#else + _snprintf_s(buf, sizeof buf, "%.17g", value); +#endif + out += buf; + } else { + out += "null"; + } +} + +static void dump(int value, string &out) { + char buf[32]; +//PMO +#ifndef _MSC_VER + snprintf(buf, sizeof buf, "%d", value); +#else + _snprintf_s(buf, sizeof buf, "%d", value); +#endif + out += buf; +} + +static void dump(int64_t value, string &out) { + char buf[64]; +//PMO +#ifndef _MSC_VER + snprintf(buf, sizeof buf, "%" PRId64, value); +#else + _snprintf_s(buf, sizeof buf, "%" PRId64, value); +#endif + out += buf; +} + +static void dump(uint64_t value, string &out) { + char buf[128]; +//PMO +#ifndef _MSC_VER + snprintf(buf, sizeof buf, "%" PRIu64, value); +#else + _snprintf_s(buf, sizeof buf, "%" PRIu64, value); +#endif + out += buf; +} + +static void dump(bool value, string &out) { + out += value ? "true" : "false"; +} + +static void dump(const string &value, string &out) { + out += '"'; + for (size_t i = 0; i < value.length(); i++) { + const char ch = value[i]; + if (ch == '\\') { + out += "\\\\"; + } else if (ch == '"') { + out += "\\\""; + } else if (ch == '\b') { + out += "\\b"; + } else if (ch == '\f') { + out += "\\f"; + } else if (ch == '\n') { + out += "\\n"; + } else if (ch == '\r') { + out += "\\r"; + } else if (ch == '\t') { + out += "\\t"; + } else if (static_cast(ch) <= 0x1f) { + char buf[8]; +//PMO +#ifndef _MSC_VER + snprintf(buf, sizeof buf, "\\u%04x", ch); +#else + _snprintf_s(buf, sizeof buf, "\\u%04x", ch); +#endif + out += buf; + } else if (static_cast(ch) == 0xe2 && + static_cast(value[i + 1]) == 0x80 && + static_cast(value[i + 2]) == 0xa8) { + out += "\\u2028"; + i += 2; + } else if (static_cast(ch) == 0xe2 && + static_cast(value[i + 1]) == 0x80 && + static_cast(value[i + 2]) == 0xa9) { + out += "\\u2029"; + i += 2; + } else { + out += ch; + } + } + out += '"'; +} + +static void dump(const Json::array &values, string &out) { + bool first = true; + out += "["; + for (const auto &value : values) { + if (!first) + out += ", "; + value.dump(out); + first = false; + } + out += "]"; +} + +static void dump(const Json::object &values, string &out) { + bool first = true; + out += "{"; + for (const auto &kv : values) { + if (!first) + out += ", "; + dump(kv.first, out); + out += ": "; + kv.second.dump(out); + first = false; + } + out += "}"; +} + +void Json::dump(string &out) const { + m_ptr->dump(out); +} + +/* * * * * * * * * * * * * * * * * * * * + * Value wrappers + */ + +template +class Value : public JsonValue { +protected: + // Constructors + explicit Value(const T &value) : m_value(value) { + } + explicit Value(T &&value) : m_value(move(value)) { + } + + // Get type tag + Json::Type type() const override { + return tag; + } + + // Comparisons + bool equals(const JsonValue *other) const override { + return m_value == static_cast *>(other)->m_value; + } + bool less(const JsonValue *other) const override { + return m_value < static_cast *>(other)->m_value; + } + + const T m_value; + void dump(string &out) const override { + json11::dump(m_value, out); + } +}; + +class JsonDouble final : public Value { + double number_value() const override { + return m_value; + } + int int_value() const override { + return static_cast(m_value); + } + int64_t int64_value() const override { + return (int64_t)m_value; + } + uint64_t uint64_value() const override { + return (uint64_t)m_value; + } + bool equals(const JsonValue *other) const override { + return m_value == other->number_value(); + } + bool less(const JsonValue *other) const override { + return m_value < other->number_value(); + } + +public: + explicit JsonDouble(double value) : Value(value) { + } +}; + +class JsonInt final : public Value { + double number_value() const override { + return m_value; + } + int int_value() const override { + return m_value; + } + int64_t int64_value() const override { + return m_value; + } + uint64_t uint64_value() const override { + return m_value; + } + bool equals(const JsonValue *other) const override { + return m_value == other->number_value(); + } + bool less(const JsonValue *other) const override { + return m_value < other->number_value(); + } + +public: + explicit JsonInt(int value) : Value(value) { + } +}; + +class JsonInt64 final : public Value { + double number_value() const override { + return m_value; + } + int int_value() const override { + return (int)m_value; + } + int64_t int64_value() const override { + return m_value; + } + uint64_t uint64_value() const override { + return (uint64_t)m_value; + } + bool equals(const JsonValue *other) const override { + return m_value == other->number_value(); + } + bool less(const JsonValue *other) const override { + return m_value < other->number_value(); + } + +public: + explicit JsonInt64(int64_t value) : Value(value) { + } +}; + +class JsonUInt64 final : public Value { + double number_value() const override { + return m_value; + } + int int_value() const override { + return (int)m_value; + } + int64_t int64_value() const override { + return (int64_t)m_value; + } + uint64_t uint64_value() const override { + return m_value; + } + bool equals(const JsonValue *other) const override { + return m_value == other->number_value(); + } + bool less(const JsonValue *other) const override { + return m_value < other->number_value(); + } + +public: + explicit JsonUInt64(uint64_t value) : Value(value) { + } +}; + +class JsonBoolean final : public Value { + bool bool_value() const override { + return m_value; + } + +public: + explicit JsonBoolean(bool value) : Value(value) { + } +}; + +class JsonString final : public Value { + const string &string_value() const override { + return m_value; + } + +public: + explicit JsonString(const string &value) : Value(value) { + } + explicit JsonString(string &&value) : Value(move(value)) { + } +}; + +class JsonArray final : public Value { + const Json::array &array_items() const override { + return m_value; + } + const Json &operator[](size_t i) const override; + +public: + explicit JsonArray(const Json::array &value) : Value(value) { + } + explicit JsonArray(Json::array &&value) : Value(move(value)) { + } +}; + +class JsonObject final : public Value { + const Json::object &object_items() const override { + return m_value; + } + const Json &operator[](const string &key) const override; + +public: + explicit JsonObject(const Json::object &value) : Value(value) { + } + explicit JsonObject(Json::object &&value) : Value(move(value)) { + } +}; + +class JsonNull final : public Value { +public: + JsonNull() : Value(nullptr) { + } +}; + +/* * * * * * * * * * * * * * * * * * * * + * Static globals - static-init-safe + */ +struct Statics { + const std::shared_ptr null = make_shared(); + const std::shared_ptr t = make_shared(true); + const std::shared_ptr f = make_shared(false); + const string empty_string; + const vector empty_vector; + const map empty_map; + Statics() { + } +}; + +static const Statics &statics() { + static const Statics s{}; + return s; +} + +static const Json &static_null() { + // This has to be separate, not in Statics, because Json() accesses + // statics().null. + static const Json json_null; + return json_null; +} + +/* * * * * * * * * * * * * * * * * * * * + * Constructors + */ + +Json::Json() NOEXCEPT : m_ptr(statics().null) { +} +Json::Json(std::nullptr_t) NOEXCEPT : m_ptr(statics().null) { +} +Json::Json(double value) : m_ptr(make_shared(value)) { +} +Json::Json(int value) : m_ptr(make_shared(value)) { +} +Json::Json(int64_t value) : m_ptr(make_shared(value)) { +} +Json::Json(uint64_t value) : m_ptr(make_shared(value)) { +} +Json::Json(bool value) : m_ptr(value ? statics().t : statics().f) { +} +Json::Json(const string &value) : m_ptr(make_shared(value)) { +} +Json::Json(string &&value) : m_ptr(make_shared(move(value))) { +} +Json::Json(const char *value) : m_ptr(make_shared(value)) { +} +Json::Json(const Json::array &values) + : m_ptr(make_shared(values)) { +} +Json::Json(Json::array &&values) + : m_ptr(make_shared(move(values))) { +} +Json::Json(const Json::object &values) + : m_ptr(make_shared(values)) { +} +Json::Json(Json::object &&values) + : m_ptr(make_shared(move(values))) { +} + +/* * * * * * * * * * * * * * * * * * * * + * Accessors + */ + +Json::Type Json::type() const { + return m_ptr->type(); +} +double Json::number_value() const { + return m_ptr->number_value(); +} +int Json::int_value() const { + return m_ptr->int_value(); +} +int64_t Json::int64_value() const { + return m_ptr->int64_value(); +} +uint64_t Json::uint64_value() const { + return m_ptr->uint64_value(); +} +bool Json::bool_value() const { + return m_ptr->bool_value(); +} +const string &Json::string_value() const { + return m_ptr->string_value(); +} +const vector &Json::array_items() const { + return m_ptr->array_items(); +} +const map &Json::object_items() const { + return m_ptr->object_items(); +} +const Json &Json::operator[](size_t i) const { + return (*m_ptr)[i]; +} +const Json &Json::operator[](const string &key) const { + return (*m_ptr)[key]; +} + +double JsonValue::number_value() const { + return 0; +} +int JsonValue::int_value() const { + return 0; +} +int64_t JsonValue::int64_value() const { + return 0; +} +uint64_t JsonValue::uint64_value() const { + return 0; +} +bool JsonValue::bool_value() const { + return false; +} +const string &JsonValue::string_value() const { + return statics().empty_string; +} +const vector &JsonValue::array_items() const { + return statics().empty_vector; +} +const map &JsonValue::object_items() const { + return statics().empty_map; +} +const Json &JsonValue::operator[](size_t) const { + return static_null(); +} +const Json &JsonValue::operator[](const string &) const { + return static_null(); +} + +const Json &JsonObject::operator[](const string &key) const { + auto iter = m_value.find(key); + return (iter == m_value.end()) ? static_null() : iter->second; +} +const Json &JsonArray::operator[](size_t i) const { + if (i >= m_value.size()) + return static_null(); + else + return m_value[i]; +} + +/* * * * * * * * * * * * * * * * * * * * + * Comparison + */ + +bool Json::operator==(const Json &other) const { + if (m_ptr->type() != other.m_ptr->type()) + return false; + + return m_ptr->equals(other.m_ptr.get()); +} + +bool Json::operator<(const Json &other) const { + if (m_ptr->type() != other.m_ptr->type()) + return m_ptr->type() < other.m_ptr->type(); + + return m_ptr->less(other.m_ptr.get()); +} + +/* * * * * * * * * * * * * * * * * * * * + * Parsing + */ + +/* esc(c) + * + * Format char c suitable for printing in an error message. + */ +static inline string esc(char c) { + char buf[12]; + if (static_cast(c) >= 0x20 && static_cast(c) <= 0x7f) { +//PMO +#ifndef _MSC_VER + snprintf(buf, sizeof buf, "'%c' (%d)", c, c); +#else + _snprintf_s(buf, sizeof buf, "'%c' (%d)", c, c); +#endif + } else { +//PMO +#ifndef _MSC_VER + snprintf(buf, sizeof buf, "(%d)", c); +#else + _snprintf_s(buf, sizeof buf, "(%d)", c); +#endif + } + return string(buf); +} + +static inline bool in_range(long x, long lower, long upper) { + return (x >= lower && x <= upper); +} + +/* JsonParser + * + * Object that tracks all state of an in-progress parse. + */ +struct JsonParser { + + /* State + */ + const string &str; + size_t i; + string &err; + bool failed; + const JsonParse strategy; + + /* fail(msg, err_ret = Json()) + * + * Mark this parse as failed. + */ + Json fail(string &&msg) { + return fail(move(msg), Json()); + } + + template + T fail(string &&msg, const T err_ret) { + if (!failed) + err = std::move(msg); + failed = true; + return err_ret; + } + + /* consume_whitespace() + * + * Advance until the current character is non-whitespace. + */ + void consume_whitespace() { + while (str[i] == ' ' || str[i] == '\r' || str[i] == '\n' || + str[i] == '\t') + i++; + } + + /* consume_comment() + * + * Advance comments (c-style inline and multiline). + */ + bool consume_comment() { + bool comment_found = false; + if (str[i] == '/') { + i++; + if (i == str.size()) + return fail("unexpected end of input inside comment", 0); + if (str[i] == '/') { // inline comment + i++; + if (i == str.size()) + return fail("unexpected end of input inside inline comment", 0); + // advance until next line + while (str[i] != '\n') { + i++; + if (i == str.size()) + return fail("unexpected end of input inside inline comment", + 0); + } + comment_found = true; + } else if (str[i] == '*') { // multiline comment + i++; + if (i > str.size() - 2) + return fail("unexpected end of input inside multi-line comment", + 0); + // advance until closing tokens + while (!(str[i] == '*' && str[i + 1] == '/')) { + i++; + if (i > str.size() - 2) + return fail( + "unexpected end of input inside multi-line comment", 0); + } + i += 2; + if (i == str.size()) + return fail("unexpected end of input inside multi-line comment", + 0); + comment_found = true; + } else + return fail("malformed comment", 0); + } + return comment_found; + } + + /* consume_garbage() + * + * Advance until the current character is non-whitespace and non-comment. + */ + void consume_garbage() { + consume_whitespace(); + if (strategy == JsonParse::COMMENTS) { + bool comment_found = false; + do { + comment_found = consume_comment(); + consume_whitespace(); + } while (comment_found); + } + } + + /* get_next_token() + * + * Return the next non-whitespace character. If the end of the input is + * reached, + * flag an error and return 0. + */ + char get_next_token() { + consume_garbage(); + if (i == str.size()) + return fail("unexpected end of input", 0); + + return str[i++]; + } + + /* encode_utf8(pt, out) + * + * Encode pt as UTF-8 and add it to out. + */ + void encode_utf8(long pt, string &out) { + if (pt < 0) + return; + + if (pt < 0x80) { + out += static_cast(pt); + } else if (pt < 0x800) { + out += static_cast((pt >> 6) | 0xC0); + out += static_cast((pt & 0x3F) | 0x80); + } else if (pt < 0x10000) { + out += static_cast((pt >> 12) | 0xE0); + out += static_cast(((pt >> 6) & 0x3F) | 0x80); + out += static_cast((pt & 0x3F) | 0x80); + } else { + out += static_cast((pt >> 18) | 0xF0); + out += static_cast(((pt >> 12) & 0x3F) | 0x80); + out += static_cast(((pt >> 6) & 0x3F) | 0x80); + out += static_cast((pt & 0x3F) | 0x80); + } + } + + /* parse_string() + * + * Parse a string, starting at the current position. + */ + string parse_string() { + string out; + long last_escaped_codepoint = -1; + while (true) { + if (i == str.size()) + return fail("unexpected end of input in string", ""); + + char ch = str[i++]; + + if (ch == '"') { + encode_utf8(last_escaped_codepoint, out); + return out; + } + + if (in_range(ch, 0, 0x1f)) + return fail("unescaped " + esc(ch) + " in string", ""); + + // The usual case: non-escaped characters + if (ch != '\\') { + encode_utf8(last_escaped_codepoint, out); + last_escaped_codepoint = -1; + out += ch; + continue; + } + + // Handle escapes + if (i == str.size()) + return fail("unexpected end of input in string", ""); + + ch = str[i++]; + + if (ch == 'u') { + // Extract 4-byte escape sequence + string esc = str.substr(i, 4); + // Explicitly check length of the substring. The following loop + // relies on std::string returning the terminating NUL when + // accessing str[length]. Checking here reduces brittleness. + if (esc.length() < 4) { + return fail("bad \\u escape: " + esc, ""); + } + for (int j = 0; j < 4; j++) { + if (!in_range(esc[j], 'a', 'f') && !in_range(esc[j], 'A', 'F') && + !in_range(esc[j], '0', '9')) + return fail("bad \\u escape: " + esc, ""); + } + + long codepoint = strtol(esc.data(), nullptr, 16); + + // JSON specifies that characters outside the BMP shall be encoded + // as a pair + // of 4-hex-digit \u escapes encoding their surrogate pair + // components. Check + // whether we're in the middle of such a beast: the previous + // codepoint was an + // escaped lead (high) surrogate, and this is a trail (low) + // surrogate. + if (in_range(last_escaped_codepoint, 0xD800, 0xDBFF) && + in_range(codepoint, 0xDC00, 0xDFFF)) { + // Reassemble the two surrogate pairs into one astral-plane + // character, per + // the UTF-16 algorithm. + encode_utf8((((last_escaped_codepoint - 0xD800) << 10) | + (codepoint - 0xDC00)) + + 0x10000, + out); + last_escaped_codepoint = -1; + } else { + encode_utf8(last_escaped_codepoint, out); + last_escaped_codepoint = codepoint; + } + + i += 4; + continue; + } + + encode_utf8(last_escaped_codepoint, out); + last_escaped_codepoint = -1; + + if (ch == 'b') { + out += '\b'; + } else if (ch == 'f') { + out += '\f'; + } else if (ch == 'n') { + out += '\n'; + } else if (ch == 'r') { + out += '\r'; + } else if (ch == 't') { + out += '\t'; + } else if (ch == '"' || ch == '\\' || ch == '/') { + out += ch; + } else { + return fail("invalid escape character " + esc(ch), ""); + } + } + } + + /* parse_number() + * + * Parse a double. + */ + Json parse_number() { + size_t start_pos = i; + + if (str[i] == '-') + i++; + + // Integer part + if (str[i] == '0') { + i++; + if (in_range(str[i], '0', '9')) + return fail("leading 0s not permitted in numbers"); + } else if (in_range(str[i], '1', '9')) { + i++; + while (in_range(str[i], '0', '9')) + i++; + } else { + return fail("invalid " + esc(str[i]) + " in number"); + } + + if (str[i] != '.' && str[i] != 'e' && str[i] != 'E' && + (i - start_pos) <= + static_cast(std::numeric_limits::digits10)) { + return std::atoi(str.c_str() + start_pos); + } + + // Decimal part + if (str[i] == '.') { + i++; + if (!in_range(str[i], '0', '9')) + return fail("at least one digit required in fractional part"); + + while (in_range(str[i], '0', '9')) + i++; + } + + // Exponent part + if (str[i] == 'e' || str[i] == 'E') { + i++; + + if (str[i] == '+' || str[i] == '-') + i++; + + if (!in_range(str[i], '0', '9')) + return fail("at least one digit required in exponent"); + + while (in_range(str[i], '0', '9')) + i++; + } + + return std::strtod(str.c_str() + start_pos, nullptr); + } + + /* expect(str, res) + * + * Expect that 'str' starts at the character that was just read. If it + * does, advance + * the input and return res. If not, flag an error. + */ + Json expect(const string &expected, Json res) { + assert(i != 0); + i--; + if (str.compare(i, expected.length(), expected) == 0) { + i += expected.length(); + return res; + } else { + return fail("parse error: expected " + expected + ", got " + + str.substr(i, expected.length())); + } + } + + /* parse_json() + * + * Parse a JSON object. + */ + Json parse_json(int depth) { + if (depth > max_depth) { + return fail("exceeded maximum nesting depth"); + } + + char ch = get_next_token(); + if (failed) + return Json(); + + if (ch == '-' || (ch >= '0' && ch <= '9')) { + i--; + return parse_number(); + } + + if (ch == 't') + return expect("true", true); + + if (ch == 'f') + return expect("false", false); + + if (ch == 'n') + return expect("null", Json()); + + if (ch == '"') + return parse_string(); + + if (ch == '{') { + map data; + ch = get_next_token(); + if (ch == '}') + return data; + + while (1) { + if (ch != '"') + return fail("expected '\"' in object, got " + esc(ch)); + + string key = parse_string(); + if (failed) + return Json(); + + ch = get_next_token(); + if (ch != ':') + return fail("expected ':' in object, got " + esc(ch)); + + data[std::move(key)] = parse_json(depth + 1); + if (failed) + return Json(); + + ch = get_next_token(); + if (ch == '}') + break; + if (ch != ',') + return fail("expected ',' in object, got " + esc(ch)); + + ch = get_next_token(); + } + return data; + } + + if (ch == '[') { + vector data; + ch = get_next_token(); + if (ch == ']') + return data; + + while (1) { + i--; + data.push_back(parse_json(depth + 1)); + if (failed) + return Json(); + + ch = get_next_token(); + if (ch == ']') + break; + if (ch != ',') + return fail("expected ',' in list, got " + esc(ch)); + + ch = get_next_token(); + (void)ch; + } + return data; + } + + return fail("expected value, got " + esc(ch)); + } +}; + +Json Json::parse(const string &in, string &err, JsonParse strategy) { + JsonParser parser{in, 0, err, false, strategy}; + Json result = parser.parse_json(0); + + // Check for any trailing garbage + parser.consume_garbage(); + if (parser.i != in.size()) + return parser.fail("unexpected trailing " + esc(in[parser.i])); + + return result; +} + +// Documented in json11.hpp +vector Json::parse_multi(const string &in, string &err, + JsonParse strategy) { + JsonParser parser{in, 0, err, false, strategy}; + + vector json_vec; + while (parser.i != in.size() && !parser.failed) { + json_vec.push_back(parser.parse_json(0)); + // Check for another object + parser.consume_garbage(); + } + return json_vec; +} + +/* * * * * * * * * * * * * * * * * * * * + * Shape-checking + */ + +bool Json::has_shape(const shape &types, string &err) const { + if (!is_object()) { + err = "expected JSON object, got " + dump(); + return false; + } + + for (auto &item : types) { + if ((*this)[item.first].type() != item.second) { + err = "bad type for " + item.first + " in " + dump(); + return false; + } + } + + return true; +} + +} // namespace json11 diff --git a/CUDA_VectorAdd/libwb/vendor/json11.hpp b/CUDA_VectorAdd/libwb/vendor/json11.hpp new file mode 100644 index 0000000..9e0f0d9 --- /dev/null +++ b/CUDA_VectorAdd/libwb/vendor/json11.hpp @@ -0,0 +1,300 @@ +/* json11 + * + * json11 is a tiny JSON library for C++11, providing JSON parsing and + * serialization. + * + * The core object provided by the library is json11::Json. A Json object + * represents any JSON + * value: null, bool, number (int or double), string (std::string), array + * (std::vector), or + * object (std::map). + * + * Json objects act like values: they can be assigned, copied, moved, + * compared for equality or + * order, etc. There are also helper methods Json::dump, to serialize a + * Json to a string, and + * Json::parse (static) to parse a std::string as a Json object. + * + * Internally, the various types of Json object are represented by the + * JsonValue class + * hierarchy. + * + * A note on numbers - JSON specifies the syntax of number formatting but + * not its semantics, + * so some JSON implementations distinguish between integers and + * floating-point numbers, while + * some don't. In json11, we choose the latter. Because some JSON + * implementations (namely + * Javascript itself) treat all numbers as the same type, distinguishing + * the two leads + * to JSON that will be *silently* changed by a round-trip through those + * implementations. + * Dangerous! To avoid that risk, json11 stores all numbers as double + * internally, but also + * provides integer helpers. + * + * Fortunately, double-precision IEEE754 ('double') can precisely store any + * integer in the + * range +/-2^53, which includes every 'int' on most systems. (Timestamps + * often use int64 + * or long long to avoid the Y2038K problem; a double storing microseconds + * since some epoch + * will be exact for +/- 275 years.) + */ + +/* Copyright (c) 2013 Dropbox, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy + * of this software and associated documentation files (the "Software"), to + * deal + * in the Software without restriction, including without limitation the + * rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN + * THE SOFTWARE. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +//PMO +#ifndef _MSC_VER +#define NOEXCEPT noexcept +#else +#define NOEXCEPT _NOEXCEPT +#endif + +namespace json11 { + +enum JsonParse { STANDARD, COMMENTS }; + +class JsonValue; + +class Json final { +public: + // Types + enum Type { + NUL, + NUMBER, + NUMBER64, + UNUMBER64, + BOOL, + STRING, + ARRAY, + OBJECT + }; + + // Array and object typedefs + typedef std::vector array; + typedef std::map object; + + // Constructors for the various types of JSON value. + //PMO + //Json() noexcept; // NUL + Json() NOEXCEPT; // NUL + //Json(std::nullptr_t) noexcept; // NUL + Json(std::nullptr_t) NOEXCEPT; // NUL + Json(double value); // NUMBER + Json(int value); // NUMBER + Json(int64_t value); // NUMBER64 + Json(uint64_t value); // UNUMBER64 + Json(bool value); // BOOL + Json(const std::string &value); // STRING + Json(std::string &&value); // STRING + Json(const char *value); // STRING + Json(const array &values); // ARRAY + Json(array &&values); // ARRAY + Json(const object &values); // OBJECT + Json(object &&values); // OBJECT + + // Implicit constructor: anything with a to_json() function. + template + Json(const T &t) : Json(t.to_json()) { + } + + // Implicit constructor: map-like objects (std::map, std::unordered_map, + // etc) + template < + class M, + typename std::enable_if< + std::is_constructible::value && + std::is_constructible::value, + int>::type = 0> + Json(const M &m) : Json(object(m.begin(), m.end())) { + } + + // Implicit constructor: vector-like objects (std::list, std::vector, + // std::set, etc) + template ::value, + int>::type = 0> + Json(const V &v) : Json(array(v.begin(), v.end())) { + } + + // This prevents Json(some_pointer) from accidentally producing a bool. + // Use + // Json(bool(some_pointer)) if that behavior is desired. + Json(void *) = delete; + + // Accessors + Type type() const; + + bool is_null() const { + return type() == NUL; + } + bool is_number() const { + return type() == NUMBER; + } + bool is_number64() const { + return type() == NUMBER64; + } + bool is_unumber64() const { + return type() == UNUMBER64; + } + bool is_bool() const { + return type() == BOOL; + } + bool is_string() const { + return type() == STRING; + } + bool is_array() const { + return type() == ARRAY; + } + bool is_object() const { + return type() == OBJECT; + } + + // Return the enclosed value if this is a number, 0 otherwise. Note that + // json11 does not + // distinguish between integer and non-integer numbers - number_value() + // and int_value() + // can both be applied to a NUMBER-typed object. + double number_value() const; + int int_value() const; + int64_t int64_value() const; + uint64_t uint64_value() const; + + // Return the enclosed value if this is a boolean, false otherwise. + bool bool_value() const; + // Return the enclosed string if this is a string, "" otherwise. + const std::string &string_value() const; + // Return the enclosed std::vector if this is an array, or an empty + // vector otherwise. + const array &array_items() const; + // Return the enclosed std::map if this is an object, or an empty map + // otherwise. + const object &object_items() const; + + // Return a reference to arr[i] if this is an array, Json() otherwise. + const Json &operator[](size_t i) const; + // Return a reference to obj[key] if this is an object, Json() otherwise. + const Json &operator[](const std::string &key) const; + + // Serialize. + void dump(std::string &out) const; + std::string dump() const { + std::string out; + dump(out); + return out; + } + + // Parse. If parse fails, return Json() and assign an error message to + // err. + static Json parse(const std::string &in, std::string &err, + JsonParse strategy = JsonParse::STANDARD); + static Json parse(const char *in, std::string &err, + JsonParse strategy = JsonParse::STANDARD) { + if (in) { + return parse(std::string(in), err, strategy); + } else { + err = "null input"; + return nullptr; + } + } + // Parse multiple objects, concatenated or separated by whitespace + static std::vector + parse_multi(const std::string &in, std::string &err, + JsonParse strategy = JsonParse::STANDARD); + + bool operator==(const Json &rhs) const; + bool operator<(const Json &rhs) const; + bool operator!=(const Json &rhs) const { + return !(*this == rhs); + } + bool operator<=(const Json &rhs) const { + return !(rhs < *this); + } + bool operator>(const Json &rhs) const { + return (rhs < *this); + } + bool operator>=(const Json &rhs) const { + return !(*this < rhs); + } + + /* has_shape(types, err) + * + * Return true if this is a JSON object and, for each item in types, has + * a field of + * the given type. If not, return false and set err to a descriptive + * message. + */ + typedef std::initializer_list> shape; + bool has_shape(const shape &types, std::string &err) const; + +private: + std::shared_ptr m_ptr; +}; + +// Internal class hierarchy - JsonValue objects are not exposed to users of +// this API. +class JsonValue { +protected: + friend class Json; + friend class JsonInt; + friend class JsonInt64; + friend class JsonUInt64; + friend class JsonDouble; + virtual Json::Type type() const = 0; + virtual bool equals(const JsonValue *other) const = 0; + virtual bool less(const JsonValue *other) const = 0; + virtual void dump(std::string &out) const = 0; + virtual double number_value() const; + virtual int int_value() const; + virtual int64_t int64_value() const; + virtual uint64_t uint64_value() const; + virtual bool bool_value() const; + virtual const std::string &string_value() const; + virtual const Json::array &array_items() const; + virtual const Json &operator[](size_t i) const; + virtual const Json::object &object_items() const; + virtual const Json &operator[](const std::string &key) const; + virtual ~JsonValue() { + } +}; + +} // namespace json11 diff --git a/CUDA_VectorAdd/libwb/wb.h b/CUDA_VectorAdd/libwb/wb.h new file mode 100644 index 0000000..8f41e23 --- /dev/null +++ b/CUDA_VectorAdd/libwb/wb.h @@ -0,0 +1,155 @@ + + +#ifndef __WB_H__ +#define __WB_H__ + +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ + +#include +#include +#include +#include + +#ifdef _MSC_VER + +// set minimal warning level +#pragma warning(push,0) +// some warnings still occur at this level +// if necessary, disable specific warnings not covered by previous pragma +#pragma warning(disable : 4244 4056 4305 4800 4267 4996 4756 4661 4385 4101) + +#define __func__ __FUNCTION__ +#ifndef _CRT_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_WARNINGS 1 +#endif /* _CRT_SECURE_NO_WARNINGS */ +#define _CRT_SECURE_NO_DEPRECATE 1 +#define _CRT_NONSTDC_NO_DEPRECATE 1 +#include +#include +#include +#define WB_USE_WINDOWS +#else /* _MSC_VER */ +#include +#include +#include +#include +#define WB_USE_UNIX +#ifdef __APPLE__ +#include +#define WB_USE_DARWIN +#else /* __APPLE__ */ +#define WB_USE_LINUX +#endif /* __APPLE__ */ +#endif /* _MSC_VER */ + +#define wbStmt(stmt) stmt + +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ + +#define wbLine __LINE__ +#define wbFile __FILE__ +#define wbFunction __func__ + +#define wbExit() \ + wbAssert(0); \ + exit(1) + +#ifdef WB_USE_COURSERA +#define wbLogger_printOnExit 1 +#else /* WB_USE_COURSERA */ +#define wbLogger_printOnLog 1 +#endif /* WB_USE_COURSERA */ + +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ + +#ifdef __cplusplus +#define EXTERN_C extern "C" +#define START_EXTERN_C EXTERN_C { +#define END_EXTERN_C } +#else +#define EXTERN_C +#define START_EXTERN_C +#define END_EXTERN_C +#endif /* __cplusplus */ + +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ + +#include +#define WB_USE_JSON11 1 + +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ + +#define LAZY_FILE_LOAD +extern char *solutionJSON; + +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ + +#ifdef WB_USE_OPENCL +#ifdef WB_USE_DARWIN +#include +#else /* WB_USE_DARWIN */ +#include +#endif /* WB_USE_DARWIN */ +#endif /* WB_USE_OPENCL */ + +#include "wbTypes.h" + +#include "wbAssert.h" +#include "wbMalloc.h" +#include "wbString.h" +#include "wbUtils.h" + +#include "wbArg.h" +#include "wbCUDA.h" +#include "wbCast.h" +#include "wbComparator.h" +#include "wbDirectory.h" +#include "wbExit.h" +#include "wbExport.h" +#include "wbFile.h" +#include "wbImage.h" +#include "wbImport.h" +#include "wbInit.h" +#include "wbLogger.h" +#include "wbMD5.h" +#include "wbMPI.h" +#include "wbSolution.h" +#include "wbSparse.h" +#include "wbThrust.h" +#include "wbTimer.h" +#include "wbPath.h" + +#include "wbDataset.h" + +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ + +#endif /* __WB_H__ */ diff --git a/CUDA_VectorAdd/libwb/wbArg.cpp b/CUDA_VectorAdd/libwb/wbArg.cpp new file mode 100644 index 0000000..2a5c736 --- /dev/null +++ b/CUDA_VectorAdd/libwb/wbArg.cpp @@ -0,0 +1,105 @@ + +#include "wb.h" + +EXTERN_C wbArg_t wbArg_new(int *argc, char ***argv) { + wbArg_t arg; + + wb_init(argc, argv); + + wbArg_setInputCount(arg, 0); + wbArg_setInputFiles(arg, NULL); + wbArg_setOutputFile(arg, NULL); + wbArg_setType(arg, NULL); + wbArg_setExpectedOutputFile(arg, NULL); + return arg; +} + +EXTERN_C void wbArg_delete(wbArg_t arg) { + if (wbArg_getInputCount(arg) > 0 && wbArg_getInputFiles(arg) != NULL) { + int ii; + for (ii = 0; ii < wbArg_getInputCount(arg); ii++) { + wbDelete(wbArg_getInputFile(arg, ii)); + } + wbDelete(wbArg_getInputFiles(arg)); + wbArg_setInputCount(arg, 0); + wbArg_setInputFiles(arg, NULL); + } + if (wbArg_getOutputFile(arg)) { + wbDelete(wbArg_getOutputFile(arg)); + wbArg_setOutputFile(arg, NULL); + } + if (wbArg_getExpectedOutputFile(arg)) { + wbDelete(wbArg_getExpectedOutputFile(arg)); + wbArg_setExpectedOutputFile(arg, NULL); + } + if (wbArg_getType(arg)) { + wbDelete(wbArg_getType(arg)); + wbArg_setType(arg, NULL); + } + return; +} + +static int getInputFileCount(char *arg) { + int count = 1; + while (*arg != '\0' && *arg != '-') { + if (*arg == ',') { + count++; + } + arg++; + } + return count; +} + +static char **parseInputFiles(char *arg, int *resCount) { + int count; + int ii = 0; + char **files; + char *token; + + count = getInputFileCount(arg); + + files = wbNewArray(char *, count); + + token = strtok(arg, ","); + while (token != NULL) { + files[ii++] = wbString_duplicate(token); + token = strtok(NULL, ","); + } + *resCount = ii; + return files; +} + +static char *parseString(char *arg) { + return wbString_duplicate(arg); +} + +EXTERN_C wbArg_t wbArg_read(int argc, char **argv) { + int ii; + wbArg_t arg; + + arg = wbArg_new(&argc, &argv); + for (ii = 0; ii < argc; ii++) { + if (wbString_startsWith(argv[ii], "-i")) { + int fileCount; + char **files; + + files = parseInputFiles(argv[ii + 1], &fileCount); + + wbArg_setInputCount(arg, fileCount); + wbArg_setInputFiles(arg, files); + } else if (wbString_startsWith(argv[ii], "-o")) { + char *file = parseString(argv[ii + 1]); + wbArg_setOutputFile(arg, file); + } else if (wbString_startsWith(argv[ii], "-e")) { + char *file = parseString(argv[ii + 1]); + wbArg_setExpectedOutputFile(arg, file); + } else if (wbString_startsWith(argv[ii], "-t")) { + char *type = parseString(argv[ii + 1]); + wbArg_setType(arg, type); + } else if (argv[ii][0] == '-') { + wbLog(ERROR, "Unexpected program option ", argv[ii]); + } + } + + return arg; +} diff --git a/CUDA_VectorAdd/libwb/wbArg.h b/CUDA_VectorAdd/libwb/wbArg.h new file mode 100644 index 0000000..c98bcf7 --- /dev/null +++ b/CUDA_VectorAdd/libwb/wbArg.h @@ -0,0 +1,33 @@ + + +#ifndef __WB_ARG_H__ +#define __WB_ARG_H__ + +struct st_wbArg_t { + int inputCount; + char **inputFiles; + char *outputFile; + char *expectedOutput; + char *type; +}; + +#define wbArg_getInputCount(wa) ((wa).inputCount) +#define wbArg_getInputFiles(wa) ((wa).inputFiles) +#define wbArg_getInputFile(wa, ii) (wbArg_getInputFiles(wa)[ii]) +#define wbArg_getOutputFile(wa) ((wa).outputFile) +#define wbArg_getExpectedOutputFile(wa) ((wa).expectedOutput) +#define wbArg_getType(wa) ((wa).type) + +#define wbArg_setInputCount(wa, val) (wbArg_getInputCount(wa) = val) +#define wbArg_setInputFiles(wa, val) (wbArg_getInputFiles(wa) = val) +#define wbArg_setInputFile(wa, ii, val) (wbArg_getInputFile(wa, ii) = val) +#define wbArg_setOutputFile(wa, val) (wbArg_getOutputFile(wa) = val) +#define wbArg_setExpectedOutputFile(wa, val) \ + (wbArg_getExpectedOutputFile(wa) = val) +#define wbArg_setType(wa, val) (wbArg_getType(wa) = val) + +EXTERN_C wbArg_t wbArg_new(int *argc, char ***argv); +EXTERN_C void wbArg_delete(wbArg_t arg); +EXTERN_C wbArg_t wbArg_read(int argc, char **argv); + +#endif /* __WB_ARG_H__ */ diff --git a/CUDA_VectorAdd/libwb/wbAssert.h b/CUDA_VectorAdd/libwb/wbAssert.h new file mode 100644 index 0000000..b8ed669 --- /dev/null +++ b/CUDA_VectorAdd/libwb/wbAssert.h @@ -0,0 +1,24 @@ + + +#ifndef __WB_ASSERT_H__ +#define __WB_ASSERT_H__ + +#include + +#ifdef WB_DEBUG +#define wbAssert(cond) assert(cond) +#define wbAssertMessage(msg, cond) \ + do { \ + if (!(cond)) { \ + wbPrint(msg); \ + wbAssert(cond); \ + } \ + } while (0) +#else /* WB_DEBUG */ +#define wbAssert(...) +#define wbAssertMessage(...) +#endif /* WB_DEBUG */ + +#define wbTodo(msg) wbAssertMessage(msg, false) + +#endif /* __WB_ASSERT_H__ */ diff --git a/CUDA_VectorAdd/libwb/wbCUDA.cpp b/CUDA_VectorAdd/libwb/wbCUDA.cpp new file mode 100644 index 0000000..cb26895 --- /dev/null +++ b/CUDA_VectorAdd/libwb/wbCUDA.cpp @@ -0,0 +1,25 @@ + +#include "wb.h" +#ifdef WB_USE_CUDA + +int _cudaMemoryListIdx = 0; + +size_t _cudaMallocSize = 0; + +wbCUDAMemory_t _cudaMemoryList[_cudaMemoryListSize]; + +char *wbRandom_list(size_t sz) { + size_t ii; + char *rands = wbNewArray(char, sz); + int *irands = (int *)rands; + for (ii = 0; ii < sz / sizeof(int); ii++) { + irands[ii] = rand(); + } + while (ii < sz) { + rands[ii] = (char)(rand() % 255); + ii++; + } + return rands; +} + +#endif /* WB_USE_CUDA */ diff --git a/CUDA_VectorAdd/libwb/wbCUDA.h b/CUDA_VectorAdd/libwb/wbCUDA.h new file mode 100644 index 0000000..658ff39 --- /dev/null +++ b/CUDA_VectorAdd/libwb/wbCUDA.h @@ -0,0 +1,77 @@ + +#ifndef __WB_CUDA_H__ +#define __WB_CUDA_H__ + +#ifdef WB_USE_CUDA +#ifdef __PGI +#define __GNUC__ 4 +#endif /* __PGI */ +#include +#include + +typedef struct st_wbCUDAMemory_t { + void *mem; + size_t sz; +} wbCUDAMemory_t; + +#define _cudaMemoryListSize 1024 + +extern size_t _cudaMallocSize; +extern wbCUDAMemory_t _cudaMemoryList[]; +extern int _cudaMemoryListIdx; + +char *wbRandom_list(size_t sz); + +static inline cudaError_t wbCUDAMalloc(void **devPtr, size_t sz) { + int idx = _cudaMemoryListIdx; + + cudaError_t err = cudaMalloc(devPtr, sz); + + if (idx == 0) { + srand(time(NULL)); + memset(_cudaMemoryList, 0, + sizeof(wbCUDAMemory_t) * _cudaMemoryListSize); + } + + if (err == cudaSuccess) { +#if 0 + char * rands = wbRandom_list(sz); + // can use curand here, but do not want to invoke a kernel + err = cudaMemcpy(*devPtr, rands, sz, cudaMemcpyHostToDevice); + wbFree(rands); +#else + err = cudaMemset(*devPtr, 0, sz); +#endif + } + + _cudaMallocSize += sz; + _cudaMemoryList[idx].mem = *devPtr; + _cudaMemoryList[idx].sz = sz; + _cudaMemoryListIdx++; + return err; +} + +static inline cudaError_t wbCUDAFree(void *mem) { + int idx = _cudaMemoryListIdx; + if (idx == 0) { + memset(_cudaMemoryList, 0, + sizeof(wbCUDAMemory_t) * _cudaMemoryListSize); + } + for (int ii = 0; ii < idx; ii++) { + if (_cudaMemoryList[ii].mem != NULL && + _cudaMemoryList[ii].mem == mem) { + cudaError_t err = cudaFree(mem); + _cudaMallocSize -= _cudaMemoryList[ii].sz; + _cudaMemoryList[ii].mem = NULL; + return err; + } + } + return cudaErrorMemoryAllocation; +} + +#define cudaMalloc(elem, err) wbCUDAMalloc((void **)elem, err) +#define cudaFree wbCUDAFree + +#endif /* WB_USE_CUDA */ + +#endif /* __WB_CUDA_H__ */ diff --git a/CUDA_VectorAdd/libwb/wbCast.h b/CUDA_VectorAdd/libwb/wbCast.h new file mode 100644 index 0000000..01e8387 --- /dev/null +++ b/CUDA_VectorAdd/libwb/wbCast.h @@ -0,0 +1,29 @@ + + +#ifndef __WB_CAST_H__ +#define __WB_CAST_H__ + +template +static inline void wbCast(X &x, const Y &y, size_t len) { + size_t ii; + + for (ii = 0; ii < len; ii++) { + x[ii] = (X)y[ii]; + } + + return; +} + +template +static inline X *wbCast(const Y &y, size_t len) { + size_t ii; + X *x = wbNewArray(X, len); + + for (ii = 0; ii < len; ii++) { + x[ii] = (X)y[ii]; + } + + return x; +} + +#endif /* __WB_CAST_H__ */ diff --git a/CUDA_VectorAdd/libwb/wbComparator.h b/CUDA_VectorAdd/libwb/wbComparator.h new file mode 100644 index 0000000..26fd0cb --- /dev/null +++ b/CUDA_VectorAdd/libwb/wbComparator.h @@ -0,0 +1,187 @@ + + +#ifndef __WB_COMPARATOR_H__ +#define __WB_COMPARATOR_H__ + +#include "wb.h" + +template +static inline T _abs(const T &a) { + return a < 0 ? -a : a; +} + +static inline wbBool _almostEqual(double A, double B, double eps) { + if (A == 0) { + return _abs(B) < eps; + } else if (B == 0) { + return _abs(A) < eps; + } else { +#if 0 + double d = max(_abs(A), _abs(B)); + double g = (_abs(A - B) / d); +#else + double g = _abs(A - B); +#endif + if (g <= eps) { + return wbTrue; + } else { + return wbFalse; + } + } +} + +static inline wbBool _almostEqual(float A, float B, float eps) { + if (A == 0) { + return _abs(B) < eps; + } else if (B == 0) { + return _abs(A) < eps; + } else { +#if 0 + float d = max(_abs(A), _abs(B)); + float g = (_abs(A - B) / d); +#else + float g = _abs(A - B); +#endif + if (g <= eps) { + return wbTrue; + } else { + return wbFalse; + } + } +} + +static inline wbBool _almostEqual(double A, double B) { + return _almostEqual(A, B, 0.2); +} + +static inline wbBool _almostEqual(float A, float B) { + return _almostEqual(A, B, 0.2f); +} + +static inline wbBool _almostEqual2sComplement(float A, float B, + int maxUlps) { + // Make sure maxUlps is non-negative and small enough that the + // default NAN won't compare as equal to anything. + + int aInt, bInt, intDiff; + + wbAssert(maxUlps > 0 && maxUlps < 4 * 1024 * 1024); + + int *tmp = reinterpret_cast(&A); + aInt = *tmp; + + // Make aInt lexicographically ordered as a twos-complement int + if (aInt < 0) { + aInt = 0x80000000 - aInt; + } + // Make bInt lexicographically ordered as a twos-complement int + tmp = reinterpret_cast(&B); + bInt = *tmp; + if (bInt < 0) { + bInt = 0x80000000 - bInt; + } + intDiff = _abs(aInt - bInt); + if (intDiff <= maxUlps) { + return wbTrue; + } + return wbFalse; +} + +static inline wbBool _almostEqual2sComplement(float A, float B) { + return _almostEqual2sComplement(A, B, 4); +} + +static inline wbBool _almostEqual2sComplement(double A, double B, + int maxUlps) { + // Make sure maxUlps is non-negative and small enough that the + // default NAN won't compare as equal to anything. + + int64_t aInt, bInt, intDiff; + + wbAssert(maxUlps > 0 && maxUlps < 4 * 1024 * 1024); + + int64_t *tmp = reinterpret_cast(&A); + aInt = *tmp; + + // Make aInt lexicographically ordered as a twos-complement int + if (aInt < 0) { + aInt = 0x80000000 - aInt; + } + // Make bInt lexicographically ordered as a twos-complement int + tmp = reinterpret_cast(&B); + bInt = *tmp; + if (bInt < 0) { + bInt = 0x80000000 - bInt; + } + intDiff = _abs(aInt - bInt); + if (intDiff <= maxUlps) { + return wbTrue; + } + return wbFalse; +} + +static inline wbBool _almostEqual2sComplement(double A, double B) { + return _almostEqual2sComplement(A, B, 4); +} + +template +static inline int wbCompare(const T &a, const T &b) { + if (a == b) { + return 0; + } else if (a < b) { + return -1; + } else { + return 1; + } +} + +template <> +inline int wbCompare(const double &a, const double &b) { + if (_almostEqual(a, b)) { + return 0; + } else if (a < b) { + return -1; + } else { + return 1; + } +} + +template <> +inline int wbCompare(const float &a, const float &b) { + if (_almostEqual(a, b)) { + return 0; + } else if (a < b) { + return -1; + } else { + return 1; + } +} + +template +static inline wbBool wbEqualQ(const T &a, const T &b) { + return wbCompare(a, b) == 0; +} + +template +static inline wbBool wbUnequalQ(const T &a, const T &b) { + return wbCompare(a, b) != 0; +} + +template +static inline wbBool wbEqualQ(const T *a, const T *b, size_t n) { + size_t ii; + + for (ii = 0; ii < n; ii++) { + if (wbUnequalQ(a[ii], b[ii])) { + return wbFalse; + } + } + return wbTrue; +} + +template +static inline wbBool wbUnequalQ(const T *a, const T *b, size_t n) { + return !wbEqualQ(a, b, n); +} + +#endif /* __WB_COMPARATOR_H__ */ diff --git a/CUDA_VectorAdd/libwb/wbDataset.cpp b/CUDA_VectorAdd/libwb/wbDataset.cpp new file mode 100644 index 0000000..a11f064 --- /dev/null +++ b/CUDA_VectorAdd/libwb/wbDataset.cpp @@ -0,0 +1,177 @@ +#include "wb.h" + +template +static inline T _min(const T &x, const T &y) { + return x < y ? x : y; +} + +template +static inline T _max(const T &x, const T &y) { + return x > y ? x : y; +} + +template +inline T lerp(const double &x, const T &start, const T &end) { + return (1 - x) * start + x * end; +} + +static inline void genRandom(void *trgt, wbType_t type, double minVal, + double maxVal) { + const int span = maxVal - minVal; + const int r = rand(); + const double rf = ((double)r) / ((double)RAND_MAX); + switch (type) { + case wbType_ascii: + *((char *)trgt) = (r % span) + minVal; // random printable character; + break; + case wbType_bit8: + *((char *)trgt) = lerp(rf, minVal, maxVal); + break; + case wbType_ubit8: + *((unsigned char *)trgt) = lerp(rf, minVal, maxVal); + break; + case wbType_integer: + *((int *)trgt) = lerp(rf, minVal, maxVal); + break; + case wbType_float: { + *((float *)trgt) = lerp(rf, minVal, maxVal); + break; + } + case wbType_double: { + *((double *)trgt) = lerp(rf, minVal, maxVal); + break; + } + case wbType_unknown: + wbAssert(false && "Invalid wbType_unknown"); + break; + } + return; +} + +static inline void *genRandomList(wbType_t type, size_t len, double minVal, + double maxVal) { + size_t ii; + void *data = wbNewArray(char, wbType_size(type) * len); + switch (type) { + case wbType_ascii: + case wbType_bit8: { + char *iter = (char *)data; + for (ii = 0; ii < len; ii++) { + genRandom(iter++, type, minVal, maxVal); + } + break; + } + case wbType_ubit8: { + unsigned char *iter = (unsigned char *)data; + for (ii = 0; ii < len; ii++) { + genRandom(iter++, type, minVal, maxVal); + } + break; + } + case wbType_integer: { + int *iter = (int *)data; + for (ii = 0; ii < len; ii++) { + genRandom(iter++, type, minVal, maxVal); + } + break; + } + case wbType_float: { + float *iter = (float *)data; + for (ii = 0; ii < len; ii++) { + genRandom(iter++, type, minVal, maxVal); + } + break; + } + case wbType_double: { + double *iter = (double *)data; + for (ii = 0; ii < len; ii++) { + genRandom(iter++, type, minVal, maxVal); + } + break; + } + case wbType_unknown: + wbAssert(false && "Invalid wbType_unknown"); + break; + } + return data; +} + +static void genRaw(const char *path, wbRaw_GenerateParams_t params) { + int rows = _max(1, params.rows); + int cols = _max(1, params.cols); + double minVal = params.minVal; + double maxVal = params.maxVal; + wbType_t type = params.type; + void *data = genRandomList(type, rows * cols, minVal, maxVal); + wbExport(path, wbExportKind_raw, data, rows, cols, type); + wbDelete(data); +} + +static void genCSV(const char *path, wbCSV_GenerateParams_t params) { + int rows = _max(1, params.rows); + int cols = _max(1, params.cols); + double minVal = params.minVal; + double maxVal = params.maxVal; + wbType_t type = params.type; + void *data = genRandomList(type, rows * cols, minVal, maxVal); + wbExport(path, wbExportKind_csv, data, rows, cols, type); + wbDelete(data); +} + +static void genTSV(const char *path, wbTSV_GenerateParams_t params) { + int rows = _max(1, params.rows); + int cols = _max(1, params.cols); + double minVal = params.minVal; + double maxVal = params.maxVal; + wbType_t type = params.type; + void *data = genRandomList(type, rows * cols, minVal, maxVal); + wbExport(path, wbExportKind_tsv, data, rows, cols, type); + wbDelete(data); +} + +static void genText(const char *path, wbText_GenerateParams_t params) { + int length = _max(1, params.length); + wbType_t type = wbType_ascii; + void *data = genRandomList(type, length, 32, 128); + wbExport(path, wbExportKind_text, data, length, 1, type); + wbDelete(data); +} + +static void genPPM(const char *path, wbPPM_GenerateParams_t params) { + int width = _max(1, params.width); + int height = _max(1, params.height); + int channels = _max(1, params.channels); + double minVal = params.minVal; + double maxVal = params.maxVal; + wbType_t type = wbType_float; + float *data = (float *)genRandomList(type, width * height * channels, + minVal, maxVal); + wbImage_t img = wbImage_new(width, height, channels, data); + wbExport(path, img); + wbImage_delete(img); +} + +EXTERN_C void wbDataset_generate(const char *path, wbExportKind_t kind, + wbGenerateParams_t params) { + wbDirectory_create(wbDirectory_name(path)); + + switch (kind) { + case wbExportKind_raw: + genRaw(path, params.raw); + break; + case wbExportKind_csv: + genCSV(path, params.csv); + break; + case wbExportKind_tsv: + genTSV(path, params.tsv); + break; + case wbExportKind_ppm: + genPPM(path, params.ppm); + break; + case wbExportKind_text: + genText(path, params.text); + break; + default: + wbAssert(false && "Invalid Export kind"); + } +} diff --git a/CUDA_VectorAdd/libwb/wbDataset.h b/CUDA_VectorAdd/libwb/wbDataset.h new file mode 100644 index 0000000..ce81c28 --- /dev/null +++ b/CUDA_VectorAdd/libwb/wbDataset.h @@ -0,0 +1,52 @@ +#ifndef __WB_DATASET_H__ +#define __WB_DATASET_H__ + +#include "wbImport.h" +#include "wbTypes.h" + +typedef struct { + int rows; + int cols; + wbType_t type; + double minVal; + double maxVal; +} wbCSV_GenerateParams_t; + +typedef struct { + int rows; + int cols; + wbType_t type; + double minVal; + double maxVal; +} wbTSV_GenerateParams_t; + +typedef struct { + int rows; + int cols; + double minVal; + double maxVal; + wbType_t type; +} wbRaw_GenerateParams_t; + +typedef struct { + int width; + int height; + int channels; + double minVal; + double maxVal; +} wbPPM_GenerateParams_t; + +typedef struct { int length; } wbText_GenerateParams_t; + +typedef union { + wbCSV_GenerateParams_t csv; + wbRaw_GenerateParams_t raw; + wbTSV_GenerateParams_t tsv; + wbPPM_GenerateParams_t ppm; + wbText_GenerateParams_t text; +} wbGenerateParams_t; + +EXTERN_C void wbDataset_generate(const char *path, wbExportKind_t kind, + wbGenerateParams_t params); + +#endif /* __WB_DATASET_H__ */ diff --git a/CUDA_VectorAdd/libwb/wbDataset_test.cpp b/CUDA_VectorAdd/libwb/wbDataset_test.cpp new file mode 100644 index 0000000..4f08042 --- /dev/null +++ b/CUDA_VectorAdd/libwb/wbDataset_test.cpp @@ -0,0 +1,23 @@ + +#include "wb.h" +#include "vendor/catch.hpp" + +TEST_CASE("Can create Raw dataset", "[DataGenerator]") { + wbGenerateParams_t params; + params.raw.rows = 2; + params.raw.cols = 300; + params.raw.minVal = 0; + params.raw.maxVal = 30; + params.raw.type = wbType_integer; + wbDataset_generate( + wbPath_join(wbDirectory_current(), "test-dataset", "test.raw"), + wbExportKind_raw, params); +} + +TEST_CASE("Can create Text dataset", "[DataGenerator]") { + wbGenerateParams_t params; + params.text.length = 2000; + wbDataset_generate( + wbPath_join(wbDirectory_current(), "test-dataset", "test.txt"), + wbExportKind_text, params); +} diff --git a/CUDA_VectorAdd/libwb/wbDirectory.cpp b/CUDA_VectorAdd/libwb/wbDirectory.cpp new file mode 100644 index 0000000..10dc8c5 --- /dev/null +++ b/CUDA_VectorAdd/libwb/wbDirectory.cpp @@ -0,0 +1,88 @@ +#include "wb.h" + +#ifndef PATH_MAX +#ifdef FILENAME_MAX +#define PATH_MAX FILENAME_MAX +#else /* FILENAME_MAX */ +#define PATH_MAX 4096 +#endif /* FILENAME_MAX */ +#endif /* PATH_MAX */ + +#ifdef WB_USE_UNIX +const char wbDirectorySeperator = '/'; +static char *getcwd_(char *buf, int maxLen) { + return getcwd(buf, maxLen); +} +static void mkdir_(const char *dir) { + mkdir(dir, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); +} +#else /* WB_USE_LINUX */ +const char wbDirectorySeperator = '\\'; +static char *getcwd_(char *buf, int maxLen) { + return _getcwd(buf, maxLen); +} +static void mkdir_(const char *dir) { + _mkdir(dir); +} +#endif /* WB_USE_LINUX */ + +EXTERN_C const char * wbDirectory_create(const char *dir) { + char tmp[PATH_MAX]; + char *p = NULL; + size_t len; +//PMO +#ifndef _MSC_VER + snprintf(tmp, sizeof(tmp), "%s", dir); +#else + _snprintf_s(tmp, sizeof(tmp), "%s", dir); +#endif + len = strlen(tmp); + if (tmp[len - 1] == wbDirectorySeperator) { + tmp[len - 1] = 0; + } + for (p = tmp + 1; *p; p++) { + if (*p == wbDirectorySeperator) { + *p = 0; + mkdir_(tmp); + *p = wbDirectorySeperator; + } + } + mkdir_(tmp); + return dir; +} + +EXTERN_C char *wbDirectory_name(const char *pth0) { + char *pth = wbString_duplicate(pth0); + char *p = strrchr(pth, wbDirectorySeperator); + if (p) { + p[0] = 0; + } + return pth; +} + +EXTERN_C char *wbDirectory_current() { + char *tmp = wbNewArray(char, PATH_MAX + 1); + if (getcwd_(tmp, PATH_MAX)) { + return tmp; + } + + wbDelete(tmp); + + int error = errno; + switch (error) { + case EACCES: + std::cerr + << "Cannot get current directory :: access denied. exiting..." + << std::endl; + exit(-1); + case ENOMEM: + std::cerr << "Cannot get current directory :: insufficient storage. " + "exiting..." + << std::endl; + exit(-1); + default: + std::cerr << "Cannot get current directory :: unrecognised error " + << error << std::endl; + exit(-1); + } +} \ No newline at end of file diff --git a/CUDA_VectorAdd/libwb/wbDirectory.h b/CUDA_VectorAdd/libwb/wbDirectory.h new file mode 100644 index 0000000..cb14f81 --- /dev/null +++ b/CUDA_VectorAdd/libwb/wbDirectory.h @@ -0,0 +1,9 @@ +#ifndef __WB_DIRECTORY__ +#define __WB_DIRECTORY__ + +extern const char wbDirectorySeperator; +EXTERN_C char *wbDirectory_name(const char *pth); +EXTERN_C const char * wbDirectory_create(const char *dir); +EXTERN_C char *wbDirectory_current(); + +#endif /* __WB_DIRECTORY__ */ diff --git a/CUDA_VectorAdd/libwb/wbExit.cpp b/CUDA_VectorAdd/libwb/wbExit.cpp new file mode 100644 index 0000000..a7edc3a --- /dev/null +++ b/CUDA_VectorAdd/libwb/wbExit.cpp @@ -0,0 +1,119 @@ + +#include "wb.h" + +enum { + wbMPI_timerTag = 2, + wbMPI_loggerTag = 4, + wbMPI_solutionExistsTag = 8, + wbMPI_solutionTag = 16 +}; + +void wb_atExit(void) { + using std::cout; + using std::endl; + +#ifdef WB_USE_CUDA + cudaDeviceSynchronize(); +#endif /* WB_USE_CUDA */ + + int nranks = rankCount(); + if (nranks > 1) { +#ifdef WB_USE_MPI + if (isMasterQ) { +#ifdef wbLogger_printOnExit + cout << "==$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$" << endl; + + cout << "{\n"; + cout << wbString_quote("timer") << ":"; + cout << "[\n"; + for (int ii = 0; ii < nranks; ii++) { + if (ii == 0) { + cout << wbTimer_toJSON(); + } else { + const char *msg = wbMPI_getStringFromRank(ii, wbMPI_timerTag); + if (msg != NULL && strlen(msg) != 0) { + cout << ",\n"; + cout << msg; + // free(msg); + } + } + } + cout << "]" << endl; // close timer + + cout << "," << endl; // start logger + cout << wbString_quote("logger") << ":"; + cout << "[\n"; + for (int ii = 0; ii < nranks; ii++) { + if (ii == 0) { + cout << wbLogger_toJSON(); + } else { + const char *msg = wbMPI_getStringFromRank(ii, wbMPI_loggerTag); + if (msg != NULL && strlen(msg) != 0) { + cout << ",\n"; + cout << msg; + // free(msg); + } + } + } + cout << "]" << endl; // close logger + + cout << "," << endl; // start solutionExists + cout << wbString_quote("cuda_memory") << ":" << _cudaMallocSize + << ",\n"; + + if (solutionJSON) { + cout << wbString_quote("solution_exists") << ": true,\n"; + cout << wbString_quote("solution") << ":" << solutionJSON << "\n"; + } else { + cout << wbString_quote("solution_exists") << ": false\n"; + } + cout << "}" << endl; // close json + + } else { + wbMPI_sendStringToMaster(wbTimer_toJSON().c_str(), wbMPI_timerTag); + wbMPI_sendStringToMaster(wbLogger_toJSON().c_str(), wbMPI_loggerTag); + } +#endif /* wbLogger_printOnExit */ + +#endif /* WB_USE_MPI */ + } else { +#ifdef wbLogger_printOnExit + cout << "==$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$" << endl; + + cout << "{\n" << wbString_quote("timer") << ":[" << wbTimer_toJSON() + << "],\n" << wbString_quote("logger") << ":[" << wbLogger_toJSON() + << "],\n"; + +#ifdef WB_USE_CUDA + cout << wbString_quote("cuda_memory") << ":" << _cudaMallocSize + << ",\n"; +#endif /* WB_USE_CUDA */ + + if (solutionJSON) { + cout << wbString_quote("solution_exists") << ": true,\n"; + cout << wbString_quote("solution") << ":" << solutionJSON << "\n"; + } else { + cout << wbString_quote("solution_exists") << ": false\n"; + } + cout << "}" << endl; +#endif /* wbLogger_printOnExit */ + } + + // wbTimer_delete(_timer); + // wbLogger_delete(_logger); + + _timer = NULL; + _logger = NULL; + +// wbFile_atExit(); + +#ifdef WB_USE_CUDA + cudaDeviceReset(); +#endif + + exit(0); + + // assert(0); + + return; +} diff --git a/CUDA_VectorAdd/libwb/wbExit.h b/CUDA_VectorAdd/libwb/wbExit.h new file mode 100644 index 0000000..4400108 --- /dev/null +++ b/CUDA_VectorAdd/libwb/wbExit.h @@ -0,0 +1,7 @@ + +#ifndef __WB_EXIT_H__ +#define __WB_EXIT_H__ + +void wb_atExit(void); + +#endif /* __WB_EXIT_H__ */ diff --git a/CUDA_VectorAdd/libwb/wbExport.cpp b/CUDA_VectorAdd/libwb/wbExport.cpp new file mode 100644 index 0000000..59b7a33 --- /dev/null +++ b/CUDA_VectorAdd/libwb/wbExport.cpp @@ -0,0 +1,510 @@ + +#include "wb.h" + +static inline void wbExportText_setFile(wbExportText_t text, + const char *path) { + if (text != NULL) { + if (wbExportText_getFile(text) != NULL) { + wbFile_delete(wbExportText_getFile(text)); + } + if (path != NULL) { + wbExportText_getFile(text) = wbFile_open(path, "w+"); + } else { + wbExportText_getFile(text) = NULL; + } + } + + return; +} + +static inline wbExportText_t wbExportText_new(void) { + wbExportText_t text; + + text = wbNew(struct st_wbExportText_t); + + wbExportText_getFile(text) = NULL; + wbExportText_setLength(text, -1); + + return text; +} + +static inline void wbExportText_delete(wbExportText_t text) { + if (text != NULL) { + wbExportText_setFile(text, NULL); + wbDelete(text); + } + return; +} + +static inline void wbExportText_write(wbExportText_t text, + const char *data, int length) { + int ii; + FILE *handle; + wbFile_t file; + + if (text == NULL || wbExportText_getFile(text) == NULL) { + return; + } + + file = wbExportText_getFile(text); + + handle = wbFile_getFileHandle(file); + + if (handle == NULL) { + return; + } + + for (ii = 0; ii < length; ii++) { + fprintf(handle, "%c", data[ii]); + } + + return; +} + +static inline void wbExportRaw_setFile(wbExportRaw_t raw, + const char *path) { + if (raw != NULL) { + if (wbExportRaw_getFile(raw) != NULL) { + wbFile_delete(wbExportRaw_getFile(raw)); + } + if (path != NULL) { + wbExportRaw_getFile(raw) = wbFile_open(path, "w+"); + } else { + wbExportRaw_getFile(raw) = NULL; + } + } + + return; +} + +static inline wbExportRaw_t wbExportRaw_new(void) { + wbExportRaw_t raw; + + raw = wbNew(struct st_wbExportRaw_t); + + wbExportRaw_getFile(raw) = NULL; + wbExportRaw_setRowCount(raw, -1); + wbExportRaw_setColumnCount(raw, -1); + + return raw; +} + +static inline void wbExportRaw_delete(wbExportRaw_t raw) { + if (raw != NULL) { + wbExportRaw_setFile(raw, NULL); + wbDelete(raw); + } + return; +} + +static inline void wbExportRaw_write(wbExportRaw_t raw, void *data, + int rows, int columns, + wbType_t type) { + int ii, jj; + FILE *handle; + wbFile_t file; + + if (raw == NULL || wbExportRaw_getFile(raw) == NULL) { + return; + } + + file = wbExportRaw_getFile(raw); + + handle = wbFile_getFileHandle(file); + + if (handle == NULL) { + return; + } + + if (columns == 1) { + fprintf(handle, "%d\n", rows); + } else { + fprintf(handle, "%d %d\n", rows, columns); + } + + for (ii = 0; ii < rows; ii++) { + for (jj = 0; jj < columns; jj++) { + if (type == wbType_integer) { + int elem = ((int *)data)[ii * columns + jj]; + fprintf(handle, "%d", elem); + } else if (type == wbType_ubit8) { + int elem = ((unsigned char *)data)[ii * columns + jj]; + fprintf(handle, "%d", elem); + } else { + wbReal_t elem = ((wbReal_t *)data)[ii * columns + jj]; + fprintf(handle, "%f", elem); + } + if (jj == columns - 1) { + fprintf(handle, "\n"); + } else { + fprintf(handle, " "); + } + } + } + + return; +} + +static inline void wbExportCSV_setFile(wbExportCSV_t csv, + const char *path) { + if (csv != NULL) { + if (wbExportCSV_getFile(csv) != NULL) { + wbFile_delete(wbExportCSV_getFile(csv)); + } + if (path != NULL) { + wbExportCSV_getFile(csv) = wbFile_open(path, "w+"); + } else { + wbExportCSV_getFile(csv) = NULL; + } + } + + return; +} + +static inline wbExportCSV_t wbExportCSV_new(void) { + wbExportCSV_t csv; + + csv = wbNew(struct st_wbExportCSV_t); + + wbExportCSV_getFile(csv) = NULL; + wbExportCSV_setColumnCount(csv, -1); + wbExportCSV_setRowCount(csv, -1); + wbExportCSV_setSeperator(csv, '\0'); + + return csv; +} + +static inline void wbExportCSV_delete(wbExportCSV_t csv) { + if (csv != NULL) { + wbExportCSV_setFile(csv, NULL); + wbDelete(csv); + } +} + +static inline void wbExportCSV_write(wbExportCSV_t csv, void *data, + int rows, int columns, char sep, + wbType_t type) { + int ii, jj; + wbFile_t file; + FILE *handle; + char seperator[2]; + + if (csv == NULL || wbExportCSV_getFile(csv) == NULL) { + return; + } + + file = wbExportCSV_getFile(csv); + + handle = wbFile_getFileHandle(file); + + if (handle == NULL) { + return; + } + + if (sep == '\0') { + seperator[0] = ','; + } else { + seperator[0] = sep; + } + seperator[1] = '\0'; + + for (ii = 0; ii < rows; ii++) { + for (jj = 0; jj < columns; jj++) { + if (type == wbType_integer) { + int elem = ((int *)data)[ii * columns + jj]; + fprintf(handle, "%d", elem); + } else if (type == wbType_ubit8) { + int elem = ((unsigned char *)data)[ii * columns + jj]; + fprintf(handle, "%d", elem); + } else { + wbReal_t elem = ((wbReal_t *)data)[ii * columns + jj]; + fprintf(handle, "%f", elem); + } + if (jj == columns - 1) { + fprintf(handle, "\n"); + } else { + fprintf(handle, "%s", seperator); + } + } + } + + return; +} + +static inline wbExport_t wbExport_open(const char *file, + wbExportKind_t kind) { + wbExport_t exprt; + + if (file == NULL) { + wbLog(ERROR, "Go NULL for file value."); + wbExit(); + } + + wbExport_setFile(exprt, NULL); + wbExport_setKind(exprt, kind); + + if (kind == wbExportKind_raw) { + wbExportRaw_t raw = wbExportRaw_new(); + wbExportRaw_setFile(raw, file); + wbExport_setRaw(exprt, raw); + } else if (kind == wbExportKind_text) { + wbExportText_t txt = wbExportText_new(); + wbExportText_setFile(txt, file); + wbExport_setText(exprt, txt); + } else if (kind == wbExportKind_tsv || kind == wbExportKind_csv) { + wbExportCSV_t csv = wbExportCSV_new(); + if (kind == wbExportKind_csv) { + wbExportCSV_setSeperator(csv, ','); + } else { + wbExportCSV_setSeperator(csv, '\t'); + } + wbExportCSV_setFile(csv, file); + wbExport_setCSV(exprt, csv); + } else if (kind == wbExportKind_ppm) { + wbExport_setFile(exprt, wbString_duplicate(file)); + } else { + wbLog(ERROR, "Invalid export type."); + wbExit(); + } + + return exprt; +} + +static inline wbExport_t wbExport_open(const char *file, + const char *type0) { + wbExport_t exprt; + wbExportKind_t kind; + char *type; + + type = wbString_toLower(type0); + + if (wbString_sameQ(type, "csv")) { + kind = wbExportKind_csv; + } else if (wbString_sameQ(type, "tsv")) { + kind = wbExportKind_tsv; + } else if (wbString_sameQ(type, "raw") || wbString_sameQ(type, "dat")) { + kind = wbExportKind_raw; + } else if (wbString_sameQ(type, "ppm") || wbString_sameQ(type, "pbm")) { + kind = wbExportKind_ppm; + } else if (wbString_sameQ(type, "txt") || wbString_sameQ(type, "text")) { + kind = wbExportKind_text; + } else { + wbLog(ERROR, "Invalid export type ", type0); + wbExit(); + } + + exprt = wbExport_open(file, kind); + + wbDelete(type); + + return exprt; +} + +static inline void wbExport_close(wbExport_t exprt) { + wbExportKind_t kind; + + kind = wbExport_getKind(exprt); + + if (wbExport_getFile(exprt)) { + wbDelete(wbExport_getFile(exprt)); + } + + if (kind == wbExportKind_tsv || kind == wbExportKind_csv) { + wbExportCSV_t csv = wbExport_getCSV(exprt); + wbExportCSV_delete(csv); + wbExport_setCSV(exprt, NULL); + } else if (kind == wbExportKind_raw) { + wbExportRaw_t raw = wbExport_getRaw(exprt); + wbExportRaw_delete(raw); + wbExport_setRaw(exprt, NULL); + } else if (kind == wbExportKind_text) { + wbExportText_t text = wbExport_getText(exprt); + wbExportText_delete(text); + wbExport_setText(exprt, NULL); + } else if (kind == wbExportKind_ppm) { + } else { + wbLog(ERROR, "Invalid export type."); + wbExit(); + } + return; +} + +static inline void wbExport_writeAsImage(wbExport_t exprt, wbImage_t img) { + wbAssert(wbExport_getKind(exprt) == wbExportKind_ppm); + + wbPPM_export(wbExport_getFile(exprt), img); + + return; +} + +static inline void wbExport_write(wbExport_t exprt, void *data, int rows, + int columns, char sep, wbType_t type) { + wbExportKind_t kind; + + kind = wbExport_getKind(exprt); + if (kind == wbExportKind_tsv || kind == wbExportKind_csv) { + wbExportCSV_t csv = wbExport_getCSV(exprt); + wbExportCSV_write(csv, data, rows, columns, sep, type); + } else if (kind == wbExportKind_raw) { + wbExportRaw_t raw = wbExport_getRaw(exprt); + wbExportRaw_write(raw, data, rows, columns, type); + } else if (kind == wbExportKind_text) { + wbExportText_t text = wbExport_getText(exprt); + if (columns == 0) { + columns = 1; + } + if (rows == 0) { + rows = 1; + } + wbExportText_write(text, (const char *)data, rows * columns); + } else { + wbLog(ERROR, "Invalid export type."); + wbExit(); + } + return; +} + +static inline void wbExport_write(wbExport_t exprt, void *data, int rows, + int columns, wbType_t type) { + wbExport_write(exprt, data, rows, columns, ',', type); +} + +static wbExportKind_t _parseExportExtension(const char *file) { + char *extension; + wbExportKind_t kind; + + extension = wbFile_extension(file); + + if (wbString_sameQ(extension, "csv")) { + kind = wbExportKind_csv; + } else if (wbString_sameQ(extension, "tsv")) { + kind = wbExportKind_tsv; + } else if (wbString_sameQ(extension, "raw") || + wbString_sameQ(extension, "dat")) { + kind = wbExportKind_raw; + } else if (wbString_sameQ(extension, "text") || + wbString_sameQ(extension, "txt")) { + kind = wbExportKind_text; + } else if (wbString_sameQ(extension, "ppm")) { + kind = wbExportKind_ppm; + } else { + kind = wbExportKind_unknown; + wbLog(ERROR, "File ", file, " does not have a compatible extension."); + } + + wbDelete(extension); + + return kind; +} + +static void wbExport(const char *file, void *data, int rows, int columns, + wbType_t type) { + wbExportKind_t kind; + wbExport_t exprt; + + if (file == NULL) { + return; + } + + kind = _parseExportExtension(file); + exprt = wbExport_open(file, kind); + + wbExport_write(exprt, data, rows, columns, type); + wbExport_close(exprt); +} + +void wbExport(const char *file, unsigned char *data, int rows) { + wbExport(file, data, rows, 1); + return; +} + +void wbExport(const char *file, int *data, int rows) { + wbExport(file, data, rows, 1); + return; +} + +void wbExport(const char *file, wbReal_t *data, int rows) { + wbExport(file, data, rows, 1); + return; +} + +void wbExport(const char *file, unsigned char *data, int rows, + int columns) { + wbExportKind_t kind; + wbExport_t exprt; + + if (file == NULL) { + return; + } + + kind = _parseExportExtension(file); + exprt = wbExport_open(file, kind); + + wbExport_write(exprt, data, rows, columns, wbType_ubit8); + wbExport_close(exprt); +} + +void wbExport(const char *file, int *data, int rows, int columns) { + wbExportKind_t kind; + wbExport_t exprt; + + if (file == NULL) { + return; + } + + kind = _parseExportExtension(file); + exprt = wbExport_open(file, kind); + + wbExport_write(exprt, data, rows, columns, wbType_integer); + wbExport_close(exprt); +} + +void wbExport(const char *file, wbReal_t *data, int rows, int columns) { + wbExportKind_t kind; + wbExport_t exprt; + + if (file == NULL) { + return; + } + + kind = _parseExportExtension(file); + exprt = wbExport_open(file, kind); + + wbExport_write(exprt, data, rows, columns, wbType_real); + wbExport_close(exprt); +} + +void wbExport(const char *file, wbExportKind_t kind, void *data, int rows, + int columns, wbType_t type) { + wbExport_t exprt; + + if (file == NULL) { + return; + } + + exprt = wbExport_open(file, kind); + + wbExport_write(exprt, data, rows, columns, type); + wbExport_close(exprt); +} + +void wbExport(const char *file, wbImage_t img) { + wbExportKind_t kind; + wbExport_t exprt; + + if (file == NULL) { + return; + } + + kind = _parseExportExtension(file); + exprt = wbExport_open(file, kind); + + wbAssert(kind == wbExportKind_ppm); + + wbExport_writeAsImage(exprt, img); + wbExport_close(exprt); +} + +void wbExport_text(const char *file, void *data, int length) { + wbExport(file, wbExportKind_text, data, 1, length, wbType_ascii); +} diff --git a/CUDA_VectorAdd/libwb/wbExport.h b/CUDA_VectorAdd/libwb/wbExport.h new file mode 100644 index 0000000..dd16b3f --- /dev/null +++ b/CUDA_VectorAdd/libwb/wbExport.h @@ -0,0 +1,106 @@ + + +#ifndef __WB_EXPORT_H__ +#define __WB_EXPORT_H__ + +#include "wb.h" +#include "wbFile.h" +#include "wbPPM.h" + +typedef enum en_wbExportKind_t { + wbExportKind_unknown = -1, + wbExportKind_raw = 0x1000, + wbExportKind_csv, + wbExportKind_tsv, + wbExportKind_ppm, + wbExportKind_text, +} wbExportKind_t; + +typedef struct st_wbExportText_t { + int length; + wbFile_t file; +} * wbExportText_t; + +#define wbExportText_getLength(txt) ((txt)->length) +#define wbExportText_getFile(txt) ((txt)->file) + +#define wbExportText_setLength(txt, val) \ + (wbExportText_getLength(txt) = val) + +typedef struct st_wbExportRaw_t { + int rows; + int columns; + wbFile_t file; +} * wbExportRaw_t; + +#define wbExportRaw_getColumnCount(raw) ((raw)->columns) +#define wbExportRaw_getRowCount(raw) ((raw)->rows) +#define wbExportRaw_getFile(raw) ((raw)->file) + +#define wbExportRaw_setRowCount(raw, val) \ + (wbExportRaw_getRowCount(raw) = val) +#define wbExportRaw_setColumnCount(raw, val) \ + (wbExportRaw_getColumnCount(raw) = val) + +typedef struct st_wbExportCSV_t { + int rows; + int columns; + wbFile_t file; + char seperator; +} * wbExportCSV_t; + +#define wbExportCSV_getRowCount(csv) ((csv)->rows) +#define wbExportCSV_getColumnCount(csv) ((csv)->columns) +#define wbExportCSV_getFile(csv) ((csv)->file) +#define wbExportCSV_getSeperator(csv) ((csv)->seperator) + +#define wbExportCSV_setRowCount(csv, val) \ + (wbExportCSV_getRowCount(csv) = val) +#define wbExportCSV_setColumnCount(csv, val) \ + (wbExportCSV_getColumnCount(csv) = val) +#define wbExportCSV_setSeperator(csv, val) \ + (wbExportCSV_getSeperator(csv) = val) + +typedef struct st_wbExport_t { + wbExportKind_t kind; + union { + wbExportRaw_t raw; + wbExportCSV_t csv; + wbImage_t img; + wbExportText_t text; + } container; + char *file; +} wbExport_t; + +#define wbExport_getKind(exprt) ((exprt).kind) +#define wbExport_getContainer(exprt) ((exprt).container) +#define wbExport_getRaw(exprt) (wbExport_getContainer(exprt).raw) +#define wbExport_getCSV(exprt) (wbExport_getContainer(exprt).csv) +#define wbExport_getImage(exprt) (wbExport_getContainer(exprt).img) +#define wbExport_getText(exprt) (wbExport_getContainer(exprt).text) +#define wbExport_getFile(exprt) ((exprt).file) + +#define wbExport_setKind(exprt, val) (wbExport_getKind(exprt) = val) +#define wbExport_setRaw(exprt, val) (wbExport_getRaw(exprt) = val) +#define wbExport_setCSV(exprt, val) (wbExport_getCSV(exprt) = val) +#define wbExport_setImage(exprt, val) (wbExport_getImage(exprt) = val) +#define wbExport_setText(exprt, val) (wbExport_getText(exprt) = val) +#define wbExport_setFile(exprt, val) (wbExport_getFile(exprt) = val) + +void wbExport(const char *file, int *data, int rows, int columns); +void wbExport(const char *file, int *data, int rows); +void wbExport(const char *file, unsigned char *data, int rows, + int columns); +void wbExport(const char *file, unsigned char *data, int rows); +void wbExport(const char *file, int *data, int rows, int columns); +void wbExport(const char *file, int *data, int rows); +void wbExport(const char *file, wbReal_t *data, int rows, int columns); +void wbExport(const char *file, wbReal_t *data, int rows); +void wbExport(const char *file, wbImage_t img); + +void wbExport(const char *file, wbExportKind_t kind, void *data, int rows, + int columns, wbType_t type); + +void wbExport_text(const char *file, void *data, int length); + +#endif /* __WB_EXPORT_H__ */ diff --git a/CUDA_VectorAdd/libwb/wbFile.cpp b/CUDA_VectorAdd/libwb/wbFile.cpp new file mode 100644 index 0000000..b3fdbe7 --- /dev/null +++ b/CUDA_VectorAdd/libwb/wbFile.cpp @@ -0,0 +1,353 @@ + + +#include "wb.h" + +#define wbFile_maxCount 256 + +static wbFile_t wbFile_handles[wbFile_maxCount]; + +static int wbFile_nextIndex(void) { + int ii; + for (ii = 0; ii < wbFile_maxCount; ii++) { + if (wbFile_handles[ii] == NULL) { + return ii; + } + } + wbLog(ERROR, "Ran out of file handles."); + wbExit(); + return -1; +} + +wbFile_t wbFile_new(void) { + int idx = wbFile_nextIndex(); + wbFile_t file = wbNew(struct st_wbFile_t); + + wbAssert(idx >= 0); + + wbFile_setIndex(file, idx); + wbFile_setFileName(file, NULL); + wbFile_setMode(file, NULL); + wbFile_setFileHandle(file, NULL); + wbFile_setData(file, NULL); + + wbFile_handles[idx] = file; + + return file; +} + +void wbFile_delete(wbFile_t file) { + if (file != NULL) { + int idx = wbFile_getIndex(file); + if (wbFile_getFileName(file) != NULL) { + wbDelete(wbFile_getFileName(file)); + } + if (wbFile_getMode(file) != NULL) { + wbDelete(wbFile_getMode(file)); + } + if (wbFile_getFileHandle(file) != NULL) { + fflush(wbFile_getFileHandle(file)); + fclose(wbFile_getFileHandle(file)); + } + if (idx >= 0) { + wbAssert(wbFile_handles[idx] == file); + wbFile_handles[idx] = NULL; + } + if (wbFile_getData(file) != NULL) { + wbDelete(wbFile_getData(file)); + } + wbDelete(file); + } +} + +void wbFile_init(void) { + int ii; + + for (ii = 0; ii < wbFile_maxCount; ii++) { + wbFile_handles[ii] = NULL; + } +} + +void wbFile_atExit(void) { + int ii; + + for (ii = 0; ii < wbFile_maxCount; ii++) { + if (wbFile_handles[ii] != NULL) { + wbFile_delete(wbFile_handles[ii]); + } + } +} + +int wbFile_count(void) { + int ii, count = 0; + + for (ii = 0; ii < wbFile_maxCount; ii++) { + if (wbFile_handles[ii] != NULL) { + count++; + } + } + return count; +} + +wbFile_t wbFile_open(const char *fileName, const char *mode) { + FILE *handle; + wbFile_t file; + + if (fileName == NULL) { + return NULL; + } + + handle = fopen(fileName, mode); + if (handle == NULL) { + wbLog(ERROR, "Failed to open ", file, " in mode ", mode); + return NULL; + } + + file = wbFile_new(); + wbFile_setFileName(file, wbString_duplicate(fileName)); + wbFile_setMode(file, wbString_duplicate(mode)); + wbFile_setFileHandle(file, handle); + + return file; +} + +wbFile_t wbFile_open(const char *fileName) { + return wbFile_open(fileName, "r"); +} + +void wbFile_close(wbFile_t file) { + wbFile_delete(file); +} + +char *wbFile_read(wbFile_t file, size_t size, size_t count) { + size_t res; + char *buffer; + size_t bufferLen; + FILE *handle; + + if (file == NULL) { + return NULL; + } +#ifndef LAZY_FILE_LOAD + if (wbFile_getData(file) != NULL) { + char *data = wbFile_getData(file) + wbFile_getDataOffset(file); + wbFile_setDataOffset(file, wbFile_getDataOffset(file) + size * count); + return data; + } +#endif /* LAZY_FILE_LOAD */ + + handle = wbFile_getFileHandle(file); + bufferLen = size * count + 1; + buffer = wbNewArray(char, bufferLen); + + res = fread(buffer, size, count, handle); + // make valid C string + buffer[size * res] = '\0'; + + return buffer; +} + +char *wbFile_read(wbFile_t file, size_t len) { + char *buffer = wbFile_read(file, sizeof(char), len); + return buffer; +} + +void wbFile_rewind(wbFile_t file) { + if (file == NULL) { + return; + } + + if (wbFile_getData(file) == NULL) { + FILE *handle; + handle = wbFile_getFileHandle(file); + wbAssert(handle != NULL); + rewind(handle); + } +#ifndef LAZY_FILE_LOAD + else { + wbFile_setDataOffset(file, 0); + } +#endif + + return; +} + +size_t wbFile_size(wbFile_t file) { + size_t len; + FILE *handle; + + if (file == NULL) { + return 0; + } +#ifndef LAZY_FILE_LOAD + if (wbFile_getData(file) != NULL) { + if (wbFile_getLength(file) == 0) { + wbFile_setLength(file, strlen(wbFile_getData(file))); + } + return wbFile_getLength(file); + } +#endif /* LAZY_FILE_LOAD */ + + handle = wbFile_getFileHandle(file); + + fseek(handle, 0, SEEK_END); + len = ftell(handle); + rewind(handle); + + return len; +} + +char *wbFile_read(wbFile_t file) { + size_t len; + + if (file == NULL) { + return NULL; + } + + len = wbFile_size(file); + + if (len == 0) { + return NULL; + } + + wbFile_setLength(file, len); + + return wbFile_read(file, len); +} + +#define MAX_CHARS_PER_LINE (1 << 17) + +static char buffer[MAX_CHARS_PER_LINE]; + +char *wbFile_readLine(wbFile_t file) { + if (file == NULL) { + return NULL; + } +#ifdef LAZY_FILE_LOAD + FILE *handle; + memset(buffer, 0, MAX_CHARS_PER_LINE); + + handle = wbFile_getFileHandle(file); + + if (fgets(buffer, MAX_CHARS_PER_LINE - 1, handle)) { + return buffer; + } else { + // wbLog(ERROR, "Was not able to read line from ", + // wbFile_getFileName(file)); + return NULL; + } +#else + size_t newOffset; + size_t lenToNewLine = 0; + const char *tmp; + + if (wbFile_getData(file) == NULL) { + wbFile_setData(file, wbFile_read(file)); + fclose(wbFile_getFileHandle(file)); + wbFile_setFileHandle(file, NULL); + wbFile_setDataOffset(file, 0); + wbFile_setLength(file, strlen(wbFile_getData(file))); + } + + memset(buffer, 0, MAX_CHARS_PER_LINE); + + if (wbFile_getDataOffset(file) >= wbFile_getLength(file)) { + return NULL; + } + + newOffset = wbFile_getDataOffset(file); + tmp = wbFile_getData(file) + wbFile_getDataOffset(file); + while (newOffset < wbFile_getLength(file) && *tmp != '\n') { + tmp++; + lenToNewLine++; + newOffset++; + } + + memcpy(buffer, wbFile_getData(file) + wbFile_getDataOffset(file), + lenToNewLine); + wbFile_setDataOffset(file, newOffset + 1); + + return buffer; +#endif +} + +void wbFile_write(wbFile_t file, const void *buffer, size_t size, + size_t count) { + size_t res; + FILE *handle; + + if (file == NULL) { + return; + } + + handle = wbFile_getFileHandle(file); + + res = fwrite(buffer, size, count, handle); + if (res != count) { + wbLog(ERROR, "Failed to write data to ", wbFile_getFileName(file)); + } + + return; +} + +void wbFile_write(wbFile_t file, const void *buffer, size_t len) { + wbFile_write(file, buffer, sizeof(char), len); + return; +} + +void wbFile_write(wbFile_t file, const char *buffer) { + size_t len; + + len = strlen(buffer); + wbFile_write(file, buffer, len); + + return; +} + +void wbFile_writeLine(wbFile_t file, const char *buffer0) { + string buffer = wbString(buffer0, "\n"); + wbFile_write(file, buffer.c_str()); +} + +void wbFile_write(wbFile_t file, string buffer) { + wbFile_write(file, buffer.c_str()); +} + +void wbFile_writeLine(wbFile_t file, string buffer0) { + string buffer = buffer0 + "\n"; + wbFile_write(file, buffer.c_str()); +} + +wbBool wbFile_existsQ(const char *path) { + if (path == NULL) { + return wbFalse; + } else { + FILE *file = fopen(path, "r"); + if (file != NULL) { + fclose(file); + return wbTrue; + } + return wbFalse; + } +} + +char *wbFile_extension(const char *file) { + char *extension; + char *extensionLower; + char *end; + size_t len; + + len = strlen(file); + end = (char *)&file[len - 1]; + while (*end != '.') { + end--; + } + if (*end == '.') { + end++; + } + + extension = wbString_duplicate(end); + extensionLower = wbString_toLower(extension); + wbDelete(extension); + + return extensionLower; +} diff --git a/CUDA_VectorAdd/libwb/wbFile.h b/CUDA_VectorAdd/libwb/wbFile.h new file mode 100644 index 0000000..ea6b0cb --- /dev/null +++ b/CUDA_VectorAdd/libwb/wbFile.h @@ -0,0 +1,56 @@ + + +#ifndef __WB_FILE_H__ +#define __WB_FILE_H__ + +struct st_wbFile_t { + int index; + char *file; + char *mode; + char *data; + FILE *handle; + size_t len; + size_t offset; +}; + +#define wbFile_getIndex(file) ((file)->index) +#define wbFile_getFileName(file) ((file)->file) +#define wbFile_getMode(file) ((file)->mode) +#define wbFile_getData(file) ((file)->data) +#define wbFile_getLength(file) ((file)->len) +#define wbFile_getDataOffset(file) ((file)->offset) +#define wbFile_getFileHandle(file) ((file)->handle) + +#define wbFile_setIndex(file, val) (wbFile_getIndex(file) = val) +#define wbFile_setFileName(file, val) (wbFile_getFileName(file) = val) +#define wbFile_setMode(file, val) (wbFile_getMode(file) = val) +#define wbFile_setData(file, val) (wbFile_getData(file) = val) +#define wbFile_setLength(file, val) (wbFile_getLength(file) = val) +#define wbFile_setDataOffset(file, val) (wbFile_getDataOffset(file) = val) +#define wbFile_setFileHandle(file, val) (wbFile_getFileHandle(file) = val) + +wbFile_t wbFile_new(void); +void wbFile_delete(wbFile_t file); +void wbFile_close(wbFile_t file); +void wbFile_init(void); +void wbFile_atExit(void); +int wbFile_count(void); +wbFile_t wbFile_open(const char *fileName, const char *mode); +wbFile_t wbFile_open(const char *fileName); +char *wbFile_read(wbFile_t file, size_t size, size_t count); +char *wbFile_read(wbFile_t file, size_t len); +void wbFile_rewind(wbFile_t file); +size_t wbFile_size(wbFile_t file); +char *wbFile_read(wbFile_t file); +char *wbFile_readLine(wbFile_t file); +void wbFile_write(wbFile_t file, const void *buffer, size_t size, + size_t count); +void wbFile_write(wbFile_t file, const void *buffer, size_t len); +void wbFile_write(wbFile_t file, const char *buffer); +void wbFile_writeLine(wbFile_t file, const char *buffer0); +void wbFile_write(wbFile_t file, string buffer); +void wbFile_writeLine(wbFile_t file, string buffer0); +wbBool wbFile_existsQ(const char *path); +char *wbFile_extension(const char *file); + +#endif /* __WB_FILE_H__ */ diff --git a/CUDA_VectorAdd/libwb/wbImage.cpp b/CUDA_VectorAdd/libwb/wbImage.cpp new file mode 100644 index 0000000..1d95928 --- /dev/null +++ b/CUDA_VectorAdd/libwb/wbImage.cpp @@ -0,0 +1,134 @@ + + +#include "wb.h" + +static inline float _min(float x, float y) { + return x < y ? x : y; +} + +static inline float _max(float x, float y) { + return x > y ? x : y; +} + +static inline float _clamp(float x, float start, float end) { + return _min(_max(x, start), end); +} + +wbImage_t wbImage_new(int width, int height, int channels, float *data) { + wbImage_t img; + + img = wbNew(struct st_wbImage_t); + + wbImage_setWidth(img, width); + wbImage_setHeight(img, height); + wbImage_setChannels(img, channels); + wbImage_setPitch(img, width * channels); + + wbImage_setData(img, data); + return img; +} + +wbImage_t wbImage_new(int width, int height, int channels) { + float *data = wbNewArray(float, width *height *channels); + return wbImage_new(width, height, channels, data); +} + +wbImage_t wbImage_new(int width, int height) { + return wbImage_new(width, height, wbImage_channels); +} + +void wbImage_delete(wbImage_t img) { + if (img != NULL) { + if (wbImage_getData(img) != NULL) { + wbDelete(wbImage_getData(img)); + } + wbDelete(img); + } +} + +static inline void wbImage_setPixel(wbImage_t img, int x, int y, int c, + float val) { + float *data = wbImage_getData(img); + int channels = wbImage_getChannels(img); + int pitch = wbImage_getPitch(img); + + data[y * pitch + x * channels + c] = val; + + return; +} + +static inline float wbImage_getPixel(wbImage_t img, int x, int y, int c) { + float *data = wbImage_getData(img); + int channels = wbImage_getChannels(img); + int pitch = wbImage_getPitch(img); + + return data[y * pitch + x * channels + c]; +} + +wbBool wbImage_sameQ(wbImage_t a, wbImage_t b, + wbImage_onSameFunction_t onUnSame) { + if (a == NULL || b == NULL) { + wbLog(ERROR, "Comparing null images."); + return wbFalse; + } else if (a == b) { + return wbTrue; + } else if (wbImage_getWidth(a) != wbImage_getWidth(b)) { + wbLog(ERROR, "Image widths do not match."); + return wbFalse; + } else if (wbImage_getHeight(a) != wbImage_getHeight(b)) { + wbLog(ERROR, "Image heights do not match."); + return wbFalse; + } else if (wbImage_getChannels(a) != wbImage_getChannels(b)) { + wbLog(ERROR, "Image channels do not match."); + return wbFalse; + } else { + float *aData, *bData; + int width, height, channels; + int ii, jj, kk; + + aData = wbImage_getData(a); + bData = wbImage_getData(b); + + wbAssert(aData != NULL); + wbAssert(bData != NULL); + + width = wbImage_getWidth(a); + height = wbImage_getHeight(a); + channels = wbImage_getChannels(a); + + for (ii = 0; ii < height; ii++) { + for (jj = 0; jj < width; jj++) { + for (kk = 0; kk < channels; kk++) { + float x, y; + if (channels <= 3) { + x = _clamp(*aData++, 0, 1); + y = _clamp(*bData++, 0, 1); + } else { + x = *aData++; + y = *bData++; + } + if (wbUnequalQ(x, y)) { + if (onUnSame != NULL) { + string str = wbString( + "Image pixels do not match at position ( row = ", + wbString(ii, ", col = ", jj, ", channel = ", kk, + ") expecting a value of "), + wbString(y, " but got a computed value of ", x)); + onUnSame(str); + } + return wbFalse; + } + } + } + } + return wbTrue; + } +} + +static void wbImage_onUnsameFunction(string str) { + wbLog(ERROR, str); +} + +wbBool wbImage_sameQ(wbImage_t a, wbImage_t b) { + return wbImage_sameQ(a, b, wbImage_onUnsameFunction); +} diff --git a/CUDA_VectorAdd/libwb/wbImage.h b/CUDA_VectorAdd/libwb/wbImage.h new file mode 100644 index 0000000..020eec5 --- /dev/null +++ b/CUDA_VectorAdd/libwb/wbImage.h @@ -0,0 +1,40 @@ + + +#ifndef __IMAGE_H__ +#define __IMAGE_H__ + +#include "wbTypes.h" + +struct st_wbImage_t { + int width; + int height; + int channels; + int pitch; + float *data; +}; + +#define wbImage_channels 3 + +#define wbImage_getWidth(img) ((img)->width) +#define wbImage_getHeight(img) ((img)->height) +#define wbImage_getChannels(img) ((img)->channels) +#define wbImage_getPitch(img) ((img)->pitch) +#define wbImage_getData(img) ((img)->data) + +#define wbImage_setWidth(img, val) (wbImage_getWidth(img) = val) +#define wbImage_setHeight(img, val) (wbImage_getHeight(img) = val) +#define wbImage_setChannels(img, val) (wbImage_getChannels(img) = val) +#define wbImage_setPitch(img, val) (wbImage_getPitch(img) = val) +#define wbImage_setData(img, val) (wbImage_getData(img) = val) + +typedef void (*wbImage_onSameFunction_t)(string str); + +wbImage_t wbImage_new(int width, int height, int channels, float *data); +wbImage_t wbImage_new(int width, int height, int channels); +wbImage_t wbImage_new(int width, int height); +void wbImage_delete(wbImage_t img); +wbBool wbImage_sameQ(wbImage_t a, wbImage_t b, + wbImage_onSameFunction_t onUnSame); +wbBool wbImage_sameQ(wbImage_t a, wbImage_t b); + +#endif /* __IMAGE_H__ */ diff --git a/CUDA_VectorAdd/libwb/wbImport.cpp b/CUDA_VectorAdd/libwb/wbImport.cpp new file mode 100644 index 0000000..fccc071 --- /dev/null +++ b/CUDA_VectorAdd/libwb/wbImport.cpp @@ -0,0 +1,711 @@ + + +#include "wb.h" + +static inline void wbImportCSV_setFile(wbImportCSV_t csv, + const char *path) { + if (csv != NULL) { + if (wbImportCSV_getFile(csv) != NULL) { + wbFile_delete(wbImportCSV_getFile(csv)); + } + if (path != NULL) { + wbImportCSV_getFile(csv) = wbFile_open(path, "r"); + } else { + wbImportCSV_getFile(csv) = NULL; + } + } + + return; +} + +static inline wbImportCSV_t wbImportCSV_new(void) { + wbImportCSV_t csv; + + csv = wbNew(struct st_wbImportCSV_t); + + wbImportCSV_setRowCount(csv, -1); + wbImportCSV_setColumnCount(csv, -1); + wbImportCSV_setData(csv, NULL); + wbImportCSV_getFile(csv) = NULL; + wbImportCSV_setSeperator(csv, '\0'); + + return csv; +} + +static inline void wbImportCSV_delete(wbImportCSV_t csv) { + if (csv != NULL) { + wbImportCSV_setFile(csv, NULL); + if (wbImportCSV_getData(csv)) { + wbDelete(wbImportCSV_getData(csv)); + } + wbDelete(csv); + } +} + +static inline wbImportCSV_t wbImportCSV_findDimensions(wbImportCSV_t csv, + int *resRows, + int *resColumns) { + int rows = 0, columns = -1; + char *line; + wbFile_t file; + char seperator[2]; + + if (csv == NULL) { + return NULL; + } + + if (wbImportCSV_getSeperator(csv) == '\0') { + seperator[0] = ','; + } else { + seperator[0] = wbImportCSV_getSeperator(csv); + } + seperator[1] = '\0'; + + file = wbImportCSV_getFile(csv); + + while ((line = wbFile_readLine(file)) != NULL) { + int currColumn = 0; + char *token = strtok(line, seperator); + while (token != NULL) { + token = strtok(NULL, seperator); + currColumn++; + } + rows++; + if (columns == -1) { + columns = currColumn; + } + if (columns != currColumn) { + wbLog(ERROR, "The csv file is not rectangular."); + } + wbAssert(columns == currColumn); + } + + wbFile_rewind(file); + + *resRows = rows; + *resColumns = columns; + + return csv; +} + +static inline int *csv_readAsInteger(wbFile_t file, char sep, int rows, + int columns) { + int ii = 0; + int *data; + char *line; + int var; + char seperator[2]; + + if (file == NULL) { + return NULL; + } + + data = wbNewArray(int, rows *columns); + + if (sep == '\0') { + seperator[0] = ','; + } else { + seperator[0] = sep; + } + seperator[1] = '\0'; + + // printf("cols = %d rows = %d\n", columns, rows); + if (columns == 1) { + while ((line = wbFile_readLine(file)) != NULL) { + sscanf(line, "%d", &var); + // printf("reading %d\n", var); + data[ii++] = var; + } + } else { + while ((line = wbFile_readLine(file)) != NULL) { + char *token = strtok(line, seperator); + while (token != NULL) { + sscanf(token, "%d", &var); + token = strtok(NULL, seperator); + data[ii++] = var; + } + } + } + + return data; +} + +static inline wbReal_t *csv_readAsReal(wbFile_t file, char sep, int rows, + int columns) { + int ii = 0; + wbReal_t *data; + char *line; + wbReal_t var; + char seperator[2]; + + if (file == NULL) { + return NULL; + } + + data = wbNewArray(wbReal_t, rows * columns); + + if (sep == '\0') { + seperator[0] = ','; + } else { + seperator[0] = sep; + } + seperator[1] = '\0'; + + if (columns == 1) { + while ((line = wbFile_readLine(file)) != NULL) { + sscanf(line, "%f", &var); + data[ii++] = var; + } + } else { + while ((line = wbFile_readLine(file)) != NULL) { + char *token = strtok(line, seperator); + while (token != NULL) { + sscanf(token, "%f", &var); + token = strtok(NULL, seperator); + data[ii++] = var; + } + } + } + + return data; +} + +static inline wbImportCSV_t wbImportCSV_read(wbImportCSV_t csv, + wbType_t type) { + void *data; + wbFile_t file; + char seperator; + int rows, columns; + + if (csv == NULL) { + return NULL; + } + + if (wbImportCSV_getRowCount(csv) == -1 || + wbImportCSV_getColumnCount(csv) == -1) { + if (wbImportCSV_findDimensions(csv, &rows, &columns) == NULL) { + wbLog(ERROR, "Failed to figure out csv dimensions."); + return NULL; + } + wbImportCSV_setRowCount(csv, rows); + wbImportCSV_setColumnCount(csv, columns); + } + + file = wbImportCSV_getFile(csv); + seperator = wbImportCSV_getSeperator(csv); + rows = wbImportCSV_getRowCount(csv); + columns = wbImportCSV_getColumnCount(csv); + + if (wbImportCSV_getData(csv) != NULL) { + wbDelete(wbImportCSV_getData(csv)); + wbImportCSV_setData(csv, NULL); + } + + if (type == wbType_integer) { + // printf("ReadXXXing as integer...\n"); + data = csv_readAsInteger(file, seperator, rows, columns); + } else { + data = csv_readAsReal(file, seperator, rows, columns); + } + + wbImportCSV_setData(csv, data); + + return csv; +} + +static inline wbImportCSV_t wbImportCSV_readAsInteger(wbImportCSV_t csv) { + return wbImportCSV_read(csv, wbType_integer); +} + +static inline wbImportCSV_t wbImportCSV_readAsReal(wbImportCSV_t csv) { + return wbImportCSV_read(csv, wbType_real); +} + +static inline void wbImportRaw_setFile(wbImportRaw_t raw, + const char *path) { + if (raw != NULL) { + if (wbImportRaw_getFile(raw) != NULL) { + wbFile_delete(wbImportRaw_getFile(raw)); + } + if (path != NULL) { + wbImportRaw_getFile(raw) = wbFile_open(path, "r"); + } else { + wbImportRaw_getFile(raw) = NULL; + } + } + + return; +} + +static inline wbImportRaw_t wbImportRaw_new(void) { + wbImportRaw_t raw; + + raw = wbNew(struct st_wbImportRaw_t); + + wbImportRaw_setRowCount(raw, -1); + wbImportRaw_setColumnCount(raw, -1); + wbImportRaw_setData(raw, NULL); + wbImportRaw_getFile(raw) = NULL; + + return raw; +} + +static inline void wbImportRaw_delete(wbImportRaw_t raw) { + if (raw != NULL) { + wbImportRaw_setFile(raw, NULL); + if (wbImportRaw_getData(raw)) { + wbDelete(wbImportRaw_getData(raw)); + } + wbDelete(raw); + } +} + +static inline wbBool lineHasSpace(const char *line) { + while (*line != '\0') { + if (*line == ' ') { + return wbTrue; + } + line++; + } + return wbFalse; +} + +static inline char *lineStrip(const char *line) { + char *sl = wbString_duplicate(line); + char *iter = sl; + size_t slen = strlen(line); + + iter += slen - 1; + while (*iter == '\0' || *iter == '\r' || *iter == '\t' || + *iter == '\n' || *iter == ' ') { + *iter-- = '\0'; + } + return sl; +} + +static inline wbBool wbImportRaw_findDimensions(wbImportRaw_t raw) { + if (raw != NULL) { + int rows; + int columns; + char *line; + wbFile_t file; + char *strippedLine; + + file = wbImportRaw_getFile(raw); + + wbFile_rewind(file); + + line = wbFile_readLine(file); + + if (line == NULL) { + return wbTrue; + } + + strippedLine = lineStrip(line); + + if (lineHasSpace(strippedLine)) { + sscanf(strippedLine, "%d %d", &rows, &columns); + } else { + columns = 1; + sscanf(strippedLine, "%d", &rows); + } + + wbImportRaw_setRowCount(raw, rows); + wbImportRaw_setColumnCount(raw, columns); + + wbDelete(strippedLine); + + return wbFalse; + } + + return wbTrue; +} + +static inline wbImportRaw_t wbImportRaw_read(wbImportRaw_t raw, + wbType_t type) { + void *data; + wbFile_t file; + char seperator; + int rows, columns; + + if (raw == NULL) { + return NULL; + } + + if (wbImportRaw_getRowCount(raw) == -1 || + wbImportRaw_getColumnCount(raw) == -1) { + if (wbImportRaw_findDimensions(raw)) { + wbLog(ERROR, "Failed to figure out raw dimensions."); + return NULL; + } + } + + file = wbImportRaw_getFile(raw); + seperator = ' '; + rows = wbImportRaw_getRowCount(raw); + columns = wbImportRaw_getColumnCount(raw); + + if (wbImportRaw_getData(raw) != NULL) { + wbDelete(wbImportRaw_getData(raw)); + wbImportRaw_setData(raw, NULL); + } + + if (type == wbType_integer) { + // printf("Rdin gas integer...\n"); + data = csv_readAsInteger(file, seperator, rows, columns); + } else { + data = csv_readAsReal(file, seperator, rows, columns); + } + + wbImportRaw_setData(raw, data); + + return raw; +} + +static inline wbImportRaw_t wbImportRaw_readAsInteger(wbImportRaw_t raw) { + return wbImportRaw_read(raw, wbType_integer); +} + +static inline wbImportRaw_t wbImportRaw_readAsReal(wbImportRaw_t raw) { + return wbImportRaw_read(raw, wbType_real); +} + +static inline wbImportText_t wbImportText_new(void) { + wbImportText_t text; + + text = wbNew(struct st_wbImportText_t); + + wbImportText_setLength(text, 0); + wbImportText_setData(text, NULL); + wbImportText_getFile(text) = NULL; + + return text; +} + +static inline void wbImportText_setFile(wbImportText_t text, + const char *path) { + if (text != NULL) { + if (wbImportText_getFile(text) != NULL) { + wbFile_delete(wbImportText_getFile(text)); + } + if (path != NULL) { + wbImportText_getFile(text) = wbFile_open(path, "r"); + } else { + wbImportText_getFile(text) = NULL; + } + } + + return; +} + +static inline void wbImportText_delete(wbImportText_t text) { + if (text != NULL) { + wbImportText_setFile(text, NULL); + if (wbImportText_getData(text)) { + wbDelete(wbImportText_getData(text)); + } + wbDelete(text); + } +} + +static inline wbImportText_t wbImportText_read(wbImportText_t text) { + char *data; + wbFile_t file; + int length; + + if (text == NULL) { + return NULL; + } + + file = wbImportText_getFile(text); + + if (wbImportText_getData(text) != NULL) { + wbDelete(wbImportText_getData(text)); + wbImportText_setData(text, NULL); + } + + length = wbFile_size(file); + data = wbFile_read(file, length); + + wbImportText_setData(text, data); + wbImportText_setLength(text, length); + + return text; +} + +static inline wbImport_t wbImport_open(const char *file, + wbImportKind_t kind) { + wbImport_t imp; + + if (file == NULL) { + wbLog(ERROR, "Go NULL for file value."); + wbExit(); + } + + if (!wbFile_existsQ(file)) { + wbLog(ERROR, "File ", file, " does not exist."); + wbExit(); + } + + wbImport_setKind(imp, kind); + + if (kind == wbImportKind_raw) { + wbImportRaw_t raw = wbImportRaw_new(); + wbImportRaw_setFile(raw, file); + wbImport_setRaw(imp, raw); + } else if (kind == wbImportKind_tsv || kind == wbImportKind_csv) { + wbImportCSV_t csv = wbImportCSV_new(); + if (kind == wbImportKind_csv) { + wbImportCSV_setSeperator(csv, ','); + } else { + wbImportCSV_setSeperator(csv, '\t'); + } + wbImportCSV_setFile(csv, file); + wbImport_setCSV(imp, csv); + } else if (kind == wbImportKind_text) { + wbImportText_t text = wbImportText_new(); + wbImportText_setFile(text, file); + wbImport_setText(imp, text); + } else if (kind == wbImportKind_ppm) { + wbImage_t img = wbPPM_import(file); + wbImport_setImage(imp, img); + } else { + wbLog(ERROR, "Invalid import type."); + wbExit(); + } + + return imp; +} + +static inline wbImport_t wbImport_open(const char *file, + const char *type0) { + wbImport_t imp; + wbImportKind_t kind; + char *type; + + type = wbString_toLower(type0); + + if (wbString_sameQ(type, "csv")) { + kind = wbImportKind_csv; + } else if (wbString_sameQ(type, "tsv")) { + kind = wbImportKind_tsv; + } else if (wbString_sameQ(type, "raw") || wbString_sameQ(type, "dat")) { + kind = wbImportKind_raw; + } else if (wbString_sameQ(type, "ppm")) { + kind = wbImportKind_ppm; + } else if (wbString_sameQ(type, "text") || wbString_sameQ(type, "txt")) { + kind = wbImportKind_text; + } else { + wbLog(ERROR, "Invalid import type ", type0); + wbExit(); + } + + imp = wbImport_open(file, kind); + + wbDelete(type); + + return imp; +} + +static inline void wbImport_close(wbImport_t imp) { + wbImportKind_t kind; + + kind = wbImport_getKind(imp); + if (kind == wbImportKind_tsv || kind == wbImportKind_csv) { + wbImportCSV_t csv = wbImport_getCSV(imp); + wbImportCSV_delete(csv); + wbImport_setCSV(imp, NULL); + } else if (kind == wbImportKind_raw) { + wbImportRaw_t raw = wbImport_getRaw(imp); + wbImportRaw_delete(raw); + wbImport_setRaw(imp, NULL); + } else if (kind == wbImportKind_text) { + wbImportText_t text = wbImport_getText(imp); + wbImportText_delete(text); + wbImport_setText(imp, NULL); + } else if (kind == wbImportKind_ppm) { + } else { + wbLog(ERROR, "Invalid import type."); + wbExit(); + } + return; +} + +static inline void *wbImport_read(wbImport_t imp, wbType_t type) { + void *data = NULL; + wbImportKind_t kind; + + kind = wbImport_getKind(imp); + if (kind == wbImportKind_tsv || kind == wbImportKind_csv) { + wbImportCSV_t csv = wbImport_getCSV(imp); + wbImportCSV_read(csv, type); + data = wbImportCSV_getData(csv); + } else if (kind == wbImportKind_raw) { + wbImportRaw_t raw = wbImport_getRaw(imp); + wbImportRaw_read(raw, type); + data = wbImportRaw_getData(raw); + } else if (wbImportKind_text == kind) { + wbImportText_t text = wbImport_getText(imp); + text = wbImportText_read(text); + data = wbImportText_getData(text); + + } else { + wbLog(ERROR, "Invalid import type."); + wbExit(); + } + return data; +} + +static inline int *wbImport_readAsInteger(wbImport_t imp) { + void *data = wbImport_read(imp, wbType_integer); + return (int *)data; +} + +static inline wbReal_t *wbImport_readAsReal(wbImport_t imp) { + void *data = wbImport_read(imp, wbType_real); + return (wbReal_t *)data; +} + +static inline wbChar_t *wbImport_readAsText(wbImport_t imp) { + void *data = wbImport_read(imp, wbType_ubit8); + return (wbChar_t *)data; +} + +static wbImportKind_t _parseImportExtension(const char *file) { + char *extension; + wbImportKind_t kind; + + extension = wbFile_extension(file); + + if (wbString_sameQ(extension, "csv")) { + kind = wbImportKind_csv; + } else if (wbString_sameQ(extension, "tsv")) { + kind = wbImportKind_tsv; + } else if (wbString_sameQ(extension, "raw") || + wbString_sameQ(extension, "dat")) { + kind = wbImportKind_raw; + } else if (wbString_sameQ(extension, "ppm") || + wbString_sameQ(extension, "pbm")) { + kind = wbImportKind_ppm; + } else if (wbString_sameQ(extension, "text") || + wbString_sameQ(extension, "txt")) { + kind = wbImportKind_text; + } else { + kind = wbImportKind_unknown; + wbLog(ERROR, "File ", file, " does not have a compatible extension."); + } + + wbDelete(extension); + + return kind; +} + +void *wbImport(const char *file, int *resRows, int *resColumns, + const char *type) { + void *data, *res; + wbImport_t imp; + size_t sz; + int columns = 0, rows = 0; + wbImportKind_t kind; + + if (file == NULL) { + fprintf(stderr, "Failed to import file.\n"); + wbExit(); + } + + kind = _parseImportExtension(file); + + wbAssert(kind != wbImportKind_unknown); + + imp = wbImport_open(file, kind); + if (wbString_sameQ(type, "Real")) { + data = wbImport_readAsReal(imp); + sz = sizeof(wbReal_t); + } else if (wbString_sameQ(type, "Text")) { + data = wbImport_readAsText(imp); + sz = sizeof(char); + } else { + // printf("Reading as integer..d\n"); + data = wbImport_readAsInteger(imp); + sz = sizeof(int); + } + + if (kind == wbImportKind_csv || kind == wbImportKind_tsv) { + rows = wbImportCSV_getRowCount(wbImport_getCSV(imp)); + columns = wbImportCSV_getColumnCount(wbImport_getCSV(imp)); + } else if (kind == wbImportKind_raw) { + rows = wbImportRaw_getRowCount(wbImport_getRaw(imp)); + columns = wbImportRaw_getColumnCount(wbImport_getRaw(imp)); + } else if (kind == wbImportKind_text) { + rows = 1; + columns = wbImportText_getLength(wbImport_getText(imp)); + } + + if (rows == 1 && columns > 0) { + rows = columns; + columns = 1; + } + + if (resRows != NULL) { + *resRows = rows; + } + + if (resColumns != NULL) { + *resColumns = columns; + } + + res = wbMalloc(sz * rows * columns); + memcpy(res, data, sz * rows * columns); + + wbImport_close(imp); + + return res; +} + +void *wbImport(const char *file, int *rows, int *columns) { + return wbImport(file, rows, columns, "Real"); +} + +EXTERN_C void *wbImport(const char *file, int *rows) { + return wbImport(file, rows, NULL, "Real"); +} + +void *wbImport(const char *file, int *res_rows, const char *type) { + int cols, rows; + void *res = wbImport(file, &rows, &cols, type); + if (rows == 1 && cols > 1) { + rows = cols; + } + *res_rows = rows; + return res; +} + +wbImage_t wbImport(const char *file) { + wbImage_t img; + wbImport_t imp; + wbImportKind_t kind; + + if (file == NULL) { + fprintf(stderr, "Failed to import file.\n"); + wbExit(); + } + + kind = _parseImportExtension(file); + + wbAssert(kind == wbImportKind_ppm); + + imp = wbImport_open(file, kind); + img = wbImport_getImage(imp); + wbImport_close(imp); + + return img; +} + +int wbImport_flag(const char *file) { + int res; + wbFile_t fh = wbFile_open(file, "r"); + const char *line = wbFile_readLine(fh); + sscanf(line, "%d", &res); + wbFile_close(fh); + return res; +} diff --git a/CUDA_VectorAdd/libwb/wbImport.h b/CUDA_VectorAdd/libwb/wbImport.h new file mode 100644 index 0000000..ce13e1b --- /dev/null +++ b/CUDA_VectorAdd/libwb/wbImport.h @@ -0,0 +1,103 @@ + +#ifndef __WB_IMPORT_H__ +#define __WB_IMPORT_H__ + +#include "wbImage.h" + +typedef enum en_wbImportKind_t { + wbImportKind_unknown = -1, + wbImportKind_raw = 0x1000, + wbImportKind_csv, + wbImportKind_tsv, + wbImportKind_ppm, + wbImportKind_text +} wbImportKind_t; + +#define wbType_real wbType_float + +typedef struct st_wbImportCSV_t { + int rows; + int columns; + void *data; + wbFile_t file; + char seperator; +} * wbImportCSV_t; + +#define wbImportCSV_getRowCount(csv) ((csv)->rows) +#define wbImportCSV_getColumnCount(csv) ((csv)->columns) +#define wbImportCSV_getData(csv) ((csv)->data) +#define wbImportCSV_getFile(csv) ((csv)->file) +#define wbImportCSV_getSeperator(csv) ((csv)->seperator) + +#define wbImportCSV_setRowCount(csv, val) \ + (wbImportCSV_getRowCount(csv) = val) +#define wbImportCSV_setColumnCount(csv, val) \ + (wbImportCSV_getColumnCount(csv) = val) +#define wbImportCSV_setData(csv, val) (wbImportCSV_getData(csv) = val) +#define wbImportCSV_setSeperator(csv, val) \ + (wbImportCSV_getSeperator(csv) = val) + +typedef struct st_wbImportRaw_t { + int rows; + int columns; + void *data; + wbFile_t file; +} * wbImportRaw_t; + +#define wbImportRaw_getRowCount(raw) ((raw)->rows) +#define wbImportRaw_getColumnCount(raw) ((raw)->columns) +#define wbImportRaw_getData(raw) ((raw)->data) +#define wbImportRaw_getFile(raw) ((raw)->file) + +#define wbImportRaw_setRowCount(raw, val) \ + (wbImportRaw_getRowCount(raw) = val) +#define wbImportRaw_setColumnCount(raw, val) \ + (wbImportRaw_getColumnCount(raw) = val) +#define wbImportRaw_setData(raw, val) (wbImportRaw_getData(raw) = val) + +typedef struct st_wbImportText_t { + int length; + char *data; + wbFile_t file; +} * wbImportText_t; + +#define wbImportText_getLength(txt) ((txt)->length) +#define wbImportText_getData(txt) ((txt)->data) +#define wbImportText_getFile(txt) ((txt)->file) + +#define wbImportText_setLength(txt, val) \ + (wbImportText_getLength(txt) = val) +#define wbImportText_setData(txt, val) (wbImportText_getData(txt) = val) + +typedef struct st_wbImport_t { + wbImportKind_t kind; + union { + wbImportRaw_t raw; + wbImportCSV_t csv; + wbImportText_t text; + wbImage_t img; + } container; +} wbImport_t; + +#define wbImport_getKind(imp) ((imp).kind) +#define wbImport_getContainer(imp) ((imp).container) +#define wbImport_getRaw(imp) (wbImport_getContainer(imp).raw) +#define wbImport_getCSV(imp) (wbImport_getContainer(imp).csv) +#define wbImport_getText(imp) (wbImport_getContainer(imp).text) +#define wbImport_getImage(imp) (wbImport_getContainer(imp).img) + +#define wbImport_setKind(imp, val) (wbImport_getKind(imp) = val) +#define wbImport_setRaw(imp, val) (wbImport_getRaw(imp) = val) +#define wbImport_setCSV(imp, val) (wbImport_getCSV(imp) = val) +#define wbImport_setText(imp, val) (wbImport_getText(imp) = val) +#define wbImport_setImage(imp, val) (wbImport_getImage(imp) = val) + +EXTERN_C void *wbImport(const char *file, int *rows); +void *wbImport(const char *file, int *rows, int *columns); +void *wbImport(const char *file, int *rows, const char *type); +void *wbImport(const char *file, int *resRows, int *resColumns, + const char *type); +wbImage_t wbImport(const char *file); +int wbImport_flag(const char *file); + +#endif /* __WB_IMPORT_H__ */ diff --git a/CUDA_VectorAdd/libwb/wbInit.cpp b/CUDA_VectorAdd/libwb/wbInit.cpp new file mode 100644 index 0000000..96ebcf3 --- /dev/null +++ b/CUDA_VectorAdd/libwb/wbInit.cpp @@ -0,0 +1,85 @@ + +#include "wb.h" + +#define MB (1 << 20) +#ifndef WB_DEFAULT_HEAP_SIZE +#define WB_DEFAULT_HEAP_SIZE (1024 * MB) +#endif /* WB_DEFAULT_HEAP_SIZE */ + +static bool _initializedQ = wbFalse; + +#ifndef WB_USE_WINDOWS +__attribute__((__constructor__)) +#endif /* WB_USE_WINDOWS */ +void wb_init(int * +#ifdef WB_USE_MPI + argc +#endif /* WB_USE_MPI */ + , + char *** +#ifdef WB_USE_MPI + argv +#endif /* WB_USE_MPI */ + ) { + if (_initializedQ == wbTrue) { + return; + } +#ifdef WB_USE_MPI + wbMPI_Init(argc, argv); +#endif /* WB_USE_MPI */ + +#ifdef WB_USE_CUDA + CUresult err = cuInit(0); + +/* Select a random GPU */ + +#ifdef WB_USE_MPI + if (rankCount() > 1) { + int deviceCount; + cudaGetDeviceCount(&deviceCount); + srand(time(NULL)); + cudaSetDevice(wbMPI_getRank() % deviceCount); + } else { + int deviceCount; + cudaGetDeviceCount(&deviceCount); + + srand(time(NULL)); + cudaSetDevice(rand() % deviceCount); + } +#else + { + int deviceCount; + cudaGetDeviceCount(&deviceCount); + + srand(time(NULL)); + cudaSetDevice(rand() % deviceCount); + } +#endif /* WB_USE_MPI */ + + cudaDeviceSetLimit(cudaLimitPrintfFifoSize, 1 * MB); + cudaDeviceSetLimit(cudaLimitMallocHeapSize, WB_DEFAULT_HEAP_SIZE); + + cudaDeviceSynchronize(); + +#endif /* WB_USE_CUDA */ + +#ifdef WB_USE_WINDOWS + QueryPerformanceFrequency((LARGE_INTEGER *)&_hrtime_frequency); +#endif /* _MSC_VER */ + + _hrtime(); + + _timer = wbTimer_new(); + _logger = wbLogger_new(); + _initializedQ = wbTrue; + + wbFile_init(); + + solutionJSON = NULL; + +#ifdef WB_USE_MPI + atexit(wbMPI_Exit); +#else /* WB_USE_MPI */ + atexit(wb_atExit); +#endif /* WB_USE_MPI */ +} diff --git a/CUDA_VectorAdd/libwb/wbInit.h b/CUDA_VectorAdd/libwb/wbInit.h new file mode 100644 index 0000000..40e8e1c --- /dev/null +++ b/CUDA_VectorAdd/libwb/wbInit.h @@ -0,0 +1,11 @@ + + +#ifndef __WB_INIT_H__ +#define __WB_INIT_H__ + +#ifndef _MSC_VER +__attribute__((__constructor__)) +#endif /* _MSC_VER */ +void wb_init(int *argc, char ***argv); + +#endif /* __WB_INIT_H__ */ diff --git a/CUDA_VectorAdd/libwb/wbLogger.cpp b/CUDA_VectorAdd/libwb/wbLogger.cpp new file mode 100644 index 0000000..c2e2e17 --- /dev/null +++ b/CUDA_VectorAdd/libwb/wbLogger.cpp @@ -0,0 +1,310 @@ + +#include "wb.h" + +wbLogger_t _logger = NULL; + +static inline wbBool wbLogEntry_hasNext(wbLogEntry_t elem) { + return wbLogEntry_getNext(elem) != NULL; +} + +static inline wbLogEntry_t wbLogEntry_new() { + wbLogEntry_t elem; + + elem = wbNew(struct st_wbLogEntry_t); + + wbLogEntry_setMessage(elem, NULL); + wbLogEntry_setMPIRank(elem, wbMPI_getRank()); + wbLogEntry_setTime(elem, _hrtime()); + + wbLogEntry_setLevel(elem, wbLogLevel_TRACE); + + wbLogEntry_setNext(elem, NULL); + + wbLogEntry_setLine(elem, -1); + wbLogEntry_setFile(elem, NULL); + wbLogEntry_setFunction(elem, NULL); + + return elem; +} + +static inline wbLogEntry_t +wbLogEntry_initialize(wbLogLevel_t level, string msg, const char *file, + const char *fun, int line) { + wbLogEntry_t elem; + + elem = wbLogEntry_new(); + + wbLogEntry_setLevel(elem, level); + + wbLogEntry_setMessage(elem, wbString_duplicate(msg)); + + wbLogEntry_setLine(elem, line); + wbLogEntry_setFile(elem, file); + wbLogEntry_setFunction(elem, fun); + + return elem; +} + +static inline void wbLogEntry_delete(wbLogEntry_t elem) { + if (elem != NULL) { + if (wbLogEntry_getMessage(elem) != NULL) { + wbFree(wbLogEntry_getMessage(elem)); + } + wbDelete(elem); + } + return; +} + +static inline const char *getLevelName(wbLogLevel_t level) { + switch (level) { + case wbLogLevel_unknown: + return "Unknown"; + case wbLogLevel_OFF: + return "Off"; + case wbLogLevel_FATAL: + return "Fatal"; + case wbLogLevel_ERROR: + return "Error"; + case wbLogLevel_WARN: + return "Warn"; + case wbLogLevel_INFO: + return "Info"; + case wbLogLevel_DEBUG: + return "Debug"; + case wbLogLevel_TRACE: + return "Trace"; + } + return NULL; +} + +static inline json11::Json wbLogEntry_toJSONObject(wbLogEntry_t elem) { + json11::Json json = json11::Json::object{ + {"mpi_rank", wbLogEntry_getMPIRank(elem)}, + {"level", getLevelName(wbLogEntry_getLevel(elem))}, + {"file", wbLogEntry_getFile(elem)}, + {"function", wbLogEntry_getFunction(elem)}, + {"line", wbLogEntry_getLine(elem)}, + {"time", wbLogEntry_getTime(elem)}, + {"message", wbLogEntry_getMessage(elem)}, + }; + return json; +} + +static inline string wbLogEntry_toJSON(wbLogEntry_t elem) { + if (elem == NULL) { + return ""; + } else if (WB_USE_JSON11) { + json11::Json json = wbLogEntry_toJSONObject(elem); + return json.string_value(); + } else { + stringstream ss; + + ss << "{\n"; + ss << wbString_quote("mpi_rank") << ":" + << wbString(wbLogEntry_getMPIRank(elem)) << ",\n"; + ss << wbString_quote("level") << ":" + << wbString_quote(getLevelName(wbLogEntry_getLevel(elem))) << ",\n"; + ss << wbString_quote("message") << ":" + << wbString_quote(wbLogEntry_getMessage(elem)) << ",\n"; + ss << wbString_quote("file") << ":" + << wbString_quote(wbLogEntry_getFile(elem)) << ",\n"; + ss << wbString_quote("function") << ":" + << wbString_quote(wbLogEntry_getFunction(elem)) << ",\n"; + ss << wbString_quote("line") << ":" << wbLogEntry_getLine(elem) + << ",\n"; + ss << wbString_quote("time") << ":" << wbLogEntry_getTime(elem) + << "\n"; + ss << "}"; + + return ss.str(); + } + return ""; +} + +static inline string wbLogEntry_toXML(wbLogEntry_t elem) { + if (elem != NULL) { + stringstream ss; + + ss << "\n"; + ss << "" + << "LoggerElement" + << "\n"; + ss << "" << wbLogEntry_getLevel(elem) << "\n"; + ss << "" << wbLogEntry_getMessage(elem) << "\n"; + ss << "" << wbLogEntry_getFile(elem) << "\n"; + ss << "" << wbLogEntry_getFunction(elem) << "\n"; + ss << "" << wbLogEntry_getLine(elem) << "\n"; + ss << "\n"; + ss << "\n"; + + return ss.str(); + } + return ""; +} + +wbLogger_t wbLogger_new() { + wbLogger_t logger; + + logger = wbNew(struct st_wbLogger_t); + + wbLogger_setLength(logger, 0); + wbLogger_setHead(logger, NULL); + + wbLogger_getLevel(logger) = wbLogLevel_TRACE; + + return logger; +} + +static inline void _wbLogger_setLevel(wbLogger_t logger, + wbLogLevel_t level) { + wbLogger_getLevel(logger) = level; +} + +static inline void _wbLogger_setLevel(wbLogLevel_t level) { + _wbLogger_setLevel(_logger, level); +} + +#define wbLogger_setLevel(level) _wbLogger_setLevel(wbLogLevel_##level) + +void wbLogger_clear(wbLogger_t logger) { + if (logger != NULL) { + wbLogEntry_t tmp; + wbLogEntry_t iter; + + iter = wbLogger_getHead(logger); + while (iter != NULL) { + tmp = wbLogEntry_getNext(iter); + wbLogEntry_delete(iter); + iter = tmp; + } + + wbLogger_setLength(logger, 0); + wbLogger_setHead(logger, NULL); + } +} + +void wbLogger_delete(wbLogger_t logger) { + if (logger != NULL) { + wbLogger_clear(logger); + wbDelete(logger); + } + return; +} + +void wbLogger_append(wbLogLevel_t level, string msg, const char *file, + const char *fun, int line) { + wbLogEntry_t elem; + wbLogger_t logger; + + wb_init(NULL, NULL); + + logger = _logger; + + if (wbLogger_getLevel(logger) < level) { + return; + } + + elem = wbLogEntry_initialize(level, msg, file, fun, line); + +#ifdef wbLogger_printOnLog + if (wbLogger_printOnLog) { + if (level <= wbLogger_getLevel(logger) && elem) { + json11::Json json = json11::Json::object{ +#ifndef _MSC_VER //PMO + { "type", "logger" }, { "data", wbLogEntry_toJSONObject(elem) }}; +#else + { "data", wbLogEntry_toJSONObject(elem) }, { "type", "logger" }}; +#endif + std::cout << json.dump() << std::endl; + } + } +#endif /* wbLogger_printOnLog */ + + if (wbLogger_getHead(logger) == NULL) { + wbLogger_setHead(logger, elem); + } else { + wbLogEntry_t prev = wbLogger_getHead(logger); + + while (wbLogEntry_hasNext(prev)) { + prev = wbLogEntry_getNext(prev); + } + wbLogEntry_setNext(prev, elem); + } + +#if 0 + if (level <= wbLogger_getLevel(logger) && elem) { + const char *levelName = getLevelName(level); + + fprintf(stderr, "= LOG: %s: %s (In %s:%s on line %d). =\n", levelName, + wbLogEntry_getMessage(elem), wbLogEntry_getFile(elem), + wbLogEntry_getFunction(elem), wbLogEntry_getLine(elem)); + } +#endif + + wbLogger_incrementLength(logger); + + return; +} + +string wbLogger_toJSON() { + return wbLogger_toJSON(_logger); +} + +static json11::Json wbLogger_toJSONObject(wbLogger_t logger) { + std::vector elems{}; + + if (logger != NULL) { + wbLogEntry_t iter; + stringstream ss; + + for (iter = wbLogger_getHead(logger); iter != NULL; + iter = wbLogEntry_getNext(iter)) { + elems.push_back(wbLogEntry_toJSONObject(iter)); + } + } + return json11::Json(elems); +} + +string wbLogger_toJSON(wbLogger_t logger) { + if (logger != NULL) { + wbLogEntry_t iter; + stringstream ss; + + for (iter = wbLogger_getHead(logger); iter != NULL; + iter = wbLogEntry_getNext(iter)) { + ss << wbLogEntry_toJSON(iter); + if (wbLogEntry_getNext(iter) != NULL) { + ss << ",\n"; + } + } + + return ss.str(); + } + return ""; +} + +string wbLogger_toXML() { + return wbLogger_toXML(_logger); +} + +string wbLogger_toXML(wbLogger_t logger) { + if (logger != NULL) { + wbLogEntry_t iter; + stringstream ss; + + ss << "\n"; + ss << "" + << "Logger" + << "\n"; + ss << "\n"; + for (iter = wbLogger_getHead(logger); iter != NULL; + iter = wbLogEntry_getNext(iter)) { + ss << wbLogEntry_toXML(iter); + } + ss << "\n"; + ss << "\n"; + + return ss.str(); + } + return ""; +} diff --git a/CUDA_VectorAdd/libwb/wbLogger.h b/CUDA_VectorAdd/libwb/wbLogger.h new file mode 100644 index 0000000..b852592 --- /dev/null +++ b/CUDA_VectorAdd/libwb/wbLogger.h @@ -0,0 +1,87 @@ + +#ifndef __WB_LOGGER_H__ +#define __WB_LOGGER_H__ + +#include + +typedef enum en_wbLogLevel_t { + wbLogLevel_unknown = -1, + wbLogLevel_OFF = 0, + wbLogLevel_FATAL, + wbLogLevel_ERROR, + wbLogLevel_WARN, + wbLogLevel_INFO, + wbLogLevel_DEBUG, + wbLogLevel_TRACE +} wbLogLevel_t; + +struct st_wbLogEntry_t { + int line; + int mpiRank; + char *msg; + uint64_t time; + const char *fun; + const char *file; + wbLogLevel_t level; + wbLogEntry_t next; +}; + +struct st_wbLogger_t { + int length; + wbLogEntry_t head; + wbLogLevel_t level; +}; + +#define wbLogEntry_getMessage(elem) ((elem)->msg) +#define wbLogEntry_getMPIRank(elem) ((elem)->mpiRank) +#define wbLogEntry_getTime(elem) ((elem)->time) +#define wbLogEntry_getLevel(elem) ((elem)->level) +#define wbLogEntry_getNext(elem) ((elem)->next) +#define wbLogEntry_getLine(elem) ((elem)->line) +#define wbLogEntry_getFunction(elem) ((elem)->fun) +#define wbLogEntry_getFile(elem) ((elem)->file) + +#define wbLogEntry_setMessage(elem, val) \ + (wbLogEntry_getMessage(elem) = val) +#define wbLogEntry_setMPIRank(elem, val) \ + (wbLogEntry_getMPIRank(elem) = val) +#define wbLogEntry_setTime(elem, val) (wbLogEntry_getTime(elem) = val) +#define wbLogEntry_setLevel(elem, val) (wbLogEntry_getLevel(elem) = val) +#define wbLogEntry_setNext(elem, val) (wbLogEntry_getNext(elem) = val) +#define wbLogEntry_setLine(elem, val) (wbLogEntry_getLine(elem) = val) +#define wbLogEntry_setFunction(elem, val) \ + (wbLogEntry_getFunction(elem) = val) +#define wbLogEntry_setFile(elem, val) (wbLogEntry_getFile(elem) = val) + +#define wbLogger_getLength(log) ((log)->length) +#define wbLogger_getHead(log) ((log)->head) +#define wbLogger_getLevel(log) ((log)->level) + +#define wbLogger_setLength(log, val) (wbLogger_getLength(log) = val) +#define wbLogger_setHead(log, val) (wbLogger_getHead(log) = val) + +#define wbLogger_incrementLength(log) (wbLogger_getLength(log)++) +#define wbLogger_decrementLength(log) (wbLogger_getLength(log)--) + +#define wbLog(level, ...) \ + wbLogger_append(wbLogLevel_##level, wbString(__VA_ARGS__), wbFile, \ + wbFunction, wbLine) + +extern wbLogger_t _logger; + +wbLogger_t wbLogger_new(); + +void wbLogger_clear(wbLogger_t logger); + +void wbLogger_delete(wbLogger_t logger); + +void wbLogger_append(wbLogLevel_t level, string msg, const char *file, + const char *fun, int line); + +string wbLogger_toXML(wbLogger_t logger); +string wbLogger_toXML(); + +string wbLogger_toJSON(wbLogger_t logger); +string wbLogger_toJSON(); + +#endif /* __WB_LOGGER_H__ */ diff --git a/CUDA_VectorAdd/libwb/wbMD5.h b/CUDA_VectorAdd/libwb/wbMD5.h new file mode 100644 index 0000000..e83a8ef --- /dev/null +++ b/CUDA_VectorAdd/libwb/wbMD5.h @@ -0,0 +1,311 @@ + +/* + * This code implements the MD5 message-digest algorithm. + * The algorithm is due to Ron Rivest. This code was + * written by Colin Plumb in 1993, no copyright is claimed. + * This code is in the public domain; do with it what you wish. + * + * Equivalent code is available from RSA Data Security, Inc. + * This code has been tested against that, and is equivalent, + * except that you don't need to include two pages of legalese + * with every copy. + * + * To compute the message digest of a chunk of bytes, declare an + * MD5Context structure, pass it to MD5Init, call MD5Update as + * needed on buffers full of bytes, and then call MD5Final, which + * will fill a supplied 16-byte array with the digest. + * + * Changed so as no longer to depend on Colin Plumb's `usual.h' header + * definitions; now uses stuff from dpkg's config.h. + * - Ian Jackson . + * Still in the public domain. + */ + +#ifndef __WB_MD5_H__ +#define __WB_MD5_H__ + +#include /* for memcpy() */ +#include /* for stupid systems */ + +#define UWORD32 unsigned int + +#define md5byte unsigned char + +struct MD5Context { + UWORD32 buf[4]; + UWORD32 bytes[2]; + UWORD32 in[16]; +}; + +static void MD5Transform(UWORD32 buf[4], UWORD32 const in[16]); + +static int g_bigEndian = 0; +static int g_endianessDetected = 0; + +static void detectEndianess() { + int nl = 0x12345678; + short ns = 0x1234; + + unsigned char *p = (unsigned char *)(&nl); + unsigned char *sp = (unsigned char *)(&ns); + + if (g_endianessDetected) + return; + if (p[0] == 0x12 && p[1] == 0x34 && p[2] == 0x56 && p[3] == 0x78) { + g_bigEndian = 1; + } else if (p[0] == 0x78 && p[1] == 0x56 && p[2] == 0x34 && + p[3] == 0x12) { + g_bigEndian = 0; + } else { + g_bigEndian = *sp != 0x12; + } + + g_endianessDetected = 1; +} + +static void byteSwap(UWORD32 *buf, unsigned words) { + md5byte *p; + + if (!g_bigEndian) + return; + + p = (md5byte *)buf; + + do { + *buf++ = (UWORD32)((unsigned)p[3] << 8 | p[2]) << 16 | + ((unsigned)p[1] << 8 | p[0]); + p += 4; + } while (--words); +} + +/* + * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious + * initialization constants. + */ +static void MD5Init(struct MD5Context *ctx) { + detectEndianess(); + + ctx->buf[0] = 0x67452301; + ctx->buf[1] = 0xefcdab89; + ctx->buf[2] = 0x98badcfe; + ctx->buf[3] = 0x10325476; + + ctx->bytes[0] = 0; + ctx->bytes[1] = 0; +} + +/* + * Update context to reflect the concatenation of another buffer full + * of bytes. + */ +static void MD5Update(struct MD5Context *ctx, md5byte const *buf, + unsigned len) { + UWORD32 t; + + /* Update byte count */ + + t = ctx->bytes[0]; + if ((ctx->bytes[0] = t + len) < t) + ctx->bytes[1]++; /* Carry from low to high */ + + t = 64 - (t & 0x3f); /* Space available in ctx->in (at least 1) */ + if (t > len) { + memcpy((md5byte *)ctx->in + 64 - t, buf, len); + return; + } + /* First chunk is an odd size */ + memcpy((md5byte *)ctx->in + 64 - t, buf, t); + byteSwap(ctx->in, 16); + MD5Transform(ctx->buf, ctx->in); + buf += t; + len -= t; + + /* Process data in 64-byte chunks */ + while (len >= 64) { + memcpy(ctx->in, buf, 64); + byteSwap(ctx->in, 16); + MD5Transform(ctx->buf, ctx->in); + buf += 64; + len -= 64; + } + + /* Handle any remaining bytes of data. */ + memcpy(ctx->in, buf, len); +} + +/* + * Final wrapup - pad to 64-byte boundary with the bit pattern + * 1 0* (64-bit count of bits processed, MSB-first) + */ +static void MD5Final(md5byte digest[16], struct MD5Context *ctx) { + int count = ctx->bytes[0] & 0x3f; /* Number of bytes in ctx->in */ + md5byte *p = (md5byte *)ctx->in + count; + + /* Set the first char of padding to 0x80. There is always room. */ + *p++ = 0x80; + + /* Bytes of padding needed to make 56 bytes (-8..55) */ + count = 56 - 1 - count; + + if (count < 0) { /* Padding forces an extra block */ + memset(p, 0, count + 8); + byteSwap(ctx->in, 16); + MD5Transform(ctx->buf, ctx->in); + p = (md5byte *)ctx->in; + count = 56; + } + memset(p, 0, count); + byteSwap(ctx->in, 14); + + /* Append length in bits and transform */ + ctx->in[14] = ctx->bytes[0] << 3; + ctx->in[15] = ctx->bytes[1] << 3 | ctx->bytes[0] >> 29; + MD5Transform(ctx->buf, ctx->in); + + byteSwap(ctx->buf, 4); + memcpy(digest, ctx->buf, 16); + memset(&ctx, 0, sizeof(ctx)); /* In case it's sensitive */ +} + +#ifndef ASM_MD5 + +/* The four core functions - F1 is optimized somewhat */ + +/* #define F1(x, y, z) (x & y | ~x & z) */ +#define F1(x, y, z) (z ^ (x & (y ^ z))) +#define F2(x, y, z) F1(z, x, y) +#define F3(x, y, z) (x ^ y ^ z) +#define F4(x, y, z) (y ^ (x | ~z)) + +/* This is the central step in the MD5 algorithm. */ +#define MD5STEP(f, w, x, y, z, in, s) \ + (w += f(x, y, z) + in, w = (w << s | w >> (32 - s)) + x) + +/* + * The core of the MD5 algorithm, this alters an existing MD5 hash to + * reflect the addition of 16 longwords of new data. MD5Update blocks + * the data and converts bytes into longwords for this routine. + */ +static void MD5Transform(UWORD32 buf[4], UWORD32 const in[16]) { + UWORD32 a, b, c, d; + + a = buf[0]; + b = buf[1]; + c = buf[2]; + d = buf[3]; + + MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); + MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); + MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); + MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); + MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); + MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); + MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); + MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); + MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); + MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); + MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); + MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); + MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); + MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); + MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); + MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); + + MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); + MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); + MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); + MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); + MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); + MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); + MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); + MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); + MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); + MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); + MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); + MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); + MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); + MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); + MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); + MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); + + MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); + MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); + MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); + MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); + MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); + MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); + MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); + MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); + MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); + MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); + MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); + MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); + MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); + MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); + MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); + MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); + + MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); + MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); + MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); + MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); + MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); + MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); + MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); + MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); + MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); + MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); + MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); + MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); + MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); + MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); + MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); + MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} + +#endif + +static void MD5_buffer(const unsigned char *buf, unsigned int len, + unsigned char sig[16]) { + struct MD5Context md5; + MD5Init(&md5); + MD5Update(&md5, buf, len); + MD5Final(sig, &md5); +} + +#define wbMD5 MD5_buffer + +#define HEX_STRING "0123456789abcdef" /* to convert to hex */ + +static void wbMD5_sigToString(unsigned char signature[16], char *str, + int len) { + unsigned char *sig_p; + char *str_p, *max_p; + unsigned int high, low; + + str_p = str; + max_p = str + len; + + for (sig_p = (unsigned char *)signature; + sig_p < (unsigned char *)signature + 16; sig_p++) { + high = *sig_p / 16; + low = *sig_p % 16; + /* account for 2 chars */ + if (str_p + 1 >= max_p) { + break; + } + *str_p++ = HEX_STRING[high]; + *str_p++ = HEX_STRING[low]; + } + /* account for 2 chars */ + if (str_p < max_p) { + *str_p++ = '\0'; + } +} + +#endif /* __WB_MD5_H__ */ diff --git a/CUDA_VectorAdd/libwb/wbMPI.cpp b/CUDA_VectorAdd/libwb/wbMPI.cpp new file mode 100644 index 0000000..546c1ed --- /dev/null +++ b/CUDA_VectorAdd/libwb/wbMPI.cpp @@ -0,0 +1,75 @@ + +#ifdef WB_USE_MPI + +#include +#include +#include +#include "wb.h" + +static int rank = -1; + +int wbMPI_getRank() { + if (rank != -1) { + return rank; + } + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + return rank; +} + +int rankCount() { + int nRanks; + MPI_Comm_size(MPI_COMM_WORLD, &nRanks); + return nRanks; +} + +const char *wbMPI_getStringFromRank(int rank, int tag) { + if (isMasterQ) { + char *buf; + int bufSize; + MPI_Recv(&bufSize, 1, MPI_INT, rank, tag, MPI_COMM_WORLD, + MPI_STATUS_IGNORE); + buf = (char *)calloc(bufSize, sizeof(char)); + MPI_Recv(buf, bufSize, MPI_CHAR, rank, tag, MPI_COMM_WORLD, + MPI_STATUS_IGNORE); + return buf; + } + + return NULL; +} +void wbMPI_sendStringToMaster(const char *str, int tag) { + if (!isMasterQ) { + // we are going to send the string to the master + int len = (int)strlen(str) + 1; + MPI_Send(&len, 1, MPI_INT, 0, tag, MPI_COMM_WORLD); + MPI_Send((void *)str, len, MPI_CHAR, 0, tag, MPI_COMM_WORLD); + } + + return; +} + +int wbMPI_Init(int *argc, char ***argv) { + int err = MPI_SUCCESS; + err = MPI_Init(argc, argv); + // printf("argc = %d\n", *argc); + // err = MPI_Init(NULL, NULL); + // printf("rank = %d is master = %d\n", wbMPI_getRank(), isMasterQ); + // MPI_Barrier(MPI_COMM_WORLD); + return err; +} + +bool finalizedQ = false; + +extern "C" int wbMPI_Finalize(void) { + if (finalizedQ) { + return MPI_SUCCESS; + } + finalizedQ = true; + wb_atExit(); + return MPI_Finalize(); +} +extern "C" void wbMPI_Exit(void) { + wbMPI_Finalize(); + return; +} + +#endif /* WB_USE_MPI */ diff --git a/CUDA_VectorAdd/libwb/wbMPI.h b/CUDA_VectorAdd/libwb/wbMPI.h new file mode 100644 index 0000000..6275eaf --- /dev/null +++ b/CUDA_VectorAdd/libwb/wbMPI.h @@ -0,0 +1,37 @@ + +#ifndef __WB_MPI_H__ +#define __WB_MPI_H__ + +#ifdef WB_USE_MPI + +#include +#include +#include + +#define isMasterQ ((wbMPI_getRank()) == 0) + +extern int wbMPI_getRank(); + +extern int rankCount(); + +extern const char *wbMPI_getStringFromRank(int rank, int tag); +extern void wbMPI_sendStringToMaster(const char *str, int tag); + +extern int wbMPI_Init(int *argc, char ***argv); + +extern bool finalizedQ; + +extern "C" int wbMPI_Finalize(void); +extern "C" void wbMPI_Exit(void); + +#define MPI_Finalize wbMPI_Finalize + +#else /* WB_USE_MPI */ +static inline int rankCount() { + return 1; +} +static inline int wbMPI_getRank() { + return 0; +} +#endif /* WB_USE_MPI */ +#endif /* __WB_MPI_H__ */ diff --git a/CUDA_VectorAdd/libwb/wbMalloc.h b/CUDA_VectorAdd/libwb/wbMalloc.h new file mode 100644 index 0000000..5d74be4 --- /dev/null +++ b/CUDA_VectorAdd/libwb/wbMalloc.h @@ -0,0 +1,140 @@ + + +#ifndef __WB_MALLOC_H__ +#define __WB_MALLOC_H__ + +#ifdef WB_USE_CUSTOM_MALLOC +#ifdef __linux__ +#define THROW __THROW +#else +#define THROW +#endif + +static inline void *_malloc(size_t size) THROW { + if (size == 0) { + return NULL; + } else { + int err; + void *res = memmgr_alloc((ulong)size, &err); + if (err) { + fprintf(stderr, "<>:: Memory allocation failed\n"); + exit(1); + } else { + size_t ii = 0; + unsigned char *p = (unsigned char *)res; + while (ii++ < size) { + *p++ = 0; + } + return res; + } + } +} + +static inline void _free(void *ptr) THROW { + if (ptr != NULL) { + memmgr_free(ptr); + } +} + +static inline void *_calloc(size_t nmemb, size_t size) THROW { + return _malloc(nmemb * size); +} + +static inline void *_realloc(void *ptr, size_t size) THROW { + if (size == 0) { + free(ptr); + return NULL; + } else if (ptr == NULL) { + return malloc(size); + } else { + void *buf; + unsigned char *dst; + unsigned char *src; + size_t alloc_size, to_copy, i = 0; + + // Allocate new buffer + buf = malloc(size); + + if (buf != 0) { + // Find original allocation size + alloc_size = (size_t)memmgr_get_block_size(ptr); + to_copy = alloc_size; + if (to_copy > size) { + to_copy = size; + } + + // Copy data to new buffer + dst = (unsigned char *)buf; + src = (unsigned char *)ptr; + while (i++ < to_copy) { + *dst++ = *src++; + } + + // Free the old buffer + free(ptr); + } + + return buf; + } +} + +#define wbNew(type) ((type *)_malloc(sizeof(type))) +#define wbNewArray(type, len) ((type *)_malloc((len) * sizeof(type))) +#define wbMalloc(sz) _malloc(sz) +#define wbDelete(var) \ + _free(var); \ + var = NULL +#define wbFree(var) \ + _free(var); \ + var = NULL +#define wbRealloc(var, newSize) _realloc(var, newSize) +#define wbReallocArray(t, m, n) ((t *)_realloc(m, n * sizeof(t))) + +#define free _free +#define malloc _malloc +#define calloc _calloc +#define realloc _realloc + +#else /* WB_USE_CUSTOM_MALLOC */ + +static inline void *xMalloc(size_t sz) { + void *mem = NULL; + if (sz != 0) { + mem = malloc(sz); + } + return mem; +} + +static inline void xFree(void *mem) { + if (mem != NULL) { + free(mem); + } + return; +} + +static inline void *xRealloc(void *mem, size_t sz) { + if (mem == NULL) { + return NULL; + } else if (sz == 0) { + xFree(mem); + return NULL; + } else { + void *res = realloc(mem, sz); + wbAssert(res != NULL); + return res; + } +} + +#define wbNew(type) ((type *)wbMalloc(sizeof(type))) +#define wbNewArray(type, len) ((type *)wbMalloc((len) * sizeof(type))) +#define wbMalloc(sz) xMalloc(sz) +#define wbDelete(var) wbFree(var) +#define wbFree(var) \ + xFree(var); \ + var = NULL +#define wbRealloc(var, newSize) xRealloc(var, newSize) +#define wbReallocArray(t, m, n) ((t *)xRealloc(m, n * sizeof(t))) + +#endif /* WB_USE_CUSTOM_MALLOC */ + +#endif /* __WB_MALLOC_H__ */ diff --git a/CUDA_VectorAdd/libwb/wbPPM.cpp b/CUDA_VectorAdd/libwb/wbPPM.cpp new file mode 100644 index 0000000..86ab208 --- /dev/null +++ b/CUDA_VectorAdd/libwb/wbPPM.cpp @@ -0,0 +1,199 @@ + +#include +#include "wb.h" + +static inline float _min(float x, float y) { + return x < y ? x : y; +} + +static inline float _max(float x, float y) { + return x > y ? x : y; +} + +static inline float _clamp(float x, float start, float end) { + return _min(_max(x, start), end); +} + +static const char *skipSpaces(const char *line) { + while (*line == ' ' || *line == '\t') { + line++; + if (*line == '\0') { + break; + } + } + return line; +} + +static char nextNonSpaceChar(const char *line0) { + const char *line = skipSpaces(line0); + return *line; +} + +static wbBool isComment(const char *line) { + char nextChar = nextNonSpaceChar(line); + if (nextChar == '\0') { + return wbTrue; + } else { + return nextChar == '#'; + } +} + +static void parseDimensions(const char *line0, int *width, int *height) { + const char *line = skipSpaces(line0); + sscanf(line, "%d %d", width, height); +} + +static void parseDimensions(const char *line0, int *width, int *height, + int *channels) { + const char *line = skipSpaces(line0); + sscanf(line, "%d %d %d", width, height, channels); +} + +static void parseDepth(const char *line0, int *depth) { + const char *line = skipSpaces(line0); + sscanf(line, "%d", depth); +} + +static char *nextLine(wbFile_t file) { + char *line = NULL; + while ((line = wbFile_readLine(file)) != NULL) { + if (!isComment(line)) { + break; + } + } + return line; +} + +wbImage_t wbPPM_import(const char *filename) { + wbImage_t img; + wbFile_t file; + char *header; + char *line; + int ii, jj, kk, channels; + int width, height, depth; + unsigned char *charData, *charIter; + float *imgData, *floatIter; + float scale; + + img = NULL; + + file = wbFile_open(filename, "rb"); + if (file == NULL) { + printf("Could not open %s\n", filename); + goto cleanup; + } + + header = wbFile_readLine(file); + if (header == NULL) { + printf("Could not read from %s\n", filename); + goto cleanup; + } else if (strcmp(header, "P6") != 0 && strcmp(header, "P6\n") != 0 && + strcmp(header, "P5") != 0 && strcmp(header, "P5\n") != 0 && + strcmp(header, "S6") != 0 && strcmp(header, "S6\n") != 0) { + printf("Could find magic number for %s\n", filename); + goto cleanup; + } + + // P5 are monochrome while P6/S6 are rgb + // S6 needs to parse number of channels out of file + if (strcmp(header, "P5") == 0 || strcmp(header, "P5\n") == 0) { + channels = 1; + line = nextLine(file); + parseDimensions(line, &width, &height); + } else if (strcmp(header, "P6") == 0 || strcmp(header, "P6\n") == 0) { + channels = 3; + line = nextLine(file); + parseDimensions(line, &width, &height); + } else { + line = nextLine(file); + parseDimensions(line, &width, &height, &channels); + } + + // the line now contains the depth information + line = nextLine(file); + parseDepth(line, &depth); + + // the rest of the lines contain the data in binary format + charData = (unsigned char *)wbFile_read( + file, width * channels * sizeof(unsigned char), height); + + img = wbImage_new(width, height, channels); + + imgData = wbImage_getData(img); + + charIter = charData; + floatIter = imgData; + + scale = 1.0f / ((float)depth); + + for (ii = 0; ii < height; ii++) { + for (jj = 0; jj < width; jj++) { + for (kk = 0; kk < channels; kk++) { + *floatIter = ((float)*charIter) * scale; + floatIter++; + charIter++; + } + } + } + +#ifdef LAZY_FILE_LOAD + wbDelete(charData); +#endif + +cleanup: + wbFile_close(file); + return img; +} + +void wbPPM_export(const char *filename, wbImage_t img) { + int ii; + int jj; + int kk; + int depth; + int width; + int height; + int channels; + wbFile_t file; + float *floatIter; + unsigned char *charData; + unsigned char *charIter; + + file = wbFile_open(filename, "wb+"); + + width = wbImage_getWidth(img); + height = wbImage_getHeight(img); + channels = wbImage_getChannels(img); + depth = 255; + + if (channels == 1) { + wbFile_writeLine(file, "P5"); + } else { + wbFile_writeLine(file, "P6"); + } + wbFile_writeLine(file, "#Created via wbPPM Export"); + wbFile_writeLine(file, wbString(width, " ", height)); + wbFile_writeLine(file, wbString(depth)); + + charData = wbNewArray(unsigned char, width *height *channels); + + charIter = charData; + floatIter = wbImage_getData(img); + + for (ii = 0; ii < height; ii++) { + for (jj = 0; jj < width; jj++) { + for (kk = 0; kk < channels; kk++) { + *charIter = (unsigned char)ceil(_clamp(*floatIter, 0, 1) * depth); + floatIter++; + charIter++; + } + } + } + + wbFile_write(file, charData, width * channels * sizeof(unsigned char), + height); + + wbDelete(charData); + wbFile_delete(file); + + return; +} diff --git a/CUDA_VectorAdd/libwb/wbPPM.h b/CUDA_VectorAdd/libwb/wbPPM.h new file mode 100644 index 0000000..d589b36 --- /dev/null +++ b/CUDA_VectorAdd/libwb/wbPPM.h @@ -0,0 +1,11 @@ + + +#ifndef __wbPPM_H__ +#define __wbPPM_H__ + +START_EXTERN_C +wbImage_t wbPPM_import(const char *filename); +void wbPPM_export(const char *filename, wbImage_t img); +END_EXTERN_C + +#endif /* __wbPPM_H__ */ diff --git a/CUDA_VectorAdd/libwb/wbPath.cpp b/CUDA_VectorAdd/libwb/wbPath.cpp new file mode 100644 index 0000000..0d93e2b --- /dev/null +++ b/CUDA_VectorAdd/libwb/wbPath.cpp @@ -0,0 +1,42 @@ +#include "wb.h" + +char *wbPath_join(const char *p1, const char *p2) { + size_t s1 = strlen(p1); + size_t s2 = strlen(p2); + char *res = + wbNewArray(char, s1 + 1 /* seperator */ + s2 + 1 /* terminator */); + memcpy(res, p1, s1); + char *iter = res + s1; + *iter++ = wbDirectorySeperator; + memcpy(iter, p2, s2); + iter += s2; + *iter = '\0'; + return res; +} + +char *wbPath_join(const char *p1, const char *p2, const char *p3) { + char *p12 = wbPath_join(p1, p2); + char *res = wbPath_join(p12, p3); + wbDelete(p12); + return res; +} + +char *wbPath_join(const char *p1, const char *p2, const char *p3, + const char *p4) { + char *p123 = wbPath_join(p1, p2, p3); + char *res = wbPath_join(p123, p4); + wbDelete(p123); + return res; +} + +char *wbPath_join(const std::string &p1, const std::string &p2) { + return wbPath_join(p1.c_str(), p2.c_str()); +} +char *wbPath_join(const std::string &p1, const std::string &p2, + const std::string &p3) { + return wbPath_join(p1.c_str(), p2.c_str(), p3.c_str()); +} +char *wbPath_join(const std::string &p1, const std::string &p2, + const std::string &p3, const std::string &p4) { + return wbPath_join(p1.c_str(), p2.c_str(), p3.c_str(), p4.c_str()); +} \ No newline at end of file diff --git a/CUDA_VectorAdd/libwb/wbPath.h b/CUDA_VectorAdd/libwb/wbPath.h new file mode 100644 index 0000000..0dd3187 --- /dev/null +++ b/CUDA_VectorAdd/libwb/wbPath.h @@ -0,0 +1,30 @@ +#ifndef __WB_PATH_H__ +#define __WB_PATH_H__ + +char *wbPath_join(const char *p1, const char *p2); +char *wbPath_join(const char *p1, const char *p2, const char *p3); +char *wbPath_join(const char *p1, const char *p2, const char *p3, + const char *p4); + +char *wbPath_join(const std::string &p1, const std::string &p2); +char *wbPath_join(const std::string &p1, const std::string &p2, + const std::string &p3); +char *wbPath_join(const std::string &p1, const std::string &p2, + const std::string &p3, const std::string &p4); + +template +static char *wbPath_join(const T1 &p1, const T2 &p2) { + return wbPath_join(wbString(p1), wbString(p2)); +} +template +static char *wbPath_join(const T1 &p1, const T2 &p2, const T3 &p3) { + return wbPath_join(wbString(p1), wbString(p2), wbString(p3)); +} +template +static char *wbPath_join(const T1 &p1, const T2 &p2, const T3 &p3, + const T4 &p4) { + return wbPath_join(wbString(p1), wbString(p2), wbString(p3), + wbString(p4)); +} + +#endif /* __WB_PATH_H__ */ diff --git a/CUDA_VectorAdd/libwb/wbSolution.cpp b/CUDA_VectorAdd/libwb/wbSolution.cpp new file mode 100644 index 0000000..703f410 --- /dev/null +++ b/CUDA_VectorAdd/libwb/wbSolution.cpp @@ -0,0 +1,271 @@ + +#include "wb.h" + +char *solutionJSON = NULL; +static string _solution_correctQ(""); + +static void _onUnsameImageFunction(string str) { + _solution_correctQ = str; +} + +template +static wbBool wbSolution_listCorrectQ(const char *expectedOutputFile, + wbSolution_t sol, const char *type) { + wbBool res; + T *expectedData; + int expectedRows, expectedColumns; + + expectedData = (T *)wbImport(expectedOutputFile, &expectedRows, + &expectedColumns, type); + + if (expectedData == NULL) { + _solution_correctQ = "Failed to open expected output file."; + res = wbFalse; + } else if (expectedRows != wbSolution_getRows(sol)) { + wbLog(TRACE, "Number of rows in the solution is ", + wbSolution_getRows(sol), ". Expected number of rows is ", + expectedRows, "."); + _solution_correctQ = + "The number of rows in the solution did not match " + "that of the expected results."; + res = wbFalse; + } else if (expectedColumns != wbSolution_getColumns(sol)) { + wbLog(TRACE, "Number of columns in the solution is ", + wbSolution_getColumns(sol), ". Expected number of columns is ", + expectedColumns, "."); + _solution_correctQ = "The number of columns in the solution did not " + "match that of the expected results."; + res = wbFalse; + } else { + int ii, jj, idx; + T *solutionData; + + solutionData = (T *)wbSolution_getData(sol); + + for (ii = 0; ii < expectedRows; ii++) { + for (jj = 0; jj < expectedColumns; jj++) { + idx = ii * expectedColumns + jj; + if (wbUnequalQ(expectedData[idx], solutionData[idx])) { + string str; + if (expectedColumns == 1) { + str = wbString( + "The solution did not match the expected results at row ", + ii, ". Expecting ", expectedData[idx], " but got ", + solutionData[idx], "."); + } else { + str = wbString("The solution did not match the expected " + "results at column ", + jj, " and row ", ii, ". Expecting ", + expectedData[idx], " but got ", + solutionData[idx], "."); + } + _solution_correctQ = str; + res = wbFalse; + goto matrixCleanup; + } + } + } + + res = wbTrue; + matrixCleanup: + if (expectedData != NULL) { + wbFree(expectedData); + } + } + return res; +} + +static wbBool wbSolution_correctQ(char *expectedOutputFile, + wbSolution_t sol) { + if (expectedOutputFile == NULL) { + _solution_correctQ = "Failed to determined the expected output file."; + return wbFalse; + } else if (!wbFile_existsQ(expectedOutputFile)) { + _solution_correctQ = + wbString("The file ", expectedOutputFile, " does not exist."); + return wbFalse; + } else if (wbString_sameQ(wbSolution_getType(sol), "image")) { + wbBool res; + wbImage_t solutionImage = NULL; + wbImage_t expectedImage = wbImport(expectedOutputFile); + if (expectedImage == NULL) { + _solution_correctQ = "Failed to open expected output file."; + res = wbFalse; + } else if (wbImage_getWidth(expectedImage) != + wbSolution_getWidth(sol)) { + _solution_correctQ = + "The image width of the expected image does not " + "match that of the solution."; + res = wbFalse; + } else if (wbImage_getHeight(expectedImage) != + wbSolution_getHeight(sol)) { + _solution_correctQ = + "The image height of the expected image does not " + "match that of the solution."; + res = wbFalse; + } else if (wbImage_getChannels(expectedImage) != + wbSolution_getChannels(sol)) { + _solution_correctQ = + "The image channels of the expected image does not " + "match that of the solution."; + res = wbFalse; + } else { + solutionImage = (wbImage_t)wbSolution_getData(sol); + wbAssert(solutionImage != NULL); + res = wbImage_sameQ(solutionImage, expectedImage, + _onUnsameImageFunction); + } + if (expectedImage != NULL) { + wbImage_delete(expectedImage); + } + return res; + } else if (wbString_sameQ(wbSolution_getType(sol), "histogram")) { + return wbSolution_listCorrectQ(expectedOutputFile, sol, + "Integer"); + } else if (wbString_sameQ(wbSolution_getType(sol), "integral_vector")) { + return wbSolution_listCorrectQ(expectedOutputFile, sol, + "Integer"); + } else if (wbString_sameQ(wbSolution_getType(sol), "vector") || + wbString_sameQ(wbSolution_getType(sol), "matrix")) { + return wbSolution_listCorrectQ(expectedOutputFile, sol, + "Real"); + } else { + wbAssert(wbFalse); + return wbFalse; + } +} + +wbBool wbSolution(char *expectedOutputFile, char *outputFile, char *type0, + void *data, int rows, int columns, int depth) { + char *type; + wbBool res; + wbSolution_t sol; + + if (expectedOutputFile == NULL || data == NULL || type0 == NULL) { + wbLog(ERROR, "Failed to grade solution"); + return wbFalse; + } + + type = wbString_toLower(type0); + + if (_solution_correctQ != "") { + _solution_correctQ = ""; + } + + wbSolution_setOutputFile(sol, outputFile); + wbSolution_setType(sol, type); + wbSolution_setData(sol, data); + wbSolution_setRows(sol, rows); + wbSolution_setColumns(sol, columns); + wbSolution_setDepth(sol, depth); + + res = wbSolution_correctQ(expectedOutputFile, sol); + + if (outputFile != NULL) { + if (wbString_sameQ(type, "image")) { + wbImage_t inputImage = (wbImage_t)data; + wbImage_t img = wbImage_new(wbImage_getWidth(inputImage), + wbImage_getHeight(inputImage), + wbImage_getChannels(inputImage)); + memcpy(wbImage_getData(img), wbImage_getData(inputImage), + rows * columns * wbImage_channels * sizeof(wbReal_t)); + wbExport(outputFile, img); + wbImage_delete(img); + } else if (wbString_sameQ(type, "integral_vector")) { + wbExport(outputFile, (int *)data, rows, columns); + } else if (wbString_sameQ(type, "vector") || + wbString_sameQ(type, "matrix")) { + wbExport(outputFile, (wbReal_t *)data, rows, columns); + } else if (wbString_sameQ(type, "histogram")) { + wbExport(outputFile, (unsigned char *)data, rows, columns); + } else if (wbString_sameQ(type, "text")) { + wbExport_text(outputFile, (unsigned char *)data, rows * columns); + } + } + + wbFree(type); + + return res; +} + +wbBool wbSolution(char *expectedOutputFile, char *outputFile, char *type0, + void *data, int rows, int columns) { + return wbSolution(expectedOutputFile, outputFile, type0, data, rows, + columns, 1); +} + +wbBool wbSolution(wbArg_t arg, void *data, int rows, int columns, + int depth) { + char *type; + wbBool res; + char *expectedOutputFile; + char *outputFile; + stringstream ss; + + expectedOutputFile = wbArg_getExpectedOutputFile(arg); + outputFile = wbArg_getOutputFile(arg); + type = wbArg_getType(arg); + + wbAssert(type != NULL); + wbAssert(expectedOutputFile != NULL); + wbAssert(outputFile != NULL); + + res = wbSolution(expectedOutputFile, outputFile, type, data, rows, + columns, depth); + + if (WB_USE_JSON11) { + json11::Json json; + if (res) { + json = json11::Json::object{{"correctq", true}, + {"message", "The solution is correct"}}; + } else { + json = json11::Json::object{{"correctq", false}, + {"message", _solution_correctQ}}; + } + +#ifdef wbLogger_printOnLog + if (wbLogger_printOnLog) { + json11::Json e = +//PMO +#ifndef _MSC_VER + json11::Json::object{{"type", "solution"}, {"data", json}}; +#else + json11::Json::object{{"data", json }, {"type", "solution" }}; +#endif + std::cout << e.dump() << std::endl; + } +#endif /* wbLogger_printOnLog */ + + solutionJSON = wbString_duplicate(json.string_value()); + } else { + if (res) { + ss << "{\n"; + ss << wbString_quote("correctq") << ": true,\n"; + ss << wbString_quote("message") << ": " + << wbString_quote("Solution is correct.") << "\n"; + ss << "}"; + } else { + ss << "{\n"; + ss << wbString_quote("correctq") << ": false,\n"; + ss << wbString_quote("message") << ": " + << wbString_quote(_solution_correctQ) << "\n"; + ss << "}"; + } + solutionJSON = wbString_duplicate(ss.str()); + } + + return res; +} + +wbBool wbSolution(wbArg_t arg, void *data, int rows, int columns) { + return wbSolution(arg, data, rows, columns, 1); +} + +EXTERN_C wbBool wbSolution(wbArg_t arg, void *data, int rows) { + return wbSolution(arg, data, rows, 1); +} + +wbBool wbSolution(wbArg_t arg, wbImage_t img) { + return wbSolution(arg, img, wbImage_getHeight(img), + wbImage_getWidth(img), wbImage_getChannels(img)); +} diff --git a/CUDA_VectorAdd/libwb/wbSolution.h b/CUDA_VectorAdd/libwb/wbSolution.h new file mode 100644 index 0000000..f18d07d --- /dev/null +++ b/CUDA_VectorAdd/libwb/wbSolution.h @@ -0,0 +1,40 @@ + + +#ifndef __WB_SOLUTION_H__ +#define __WB_SOLUTION_H__ + +typedef struct st_wbSolution_t { + char *type; + char *outputFile; + void *data; + int rows; + int columns; + int depth; +} wbSolution_t; + +#define wbSolution_getType(sol) ((sol).type) +#define wbSolution_getOutputFile(sol) ((sol).outputFile) +#define wbSolution_getData(sol) ((sol).data) +#define wbSolution_getRows(sol) ((sol).rows) +#define wbSolution_getColumns(sol) ((sol).columns) +#define wbSolution_getDepth(sol) ((sol).depth) + +#define wbSolution_getHeight wbSolution_getRows +#define wbSolution_getWidth wbSolution_getColumns +#define wbSolution_getChannels wbSolution_getDepth + +#define wbSolution_setType(sol, val) (wbSolution_getType(sol) = val) +#define wbSolution_setOutputFile(sol, val) \ + (wbSolution_getOutputFile(sol) = val) +#define wbSolution_setData(sol, val) (wbSolution_getData(sol) = val) +#define wbSolution_setRows(sol, val) (wbSolution_getRows(sol) = val) +#define wbSolution_setColumns(sol, val) (wbSolution_getColumns(sol) = val) +#define wbSolution_setDepth(sol, val) (wbSolution_getDepth(sol) = val) + +wbBool wbSolution(char *expectedOutputFile, char *outputFile, char *type0, + void *data, int rows, int columns); +wbBool wbSolution(wbArg_t arg, void *data, int rows, int columns); +EXTERN_C wbBool wbSolution(wbArg_t arg, void *data, int rows); +wbBool wbSolution(wbArg_t arg, wbImage_t img); + +#endif /* __WB_SOLUTION_H__ */ diff --git a/CUDA_VectorAdd/libwb/wbSparse.cpp b/CUDA_VectorAdd/libwb/wbSparse.cpp new file mode 100644 index 0000000..9cdcba3 --- /dev/null +++ b/CUDA_VectorAdd/libwb/wbSparse.cpp @@ -0,0 +1,82 @@ + +#include "wb.h" + +static void sort(int *data, int *key, int start, int end) { + if ((end - start + 1) > 1) { + int left = start, right = end; + int pivot = key[right]; + while (left <= right) { + while (key[left] > pivot) { + left = left + 1; + } + while (key[right] < pivot) { + right = right - 1; + } + if (left <= right) { + int tmp = key[left]; + key[left] = key[right]; + key[right] = tmp; + tmp = data[left]; + data[left] = data[right]; + data[right] = tmp; + left = left + 1; + right = right - 1; + } + } + sort(data, key, start, right); + sort(data, key, left, end); + } +} + +EXTERN_C void CSRToJDS(int dim, int *csrRowPtr, int *csrColIdx, + float *csrData, int **jdsRowPerm, int **jdsRowNNZ, + int **jdsColStartIdx, int **jdsColIdx, + float **jdsData) { + // Row Permutation Vector + *jdsRowPerm = (int *)malloc(sizeof(int) * dim); + for (int rowIdx = 0; rowIdx < dim; ++rowIdx) { + (*jdsRowPerm)[rowIdx] = rowIdx; + } + + // Number of non-zeros per row + *jdsRowNNZ = (int *)malloc(sizeof(int) * dim); + for (int rowIdx = 0; rowIdx < dim; ++rowIdx) { + (*jdsRowNNZ)[rowIdx] = csrRowPtr[rowIdx + 1] - csrRowPtr[rowIdx]; + } + + // Sort rows by number of non-zeros + sort(*jdsRowPerm, *jdsRowNNZ, 0, dim - 1); + + // Starting point of each compressed column + int maxRowNNZ = (*jdsRowNNZ)[0]; // Largest number of non-zeros per row + DEBUG(printf("jdsRowNNZ = %d\n", maxRowNNZ)); + *jdsColStartIdx = (int *)malloc(sizeof(int) * maxRowNNZ); + (*jdsColStartIdx)[0] = 0; // First column starts at 0 + for (int col = 0; col < maxRowNNZ - 1; ++col) { + // Count the number of rows with entries in this column + int count = 0; + for (int idx = 0; idx < dim; ++idx) { + if ((*jdsRowNNZ)[idx] > col) { + ++count; + } + } + (*jdsColStartIdx)[col + 1] = (*jdsColStartIdx)[col] + count; + } + + // Sort the column indexes and data + const int NNZ = csrRowPtr[dim]; + DEBUG(printf("NNZ = %d\n", NNZ)); + *jdsColIdx = (int *)malloc(sizeof(int) * NNZ); + DEBUG(printf("dim = %d\n", dim)); + *jdsData = (float *)malloc(sizeof(float) * NNZ); + for (int idx = 0; idx < dim; ++idx) { // For every row + int row = (*jdsRowPerm)[idx]; + int rowNNZ = (*jdsRowNNZ)[idx]; + for (int nnzIdx = 0; nnzIdx < rowNNZ; ++nnzIdx) { + int jdsPos = (*jdsColStartIdx)[nnzIdx] + idx; + int csrPos = csrRowPtr[row] + nnzIdx; + (*jdsColIdx)[jdsPos] = csrColIdx[csrPos]; + (*jdsData)[jdsPos] = csrData[csrPos]; + } + } +} diff --git a/CUDA_VectorAdd/libwb/wbSparse.h b/CUDA_VectorAdd/libwb/wbSparse.h new file mode 100644 index 0000000..c04a857 --- /dev/null +++ b/CUDA_VectorAdd/libwb/wbSparse.h @@ -0,0 +1,10 @@ + +#ifndef __WB_SPARSE_H__ +#define __WB_SPARSE_H__ + +EXTERN_C void CSRToJDS(int dim, int *csrRowPtr, int *csrColIdx, + float *csrData, int **jdsRowPerm, int **jdsRowNNZ, + int **jdsColStartIdx, int **jdsColIdx, + float **jdsData); + +#endif /* __WB_SPARSE_H__ */ diff --git a/CUDA_VectorAdd/libwb/wbString.h b/CUDA_VectorAdd/libwb/wbString.h new file mode 100644 index 0000000..65e52f8 --- /dev/null +++ b/CUDA_VectorAdd/libwb/wbString.h @@ -0,0 +1,324 @@ + + +#ifndef __WB_STRING_H__ +#define __WB_STRING_H__ + +#include +#include +#include +#include +#include +#include +#include "wb.h" + +using std::string; +using std::vector; +using std::stringstream; +using std::exception; + +template +static inline string wbString(const T &x); + +static inline void wbString_replace(string &value, string const &search, + string const &replace) { + for (string::size_type next = value.find(search); next != string::npos; + next = value.find(search, next)) { + value.replace(next, search.length(), replace); + next += replace.length(); + } +} + +static inline string wbString_quote(string str) { + string s = str; + wbString_replace(s, "\\", "\\\\"); + s = "\"" + s + "\""; + return s; +} + +static inline string wbString_quote(const char *str) { + if (str == NULL) { + return wbString_quote(""); + } else { + return wbString_quote(string(str)); + } +} + +static inline char *wbString_duplicate(const char *str) { + if (str == NULL) { + return NULL; + } else { + char *newstr; + size_t len = strlen(str); + newstr = wbNewArray(char, len + 1); + memcpy(newstr, str, len * sizeof(char)); + newstr[len] = '\0'; + return newstr; + } +} + +static inline char *wbString_duplicate(std::string str) { + return wbString_duplicate(str.c_str()); +} + +static inline string wbString(void) { + string s = ""; + return s; +} + +template +static inline string wbString(const T &x) { + try { + stringstream ss; + ss << x; + return ss.str(); + } catch (exception &e) { + return string(); + } +} + +template <> +inline string wbString(const bool &x) { + return x ? "True" : "False"; +} + +template <> +inline string wbString(const vector &x) { + stringstream ss; + ss << "{"; + for (size_t ii = 0; ii < x.size(); ii++) { + ss << wbString_quote(x[ii]); + if (ii != x.size() - 1) { + ss << ", "; + } + } + ss << "}"; + + return ss.str(); +} + +template <> +inline string wbString(const vector &x) { + stringstream ss; + ss << "{"; + for (size_t ii = 0; ii < x.size(); ii++) { + ss << x[ii]; + if (ii != x.size() - 1) { + ss << ", "; + } + } + ss << "}"; + + return ss.str(); +} + +template <> +inline string wbString(const vector &x) { + stringstream ss; + ss << "{"; + for (size_t ii = 0; ii < x.size(); ii++) { + ss << x[ii]; + if (ii != x.size() - 1) { + ss << ", "; + } + } + ss << "}"; + + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1) { + stringstream ss; + ss << wbString(x0) << wbString(x1); + + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1, const T2 &x2) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2); + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1, const T2 &x2, + const T3 &x3) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2) << wbString(x3); + + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1, const T2 &x2, + const T3 &x3, const T4 &x4) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2) << wbString(x3) + << wbString(x4); + + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1, const T2 &x2, + const T3 &x3, const T4 &x4, const T5 &x5) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2) << wbString(x3) + << wbString(x4) << wbString(x5); + + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1, const T2 &x2, + const T3 &x3, const T4 &x4, const T5 &x5, + const T6 &x6) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2) << wbString(x3) + << wbString(x4) << wbString(x5) << wbString(x6); + + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1, const T2 &x2, + const T3 &x3, const T4 &x4, const T5 &x5, + const T6 &x6, const T7 &x7) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2) << wbString(x3) + << wbString(x4) << wbString(x5) << wbString(x6) << wbString(x7); + + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1, const T2 &x2, + const T3 &x3, const T4 &x4, const T5 &x5, + const T6 &x6, const T7 &x7, const T8 &x8) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2) << wbString(x3) + << wbString(x4) << wbString(x5) << wbString(x6) << wbString(x7) + << wbString(x8); + + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1, const T2 &x2, + const T3 &x3, const T4 &x4, const T5 &x5, + const T6 &x6, const T7 &x7, const T8 &x8, + const T9 &x9) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2) << wbString(x3) + << wbString(x4) << wbString(x5) << wbString(x6) << wbString(x7) + << wbString(x8) << wbString(x9); + + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1, const T2 &x2, + const T3 &x3, const T4 &x4, const T5 &x5, + const T6 &x6, const T7 &x7, const T8 &x8, + const T9 &x9, const T10 &x10) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2) << wbString(x3) + << wbString(x4) << wbString(x5) << wbString(x6) << wbString(x7) + << wbString(x8) << wbString(x9) << wbString(x10); + + return ss.str(); +} + +template +static inline string +wbString(const T0 &x0, const T1 &x1, const T2 &x2, const T3 &x3, + const T4 &x4, const T5 &x5, const T6 &x6, const T7 &x7, + const T8 &x8, const T9 &x9, const T10 &x10, const T11 &x11) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2) << wbString(x3) + << wbString(x4) << wbString(x5) << wbString(x6) << wbString(x7) + << wbString(x8) << wbString(x9) << wbString(x10) << wbString(x11); + + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1, const T2 &x2, + const T3 &x3, const T4 &x4, const T5 &x5, + const T6 &x6, const T7 &x7, const T8 &x8, + const T9 &x9, const T10 &x10, const T11 &x11, + const T12 &x12) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2) << wbString(x3) + << wbString(x4) << wbString(x5) << wbString(x6) << wbString(x7) + << wbString(x8) << wbString(x9) << wbString(x10) << wbString(x11) + << wbString(x12); + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1, const T2 &x2, + const T3 &x3, const T4 &x4, const T5 &x5, + const T6 &x6, const T7 &x7, const T8 &x8, + const T9 &x9, const T10 &x10, const T11 &x11, + const T12 &x12, const T13 &x13) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2) << wbString(x3) + << wbString(x4) << wbString(x5) << wbString(x6) << wbString(x7) + << wbString(x8) << wbString(x9) << wbString(x10) << wbString(x11) + << wbString(x12) << wbString(x13); + return ss.str(); +} + +template +static inline wbBool wbString_sameQ(const X &x, const Y &y) { + string xs = wbString(x); + string ys = wbString(y); + return strcmp(xs.c_str(), ys.c_str()) == 0; +} + +static inline wbBool wbString_sameQ(const string &x, const string &y) { + return x.compare(y) == 0; +} + +static inline char *wbString_toLower(const char *str) { + if (str == NULL) { + return NULL; + } else { + char *res, *iter; + + res = iter = wbString_duplicate(str); + while (*iter != '\0') { + *iter++ = tolower(*str++); + } + return res; + } +} + +static inline wbBool wbString_startsWith(const char *str, + const char *prefix) { + while (*prefix != '\0') { + if (*str == '\0' || *str != *prefix) { + return wbFalse; + } + str++; + prefix++; + } + return wbTrue; +} + +#endif /* __WB_STRING_H__ */ diff --git a/CUDA_VectorAdd/libwb/wbThrust.h b/CUDA_VectorAdd/libwb/wbThrust.h new file mode 100644 index 0000000..e2d3160 --- /dev/null +++ b/CUDA_VectorAdd/libwb/wbThrust.h @@ -0,0 +1,15 @@ + +#ifndef __WB_THRUST_H__ +#define __WB_THRUST_H__ + +#ifdef WB_USE_CUDA +#include +#include +#include +#include +#include +#include + +#endif /* WB_USE_CUDA */ + +#endif /* __WB_THRUST_H__ */ diff --git a/CUDA_VectorAdd/libwb/wbTimer.cpp b/CUDA_VectorAdd/libwb/wbTimer.cpp new file mode 100644 index 0000000..c9fbdb8 --- /dev/null +++ b/CUDA_VectorAdd/libwb/wbTimer.cpp @@ -0,0 +1,493 @@ +#include "wb.h" + +#ifdef WB_USE_WINDOWS +uint64_t _hrtime_frequency = 0; +#endif /* WB_USE_WINDOWS */ +wbTimer_t _timer = NULL; + +#ifdef WB_USE_DARWIN +static double o_timebase = 0; +static uint64_t o_timestart = 0; +#endif /* WB_USE_DARWIN */ + +uint64_t _hrtime(void) { +#define NANOSEC ((uint64_t)1e9) +#ifdef WB_USE_WINDOWS + LARGE_INTEGER counter; + if (!QueryPerformanceCounter(&counter)) { + return 0; + } + return ((uint64_t)counter.LowPart * NANOSEC / _hrtime_frequency) + + (((uint64_t)counter.HighPart * NANOSEC / _hrtime_frequency) + << 32); +#else + struct timespec ts; +#ifdef WB_USE_DARWIN +#define O_NANOSEC (+1.0E-9) +#define O_GIGA UINT64_C(1000000000) + if (!o_timestart) { + mach_timebase_info_data_t tb{}; + mach_timebase_info(&tb); + o_timebase = tb.numer; + o_timebase /= tb.denom; + o_timestart = mach_absolute_time(); + } + double diff = (mach_absolute_time() - o_timestart) * o_timebase; + ts.tv_sec = diff * O_NANOSEC; + ts.tv_nsec = diff - (ts.tv_sec * O_GIGA); +#undef O_NANOSEC +#undef O_GIGA +#else /* WB_USE_DARWIN */ + clock_gettime(CLOCK_MONOTONIC, &ts); +#endif /* WB_USE_DARWIN */ + return (((uint64_t)ts.tv_sec) * NANOSEC + ts.tv_nsec); +#endif /* WB_USE_WINDOWS */ +#undef NANOSEC +} + +static inline uint64_t getTime(void) { +#ifdef WB_USE_CUDA + cudaDeviceSynchronize(); +#endif /* WB_USE_CUDA */ + return _hrtime(); +} + +static inline wbTimerNode_t wbTimerNode_new(int id, wbTimerKind_t kind, + const char *file, + const char *fun, + int startLine) { + wbTimerNode_t node = wbNew(struct st_wbTimerNode_t); + wbTimerNode_setId(node, id); + wbTimerNode_setMPIRank(node, wbMPI_getRank()); + wbTimerNode_setLevel(node, 0); + wbTimerNode_setStoppedQ(node, wbFalse); + wbTimerNode_setKind(node, kind); + wbTimerNode_setStartTime(node, 0); + wbTimerNode_setEndTime(node, 0); + wbTimerNode_setElapsedTime(node, 0); + wbTimerNode_setStartLine(node, startLine); + wbTimerNode_setEndLine(node, 0); + wbTimerNode_setStartFunction(node, fun); + wbTimerNode_setEndFunction(node, NULL); + wbTimerNode_setStartFile(node, file); + wbTimerNode_setEndFile(node, NULL); + wbTimerNode_setNext(node, NULL); + wbTimerNode_setPrevious(node, NULL); + wbTimerNode_setParent(node, NULL); + wbTimerNode_setMessage(node, NULL); + return node; +} + +static inline void wbTimerNode_delete(wbTimerNode_t node) { + if (node != NULL) { + if (wbTimerNode_getMessage(node)) { + wbDelete(wbTimerNode_getMessage(node)); + } + wbDelete(node); + } +} + +static inline const char *_nodeKind(wbTimerKind_t kind) { + switch (kind) { + case wbTimerKind_Generic: + return "Generic"; + case wbTimerKind_IO: + return "IO"; + case wbTimerKind_GPU: + return "GPU"; + case wbTimerKind_Copy: + return "Copy"; + case wbTimerKind_Driver: + return "Driver"; + case wbTimerKind_CopyAsync: + return "CopyAsync"; + case wbTimerKind_Compute: + return "Compute"; + case wbTimerKind_CPUGPUOverlap: + return "CPUGPUOverlap"; + } + return "Undefined"; +} + +static inline json11::Json wbTimerNode_toJSONObject(wbTimerNode_t node) { + json11::Json json = json11::Json::object{ + {"id", wbTimerNode_getId(node)}, + {"mpi_rank", wbTimerNode_getMPIRank(node)}, + {"stopped", wbTimerNode_stoppedQ(node)}, + {"kind", _nodeKind(wbTimerNode_getKind(node))}, + {"start_time", wbTimerNode_getStartTime(node)}, + {"end_time", wbTimerNode_getEndTime(node)}, + {"elapsed_time", wbTimerNode_getElapsedTime(node)}, + {"start_line", wbTimerNode_getStartLine(node)}, + {"end_line", wbTimerNode_getEndLine(node)}, + {"start_function", wbTimerNode_getStartFunction(node)}, + {"end_function", wbTimerNode_getEndFunction(node)}, + {"start_file", wbTimerNode_getStartFile(node)}, + {"end_file", wbTimerNode_getEndFile(node)}, + {"parent_id", wbTimerNode_hasParent(node) + ? wbTimerNode_getId(wbTimerNode_getParent(node)) + : -1}, + {"message", wbTimerNode_getMessage(node)}, + }; + return json; +} + +static inline string wbTimerNode_toJSON(wbTimerNode_t node) { + if (node == NULL) { + return ""; + } else if (WB_USE_JSON11) { + json11::Json json = wbTimerNode_toJSONObject(node); + return json.string_value(); + } else { + stringstream ss; + + ss << "{\n"; + ss << wbString_quote("id") << ":" << wbTimerNode_getId(node) << ",\n"; + ss << wbString_quote("mpi_rank") << ":" << wbTimerNode_getMPIRank(node) + << ",\n"; + ss << wbString_quote("stopped") << ":" + << wbString(wbTimerNode_stoppedQ(node) ? "true" : "false") << ",\n"; + ss << wbString_quote("kind") << ":" + << wbString_quote(_nodeKind(wbTimerNode_getKind(node))) << ",\n"; + ss << wbString_quote("start_time") << ":" + << wbTimerNode_getStartTime(node) << ",\n"; + ss << wbString_quote("end_time") << ":" << wbTimerNode_getEndTime(node) + << ",\n"; + ss << wbString_quote("elapsed_time") << ":" + << wbTimerNode_getElapsedTime(node) << ",\n"; + ss << wbString_quote("start_line") << ":" + << wbTimerNode_getStartLine(node) << ",\n"; + ss << wbString_quote("end_line") << ":" << wbTimerNode_getEndLine(node) + << ",\n"; + ss << wbString_quote("start_function") << ":" + << wbString_quote(wbTimerNode_getStartFunction(node)) << ",\n"; + ss << wbString_quote("end_function") << ":" + << wbString_quote(wbTimerNode_getEndFunction(node)) << ",\n"; + ss << wbString_quote("start_file") << ":" + << wbString_quote(wbTimerNode_getStartFile(node)) << ",\n"; + ss << wbString_quote("end_file") << ":" + << wbString_quote(wbTimerNode_getEndFile(node)) << ",\n"; + ss << wbString_quote("parent_id") << ":" + << wbString(wbTimerNode_hasParent(node) + ? wbTimerNode_getId(wbTimerNode_getParent(node)) + : -1) + << ",\n"; + ss << wbString_quote("message") << ":" + << wbString_quote(wbTimerNode_getMessage(node)) << "\n"; + ss << "}"; + + return ss.str(); + } +} + +static inline string wbTimerNode_toXML(wbTimerNode_t node) { + if (node == NULL) { + return ""; + } else { + stringstream ss; + + ss << "\n"; + ss << "" << wbTimerNode_getId(node) << "\n"; + ss << "" + << wbString(wbTimerNode_stoppedQ(node) ? "true" : "false") + << "\n"; + ss << "" << _nodeKind(wbTimerNode_getKind(node)) << "\n"; + ss << "" << wbTimerNode_getStartTime(node) + << "\n"; + ss << "" << wbTimerNode_getEndTime(node) << "\n"; + ss << "" << wbTimerNode_getElapsedTime(node) + << "\n"; + ss << "" << wbTimerNode_getStartLine(node) + << "\n"; + ss << "" << wbTimerNode_getEndLine(node) << "\n"; + ss << "" << wbTimerNode_getStartFunction(node) + << "\n"; + ss << "" << wbTimerNode_getEndFunction(node) + << "\n"; + ss << "" << wbTimerNode_getStartFile(node) + << "\n"; + ss << "" << wbTimerNode_getEndFile(node) << "\n"; + ss << "" + << wbString(wbTimerNode_hasParent(node) + ? wbTimerNode_getId(wbTimerNode_getParent(node)) + : -1) + << "\n"; + ss << "" << wbTimerNode_getMessage(node) << "\n"; + ss << "\n"; + + return ss.str(); + } +} + +#define wbTimer_getLength(timer) ((timer)->length) +#define wbTimer_getHead(timer) ((timer)->head) +#define wbTimer_getTail(timer) ((timer)->tail) +#define wbTimer_getStartTime(timer) ((timer)->startTime) +#define wbTimer_getEndTime(timer) ((timer)->endTime) +#define wbTimer_getElapsedTime(timer) ((timer)->elapsedTime) + +#define wbTimer_setLength(timer, val) (wbTimer_getLength(timer) = val) +#define wbTimer_setHead(timer, val) (wbTimer_getHead(timer) = val) +#define wbTimer_setTail(timer, val) (wbTimer_getTail(timer) = val) +#define wbTimer_setStartTime(node, val) (wbTimer_getStartTime(node) = val) +#define wbTimer_setEndTime(node, val) (wbTimer_getEndTime(node) = val) +#define wbTimer_setElapsedTime(node, val) \ + (wbTimer_getElapsedTime(node) = val) + +#define wbTimer_incrementLength(timer) (wbTimer_getLength(timer)++) +#define wbTimer_decrementLength(timer) (wbTimer_getLength(timer)--) + +#define wbTimer_emptyQ(timer) (wbTimer_getLength(timer) == 0) + +void wbTimer_delete(wbTimer_t timer) { + if (timer != NULL) { + wbTimerNode_t tmp, iter; + + iter = wbTimer_getHead(timer); + while (iter) { + tmp = wbTimerNode_getNext(iter); + wbTimerNode_delete(iter); + iter = tmp; + } + + wbDelete(timer); + } +} + +static json11::Json wbTimer_toJSONObject(wbTimer_t timer) { + + stringstream ss; + wbTimerNode_t iter; + uint64_t currentTime; + std::vector elems; + + currentTime = getTime(); + + wbTimer_setEndTime(timer, currentTime); + wbTimer_setElapsedTime(timer, currentTime - wbTimer_getStartTime(timer)); + + for (iter = wbTimer_getHead(timer); iter != NULL; + iter = wbTimerNode_getNext(iter)) { + if (!wbTimerNode_stoppedQ(iter)) { + wbTimerNode_setEndTime(iter, currentTime); + wbTimerNode_setElapsedTime(iter, currentTime - + wbTimerNode_getStartTime(iter)); + } + elems.push_back(wbTimerNode_toJSONObject(iter)); + } + return json11::Json(elems); +} + +string wbTimer_toJSON(wbTimer_t timer) { + if (timer == NULL) { + return ""; + } else if (WB_USE_JSON11) { + json11::Json json = wbTimer_toJSONObject(timer); + return json.string_value(); + } else { + stringstream ss; + wbTimerNode_t iter; + uint64_t currentTime; + + currentTime = getTime(); + + wbTimer_setEndTime(timer, currentTime); + wbTimer_setElapsedTime(timer, + currentTime - wbTimer_getStartTime(timer)); + + for (iter = wbTimer_getHead(timer); iter != NULL; + iter = wbTimerNode_getNext(iter)) { + if (!wbTimerNode_stoppedQ(iter)) { + wbTimerNode_setEndTime(iter, currentTime); + wbTimerNode_setElapsedTime( + iter, currentTime - wbTimerNode_getStartTime(iter)); + } + ss << wbTimerNode_toJSON(iter); + if (wbTimerNode_getNext(iter) != NULL) { + ss << ",\n"; + } + } + + return ss.str(); + } +} + +string wbTimer_toJSON() { + return wbTimer_toJSON(_timer); +} + +string wbTimer_toXML(wbTimer_t timer) { + if (timer == NULL) { + return ""; + } else { + stringstream ss; + wbTimerNode_t iter; + uint64_t currentTime; + + currentTime = getTime(); + + wbTimer_setEndTime(timer, currentTime); + wbTimer_setElapsedTime(timer, + currentTime - wbTimer_getStartTime(timer)); + + ss << "\n"; + ss << "" << wbTimer_getStartTime(timer) + << "\n"; + ss << "" << wbTimer_getEndTime(timer) << "\n"; + ss << "" << wbTimer_getElapsedTime(timer) + << "\n"; + ss << "\n"; + for (iter = wbTimer_getHead(timer); iter != NULL; + iter = wbTimerNode_getNext(iter)) { + if (!wbTimerNode_stoppedQ(iter)) { + wbTimerNode_setEndTime(iter, currentTime); + wbTimerNode_setElapsedTime( + iter, currentTime - wbTimerNode_getStartTime(iter)); + } + ss << wbTimerNode_toXML(iter); + } + ss << "\n"; + ss << "\n"; + + return ss.str(); + } +} + +string wbTimer_toXML() { + return wbTimer_toXML(_timer); +} + +wbTimer_t wbTimer_new(void) { + wbTimer_t timer = wbNew(struct st_wbTimer_t); + wbTimer_setLength(timer, 0); + wbTimer_setHead(timer, NULL); + wbTimer_setTail(timer, NULL); + wbTimer_setStartTime(timer, getTime()); + wbTimer_setEndTime(timer, 0); + wbTimer_setElapsedTime(timer, 0); + + return timer; +} + +static inline wbTimerNode_t _findParent(wbTimer_t timer) { + wbTimerNode_t iter; + + for (iter = wbTimer_getTail(timer); iter != NULL; + iter = wbTimerNode_getPrevious(iter)) { + if (!wbTimerNode_stoppedQ(iter)) { + return iter; + } + } + return NULL; +} + +static inline void _insertIntoList(wbTimer_t timer, wbTimerNode_t node) { + if (wbTimer_emptyQ(timer)) { + wbTimer_setHead(timer, node); + wbTimer_setTail(timer, node); + } else { + wbTimerNode_t end = wbTimer_getTail(timer); + wbTimer_setTail(timer, node); + wbTimerNode_setNext(end, node); + wbTimerNode_setPrevious(node, end); + } + wbTimer_incrementLength(timer); +} + +wbTimerNode_t wbTimer_start(wbTimerKind_t kind, const char *file, + const char *fun, int line) { + int id; + uint64_t currentTime; + wbTimerNode_t node; + wbTimerNode_t parent; + + wb_init(NULL, NULL); + + currentTime = getTime(); + + id = wbTimer_getLength(_timer); + + node = wbTimerNode_new(id, kind, file, fun, line); + + parent = _findParent(_timer); + _insertIntoList(_timer, node); + + wbTimerNode_setStartTime(node, currentTime); + wbTimerNode_setParent(node, parent); + if (parent != NULL) { + wbTimerNode_setLevel(node, wbTimerNode_getLevel(parent) + 1); + } + + return node; +} + +wbTimerNode_t wbTimer_start(wbTimerKind_t kind, string msg, + const char *file, const char *fun, int line) { + wbTimerNode_t node = wbTimer_start(kind, file, fun, line); + wbTimerNode_setMessage(node, wbString_duplicate(msg)); + return node; +} + +static inline wbTimerNode_t _findNode(wbTimer_t timer, wbTimerKind_t kind, + string msg) { + wbTimerNode_t iter; + + for (iter = wbTimer_getTail(timer); iter != NULL; + iter = wbTimerNode_getPrevious(iter)) { + if (msg == "") { + if (!wbTimerNode_stoppedQ(iter) && + wbTimerNode_getKind(iter) == kind) { + return iter; + } + } else { + if (!wbTimerNode_stoppedQ(iter) && + wbTimerNode_getKind(iter) == kind && + msg == wbTimerNode_getMessage(iter)) { + return iter; + } + } + } + return NULL; +} + +void wbTimer_stop(wbTimerKind_t kind, string msg, const char *file, + const char *fun, int line) { + uint64_t currentTime; + wbTimerNode_t node; + + currentTime = getTime(); + + node = _findNode(_timer, kind, msg); + + wbAssert(node != NULL); + if (node == NULL) { + return; + } + + wbTimerNode_setEndTime(node, currentTime); + wbTimerNode_setElapsedTime(node, + currentTime - wbTimerNode_getStartTime(node)); + wbTimerNode_setEndLine(node, line); + wbTimerNode_setEndFunction(node, fun); + wbTimerNode_setEndFile(node, file); + wbTimerNode_setStoppedQ(node, wbTrue); + +#ifdef wbLogger_printOnLog + if (wbLogger_printOnLog) { + json11::Json json = json11::Json::object{ +//PMO +#ifndef _MSC_VER + { "type", "timer" }, { "data", wbTimerNode_toJSONObject(node) }}; +#else + { "data", wbTimerNode_toJSONObject(node) }, { "type", "timer" }}; +#endif + std::cout << json.dump() << std::endl; + } +#endif /* wbLogger_printOnLog */ + return; +} + +void wbTimer_stop(wbTimerKind_t kind, const char *file, const char *fun, + int line) { + wbTimer_stop(kind, "", file, fun, line); +} diff --git a/CUDA_VectorAdd/libwb/wbTimer.h b/CUDA_VectorAdd/libwb/wbTimer.h new file mode 100644 index 0000000..133b58f --- /dev/null +++ b/CUDA_VectorAdd/libwb/wbTimer.h @@ -0,0 +1,139 @@ + + +#ifndef __WB_TIMER_H__ +#define __WB_TIMER_H__ + +#ifdef WB_USE_WINDOWS +extern uint64_t _hrtime_frequency; +#endif /* _WIN32 */ + +extern wbTimer_t _timer; + +typedef enum en_wbTimerKind_t { + wbTimerKind_Generic, + wbTimerKind_IO, + wbTimerKind_GPU, + wbTimerKind_Copy, + wbTimerKind_Driver, + wbTimerKind_CopyAsync, + wbTimerKind_Compute, + wbTimerKind_CPUGPUOverlap, +} wbTimerKind_t; + +struct st_wbTimerNode_t { + int id; + int mpiRank; + int level; + wbBool stoppedQ; + wbTimerKind_t kind; + uint64_t startTime; + uint64_t endTime; + uint64_t elapsedTime; + int startLine; + int endLine; + const char *startFunction; + const char *endFunction; + const char *startFile; + const char *endFile; + wbTimerNode_t next; + wbTimerNode_t prev; + wbTimerNode_t parent; + char *msg; +}; + +struct st_wbTimer_t { + size_t length; + wbTimerNode_t head; + wbTimerNode_t tail; + uint64_t startTime; + uint64_t endTime; + uint64_t elapsedTime; +}; + +#define wbTimerNode_getId(node) ((node)->id) +#define wbTimerNode_getMPIRank(node) ((node)->mpiRank) +#define wbTimerNode_getLevel(node) ((node)->level) +#define wbTimerNode_getStoppedQ(node) ((node)->stoppedQ) +#define wbTimerNode_getKind(node) ((node)->kind) +#define wbTimerNode_getStartTime(node) ((node)->startTime) +#define wbTimerNode_getEndTime(node) ((node)->endTime) +#define wbTimerNode_getElapsedTime(node) ((node)->elapsedTime) +#define wbTimerNode_getStartLine(node) ((node)->startLine) +#define wbTimerNode_getEndLine(node) ((node)->endLine) +#define wbTimerNode_getStartFunction(node) ((node)->startFunction) +#define wbTimerNode_getEndFunction(node) ((node)->endFunction) +#define wbTimerNode_getStartFile(node) ((node)->startFile) +#define wbTimerNode_getEndFile(node) ((node)->endFile) +#define wbTimerNode_getNext(node) ((node)->next) +#define wbTimerNode_getPrevious(node) ((node)->prev) +#define wbTimerNode_getParent(node) ((node)->parent) +#define wbTimerNode_getMessage(node) ((node)->msg) + +#define wbTimerNode_setId(node, val) (wbTimerNode_getId(node) = val) +#define wbTimerNode_setMPIRank(node, val) \ + (wbTimerNode_getMPIRank(node) = val) +#define wbTimerNode_setLevel(node, val) (wbTimerNode_getLevel(node) = val) +#define wbTimerNode_setStoppedQ(node, val) \ + (wbTimerNode_getStoppedQ(node) = val) +#define wbTimerNode_setKind(node, val) (wbTimerNode_getKind(node) = val) +#define wbTimerNode_setStartTime(node, val) \ + (wbTimerNode_getStartTime(node) = val) +#define wbTimerNode_setEndTime(node, val) \ + (wbTimerNode_getEndTime(node) = val) +#define wbTimerNode_setElapsedTime(node, val) \ + (wbTimerNode_getElapsedTime(node) = val) +#define wbTimerNode_setStartLine(node, val) \ + (wbTimerNode_getStartLine(node) = val) +#define wbTimerNode_setEndLine(node, val) \ + (wbTimerNode_getEndLine(node) = val) +#define wbTimerNode_setStartFunction(node, val) \ + (wbTimerNode_getStartFunction(node) = val) +#define wbTimerNode_setEndFunction(node, val) \ + (wbTimerNode_getEndFunction(node) = val) +#define wbTimerNode_setStartFile(node, val) \ + (wbTimerNode_getStartFile(node) = val) +#define wbTimerNode_setEndFile(node, val) \ + (wbTimerNode_getEndFile(node) = val) +#define wbTimerNode_setNext(node, val) (wbTimerNode_getNext(node) = val) +#define wbTimerNode_setPrevious(node, val) \ + (wbTimerNode_getPrevious(node) = val) +#define wbTimerNode_setParent(node, val) \ + (wbTimerNode_getParent(node) = val) +#define wbTimerNode_setMessage(node, val) \ + (wbTimerNode_getMessage(node) = val) + +#define wbTimerNode_stoppedQ(node) \ + (wbTimerNode_getStoppedQ(node) == wbTrue) +#define wbTimerNode_hasNext(node) (wbTimerNode_getNext(node) != NULL) +#define wbTimerNode_hasPrevious(node) \ + (wbTimerNode_getPrevious(node) != NULL) +#define wbTimerNode_hasParent(node) (wbTimerNode_getParent(node) != NULL) + +uint64_t _hrtime(void); + +wbTimer_t wbTimer_new(void); +void wbTimer_delete(wbTimer_t timer); + +string wbTimer_toJSON(wbTimer_t timer); +string wbTimer_toJSON(); + +string wbTimer_toXML(wbTimer_t timer); +string wbTimer_toXML(); + +wbTimerNode_t wbTimer_start(wbTimerKind_t kind, const char *file, + const char *fun, int line); +wbTimerNode_t wbTimer_start(wbTimerKind_t kind, string msg, + const char *file, const char *fun, int line); +void wbTimer_stop(wbTimerKind_t kind, string msg, const char *file, + const char *fun, int line); +void wbTimer_stop(wbTimerKind_t kind, const char *file, const char *fun, + int line); + +#define wbTime_start(kind, ...) \ + wbTimer_start(wbTimerKind_##kind, wbString(__VA_ARGS__), wbFile, \ + wbFunction, wbLine) +#define wbTime_stop(kind, ...) \ + wbTimer_stop(wbTimerKind_##kind, wbString(__VA_ARGS__), wbFile, \ + wbFunction, wbLine) + +#endif /* __WB_TIMER_H__ */ diff --git a/CUDA_VectorAdd/libwb/wbTypes.h b/CUDA_VectorAdd/libwb/wbTypes.h new file mode 100644 index 0000000..6837792 --- /dev/null +++ b/CUDA_VectorAdd/libwb/wbTypes.h @@ -0,0 +1,55 @@ + + +#ifndef __WB_TYPES_H__ +#define __WB_TYPES_H__ + +#include "wbAssert.h" + +typedef bool wbBool; +typedef float wbReal_t; +typedef char wbChar_t; + +typedef struct st_wbTimerNode_t *wbTimerNode_t; +typedef struct st_wbTimer_t *wbTimer_t; +typedef struct st_wbLogEntry_t *wbLogEntry_t; +typedef struct st_wbLogger_t *wbLogger_t; +typedef struct st_wbArg_t wbArg_t; +typedef struct st_wbImage_t *wbImage_t; +typedef struct st_wbFile_t *wbFile_t; + +#define wbTrue true +#define wbFalse false + +typedef enum en_wbType_t { + wbType_unknown = -1, + wbType_ascii = 1, + wbType_bit8, + wbType_ubit8, + wbType_integer, + wbType_float, + wbType_double +} wbType_t; + +static inline size_t wbType_size(wbType_t ty) { + switch (ty) { + case wbType_unknown: + wbAssert(false && "Invalid wbType_unknown"); + return 0; + case wbType_ascii: + return sizeof(char); + case wbType_bit8: + return sizeof(char); + case wbType_ubit8: + return sizeof(unsigned char); + case wbType_integer: + return sizeof(int); + case wbType_float: + return sizeof(float); + case wbType_double: + return sizeof(double); + } + wbAssert(false && "Invalid type"); + return 0; +} + +#endif /* __WB_TYPES_H__ */ diff --git a/CUDA_VectorAdd/libwb/wbUtils.h b/CUDA_VectorAdd/libwb/wbUtils.h new file mode 100644 index 0000000..cbd1b91 --- /dev/null +++ b/CUDA_VectorAdd/libwb/wbUtils.h @@ -0,0 +1,10 @@ +#ifndef __WB_UTILS_H__ +#define __WB_UTILS_H__ + +#ifdef WB_DEBUG +#define DEBUG(...) __VA_ARGS__ +#else /* WB_DEBUG */ +#define DEBUG(...) +#endif /* WB_DEBUG */ + +#endif /* __WB_UTILS_H__ */ diff --git a/CUDA_VectorAdd/libwb/wb_test.cpp b/CUDA_VectorAdd/libwb/wb_test.cpp new file mode 100644 index 0000000..87883c8 --- /dev/null +++ b/CUDA_VectorAdd/libwb/wb_test.cpp @@ -0,0 +1,4 @@ +#define CATCH_CONFIG_MAIN + +#include "wb.h" +#include "vendor/catch.hpp" diff --git a/OpenCL_VectorAdd/VectorAdd/template.cpp b/OpenCL_VectorAdd/VectorAdd/template.cpp new file mode 100644 index 0000000..0868d7a --- /dev/null +++ b/OpenCL_VectorAdd/VectorAdd/template.cpp @@ -0,0 +1,146 @@ +#include +#include +#include +#include +#include + +//@@ OpenCL kernel +//const char *kernelSource = ""; + +const char *kernelSource = +"__kernel void vadd( __global const float *a, \n" +" __global const float *b, \n" +" __global float *result, \n" +" unsigned int n) \n" +"{ \n" +" int id = get_global_id(0); \n" +" if (id < n) \n" +" { \n" +" result[id] = a[id] + b[id]; \n" +" } \n" +"} \n"; + + +int main(int argc, char *argv[]) { + wbArg_t args; + int inputLength; + int inputLengthBytes; + float *hostInput1; + float *hostInput2; + float *hostOutput; + cl_mem deviceInput1; + cl_mem deviceInput2; + cl_mem deviceOutput; + deviceInput1 = NULL; + deviceInput2 = NULL; + deviceOutput = NULL; + + cl_platform_id cpPlatform; // OpenCL platform + cl_device_id device_id; // device ID + cl_context context; // context + cl_command_queue queue; // command queue + cl_program program; // program + cl_kernel kernel; // kernel + + context = NULL; + queue = NULL; + program = NULL; + kernel = NULL; + + args = wbArg_read(argc, argv); + + wbTime_start(Generic, "Importing data and creating memory on host"); + hostInput1 = + (float *)wbImport(wbArg_getInputFile(args, 0), &inputLength); + hostInput2 = + (float *)wbImport(wbArg_getInputFile(args, 1), &inputLength); + inputLengthBytes = inputLength * sizeof(float); + hostOutput = (float *)malloc(inputLengthBytes); + wbTime_stop(Generic, "Importing data and creating memory on host"); + + wbLog(TRACE, "The input length is ", inputLength); + wbLog(TRACE, "The input size is ", inputLengthBytes, " bytes"); + + cl_int clerr = CL_SUCCESS; + + //@@ Initialize the workgroup dimensions + + size_t localSize = 64; + size_t globalSize = ceil(inputLength / (float) localSize) * localSize; + + //@@ Bind to platform + + clerr = clGetPlatformIDs(1, &cpPlatform, NULL); + + //@@ Get ID for the device + + clerr = clGetDeviceIDs(cpPlatform, CL_DEVICE_TYPE_GPU, 1, &device_id, NULL); + + //@@ Create a context + + context = clCreateContext(0, 1, &device_id, NULL, NULL, &clerr); + + //@@ Create a command queue + + queue = clCreateCommandQueue(context, device_id, 0, &clerr); + + //@@ Create the compute program from the source buffer + + program = clCreateProgramWithSource(context, 1, (const char **) &kernelSource, NULL, &clerr); + + //@@ Build the program executable + + clBuildProgram(program, 0, NULL, NULL, NULL, NULL); + + //@@ Create the compute kernel + + kernel = clCreateKernel(program, "vadd", &clerr); + + //@@ Create the input and output arrays in device memory for calculation + + deviceInput1 = clCreateBuffer(context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, inputLengthBytes, hostInput1, NULL); + deviceInput2 = clCreateBuffer(context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, inputLengthBytes, hostInput2, NULL); + deviceOutput = clCreateBuffer(context, CL_MEM_WRITE_ONLY, inputLengthBytes, NULL, NULL); + + //@@ Write data set into the input array in device memory + + clerr = clEnqueueWriteBuffer(queue, deviceInput1, CL_TRUE, 0, inputLengthBytes, hostInput1, 0, NULL, NULL); + clerr |= clEnqueueWriteBuffer(queue, deviceInput2, CL_TRUE, 0, inputLengthBytes, hostInput2, 0, NULL, NULL); + + //@@ Set the arguments to compute kernel + + clerr = clSetKernelArg(kernel, 0, sizeof(cl_mem), &deviceInput1); + clerr |= clSetKernelArg(kernel, 1, sizeof(cl_mem), &deviceInput2); + clerr |= clSetKernelArg(kernel, 2, sizeof(cl_mem), &deviceOutput); + clerr |= clSetKernelArg(kernel, 3, sizeof(unsigned int), &inputLength); + + //@@ Execute the kernel over the entire range of the data set + + clerr = clEnqueueNDRangeKernel(queue, kernel, 1, NULL, &globalSize, &localSize, 0, NULL, NULL); + + //@@ Wait for the command queue to get serviced before reading back results + + clFinish(queue); + + //@@ Read the results from the device + + clEnqueueReadBuffer(queue, deviceOutput, CL_FALSE, 0, inputLengthBytes, hostOutput, 0, NULL, NULL); + + wbSolution(args, hostOutput, inputLength); + + // release OpenCL resources + clReleaseMemObject(deviceInput1); + clReleaseMemObject(deviceInput2); + clReleaseMemObject(deviceOutput); + clReleaseProgram(program); + clReleaseKernel(kernel); + clReleaseCommandQueue(queue); + clReleaseContext(context); + + // release host memory + free(hostInput1); + free(hostInput2); + free(hostOutput); + + return 0; +} diff --git a/OpenCL_VectorAdd/libwb/.clang-format b/OpenCL_VectorAdd/libwb/.clang-format new file mode 100644 index 0000000..4757ed4 --- /dev/null +++ b/OpenCL_VectorAdd/libwb/.clang-format @@ -0,0 +1,21 @@ +--- +Language: Cpp +BasedOnStyle: LLVM +ColumnLimit: 75 +AccessModifierOffset: -2 +BreakBeforeBraces: Attach +AlignTrailingComments: true +AlignEscapedNewlinesLeft: false +AlignConsecutiveAssignments: true +AlignOperands: true +AllowShortFunctionsOnASingleLine: false +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AlwaysBreakTemplateDeclarations: true +IndentCaseLabels: true +SpacesBeforeTrailingComments: 1 +Standard: Cpp11 +TabWidth: 4 +UseTab: Never +SortIncludes: false +... diff --git a/OpenCL_VectorAdd/libwb/.travis.yml b/OpenCL_VectorAdd/libwb/.travis.yml new file mode 100644 index 0000000..e32c621 --- /dev/null +++ b/OpenCL_VectorAdd/libwb/.travis.yml @@ -0,0 +1,65 @@ +# Use new trusty images, should yield newer compilers and packages +sudo: required +dist: precise +language: cpp + +matrix: + include: + - compiler: gcc + addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - g++-4.9 + env: COMPILER=g++-4.9 + - compiler: gcc + addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - g++-5 + env: COMPILER=g++-5 + - compiler: clang + addons: + apt: + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-precise-3.6 + packages: + - clang-3.6 + env: COMPILER=clang++-3.6 + - compiler: clang + addons: + apt: + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-precise-3.7 + packages: + - clang-3.7 + env: COMPILER=clang++-3.7 +# - compiler: gcc +# addons: +# apt: +# sources: +# - ubuntu-toolchain-r-test +# packages: +# - g++-6 +# env: COMPILER=g++-6 + # - compiler: clang + # addons: + # apt: + # sources: + # - ubuntu-toolchain-r-test + # - llvm-toolchain-precise-3.8 + # packages: + # - clang-3.8 + # env: COMPILER=clang++-3.8 + +before_install: + - sudo apt-get update -qq +script: + - $COMPILER --version + - make CXX=$COMPILER test + - ./test diff --git a/OpenCL_VectorAdd/libwb/CMakeLists.txt b/OpenCL_VectorAdd/libwb/CMakeLists.txt new file mode 100644 index 0000000..f732c32 --- /dev/null +++ b/OpenCL_VectorAdd/libwb/CMakeLists.txt @@ -0,0 +1,34 @@ +cmake_minimum_required(VERSION 2.8 FATAL_ERROR) + +set(CMAKE_BUILD_TYPE Release) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) +set(CMAKE_COLOR_MAKEFILE ON) +set(VERBOSE_BUILD ON) +set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) +set(CMAKE_MACOSX_RPATH TRUE) +set_property(GLOBAL PROPERTY USE_FOLDERS ON) + + +project(wb) + +set(current_dir "${CMAKE_CURRENT_SOURCE_DIR}") + +if(NOT EXISTS "${CMAKE_CURRENT_BINARY_DIR}/cotire.cmake") + file(DOWNLOAD "https://raw.githubusercontent.com/sakra/cotire/master/CMake/cotire.cmake" "${CMAKE_CURRENT_BINARY_DIR}/cotire.cmake") +endif() + + + +include(${current_dir}/sources.cmake) + +set(WBLIB_STATIC ${WBLIB}) +set(WBLIB_SHARED lib${WBLIB}) + +add_library(${WBLIB_STATIC} STATIC ${LIBWB_SOURCE_FILES} ) +add_library(${WBLIB_SHARED} SHARED ${LIBWB_SOURCE_FILES} ) +set_property(TARGET ${WBLIB_STATIC} PROPERTY CXX_STANDARD 11) +set_property(TARGET ${WBLIB_SHARED} PROPERTY CXX_STANDARD 11) +if (UNIX) + set_target_properties(${WBLIB_SHARED} PROPERTIES OUTPUT_NAME ${WBLIB_STATIC}) +endif (UNIX) +set_property(TARGET ${WBLIB} PROPERTY CXX_STANDARD 11) diff --git a/OpenCL_VectorAdd/libwb/LICENSE.TXT b/OpenCL_VectorAdd/libwb/LICENSE.TXT new file mode 100644 index 0000000..8df244d --- /dev/null +++ b/OpenCL_VectorAdd/libwb/LICENSE.TXT @@ -0,0 +1,36 @@ +Copyright (c) 2016, Abdul Dakkak All rights reserved. + +Developed by: Abdul Dakkak + IMPACT Group + University of Illinois, Urbana-Champaign + impact.crhc.illinois.edu + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal with the +Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, +sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +Redistributions of source code must retain the above +copyright notice, this list of conditions and the following +disclaimers. +Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following +disclaimers in the documentation and/or other materials +provided with the distribution. +Neither the names of Abdul Dakkak, Impact Group, nor the +names of its contributors may be used to endorse or promote +products derived from this Software without specific prior +written permission. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +WITH THE SOFTWARE. diff --git a/OpenCL_VectorAdd/libwb/Makefile b/OpenCL_VectorAdd/libwb/Makefile new file mode 100644 index 0000000..b8a72d7 --- /dev/null +++ b/OpenCL_VectorAdd/libwb/Makefile @@ -0,0 +1,56 @@ +########################################## +# Options +########################################## +WB_LIB_PATH=$(CURDIR)/lib +WB_SRC_PATH=$(CURDIR) + +########################################## +########################################## + +DEFINES= +CXX_FLAGS=-fPIC -Wno-unused-function -x c++ -O3 -g -std=c++11 -Wall -Wno-unused-function -pedantic -I . -I $(WB_SRC_PATH) $(DEFINES) +LIBS=-lm -lstdc++ + +########################################## +########################################## + +UNAME_S := $(shell uname -s) +ifeq ($(UNAME_S),Linux) + LIBS += -lrt +endif + +########################################## +########################################## + +SOURCES := $(shell find $(WB_SRC_PATH) ! -name "*_test.cpp" -name "*.cpp") +TESTS := $(shell find $(WB_SRC_PATH) -name "*_test.cpp") + +OBJECTS = $(SOURCES:.cpp=.o) +TESTOBJECTS = $(TESTS:.cpp=.o) + +############################################## +# OUTPUT +############################################## + +.PHONY: all +.SUFFIXES: .o .cpp +all: libwb.so + +.cpp.o: + $(CXX) $(DEFINES) $(CXX_FLAGS) -c -o $@ $< + +libwb.so: $(OBJECTS) + mkdir -p $(WB_LIB_PATH) + $(CXX) -fPIC -shared -o $(WB_LIB_PATH)/$@ $(OBJECTS) $(LIBS) + +libwb.a: $(OBJECTS) + mkdir -p $(WB_LIB_PATH) + ar rcs -o $(WB_LIB_PATH)/$@ $(OBJECTS) + +test: $(TESTOBJECTS) $(OBJECTS) + $(CXX) -fPIC -o $@ $(TESTOBJECTS) $(OBJECTS) $(LIBS) + + +clean: + rm -fr $(ARCH) + -rm -f $(EXES) *.o *~ \ No newline at end of file diff --git a/OpenCL_VectorAdd/libwb/README.md b/OpenCL_VectorAdd/libwb/README.md new file mode 100644 index 0000000..0486f93 --- /dev/null +++ b/OpenCL_VectorAdd/libwb/README.md @@ -0,0 +1,7 @@ + +# libWB + +[![Travis Build Status](https://travis-ci.org/abduld/libwb.svg?branch=master)](https://travis-ci.org/abduld/libwb) +[![AppVeyor status](https://ci.appveyor.com/api/projects/status/0nx5ie7gn5c0e6ai/branch/master?svg=true)](https://ci.appveyor.com/project/abduld/libwb/branch/master) + \ No newline at end of file diff --git a/OpenCL_VectorAdd/libwb/appveyor.yml b/OpenCL_VectorAdd/libwb/appveyor.yml new file mode 100644 index 0000000..e7a6c95 --- /dev/null +++ b/OpenCL_VectorAdd/libwb/appveyor.yml @@ -0,0 +1,54 @@ + + +# Operating system (build VM template) +os: + - Visual Studio 2015 + + +# scripts that are called at very beginning, before repo cloning +init: + - echo init step + - git config --global core.autocrlf input + - cmake --version + - C:\"Program Files (x86)"\"Microsoft Visual Studio 14.0"\VC\vcvarsall.bat %PLATFORM% + +# clone directory +clone_folder: c:\projects\libwb +# fetch repository as zip archive +shallow_clone: true # default is "false" + +# branches to build +branches: + # whitelist + only: + - master + +platform: + - x64 +configuration: + - Release + +environment: + P: "c:/projects/libs" + + +install: + # by default, all script lines are interpreted as batch + +build: + project: ALL_BUILD.vcxproj # path to Visual Studio solution or project + +# scripts to run before build +before_build: + - echo Running cmake... + - cd c:\projects\libwb + - cmake -G "Visual Studio 14 2015 Win64" -DCMAKE_INSTALL_PREFIX=%P% + +# after_build: +# - echo after_build step + + +# on_finish always executes regardless of passed or failed builds +# on_finish: +# - echo on_finish step +# - ps: ls \ No newline at end of file diff --git a/OpenCL_VectorAdd/libwb/sources.cmake b/OpenCL_VectorAdd/libwb/sources.cmake new file mode 100644 index 0000000..4ac1b10 --- /dev/null +++ b/OpenCL_VectorAdd/libwb/sources.cmake @@ -0,0 +1,31 @@ + +set(WBLIB "wb") + +include_directories(${CMAKE_CURRENT_LIST_DIR}) + +file(GLOB THESE_CPP_FILES + ${CMAKE_CURRENT_LIST_DIR}/*.cpp +) + +file(GLOB THESE_TEST_FILES + ${CMAKE_CURRENT_LIST_DIR}/*_test.cpp +) + +list(REMOVE_ITEM THESE_CPP_FILES ${THESE_TEST_FILES}) + +file(GLOB THESE_HEADER_FILES + ${CMAKE_CURRENT_LIST_DIR}/*.h +) + +list(APPEND LIBWB_HEADER_FILES + ${THESE_HEADER_FILES} +) + +list(APPEND LIBWB_SOURCE_FILES + ${THESE_CPP_FILES} + ${CMAKE_CURRENT_LIST_DIR}/vendor/json11.cpp +) + +list(APPEND LIBWB_TEST_FILES + ${THESE_TEST_FILES} +) diff --git a/OpenCL_VectorAdd/libwb/vendor/catch.hpp b/OpenCL_VectorAdd/libwb/vendor/catch.hpp new file mode 100644 index 0000000..f52eebd --- /dev/null +++ b/OpenCL_VectorAdd/libwb/vendor/catch.hpp @@ -0,0 +1,10414 @@ +/* + * Catch v1.3.6 + * Generated: 2016-03-11 18:30:42.852700 + * ---------------------------------------------------------- + * This file has been merged from multiple headers. Please don't edit it directly + * Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved. + * + * Distributed under the Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + */ +#ifndef TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED +#define TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED + +#define TWOBLUECUBES_CATCH_HPP_INCLUDED + +#ifdef __clang__ +# pragma clang system_header +#elif defined __GNUC__ +# pragma GCC system_header +#endif + +// #included from: internal/catch_suppress_warnings.h + +#ifdef __clang__ +# ifdef __ICC // icpc defines the __clang__ macro +# pragma warning(push) +# pragma warning(disable: 161 1682) +# else // __ICC +# pragma clang diagnostic ignored "-Wglobal-constructors" +# pragma clang diagnostic ignored "-Wvariadic-macros" +# pragma clang diagnostic ignored "-Wc99-extensions" +# pragma clang diagnostic ignored "-Wunused-variable" +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wpadded" +# pragma clang diagnostic ignored "-Wc++98-compat" +# pragma clang diagnostic ignored "-Wc++98-compat-pedantic" +# pragma clang diagnostic ignored "-Wswitch-enum" +# pragma clang diagnostic ignored "-Wcovered-switch-default" +# endif +#elif defined __GNUC__ +# pragma GCC diagnostic ignored "-Wvariadic-macros" +# pragma GCC diagnostic ignored "-Wunused-variable" +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wpadded" +#endif +#if defined(CATCH_CONFIG_MAIN) || defined(CATCH_CONFIG_RUNNER) +# define CATCH_IMPL +#endif + +#ifdef CATCH_IMPL +# ifndef CLARA_CONFIG_MAIN +# define CLARA_CONFIG_MAIN_NOT_DEFINED +# define CLARA_CONFIG_MAIN +# endif +#endif + +// #included from: internal/catch_notimplemented_exception.h +#define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_H_INCLUDED + +// #included from: catch_common.h +#define TWOBLUECUBES_CATCH_COMMON_H_INCLUDED + +#define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line +#define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) +#define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ ) + +#define INTERNAL_CATCH_STRINGIFY2( expr ) #expr +#define INTERNAL_CATCH_STRINGIFY( expr ) INTERNAL_CATCH_STRINGIFY2( expr ) + +#include +#include +#include + +// #included from: catch_compiler_capabilities.h +#define TWOBLUECUBES_CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED + +// Detect a number of compiler features - mostly C++11/14 conformance - by compiler +// The following features are defined: +// +// CATCH_CONFIG_CPP11_NULLPTR : is nullptr supported? +// CATCH_CONFIG_CPP11_NOEXCEPT : is noexcept supported? +// CATCH_CONFIG_CPP11_GENERATED_METHODS : The delete and default keywords for compiler generated methods +// CATCH_CONFIG_CPP11_IS_ENUM : std::is_enum is supported? +// CATCH_CONFIG_CPP11_TUPLE : std::tuple is supported +// CATCH_CONFIG_CPP11_LONG_LONG : is long long supported? +// CATCH_CONFIG_CPP11_OVERRIDE : is override supported? +// CATCH_CONFIG_CPP11_UNIQUE_PTR : is unique_ptr supported (otherwise use auto_ptr) + +// CATCH_CONFIG_CPP11_OR_GREATER : Is C++11 supported? + +// CATCH_CONFIG_VARIADIC_MACROS : are variadic macros supported? + +// **************** +// Note to maintainers: if new toggles are added please document them +// in configuration.md, too +// **************** + +// In general each macro has a _NO_ form +// (e.g. CATCH_CONFIG_CPP11_NO_NULLPTR) which disables the feature. +// Many features, at point of detection, define an _INTERNAL_ macro, so they +// can be combined, en-mass, with the _NO_ forms later. + +// All the C++11 features can be disabled with CATCH_CONFIG_NO_CPP11 + +#if defined(__cplusplus) && __cplusplus >= 201103L +# define CATCH_CPP11_OR_GREATER +#endif + +#ifdef __clang__ + +# if __has_feature(cxx_nullptr) +# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR +# endif + +# if __has_feature(cxx_noexcept) +# define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT +# endif + +# if defined(CATCH_CPP11_OR_GREATER) +# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS _Pragma( "clang diagnostic ignored \"-Wparentheses\"" ) +# endif + +#endif // __clang__ + +//////////////////////////////////////////////////////////////////////////////// +// Borland +#ifdef __BORLANDC__ + +#endif // __BORLANDC__ + +//////////////////////////////////////////////////////////////////////////////// +// EDG +#ifdef __EDG_VERSION__ + +#endif // __EDG_VERSION__ + +//////////////////////////////////////////////////////////////////////////////// +// Digital Mars +#ifdef __DMC__ + +#endif // __DMC__ + +//////////////////////////////////////////////////////////////////////////////// +// GCC +#ifdef __GNUC__ + +# if __GNUC__ == 4 && __GNUC_MINOR__ >= 6 && defined(__GXX_EXPERIMENTAL_CXX0X__) +# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR +# endif + +# if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS) && defined(CATCH_CPP11_OR_GREATER) +# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS _Pragma( "GCC diagnostic ignored \"-Wparentheses\"" ) +# endif + +// - otherwise more recent versions define __cplusplus >= 201103L +// and will get picked up below + +#endif // __GNUC__ + +//////////////////////////////////////////////////////////////////////////////// +// Visual C++ +#ifdef _MSC_VER + +#if (_MSC_VER >= 1600) +# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR +# define CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR +#endif + +#if (_MSC_VER >= 1900 ) // (VC++ 13 (VS2015)) +#define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT +#define CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS +#endif + +#endif // _MSC_VER + +//////////////////////////////////////////////////////////////////////////////// + +// Use variadic macros if the compiler supports them +#if ( defined _MSC_VER && _MSC_VER > 1400 && !defined __EDGE__) || \ + ( defined __WAVE__ && __WAVE_HAS_VARIADICS ) || \ + ( defined __GNUC__ && __GNUC__ >= 3 ) || \ + ( !defined __cplusplus && __STDC_VERSION__ >= 199901L || __cplusplus >= 201103L ) + +#define CATCH_INTERNAL_CONFIG_VARIADIC_MACROS + +#endif + +//////////////////////////////////////////////////////////////////////////////// +// C++ language feature support + +// catch all support for C++11 +#if defined(CATCH_CPP11_OR_GREATER) + +# if !defined(CATCH_INTERNAL_CONFIG_CPP11_NULLPTR) +# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR +# endif + +# ifndef CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT +# define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT +# endif + +# ifndef CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS +# define CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS +# endif + +# ifndef CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM +# define CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM +# endif + +# ifndef CATCH_INTERNAL_CONFIG_CPP11_TUPLE +# define CATCH_INTERNAL_CONFIG_CPP11_TUPLE +# endif + +# ifndef CATCH_INTERNAL_CONFIG_VARIADIC_MACROS +# define CATCH_INTERNAL_CONFIG_VARIADIC_MACROS +# endif + +# if !defined(CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG) +# define CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG +# endif + +# if !defined(CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE) +# define CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE +# endif +# if !defined(CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) +# define CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR +# endif + +#endif // __cplusplus >= 201103L + +// Now set the actual defines based on the above + anything the user has configured +#if defined(CATCH_INTERNAL_CONFIG_CPP11_NULLPTR) && !defined(CATCH_CONFIG_CPP11_NO_NULLPTR) && !defined(CATCH_CONFIG_CPP11_NULLPTR) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_NULLPTR +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_CONFIG_CPP11_NO_NOEXCEPT) && !defined(CATCH_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_NOEXCEPT +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS) && !defined(CATCH_CONFIG_CPP11_NO_GENERATED_METHODS) && !defined(CATCH_CONFIG_CPP11_GENERATED_METHODS) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_GENERATED_METHODS +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM) && !defined(CATCH_CONFIG_CPP11_NO_IS_ENUM) && !defined(CATCH_CONFIG_CPP11_IS_ENUM) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_IS_ENUM +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_TUPLE) && !defined(CATCH_CONFIG_CPP11_NO_TUPLE) && !defined(CATCH_CONFIG_CPP11_TUPLE) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_TUPLE +#endif +#if defined(CATCH_INTERNAL_CONFIG_VARIADIC_MACROS) && !defined(CATCH_CONFIG_NO_VARIADIC_MACROS) && !defined(CATCH_CONFIG_VARIADIC_MACROS) +# define CATCH_CONFIG_VARIADIC_MACROS +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG) && !defined(CATCH_CONFIG_NO_LONG_LONG) && !defined(CATCH_CONFIG_CPP11_LONG_LONG) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_LONG_LONG +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE) && !defined(CATCH_CONFIG_NO_OVERRIDE) && !defined(CATCH_CONFIG_CPP11_OVERRIDE) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_OVERRIDE +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) && !defined(CATCH_CONFIG_NO_UNIQUE_PTR) && !defined(CATCH_CONFIG_CPP11_UNIQUE_PTR) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_UNIQUE_PTR +#endif + +#if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS) +# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS +#endif + +// noexcept support: +#if defined(CATCH_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_NOEXCEPT) +# define CATCH_NOEXCEPT noexcept +# define CATCH_NOEXCEPT_IS(x) noexcept(x) +#else +# define CATCH_NOEXCEPT throw() +# define CATCH_NOEXCEPT_IS(x) +#endif + +// nullptr support +#ifdef CATCH_CONFIG_CPP11_NULLPTR +# define CATCH_NULL nullptr +#else +# define CATCH_NULL NULL +#endif + +// override support +#ifdef CATCH_CONFIG_CPP11_OVERRIDE +# define CATCH_OVERRIDE override +#else +# define CATCH_OVERRIDE +#endif + +// unique_ptr support +#ifdef CATCH_CONFIG_CPP11_UNIQUE_PTR +# define CATCH_AUTO_PTR( T ) std::unique_ptr +#else +# define CATCH_AUTO_PTR( T ) std::auto_ptr +#endif + +namespace Catch { + + struct IConfig; + + struct CaseSensitive { enum Choice { + Yes, + No + }; }; + + class NonCopyable { +#ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + NonCopyable( NonCopyable const& ) = delete; + NonCopyable( NonCopyable && ) = delete; + NonCopyable& operator = ( NonCopyable const& ) = delete; + NonCopyable& operator = ( NonCopyable && ) = delete; +#else + NonCopyable( NonCopyable const& info ); + NonCopyable& operator = ( NonCopyable const& ); +#endif + + protected: + NonCopyable() {} + virtual ~NonCopyable(); + }; + + class SafeBool { + public: + typedef void (SafeBool::*type)() const; + + static type makeSafe( bool value ) { + return value ? &SafeBool::trueValue : 0; + } + private: + void trueValue() const {} + }; + + template + inline void deleteAll( ContainerT& container ) { + typename ContainerT::const_iterator it = container.begin(); + typename ContainerT::const_iterator itEnd = container.end(); + for(; it != itEnd; ++it ) + delete *it; + } + template + inline void deleteAllValues( AssociativeContainerT& container ) { + typename AssociativeContainerT::const_iterator it = container.begin(); + typename AssociativeContainerT::const_iterator itEnd = container.end(); + for(; it != itEnd; ++it ) + delete it->second; + } + + bool startsWith( std::string const& s, std::string const& prefix ); + bool endsWith( std::string const& s, std::string const& suffix ); + bool contains( std::string const& s, std::string const& infix ); + void toLowerInPlace( std::string& s ); + std::string toLower( std::string const& s ); + std::string trim( std::string const& str ); + bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ); + + struct pluralise { + pluralise( std::size_t count, std::string const& label ); + + friend std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ); + + std::size_t m_count; + std::string m_label; + }; + + struct SourceLineInfo { + + SourceLineInfo(); + SourceLineInfo( char const* _file, std::size_t _line ); + SourceLineInfo( SourceLineInfo const& other ); +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + SourceLineInfo( SourceLineInfo && ) = default; + SourceLineInfo& operator = ( SourceLineInfo const& ) = default; + SourceLineInfo& operator = ( SourceLineInfo && ) = default; +# endif + bool empty() const; + bool operator == ( SourceLineInfo const& other ) const; + bool operator < ( SourceLineInfo const& other ) const; + + std::string file; + std::size_t line; + }; + + std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ); + + // This is just here to avoid compiler warnings with macro constants and boolean literals + inline bool isTrue( bool value ){ return value; } + inline bool alwaysTrue() { return true; } + inline bool alwaysFalse() { return false; } + + void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo ); + + void seedRng( IConfig const& config ); + unsigned int rngSeed(); + + // Use this in variadic streaming macros to allow + // >> +StreamEndStop + // as well as + // >> stuff +StreamEndStop + struct StreamEndStop { + std::string operator+() { + return std::string(); + } + }; + template + T const& operator + ( T const& value, StreamEndStop ) { + return value; + } +} + +#define CATCH_INTERNAL_LINEINFO ::Catch::SourceLineInfo( __FILE__, static_cast( __LINE__ ) ) +#define CATCH_INTERNAL_ERROR( msg ) ::Catch::throwLogicError( msg, CATCH_INTERNAL_LINEINFO ); + +#include + +namespace Catch { + + class NotImplementedException : public std::exception + { + public: + NotImplementedException( SourceLineInfo const& lineInfo ); + NotImplementedException( NotImplementedException const& ) {} + + virtual ~NotImplementedException() CATCH_NOEXCEPT {} + + virtual const char* what() const CATCH_NOEXCEPT; + + private: + std::string m_what; + SourceLineInfo m_lineInfo; + }; + +} // end namespace Catch + +/////////////////////////////////////////////////////////////////////////////// +#define CATCH_NOT_IMPLEMENTED throw Catch::NotImplementedException( CATCH_INTERNAL_LINEINFO ) + +// #included from: internal/catch_context.h +#define TWOBLUECUBES_CATCH_CONTEXT_H_INCLUDED + +// #included from: catch_interfaces_generators.h +#define TWOBLUECUBES_CATCH_INTERFACES_GENERATORS_H_INCLUDED + +#include + +namespace Catch { + + struct IGeneratorInfo { + virtual ~IGeneratorInfo(); + virtual bool moveNext() = 0; + virtual std::size_t getCurrentIndex() const = 0; + }; + + struct IGeneratorsForTest { + virtual ~IGeneratorsForTest(); + + virtual IGeneratorInfo& getGeneratorInfo( std::string const& fileInfo, std::size_t size ) = 0; + virtual bool moveNext() = 0; + }; + + IGeneratorsForTest* createGeneratorsForTest(); + +} // end namespace Catch + +// #included from: catch_ptr.hpp +#define TWOBLUECUBES_CATCH_PTR_HPP_INCLUDED + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpadded" +#endif + +namespace Catch { + + // An intrusive reference counting smart pointer. + // T must implement addRef() and release() methods + // typically implementing the IShared interface + template + class Ptr { + public: + Ptr() : m_p( CATCH_NULL ){} + Ptr( T* p ) : m_p( p ){ + if( m_p ) + m_p->addRef(); + } + Ptr( Ptr const& other ) : m_p( other.m_p ){ + if( m_p ) + m_p->addRef(); + } + ~Ptr(){ + if( m_p ) + m_p->release(); + } + void reset() { + if( m_p ) + m_p->release(); + m_p = CATCH_NULL; + } + Ptr& operator = ( T* p ){ + Ptr temp( p ); + swap( temp ); + return *this; + } + Ptr& operator = ( Ptr const& other ){ + Ptr temp( other ); + swap( temp ); + return *this; + } + void swap( Ptr& other ) { std::swap( m_p, other.m_p ); } + T* get() const{ return m_p; } + T& operator*() const { return *m_p; } + T* operator->() const { return m_p; } + bool operator !() const { return m_p == CATCH_NULL; } + operator SafeBool::type() const { return SafeBool::makeSafe( m_p != CATCH_NULL ); } + + private: + T* m_p; + }; + + struct IShared : NonCopyable { + virtual ~IShared(); + virtual void addRef() const = 0; + virtual void release() const = 0; + }; + + template + struct SharedImpl : T { + + SharedImpl() : m_rc( 0 ){} + + virtual void addRef() const { + ++m_rc; + } + virtual void release() const { + if( --m_rc == 0 ) + delete this; + } + + mutable unsigned int m_rc; + }; + +} // end namespace Catch + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +#include +#include +#include + +namespace Catch { + + class TestCase; + class Stream; + struct IResultCapture; + struct IRunner; + struct IGeneratorsForTest; + struct IConfig; + + struct IContext + { + virtual ~IContext(); + + virtual IResultCapture* getResultCapture() = 0; + virtual IRunner* getRunner() = 0; + virtual size_t getGeneratorIndex( std::string const& fileInfo, size_t totalSize ) = 0; + virtual bool advanceGeneratorsForCurrentTest() = 0; + virtual Ptr getConfig() const = 0; + }; + + struct IMutableContext : IContext + { + virtual ~IMutableContext(); + virtual void setResultCapture( IResultCapture* resultCapture ) = 0; + virtual void setRunner( IRunner* runner ) = 0; + virtual void setConfig( Ptr const& config ) = 0; + }; + + IContext& getCurrentContext(); + IMutableContext& getCurrentMutableContext(); + void cleanUpContext(); + Stream createStream( std::string const& streamName ); + +} + +// #included from: internal/catch_test_registry.hpp +#define TWOBLUECUBES_CATCH_TEST_REGISTRY_HPP_INCLUDED + +// #included from: catch_interfaces_testcase.h +#define TWOBLUECUBES_CATCH_INTERFACES_TESTCASE_H_INCLUDED + +#include + +namespace Catch { + + class TestSpec; + + struct ITestCase : IShared { + virtual void invoke () const = 0; + protected: + virtual ~ITestCase(); + }; + + class TestCase; + struct IConfig; + + struct ITestCaseRegistry { + virtual ~ITestCaseRegistry(); + virtual std::vector const& getAllTests() const = 0; + virtual std::vector const& getAllTestsSorted( IConfig const& config ) const = 0; + }; + + bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ); + std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ); + std::vector const& getAllTestCasesSorted( IConfig const& config ); + +} + +namespace Catch { + +template +class MethodTestCase : public SharedImpl { + +public: + MethodTestCase( void (C::*method)() ) : m_method( method ) {} + + virtual void invoke() const { + C obj; + (obj.*m_method)(); + } + +private: + virtual ~MethodTestCase() {} + + void (C::*m_method)(); +}; + +typedef void(*TestFunction)(); + +struct NameAndDesc { + NameAndDesc( const char* _name = "", const char* _description= "" ) + : name( _name ), description( _description ) + {} + + const char* name; + const char* description; +}; + +void registerTestCase + ( ITestCase* testCase, + char const* className, + NameAndDesc const& nameAndDesc, + SourceLineInfo const& lineInfo ); + +struct AutoReg { + + AutoReg + ( TestFunction function, + SourceLineInfo const& lineInfo, + NameAndDesc const& nameAndDesc ); + + template + AutoReg + ( void (C::*method)(), + char const* className, + NameAndDesc const& nameAndDesc, + SourceLineInfo const& lineInfo ) { + + registerTestCase + ( new MethodTestCase( method ), + className, + nameAndDesc, + lineInfo ); + } + + ~AutoReg(); + +private: + AutoReg( AutoReg const& ); + void operator= ( AutoReg const& ); +}; + +void registerTestCaseFunction + ( TestFunction function, + SourceLineInfo const& lineInfo, + NameAndDesc const& nameAndDesc ); + +} // end namespace Catch + +#ifdef CATCH_CONFIG_VARIADIC_MACROS + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_TESTCASE( ... ) \ + static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )(); \ + namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( __VA_ARGS__ ) ); }\ + static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )() + + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \ + namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); } + + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, ... )\ + namespace{ \ + struct INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ) : ClassName{ \ + void test(); \ + }; \ + Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test, #ClassName, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); \ + } \ + void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test() + + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, ... ) \ + Catch::AutoReg( Function, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( __VA_ARGS__ ) ); + +#else + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_TESTCASE( Name, Desc ) \ + static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )(); \ + namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( Name, Desc ) ); }\ + static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )() + + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, Name, Desc ) \ + namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( Name, Desc ), CATCH_INTERNAL_LINEINFO ); } + + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, TestName, Desc )\ + namespace{ \ + struct INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ) : ClassName{ \ + void test(); \ + }; \ + Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test, #ClassName, Catch::NameAndDesc( TestName, Desc ), CATCH_INTERNAL_LINEINFO ); \ + } \ + void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test() + + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, Name, Desc ) \ + Catch::AutoReg( Function, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( Name, Desc ) ); +#endif + +// #included from: internal/catch_capture.hpp +#define TWOBLUECUBES_CATCH_CAPTURE_HPP_INCLUDED + +// #included from: catch_result_builder.h +#define TWOBLUECUBES_CATCH_RESULT_BUILDER_H_INCLUDED + +// #included from: catch_result_type.h +#define TWOBLUECUBES_CATCH_RESULT_TYPE_H_INCLUDED + +namespace Catch { + + // ResultWas::OfType enum + struct ResultWas { enum OfType { + Unknown = -1, + Ok = 0, + Info = 1, + Warning = 2, + + FailureBit = 0x10, + + ExpressionFailed = FailureBit | 1, + ExplicitFailure = FailureBit | 2, + + Exception = 0x100 | FailureBit, + + ThrewException = Exception | 1, + DidntThrowException = Exception | 2, + + FatalErrorCondition = 0x200 | FailureBit + + }; }; + + inline bool isOk( ResultWas::OfType resultType ) { + return ( resultType & ResultWas::FailureBit ) == 0; + } + inline bool isJustInfo( int flags ) { + return flags == ResultWas::Info; + } + + // ResultDisposition::Flags enum + struct ResultDisposition { enum Flags { + Normal = 0x01, + + ContinueOnFailure = 0x02, // Failures fail test, but execution continues + FalseTest = 0x04, // Prefix expression with ! + SuppressFail = 0x08 // Failures are reported but do not fail the test + }; }; + + inline ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs ) { + return static_cast( static_cast( lhs ) | static_cast( rhs ) ); + } + + inline bool shouldContinueOnFailure( int flags ) { return ( flags & ResultDisposition::ContinueOnFailure ) != 0; } + inline bool isFalseTest( int flags ) { return ( flags & ResultDisposition::FalseTest ) != 0; } + inline bool shouldSuppressFailure( int flags ) { return ( flags & ResultDisposition::SuppressFail ) != 0; } + +} // end namespace Catch + +// #included from: catch_assertionresult.h +#define TWOBLUECUBES_CATCH_ASSERTIONRESULT_H_INCLUDED + +#include + +namespace Catch { + + struct AssertionInfo + { + AssertionInfo() {} + AssertionInfo( std::string const& _macroName, + SourceLineInfo const& _lineInfo, + std::string const& _capturedExpression, + ResultDisposition::Flags _resultDisposition ); + + std::string macroName; + SourceLineInfo lineInfo; + std::string capturedExpression; + ResultDisposition::Flags resultDisposition; + }; + + struct AssertionResultData + { + AssertionResultData() : resultType( ResultWas::Unknown ) {} + + std::string reconstructedExpression; + std::string message; + ResultWas::OfType resultType; + }; + + class AssertionResult { + public: + AssertionResult(); + AssertionResult( AssertionInfo const& info, AssertionResultData const& data ); + ~AssertionResult(); +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + AssertionResult( AssertionResult const& ) = default; + AssertionResult( AssertionResult && ) = default; + AssertionResult& operator = ( AssertionResult const& ) = default; + AssertionResult& operator = ( AssertionResult && ) = default; +# endif + + bool isOk() const; + bool succeeded() const; + ResultWas::OfType getResultType() const; + bool hasExpression() const; + bool hasMessage() const; + std::string getExpression() const; + std::string getExpressionInMacro() const; + bool hasExpandedExpression() const; + std::string getExpandedExpression() const; + std::string getMessage() const; + SourceLineInfo getSourceInfo() const; + std::string getTestMacroName() const; + + protected: + AssertionInfo m_info; + AssertionResultData m_resultData; + }; + +} // end namespace Catch + +// #included from: catch_matchers.hpp +#define TWOBLUECUBES_CATCH_MATCHERS_HPP_INCLUDED + +namespace Catch { +namespace Matchers { + namespace Impl { + + namespace Generic { + template class AllOf; + template class AnyOf; + template class Not; + } + + template + struct Matcher : SharedImpl + { + typedef ExpressionT ExpressionType; + + virtual ~Matcher() {} + virtual Ptr clone() const = 0; + virtual bool match( ExpressionT const& expr ) const = 0; + virtual std::string toString() const = 0; + + Generic::AllOf operator && ( Matcher const& other ) const; + Generic::AnyOf operator || ( Matcher const& other ) const; + Generic::Not operator ! () const; + }; + + template + struct MatcherImpl : Matcher { + + virtual Ptr > clone() const { + return Ptr >( new DerivedT( static_cast( *this ) ) ); + } + }; + + namespace Generic { + template + class Not : public MatcherImpl, ExpressionT> { + public: + explicit Not( Matcher const& matcher ) : m_matcher(matcher.clone()) {} + Not( Not const& other ) : m_matcher( other.m_matcher ) {} + + virtual bool match( ExpressionT const& expr ) const CATCH_OVERRIDE { + return !m_matcher->match( expr ); + } + + virtual std::string toString() const CATCH_OVERRIDE { + return "not " + m_matcher->toString(); + } + private: + Ptr< Matcher > m_matcher; + }; + + template + class AllOf : public MatcherImpl, ExpressionT> { + public: + + AllOf() {} + AllOf( AllOf const& other ) : m_matchers( other.m_matchers ) {} + + AllOf& add( Matcher const& matcher ) { + m_matchers.push_back( matcher.clone() ); + return *this; + } + virtual bool match( ExpressionT const& expr ) const + { + for( std::size_t i = 0; i < m_matchers.size(); ++i ) + if( !m_matchers[i]->match( expr ) ) + return false; + return true; + } + virtual std::string toString() const { + std::ostringstream oss; + oss << "( "; + for( std::size_t i = 0; i < m_matchers.size(); ++i ) { + if( i != 0 ) + oss << " and "; + oss << m_matchers[i]->toString(); + } + oss << " )"; + return oss.str(); + } + + AllOf operator && ( Matcher const& other ) const { + AllOf allOfExpr( *this ); + allOfExpr.add( other ); + return allOfExpr; + } + + private: + std::vector > > m_matchers; + }; + + template + class AnyOf : public MatcherImpl, ExpressionT> { + public: + + AnyOf() {} + AnyOf( AnyOf const& other ) : m_matchers( other.m_matchers ) {} + + AnyOf& add( Matcher const& matcher ) { + m_matchers.push_back( matcher.clone() ); + return *this; + } + virtual bool match( ExpressionT const& expr ) const + { + for( std::size_t i = 0; i < m_matchers.size(); ++i ) + if( m_matchers[i]->match( expr ) ) + return true; + return false; + } + virtual std::string toString() const { + std::ostringstream oss; + oss << "( "; + for( std::size_t i = 0; i < m_matchers.size(); ++i ) { + if( i != 0 ) + oss << " or "; + oss << m_matchers[i]->toString(); + } + oss << " )"; + return oss.str(); + } + + AnyOf operator || ( Matcher const& other ) const { + AnyOf anyOfExpr( *this ); + anyOfExpr.add( other ); + return anyOfExpr; + } + + private: + std::vector > > m_matchers; + }; + + } // namespace Generic + + template + Generic::AllOf Matcher::operator && ( Matcher const& other ) const { + Generic::AllOf allOfExpr; + allOfExpr.add( *this ); + allOfExpr.add( other ); + return allOfExpr; + } + + template + Generic::AnyOf Matcher::operator || ( Matcher const& other ) const { + Generic::AnyOf anyOfExpr; + anyOfExpr.add( *this ); + anyOfExpr.add( other ); + return anyOfExpr; + } + + template + Generic::Not Matcher::operator ! () const { + return Generic::Not( *this ); + } + + namespace StdString { + + inline std::string makeString( std::string const& str ) { return str; } + inline std::string makeString( const char* str ) { return str ? std::string( str ) : std::string(); } + + struct CasedString + { + CasedString( std::string const& str, CaseSensitive::Choice caseSensitivity ) + : m_caseSensitivity( caseSensitivity ), + m_str( adjustString( str ) ) + {} + std::string adjustString( std::string const& str ) const { + return m_caseSensitivity == CaseSensitive::No + ? toLower( str ) + : str; + + } + std::string toStringSuffix() const + { + return m_caseSensitivity == CaseSensitive::No + ? " (case insensitive)" + : ""; + } + CaseSensitive::Choice m_caseSensitivity; + std::string m_str; + }; + + struct Equals : MatcherImpl { + Equals( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) + : m_data( str, caseSensitivity ) + {} + Equals( Equals const& other ) : m_data( other.m_data ){} + + virtual ~Equals(); + + virtual bool match( std::string const& expr ) const { + return m_data.m_str == m_data.adjustString( expr );; + } + virtual std::string toString() const { + return "equals: \"" + m_data.m_str + "\"" + m_data.toStringSuffix(); + } + + CasedString m_data; + }; + + struct Contains : MatcherImpl { + Contains( std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) + : m_data( substr, caseSensitivity ){} + Contains( Contains const& other ) : m_data( other.m_data ){} + + virtual ~Contains(); + + virtual bool match( std::string const& expr ) const { + return m_data.adjustString( expr ).find( m_data.m_str ) != std::string::npos; + } + virtual std::string toString() const { + return "contains: \"" + m_data.m_str + "\"" + m_data.toStringSuffix(); + } + + CasedString m_data; + }; + + struct StartsWith : MatcherImpl { + StartsWith( std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) + : m_data( substr, caseSensitivity ){} + + StartsWith( StartsWith const& other ) : m_data( other.m_data ){} + + virtual ~StartsWith(); + + virtual bool match( std::string const& expr ) const { + return startsWith( m_data.adjustString( expr ), m_data.m_str ); + } + virtual std::string toString() const { + return "starts with: \"" + m_data.m_str + "\"" + m_data.toStringSuffix(); + } + + CasedString m_data; + }; + + struct EndsWith : MatcherImpl { + EndsWith( std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) + : m_data( substr, caseSensitivity ){} + EndsWith( EndsWith const& other ) : m_data( other.m_data ){} + + virtual ~EndsWith(); + + virtual bool match( std::string const& expr ) const { + return endsWith( m_data.adjustString( expr ), m_data.m_str ); + } + virtual std::string toString() const { + return "ends with: \"" + m_data.m_str + "\"" + m_data.toStringSuffix(); + } + + CasedString m_data; + }; + } // namespace StdString + } // namespace Impl + + // The following functions create the actual matcher objects. + // This allows the types to be inferred + template + inline Impl::Generic::Not Not( Impl::Matcher const& m ) { + return Impl::Generic::Not( m ); + } + + template + inline Impl::Generic::AllOf AllOf( Impl::Matcher const& m1, + Impl::Matcher const& m2 ) { + return Impl::Generic::AllOf().add( m1 ).add( m2 ); + } + template + inline Impl::Generic::AllOf AllOf( Impl::Matcher const& m1, + Impl::Matcher const& m2, + Impl::Matcher const& m3 ) { + return Impl::Generic::AllOf().add( m1 ).add( m2 ).add( m3 ); + } + template + inline Impl::Generic::AnyOf AnyOf( Impl::Matcher const& m1, + Impl::Matcher const& m2 ) { + return Impl::Generic::AnyOf().add( m1 ).add( m2 ); + } + template + inline Impl::Generic::AnyOf AnyOf( Impl::Matcher const& m1, + Impl::Matcher const& m2, + Impl::Matcher const& m3 ) { + return Impl::Generic::AnyOf().add( m1 ).add( m2 ).add( m3 ); + } + + inline Impl::StdString::Equals Equals( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) { + return Impl::StdString::Equals( str, caseSensitivity ); + } + inline Impl::StdString::Equals Equals( const char* str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) { + return Impl::StdString::Equals( Impl::StdString::makeString( str ), caseSensitivity ); + } + inline Impl::StdString::Contains Contains( std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) { + return Impl::StdString::Contains( substr, caseSensitivity ); + } + inline Impl::StdString::Contains Contains( const char* substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) { + return Impl::StdString::Contains( Impl::StdString::makeString( substr ), caseSensitivity ); + } + inline Impl::StdString::StartsWith StartsWith( std::string const& substr ) { + return Impl::StdString::StartsWith( substr ); + } + inline Impl::StdString::StartsWith StartsWith( const char* substr ) { + return Impl::StdString::StartsWith( Impl::StdString::makeString( substr ) ); + } + inline Impl::StdString::EndsWith EndsWith( std::string const& substr ) { + return Impl::StdString::EndsWith( substr ); + } + inline Impl::StdString::EndsWith EndsWith( const char* substr ) { + return Impl::StdString::EndsWith( Impl::StdString::makeString( substr ) ); + } + +} // namespace Matchers + +using namespace Matchers; + +} // namespace Catch + +namespace Catch { + + struct TestFailureException{}; + + template class ExpressionLhs; + + struct STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison; + + struct CopyableStream { + CopyableStream() {} + CopyableStream( CopyableStream const& other ) { + oss << other.oss.str(); + } + CopyableStream& operator=( CopyableStream const& other ) { + oss.str(""); + oss << other.oss.str(); + return *this; + } + std::ostringstream oss; + }; + + class ResultBuilder { + public: + ResultBuilder( char const* macroName, + SourceLineInfo const& lineInfo, + char const* capturedExpression, + ResultDisposition::Flags resultDisposition, + char const* secondArg = "" ); + + template + ExpressionLhs operator <= ( T const& operand ); + ExpressionLhs operator <= ( bool value ); + + template + ResultBuilder& operator << ( T const& value ) { + m_stream.oss << value; + return *this; + } + + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( RhsT const& ); + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || ( RhsT const& ); + + ResultBuilder& setResultType( ResultWas::OfType result ); + ResultBuilder& setResultType( bool result ); + ResultBuilder& setLhs( std::string const& lhs ); + ResultBuilder& setRhs( std::string const& rhs ); + ResultBuilder& setOp( std::string const& op ); + + void endExpression(); + + std::string reconstructExpression() const; + AssertionResult build() const; + + void useActiveException( ResultDisposition::Flags resultDisposition = ResultDisposition::Normal ); + void captureResult( ResultWas::OfType resultType ); + void captureExpression(); + void captureExpectedException( std::string const& expectedMessage ); + void captureExpectedException( Matchers::Impl::Matcher const& matcher ); + void handleResult( AssertionResult const& result ); + void react(); + bool shouldDebugBreak() const; + bool allowThrows() const; + + private: + AssertionInfo m_assertionInfo; + AssertionResultData m_data; + struct ExprComponents { + ExprComponents() : testFalse( false ) {} + bool testFalse; + std::string lhs, rhs, op; + } m_exprComponents; + CopyableStream m_stream; + + bool m_shouldDebugBreak; + bool m_shouldThrow; + }; + +} // namespace Catch + +// Include after due to circular dependency: +// #included from: catch_expression_lhs.hpp +#define TWOBLUECUBES_CATCH_EXPRESSION_LHS_HPP_INCLUDED + +// #included from: catch_evaluate.hpp +#define TWOBLUECUBES_CATCH_EVALUATE_HPP_INCLUDED + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable:4389) // '==' : signed/unsigned mismatch +#endif + +#include + +namespace Catch { +namespace Internal { + + enum Operator { + IsEqualTo, + IsNotEqualTo, + IsLessThan, + IsGreaterThan, + IsLessThanOrEqualTo, + IsGreaterThanOrEqualTo + }; + + template struct OperatorTraits { static const char* getName(){ return "*error*"; } }; + template<> struct OperatorTraits { static const char* getName(){ return "=="; } }; + template<> struct OperatorTraits { static const char* getName(){ return "!="; } }; + template<> struct OperatorTraits { static const char* getName(){ return "<"; } }; + template<> struct OperatorTraits { static const char* getName(){ return ">"; } }; + template<> struct OperatorTraits { static const char* getName(){ return "<="; } }; + template<> struct OperatorTraits{ static const char* getName(){ return ">="; } }; + + template + inline T& opCast(T const& t) { return const_cast(t); } + +// nullptr_t support based on pull request #154 from Konstantin Baumann +#ifdef CATCH_CONFIG_CPP11_NULLPTR + inline std::nullptr_t opCast(std::nullptr_t) { return nullptr; } +#endif // CATCH_CONFIG_CPP11_NULLPTR + + // So the compare overloads can be operator agnostic we convey the operator as a template + // enum, which is used to specialise an Evaluator for doing the comparison. + template + class Evaluator{}; + + template + struct Evaluator { + static bool evaluate( T1 const& lhs, T2 const& rhs) { + return bool( opCast( lhs ) == opCast( rhs ) ); + } + }; + template + struct Evaluator { + static bool evaluate( T1 const& lhs, T2 const& rhs ) { + return bool( opCast( lhs ) != opCast( rhs ) ); + } + }; + template + struct Evaluator { + static bool evaluate( T1 const& lhs, T2 const& rhs ) { + return bool( opCast( lhs ) < opCast( rhs ) ); + } + }; + template + struct Evaluator { + static bool evaluate( T1 const& lhs, T2 const& rhs ) { + return bool( opCast( lhs ) > opCast( rhs ) ); + } + }; + template + struct Evaluator { + static bool evaluate( T1 const& lhs, T2 const& rhs ) { + return bool( opCast( lhs ) >= opCast( rhs ) ); + } + }; + template + struct Evaluator { + static bool evaluate( T1 const& lhs, T2 const& rhs ) { + return bool( opCast( lhs ) <= opCast( rhs ) ); + } + }; + + template + bool applyEvaluator( T1 const& lhs, T2 const& rhs ) { + return Evaluator::evaluate( lhs, rhs ); + } + + // This level of indirection allows us to specialise for integer types + // to avoid signed/ unsigned warnings + + // "base" overload + template + bool compare( T1 const& lhs, T2 const& rhs ) { + return Evaluator::evaluate( lhs, rhs ); + } + + // unsigned X to int + template bool compare( unsigned int lhs, int rhs ) { + return applyEvaluator( lhs, static_cast( rhs ) ); + } + template bool compare( unsigned long lhs, int rhs ) { + return applyEvaluator( lhs, static_cast( rhs ) ); + } + template bool compare( unsigned char lhs, int rhs ) { + return applyEvaluator( lhs, static_cast( rhs ) ); + } + + // unsigned X to long + template bool compare( unsigned int lhs, long rhs ) { + return applyEvaluator( lhs, static_cast( rhs ) ); + } + template bool compare( unsigned long lhs, long rhs ) { + return applyEvaluator( lhs, static_cast( rhs ) ); + } + template bool compare( unsigned char lhs, long rhs ) { + return applyEvaluator( lhs, static_cast( rhs ) ); + } + + // int to unsigned X + template bool compare( int lhs, unsigned int rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( int lhs, unsigned long rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( int lhs, unsigned char rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + + // long to unsigned X + template bool compare( long lhs, unsigned int rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( long lhs, unsigned long rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( long lhs, unsigned char rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + + // pointer to long (when comparing against NULL) + template bool compare( long lhs, T* rhs ) { + return Evaluator::evaluate( reinterpret_cast( lhs ), rhs ); + } + template bool compare( T* lhs, long rhs ) { + return Evaluator::evaluate( lhs, reinterpret_cast( rhs ) ); + } + + // pointer to int (when comparing against NULL) + template bool compare( int lhs, T* rhs ) { + return Evaluator::evaluate( reinterpret_cast( lhs ), rhs ); + } + template bool compare( T* lhs, int rhs ) { + return Evaluator::evaluate( lhs, reinterpret_cast( rhs ) ); + } + +#ifdef CATCH_CONFIG_CPP11_LONG_LONG + // long long to unsigned X + template bool compare( long long lhs, unsigned int rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( long long lhs, unsigned long rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( long long lhs, unsigned long long rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( long long lhs, unsigned char rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + + // unsigned long long to X + template bool compare( unsigned long long lhs, int rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( unsigned long long lhs, long rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( unsigned long long lhs, long long rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( unsigned long long lhs, char rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + + // pointer to long long (when comparing against NULL) + template bool compare( long long lhs, T* rhs ) { + return Evaluator::evaluate( reinterpret_cast( lhs ), rhs ); + } + template bool compare( T* lhs, long long rhs ) { + return Evaluator::evaluate( lhs, reinterpret_cast( rhs ) ); + } +#endif // CATCH_CONFIG_CPP11_LONG_LONG + +#ifdef CATCH_CONFIG_CPP11_NULLPTR + // pointer to nullptr_t (when comparing against nullptr) + template bool compare( std::nullptr_t, T* rhs ) { + return Evaluator::evaluate( nullptr, rhs ); + } + template bool compare( T* lhs, std::nullptr_t ) { + return Evaluator::evaluate( lhs, nullptr ); + } +#endif // CATCH_CONFIG_CPP11_NULLPTR + +} // end of namespace Internal +} // end of namespace Catch + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +// #included from: catch_tostring.h +#define TWOBLUECUBES_CATCH_TOSTRING_H_INCLUDED + +#include +#include +#include +#include +#include + +#ifdef __OBJC__ +// #included from: catch_objc_arc.hpp +#define TWOBLUECUBES_CATCH_OBJC_ARC_HPP_INCLUDED + +#import + +#ifdef __has_feature +#define CATCH_ARC_ENABLED __has_feature(objc_arc) +#else +#define CATCH_ARC_ENABLED 0 +#endif + +void arcSafeRelease( NSObject* obj ); +id performOptionalSelector( id obj, SEL sel ); + +#if !CATCH_ARC_ENABLED +inline void arcSafeRelease( NSObject* obj ) { + [obj release]; +} +inline id performOptionalSelector( id obj, SEL sel ) { + if( [obj respondsToSelector: sel] ) + return [obj performSelector: sel]; + return nil; +} +#define CATCH_UNSAFE_UNRETAINED +#define CATCH_ARC_STRONG +#else +inline void arcSafeRelease( NSObject* ){} +inline id performOptionalSelector( id obj, SEL sel ) { +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Warc-performSelector-leaks" +#endif + if( [obj respondsToSelector: sel] ) + return [obj performSelector: sel]; +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + return nil; +} +#define CATCH_UNSAFE_UNRETAINED __unsafe_unretained +#define CATCH_ARC_STRONG __strong +#endif + +#endif + +#ifdef CATCH_CONFIG_CPP11_TUPLE +#include +#endif + +#ifdef CATCH_CONFIG_CPP11_IS_ENUM +#include +#endif + +namespace Catch { + +// Why we're here. +template +std::string toString( T const& value ); + +// Built in overloads + +std::string toString( std::string const& value ); +std::string toString( std::wstring const& value ); +std::string toString( const char* const value ); +std::string toString( char* const value ); +std::string toString( const wchar_t* const value ); +std::string toString( wchar_t* const value ); +std::string toString( int value ); +std::string toString( unsigned long value ); +std::string toString( unsigned int value ); +std::string toString( const double value ); +std::string toString( const float value ); +std::string toString( bool value ); +std::string toString( char value ); +std::string toString( signed char value ); +std::string toString( unsigned char value ); + +#ifdef CATCH_CONFIG_CPP11_LONG_LONG +std::string toString( long long value ); +std::string toString( unsigned long long value ); +#endif + +#ifdef CATCH_CONFIG_CPP11_NULLPTR +std::string toString( std::nullptr_t ); +#endif + +#ifdef __OBJC__ + std::string toString( NSString const * const& nsstring ); + std::string toString( NSString * CATCH_ARC_STRONG const& nsstring ); + std::string toString( NSObject* const& nsObject ); +#endif + +namespace Detail { + + extern const std::string unprintableString; + + struct BorgType { + template BorgType( T const& ); + }; + + struct TrueType { char sizer[1]; }; + struct FalseType { char sizer[2]; }; + + TrueType& testStreamable( std::ostream& ); + FalseType testStreamable( FalseType ); + + FalseType operator<<( std::ostream const&, BorgType const& ); + + template + struct IsStreamInsertable { + static std::ostream &s; + static T const&t; + enum { value = sizeof( testStreamable(s << t) ) == sizeof( TrueType ) }; + }; + +#if defined(CATCH_CONFIG_CPP11_IS_ENUM) + template::value + > + struct EnumStringMaker + { + static std::string convert( T const& ) { return unprintableString; } + }; + + template + struct EnumStringMaker + { + static std::string convert( T const& v ) + { + return ::Catch::toString( + static_cast::type>(v) + ); + } + }; +#endif + template + struct StringMakerBase { +#if defined(CATCH_CONFIG_CPP11_IS_ENUM) + template + static std::string convert( T const& v ) + { + return EnumStringMaker::convert( v ); + } +#else + template + static std::string convert( T const& ) { return unprintableString; } +#endif + }; + + template<> + struct StringMakerBase { + template + static std::string convert( T const& _value ) { + std::ostringstream oss; + oss << _value; + return oss.str(); + } + }; + + std::string rawMemoryToString( const void *object, std::size_t size ); + + template + inline std::string rawMemoryToString( const T& object ) { + return rawMemoryToString( &object, sizeof(object) ); + } + +} // end namespace Detail + +template +struct StringMaker : + Detail::StringMakerBase::value> {}; + +template +struct StringMaker { + template + static std::string convert( U* p ) { + if( !p ) + return "NULL"; + else + return Detail::rawMemoryToString( p ); + } +}; + +template +struct StringMaker { + static std::string convert( R C::* p ) { + if( !p ) + return "NULL"; + else + return Detail::rawMemoryToString( p ); + } +}; + +namespace Detail { + template + std::string rangeToString( InputIterator first, InputIterator last ); +} + +//template +//struct StringMaker > { +// static std::string convert( std::vector const& v ) { +// return Detail::rangeToString( v.begin(), v.end() ); +// } +//}; + +template +std::string toString( std::vector const& v ) { + return Detail::rangeToString( v.begin(), v.end() ); +} + +#ifdef CATCH_CONFIG_CPP11_TUPLE + +// toString for tuples +namespace TupleDetail { + template< + typename Tuple, + std::size_t N = 0, + bool = (N < std::tuple_size::value) + > + struct ElementPrinter { + static void print( const Tuple& tuple, std::ostream& os ) + { + os << ( N ? ", " : " " ) + << Catch::toString(std::get(tuple)); + ElementPrinter::print(tuple,os); + } + }; + + template< + typename Tuple, + std::size_t N + > + struct ElementPrinter { + static void print( const Tuple&, std::ostream& ) {} + }; + +} + +template +struct StringMaker> { + + static std::string convert( const std::tuple& tuple ) + { + std::ostringstream os; + os << '{'; + TupleDetail::ElementPrinter>::print( tuple, os ); + os << " }"; + return os.str(); + } +}; +#endif // CATCH_CONFIG_CPP11_TUPLE + +namespace Detail { + template + std::string makeString( T const& value ) { + return StringMaker::convert( value ); + } +} // end namespace Detail + +/// \brief converts any type to a string +/// +/// The default template forwards on to ostringstream - except when an +/// ostringstream overload does not exist - in which case it attempts to detect +/// that and writes {?}. +/// Overload (not specialise) this template for custom typs that you don't want +/// to provide an ostream overload for. +template +std::string toString( T const& value ) { + return StringMaker::convert( value ); +} + + namespace Detail { + template + std::string rangeToString( InputIterator first, InputIterator last ) { + std::ostringstream oss; + oss << "{ "; + if( first != last ) { + oss << Catch::toString( *first ); + for( ++first ; first != last ; ++first ) + oss << ", " << Catch::toString( *first ); + } + oss << " }"; + return oss.str(); + } +} + +} // end namespace Catch + +namespace Catch { + +// Wraps the LHS of an expression and captures the operator and RHS (if any) - +// wrapping them all in a ResultBuilder object +template +class ExpressionLhs { + ExpressionLhs& operator = ( ExpressionLhs const& ); +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + ExpressionLhs& operator = ( ExpressionLhs && ) = delete; +# endif + +public: + ExpressionLhs( ResultBuilder& rb, T lhs ) : m_rb( rb ), m_lhs( lhs ) {} +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + ExpressionLhs( ExpressionLhs const& ) = default; + ExpressionLhs( ExpressionLhs && ) = default; +# endif + + template + ResultBuilder& operator == ( RhsT const& rhs ) { + return captureExpression( rhs ); + } + + template + ResultBuilder& operator != ( RhsT const& rhs ) { + return captureExpression( rhs ); + } + + template + ResultBuilder& operator < ( RhsT const& rhs ) { + return captureExpression( rhs ); + } + + template + ResultBuilder& operator > ( RhsT const& rhs ) { + return captureExpression( rhs ); + } + + template + ResultBuilder& operator <= ( RhsT const& rhs ) { + return captureExpression( rhs ); + } + + template + ResultBuilder& operator >= ( RhsT const& rhs ) { + return captureExpression( rhs ); + } + + ResultBuilder& operator == ( bool rhs ) { + return captureExpression( rhs ); + } + + ResultBuilder& operator != ( bool rhs ) { + return captureExpression( rhs ); + } + + void endExpression() { + bool value = m_lhs ? true : false; + m_rb + .setLhs( Catch::toString( value ) ) + .setResultType( value ) + .endExpression(); + } + + // Only simple binary expressions are allowed on the LHS. + // If more complex compositions are required then place the sub expression in parentheses + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator + ( RhsT const& ); + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator - ( RhsT const& ); + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator / ( RhsT const& ); + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator * ( RhsT const& ); + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( RhsT const& ); + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || ( RhsT const& ); + +private: + template + ResultBuilder& captureExpression( RhsT const& rhs ) { + return m_rb + .setResultType( Internal::compare( m_lhs, rhs ) ) + .setLhs( Catch::toString( m_lhs ) ) + .setRhs( Catch::toString( rhs ) ) + .setOp( Internal::OperatorTraits::getName() ); + } + +private: + ResultBuilder& m_rb; + T m_lhs; +}; + +} // end namespace Catch + + +namespace Catch { + + template + inline ExpressionLhs ResultBuilder::operator <= ( T const& operand ) { + return ExpressionLhs( *this, operand ); + } + + inline ExpressionLhs ResultBuilder::operator <= ( bool value ) { + return ExpressionLhs( *this, value ); + } + +} // namespace Catch + +// #included from: catch_message.h +#define TWOBLUECUBES_CATCH_MESSAGE_H_INCLUDED + +#include + +namespace Catch { + + struct MessageInfo { + MessageInfo( std::string const& _macroName, + SourceLineInfo const& _lineInfo, + ResultWas::OfType _type ); + + std::string macroName; + SourceLineInfo lineInfo; + ResultWas::OfType type; + std::string message; + unsigned int sequence; + + bool operator == ( MessageInfo const& other ) const { + return sequence == other.sequence; + } + bool operator < ( MessageInfo const& other ) const { + return sequence < other.sequence; + } + private: + static unsigned int globalCount; + }; + + struct MessageBuilder { + MessageBuilder( std::string const& macroName, + SourceLineInfo const& lineInfo, + ResultWas::OfType type ) + : m_info( macroName, lineInfo, type ) + {} + + template + MessageBuilder& operator << ( T const& value ) { + m_stream << value; + return *this; + } + + MessageInfo m_info; + std::ostringstream m_stream; + }; + + class ScopedMessage { + public: + ScopedMessage( MessageBuilder const& builder ); + ScopedMessage( ScopedMessage const& other ); + ~ScopedMessage(); + + MessageInfo m_info; + }; + +} // end namespace Catch + +// #included from: catch_interfaces_capture.h +#define TWOBLUECUBES_CATCH_INTERFACES_CAPTURE_H_INCLUDED + +#include + +namespace Catch { + + class TestCase; + class AssertionResult; + struct AssertionInfo; + struct SectionInfo; + struct SectionEndInfo; + struct MessageInfo; + class ScopedMessageBuilder; + struct Counts; + + struct IResultCapture { + + virtual ~IResultCapture(); + + virtual void assertionEnded( AssertionResult const& result ) = 0; + virtual bool sectionStarted( SectionInfo const& sectionInfo, + Counts& assertions ) = 0; + virtual void sectionEnded( SectionEndInfo const& endInfo ) = 0; + virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) = 0; + virtual void pushScopedMessage( MessageInfo const& message ) = 0; + virtual void popScopedMessage( MessageInfo const& message ) = 0; + + virtual std::string getCurrentTestName() const = 0; + virtual const AssertionResult* getLastResult() const = 0; + + virtual void handleFatalErrorCondition( std::string const& message ) = 0; + }; + + IResultCapture& getResultCapture(); +} + +// #included from: catch_debugger.h +#define TWOBLUECUBES_CATCH_DEBUGGER_H_INCLUDED + +// #included from: catch_platform.h +#define TWOBLUECUBES_CATCH_PLATFORM_H_INCLUDED + +#if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) +#define CATCH_PLATFORM_MAC +#elif defined(__IPHONE_OS_VERSION_MIN_REQUIRED) +#define CATCH_PLATFORM_IPHONE +#elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) +#define CATCH_PLATFORM_WINDOWS +#endif + +#include + +namespace Catch{ + + bool isDebuggerActive(); + void writeToDebugConsole( std::string const& text ); +} + +#ifdef CATCH_PLATFORM_MAC + + // The following code snippet based on: + // http://cocoawithlove.com/2008/03/break-into-debugger.html + #ifdef DEBUG + #if defined(__ppc64__) || defined(__ppc__) + #define CATCH_BREAK_INTO_DEBUGGER() \ + if( Catch::isDebuggerActive() ) { \ + __asm__("li r0, 20\nsc\nnop\nli r0, 37\nli r4, 2\nsc\nnop\n" \ + : : : "memory","r0","r3","r4" ); \ + } + #else + #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) {__asm__("int $3\n" : : );} + #endif + #endif + +#elif defined(_MSC_VER) + #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { __debugbreak(); } +#elif defined(__MINGW32__) + extern "C" __declspec(dllimport) void __stdcall DebugBreak(); + #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { DebugBreak(); } +#endif + +#ifndef CATCH_BREAK_INTO_DEBUGGER +#define CATCH_BREAK_INTO_DEBUGGER() Catch::alwaysTrue(); +#endif + +// #included from: catch_interfaces_runner.h +#define TWOBLUECUBES_CATCH_INTERFACES_RUNNER_H_INCLUDED + +namespace Catch { + class TestCase; + + struct IRunner { + virtual ~IRunner(); + virtual bool aborting() const = 0; + }; +} + +/////////////////////////////////////////////////////////////////////////////// +// In the event of a failure works out if the debugger needs to be invoked +// and/or an exception thrown and takes appropriate action. +// This needs to be done as a macro so the debugger will stop in the user +// source code rather than in Catch library code +#define INTERNAL_CATCH_REACT( resultBuilder ) \ + if( resultBuilder.shouldDebugBreak() ) CATCH_BREAK_INTO_DEBUGGER(); \ + resultBuilder.react(); + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \ + try { \ + CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ + ( __catchResult <= expr ).endExpression(); \ + } \ + catch( ... ) { \ + __catchResult.useActiveException( Catch::ResultDisposition::Normal ); \ + } \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::isTrue( false && static_cast(expr) ) ) // expr here is never evaluated at runtime but it forces the compiler to give it a look + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_IF( expr, resultDisposition, macroName ) \ + INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ); \ + if( Catch::getResultCapture().getLastResult()->succeeded() ) + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_ELSE( expr, resultDisposition, macroName ) \ + INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ); \ + if( !Catch::getResultCapture().getLastResult()->succeeded() ) + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_NO_THROW( expr, resultDisposition, macroName ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \ + try { \ + expr; \ + __catchResult.captureResult( Catch::ResultWas::Ok ); \ + } \ + catch( ... ) { \ + __catchResult.useActiveException( resultDisposition ); \ + } \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::alwaysFalse() ) + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_THROWS( expr, resultDisposition, matcher, macroName ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition, #matcher ); \ + if( __catchResult.allowThrows() ) \ + try { \ + expr; \ + __catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \ + } \ + catch( ... ) { \ + __catchResult.captureExpectedException( matcher ); \ + } \ + else \ + __catchResult.captureResult( Catch::ResultWas::Ok ); \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::alwaysFalse() ) + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_THROWS_AS( expr, exceptionType, resultDisposition, macroName ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \ + if( __catchResult.allowThrows() ) \ + try { \ + expr; \ + __catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \ + } \ + catch( exceptionType ) { \ + __catchResult.captureResult( Catch::ResultWas::Ok ); \ + } \ + catch( ... ) { \ + __catchResult.useActiveException( resultDisposition ); \ + } \ + else \ + __catchResult.captureResult( Catch::ResultWas::Ok ); \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::alwaysFalse() ) + +/////////////////////////////////////////////////////////////////////////////// +#ifdef CATCH_CONFIG_VARIADIC_MACROS + #define INTERNAL_CATCH_MSG( messageType, resultDisposition, macroName, ... ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \ + __catchResult << __VA_ARGS__ + ::Catch::StreamEndStop(); \ + __catchResult.captureResult( messageType ); \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::alwaysFalse() ) +#else + #define INTERNAL_CATCH_MSG( messageType, resultDisposition, macroName, log ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \ + __catchResult << log + ::Catch::StreamEndStop(); \ + __catchResult.captureResult( messageType ); \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::alwaysFalse() ) +#endif + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_INFO( log, macroName ) \ + Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME( scopedMessage ) = Catch::MessageBuilder( macroName, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log; + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CHECK_THAT( arg, matcher, resultDisposition, macroName ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #arg ", " #matcher, resultDisposition ); \ + try { \ + std::string matcherAsString = (matcher).toString(); \ + __catchResult \ + .setLhs( Catch::toString( arg ) ) \ + .setRhs( matcherAsString == Catch::Detail::unprintableString ? #matcher : matcherAsString ) \ + .setOp( "matches" ) \ + .setResultType( (matcher).match( arg ) ); \ + __catchResult.captureExpression(); \ + } catch( ... ) { \ + __catchResult.useActiveException( resultDisposition | Catch::ResultDisposition::ContinueOnFailure ); \ + } \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::alwaysFalse() ) + +// #included from: internal/catch_section.h +#define TWOBLUECUBES_CATCH_SECTION_H_INCLUDED + +// #included from: catch_section_info.h +#define TWOBLUECUBES_CATCH_SECTION_INFO_H_INCLUDED + +// #included from: catch_totals.hpp +#define TWOBLUECUBES_CATCH_TOTALS_HPP_INCLUDED + +#include + +namespace Catch { + + struct Counts { + Counts() : passed( 0 ), failed( 0 ), failedButOk( 0 ) {} + + Counts operator - ( Counts const& other ) const { + Counts diff; + diff.passed = passed - other.passed; + diff.failed = failed - other.failed; + diff.failedButOk = failedButOk - other.failedButOk; + return diff; + } + Counts& operator += ( Counts const& other ) { + passed += other.passed; + failed += other.failed; + failedButOk += other.failedButOk; + return *this; + } + + std::size_t total() const { + return passed + failed + failedButOk; + } + bool allPassed() const { + return failed == 0 && failedButOk == 0; + } + bool allOk() const { + return failed == 0; + } + + std::size_t passed; + std::size_t failed; + std::size_t failedButOk; + }; + + struct Totals { + + Totals operator - ( Totals const& other ) const { + Totals diff; + diff.assertions = assertions - other.assertions; + diff.testCases = testCases - other.testCases; + return diff; + } + + Totals delta( Totals const& prevTotals ) const { + Totals diff = *this - prevTotals; + if( diff.assertions.failed > 0 ) + ++diff.testCases.failed; + else if( diff.assertions.failedButOk > 0 ) + ++diff.testCases.failedButOk; + else + ++diff.testCases.passed; + return diff; + } + + Totals& operator += ( Totals const& other ) { + assertions += other.assertions; + testCases += other.testCases; + return *this; + } + + Counts assertions; + Counts testCases; + }; +} + +namespace Catch { + + struct SectionInfo { + SectionInfo + ( SourceLineInfo const& _lineInfo, + std::string const& _name, + std::string const& _description = std::string() ); + + std::string name; + std::string description; + SourceLineInfo lineInfo; + }; + + struct SectionEndInfo { + SectionEndInfo( SectionInfo const& _sectionInfo, Counts const& _prevAssertions, double _durationInSeconds ) + : sectionInfo( _sectionInfo ), prevAssertions( _prevAssertions ), durationInSeconds( _durationInSeconds ) + {} + + SectionInfo sectionInfo; + Counts prevAssertions; + double durationInSeconds; + }; + +} // end namespace Catch + +// #included from: catch_timer.h +#define TWOBLUECUBES_CATCH_TIMER_H_INCLUDED + +#ifdef CATCH_PLATFORM_WINDOWS +typedef unsigned long long uint64_t; +#else +#include +#endif + +namespace Catch { + + class Timer { + public: + Timer() : m_ticks( 0 ) {} + void start(); + unsigned int getElapsedMicroseconds() const; + unsigned int getElapsedMilliseconds() const; + double getElapsedSeconds() const; + + private: + uint64_t m_ticks; + }; + +} // namespace Catch + +#include + +namespace Catch { + + class Section : NonCopyable { + public: + Section( SectionInfo const& info ); + ~Section(); + + // This indicates whether the section should be executed or not + operator bool() const; + + private: + SectionInfo m_info; + + std::string m_name; + Counts m_assertions; + bool m_sectionIncluded; + Timer m_timer; + }; + +} // end namespace Catch + +#ifdef CATCH_CONFIG_VARIADIC_MACROS + #define INTERNAL_CATCH_SECTION( ... ) \ + if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) ) +#else + #define INTERNAL_CATCH_SECTION( name, desc ) \ + if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, name, desc ) ) +#endif + +// #included from: internal/catch_generators.hpp +#define TWOBLUECUBES_CATCH_GENERATORS_HPP_INCLUDED + +#include +#include +#include +#include + +namespace Catch { + +template +struct IGenerator { + virtual ~IGenerator() {} + virtual T getValue( std::size_t index ) const = 0; + virtual std::size_t size () const = 0; +}; + +template +class BetweenGenerator : public IGenerator { +public: + BetweenGenerator( T from, T to ) : m_from( from ), m_to( to ){} + + virtual T getValue( std::size_t index ) const { + return m_from+static_cast( index ); + } + + virtual std::size_t size() const { + return static_cast( 1+m_to-m_from ); + } + +private: + + T m_from; + T m_to; +}; + +template +class ValuesGenerator : public IGenerator { +public: + ValuesGenerator(){} + + void add( T value ) { + m_values.push_back( value ); + } + + virtual T getValue( std::size_t index ) const { + return m_values[index]; + } + + virtual std::size_t size() const { + return m_values.size(); + } + +private: + std::vector m_values; +}; + +template +class CompositeGenerator { +public: + CompositeGenerator() : m_totalSize( 0 ) {} + + // *** Move semantics, similar to auto_ptr *** + CompositeGenerator( CompositeGenerator& other ) + : m_fileInfo( other.m_fileInfo ), + m_totalSize( 0 ) + { + move( other ); + } + + CompositeGenerator& setFileInfo( const char* fileInfo ) { + m_fileInfo = fileInfo; + return *this; + } + + ~CompositeGenerator() { + deleteAll( m_composed ); + } + + operator T () const { + size_t overallIndex = getCurrentContext().getGeneratorIndex( m_fileInfo, m_totalSize ); + + typename std::vector*>::const_iterator it = m_composed.begin(); + typename std::vector*>::const_iterator itEnd = m_composed.end(); + for( size_t index = 0; it != itEnd; ++it ) + { + const IGenerator* generator = *it; + if( overallIndex >= index && overallIndex < index + generator->size() ) + { + return generator->getValue( overallIndex-index ); + } + index += generator->size(); + } + CATCH_INTERNAL_ERROR( "Indexed past end of generated range" ); + return T(); // Suppress spurious "not all control paths return a value" warning in Visual Studio - if you know how to fix this please do so + } + + void add( const IGenerator* generator ) { + m_totalSize += generator->size(); + m_composed.push_back( generator ); + } + + CompositeGenerator& then( CompositeGenerator& other ) { + move( other ); + return *this; + } + + CompositeGenerator& then( T value ) { + ValuesGenerator* valuesGen = new ValuesGenerator(); + valuesGen->add( value ); + add( valuesGen ); + return *this; + } + +private: + + void move( CompositeGenerator& other ) { + std::copy( other.m_composed.begin(), other.m_composed.end(), std::back_inserter( m_composed ) ); + m_totalSize += other.m_totalSize; + other.m_composed.clear(); + } + + std::vector*> m_composed; + std::string m_fileInfo; + size_t m_totalSize; +}; + +namespace Generators +{ + template + CompositeGenerator between( T from, T to ) { + CompositeGenerator generators; + generators.add( new BetweenGenerator( from, to ) ); + return generators; + } + + template + CompositeGenerator values( T val1, T val2 ) { + CompositeGenerator generators; + ValuesGenerator* valuesGen = new ValuesGenerator(); + valuesGen->add( val1 ); + valuesGen->add( val2 ); + generators.add( valuesGen ); + return generators; + } + + template + CompositeGenerator values( T val1, T val2, T val3 ){ + CompositeGenerator generators; + ValuesGenerator* valuesGen = new ValuesGenerator(); + valuesGen->add( val1 ); + valuesGen->add( val2 ); + valuesGen->add( val3 ); + generators.add( valuesGen ); + return generators; + } + + template + CompositeGenerator values( T val1, T val2, T val3, T val4 ) { + CompositeGenerator generators; + ValuesGenerator* valuesGen = new ValuesGenerator(); + valuesGen->add( val1 ); + valuesGen->add( val2 ); + valuesGen->add( val3 ); + valuesGen->add( val4 ); + generators.add( valuesGen ); + return generators; + } + +} // end namespace Generators + +using namespace Generators; + +} // end namespace Catch + +#define INTERNAL_CATCH_LINESTR2( line ) #line +#define INTERNAL_CATCH_LINESTR( line ) INTERNAL_CATCH_LINESTR2( line ) + +#define INTERNAL_CATCH_GENERATE( expr ) expr.setFileInfo( __FILE__ "(" INTERNAL_CATCH_LINESTR( __LINE__ ) ")" ) + +// #included from: internal/catch_interfaces_exception.h +#define TWOBLUECUBES_CATCH_INTERFACES_EXCEPTION_H_INCLUDED + +#include +#include + +// #included from: catch_interfaces_registry_hub.h +#define TWOBLUECUBES_CATCH_INTERFACES_REGISTRY_HUB_H_INCLUDED + +#include + +namespace Catch { + + class TestCase; + struct ITestCaseRegistry; + struct IExceptionTranslatorRegistry; + struct IExceptionTranslator; + struct IReporterRegistry; + struct IReporterFactory; + + struct IRegistryHub { + virtual ~IRegistryHub(); + + virtual IReporterRegistry const& getReporterRegistry() const = 0; + virtual ITestCaseRegistry const& getTestCaseRegistry() const = 0; + virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() = 0; + }; + + struct IMutableRegistryHub { + virtual ~IMutableRegistryHub(); + virtual void registerReporter( std::string const& name, Ptr const& factory ) = 0; + virtual void registerListener( Ptr const& factory ) = 0; + virtual void registerTest( TestCase const& testInfo ) = 0; + virtual void registerTranslator( const IExceptionTranslator* translator ) = 0; + }; + + IRegistryHub& getRegistryHub(); + IMutableRegistryHub& getMutableRegistryHub(); + void cleanUp(); + std::string translateActiveException(); + +} + +namespace Catch { + + typedef std::string(*exceptionTranslateFunction)(); + + struct IExceptionTranslator; + typedef std::vector ExceptionTranslators; + + struct IExceptionTranslator { + virtual ~IExceptionTranslator(); + virtual std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const = 0; + }; + + struct IExceptionTranslatorRegistry { + virtual ~IExceptionTranslatorRegistry(); + + virtual std::string translateActiveException() const = 0; + }; + + class ExceptionTranslatorRegistrar { + template + class ExceptionTranslator : public IExceptionTranslator { + public: + + ExceptionTranslator( std::string(*translateFunction)( T& ) ) + : m_translateFunction( translateFunction ) + {} + + virtual std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const CATCH_OVERRIDE { + try { + if( it == itEnd ) + throw; + else + return (*it)->translate( it+1, itEnd ); + } + catch( T& ex ) { + return m_translateFunction( ex ); + } + } + + protected: + std::string(*m_translateFunction)( T& ); + }; + + public: + template + ExceptionTranslatorRegistrar( std::string(*translateFunction)( T& ) ) { + getMutableRegistryHub().registerTranslator + ( new ExceptionTranslator( translateFunction ) ); + } + }; +} + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) \ + static std::string INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator )( signature ); \ + namespace{ Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ) ); }\ + static std::string INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator )( signature ) + +// #included from: internal/catch_approx.hpp +#define TWOBLUECUBES_CATCH_APPROX_HPP_INCLUDED + +#include +#include + +namespace Catch { +namespace Detail { + + class Approx { + public: + explicit Approx ( double value ) + : m_epsilon( std::numeric_limits::epsilon()*100 ), + m_scale( 1.0 ), + m_value( value ) + {} + + Approx( Approx const& other ) + : m_epsilon( other.m_epsilon ), + m_scale( other.m_scale ), + m_value( other.m_value ) + {} + + static Approx custom() { + return Approx( 0 ); + } + + Approx operator()( double value ) { + Approx approx( value ); + approx.epsilon( m_epsilon ); + approx.scale( m_scale ); + return approx; + } + + friend bool operator == ( double lhs, Approx const& rhs ) { + // Thanks to Richard Harris for his help refining this formula + return fabs( lhs - rhs.m_value ) < rhs.m_epsilon * (rhs.m_scale + (std::max)( fabs(lhs), fabs(rhs.m_value) ) ); + } + + friend bool operator == ( Approx const& lhs, double rhs ) { + return operator==( rhs, lhs ); + } + + friend bool operator != ( double lhs, Approx const& rhs ) { + return !operator==( lhs, rhs ); + } + + friend bool operator != ( Approx const& lhs, double rhs ) { + return !operator==( rhs, lhs ); + } + + Approx& epsilon( double newEpsilon ) { + m_epsilon = newEpsilon; + return *this; + } + + Approx& scale( double newScale ) { + m_scale = newScale; + return *this; + } + + std::string toString() const { + std::ostringstream oss; + oss << "Approx( " << Catch::toString( m_value ) << " )"; + return oss.str(); + } + + private: + double m_epsilon; + double m_scale; + double m_value; + }; +} + +template<> +inline std::string toString( Detail::Approx const& value ) { + return value.toString(); +} + +} // end namespace Catch + +// #included from: internal/catch_interfaces_tag_alias_registry.h +#define TWOBLUECUBES_CATCH_INTERFACES_TAG_ALIAS_REGISTRY_H_INCLUDED + +// #included from: catch_tag_alias.h +#define TWOBLUECUBES_CATCH_TAG_ALIAS_H_INCLUDED + +#include + +namespace Catch { + + struct TagAlias { + TagAlias( std::string _tag, SourceLineInfo _lineInfo ) : tag( _tag ), lineInfo( _lineInfo ) {} + + std::string tag; + SourceLineInfo lineInfo; + }; + + struct RegistrarForTagAliases { + RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ); + }; + +} // end namespace Catch + +#define CATCH_REGISTER_TAG_ALIAS( alias, spec ) namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); } +// #included from: catch_option.hpp +#define TWOBLUECUBES_CATCH_OPTION_HPP_INCLUDED + +namespace Catch { + + // An optional type + template + class Option { + public: + Option() : nullableValue( CATCH_NULL ) {} + Option( T const& _value ) + : nullableValue( new( storage ) T( _value ) ) + {} + Option( Option const& _other ) + : nullableValue( _other ? new( storage ) T( *_other ) : CATCH_NULL ) + {} + + ~Option() { + reset(); + } + + Option& operator= ( Option const& _other ) { + if( &_other != this ) { + reset(); + if( _other ) + nullableValue = new( storage ) T( *_other ); + } + return *this; + } + Option& operator = ( T const& _value ) { + reset(); + nullableValue = new( storage ) T( _value ); + return *this; + } + + void reset() { + if( nullableValue ) + nullableValue->~T(); + nullableValue = CATCH_NULL; + } + + T& operator*() { return *nullableValue; } + T const& operator*() const { return *nullableValue; } + T* operator->() { return nullableValue; } + const T* operator->() const { return nullableValue; } + + T valueOr( T const& defaultValue ) const { + return nullableValue ? *nullableValue : defaultValue; + } + + bool some() const { return nullableValue != CATCH_NULL; } + bool none() const { return nullableValue == CATCH_NULL; } + + bool operator !() const { return nullableValue == CATCH_NULL; } + operator SafeBool::type() const { + return SafeBool::makeSafe( some() ); + } + + private: + T* nullableValue; + char storage[sizeof(T)]; + }; + +} // end namespace Catch + +namespace Catch { + + struct ITagAliasRegistry { + virtual ~ITagAliasRegistry(); + virtual Option find( std::string const& alias ) const = 0; + virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const = 0; + + static ITagAliasRegistry const& get(); + }; + +} // end namespace Catch + +// These files are included here so the single_include script doesn't put them +// in the conditionally compiled sections +// #included from: internal/catch_test_case_info.h +#define TWOBLUECUBES_CATCH_TEST_CASE_INFO_H_INCLUDED + +#include +#include + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpadded" +#endif + +namespace Catch { + + struct ITestCase; + + struct TestCaseInfo { + enum SpecialProperties{ + None = 0, + IsHidden = 1 << 1, + ShouldFail = 1 << 2, + MayFail = 1 << 3, + Throws = 1 << 4 + }; + + TestCaseInfo( std::string const& _name, + std::string const& _className, + std::string const& _description, + std::set const& _tags, + SourceLineInfo const& _lineInfo ); + + TestCaseInfo( TestCaseInfo const& other ); + + friend void setTags( TestCaseInfo& testCaseInfo, std::set const& tags ); + + bool isHidden() const; + bool throws() const; + bool okToFail() const; + bool expectedToFail() const; + + std::string name; + std::string className; + std::string description; + std::set tags; + std::set lcaseTags; + std::string tagsAsString; + SourceLineInfo lineInfo; + SpecialProperties properties; + }; + + class TestCase : public TestCaseInfo { + public: + + TestCase( ITestCase* testCase, TestCaseInfo const& info ); + TestCase( TestCase const& other ); + + TestCase withName( std::string const& _newName ) const; + + void invoke() const; + + TestCaseInfo const& getTestCaseInfo() const; + + void swap( TestCase& other ); + bool operator == ( TestCase const& other ) const; + bool operator < ( TestCase const& other ) const; + TestCase& operator = ( TestCase const& other ); + + private: + Ptr test; + }; + + TestCase makeTestCase( ITestCase* testCase, + std::string const& className, + std::string const& name, + std::string const& description, + SourceLineInfo const& lineInfo ); +} + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + + +#ifdef __OBJC__ +// #included from: internal/catch_objc.hpp +#define TWOBLUECUBES_CATCH_OBJC_HPP_INCLUDED + +#import + +#include + +// NB. Any general catch headers included here must be included +// in catch.hpp first to make sure they are included by the single +// header for non obj-usage + +/////////////////////////////////////////////////////////////////////////////// +// This protocol is really only here for (self) documenting purposes, since +// all its methods are optional. +@protocol OcFixture + +@optional + +-(void) setUp; +-(void) tearDown; + +@end + +namespace Catch { + + class OcMethod : public SharedImpl { + + public: + OcMethod( Class cls, SEL sel ) : m_cls( cls ), m_sel( sel ) {} + + virtual void invoke() const { + id obj = [[m_cls alloc] init]; + + performOptionalSelector( obj, @selector(setUp) ); + performOptionalSelector( obj, m_sel ); + performOptionalSelector( obj, @selector(tearDown) ); + + arcSafeRelease( obj ); + } + private: + virtual ~OcMethod() {} + + Class m_cls; + SEL m_sel; + }; + + namespace Detail{ + + inline std::string getAnnotation( Class cls, + std::string const& annotationName, + std::string const& testCaseName ) { + NSString* selStr = [[NSString alloc] initWithFormat:@"Catch_%s_%s", annotationName.c_str(), testCaseName.c_str()]; + SEL sel = NSSelectorFromString( selStr ); + arcSafeRelease( selStr ); + id value = performOptionalSelector( cls, sel ); + if( value ) + return [(NSString*)value UTF8String]; + return ""; + } + } + + inline size_t registerTestMethods() { + size_t noTestMethods = 0; + int noClasses = objc_getClassList( CATCH_NULL, 0 ); + + Class* classes = (CATCH_UNSAFE_UNRETAINED Class *)malloc( sizeof(Class) * noClasses); + objc_getClassList( classes, noClasses ); + + for( int c = 0; c < noClasses; c++ ) { + Class cls = classes[c]; + { + u_int count; + Method* methods = class_copyMethodList( cls, &count ); + for( u_int m = 0; m < count ; m++ ) { + SEL selector = method_getName(methods[m]); + std::string methodName = sel_getName(selector); + if( startsWith( methodName, "Catch_TestCase_" ) ) { + std::string testCaseName = methodName.substr( 15 ); + std::string name = Detail::getAnnotation( cls, "Name", testCaseName ); + std::string desc = Detail::getAnnotation( cls, "Description", testCaseName ); + const char* className = class_getName( cls ); + + getMutableRegistryHub().registerTest( makeTestCase( new OcMethod( cls, selector ), className, name.c_str(), desc.c_str(), SourceLineInfo() ) ); + noTestMethods++; + } + } + free(methods); + } + } + return noTestMethods; + } + + namespace Matchers { + namespace Impl { + namespace NSStringMatchers { + + template + struct StringHolder : MatcherImpl{ + StringHolder( NSString* substr ) : m_substr( [substr copy] ){} + StringHolder( StringHolder const& other ) : m_substr( [other.m_substr copy] ){} + StringHolder() { + arcSafeRelease( m_substr ); + } + + NSString* m_substr; + }; + + struct Equals : StringHolder { + Equals( NSString* substr ) : StringHolder( substr ){} + + virtual bool match( ExpressionType const& str ) const { + return (str != nil || m_substr == nil ) && + [str isEqualToString:m_substr]; + } + + virtual std::string toString() const { + return "equals string: " + Catch::toString( m_substr ); + } + }; + + struct Contains : StringHolder { + Contains( NSString* substr ) : StringHolder( substr ){} + + virtual bool match( ExpressionType const& str ) const { + return (str != nil || m_substr == nil ) && + [str rangeOfString:m_substr].location != NSNotFound; + } + + virtual std::string toString() const { + return "contains string: " + Catch::toString( m_substr ); + } + }; + + struct StartsWith : StringHolder { + StartsWith( NSString* substr ) : StringHolder( substr ){} + + virtual bool match( ExpressionType const& str ) const { + return (str != nil || m_substr == nil ) && + [str rangeOfString:m_substr].location == 0; + } + + virtual std::string toString() const { + return "starts with: " + Catch::toString( m_substr ); + } + }; + struct EndsWith : StringHolder { + EndsWith( NSString* substr ) : StringHolder( substr ){} + + virtual bool match( ExpressionType const& str ) const { + return (str != nil || m_substr == nil ) && + [str rangeOfString:m_substr].location == [str length] - [m_substr length]; + } + + virtual std::string toString() const { + return "ends with: " + Catch::toString( m_substr ); + } + }; + + } // namespace NSStringMatchers + } // namespace Impl + + inline Impl::NSStringMatchers::Equals + Equals( NSString* substr ){ return Impl::NSStringMatchers::Equals( substr ); } + + inline Impl::NSStringMatchers::Contains + Contains( NSString* substr ){ return Impl::NSStringMatchers::Contains( substr ); } + + inline Impl::NSStringMatchers::StartsWith + StartsWith( NSString* substr ){ return Impl::NSStringMatchers::StartsWith( substr ); } + + inline Impl::NSStringMatchers::EndsWith + EndsWith( NSString* substr ){ return Impl::NSStringMatchers::EndsWith( substr ); } + + } // namespace Matchers + + using namespace Matchers; + +} // namespace Catch + +/////////////////////////////////////////////////////////////////////////////// +#define OC_TEST_CASE( name, desc )\ ++(NSString*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Name_test ) \ +{\ +return @ name; \ +}\ ++(NSString*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Description_test ) \ +{ \ +return @ desc; \ +} \ +-(void) INTERNAL_CATCH_UNIQUE_NAME( Catch_TestCase_test ) + +#endif + +#ifdef CATCH_IMPL +// #included from: internal/catch_impl.hpp +#define TWOBLUECUBES_CATCH_IMPL_HPP_INCLUDED + +// Collect all the implementation files together here +// These are the equivalent of what would usually be cpp files + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wweak-vtables" +#endif + +// #included from: ../catch_session.hpp +#define TWOBLUECUBES_CATCH_RUNNER_HPP_INCLUDED + +// #included from: internal/catch_commandline.hpp +#define TWOBLUECUBES_CATCH_COMMANDLINE_HPP_INCLUDED + +// #included from: catch_config.hpp +#define TWOBLUECUBES_CATCH_CONFIG_HPP_INCLUDED + +// #included from: catch_test_spec_parser.hpp +#define TWOBLUECUBES_CATCH_TEST_SPEC_PARSER_HPP_INCLUDED + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpadded" +#endif + +// #included from: catch_test_spec.hpp +#define TWOBLUECUBES_CATCH_TEST_SPEC_HPP_INCLUDED + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpadded" +#endif + +// #included from: catch_wildcard_pattern.hpp +#define TWOBLUECUBES_CATCH_WILDCARD_PATTERN_HPP_INCLUDED + +namespace Catch +{ + class WildcardPattern { + enum WildcardPosition { + NoWildcard = 0, + WildcardAtStart = 1, + WildcardAtEnd = 2, + WildcardAtBothEnds = WildcardAtStart | WildcardAtEnd + }; + + public: + + WildcardPattern( std::string const& pattern, CaseSensitive::Choice caseSensitivity ) + : m_caseSensitivity( caseSensitivity ), + m_wildcard( NoWildcard ), + m_pattern( adjustCase( pattern ) ) + { + if( startsWith( m_pattern, "*" ) ) { + m_pattern = m_pattern.substr( 1 ); + m_wildcard = WildcardAtStart; + } + if( endsWith( m_pattern, "*" ) ) { + m_pattern = m_pattern.substr( 0, m_pattern.size()-1 ); + m_wildcard = static_cast( m_wildcard | WildcardAtEnd ); + } + } + virtual ~WildcardPattern(); + virtual bool matches( std::string const& str ) const { + switch( m_wildcard ) { + case NoWildcard: + return m_pattern == adjustCase( str ); + case WildcardAtStart: + return endsWith( adjustCase( str ), m_pattern ); + case WildcardAtEnd: + return startsWith( adjustCase( str ), m_pattern ); + case WildcardAtBothEnds: + return contains( adjustCase( str ), m_pattern ); + } + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunreachable-code" +#endif + throw std::logic_error( "Unknown enum" ); +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + } + private: + std::string adjustCase( std::string const& str ) const { + return m_caseSensitivity == CaseSensitive::No ? toLower( str ) : str; + } + CaseSensitive::Choice m_caseSensitivity; + WildcardPosition m_wildcard; + std::string m_pattern; + }; +} + +#include +#include + +namespace Catch { + + class TestSpec { + struct Pattern : SharedImpl<> { + virtual ~Pattern(); + virtual bool matches( TestCaseInfo const& testCase ) const = 0; + }; + class NamePattern : public Pattern { + public: + NamePattern( std::string const& name ) + : m_wildcardPattern( toLower( name ), CaseSensitive::No ) + {} + virtual ~NamePattern(); + virtual bool matches( TestCaseInfo const& testCase ) const { + return m_wildcardPattern.matches( toLower( testCase.name ) ); + } + private: + WildcardPattern m_wildcardPattern; + }; + + class TagPattern : public Pattern { + public: + TagPattern( std::string const& tag ) : m_tag( toLower( tag ) ) {} + virtual ~TagPattern(); + virtual bool matches( TestCaseInfo const& testCase ) const { + return testCase.lcaseTags.find( m_tag ) != testCase.lcaseTags.end(); + } + private: + std::string m_tag; + }; + + class ExcludedPattern : public Pattern { + public: + ExcludedPattern( Ptr const& underlyingPattern ) : m_underlyingPattern( underlyingPattern ) {} + virtual ~ExcludedPattern(); + virtual bool matches( TestCaseInfo const& testCase ) const { return !m_underlyingPattern->matches( testCase ); } + private: + Ptr m_underlyingPattern; + }; + + struct Filter { + std::vector > m_patterns; + + bool matches( TestCaseInfo const& testCase ) const { + // All patterns in a filter must match for the filter to be a match + for( std::vector >::const_iterator it = m_patterns.begin(), itEnd = m_patterns.end(); it != itEnd; ++it ) + if( !(*it)->matches( testCase ) ) + return false; + return true; + } + }; + + public: + bool hasFilters() const { + return !m_filters.empty(); + } + bool matches( TestCaseInfo const& testCase ) const { + // A TestSpec matches if any filter matches + for( std::vector::const_iterator it = m_filters.begin(), itEnd = m_filters.end(); it != itEnd; ++it ) + if( it->matches( testCase ) ) + return true; + return false; + } + + private: + std::vector m_filters; + + friend class TestSpecParser; + }; +} + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +namespace Catch { + + class TestSpecParser { + enum Mode{ None, Name, QuotedName, Tag }; + Mode m_mode; + bool m_exclusion; + std::size_t m_start, m_pos; + std::string m_arg; + TestSpec::Filter m_currentFilter; + TestSpec m_testSpec; + ITagAliasRegistry const* m_tagAliases; + + public: + TestSpecParser( ITagAliasRegistry const& tagAliases ) : m_tagAliases( &tagAliases ) {} + + TestSpecParser& parse( std::string const& arg ) { + m_mode = None; + m_exclusion = false; + m_start = std::string::npos; + m_arg = m_tagAliases->expandAliases( arg ); + for( m_pos = 0; m_pos < m_arg.size(); ++m_pos ) + visitChar( m_arg[m_pos] ); + if( m_mode == Name ) + addPattern(); + return *this; + } + TestSpec testSpec() { + addFilter(); + return m_testSpec; + } + private: + void visitChar( char c ) { + if( m_mode == None ) { + switch( c ) { + case ' ': return; + case '~': m_exclusion = true; return; + case '[': return startNewMode( Tag, ++m_pos ); + case '"': return startNewMode( QuotedName, ++m_pos ); + default: startNewMode( Name, m_pos ); break; + } + } + if( m_mode == Name ) { + if( c == ',' ) { + addPattern(); + addFilter(); + } + else if( c == '[' ) { + if( subString() == "exclude:" ) + m_exclusion = true; + else + addPattern(); + startNewMode( Tag, ++m_pos ); + } + } + else if( m_mode == QuotedName && c == '"' ) + addPattern(); + else if( m_mode == Tag && c == ']' ) + addPattern(); + } + void startNewMode( Mode mode, std::size_t start ) { + m_mode = mode; + m_start = start; + } + std::string subString() const { return m_arg.substr( m_start, m_pos - m_start ); } + template + void addPattern() { + std::string token = subString(); + if( startsWith( token, "exclude:" ) ) { + m_exclusion = true; + token = token.substr( 8 ); + } + if( !token.empty() ) { + Ptr pattern = new T( token ); + if( m_exclusion ) + pattern = new TestSpec::ExcludedPattern( pattern ); + m_currentFilter.m_patterns.push_back( pattern ); + } + m_exclusion = false; + m_mode = None; + } + void addFilter() { + if( !m_currentFilter.m_patterns.empty() ) { + m_testSpec.m_filters.push_back( m_currentFilter ); + m_currentFilter = TestSpec::Filter(); + } + } + }; + inline TestSpec parseTestSpec( std::string const& arg ) { + return TestSpecParser( ITagAliasRegistry::get() ).parse( arg ).testSpec(); + } + +} // namespace Catch + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +// #included from: catch_interfaces_config.h +#define TWOBLUECUBES_CATCH_INTERFACES_CONFIG_H_INCLUDED + +#include +#include +#include + +namespace Catch { + + struct Verbosity { enum Level { + NoOutput = 0, + Quiet, + Normal + }; }; + + struct WarnAbout { enum What { + Nothing = 0x00, + NoAssertions = 0x01 + }; }; + + struct ShowDurations { enum OrNot { + DefaultForReporter, + Always, + Never + }; }; + struct RunTests { enum InWhatOrder { + InDeclarationOrder, + InLexicographicalOrder, + InRandomOrder + }; }; + struct UseColour { enum YesOrNo { + Auto, + Yes, + No + }; }; + + class TestSpec; + + struct IConfig : IShared { + + virtual ~IConfig(); + + virtual bool allowThrows() const = 0; + virtual std::ostream& stream() const = 0; + virtual std::string name() const = 0; + virtual bool includeSuccessfulResults() const = 0; + virtual bool shouldDebugBreak() const = 0; + virtual bool warnAboutMissingAssertions() const = 0; + virtual int abortAfter() const = 0; + virtual bool showInvisibles() const = 0; + virtual ShowDurations::OrNot showDurations() const = 0; + virtual TestSpec const& testSpec() const = 0; + virtual RunTests::InWhatOrder runOrder() const = 0; + virtual unsigned int rngSeed() const = 0; + virtual UseColour::YesOrNo useColour() const = 0; + }; +} + +// #included from: catch_stream.h +#define TWOBLUECUBES_CATCH_STREAM_H_INCLUDED + +// #included from: catch_streambuf.h +#define TWOBLUECUBES_CATCH_STREAMBUF_H_INCLUDED + +#include + +namespace Catch { + + class StreamBufBase : public std::streambuf { + public: + virtual ~StreamBufBase() CATCH_NOEXCEPT; + }; +} + +#include +#include +#include + +namespace Catch { + + std::ostream& cout(); + std::ostream& cerr(); + + struct IStream { + virtual ~IStream() CATCH_NOEXCEPT; + virtual std::ostream& stream() const = 0; + }; + + class FileStream : public IStream { + mutable std::ofstream m_ofs; + public: + FileStream( std::string const& filename ); + virtual ~FileStream() CATCH_NOEXCEPT; + public: // IStream + virtual std::ostream& stream() const CATCH_OVERRIDE; + }; + + class CoutStream : public IStream { + mutable std::ostream m_os; + public: + CoutStream(); + virtual ~CoutStream() CATCH_NOEXCEPT; + + public: // IStream + virtual std::ostream& stream() const CATCH_OVERRIDE; + }; + + class DebugOutStream : public IStream { + std::auto_ptr m_streamBuf; + mutable std::ostream m_os; + public: + DebugOutStream(); + virtual ~DebugOutStream() CATCH_NOEXCEPT; + + public: // IStream + virtual std::ostream& stream() const CATCH_OVERRIDE; + }; +} + +#include +#include +#include +#include +#include + +#ifndef CATCH_CONFIG_CONSOLE_WIDTH +#define CATCH_CONFIG_CONSOLE_WIDTH 80 +#endif + +namespace Catch { + + struct ConfigData { + + ConfigData() + : listTests( false ), + listTags( false ), + listReporters( false ), + listTestNamesOnly( false ), + showSuccessfulTests( false ), + shouldDebugBreak( false ), + noThrow( false ), + showHelp( false ), + showInvisibles( false ), + filenamesAsTags( false ), + abortAfter( -1 ), + rngSeed( 0 ), + verbosity( Verbosity::Normal ), + warnings( WarnAbout::Nothing ), + showDurations( ShowDurations::DefaultForReporter ), + runOrder( RunTests::InDeclarationOrder ), + useColour( UseColour::Auto ) + {} + + bool listTests; + bool listTags; + bool listReporters; + bool listTestNamesOnly; + + bool showSuccessfulTests; + bool shouldDebugBreak; + bool noThrow; + bool showHelp; + bool showInvisibles; + bool filenamesAsTags; + + int abortAfter; + unsigned int rngSeed; + + Verbosity::Level verbosity; + WarnAbout::What warnings; + ShowDurations::OrNot showDurations; + RunTests::InWhatOrder runOrder; + UseColour::YesOrNo useColour; + + std::string outputFilename; + std::string name; + std::string processName; + + std::vector reporterNames; + std::vector testsOrTags; + }; + + class Config : public SharedImpl { + private: + Config( Config const& other ); + Config& operator = ( Config const& other ); + virtual void dummy(); + public: + + Config() + {} + + Config( ConfigData const& data ) + : m_data( data ), + m_stream( openStream() ) + { + if( !data.testsOrTags.empty() ) { + TestSpecParser parser( ITagAliasRegistry::get() ); + for( std::size_t i = 0; i < data.testsOrTags.size(); ++i ) + parser.parse( data.testsOrTags[i] ); + m_testSpec = parser.testSpec(); + } + } + + virtual ~Config() { + } + + std::string const& getFilename() const { + return m_data.outputFilename ; + } + + bool listTests() const { return m_data.listTests; } + bool listTestNamesOnly() const { return m_data.listTestNamesOnly; } + bool listTags() const { return m_data.listTags; } + bool listReporters() const { return m_data.listReporters; } + + std::string getProcessName() const { return m_data.processName; } + + bool shouldDebugBreak() const { return m_data.shouldDebugBreak; } + + std::vector getReporterNames() const { return m_data.reporterNames; } + + int abortAfter() const { return m_data.abortAfter; } + + TestSpec const& testSpec() const { return m_testSpec; } + + bool showHelp() const { return m_data.showHelp; } + bool showInvisibles() const { return m_data.showInvisibles; } + + // IConfig interface + virtual bool allowThrows() const { return !m_data.noThrow; } + virtual std::ostream& stream() const { return m_stream->stream(); } + virtual std::string name() const { return m_data.name.empty() ? m_data.processName : m_data.name; } + virtual bool includeSuccessfulResults() const { return m_data.showSuccessfulTests; } + virtual bool warnAboutMissingAssertions() const { return m_data.warnings & WarnAbout::NoAssertions; } + virtual ShowDurations::OrNot showDurations() const { return m_data.showDurations; } + virtual RunTests::InWhatOrder runOrder() const { return m_data.runOrder; } + virtual unsigned int rngSeed() const { return m_data.rngSeed; } + virtual UseColour::YesOrNo useColour() const { return m_data.useColour; } + + private: + + IStream const* openStream() { + if( m_data.outputFilename.empty() ) + return new CoutStream(); + else if( m_data.outputFilename[0] == '%' ) { + if( m_data.outputFilename == "%debug" ) + return new DebugOutStream(); + else + throw std::domain_error( "Unrecognised stream: " + m_data.outputFilename ); + } + else + return new FileStream( m_data.outputFilename ); + } + ConfigData m_data; + + std::auto_ptr m_stream; + TestSpec m_testSpec; + }; + +} // end namespace Catch + +// #included from: catch_clara.h +#define TWOBLUECUBES_CATCH_CLARA_H_INCLUDED + +// Use Catch's value for console width (store Clara's off to the side, if present) +#ifdef CLARA_CONFIG_CONSOLE_WIDTH +#define CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH CLARA_CONFIG_CONSOLE_WIDTH +#undef CLARA_CONFIG_CONSOLE_WIDTH +#endif +#define CLARA_CONFIG_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH + +// Declare Clara inside the Catch namespace +#define STITCH_CLARA_OPEN_NAMESPACE namespace Catch { +// #included from: ../external/clara.h + +// Version 0.0.1.1 + +// Only use header guard if we are not using an outer namespace +#if !defined(TWOBLUECUBES_CLARA_H_INCLUDED) || defined(STITCH_CLARA_OPEN_NAMESPACE) + +#ifndef STITCH_CLARA_OPEN_NAMESPACE +#define TWOBLUECUBES_CLARA_H_INCLUDED +#define STITCH_CLARA_OPEN_NAMESPACE +#define STITCH_CLARA_CLOSE_NAMESPACE +#else +#define STITCH_CLARA_CLOSE_NAMESPACE } +#endif + +#define STITCH_TBC_TEXT_FORMAT_OPEN_NAMESPACE STITCH_CLARA_OPEN_NAMESPACE + +// ----------- #included from tbc_text_format.h ----------- + +// Only use header guard if we are not using an outer namespace +#if !defined(TBC_TEXT_FORMAT_H_INCLUDED) || defined(STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE) +#ifndef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE +#define TBC_TEXT_FORMAT_H_INCLUDED +#endif + +#include +#include +#include +#include + +// Use optional outer namespace +#ifdef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE +namespace STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE { +#endif + +namespace Tbc { + +#ifdef TBC_TEXT_FORMAT_CONSOLE_WIDTH + const unsigned int consoleWidth = TBC_TEXT_FORMAT_CONSOLE_WIDTH; +#else + const unsigned int consoleWidth = 80; +#endif + + struct TextAttributes { + TextAttributes() + : initialIndent( std::string::npos ), + indent( 0 ), + width( consoleWidth-1 ), + tabChar( '\t' ) + {} + + TextAttributes& setInitialIndent( std::size_t _value ) { initialIndent = _value; return *this; } + TextAttributes& setIndent( std::size_t _value ) { indent = _value; return *this; } + TextAttributes& setWidth( std::size_t _value ) { width = _value; return *this; } + TextAttributes& setTabChar( char _value ) { tabChar = _value; return *this; } + + std::size_t initialIndent; // indent of first line, or npos + std::size_t indent; // indent of subsequent lines, or all if initialIndent is npos + std::size_t width; // maximum width of text, including indent. Longer text will wrap + char tabChar; // If this char is seen the indent is changed to current pos + }; + + class Text { + public: + Text( std::string const& _str, TextAttributes const& _attr = TextAttributes() ) + : attr( _attr ) + { + std::string wrappableChars = " [({.,/|\\-"; + std::size_t indent = _attr.initialIndent != std::string::npos + ? _attr.initialIndent + : _attr.indent; + std::string remainder = _str; + + while( !remainder.empty() ) { + if( lines.size() >= 1000 ) { + lines.push_back( "... message truncated due to excessive size" ); + return; + } + std::size_t tabPos = std::string::npos; + std::size_t width = (std::min)( remainder.size(), _attr.width - indent ); + std::size_t pos = remainder.find_first_of( '\n' ); + if( pos <= width ) { + width = pos; + } + pos = remainder.find_last_of( _attr.tabChar, width ); + if( pos != std::string::npos ) { + tabPos = pos; + if( remainder[width] == '\n' ) + width--; + remainder = remainder.substr( 0, tabPos ) + remainder.substr( tabPos+1 ); + } + + if( width == remainder.size() ) { + spliceLine( indent, remainder, width ); + } + else if( remainder[width] == '\n' ) { + spliceLine( indent, remainder, width ); + if( width <= 1 || remainder.size() != 1 ) + remainder = remainder.substr( 1 ); + indent = _attr.indent; + } + else { + pos = remainder.find_last_of( wrappableChars, width ); + if( pos != std::string::npos && pos > 0 ) { + spliceLine( indent, remainder, pos ); + if( remainder[0] == ' ' ) + remainder = remainder.substr( 1 ); + } + else { + spliceLine( indent, remainder, width-1 ); + lines.back() += "-"; + } + if( lines.size() == 1 ) + indent = _attr.indent; + if( tabPos != std::string::npos ) + indent += tabPos; + } + } + } + + void spliceLine( std::size_t _indent, std::string& _remainder, std::size_t _pos ) { + lines.push_back( std::string( _indent, ' ' ) + _remainder.substr( 0, _pos ) ); + _remainder = _remainder.substr( _pos ); + } + + typedef std::vector::const_iterator const_iterator; + + const_iterator begin() const { return lines.begin(); } + const_iterator end() const { return lines.end(); } + std::string const& last() const { return lines.back(); } + std::size_t size() const { return lines.size(); } + std::string const& operator[]( std::size_t _index ) const { return lines[_index]; } + std::string toString() const { + std::ostringstream oss; + oss << *this; + return oss.str(); + } + + inline friend std::ostream& operator << ( std::ostream& _stream, Text const& _text ) { + for( Text::const_iterator it = _text.begin(), itEnd = _text.end(); + it != itEnd; ++it ) { + if( it != _text.begin() ) + _stream << "\n"; + _stream << *it; + } + return _stream; + } + + private: + std::string str; + TextAttributes attr; + std::vector lines; + }; + +} // end namespace Tbc + +#ifdef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE +} // end outer namespace +#endif + +#endif // TBC_TEXT_FORMAT_H_INCLUDED + +// ----------- end of #include from tbc_text_format.h ----------- +// ........... back in clara.h + +#undef STITCH_TBC_TEXT_FORMAT_OPEN_NAMESPACE + +// ----------- #included from clara_compilers.h ----------- + +#ifndef TWOBLUECUBES_CLARA_COMPILERS_H_INCLUDED +#define TWOBLUECUBES_CLARA_COMPILERS_H_INCLUDED + +// Detect a number of compiler features - mostly C++11/14 conformance - by compiler +// The following features are defined: +// +// CLARA_CONFIG_CPP11_NULLPTR : is nullptr supported? +// CLARA_CONFIG_CPP11_NOEXCEPT : is noexcept supported? +// CLARA_CONFIG_CPP11_GENERATED_METHODS : The delete and default keywords for compiler generated methods +// CLARA_CONFIG_CPP11_OVERRIDE : is override supported? +// CLARA_CONFIG_CPP11_UNIQUE_PTR : is unique_ptr supported (otherwise use auto_ptr) + +// CLARA_CONFIG_CPP11_OR_GREATER : Is C++11 supported? + +// CLARA_CONFIG_VARIADIC_MACROS : are variadic macros supported? + +// In general each macro has a _NO_ form +// (e.g. CLARA_CONFIG_CPP11_NO_NULLPTR) which disables the feature. +// Many features, at point of detection, define an _INTERNAL_ macro, so they +// can be combined, en-mass, with the _NO_ forms later. + +// All the C++11 features can be disabled with CLARA_CONFIG_NO_CPP11 + +#ifdef __clang__ + +#if __has_feature(cxx_nullptr) +#define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR +#endif + +#if __has_feature(cxx_noexcept) +#define CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT +#endif + +#endif // __clang__ + +//////////////////////////////////////////////////////////////////////////////// +// GCC +#ifdef __GNUC__ + +#if __GNUC__ == 4 && __GNUC_MINOR__ >= 6 && defined(__GXX_EXPERIMENTAL_CXX0X__) +#define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR +#endif + +// - otherwise more recent versions define __cplusplus >= 201103L +// and will get picked up below + +#endif // __GNUC__ + +//////////////////////////////////////////////////////////////////////////////// +// Visual C++ +#ifdef _MSC_VER + +#if (_MSC_VER >= 1600) +#define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR +#define CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR +#endif + +#if (_MSC_VER >= 1900 ) // (VC++ 13 (VS2015)) +#define CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT +#define CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS +#endif + +#endif // _MSC_VER + +//////////////////////////////////////////////////////////////////////////////// +// C++ language feature support + +// catch all support for C++11 +#if defined(__cplusplus) && __cplusplus >= 201103L + +#define CLARA_CPP11_OR_GREATER + +#if !defined(CLARA_INTERNAL_CONFIG_CPP11_NULLPTR) +#define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR +#endif + +#ifndef CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT +#define CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT +#endif + +#ifndef CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS +#define CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS +#endif + +#if !defined(CLARA_INTERNAL_CONFIG_CPP11_OVERRIDE) +#define CLARA_INTERNAL_CONFIG_CPP11_OVERRIDE +#endif +#if !defined(CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) +#define CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR +#endif + +#endif // __cplusplus >= 201103L + +// Now set the actual defines based on the above + anything the user has configured +#if defined(CLARA_INTERNAL_CONFIG_CPP11_NULLPTR) && !defined(CLARA_CONFIG_CPP11_NO_NULLPTR) && !defined(CLARA_CONFIG_CPP11_NULLPTR) && !defined(CLARA_CONFIG_NO_CPP11) +#define CLARA_CONFIG_CPP11_NULLPTR +#endif +#if defined(CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT) && !defined(CLARA_CONFIG_CPP11_NO_NOEXCEPT) && !defined(CLARA_CONFIG_CPP11_NOEXCEPT) && !defined(CLARA_CONFIG_NO_CPP11) +#define CLARA_CONFIG_CPP11_NOEXCEPT +#endif +#if defined(CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS) && !defined(CLARA_CONFIG_CPP11_NO_GENERATED_METHODS) && !defined(CLARA_CONFIG_CPP11_GENERATED_METHODS) && !defined(CLARA_CONFIG_NO_CPP11) +#define CLARA_CONFIG_CPP11_GENERATED_METHODS +#endif +#if defined(CLARA_INTERNAL_CONFIG_CPP11_OVERRIDE) && !defined(CLARA_CONFIG_NO_OVERRIDE) && !defined(CLARA_CONFIG_CPP11_OVERRIDE) && !defined(CLARA_CONFIG_NO_CPP11) +#define CLARA_CONFIG_CPP11_OVERRIDE +#endif +#if defined(CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) && !defined(CLARA_CONFIG_NO_UNIQUE_PTR) && !defined(CLARA_CONFIG_CPP11_UNIQUE_PTR) && !defined(CLARA_CONFIG_NO_CPP11) +#define CLARA_CONFIG_CPP11_UNIQUE_PTR +#endif + +// noexcept support: +#if defined(CLARA_CONFIG_CPP11_NOEXCEPT) && !defined(CLARA_NOEXCEPT) +#define CLARA_NOEXCEPT noexcept +# define CLARA_NOEXCEPT_IS(x) noexcept(x) +#else +#define CLARA_NOEXCEPT throw() +# define CLARA_NOEXCEPT_IS(x) +#endif + +// nullptr support +#ifdef CLARA_CONFIG_CPP11_NULLPTR +#define CLARA_NULL nullptr +#else +#define CLARA_NULL NULL +#endif + +// override support +#ifdef CLARA_CONFIG_CPP11_OVERRIDE +#define CLARA_OVERRIDE override +#else +#define CLARA_OVERRIDE +#endif + +// unique_ptr support +#ifdef CLARA_CONFIG_CPP11_UNIQUE_PTR +# define CLARA_AUTO_PTR( T ) std::unique_ptr +#else +# define CLARA_AUTO_PTR( T ) std::auto_ptr +#endif + +#endif // TWOBLUECUBES_CLARA_COMPILERS_H_INCLUDED + +// ----------- end of #include from clara_compilers.h ----------- +// ........... back in clara.h + +#include +#include +#include + +// Use optional outer namespace +#ifdef STITCH_CLARA_OPEN_NAMESPACE +STITCH_CLARA_OPEN_NAMESPACE +#endif + +namespace Clara { + + struct UnpositionalTag {}; + + extern UnpositionalTag _; + +#ifdef CLARA_CONFIG_MAIN + UnpositionalTag _; +#endif + + namespace Detail { + +#ifdef CLARA_CONSOLE_WIDTH + const unsigned int consoleWidth = CLARA_CONFIG_CONSOLE_WIDTH; +#else + const unsigned int consoleWidth = 80; +#endif + + // Use this to try and stop compiler from warning about unreachable code + inline bool isTrue( bool value ) { return value; } + + using namespace Tbc; + + inline bool startsWith( std::string const& str, std::string const& prefix ) { + return str.size() >= prefix.size() && str.substr( 0, prefix.size() ) == prefix; + } + + template struct RemoveConstRef{ typedef T type; }; + template struct RemoveConstRef{ typedef T type; }; + template struct RemoveConstRef{ typedef T type; }; + template struct RemoveConstRef{ typedef T type; }; + + template struct IsBool { static const bool value = false; }; + template<> struct IsBool { static const bool value = true; }; + + template + void convertInto( std::string const& _source, T& _dest ) { + std::stringstream ss; + ss << _source; + ss >> _dest; + if( ss.fail() ) + throw std::runtime_error( "Unable to convert " + _source + " to destination type" ); + } + inline void convertInto( std::string const& _source, std::string& _dest ) { + _dest = _source; + } + inline void convertInto( std::string const& _source, bool& _dest ) { + std::string sourceLC = _source; + std::transform( sourceLC.begin(), sourceLC.end(), sourceLC.begin(), ::tolower ); + if( sourceLC == "y" || sourceLC == "1" || sourceLC == "true" || sourceLC == "yes" || sourceLC == "on" ) + _dest = true; + else if( sourceLC == "n" || sourceLC == "0" || sourceLC == "false" || sourceLC == "no" || sourceLC == "off" ) + _dest = false; + else + throw std::runtime_error( "Expected a boolean value but did not recognise:\n '" + _source + "'" ); + } + inline void convertInto( bool _source, bool& _dest ) { + _dest = _source; + } + template + inline void convertInto( bool, T& ) { + if( isTrue( true ) ) + throw std::runtime_error( "Invalid conversion" ); + } + + template + struct IArgFunction { + virtual ~IArgFunction() {} +#ifdef CLARA_CONFIG_CPP11_GENERATED_METHODS + IArgFunction() = default; + IArgFunction( IArgFunction const& ) = default; +#endif + virtual void set( ConfigT& config, std::string const& value ) const = 0; + virtual void setFlag( ConfigT& config ) const = 0; + virtual bool takesArg() const = 0; + virtual IArgFunction* clone() const = 0; + }; + + template + class BoundArgFunction { + public: + BoundArgFunction() : functionObj( CLARA_NULL ) {} + BoundArgFunction( IArgFunction* _functionObj ) : functionObj( _functionObj ) {} + BoundArgFunction( BoundArgFunction const& other ) : functionObj( other.functionObj ? other.functionObj->clone() : CLARA_NULL ) {} + BoundArgFunction& operator = ( BoundArgFunction const& other ) { + IArgFunction* newFunctionObj = other.functionObj ? other.functionObj->clone() : CLARA_NULL; + delete functionObj; + functionObj = newFunctionObj; + return *this; + } + ~BoundArgFunction() { delete functionObj; } + + void set( ConfigT& config, std::string const& value ) const { + functionObj->set( config, value ); + } + void setFlag( ConfigT& config ) const { + functionObj->setFlag( config ); + } + bool takesArg() const { return functionObj->takesArg(); } + + bool isSet() const { + return functionObj != CLARA_NULL; + } + private: + IArgFunction* functionObj; + }; + + template + struct NullBinder : IArgFunction{ + virtual void set( C&, std::string const& ) const {} + virtual void setFlag( C& ) const {} + virtual bool takesArg() const { return true; } + virtual IArgFunction* clone() const { return new NullBinder( *this ); } + }; + + template + struct BoundDataMember : IArgFunction{ + BoundDataMember( M C::* _member ) : member( _member ) {} + virtual void set( C& p, std::string const& stringValue ) const { + convertInto( stringValue, p.*member ); + } + virtual void setFlag( C& p ) const { + convertInto( true, p.*member ); + } + virtual bool takesArg() const { return !IsBool::value; } + virtual IArgFunction* clone() const { return new BoundDataMember( *this ); } + M C::* member; + }; + template + struct BoundUnaryMethod : IArgFunction{ + BoundUnaryMethod( void (C::*_member)( M ) ) : member( _member ) {} + virtual void set( C& p, std::string const& stringValue ) const { + typename RemoveConstRef::type value; + convertInto( stringValue, value ); + (p.*member)( value ); + } + virtual void setFlag( C& p ) const { + typename RemoveConstRef::type value; + convertInto( true, value ); + (p.*member)( value ); + } + virtual bool takesArg() const { return !IsBool::value; } + virtual IArgFunction* clone() const { return new BoundUnaryMethod( *this ); } + void (C::*member)( M ); + }; + template + struct BoundNullaryMethod : IArgFunction{ + BoundNullaryMethod( void (C::*_member)() ) : member( _member ) {} + virtual void set( C& p, std::string const& stringValue ) const { + bool value; + convertInto( stringValue, value ); + if( value ) + (p.*member)(); + } + virtual void setFlag( C& p ) const { + (p.*member)(); + } + virtual bool takesArg() const { return false; } + virtual IArgFunction* clone() const { return new BoundNullaryMethod( *this ); } + void (C::*member)(); + }; + + template + struct BoundUnaryFunction : IArgFunction{ + BoundUnaryFunction( void (*_function)( C& ) ) : function( _function ) {} + virtual void set( C& obj, std::string const& stringValue ) const { + bool value; + convertInto( stringValue, value ); + if( value ) + function( obj ); + } + virtual void setFlag( C& p ) const { + function( p ); + } + virtual bool takesArg() const { return false; } + virtual IArgFunction* clone() const { return new BoundUnaryFunction( *this ); } + void (*function)( C& ); + }; + + template + struct BoundBinaryFunction : IArgFunction{ + BoundBinaryFunction( void (*_function)( C&, T ) ) : function( _function ) {} + virtual void set( C& obj, std::string const& stringValue ) const { + typename RemoveConstRef::type value; + convertInto( stringValue, value ); + function( obj, value ); + } + virtual void setFlag( C& obj ) const { + typename RemoveConstRef::type value; + convertInto( true, value ); + function( obj, value ); + } + virtual bool takesArg() const { return !IsBool::value; } + virtual IArgFunction* clone() const { return new BoundBinaryFunction( *this ); } + void (*function)( C&, T ); + }; + + } // namespace Detail + + struct Parser { + Parser() : separators( " \t=:" ) {} + + struct Token { + enum Type { Positional, ShortOpt, LongOpt }; + Token( Type _type, std::string const& _data ) : type( _type ), data( _data ) {} + Type type; + std::string data; + }; + + void parseIntoTokens( int argc, char const* const argv[], std::vector& tokens ) const { + const std::string doubleDash = "--"; + for( int i = 1; i < argc && argv[i] != doubleDash; ++i ) + parseIntoTokens( argv[i] , tokens); + } + void parseIntoTokens( std::string arg, std::vector& tokens ) const { + while( !arg.empty() ) { + Parser::Token token( Parser::Token::Positional, arg ); + arg = ""; + if( token.data[0] == '-' ) { + if( token.data.size() > 1 && token.data[1] == '-' ) { + token = Parser::Token( Parser::Token::LongOpt, token.data.substr( 2 ) ); + } + else { + token = Parser::Token( Parser::Token::ShortOpt, token.data.substr( 1 ) ); + if( token.data.size() > 1 && separators.find( token.data[1] ) == std::string::npos ) { + arg = "-" + token.data.substr( 1 ); + token.data = token.data.substr( 0, 1 ); + } + } + } + if( token.type != Parser::Token::Positional ) { + std::size_t pos = token.data.find_first_of( separators ); + if( pos != std::string::npos ) { + arg = token.data.substr( pos+1 ); + token.data = token.data.substr( 0, pos ); + } + } + tokens.push_back( token ); + } + } + std::string separators; + }; + + template + struct CommonArgProperties { + CommonArgProperties() {} + CommonArgProperties( Detail::BoundArgFunction const& _boundField ) : boundField( _boundField ) {} + + Detail::BoundArgFunction boundField; + std::string description; + std::string detail; + std::string placeholder; // Only value if boundField takes an arg + + bool takesArg() const { + return !placeholder.empty(); + } + void validate() const { + if( !boundField.isSet() ) + throw std::logic_error( "option not bound" ); + } + }; + struct OptionArgProperties { + std::vector shortNames; + std::string longName; + + bool hasShortName( std::string const& shortName ) const { + return std::find( shortNames.begin(), shortNames.end(), shortName ) != shortNames.end(); + } + bool hasLongName( std::string const& _longName ) const { + return _longName == longName; + } + }; + struct PositionalArgProperties { + PositionalArgProperties() : position( -1 ) {} + int position; // -1 means non-positional (floating) + + bool isFixedPositional() const { + return position != -1; + } + }; + + template + class CommandLine { + + struct Arg : CommonArgProperties, OptionArgProperties, PositionalArgProperties { + Arg() {} + Arg( Detail::BoundArgFunction const& _boundField ) : CommonArgProperties( _boundField ) {} + + using CommonArgProperties::placeholder; // !TBD + + std::string dbgName() const { + if( !longName.empty() ) + return "--" + longName; + if( !shortNames.empty() ) + return "-" + shortNames[0]; + return "positional args"; + } + std::string commands() const { + std::ostringstream oss; + bool first = true; + std::vector::const_iterator it = shortNames.begin(), itEnd = shortNames.end(); + for(; it != itEnd; ++it ) { + if( first ) + first = false; + else + oss << ", "; + oss << "-" << *it; + } + if( !longName.empty() ) { + if( !first ) + oss << ", "; + oss << "--" << longName; + } + if( !placeholder.empty() ) + oss << " <" << placeholder << ">"; + return oss.str(); + } + }; + + typedef CLARA_AUTO_PTR( Arg ) ArgAutoPtr; + + friend void addOptName( Arg& arg, std::string const& optName ) + { + if( optName.empty() ) + return; + if( Detail::startsWith( optName, "--" ) ) { + if( !arg.longName.empty() ) + throw std::logic_error( "Only one long opt may be specified. '" + + arg.longName + + "' already specified, now attempting to add '" + + optName + "'" ); + arg.longName = optName.substr( 2 ); + } + else if( Detail::startsWith( optName, "-" ) ) + arg.shortNames.push_back( optName.substr( 1 ) ); + else + throw std::logic_error( "option must begin with - or --. Option was: '" + optName + "'" ); + } + friend void setPositionalArg( Arg& arg, int position ) + { + arg.position = position; + } + + class ArgBuilder { + public: + ArgBuilder( Arg* arg ) : m_arg( arg ) {} + + // Bind a non-boolean data member (requires placeholder string) + template + void bind( M C::* field, std::string const& placeholder ) { + m_arg->boundField = new Detail::BoundDataMember( field ); + m_arg->placeholder = placeholder; + } + // Bind a boolean data member (no placeholder required) + template + void bind( bool C::* field ) { + m_arg->boundField = new Detail::BoundDataMember( field ); + } + + // Bind a method taking a single, non-boolean argument (requires a placeholder string) + template + void bind( void (C::* unaryMethod)( M ), std::string const& placeholder ) { + m_arg->boundField = new Detail::BoundUnaryMethod( unaryMethod ); + m_arg->placeholder = placeholder; + } + + // Bind a method taking a single, boolean argument (no placeholder string required) + template + void bind( void (C::* unaryMethod)( bool ) ) { + m_arg->boundField = new Detail::BoundUnaryMethod( unaryMethod ); + } + + // Bind a method that takes no arguments (will be called if opt is present) + template + void bind( void (C::* nullaryMethod)() ) { + m_arg->boundField = new Detail::BoundNullaryMethod( nullaryMethod ); + } + + // Bind a free function taking a single argument - the object to operate on (no placeholder string required) + template + void bind( void (* unaryFunction)( C& ) ) { + m_arg->boundField = new Detail::BoundUnaryFunction( unaryFunction ); + } + + // Bind a free function taking a single argument - the object to operate on (requires a placeholder string) + template + void bind( void (* binaryFunction)( C&, T ), std::string const& placeholder ) { + m_arg->boundField = new Detail::BoundBinaryFunction( binaryFunction ); + m_arg->placeholder = placeholder; + } + + ArgBuilder& describe( std::string const& description ) { + m_arg->description = description; + return *this; + } + ArgBuilder& detail( std::string const& detail ) { + m_arg->detail = detail; + return *this; + } + + protected: + Arg* m_arg; + }; + + class OptBuilder : public ArgBuilder { + public: + OptBuilder( Arg* arg ) : ArgBuilder( arg ) {} + OptBuilder( OptBuilder& other ) : ArgBuilder( other ) {} + + OptBuilder& operator[]( std::string const& optName ) { + addOptName( *ArgBuilder::m_arg, optName ); + return *this; + } + }; + + public: + + CommandLine() + : m_boundProcessName( new Detail::NullBinder() ), + m_highestSpecifiedArgPosition( 0 ), + m_throwOnUnrecognisedTokens( false ) + {} + CommandLine( CommandLine const& other ) + : m_boundProcessName( other.m_boundProcessName ), + m_options ( other.m_options ), + m_positionalArgs( other.m_positionalArgs ), + m_highestSpecifiedArgPosition( other.m_highestSpecifiedArgPosition ), + m_throwOnUnrecognisedTokens( other.m_throwOnUnrecognisedTokens ) + { + if( other.m_floatingArg.get() ) + m_floatingArg.reset( new Arg( *other.m_floatingArg ) ); + } + + CommandLine& setThrowOnUnrecognisedTokens( bool shouldThrow = true ) { + m_throwOnUnrecognisedTokens = shouldThrow; + return *this; + } + + OptBuilder operator[]( std::string const& optName ) { + m_options.push_back( Arg() ); + addOptName( m_options.back(), optName ); + OptBuilder builder( &m_options.back() ); + return builder; + } + + ArgBuilder operator[]( int position ) { + m_positionalArgs.insert( std::make_pair( position, Arg() ) ); + if( position > m_highestSpecifiedArgPosition ) + m_highestSpecifiedArgPosition = position; + setPositionalArg( m_positionalArgs[position], position ); + ArgBuilder builder( &m_positionalArgs[position] ); + return builder; + } + + // Invoke this with the _ instance + ArgBuilder operator[]( UnpositionalTag ) { + if( m_floatingArg.get() ) + throw std::logic_error( "Only one unpositional argument can be added" ); + m_floatingArg.reset( new Arg() ); + ArgBuilder builder( m_floatingArg.get() ); + return builder; + } + + template + void bindProcessName( M C::* field ) { + m_boundProcessName = new Detail::BoundDataMember( field ); + } + template + void bindProcessName( void (C::*_unaryMethod)( M ) ) { + m_boundProcessName = new Detail::BoundUnaryMethod( _unaryMethod ); + } + + void optUsage( std::ostream& os, std::size_t indent = 0, std::size_t width = Detail::consoleWidth ) const { + typename std::vector::const_iterator itBegin = m_options.begin(), itEnd = m_options.end(), it; + std::size_t maxWidth = 0; + for( it = itBegin; it != itEnd; ++it ) + maxWidth = (std::max)( maxWidth, it->commands().size() ); + + for( it = itBegin; it != itEnd; ++it ) { + Detail::Text usage( it->commands(), Detail::TextAttributes() + .setWidth( maxWidth+indent ) + .setIndent( indent ) ); + Detail::Text desc( it->description, Detail::TextAttributes() + .setWidth( width - maxWidth - 3 ) ); + + for( std::size_t i = 0; i < (std::max)( usage.size(), desc.size() ); ++i ) { + std::string usageCol = i < usage.size() ? usage[i] : ""; + os << usageCol; + + if( i < desc.size() && !desc[i].empty() ) + os << std::string( indent + 2 + maxWidth - usageCol.size(), ' ' ) + << desc[i]; + os << "\n"; + } + } + } + std::string optUsage() const { + std::ostringstream oss; + optUsage( oss ); + return oss.str(); + } + + void argSynopsis( std::ostream& os ) const { + for( int i = 1; i <= m_highestSpecifiedArgPosition; ++i ) { + if( i > 1 ) + os << " "; + typename std::map::const_iterator it = m_positionalArgs.find( i ); + if( it != m_positionalArgs.end() ) + os << "<" << it->second.placeholder << ">"; + else if( m_floatingArg.get() ) + os << "<" << m_floatingArg->placeholder << ">"; + else + throw std::logic_error( "non consecutive positional arguments with no floating args" ); + } + // !TBD No indication of mandatory args + if( m_floatingArg.get() ) { + if( m_highestSpecifiedArgPosition > 1 ) + os << " "; + os << "[<" << m_floatingArg->placeholder << "> ...]"; + } + } + std::string argSynopsis() const { + std::ostringstream oss; + argSynopsis( oss ); + return oss.str(); + } + + void usage( std::ostream& os, std::string const& procName ) const { + validate(); + os << "usage:\n " << procName << " "; + argSynopsis( os ); + if( !m_options.empty() ) { + os << " [options]\n\nwhere options are: \n"; + optUsage( os, 2 ); + } + os << "\n"; + } + std::string usage( std::string const& procName ) const { + std::ostringstream oss; + usage( oss, procName ); + return oss.str(); + } + + ConfigT parse( int argc, char const* const argv[] ) const { + ConfigT config; + parseInto( argc, argv, config ); + return config; + } + + std::vector parseInto( int argc, char const* argv[], ConfigT& config ) const { + std::string processName = argv[0]; + std::size_t lastSlash = processName.find_last_of( "/\\" ); + if( lastSlash != std::string::npos ) + processName = processName.substr( lastSlash+1 ); + m_boundProcessName.set( config, processName ); + std::vector tokens; + Parser parser; + parser.parseIntoTokens( argc, argv, tokens ); + return populate( tokens, config ); + } + + std::vector populate( std::vector const& tokens, ConfigT& config ) const { + validate(); + std::vector unusedTokens = populateOptions( tokens, config ); + unusedTokens = populateFixedArgs( unusedTokens, config ); + unusedTokens = populateFloatingArgs( unusedTokens, config ); + return unusedTokens; + } + + std::vector populateOptions( std::vector const& tokens, ConfigT& config ) const { + std::vector unusedTokens; + std::vector errors; + for( std::size_t i = 0; i < tokens.size(); ++i ) { + Parser::Token const& token = tokens[i]; + typename std::vector::const_iterator it = m_options.begin(), itEnd = m_options.end(); + for(; it != itEnd; ++it ) { + Arg const& arg = *it; + + try { + if( ( token.type == Parser::Token::ShortOpt && arg.hasShortName( token.data ) ) || + ( token.type == Parser::Token::LongOpt && arg.hasLongName( token.data ) ) ) { + if( arg.takesArg() ) { + if( i == tokens.size()-1 || tokens[i+1].type != Parser::Token::Positional ) + errors.push_back( "Expected argument to option: " + token.data ); + else + arg.boundField.set( config, tokens[++i].data ); + } + else { + arg.boundField.setFlag( config ); + } + break; + } + } + catch( std::exception& ex ) { + errors.push_back( std::string( ex.what() ) + "\n- while parsing: (" + arg.commands() + ")" ); + } + } + if( it == itEnd ) { + if( token.type == Parser::Token::Positional || !m_throwOnUnrecognisedTokens ) + unusedTokens.push_back( token ); + else if( errors.empty() && m_throwOnUnrecognisedTokens ) + errors.push_back( "unrecognised option: " + token.data ); + } + } + if( !errors.empty() ) { + std::ostringstream oss; + for( std::vector::const_iterator it = errors.begin(), itEnd = errors.end(); + it != itEnd; + ++it ) { + if( it != errors.begin() ) + oss << "\n"; + oss << *it; + } + throw std::runtime_error( oss.str() ); + } + return unusedTokens; + } + std::vector populateFixedArgs( std::vector const& tokens, ConfigT& config ) const { + std::vector unusedTokens; + int position = 1; + for( std::size_t i = 0; i < tokens.size(); ++i ) { + Parser::Token const& token = tokens[i]; + typename std::map::const_iterator it = m_positionalArgs.find( position ); + if( it != m_positionalArgs.end() ) + it->second.boundField.set( config, token.data ); + else + unusedTokens.push_back( token ); + if( token.type == Parser::Token::Positional ) + position++; + } + return unusedTokens; + } + std::vector populateFloatingArgs( std::vector const& tokens, ConfigT& config ) const { + if( !m_floatingArg.get() ) + return tokens; + std::vector unusedTokens; + for( std::size_t i = 0; i < tokens.size(); ++i ) { + Parser::Token const& token = tokens[i]; + if( token.type == Parser::Token::Positional ) + m_floatingArg->boundField.set( config, token.data ); + else + unusedTokens.push_back( token ); + } + return unusedTokens; + } + + void validate() const + { + if( m_options.empty() && m_positionalArgs.empty() && !m_floatingArg.get() ) + throw std::logic_error( "No options or arguments specified" ); + + for( typename std::vector::const_iterator it = m_options.begin(), + itEnd = m_options.end(); + it != itEnd; ++it ) + it->validate(); + } + + private: + Detail::BoundArgFunction m_boundProcessName; + std::vector m_options; + std::map m_positionalArgs; + ArgAutoPtr m_floatingArg; + int m_highestSpecifiedArgPosition; + bool m_throwOnUnrecognisedTokens; + }; + +} // end namespace Clara + +STITCH_CLARA_CLOSE_NAMESPACE +#undef STITCH_CLARA_OPEN_NAMESPACE +#undef STITCH_CLARA_CLOSE_NAMESPACE + +#endif // TWOBLUECUBES_CLARA_H_INCLUDED +#undef STITCH_CLARA_OPEN_NAMESPACE + +// Restore Clara's value for console width, if present +#ifdef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH +#define CLARA_CONFIG_CONSOLE_WIDTH CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH +#undef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH +#endif + +#include + +namespace Catch { + + inline void abortAfterFirst( ConfigData& config ) { config.abortAfter = 1; } + inline void abortAfterX( ConfigData& config, int x ) { + if( x < 1 ) + throw std::runtime_error( "Value after -x or --abortAfter must be greater than zero" ); + config.abortAfter = x; + } + inline void addTestOrTags( ConfigData& config, std::string const& _testSpec ) { config.testsOrTags.push_back( _testSpec ); } + inline void addReporterName( ConfigData& config, std::string const& _reporterName ) { config.reporterNames.push_back( _reporterName ); } + + inline void addWarning( ConfigData& config, std::string const& _warning ) { + if( _warning == "NoAssertions" ) + config.warnings = static_cast( config.warnings | WarnAbout::NoAssertions ); + else + throw std::runtime_error( "Unrecognised warning: '" + _warning + "'" ); + } + inline void setOrder( ConfigData& config, std::string const& order ) { + if( startsWith( "declared", order ) ) + config.runOrder = RunTests::InDeclarationOrder; + else if( startsWith( "lexical", order ) ) + config.runOrder = RunTests::InLexicographicalOrder; + else if( startsWith( "random", order ) ) + config.runOrder = RunTests::InRandomOrder; + else + throw std::runtime_error( "Unrecognised ordering: '" + order + "'" ); + } + inline void setRngSeed( ConfigData& config, std::string const& seed ) { + if( seed == "time" ) { + config.rngSeed = static_cast( std::time(0) ); + } + else { + std::stringstream ss; + ss << seed; + ss >> config.rngSeed; + if( ss.fail() ) + throw std::runtime_error( "Argment to --rng-seed should be the word 'time' or a number" ); + } + } + inline void setVerbosity( ConfigData& config, int level ) { + // !TBD: accept strings? + config.verbosity = static_cast( level ); + } + inline void setShowDurations( ConfigData& config, bool _showDurations ) { + config.showDurations = _showDurations + ? ShowDurations::Always + : ShowDurations::Never; + } + inline void setUseColour( ConfigData& config, std::string const& value ) { + std::string mode = toLower( value ); + + if( mode == "yes" ) + config.useColour = UseColour::Yes; + else if( mode == "no" ) + config.useColour = UseColour::No; + else if( mode == "auto" ) + config.useColour = UseColour::Auto; + else + throw std::runtime_error( "colour mode must be one of: auto, yes or no" ); + } + inline void forceColour( ConfigData& config ) { + config.useColour = UseColour::Yes; + } + inline void loadTestNamesFromFile( ConfigData& config, std::string const& _filename ) { + std::ifstream f( _filename.c_str() ); + if( !f.is_open() ) + throw std::domain_error( "Unable to load input file: " + _filename ); + + std::string line; + while( std::getline( f, line ) ) { + line = trim(line); + if( !line.empty() && !startsWith( line, "#" ) ) + addTestOrTags( config, "\"" + line + "\"," ); + } + } + + inline Clara::CommandLine makeCommandLineParser() { + + using namespace Clara; + CommandLine cli; + + cli.bindProcessName( &ConfigData::processName ); + + cli["-?"]["-h"]["--help"] + .describe( "display usage information" ) + .bind( &ConfigData::showHelp ); + + cli["-l"]["--list-tests"] + .describe( "list all/matching test cases" ) + .bind( &ConfigData::listTests ); + + cli["-t"]["--list-tags"] + .describe( "list all/matching tags" ) + .bind( &ConfigData::listTags ); + + cli["-s"]["--success"] + .describe( "include successful tests in output" ) + .bind( &ConfigData::showSuccessfulTests ); + + cli["-b"]["--break"] + .describe( "break into debugger on failure" ) + .bind( &ConfigData::shouldDebugBreak ); + + cli["-e"]["--nothrow"] + .describe( "skip exception tests" ) + .bind( &ConfigData::noThrow ); + + cli["-i"]["--invisibles"] + .describe( "show invisibles (tabs, newlines)" ) + .bind( &ConfigData::showInvisibles ); + + cli["-o"]["--out"] + .describe( "output filename" ) + .bind( &ConfigData::outputFilename, "filename" ); + + cli["-r"]["--reporter"] +// .placeholder( "name[:filename]" ) + .describe( "reporter to use (defaults to console)" ) + .bind( &addReporterName, "name" ); + + cli["-n"]["--name"] + .describe( "suite name" ) + .bind( &ConfigData::name, "name" ); + + cli["-a"]["--abort"] + .describe( "abort at first failure" ) + .bind( &abortAfterFirst ); + + cli["-x"]["--abortx"] + .describe( "abort after x failures" ) + .bind( &abortAfterX, "no. failures" ); + + cli["-w"]["--warn"] + .describe( "enable warnings" ) + .bind( &addWarning, "warning name" ); + +// - needs updating if reinstated +// cli.into( &setVerbosity ) +// .describe( "level of verbosity (0=no output)" ) +// .shortOpt( "v") +// .longOpt( "verbosity" ) +// .placeholder( "level" ); + + cli[_] + .describe( "which test or tests to use" ) + .bind( &addTestOrTags, "test name, pattern or tags" ); + + cli["-d"]["--durations"] + .describe( "show test durations" ) + .bind( &setShowDurations, "yes|no" ); + + cli["-f"]["--input-file"] + .describe( "load test names to run from a file" ) + .bind( &loadTestNamesFromFile, "filename" ); + + cli["-#"]["--filenames-as-tags"] + .describe( "adds a tag for the filename" ) + .bind( &ConfigData::filenamesAsTags ); + + // Less common commands which don't have a short form + cli["--list-test-names-only"] + .describe( "list all/matching test cases names only" ) + .bind( &ConfigData::listTestNamesOnly ); + + cli["--list-reporters"] + .describe( "list all reporters" ) + .bind( &ConfigData::listReporters ); + + cli["--order"] + .describe( "test case order (defaults to decl)" ) + .bind( &setOrder, "decl|lex|rand" ); + + cli["--rng-seed"] + .describe( "set a specific seed for random numbers" ) + .bind( &setRngSeed, "'time'|number" ); + + cli["--force-colour"] + .describe( "force colourised output (deprecated)" ) + .bind( &forceColour ); + + cli["--use-colour"] + .describe( "should output be colourised" ) + .bind( &setUseColour, "yes|no" ); + + return cli; + } + +} // end namespace Catch + +// #included from: internal/catch_list.hpp +#define TWOBLUECUBES_CATCH_LIST_HPP_INCLUDED + +// #included from: catch_text.h +#define TWOBLUECUBES_CATCH_TEXT_H_INCLUDED + +#define TBC_TEXT_FORMAT_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH + +#define CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE Catch +// #included from: ../external/tbc_text_format.h +// Only use header guard if we are not using an outer namespace +#ifndef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE +# ifdef TWOBLUECUBES_TEXT_FORMAT_H_INCLUDED +# ifndef TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED +# define TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED +# endif +# else +# define TWOBLUECUBES_TEXT_FORMAT_H_INCLUDED +# endif +#endif +#ifndef TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED +#include +#include +#include + +// Use optional outer namespace +#ifdef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE +namespace CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE { +#endif + +namespace Tbc { + +#ifdef TBC_TEXT_FORMAT_CONSOLE_WIDTH + const unsigned int consoleWidth = TBC_TEXT_FORMAT_CONSOLE_WIDTH; +#else + const unsigned int consoleWidth = 80; +#endif + + struct TextAttributes { + TextAttributes() + : initialIndent( std::string::npos ), + indent( 0 ), + width( consoleWidth-1 ), + tabChar( '\t' ) + {} + + TextAttributes& setInitialIndent( std::size_t _value ) { initialIndent = _value; return *this; } + TextAttributes& setIndent( std::size_t _value ) { indent = _value; return *this; } + TextAttributes& setWidth( std::size_t _value ) { width = _value; return *this; } + TextAttributes& setTabChar( char _value ) { tabChar = _value; return *this; } + + std::size_t initialIndent; // indent of first line, or npos + std::size_t indent; // indent of subsequent lines, or all if initialIndent is npos + std::size_t width; // maximum width of text, including indent. Longer text will wrap + char tabChar; // If this char is seen the indent is changed to current pos + }; + + class Text { + public: + Text( std::string const& _str, TextAttributes const& _attr = TextAttributes() ) + : attr( _attr ) + { + std::string wrappableChars = " [({.,/|\\-"; + std::size_t indent = _attr.initialIndent != std::string::npos + ? _attr.initialIndent + : _attr.indent; + std::string remainder = _str; + + while( !remainder.empty() ) { + if( lines.size() >= 1000 ) { + lines.push_back( "... message truncated due to excessive size" ); + return; + } + std::size_t tabPos = std::string::npos; + std::size_t width = (std::min)( remainder.size(), _attr.width - indent ); + std::size_t pos = remainder.find_first_of( '\n' ); + if( pos <= width ) { + width = pos; + } + pos = remainder.find_last_of( _attr.tabChar, width ); + if( pos != std::string::npos ) { + tabPos = pos; + if( remainder[width] == '\n' ) + width--; + remainder = remainder.substr( 0, tabPos ) + remainder.substr( tabPos+1 ); + } + + if( width == remainder.size() ) { + spliceLine( indent, remainder, width ); + } + else if( remainder[width] == '\n' ) { + spliceLine( indent, remainder, width ); + if( width <= 1 || remainder.size() != 1 ) + remainder = remainder.substr( 1 ); + indent = _attr.indent; + } + else { + pos = remainder.find_last_of( wrappableChars, width ); + if( pos != std::string::npos && pos > 0 ) { + spliceLine( indent, remainder, pos ); + if( remainder[0] == ' ' ) + remainder = remainder.substr( 1 ); + } + else { + spliceLine( indent, remainder, width-1 ); + lines.back() += "-"; + } + if( lines.size() == 1 ) + indent = _attr.indent; + if( tabPos != std::string::npos ) + indent += tabPos; + } + } + } + + void spliceLine( std::size_t _indent, std::string& _remainder, std::size_t _pos ) { + lines.push_back( std::string( _indent, ' ' ) + _remainder.substr( 0, _pos ) ); + _remainder = _remainder.substr( _pos ); + } + + typedef std::vector::const_iterator const_iterator; + + const_iterator begin() const { return lines.begin(); } + const_iterator end() const { return lines.end(); } + std::string const& last() const { return lines.back(); } + std::size_t size() const { return lines.size(); } + std::string const& operator[]( std::size_t _index ) const { return lines[_index]; } + std::string toString() const { + std::ostringstream oss; + oss << *this; + return oss.str(); + } + + inline friend std::ostream& operator << ( std::ostream& _stream, Text const& _text ) { + for( Text::const_iterator it = _text.begin(), itEnd = _text.end(); + it != itEnd; ++it ) { + if( it != _text.begin() ) + _stream << "\n"; + _stream << *it; + } + return _stream; + } + + private: + std::string str; + TextAttributes attr; + std::vector lines; + }; + +} // end namespace Tbc + +#ifdef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE +} // end outer namespace +#endif + +#endif // TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED +#undef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE + +namespace Catch { + using Tbc::Text; + using Tbc::TextAttributes; +} + +// #included from: catch_console_colour.hpp +#define TWOBLUECUBES_CATCH_CONSOLE_COLOUR_HPP_INCLUDED + +namespace Catch { + + struct Colour { + enum Code { + None = 0, + + White, + Red, + Green, + Blue, + Cyan, + Yellow, + Grey, + + Bright = 0x10, + + BrightRed = Bright | Red, + BrightGreen = Bright | Green, + LightGrey = Bright | Grey, + BrightWhite = Bright | White, + + // By intention + FileName = LightGrey, + Warning = Yellow, + ResultError = BrightRed, + ResultSuccess = BrightGreen, + ResultExpectedFailure = Warning, + + Error = BrightRed, + Success = Green, + + OriginalExpression = Cyan, + ReconstructedExpression = Yellow, + + SecondaryText = LightGrey, + Headers = White + }; + + // Use constructed object for RAII guard + Colour( Code _colourCode ); + Colour( Colour const& other ); + ~Colour(); + + // Use static method for one-shot changes + static void use( Code _colourCode ); + + private: + bool m_moved; + }; + + inline std::ostream& operator << ( std::ostream& os, Colour const& ) { return os; } + +} // end namespace Catch + +// #included from: catch_interfaces_reporter.h +#define TWOBLUECUBES_CATCH_INTERFACES_REPORTER_H_INCLUDED + +#include +#include +#include +#include + +namespace Catch +{ + struct ReporterConfig { + explicit ReporterConfig( Ptr const& _fullConfig ) + : m_stream( &_fullConfig->stream() ), m_fullConfig( _fullConfig ) {} + + ReporterConfig( Ptr const& _fullConfig, std::ostream& _stream ) + : m_stream( &_stream ), m_fullConfig( _fullConfig ) {} + + std::ostream& stream() const { return *m_stream; } + Ptr fullConfig() const { return m_fullConfig; } + + private: + std::ostream* m_stream; + Ptr m_fullConfig; + }; + + struct ReporterPreferences { + ReporterPreferences() + : shouldRedirectStdOut( false ) + {} + + bool shouldRedirectStdOut; + }; + + template + struct LazyStat : Option { + LazyStat() : used( false ) {} + LazyStat& operator=( T const& _value ) { + Option::operator=( _value ); + used = false; + return *this; + } + void reset() { + Option::reset(); + used = false; + } + bool used; + }; + + struct TestRunInfo { + TestRunInfo( std::string const& _name ) : name( _name ) {} + std::string name; + }; + struct GroupInfo { + GroupInfo( std::string const& _name, + std::size_t _groupIndex, + std::size_t _groupsCount ) + : name( _name ), + groupIndex( _groupIndex ), + groupsCounts( _groupsCount ) + {} + + std::string name; + std::size_t groupIndex; + std::size_t groupsCounts; + }; + + struct AssertionStats { + AssertionStats( AssertionResult const& _assertionResult, + std::vector const& _infoMessages, + Totals const& _totals ) + : assertionResult( _assertionResult ), + infoMessages( _infoMessages ), + totals( _totals ) + { + if( assertionResult.hasMessage() ) { + // Copy message into messages list. + // !TBD This should have been done earlier, somewhere + MessageBuilder builder( assertionResult.getTestMacroName(), assertionResult.getSourceInfo(), assertionResult.getResultType() ); + builder << assertionResult.getMessage(); + builder.m_info.message = builder.m_stream.str(); + + infoMessages.push_back( builder.m_info ); + } + } + virtual ~AssertionStats(); + +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + AssertionStats( AssertionStats const& ) = default; + AssertionStats( AssertionStats && ) = default; + AssertionStats& operator = ( AssertionStats const& ) = default; + AssertionStats& operator = ( AssertionStats && ) = default; +# endif + + AssertionResult assertionResult; + std::vector infoMessages; + Totals totals; + }; + + struct SectionStats { + SectionStats( SectionInfo const& _sectionInfo, + Counts const& _assertions, + double _durationInSeconds, + bool _missingAssertions ) + : sectionInfo( _sectionInfo ), + assertions( _assertions ), + durationInSeconds( _durationInSeconds ), + missingAssertions( _missingAssertions ) + {} + virtual ~SectionStats(); +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + SectionStats( SectionStats const& ) = default; + SectionStats( SectionStats && ) = default; + SectionStats& operator = ( SectionStats const& ) = default; + SectionStats& operator = ( SectionStats && ) = default; +# endif + + SectionInfo sectionInfo; + Counts assertions; + double durationInSeconds; + bool missingAssertions; + }; + + struct TestCaseStats { + TestCaseStats( TestCaseInfo const& _testInfo, + Totals const& _totals, + std::string const& _stdOut, + std::string const& _stdErr, + bool _aborting ) + : testInfo( _testInfo ), + totals( _totals ), + stdOut( _stdOut ), + stdErr( _stdErr ), + aborting( _aborting ) + {} + virtual ~TestCaseStats(); + +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + TestCaseStats( TestCaseStats const& ) = default; + TestCaseStats( TestCaseStats && ) = default; + TestCaseStats& operator = ( TestCaseStats const& ) = default; + TestCaseStats& operator = ( TestCaseStats && ) = default; +# endif + + TestCaseInfo testInfo; + Totals totals; + std::string stdOut; + std::string stdErr; + bool aborting; + }; + + struct TestGroupStats { + TestGroupStats( GroupInfo const& _groupInfo, + Totals const& _totals, + bool _aborting ) + : groupInfo( _groupInfo ), + totals( _totals ), + aborting( _aborting ) + {} + TestGroupStats( GroupInfo const& _groupInfo ) + : groupInfo( _groupInfo ), + aborting( false ) + {} + virtual ~TestGroupStats(); + +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + TestGroupStats( TestGroupStats const& ) = default; + TestGroupStats( TestGroupStats && ) = default; + TestGroupStats& operator = ( TestGroupStats const& ) = default; + TestGroupStats& operator = ( TestGroupStats && ) = default; +# endif + + GroupInfo groupInfo; + Totals totals; + bool aborting; + }; + + struct TestRunStats { + TestRunStats( TestRunInfo const& _runInfo, + Totals const& _totals, + bool _aborting ) + : runInfo( _runInfo ), + totals( _totals ), + aborting( _aborting ) + {} + virtual ~TestRunStats(); + +# ifndef CATCH_CONFIG_CPP11_GENERATED_METHODS + TestRunStats( TestRunStats const& _other ) + : runInfo( _other.runInfo ), + totals( _other.totals ), + aborting( _other.aborting ) + {} +# else + TestRunStats( TestRunStats const& ) = default; + TestRunStats( TestRunStats && ) = default; + TestRunStats& operator = ( TestRunStats const& ) = default; + TestRunStats& operator = ( TestRunStats && ) = default; +# endif + + TestRunInfo runInfo; + Totals totals; + bool aborting; + }; + + struct IStreamingReporter : IShared { + virtual ~IStreamingReporter(); + + // Implementing class must also provide the following static method: + // static std::string getDescription(); + + virtual ReporterPreferences getPreferences() const = 0; + + virtual void noMatchingTestCases( std::string const& spec ) = 0; + + virtual void testRunStarting( TestRunInfo const& testRunInfo ) = 0; + virtual void testGroupStarting( GroupInfo const& groupInfo ) = 0; + + virtual void testCaseStarting( TestCaseInfo const& testInfo ) = 0; + virtual void sectionStarting( SectionInfo const& sectionInfo ) = 0; + + virtual void assertionStarting( AssertionInfo const& assertionInfo ) = 0; + + // The return value indicates if the messages buffer should be cleared: + virtual bool assertionEnded( AssertionStats const& assertionStats ) = 0; + + virtual void sectionEnded( SectionStats const& sectionStats ) = 0; + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) = 0; + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) = 0; + virtual void testRunEnded( TestRunStats const& testRunStats ) = 0; + + virtual void skipTest( TestCaseInfo const& testInfo ) = 0; + }; + + struct IReporterFactory : IShared { + virtual ~IReporterFactory(); + virtual IStreamingReporter* create( ReporterConfig const& config ) const = 0; + virtual std::string getDescription() const = 0; + }; + + struct IReporterRegistry { + typedef std::map > FactoryMap; + typedef std::vector > Listeners; + + virtual ~IReporterRegistry(); + virtual IStreamingReporter* create( std::string const& name, Ptr const& config ) const = 0; + virtual FactoryMap const& getFactories() const = 0; + virtual Listeners const& getListeners() const = 0; + }; + + Ptr addReporter( Ptr const& existingReporter, Ptr const& additionalReporter ); + +} + +#include +#include + +namespace Catch { + + inline std::size_t listTests( Config const& config ) { + + TestSpec testSpec = config.testSpec(); + if( config.testSpec().hasFilters() ) + Catch::cout() << "Matching test cases:\n"; + else { + Catch::cout() << "All available test cases:\n"; + testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); + } + + std::size_t matchedTests = 0; + TextAttributes nameAttr, tagsAttr; + nameAttr.setInitialIndent( 2 ).setIndent( 4 ); + tagsAttr.setIndent( 6 ); + + std::vector matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); + for( std::vector::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); + it != itEnd; + ++it ) { + matchedTests++; + TestCaseInfo const& testCaseInfo = it->getTestCaseInfo(); + Colour::Code colour = testCaseInfo.isHidden() + ? Colour::SecondaryText + : Colour::None; + Colour colourGuard( colour ); + + Catch::cout() << Text( testCaseInfo.name, nameAttr ) << std::endl; + if( !testCaseInfo.tags.empty() ) + Catch::cout() << Text( testCaseInfo.tagsAsString, tagsAttr ) << std::endl; + } + + if( !config.testSpec().hasFilters() ) + Catch::cout() << pluralise( matchedTests, "test case" ) << "\n" << std::endl; + else + Catch::cout() << pluralise( matchedTests, "matching test case" ) << "\n" << std::endl; + return matchedTests; + } + + inline std::size_t listTestsNamesOnly( Config const& config ) { + TestSpec testSpec = config.testSpec(); + if( !config.testSpec().hasFilters() ) + testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); + std::size_t matchedTests = 0; + std::vector matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); + for( std::vector::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); + it != itEnd; + ++it ) { + matchedTests++; + TestCaseInfo const& testCaseInfo = it->getTestCaseInfo(); + Catch::cout() << testCaseInfo.name << std::endl; + } + return matchedTests; + } + + struct TagInfo { + TagInfo() : count ( 0 ) {} + void add( std::string const& spelling ) { + ++count; + spellings.insert( spelling ); + } + std::string all() const { + std::string out; + for( std::set::const_iterator it = spellings.begin(), itEnd = spellings.end(); + it != itEnd; + ++it ) + out += "[" + *it + "]"; + return out; + } + std::set spellings; + std::size_t count; + }; + + inline std::size_t listTags( Config const& config ) { + TestSpec testSpec = config.testSpec(); + if( config.testSpec().hasFilters() ) + Catch::cout() << "Tags for matching test cases:\n"; + else { + Catch::cout() << "All available tags:\n"; + testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); + } + + std::map tagCounts; + + std::vector matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); + for( std::vector::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); + it != itEnd; + ++it ) { + for( std::set::const_iterator tagIt = it->getTestCaseInfo().tags.begin(), + tagItEnd = it->getTestCaseInfo().tags.end(); + tagIt != tagItEnd; + ++tagIt ) { + std::string tagName = *tagIt; + std::string lcaseTagName = toLower( tagName ); + std::map::iterator countIt = tagCounts.find( lcaseTagName ); + if( countIt == tagCounts.end() ) + countIt = tagCounts.insert( std::make_pair( lcaseTagName, TagInfo() ) ).first; + countIt->second.add( tagName ); + } + } + + for( std::map::const_iterator countIt = tagCounts.begin(), + countItEnd = tagCounts.end(); + countIt != countItEnd; + ++countIt ) { + std::ostringstream oss; + oss << " " << std::setw(2) << countIt->second.count << " "; + Text wrapper( countIt->second.all(), TextAttributes() + .setInitialIndent( 0 ) + .setIndent( oss.str().size() ) + .setWidth( CATCH_CONFIG_CONSOLE_WIDTH-10 ) ); + Catch::cout() << oss.str() << wrapper << "\n"; + } + Catch::cout() << pluralise( tagCounts.size(), "tag" ) << "\n" << std::endl; + return tagCounts.size(); + } + + inline std::size_t listReporters( Config const& /*config*/ ) { + Catch::cout() << "Available reporters:\n"; + IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories(); + IReporterRegistry::FactoryMap::const_iterator itBegin = factories.begin(), itEnd = factories.end(), it; + std::size_t maxNameLen = 0; + for(it = itBegin; it != itEnd; ++it ) + maxNameLen = (std::max)( maxNameLen, it->first.size() ); + + for(it = itBegin; it != itEnd; ++it ) { + Text wrapper( it->second->getDescription(), TextAttributes() + .setInitialIndent( 0 ) + .setIndent( 7+maxNameLen ) + .setWidth( CATCH_CONFIG_CONSOLE_WIDTH - maxNameLen-8 ) ); + Catch::cout() << " " + << it->first + << ":" + << std::string( maxNameLen - it->first.size() + 2, ' ' ) + << wrapper << "\n"; + } + Catch::cout() << std::endl; + return factories.size(); + } + + inline Option list( Config const& config ) { + Option listedCount; + if( config.listTests() ) + listedCount = listedCount.valueOr(0) + listTests( config ); + if( config.listTestNamesOnly() ) + listedCount = listedCount.valueOr(0) + listTestsNamesOnly( config ); + if( config.listTags() ) + listedCount = listedCount.valueOr(0) + listTags( config ); + if( config.listReporters() ) + listedCount = listedCount.valueOr(0) + listReporters( config ); + return listedCount; + } + +} // end namespace Catch + +// #included from: internal/catch_run_context.hpp +#define TWOBLUECUBES_CATCH_RUNNER_IMPL_HPP_INCLUDED + +// #included from: catch_test_case_tracker.hpp +#define TWOBLUECUBES_CATCH_TEST_CASE_TRACKER_HPP_INCLUDED + +#include +#include +#include +#include + +namespace Catch { +namespace TestCaseTracking { + + struct ITracker : SharedImpl<> { + virtual ~ITracker(); + + // static queries + virtual std::string name() const = 0; + + // dynamic queries + virtual bool isComplete() const = 0; // Successfully completed or failed + virtual bool isSuccessfullyCompleted() const = 0; + virtual bool isOpen() const = 0; // Started but not complete + virtual bool hasChildren() const = 0; + + virtual ITracker& parent() = 0; + + // actions + virtual void close() = 0; // Successfully complete + virtual void fail() = 0; + virtual void markAsNeedingAnotherRun() = 0; + + virtual void addChild( Ptr const& child ) = 0; + virtual ITracker* findChild( std::string const& name ) = 0; + virtual void openChild() = 0; + }; + + class TrackerContext { + + enum RunState { + NotStarted, + Executing, + CompletedCycle + }; + + Ptr m_rootTracker; + ITracker* m_currentTracker; + RunState m_runState; + + public: + + static TrackerContext& instance() { + static TrackerContext s_instance; + return s_instance; + } + + TrackerContext() + : m_currentTracker( CATCH_NULL ), + m_runState( NotStarted ) + {} + + ITracker& startRun(); + + void endRun() { + m_rootTracker.reset(); + m_currentTracker = CATCH_NULL; + m_runState = NotStarted; + } + + void startCycle() { + m_currentTracker = m_rootTracker.get(); + m_runState = Executing; + } + void completeCycle() { + m_runState = CompletedCycle; + } + + bool completedCycle() const { + return m_runState == CompletedCycle; + } + ITracker& currentTracker() { + return *m_currentTracker; + } + void setCurrentTracker( ITracker* tracker ) { + m_currentTracker = tracker; + } + }; + + class TrackerBase : public ITracker { + protected: + enum CycleState { + NotStarted, + Executing, + ExecutingChildren, + NeedsAnotherRun, + CompletedSuccessfully, + Failed + }; + class TrackerHasName { + std::string m_name; + public: + TrackerHasName( std::string const& name ) : m_name( name ) {} + bool operator ()( Ptr const& tracker ) { + return tracker->name() == m_name; + } + }; + typedef std::vector > Children; + std::string m_name; + TrackerContext& m_ctx; + ITracker* m_parent; + Children m_children; + CycleState m_runState; + public: + TrackerBase( std::string const& name, TrackerContext& ctx, ITracker* parent ) + : m_name( name ), + m_ctx( ctx ), + m_parent( parent ), + m_runState( NotStarted ) + {} + virtual ~TrackerBase(); + + virtual std::string name() const CATCH_OVERRIDE { + return m_name; + } + virtual bool isComplete() const CATCH_OVERRIDE { + return m_runState == CompletedSuccessfully || m_runState == Failed; + } + virtual bool isSuccessfullyCompleted() const CATCH_OVERRIDE { + return m_runState == CompletedSuccessfully; + } + virtual bool isOpen() const CATCH_OVERRIDE { + return m_runState != NotStarted && !isComplete(); + } + virtual bool hasChildren() const CATCH_OVERRIDE { + return !m_children.empty(); + } + + virtual void addChild( Ptr const& child ) CATCH_OVERRIDE { + m_children.push_back( child ); + } + + virtual ITracker* findChild( std::string const& name ) CATCH_OVERRIDE { + Children::const_iterator it = std::find_if( m_children.begin(), m_children.end(), TrackerHasName( name ) ); + return( it != m_children.end() ) + ? it->get() + : CATCH_NULL; + } + virtual ITracker& parent() CATCH_OVERRIDE { + assert( m_parent ); // Should always be non-null except for root + return *m_parent; + } + + virtual void openChild() CATCH_OVERRIDE { + if( m_runState != ExecutingChildren ) { + m_runState = ExecutingChildren; + if( m_parent ) + m_parent->openChild(); + } + } + void open() { + m_runState = Executing; + moveToThis(); + if( m_parent ) + m_parent->openChild(); + } + + virtual void close() CATCH_OVERRIDE { + + // Close any still open children (e.g. generators) + while( &m_ctx.currentTracker() != this ) + m_ctx.currentTracker().close(); + + switch( m_runState ) { + case NotStarted: + case CompletedSuccessfully: + case Failed: + throw std::logic_error( "Illogical state" ); + + case NeedsAnotherRun: + break;; + + case Executing: + m_runState = CompletedSuccessfully; + break; + case ExecutingChildren: + if( m_children.empty() || m_children.back()->isComplete() ) + m_runState = CompletedSuccessfully; + break; + + default: + throw std::logic_error( "Unexpected state" ); + } + moveToParent(); + m_ctx.completeCycle(); + } + virtual void fail() CATCH_OVERRIDE { + m_runState = Failed; + if( m_parent ) + m_parent->markAsNeedingAnotherRun(); + moveToParent(); + m_ctx.completeCycle(); + } + virtual void markAsNeedingAnotherRun() CATCH_OVERRIDE { + m_runState = NeedsAnotherRun; + } + private: + void moveToParent() { + assert( m_parent ); + m_ctx.setCurrentTracker( m_parent ); + } + void moveToThis() { + m_ctx.setCurrentTracker( this ); + } + }; + + class SectionTracker : public TrackerBase { + public: + SectionTracker( std::string const& name, TrackerContext& ctx, ITracker* parent ) + : TrackerBase( name, ctx, parent ) + {} + virtual ~SectionTracker(); + + static SectionTracker& acquire( TrackerContext& ctx, std::string const& name ) { + SectionTracker* section = CATCH_NULL; + + ITracker& currentTracker = ctx.currentTracker(); + if( ITracker* childTracker = currentTracker.findChild( name ) ) { + section = dynamic_cast( childTracker ); + assert( section ); + } + else { + section = new SectionTracker( name, ctx, ¤tTracker ); + currentTracker.addChild( section ); + } + if( !ctx.completedCycle() && !section->isComplete() ) { + + section->open(); + } + return *section; + } + }; + + class IndexTracker : public TrackerBase { + int m_size; + int m_index; + public: + IndexTracker( std::string const& name, TrackerContext& ctx, ITracker* parent, int size ) + : TrackerBase( name, ctx, parent ), + m_size( size ), + m_index( -1 ) + {} + virtual ~IndexTracker(); + + static IndexTracker& acquire( TrackerContext& ctx, std::string const& name, int size ) { + IndexTracker* tracker = CATCH_NULL; + + ITracker& currentTracker = ctx.currentTracker(); + if( ITracker* childTracker = currentTracker.findChild( name ) ) { + tracker = dynamic_cast( childTracker ); + assert( tracker ); + } + else { + tracker = new IndexTracker( name, ctx, ¤tTracker, size ); + currentTracker.addChild( tracker ); + } + + if( !ctx.completedCycle() && !tracker->isComplete() ) { + if( tracker->m_runState != ExecutingChildren && tracker->m_runState != NeedsAnotherRun ) + tracker->moveNext(); + tracker->open(); + } + + return *tracker; + } + + int index() const { return m_index; } + + void moveNext() { + m_index++; + m_children.clear(); + } + + virtual void close() CATCH_OVERRIDE { + TrackerBase::close(); + if( m_runState == CompletedSuccessfully && m_index < m_size-1 ) + m_runState = Executing; + } + }; + + inline ITracker& TrackerContext::startRun() { + m_rootTracker = new SectionTracker( "{root}", *this, CATCH_NULL ); + m_currentTracker = CATCH_NULL; + m_runState = Executing; + return *m_rootTracker; + } + +} // namespace TestCaseTracking + +using TestCaseTracking::ITracker; +using TestCaseTracking::TrackerContext; +using TestCaseTracking::SectionTracker; +using TestCaseTracking::IndexTracker; + +} // namespace Catch + +// #included from: catch_fatal_condition.hpp +#define TWOBLUECUBES_CATCH_FATAL_CONDITION_H_INCLUDED + +namespace Catch { + + // Report the error condition then exit the process + inline void fatal( std::string const& message, int exitCode ) { + IContext& context = Catch::getCurrentContext(); + IResultCapture* resultCapture = context.getResultCapture(); + resultCapture->handleFatalErrorCondition( message ); + + if( Catch::alwaysTrue() ) // avoids "no return" warnings + exit( exitCode ); + } + +} // namespace Catch + +#if defined ( CATCH_PLATFORM_WINDOWS ) ///////////////////////////////////////// + +namespace Catch { + + struct FatalConditionHandler { + void reset() {} + }; + +} // namespace Catch + +#else // Not Windows - assumed to be POSIX compatible ////////////////////////// + +#include + +namespace Catch { + + struct SignalDefs { int id; const char* name; }; + extern SignalDefs signalDefs[]; + SignalDefs signalDefs[] = { + { SIGINT, "SIGINT - Terminal interrupt signal" }, + { SIGILL, "SIGILL - Illegal instruction signal" }, + { SIGFPE, "SIGFPE - Floating point error signal" }, + { SIGSEGV, "SIGSEGV - Segmentation violation signal" }, + { SIGTERM, "SIGTERM - Termination request signal" }, + { SIGABRT, "SIGABRT - Abort (abnormal termination) signal" } + }; + + struct FatalConditionHandler { + + static void handleSignal( int sig ) { + for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) + if( sig == signalDefs[i].id ) + fatal( signalDefs[i].name, -sig ); + fatal( "", -sig ); + } + + FatalConditionHandler() : m_isSet( true ) { + for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) + signal( signalDefs[i].id, handleSignal ); + } + ~FatalConditionHandler() { + reset(); + } + void reset() { + if( m_isSet ) { + for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) + signal( signalDefs[i].id, SIG_DFL ); + m_isSet = false; + } + } + + bool m_isSet; + }; + +} // namespace Catch + +#endif // not Windows + +#include +#include + +namespace Catch { + + class StreamRedirect { + + public: + StreamRedirect( std::ostream& stream, std::string& targetString ) + : m_stream( stream ), + m_prevBuf( stream.rdbuf() ), + m_targetString( targetString ) + { + stream.rdbuf( m_oss.rdbuf() ); + } + + ~StreamRedirect() { + m_targetString += m_oss.str(); + m_stream.rdbuf( m_prevBuf ); + } + + private: + std::ostream& m_stream; + std::streambuf* m_prevBuf; + std::ostringstream m_oss; + std::string& m_targetString; + }; + + /////////////////////////////////////////////////////////////////////////// + + class RunContext : public IResultCapture, public IRunner { + + RunContext( RunContext const& ); + void operator =( RunContext const& ); + + public: + + explicit RunContext( Ptr const& _config, Ptr const& reporter ) + : m_runInfo( _config->name() ), + m_context( getCurrentMutableContext() ), + m_activeTestCase( CATCH_NULL ), + m_config( _config ), + m_reporter( reporter ) + { + m_context.setRunner( this ); + m_context.setConfig( m_config ); + m_context.setResultCapture( this ); + m_reporter->testRunStarting( m_runInfo ); + } + + virtual ~RunContext() { + m_reporter->testRunEnded( TestRunStats( m_runInfo, m_totals, aborting() ) ); + } + + void testGroupStarting( std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount ) { + m_reporter->testGroupStarting( GroupInfo( testSpec, groupIndex, groupsCount ) ); + } + void testGroupEnded( std::string const& testSpec, Totals const& totals, std::size_t groupIndex, std::size_t groupsCount ) { + m_reporter->testGroupEnded( TestGroupStats( GroupInfo( testSpec, groupIndex, groupsCount ), totals, aborting() ) ); + } + + Totals runTest( TestCase const& testCase ) { + Totals prevTotals = m_totals; + + std::string redirectedCout; + std::string redirectedCerr; + + TestCaseInfo testInfo = testCase.getTestCaseInfo(); + + m_reporter->testCaseStarting( testInfo ); + + m_activeTestCase = &testCase; + + do { + m_trackerContext.startRun(); + do { + m_trackerContext.startCycle(); + m_testCaseTracker = &SectionTracker::acquire( m_trackerContext, testInfo.name ); + runCurrentTest( redirectedCout, redirectedCerr ); + } + while( !m_testCaseTracker->isSuccessfullyCompleted() && !aborting() ); + } + // !TBD: deprecated - this will be replaced by indexed trackers + while( getCurrentContext().advanceGeneratorsForCurrentTest() && !aborting() ); + + Totals deltaTotals = m_totals.delta( prevTotals ); + m_totals.testCases += deltaTotals.testCases; + m_reporter->testCaseEnded( TestCaseStats( testInfo, + deltaTotals, + redirectedCout, + redirectedCerr, + aborting() ) ); + + m_activeTestCase = CATCH_NULL; + m_testCaseTracker = CATCH_NULL; + + return deltaTotals; + } + + Ptr config() const { + return m_config; + } + + private: // IResultCapture + + virtual void assertionEnded( AssertionResult const& result ) { + if( result.getResultType() == ResultWas::Ok ) { + m_totals.assertions.passed++; + } + else if( !result.isOk() ) { + m_totals.assertions.failed++; + } + + if( m_reporter->assertionEnded( AssertionStats( result, m_messages, m_totals ) ) ) + m_messages.clear(); + + // Reset working state + m_lastAssertionInfo = AssertionInfo( "", m_lastAssertionInfo.lineInfo, "{Unknown expression after the reported line}" , m_lastAssertionInfo.resultDisposition ); + m_lastResult = result; + } + + virtual bool sectionStarted ( + SectionInfo const& sectionInfo, + Counts& assertions + ) + { + std::ostringstream oss; + oss << sectionInfo.name << "@" << sectionInfo.lineInfo; + + ITracker& sectionTracker = SectionTracker::acquire( m_trackerContext, oss.str() ); + if( !sectionTracker.isOpen() ) + return false; + m_activeSections.push_back( §ionTracker ); + + m_lastAssertionInfo.lineInfo = sectionInfo.lineInfo; + + m_reporter->sectionStarting( sectionInfo ); + + assertions = m_totals.assertions; + + return true; + } + bool testForMissingAssertions( Counts& assertions ) { + if( assertions.total() != 0 ) + return false; + if( !m_config->warnAboutMissingAssertions() ) + return false; + if( m_trackerContext.currentTracker().hasChildren() ) + return false; + m_totals.assertions.failed++; + assertions.failed++; + return true; + } + + virtual void sectionEnded( SectionEndInfo const& endInfo ) { + Counts assertions = m_totals.assertions - endInfo.prevAssertions; + bool missingAssertions = testForMissingAssertions( assertions ); + + if( !m_activeSections.empty() ) { + m_activeSections.back()->close(); + m_activeSections.pop_back(); + } + + m_reporter->sectionEnded( SectionStats( endInfo.sectionInfo, assertions, endInfo.durationInSeconds, missingAssertions ) ); + m_messages.clear(); + } + + virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) { + if( m_unfinishedSections.empty() ) + m_activeSections.back()->fail(); + else + m_activeSections.back()->close(); + m_activeSections.pop_back(); + + m_unfinishedSections.push_back( endInfo ); + } + + virtual void pushScopedMessage( MessageInfo const& message ) { + m_messages.push_back( message ); + } + + virtual void popScopedMessage( MessageInfo const& message ) { + m_messages.erase( std::remove( m_messages.begin(), m_messages.end(), message ), m_messages.end() ); + } + + virtual std::string getCurrentTestName() const { + return m_activeTestCase + ? m_activeTestCase->getTestCaseInfo().name + : ""; + } + + virtual const AssertionResult* getLastResult() const { + return &m_lastResult; + } + + virtual void handleFatalErrorCondition( std::string const& message ) { + ResultBuilder resultBuilder = makeUnexpectedResultBuilder(); + resultBuilder.setResultType( ResultWas::FatalErrorCondition ); + resultBuilder << message; + resultBuilder.captureExpression(); + + handleUnfinishedSections(); + + // Recreate section for test case (as we will lose the one that was in scope) + TestCaseInfo const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); + SectionInfo testCaseSection( testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description ); + + Counts assertions; + assertions.failed = 1; + SectionStats testCaseSectionStats( testCaseSection, assertions, 0, false ); + m_reporter->sectionEnded( testCaseSectionStats ); + + TestCaseInfo testInfo = m_activeTestCase->getTestCaseInfo(); + + Totals deltaTotals; + deltaTotals.testCases.failed = 1; + m_reporter->testCaseEnded( TestCaseStats( testInfo, + deltaTotals, + "", + "", + false ) ); + m_totals.testCases.failed++; + testGroupEnded( "", m_totals, 1, 1 ); + m_reporter->testRunEnded( TestRunStats( m_runInfo, m_totals, false ) ); + } + + public: + // !TBD We need to do this another way! + bool aborting() const { + return m_totals.assertions.failed == static_cast( m_config->abortAfter() ); + } + + private: + + void runCurrentTest( std::string& redirectedCout, std::string& redirectedCerr ) { + TestCaseInfo const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); + SectionInfo testCaseSection( testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description ); + m_reporter->sectionStarting( testCaseSection ); + Counts prevAssertions = m_totals.assertions; + double duration = 0; + try { + m_lastAssertionInfo = AssertionInfo( "TEST_CASE", testCaseInfo.lineInfo, "", ResultDisposition::Normal ); + + seedRng( *m_config ); + + Timer timer; + timer.start(); + if( m_reporter->getPreferences().shouldRedirectStdOut ) { + StreamRedirect coutRedir( Catch::cout(), redirectedCout ); + StreamRedirect cerrRedir( Catch::cerr(), redirectedCerr ); + invokeActiveTestCase(); + } + else { + invokeActiveTestCase(); + } + duration = timer.getElapsedSeconds(); + } + catch( TestFailureException& ) { + // This just means the test was aborted due to failure + } + catch(...) { + makeUnexpectedResultBuilder().useActiveException(); + } + m_testCaseTracker->close(); + handleUnfinishedSections(); + m_messages.clear(); + + Counts assertions = m_totals.assertions - prevAssertions; + bool missingAssertions = testForMissingAssertions( assertions ); + + if( testCaseInfo.okToFail() ) { + std::swap( assertions.failedButOk, assertions.failed ); + m_totals.assertions.failed -= assertions.failedButOk; + m_totals.assertions.failedButOk += assertions.failedButOk; + } + + SectionStats testCaseSectionStats( testCaseSection, assertions, duration, missingAssertions ); + m_reporter->sectionEnded( testCaseSectionStats ); + } + + void invokeActiveTestCase() { + FatalConditionHandler fatalConditionHandler; // Handle signals + m_activeTestCase->invoke(); + fatalConditionHandler.reset(); + } + + private: + + ResultBuilder makeUnexpectedResultBuilder() const { + return ResultBuilder( m_lastAssertionInfo.macroName.c_str(), + m_lastAssertionInfo.lineInfo, + m_lastAssertionInfo.capturedExpression.c_str(), + m_lastAssertionInfo.resultDisposition ); + } + + void handleUnfinishedSections() { + // If sections ended prematurely due to an exception we stored their + // infos here so we can tear them down outside the unwind process. + for( std::vector::const_reverse_iterator it = m_unfinishedSections.rbegin(), + itEnd = m_unfinishedSections.rend(); + it != itEnd; + ++it ) + sectionEnded( *it ); + m_unfinishedSections.clear(); + } + + TestRunInfo m_runInfo; + IMutableContext& m_context; + TestCase const* m_activeTestCase; + ITracker* m_testCaseTracker; + ITracker* m_currentSectionTracker; + AssertionResult m_lastResult; + + Ptr m_config; + Totals m_totals; + Ptr m_reporter; + std::vector m_messages; + AssertionInfo m_lastAssertionInfo; + std::vector m_unfinishedSections; + std::vector m_activeSections; + TrackerContext m_trackerContext; + }; + + IResultCapture& getResultCapture() { + if( IResultCapture* capture = getCurrentContext().getResultCapture() ) + return *capture; + else + throw std::logic_error( "No result capture instance" ); + } + +} // end namespace Catch + +// #included from: internal/catch_version.h +#define TWOBLUECUBES_CATCH_VERSION_H_INCLUDED + +namespace Catch { + + // Versioning information + struct Version { + Version( unsigned int _majorVersion, + unsigned int _minorVersion, + unsigned int _patchNumber, + std::string const& _branchName, + unsigned int _buildNumber ); + + unsigned int const majorVersion; + unsigned int const minorVersion; + unsigned int const patchNumber; + + // buildNumber is only used if branchName is not null + std::string const branchName; + unsigned int const buildNumber; + + friend std::ostream& operator << ( std::ostream& os, Version const& version ); + + private: + void operator=( Version const& ); + }; + + extern Version libraryVersion; +} + +#include +#include +#include + +namespace Catch { + + Ptr createReporter( std::string const& reporterName, Ptr const& config ) { + Ptr reporter = getRegistryHub().getReporterRegistry().create( reporterName, config.get() ); + if( !reporter ) { + std::ostringstream oss; + oss << "No reporter registered with name: '" << reporterName << "'"; + throw std::domain_error( oss.str() ); + } + return reporter; + } + + Ptr makeReporter( Ptr const& config ) { + std::vector reporters = config->getReporterNames(); + if( reporters.empty() ) + reporters.push_back( "console" ); + + Ptr reporter; + for( std::vector::const_iterator it = reporters.begin(), itEnd = reporters.end(); + it != itEnd; + ++it ) + reporter = addReporter( reporter, createReporter( *it, config ) ); + return reporter; + } + Ptr addListeners( Ptr const& config, Ptr reporters ) { + IReporterRegistry::Listeners listeners = getRegistryHub().getReporterRegistry().getListeners(); + for( IReporterRegistry::Listeners::const_iterator it = listeners.begin(), itEnd = listeners.end(); + it != itEnd; + ++it ) + reporters = addReporter(reporters, (*it)->create( ReporterConfig( config ) ) ); + return reporters; + } + + Totals runTests( Ptr const& config ) { + + Ptr iconfig = config.get(); + + Ptr reporter = makeReporter( config ); + reporter = addListeners( iconfig, reporter ); + + RunContext context( iconfig, reporter ); + + Totals totals; + + context.testGroupStarting( config->name(), 1, 1 ); + + TestSpec testSpec = config->testSpec(); + if( !testSpec.hasFilters() ) + testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "~[.]" ).testSpec(); // All not hidden tests + + std::vector const& allTestCases = getAllTestCasesSorted( *iconfig ); + for( std::vector::const_iterator it = allTestCases.begin(), itEnd = allTestCases.end(); + it != itEnd; + ++it ) { + if( !context.aborting() && matchTest( *it, testSpec, *iconfig ) ) + totals += context.runTest( *it ); + else + reporter->skipTest( *it ); + } + + context.testGroupEnded( iconfig->name(), totals, 1, 1 ); + return totals; + } + + void applyFilenamesAsTags( IConfig const& config ) { + std::vector const& tests = getAllTestCasesSorted( config ); + for(std::size_t i = 0; i < tests.size(); ++i ) { + TestCase& test = const_cast( tests[i] ); + std::set tags = test.tags; + + std::string filename = test.lineInfo.file; + std::string::size_type lastSlash = filename.find_last_of( "\\/" ); + if( lastSlash != std::string::npos ) + filename = filename.substr( lastSlash+1 ); + + std::string::size_type lastDot = filename.find_last_of( "." ); + if( lastDot != std::string::npos ) + filename = filename.substr( 0, lastDot ); + + tags.insert( "#" + filename ); + setTags( test, tags ); + } + } + + class Session : NonCopyable { + static bool alreadyInstantiated; + + public: + + struct OnUnusedOptions { enum DoWhat { Ignore, Fail }; }; + + Session() + : m_cli( makeCommandLineParser() ) { + if( alreadyInstantiated ) { + std::string msg = "Only one instance of Catch::Session can ever be used"; + Catch::cerr() << msg << std::endl; + throw std::logic_error( msg ); + } + alreadyInstantiated = true; + } + ~Session() { + Catch::cleanUp(); + } + + void showHelp( std::string const& processName ) { + Catch::cout() << "\nCatch v" << libraryVersion << "\n"; + + m_cli.usage( Catch::cout(), processName ); + Catch::cout() << "For more detail usage please see the project docs\n" << std::endl; + } + + int applyCommandLine( int argc, char const* argv[], OnUnusedOptions::DoWhat unusedOptionBehaviour = OnUnusedOptions::Fail ) { + try { + m_cli.setThrowOnUnrecognisedTokens( unusedOptionBehaviour == OnUnusedOptions::Fail ); + m_unusedTokens = m_cli.parseInto( argc, argv, m_configData ); + if( m_configData.showHelp ) + showHelp( m_configData.processName ); + m_config.reset(); + } + catch( std::exception& ex ) { + { + Colour colourGuard( Colour::Red ); + Catch::cerr() + << "\nError(s) in input:\n" + << Text( ex.what(), TextAttributes().setIndent(2) ) + << "\n\n"; + } + m_cli.usage( Catch::cout(), m_configData.processName ); + return (std::numeric_limits::max)(); + } + return 0; + } + + void useConfigData( ConfigData const& _configData ) { + m_configData = _configData; + m_config.reset(); + } + + int run( int argc, char const* argv[] ) { + + int returnCode = applyCommandLine( argc, argv ); + if( returnCode == 0 ) + returnCode = run(); + return returnCode; + } + int run( int argc, char* argv[] ) { + return run( argc, const_cast( argv ) ); + } + + int run() { + if( m_configData.showHelp ) + return 0; + + try + { + config(); // Force config to be constructed + + seedRng( *m_config ); + + if( m_configData.filenamesAsTags ) + applyFilenamesAsTags( *m_config ); + + // Handle list request + if( Option listed = list( config() ) ) + return static_cast( *listed ); + + return static_cast( runTests( m_config ).assertions.failed ); + } + catch( std::exception& ex ) { + Catch::cerr() << ex.what() << std::endl; + return (std::numeric_limits::max)(); + } + } + + Clara::CommandLine const& cli() const { + return m_cli; + } + std::vector const& unusedTokens() const { + return m_unusedTokens; + } + ConfigData& configData() { + return m_configData; + } + Config& config() { + if( !m_config ) + m_config = new Config( m_configData ); + return *m_config; + } + private: + Clara::CommandLine m_cli; + std::vector m_unusedTokens; + ConfigData m_configData; + Ptr m_config; + }; + + bool Session::alreadyInstantiated = false; + +} // end namespace Catch + +// #included from: catch_registry_hub.hpp +#define TWOBLUECUBES_CATCH_REGISTRY_HUB_HPP_INCLUDED + +// #included from: catch_test_case_registry_impl.hpp +#define TWOBLUECUBES_CATCH_TEST_CASE_REGISTRY_IMPL_HPP_INCLUDED + +#include +#include +#include +#include +#include + +namespace Catch { + + struct LexSort { + bool operator() (TestCase i,TestCase j) const { return (i sortTests( IConfig const& config, std::vector const& unsortedTestCases ) { + + std::vector sorted = unsortedTestCases; + + switch( config.runOrder() ) { + case RunTests::InLexicographicalOrder: + std::sort( sorted.begin(), sorted.end(), LexSort() ); + break; + case RunTests::InRandomOrder: + { + seedRng( config ); + + RandomNumberGenerator rng; + std::random_shuffle( sorted.begin(), sorted.end(), rng ); + } + break; + case RunTests::InDeclarationOrder: + // already in declaration order + break; + } + return sorted; + } + bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ) { + return testSpec.matches( testCase ) && ( config.allowThrows() || !testCase.throws() ); + } + + void enforceNoDuplicateTestCases( std::vector const& functions ) { + std::set seenFunctions; + for( std::vector::const_iterator it = functions.begin(), itEnd = functions.end(); + it != itEnd; + ++it ) { + std::pair::const_iterator, bool> prev = seenFunctions.insert( *it ); + if( !prev.second ){ + Catch::cerr() + << Colour( Colour::Red ) + << "error: TEST_CASE( \"" << it->name << "\" ) already defined.\n" + << "\tFirst seen at " << prev.first->getTestCaseInfo().lineInfo << "\n" + << "\tRedefined at " << it->getTestCaseInfo().lineInfo << std::endl; + exit(1); + } + } + } + + std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ) { + std::vector filtered; + filtered.reserve( testCases.size() ); + for( std::vector::const_iterator it = testCases.begin(), itEnd = testCases.end(); + it != itEnd; + ++it ) + if( matchTest( *it, testSpec, config ) ) + filtered.push_back( *it ); + return filtered; + } + std::vector const& getAllTestCasesSorted( IConfig const& config ) { + return getRegistryHub().getTestCaseRegistry().getAllTestsSorted( config ); + } + + class TestRegistry : public ITestCaseRegistry { + public: + TestRegistry() + : m_currentSortOrder( RunTests::InDeclarationOrder ), + m_unnamedCount( 0 ) + {} + virtual ~TestRegistry(); + + virtual void registerTest( TestCase const& testCase ) { + std::string name = testCase.getTestCaseInfo().name; + if( name == "" ) { + std::ostringstream oss; + oss << "Anonymous test case " << ++m_unnamedCount; + return registerTest( testCase.withName( oss.str() ) ); + } + m_functions.push_back( testCase ); + } + + virtual std::vector const& getAllTests() const { + return m_functions; + } + virtual std::vector const& getAllTestsSorted( IConfig const& config ) const { + if( m_sortedFunctions.empty() ) + enforceNoDuplicateTestCases( m_functions ); + + if( m_currentSortOrder != config.runOrder() || m_sortedFunctions.empty() ) { + m_sortedFunctions = sortTests( config, m_functions ); + m_currentSortOrder = config.runOrder(); + } + return m_sortedFunctions; + } + + private: + std::vector m_functions; + mutable RunTests::InWhatOrder m_currentSortOrder; + mutable std::vector m_sortedFunctions; + size_t m_unnamedCount; + std::ios_base::Init m_ostreamInit; // Forces cout/ cerr to be initialised + }; + + /////////////////////////////////////////////////////////////////////////// + + class FreeFunctionTestCase : public SharedImpl { + public: + + FreeFunctionTestCase( TestFunction fun ) : m_fun( fun ) {} + + virtual void invoke() const { + m_fun(); + } + + private: + virtual ~FreeFunctionTestCase(); + + TestFunction m_fun; + }; + + inline std::string extractClassName( std::string const& classOrQualifiedMethodName ) { + std::string className = classOrQualifiedMethodName; + if( startsWith( className, "&" ) ) + { + std::size_t lastColons = className.rfind( "::" ); + std::size_t penultimateColons = className.rfind( "::", lastColons-1 ); + if( penultimateColons == std::string::npos ) + penultimateColons = 1; + className = className.substr( penultimateColons, lastColons-penultimateColons ); + } + return className; + } + + void registerTestCase + ( ITestCase* testCase, + char const* classOrQualifiedMethodName, + NameAndDesc const& nameAndDesc, + SourceLineInfo const& lineInfo ) { + + getMutableRegistryHub().registerTest + ( makeTestCase + ( testCase, + extractClassName( classOrQualifiedMethodName ), + nameAndDesc.name, + nameAndDesc.description, + lineInfo ) ); + } + void registerTestCaseFunction + ( TestFunction function, + SourceLineInfo const& lineInfo, + NameAndDesc const& nameAndDesc ) { + registerTestCase( new FreeFunctionTestCase( function ), "", nameAndDesc, lineInfo ); + } + + /////////////////////////////////////////////////////////////////////////// + + AutoReg::AutoReg + ( TestFunction function, + SourceLineInfo const& lineInfo, + NameAndDesc const& nameAndDesc ) { + registerTestCaseFunction( function, lineInfo, nameAndDesc ); + } + + AutoReg::~AutoReg() {} + +} // end namespace Catch + +// #included from: catch_reporter_registry.hpp +#define TWOBLUECUBES_CATCH_REPORTER_REGISTRY_HPP_INCLUDED + +#include + +namespace Catch { + + class ReporterRegistry : public IReporterRegistry { + + public: + + virtual ~ReporterRegistry() CATCH_OVERRIDE {} + + virtual IStreamingReporter* create( std::string const& name, Ptr const& config ) const CATCH_OVERRIDE { + FactoryMap::const_iterator it = m_factories.find( name ); + if( it == m_factories.end() ) + return CATCH_NULL; + return it->second->create( ReporterConfig( config ) ); + } + + void registerReporter( std::string const& name, Ptr const& factory ) { + m_factories.insert( std::make_pair( name, factory ) ); + } + void registerListener( Ptr const& factory ) { + m_listeners.push_back( factory ); + } + + virtual FactoryMap const& getFactories() const CATCH_OVERRIDE { + return m_factories; + } + virtual Listeners const& getListeners() const CATCH_OVERRIDE { + return m_listeners; + } + + private: + FactoryMap m_factories; + Listeners m_listeners; + }; +} + +// #included from: catch_exception_translator_registry.hpp +#define TWOBLUECUBES_CATCH_EXCEPTION_TRANSLATOR_REGISTRY_HPP_INCLUDED + +#ifdef __OBJC__ +#import "Foundation/Foundation.h" +#endif + +namespace Catch { + + class ExceptionTranslatorRegistry : public IExceptionTranslatorRegistry { + public: + ~ExceptionTranslatorRegistry() { + deleteAll( m_translators ); + } + + virtual void registerTranslator( const IExceptionTranslator* translator ) { + m_translators.push_back( translator ); + } + + virtual std::string translateActiveException() const { + try { +#ifdef __OBJC__ + // In Objective-C try objective-c exceptions first + @try { + return tryTranslators(); + } + @catch (NSException *exception) { + return Catch::toString( [exception description] ); + } +#else + return tryTranslators(); +#endif + } + catch( TestFailureException& ) { + throw; + } + catch( std::exception& ex ) { + return ex.what(); + } + catch( std::string& msg ) { + return msg; + } + catch( const char* msg ) { + return msg; + } + catch(...) { + return "Unknown exception"; + } + } + + std::string tryTranslators() const { + if( m_translators.empty() ) + throw; + else + return m_translators[0]->translate( m_translators.begin()+1, m_translators.end() ); + } + + private: + std::vector m_translators; + }; +} + +namespace Catch { + + namespace { + + class RegistryHub : public IRegistryHub, public IMutableRegistryHub { + + RegistryHub( RegistryHub const& ); + void operator=( RegistryHub const& ); + + public: // IRegistryHub + RegistryHub() { + } + virtual IReporterRegistry const& getReporterRegistry() const CATCH_OVERRIDE { + return m_reporterRegistry; + } + virtual ITestCaseRegistry const& getTestCaseRegistry() const CATCH_OVERRIDE { + return m_testCaseRegistry; + } + virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() CATCH_OVERRIDE { + return m_exceptionTranslatorRegistry; + } + + public: // IMutableRegistryHub + virtual void registerReporter( std::string const& name, Ptr const& factory ) CATCH_OVERRIDE { + m_reporterRegistry.registerReporter( name, factory ); + } + virtual void registerListener( Ptr const& factory ) CATCH_OVERRIDE { + m_reporterRegistry.registerListener( factory ); + } + virtual void registerTest( TestCase const& testInfo ) CATCH_OVERRIDE { + m_testCaseRegistry.registerTest( testInfo ); + } + virtual void registerTranslator( const IExceptionTranslator* translator ) CATCH_OVERRIDE { + m_exceptionTranslatorRegistry.registerTranslator( translator ); + } + + private: + TestRegistry m_testCaseRegistry; + ReporterRegistry m_reporterRegistry; + ExceptionTranslatorRegistry m_exceptionTranslatorRegistry; + }; + + // Single, global, instance + inline RegistryHub*& getTheRegistryHub() { + static RegistryHub* theRegistryHub = CATCH_NULL; + if( !theRegistryHub ) + theRegistryHub = new RegistryHub(); + return theRegistryHub; + } + } + + IRegistryHub& getRegistryHub() { + return *getTheRegistryHub(); + } + IMutableRegistryHub& getMutableRegistryHub() { + return *getTheRegistryHub(); + } + void cleanUp() { + delete getTheRegistryHub(); + getTheRegistryHub() = CATCH_NULL; + cleanUpContext(); + } + std::string translateActiveException() { + return getRegistryHub().getExceptionTranslatorRegistry().translateActiveException(); + } + +} // end namespace Catch + +// #included from: catch_notimplemented_exception.hpp +#define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_HPP_INCLUDED + +#include + +namespace Catch { + + NotImplementedException::NotImplementedException( SourceLineInfo const& lineInfo ) + : m_lineInfo( lineInfo ) { + std::ostringstream oss; + oss << lineInfo << ": function "; + oss << "not implemented"; + m_what = oss.str(); + } + + const char* NotImplementedException::what() const CATCH_NOEXCEPT { + return m_what.c_str(); + } + +} // end namespace Catch + +// #included from: catch_context_impl.hpp +#define TWOBLUECUBES_CATCH_CONTEXT_IMPL_HPP_INCLUDED + +// #included from: catch_stream.hpp +#define TWOBLUECUBES_CATCH_STREAM_HPP_INCLUDED + +#include +#include +#include + +namespace Catch { + + template + class StreamBufImpl : public StreamBufBase { + char data[bufferSize]; + WriterF m_writer; + + public: + StreamBufImpl() { + setp( data, data + sizeof(data) ); + } + + ~StreamBufImpl() CATCH_NOEXCEPT { + sync(); + } + + private: + int overflow( int c ) { + sync(); + + if( c != EOF ) { + if( pbase() == epptr() ) + m_writer( std::string( 1, static_cast( c ) ) ); + else + sputc( static_cast( c ) ); + } + return 0; + } + + int sync() { + if( pbase() != pptr() ) { + m_writer( std::string( pbase(), static_cast( pptr() - pbase() ) ) ); + setp( pbase(), epptr() ); + } + return 0; + } + }; + + /////////////////////////////////////////////////////////////////////////// + + FileStream::FileStream( std::string const& filename ) { + m_ofs.open( filename.c_str() ); + if( m_ofs.fail() ) { + std::ostringstream oss; + oss << "Unable to open file: '" << filename << "'"; + throw std::domain_error( oss.str() ); + } + } + + std::ostream& FileStream::stream() const { + return m_ofs; + } + + struct OutputDebugWriter { + + void operator()( std::string const&str ) { + writeToDebugConsole( str ); + } + }; + + DebugOutStream::DebugOutStream() + : m_streamBuf( new StreamBufImpl() ), + m_os( m_streamBuf.get() ) + {} + + std::ostream& DebugOutStream::stream() const { + return m_os; + } + + // Store the streambuf from cout up-front because + // cout may get redirected when running tests + CoutStream::CoutStream() + : m_os( Catch::cout().rdbuf() ) + {} + + std::ostream& CoutStream::stream() const { + return m_os; + } + +#ifndef CATCH_CONFIG_NOSTDOUT // If you #define this you must implement these functions + std::ostream& cout() { + return std::cout; + } + std::ostream& cerr() { + return std::cerr; + } +#endif +} + +namespace Catch { + + class Context : public IMutableContext { + + Context() : m_config( CATCH_NULL ), m_runner( CATCH_NULL ), m_resultCapture( CATCH_NULL ) {} + Context( Context const& ); + void operator=( Context const& ); + + public: // IContext + virtual IResultCapture* getResultCapture() { + return m_resultCapture; + } + virtual IRunner* getRunner() { + return m_runner; + } + virtual size_t getGeneratorIndex( std::string const& fileInfo, size_t totalSize ) { + return getGeneratorsForCurrentTest() + .getGeneratorInfo( fileInfo, totalSize ) + .getCurrentIndex(); + } + virtual bool advanceGeneratorsForCurrentTest() { + IGeneratorsForTest* generators = findGeneratorsForCurrentTest(); + return generators && generators->moveNext(); + } + + virtual Ptr getConfig() const { + return m_config; + } + + public: // IMutableContext + virtual void setResultCapture( IResultCapture* resultCapture ) { + m_resultCapture = resultCapture; + } + virtual void setRunner( IRunner* runner ) { + m_runner = runner; + } + virtual void setConfig( Ptr const& config ) { + m_config = config; + } + + friend IMutableContext& getCurrentMutableContext(); + + private: + IGeneratorsForTest* findGeneratorsForCurrentTest() { + std::string testName = getResultCapture()->getCurrentTestName(); + + std::map::const_iterator it = + m_generatorsByTestName.find( testName ); + return it != m_generatorsByTestName.end() + ? it->second + : CATCH_NULL; + } + + IGeneratorsForTest& getGeneratorsForCurrentTest() { + IGeneratorsForTest* generators = findGeneratorsForCurrentTest(); + if( !generators ) { + std::string testName = getResultCapture()->getCurrentTestName(); + generators = createGeneratorsForTest(); + m_generatorsByTestName.insert( std::make_pair( testName, generators ) ); + } + return *generators; + } + + private: + Ptr m_config; + IRunner* m_runner; + IResultCapture* m_resultCapture; + std::map m_generatorsByTestName; + }; + + namespace { + Context* currentContext = CATCH_NULL; + } + IMutableContext& getCurrentMutableContext() { + if( !currentContext ) + currentContext = new Context(); + return *currentContext; + } + IContext& getCurrentContext() { + return getCurrentMutableContext(); + } + + void cleanUpContext() { + delete currentContext; + currentContext = CATCH_NULL; + } +} + +// #included from: catch_console_colour_impl.hpp +#define TWOBLUECUBES_CATCH_CONSOLE_COLOUR_IMPL_HPP_INCLUDED + +namespace Catch { + namespace { + + struct IColourImpl { + virtual ~IColourImpl() {} + virtual void use( Colour::Code _colourCode ) = 0; + }; + + struct NoColourImpl : IColourImpl { + void use( Colour::Code ) {} + + static IColourImpl* instance() { + static NoColourImpl s_instance; + return &s_instance; + } + }; + + } // anon namespace +} // namespace Catch + +#if !defined( CATCH_CONFIG_COLOUR_NONE ) && !defined( CATCH_CONFIG_COLOUR_WINDOWS ) && !defined( CATCH_CONFIG_COLOUR_ANSI ) +# ifdef CATCH_PLATFORM_WINDOWS +# define CATCH_CONFIG_COLOUR_WINDOWS +# else +# define CATCH_CONFIG_COLOUR_ANSI +# endif +#endif + +#if defined ( CATCH_CONFIG_COLOUR_WINDOWS ) ///////////////////////////////////////// + +#ifndef NOMINMAX +#define NOMINMAX +#endif + +#ifdef __AFXDLL +#include +#else +#include +#endif + +namespace Catch { +namespace { + + class Win32ColourImpl : public IColourImpl { + public: + Win32ColourImpl() : stdoutHandle( GetStdHandle(STD_OUTPUT_HANDLE) ) + { + CONSOLE_SCREEN_BUFFER_INFO csbiInfo; + GetConsoleScreenBufferInfo( stdoutHandle, &csbiInfo ); + originalForegroundAttributes = csbiInfo.wAttributes & ~( BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_BLUE | BACKGROUND_INTENSITY ); + originalBackgroundAttributes = csbiInfo.wAttributes & ~( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY ); + } + + virtual void use( Colour::Code _colourCode ) { + switch( _colourCode ) { + case Colour::None: return setTextAttribute( originalForegroundAttributes ); + case Colour::White: return setTextAttribute( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE ); + case Colour::Red: return setTextAttribute( FOREGROUND_RED ); + case Colour::Green: return setTextAttribute( FOREGROUND_GREEN ); + case Colour::Blue: return setTextAttribute( FOREGROUND_BLUE ); + case Colour::Cyan: return setTextAttribute( FOREGROUND_BLUE | FOREGROUND_GREEN ); + case Colour::Yellow: return setTextAttribute( FOREGROUND_RED | FOREGROUND_GREEN ); + case Colour::Grey: return setTextAttribute( 0 ); + + case Colour::LightGrey: return setTextAttribute( FOREGROUND_INTENSITY ); + case Colour::BrightRed: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED ); + case Colour::BrightGreen: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN ); + case Colour::BrightWhite: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE ); + + case Colour::Bright: throw std::logic_error( "not a colour" ); + } + } + + private: + void setTextAttribute( WORD _textAttribute ) { + SetConsoleTextAttribute( stdoutHandle, _textAttribute | originalBackgroundAttributes ); + } + HANDLE stdoutHandle; + WORD originalForegroundAttributes; + WORD originalBackgroundAttributes; + }; + + IColourImpl* platformColourInstance() { + static Win32ColourImpl s_instance; + + Ptr config = getCurrentContext().getConfig(); + UseColour::YesOrNo colourMode = config + ? config->useColour() + : UseColour::Auto; + if( colourMode == UseColour::Auto ) + colourMode = !isDebuggerActive() + ? UseColour::Yes + : UseColour::No; + return colourMode == UseColour::Yes + ? &s_instance + : NoColourImpl::instance(); + } + +} // end anon namespace +} // end namespace Catch + +#elif defined( CATCH_CONFIG_COLOUR_ANSI ) ////////////////////////////////////// + +#include + +namespace Catch { +namespace { + + // use POSIX/ ANSI console terminal codes + // Thanks to Adam Strzelecki for original contribution + // (http://github.com/nanoant) + // https://github.com/philsquared/Catch/pull/131 + class PosixColourImpl : public IColourImpl { + public: + virtual void use( Colour::Code _colourCode ) { + switch( _colourCode ) { + case Colour::None: + case Colour::White: return setColour( "[0m" ); + case Colour::Red: return setColour( "[0;31m" ); + case Colour::Green: return setColour( "[0;32m" ); + case Colour::Blue: return setColour( "[0:34m" ); + case Colour::Cyan: return setColour( "[0;36m" ); + case Colour::Yellow: return setColour( "[0;33m" ); + case Colour::Grey: return setColour( "[1;30m" ); + + case Colour::LightGrey: return setColour( "[0;37m" ); + case Colour::BrightRed: return setColour( "[1;31m" ); + case Colour::BrightGreen: return setColour( "[1;32m" ); + case Colour::BrightWhite: return setColour( "[1;37m" ); + + case Colour::Bright: throw std::logic_error( "not a colour" ); + } + } + static IColourImpl* instance() { + static PosixColourImpl s_instance; + return &s_instance; + } + + private: + void setColour( const char* _escapeCode ) { + Catch::cout() << '\033' << _escapeCode; + } + }; + + IColourImpl* platformColourInstance() { + Ptr config = getCurrentContext().getConfig(); + UseColour::YesOrNo colourMode = config + ? config->useColour() + : UseColour::Auto; + if( colourMode == UseColour::Auto ) + colourMode = (!isDebuggerActive() && isatty(STDOUT_FILENO) ) + ? UseColour::Yes + : UseColour::No; + return colourMode == UseColour::Yes + ? PosixColourImpl::instance() + : NoColourImpl::instance(); + } + +} // end anon namespace +} // end namespace Catch + +#else // not Windows or ANSI /////////////////////////////////////////////// + +namespace Catch { + + static IColourImpl* platformColourInstance() { return NoColourImpl::instance(); } + +} // end namespace Catch + +#endif // Windows/ ANSI/ None + +namespace Catch { + + Colour::Colour( Code _colourCode ) : m_moved( false ) { use( _colourCode ); } + Colour::Colour( Colour const& _other ) : m_moved( false ) { const_cast( _other ).m_moved = true; } + Colour::~Colour(){ if( !m_moved ) use( None ); } + + void Colour::use( Code _colourCode ) { + static IColourImpl* impl = platformColourInstance(); + impl->use( _colourCode ); + } + +} // end namespace Catch + +// #included from: catch_generators_impl.hpp +#define TWOBLUECUBES_CATCH_GENERATORS_IMPL_HPP_INCLUDED + +#include +#include +#include + +namespace Catch { + + struct GeneratorInfo : IGeneratorInfo { + + GeneratorInfo( std::size_t size ) + : m_size( size ), + m_currentIndex( 0 ) + {} + + bool moveNext() { + if( ++m_currentIndex == m_size ) { + m_currentIndex = 0; + return false; + } + return true; + } + + std::size_t getCurrentIndex() const { + return m_currentIndex; + } + + std::size_t m_size; + std::size_t m_currentIndex; + }; + + /////////////////////////////////////////////////////////////////////////// + + class GeneratorsForTest : public IGeneratorsForTest { + + public: + ~GeneratorsForTest() { + deleteAll( m_generatorsInOrder ); + } + + IGeneratorInfo& getGeneratorInfo( std::string const& fileInfo, std::size_t size ) { + std::map::const_iterator it = m_generatorsByName.find( fileInfo ); + if( it == m_generatorsByName.end() ) { + IGeneratorInfo* info = new GeneratorInfo( size ); + m_generatorsByName.insert( std::make_pair( fileInfo, info ) ); + m_generatorsInOrder.push_back( info ); + return *info; + } + return *it->second; + } + + bool moveNext() { + std::vector::const_iterator it = m_generatorsInOrder.begin(); + std::vector::const_iterator itEnd = m_generatorsInOrder.end(); + for(; it != itEnd; ++it ) { + if( (*it)->moveNext() ) + return true; + } + return false; + } + + private: + std::map m_generatorsByName; + std::vector m_generatorsInOrder; + }; + + IGeneratorsForTest* createGeneratorsForTest() + { + return new GeneratorsForTest(); + } + +} // end namespace Catch + +// #included from: catch_assertionresult.hpp +#define TWOBLUECUBES_CATCH_ASSERTIONRESULT_HPP_INCLUDED + +namespace Catch { + + AssertionInfo::AssertionInfo( std::string const& _macroName, + SourceLineInfo const& _lineInfo, + std::string const& _capturedExpression, + ResultDisposition::Flags _resultDisposition ) + : macroName( _macroName ), + lineInfo( _lineInfo ), + capturedExpression( _capturedExpression ), + resultDisposition( _resultDisposition ) + {} + + AssertionResult::AssertionResult() {} + + AssertionResult::AssertionResult( AssertionInfo const& info, AssertionResultData const& data ) + : m_info( info ), + m_resultData( data ) + {} + + AssertionResult::~AssertionResult() {} + + // Result was a success + bool AssertionResult::succeeded() const { + return Catch::isOk( m_resultData.resultType ); + } + + // Result was a success, or failure is suppressed + bool AssertionResult::isOk() const { + return Catch::isOk( m_resultData.resultType ) || shouldSuppressFailure( m_info.resultDisposition ); + } + + ResultWas::OfType AssertionResult::getResultType() const { + return m_resultData.resultType; + } + + bool AssertionResult::hasExpression() const { + return !m_info.capturedExpression.empty(); + } + + bool AssertionResult::hasMessage() const { + return !m_resultData.message.empty(); + } + + std::string AssertionResult::getExpression() const { + if( isFalseTest( m_info.resultDisposition ) ) + return "!" + m_info.capturedExpression; + else + return m_info.capturedExpression; + } + std::string AssertionResult::getExpressionInMacro() const { + if( m_info.macroName.empty() ) + return m_info.capturedExpression; + else + return m_info.macroName + "( " + m_info.capturedExpression + " )"; + } + + bool AssertionResult::hasExpandedExpression() const { + return hasExpression() && getExpandedExpression() != getExpression(); + } + + std::string AssertionResult::getExpandedExpression() const { + return m_resultData.reconstructedExpression; + } + + std::string AssertionResult::getMessage() const { + return m_resultData.message; + } + SourceLineInfo AssertionResult::getSourceInfo() const { + return m_info.lineInfo; + } + + std::string AssertionResult::getTestMacroName() const { + return m_info.macroName; + } + +} // end namespace Catch + +// #included from: catch_test_case_info.hpp +#define TWOBLUECUBES_CATCH_TEST_CASE_INFO_HPP_INCLUDED + +namespace Catch { + + inline TestCaseInfo::SpecialProperties parseSpecialTag( std::string const& tag ) { + if( startsWith( tag, "." ) || + tag == "hide" || + tag == "!hide" ) + return TestCaseInfo::IsHidden; + else if( tag == "!throws" ) + return TestCaseInfo::Throws; + else if( tag == "!shouldfail" ) + return TestCaseInfo::ShouldFail; + else if( tag == "!mayfail" ) + return TestCaseInfo::MayFail; + else + return TestCaseInfo::None; + } + inline bool isReservedTag( std::string const& tag ) { + return parseSpecialTag( tag ) == TestCaseInfo::None && tag.size() > 0 && !isalnum( tag[0] ); + } + inline void enforceNotReservedTag( std::string const& tag, SourceLineInfo const& _lineInfo ) { + if( isReservedTag( tag ) ) { + { + Colour colourGuard( Colour::Red ); + Catch::cerr() + << "Tag name [" << tag << "] not allowed.\n" + << "Tag names starting with non alpha-numeric characters are reserved\n"; + } + { + Colour colourGuard( Colour::FileName ); + Catch::cerr() << _lineInfo << std::endl; + } + exit(1); + } + } + + TestCase makeTestCase( ITestCase* _testCase, + std::string const& _className, + std::string const& _name, + std::string const& _descOrTags, + SourceLineInfo const& _lineInfo ) + { + bool isHidden( startsWith( _name, "./" ) ); // Legacy support + + // Parse out tags + std::set tags; + std::string desc, tag; + bool inTag = false; + for( std::size_t i = 0; i < _descOrTags.size(); ++i ) { + char c = _descOrTags[i]; + if( !inTag ) { + if( c == '[' ) + inTag = true; + else + desc += c; + } + else { + if( c == ']' ) { + TestCaseInfo::SpecialProperties prop = parseSpecialTag( tag ); + if( prop == TestCaseInfo::IsHidden ) + isHidden = true; + else if( prop == TestCaseInfo::None ) + enforceNotReservedTag( tag, _lineInfo ); + + tags.insert( tag ); + tag.clear(); + inTag = false; + } + else + tag += c; + } + } + if( isHidden ) { + tags.insert( "hide" ); + tags.insert( "." ); + } + + TestCaseInfo info( _name, _className, desc, tags, _lineInfo ); + return TestCase( _testCase, info ); + } + + void setTags( TestCaseInfo& testCaseInfo, std::set const& tags ) + { + testCaseInfo.tags = tags; + testCaseInfo.lcaseTags.clear(); + + std::ostringstream oss; + for( std::set::const_iterator it = tags.begin(), itEnd = tags.end(); it != itEnd; ++it ) { + oss << "[" << *it << "]"; + std::string lcaseTag = toLower( *it ); + testCaseInfo.properties = static_cast( testCaseInfo.properties | parseSpecialTag( lcaseTag ) ); + testCaseInfo.lcaseTags.insert( lcaseTag ); + } + testCaseInfo.tagsAsString = oss.str(); + } + + TestCaseInfo::TestCaseInfo( std::string const& _name, + std::string const& _className, + std::string const& _description, + std::set const& _tags, + SourceLineInfo const& _lineInfo ) + : name( _name ), + className( _className ), + description( _description ), + lineInfo( _lineInfo ), + properties( None ) + { + setTags( *this, _tags ); + } + + TestCaseInfo::TestCaseInfo( TestCaseInfo const& other ) + : name( other.name ), + className( other.className ), + description( other.description ), + tags( other.tags ), + lcaseTags( other.lcaseTags ), + tagsAsString( other.tagsAsString ), + lineInfo( other.lineInfo ), + properties( other.properties ) + {} + + bool TestCaseInfo::isHidden() const { + return ( properties & IsHidden ) != 0; + } + bool TestCaseInfo::throws() const { + return ( properties & Throws ) != 0; + } + bool TestCaseInfo::okToFail() const { + return ( properties & (ShouldFail | MayFail ) ) != 0; + } + bool TestCaseInfo::expectedToFail() const { + return ( properties & (ShouldFail ) ) != 0; + } + + TestCase::TestCase( ITestCase* testCase, TestCaseInfo const& info ) : TestCaseInfo( info ), test( testCase ) {} + + TestCase::TestCase( TestCase const& other ) + : TestCaseInfo( other ), + test( other.test ) + {} + + TestCase TestCase::withName( std::string const& _newName ) const { + TestCase other( *this ); + other.name = _newName; + return other; + } + + void TestCase::swap( TestCase& other ) { + test.swap( other.test ); + name.swap( other.name ); + className.swap( other.className ); + description.swap( other.description ); + tags.swap( other.tags ); + lcaseTags.swap( other.lcaseTags ); + tagsAsString.swap( other.tagsAsString ); + std::swap( TestCaseInfo::properties, static_cast( other ).properties ); + std::swap( lineInfo, other.lineInfo ); + } + + void TestCase::invoke() const { + test->invoke(); + } + + bool TestCase::operator == ( TestCase const& other ) const { + return test.get() == other.test.get() && + name == other.name && + className == other.className; + } + + bool TestCase::operator < ( TestCase const& other ) const { + return name < other.name; + } + TestCase& TestCase::operator = ( TestCase const& other ) { + TestCase temp( other ); + swap( temp ); + return *this; + } + + TestCaseInfo const& TestCase::getTestCaseInfo() const + { + return *this; + } + +} // end namespace Catch + +// #included from: catch_version.hpp +#define TWOBLUECUBES_CATCH_VERSION_HPP_INCLUDED + +namespace Catch { + + Version::Version + ( unsigned int _majorVersion, + unsigned int _minorVersion, + unsigned int _patchNumber, + std::string const& _branchName, + unsigned int _buildNumber ) + : majorVersion( _majorVersion ), + minorVersion( _minorVersion ), + patchNumber( _patchNumber ), + branchName( _branchName ), + buildNumber( _buildNumber ) + {} + + std::ostream& operator << ( std::ostream& os, Version const& version ) { + os << version.majorVersion << "." + << version.minorVersion << "." + << version.patchNumber; + + if( !version.branchName.empty() ) { + os << "-" << version.branchName + << "." << version.buildNumber; + } + return os; + } + + Version libraryVersion( 1, 3, 6, "", 0 ); + +} + +// #included from: catch_message.hpp +#define TWOBLUECUBES_CATCH_MESSAGE_HPP_INCLUDED + +namespace Catch { + + MessageInfo::MessageInfo( std::string const& _macroName, + SourceLineInfo const& _lineInfo, + ResultWas::OfType _type ) + : macroName( _macroName ), + lineInfo( _lineInfo ), + type( _type ), + sequence( ++globalCount ) + {} + + // This may need protecting if threading support is added + unsigned int MessageInfo::globalCount = 0; + + //////////////////////////////////////////////////////////////////////////// + + ScopedMessage::ScopedMessage( MessageBuilder const& builder ) + : m_info( builder.m_info ) + { + m_info.message = builder.m_stream.str(); + getResultCapture().pushScopedMessage( m_info ); + } + ScopedMessage::ScopedMessage( ScopedMessage const& other ) + : m_info( other.m_info ) + {} + + ScopedMessage::~ScopedMessage() { + getResultCapture().popScopedMessage( m_info ); + } + +} // end namespace Catch + +// #included from: catch_legacy_reporter_adapter.hpp +#define TWOBLUECUBES_CATCH_LEGACY_REPORTER_ADAPTER_HPP_INCLUDED + +// #included from: catch_legacy_reporter_adapter.h +#define TWOBLUECUBES_CATCH_LEGACY_REPORTER_ADAPTER_H_INCLUDED + +namespace Catch +{ + // Deprecated + struct IReporter : IShared { + virtual ~IReporter(); + + virtual bool shouldRedirectStdout() const = 0; + + virtual void StartTesting() = 0; + virtual void EndTesting( Totals const& totals ) = 0; + virtual void StartGroup( std::string const& groupName ) = 0; + virtual void EndGroup( std::string const& groupName, Totals const& totals ) = 0; + virtual void StartTestCase( TestCaseInfo const& testInfo ) = 0; + virtual void EndTestCase( TestCaseInfo const& testInfo, Totals const& totals, std::string const& stdOut, std::string const& stdErr ) = 0; + virtual void StartSection( std::string const& sectionName, std::string const& description ) = 0; + virtual void EndSection( std::string const& sectionName, Counts const& assertions ) = 0; + virtual void NoAssertionsInSection( std::string const& sectionName ) = 0; + virtual void NoAssertionsInTestCase( std::string const& testName ) = 0; + virtual void Aborted() = 0; + virtual void Result( AssertionResult const& result ) = 0; + }; + + class LegacyReporterAdapter : public SharedImpl + { + public: + LegacyReporterAdapter( Ptr const& legacyReporter ); + virtual ~LegacyReporterAdapter(); + + virtual ReporterPreferences getPreferences() const; + virtual void noMatchingTestCases( std::string const& ); + virtual void testRunStarting( TestRunInfo const& ); + virtual void testGroupStarting( GroupInfo const& groupInfo ); + virtual void testCaseStarting( TestCaseInfo const& testInfo ); + virtual void sectionStarting( SectionInfo const& sectionInfo ); + virtual void assertionStarting( AssertionInfo const& ); + virtual bool assertionEnded( AssertionStats const& assertionStats ); + virtual void sectionEnded( SectionStats const& sectionStats ); + virtual void testCaseEnded( TestCaseStats const& testCaseStats ); + virtual void testGroupEnded( TestGroupStats const& testGroupStats ); + virtual void testRunEnded( TestRunStats const& testRunStats ); + virtual void skipTest( TestCaseInfo const& ); + + private: + Ptr m_legacyReporter; + }; +} + +namespace Catch +{ + LegacyReporterAdapter::LegacyReporterAdapter( Ptr const& legacyReporter ) + : m_legacyReporter( legacyReporter ) + {} + LegacyReporterAdapter::~LegacyReporterAdapter() {} + + ReporterPreferences LegacyReporterAdapter::getPreferences() const { + ReporterPreferences prefs; + prefs.shouldRedirectStdOut = m_legacyReporter->shouldRedirectStdout(); + return prefs; + } + + void LegacyReporterAdapter::noMatchingTestCases( std::string const& ) {} + void LegacyReporterAdapter::testRunStarting( TestRunInfo const& ) { + m_legacyReporter->StartTesting(); + } + void LegacyReporterAdapter::testGroupStarting( GroupInfo const& groupInfo ) { + m_legacyReporter->StartGroup( groupInfo.name ); + } + void LegacyReporterAdapter::testCaseStarting( TestCaseInfo const& testInfo ) { + m_legacyReporter->StartTestCase( testInfo ); + } + void LegacyReporterAdapter::sectionStarting( SectionInfo const& sectionInfo ) { + m_legacyReporter->StartSection( sectionInfo.name, sectionInfo.description ); + } + void LegacyReporterAdapter::assertionStarting( AssertionInfo const& ) { + // Not on legacy interface + } + + bool LegacyReporterAdapter::assertionEnded( AssertionStats const& assertionStats ) { + if( assertionStats.assertionResult.getResultType() != ResultWas::Ok ) { + for( std::vector::const_iterator it = assertionStats.infoMessages.begin(), itEnd = assertionStats.infoMessages.end(); + it != itEnd; + ++it ) { + if( it->type == ResultWas::Info ) { + ResultBuilder rb( it->macroName.c_str(), it->lineInfo, "", ResultDisposition::Normal ); + rb << it->message; + rb.setResultType( ResultWas::Info ); + AssertionResult result = rb.build(); + m_legacyReporter->Result( result ); + } + } + } + m_legacyReporter->Result( assertionStats.assertionResult ); + return true; + } + void LegacyReporterAdapter::sectionEnded( SectionStats const& sectionStats ) { + if( sectionStats.missingAssertions ) + m_legacyReporter->NoAssertionsInSection( sectionStats.sectionInfo.name ); + m_legacyReporter->EndSection( sectionStats.sectionInfo.name, sectionStats.assertions ); + } + void LegacyReporterAdapter::testCaseEnded( TestCaseStats const& testCaseStats ) { + m_legacyReporter->EndTestCase + ( testCaseStats.testInfo, + testCaseStats.totals, + testCaseStats.stdOut, + testCaseStats.stdErr ); + } + void LegacyReporterAdapter::testGroupEnded( TestGroupStats const& testGroupStats ) { + if( testGroupStats.aborting ) + m_legacyReporter->Aborted(); + m_legacyReporter->EndGroup( testGroupStats.groupInfo.name, testGroupStats.totals ); + } + void LegacyReporterAdapter::testRunEnded( TestRunStats const& testRunStats ) { + m_legacyReporter->EndTesting( testRunStats.totals ); + } + void LegacyReporterAdapter::skipTest( TestCaseInfo const& ) { + } +} + +// #included from: catch_timer.hpp + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wc++11-long-long" +#endif + +#ifdef CATCH_PLATFORM_WINDOWS +#include +#else +#include +#endif + +namespace Catch { + + namespace { +#ifdef CATCH_PLATFORM_WINDOWS + uint64_t getCurrentTicks() { + static uint64_t hz=0, hzo=0; + if (!hz) { + QueryPerformanceFrequency( reinterpret_cast( &hz ) ); + QueryPerformanceCounter( reinterpret_cast( &hzo ) ); + } + uint64_t t; + QueryPerformanceCounter( reinterpret_cast( &t ) ); + return ((t-hzo)*1000000)/hz; + } +#else + uint64_t getCurrentTicks() { + timeval t; + gettimeofday(&t,CATCH_NULL); + return static_cast( t.tv_sec ) * 1000000ull + static_cast( t.tv_usec ); + } +#endif + } + + void Timer::start() { + m_ticks = getCurrentTicks(); + } + unsigned int Timer::getElapsedMicroseconds() const { + return static_cast(getCurrentTicks() - m_ticks); + } + unsigned int Timer::getElapsedMilliseconds() const { + return static_cast(getElapsedMicroseconds()/1000); + } + double Timer::getElapsedSeconds() const { + return getElapsedMicroseconds()/1000000.0; + } + +} // namespace Catch + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif +// #included from: catch_common.hpp +#define TWOBLUECUBES_CATCH_COMMON_HPP_INCLUDED + +namespace Catch { + + bool startsWith( std::string const& s, std::string const& prefix ) { + return s.size() >= prefix.size() && s.substr( 0, prefix.size() ) == prefix; + } + bool endsWith( std::string const& s, std::string const& suffix ) { + return s.size() >= suffix.size() && s.substr( s.size()-suffix.size(), suffix.size() ) == suffix; + } + bool contains( std::string const& s, std::string const& infix ) { + return s.find( infix ) != std::string::npos; + } + void toLowerInPlace( std::string& s ) { + std::transform( s.begin(), s.end(), s.begin(), ::tolower ); + } + std::string toLower( std::string const& s ) { + std::string lc = s; + toLowerInPlace( lc ); + return lc; + } + std::string trim( std::string const& str ) { + static char const* whitespaceChars = "\n\r\t "; + std::string::size_type start = str.find_first_not_of( whitespaceChars ); + std::string::size_type end = str.find_last_not_of( whitespaceChars ); + + return start != std::string::npos ? str.substr( start, 1+end-start ) : ""; + } + + bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ) { + bool replaced = false; + std::size_t i = str.find( replaceThis ); + while( i != std::string::npos ) { + replaced = true; + str = str.substr( 0, i ) + withThis + str.substr( i+replaceThis.size() ); + if( i < str.size()-withThis.size() ) + i = str.find( replaceThis, i+withThis.size() ); + else + i = std::string::npos; + } + return replaced; + } + + pluralise::pluralise( std::size_t count, std::string const& label ) + : m_count( count ), + m_label( label ) + {} + + std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ) { + os << pluraliser.m_count << " " << pluraliser.m_label; + if( pluraliser.m_count != 1 ) + os << "s"; + return os; + } + + SourceLineInfo::SourceLineInfo() : line( 0 ){} + SourceLineInfo::SourceLineInfo( char const* _file, std::size_t _line ) + : file( _file ), + line( _line ) + {} + SourceLineInfo::SourceLineInfo( SourceLineInfo const& other ) + : file( other.file ), + line( other.line ) + {} + bool SourceLineInfo::empty() const { + return file.empty(); + } + bool SourceLineInfo::operator == ( SourceLineInfo const& other ) const { + return line == other.line && file == other.file; + } + bool SourceLineInfo::operator < ( SourceLineInfo const& other ) const { + return line < other.line || ( line == other.line && file < other.file ); + } + + void seedRng( IConfig const& config ) { + if( config.rngSeed() != 0 ) + std::srand( config.rngSeed() ); + } + unsigned int rngSeed() { + return getCurrentContext().getConfig()->rngSeed(); + } + + std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ) { +#ifndef __GNUG__ + os << info.file << "(" << info.line << ")"; +#else + os << info.file << ":" << info.line; +#endif + return os; + } + + void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo ) { + std::ostringstream oss; + oss << locationInfo << ": Internal Catch error: '" << message << "'"; + if( alwaysTrue() ) + throw std::logic_error( oss.str() ); + } +} + +// #included from: catch_section.hpp +#define TWOBLUECUBES_CATCH_SECTION_HPP_INCLUDED + +namespace Catch { + + SectionInfo::SectionInfo + ( SourceLineInfo const& _lineInfo, + std::string const& _name, + std::string const& _description ) + : name( _name ), + description( _description ), + lineInfo( _lineInfo ) + {} + + Section::Section( SectionInfo const& info ) + : m_info( info ), + m_sectionIncluded( getResultCapture().sectionStarted( m_info, m_assertions ) ) + { + m_timer.start(); + } + + Section::~Section() { + if( m_sectionIncluded ) { + SectionEndInfo endInfo( m_info, m_assertions, m_timer.getElapsedSeconds() ); + if( std::uncaught_exception() ) + getResultCapture().sectionEndedEarly( endInfo ); + else + getResultCapture().sectionEnded( endInfo ); + } + } + + // This indicates whether the section should be executed or not + Section::operator bool() const { + return m_sectionIncluded; + } + +} // end namespace Catch + +// #included from: catch_debugger.hpp +#define TWOBLUECUBES_CATCH_DEBUGGER_HPP_INCLUDED + +#include + +#ifdef CATCH_PLATFORM_MAC + + #include + #include + #include + #include + #include + + namespace Catch{ + + // The following function is taken directly from the following technical note: + // http://developer.apple.com/library/mac/#qa/qa2004/qa1361.html + + // Returns true if the current process is being debugged (either + // running under the debugger or has a debugger attached post facto). + bool isDebuggerActive(){ + + int mib[4]; + struct kinfo_proc info; + size_t size; + + // Initialize the flags so that, if sysctl fails for some bizarre + // reason, we get a predictable result. + + info.kp_proc.p_flag = 0; + + // Initialize mib, which tells sysctl the info we want, in this case + // we're looking for information about a specific process ID. + + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PID; + mib[3] = getpid(); + + // Call sysctl. + + size = sizeof(info); + if( sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, CATCH_NULL, 0) != 0 ) { + Catch::cerr() << "\n** Call to sysctl failed - unable to determine if debugger is active **\n" << std::endl; + return false; + } + + // We're being debugged if the P_TRACED flag is set. + + return ( (info.kp_proc.p_flag & P_TRACED) != 0 ); + } + } // namespace Catch + +#elif defined(_MSC_VER) + extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); + namespace Catch { + bool isDebuggerActive() { + return IsDebuggerPresent() != 0; + } + } +#elif defined(__MINGW32__) + extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); + namespace Catch { + bool isDebuggerActive() { + return IsDebuggerPresent() != 0; + } + } +#else + namespace Catch { + inline bool isDebuggerActive() { return false; } + } +#endif // Platform + +#ifdef CATCH_PLATFORM_WINDOWS + extern "C" __declspec(dllimport) void __stdcall OutputDebugStringA( const char* ); + namespace Catch { + void writeToDebugConsole( std::string const& text ) { + ::OutputDebugStringA( text.c_str() ); + } + } +#else + namespace Catch { + void writeToDebugConsole( std::string const& text ) { + // !TBD: Need a version for Mac/ XCode and other IDEs + Catch::cout() << text; + } + } +#endif // Platform + +// #included from: catch_tostring.hpp +#define TWOBLUECUBES_CATCH_TOSTRING_HPP_INCLUDED + +namespace Catch { + +namespace Detail { + + const std::string unprintableString = "{?}"; + + namespace { + const int hexThreshold = 255; + + struct Endianness { + enum Arch { Big, Little }; + + static Arch which() { + union _{ + int asInt; + char asChar[sizeof (int)]; + } u; + + u.asInt = 1; + return ( u.asChar[sizeof(int)-1] == 1 ) ? Big : Little; + } + }; + } + + std::string rawMemoryToString( const void *object, std::size_t size ) + { + // Reverse order for little endian architectures + int i = 0, end = static_cast( size ), inc = 1; + if( Endianness::which() == Endianness::Little ) { + i = end-1; + end = inc = -1; + } + + unsigned char const *bytes = static_cast(object); + std::ostringstream os; + os << "0x" << std::setfill('0') << std::hex; + for( ; i != end; i += inc ) + os << std::setw(2) << static_cast(bytes[i]); + return os.str(); + } +} + +std::string toString( std::string const& value ) { + std::string s = value; + if( getCurrentContext().getConfig()->showInvisibles() ) { + for(size_t i = 0; i < s.size(); ++i ) { + std::string subs; + switch( s[i] ) { + case '\n': subs = "\\n"; break; + case '\t': subs = "\\t"; break; + default: break; + } + if( !subs.empty() ) { + s = s.substr( 0, i ) + subs + s.substr( i+1 ); + ++i; + } + } + } + return "\"" + s + "\""; +} +std::string toString( std::wstring const& value ) { + + std::string s; + s.reserve( value.size() ); + for(size_t i = 0; i < value.size(); ++i ) + s += value[i] <= 0xff ? static_cast( value[i] ) : '?'; + return Catch::toString( s ); +} + +std::string toString( const char* const value ) { + return value ? Catch::toString( std::string( value ) ) : std::string( "{null string}" ); +} + +std::string toString( char* const value ) { + return Catch::toString( static_cast( value ) ); +} + +std::string toString( const wchar_t* const value ) +{ + return value ? Catch::toString( std::wstring(value) ) : std::string( "{null string}" ); +} + +std::string toString( wchar_t* const value ) +{ + return Catch::toString( static_cast( value ) ); +} + +std::string toString( int value ) { + std::ostringstream oss; + oss << value; + if( value > Detail::hexThreshold ) + oss << " (0x" << std::hex << value << ")"; + return oss.str(); +} + +std::string toString( unsigned long value ) { + std::ostringstream oss; + oss << value; + if( value > Detail::hexThreshold ) + oss << " (0x" << std::hex << value << ")"; + return oss.str(); +} + +std::string toString( unsigned int value ) { + return Catch::toString( static_cast( value ) ); +} + +template +std::string fpToString( T value, int precision ) { + std::ostringstream oss; + oss << std::setprecision( precision ) + << std::fixed + << value; + std::string d = oss.str(); + std::size_t i = d.find_last_not_of( '0' ); + if( i != std::string::npos && i != d.size()-1 ) { + if( d[i] == '.' ) + i++; + d = d.substr( 0, i+1 ); + } + return d; +} + +std::string toString( const double value ) { + return fpToString( value, 10 ); +} +std::string toString( const float value ) { + return fpToString( value, 5 ) + "f"; +} + +std::string toString( bool value ) { + return value ? "true" : "false"; +} + +std::string toString( char value ) { + return value < ' ' + ? toString( static_cast( value ) ) + : Detail::makeString( value ); +} + +std::string toString( signed char value ) { + return toString( static_cast( value ) ); +} + +std::string toString( unsigned char value ) { + return toString( static_cast( value ) ); +} + +#ifdef CATCH_CONFIG_CPP11_LONG_LONG +std::string toString( long long value ) { + std::ostringstream oss; + oss << value; + if( value > Detail::hexThreshold ) + oss << " (0x" << std::hex << value << ")"; + return oss.str(); +} +std::string toString( unsigned long long value ) { + std::ostringstream oss; + oss << value; + if( value > Detail::hexThreshold ) + oss << " (0x" << std::hex << value << ")"; + return oss.str(); +} +#endif + +#ifdef CATCH_CONFIG_CPP11_NULLPTR +std::string toString( std::nullptr_t ) { + return "nullptr"; +} +#endif + +#ifdef __OBJC__ + std::string toString( NSString const * const& nsstring ) { + if( !nsstring ) + return "nil"; + return "@" + toString([nsstring UTF8String]); + } + std::string toString( NSString * CATCH_ARC_STRONG const& nsstring ) { + if( !nsstring ) + return "nil"; + return "@" + toString([nsstring UTF8String]); + } + std::string toString( NSObject* const& nsObject ) { + return toString( [nsObject description] ); + } +#endif + +} // end namespace Catch + +// #included from: catch_result_builder.hpp +#define TWOBLUECUBES_CATCH_RESULT_BUILDER_HPP_INCLUDED + +namespace Catch { + + std::string capturedExpressionWithSecondArgument( std::string const& capturedExpression, std::string const& secondArg ) { + return secondArg.empty() || secondArg == "\"\"" + ? capturedExpression + : capturedExpression + ", " + secondArg; + } + ResultBuilder::ResultBuilder( char const* macroName, + SourceLineInfo const& lineInfo, + char const* capturedExpression, + ResultDisposition::Flags resultDisposition, + char const* secondArg ) + : m_assertionInfo( macroName, lineInfo, capturedExpressionWithSecondArgument( capturedExpression, secondArg ), resultDisposition ), + m_shouldDebugBreak( false ), + m_shouldThrow( false ) + {} + + ResultBuilder& ResultBuilder::setResultType( ResultWas::OfType result ) { + m_data.resultType = result; + return *this; + } + ResultBuilder& ResultBuilder::setResultType( bool result ) { + m_data.resultType = result ? ResultWas::Ok : ResultWas::ExpressionFailed; + return *this; + } + ResultBuilder& ResultBuilder::setLhs( std::string const& lhs ) { + m_exprComponents.lhs = lhs; + return *this; + } + ResultBuilder& ResultBuilder::setRhs( std::string const& rhs ) { + m_exprComponents.rhs = rhs; + return *this; + } + ResultBuilder& ResultBuilder::setOp( std::string const& op ) { + m_exprComponents.op = op; + return *this; + } + + void ResultBuilder::endExpression() { + m_exprComponents.testFalse = isFalseTest( m_assertionInfo.resultDisposition ); + captureExpression(); + } + + void ResultBuilder::useActiveException( ResultDisposition::Flags resultDisposition ) { + m_assertionInfo.resultDisposition = resultDisposition; + m_stream.oss << Catch::translateActiveException(); + captureResult( ResultWas::ThrewException ); + } + + void ResultBuilder::captureResult( ResultWas::OfType resultType ) { + setResultType( resultType ); + captureExpression(); + } + void ResultBuilder::captureExpectedException( std::string const& expectedMessage ) { + if( expectedMessage.empty() ) + captureExpectedException( Matchers::Impl::Generic::AllOf() ); + else + captureExpectedException( Matchers::Equals( expectedMessage ) ); + } + + void ResultBuilder::captureExpectedException( Matchers::Impl::Matcher const& matcher ) { + + assert( m_exprComponents.testFalse == false ); + AssertionResultData data = m_data; + data.resultType = ResultWas::Ok; + data.reconstructedExpression = m_assertionInfo.capturedExpression; + + std::string actualMessage = Catch::translateActiveException(); + if( !matcher.match( actualMessage ) ) { + data.resultType = ResultWas::ExpressionFailed; + data.reconstructedExpression = actualMessage; + } + AssertionResult result( m_assertionInfo, data ); + handleResult( result ); + } + + void ResultBuilder::captureExpression() { + AssertionResult result = build(); + handleResult( result ); + } + void ResultBuilder::handleResult( AssertionResult const& result ) + { + getResultCapture().assertionEnded( result ); + + if( !result.isOk() ) { + if( getCurrentContext().getConfig()->shouldDebugBreak() ) + m_shouldDebugBreak = true; + if( getCurrentContext().getRunner()->aborting() || (m_assertionInfo.resultDisposition & ResultDisposition::Normal) ) + m_shouldThrow = true; + } + } + void ResultBuilder::react() { + if( m_shouldThrow ) + throw Catch::TestFailureException(); + } + + bool ResultBuilder::shouldDebugBreak() const { return m_shouldDebugBreak; } + bool ResultBuilder::allowThrows() const { return getCurrentContext().getConfig()->allowThrows(); } + + AssertionResult ResultBuilder::build() const + { + assert( m_data.resultType != ResultWas::Unknown ); + + AssertionResultData data = m_data; + + // Flip bool results if testFalse is set + if( m_exprComponents.testFalse ) { + if( data.resultType == ResultWas::Ok ) + data.resultType = ResultWas::ExpressionFailed; + else if( data.resultType == ResultWas::ExpressionFailed ) + data.resultType = ResultWas::Ok; + } + + data.message = m_stream.oss.str(); + data.reconstructedExpression = reconstructExpression(); + if( m_exprComponents.testFalse ) { + if( m_exprComponents.op == "" ) + data.reconstructedExpression = "!" + data.reconstructedExpression; + else + data.reconstructedExpression = "!(" + data.reconstructedExpression + ")"; + } + return AssertionResult( m_assertionInfo, data ); + } + std::string ResultBuilder::reconstructExpression() const { + if( m_exprComponents.op == "" ) + return m_exprComponents.lhs.empty() ? m_assertionInfo.capturedExpression : m_exprComponents.op + m_exprComponents.lhs; + else if( m_exprComponents.op == "matches" ) + return m_exprComponents.lhs + " " + m_exprComponents.rhs; + else if( m_exprComponents.op != "!" ) { + if( m_exprComponents.lhs.size() + m_exprComponents.rhs.size() < 40 && + m_exprComponents.lhs.find("\n") == std::string::npos && + m_exprComponents.rhs.find("\n") == std::string::npos ) + return m_exprComponents.lhs + " " + m_exprComponents.op + " " + m_exprComponents.rhs; + else + return m_exprComponents.lhs + "\n" + m_exprComponents.op + "\n" + m_exprComponents.rhs; + } + else + return "{can't expand - use " + m_assertionInfo.macroName + "_FALSE( " + m_assertionInfo.capturedExpression.substr(1) + " ) instead of " + m_assertionInfo.macroName + "( " + m_assertionInfo.capturedExpression + " ) for better diagnostics}"; + } + +} // end namespace Catch + +// #included from: catch_tag_alias_registry.hpp +#define TWOBLUECUBES_CATCH_TAG_ALIAS_REGISTRY_HPP_INCLUDED + +// #included from: catch_tag_alias_registry.h +#define TWOBLUECUBES_CATCH_TAG_ALIAS_REGISTRY_H_INCLUDED + +#include + +namespace Catch { + + class TagAliasRegistry : public ITagAliasRegistry { + public: + virtual ~TagAliasRegistry(); + virtual Option find( std::string const& alias ) const; + virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const; + void add( char const* alias, char const* tag, SourceLineInfo const& lineInfo ); + static TagAliasRegistry& get(); + + private: + std::map m_registry; + }; + +} // end namespace Catch + +#include +#include + +namespace Catch { + + TagAliasRegistry::~TagAliasRegistry() {} + + Option TagAliasRegistry::find( std::string const& alias ) const { + std::map::const_iterator it = m_registry.find( alias ); + if( it != m_registry.end() ) + return it->second; + else + return Option(); + } + + std::string TagAliasRegistry::expandAliases( std::string const& unexpandedTestSpec ) const { + std::string expandedTestSpec = unexpandedTestSpec; + for( std::map::const_iterator it = m_registry.begin(), itEnd = m_registry.end(); + it != itEnd; + ++it ) { + std::size_t pos = expandedTestSpec.find( it->first ); + if( pos != std::string::npos ) { + expandedTestSpec = expandedTestSpec.substr( 0, pos ) + + it->second.tag + + expandedTestSpec.substr( pos + it->first.size() ); + } + } + return expandedTestSpec; + } + + void TagAliasRegistry::add( char const* alias, char const* tag, SourceLineInfo const& lineInfo ) { + + if( !startsWith( alias, "[@" ) || !endsWith( alias, "]" ) ) { + std::ostringstream oss; + oss << "error: tag alias, \"" << alias << "\" is not of the form [@alias name].\n" << lineInfo; + throw std::domain_error( oss.str().c_str() ); + } + if( !m_registry.insert( std::make_pair( alias, TagAlias( tag, lineInfo ) ) ).second ) { + std::ostringstream oss; + oss << "error: tag alias, \"" << alias << "\" already registered.\n" + << "\tFirst seen at " << find(alias)->lineInfo << "\n" + << "\tRedefined at " << lineInfo; + throw std::domain_error( oss.str().c_str() ); + } + } + + TagAliasRegistry& TagAliasRegistry::get() { + static TagAliasRegistry instance; + return instance; + + } + + ITagAliasRegistry::~ITagAliasRegistry() {} + ITagAliasRegistry const& ITagAliasRegistry::get() { return TagAliasRegistry::get(); } + + RegistrarForTagAliases::RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ) { + try { + TagAliasRegistry::get().add( alias, tag, lineInfo ); + } + catch( std::exception& ex ) { + Colour colourGuard( Colour::Red ); + Catch::cerr() << ex.what() << std::endl; + exit(1); + } + } + +} // end namespace Catch + +// #included from: ../reporters/catch_reporter_multi.hpp +#define TWOBLUECUBES_CATCH_REPORTER_MULTI_HPP_INCLUDED + +namespace Catch { + +class MultipleReporters : public SharedImpl { + typedef std::vector > Reporters; + Reporters m_reporters; + +public: + void add( Ptr const& reporter ) { + m_reporters.push_back( reporter ); + } + +public: // IStreamingReporter + + virtual ReporterPreferences getPreferences() const CATCH_OVERRIDE { + return m_reporters[0]->getPreferences(); + } + + virtual void noMatchingTestCases( std::string const& spec ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->noMatchingTestCases( spec ); + } + + virtual void testRunStarting( TestRunInfo const& testRunInfo ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->testRunStarting( testRunInfo ); + } + + virtual void testGroupStarting( GroupInfo const& groupInfo ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->testGroupStarting( groupInfo ); + } + + virtual void testCaseStarting( TestCaseInfo const& testInfo ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->testCaseStarting( testInfo ); + } + + virtual void sectionStarting( SectionInfo const& sectionInfo ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->sectionStarting( sectionInfo ); + } + + virtual void assertionStarting( AssertionInfo const& assertionInfo ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->assertionStarting( assertionInfo ); + } + + // The return value indicates if the messages buffer should be cleared: + virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE { + bool clearBuffer = false; + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + clearBuffer |= (*it)->assertionEnded( assertionStats ); + return clearBuffer; + } + + virtual void sectionEnded( SectionStats const& sectionStats ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->sectionEnded( sectionStats ); + } + + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->testCaseEnded( testCaseStats ); + } + + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->testGroupEnded( testGroupStats ); + } + + virtual void testRunEnded( TestRunStats const& testRunStats ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->testRunEnded( testRunStats ); + } + + virtual void skipTest( TestCaseInfo const& testInfo ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->skipTest( testInfo ); + } +}; + +Ptr addReporter( Ptr const& existingReporter, Ptr const& additionalReporter ) { + Ptr resultingReporter; + + if( existingReporter ) { + MultipleReporters* multi = dynamic_cast( existingReporter.get() ); + if( !multi ) { + multi = new MultipleReporters; + resultingReporter = Ptr( multi ); + if( existingReporter ) + multi->add( existingReporter ); + } + else + resultingReporter = existingReporter; + multi->add( additionalReporter ); + } + else + resultingReporter = additionalReporter; + + return resultingReporter; +} + +} // end namespace Catch + +// #included from: ../reporters/catch_reporter_xml.hpp +#define TWOBLUECUBES_CATCH_REPORTER_XML_HPP_INCLUDED + +// #included from: catch_reporter_bases.hpp +#define TWOBLUECUBES_CATCH_REPORTER_BASES_HPP_INCLUDED + +#include + +namespace Catch { + + struct StreamingReporterBase : SharedImpl { + + StreamingReporterBase( ReporterConfig const& _config ) + : m_config( _config.fullConfig() ), + stream( _config.stream() ) + { + m_reporterPrefs.shouldRedirectStdOut = false; + } + + virtual ReporterPreferences getPreferences() const CATCH_OVERRIDE { + return m_reporterPrefs; + } + + virtual ~StreamingReporterBase() CATCH_OVERRIDE; + + virtual void noMatchingTestCases( std::string const& ) CATCH_OVERRIDE {} + + virtual void testRunStarting( TestRunInfo const& _testRunInfo ) CATCH_OVERRIDE { + currentTestRunInfo = _testRunInfo; + } + virtual void testGroupStarting( GroupInfo const& _groupInfo ) CATCH_OVERRIDE { + currentGroupInfo = _groupInfo; + } + + virtual void testCaseStarting( TestCaseInfo const& _testInfo ) CATCH_OVERRIDE { + currentTestCaseInfo = _testInfo; + } + virtual void sectionStarting( SectionInfo const& _sectionInfo ) CATCH_OVERRIDE { + m_sectionStack.push_back( _sectionInfo ); + } + + virtual void sectionEnded( SectionStats const& /* _sectionStats */ ) CATCH_OVERRIDE { + m_sectionStack.pop_back(); + } + virtual void testCaseEnded( TestCaseStats const& /* _testCaseStats */ ) CATCH_OVERRIDE { + currentTestCaseInfo.reset(); + } + virtual void testGroupEnded( TestGroupStats const& /* _testGroupStats */ ) CATCH_OVERRIDE { + currentGroupInfo.reset(); + } + virtual void testRunEnded( TestRunStats const& /* _testRunStats */ ) CATCH_OVERRIDE { + currentTestCaseInfo.reset(); + currentGroupInfo.reset(); + currentTestRunInfo.reset(); + } + + virtual void skipTest( TestCaseInfo const& ) CATCH_OVERRIDE { + // Don't do anything with this by default. + // It can optionally be overridden in the derived class. + } + + Ptr m_config; + std::ostream& stream; + + LazyStat currentTestRunInfo; + LazyStat currentGroupInfo; + LazyStat currentTestCaseInfo; + + std::vector m_sectionStack; + ReporterPreferences m_reporterPrefs; + }; + + struct CumulativeReporterBase : SharedImpl { + template + struct Node : SharedImpl<> { + explicit Node( T const& _value ) : value( _value ) {} + virtual ~Node() {} + + typedef std::vector > ChildNodes; + T value; + ChildNodes children; + }; + struct SectionNode : SharedImpl<> { + explicit SectionNode( SectionStats const& _stats ) : stats( _stats ) {} + virtual ~SectionNode(); + + bool operator == ( SectionNode const& other ) const { + return stats.sectionInfo.lineInfo == other.stats.sectionInfo.lineInfo; + } + bool operator == ( Ptr const& other ) const { + return operator==( *other ); + } + + SectionStats stats; + typedef std::vector > ChildSections; + typedef std::vector Assertions; + ChildSections childSections; + Assertions assertions; + std::string stdOut; + std::string stdErr; + }; + + struct BySectionInfo { + BySectionInfo( SectionInfo const& other ) : m_other( other ) {} + BySectionInfo( BySectionInfo const& other ) : m_other( other.m_other ) {} + bool operator() ( Ptr const& node ) const { + return node->stats.sectionInfo.lineInfo == m_other.lineInfo; + } + private: + void operator=( BySectionInfo const& ); + SectionInfo const& m_other; + }; + + typedef Node TestCaseNode; + typedef Node TestGroupNode; + typedef Node TestRunNode; + + CumulativeReporterBase( ReporterConfig const& _config ) + : m_config( _config.fullConfig() ), + stream( _config.stream() ) + { + m_reporterPrefs.shouldRedirectStdOut = false; + } + ~CumulativeReporterBase(); + + virtual ReporterPreferences getPreferences() const CATCH_OVERRIDE { + return m_reporterPrefs; + } + + virtual void testRunStarting( TestRunInfo const& ) CATCH_OVERRIDE {} + virtual void testGroupStarting( GroupInfo const& ) CATCH_OVERRIDE {} + + virtual void testCaseStarting( TestCaseInfo const& ) CATCH_OVERRIDE {} + + virtual void sectionStarting( SectionInfo const& sectionInfo ) CATCH_OVERRIDE { + SectionStats incompleteStats( sectionInfo, Counts(), 0, false ); + Ptr node; + if( m_sectionStack.empty() ) { + if( !m_rootSection ) + m_rootSection = new SectionNode( incompleteStats ); + node = m_rootSection; + } + else { + SectionNode& parentNode = *m_sectionStack.back(); + SectionNode::ChildSections::const_iterator it = + std::find_if( parentNode.childSections.begin(), + parentNode.childSections.end(), + BySectionInfo( sectionInfo ) ); + if( it == parentNode.childSections.end() ) { + node = new SectionNode( incompleteStats ); + parentNode.childSections.push_back( node ); + } + else + node = *it; + } + m_sectionStack.push_back( node ); + m_deepestSection = node; + } + + virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE {} + + virtual bool assertionEnded( AssertionStats const& assertionStats ) { + assert( !m_sectionStack.empty() ); + SectionNode& sectionNode = *m_sectionStack.back(); + sectionNode.assertions.push_back( assertionStats ); + return true; + } + virtual void sectionEnded( SectionStats const& sectionStats ) CATCH_OVERRIDE { + assert( !m_sectionStack.empty() ); + SectionNode& node = *m_sectionStack.back(); + node.stats = sectionStats; + m_sectionStack.pop_back(); + } + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE { + Ptr node = new TestCaseNode( testCaseStats ); + assert( m_sectionStack.size() == 0 ); + node->children.push_back( m_rootSection ); + m_testCases.push_back( node ); + m_rootSection.reset(); + + assert( m_deepestSection ); + m_deepestSection->stdOut = testCaseStats.stdOut; + m_deepestSection->stdErr = testCaseStats.stdErr; + } + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE { + Ptr node = new TestGroupNode( testGroupStats ); + node->children.swap( m_testCases ); + m_testGroups.push_back( node ); + } + virtual void testRunEnded( TestRunStats const& testRunStats ) CATCH_OVERRIDE { + Ptr node = new TestRunNode( testRunStats ); + node->children.swap( m_testGroups ); + m_testRuns.push_back( node ); + testRunEndedCumulative(); + } + virtual void testRunEndedCumulative() = 0; + + virtual void skipTest( TestCaseInfo const& ) CATCH_OVERRIDE {} + + Ptr m_config; + std::ostream& stream; + std::vector m_assertions; + std::vector > > m_sections; + std::vector > m_testCases; + std::vector > m_testGroups; + + std::vector > m_testRuns; + + Ptr m_rootSection; + Ptr m_deepestSection; + std::vector > m_sectionStack; + ReporterPreferences m_reporterPrefs; + + }; + + template + char const* getLineOfChars() { + static char line[CATCH_CONFIG_CONSOLE_WIDTH] = {0}; + if( !*line ) { + memset( line, C, CATCH_CONFIG_CONSOLE_WIDTH-1 ); + line[CATCH_CONFIG_CONSOLE_WIDTH-1] = 0; + } + return line; + } + + struct TestEventListenerBase : StreamingReporterBase { + TestEventListenerBase( ReporterConfig const& _config ) + : StreamingReporterBase( _config ) + {} + + virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE {} + virtual bool assertionEnded( AssertionStats const& ) CATCH_OVERRIDE { + return false; + } + }; + +} // end namespace Catch + +// #included from: ../internal/catch_reporter_registrars.hpp +#define TWOBLUECUBES_CATCH_REPORTER_REGISTRARS_HPP_INCLUDED + +namespace Catch { + + template + class LegacyReporterRegistrar { + + class ReporterFactory : public IReporterFactory { + virtual IStreamingReporter* create( ReporterConfig const& config ) const { + return new LegacyReporterAdapter( new T( config ) ); + } + + virtual std::string getDescription() const { + return T::getDescription(); + } + }; + + public: + + LegacyReporterRegistrar( std::string const& name ) { + getMutableRegistryHub().registerReporter( name, new ReporterFactory() ); + } + }; + + template + class ReporterRegistrar { + + class ReporterFactory : public SharedImpl { + + // *** Please Note ***: + // - If you end up here looking at a compiler error because it's trying to register + // your custom reporter class be aware that the native reporter interface has changed + // to IStreamingReporter. The "legacy" interface, IReporter, is still supported via + // an adapter. Just use REGISTER_LEGACY_REPORTER to take advantage of the adapter. + // However please consider updating to the new interface as the old one is now + // deprecated and will probably be removed quite soon! + // Please contact me via github if you have any questions at all about this. + // In fact, ideally, please contact me anyway to let me know you've hit this - as I have + // no idea who is actually using custom reporters at all (possibly no-one!). + // The new interface is designed to minimise exposure to interface changes in the future. + virtual IStreamingReporter* create( ReporterConfig const& config ) const { + return new T( config ); + } + + virtual std::string getDescription() const { + return T::getDescription(); + } + }; + + public: + + ReporterRegistrar( std::string const& name ) { + getMutableRegistryHub().registerReporter( name, new ReporterFactory() ); + } + }; + + template + class ListenerRegistrar { + + class ListenerFactory : public SharedImpl { + + virtual IStreamingReporter* create( ReporterConfig const& config ) const { + return new T( config ); + } + virtual std::string getDescription() const { + return ""; + } + }; + + public: + + ListenerRegistrar() { + getMutableRegistryHub().registerListener( new ListenerFactory() ); + } + }; +} + +#define INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) \ + namespace{ Catch::LegacyReporterRegistrar catch_internal_RegistrarFor##reporterType( name ); } + +#define INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) \ + namespace{ Catch::ReporterRegistrar catch_internal_RegistrarFor##reporterType( name ); } + +#define INTERNAL_CATCH_REGISTER_LISTENER( listenerType ) \ + namespace{ Catch::ListenerRegistrar catch_internal_RegistrarFor##listenerType; } + +// #included from: ../internal/catch_xmlwriter.hpp +#define TWOBLUECUBES_CATCH_XMLWRITER_HPP_INCLUDED + +#include +#include +#include +#include + +namespace Catch { + + class XmlEncode { + public: + enum ForWhat { ForTextNodes, ForAttributes }; + + XmlEncode( std::string const& str, ForWhat forWhat = ForTextNodes ) + : m_str( str ), + m_forWhat( forWhat ) + {} + + void encodeTo( std::ostream& os ) const { + + // Apostrophe escaping not necessary if we always use " to write attributes + // (see: http://www.w3.org/TR/xml/#syntax) + + for( std::size_t i = 0; i < m_str.size(); ++ i ) { + char c = m_str[i]; + switch( c ) { + case '<': os << "<"; break; + case '&': os << "&"; break; + + case '>': + // See: http://www.w3.org/TR/xml/#syntax + if( i > 2 && m_str[i-1] == ']' && m_str[i-2] == ']' ) + os << ">"; + else + os << c; + break; + + case '\"': + if( m_forWhat == ForAttributes ) + os << """; + else + os << c; + break; + + default: + // Escape control chars - based on contribution by @espenalb in PR #465 + if ( ( c < '\x09' ) || ( c > '\x0D' && c < '\x20') || c=='\x7F' ) + os << "&#x" << std::uppercase << std::hex << static_cast( c ); + else + os << c; + } + } + } + + friend std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ) { + xmlEncode.encodeTo( os ); + return os; + } + + private: + std::string m_str; + ForWhat m_forWhat; + }; + + class XmlWriter { + public: + + class ScopedElement { + public: + ScopedElement( XmlWriter* writer ) + : m_writer( writer ) + {} + + ScopedElement( ScopedElement const& other ) + : m_writer( other.m_writer ){ + other.m_writer = CATCH_NULL; + } + + ~ScopedElement() { + if( m_writer ) + m_writer->endElement(); + } + + ScopedElement& writeText( std::string const& text, bool indent = true ) { + m_writer->writeText( text, indent ); + return *this; + } + + template + ScopedElement& writeAttribute( std::string const& name, T const& attribute ) { + m_writer->writeAttribute( name, attribute ); + return *this; + } + + private: + mutable XmlWriter* m_writer; + }; + + XmlWriter() + : m_tagIsOpen( false ), + m_needsNewline( false ), + m_os( &Catch::cout() ) + {} + + XmlWriter( std::ostream& os ) + : m_tagIsOpen( false ), + m_needsNewline( false ), + m_os( &os ) + {} + + ~XmlWriter() { + while( !m_tags.empty() ) + endElement(); + } + + XmlWriter& startElement( std::string const& name ) { + ensureTagClosed(); + newlineIfNecessary(); + stream() << m_indent << "<" << name; + m_tags.push_back( name ); + m_indent += " "; + m_tagIsOpen = true; + return *this; + } + + ScopedElement scopedElement( std::string const& name ) { + ScopedElement scoped( this ); + startElement( name ); + return scoped; + } + + XmlWriter& endElement() { + newlineIfNecessary(); + m_indent = m_indent.substr( 0, m_indent.size()-2 ); + if( m_tagIsOpen ) { + stream() << "/>\n"; + m_tagIsOpen = false; + } + else { + stream() << m_indent << "\n"; + } + m_tags.pop_back(); + return *this; + } + + XmlWriter& writeAttribute( std::string const& name, std::string const& attribute ) { + if( !name.empty() && !attribute.empty() ) + stream() << " " << name << "=\"" << XmlEncode( attribute, XmlEncode::ForAttributes ) << "\""; + return *this; + } + + XmlWriter& writeAttribute( std::string const& name, bool attribute ) { + stream() << " " << name << "=\"" << ( attribute ? "true" : "false" ) << "\""; + return *this; + } + + template + XmlWriter& writeAttribute( std::string const& name, T const& attribute ) { + std::ostringstream oss; + oss << attribute; + return writeAttribute( name, oss.str() ); + } + + XmlWriter& writeText( std::string const& text, bool indent = true ) { + if( !text.empty() ){ + bool tagWasOpen = m_tagIsOpen; + ensureTagClosed(); + if( tagWasOpen && indent ) + stream() << m_indent; + stream() << XmlEncode( text ); + m_needsNewline = true; + } + return *this; + } + + XmlWriter& writeComment( std::string const& text ) { + ensureTagClosed(); + stream() << m_indent << ""; + m_needsNewline = true; + return *this; + } + + XmlWriter& writeBlankLine() { + ensureTagClosed(); + stream() << "\n"; + return *this; + } + + void setStream( std::ostream& os ) { + m_os = &os; + } + + private: + XmlWriter( XmlWriter const& ); + void operator=( XmlWriter const& ); + + std::ostream& stream() { + return *m_os; + } + + void ensureTagClosed() { + if( m_tagIsOpen ) { + stream() << ">\n"; + m_tagIsOpen = false; + } + } + + void newlineIfNecessary() { + if( m_needsNewline ) { + stream() << "\n"; + m_needsNewline = false; + } + } + + bool m_tagIsOpen; + bool m_needsNewline; + std::vector m_tags; + std::string m_indent; + std::ostream* m_os; + }; + +} +// #included from: catch_reenable_warnings.h + +#define TWOBLUECUBES_CATCH_REENABLE_WARNINGS_H_INCLUDED + +#ifdef __clang__ +# ifdef __ICC // icpc defines the __clang__ macro +# pragma warning(pop) +# else +# pragma clang diagnostic pop +# endif +#elif defined __GNUC__ +# pragma GCC diagnostic pop +#endif + + +namespace Catch { + class XmlReporter : public StreamingReporterBase { + public: + XmlReporter( ReporterConfig const& _config ) + : StreamingReporterBase( _config ), + m_sectionDepth( 0 ) + { + m_reporterPrefs.shouldRedirectStdOut = true; + } + + virtual ~XmlReporter() CATCH_OVERRIDE; + + static std::string getDescription() { + return "Reports test results as an XML document"; + } + + public: // StreamingReporterBase + + virtual void noMatchingTestCases( std::string const& s ) CATCH_OVERRIDE { + StreamingReporterBase::noMatchingTestCases( s ); + } + + virtual void testRunStarting( TestRunInfo const& testInfo ) CATCH_OVERRIDE { + StreamingReporterBase::testRunStarting( testInfo ); + m_xml.setStream( stream ); + m_xml.startElement( "Catch" ); + if( !m_config->name().empty() ) + m_xml.writeAttribute( "name", m_config->name() ); + } + + virtual void testGroupStarting( GroupInfo const& groupInfo ) CATCH_OVERRIDE { + StreamingReporterBase::testGroupStarting( groupInfo ); + m_xml.startElement( "Group" ) + .writeAttribute( "name", groupInfo.name ); + } + + virtual void testCaseStarting( TestCaseInfo const& testInfo ) CATCH_OVERRIDE { + StreamingReporterBase::testCaseStarting(testInfo); + m_xml.startElement( "TestCase" ).writeAttribute( "name", trim( testInfo.name ) ); + + if ( m_config->showDurations() == ShowDurations::Always ) + m_testCaseTimer.start(); + } + + virtual void sectionStarting( SectionInfo const& sectionInfo ) CATCH_OVERRIDE { + StreamingReporterBase::sectionStarting( sectionInfo ); + if( m_sectionDepth++ > 0 ) { + m_xml.startElement( "Section" ) + .writeAttribute( "name", trim( sectionInfo.name ) ) + .writeAttribute( "description", sectionInfo.description ); + } + } + + virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE { } + + virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE { + const AssertionResult& assertionResult = assertionStats.assertionResult; + + // Print any info messages in tags. + if( assertionStats.assertionResult.getResultType() != ResultWas::Ok ) { + for( std::vector::const_iterator it = assertionStats.infoMessages.begin(), itEnd = assertionStats.infoMessages.end(); + it != itEnd; + ++it ) { + if( it->type == ResultWas::Info ) { + m_xml.scopedElement( "Info" ) + .writeText( it->message ); + } else if ( it->type == ResultWas::Warning ) { + m_xml.scopedElement( "Warning" ) + .writeText( it->message ); + } + } + } + + // Drop out if result was successful but we're not printing them. + if( !m_config->includeSuccessfulResults() && isOk(assertionResult.getResultType()) ) + return true; + + // Print the expression if there is one. + if( assertionResult.hasExpression() ) { + m_xml.startElement( "Expression" ) + .writeAttribute( "success", assertionResult.succeeded() ) + .writeAttribute( "type", assertionResult.getTestMacroName() ) + .writeAttribute( "filename", assertionResult.getSourceInfo().file ) + .writeAttribute( "line", assertionResult.getSourceInfo().line ); + + m_xml.scopedElement( "Original" ) + .writeText( assertionResult.getExpression() ); + m_xml.scopedElement( "Expanded" ) + .writeText( assertionResult.getExpandedExpression() ); + } + + // And... Print a result applicable to each result type. + switch( assertionResult.getResultType() ) { + case ResultWas::ThrewException: + m_xml.scopedElement( "Exception" ) + .writeAttribute( "filename", assertionResult.getSourceInfo().file ) + .writeAttribute( "line", assertionResult.getSourceInfo().line ) + .writeText( assertionResult.getMessage() ); + break; + case ResultWas::FatalErrorCondition: + m_xml.scopedElement( "Fatal Error Condition" ) + .writeAttribute( "filename", assertionResult.getSourceInfo().file ) + .writeAttribute( "line", assertionResult.getSourceInfo().line ) + .writeText( assertionResult.getMessage() ); + break; + case ResultWas::Info: + m_xml.scopedElement( "Info" ) + .writeText( assertionResult.getMessage() ); + break; + case ResultWas::Warning: + // Warning will already have been written + break; + case ResultWas::ExplicitFailure: + m_xml.scopedElement( "Failure" ) + .writeText( assertionResult.getMessage() ); + break; + default: + break; + } + + if( assertionResult.hasExpression() ) + m_xml.endElement(); + + return true; + } + + virtual void sectionEnded( SectionStats const& sectionStats ) CATCH_OVERRIDE { + StreamingReporterBase::sectionEnded( sectionStats ); + if( --m_sectionDepth > 0 ) { + XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResults" ); + e.writeAttribute( "successes", sectionStats.assertions.passed ); + e.writeAttribute( "failures", sectionStats.assertions.failed ); + e.writeAttribute( "expectedFailures", sectionStats.assertions.failedButOk ); + + if ( m_config->showDurations() == ShowDurations::Always ) + e.writeAttribute( "durationInSeconds", sectionStats.durationInSeconds ); + + m_xml.endElement(); + } + } + + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE { + StreamingReporterBase::testCaseEnded( testCaseStats ); + XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResult" ); + e.writeAttribute( "success", testCaseStats.totals.assertions.allOk() ); + + if ( m_config->showDurations() == ShowDurations::Always ) + e.writeAttribute( "durationInSeconds", m_testCaseTimer.getElapsedSeconds() ); + + m_xml.endElement(); + } + + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE { + StreamingReporterBase::testGroupEnded( testGroupStats ); + // TODO: Check testGroupStats.aborting and act accordingly. + m_xml.scopedElement( "OverallResults" ) + .writeAttribute( "successes", testGroupStats.totals.assertions.passed ) + .writeAttribute( "failures", testGroupStats.totals.assertions.failed ) + .writeAttribute( "expectedFailures", testGroupStats.totals.assertions.failedButOk ); + m_xml.endElement(); + } + + virtual void testRunEnded( TestRunStats const& testRunStats ) CATCH_OVERRIDE { + StreamingReporterBase::testRunEnded( testRunStats ); + m_xml.scopedElement( "OverallResults" ) + .writeAttribute( "successes", testRunStats.totals.assertions.passed ) + .writeAttribute( "failures", testRunStats.totals.assertions.failed ) + .writeAttribute( "expectedFailures", testRunStats.totals.assertions.failedButOk ); + m_xml.endElement(); + } + + private: + Timer m_testCaseTimer; + XmlWriter m_xml; + int m_sectionDepth; + }; + + INTERNAL_CATCH_REGISTER_REPORTER( "xml", XmlReporter ) + +} // end namespace Catch + +// #included from: ../reporters/catch_reporter_junit.hpp +#define TWOBLUECUBES_CATCH_REPORTER_JUNIT_HPP_INCLUDED + +#include + +namespace Catch { + + class JunitReporter : public CumulativeReporterBase { + public: + JunitReporter( ReporterConfig const& _config ) + : CumulativeReporterBase( _config ), + xml( _config.stream() ) + { + m_reporterPrefs.shouldRedirectStdOut = true; + } + + virtual ~JunitReporter() CATCH_OVERRIDE; + + static std::string getDescription() { + return "Reports test results in an XML format that looks like Ant's junitreport target"; + } + + virtual void noMatchingTestCases( std::string const& /*spec*/ ) CATCH_OVERRIDE {} + + virtual void testRunStarting( TestRunInfo const& runInfo ) CATCH_OVERRIDE { + CumulativeReporterBase::testRunStarting( runInfo ); + xml.startElement( "testsuites" ); + } + + virtual void testGroupStarting( GroupInfo const& groupInfo ) CATCH_OVERRIDE { + suiteTimer.start(); + stdOutForSuite.str(""); + stdErrForSuite.str(""); + unexpectedExceptions = 0; + CumulativeReporterBase::testGroupStarting( groupInfo ); + } + + virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE { + if( assertionStats.assertionResult.getResultType() == ResultWas::ThrewException ) + unexpectedExceptions++; + return CumulativeReporterBase::assertionEnded( assertionStats ); + } + + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE { + stdOutForSuite << testCaseStats.stdOut; + stdErrForSuite << testCaseStats.stdErr; + CumulativeReporterBase::testCaseEnded( testCaseStats ); + } + + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE { + double suiteTime = suiteTimer.getElapsedSeconds(); + CumulativeReporterBase::testGroupEnded( testGroupStats ); + writeGroup( *m_testGroups.back(), suiteTime ); + } + + virtual void testRunEndedCumulative() CATCH_OVERRIDE { + xml.endElement(); + } + + void writeGroup( TestGroupNode const& groupNode, double suiteTime ) { + XmlWriter::ScopedElement e = xml.scopedElement( "testsuite" ); + TestGroupStats const& stats = groupNode.value; + xml.writeAttribute( "name", stats.groupInfo.name ); + xml.writeAttribute( "errors", unexpectedExceptions ); + xml.writeAttribute( "failures", stats.totals.assertions.failed-unexpectedExceptions ); + xml.writeAttribute( "tests", stats.totals.assertions.total() ); + xml.writeAttribute( "hostname", "tbd" ); // !TBD + if( m_config->showDurations() == ShowDurations::Never ) + xml.writeAttribute( "time", "" ); + else + xml.writeAttribute( "time", suiteTime ); + xml.writeAttribute( "timestamp", "tbd" ); // !TBD + + // Write test cases + for( TestGroupNode::ChildNodes::const_iterator + it = groupNode.children.begin(), itEnd = groupNode.children.end(); + it != itEnd; + ++it ) + writeTestCase( **it ); + + xml.scopedElement( "system-out" ).writeText( trim( stdOutForSuite.str() ), false ); + xml.scopedElement( "system-err" ).writeText( trim( stdErrForSuite.str() ), false ); + } + + void writeTestCase( TestCaseNode const& testCaseNode ) { + TestCaseStats const& stats = testCaseNode.value; + + // All test cases have exactly one section - which represents the + // test case itself. That section may have 0-n nested sections + assert( testCaseNode.children.size() == 1 ); + SectionNode const& rootSection = *testCaseNode.children.front(); + + std::string className = stats.testInfo.className; + + if( className.empty() ) { + if( rootSection.childSections.empty() ) + className = "global"; + } + writeSection( className, "", rootSection ); + } + + void writeSection( std::string const& className, + std::string const& rootName, + SectionNode const& sectionNode ) { + std::string name = trim( sectionNode.stats.sectionInfo.name ); + if( !rootName.empty() ) + name = rootName + "/" + name; + + if( !sectionNode.assertions.empty() || + !sectionNode.stdOut.empty() || + !sectionNode.stdErr.empty() ) { + XmlWriter::ScopedElement e = xml.scopedElement( "testcase" ); + if( className.empty() ) { + xml.writeAttribute( "classname", name ); + xml.writeAttribute( "name", "root" ); + } + else { + xml.writeAttribute( "classname", className ); + xml.writeAttribute( "name", name ); + } + xml.writeAttribute( "time", Catch::toString( sectionNode.stats.durationInSeconds ) ); + + writeAssertions( sectionNode ); + + if( !sectionNode.stdOut.empty() ) + xml.scopedElement( "system-out" ).writeText( trim( sectionNode.stdOut ), false ); + if( !sectionNode.stdErr.empty() ) + xml.scopedElement( "system-err" ).writeText( trim( sectionNode.stdErr ), false ); + } + for( SectionNode::ChildSections::const_iterator + it = sectionNode.childSections.begin(), + itEnd = sectionNode.childSections.end(); + it != itEnd; + ++it ) + if( className.empty() ) + writeSection( name, "", **it ); + else + writeSection( className, name, **it ); + } + + void writeAssertions( SectionNode const& sectionNode ) { + for( SectionNode::Assertions::const_iterator + it = sectionNode.assertions.begin(), itEnd = sectionNode.assertions.end(); + it != itEnd; + ++it ) + writeAssertion( *it ); + } + void writeAssertion( AssertionStats const& stats ) { + AssertionResult const& result = stats.assertionResult; + if( !result.isOk() ) { + std::string elementName; + switch( result.getResultType() ) { + case ResultWas::ThrewException: + case ResultWas::FatalErrorCondition: + elementName = "error"; + break; + case ResultWas::ExplicitFailure: + elementName = "failure"; + break; + case ResultWas::ExpressionFailed: + elementName = "failure"; + break; + case ResultWas::DidntThrowException: + elementName = "failure"; + break; + + // We should never see these here: + case ResultWas::Info: + case ResultWas::Warning: + case ResultWas::Ok: + case ResultWas::Unknown: + case ResultWas::FailureBit: + case ResultWas::Exception: + elementName = "internalError"; + break; + } + + XmlWriter::ScopedElement e = xml.scopedElement( elementName ); + + xml.writeAttribute( "message", result.getExpandedExpression() ); + xml.writeAttribute( "type", result.getTestMacroName() ); + + std::ostringstream oss; + if( !result.getMessage().empty() ) + oss << result.getMessage() << "\n"; + for( std::vector::const_iterator + it = stats.infoMessages.begin(), + itEnd = stats.infoMessages.end(); + it != itEnd; + ++it ) + if( it->type == ResultWas::Info ) + oss << it->message << "\n"; + + oss << "at " << result.getSourceInfo(); + xml.writeText( oss.str(), false ); + } + } + + XmlWriter xml; + Timer suiteTimer; + std::ostringstream stdOutForSuite; + std::ostringstream stdErrForSuite; + unsigned int unexpectedExceptions; + }; + + INTERNAL_CATCH_REGISTER_REPORTER( "junit", JunitReporter ) + +} // end namespace Catch + +// #included from: ../reporters/catch_reporter_console.hpp +#define TWOBLUECUBES_CATCH_REPORTER_CONSOLE_HPP_INCLUDED + +namespace Catch { + + struct ConsoleReporter : StreamingReporterBase { + ConsoleReporter( ReporterConfig const& _config ) + : StreamingReporterBase( _config ), + m_headerPrinted( false ) + {} + + virtual ~ConsoleReporter() CATCH_OVERRIDE; + static std::string getDescription() { + return "Reports test results as plain lines of text"; + } + + virtual void noMatchingTestCases( std::string const& spec ) CATCH_OVERRIDE { + stream << "No test cases matched '" << spec << "'" << std::endl; + } + + virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE { + } + + virtual bool assertionEnded( AssertionStats const& _assertionStats ) CATCH_OVERRIDE { + AssertionResult const& result = _assertionStats.assertionResult; + + bool printInfoMessages = true; + + // Drop out if result was successful and we're not printing those + if( !m_config->includeSuccessfulResults() && result.isOk() ) { + if( result.getResultType() != ResultWas::Warning ) + return false; + printInfoMessages = false; + } + + lazyPrint(); + + AssertionPrinter printer( stream, _assertionStats, printInfoMessages ); + printer.print(); + stream << std::endl; + return true; + } + + virtual void sectionStarting( SectionInfo const& _sectionInfo ) CATCH_OVERRIDE { + m_headerPrinted = false; + StreamingReporterBase::sectionStarting( _sectionInfo ); + } + virtual void sectionEnded( SectionStats const& _sectionStats ) CATCH_OVERRIDE { + if( _sectionStats.missingAssertions ) { + lazyPrint(); + Colour colour( Colour::ResultError ); + if( m_sectionStack.size() > 1 ) + stream << "\nNo assertions in section"; + else + stream << "\nNo assertions in test case"; + stream << " '" << _sectionStats.sectionInfo.name << "'\n" << std::endl; + } + if( m_headerPrinted ) { + if( m_config->showDurations() == ShowDurations::Always ) + stream << "Completed in " << _sectionStats.durationInSeconds << "s" << std::endl; + m_headerPrinted = false; + } + else { + if( m_config->showDurations() == ShowDurations::Always ) + stream << _sectionStats.sectionInfo.name << " completed in " << _sectionStats.durationInSeconds << "s" << std::endl; + } + StreamingReporterBase::sectionEnded( _sectionStats ); + } + + virtual void testCaseEnded( TestCaseStats const& _testCaseStats ) CATCH_OVERRIDE { + StreamingReporterBase::testCaseEnded( _testCaseStats ); + m_headerPrinted = false; + } + virtual void testGroupEnded( TestGroupStats const& _testGroupStats ) CATCH_OVERRIDE { + if( currentGroupInfo.used ) { + printSummaryDivider(); + stream << "Summary for group '" << _testGroupStats.groupInfo.name << "':\n"; + printTotals( _testGroupStats.totals ); + stream << "\n" << std::endl; + } + StreamingReporterBase::testGroupEnded( _testGroupStats ); + } + virtual void testRunEnded( TestRunStats const& _testRunStats ) CATCH_OVERRIDE { + printTotalsDivider( _testRunStats.totals ); + printTotals( _testRunStats.totals ); + stream << std::endl; + StreamingReporterBase::testRunEnded( _testRunStats ); + } + + private: + + class AssertionPrinter { + void operator= ( AssertionPrinter const& ); + public: + AssertionPrinter( std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages ) + : stream( _stream ), + stats( _stats ), + result( _stats.assertionResult ), + colour( Colour::None ), + message( result.getMessage() ), + messages( _stats.infoMessages ), + printInfoMessages( _printInfoMessages ) + { + switch( result.getResultType() ) { + case ResultWas::Ok: + colour = Colour::Success; + passOrFail = "PASSED"; + //if( result.hasMessage() ) + if( _stats.infoMessages.size() == 1 ) + messageLabel = "with message"; + if( _stats.infoMessages.size() > 1 ) + messageLabel = "with messages"; + break; + case ResultWas::ExpressionFailed: + if( result.isOk() ) { + colour = Colour::Success; + passOrFail = "FAILED - but was ok"; + } + else { + colour = Colour::Error; + passOrFail = "FAILED"; + } + if( _stats.infoMessages.size() == 1 ) + messageLabel = "with message"; + if( _stats.infoMessages.size() > 1 ) + messageLabel = "with messages"; + break; + case ResultWas::ThrewException: + colour = Colour::Error; + passOrFail = "FAILED"; + messageLabel = "due to unexpected exception with message"; + break; + case ResultWas::FatalErrorCondition: + colour = Colour::Error; + passOrFail = "FAILED"; + messageLabel = "due to a fatal error condition"; + break; + case ResultWas::DidntThrowException: + colour = Colour::Error; + passOrFail = "FAILED"; + messageLabel = "because no exception was thrown where one was expected"; + break; + case ResultWas::Info: + messageLabel = "info"; + break; + case ResultWas::Warning: + messageLabel = "warning"; + break; + case ResultWas::ExplicitFailure: + passOrFail = "FAILED"; + colour = Colour::Error; + if( _stats.infoMessages.size() == 1 ) + messageLabel = "explicitly with message"; + if( _stats.infoMessages.size() > 1 ) + messageLabel = "explicitly with messages"; + break; + // These cases are here to prevent compiler warnings + case ResultWas::Unknown: + case ResultWas::FailureBit: + case ResultWas::Exception: + passOrFail = "** internal error **"; + colour = Colour::Error; + break; + } + } + + void print() const { + printSourceInfo(); + if( stats.totals.assertions.total() > 0 ) { + if( result.isOk() ) + stream << "\n"; + printResultType(); + printOriginalExpression(); + printReconstructedExpression(); + } + else { + stream << "\n"; + } + printMessage(); + } + + private: + void printResultType() const { + if( !passOrFail.empty() ) { + Colour colourGuard( colour ); + stream << passOrFail << ":\n"; + } + } + void printOriginalExpression() const { + if( result.hasExpression() ) { + Colour colourGuard( Colour::OriginalExpression ); + stream << " "; + stream << result.getExpressionInMacro(); + stream << "\n"; + } + } + void printReconstructedExpression() const { + if( result.hasExpandedExpression() ) { + stream << "with expansion:\n"; + Colour colourGuard( Colour::ReconstructedExpression ); + stream << Text( result.getExpandedExpression(), TextAttributes().setIndent(2) ) << "\n"; + } + } + void printMessage() const { + if( !messageLabel.empty() ) + stream << messageLabel << ":" << "\n"; + for( std::vector::const_iterator it = messages.begin(), itEnd = messages.end(); + it != itEnd; + ++it ) { + // If this assertion is a warning ignore any INFO messages + if( printInfoMessages || it->type != ResultWas::Info ) + stream << Text( it->message, TextAttributes().setIndent(2) ) << "\n"; + } + } + void printSourceInfo() const { + Colour colourGuard( Colour::FileName ); + stream << result.getSourceInfo() << ": "; + } + + std::ostream& stream; + AssertionStats const& stats; + AssertionResult const& result; + Colour::Code colour; + std::string passOrFail; + std::string messageLabel; + std::string message; + std::vector messages; + bool printInfoMessages; + }; + + void lazyPrint() { + + if( !currentTestRunInfo.used ) + lazyPrintRunInfo(); + if( !currentGroupInfo.used ) + lazyPrintGroupInfo(); + + if( !m_headerPrinted ) { + printTestCaseAndSectionHeader(); + m_headerPrinted = true; + } + } + void lazyPrintRunInfo() { + stream << "\n" << getLineOfChars<'~'>() << "\n"; + Colour colour( Colour::SecondaryText ); + stream << currentTestRunInfo->name + << " is a Catch v" << libraryVersion << " host application.\n" + << "Run with -? for options\n\n"; + + if( m_config->rngSeed() != 0 ) + stream << "Randomness seeded to: " << m_config->rngSeed() << "\n\n"; + + currentTestRunInfo.used = true; + } + void lazyPrintGroupInfo() { + if( !currentGroupInfo->name.empty() && currentGroupInfo->groupsCounts > 1 ) { + printClosedHeader( "Group: " + currentGroupInfo->name ); + currentGroupInfo.used = true; + } + } + void printTestCaseAndSectionHeader() { + assert( !m_sectionStack.empty() ); + printOpenHeader( currentTestCaseInfo->name ); + + if( m_sectionStack.size() > 1 ) { + Colour colourGuard( Colour::Headers ); + + std::vector::const_iterator + it = m_sectionStack.begin()+1, // Skip first section (test case) + itEnd = m_sectionStack.end(); + for( ; it != itEnd; ++it ) + printHeaderString( it->name, 2 ); + } + + SourceLineInfo lineInfo = m_sectionStack.front().lineInfo; + + if( !lineInfo.empty() ){ + stream << getLineOfChars<'-'>() << "\n"; + Colour colourGuard( Colour::FileName ); + stream << lineInfo << "\n"; + } + stream << getLineOfChars<'.'>() << "\n" << std::endl; + } + + void printClosedHeader( std::string const& _name ) { + printOpenHeader( _name ); + stream << getLineOfChars<'.'>() << "\n"; + } + void printOpenHeader( std::string const& _name ) { + stream << getLineOfChars<'-'>() << "\n"; + { + Colour colourGuard( Colour::Headers ); + printHeaderString( _name ); + } + } + + // if string has a : in first line will set indent to follow it on + // subsequent lines + void printHeaderString( std::string const& _string, std::size_t indent = 0 ) { + std::size_t i = _string.find( ": " ); + if( i != std::string::npos ) + i+=2; + else + i = 0; + stream << Text( _string, TextAttributes() + .setIndent( indent+i) + .setInitialIndent( indent ) ) << "\n"; + } + + struct SummaryColumn { + + SummaryColumn( std::string const& _label, Colour::Code _colour ) + : label( _label ), + colour( _colour ) + {} + SummaryColumn addRow( std::size_t count ) { + std::ostringstream oss; + oss << count; + std::string row = oss.str(); + for( std::vector::iterator it = rows.begin(); it != rows.end(); ++it ) { + while( it->size() < row.size() ) + *it = " " + *it; + while( it->size() > row.size() ) + row = " " + row; + } + rows.push_back( row ); + return *this; + } + + std::string label; + Colour::Code colour; + std::vector rows; + + }; + + void printTotals( Totals const& totals ) { + if( totals.testCases.total() == 0 ) { + stream << Colour( Colour::Warning ) << "No tests ran\n"; + } + else if( totals.assertions.total() > 0 && totals.assertions.allPassed() ) { + stream << Colour( Colour::ResultSuccess ) << "All tests passed"; + stream << " (" + << pluralise( totals.assertions.passed, "assertion" ) << " in " + << pluralise( totals.testCases.passed, "test case" ) << ")" + << "\n"; + } + else { + + std::vector columns; + columns.push_back( SummaryColumn( "", Colour::None ) + .addRow( totals.testCases.total() ) + .addRow( totals.assertions.total() ) ); + columns.push_back( SummaryColumn( "passed", Colour::Success ) + .addRow( totals.testCases.passed ) + .addRow( totals.assertions.passed ) ); + columns.push_back( SummaryColumn( "failed", Colour::ResultError ) + .addRow( totals.testCases.failed ) + .addRow( totals.assertions.failed ) ); + columns.push_back( SummaryColumn( "failed as expected", Colour::ResultExpectedFailure ) + .addRow( totals.testCases.failedButOk ) + .addRow( totals.assertions.failedButOk ) ); + + printSummaryRow( "test cases", columns, 0 ); + printSummaryRow( "assertions", columns, 1 ); + } + } + void printSummaryRow( std::string const& label, std::vector const& cols, std::size_t row ) { + for( std::vector::const_iterator it = cols.begin(); it != cols.end(); ++it ) { + std::string value = it->rows[row]; + if( it->label.empty() ) { + stream << label << ": "; + if( value != "0" ) + stream << value; + else + stream << Colour( Colour::Warning ) << "- none -"; + } + else if( value != "0" ) { + stream << Colour( Colour::LightGrey ) << " | "; + stream << Colour( it->colour ) + << value << " " << it->label; + } + } + stream << "\n"; + } + + static std::size_t makeRatio( std::size_t number, std::size_t total ) { + std::size_t ratio = total > 0 ? CATCH_CONFIG_CONSOLE_WIDTH * number/ total : 0; + return ( ratio == 0 && number > 0 ) ? 1 : ratio; + } + static std::size_t& findMax( std::size_t& i, std::size_t& j, std::size_t& k ) { + if( i > j && i > k ) + return i; + else if( j > k ) + return j; + else + return k; + } + + void printTotalsDivider( Totals const& totals ) { + if( totals.testCases.total() > 0 ) { + std::size_t failedRatio = makeRatio( totals.testCases.failed, totals.testCases.total() ); + std::size_t failedButOkRatio = makeRatio( totals.testCases.failedButOk, totals.testCases.total() ); + std::size_t passedRatio = makeRatio( totals.testCases.passed, totals.testCases.total() ); + while( failedRatio + failedButOkRatio + passedRatio < CATCH_CONFIG_CONSOLE_WIDTH-1 ) + findMax( failedRatio, failedButOkRatio, passedRatio )++; + while( failedRatio + failedButOkRatio + passedRatio > CATCH_CONFIG_CONSOLE_WIDTH-1 ) + findMax( failedRatio, failedButOkRatio, passedRatio )--; + + stream << Colour( Colour::Error ) << std::string( failedRatio, '=' ); + stream << Colour( Colour::ResultExpectedFailure ) << std::string( failedButOkRatio, '=' ); + if( totals.testCases.allPassed() ) + stream << Colour( Colour::ResultSuccess ) << std::string( passedRatio, '=' ); + else + stream << Colour( Colour::Success ) << std::string( passedRatio, '=' ); + } + else { + stream << Colour( Colour::Warning ) << std::string( CATCH_CONFIG_CONSOLE_WIDTH-1, '=' ); + } + stream << "\n"; + } + void printSummaryDivider() { + stream << getLineOfChars<'-'>() << "\n"; + } + + private: + bool m_headerPrinted; + }; + + INTERNAL_CATCH_REGISTER_REPORTER( "console", ConsoleReporter ) + +} // end namespace Catch + +// #included from: ../reporters/catch_reporter_compact.hpp +#define TWOBLUECUBES_CATCH_REPORTER_COMPACT_HPP_INCLUDED + +namespace Catch { + + struct CompactReporter : StreamingReporterBase { + + CompactReporter( ReporterConfig const& _config ) + : StreamingReporterBase( _config ) + {} + + virtual ~CompactReporter(); + + static std::string getDescription() { + return "Reports test results on a single line, suitable for IDEs"; + } + + virtual ReporterPreferences getPreferences() const { + ReporterPreferences prefs; + prefs.shouldRedirectStdOut = false; + return prefs; + } + + virtual void noMatchingTestCases( std::string const& spec ) { + stream << "No test cases matched '" << spec << "'" << std::endl; + } + + virtual void assertionStarting( AssertionInfo const& ) { + } + + virtual bool assertionEnded( AssertionStats const& _assertionStats ) { + AssertionResult const& result = _assertionStats.assertionResult; + + bool printInfoMessages = true; + + // Drop out if result was successful and we're not printing those + if( !m_config->includeSuccessfulResults() && result.isOk() ) { + if( result.getResultType() != ResultWas::Warning ) + return false; + printInfoMessages = false; + } + + AssertionPrinter printer( stream, _assertionStats, printInfoMessages ); + printer.print(); + + stream << std::endl; + return true; + } + + virtual void testRunEnded( TestRunStats const& _testRunStats ) { + printTotals( _testRunStats.totals ); + stream << "\n" << std::endl; + StreamingReporterBase::testRunEnded( _testRunStats ); + } + + private: + class AssertionPrinter { + void operator= ( AssertionPrinter const& ); + public: + AssertionPrinter( std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages ) + : stream( _stream ) + , stats( _stats ) + , result( _stats.assertionResult ) + , messages( _stats.infoMessages ) + , itMessage( _stats.infoMessages.begin() ) + , printInfoMessages( _printInfoMessages ) + {} + + void print() { + printSourceInfo(); + + itMessage = messages.begin(); + + switch( result.getResultType() ) { + case ResultWas::Ok: + printResultType( Colour::ResultSuccess, passedString() ); + printOriginalExpression(); + printReconstructedExpression(); + if ( ! result.hasExpression() ) + printRemainingMessages( Colour::None ); + else + printRemainingMessages(); + break; + case ResultWas::ExpressionFailed: + if( result.isOk() ) + printResultType( Colour::ResultSuccess, failedString() + std::string( " - but was ok" ) ); + else + printResultType( Colour::Error, failedString() ); + printOriginalExpression(); + printReconstructedExpression(); + printRemainingMessages(); + break; + case ResultWas::ThrewException: + printResultType( Colour::Error, failedString() ); + printIssue( "unexpected exception with message:" ); + printMessage(); + printExpressionWas(); + printRemainingMessages(); + break; + case ResultWas::FatalErrorCondition: + printResultType( Colour::Error, failedString() ); + printIssue( "fatal error condition with message:" ); + printMessage(); + printExpressionWas(); + printRemainingMessages(); + break; + case ResultWas::DidntThrowException: + printResultType( Colour::Error, failedString() ); + printIssue( "expected exception, got none" ); + printExpressionWas(); + printRemainingMessages(); + break; + case ResultWas::Info: + printResultType( Colour::None, "info" ); + printMessage(); + printRemainingMessages(); + break; + case ResultWas::Warning: + printResultType( Colour::None, "warning" ); + printMessage(); + printRemainingMessages(); + break; + case ResultWas::ExplicitFailure: + printResultType( Colour::Error, failedString() ); + printIssue( "explicitly" ); + printRemainingMessages( Colour::None ); + break; + // These cases are here to prevent compiler warnings + case ResultWas::Unknown: + case ResultWas::FailureBit: + case ResultWas::Exception: + printResultType( Colour::Error, "** internal error **" ); + break; + } + } + + private: + // Colour::LightGrey + + static Colour::Code dimColour() { return Colour::FileName; } + +#ifdef CATCH_PLATFORM_MAC + static const char* failedString() { return "FAILED"; } + static const char* passedString() { return "PASSED"; } +#else + static const char* failedString() { return "failed"; } + static const char* passedString() { return "passed"; } +#endif + + void printSourceInfo() const { + Colour colourGuard( Colour::FileName ); + stream << result.getSourceInfo() << ":"; + } + + void printResultType( Colour::Code colour, std::string passOrFail ) const { + if( !passOrFail.empty() ) { + { + Colour colourGuard( colour ); + stream << " " << passOrFail; + } + stream << ":"; + } + } + + void printIssue( std::string issue ) const { + stream << " " << issue; + } + + void printExpressionWas() { + if( result.hasExpression() ) { + stream << ";"; + { + Colour colour( dimColour() ); + stream << " expression was:"; + } + printOriginalExpression(); + } + } + + void printOriginalExpression() const { + if( result.hasExpression() ) { + stream << " " << result.getExpression(); + } + } + + void printReconstructedExpression() const { + if( result.hasExpandedExpression() ) { + { + Colour colour( dimColour() ); + stream << " for: "; + } + stream << result.getExpandedExpression(); + } + } + + void printMessage() { + if ( itMessage != messages.end() ) { + stream << " '" << itMessage->message << "'"; + ++itMessage; + } + } + + void printRemainingMessages( Colour::Code colour = dimColour() ) { + if ( itMessage == messages.end() ) + return; + + // using messages.end() directly yields compilation error: + std::vector::const_iterator itEnd = messages.end(); + const std::size_t N = static_cast( std::distance( itMessage, itEnd ) ); + + { + Colour colourGuard( colour ); + stream << " with " << pluralise( N, "message" ) << ":"; + } + + for(; itMessage != itEnd; ) { + // If this assertion is a warning ignore any INFO messages + if( printInfoMessages || itMessage->type != ResultWas::Info ) { + stream << " '" << itMessage->message << "'"; + if ( ++itMessage != itEnd ) { + Colour colourGuard( dimColour() ); + stream << " and"; + } + } + } + } + + private: + std::ostream& stream; + AssertionStats const& stats; + AssertionResult const& result; + std::vector messages; + std::vector::const_iterator itMessage; + bool printInfoMessages; + }; + + // Colour, message variants: + // - white: No tests ran. + // - red: Failed [both/all] N test cases, failed [both/all] M assertions. + // - white: Passed [both/all] N test cases (no assertions). + // - red: Failed N tests cases, failed M assertions. + // - green: Passed [both/all] N tests cases with M assertions. + + std::string bothOrAll( std::size_t count ) const { + return count == 1 ? "" : count == 2 ? "both " : "all " ; + } + + void printTotals( const Totals& totals ) const { + if( totals.testCases.total() == 0 ) { + stream << "No tests ran."; + } + else if( totals.testCases.failed == totals.testCases.total() ) { + Colour colour( Colour::ResultError ); + const std::string qualify_assertions_failed = + totals.assertions.failed == totals.assertions.total() ? + bothOrAll( totals.assertions.failed ) : ""; + stream << + "Failed " << bothOrAll( totals.testCases.failed ) + << pluralise( totals.testCases.failed, "test case" ) << ", " + "failed " << qualify_assertions_failed << + pluralise( totals.assertions.failed, "assertion" ) << "."; + } + else if( totals.assertions.total() == 0 ) { + stream << + "Passed " << bothOrAll( totals.testCases.total() ) + << pluralise( totals.testCases.total(), "test case" ) + << " (no assertions)."; + } + else if( totals.assertions.failed ) { + Colour colour( Colour::ResultError ); + stream << + "Failed " << pluralise( totals.testCases.failed, "test case" ) << ", " + "failed " << pluralise( totals.assertions.failed, "assertion" ) << "."; + } + else { + Colour colour( Colour::ResultSuccess ); + stream << + "Passed " << bothOrAll( totals.testCases.passed ) + << pluralise( totals.testCases.passed, "test case" ) << + " with " << pluralise( totals.assertions.passed, "assertion" ) << "."; + } + } + }; + + INTERNAL_CATCH_REGISTER_REPORTER( "compact", CompactReporter ) + +} // end namespace Catch + +namespace Catch { + // These are all here to avoid warnings about not having any out of line + // virtual methods + NonCopyable::~NonCopyable() {} + IShared::~IShared() {} + IStream::~IStream() CATCH_NOEXCEPT {} + FileStream::~FileStream() CATCH_NOEXCEPT {} + CoutStream::~CoutStream() CATCH_NOEXCEPT {} + DebugOutStream::~DebugOutStream() CATCH_NOEXCEPT {} + StreamBufBase::~StreamBufBase() CATCH_NOEXCEPT {} + IContext::~IContext() {} + IResultCapture::~IResultCapture() {} + ITestCase::~ITestCase() {} + ITestCaseRegistry::~ITestCaseRegistry() {} + IRegistryHub::~IRegistryHub() {} + IMutableRegistryHub::~IMutableRegistryHub() {} + IExceptionTranslator::~IExceptionTranslator() {} + IExceptionTranslatorRegistry::~IExceptionTranslatorRegistry() {} + IReporter::~IReporter() {} + IReporterFactory::~IReporterFactory() {} + IReporterRegistry::~IReporterRegistry() {} + IStreamingReporter::~IStreamingReporter() {} + AssertionStats::~AssertionStats() {} + SectionStats::~SectionStats() {} + TestCaseStats::~TestCaseStats() {} + TestGroupStats::~TestGroupStats() {} + TestRunStats::~TestRunStats() {} + CumulativeReporterBase::SectionNode::~SectionNode() {} + CumulativeReporterBase::~CumulativeReporterBase() {} + + StreamingReporterBase::~StreamingReporterBase() {} + ConsoleReporter::~ConsoleReporter() {} + CompactReporter::~CompactReporter() {} + IRunner::~IRunner() {} + IMutableContext::~IMutableContext() {} + IConfig::~IConfig() {} + XmlReporter::~XmlReporter() {} + JunitReporter::~JunitReporter() {} + TestRegistry::~TestRegistry() {} + FreeFunctionTestCase::~FreeFunctionTestCase() {} + IGeneratorInfo::~IGeneratorInfo() {} + IGeneratorsForTest::~IGeneratorsForTest() {} + WildcardPattern::~WildcardPattern() {} + TestSpec::Pattern::~Pattern() {} + TestSpec::NamePattern::~NamePattern() {} + TestSpec::TagPattern::~TagPattern() {} + TestSpec::ExcludedPattern::~ExcludedPattern() {} + + Matchers::Impl::StdString::Equals::~Equals() {} + Matchers::Impl::StdString::Contains::~Contains() {} + Matchers::Impl::StdString::StartsWith::~StartsWith() {} + Matchers::Impl::StdString::EndsWith::~EndsWith() {} + + void Config::dummy() {} + + namespace TestCaseTracking { + ITracker::~ITracker() {} + TrackerBase::~TrackerBase() {} + SectionTracker::~SectionTracker() {} + IndexTracker::~IndexTracker() {} + } +} + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +#endif + +#ifdef CATCH_CONFIG_MAIN +// #included from: internal/catch_default_main.hpp +#define TWOBLUECUBES_CATCH_DEFAULT_MAIN_HPP_INCLUDED + +#ifndef __OBJC__ + +// Standard C/C++ main entry point +int main (int argc, char * argv[]) { + return Catch::Session().run( argc, argv ); +} + +#else // __OBJC__ + +// Objective-C entry point +int main (int argc, char * const argv[]) { +#if !CATCH_ARC_ENABLED + NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; +#endif + + Catch::registerTestMethods(); + int result = Catch::Session().run( argc, (char* const*)argv ); + +#if !CATCH_ARC_ENABLED + [pool drain]; +#endif + + return result; +} + +#endif // __OBJC__ + +#endif + +#ifdef CLARA_CONFIG_MAIN_NOT_DEFINED +# undef CLARA_CONFIG_MAIN +#endif + +////// + +// If this config identifier is defined then all CATCH macros are prefixed with CATCH_ +#ifdef CATCH_CONFIG_PREFIX_ALL + +#define CATCH_REQUIRE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE" ) +#define CATCH_REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, "CATCH_REQUIRE_FALSE" ) + +#define CATCH_REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, "", "CATCH_REQUIRE_THROWS" ) +#define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THROWS_AS" ) +#define CATCH_REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, matcher, "CATCH_REQUIRE_THROWS_WITH" ) +#define CATCH_REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_NOTHROW" ) + +#define CATCH_CHECK( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK" ) +#define CATCH_CHECK_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, "CATCH_CHECK_FALSE" ) +#define CATCH_CHECKED_IF( expr ) INTERNAL_CATCH_IF( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECKED_IF" ) +#define CATCH_CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECKED_ELSE" ) +#define CATCH_CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, "CATCH_CHECK_NOFAIL" ) + +#define CATCH_CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THROWS" ) +#define CATCH_CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THROWS_AS" ) +#define CATCH_CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, matcher, "CATCH_CHECK_THROWS_WITH" ) +#define CATCH_CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_NOTHROW" ) + +#define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THAT" ) +#define CATCH_REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THAT" ) + +#define CATCH_INFO( msg ) INTERNAL_CATCH_INFO( msg, "CATCH_INFO" ) +#define CATCH_WARN( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, "CATCH_WARN", msg ) +#define CATCH_SCOPED_INFO( msg ) INTERNAL_CATCH_INFO( msg, "CATCH_INFO" ) +#define CATCH_CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CATCH_CAPTURE" ) +#define CATCH_SCOPED_CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CATCH_CAPTURE" ) + +#ifdef CATCH_CONFIG_VARIADIC_MACROS + #define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ ) + #define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ ) + #define CATCH_METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ ) + #define CATCH_REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ ) + #define CATCH_SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) + #define CATCH_FAIL( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "CATCH_FAIL", __VA_ARGS__ ) + #define CATCH_SUCCEED( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "CATCH_SUCCEED", __VA_ARGS__ ) +#else + #define CATCH_TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description ) + #define CATCH_TEST_CASE_METHOD( className, name, description ) INTERNAL_CATCH_TEST_CASE_METHOD( className, name, description ) + #define CATCH_METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description ) + #define CATCH_REGISTER_TEST_CASE( function, name, description ) INTERNAL_CATCH_REGISTER_TESTCASE( function, name, description ) + #define CATCH_SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description ) + #define CATCH_FAIL( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "CATCH_FAIL", msg ) + #define CATCH_SUCCEED( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "CATCH_SUCCEED", msg ) +#endif +#define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE( "", "" ) + +#define CATCH_REGISTER_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) +#define CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) + +#define CATCH_GENERATE( expr) INTERNAL_CATCH_GENERATE( expr ) + +// "BDD-style" convenience wrappers +#ifdef CATCH_CONFIG_VARIADIC_MACROS +#define CATCH_SCENARIO( ... ) CATCH_TEST_CASE( "Scenario: " __VA_ARGS__ ) +#define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ ) +#else +#define CATCH_SCENARIO( name, tags ) CATCH_TEST_CASE( "Scenario: " name, tags ) +#define CATCH_SCENARIO_METHOD( className, name, tags ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " name, tags ) +#endif +#define CATCH_GIVEN( desc ) CATCH_SECTION( std::string( "Given: ") + desc, "" ) +#define CATCH_WHEN( desc ) CATCH_SECTION( std::string( " When: ") + desc, "" ) +#define CATCH_AND_WHEN( desc ) CATCH_SECTION( std::string( " And: ") + desc, "" ) +#define CATCH_THEN( desc ) CATCH_SECTION( std::string( " Then: ") + desc, "" ) +#define CATCH_AND_THEN( desc ) CATCH_SECTION( std::string( " And: ") + desc, "" ) + +// If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required +#else + +#define REQUIRE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal, "REQUIRE" ) +#define REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, "REQUIRE_FALSE" ) + +#define REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, "", "REQUIRE_THROWS" ) +#define REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::Normal, "REQUIRE_THROWS_AS" ) +#define REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, matcher, "REQUIRE_THROWS_WITH" ) +#define REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::Normal, "REQUIRE_NOTHROW" ) + +#define CHECK( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK" ) +#define CHECK_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, "CHECK_FALSE" ) +#define CHECKED_IF( expr ) INTERNAL_CATCH_IF( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECKED_IF" ) +#define CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECKED_ELSE" ) +#define CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, "CHECK_NOFAIL" ) + +#define CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, "", "CHECK_THROWS" ) +#define CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THROWS_AS" ) +#define CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, matcher, "CHECK_THROWS_WITH" ) +#define CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK_NOTHROW" ) + +#define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THAT" ) +#define REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::Normal, "REQUIRE_THAT" ) + +#define INFO( msg ) INTERNAL_CATCH_INFO( msg, "INFO" ) +#define WARN( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, "WARN", msg ) +#define SCOPED_INFO( msg ) INTERNAL_CATCH_INFO( msg, "INFO" ) +#define CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CAPTURE" ) +#define SCOPED_CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CAPTURE" ) + +#ifdef CATCH_CONFIG_VARIADIC_MACROS + #define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ ) + #define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ ) + #define METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ ) + #define REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ ) + #define SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) + #define FAIL( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "FAIL", __VA_ARGS__ ) + #define SUCCEED( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "SUCCEED", __VA_ARGS__ ) +#else + #define TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description ) + #define TEST_CASE_METHOD( className, name, description ) INTERNAL_CATCH_TEST_CASE_METHOD( className, name, description ) + #define METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description ) + #define REGISTER_TEST_CASE( method, name, description ) INTERNAL_CATCH_REGISTER_TESTCASE( method, name, description ) + #define SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description ) + #define FAIL( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "FAIL", msg ) + #define SUCCEED( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "SUCCEED", msg ) +#endif +#define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE( "", "" ) + +#define REGISTER_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) +#define REGISTER_LEGACY_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) + +#define GENERATE( expr) INTERNAL_CATCH_GENERATE( expr ) + +#endif + +#define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) + +// "BDD-style" convenience wrappers +#ifdef CATCH_CONFIG_VARIADIC_MACROS +#define SCENARIO( ... ) TEST_CASE( "Scenario: " __VA_ARGS__ ) +#define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ ) +#else +#define SCENARIO( name, tags ) TEST_CASE( "Scenario: " name, tags ) +#define SCENARIO_METHOD( className, name, tags ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " name, tags ) +#endif +#define GIVEN( desc ) SECTION( std::string(" Given: ") + desc, "" ) +#define WHEN( desc ) SECTION( std::string(" When: ") + desc, "" ) +#define AND_WHEN( desc ) SECTION( std::string("And when: ") + desc, "" ) +#define THEN( desc ) SECTION( std::string(" Then: ") + desc, "" ) +#define AND_THEN( desc ) SECTION( std::string(" And: ") + desc, "" ) + +using Catch::Detail::Approx; + +#endif // TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED + diff --git a/OpenCL_VectorAdd/libwb/vendor/json11.cpp b/OpenCL_VectorAdd/libwb/vendor/json11.cpp new file mode 100644 index 0000000..f401c26 --- /dev/null +++ b/OpenCL_VectorAdd/libwb/vendor/json11.cpp @@ -0,0 +1,1013 @@ +/* Copyright (c) 2013 Dropbox, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy + * of this software and associated documentation files (the "Software"), to + * deal + * in the Software without restriction, including without limitation the + * rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN + * THE SOFTWARE. + */ + +#include "json11.hpp" +#include +#include +#include +#include +#include +#include + +namespace json11 { + +static const int max_depth = 200; + +using std::string; +using std::vector; +using std::map; +using std::make_shared; +using std::initializer_list; +using std::move; + +/* * * * * * * * * * * * * * * * * * * * + * Serialization + */ + +static void dump(std::nullptr_t, string &out) { + out += "null"; +} + +static void dump(double value, string &out) { + if (std::isfinite(value)) { + char buf[32]; +//PMO +#ifndef _MSC_VER + snprintf(buf, sizeof buf, "%.17g", value); +#else + _snprintf_s(buf, sizeof buf, "%.17g", value); +#endif + out += buf; + } else { + out += "null"; + } +} + +static void dump(int value, string &out) { + char buf[32]; +//PMO +#ifndef _MSC_VER + snprintf(buf, sizeof buf, "%d", value); +#else + _snprintf_s(buf, sizeof buf, "%d", value); +#endif + out += buf; +} + +static void dump(int64_t value, string &out) { + char buf[64]; +//PMO +#ifndef _MSC_VER + snprintf(buf, sizeof buf, "%" PRId64, value); +#else + _snprintf_s(buf, sizeof buf, "%" PRId64, value); +#endif + out += buf; +} + +static void dump(uint64_t value, string &out) { + char buf[128]; +//PMO +#ifndef _MSC_VER + snprintf(buf, sizeof buf, "%" PRIu64, value); +#else + _snprintf_s(buf, sizeof buf, "%" PRIu64, value); +#endif + out += buf; +} + +static void dump(bool value, string &out) { + out += value ? "true" : "false"; +} + +static void dump(const string &value, string &out) { + out += '"'; + for (size_t i = 0; i < value.length(); i++) { + const char ch = value[i]; + if (ch == '\\') { + out += "\\\\"; + } else if (ch == '"') { + out += "\\\""; + } else if (ch == '\b') { + out += "\\b"; + } else if (ch == '\f') { + out += "\\f"; + } else if (ch == '\n') { + out += "\\n"; + } else if (ch == '\r') { + out += "\\r"; + } else if (ch == '\t') { + out += "\\t"; + } else if (static_cast(ch) <= 0x1f) { + char buf[8]; +//PMO +#ifndef _MSC_VER + snprintf(buf, sizeof buf, "\\u%04x", ch); +#else + _snprintf_s(buf, sizeof buf, "\\u%04x", ch); +#endif + out += buf; + } else if (static_cast(ch) == 0xe2 && + static_cast(value[i + 1]) == 0x80 && + static_cast(value[i + 2]) == 0xa8) { + out += "\\u2028"; + i += 2; + } else if (static_cast(ch) == 0xe2 && + static_cast(value[i + 1]) == 0x80 && + static_cast(value[i + 2]) == 0xa9) { + out += "\\u2029"; + i += 2; + } else { + out += ch; + } + } + out += '"'; +} + +static void dump(const Json::array &values, string &out) { + bool first = true; + out += "["; + for (const auto &value : values) { + if (!first) + out += ", "; + value.dump(out); + first = false; + } + out += "]"; +} + +static void dump(const Json::object &values, string &out) { + bool first = true; + out += "{"; + for (const auto &kv : values) { + if (!first) + out += ", "; + dump(kv.first, out); + out += ": "; + kv.second.dump(out); + first = false; + } + out += "}"; +} + +void Json::dump(string &out) const { + m_ptr->dump(out); +} + +/* * * * * * * * * * * * * * * * * * * * + * Value wrappers + */ + +template +class Value : public JsonValue { +protected: + // Constructors + explicit Value(const T &value) : m_value(value) { + } + explicit Value(T &&value) : m_value(move(value)) { + } + + // Get type tag + Json::Type type() const override { + return tag; + } + + // Comparisons + bool equals(const JsonValue *other) const override { + return m_value == static_cast *>(other)->m_value; + } + bool less(const JsonValue *other) const override { + return m_value < static_cast *>(other)->m_value; + } + + const T m_value; + void dump(string &out) const override { + json11::dump(m_value, out); + } +}; + +class JsonDouble final : public Value { + double number_value() const override { + return m_value; + } + int int_value() const override { + return static_cast(m_value); + } + int64_t int64_value() const override { + return (int64_t)m_value; + } + uint64_t uint64_value() const override { + return (uint64_t)m_value; + } + bool equals(const JsonValue *other) const override { + return m_value == other->number_value(); + } + bool less(const JsonValue *other) const override { + return m_value < other->number_value(); + } + +public: + explicit JsonDouble(double value) : Value(value) { + } +}; + +class JsonInt final : public Value { + double number_value() const override { + return m_value; + } + int int_value() const override { + return m_value; + } + int64_t int64_value() const override { + return m_value; + } + uint64_t uint64_value() const override { + return m_value; + } + bool equals(const JsonValue *other) const override { + return m_value == other->number_value(); + } + bool less(const JsonValue *other) const override { + return m_value < other->number_value(); + } + +public: + explicit JsonInt(int value) : Value(value) { + } +}; + +class JsonInt64 final : public Value { + double number_value() const override { + return m_value; + } + int int_value() const override { + return (int)m_value; + } + int64_t int64_value() const override { + return m_value; + } + uint64_t uint64_value() const override { + return (uint64_t)m_value; + } + bool equals(const JsonValue *other) const override { + return m_value == other->number_value(); + } + bool less(const JsonValue *other) const override { + return m_value < other->number_value(); + } + +public: + explicit JsonInt64(int64_t value) : Value(value) { + } +}; + +class JsonUInt64 final : public Value { + double number_value() const override { + return m_value; + } + int int_value() const override { + return (int)m_value; + } + int64_t int64_value() const override { + return (int64_t)m_value; + } + uint64_t uint64_value() const override { + return m_value; + } + bool equals(const JsonValue *other) const override { + return m_value == other->number_value(); + } + bool less(const JsonValue *other) const override { + return m_value < other->number_value(); + } + +public: + explicit JsonUInt64(uint64_t value) : Value(value) { + } +}; + +class JsonBoolean final : public Value { + bool bool_value() const override { + return m_value; + } + +public: + explicit JsonBoolean(bool value) : Value(value) { + } +}; + +class JsonString final : public Value { + const string &string_value() const override { + return m_value; + } + +public: + explicit JsonString(const string &value) : Value(value) { + } + explicit JsonString(string &&value) : Value(move(value)) { + } +}; + +class JsonArray final : public Value { + const Json::array &array_items() const override { + return m_value; + } + const Json &operator[](size_t i) const override; + +public: + explicit JsonArray(const Json::array &value) : Value(value) { + } + explicit JsonArray(Json::array &&value) : Value(move(value)) { + } +}; + +class JsonObject final : public Value { + const Json::object &object_items() const override { + return m_value; + } + const Json &operator[](const string &key) const override; + +public: + explicit JsonObject(const Json::object &value) : Value(value) { + } + explicit JsonObject(Json::object &&value) : Value(move(value)) { + } +}; + +class JsonNull final : public Value { +public: + JsonNull() : Value(nullptr) { + } +}; + +/* * * * * * * * * * * * * * * * * * * * + * Static globals - static-init-safe + */ +struct Statics { + const std::shared_ptr null = make_shared(); + const std::shared_ptr t = make_shared(true); + const std::shared_ptr f = make_shared(false); + const string empty_string; + const vector empty_vector; + const map empty_map; + Statics() { + } +}; + +static const Statics &statics() { + static const Statics s{}; + return s; +} + +static const Json &static_null() { + // This has to be separate, not in Statics, because Json() accesses + // statics().null. + static const Json json_null; + return json_null; +} + +/* * * * * * * * * * * * * * * * * * * * + * Constructors + */ + +Json::Json() NOEXCEPT : m_ptr(statics().null) { +} +Json::Json(std::nullptr_t) NOEXCEPT : m_ptr(statics().null) { +} +Json::Json(double value) : m_ptr(make_shared(value)) { +} +Json::Json(int value) : m_ptr(make_shared(value)) { +} +Json::Json(int64_t value) : m_ptr(make_shared(value)) { +} +Json::Json(uint64_t value) : m_ptr(make_shared(value)) { +} +Json::Json(bool value) : m_ptr(value ? statics().t : statics().f) { +} +Json::Json(const string &value) : m_ptr(make_shared(value)) { +} +Json::Json(string &&value) : m_ptr(make_shared(move(value))) { +} +Json::Json(const char *value) : m_ptr(make_shared(value)) { +} +Json::Json(const Json::array &values) + : m_ptr(make_shared(values)) { +} +Json::Json(Json::array &&values) + : m_ptr(make_shared(move(values))) { +} +Json::Json(const Json::object &values) + : m_ptr(make_shared(values)) { +} +Json::Json(Json::object &&values) + : m_ptr(make_shared(move(values))) { +} + +/* * * * * * * * * * * * * * * * * * * * + * Accessors + */ + +Json::Type Json::type() const { + return m_ptr->type(); +} +double Json::number_value() const { + return m_ptr->number_value(); +} +int Json::int_value() const { + return m_ptr->int_value(); +} +int64_t Json::int64_value() const { + return m_ptr->int64_value(); +} +uint64_t Json::uint64_value() const { + return m_ptr->uint64_value(); +} +bool Json::bool_value() const { + return m_ptr->bool_value(); +} +const string &Json::string_value() const { + return m_ptr->string_value(); +} +const vector &Json::array_items() const { + return m_ptr->array_items(); +} +const map &Json::object_items() const { + return m_ptr->object_items(); +} +const Json &Json::operator[](size_t i) const { + return (*m_ptr)[i]; +} +const Json &Json::operator[](const string &key) const { + return (*m_ptr)[key]; +} + +double JsonValue::number_value() const { + return 0; +} +int JsonValue::int_value() const { + return 0; +} +int64_t JsonValue::int64_value() const { + return 0; +} +uint64_t JsonValue::uint64_value() const { + return 0; +} +bool JsonValue::bool_value() const { + return false; +} +const string &JsonValue::string_value() const { + return statics().empty_string; +} +const vector &JsonValue::array_items() const { + return statics().empty_vector; +} +const map &JsonValue::object_items() const { + return statics().empty_map; +} +const Json &JsonValue::operator[](size_t) const { + return static_null(); +} +const Json &JsonValue::operator[](const string &) const { + return static_null(); +} + +const Json &JsonObject::operator[](const string &key) const { + auto iter = m_value.find(key); + return (iter == m_value.end()) ? static_null() : iter->second; +} +const Json &JsonArray::operator[](size_t i) const { + if (i >= m_value.size()) + return static_null(); + else + return m_value[i]; +} + +/* * * * * * * * * * * * * * * * * * * * + * Comparison + */ + +bool Json::operator==(const Json &other) const { + if (m_ptr->type() != other.m_ptr->type()) + return false; + + return m_ptr->equals(other.m_ptr.get()); +} + +bool Json::operator<(const Json &other) const { + if (m_ptr->type() != other.m_ptr->type()) + return m_ptr->type() < other.m_ptr->type(); + + return m_ptr->less(other.m_ptr.get()); +} + +/* * * * * * * * * * * * * * * * * * * * + * Parsing + */ + +/* esc(c) + * + * Format char c suitable for printing in an error message. + */ +static inline string esc(char c) { + char buf[12]; + if (static_cast(c) >= 0x20 && static_cast(c) <= 0x7f) { +//PMO +#ifndef _MSC_VER + snprintf(buf, sizeof buf, "'%c' (%d)", c, c); +#else + _snprintf_s(buf, sizeof buf, "'%c' (%d)", c, c); +#endif + } else { +//PMO +#ifndef _MSC_VER + snprintf(buf, sizeof buf, "(%d)", c); +#else + _snprintf_s(buf, sizeof buf, "(%d)", c); +#endif + } + return string(buf); +} + +static inline bool in_range(long x, long lower, long upper) { + return (x >= lower && x <= upper); +} + +/* JsonParser + * + * Object that tracks all state of an in-progress parse. + */ +struct JsonParser { + + /* State + */ + const string &str; + size_t i; + string &err; + bool failed; + const JsonParse strategy; + + /* fail(msg, err_ret = Json()) + * + * Mark this parse as failed. + */ + Json fail(string &&msg) { + return fail(move(msg), Json()); + } + + template + T fail(string &&msg, const T err_ret) { + if (!failed) + err = std::move(msg); + failed = true; + return err_ret; + } + + /* consume_whitespace() + * + * Advance until the current character is non-whitespace. + */ + void consume_whitespace() { + while (str[i] == ' ' || str[i] == '\r' || str[i] == '\n' || + str[i] == '\t') + i++; + } + + /* consume_comment() + * + * Advance comments (c-style inline and multiline). + */ + bool consume_comment() { + bool comment_found = false; + if (str[i] == '/') { + i++; + if (i == str.size()) + return fail("unexpected end of input inside comment", 0); + if (str[i] == '/') { // inline comment + i++; + if (i == str.size()) + return fail("unexpected end of input inside inline comment", 0); + // advance until next line + while (str[i] != '\n') { + i++; + if (i == str.size()) + return fail("unexpected end of input inside inline comment", + 0); + } + comment_found = true; + } else if (str[i] == '*') { // multiline comment + i++; + if (i > str.size() - 2) + return fail("unexpected end of input inside multi-line comment", + 0); + // advance until closing tokens + while (!(str[i] == '*' && str[i + 1] == '/')) { + i++; + if (i > str.size() - 2) + return fail( + "unexpected end of input inside multi-line comment", 0); + } + i += 2; + if (i == str.size()) + return fail("unexpected end of input inside multi-line comment", + 0); + comment_found = true; + } else + return fail("malformed comment", 0); + } + return comment_found; + } + + /* consume_garbage() + * + * Advance until the current character is non-whitespace and non-comment. + */ + void consume_garbage() { + consume_whitespace(); + if (strategy == JsonParse::COMMENTS) { + bool comment_found = false; + do { + comment_found = consume_comment(); + consume_whitespace(); + } while (comment_found); + } + } + + /* get_next_token() + * + * Return the next non-whitespace character. If the end of the input is + * reached, + * flag an error and return 0. + */ + char get_next_token() { + consume_garbage(); + if (i == str.size()) + return fail("unexpected end of input", 0); + + return str[i++]; + } + + /* encode_utf8(pt, out) + * + * Encode pt as UTF-8 and add it to out. + */ + void encode_utf8(long pt, string &out) { + if (pt < 0) + return; + + if (pt < 0x80) { + out += static_cast(pt); + } else if (pt < 0x800) { + out += static_cast((pt >> 6) | 0xC0); + out += static_cast((pt & 0x3F) | 0x80); + } else if (pt < 0x10000) { + out += static_cast((pt >> 12) | 0xE0); + out += static_cast(((pt >> 6) & 0x3F) | 0x80); + out += static_cast((pt & 0x3F) | 0x80); + } else { + out += static_cast((pt >> 18) | 0xF0); + out += static_cast(((pt >> 12) & 0x3F) | 0x80); + out += static_cast(((pt >> 6) & 0x3F) | 0x80); + out += static_cast((pt & 0x3F) | 0x80); + } + } + + /* parse_string() + * + * Parse a string, starting at the current position. + */ + string parse_string() { + string out; + long last_escaped_codepoint = -1; + while (true) { + if (i == str.size()) + return fail("unexpected end of input in string", ""); + + char ch = str[i++]; + + if (ch == '"') { + encode_utf8(last_escaped_codepoint, out); + return out; + } + + if (in_range(ch, 0, 0x1f)) + return fail("unescaped " + esc(ch) + " in string", ""); + + // The usual case: non-escaped characters + if (ch != '\\') { + encode_utf8(last_escaped_codepoint, out); + last_escaped_codepoint = -1; + out += ch; + continue; + } + + // Handle escapes + if (i == str.size()) + return fail("unexpected end of input in string", ""); + + ch = str[i++]; + + if (ch == 'u') { + // Extract 4-byte escape sequence + string esc = str.substr(i, 4); + // Explicitly check length of the substring. The following loop + // relies on std::string returning the terminating NUL when + // accessing str[length]. Checking here reduces brittleness. + if (esc.length() < 4) { + return fail("bad \\u escape: " + esc, ""); + } + for (int j = 0; j < 4; j++) { + if (!in_range(esc[j], 'a', 'f') && !in_range(esc[j], 'A', 'F') && + !in_range(esc[j], '0', '9')) + return fail("bad \\u escape: " + esc, ""); + } + + long codepoint = strtol(esc.data(), nullptr, 16); + + // JSON specifies that characters outside the BMP shall be encoded + // as a pair + // of 4-hex-digit \u escapes encoding their surrogate pair + // components. Check + // whether we're in the middle of such a beast: the previous + // codepoint was an + // escaped lead (high) surrogate, and this is a trail (low) + // surrogate. + if (in_range(last_escaped_codepoint, 0xD800, 0xDBFF) && + in_range(codepoint, 0xDC00, 0xDFFF)) { + // Reassemble the two surrogate pairs into one astral-plane + // character, per + // the UTF-16 algorithm. + encode_utf8((((last_escaped_codepoint - 0xD800) << 10) | + (codepoint - 0xDC00)) + + 0x10000, + out); + last_escaped_codepoint = -1; + } else { + encode_utf8(last_escaped_codepoint, out); + last_escaped_codepoint = codepoint; + } + + i += 4; + continue; + } + + encode_utf8(last_escaped_codepoint, out); + last_escaped_codepoint = -1; + + if (ch == 'b') { + out += '\b'; + } else if (ch == 'f') { + out += '\f'; + } else if (ch == 'n') { + out += '\n'; + } else if (ch == 'r') { + out += '\r'; + } else if (ch == 't') { + out += '\t'; + } else if (ch == '"' || ch == '\\' || ch == '/') { + out += ch; + } else { + return fail("invalid escape character " + esc(ch), ""); + } + } + } + + /* parse_number() + * + * Parse a double. + */ + Json parse_number() { + size_t start_pos = i; + + if (str[i] == '-') + i++; + + // Integer part + if (str[i] == '0') { + i++; + if (in_range(str[i], '0', '9')) + return fail("leading 0s not permitted in numbers"); + } else if (in_range(str[i], '1', '9')) { + i++; + while (in_range(str[i], '0', '9')) + i++; + } else { + return fail("invalid " + esc(str[i]) + " in number"); + } + + if (str[i] != '.' && str[i] != 'e' && str[i] != 'E' && + (i - start_pos) <= + static_cast(std::numeric_limits::digits10)) { + return std::atoi(str.c_str() + start_pos); + } + + // Decimal part + if (str[i] == '.') { + i++; + if (!in_range(str[i], '0', '9')) + return fail("at least one digit required in fractional part"); + + while (in_range(str[i], '0', '9')) + i++; + } + + // Exponent part + if (str[i] == 'e' || str[i] == 'E') { + i++; + + if (str[i] == '+' || str[i] == '-') + i++; + + if (!in_range(str[i], '0', '9')) + return fail("at least one digit required in exponent"); + + while (in_range(str[i], '0', '9')) + i++; + } + + return std::strtod(str.c_str() + start_pos, nullptr); + } + + /* expect(str, res) + * + * Expect that 'str' starts at the character that was just read. If it + * does, advance + * the input and return res. If not, flag an error. + */ + Json expect(const string &expected, Json res) { + assert(i != 0); + i--; + if (str.compare(i, expected.length(), expected) == 0) { + i += expected.length(); + return res; + } else { + return fail("parse error: expected " + expected + ", got " + + str.substr(i, expected.length())); + } + } + + /* parse_json() + * + * Parse a JSON object. + */ + Json parse_json(int depth) { + if (depth > max_depth) { + return fail("exceeded maximum nesting depth"); + } + + char ch = get_next_token(); + if (failed) + return Json(); + + if (ch == '-' || (ch >= '0' && ch <= '9')) { + i--; + return parse_number(); + } + + if (ch == 't') + return expect("true", true); + + if (ch == 'f') + return expect("false", false); + + if (ch == 'n') + return expect("null", Json()); + + if (ch == '"') + return parse_string(); + + if (ch == '{') { + map data; + ch = get_next_token(); + if (ch == '}') + return data; + + while (1) { + if (ch != '"') + return fail("expected '\"' in object, got " + esc(ch)); + + string key = parse_string(); + if (failed) + return Json(); + + ch = get_next_token(); + if (ch != ':') + return fail("expected ':' in object, got " + esc(ch)); + + data[std::move(key)] = parse_json(depth + 1); + if (failed) + return Json(); + + ch = get_next_token(); + if (ch == '}') + break; + if (ch != ',') + return fail("expected ',' in object, got " + esc(ch)); + + ch = get_next_token(); + } + return data; + } + + if (ch == '[') { + vector data; + ch = get_next_token(); + if (ch == ']') + return data; + + while (1) { + i--; + data.push_back(parse_json(depth + 1)); + if (failed) + return Json(); + + ch = get_next_token(); + if (ch == ']') + break; + if (ch != ',') + return fail("expected ',' in list, got " + esc(ch)); + + ch = get_next_token(); + (void)ch; + } + return data; + } + + return fail("expected value, got " + esc(ch)); + } +}; + +Json Json::parse(const string &in, string &err, JsonParse strategy) { + JsonParser parser{in, 0, err, false, strategy}; + Json result = parser.parse_json(0); + + // Check for any trailing garbage + parser.consume_garbage(); + if (parser.i != in.size()) + return parser.fail("unexpected trailing " + esc(in[parser.i])); + + return result; +} + +// Documented in json11.hpp +vector Json::parse_multi(const string &in, string &err, + JsonParse strategy) { + JsonParser parser{in, 0, err, false, strategy}; + + vector json_vec; + while (parser.i != in.size() && !parser.failed) { + json_vec.push_back(parser.parse_json(0)); + // Check for another object + parser.consume_garbage(); + } + return json_vec; +} + +/* * * * * * * * * * * * * * * * * * * * + * Shape-checking + */ + +bool Json::has_shape(const shape &types, string &err) const { + if (!is_object()) { + err = "expected JSON object, got " + dump(); + return false; + } + + for (auto &item : types) { + if ((*this)[item.first].type() != item.second) { + err = "bad type for " + item.first + " in " + dump(); + return false; + } + } + + return true; +} + +} // namespace json11 diff --git a/OpenCL_VectorAdd/libwb/vendor/json11.hpp b/OpenCL_VectorAdd/libwb/vendor/json11.hpp new file mode 100644 index 0000000..9e0f0d9 --- /dev/null +++ b/OpenCL_VectorAdd/libwb/vendor/json11.hpp @@ -0,0 +1,300 @@ +/* json11 + * + * json11 is a tiny JSON library for C++11, providing JSON parsing and + * serialization. + * + * The core object provided by the library is json11::Json. A Json object + * represents any JSON + * value: null, bool, number (int or double), string (std::string), array + * (std::vector), or + * object (std::map). + * + * Json objects act like values: they can be assigned, copied, moved, + * compared for equality or + * order, etc. There are also helper methods Json::dump, to serialize a + * Json to a string, and + * Json::parse (static) to parse a std::string as a Json object. + * + * Internally, the various types of Json object are represented by the + * JsonValue class + * hierarchy. + * + * A note on numbers - JSON specifies the syntax of number formatting but + * not its semantics, + * so some JSON implementations distinguish between integers and + * floating-point numbers, while + * some don't. In json11, we choose the latter. Because some JSON + * implementations (namely + * Javascript itself) treat all numbers as the same type, distinguishing + * the two leads + * to JSON that will be *silently* changed by a round-trip through those + * implementations. + * Dangerous! To avoid that risk, json11 stores all numbers as double + * internally, but also + * provides integer helpers. + * + * Fortunately, double-precision IEEE754 ('double') can precisely store any + * integer in the + * range +/-2^53, which includes every 'int' on most systems. (Timestamps + * often use int64 + * or long long to avoid the Y2038K problem; a double storing microseconds + * since some epoch + * will be exact for +/- 275 years.) + */ + +/* Copyright (c) 2013 Dropbox, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy + * of this software and associated documentation files (the "Software"), to + * deal + * in the Software without restriction, including without limitation the + * rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN + * THE SOFTWARE. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +//PMO +#ifndef _MSC_VER +#define NOEXCEPT noexcept +#else +#define NOEXCEPT _NOEXCEPT +#endif + +namespace json11 { + +enum JsonParse { STANDARD, COMMENTS }; + +class JsonValue; + +class Json final { +public: + // Types + enum Type { + NUL, + NUMBER, + NUMBER64, + UNUMBER64, + BOOL, + STRING, + ARRAY, + OBJECT + }; + + // Array and object typedefs + typedef std::vector array; + typedef std::map object; + + // Constructors for the various types of JSON value. + //PMO + //Json() noexcept; // NUL + Json() NOEXCEPT; // NUL + //Json(std::nullptr_t) noexcept; // NUL + Json(std::nullptr_t) NOEXCEPT; // NUL + Json(double value); // NUMBER + Json(int value); // NUMBER + Json(int64_t value); // NUMBER64 + Json(uint64_t value); // UNUMBER64 + Json(bool value); // BOOL + Json(const std::string &value); // STRING + Json(std::string &&value); // STRING + Json(const char *value); // STRING + Json(const array &values); // ARRAY + Json(array &&values); // ARRAY + Json(const object &values); // OBJECT + Json(object &&values); // OBJECT + + // Implicit constructor: anything with a to_json() function. + template + Json(const T &t) : Json(t.to_json()) { + } + + // Implicit constructor: map-like objects (std::map, std::unordered_map, + // etc) + template < + class M, + typename std::enable_if< + std::is_constructible::value && + std::is_constructible::value, + int>::type = 0> + Json(const M &m) : Json(object(m.begin(), m.end())) { + } + + // Implicit constructor: vector-like objects (std::list, std::vector, + // std::set, etc) + template ::value, + int>::type = 0> + Json(const V &v) : Json(array(v.begin(), v.end())) { + } + + // This prevents Json(some_pointer) from accidentally producing a bool. + // Use + // Json(bool(some_pointer)) if that behavior is desired. + Json(void *) = delete; + + // Accessors + Type type() const; + + bool is_null() const { + return type() == NUL; + } + bool is_number() const { + return type() == NUMBER; + } + bool is_number64() const { + return type() == NUMBER64; + } + bool is_unumber64() const { + return type() == UNUMBER64; + } + bool is_bool() const { + return type() == BOOL; + } + bool is_string() const { + return type() == STRING; + } + bool is_array() const { + return type() == ARRAY; + } + bool is_object() const { + return type() == OBJECT; + } + + // Return the enclosed value if this is a number, 0 otherwise. Note that + // json11 does not + // distinguish between integer and non-integer numbers - number_value() + // and int_value() + // can both be applied to a NUMBER-typed object. + double number_value() const; + int int_value() const; + int64_t int64_value() const; + uint64_t uint64_value() const; + + // Return the enclosed value if this is a boolean, false otherwise. + bool bool_value() const; + // Return the enclosed string if this is a string, "" otherwise. + const std::string &string_value() const; + // Return the enclosed std::vector if this is an array, or an empty + // vector otherwise. + const array &array_items() const; + // Return the enclosed std::map if this is an object, or an empty map + // otherwise. + const object &object_items() const; + + // Return a reference to arr[i] if this is an array, Json() otherwise. + const Json &operator[](size_t i) const; + // Return a reference to obj[key] if this is an object, Json() otherwise. + const Json &operator[](const std::string &key) const; + + // Serialize. + void dump(std::string &out) const; + std::string dump() const { + std::string out; + dump(out); + return out; + } + + // Parse. If parse fails, return Json() and assign an error message to + // err. + static Json parse(const std::string &in, std::string &err, + JsonParse strategy = JsonParse::STANDARD); + static Json parse(const char *in, std::string &err, + JsonParse strategy = JsonParse::STANDARD) { + if (in) { + return parse(std::string(in), err, strategy); + } else { + err = "null input"; + return nullptr; + } + } + // Parse multiple objects, concatenated or separated by whitespace + static std::vector + parse_multi(const std::string &in, std::string &err, + JsonParse strategy = JsonParse::STANDARD); + + bool operator==(const Json &rhs) const; + bool operator<(const Json &rhs) const; + bool operator!=(const Json &rhs) const { + return !(*this == rhs); + } + bool operator<=(const Json &rhs) const { + return !(rhs < *this); + } + bool operator>(const Json &rhs) const { + return (rhs < *this); + } + bool operator>=(const Json &rhs) const { + return !(*this < rhs); + } + + /* has_shape(types, err) + * + * Return true if this is a JSON object and, for each item in types, has + * a field of + * the given type. If not, return false and set err to a descriptive + * message. + */ + typedef std::initializer_list> shape; + bool has_shape(const shape &types, std::string &err) const; + +private: + std::shared_ptr m_ptr; +}; + +// Internal class hierarchy - JsonValue objects are not exposed to users of +// this API. +class JsonValue { +protected: + friend class Json; + friend class JsonInt; + friend class JsonInt64; + friend class JsonUInt64; + friend class JsonDouble; + virtual Json::Type type() const = 0; + virtual bool equals(const JsonValue *other) const = 0; + virtual bool less(const JsonValue *other) const = 0; + virtual void dump(std::string &out) const = 0; + virtual double number_value() const; + virtual int int_value() const; + virtual int64_t int64_value() const; + virtual uint64_t uint64_value() const; + virtual bool bool_value() const; + virtual const std::string &string_value() const; + virtual const Json::array &array_items() const; + virtual const Json &operator[](size_t i) const; + virtual const Json::object &object_items() const; + virtual const Json &operator[](const std::string &key) const; + virtual ~JsonValue() { + } +}; + +} // namespace json11 diff --git a/OpenCL_VectorAdd/libwb/wb.h b/OpenCL_VectorAdd/libwb/wb.h new file mode 100644 index 0000000..8f41e23 --- /dev/null +++ b/OpenCL_VectorAdd/libwb/wb.h @@ -0,0 +1,155 @@ + + +#ifndef __WB_H__ +#define __WB_H__ + +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ + +#include +#include +#include +#include + +#ifdef _MSC_VER + +// set minimal warning level +#pragma warning(push,0) +// some warnings still occur at this level +// if necessary, disable specific warnings not covered by previous pragma +#pragma warning(disable : 4244 4056 4305 4800 4267 4996 4756 4661 4385 4101) + +#define __func__ __FUNCTION__ +#ifndef _CRT_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_WARNINGS 1 +#endif /* _CRT_SECURE_NO_WARNINGS */ +#define _CRT_SECURE_NO_DEPRECATE 1 +#define _CRT_NONSTDC_NO_DEPRECATE 1 +#include +#include +#include +#define WB_USE_WINDOWS +#else /* _MSC_VER */ +#include +#include +#include +#include +#define WB_USE_UNIX +#ifdef __APPLE__ +#include +#define WB_USE_DARWIN +#else /* __APPLE__ */ +#define WB_USE_LINUX +#endif /* __APPLE__ */ +#endif /* _MSC_VER */ + +#define wbStmt(stmt) stmt + +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ + +#define wbLine __LINE__ +#define wbFile __FILE__ +#define wbFunction __func__ + +#define wbExit() \ + wbAssert(0); \ + exit(1) + +#ifdef WB_USE_COURSERA +#define wbLogger_printOnExit 1 +#else /* WB_USE_COURSERA */ +#define wbLogger_printOnLog 1 +#endif /* WB_USE_COURSERA */ + +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ + +#ifdef __cplusplus +#define EXTERN_C extern "C" +#define START_EXTERN_C EXTERN_C { +#define END_EXTERN_C } +#else +#define EXTERN_C +#define START_EXTERN_C +#define END_EXTERN_C +#endif /* __cplusplus */ + +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ + +#include +#define WB_USE_JSON11 1 + +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ + +#define LAZY_FILE_LOAD +extern char *solutionJSON; + +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ + +#ifdef WB_USE_OPENCL +#ifdef WB_USE_DARWIN +#include +#else /* WB_USE_DARWIN */ +#include +#endif /* WB_USE_DARWIN */ +#endif /* WB_USE_OPENCL */ + +#include "wbTypes.h" + +#include "wbAssert.h" +#include "wbMalloc.h" +#include "wbString.h" +#include "wbUtils.h" + +#include "wbArg.h" +#include "wbCUDA.h" +#include "wbCast.h" +#include "wbComparator.h" +#include "wbDirectory.h" +#include "wbExit.h" +#include "wbExport.h" +#include "wbFile.h" +#include "wbImage.h" +#include "wbImport.h" +#include "wbInit.h" +#include "wbLogger.h" +#include "wbMD5.h" +#include "wbMPI.h" +#include "wbSolution.h" +#include "wbSparse.h" +#include "wbThrust.h" +#include "wbTimer.h" +#include "wbPath.h" + +#include "wbDataset.h" + +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ +/***********************************************************/ + +#endif /* __WB_H__ */ diff --git a/OpenCL_VectorAdd/libwb/wbArg.cpp b/OpenCL_VectorAdd/libwb/wbArg.cpp new file mode 100644 index 0000000..2a5c736 --- /dev/null +++ b/OpenCL_VectorAdd/libwb/wbArg.cpp @@ -0,0 +1,105 @@ + +#include "wb.h" + +EXTERN_C wbArg_t wbArg_new(int *argc, char ***argv) { + wbArg_t arg; + + wb_init(argc, argv); + + wbArg_setInputCount(arg, 0); + wbArg_setInputFiles(arg, NULL); + wbArg_setOutputFile(arg, NULL); + wbArg_setType(arg, NULL); + wbArg_setExpectedOutputFile(arg, NULL); + return arg; +} + +EXTERN_C void wbArg_delete(wbArg_t arg) { + if (wbArg_getInputCount(arg) > 0 && wbArg_getInputFiles(arg) != NULL) { + int ii; + for (ii = 0; ii < wbArg_getInputCount(arg); ii++) { + wbDelete(wbArg_getInputFile(arg, ii)); + } + wbDelete(wbArg_getInputFiles(arg)); + wbArg_setInputCount(arg, 0); + wbArg_setInputFiles(arg, NULL); + } + if (wbArg_getOutputFile(arg)) { + wbDelete(wbArg_getOutputFile(arg)); + wbArg_setOutputFile(arg, NULL); + } + if (wbArg_getExpectedOutputFile(arg)) { + wbDelete(wbArg_getExpectedOutputFile(arg)); + wbArg_setExpectedOutputFile(arg, NULL); + } + if (wbArg_getType(arg)) { + wbDelete(wbArg_getType(arg)); + wbArg_setType(arg, NULL); + } + return; +} + +static int getInputFileCount(char *arg) { + int count = 1; + while (*arg != '\0' && *arg != '-') { + if (*arg == ',') { + count++; + } + arg++; + } + return count; +} + +static char **parseInputFiles(char *arg, int *resCount) { + int count; + int ii = 0; + char **files; + char *token; + + count = getInputFileCount(arg); + + files = wbNewArray(char *, count); + + token = strtok(arg, ","); + while (token != NULL) { + files[ii++] = wbString_duplicate(token); + token = strtok(NULL, ","); + } + *resCount = ii; + return files; +} + +static char *parseString(char *arg) { + return wbString_duplicate(arg); +} + +EXTERN_C wbArg_t wbArg_read(int argc, char **argv) { + int ii; + wbArg_t arg; + + arg = wbArg_new(&argc, &argv); + for (ii = 0; ii < argc; ii++) { + if (wbString_startsWith(argv[ii], "-i")) { + int fileCount; + char **files; + + files = parseInputFiles(argv[ii + 1], &fileCount); + + wbArg_setInputCount(arg, fileCount); + wbArg_setInputFiles(arg, files); + } else if (wbString_startsWith(argv[ii], "-o")) { + char *file = parseString(argv[ii + 1]); + wbArg_setOutputFile(arg, file); + } else if (wbString_startsWith(argv[ii], "-e")) { + char *file = parseString(argv[ii + 1]); + wbArg_setExpectedOutputFile(arg, file); + } else if (wbString_startsWith(argv[ii], "-t")) { + char *type = parseString(argv[ii + 1]); + wbArg_setType(arg, type); + } else if (argv[ii][0] == '-') { + wbLog(ERROR, "Unexpected program option ", argv[ii]); + } + } + + return arg; +} diff --git a/OpenCL_VectorAdd/libwb/wbArg.h b/OpenCL_VectorAdd/libwb/wbArg.h new file mode 100644 index 0000000..c98bcf7 --- /dev/null +++ b/OpenCL_VectorAdd/libwb/wbArg.h @@ -0,0 +1,33 @@ + + +#ifndef __WB_ARG_H__ +#define __WB_ARG_H__ + +struct st_wbArg_t { + int inputCount; + char **inputFiles; + char *outputFile; + char *expectedOutput; + char *type; +}; + +#define wbArg_getInputCount(wa) ((wa).inputCount) +#define wbArg_getInputFiles(wa) ((wa).inputFiles) +#define wbArg_getInputFile(wa, ii) (wbArg_getInputFiles(wa)[ii]) +#define wbArg_getOutputFile(wa) ((wa).outputFile) +#define wbArg_getExpectedOutputFile(wa) ((wa).expectedOutput) +#define wbArg_getType(wa) ((wa).type) + +#define wbArg_setInputCount(wa, val) (wbArg_getInputCount(wa) = val) +#define wbArg_setInputFiles(wa, val) (wbArg_getInputFiles(wa) = val) +#define wbArg_setInputFile(wa, ii, val) (wbArg_getInputFile(wa, ii) = val) +#define wbArg_setOutputFile(wa, val) (wbArg_getOutputFile(wa) = val) +#define wbArg_setExpectedOutputFile(wa, val) \ + (wbArg_getExpectedOutputFile(wa) = val) +#define wbArg_setType(wa, val) (wbArg_getType(wa) = val) + +EXTERN_C wbArg_t wbArg_new(int *argc, char ***argv); +EXTERN_C void wbArg_delete(wbArg_t arg); +EXTERN_C wbArg_t wbArg_read(int argc, char **argv); + +#endif /* __WB_ARG_H__ */ diff --git a/OpenCL_VectorAdd/libwb/wbAssert.h b/OpenCL_VectorAdd/libwb/wbAssert.h new file mode 100644 index 0000000..b8ed669 --- /dev/null +++ b/OpenCL_VectorAdd/libwb/wbAssert.h @@ -0,0 +1,24 @@ + + +#ifndef __WB_ASSERT_H__ +#define __WB_ASSERT_H__ + +#include + +#ifdef WB_DEBUG +#define wbAssert(cond) assert(cond) +#define wbAssertMessage(msg, cond) \ + do { \ + if (!(cond)) { \ + wbPrint(msg); \ + wbAssert(cond); \ + } \ + } while (0) +#else /* WB_DEBUG */ +#define wbAssert(...) +#define wbAssertMessage(...) +#endif /* WB_DEBUG */ + +#define wbTodo(msg) wbAssertMessage(msg, false) + +#endif /* __WB_ASSERT_H__ */ diff --git a/OpenCL_VectorAdd/libwb/wbCUDA.cpp b/OpenCL_VectorAdd/libwb/wbCUDA.cpp new file mode 100644 index 0000000..cb26895 --- /dev/null +++ b/OpenCL_VectorAdd/libwb/wbCUDA.cpp @@ -0,0 +1,25 @@ + +#include "wb.h" +#ifdef WB_USE_CUDA + +int _cudaMemoryListIdx = 0; + +size_t _cudaMallocSize = 0; + +wbCUDAMemory_t _cudaMemoryList[_cudaMemoryListSize]; + +char *wbRandom_list(size_t sz) { + size_t ii; + char *rands = wbNewArray(char, sz); + int *irands = (int *)rands; + for (ii = 0; ii < sz / sizeof(int); ii++) { + irands[ii] = rand(); + } + while (ii < sz) { + rands[ii] = (char)(rand() % 255); + ii++; + } + return rands; +} + +#endif /* WB_USE_CUDA */ diff --git a/OpenCL_VectorAdd/libwb/wbCUDA.h b/OpenCL_VectorAdd/libwb/wbCUDA.h new file mode 100644 index 0000000..658ff39 --- /dev/null +++ b/OpenCL_VectorAdd/libwb/wbCUDA.h @@ -0,0 +1,77 @@ + +#ifndef __WB_CUDA_H__ +#define __WB_CUDA_H__ + +#ifdef WB_USE_CUDA +#ifdef __PGI +#define __GNUC__ 4 +#endif /* __PGI */ +#include +#include + +typedef struct st_wbCUDAMemory_t { + void *mem; + size_t sz; +} wbCUDAMemory_t; + +#define _cudaMemoryListSize 1024 + +extern size_t _cudaMallocSize; +extern wbCUDAMemory_t _cudaMemoryList[]; +extern int _cudaMemoryListIdx; + +char *wbRandom_list(size_t sz); + +static inline cudaError_t wbCUDAMalloc(void **devPtr, size_t sz) { + int idx = _cudaMemoryListIdx; + + cudaError_t err = cudaMalloc(devPtr, sz); + + if (idx == 0) { + srand(time(NULL)); + memset(_cudaMemoryList, 0, + sizeof(wbCUDAMemory_t) * _cudaMemoryListSize); + } + + if (err == cudaSuccess) { +#if 0 + char * rands = wbRandom_list(sz); + // can use curand here, but do not want to invoke a kernel + err = cudaMemcpy(*devPtr, rands, sz, cudaMemcpyHostToDevice); + wbFree(rands); +#else + err = cudaMemset(*devPtr, 0, sz); +#endif + } + + _cudaMallocSize += sz; + _cudaMemoryList[idx].mem = *devPtr; + _cudaMemoryList[idx].sz = sz; + _cudaMemoryListIdx++; + return err; +} + +static inline cudaError_t wbCUDAFree(void *mem) { + int idx = _cudaMemoryListIdx; + if (idx == 0) { + memset(_cudaMemoryList, 0, + sizeof(wbCUDAMemory_t) * _cudaMemoryListSize); + } + for (int ii = 0; ii < idx; ii++) { + if (_cudaMemoryList[ii].mem != NULL && + _cudaMemoryList[ii].mem == mem) { + cudaError_t err = cudaFree(mem); + _cudaMallocSize -= _cudaMemoryList[ii].sz; + _cudaMemoryList[ii].mem = NULL; + return err; + } + } + return cudaErrorMemoryAllocation; +} + +#define cudaMalloc(elem, err) wbCUDAMalloc((void **)elem, err) +#define cudaFree wbCUDAFree + +#endif /* WB_USE_CUDA */ + +#endif /* __WB_CUDA_H__ */ diff --git a/OpenCL_VectorAdd/libwb/wbCast.h b/OpenCL_VectorAdd/libwb/wbCast.h new file mode 100644 index 0000000..01e8387 --- /dev/null +++ b/OpenCL_VectorAdd/libwb/wbCast.h @@ -0,0 +1,29 @@ + + +#ifndef __WB_CAST_H__ +#define __WB_CAST_H__ + +template +static inline void wbCast(X &x, const Y &y, size_t len) { + size_t ii; + + for (ii = 0; ii < len; ii++) { + x[ii] = (X)y[ii]; + } + + return; +} + +template +static inline X *wbCast(const Y &y, size_t len) { + size_t ii; + X *x = wbNewArray(X, len); + + for (ii = 0; ii < len; ii++) { + x[ii] = (X)y[ii]; + } + + return x; +} + +#endif /* __WB_CAST_H__ */ diff --git a/OpenCL_VectorAdd/libwb/wbComparator.h b/OpenCL_VectorAdd/libwb/wbComparator.h new file mode 100644 index 0000000..26fd0cb --- /dev/null +++ b/OpenCL_VectorAdd/libwb/wbComparator.h @@ -0,0 +1,187 @@ + + +#ifndef __WB_COMPARATOR_H__ +#define __WB_COMPARATOR_H__ + +#include "wb.h" + +template +static inline T _abs(const T &a) { + return a < 0 ? -a : a; +} + +static inline wbBool _almostEqual(double A, double B, double eps) { + if (A == 0) { + return _abs(B) < eps; + } else if (B == 0) { + return _abs(A) < eps; + } else { +#if 0 + double d = max(_abs(A), _abs(B)); + double g = (_abs(A - B) / d); +#else + double g = _abs(A - B); +#endif + if (g <= eps) { + return wbTrue; + } else { + return wbFalse; + } + } +} + +static inline wbBool _almostEqual(float A, float B, float eps) { + if (A == 0) { + return _abs(B) < eps; + } else if (B == 0) { + return _abs(A) < eps; + } else { +#if 0 + float d = max(_abs(A), _abs(B)); + float g = (_abs(A - B) / d); +#else + float g = _abs(A - B); +#endif + if (g <= eps) { + return wbTrue; + } else { + return wbFalse; + } + } +} + +static inline wbBool _almostEqual(double A, double B) { + return _almostEqual(A, B, 0.2); +} + +static inline wbBool _almostEqual(float A, float B) { + return _almostEqual(A, B, 0.2f); +} + +static inline wbBool _almostEqual2sComplement(float A, float B, + int maxUlps) { + // Make sure maxUlps is non-negative and small enough that the + // default NAN won't compare as equal to anything. + + int aInt, bInt, intDiff; + + wbAssert(maxUlps > 0 && maxUlps < 4 * 1024 * 1024); + + int *tmp = reinterpret_cast(&A); + aInt = *tmp; + + // Make aInt lexicographically ordered as a twos-complement int + if (aInt < 0) { + aInt = 0x80000000 - aInt; + } + // Make bInt lexicographically ordered as a twos-complement int + tmp = reinterpret_cast(&B); + bInt = *tmp; + if (bInt < 0) { + bInt = 0x80000000 - bInt; + } + intDiff = _abs(aInt - bInt); + if (intDiff <= maxUlps) { + return wbTrue; + } + return wbFalse; +} + +static inline wbBool _almostEqual2sComplement(float A, float B) { + return _almostEqual2sComplement(A, B, 4); +} + +static inline wbBool _almostEqual2sComplement(double A, double B, + int maxUlps) { + // Make sure maxUlps is non-negative and small enough that the + // default NAN won't compare as equal to anything. + + int64_t aInt, bInt, intDiff; + + wbAssert(maxUlps > 0 && maxUlps < 4 * 1024 * 1024); + + int64_t *tmp = reinterpret_cast(&A); + aInt = *tmp; + + // Make aInt lexicographically ordered as a twos-complement int + if (aInt < 0) { + aInt = 0x80000000 - aInt; + } + // Make bInt lexicographically ordered as a twos-complement int + tmp = reinterpret_cast(&B); + bInt = *tmp; + if (bInt < 0) { + bInt = 0x80000000 - bInt; + } + intDiff = _abs(aInt - bInt); + if (intDiff <= maxUlps) { + return wbTrue; + } + return wbFalse; +} + +static inline wbBool _almostEqual2sComplement(double A, double B) { + return _almostEqual2sComplement(A, B, 4); +} + +template +static inline int wbCompare(const T &a, const T &b) { + if (a == b) { + return 0; + } else if (a < b) { + return -1; + } else { + return 1; + } +} + +template <> +inline int wbCompare(const double &a, const double &b) { + if (_almostEqual(a, b)) { + return 0; + } else if (a < b) { + return -1; + } else { + return 1; + } +} + +template <> +inline int wbCompare(const float &a, const float &b) { + if (_almostEqual(a, b)) { + return 0; + } else if (a < b) { + return -1; + } else { + return 1; + } +} + +template +static inline wbBool wbEqualQ(const T &a, const T &b) { + return wbCompare(a, b) == 0; +} + +template +static inline wbBool wbUnequalQ(const T &a, const T &b) { + return wbCompare(a, b) != 0; +} + +template +static inline wbBool wbEqualQ(const T *a, const T *b, size_t n) { + size_t ii; + + for (ii = 0; ii < n; ii++) { + if (wbUnequalQ(a[ii], b[ii])) { + return wbFalse; + } + } + return wbTrue; +} + +template +static inline wbBool wbUnequalQ(const T *a, const T *b, size_t n) { + return !wbEqualQ(a, b, n); +} + +#endif /* __WB_COMPARATOR_H__ */ diff --git a/OpenCL_VectorAdd/libwb/wbDataset.cpp b/OpenCL_VectorAdd/libwb/wbDataset.cpp new file mode 100644 index 0000000..a11f064 --- /dev/null +++ b/OpenCL_VectorAdd/libwb/wbDataset.cpp @@ -0,0 +1,177 @@ +#include "wb.h" + +template +static inline T _min(const T &x, const T &y) { + return x < y ? x : y; +} + +template +static inline T _max(const T &x, const T &y) { + return x > y ? x : y; +} + +template +inline T lerp(const double &x, const T &start, const T &end) { + return (1 - x) * start + x * end; +} + +static inline void genRandom(void *trgt, wbType_t type, double minVal, + double maxVal) { + const int span = maxVal - minVal; + const int r = rand(); + const double rf = ((double)r) / ((double)RAND_MAX); + switch (type) { + case wbType_ascii: + *((char *)trgt) = (r % span) + minVal; // random printable character; + break; + case wbType_bit8: + *((char *)trgt) = lerp(rf, minVal, maxVal); + break; + case wbType_ubit8: + *((unsigned char *)trgt) = lerp(rf, minVal, maxVal); + break; + case wbType_integer: + *((int *)trgt) = lerp(rf, minVal, maxVal); + break; + case wbType_float: { + *((float *)trgt) = lerp(rf, minVal, maxVal); + break; + } + case wbType_double: { + *((double *)trgt) = lerp(rf, minVal, maxVal); + break; + } + case wbType_unknown: + wbAssert(false && "Invalid wbType_unknown"); + break; + } + return; +} + +static inline void *genRandomList(wbType_t type, size_t len, double minVal, + double maxVal) { + size_t ii; + void *data = wbNewArray(char, wbType_size(type) * len); + switch (type) { + case wbType_ascii: + case wbType_bit8: { + char *iter = (char *)data; + for (ii = 0; ii < len; ii++) { + genRandom(iter++, type, minVal, maxVal); + } + break; + } + case wbType_ubit8: { + unsigned char *iter = (unsigned char *)data; + for (ii = 0; ii < len; ii++) { + genRandom(iter++, type, minVal, maxVal); + } + break; + } + case wbType_integer: { + int *iter = (int *)data; + for (ii = 0; ii < len; ii++) { + genRandom(iter++, type, minVal, maxVal); + } + break; + } + case wbType_float: { + float *iter = (float *)data; + for (ii = 0; ii < len; ii++) { + genRandom(iter++, type, minVal, maxVal); + } + break; + } + case wbType_double: { + double *iter = (double *)data; + for (ii = 0; ii < len; ii++) { + genRandom(iter++, type, minVal, maxVal); + } + break; + } + case wbType_unknown: + wbAssert(false && "Invalid wbType_unknown"); + break; + } + return data; +} + +static void genRaw(const char *path, wbRaw_GenerateParams_t params) { + int rows = _max(1, params.rows); + int cols = _max(1, params.cols); + double minVal = params.minVal; + double maxVal = params.maxVal; + wbType_t type = params.type; + void *data = genRandomList(type, rows * cols, minVal, maxVal); + wbExport(path, wbExportKind_raw, data, rows, cols, type); + wbDelete(data); +} + +static void genCSV(const char *path, wbCSV_GenerateParams_t params) { + int rows = _max(1, params.rows); + int cols = _max(1, params.cols); + double minVal = params.minVal; + double maxVal = params.maxVal; + wbType_t type = params.type; + void *data = genRandomList(type, rows * cols, minVal, maxVal); + wbExport(path, wbExportKind_csv, data, rows, cols, type); + wbDelete(data); +} + +static void genTSV(const char *path, wbTSV_GenerateParams_t params) { + int rows = _max(1, params.rows); + int cols = _max(1, params.cols); + double minVal = params.minVal; + double maxVal = params.maxVal; + wbType_t type = params.type; + void *data = genRandomList(type, rows * cols, minVal, maxVal); + wbExport(path, wbExportKind_tsv, data, rows, cols, type); + wbDelete(data); +} + +static void genText(const char *path, wbText_GenerateParams_t params) { + int length = _max(1, params.length); + wbType_t type = wbType_ascii; + void *data = genRandomList(type, length, 32, 128); + wbExport(path, wbExportKind_text, data, length, 1, type); + wbDelete(data); +} + +static void genPPM(const char *path, wbPPM_GenerateParams_t params) { + int width = _max(1, params.width); + int height = _max(1, params.height); + int channels = _max(1, params.channels); + double minVal = params.minVal; + double maxVal = params.maxVal; + wbType_t type = wbType_float; + float *data = (float *)genRandomList(type, width * height * channels, + minVal, maxVal); + wbImage_t img = wbImage_new(width, height, channels, data); + wbExport(path, img); + wbImage_delete(img); +} + +EXTERN_C void wbDataset_generate(const char *path, wbExportKind_t kind, + wbGenerateParams_t params) { + wbDirectory_create(wbDirectory_name(path)); + + switch (kind) { + case wbExportKind_raw: + genRaw(path, params.raw); + break; + case wbExportKind_csv: + genCSV(path, params.csv); + break; + case wbExportKind_tsv: + genTSV(path, params.tsv); + break; + case wbExportKind_ppm: + genPPM(path, params.ppm); + break; + case wbExportKind_text: + genText(path, params.text); + break; + default: + wbAssert(false && "Invalid Export kind"); + } +} diff --git a/OpenCL_VectorAdd/libwb/wbDataset.h b/OpenCL_VectorAdd/libwb/wbDataset.h new file mode 100644 index 0000000..ce81c28 --- /dev/null +++ b/OpenCL_VectorAdd/libwb/wbDataset.h @@ -0,0 +1,52 @@ +#ifndef __WB_DATASET_H__ +#define __WB_DATASET_H__ + +#include "wbImport.h" +#include "wbTypes.h" + +typedef struct { + int rows; + int cols; + wbType_t type; + double minVal; + double maxVal; +} wbCSV_GenerateParams_t; + +typedef struct { + int rows; + int cols; + wbType_t type; + double minVal; + double maxVal; +} wbTSV_GenerateParams_t; + +typedef struct { + int rows; + int cols; + double minVal; + double maxVal; + wbType_t type; +} wbRaw_GenerateParams_t; + +typedef struct { + int width; + int height; + int channels; + double minVal; + double maxVal; +} wbPPM_GenerateParams_t; + +typedef struct { int length; } wbText_GenerateParams_t; + +typedef union { + wbCSV_GenerateParams_t csv; + wbRaw_GenerateParams_t raw; + wbTSV_GenerateParams_t tsv; + wbPPM_GenerateParams_t ppm; + wbText_GenerateParams_t text; +} wbGenerateParams_t; + +EXTERN_C void wbDataset_generate(const char *path, wbExportKind_t kind, + wbGenerateParams_t params); + +#endif /* __WB_DATASET_H__ */ diff --git a/OpenCL_VectorAdd/libwb/wbDataset_test.cpp b/OpenCL_VectorAdd/libwb/wbDataset_test.cpp new file mode 100644 index 0000000..4f08042 --- /dev/null +++ b/OpenCL_VectorAdd/libwb/wbDataset_test.cpp @@ -0,0 +1,23 @@ + +#include "wb.h" +#include "vendor/catch.hpp" + +TEST_CASE("Can create Raw dataset", "[DataGenerator]") { + wbGenerateParams_t params; + params.raw.rows = 2; + params.raw.cols = 300; + params.raw.minVal = 0; + params.raw.maxVal = 30; + params.raw.type = wbType_integer; + wbDataset_generate( + wbPath_join(wbDirectory_current(), "test-dataset", "test.raw"), + wbExportKind_raw, params); +} + +TEST_CASE("Can create Text dataset", "[DataGenerator]") { + wbGenerateParams_t params; + params.text.length = 2000; + wbDataset_generate( + wbPath_join(wbDirectory_current(), "test-dataset", "test.txt"), + wbExportKind_text, params); +} diff --git a/OpenCL_VectorAdd/libwb/wbDirectory.cpp b/OpenCL_VectorAdd/libwb/wbDirectory.cpp new file mode 100644 index 0000000..10dc8c5 --- /dev/null +++ b/OpenCL_VectorAdd/libwb/wbDirectory.cpp @@ -0,0 +1,88 @@ +#include "wb.h" + +#ifndef PATH_MAX +#ifdef FILENAME_MAX +#define PATH_MAX FILENAME_MAX +#else /* FILENAME_MAX */ +#define PATH_MAX 4096 +#endif /* FILENAME_MAX */ +#endif /* PATH_MAX */ + +#ifdef WB_USE_UNIX +const char wbDirectorySeperator = '/'; +static char *getcwd_(char *buf, int maxLen) { + return getcwd(buf, maxLen); +} +static void mkdir_(const char *dir) { + mkdir(dir, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); +} +#else /* WB_USE_LINUX */ +const char wbDirectorySeperator = '\\'; +static char *getcwd_(char *buf, int maxLen) { + return _getcwd(buf, maxLen); +} +static void mkdir_(const char *dir) { + _mkdir(dir); +} +#endif /* WB_USE_LINUX */ + +EXTERN_C const char * wbDirectory_create(const char *dir) { + char tmp[PATH_MAX]; + char *p = NULL; + size_t len; +//PMO +#ifndef _MSC_VER + snprintf(tmp, sizeof(tmp), "%s", dir); +#else + _snprintf_s(tmp, sizeof(tmp), "%s", dir); +#endif + len = strlen(tmp); + if (tmp[len - 1] == wbDirectorySeperator) { + tmp[len - 1] = 0; + } + for (p = tmp + 1; *p; p++) { + if (*p == wbDirectorySeperator) { + *p = 0; + mkdir_(tmp); + *p = wbDirectorySeperator; + } + } + mkdir_(tmp); + return dir; +} + +EXTERN_C char *wbDirectory_name(const char *pth0) { + char *pth = wbString_duplicate(pth0); + char *p = strrchr(pth, wbDirectorySeperator); + if (p) { + p[0] = 0; + } + return pth; +} + +EXTERN_C char *wbDirectory_current() { + char *tmp = wbNewArray(char, PATH_MAX + 1); + if (getcwd_(tmp, PATH_MAX)) { + return tmp; + } + + wbDelete(tmp); + + int error = errno; + switch (error) { + case EACCES: + std::cerr + << "Cannot get current directory :: access denied. exiting..." + << std::endl; + exit(-1); + case ENOMEM: + std::cerr << "Cannot get current directory :: insufficient storage. " + "exiting..." + << std::endl; + exit(-1); + default: + std::cerr << "Cannot get current directory :: unrecognised error " + << error << std::endl; + exit(-1); + } +} \ No newline at end of file diff --git a/OpenCL_VectorAdd/libwb/wbDirectory.h b/OpenCL_VectorAdd/libwb/wbDirectory.h new file mode 100644 index 0000000..cb14f81 --- /dev/null +++ b/OpenCL_VectorAdd/libwb/wbDirectory.h @@ -0,0 +1,9 @@ +#ifndef __WB_DIRECTORY__ +#define __WB_DIRECTORY__ + +extern const char wbDirectorySeperator; +EXTERN_C char *wbDirectory_name(const char *pth); +EXTERN_C const char * wbDirectory_create(const char *dir); +EXTERN_C char *wbDirectory_current(); + +#endif /* __WB_DIRECTORY__ */ diff --git a/OpenCL_VectorAdd/libwb/wbExit.cpp b/OpenCL_VectorAdd/libwb/wbExit.cpp new file mode 100644 index 0000000..a7edc3a --- /dev/null +++ b/OpenCL_VectorAdd/libwb/wbExit.cpp @@ -0,0 +1,119 @@ + +#include "wb.h" + +enum { + wbMPI_timerTag = 2, + wbMPI_loggerTag = 4, + wbMPI_solutionExistsTag = 8, + wbMPI_solutionTag = 16 +}; + +void wb_atExit(void) { + using std::cout; + using std::endl; + +#ifdef WB_USE_CUDA + cudaDeviceSynchronize(); +#endif /* WB_USE_CUDA */ + + int nranks = rankCount(); + if (nranks > 1) { +#ifdef WB_USE_MPI + if (isMasterQ) { +#ifdef wbLogger_printOnExit + cout << "==$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$" << endl; + + cout << "{\n"; + cout << wbString_quote("timer") << ":"; + cout << "[\n"; + for (int ii = 0; ii < nranks; ii++) { + if (ii == 0) { + cout << wbTimer_toJSON(); + } else { + const char *msg = wbMPI_getStringFromRank(ii, wbMPI_timerTag); + if (msg != NULL && strlen(msg) != 0) { + cout << ",\n"; + cout << msg; + // free(msg); + } + } + } + cout << "]" << endl; // close timer + + cout << "," << endl; // start logger + cout << wbString_quote("logger") << ":"; + cout << "[\n"; + for (int ii = 0; ii < nranks; ii++) { + if (ii == 0) { + cout << wbLogger_toJSON(); + } else { + const char *msg = wbMPI_getStringFromRank(ii, wbMPI_loggerTag); + if (msg != NULL && strlen(msg) != 0) { + cout << ",\n"; + cout << msg; + // free(msg); + } + } + } + cout << "]" << endl; // close logger + + cout << "," << endl; // start solutionExists + cout << wbString_quote("cuda_memory") << ":" << _cudaMallocSize + << ",\n"; + + if (solutionJSON) { + cout << wbString_quote("solution_exists") << ": true,\n"; + cout << wbString_quote("solution") << ":" << solutionJSON << "\n"; + } else { + cout << wbString_quote("solution_exists") << ": false\n"; + } + cout << "}" << endl; // close json + + } else { + wbMPI_sendStringToMaster(wbTimer_toJSON().c_str(), wbMPI_timerTag); + wbMPI_sendStringToMaster(wbLogger_toJSON().c_str(), wbMPI_loggerTag); + } +#endif /* wbLogger_printOnExit */ + +#endif /* WB_USE_MPI */ + } else { +#ifdef wbLogger_printOnExit + cout << "==$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$" << endl; + + cout << "{\n" << wbString_quote("timer") << ":[" << wbTimer_toJSON() + << "],\n" << wbString_quote("logger") << ":[" << wbLogger_toJSON() + << "],\n"; + +#ifdef WB_USE_CUDA + cout << wbString_quote("cuda_memory") << ":" << _cudaMallocSize + << ",\n"; +#endif /* WB_USE_CUDA */ + + if (solutionJSON) { + cout << wbString_quote("solution_exists") << ": true,\n"; + cout << wbString_quote("solution") << ":" << solutionJSON << "\n"; + } else { + cout << wbString_quote("solution_exists") << ": false\n"; + } + cout << "}" << endl; +#endif /* wbLogger_printOnExit */ + } + + // wbTimer_delete(_timer); + // wbLogger_delete(_logger); + + _timer = NULL; + _logger = NULL; + +// wbFile_atExit(); + +#ifdef WB_USE_CUDA + cudaDeviceReset(); +#endif + + exit(0); + + // assert(0); + + return; +} diff --git a/OpenCL_VectorAdd/libwb/wbExit.h b/OpenCL_VectorAdd/libwb/wbExit.h new file mode 100644 index 0000000..4400108 --- /dev/null +++ b/OpenCL_VectorAdd/libwb/wbExit.h @@ -0,0 +1,7 @@ + +#ifndef __WB_EXIT_H__ +#define __WB_EXIT_H__ + +void wb_atExit(void); + +#endif /* __WB_EXIT_H__ */ diff --git a/OpenCL_VectorAdd/libwb/wbExport.cpp b/OpenCL_VectorAdd/libwb/wbExport.cpp new file mode 100644 index 0000000..59b7a33 --- /dev/null +++ b/OpenCL_VectorAdd/libwb/wbExport.cpp @@ -0,0 +1,510 @@ + +#include "wb.h" + +static inline void wbExportText_setFile(wbExportText_t text, + const char *path) { + if (text != NULL) { + if (wbExportText_getFile(text) != NULL) { + wbFile_delete(wbExportText_getFile(text)); + } + if (path != NULL) { + wbExportText_getFile(text) = wbFile_open(path, "w+"); + } else { + wbExportText_getFile(text) = NULL; + } + } + + return; +} + +static inline wbExportText_t wbExportText_new(void) { + wbExportText_t text; + + text = wbNew(struct st_wbExportText_t); + + wbExportText_getFile(text) = NULL; + wbExportText_setLength(text, -1); + + return text; +} + +static inline void wbExportText_delete(wbExportText_t text) { + if (text != NULL) { + wbExportText_setFile(text, NULL); + wbDelete(text); + } + return; +} + +static inline void wbExportText_write(wbExportText_t text, + const char *data, int length) { + int ii; + FILE *handle; + wbFile_t file; + + if (text == NULL || wbExportText_getFile(text) == NULL) { + return; + } + + file = wbExportText_getFile(text); + + handle = wbFile_getFileHandle(file); + + if (handle == NULL) { + return; + } + + for (ii = 0; ii < length; ii++) { + fprintf(handle, "%c", data[ii]); + } + + return; +} + +static inline void wbExportRaw_setFile(wbExportRaw_t raw, + const char *path) { + if (raw != NULL) { + if (wbExportRaw_getFile(raw) != NULL) { + wbFile_delete(wbExportRaw_getFile(raw)); + } + if (path != NULL) { + wbExportRaw_getFile(raw) = wbFile_open(path, "w+"); + } else { + wbExportRaw_getFile(raw) = NULL; + } + } + + return; +} + +static inline wbExportRaw_t wbExportRaw_new(void) { + wbExportRaw_t raw; + + raw = wbNew(struct st_wbExportRaw_t); + + wbExportRaw_getFile(raw) = NULL; + wbExportRaw_setRowCount(raw, -1); + wbExportRaw_setColumnCount(raw, -1); + + return raw; +} + +static inline void wbExportRaw_delete(wbExportRaw_t raw) { + if (raw != NULL) { + wbExportRaw_setFile(raw, NULL); + wbDelete(raw); + } + return; +} + +static inline void wbExportRaw_write(wbExportRaw_t raw, void *data, + int rows, int columns, + wbType_t type) { + int ii, jj; + FILE *handle; + wbFile_t file; + + if (raw == NULL || wbExportRaw_getFile(raw) == NULL) { + return; + } + + file = wbExportRaw_getFile(raw); + + handle = wbFile_getFileHandle(file); + + if (handle == NULL) { + return; + } + + if (columns == 1) { + fprintf(handle, "%d\n", rows); + } else { + fprintf(handle, "%d %d\n", rows, columns); + } + + for (ii = 0; ii < rows; ii++) { + for (jj = 0; jj < columns; jj++) { + if (type == wbType_integer) { + int elem = ((int *)data)[ii * columns + jj]; + fprintf(handle, "%d", elem); + } else if (type == wbType_ubit8) { + int elem = ((unsigned char *)data)[ii * columns + jj]; + fprintf(handle, "%d", elem); + } else { + wbReal_t elem = ((wbReal_t *)data)[ii * columns + jj]; + fprintf(handle, "%f", elem); + } + if (jj == columns - 1) { + fprintf(handle, "\n"); + } else { + fprintf(handle, " "); + } + } + } + + return; +} + +static inline void wbExportCSV_setFile(wbExportCSV_t csv, + const char *path) { + if (csv != NULL) { + if (wbExportCSV_getFile(csv) != NULL) { + wbFile_delete(wbExportCSV_getFile(csv)); + } + if (path != NULL) { + wbExportCSV_getFile(csv) = wbFile_open(path, "w+"); + } else { + wbExportCSV_getFile(csv) = NULL; + } + } + + return; +} + +static inline wbExportCSV_t wbExportCSV_new(void) { + wbExportCSV_t csv; + + csv = wbNew(struct st_wbExportCSV_t); + + wbExportCSV_getFile(csv) = NULL; + wbExportCSV_setColumnCount(csv, -1); + wbExportCSV_setRowCount(csv, -1); + wbExportCSV_setSeperator(csv, '\0'); + + return csv; +} + +static inline void wbExportCSV_delete(wbExportCSV_t csv) { + if (csv != NULL) { + wbExportCSV_setFile(csv, NULL); + wbDelete(csv); + } +} + +static inline void wbExportCSV_write(wbExportCSV_t csv, void *data, + int rows, int columns, char sep, + wbType_t type) { + int ii, jj; + wbFile_t file; + FILE *handle; + char seperator[2]; + + if (csv == NULL || wbExportCSV_getFile(csv) == NULL) { + return; + } + + file = wbExportCSV_getFile(csv); + + handle = wbFile_getFileHandle(file); + + if (handle == NULL) { + return; + } + + if (sep == '\0') { + seperator[0] = ','; + } else { + seperator[0] = sep; + } + seperator[1] = '\0'; + + for (ii = 0; ii < rows; ii++) { + for (jj = 0; jj < columns; jj++) { + if (type == wbType_integer) { + int elem = ((int *)data)[ii * columns + jj]; + fprintf(handle, "%d", elem); + } else if (type == wbType_ubit8) { + int elem = ((unsigned char *)data)[ii * columns + jj]; + fprintf(handle, "%d", elem); + } else { + wbReal_t elem = ((wbReal_t *)data)[ii * columns + jj]; + fprintf(handle, "%f", elem); + } + if (jj == columns - 1) { + fprintf(handle, "\n"); + } else { + fprintf(handle, "%s", seperator); + } + } + } + + return; +} + +static inline wbExport_t wbExport_open(const char *file, + wbExportKind_t kind) { + wbExport_t exprt; + + if (file == NULL) { + wbLog(ERROR, "Go NULL for file value."); + wbExit(); + } + + wbExport_setFile(exprt, NULL); + wbExport_setKind(exprt, kind); + + if (kind == wbExportKind_raw) { + wbExportRaw_t raw = wbExportRaw_new(); + wbExportRaw_setFile(raw, file); + wbExport_setRaw(exprt, raw); + } else if (kind == wbExportKind_text) { + wbExportText_t txt = wbExportText_new(); + wbExportText_setFile(txt, file); + wbExport_setText(exprt, txt); + } else if (kind == wbExportKind_tsv || kind == wbExportKind_csv) { + wbExportCSV_t csv = wbExportCSV_new(); + if (kind == wbExportKind_csv) { + wbExportCSV_setSeperator(csv, ','); + } else { + wbExportCSV_setSeperator(csv, '\t'); + } + wbExportCSV_setFile(csv, file); + wbExport_setCSV(exprt, csv); + } else if (kind == wbExportKind_ppm) { + wbExport_setFile(exprt, wbString_duplicate(file)); + } else { + wbLog(ERROR, "Invalid export type."); + wbExit(); + } + + return exprt; +} + +static inline wbExport_t wbExport_open(const char *file, + const char *type0) { + wbExport_t exprt; + wbExportKind_t kind; + char *type; + + type = wbString_toLower(type0); + + if (wbString_sameQ(type, "csv")) { + kind = wbExportKind_csv; + } else if (wbString_sameQ(type, "tsv")) { + kind = wbExportKind_tsv; + } else if (wbString_sameQ(type, "raw") || wbString_sameQ(type, "dat")) { + kind = wbExportKind_raw; + } else if (wbString_sameQ(type, "ppm") || wbString_sameQ(type, "pbm")) { + kind = wbExportKind_ppm; + } else if (wbString_sameQ(type, "txt") || wbString_sameQ(type, "text")) { + kind = wbExportKind_text; + } else { + wbLog(ERROR, "Invalid export type ", type0); + wbExit(); + } + + exprt = wbExport_open(file, kind); + + wbDelete(type); + + return exprt; +} + +static inline void wbExport_close(wbExport_t exprt) { + wbExportKind_t kind; + + kind = wbExport_getKind(exprt); + + if (wbExport_getFile(exprt)) { + wbDelete(wbExport_getFile(exprt)); + } + + if (kind == wbExportKind_tsv || kind == wbExportKind_csv) { + wbExportCSV_t csv = wbExport_getCSV(exprt); + wbExportCSV_delete(csv); + wbExport_setCSV(exprt, NULL); + } else if (kind == wbExportKind_raw) { + wbExportRaw_t raw = wbExport_getRaw(exprt); + wbExportRaw_delete(raw); + wbExport_setRaw(exprt, NULL); + } else if (kind == wbExportKind_text) { + wbExportText_t text = wbExport_getText(exprt); + wbExportText_delete(text); + wbExport_setText(exprt, NULL); + } else if (kind == wbExportKind_ppm) { + } else { + wbLog(ERROR, "Invalid export type."); + wbExit(); + } + return; +} + +static inline void wbExport_writeAsImage(wbExport_t exprt, wbImage_t img) { + wbAssert(wbExport_getKind(exprt) == wbExportKind_ppm); + + wbPPM_export(wbExport_getFile(exprt), img); + + return; +} + +static inline void wbExport_write(wbExport_t exprt, void *data, int rows, + int columns, char sep, wbType_t type) { + wbExportKind_t kind; + + kind = wbExport_getKind(exprt); + if (kind == wbExportKind_tsv || kind == wbExportKind_csv) { + wbExportCSV_t csv = wbExport_getCSV(exprt); + wbExportCSV_write(csv, data, rows, columns, sep, type); + } else if (kind == wbExportKind_raw) { + wbExportRaw_t raw = wbExport_getRaw(exprt); + wbExportRaw_write(raw, data, rows, columns, type); + } else if (kind == wbExportKind_text) { + wbExportText_t text = wbExport_getText(exprt); + if (columns == 0) { + columns = 1; + } + if (rows == 0) { + rows = 1; + } + wbExportText_write(text, (const char *)data, rows * columns); + } else { + wbLog(ERROR, "Invalid export type."); + wbExit(); + } + return; +} + +static inline void wbExport_write(wbExport_t exprt, void *data, int rows, + int columns, wbType_t type) { + wbExport_write(exprt, data, rows, columns, ',', type); +} + +static wbExportKind_t _parseExportExtension(const char *file) { + char *extension; + wbExportKind_t kind; + + extension = wbFile_extension(file); + + if (wbString_sameQ(extension, "csv")) { + kind = wbExportKind_csv; + } else if (wbString_sameQ(extension, "tsv")) { + kind = wbExportKind_tsv; + } else if (wbString_sameQ(extension, "raw") || + wbString_sameQ(extension, "dat")) { + kind = wbExportKind_raw; + } else if (wbString_sameQ(extension, "text") || + wbString_sameQ(extension, "txt")) { + kind = wbExportKind_text; + } else if (wbString_sameQ(extension, "ppm")) { + kind = wbExportKind_ppm; + } else { + kind = wbExportKind_unknown; + wbLog(ERROR, "File ", file, " does not have a compatible extension."); + } + + wbDelete(extension); + + return kind; +} + +static void wbExport(const char *file, void *data, int rows, int columns, + wbType_t type) { + wbExportKind_t kind; + wbExport_t exprt; + + if (file == NULL) { + return; + } + + kind = _parseExportExtension(file); + exprt = wbExport_open(file, kind); + + wbExport_write(exprt, data, rows, columns, type); + wbExport_close(exprt); +} + +void wbExport(const char *file, unsigned char *data, int rows) { + wbExport(file, data, rows, 1); + return; +} + +void wbExport(const char *file, int *data, int rows) { + wbExport(file, data, rows, 1); + return; +} + +void wbExport(const char *file, wbReal_t *data, int rows) { + wbExport(file, data, rows, 1); + return; +} + +void wbExport(const char *file, unsigned char *data, int rows, + int columns) { + wbExportKind_t kind; + wbExport_t exprt; + + if (file == NULL) { + return; + } + + kind = _parseExportExtension(file); + exprt = wbExport_open(file, kind); + + wbExport_write(exprt, data, rows, columns, wbType_ubit8); + wbExport_close(exprt); +} + +void wbExport(const char *file, int *data, int rows, int columns) { + wbExportKind_t kind; + wbExport_t exprt; + + if (file == NULL) { + return; + } + + kind = _parseExportExtension(file); + exprt = wbExport_open(file, kind); + + wbExport_write(exprt, data, rows, columns, wbType_integer); + wbExport_close(exprt); +} + +void wbExport(const char *file, wbReal_t *data, int rows, int columns) { + wbExportKind_t kind; + wbExport_t exprt; + + if (file == NULL) { + return; + } + + kind = _parseExportExtension(file); + exprt = wbExport_open(file, kind); + + wbExport_write(exprt, data, rows, columns, wbType_real); + wbExport_close(exprt); +} + +void wbExport(const char *file, wbExportKind_t kind, void *data, int rows, + int columns, wbType_t type) { + wbExport_t exprt; + + if (file == NULL) { + return; + } + + exprt = wbExport_open(file, kind); + + wbExport_write(exprt, data, rows, columns, type); + wbExport_close(exprt); +} + +void wbExport(const char *file, wbImage_t img) { + wbExportKind_t kind; + wbExport_t exprt; + + if (file == NULL) { + return; + } + + kind = _parseExportExtension(file); + exprt = wbExport_open(file, kind); + + wbAssert(kind == wbExportKind_ppm); + + wbExport_writeAsImage(exprt, img); + wbExport_close(exprt); +} + +void wbExport_text(const char *file, void *data, int length) { + wbExport(file, wbExportKind_text, data, 1, length, wbType_ascii); +} diff --git a/OpenCL_VectorAdd/libwb/wbExport.h b/OpenCL_VectorAdd/libwb/wbExport.h new file mode 100644 index 0000000..dd16b3f --- /dev/null +++ b/OpenCL_VectorAdd/libwb/wbExport.h @@ -0,0 +1,106 @@ + + +#ifndef __WB_EXPORT_H__ +#define __WB_EXPORT_H__ + +#include "wb.h" +#include "wbFile.h" +#include "wbPPM.h" + +typedef enum en_wbExportKind_t { + wbExportKind_unknown = -1, + wbExportKind_raw = 0x1000, + wbExportKind_csv, + wbExportKind_tsv, + wbExportKind_ppm, + wbExportKind_text, +} wbExportKind_t; + +typedef struct st_wbExportText_t { + int length; + wbFile_t file; +} * wbExportText_t; + +#define wbExportText_getLength(txt) ((txt)->length) +#define wbExportText_getFile(txt) ((txt)->file) + +#define wbExportText_setLength(txt, val) \ + (wbExportText_getLength(txt) = val) + +typedef struct st_wbExportRaw_t { + int rows; + int columns; + wbFile_t file; +} * wbExportRaw_t; + +#define wbExportRaw_getColumnCount(raw) ((raw)->columns) +#define wbExportRaw_getRowCount(raw) ((raw)->rows) +#define wbExportRaw_getFile(raw) ((raw)->file) + +#define wbExportRaw_setRowCount(raw, val) \ + (wbExportRaw_getRowCount(raw) = val) +#define wbExportRaw_setColumnCount(raw, val) \ + (wbExportRaw_getColumnCount(raw) = val) + +typedef struct st_wbExportCSV_t { + int rows; + int columns; + wbFile_t file; + char seperator; +} * wbExportCSV_t; + +#define wbExportCSV_getRowCount(csv) ((csv)->rows) +#define wbExportCSV_getColumnCount(csv) ((csv)->columns) +#define wbExportCSV_getFile(csv) ((csv)->file) +#define wbExportCSV_getSeperator(csv) ((csv)->seperator) + +#define wbExportCSV_setRowCount(csv, val) \ + (wbExportCSV_getRowCount(csv) = val) +#define wbExportCSV_setColumnCount(csv, val) \ + (wbExportCSV_getColumnCount(csv) = val) +#define wbExportCSV_setSeperator(csv, val) \ + (wbExportCSV_getSeperator(csv) = val) + +typedef struct st_wbExport_t { + wbExportKind_t kind; + union { + wbExportRaw_t raw; + wbExportCSV_t csv; + wbImage_t img; + wbExportText_t text; + } container; + char *file; +} wbExport_t; + +#define wbExport_getKind(exprt) ((exprt).kind) +#define wbExport_getContainer(exprt) ((exprt).container) +#define wbExport_getRaw(exprt) (wbExport_getContainer(exprt).raw) +#define wbExport_getCSV(exprt) (wbExport_getContainer(exprt).csv) +#define wbExport_getImage(exprt) (wbExport_getContainer(exprt).img) +#define wbExport_getText(exprt) (wbExport_getContainer(exprt).text) +#define wbExport_getFile(exprt) ((exprt).file) + +#define wbExport_setKind(exprt, val) (wbExport_getKind(exprt) = val) +#define wbExport_setRaw(exprt, val) (wbExport_getRaw(exprt) = val) +#define wbExport_setCSV(exprt, val) (wbExport_getCSV(exprt) = val) +#define wbExport_setImage(exprt, val) (wbExport_getImage(exprt) = val) +#define wbExport_setText(exprt, val) (wbExport_getText(exprt) = val) +#define wbExport_setFile(exprt, val) (wbExport_getFile(exprt) = val) + +void wbExport(const char *file, int *data, int rows, int columns); +void wbExport(const char *file, int *data, int rows); +void wbExport(const char *file, unsigned char *data, int rows, + int columns); +void wbExport(const char *file, unsigned char *data, int rows); +void wbExport(const char *file, int *data, int rows, int columns); +void wbExport(const char *file, int *data, int rows); +void wbExport(const char *file, wbReal_t *data, int rows, int columns); +void wbExport(const char *file, wbReal_t *data, int rows); +void wbExport(const char *file, wbImage_t img); + +void wbExport(const char *file, wbExportKind_t kind, void *data, int rows, + int columns, wbType_t type); + +void wbExport_text(const char *file, void *data, int length); + +#endif /* __WB_EXPORT_H__ */ diff --git a/OpenCL_VectorAdd/libwb/wbFile.cpp b/OpenCL_VectorAdd/libwb/wbFile.cpp new file mode 100644 index 0000000..b3fdbe7 --- /dev/null +++ b/OpenCL_VectorAdd/libwb/wbFile.cpp @@ -0,0 +1,353 @@ + + +#include "wb.h" + +#define wbFile_maxCount 256 + +static wbFile_t wbFile_handles[wbFile_maxCount]; + +static int wbFile_nextIndex(void) { + int ii; + for (ii = 0; ii < wbFile_maxCount; ii++) { + if (wbFile_handles[ii] == NULL) { + return ii; + } + } + wbLog(ERROR, "Ran out of file handles."); + wbExit(); + return -1; +} + +wbFile_t wbFile_new(void) { + int idx = wbFile_nextIndex(); + wbFile_t file = wbNew(struct st_wbFile_t); + + wbAssert(idx >= 0); + + wbFile_setIndex(file, idx); + wbFile_setFileName(file, NULL); + wbFile_setMode(file, NULL); + wbFile_setFileHandle(file, NULL); + wbFile_setData(file, NULL); + + wbFile_handles[idx] = file; + + return file; +} + +void wbFile_delete(wbFile_t file) { + if (file != NULL) { + int idx = wbFile_getIndex(file); + if (wbFile_getFileName(file) != NULL) { + wbDelete(wbFile_getFileName(file)); + } + if (wbFile_getMode(file) != NULL) { + wbDelete(wbFile_getMode(file)); + } + if (wbFile_getFileHandle(file) != NULL) { + fflush(wbFile_getFileHandle(file)); + fclose(wbFile_getFileHandle(file)); + } + if (idx >= 0) { + wbAssert(wbFile_handles[idx] == file); + wbFile_handles[idx] = NULL; + } + if (wbFile_getData(file) != NULL) { + wbDelete(wbFile_getData(file)); + } + wbDelete(file); + } +} + +void wbFile_init(void) { + int ii; + + for (ii = 0; ii < wbFile_maxCount; ii++) { + wbFile_handles[ii] = NULL; + } +} + +void wbFile_atExit(void) { + int ii; + + for (ii = 0; ii < wbFile_maxCount; ii++) { + if (wbFile_handles[ii] != NULL) { + wbFile_delete(wbFile_handles[ii]); + } + } +} + +int wbFile_count(void) { + int ii, count = 0; + + for (ii = 0; ii < wbFile_maxCount; ii++) { + if (wbFile_handles[ii] != NULL) { + count++; + } + } + return count; +} + +wbFile_t wbFile_open(const char *fileName, const char *mode) { + FILE *handle; + wbFile_t file; + + if (fileName == NULL) { + return NULL; + } + + handle = fopen(fileName, mode); + if (handle == NULL) { + wbLog(ERROR, "Failed to open ", file, " in mode ", mode); + return NULL; + } + + file = wbFile_new(); + wbFile_setFileName(file, wbString_duplicate(fileName)); + wbFile_setMode(file, wbString_duplicate(mode)); + wbFile_setFileHandle(file, handle); + + return file; +} + +wbFile_t wbFile_open(const char *fileName) { + return wbFile_open(fileName, "r"); +} + +void wbFile_close(wbFile_t file) { + wbFile_delete(file); +} + +char *wbFile_read(wbFile_t file, size_t size, size_t count) { + size_t res; + char *buffer; + size_t bufferLen; + FILE *handle; + + if (file == NULL) { + return NULL; + } +#ifndef LAZY_FILE_LOAD + if (wbFile_getData(file) != NULL) { + char *data = wbFile_getData(file) + wbFile_getDataOffset(file); + wbFile_setDataOffset(file, wbFile_getDataOffset(file) + size * count); + return data; + } +#endif /* LAZY_FILE_LOAD */ + + handle = wbFile_getFileHandle(file); + bufferLen = size * count + 1; + buffer = wbNewArray(char, bufferLen); + + res = fread(buffer, size, count, handle); + // make valid C string + buffer[size * res] = '\0'; + + return buffer; +} + +char *wbFile_read(wbFile_t file, size_t len) { + char *buffer = wbFile_read(file, sizeof(char), len); + return buffer; +} + +void wbFile_rewind(wbFile_t file) { + if (file == NULL) { + return; + } + + if (wbFile_getData(file) == NULL) { + FILE *handle; + handle = wbFile_getFileHandle(file); + wbAssert(handle != NULL); + rewind(handle); + } +#ifndef LAZY_FILE_LOAD + else { + wbFile_setDataOffset(file, 0); + } +#endif + + return; +} + +size_t wbFile_size(wbFile_t file) { + size_t len; + FILE *handle; + + if (file == NULL) { + return 0; + } +#ifndef LAZY_FILE_LOAD + if (wbFile_getData(file) != NULL) { + if (wbFile_getLength(file) == 0) { + wbFile_setLength(file, strlen(wbFile_getData(file))); + } + return wbFile_getLength(file); + } +#endif /* LAZY_FILE_LOAD */ + + handle = wbFile_getFileHandle(file); + + fseek(handle, 0, SEEK_END); + len = ftell(handle); + rewind(handle); + + return len; +} + +char *wbFile_read(wbFile_t file) { + size_t len; + + if (file == NULL) { + return NULL; + } + + len = wbFile_size(file); + + if (len == 0) { + return NULL; + } + + wbFile_setLength(file, len); + + return wbFile_read(file, len); +} + +#define MAX_CHARS_PER_LINE (1 << 17) + +static char buffer[MAX_CHARS_PER_LINE]; + +char *wbFile_readLine(wbFile_t file) { + if (file == NULL) { + return NULL; + } +#ifdef LAZY_FILE_LOAD + FILE *handle; + memset(buffer, 0, MAX_CHARS_PER_LINE); + + handle = wbFile_getFileHandle(file); + + if (fgets(buffer, MAX_CHARS_PER_LINE - 1, handle)) { + return buffer; + } else { + // wbLog(ERROR, "Was not able to read line from ", + // wbFile_getFileName(file)); + return NULL; + } +#else + size_t newOffset; + size_t lenToNewLine = 0; + const char *tmp; + + if (wbFile_getData(file) == NULL) { + wbFile_setData(file, wbFile_read(file)); + fclose(wbFile_getFileHandle(file)); + wbFile_setFileHandle(file, NULL); + wbFile_setDataOffset(file, 0); + wbFile_setLength(file, strlen(wbFile_getData(file))); + } + + memset(buffer, 0, MAX_CHARS_PER_LINE); + + if (wbFile_getDataOffset(file) >= wbFile_getLength(file)) { + return NULL; + } + + newOffset = wbFile_getDataOffset(file); + tmp = wbFile_getData(file) + wbFile_getDataOffset(file); + while (newOffset < wbFile_getLength(file) && *tmp != '\n') { + tmp++; + lenToNewLine++; + newOffset++; + } + + memcpy(buffer, wbFile_getData(file) + wbFile_getDataOffset(file), + lenToNewLine); + wbFile_setDataOffset(file, newOffset + 1); + + return buffer; +#endif +} + +void wbFile_write(wbFile_t file, const void *buffer, size_t size, + size_t count) { + size_t res; + FILE *handle; + + if (file == NULL) { + return; + } + + handle = wbFile_getFileHandle(file); + + res = fwrite(buffer, size, count, handle); + if (res != count) { + wbLog(ERROR, "Failed to write data to ", wbFile_getFileName(file)); + } + + return; +} + +void wbFile_write(wbFile_t file, const void *buffer, size_t len) { + wbFile_write(file, buffer, sizeof(char), len); + return; +} + +void wbFile_write(wbFile_t file, const char *buffer) { + size_t len; + + len = strlen(buffer); + wbFile_write(file, buffer, len); + + return; +} + +void wbFile_writeLine(wbFile_t file, const char *buffer0) { + string buffer = wbString(buffer0, "\n"); + wbFile_write(file, buffer.c_str()); +} + +void wbFile_write(wbFile_t file, string buffer) { + wbFile_write(file, buffer.c_str()); +} + +void wbFile_writeLine(wbFile_t file, string buffer0) { + string buffer = buffer0 + "\n"; + wbFile_write(file, buffer.c_str()); +} + +wbBool wbFile_existsQ(const char *path) { + if (path == NULL) { + return wbFalse; + } else { + FILE *file = fopen(path, "r"); + if (file != NULL) { + fclose(file); + return wbTrue; + } + return wbFalse; + } +} + +char *wbFile_extension(const char *file) { + char *extension; + char *extensionLower; + char *end; + size_t len; + + len = strlen(file); + end = (char *)&file[len - 1]; + while (*end != '.') { + end--; + } + if (*end == '.') { + end++; + } + + extension = wbString_duplicate(end); + extensionLower = wbString_toLower(extension); + wbDelete(extension); + + return extensionLower; +} diff --git a/OpenCL_VectorAdd/libwb/wbFile.h b/OpenCL_VectorAdd/libwb/wbFile.h new file mode 100644 index 0000000..ea6b0cb --- /dev/null +++ b/OpenCL_VectorAdd/libwb/wbFile.h @@ -0,0 +1,56 @@ + + +#ifndef __WB_FILE_H__ +#define __WB_FILE_H__ + +struct st_wbFile_t { + int index; + char *file; + char *mode; + char *data; + FILE *handle; + size_t len; + size_t offset; +}; + +#define wbFile_getIndex(file) ((file)->index) +#define wbFile_getFileName(file) ((file)->file) +#define wbFile_getMode(file) ((file)->mode) +#define wbFile_getData(file) ((file)->data) +#define wbFile_getLength(file) ((file)->len) +#define wbFile_getDataOffset(file) ((file)->offset) +#define wbFile_getFileHandle(file) ((file)->handle) + +#define wbFile_setIndex(file, val) (wbFile_getIndex(file) = val) +#define wbFile_setFileName(file, val) (wbFile_getFileName(file) = val) +#define wbFile_setMode(file, val) (wbFile_getMode(file) = val) +#define wbFile_setData(file, val) (wbFile_getData(file) = val) +#define wbFile_setLength(file, val) (wbFile_getLength(file) = val) +#define wbFile_setDataOffset(file, val) (wbFile_getDataOffset(file) = val) +#define wbFile_setFileHandle(file, val) (wbFile_getFileHandle(file) = val) + +wbFile_t wbFile_new(void); +void wbFile_delete(wbFile_t file); +void wbFile_close(wbFile_t file); +void wbFile_init(void); +void wbFile_atExit(void); +int wbFile_count(void); +wbFile_t wbFile_open(const char *fileName, const char *mode); +wbFile_t wbFile_open(const char *fileName); +char *wbFile_read(wbFile_t file, size_t size, size_t count); +char *wbFile_read(wbFile_t file, size_t len); +void wbFile_rewind(wbFile_t file); +size_t wbFile_size(wbFile_t file); +char *wbFile_read(wbFile_t file); +char *wbFile_readLine(wbFile_t file); +void wbFile_write(wbFile_t file, const void *buffer, size_t size, + size_t count); +void wbFile_write(wbFile_t file, const void *buffer, size_t len); +void wbFile_write(wbFile_t file, const char *buffer); +void wbFile_writeLine(wbFile_t file, const char *buffer0); +void wbFile_write(wbFile_t file, string buffer); +void wbFile_writeLine(wbFile_t file, string buffer0); +wbBool wbFile_existsQ(const char *path); +char *wbFile_extension(const char *file); + +#endif /* __WB_FILE_H__ */ diff --git a/OpenCL_VectorAdd/libwb/wbImage.cpp b/OpenCL_VectorAdd/libwb/wbImage.cpp new file mode 100644 index 0000000..1d95928 --- /dev/null +++ b/OpenCL_VectorAdd/libwb/wbImage.cpp @@ -0,0 +1,134 @@ + + +#include "wb.h" + +static inline float _min(float x, float y) { + return x < y ? x : y; +} + +static inline float _max(float x, float y) { + return x > y ? x : y; +} + +static inline float _clamp(float x, float start, float end) { + return _min(_max(x, start), end); +} + +wbImage_t wbImage_new(int width, int height, int channels, float *data) { + wbImage_t img; + + img = wbNew(struct st_wbImage_t); + + wbImage_setWidth(img, width); + wbImage_setHeight(img, height); + wbImage_setChannels(img, channels); + wbImage_setPitch(img, width * channels); + + wbImage_setData(img, data); + return img; +} + +wbImage_t wbImage_new(int width, int height, int channels) { + float *data = wbNewArray(float, width *height *channels); + return wbImage_new(width, height, channels, data); +} + +wbImage_t wbImage_new(int width, int height) { + return wbImage_new(width, height, wbImage_channels); +} + +void wbImage_delete(wbImage_t img) { + if (img != NULL) { + if (wbImage_getData(img) != NULL) { + wbDelete(wbImage_getData(img)); + } + wbDelete(img); + } +} + +static inline void wbImage_setPixel(wbImage_t img, int x, int y, int c, + float val) { + float *data = wbImage_getData(img); + int channels = wbImage_getChannels(img); + int pitch = wbImage_getPitch(img); + + data[y * pitch + x * channels + c] = val; + + return; +} + +static inline float wbImage_getPixel(wbImage_t img, int x, int y, int c) { + float *data = wbImage_getData(img); + int channels = wbImage_getChannels(img); + int pitch = wbImage_getPitch(img); + + return data[y * pitch + x * channels + c]; +} + +wbBool wbImage_sameQ(wbImage_t a, wbImage_t b, + wbImage_onSameFunction_t onUnSame) { + if (a == NULL || b == NULL) { + wbLog(ERROR, "Comparing null images."); + return wbFalse; + } else if (a == b) { + return wbTrue; + } else if (wbImage_getWidth(a) != wbImage_getWidth(b)) { + wbLog(ERROR, "Image widths do not match."); + return wbFalse; + } else if (wbImage_getHeight(a) != wbImage_getHeight(b)) { + wbLog(ERROR, "Image heights do not match."); + return wbFalse; + } else if (wbImage_getChannels(a) != wbImage_getChannels(b)) { + wbLog(ERROR, "Image channels do not match."); + return wbFalse; + } else { + float *aData, *bData; + int width, height, channels; + int ii, jj, kk; + + aData = wbImage_getData(a); + bData = wbImage_getData(b); + + wbAssert(aData != NULL); + wbAssert(bData != NULL); + + width = wbImage_getWidth(a); + height = wbImage_getHeight(a); + channels = wbImage_getChannels(a); + + for (ii = 0; ii < height; ii++) { + for (jj = 0; jj < width; jj++) { + for (kk = 0; kk < channels; kk++) { + float x, y; + if (channels <= 3) { + x = _clamp(*aData++, 0, 1); + y = _clamp(*bData++, 0, 1); + } else { + x = *aData++; + y = *bData++; + } + if (wbUnequalQ(x, y)) { + if (onUnSame != NULL) { + string str = wbString( + "Image pixels do not match at position ( row = ", + wbString(ii, ", col = ", jj, ", channel = ", kk, + ") expecting a value of "), + wbString(y, " but got a computed value of ", x)); + onUnSame(str); + } + return wbFalse; + } + } + } + } + return wbTrue; + } +} + +static void wbImage_onUnsameFunction(string str) { + wbLog(ERROR, str); +} + +wbBool wbImage_sameQ(wbImage_t a, wbImage_t b) { + return wbImage_sameQ(a, b, wbImage_onUnsameFunction); +} diff --git a/OpenCL_VectorAdd/libwb/wbImage.h b/OpenCL_VectorAdd/libwb/wbImage.h new file mode 100644 index 0000000..020eec5 --- /dev/null +++ b/OpenCL_VectorAdd/libwb/wbImage.h @@ -0,0 +1,40 @@ + + +#ifndef __IMAGE_H__ +#define __IMAGE_H__ + +#include "wbTypes.h" + +struct st_wbImage_t { + int width; + int height; + int channels; + int pitch; + float *data; +}; + +#define wbImage_channels 3 + +#define wbImage_getWidth(img) ((img)->width) +#define wbImage_getHeight(img) ((img)->height) +#define wbImage_getChannels(img) ((img)->channels) +#define wbImage_getPitch(img) ((img)->pitch) +#define wbImage_getData(img) ((img)->data) + +#define wbImage_setWidth(img, val) (wbImage_getWidth(img) = val) +#define wbImage_setHeight(img, val) (wbImage_getHeight(img) = val) +#define wbImage_setChannels(img, val) (wbImage_getChannels(img) = val) +#define wbImage_setPitch(img, val) (wbImage_getPitch(img) = val) +#define wbImage_setData(img, val) (wbImage_getData(img) = val) + +typedef void (*wbImage_onSameFunction_t)(string str); + +wbImage_t wbImage_new(int width, int height, int channels, float *data); +wbImage_t wbImage_new(int width, int height, int channels); +wbImage_t wbImage_new(int width, int height); +void wbImage_delete(wbImage_t img); +wbBool wbImage_sameQ(wbImage_t a, wbImage_t b, + wbImage_onSameFunction_t onUnSame); +wbBool wbImage_sameQ(wbImage_t a, wbImage_t b); + +#endif /* __IMAGE_H__ */ diff --git a/OpenCL_VectorAdd/libwb/wbImport.cpp b/OpenCL_VectorAdd/libwb/wbImport.cpp new file mode 100644 index 0000000..fccc071 --- /dev/null +++ b/OpenCL_VectorAdd/libwb/wbImport.cpp @@ -0,0 +1,711 @@ + + +#include "wb.h" + +static inline void wbImportCSV_setFile(wbImportCSV_t csv, + const char *path) { + if (csv != NULL) { + if (wbImportCSV_getFile(csv) != NULL) { + wbFile_delete(wbImportCSV_getFile(csv)); + } + if (path != NULL) { + wbImportCSV_getFile(csv) = wbFile_open(path, "r"); + } else { + wbImportCSV_getFile(csv) = NULL; + } + } + + return; +} + +static inline wbImportCSV_t wbImportCSV_new(void) { + wbImportCSV_t csv; + + csv = wbNew(struct st_wbImportCSV_t); + + wbImportCSV_setRowCount(csv, -1); + wbImportCSV_setColumnCount(csv, -1); + wbImportCSV_setData(csv, NULL); + wbImportCSV_getFile(csv) = NULL; + wbImportCSV_setSeperator(csv, '\0'); + + return csv; +} + +static inline void wbImportCSV_delete(wbImportCSV_t csv) { + if (csv != NULL) { + wbImportCSV_setFile(csv, NULL); + if (wbImportCSV_getData(csv)) { + wbDelete(wbImportCSV_getData(csv)); + } + wbDelete(csv); + } +} + +static inline wbImportCSV_t wbImportCSV_findDimensions(wbImportCSV_t csv, + int *resRows, + int *resColumns) { + int rows = 0, columns = -1; + char *line; + wbFile_t file; + char seperator[2]; + + if (csv == NULL) { + return NULL; + } + + if (wbImportCSV_getSeperator(csv) == '\0') { + seperator[0] = ','; + } else { + seperator[0] = wbImportCSV_getSeperator(csv); + } + seperator[1] = '\0'; + + file = wbImportCSV_getFile(csv); + + while ((line = wbFile_readLine(file)) != NULL) { + int currColumn = 0; + char *token = strtok(line, seperator); + while (token != NULL) { + token = strtok(NULL, seperator); + currColumn++; + } + rows++; + if (columns == -1) { + columns = currColumn; + } + if (columns != currColumn) { + wbLog(ERROR, "The csv file is not rectangular."); + } + wbAssert(columns == currColumn); + } + + wbFile_rewind(file); + + *resRows = rows; + *resColumns = columns; + + return csv; +} + +static inline int *csv_readAsInteger(wbFile_t file, char sep, int rows, + int columns) { + int ii = 0; + int *data; + char *line; + int var; + char seperator[2]; + + if (file == NULL) { + return NULL; + } + + data = wbNewArray(int, rows *columns); + + if (sep == '\0') { + seperator[0] = ','; + } else { + seperator[0] = sep; + } + seperator[1] = '\0'; + + // printf("cols = %d rows = %d\n", columns, rows); + if (columns == 1) { + while ((line = wbFile_readLine(file)) != NULL) { + sscanf(line, "%d", &var); + // printf("reading %d\n", var); + data[ii++] = var; + } + } else { + while ((line = wbFile_readLine(file)) != NULL) { + char *token = strtok(line, seperator); + while (token != NULL) { + sscanf(token, "%d", &var); + token = strtok(NULL, seperator); + data[ii++] = var; + } + } + } + + return data; +} + +static inline wbReal_t *csv_readAsReal(wbFile_t file, char sep, int rows, + int columns) { + int ii = 0; + wbReal_t *data; + char *line; + wbReal_t var; + char seperator[2]; + + if (file == NULL) { + return NULL; + } + + data = wbNewArray(wbReal_t, rows * columns); + + if (sep == '\0') { + seperator[0] = ','; + } else { + seperator[0] = sep; + } + seperator[1] = '\0'; + + if (columns == 1) { + while ((line = wbFile_readLine(file)) != NULL) { + sscanf(line, "%f", &var); + data[ii++] = var; + } + } else { + while ((line = wbFile_readLine(file)) != NULL) { + char *token = strtok(line, seperator); + while (token != NULL) { + sscanf(token, "%f", &var); + token = strtok(NULL, seperator); + data[ii++] = var; + } + } + } + + return data; +} + +static inline wbImportCSV_t wbImportCSV_read(wbImportCSV_t csv, + wbType_t type) { + void *data; + wbFile_t file; + char seperator; + int rows, columns; + + if (csv == NULL) { + return NULL; + } + + if (wbImportCSV_getRowCount(csv) == -1 || + wbImportCSV_getColumnCount(csv) == -1) { + if (wbImportCSV_findDimensions(csv, &rows, &columns) == NULL) { + wbLog(ERROR, "Failed to figure out csv dimensions."); + return NULL; + } + wbImportCSV_setRowCount(csv, rows); + wbImportCSV_setColumnCount(csv, columns); + } + + file = wbImportCSV_getFile(csv); + seperator = wbImportCSV_getSeperator(csv); + rows = wbImportCSV_getRowCount(csv); + columns = wbImportCSV_getColumnCount(csv); + + if (wbImportCSV_getData(csv) != NULL) { + wbDelete(wbImportCSV_getData(csv)); + wbImportCSV_setData(csv, NULL); + } + + if (type == wbType_integer) { + // printf("ReadXXXing as integer...\n"); + data = csv_readAsInteger(file, seperator, rows, columns); + } else { + data = csv_readAsReal(file, seperator, rows, columns); + } + + wbImportCSV_setData(csv, data); + + return csv; +} + +static inline wbImportCSV_t wbImportCSV_readAsInteger(wbImportCSV_t csv) { + return wbImportCSV_read(csv, wbType_integer); +} + +static inline wbImportCSV_t wbImportCSV_readAsReal(wbImportCSV_t csv) { + return wbImportCSV_read(csv, wbType_real); +} + +static inline void wbImportRaw_setFile(wbImportRaw_t raw, + const char *path) { + if (raw != NULL) { + if (wbImportRaw_getFile(raw) != NULL) { + wbFile_delete(wbImportRaw_getFile(raw)); + } + if (path != NULL) { + wbImportRaw_getFile(raw) = wbFile_open(path, "r"); + } else { + wbImportRaw_getFile(raw) = NULL; + } + } + + return; +} + +static inline wbImportRaw_t wbImportRaw_new(void) { + wbImportRaw_t raw; + + raw = wbNew(struct st_wbImportRaw_t); + + wbImportRaw_setRowCount(raw, -1); + wbImportRaw_setColumnCount(raw, -1); + wbImportRaw_setData(raw, NULL); + wbImportRaw_getFile(raw) = NULL; + + return raw; +} + +static inline void wbImportRaw_delete(wbImportRaw_t raw) { + if (raw != NULL) { + wbImportRaw_setFile(raw, NULL); + if (wbImportRaw_getData(raw)) { + wbDelete(wbImportRaw_getData(raw)); + } + wbDelete(raw); + } +} + +static inline wbBool lineHasSpace(const char *line) { + while (*line != '\0') { + if (*line == ' ') { + return wbTrue; + } + line++; + } + return wbFalse; +} + +static inline char *lineStrip(const char *line) { + char *sl = wbString_duplicate(line); + char *iter = sl; + size_t slen = strlen(line); + + iter += slen - 1; + while (*iter == '\0' || *iter == '\r' || *iter == '\t' || + *iter == '\n' || *iter == ' ') { + *iter-- = '\0'; + } + return sl; +} + +static inline wbBool wbImportRaw_findDimensions(wbImportRaw_t raw) { + if (raw != NULL) { + int rows; + int columns; + char *line; + wbFile_t file; + char *strippedLine; + + file = wbImportRaw_getFile(raw); + + wbFile_rewind(file); + + line = wbFile_readLine(file); + + if (line == NULL) { + return wbTrue; + } + + strippedLine = lineStrip(line); + + if (lineHasSpace(strippedLine)) { + sscanf(strippedLine, "%d %d", &rows, &columns); + } else { + columns = 1; + sscanf(strippedLine, "%d", &rows); + } + + wbImportRaw_setRowCount(raw, rows); + wbImportRaw_setColumnCount(raw, columns); + + wbDelete(strippedLine); + + return wbFalse; + } + + return wbTrue; +} + +static inline wbImportRaw_t wbImportRaw_read(wbImportRaw_t raw, + wbType_t type) { + void *data; + wbFile_t file; + char seperator; + int rows, columns; + + if (raw == NULL) { + return NULL; + } + + if (wbImportRaw_getRowCount(raw) == -1 || + wbImportRaw_getColumnCount(raw) == -1) { + if (wbImportRaw_findDimensions(raw)) { + wbLog(ERROR, "Failed to figure out raw dimensions."); + return NULL; + } + } + + file = wbImportRaw_getFile(raw); + seperator = ' '; + rows = wbImportRaw_getRowCount(raw); + columns = wbImportRaw_getColumnCount(raw); + + if (wbImportRaw_getData(raw) != NULL) { + wbDelete(wbImportRaw_getData(raw)); + wbImportRaw_setData(raw, NULL); + } + + if (type == wbType_integer) { + // printf("Rdin gas integer...\n"); + data = csv_readAsInteger(file, seperator, rows, columns); + } else { + data = csv_readAsReal(file, seperator, rows, columns); + } + + wbImportRaw_setData(raw, data); + + return raw; +} + +static inline wbImportRaw_t wbImportRaw_readAsInteger(wbImportRaw_t raw) { + return wbImportRaw_read(raw, wbType_integer); +} + +static inline wbImportRaw_t wbImportRaw_readAsReal(wbImportRaw_t raw) { + return wbImportRaw_read(raw, wbType_real); +} + +static inline wbImportText_t wbImportText_new(void) { + wbImportText_t text; + + text = wbNew(struct st_wbImportText_t); + + wbImportText_setLength(text, 0); + wbImportText_setData(text, NULL); + wbImportText_getFile(text) = NULL; + + return text; +} + +static inline void wbImportText_setFile(wbImportText_t text, + const char *path) { + if (text != NULL) { + if (wbImportText_getFile(text) != NULL) { + wbFile_delete(wbImportText_getFile(text)); + } + if (path != NULL) { + wbImportText_getFile(text) = wbFile_open(path, "r"); + } else { + wbImportText_getFile(text) = NULL; + } + } + + return; +} + +static inline void wbImportText_delete(wbImportText_t text) { + if (text != NULL) { + wbImportText_setFile(text, NULL); + if (wbImportText_getData(text)) { + wbDelete(wbImportText_getData(text)); + } + wbDelete(text); + } +} + +static inline wbImportText_t wbImportText_read(wbImportText_t text) { + char *data; + wbFile_t file; + int length; + + if (text == NULL) { + return NULL; + } + + file = wbImportText_getFile(text); + + if (wbImportText_getData(text) != NULL) { + wbDelete(wbImportText_getData(text)); + wbImportText_setData(text, NULL); + } + + length = wbFile_size(file); + data = wbFile_read(file, length); + + wbImportText_setData(text, data); + wbImportText_setLength(text, length); + + return text; +} + +static inline wbImport_t wbImport_open(const char *file, + wbImportKind_t kind) { + wbImport_t imp; + + if (file == NULL) { + wbLog(ERROR, "Go NULL for file value."); + wbExit(); + } + + if (!wbFile_existsQ(file)) { + wbLog(ERROR, "File ", file, " does not exist."); + wbExit(); + } + + wbImport_setKind(imp, kind); + + if (kind == wbImportKind_raw) { + wbImportRaw_t raw = wbImportRaw_new(); + wbImportRaw_setFile(raw, file); + wbImport_setRaw(imp, raw); + } else if (kind == wbImportKind_tsv || kind == wbImportKind_csv) { + wbImportCSV_t csv = wbImportCSV_new(); + if (kind == wbImportKind_csv) { + wbImportCSV_setSeperator(csv, ','); + } else { + wbImportCSV_setSeperator(csv, '\t'); + } + wbImportCSV_setFile(csv, file); + wbImport_setCSV(imp, csv); + } else if (kind == wbImportKind_text) { + wbImportText_t text = wbImportText_new(); + wbImportText_setFile(text, file); + wbImport_setText(imp, text); + } else if (kind == wbImportKind_ppm) { + wbImage_t img = wbPPM_import(file); + wbImport_setImage(imp, img); + } else { + wbLog(ERROR, "Invalid import type."); + wbExit(); + } + + return imp; +} + +static inline wbImport_t wbImport_open(const char *file, + const char *type0) { + wbImport_t imp; + wbImportKind_t kind; + char *type; + + type = wbString_toLower(type0); + + if (wbString_sameQ(type, "csv")) { + kind = wbImportKind_csv; + } else if (wbString_sameQ(type, "tsv")) { + kind = wbImportKind_tsv; + } else if (wbString_sameQ(type, "raw") || wbString_sameQ(type, "dat")) { + kind = wbImportKind_raw; + } else if (wbString_sameQ(type, "ppm")) { + kind = wbImportKind_ppm; + } else if (wbString_sameQ(type, "text") || wbString_sameQ(type, "txt")) { + kind = wbImportKind_text; + } else { + wbLog(ERROR, "Invalid import type ", type0); + wbExit(); + } + + imp = wbImport_open(file, kind); + + wbDelete(type); + + return imp; +} + +static inline void wbImport_close(wbImport_t imp) { + wbImportKind_t kind; + + kind = wbImport_getKind(imp); + if (kind == wbImportKind_tsv || kind == wbImportKind_csv) { + wbImportCSV_t csv = wbImport_getCSV(imp); + wbImportCSV_delete(csv); + wbImport_setCSV(imp, NULL); + } else if (kind == wbImportKind_raw) { + wbImportRaw_t raw = wbImport_getRaw(imp); + wbImportRaw_delete(raw); + wbImport_setRaw(imp, NULL); + } else if (kind == wbImportKind_text) { + wbImportText_t text = wbImport_getText(imp); + wbImportText_delete(text); + wbImport_setText(imp, NULL); + } else if (kind == wbImportKind_ppm) { + } else { + wbLog(ERROR, "Invalid import type."); + wbExit(); + } + return; +} + +static inline void *wbImport_read(wbImport_t imp, wbType_t type) { + void *data = NULL; + wbImportKind_t kind; + + kind = wbImport_getKind(imp); + if (kind == wbImportKind_tsv || kind == wbImportKind_csv) { + wbImportCSV_t csv = wbImport_getCSV(imp); + wbImportCSV_read(csv, type); + data = wbImportCSV_getData(csv); + } else if (kind == wbImportKind_raw) { + wbImportRaw_t raw = wbImport_getRaw(imp); + wbImportRaw_read(raw, type); + data = wbImportRaw_getData(raw); + } else if (wbImportKind_text == kind) { + wbImportText_t text = wbImport_getText(imp); + text = wbImportText_read(text); + data = wbImportText_getData(text); + + } else { + wbLog(ERROR, "Invalid import type."); + wbExit(); + } + return data; +} + +static inline int *wbImport_readAsInteger(wbImport_t imp) { + void *data = wbImport_read(imp, wbType_integer); + return (int *)data; +} + +static inline wbReal_t *wbImport_readAsReal(wbImport_t imp) { + void *data = wbImport_read(imp, wbType_real); + return (wbReal_t *)data; +} + +static inline wbChar_t *wbImport_readAsText(wbImport_t imp) { + void *data = wbImport_read(imp, wbType_ubit8); + return (wbChar_t *)data; +} + +static wbImportKind_t _parseImportExtension(const char *file) { + char *extension; + wbImportKind_t kind; + + extension = wbFile_extension(file); + + if (wbString_sameQ(extension, "csv")) { + kind = wbImportKind_csv; + } else if (wbString_sameQ(extension, "tsv")) { + kind = wbImportKind_tsv; + } else if (wbString_sameQ(extension, "raw") || + wbString_sameQ(extension, "dat")) { + kind = wbImportKind_raw; + } else if (wbString_sameQ(extension, "ppm") || + wbString_sameQ(extension, "pbm")) { + kind = wbImportKind_ppm; + } else if (wbString_sameQ(extension, "text") || + wbString_sameQ(extension, "txt")) { + kind = wbImportKind_text; + } else { + kind = wbImportKind_unknown; + wbLog(ERROR, "File ", file, " does not have a compatible extension."); + } + + wbDelete(extension); + + return kind; +} + +void *wbImport(const char *file, int *resRows, int *resColumns, + const char *type) { + void *data, *res; + wbImport_t imp; + size_t sz; + int columns = 0, rows = 0; + wbImportKind_t kind; + + if (file == NULL) { + fprintf(stderr, "Failed to import file.\n"); + wbExit(); + } + + kind = _parseImportExtension(file); + + wbAssert(kind != wbImportKind_unknown); + + imp = wbImport_open(file, kind); + if (wbString_sameQ(type, "Real")) { + data = wbImport_readAsReal(imp); + sz = sizeof(wbReal_t); + } else if (wbString_sameQ(type, "Text")) { + data = wbImport_readAsText(imp); + sz = sizeof(char); + } else { + // printf("Reading as integer..d\n"); + data = wbImport_readAsInteger(imp); + sz = sizeof(int); + } + + if (kind == wbImportKind_csv || kind == wbImportKind_tsv) { + rows = wbImportCSV_getRowCount(wbImport_getCSV(imp)); + columns = wbImportCSV_getColumnCount(wbImport_getCSV(imp)); + } else if (kind == wbImportKind_raw) { + rows = wbImportRaw_getRowCount(wbImport_getRaw(imp)); + columns = wbImportRaw_getColumnCount(wbImport_getRaw(imp)); + } else if (kind == wbImportKind_text) { + rows = 1; + columns = wbImportText_getLength(wbImport_getText(imp)); + } + + if (rows == 1 && columns > 0) { + rows = columns; + columns = 1; + } + + if (resRows != NULL) { + *resRows = rows; + } + + if (resColumns != NULL) { + *resColumns = columns; + } + + res = wbMalloc(sz * rows * columns); + memcpy(res, data, sz * rows * columns); + + wbImport_close(imp); + + return res; +} + +void *wbImport(const char *file, int *rows, int *columns) { + return wbImport(file, rows, columns, "Real"); +} + +EXTERN_C void *wbImport(const char *file, int *rows) { + return wbImport(file, rows, NULL, "Real"); +} + +void *wbImport(const char *file, int *res_rows, const char *type) { + int cols, rows; + void *res = wbImport(file, &rows, &cols, type); + if (rows == 1 && cols > 1) { + rows = cols; + } + *res_rows = rows; + return res; +} + +wbImage_t wbImport(const char *file) { + wbImage_t img; + wbImport_t imp; + wbImportKind_t kind; + + if (file == NULL) { + fprintf(stderr, "Failed to import file.\n"); + wbExit(); + } + + kind = _parseImportExtension(file); + + wbAssert(kind == wbImportKind_ppm); + + imp = wbImport_open(file, kind); + img = wbImport_getImage(imp); + wbImport_close(imp); + + return img; +} + +int wbImport_flag(const char *file) { + int res; + wbFile_t fh = wbFile_open(file, "r"); + const char *line = wbFile_readLine(fh); + sscanf(line, "%d", &res); + wbFile_close(fh); + return res; +} diff --git a/OpenCL_VectorAdd/libwb/wbImport.h b/OpenCL_VectorAdd/libwb/wbImport.h new file mode 100644 index 0000000..ce13e1b --- /dev/null +++ b/OpenCL_VectorAdd/libwb/wbImport.h @@ -0,0 +1,103 @@ + +#ifndef __WB_IMPORT_H__ +#define __WB_IMPORT_H__ + +#include "wbImage.h" + +typedef enum en_wbImportKind_t { + wbImportKind_unknown = -1, + wbImportKind_raw = 0x1000, + wbImportKind_csv, + wbImportKind_tsv, + wbImportKind_ppm, + wbImportKind_text +} wbImportKind_t; + +#define wbType_real wbType_float + +typedef struct st_wbImportCSV_t { + int rows; + int columns; + void *data; + wbFile_t file; + char seperator; +} * wbImportCSV_t; + +#define wbImportCSV_getRowCount(csv) ((csv)->rows) +#define wbImportCSV_getColumnCount(csv) ((csv)->columns) +#define wbImportCSV_getData(csv) ((csv)->data) +#define wbImportCSV_getFile(csv) ((csv)->file) +#define wbImportCSV_getSeperator(csv) ((csv)->seperator) + +#define wbImportCSV_setRowCount(csv, val) \ + (wbImportCSV_getRowCount(csv) = val) +#define wbImportCSV_setColumnCount(csv, val) \ + (wbImportCSV_getColumnCount(csv) = val) +#define wbImportCSV_setData(csv, val) (wbImportCSV_getData(csv) = val) +#define wbImportCSV_setSeperator(csv, val) \ + (wbImportCSV_getSeperator(csv) = val) + +typedef struct st_wbImportRaw_t { + int rows; + int columns; + void *data; + wbFile_t file; +} * wbImportRaw_t; + +#define wbImportRaw_getRowCount(raw) ((raw)->rows) +#define wbImportRaw_getColumnCount(raw) ((raw)->columns) +#define wbImportRaw_getData(raw) ((raw)->data) +#define wbImportRaw_getFile(raw) ((raw)->file) + +#define wbImportRaw_setRowCount(raw, val) \ + (wbImportRaw_getRowCount(raw) = val) +#define wbImportRaw_setColumnCount(raw, val) \ + (wbImportRaw_getColumnCount(raw) = val) +#define wbImportRaw_setData(raw, val) (wbImportRaw_getData(raw) = val) + +typedef struct st_wbImportText_t { + int length; + char *data; + wbFile_t file; +} * wbImportText_t; + +#define wbImportText_getLength(txt) ((txt)->length) +#define wbImportText_getData(txt) ((txt)->data) +#define wbImportText_getFile(txt) ((txt)->file) + +#define wbImportText_setLength(txt, val) \ + (wbImportText_getLength(txt) = val) +#define wbImportText_setData(txt, val) (wbImportText_getData(txt) = val) + +typedef struct st_wbImport_t { + wbImportKind_t kind; + union { + wbImportRaw_t raw; + wbImportCSV_t csv; + wbImportText_t text; + wbImage_t img; + } container; +} wbImport_t; + +#define wbImport_getKind(imp) ((imp).kind) +#define wbImport_getContainer(imp) ((imp).container) +#define wbImport_getRaw(imp) (wbImport_getContainer(imp).raw) +#define wbImport_getCSV(imp) (wbImport_getContainer(imp).csv) +#define wbImport_getText(imp) (wbImport_getContainer(imp).text) +#define wbImport_getImage(imp) (wbImport_getContainer(imp).img) + +#define wbImport_setKind(imp, val) (wbImport_getKind(imp) = val) +#define wbImport_setRaw(imp, val) (wbImport_getRaw(imp) = val) +#define wbImport_setCSV(imp, val) (wbImport_getCSV(imp) = val) +#define wbImport_setText(imp, val) (wbImport_getText(imp) = val) +#define wbImport_setImage(imp, val) (wbImport_getImage(imp) = val) + +EXTERN_C void *wbImport(const char *file, int *rows); +void *wbImport(const char *file, int *rows, int *columns); +void *wbImport(const char *file, int *rows, const char *type); +void *wbImport(const char *file, int *resRows, int *resColumns, + const char *type); +wbImage_t wbImport(const char *file); +int wbImport_flag(const char *file); + +#endif /* __WB_IMPORT_H__ */ diff --git a/OpenCL_VectorAdd/libwb/wbInit.cpp b/OpenCL_VectorAdd/libwb/wbInit.cpp new file mode 100644 index 0000000..96ebcf3 --- /dev/null +++ b/OpenCL_VectorAdd/libwb/wbInit.cpp @@ -0,0 +1,85 @@ + +#include "wb.h" + +#define MB (1 << 20) +#ifndef WB_DEFAULT_HEAP_SIZE +#define WB_DEFAULT_HEAP_SIZE (1024 * MB) +#endif /* WB_DEFAULT_HEAP_SIZE */ + +static bool _initializedQ = wbFalse; + +#ifndef WB_USE_WINDOWS +__attribute__((__constructor__)) +#endif /* WB_USE_WINDOWS */ +void wb_init(int * +#ifdef WB_USE_MPI + argc +#endif /* WB_USE_MPI */ + , + char *** +#ifdef WB_USE_MPI + argv +#endif /* WB_USE_MPI */ + ) { + if (_initializedQ == wbTrue) { + return; + } +#ifdef WB_USE_MPI + wbMPI_Init(argc, argv); +#endif /* WB_USE_MPI */ + +#ifdef WB_USE_CUDA + CUresult err = cuInit(0); + +/* Select a random GPU */ + +#ifdef WB_USE_MPI + if (rankCount() > 1) { + int deviceCount; + cudaGetDeviceCount(&deviceCount); + srand(time(NULL)); + cudaSetDevice(wbMPI_getRank() % deviceCount); + } else { + int deviceCount; + cudaGetDeviceCount(&deviceCount); + + srand(time(NULL)); + cudaSetDevice(rand() % deviceCount); + } +#else + { + int deviceCount; + cudaGetDeviceCount(&deviceCount); + + srand(time(NULL)); + cudaSetDevice(rand() % deviceCount); + } +#endif /* WB_USE_MPI */ + + cudaDeviceSetLimit(cudaLimitPrintfFifoSize, 1 * MB); + cudaDeviceSetLimit(cudaLimitMallocHeapSize, WB_DEFAULT_HEAP_SIZE); + + cudaDeviceSynchronize(); + +#endif /* WB_USE_CUDA */ + +#ifdef WB_USE_WINDOWS + QueryPerformanceFrequency((LARGE_INTEGER *)&_hrtime_frequency); +#endif /* _MSC_VER */ + + _hrtime(); + + _timer = wbTimer_new(); + _logger = wbLogger_new(); + _initializedQ = wbTrue; + + wbFile_init(); + + solutionJSON = NULL; + +#ifdef WB_USE_MPI + atexit(wbMPI_Exit); +#else /* WB_USE_MPI */ + atexit(wb_atExit); +#endif /* WB_USE_MPI */ +} diff --git a/OpenCL_VectorAdd/libwb/wbInit.h b/OpenCL_VectorAdd/libwb/wbInit.h new file mode 100644 index 0000000..40e8e1c --- /dev/null +++ b/OpenCL_VectorAdd/libwb/wbInit.h @@ -0,0 +1,11 @@ + + +#ifndef __WB_INIT_H__ +#define __WB_INIT_H__ + +#ifndef _MSC_VER +__attribute__((__constructor__)) +#endif /* _MSC_VER */ +void wb_init(int *argc, char ***argv); + +#endif /* __WB_INIT_H__ */ diff --git a/OpenCL_VectorAdd/libwb/wbLogger.cpp b/OpenCL_VectorAdd/libwb/wbLogger.cpp new file mode 100644 index 0000000..c2e2e17 --- /dev/null +++ b/OpenCL_VectorAdd/libwb/wbLogger.cpp @@ -0,0 +1,310 @@ + +#include "wb.h" + +wbLogger_t _logger = NULL; + +static inline wbBool wbLogEntry_hasNext(wbLogEntry_t elem) { + return wbLogEntry_getNext(elem) != NULL; +} + +static inline wbLogEntry_t wbLogEntry_new() { + wbLogEntry_t elem; + + elem = wbNew(struct st_wbLogEntry_t); + + wbLogEntry_setMessage(elem, NULL); + wbLogEntry_setMPIRank(elem, wbMPI_getRank()); + wbLogEntry_setTime(elem, _hrtime()); + + wbLogEntry_setLevel(elem, wbLogLevel_TRACE); + + wbLogEntry_setNext(elem, NULL); + + wbLogEntry_setLine(elem, -1); + wbLogEntry_setFile(elem, NULL); + wbLogEntry_setFunction(elem, NULL); + + return elem; +} + +static inline wbLogEntry_t +wbLogEntry_initialize(wbLogLevel_t level, string msg, const char *file, + const char *fun, int line) { + wbLogEntry_t elem; + + elem = wbLogEntry_new(); + + wbLogEntry_setLevel(elem, level); + + wbLogEntry_setMessage(elem, wbString_duplicate(msg)); + + wbLogEntry_setLine(elem, line); + wbLogEntry_setFile(elem, file); + wbLogEntry_setFunction(elem, fun); + + return elem; +} + +static inline void wbLogEntry_delete(wbLogEntry_t elem) { + if (elem != NULL) { + if (wbLogEntry_getMessage(elem) != NULL) { + wbFree(wbLogEntry_getMessage(elem)); + } + wbDelete(elem); + } + return; +} + +static inline const char *getLevelName(wbLogLevel_t level) { + switch (level) { + case wbLogLevel_unknown: + return "Unknown"; + case wbLogLevel_OFF: + return "Off"; + case wbLogLevel_FATAL: + return "Fatal"; + case wbLogLevel_ERROR: + return "Error"; + case wbLogLevel_WARN: + return "Warn"; + case wbLogLevel_INFO: + return "Info"; + case wbLogLevel_DEBUG: + return "Debug"; + case wbLogLevel_TRACE: + return "Trace"; + } + return NULL; +} + +static inline json11::Json wbLogEntry_toJSONObject(wbLogEntry_t elem) { + json11::Json json = json11::Json::object{ + {"mpi_rank", wbLogEntry_getMPIRank(elem)}, + {"level", getLevelName(wbLogEntry_getLevel(elem))}, + {"file", wbLogEntry_getFile(elem)}, + {"function", wbLogEntry_getFunction(elem)}, + {"line", wbLogEntry_getLine(elem)}, + {"time", wbLogEntry_getTime(elem)}, + {"message", wbLogEntry_getMessage(elem)}, + }; + return json; +} + +static inline string wbLogEntry_toJSON(wbLogEntry_t elem) { + if (elem == NULL) { + return ""; + } else if (WB_USE_JSON11) { + json11::Json json = wbLogEntry_toJSONObject(elem); + return json.string_value(); + } else { + stringstream ss; + + ss << "{\n"; + ss << wbString_quote("mpi_rank") << ":" + << wbString(wbLogEntry_getMPIRank(elem)) << ",\n"; + ss << wbString_quote("level") << ":" + << wbString_quote(getLevelName(wbLogEntry_getLevel(elem))) << ",\n"; + ss << wbString_quote("message") << ":" + << wbString_quote(wbLogEntry_getMessage(elem)) << ",\n"; + ss << wbString_quote("file") << ":" + << wbString_quote(wbLogEntry_getFile(elem)) << ",\n"; + ss << wbString_quote("function") << ":" + << wbString_quote(wbLogEntry_getFunction(elem)) << ",\n"; + ss << wbString_quote("line") << ":" << wbLogEntry_getLine(elem) + << ",\n"; + ss << wbString_quote("time") << ":" << wbLogEntry_getTime(elem) + << "\n"; + ss << "}"; + + return ss.str(); + } + return ""; +} + +static inline string wbLogEntry_toXML(wbLogEntry_t elem) { + if (elem != NULL) { + stringstream ss; + + ss << "\n"; + ss << "" + << "LoggerElement" + << "\n"; + ss << "" << wbLogEntry_getLevel(elem) << "\n"; + ss << "" << wbLogEntry_getMessage(elem) << "\n"; + ss << "" << wbLogEntry_getFile(elem) << "\n"; + ss << "" << wbLogEntry_getFunction(elem) << "\n"; + ss << "" << wbLogEntry_getLine(elem) << "\n"; + ss << "\n"; + ss << "\n"; + + return ss.str(); + } + return ""; +} + +wbLogger_t wbLogger_new() { + wbLogger_t logger; + + logger = wbNew(struct st_wbLogger_t); + + wbLogger_setLength(logger, 0); + wbLogger_setHead(logger, NULL); + + wbLogger_getLevel(logger) = wbLogLevel_TRACE; + + return logger; +} + +static inline void _wbLogger_setLevel(wbLogger_t logger, + wbLogLevel_t level) { + wbLogger_getLevel(logger) = level; +} + +static inline void _wbLogger_setLevel(wbLogLevel_t level) { + _wbLogger_setLevel(_logger, level); +} + +#define wbLogger_setLevel(level) _wbLogger_setLevel(wbLogLevel_##level) + +void wbLogger_clear(wbLogger_t logger) { + if (logger != NULL) { + wbLogEntry_t tmp; + wbLogEntry_t iter; + + iter = wbLogger_getHead(logger); + while (iter != NULL) { + tmp = wbLogEntry_getNext(iter); + wbLogEntry_delete(iter); + iter = tmp; + } + + wbLogger_setLength(logger, 0); + wbLogger_setHead(logger, NULL); + } +} + +void wbLogger_delete(wbLogger_t logger) { + if (logger != NULL) { + wbLogger_clear(logger); + wbDelete(logger); + } + return; +} + +void wbLogger_append(wbLogLevel_t level, string msg, const char *file, + const char *fun, int line) { + wbLogEntry_t elem; + wbLogger_t logger; + + wb_init(NULL, NULL); + + logger = _logger; + + if (wbLogger_getLevel(logger) < level) { + return; + } + + elem = wbLogEntry_initialize(level, msg, file, fun, line); + +#ifdef wbLogger_printOnLog + if (wbLogger_printOnLog) { + if (level <= wbLogger_getLevel(logger) && elem) { + json11::Json json = json11::Json::object{ +#ifndef _MSC_VER //PMO + { "type", "logger" }, { "data", wbLogEntry_toJSONObject(elem) }}; +#else + { "data", wbLogEntry_toJSONObject(elem) }, { "type", "logger" }}; +#endif + std::cout << json.dump() << std::endl; + } + } +#endif /* wbLogger_printOnLog */ + + if (wbLogger_getHead(logger) == NULL) { + wbLogger_setHead(logger, elem); + } else { + wbLogEntry_t prev = wbLogger_getHead(logger); + + while (wbLogEntry_hasNext(prev)) { + prev = wbLogEntry_getNext(prev); + } + wbLogEntry_setNext(prev, elem); + } + +#if 0 + if (level <= wbLogger_getLevel(logger) && elem) { + const char *levelName = getLevelName(level); + + fprintf(stderr, "= LOG: %s: %s (In %s:%s on line %d). =\n", levelName, + wbLogEntry_getMessage(elem), wbLogEntry_getFile(elem), + wbLogEntry_getFunction(elem), wbLogEntry_getLine(elem)); + } +#endif + + wbLogger_incrementLength(logger); + + return; +} + +string wbLogger_toJSON() { + return wbLogger_toJSON(_logger); +} + +static json11::Json wbLogger_toJSONObject(wbLogger_t logger) { + std::vector elems{}; + + if (logger != NULL) { + wbLogEntry_t iter; + stringstream ss; + + for (iter = wbLogger_getHead(logger); iter != NULL; + iter = wbLogEntry_getNext(iter)) { + elems.push_back(wbLogEntry_toJSONObject(iter)); + } + } + return json11::Json(elems); +} + +string wbLogger_toJSON(wbLogger_t logger) { + if (logger != NULL) { + wbLogEntry_t iter; + stringstream ss; + + for (iter = wbLogger_getHead(logger); iter != NULL; + iter = wbLogEntry_getNext(iter)) { + ss << wbLogEntry_toJSON(iter); + if (wbLogEntry_getNext(iter) != NULL) { + ss << ",\n"; + } + } + + return ss.str(); + } + return ""; +} + +string wbLogger_toXML() { + return wbLogger_toXML(_logger); +} + +string wbLogger_toXML(wbLogger_t logger) { + if (logger != NULL) { + wbLogEntry_t iter; + stringstream ss; + + ss << "\n"; + ss << "" + << "Logger" + << "\n"; + ss << "\n"; + for (iter = wbLogger_getHead(logger); iter != NULL; + iter = wbLogEntry_getNext(iter)) { + ss << wbLogEntry_toXML(iter); + } + ss << "\n"; + ss << "\n"; + + return ss.str(); + } + return ""; +} diff --git a/OpenCL_VectorAdd/libwb/wbLogger.h b/OpenCL_VectorAdd/libwb/wbLogger.h new file mode 100644 index 0000000..b852592 --- /dev/null +++ b/OpenCL_VectorAdd/libwb/wbLogger.h @@ -0,0 +1,87 @@ + +#ifndef __WB_LOGGER_H__ +#define __WB_LOGGER_H__ + +#include + +typedef enum en_wbLogLevel_t { + wbLogLevel_unknown = -1, + wbLogLevel_OFF = 0, + wbLogLevel_FATAL, + wbLogLevel_ERROR, + wbLogLevel_WARN, + wbLogLevel_INFO, + wbLogLevel_DEBUG, + wbLogLevel_TRACE +} wbLogLevel_t; + +struct st_wbLogEntry_t { + int line; + int mpiRank; + char *msg; + uint64_t time; + const char *fun; + const char *file; + wbLogLevel_t level; + wbLogEntry_t next; +}; + +struct st_wbLogger_t { + int length; + wbLogEntry_t head; + wbLogLevel_t level; +}; + +#define wbLogEntry_getMessage(elem) ((elem)->msg) +#define wbLogEntry_getMPIRank(elem) ((elem)->mpiRank) +#define wbLogEntry_getTime(elem) ((elem)->time) +#define wbLogEntry_getLevel(elem) ((elem)->level) +#define wbLogEntry_getNext(elem) ((elem)->next) +#define wbLogEntry_getLine(elem) ((elem)->line) +#define wbLogEntry_getFunction(elem) ((elem)->fun) +#define wbLogEntry_getFile(elem) ((elem)->file) + +#define wbLogEntry_setMessage(elem, val) \ + (wbLogEntry_getMessage(elem) = val) +#define wbLogEntry_setMPIRank(elem, val) \ + (wbLogEntry_getMPIRank(elem) = val) +#define wbLogEntry_setTime(elem, val) (wbLogEntry_getTime(elem) = val) +#define wbLogEntry_setLevel(elem, val) (wbLogEntry_getLevel(elem) = val) +#define wbLogEntry_setNext(elem, val) (wbLogEntry_getNext(elem) = val) +#define wbLogEntry_setLine(elem, val) (wbLogEntry_getLine(elem) = val) +#define wbLogEntry_setFunction(elem, val) \ + (wbLogEntry_getFunction(elem) = val) +#define wbLogEntry_setFile(elem, val) (wbLogEntry_getFile(elem) = val) + +#define wbLogger_getLength(log) ((log)->length) +#define wbLogger_getHead(log) ((log)->head) +#define wbLogger_getLevel(log) ((log)->level) + +#define wbLogger_setLength(log, val) (wbLogger_getLength(log) = val) +#define wbLogger_setHead(log, val) (wbLogger_getHead(log) = val) + +#define wbLogger_incrementLength(log) (wbLogger_getLength(log)++) +#define wbLogger_decrementLength(log) (wbLogger_getLength(log)--) + +#define wbLog(level, ...) \ + wbLogger_append(wbLogLevel_##level, wbString(__VA_ARGS__), wbFile, \ + wbFunction, wbLine) + +extern wbLogger_t _logger; + +wbLogger_t wbLogger_new(); + +void wbLogger_clear(wbLogger_t logger); + +void wbLogger_delete(wbLogger_t logger); + +void wbLogger_append(wbLogLevel_t level, string msg, const char *file, + const char *fun, int line); + +string wbLogger_toXML(wbLogger_t logger); +string wbLogger_toXML(); + +string wbLogger_toJSON(wbLogger_t logger); +string wbLogger_toJSON(); + +#endif /* __WB_LOGGER_H__ */ diff --git a/OpenCL_VectorAdd/libwb/wbMD5.h b/OpenCL_VectorAdd/libwb/wbMD5.h new file mode 100644 index 0000000..e83a8ef --- /dev/null +++ b/OpenCL_VectorAdd/libwb/wbMD5.h @@ -0,0 +1,311 @@ + +/* + * This code implements the MD5 message-digest algorithm. + * The algorithm is due to Ron Rivest. This code was + * written by Colin Plumb in 1993, no copyright is claimed. + * This code is in the public domain; do with it what you wish. + * + * Equivalent code is available from RSA Data Security, Inc. + * This code has been tested against that, and is equivalent, + * except that you don't need to include two pages of legalese + * with every copy. + * + * To compute the message digest of a chunk of bytes, declare an + * MD5Context structure, pass it to MD5Init, call MD5Update as + * needed on buffers full of bytes, and then call MD5Final, which + * will fill a supplied 16-byte array with the digest. + * + * Changed so as no longer to depend on Colin Plumb's `usual.h' header + * definitions; now uses stuff from dpkg's config.h. + * - Ian Jackson . + * Still in the public domain. + */ + +#ifndef __WB_MD5_H__ +#define __WB_MD5_H__ + +#include /* for memcpy() */ +#include /* for stupid systems */ + +#define UWORD32 unsigned int + +#define md5byte unsigned char + +struct MD5Context { + UWORD32 buf[4]; + UWORD32 bytes[2]; + UWORD32 in[16]; +}; + +static void MD5Transform(UWORD32 buf[4], UWORD32 const in[16]); + +static int g_bigEndian = 0; +static int g_endianessDetected = 0; + +static void detectEndianess() { + int nl = 0x12345678; + short ns = 0x1234; + + unsigned char *p = (unsigned char *)(&nl); + unsigned char *sp = (unsigned char *)(&ns); + + if (g_endianessDetected) + return; + if (p[0] == 0x12 && p[1] == 0x34 && p[2] == 0x56 && p[3] == 0x78) { + g_bigEndian = 1; + } else if (p[0] == 0x78 && p[1] == 0x56 && p[2] == 0x34 && + p[3] == 0x12) { + g_bigEndian = 0; + } else { + g_bigEndian = *sp != 0x12; + } + + g_endianessDetected = 1; +} + +static void byteSwap(UWORD32 *buf, unsigned words) { + md5byte *p; + + if (!g_bigEndian) + return; + + p = (md5byte *)buf; + + do { + *buf++ = (UWORD32)((unsigned)p[3] << 8 | p[2]) << 16 | + ((unsigned)p[1] << 8 | p[0]); + p += 4; + } while (--words); +} + +/* + * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious + * initialization constants. + */ +static void MD5Init(struct MD5Context *ctx) { + detectEndianess(); + + ctx->buf[0] = 0x67452301; + ctx->buf[1] = 0xefcdab89; + ctx->buf[2] = 0x98badcfe; + ctx->buf[3] = 0x10325476; + + ctx->bytes[0] = 0; + ctx->bytes[1] = 0; +} + +/* + * Update context to reflect the concatenation of another buffer full + * of bytes. + */ +static void MD5Update(struct MD5Context *ctx, md5byte const *buf, + unsigned len) { + UWORD32 t; + + /* Update byte count */ + + t = ctx->bytes[0]; + if ((ctx->bytes[0] = t + len) < t) + ctx->bytes[1]++; /* Carry from low to high */ + + t = 64 - (t & 0x3f); /* Space available in ctx->in (at least 1) */ + if (t > len) { + memcpy((md5byte *)ctx->in + 64 - t, buf, len); + return; + } + /* First chunk is an odd size */ + memcpy((md5byte *)ctx->in + 64 - t, buf, t); + byteSwap(ctx->in, 16); + MD5Transform(ctx->buf, ctx->in); + buf += t; + len -= t; + + /* Process data in 64-byte chunks */ + while (len >= 64) { + memcpy(ctx->in, buf, 64); + byteSwap(ctx->in, 16); + MD5Transform(ctx->buf, ctx->in); + buf += 64; + len -= 64; + } + + /* Handle any remaining bytes of data. */ + memcpy(ctx->in, buf, len); +} + +/* + * Final wrapup - pad to 64-byte boundary with the bit pattern + * 1 0* (64-bit count of bits processed, MSB-first) + */ +static void MD5Final(md5byte digest[16], struct MD5Context *ctx) { + int count = ctx->bytes[0] & 0x3f; /* Number of bytes in ctx->in */ + md5byte *p = (md5byte *)ctx->in + count; + + /* Set the first char of padding to 0x80. There is always room. */ + *p++ = 0x80; + + /* Bytes of padding needed to make 56 bytes (-8..55) */ + count = 56 - 1 - count; + + if (count < 0) { /* Padding forces an extra block */ + memset(p, 0, count + 8); + byteSwap(ctx->in, 16); + MD5Transform(ctx->buf, ctx->in); + p = (md5byte *)ctx->in; + count = 56; + } + memset(p, 0, count); + byteSwap(ctx->in, 14); + + /* Append length in bits and transform */ + ctx->in[14] = ctx->bytes[0] << 3; + ctx->in[15] = ctx->bytes[1] << 3 | ctx->bytes[0] >> 29; + MD5Transform(ctx->buf, ctx->in); + + byteSwap(ctx->buf, 4); + memcpy(digest, ctx->buf, 16); + memset(&ctx, 0, sizeof(ctx)); /* In case it's sensitive */ +} + +#ifndef ASM_MD5 + +/* The four core functions - F1 is optimized somewhat */ + +/* #define F1(x, y, z) (x & y | ~x & z) */ +#define F1(x, y, z) (z ^ (x & (y ^ z))) +#define F2(x, y, z) F1(z, x, y) +#define F3(x, y, z) (x ^ y ^ z) +#define F4(x, y, z) (y ^ (x | ~z)) + +/* This is the central step in the MD5 algorithm. */ +#define MD5STEP(f, w, x, y, z, in, s) \ + (w += f(x, y, z) + in, w = (w << s | w >> (32 - s)) + x) + +/* + * The core of the MD5 algorithm, this alters an existing MD5 hash to + * reflect the addition of 16 longwords of new data. MD5Update blocks + * the data and converts bytes into longwords for this routine. + */ +static void MD5Transform(UWORD32 buf[4], UWORD32 const in[16]) { + UWORD32 a, b, c, d; + + a = buf[0]; + b = buf[1]; + c = buf[2]; + d = buf[3]; + + MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); + MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); + MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); + MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); + MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); + MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); + MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); + MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); + MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); + MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); + MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); + MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); + MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); + MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); + MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); + MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); + + MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); + MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); + MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); + MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); + MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); + MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); + MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); + MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); + MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); + MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); + MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); + MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); + MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); + MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); + MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); + MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); + + MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); + MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); + MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); + MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); + MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); + MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); + MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); + MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); + MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); + MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); + MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); + MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); + MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); + MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); + MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); + MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); + + MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); + MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); + MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); + MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); + MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); + MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); + MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); + MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); + MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); + MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); + MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); + MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); + MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); + MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); + MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); + MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} + +#endif + +static void MD5_buffer(const unsigned char *buf, unsigned int len, + unsigned char sig[16]) { + struct MD5Context md5; + MD5Init(&md5); + MD5Update(&md5, buf, len); + MD5Final(sig, &md5); +} + +#define wbMD5 MD5_buffer + +#define HEX_STRING "0123456789abcdef" /* to convert to hex */ + +static void wbMD5_sigToString(unsigned char signature[16], char *str, + int len) { + unsigned char *sig_p; + char *str_p, *max_p; + unsigned int high, low; + + str_p = str; + max_p = str + len; + + for (sig_p = (unsigned char *)signature; + sig_p < (unsigned char *)signature + 16; sig_p++) { + high = *sig_p / 16; + low = *sig_p % 16; + /* account for 2 chars */ + if (str_p + 1 >= max_p) { + break; + } + *str_p++ = HEX_STRING[high]; + *str_p++ = HEX_STRING[low]; + } + /* account for 2 chars */ + if (str_p < max_p) { + *str_p++ = '\0'; + } +} + +#endif /* __WB_MD5_H__ */ diff --git a/OpenCL_VectorAdd/libwb/wbMPI.cpp b/OpenCL_VectorAdd/libwb/wbMPI.cpp new file mode 100644 index 0000000..546c1ed --- /dev/null +++ b/OpenCL_VectorAdd/libwb/wbMPI.cpp @@ -0,0 +1,75 @@ + +#ifdef WB_USE_MPI + +#include +#include +#include +#include "wb.h" + +static int rank = -1; + +int wbMPI_getRank() { + if (rank != -1) { + return rank; + } + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + return rank; +} + +int rankCount() { + int nRanks; + MPI_Comm_size(MPI_COMM_WORLD, &nRanks); + return nRanks; +} + +const char *wbMPI_getStringFromRank(int rank, int tag) { + if (isMasterQ) { + char *buf; + int bufSize; + MPI_Recv(&bufSize, 1, MPI_INT, rank, tag, MPI_COMM_WORLD, + MPI_STATUS_IGNORE); + buf = (char *)calloc(bufSize, sizeof(char)); + MPI_Recv(buf, bufSize, MPI_CHAR, rank, tag, MPI_COMM_WORLD, + MPI_STATUS_IGNORE); + return buf; + } + + return NULL; +} +void wbMPI_sendStringToMaster(const char *str, int tag) { + if (!isMasterQ) { + // we are going to send the string to the master + int len = (int)strlen(str) + 1; + MPI_Send(&len, 1, MPI_INT, 0, tag, MPI_COMM_WORLD); + MPI_Send((void *)str, len, MPI_CHAR, 0, tag, MPI_COMM_WORLD); + } + + return; +} + +int wbMPI_Init(int *argc, char ***argv) { + int err = MPI_SUCCESS; + err = MPI_Init(argc, argv); + // printf("argc = %d\n", *argc); + // err = MPI_Init(NULL, NULL); + // printf("rank = %d is master = %d\n", wbMPI_getRank(), isMasterQ); + // MPI_Barrier(MPI_COMM_WORLD); + return err; +} + +bool finalizedQ = false; + +extern "C" int wbMPI_Finalize(void) { + if (finalizedQ) { + return MPI_SUCCESS; + } + finalizedQ = true; + wb_atExit(); + return MPI_Finalize(); +} +extern "C" void wbMPI_Exit(void) { + wbMPI_Finalize(); + return; +} + +#endif /* WB_USE_MPI */ diff --git a/OpenCL_VectorAdd/libwb/wbMPI.h b/OpenCL_VectorAdd/libwb/wbMPI.h new file mode 100644 index 0000000..6275eaf --- /dev/null +++ b/OpenCL_VectorAdd/libwb/wbMPI.h @@ -0,0 +1,37 @@ + +#ifndef __WB_MPI_H__ +#define __WB_MPI_H__ + +#ifdef WB_USE_MPI + +#include +#include +#include + +#define isMasterQ ((wbMPI_getRank()) == 0) + +extern int wbMPI_getRank(); + +extern int rankCount(); + +extern const char *wbMPI_getStringFromRank(int rank, int tag); +extern void wbMPI_sendStringToMaster(const char *str, int tag); + +extern int wbMPI_Init(int *argc, char ***argv); + +extern bool finalizedQ; + +extern "C" int wbMPI_Finalize(void); +extern "C" void wbMPI_Exit(void); + +#define MPI_Finalize wbMPI_Finalize + +#else /* WB_USE_MPI */ +static inline int rankCount() { + return 1; +} +static inline int wbMPI_getRank() { + return 0; +} +#endif /* WB_USE_MPI */ +#endif /* __WB_MPI_H__ */ diff --git a/OpenCL_VectorAdd/libwb/wbMalloc.h b/OpenCL_VectorAdd/libwb/wbMalloc.h new file mode 100644 index 0000000..5d74be4 --- /dev/null +++ b/OpenCL_VectorAdd/libwb/wbMalloc.h @@ -0,0 +1,140 @@ + + +#ifndef __WB_MALLOC_H__ +#define __WB_MALLOC_H__ + +#ifdef WB_USE_CUSTOM_MALLOC +#ifdef __linux__ +#define THROW __THROW +#else +#define THROW +#endif + +static inline void *_malloc(size_t size) THROW { + if (size == 0) { + return NULL; + } else { + int err; + void *res = memmgr_alloc((ulong)size, &err); + if (err) { + fprintf(stderr, "<>:: Memory allocation failed\n"); + exit(1); + } else { + size_t ii = 0; + unsigned char *p = (unsigned char *)res; + while (ii++ < size) { + *p++ = 0; + } + return res; + } + } +} + +static inline void _free(void *ptr) THROW { + if (ptr != NULL) { + memmgr_free(ptr); + } +} + +static inline void *_calloc(size_t nmemb, size_t size) THROW { + return _malloc(nmemb * size); +} + +static inline void *_realloc(void *ptr, size_t size) THROW { + if (size == 0) { + free(ptr); + return NULL; + } else if (ptr == NULL) { + return malloc(size); + } else { + void *buf; + unsigned char *dst; + unsigned char *src; + size_t alloc_size, to_copy, i = 0; + + // Allocate new buffer + buf = malloc(size); + + if (buf != 0) { + // Find original allocation size + alloc_size = (size_t)memmgr_get_block_size(ptr); + to_copy = alloc_size; + if (to_copy > size) { + to_copy = size; + } + + // Copy data to new buffer + dst = (unsigned char *)buf; + src = (unsigned char *)ptr; + while (i++ < to_copy) { + *dst++ = *src++; + } + + // Free the old buffer + free(ptr); + } + + return buf; + } +} + +#define wbNew(type) ((type *)_malloc(sizeof(type))) +#define wbNewArray(type, len) ((type *)_malloc((len) * sizeof(type))) +#define wbMalloc(sz) _malloc(sz) +#define wbDelete(var) \ + _free(var); \ + var = NULL +#define wbFree(var) \ + _free(var); \ + var = NULL +#define wbRealloc(var, newSize) _realloc(var, newSize) +#define wbReallocArray(t, m, n) ((t *)_realloc(m, n * sizeof(t))) + +#define free _free +#define malloc _malloc +#define calloc _calloc +#define realloc _realloc + +#else /* WB_USE_CUSTOM_MALLOC */ + +static inline void *xMalloc(size_t sz) { + void *mem = NULL; + if (sz != 0) { + mem = malloc(sz); + } + return mem; +} + +static inline void xFree(void *mem) { + if (mem != NULL) { + free(mem); + } + return; +} + +static inline void *xRealloc(void *mem, size_t sz) { + if (mem == NULL) { + return NULL; + } else if (sz == 0) { + xFree(mem); + return NULL; + } else { + void *res = realloc(mem, sz); + wbAssert(res != NULL); + return res; + } +} + +#define wbNew(type) ((type *)wbMalloc(sizeof(type))) +#define wbNewArray(type, len) ((type *)wbMalloc((len) * sizeof(type))) +#define wbMalloc(sz) xMalloc(sz) +#define wbDelete(var) wbFree(var) +#define wbFree(var) \ + xFree(var); \ + var = NULL +#define wbRealloc(var, newSize) xRealloc(var, newSize) +#define wbReallocArray(t, m, n) ((t *)xRealloc(m, n * sizeof(t))) + +#endif /* WB_USE_CUSTOM_MALLOC */ + +#endif /* __WB_MALLOC_H__ */ diff --git a/OpenCL_VectorAdd/libwb/wbPPM.cpp b/OpenCL_VectorAdd/libwb/wbPPM.cpp new file mode 100644 index 0000000..86ab208 --- /dev/null +++ b/OpenCL_VectorAdd/libwb/wbPPM.cpp @@ -0,0 +1,199 @@ + +#include +#include "wb.h" + +static inline float _min(float x, float y) { + return x < y ? x : y; +} + +static inline float _max(float x, float y) { + return x > y ? x : y; +} + +static inline float _clamp(float x, float start, float end) { + return _min(_max(x, start), end); +} + +static const char *skipSpaces(const char *line) { + while (*line == ' ' || *line == '\t') { + line++; + if (*line == '\0') { + break; + } + } + return line; +} + +static char nextNonSpaceChar(const char *line0) { + const char *line = skipSpaces(line0); + return *line; +} + +static wbBool isComment(const char *line) { + char nextChar = nextNonSpaceChar(line); + if (nextChar == '\0') { + return wbTrue; + } else { + return nextChar == '#'; + } +} + +static void parseDimensions(const char *line0, int *width, int *height) { + const char *line = skipSpaces(line0); + sscanf(line, "%d %d", width, height); +} + +static void parseDimensions(const char *line0, int *width, int *height, + int *channels) { + const char *line = skipSpaces(line0); + sscanf(line, "%d %d %d", width, height, channels); +} + +static void parseDepth(const char *line0, int *depth) { + const char *line = skipSpaces(line0); + sscanf(line, "%d", depth); +} + +static char *nextLine(wbFile_t file) { + char *line = NULL; + while ((line = wbFile_readLine(file)) != NULL) { + if (!isComment(line)) { + break; + } + } + return line; +} + +wbImage_t wbPPM_import(const char *filename) { + wbImage_t img; + wbFile_t file; + char *header; + char *line; + int ii, jj, kk, channels; + int width, height, depth; + unsigned char *charData, *charIter; + float *imgData, *floatIter; + float scale; + + img = NULL; + + file = wbFile_open(filename, "rb"); + if (file == NULL) { + printf("Could not open %s\n", filename); + goto cleanup; + } + + header = wbFile_readLine(file); + if (header == NULL) { + printf("Could not read from %s\n", filename); + goto cleanup; + } else if (strcmp(header, "P6") != 0 && strcmp(header, "P6\n") != 0 && + strcmp(header, "P5") != 0 && strcmp(header, "P5\n") != 0 && + strcmp(header, "S6") != 0 && strcmp(header, "S6\n") != 0) { + printf("Could find magic number for %s\n", filename); + goto cleanup; + } + + // P5 are monochrome while P6/S6 are rgb + // S6 needs to parse number of channels out of file + if (strcmp(header, "P5") == 0 || strcmp(header, "P5\n") == 0) { + channels = 1; + line = nextLine(file); + parseDimensions(line, &width, &height); + } else if (strcmp(header, "P6") == 0 || strcmp(header, "P6\n") == 0) { + channels = 3; + line = nextLine(file); + parseDimensions(line, &width, &height); + } else { + line = nextLine(file); + parseDimensions(line, &width, &height, &channels); + } + + // the line now contains the depth information + line = nextLine(file); + parseDepth(line, &depth); + + // the rest of the lines contain the data in binary format + charData = (unsigned char *)wbFile_read( + file, width * channels * sizeof(unsigned char), height); + + img = wbImage_new(width, height, channels); + + imgData = wbImage_getData(img); + + charIter = charData; + floatIter = imgData; + + scale = 1.0f / ((float)depth); + + for (ii = 0; ii < height; ii++) { + for (jj = 0; jj < width; jj++) { + for (kk = 0; kk < channels; kk++) { + *floatIter = ((float)*charIter) * scale; + floatIter++; + charIter++; + } + } + } + +#ifdef LAZY_FILE_LOAD + wbDelete(charData); +#endif + +cleanup: + wbFile_close(file); + return img; +} + +void wbPPM_export(const char *filename, wbImage_t img) { + int ii; + int jj; + int kk; + int depth; + int width; + int height; + int channels; + wbFile_t file; + float *floatIter; + unsigned char *charData; + unsigned char *charIter; + + file = wbFile_open(filename, "wb+"); + + width = wbImage_getWidth(img); + height = wbImage_getHeight(img); + channels = wbImage_getChannels(img); + depth = 255; + + if (channels == 1) { + wbFile_writeLine(file, "P5"); + } else { + wbFile_writeLine(file, "P6"); + } + wbFile_writeLine(file, "#Created via wbPPM Export"); + wbFile_writeLine(file, wbString(width, " ", height)); + wbFile_writeLine(file, wbString(depth)); + + charData = wbNewArray(unsigned char, width *height *channels); + + charIter = charData; + floatIter = wbImage_getData(img); + + for (ii = 0; ii < height; ii++) { + for (jj = 0; jj < width; jj++) { + for (kk = 0; kk < channels; kk++) { + *charIter = (unsigned char)ceil(_clamp(*floatIter, 0, 1) * depth); + floatIter++; + charIter++; + } + } + } + + wbFile_write(file, charData, width * channels * sizeof(unsigned char), + height); + + wbDelete(charData); + wbFile_delete(file); + + return; +} diff --git a/OpenCL_VectorAdd/libwb/wbPPM.h b/OpenCL_VectorAdd/libwb/wbPPM.h new file mode 100644 index 0000000..d589b36 --- /dev/null +++ b/OpenCL_VectorAdd/libwb/wbPPM.h @@ -0,0 +1,11 @@ + + +#ifndef __wbPPM_H__ +#define __wbPPM_H__ + +START_EXTERN_C +wbImage_t wbPPM_import(const char *filename); +void wbPPM_export(const char *filename, wbImage_t img); +END_EXTERN_C + +#endif /* __wbPPM_H__ */ diff --git a/OpenCL_VectorAdd/libwb/wbPath.cpp b/OpenCL_VectorAdd/libwb/wbPath.cpp new file mode 100644 index 0000000..0d93e2b --- /dev/null +++ b/OpenCL_VectorAdd/libwb/wbPath.cpp @@ -0,0 +1,42 @@ +#include "wb.h" + +char *wbPath_join(const char *p1, const char *p2) { + size_t s1 = strlen(p1); + size_t s2 = strlen(p2); + char *res = + wbNewArray(char, s1 + 1 /* seperator */ + s2 + 1 /* terminator */); + memcpy(res, p1, s1); + char *iter = res + s1; + *iter++ = wbDirectorySeperator; + memcpy(iter, p2, s2); + iter += s2; + *iter = '\0'; + return res; +} + +char *wbPath_join(const char *p1, const char *p2, const char *p3) { + char *p12 = wbPath_join(p1, p2); + char *res = wbPath_join(p12, p3); + wbDelete(p12); + return res; +} + +char *wbPath_join(const char *p1, const char *p2, const char *p3, + const char *p4) { + char *p123 = wbPath_join(p1, p2, p3); + char *res = wbPath_join(p123, p4); + wbDelete(p123); + return res; +} + +char *wbPath_join(const std::string &p1, const std::string &p2) { + return wbPath_join(p1.c_str(), p2.c_str()); +} +char *wbPath_join(const std::string &p1, const std::string &p2, + const std::string &p3) { + return wbPath_join(p1.c_str(), p2.c_str(), p3.c_str()); +} +char *wbPath_join(const std::string &p1, const std::string &p2, + const std::string &p3, const std::string &p4) { + return wbPath_join(p1.c_str(), p2.c_str(), p3.c_str(), p4.c_str()); +} \ No newline at end of file diff --git a/OpenCL_VectorAdd/libwb/wbPath.h b/OpenCL_VectorAdd/libwb/wbPath.h new file mode 100644 index 0000000..0dd3187 --- /dev/null +++ b/OpenCL_VectorAdd/libwb/wbPath.h @@ -0,0 +1,30 @@ +#ifndef __WB_PATH_H__ +#define __WB_PATH_H__ + +char *wbPath_join(const char *p1, const char *p2); +char *wbPath_join(const char *p1, const char *p2, const char *p3); +char *wbPath_join(const char *p1, const char *p2, const char *p3, + const char *p4); + +char *wbPath_join(const std::string &p1, const std::string &p2); +char *wbPath_join(const std::string &p1, const std::string &p2, + const std::string &p3); +char *wbPath_join(const std::string &p1, const std::string &p2, + const std::string &p3, const std::string &p4); + +template +static char *wbPath_join(const T1 &p1, const T2 &p2) { + return wbPath_join(wbString(p1), wbString(p2)); +} +template +static char *wbPath_join(const T1 &p1, const T2 &p2, const T3 &p3) { + return wbPath_join(wbString(p1), wbString(p2), wbString(p3)); +} +template +static char *wbPath_join(const T1 &p1, const T2 &p2, const T3 &p3, + const T4 &p4) { + return wbPath_join(wbString(p1), wbString(p2), wbString(p3), + wbString(p4)); +} + +#endif /* __WB_PATH_H__ */ diff --git a/OpenCL_VectorAdd/libwb/wbSolution.cpp b/OpenCL_VectorAdd/libwb/wbSolution.cpp new file mode 100644 index 0000000..703f410 --- /dev/null +++ b/OpenCL_VectorAdd/libwb/wbSolution.cpp @@ -0,0 +1,271 @@ + +#include "wb.h" + +char *solutionJSON = NULL; +static string _solution_correctQ(""); + +static void _onUnsameImageFunction(string str) { + _solution_correctQ = str; +} + +template +static wbBool wbSolution_listCorrectQ(const char *expectedOutputFile, + wbSolution_t sol, const char *type) { + wbBool res; + T *expectedData; + int expectedRows, expectedColumns; + + expectedData = (T *)wbImport(expectedOutputFile, &expectedRows, + &expectedColumns, type); + + if (expectedData == NULL) { + _solution_correctQ = "Failed to open expected output file."; + res = wbFalse; + } else if (expectedRows != wbSolution_getRows(sol)) { + wbLog(TRACE, "Number of rows in the solution is ", + wbSolution_getRows(sol), ". Expected number of rows is ", + expectedRows, "."); + _solution_correctQ = + "The number of rows in the solution did not match " + "that of the expected results."; + res = wbFalse; + } else if (expectedColumns != wbSolution_getColumns(sol)) { + wbLog(TRACE, "Number of columns in the solution is ", + wbSolution_getColumns(sol), ". Expected number of columns is ", + expectedColumns, "."); + _solution_correctQ = "The number of columns in the solution did not " + "match that of the expected results."; + res = wbFalse; + } else { + int ii, jj, idx; + T *solutionData; + + solutionData = (T *)wbSolution_getData(sol); + + for (ii = 0; ii < expectedRows; ii++) { + for (jj = 0; jj < expectedColumns; jj++) { + idx = ii * expectedColumns + jj; + if (wbUnequalQ(expectedData[idx], solutionData[idx])) { + string str; + if (expectedColumns == 1) { + str = wbString( + "The solution did not match the expected results at row ", + ii, ". Expecting ", expectedData[idx], " but got ", + solutionData[idx], "."); + } else { + str = wbString("The solution did not match the expected " + "results at column ", + jj, " and row ", ii, ". Expecting ", + expectedData[idx], " but got ", + solutionData[idx], "."); + } + _solution_correctQ = str; + res = wbFalse; + goto matrixCleanup; + } + } + } + + res = wbTrue; + matrixCleanup: + if (expectedData != NULL) { + wbFree(expectedData); + } + } + return res; +} + +static wbBool wbSolution_correctQ(char *expectedOutputFile, + wbSolution_t sol) { + if (expectedOutputFile == NULL) { + _solution_correctQ = "Failed to determined the expected output file."; + return wbFalse; + } else if (!wbFile_existsQ(expectedOutputFile)) { + _solution_correctQ = + wbString("The file ", expectedOutputFile, " does not exist."); + return wbFalse; + } else if (wbString_sameQ(wbSolution_getType(sol), "image")) { + wbBool res; + wbImage_t solutionImage = NULL; + wbImage_t expectedImage = wbImport(expectedOutputFile); + if (expectedImage == NULL) { + _solution_correctQ = "Failed to open expected output file."; + res = wbFalse; + } else if (wbImage_getWidth(expectedImage) != + wbSolution_getWidth(sol)) { + _solution_correctQ = + "The image width of the expected image does not " + "match that of the solution."; + res = wbFalse; + } else if (wbImage_getHeight(expectedImage) != + wbSolution_getHeight(sol)) { + _solution_correctQ = + "The image height of the expected image does not " + "match that of the solution."; + res = wbFalse; + } else if (wbImage_getChannels(expectedImage) != + wbSolution_getChannels(sol)) { + _solution_correctQ = + "The image channels of the expected image does not " + "match that of the solution."; + res = wbFalse; + } else { + solutionImage = (wbImage_t)wbSolution_getData(sol); + wbAssert(solutionImage != NULL); + res = wbImage_sameQ(solutionImage, expectedImage, + _onUnsameImageFunction); + } + if (expectedImage != NULL) { + wbImage_delete(expectedImage); + } + return res; + } else if (wbString_sameQ(wbSolution_getType(sol), "histogram")) { + return wbSolution_listCorrectQ(expectedOutputFile, sol, + "Integer"); + } else if (wbString_sameQ(wbSolution_getType(sol), "integral_vector")) { + return wbSolution_listCorrectQ(expectedOutputFile, sol, + "Integer"); + } else if (wbString_sameQ(wbSolution_getType(sol), "vector") || + wbString_sameQ(wbSolution_getType(sol), "matrix")) { + return wbSolution_listCorrectQ(expectedOutputFile, sol, + "Real"); + } else { + wbAssert(wbFalse); + return wbFalse; + } +} + +wbBool wbSolution(char *expectedOutputFile, char *outputFile, char *type0, + void *data, int rows, int columns, int depth) { + char *type; + wbBool res; + wbSolution_t sol; + + if (expectedOutputFile == NULL || data == NULL || type0 == NULL) { + wbLog(ERROR, "Failed to grade solution"); + return wbFalse; + } + + type = wbString_toLower(type0); + + if (_solution_correctQ != "") { + _solution_correctQ = ""; + } + + wbSolution_setOutputFile(sol, outputFile); + wbSolution_setType(sol, type); + wbSolution_setData(sol, data); + wbSolution_setRows(sol, rows); + wbSolution_setColumns(sol, columns); + wbSolution_setDepth(sol, depth); + + res = wbSolution_correctQ(expectedOutputFile, sol); + + if (outputFile != NULL) { + if (wbString_sameQ(type, "image")) { + wbImage_t inputImage = (wbImage_t)data; + wbImage_t img = wbImage_new(wbImage_getWidth(inputImage), + wbImage_getHeight(inputImage), + wbImage_getChannels(inputImage)); + memcpy(wbImage_getData(img), wbImage_getData(inputImage), + rows * columns * wbImage_channels * sizeof(wbReal_t)); + wbExport(outputFile, img); + wbImage_delete(img); + } else if (wbString_sameQ(type, "integral_vector")) { + wbExport(outputFile, (int *)data, rows, columns); + } else if (wbString_sameQ(type, "vector") || + wbString_sameQ(type, "matrix")) { + wbExport(outputFile, (wbReal_t *)data, rows, columns); + } else if (wbString_sameQ(type, "histogram")) { + wbExport(outputFile, (unsigned char *)data, rows, columns); + } else if (wbString_sameQ(type, "text")) { + wbExport_text(outputFile, (unsigned char *)data, rows * columns); + } + } + + wbFree(type); + + return res; +} + +wbBool wbSolution(char *expectedOutputFile, char *outputFile, char *type0, + void *data, int rows, int columns) { + return wbSolution(expectedOutputFile, outputFile, type0, data, rows, + columns, 1); +} + +wbBool wbSolution(wbArg_t arg, void *data, int rows, int columns, + int depth) { + char *type; + wbBool res; + char *expectedOutputFile; + char *outputFile; + stringstream ss; + + expectedOutputFile = wbArg_getExpectedOutputFile(arg); + outputFile = wbArg_getOutputFile(arg); + type = wbArg_getType(arg); + + wbAssert(type != NULL); + wbAssert(expectedOutputFile != NULL); + wbAssert(outputFile != NULL); + + res = wbSolution(expectedOutputFile, outputFile, type, data, rows, + columns, depth); + + if (WB_USE_JSON11) { + json11::Json json; + if (res) { + json = json11::Json::object{{"correctq", true}, + {"message", "The solution is correct"}}; + } else { + json = json11::Json::object{{"correctq", false}, + {"message", _solution_correctQ}}; + } + +#ifdef wbLogger_printOnLog + if (wbLogger_printOnLog) { + json11::Json e = +//PMO +#ifndef _MSC_VER + json11::Json::object{{"type", "solution"}, {"data", json}}; +#else + json11::Json::object{{"data", json }, {"type", "solution" }}; +#endif + std::cout << e.dump() << std::endl; + } +#endif /* wbLogger_printOnLog */ + + solutionJSON = wbString_duplicate(json.string_value()); + } else { + if (res) { + ss << "{\n"; + ss << wbString_quote("correctq") << ": true,\n"; + ss << wbString_quote("message") << ": " + << wbString_quote("Solution is correct.") << "\n"; + ss << "}"; + } else { + ss << "{\n"; + ss << wbString_quote("correctq") << ": false,\n"; + ss << wbString_quote("message") << ": " + << wbString_quote(_solution_correctQ) << "\n"; + ss << "}"; + } + solutionJSON = wbString_duplicate(ss.str()); + } + + return res; +} + +wbBool wbSolution(wbArg_t arg, void *data, int rows, int columns) { + return wbSolution(arg, data, rows, columns, 1); +} + +EXTERN_C wbBool wbSolution(wbArg_t arg, void *data, int rows) { + return wbSolution(arg, data, rows, 1); +} + +wbBool wbSolution(wbArg_t arg, wbImage_t img) { + return wbSolution(arg, img, wbImage_getHeight(img), + wbImage_getWidth(img), wbImage_getChannels(img)); +} diff --git a/OpenCL_VectorAdd/libwb/wbSolution.h b/OpenCL_VectorAdd/libwb/wbSolution.h new file mode 100644 index 0000000..f18d07d --- /dev/null +++ b/OpenCL_VectorAdd/libwb/wbSolution.h @@ -0,0 +1,40 @@ + + +#ifndef __WB_SOLUTION_H__ +#define __WB_SOLUTION_H__ + +typedef struct st_wbSolution_t { + char *type; + char *outputFile; + void *data; + int rows; + int columns; + int depth; +} wbSolution_t; + +#define wbSolution_getType(sol) ((sol).type) +#define wbSolution_getOutputFile(sol) ((sol).outputFile) +#define wbSolution_getData(sol) ((sol).data) +#define wbSolution_getRows(sol) ((sol).rows) +#define wbSolution_getColumns(sol) ((sol).columns) +#define wbSolution_getDepth(sol) ((sol).depth) + +#define wbSolution_getHeight wbSolution_getRows +#define wbSolution_getWidth wbSolution_getColumns +#define wbSolution_getChannels wbSolution_getDepth + +#define wbSolution_setType(sol, val) (wbSolution_getType(sol) = val) +#define wbSolution_setOutputFile(sol, val) \ + (wbSolution_getOutputFile(sol) = val) +#define wbSolution_setData(sol, val) (wbSolution_getData(sol) = val) +#define wbSolution_setRows(sol, val) (wbSolution_getRows(sol) = val) +#define wbSolution_setColumns(sol, val) (wbSolution_getColumns(sol) = val) +#define wbSolution_setDepth(sol, val) (wbSolution_getDepth(sol) = val) + +wbBool wbSolution(char *expectedOutputFile, char *outputFile, char *type0, + void *data, int rows, int columns); +wbBool wbSolution(wbArg_t arg, void *data, int rows, int columns); +EXTERN_C wbBool wbSolution(wbArg_t arg, void *data, int rows); +wbBool wbSolution(wbArg_t arg, wbImage_t img); + +#endif /* __WB_SOLUTION_H__ */ diff --git a/OpenCL_VectorAdd/libwb/wbSparse.cpp b/OpenCL_VectorAdd/libwb/wbSparse.cpp new file mode 100644 index 0000000..9cdcba3 --- /dev/null +++ b/OpenCL_VectorAdd/libwb/wbSparse.cpp @@ -0,0 +1,82 @@ + +#include "wb.h" + +static void sort(int *data, int *key, int start, int end) { + if ((end - start + 1) > 1) { + int left = start, right = end; + int pivot = key[right]; + while (left <= right) { + while (key[left] > pivot) { + left = left + 1; + } + while (key[right] < pivot) { + right = right - 1; + } + if (left <= right) { + int tmp = key[left]; + key[left] = key[right]; + key[right] = tmp; + tmp = data[left]; + data[left] = data[right]; + data[right] = tmp; + left = left + 1; + right = right - 1; + } + } + sort(data, key, start, right); + sort(data, key, left, end); + } +} + +EXTERN_C void CSRToJDS(int dim, int *csrRowPtr, int *csrColIdx, + float *csrData, int **jdsRowPerm, int **jdsRowNNZ, + int **jdsColStartIdx, int **jdsColIdx, + float **jdsData) { + // Row Permutation Vector + *jdsRowPerm = (int *)malloc(sizeof(int) * dim); + for (int rowIdx = 0; rowIdx < dim; ++rowIdx) { + (*jdsRowPerm)[rowIdx] = rowIdx; + } + + // Number of non-zeros per row + *jdsRowNNZ = (int *)malloc(sizeof(int) * dim); + for (int rowIdx = 0; rowIdx < dim; ++rowIdx) { + (*jdsRowNNZ)[rowIdx] = csrRowPtr[rowIdx + 1] - csrRowPtr[rowIdx]; + } + + // Sort rows by number of non-zeros + sort(*jdsRowPerm, *jdsRowNNZ, 0, dim - 1); + + // Starting point of each compressed column + int maxRowNNZ = (*jdsRowNNZ)[0]; // Largest number of non-zeros per row + DEBUG(printf("jdsRowNNZ = %d\n", maxRowNNZ)); + *jdsColStartIdx = (int *)malloc(sizeof(int) * maxRowNNZ); + (*jdsColStartIdx)[0] = 0; // First column starts at 0 + for (int col = 0; col < maxRowNNZ - 1; ++col) { + // Count the number of rows with entries in this column + int count = 0; + for (int idx = 0; idx < dim; ++idx) { + if ((*jdsRowNNZ)[idx] > col) { + ++count; + } + } + (*jdsColStartIdx)[col + 1] = (*jdsColStartIdx)[col] + count; + } + + // Sort the column indexes and data + const int NNZ = csrRowPtr[dim]; + DEBUG(printf("NNZ = %d\n", NNZ)); + *jdsColIdx = (int *)malloc(sizeof(int) * NNZ); + DEBUG(printf("dim = %d\n", dim)); + *jdsData = (float *)malloc(sizeof(float) * NNZ); + for (int idx = 0; idx < dim; ++idx) { // For every row + int row = (*jdsRowPerm)[idx]; + int rowNNZ = (*jdsRowNNZ)[idx]; + for (int nnzIdx = 0; nnzIdx < rowNNZ; ++nnzIdx) { + int jdsPos = (*jdsColStartIdx)[nnzIdx] + idx; + int csrPos = csrRowPtr[row] + nnzIdx; + (*jdsColIdx)[jdsPos] = csrColIdx[csrPos]; + (*jdsData)[jdsPos] = csrData[csrPos]; + } + } +} diff --git a/OpenCL_VectorAdd/libwb/wbSparse.h b/OpenCL_VectorAdd/libwb/wbSparse.h new file mode 100644 index 0000000..c04a857 --- /dev/null +++ b/OpenCL_VectorAdd/libwb/wbSparse.h @@ -0,0 +1,10 @@ + +#ifndef __WB_SPARSE_H__ +#define __WB_SPARSE_H__ + +EXTERN_C void CSRToJDS(int dim, int *csrRowPtr, int *csrColIdx, + float *csrData, int **jdsRowPerm, int **jdsRowNNZ, + int **jdsColStartIdx, int **jdsColIdx, + float **jdsData); + +#endif /* __WB_SPARSE_H__ */ diff --git a/OpenCL_VectorAdd/libwb/wbString.h b/OpenCL_VectorAdd/libwb/wbString.h new file mode 100644 index 0000000..65e52f8 --- /dev/null +++ b/OpenCL_VectorAdd/libwb/wbString.h @@ -0,0 +1,324 @@ + + +#ifndef __WB_STRING_H__ +#define __WB_STRING_H__ + +#include +#include +#include +#include +#include +#include +#include "wb.h" + +using std::string; +using std::vector; +using std::stringstream; +using std::exception; + +template +static inline string wbString(const T &x); + +static inline void wbString_replace(string &value, string const &search, + string const &replace) { + for (string::size_type next = value.find(search); next != string::npos; + next = value.find(search, next)) { + value.replace(next, search.length(), replace); + next += replace.length(); + } +} + +static inline string wbString_quote(string str) { + string s = str; + wbString_replace(s, "\\", "\\\\"); + s = "\"" + s + "\""; + return s; +} + +static inline string wbString_quote(const char *str) { + if (str == NULL) { + return wbString_quote(""); + } else { + return wbString_quote(string(str)); + } +} + +static inline char *wbString_duplicate(const char *str) { + if (str == NULL) { + return NULL; + } else { + char *newstr; + size_t len = strlen(str); + newstr = wbNewArray(char, len + 1); + memcpy(newstr, str, len * sizeof(char)); + newstr[len] = '\0'; + return newstr; + } +} + +static inline char *wbString_duplicate(std::string str) { + return wbString_duplicate(str.c_str()); +} + +static inline string wbString(void) { + string s = ""; + return s; +} + +template +static inline string wbString(const T &x) { + try { + stringstream ss; + ss << x; + return ss.str(); + } catch (exception &e) { + return string(); + } +} + +template <> +inline string wbString(const bool &x) { + return x ? "True" : "False"; +} + +template <> +inline string wbString(const vector &x) { + stringstream ss; + ss << "{"; + for (size_t ii = 0; ii < x.size(); ii++) { + ss << wbString_quote(x[ii]); + if (ii != x.size() - 1) { + ss << ", "; + } + } + ss << "}"; + + return ss.str(); +} + +template <> +inline string wbString(const vector &x) { + stringstream ss; + ss << "{"; + for (size_t ii = 0; ii < x.size(); ii++) { + ss << x[ii]; + if (ii != x.size() - 1) { + ss << ", "; + } + } + ss << "}"; + + return ss.str(); +} + +template <> +inline string wbString(const vector &x) { + stringstream ss; + ss << "{"; + for (size_t ii = 0; ii < x.size(); ii++) { + ss << x[ii]; + if (ii != x.size() - 1) { + ss << ", "; + } + } + ss << "}"; + + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1) { + stringstream ss; + ss << wbString(x0) << wbString(x1); + + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1, const T2 &x2) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2); + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1, const T2 &x2, + const T3 &x3) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2) << wbString(x3); + + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1, const T2 &x2, + const T3 &x3, const T4 &x4) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2) << wbString(x3) + << wbString(x4); + + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1, const T2 &x2, + const T3 &x3, const T4 &x4, const T5 &x5) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2) << wbString(x3) + << wbString(x4) << wbString(x5); + + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1, const T2 &x2, + const T3 &x3, const T4 &x4, const T5 &x5, + const T6 &x6) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2) << wbString(x3) + << wbString(x4) << wbString(x5) << wbString(x6); + + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1, const T2 &x2, + const T3 &x3, const T4 &x4, const T5 &x5, + const T6 &x6, const T7 &x7) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2) << wbString(x3) + << wbString(x4) << wbString(x5) << wbString(x6) << wbString(x7); + + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1, const T2 &x2, + const T3 &x3, const T4 &x4, const T5 &x5, + const T6 &x6, const T7 &x7, const T8 &x8) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2) << wbString(x3) + << wbString(x4) << wbString(x5) << wbString(x6) << wbString(x7) + << wbString(x8); + + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1, const T2 &x2, + const T3 &x3, const T4 &x4, const T5 &x5, + const T6 &x6, const T7 &x7, const T8 &x8, + const T9 &x9) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2) << wbString(x3) + << wbString(x4) << wbString(x5) << wbString(x6) << wbString(x7) + << wbString(x8) << wbString(x9); + + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1, const T2 &x2, + const T3 &x3, const T4 &x4, const T5 &x5, + const T6 &x6, const T7 &x7, const T8 &x8, + const T9 &x9, const T10 &x10) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2) << wbString(x3) + << wbString(x4) << wbString(x5) << wbString(x6) << wbString(x7) + << wbString(x8) << wbString(x9) << wbString(x10); + + return ss.str(); +} + +template +static inline string +wbString(const T0 &x0, const T1 &x1, const T2 &x2, const T3 &x3, + const T4 &x4, const T5 &x5, const T6 &x6, const T7 &x7, + const T8 &x8, const T9 &x9, const T10 &x10, const T11 &x11) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2) << wbString(x3) + << wbString(x4) << wbString(x5) << wbString(x6) << wbString(x7) + << wbString(x8) << wbString(x9) << wbString(x10) << wbString(x11); + + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1, const T2 &x2, + const T3 &x3, const T4 &x4, const T5 &x5, + const T6 &x6, const T7 &x7, const T8 &x8, + const T9 &x9, const T10 &x10, const T11 &x11, + const T12 &x12) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2) << wbString(x3) + << wbString(x4) << wbString(x5) << wbString(x6) << wbString(x7) + << wbString(x8) << wbString(x9) << wbString(x10) << wbString(x11) + << wbString(x12); + return ss.str(); +} + +template +static inline string wbString(const T0 &x0, const T1 &x1, const T2 &x2, + const T3 &x3, const T4 &x4, const T5 &x5, + const T6 &x6, const T7 &x7, const T8 &x8, + const T9 &x9, const T10 &x10, const T11 &x11, + const T12 &x12, const T13 &x13) { + stringstream ss; + ss << wbString(x0) << wbString(x1) << wbString(x2) << wbString(x3) + << wbString(x4) << wbString(x5) << wbString(x6) << wbString(x7) + << wbString(x8) << wbString(x9) << wbString(x10) << wbString(x11) + << wbString(x12) << wbString(x13); + return ss.str(); +} + +template +static inline wbBool wbString_sameQ(const X &x, const Y &y) { + string xs = wbString(x); + string ys = wbString(y); + return strcmp(xs.c_str(), ys.c_str()) == 0; +} + +static inline wbBool wbString_sameQ(const string &x, const string &y) { + return x.compare(y) == 0; +} + +static inline char *wbString_toLower(const char *str) { + if (str == NULL) { + return NULL; + } else { + char *res, *iter; + + res = iter = wbString_duplicate(str); + while (*iter != '\0') { + *iter++ = tolower(*str++); + } + return res; + } +} + +static inline wbBool wbString_startsWith(const char *str, + const char *prefix) { + while (*prefix != '\0') { + if (*str == '\0' || *str != *prefix) { + return wbFalse; + } + str++; + prefix++; + } + return wbTrue; +} + +#endif /* __WB_STRING_H__ */ diff --git a/OpenCL_VectorAdd/libwb/wbThrust.h b/OpenCL_VectorAdd/libwb/wbThrust.h new file mode 100644 index 0000000..e2d3160 --- /dev/null +++ b/OpenCL_VectorAdd/libwb/wbThrust.h @@ -0,0 +1,15 @@ + +#ifndef __WB_THRUST_H__ +#define __WB_THRUST_H__ + +#ifdef WB_USE_CUDA +#include +#include +#include +#include +#include +#include + +#endif /* WB_USE_CUDA */ + +#endif /* __WB_THRUST_H__ */ diff --git a/OpenCL_VectorAdd/libwb/wbTimer.cpp b/OpenCL_VectorAdd/libwb/wbTimer.cpp new file mode 100644 index 0000000..c9fbdb8 --- /dev/null +++ b/OpenCL_VectorAdd/libwb/wbTimer.cpp @@ -0,0 +1,493 @@ +#include "wb.h" + +#ifdef WB_USE_WINDOWS +uint64_t _hrtime_frequency = 0; +#endif /* WB_USE_WINDOWS */ +wbTimer_t _timer = NULL; + +#ifdef WB_USE_DARWIN +static double o_timebase = 0; +static uint64_t o_timestart = 0; +#endif /* WB_USE_DARWIN */ + +uint64_t _hrtime(void) { +#define NANOSEC ((uint64_t)1e9) +#ifdef WB_USE_WINDOWS + LARGE_INTEGER counter; + if (!QueryPerformanceCounter(&counter)) { + return 0; + } + return ((uint64_t)counter.LowPart * NANOSEC / _hrtime_frequency) + + (((uint64_t)counter.HighPart * NANOSEC / _hrtime_frequency) + << 32); +#else + struct timespec ts; +#ifdef WB_USE_DARWIN +#define O_NANOSEC (+1.0E-9) +#define O_GIGA UINT64_C(1000000000) + if (!o_timestart) { + mach_timebase_info_data_t tb{}; + mach_timebase_info(&tb); + o_timebase = tb.numer; + o_timebase /= tb.denom; + o_timestart = mach_absolute_time(); + } + double diff = (mach_absolute_time() - o_timestart) * o_timebase; + ts.tv_sec = diff * O_NANOSEC; + ts.tv_nsec = diff - (ts.tv_sec * O_GIGA); +#undef O_NANOSEC +#undef O_GIGA +#else /* WB_USE_DARWIN */ + clock_gettime(CLOCK_MONOTONIC, &ts); +#endif /* WB_USE_DARWIN */ + return (((uint64_t)ts.tv_sec) * NANOSEC + ts.tv_nsec); +#endif /* WB_USE_WINDOWS */ +#undef NANOSEC +} + +static inline uint64_t getTime(void) { +#ifdef WB_USE_CUDA + cudaDeviceSynchronize(); +#endif /* WB_USE_CUDA */ + return _hrtime(); +} + +static inline wbTimerNode_t wbTimerNode_new(int id, wbTimerKind_t kind, + const char *file, + const char *fun, + int startLine) { + wbTimerNode_t node = wbNew(struct st_wbTimerNode_t); + wbTimerNode_setId(node, id); + wbTimerNode_setMPIRank(node, wbMPI_getRank()); + wbTimerNode_setLevel(node, 0); + wbTimerNode_setStoppedQ(node, wbFalse); + wbTimerNode_setKind(node, kind); + wbTimerNode_setStartTime(node, 0); + wbTimerNode_setEndTime(node, 0); + wbTimerNode_setElapsedTime(node, 0); + wbTimerNode_setStartLine(node, startLine); + wbTimerNode_setEndLine(node, 0); + wbTimerNode_setStartFunction(node, fun); + wbTimerNode_setEndFunction(node, NULL); + wbTimerNode_setStartFile(node, file); + wbTimerNode_setEndFile(node, NULL); + wbTimerNode_setNext(node, NULL); + wbTimerNode_setPrevious(node, NULL); + wbTimerNode_setParent(node, NULL); + wbTimerNode_setMessage(node, NULL); + return node; +} + +static inline void wbTimerNode_delete(wbTimerNode_t node) { + if (node != NULL) { + if (wbTimerNode_getMessage(node)) { + wbDelete(wbTimerNode_getMessage(node)); + } + wbDelete(node); + } +} + +static inline const char *_nodeKind(wbTimerKind_t kind) { + switch (kind) { + case wbTimerKind_Generic: + return "Generic"; + case wbTimerKind_IO: + return "IO"; + case wbTimerKind_GPU: + return "GPU"; + case wbTimerKind_Copy: + return "Copy"; + case wbTimerKind_Driver: + return "Driver"; + case wbTimerKind_CopyAsync: + return "CopyAsync"; + case wbTimerKind_Compute: + return "Compute"; + case wbTimerKind_CPUGPUOverlap: + return "CPUGPUOverlap"; + } + return "Undefined"; +} + +static inline json11::Json wbTimerNode_toJSONObject(wbTimerNode_t node) { + json11::Json json = json11::Json::object{ + {"id", wbTimerNode_getId(node)}, + {"mpi_rank", wbTimerNode_getMPIRank(node)}, + {"stopped", wbTimerNode_stoppedQ(node)}, + {"kind", _nodeKind(wbTimerNode_getKind(node))}, + {"start_time", wbTimerNode_getStartTime(node)}, + {"end_time", wbTimerNode_getEndTime(node)}, + {"elapsed_time", wbTimerNode_getElapsedTime(node)}, + {"start_line", wbTimerNode_getStartLine(node)}, + {"end_line", wbTimerNode_getEndLine(node)}, + {"start_function", wbTimerNode_getStartFunction(node)}, + {"end_function", wbTimerNode_getEndFunction(node)}, + {"start_file", wbTimerNode_getStartFile(node)}, + {"end_file", wbTimerNode_getEndFile(node)}, + {"parent_id", wbTimerNode_hasParent(node) + ? wbTimerNode_getId(wbTimerNode_getParent(node)) + : -1}, + {"message", wbTimerNode_getMessage(node)}, + }; + return json; +} + +static inline string wbTimerNode_toJSON(wbTimerNode_t node) { + if (node == NULL) { + return ""; + } else if (WB_USE_JSON11) { + json11::Json json = wbTimerNode_toJSONObject(node); + return json.string_value(); + } else { + stringstream ss; + + ss << "{\n"; + ss << wbString_quote("id") << ":" << wbTimerNode_getId(node) << ",\n"; + ss << wbString_quote("mpi_rank") << ":" << wbTimerNode_getMPIRank(node) + << ",\n"; + ss << wbString_quote("stopped") << ":" + << wbString(wbTimerNode_stoppedQ(node) ? "true" : "false") << ",\n"; + ss << wbString_quote("kind") << ":" + << wbString_quote(_nodeKind(wbTimerNode_getKind(node))) << ",\n"; + ss << wbString_quote("start_time") << ":" + << wbTimerNode_getStartTime(node) << ",\n"; + ss << wbString_quote("end_time") << ":" << wbTimerNode_getEndTime(node) + << ",\n"; + ss << wbString_quote("elapsed_time") << ":" + << wbTimerNode_getElapsedTime(node) << ",\n"; + ss << wbString_quote("start_line") << ":" + << wbTimerNode_getStartLine(node) << ",\n"; + ss << wbString_quote("end_line") << ":" << wbTimerNode_getEndLine(node) + << ",\n"; + ss << wbString_quote("start_function") << ":" + << wbString_quote(wbTimerNode_getStartFunction(node)) << ",\n"; + ss << wbString_quote("end_function") << ":" + << wbString_quote(wbTimerNode_getEndFunction(node)) << ",\n"; + ss << wbString_quote("start_file") << ":" + << wbString_quote(wbTimerNode_getStartFile(node)) << ",\n"; + ss << wbString_quote("end_file") << ":" + << wbString_quote(wbTimerNode_getEndFile(node)) << ",\n"; + ss << wbString_quote("parent_id") << ":" + << wbString(wbTimerNode_hasParent(node) + ? wbTimerNode_getId(wbTimerNode_getParent(node)) + : -1) + << ",\n"; + ss << wbString_quote("message") << ":" + << wbString_quote(wbTimerNode_getMessage(node)) << "\n"; + ss << "}"; + + return ss.str(); + } +} + +static inline string wbTimerNode_toXML(wbTimerNode_t node) { + if (node == NULL) { + return ""; + } else { + stringstream ss; + + ss << "\n"; + ss << "" << wbTimerNode_getId(node) << "\n"; + ss << "" + << wbString(wbTimerNode_stoppedQ(node) ? "true" : "false") + << "\n"; + ss << "" << _nodeKind(wbTimerNode_getKind(node)) << "\n"; + ss << "" << wbTimerNode_getStartTime(node) + << "\n"; + ss << "" << wbTimerNode_getEndTime(node) << "\n"; + ss << "" << wbTimerNode_getElapsedTime(node) + << "\n"; + ss << "" << wbTimerNode_getStartLine(node) + << "\n"; + ss << "" << wbTimerNode_getEndLine(node) << "\n"; + ss << "" << wbTimerNode_getStartFunction(node) + << "\n"; + ss << "" << wbTimerNode_getEndFunction(node) + << "\n"; + ss << "" << wbTimerNode_getStartFile(node) + << "\n"; + ss << "" << wbTimerNode_getEndFile(node) << "\n"; + ss << "" + << wbString(wbTimerNode_hasParent(node) + ? wbTimerNode_getId(wbTimerNode_getParent(node)) + : -1) + << "\n"; + ss << "" << wbTimerNode_getMessage(node) << "\n"; + ss << "\n"; + + return ss.str(); + } +} + +#define wbTimer_getLength(timer) ((timer)->length) +#define wbTimer_getHead(timer) ((timer)->head) +#define wbTimer_getTail(timer) ((timer)->tail) +#define wbTimer_getStartTime(timer) ((timer)->startTime) +#define wbTimer_getEndTime(timer) ((timer)->endTime) +#define wbTimer_getElapsedTime(timer) ((timer)->elapsedTime) + +#define wbTimer_setLength(timer, val) (wbTimer_getLength(timer) = val) +#define wbTimer_setHead(timer, val) (wbTimer_getHead(timer) = val) +#define wbTimer_setTail(timer, val) (wbTimer_getTail(timer) = val) +#define wbTimer_setStartTime(node, val) (wbTimer_getStartTime(node) = val) +#define wbTimer_setEndTime(node, val) (wbTimer_getEndTime(node) = val) +#define wbTimer_setElapsedTime(node, val) \ + (wbTimer_getElapsedTime(node) = val) + +#define wbTimer_incrementLength(timer) (wbTimer_getLength(timer)++) +#define wbTimer_decrementLength(timer) (wbTimer_getLength(timer)--) + +#define wbTimer_emptyQ(timer) (wbTimer_getLength(timer) == 0) + +void wbTimer_delete(wbTimer_t timer) { + if (timer != NULL) { + wbTimerNode_t tmp, iter; + + iter = wbTimer_getHead(timer); + while (iter) { + tmp = wbTimerNode_getNext(iter); + wbTimerNode_delete(iter); + iter = tmp; + } + + wbDelete(timer); + } +} + +static json11::Json wbTimer_toJSONObject(wbTimer_t timer) { + + stringstream ss; + wbTimerNode_t iter; + uint64_t currentTime; + std::vector elems; + + currentTime = getTime(); + + wbTimer_setEndTime(timer, currentTime); + wbTimer_setElapsedTime(timer, currentTime - wbTimer_getStartTime(timer)); + + for (iter = wbTimer_getHead(timer); iter != NULL; + iter = wbTimerNode_getNext(iter)) { + if (!wbTimerNode_stoppedQ(iter)) { + wbTimerNode_setEndTime(iter, currentTime); + wbTimerNode_setElapsedTime(iter, currentTime - + wbTimerNode_getStartTime(iter)); + } + elems.push_back(wbTimerNode_toJSONObject(iter)); + } + return json11::Json(elems); +} + +string wbTimer_toJSON(wbTimer_t timer) { + if (timer == NULL) { + return ""; + } else if (WB_USE_JSON11) { + json11::Json json = wbTimer_toJSONObject(timer); + return json.string_value(); + } else { + stringstream ss; + wbTimerNode_t iter; + uint64_t currentTime; + + currentTime = getTime(); + + wbTimer_setEndTime(timer, currentTime); + wbTimer_setElapsedTime(timer, + currentTime - wbTimer_getStartTime(timer)); + + for (iter = wbTimer_getHead(timer); iter != NULL; + iter = wbTimerNode_getNext(iter)) { + if (!wbTimerNode_stoppedQ(iter)) { + wbTimerNode_setEndTime(iter, currentTime); + wbTimerNode_setElapsedTime( + iter, currentTime - wbTimerNode_getStartTime(iter)); + } + ss << wbTimerNode_toJSON(iter); + if (wbTimerNode_getNext(iter) != NULL) { + ss << ",\n"; + } + } + + return ss.str(); + } +} + +string wbTimer_toJSON() { + return wbTimer_toJSON(_timer); +} + +string wbTimer_toXML(wbTimer_t timer) { + if (timer == NULL) { + return ""; + } else { + stringstream ss; + wbTimerNode_t iter; + uint64_t currentTime; + + currentTime = getTime(); + + wbTimer_setEndTime(timer, currentTime); + wbTimer_setElapsedTime(timer, + currentTime - wbTimer_getStartTime(timer)); + + ss << "\n"; + ss << "" << wbTimer_getStartTime(timer) + << "\n"; + ss << "" << wbTimer_getEndTime(timer) << "\n"; + ss << "" << wbTimer_getElapsedTime(timer) + << "\n"; + ss << "\n"; + for (iter = wbTimer_getHead(timer); iter != NULL; + iter = wbTimerNode_getNext(iter)) { + if (!wbTimerNode_stoppedQ(iter)) { + wbTimerNode_setEndTime(iter, currentTime); + wbTimerNode_setElapsedTime( + iter, currentTime - wbTimerNode_getStartTime(iter)); + } + ss << wbTimerNode_toXML(iter); + } + ss << "\n"; + ss << "\n"; + + return ss.str(); + } +} + +string wbTimer_toXML() { + return wbTimer_toXML(_timer); +} + +wbTimer_t wbTimer_new(void) { + wbTimer_t timer = wbNew(struct st_wbTimer_t); + wbTimer_setLength(timer, 0); + wbTimer_setHead(timer, NULL); + wbTimer_setTail(timer, NULL); + wbTimer_setStartTime(timer, getTime()); + wbTimer_setEndTime(timer, 0); + wbTimer_setElapsedTime(timer, 0); + + return timer; +} + +static inline wbTimerNode_t _findParent(wbTimer_t timer) { + wbTimerNode_t iter; + + for (iter = wbTimer_getTail(timer); iter != NULL; + iter = wbTimerNode_getPrevious(iter)) { + if (!wbTimerNode_stoppedQ(iter)) { + return iter; + } + } + return NULL; +} + +static inline void _insertIntoList(wbTimer_t timer, wbTimerNode_t node) { + if (wbTimer_emptyQ(timer)) { + wbTimer_setHead(timer, node); + wbTimer_setTail(timer, node); + } else { + wbTimerNode_t end = wbTimer_getTail(timer); + wbTimer_setTail(timer, node); + wbTimerNode_setNext(end, node); + wbTimerNode_setPrevious(node, end); + } + wbTimer_incrementLength(timer); +} + +wbTimerNode_t wbTimer_start(wbTimerKind_t kind, const char *file, + const char *fun, int line) { + int id; + uint64_t currentTime; + wbTimerNode_t node; + wbTimerNode_t parent; + + wb_init(NULL, NULL); + + currentTime = getTime(); + + id = wbTimer_getLength(_timer); + + node = wbTimerNode_new(id, kind, file, fun, line); + + parent = _findParent(_timer); + _insertIntoList(_timer, node); + + wbTimerNode_setStartTime(node, currentTime); + wbTimerNode_setParent(node, parent); + if (parent != NULL) { + wbTimerNode_setLevel(node, wbTimerNode_getLevel(parent) + 1); + } + + return node; +} + +wbTimerNode_t wbTimer_start(wbTimerKind_t kind, string msg, + const char *file, const char *fun, int line) { + wbTimerNode_t node = wbTimer_start(kind, file, fun, line); + wbTimerNode_setMessage(node, wbString_duplicate(msg)); + return node; +} + +static inline wbTimerNode_t _findNode(wbTimer_t timer, wbTimerKind_t kind, + string msg) { + wbTimerNode_t iter; + + for (iter = wbTimer_getTail(timer); iter != NULL; + iter = wbTimerNode_getPrevious(iter)) { + if (msg == "") { + if (!wbTimerNode_stoppedQ(iter) && + wbTimerNode_getKind(iter) == kind) { + return iter; + } + } else { + if (!wbTimerNode_stoppedQ(iter) && + wbTimerNode_getKind(iter) == kind && + msg == wbTimerNode_getMessage(iter)) { + return iter; + } + } + } + return NULL; +} + +void wbTimer_stop(wbTimerKind_t kind, string msg, const char *file, + const char *fun, int line) { + uint64_t currentTime; + wbTimerNode_t node; + + currentTime = getTime(); + + node = _findNode(_timer, kind, msg); + + wbAssert(node != NULL); + if (node == NULL) { + return; + } + + wbTimerNode_setEndTime(node, currentTime); + wbTimerNode_setElapsedTime(node, + currentTime - wbTimerNode_getStartTime(node)); + wbTimerNode_setEndLine(node, line); + wbTimerNode_setEndFunction(node, fun); + wbTimerNode_setEndFile(node, file); + wbTimerNode_setStoppedQ(node, wbTrue); + +#ifdef wbLogger_printOnLog + if (wbLogger_printOnLog) { + json11::Json json = json11::Json::object{ +//PMO +#ifndef _MSC_VER + { "type", "timer" }, { "data", wbTimerNode_toJSONObject(node) }}; +#else + { "data", wbTimerNode_toJSONObject(node) }, { "type", "timer" }}; +#endif + std::cout << json.dump() << std::endl; + } +#endif /* wbLogger_printOnLog */ + return; +} + +void wbTimer_stop(wbTimerKind_t kind, const char *file, const char *fun, + int line) { + wbTimer_stop(kind, "", file, fun, line); +} diff --git a/OpenCL_VectorAdd/libwb/wbTimer.h b/OpenCL_VectorAdd/libwb/wbTimer.h new file mode 100644 index 0000000..133b58f --- /dev/null +++ b/OpenCL_VectorAdd/libwb/wbTimer.h @@ -0,0 +1,139 @@ + + +#ifndef __WB_TIMER_H__ +#define __WB_TIMER_H__ + +#ifdef WB_USE_WINDOWS +extern uint64_t _hrtime_frequency; +#endif /* _WIN32 */ + +extern wbTimer_t _timer; + +typedef enum en_wbTimerKind_t { + wbTimerKind_Generic, + wbTimerKind_IO, + wbTimerKind_GPU, + wbTimerKind_Copy, + wbTimerKind_Driver, + wbTimerKind_CopyAsync, + wbTimerKind_Compute, + wbTimerKind_CPUGPUOverlap, +} wbTimerKind_t; + +struct st_wbTimerNode_t { + int id; + int mpiRank; + int level; + wbBool stoppedQ; + wbTimerKind_t kind; + uint64_t startTime; + uint64_t endTime; + uint64_t elapsedTime; + int startLine; + int endLine; + const char *startFunction; + const char *endFunction; + const char *startFile; + const char *endFile; + wbTimerNode_t next; + wbTimerNode_t prev; + wbTimerNode_t parent; + char *msg; +}; + +struct st_wbTimer_t { + size_t length; + wbTimerNode_t head; + wbTimerNode_t tail; + uint64_t startTime; + uint64_t endTime; + uint64_t elapsedTime; +}; + +#define wbTimerNode_getId(node) ((node)->id) +#define wbTimerNode_getMPIRank(node) ((node)->mpiRank) +#define wbTimerNode_getLevel(node) ((node)->level) +#define wbTimerNode_getStoppedQ(node) ((node)->stoppedQ) +#define wbTimerNode_getKind(node) ((node)->kind) +#define wbTimerNode_getStartTime(node) ((node)->startTime) +#define wbTimerNode_getEndTime(node) ((node)->endTime) +#define wbTimerNode_getElapsedTime(node) ((node)->elapsedTime) +#define wbTimerNode_getStartLine(node) ((node)->startLine) +#define wbTimerNode_getEndLine(node) ((node)->endLine) +#define wbTimerNode_getStartFunction(node) ((node)->startFunction) +#define wbTimerNode_getEndFunction(node) ((node)->endFunction) +#define wbTimerNode_getStartFile(node) ((node)->startFile) +#define wbTimerNode_getEndFile(node) ((node)->endFile) +#define wbTimerNode_getNext(node) ((node)->next) +#define wbTimerNode_getPrevious(node) ((node)->prev) +#define wbTimerNode_getParent(node) ((node)->parent) +#define wbTimerNode_getMessage(node) ((node)->msg) + +#define wbTimerNode_setId(node, val) (wbTimerNode_getId(node) = val) +#define wbTimerNode_setMPIRank(node, val) \ + (wbTimerNode_getMPIRank(node) = val) +#define wbTimerNode_setLevel(node, val) (wbTimerNode_getLevel(node) = val) +#define wbTimerNode_setStoppedQ(node, val) \ + (wbTimerNode_getStoppedQ(node) = val) +#define wbTimerNode_setKind(node, val) (wbTimerNode_getKind(node) = val) +#define wbTimerNode_setStartTime(node, val) \ + (wbTimerNode_getStartTime(node) = val) +#define wbTimerNode_setEndTime(node, val) \ + (wbTimerNode_getEndTime(node) = val) +#define wbTimerNode_setElapsedTime(node, val) \ + (wbTimerNode_getElapsedTime(node) = val) +#define wbTimerNode_setStartLine(node, val) \ + (wbTimerNode_getStartLine(node) = val) +#define wbTimerNode_setEndLine(node, val) \ + (wbTimerNode_getEndLine(node) = val) +#define wbTimerNode_setStartFunction(node, val) \ + (wbTimerNode_getStartFunction(node) = val) +#define wbTimerNode_setEndFunction(node, val) \ + (wbTimerNode_getEndFunction(node) = val) +#define wbTimerNode_setStartFile(node, val) \ + (wbTimerNode_getStartFile(node) = val) +#define wbTimerNode_setEndFile(node, val) \ + (wbTimerNode_getEndFile(node) = val) +#define wbTimerNode_setNext(node, val) (wbTimerNode_getNext(node) = val) +#define wbTimerNode_setPrevious(node, val) \ + (wbTimerNode_getPrevious(node) = val) +#define wbTimerNode_setParent(node, val) \ + (wbTimerNode_getParent(node) = val) +#define wbTimerNode_setMessage(node, val) \ + (wbTimerNode_getMessage(node) = val) + +#define wbTimerNode_stoppedQ(node) \ + (wbTimerNode_getStoppedQ(node) == wbTrue) +#define wbTimerNode_hasNext(node) (wbTimerNode_getNext(node) != NULL) +#define wbTimerNode_hasPrevious(node) \ + (wbTimerNode_getPrevious(node) != NULL) +#define wbTimerNode_hasParent(node) (wbTimerNode_getParent(node) != NULL) + +uint64_t _hrtime(void); + +wbTimer_t wbTimer_new(void); +void wbTimer_delete(wbTimer_t timer); + +string wbTimer_toJSON(wbTimer_t timer); +string wbTimer_toJSON(); + +string wbTimer_toXML(wbTimer_t timer); +string wbTimer_toXML(); + +wbTimerNode_t wbTimer_start(wbTimerKind_t kind, const char *file, + const char *fun, int line); +wbTimerNode_t wbTimer_start(wbTimerKind_t kind, string msg, + const char *file, const char *fun, int line); +void wbTimer_stop(wbTimerKind_t kind, string msg, const char *file, + const char *fun, int line); +void wbTimer_stop(wbTimerKind_t kind, const char *file, const char *fun, + int line); + +#define wbTime_start(kind, ...) \ + wbTimer_start(wbTimerKind_##kind, wbString(__VA_ARGS__), wbFile, \ + wbFunction, wbLine) +#define wbTime_stop(kind, ...) \ + wbTimer_stop(wbTimerKind_##kind, wbString(__VA_ARGS__), wbFile, \ + wbFunction, wbLine) + +#endif /* __WB_TIMER_H__ */ diff --git a/OpenCL_VectorAdd/libwb/wbTypes.h b/OpenCL_VectorAdd/libwb/wbTypes.h new file mode 100644 index 0000000..6837792 --- /dev/null +++ b/OpenCL_VectorAdd/libwb/wbTypes.h @@ -0,0 +1,55 @@ + + +#ifndef __WB_TYPES_H__ +#define __WB_TYPES_H__ + +#include "wbAssert.h" + +typedef bool wbBool; +typedef float wbReal_t; +typedef char wbChar_t; + +typedef struct st_wbTimerNode_t *wbTimerNode_t; +typedef struct st_wbTimer_t *wbTimer_t; +typedef struct st_wbLogEntry_t *wbLogEntry_t; +typedef struct st_wbLogger_t *wbLogger_t; +typedef struct st_wbArg_t wbArg_t; +typedef struct st_wbImage_t *wbImage_t; +typedef struct st_wbFile_t *wbFile_t; + +#define wbTrue true +#define wbFalse false + +typedef enum en_wbType_t { + wbType_unknown = -1, + wbType_ascii = 1, + wbType_bit8, + wbType_ubit8, + wbType_integer, + wbType_float, + wbType_double +} wbType_t; + +static inline size_t wbType_size(wbType_t ty) { + switch (ty) { + case wbType_unknown: + wbAssert(false && "Invalid wbType_unknown"); + return 0; + case wbType_ascii: + return sizeof(char); + case wbType_bit8: + return sizeof(char); + case wbType_ubit8: + return sizeof(unsigned char); + case wbType_integer: + return sizeof(int); + case wbType_float: + return sizeof(float); + case wbType_double: + return sizeof(double); + } + wbAssert(false && "Invalid type"); + return 0; +} + +#endif /* __WB_TYPES_H__ */ diff --git a/OpenCL_VectorAdd/libwb/wbUtils.h b/OpenCL_VectorAdd/libwb/wbUtils.h new file mode 100644 index 0000000..cbd1b91 --- /dev/null +++ b/OpenCL_VectorAdd/libwb/wbUtils.h @@ -0,0 +1,10 @@ +#ifndef __WB_UTILS_H__ +#define __WB_UTILS_H__ + +#ifdef WB_DEBUG +#define DEBUG(...) __VA_ARGS__ +#else /* WB_DEBUG */ +#define DEBUG(...) +#endif /* WB_DEBUG */ + +#endif /* __WB_UTILS_H__ */ diff --git a/OpenCL_VectorAdd/libwb/wb_test.cpp b/OpenCL_VectorAdd/libwb/wb_test.cpp new file mode 100644 index 0000000..87883c8 --- /dev/null +++ b/OpenCL_VectorAdd/libwb/wb_test.cpp @@ -0,0 +1,4 @@ +#define CATCH_CONFIG_MAIN + +#include "wb.h" +#include "vendor/catch.hpp"